Demo

Tic Tac Toe Game

Experience the classic Tic Tac Toe game reimagined with LemonadeJS. Two players take turns marking spaces in a three-by-three grid with X or O. The first player to get three marks in a row wins!


<html>
<script src="https://cdn.jsdelivr.net/npm/lemonadejs/dist/lemonade.min.js"></script>
<div id='root'></div>
<script>
function Tictactoe() {
    const self = this;

    let text = [
        'can start the game',
        'turn to play',
        'won the game',
    ]
    self.players = [ 'O','X' ];

    const checkMatching = function(a, b, c) {
        if (self.board[a].player &&
            self.board[a].player === self.board[b].player &&
            self.board[b].player === self.board[c].player) {
            return true;
        }
        return false;
    }

    const isWinner = function() {
        return (checkMatching(0, 1, 2) || checkMatching(3, 4, 5) || checkMatching(6, 7, 8) ||
                checkMatching(0, 3, 6) || checkMatching(1, 4, 7) || checkMatching(2, 5, 8) ||
                checkMatching(0, 4, 8) || checkMatching(2, 4, 6));
    }

    self.click = function(e) {
        if (e.target.tagName === 'SPAN') {
            if (self.winner) {
                alert(self.title.textContent);
            } else {
                if (!e.target.textContent) {
                    let index = Array.prototype.indexOf.call(e.target.parentNode.children, e.target);
                    self.board[index].player = self.player;
                    self.text = text[1];
                    if (isWinner()) {
                        self.text = text[2];
                        self.winner = true;
                        alert(self.title.textContent);
                    } else {
                        self.player = self.player ? 0 : 1;
                    }
                }
            }
        }
    }

    self.reset = function() {
        self.player = 0;
        self.text = text[0];
        self.winner = false;
        self.board = [{},{},{},{},{},{},{},{},{}];
    }

    self.reset();

    return `<div class="tictactoe">
        <div class="title" :ref="self.title">{{self.players[self.player]}} {{self.text}}</div>
        <div :loop="self.board" class="board" onclick="self.click">
            <span>{{self.parent.players[self.player]}}</span>
        </div><br/>
        <input type="button" onclick="self.reset" value="Reset the game" />
    </div>`;
}

lemonade.render(Tictactoe, document.getElementById('root'));
</script>

<style>
.tictactoe {
    max-width: 244px;
}

.tictactoe .title {
    padding: 20px;
    text-align: center;
}

.tictactoe .board {
    display: grid;
    gap: 1px;
    grid-template-columns: repeat(3, 1fr);
}

.tictactoe .board > span {
    margin: 2px;
    width: 80px;
    height: 80px;
    background-color: #ddd;
    line-height: 80px;
    text-align: center;
    font-size: 22px;
    cursor: pointer;
}

.tictactoe button {
    width: 100%;
}
</style>
</html>
import lemonade from 'lemonadejs';

export default function Tictactoe() {
    const self = this;

    let text = [
        'can start the game',
        'turn to play',
        'won the game',
    ]
    self.players = [ 'O','X' ];

    const checkMatching = function(a, b, c) {
        if (self.board[a].player &&
            self.board[a].player === self.board[b].player &&
            self.board[b].player === self.board[c].player) {
            return true;
        }
        return false;
    }

    const isWinner = function() {
        return (checkMatching(0, 1, 2) || checkMatching(3, 4, 5) || checkMatching(6, 7, 8) ||
                checkMatching(0, 3, 6) || checkMatching(1, 4, 7) || checkMatching(2, 5, 8) ||
                checkMatching(0, 4, 8) || checkMatching(2, 4, 6));
    }

    self.click = function(e) {
        if (e.target.tagName === 'SPAN') {
            if (self.winner) {
                alert(self.title.textContent);
            } else {
                if (!e.target.textContent) {
                    let index = Array.prototype.indexOf.call(e.target.parentNode.children, e.target);
                    self.board[index].player = self.player;
                    self.text = text[1];
                    if (isWinner()) {
                        self.text = text[2];
                        self.winner = true;
                        alert(self.title.textContent);
                    } else {
                        self.player = self.player ? 0 : 1;
                    }
                }
            }
        }
    }

    self.reset = function() {
        self.player = 0;
        self.text = text[0];
        self.winner = false;
        self.board = [{},{},{},{},{},{},{},{},{}];
    }

    self.reset();

    return `<div class="tictactoe">
        <div class="title" :ref="self.title">{{self.players[self.player]}} {{self.text}}</div>
        <div :loop="self.board" class="board" onclick="self.click">
            <span>{{self.parent.players[self.player]}}</span>
        </div><br/>
        <input type="button" onclick="self.reset" value="Reset the game" />
    </div>`;
}
import React, { useState, useEffect } from 'react';
import './TicTacToe.css';

