Created
February 6, 2019 20:04
-
-
Save thiskevinwang/67a071cf89d789fbda5dd3a5bb271e30 to your computer and use it in GitHub Desktop.
The final code, before the extras.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // Source: Dan Abramov | |
| // https://codepen.io/gaearon/pen/gWWZgR?editors=0010 | |
| import React from "react"; | |
| import ReactDOM from "react-dom"; | |
| import "./index.css"; | |
| function Square(props) { | |
| return ( | |
| <button className="square" onClick={props.onClick}> | |
| {props.value} | |
| </button> | |
| ); | |
| } | |
| class Board extends React.Component { | |
| renderSquare(i) { | |
| return ( | |
| <Square | |
| value={this.props.squares[i]} | |
| onClick={() => this.props.onClick(i)} | |
| /> | |
| ); | |
| } | |
| render() { | |
| return ( | |
| <div> | |
| <div className="board-row"> | |
| {this.renderSquare(0)} | |
| {this.renderSquare(1)} | |
| {this.renderSquare(2)} | |
| </div> | |
| <div className="board-row"> | |
| {this.renderSquare(3)} | |
| {this.renderSquare(4)} | |
| {this.renderSquare(5)} | |
| </div> | |
| <div className="board-row"> | |
| {this.renderSquare(6)} | |
| {this.renderSquare(7)} | |
| {this.renderSquare(8)} | |
| </div> | |
| </div> | |
| ); | |
| } | |
| } | |
| class Game extends React.Component { | |
| constructor(props) { | |
| super(props); | |
| this.state = { | |
| history: [ | |
| { | |
| squares: Array(9).fill(null) | |
| } | |
| ], | |
| stepNumber: 0, | |
| xIsNext: true | |
| }; | |
| } | |
| 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 | |
| } | |
| ]), | |
| stepNumber: history.length, | |
| xIsNext: !this.state.xIsNext | |
| }); | |
| } | |
| 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 ( | |
| <li key={move}> | |
| <button onClick={() => this.jumpTo(move)}>{desc}</button> | |
| </li> | |
| ); | |
| }); | |
| let status; | |
| if (winner) { | |
| status = "Winner: " + winner; | |
| } else { | |
| status = "Next player: " + (this.state.xIsNext ? "X" : "O"); | |
| } | |
| return ( | |
| <div className="game"> | |
| <div className="game-board"> | |
| <Board | |
| squares={current.squares} | |
| onClick={i => this.handleClick(i)} | |
| /> | |
| </div> | |
| <div className="game-info"> | |
| <div>{status}</div> | |
| <ol>{moves}</ol> | |
| </div> | |
| </div> | |
| ); | |
| } | |
| } | |
| // ======================================== | |
| ReactDOM.render(<Game />, document.getElementById("root")); | |
| 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; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment