From f6b5e3459423b892554a43dcffab51ea8df0e479 Mon Sep 17 00:00:00 2001 From: Neal Rea Date: Thu, 14 Sep 2017 14:37:38 -0400 Subject: [PATCH 1/7] add constructor to square class --- react-fb-tictactoe/src/TicTacToe/index.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/react-fb-tictactoe/src/TicTacToe/index.js b/react-fb-tictactoe/src/TicTacToe/index.js index 56944d57..0f150312 100644 --- a/react-fb-tictactoe/src/TicTacToe/index.js +++ b/react-fb-tictactoe/src/TicTacToe/index.js @@ -10,10 +10,16 @@ import './TicTacToe.css' * class Square extends Component */ class Square extends Component { + constructor() { + super(); + this.state = { + value : null, + }; + } render() { return ( - ); } @@ -21,7 +27,7 @@ class Square extends Component { class Board extends Component { renderSquare(i) { - return ; + return ; } render() { From b66d3e5e3006df3bc1144b29e110f0ca12818469 Mon Sep 17 00:00:00 2001 From: Neal Rea Date: Thu, 14 Sep 2017 15:21:39 -0400 Subject: [PATCH 2/7] create controlled components (squares) in Board --- react-fb-tictactoe/src/TicTacToe/index.js | 28 ++++++++++++++++------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/react-fb-tictactoe/src/TicTacToe/index.js b/react-fb-tictactoe/src/TicTacToe/index.js index 0f150312..6c5122cf 100644 --- a/react-fb-tictactoe/src/TicTacToe/index.js +++ b/react-fb-tictactoe/src/TicTacToe/index.js @@ -10,15 +10,9 @@ import './TicTacToe.css' * class Square extends Component */ class Square extends Component { - constructor() { - super(); - this.state = { - value : null, - }; - } render() { return ( - ); @@ -26,8 +20,26 @@ class Square extends Component { } class Board extends Component { + constructor() { + super(); + this.state = { + squares: Array(9).fill(null), + }; + } + + handleClick(i) { + const squares = this.state.squares.slice(); + squares[i] = 'X'; + this.setState({squares: squares}); + } + renderSquare(i) { - return ; + return ( + this.handleClick(i)} + /> + ); } render() { From bd658ee91b93b86c19201f9d78848145508bd34e Mon Sep 17 00:00:00 2001 From: Neal Rea Date: Sun, 17 Sep 2017 15:26:14 -0400 Subject: [PATCH 3/7] replace square class with functional component --- react-fb-tictactoe/src/TicTacToe/index.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/react-fb-tictactoe/src/TicTacToe/index.js b/react-fb-tictactoe/src/TicTacToe/index.js index 6c5122cf..11ac1995 100644 --- a/react-fb-tictactoe/src/TicTacToe/index.js +++ b/react-fb-tictactoe/src/TicTacToe/index.js @@ -9,6 +9,14 @@ import './TicTacToe.css' * with * class Square extends Component */ +function Square(props) { + return ( + + ); +} +/* class Square extends Component { render() { return ( @@ -18,6 +26,7 @@ class Square extends Component { ); } } +*/ class Board extends Component { constructor() { From 07e2fd41133ff7f809e02f759b23e52be0db3925 Mon Sep 17 00:00:00 2001 From: Neal Rea Date: Sun, 17 Sep 2017 15:33:08 -0400 Subject: [PATCH 4/7] add two player functionality --- react-fb-tictactoe/src/TicTacToe/index.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/react-fb-tictactoe/src/TicTacToe/index.js b/react-fb-tictactoe/src/TicTacToe/index.js index 11ac1995..431dbf3c 100644 --- a/react-fb-tictactoe/src/TicTacToe/index.js +++ b/react-fb-tictactoe/src/TicTacToe/index.js @@ -33,13 +33,17 @@ class Board extends Component { super(); this.state = { squares: Array(9).fill(null), + xIsNext: true, }; } handleClick(i) { const squares = this.state.squares.slice(); - squares[i] = 'X'; - this.setState({squares: squares}); + squares[i] = this.state.xIsNext ? 'X' : 'O'; + this.setState({ + squares: squares, + xIsNext: !this.state.xIsNext, + }); } renderSquare(i) { @@ -52,7 +56,7 @@ class Board extends Component { } render() { - const status = 'Next player: X'; + const status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O'); return (
From 91627267067f2c575c4d1965f580c72df7e13bc6 Mon Sep 17 00:00:00 2001 From: Neal Rea Date: Sun, 17 Sep 2017 15:43:08 -0400 Subject: [PATCH 5/7] add function to check for winner, disable handleClick in used squares and after winner is declared --- react-fb-tictactoe/src/TicTacToe/index.js | 31 ++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/react-fb-tictactoe/src/TicTacToe/index.js b/react-fb-tictactoe/src/TicTacToe/index.js index 431dbf3c..cb84289d 100644 --- a/react-fb-tictactoe/src/TicTacToe/index.js +++ b/react-fb-tictactoe/src/TicTacToe/index.js @@ -39,6 +39,9 @@ class Board extends Component { handleClick(i) { const squares = this.state.squares.slice(); + if (calculateWinner(squares) || squares[i]) { + return; + } squares[i] = this.state.xIsNext ? 'X' : 'O'; this.setState({ squares: squares, @@ -56,7 +59,13 @@ class Board extends Component { } render() { - const status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O'); + const winner = calculateWinner(this.state.squares); + let status; + if (winner) { + status = winner + ' wins!!'; + } else { + status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O'); + } return (
@@ -97,4 +106,24 @@ class Game extends Component { } } +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; +} + export default Game; From 25036b9840188745117a13e2e8af481e65f6f446 Mon Sep 17 00:00:00 2001 From: Neal Rea Date: Sun, 17 Sep 2017 16:25:34 -0400 Subject: [PATCH 6/7] pull state up from Board into Game --- react-fb-tictactoe/src/TicTacToe/index.js | 77 +++++++++++++---------- 1 file changed, 44 insertions(+), 33 deletions(-) diff --git a/react-fb-tictactoe/src/TicTacToe/index.js b/react-fb-tictactoe/src/TicTacToe/index.js index cb84289d..d0b81a4c 100644 --- a/react-fb-tictactoe/src/TicTacToe/index.js +++ b/react-fb-tictactoe/src/TicTacToe/index.js @@ -29,47 +29,18 @@ class Square extends Component { */ class Board extends Component { - constructor() { - super(); - this.state = { - squares: Array(9).fill(null), - xIsNext: true, - }; - } - - handleClick(i) { - const squares = this.state.squares.slice(); - if (calculateWinner(squares) || squares[i]) { - return; - } - squares[i] = this.state.xIsNext ? 'X' : 'O'; - this.setState({ - squares: squares, - xIsNext: !this.state.xIsNext, - }); - } - renderSquare(i) { return ( this.handleClick(i)} + value={this.props.squares[i]} + onClick={() => this.props.onClick(i)} /> ); } render() { - const winner = calculateWinner(this.state.squares); - let status; - if (winner) { - status = winner + ' wins!!'; - } else { - status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O'); - } - return (
-
{status}
{this.renderSquare(0)} {this.renderSquare(1)} @@ -91,14 +62,54 @@ class Board extends Component { } class Game extends Component { + constructor() { + super(); + this.state = { + history: [{ + squares: Array(9).fill(null), + }], + xIsNext: true, + }; + } + + handleClick(i) { + const history = this.state.history; + 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, + }]), + xIsNext: !this.state.xIsNext, + }); + } + render() { + const history = this.state.history; + const current = history[history.length - 1]; + const winner = calculateWinner(current.squares); + + let status; + if (winner) { + status = 'Winner: ' + winner; + } else { + status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O'); + } + return (
- + this.handleClick(i)} + />
-
{/* status */}
+
{status}
    {/* todo */}
From b461a15242211f185f822de0904eaf3968e323b8 Mon Sep 17 00:00:00 2001 From: Neal Rea Date: Sun, 17 Sep 2017 16:56:49 -0400 Subject: [PATCH 7/7] add time-travel move history --- react-fb-tictactoe/src/TicTacToe/index.js | 26 ++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/react-fb-tictactoe/src/TicTacToe/index.js b/react-fb-tictactoe/src/TicTacToe/index.js index d0b81a4c..038bc834 100644 --- a/react-fb-tictactoe/src/TicTacToe/index.js +++ b/react-fb-tictactoe/src/TicTacToe/index.js @@ -68,12 +68,13 @@ class Game extends Component { history: [{ squares: Array(9).fill(null), }], + stepNumber: 0, xIsNext: true, }; } handleClick(i) { - const history = this.state.history; + 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]) { @@ -84,15 +85,34 @@ class Game extends Component { 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[history.length - 1]; + const current = history[this.state.stepNumber]; const winner = calculateWinner(current.squares); + const moves = history.map((step, move) => { + const desc = move ? + 'Move #' + move : + 'Game start'; + return ( +
  • + this.jumpTo(move)}>{desc} +
  • + ); + }); + let status; if (winner) { status = 'Winner: ' + winner; @@ -110,7 +130,7 @@ class Game extends Component {
    {status}
    -
      {/* todo */}
    +
      {moves}
    );