export default function TicTacToe() {
    const [player, setPlayer] = useState(0);
    const [text, setText] = useState('can start the game');
    const [winner, setWinner] = useState(false);
    const [board, setBoard] = useState([{},{},{},{},{},{},{},{},{}]);
    const players = ['O', 'X'];

    const checkMatching = (a, b, c) => {
        if (board[a].player &&
            board[a].player === board[b].player &&
            board[b].player === board[c].player) {
            return true;
        }
        return false;
    }

    const isWinner = () => {
        return (checkMatching(0, 1, 2) || checkMatching(3, 4, 5) || checkMatching(6, 7, 8) ||
                checkMatching(0, 3, 6) || checkMatching(1, 4, 7) || checkMatching(2, 5, 8) ||
                checkMatching(0, 4, 8) || checkMatching(2, 4, 6));
    }

    const handleClick = (index) => {
        if (winner) {
            alert(`${players[player]} won the game`);
        } else {
            if (!board[index].player) {
                const newBoard = [...board];
                newBoard[index].player = player;
                setBoard(newBoard);
                setText('turn to play');

                if (isWinner()) {
                    setText('won the game');
                    setWinner(true);
                    setTimeout(() => alert(`${players[player]} won the game`), 100);
                } else {
                    setPlayer(player ? 0 : 1);
                }
            }
        }
    }

    const reset = () => {
        setPlayer(0);
        setText('can start the game');
        setWinner(false);
        setBoard([{},{},{},{},{},{},{},{},{}]);
    }

    return (
        <div className="tictactoe">
            <div className="title">{players[player]} {text}</div>
            <div className="board">
                {board.map((cell, index) => (
                    <span key={index} onClick={() => handleClick(index)}>
                        {cell.player !== undefined ? players[cell.player] : ''}
                    </span>
                ))}
            </div>
            <br/>
            <input type="button" onClick={reset} value="Reset the game" />
        </div>
    );
}
<template>
    <div class="tictactoe">
        <div class="title">{{ players[player] }} {{ text }}</div>
        <div class="board">
            <span v-for="(cell, index) in board" :key="index" @click="handleClick(index)">
                {{ cell.player !== undefined ? players[cell.player] : '' }}
            </span>
        </div>
        <br/>
        <input type="button" @click="reset" value="Reset the game" />
    </div>
</template>

<script>
export default {
    name: 'TicTacToe',
    data() {
        return {
            player: 0,
            text: 'can start the game',
            winner: false,
            board: [{},{},{},{},{},{},{},{},{}],
            players: ['O', 'X']
        }
    },
    methods: {
        checkMatching(a, b, c) {
            if (this.board[a].player &&
                this.board[a].player === this.board[b].player &&
                this.board[b].player === this.board[c].player) {
                return true;
            }
            return false;
        },
        isWinner() {
            return (this.checkMatching(0, 1, 2) || this.checkMatching(3, 4, 5) || this.checkMatching(6, 7, 8) ||
                    this.checkMatching(0, 3, 6) || this.checkMatching(1, 4, 7) || this.checkMatching(2, 5, 8) ||
                    this.checkMatching(0, 4, 8) || this.checkMatching(2, 4, 6));
        },
        handleClick(index) {
            if (this.winner) {
                alert(`${this.players[this.player]} won the game`);
            } else {
                if (!this.board[index].player) {
                    this.board[index].player = this.player;
                    this.text = 'turn to play';

                    if (this.isWinner()) {
                        this.text = 'won the game';
                        this.winner = true;
                        setTimeout(() => alert(`${this.players[this.player]} won the game`), 100);
                    } else {
                        this.player = this.player ? 0 : 1;
                    }
                }
            }
        },
        reset() {
            this.player = 0;
            this.text = 'can start the game';
            this.winner = false;
            this.board = [{},{},{},{},{},{},{},{},{}];
        }
    }
}
</script>

<style scoped>
.tictactoe {
    max-width: 244px;
}

.tictactoe .title {
    padding: 20px;
    text-align: center;
}

.tictactoe .board {
    display: grid;
    gap: 1px;
    grid-template-columns: repeat(3, 1fr);
}

.tictactoe .board > span {
    margin: 2px;
    width: 80px;
    height: 80px;
    background-color: #ddd;
    line-height: 80px;
    text-align: center;
    font-size: 22px;
    cursor: pointer;
}

.tictactoe button {
    width: 100%;
}
</style>