Skip to content

Instantly share code, notes, and snippets.

@quanfoo
Created February 9, 2017 15:58
Show Gist options
  • Select an option

  • Save quanfoo/d1589710b3c444dfcf08cd21cd261fa8 to your computer and use it in GitHub Desktop.

Select an option

Save quanfoo/d1589710b3c444dfcf08cd21cd261fa8 to your computer and use it in GitHub Desktop.

Revisions

  1. quanfoo created this gist Feb 9, 2017.
    173 changes: 173 additions & 0 deletions tic-tac-toe.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,173 @@
    function Square({ value, style, onClick }) {
    return (
    <button className="square" onClick={onClick} style={{background: style}}>
    {value}
    </button>
    );
    }

    function Board({ squares, winner, onClick }) {
    function renderSquare(i) {
    let style;

    if (winner && winner.line.includes(i)) {
    style = 'red';
    }

    return <Square value={squares[i]}
    key={i}
    onClick={() => onClick(i)}
    style={style}/>;
    }

    return (
    <div>
    <div className="status">{status}</div>
    {
    Array(3).fill(null).map((val, i) => {
    return (
    <div className="board-row" key={i}>
    {
    Array(3).fill(null).map((val, j) => {
    return renderSquare(i * 3 + j);
    })
    }
    </div>
    );
    })
    }
    </div>
    );
    }

    class Game extends React.Component {
    constructor() {
    super();

    this.state = {
    history: [{
    squares: Array(9).fill(null),
    clickIdx: 0,
    winnerLine: []
    }],
    xIsNext: true,
    stepNumber: 0,
    moveOrderAsc: true,
    };

    this.handleClick = this.handleClick.bind(this);
    this.jumpTo = this.jumpTo.bind(this);
    this.toggleOrder = this.toggleOrder.bind(this);
    }

    handleClick(i) {
    const history = this.state.history.slice(0, this.state.stepNumber + 1);
    const current = history[history.length - 1];
    const squares = current.squares.slice();

    if (calculateWinner(squares) || squares[i]) {
    return;
    }

    squares[i] = this.state.xIsNext ? 'X' : 'O';

    this.setState({
    history: history.concat([{
    squares: squares,
    clickIdx: i,
    }]),
    xIsNext: !this.state.xIsNext,
    stepNumber: this.state.stepNumber + 1,
    });
    }

    jumpTo(step) {
    this.setState({
    stepNumber: step,
    xIsNext: step % 2 === 1,
    });
    }

    toggleOrder() {
    this.setState({
    moveOrderAsc: !this.state.moveOrderAsc
    });
    }

    render() {
    const { history, stepNumber, xIsNext, moveOrderAsc } = this.state;
    const squares = history[stepNumber].squares;

    const moves = history.map((step, move) => {
    const desc = move ? 'Move ' + getPosition(step.clickIdx) : 'Game start';
    return (
    <li key={move} style={{fontWeight: move === stepNumber ? 'bold' : 'normal'}}>
    <a href="#" onClick={() => this.jumpTo(move)}>{desc}</a>
    </li>
    );
    });

    if (!moveOrderAsc) moves.reverse();

    const winner = calculateWinner(squares);
    let status;
    if (winner) {
    status = `Winner: ${winner.name}`;
    } else {
    status = `Next player: ${xIsNext ? 'X' : 'O'}`;
    }

    return (
    <div>
    <div className="game">
    <div className="game-board">
    <Board squares={squares} winner={winner} onClick={(i) => this.handleClick(i)} />
    </div>
    <div className="game-info">
    <div>{status}</div>
    <ol>{moves}</ol>
    </div>
    </div>
    <button onClick={this.toggleOrder} style={{marginTop: '10px'}}>
    {moveOrderAsc ? 'Descending' : 'Ascending'}
    </button>
    </div>
    );
    }
    }

    // ========================================

    ReactDOM.render(
    <Game />,
    document.getElementById('container')
    );

    function calculateWinner(squares) {
    const lines = [
    [0, 1, 2],
    [3, 4, 5],
    [6, 7, 8],
    [0, 3, 6],
    [1, 4, 7],
    [2, 5, 8],
    [0, 4, 8],
    [2, 4, 6],
    ];
    for (let i = 0; i < lines.length; i++) {
    const [a, b, c] = lines[i];
    if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) {
    return {
    name: squares[a],
    line: lines[i],
    };
    }
    }
    return null;
    }

    function getPosition(index) {
    var row = Math.floor(index / 3) + 1;
    var col = index % 3 + 1;
    return `(${row}, ${col})`;
    }