function undisplay(element) { element.style.display="none"; } function add_message(severity, message) { message = `
× ${message}
`; const message_area = document.getElementById('message-area'); message_area.insertAdjacentHTML('beforeend', message); } const events = new EventSource("events"); events.onerror = function(event) { if (event.target.readyState === EventSource.CLOSED) { add_message("danger", "Connection to server lost."); } }; events.addEventListener("move", event => { const square = JSON.parse(event.data); window.game.receiveMove(square); }); function Square(props) { return ( ); } class Board extends React.Component { renderSquare(i) { return ( this.props.onClick(i)} /> ); } render() { return (
{this.renderSquare(0)} {this.renderSquare(1)} {this.renderSquare(2)}
{this.renderSquare(3)} {this.renderSquare(4)} {this.renderSquare(5)}
{this.renderSquare(6)} {this.renderSquare(7)} {this.renderSquare(8)}
); } } function fetch_post_json(api = '', data = {}) { const response = fetch(api, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data) }); return response; } class Game extends React.Component { constructor(props) { super(props); this.state = { history: [ { squares: Array(9).fill(null) } ], stepNumber: 0, xIsNext: true }; } sendMove(i) { return fetch_post_json("move", { square: i }); } receiveMove(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 } ]), stepNumber: history.length, xIsNext: !this.state.xIsNext }); } async handleClick(i) { const response = await this.sendMove(i); if (response.status == 200) { const legal = await response.json(); if (! legal) add_message("danger", `Illegal move.`); } else { add_message("danger", `Error occurred sending move`); } } jumpTo(step) { this.setState({ stepNumber: step, xIsNext: (step % 2) === 0 }); } render() { const history = this.state.history; const current = history[this.state.stepNumber]; const winner = calculateWinner(current.squares); const moves = history.map((step, move) => { const desc = move ? 'Go to move #' + move : 'Go to game start'; return (
  • ); }); let status; if (winner) { status = "Winner: " + winner; } else { status = "Next player: " + (this.state.xIsNext ? "X" : "O"); } return (
    this.handleClick(i)} />
    {status}
      {moves}
    ); } } // ======================================== ReactDOM.render( window.game = me} />, document.getElementById("tictactoe")); 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 squares[a]; } } return null; }