Reactive Tic-Tac-Toe
up vote
-1
down vote
favorite
I'm trying to learn React and, as most other people, I decided to start from the React tutorial where a TicTacToe game is built .
I tried to rewrite the example by myself and one thing that I did differently was to separate the model of the Tic-tac-toe game from the React component, a style that I think is closer to a real world program.
I'm not exactly sure If I'm managing the state of the component in the correct way.
More in detail at the moment my idea has been to create a TicTacToeGame
class with a mark
method.
class TicTacToeGame {
constructor(board = new Array(9).fill(undefined), currentPlayer = 0) {
this.board = board;
this.currentPlayer = currentPlayer;
}
mark(cell) {
if (this.board[cell] !== undefined || this.hasWinner())
return;
const nextBoard = this.board.slice();
nextBoard[cell] = this.currentPlayer;
const nextPlayer = this.getNextPlayer();
const nextGame = new TicTacToeGame(nextBoard, nextPlayer);
return nextGame;
}
getNextPlayer() {
return (this.currentPlayer + 1) % 2;
}
hasWinner() {
return this.getWinner() !== undefined;
}
getWinner() {
function getWinnerAux(i0, i1, i2) {
if (that.board[i0] === that.board[i1] &&
that.board[i0] === that.board[i2])
return that.board[i0];
return undefined;
}
const that = this;
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]
];
let winner;
for (let [i0, i1, i2] of lines) {
winner = getWinnerAux(i0, i1, i2);
if (winner !== undefined)
break;
}
return winner;
}
}
What this method does is to create a new TicTacToeGame
object every time a mark action takes place and the action is valid.
Every time a click event happens on the game board and a new TicTacToeGame
is created, the game is added to the history of the games.
class TicTacToe extends Component {
constructor(props) {
super(props);
const ticTacToeGame = new TicTacToeGame();
this.state = { history: [ticTacToeGame] };
this.onBoardCellClick = this.onBoardCellClick.bind(this);
this.onHistoryCellClick = this.onHistoryCellClick.bind(this);
}
render() {
return (
<div>
<h2>Tic tac toe</h2>
<div className="tic-tac-toe-board">
{this.getCurrentGame().board.map((item, i) => (
<TicTacToeCell key={'cell' + i} status={this.getSymbol(item)} onClick={() => this.onBoardCellClick(i)}></TicTacToeCell>
))}
</div>
{this.getCurrentGame().hasWinner() ? 'Winner: ' : 'Next player: '} {this.getSymbol(this.getCurrentGame().currentPlayer)}
<h3>History</h3>
<div className="tic-tac-toe-history">
{this.state.history.map((item, i) => (
<button key={'board' + i} onClick={() => this.onHistoryCellClick(i)}>#{i}</button>
))}
</div>
</div>
);
}
onHistoryCellClick(boardId) {
const history = this.state.history.slice(0, boardId + 1);
this.setState({ history });
}
onBoardCellClick(cell) {
const newGame = this.getCurrentGame().mark(cell);
if (!newGame)
return;
this.state.history.push(newGame);
this.setState(this.state);
}
last(a) {
return a[a.length - 1];
}
getCurrentGame() {
return this.last(this.state.history);
}
getSymbol(playerCode) {
switch (playerCode) {
case 0: return 'X';
case 1: return 'O';
default: return ' ';
}
}
}
A few questions about what I'm doing:
Is the idea of creating models like this correct? I am still learning React and I may be missing something but I think even with more complex state management libraries like Redux this approach should make sense.
Is the idea of creating immutable models correct? I think this is not always possible, hence I think sometimes a different approach may be needed. Is there any good alternative I could use?
I'm also not sure about directly modifying history (
this.state.history.push(newGame);
). Is this ok in React?In this case I think that there should be also a class/object to manage the games history. Do you agree?
Any other comment is of course appreciated.
object-oriented tic-tac-toe react.js jsx
add a comment |
up vote
-1
down vote
favorite
I'm trying to learn React and, as most other people, I decided to start from the React tutorial where a TicTacToe game is built .
I tried to rewrite the example by myself and one thing that I did differently was to separate the model of the Tic-tac-toe game from the React component, a style that I think is closer to a real world program.
I'm not exactly sure If I'm managing the state of the component in the correct way.
More in detail at the moment my idea has been to create a TicTacToeGame
class with a mark
method.
class TicTacToeGame {
constructor(board = new Array(9).fill(undefined), currentPlayer = 0) {
this.board = board;
this.currentPlayer = currentPlayer;
}
mark(cell) {
if (this.board[cell] !== undefined || this.hasWinner())
return;
const nextBoard = this.board.slice();
nextBoard[cell] = this.currentPlayer;
const nextPlayer = this.getNextPlayer();
const nextGame = new TicTacToeGame(nextBoard, nextPlayer);
return nextGame;
}
getNextPlayer() {
return (this.currentPlayer + 1) % 2;
}
hasWinner() {
return this.getWinner() !== undefined;
}
getWinner() {
function getWinnerAux(i0, i1, i2) {
if (that.board[i0] === that.board[i1] &&
that.board[i0] === that.board[i2])
return that.board[i0];
return undefined;
}
const that = this;
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]
];
let winner;
for (let [i0, i1, i2] of lines) {
winner = getWinnerAux(i0, i1, i2);
if (winner !== undefined)
break;
}
return winner;
}
}
What this method does is to create a new TicTacToeGame
object every time a mark action takes place and the action is valid.
Every time a click event happens on the game board and a new TicTacToeGame
is created, the game is added to the history of the games.
class TicTacToe extends Component {
constructor(props) {
super(props);
const ticTacToeGame = new TicTacToeGame();
this.state = { history: [ticTacToeGame] };
this.onBoardCellClick = this.onBoardCellClick.bind(this);
this.onHistoryCellClick = this.onHistoryCellClick.bind(this);
}
render() {
return (
<div>
<h2>Tic tac toe</h2>
<div className="tic-tac-toe-board">
{this.getCurrentGame().board.map((item, i) => (
<TicTacToeCell key={'cell' + i} status={this.getSymbol(item)} onClick={() => this.onBoardCellClick(i)}></TicTacToeCell>
))}
</div>
{this.getCurrentGame().hasWinner() ? 'Winner: ' : 'Next player: '} {this.getSymbol(this.getCurrentGame().currentPlayer)}
<h3>History</h3>
<div className="tic-tac-toe-history">
{this.state.history.map((item, i) => (
<button key={'board' + i} onClick={() => this.onHistoryCellClick(i)}>#{i}</button>
))}
</div>
</div>
);
}
onHistoryCellClick(boardId) {
const history = this.state.history.slice(0, boardId + 1);
this.setState({ history });
}
onBoardCellClick(cell) {
const newGame = this.getCurrentGame().mark(cell);
if (!newGame)
return;
this.state.history.push(newGame);
this.setState(this.state);
}
last(a) {
return a[a.length - 1];
}
getCurrentGame() {
return this.last(this.state.history);
}
getSymbol(playerCode) {
switch (playerCode) {
case 0: return 'X';
case 1: return 'O';
default: return ' ';
}
}
}
A few questions about what I'm doing:
Is the idea of creating models like this correct? I am still learning React and I may be missing something but I think even with more complex state management libraries like Redux this approach should make sense.
Is the idea of creating immutable models correct? I think this is not always possible, hence I think sometimes a different approach may be needed. Is there any good alternative I could use?
I'm also not sure about directly modifying history (
this.state.history.push(newGame);
). Is this ok in React?In this case I think that there should be also a class/object to manage the games history. Do you agree?
Any other comment is of course appreciated.
object-oriented tic-tac-toe react.js jsx
add a comment |
up vote
-1
down vote
favorite
up vote
-1
down vote
favorite
I'm trying to learn React and, as most other people, I decided to start from the React tutorial where a TicTacToe game is built .
I tried to rewrite the example by myself and one thing that I did differently was to separate the model of the Tic-tac-toe game from the React component, a style that I think is closer to a real world program.
I'm not exactly sure If I'm managing the state of the component in the correct way.
More in detail at the moment my idea has been to create a TicTacToeGame
class with a mark
method.
class TicTacToeGame {
constructor(board = new Array(9).fill(undefined), currentPlayer = 0) {
this.board = board;
this.currentPlayer = currentPlayer;
}
mark(cell) {
if (this.board[cell] !== undefined || this.hasWinner())
return;
const nextBoard = this.board.slice();
nextBoard[cell] = this.currentPlayer;
const nextPlayer = this.getNextPlayer();
const nextGame = new TicTacToeGame(nextBoard, nextPlayer);
return nextGame;
}
getNextPlayer() {
return (this.currentPlayer + 1) % 2;
}
hasWinner() {
return this.getWinner() !== undefined;
}
getWinner() {
function getWinnerAux(i0, i1, i2) {
if (that.board[i0] === that.board[i1] &&
that.board[i0] === that.board[i2])
return that.board[i0];
return undefined;
}
const that = this;
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]
];
let winner;
for (let [i0, i1, i2] of lines) {
winner = getWinnerAux(i0, i1, i2);
if (winner !== undefined)
break;
}
return winner;
}
}
What this method does is to create a new TicTacToeGame
object every time a mark action takes place and the action is valid.
Every time a click event happens on the game board and a new TicTacToeGame
is created, the game is added to the history of the games.
class TicTacToe extends Component {
constructor(props) {
super(props);
const ticTacToeGame = new TicTacToeGame();
this.state = { history: [ticTacToeGame] };
this.onBoardCellClick = this.onBoardCellClick.bind(this);
this.onHistoryCellClick = this.onHistoryCellClick.bind(this);
}
render() {
return (
<div>
<h2>Tic tac toe</h2>
<div className="tic-tac-toe-board">
{this.getCurrentGame().board.map((item, i) => (
<TicTacToeCell key={'cell' + i} status={this.getSymbol(item)} onClick={() => this.onBoardCellClick(i)}></TicTacToeCell>
))}
</div>
{this.getCurrentGame().hasWinner() ? 'Winner: ' : 'Next player: '} {this.getSymbol(this.getCurrentGame().currentPlayer)}
<h3>History</h3>
<div className="tic-tac-toe-history">
{this.state.history.map((item, i) => (
<button key={'board' + i} onClick={() => this.onHistoryCellClick(i)}>#{i}</button>
))}
</div>
</div>
);
}
onHistoryCellClick(boardId) {
const history = this.state.history.slice(0, boardId + 1);
this.setState({ history });
}
onBoardCellClick(cell) {
const newGame = this.getCurrentGame().mark(cell);
if (!newGame)
return;
this.state.history.push(newGame);
this.setState(this.state);
}
last(a) {
return a[a.length - 1];
}
getCurrentGame() {
return this.last(this.state.history);
}
getSymbol(playerCode) {
switch (playerCode) {
case 0: return 'X';
case 1: return 'O';
default: return ' ';
}
}
}
A few questions about what I'm doing:
Is the idea of creating models like this correct? I am still learning React and I may be missing something but I think even with more complex state management libraries like Redux this approach should make sense.
Is the idea of creating immutable models correct? I think this is not always possible, hence I think sometimes a different approach may be needed. Is there any good alternative I could use?
I'm also not sure about directly modifying history (
this.state.history.push(newGame);
). Is this ok in React?In this case I think that there should be also a class/object to manage the games history. Do you agree?
Any other comment is of course appreciated.
object-oriented tic-tac-toe react.js jsx
I'm trying to learn React and, as most other people, I decided to start from the React tutorial where a TicTacToe game is built .
I tried to rewrite the example by myself and one thing that I did differently was to separate the model of the Tic-tac-toe game from the React component, a style that I think is closer to a real world program.
I'm not exactly sure If I'm managing the state of the component in the correct way.
More in detail at the moment my idea has been to create a TicTacToeGame
class with a mark
method.
class TicTacToeGame {
constructor(board = new Array(9).fill(undefined), currentPlayer = 0) {
this.board = board;
this.currentPlayer = currentPlayer;
}
mark(cell) {
if (this.board[cell] !== undefined || this.hasWinner())
return;
const nextBoard = this.board.slice();
nextBoard[cell] = this.currentPlayer;
const nextPlayer = this.getNextPlayer();
const nextGame = new TicTacToeGame(nextBoard, nextPlayer);
return nextGame;
}
getNextPlayer() {
return (this.currentPlayer + 1) % 2;
}
hasWinner() {
return this.getWinner() !== undefined;
}
getWinner() {
function getWinnerAux(i0, i1, i2) {
if (that.board[i0] === that.board[i1] &&
that.board[i0] === that.board[i2])
return that.board[i0];
return undefined;
}
const that = this;
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]
];
let winner;
for (let [i0, i1, i2] of lines) {
winner = getWinnerAux(i0, i1, i2);
if (winner !== undefined)
break;
}
return winner;
}
}
What this method does is to create a new TicTacToeGame
object every time a mark action takes place and the action is valid.
Every time a click event happens on the game board and a new TicTacToeGame
is created, the game is added to the history of the games.
class TicTacToe extends Component {
constructor(props) {
super(props);
const ticTacToeGame = new TicTacToeGame();
this.state = { history: [ticTacToeGame] };
this.onBoardCellClick = this.onBoardCellClick.bind(this);
this.onHistoryCellClick = this.onHistoryCellClick.bind(this);
}
render() {
return (
<div>
<h2>Tic tac toe</h2>
<div className="tic-tac-toe-board">
{this.getCurrentGame().board.map((item, i) => (
<TicTacToeCell key={'cell' + i} status={this.getSymbol(item)} onClick={() => this.onBoardCellClick(i)}></TicTacToeCell>
))}
</div>
{this.getCurrentGame().hasWinner() ? 'Winner: ' : 'Next player: '} {this.getSymbol(this.getCurrentGame().currentPlayer)}
<h3>History</h3>
<div className="tic-tac-toe-history">
{this.state.history.map((item, i) => (
<button key={'board' + i} onClick={() => this.onHistoryCellClick(i)}>#{i}</button>
))}
</div>
</div>
);
}
onHistoryCellClick(boardId) {
const history = this.state.history.slice(0, boardId + 1);
this.setState({ history });
}
onBoardCellClick(cell) {
const newGame = this.getCurrentGame().mark(cell);
if (!newGame)
return;
this.state.history.push(newGame);
this.setState(this.state);
}
last(a) {
return a[a.length - 1];
}
getCurrentGame() {
return this.last(this.state.history);
}
getSymbol(playerCode) {
switch (playerCode) {
case 0: return 'X';
case 1: return 'O';
default: return ' ';
}
}
}
A few questions about what I'm doing:
Is the idea of creating models like this correct? I am still learning React and I may be missing something but I think even with more complex state management libraries like Redux this approach should make sense.
Is the idea of creating immutable models correct? I think this is not always possible, hence I think sometimes a different approach may be needed. Is there any good alternative I could use?
I'm also not sure about directly modifying history (
this.state.history.push(newGame);
). Is this ok in React?In this case I think that there should be also a class/object to manage the games history. Do you agree?
Any other comment is of course appreciated.
object-oriented tic-tac-toe react.js jsx
object-oriented tic-tac-toe react.js jsx
edited 2 days ago
200_success
127k15148411
127k15148411
asked Nov 19 at 16:50
heapOverflow
1174
1174
add a comment |
add a comment |
active
oldest
votes
active
oldest
votes
active
oldest
votes
active
oldest
votes
active
oldest
votes
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f207990%2freactive-tic-tac-toe%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown