Skip to content

Commit 71800e8

Browse files
Added components for tic tac toe game
1 parent dcd4af6 commit 71800e8

File tree

5 files changed

+173
-0
lines changed

5 files changed

+173
-0
lines changed

app/javascript/packs/components/App.jsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ class App extends React.Component {
1919
<Route exact path="/" component={Root} />
2020
<Route exact path="/users" component={User} />
2121
<Route exact path="/users/:id/:name" component={UserDetails} />
22+
<Route exact path="/games" component={Game} />
2223
<Route component={NotFound} />
2324
</Switch>
2425
</div>
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import React from 'react';
2+
import Square from './Square';
3+
4+
function calculateWinner(squares) {
5+
const lines = [
6+
[0, 1, 2],
7+
[3, 4, 5],
8+
[6, 7, 8],
9+
[0, 3, 6],
10+
[1, 4, 7],
11+
[2, 5, 8],
12+
[0, 4, 8],
13+
[2, 4, 6],
14+
];
15+
16+
for (let i = 0; i < lines.length; i += 1) {
17+
const [a, b, c] = lines[i];
18+
if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) {
19+
return squares[a];
20+
}
21+
}
22+
return null;
23+
}
24+
25+
class Board extends React.Component {
26+
constructor(props) {
27+
super(props);
28+
this.state = {
29+
squares: Array(9).fill(null),
30+
xIsNext: true,
31+
};
32+
}
33+
34+
handleClick(i) {
35+
const squares = this.state.squares.slice();
36+
if (calculateWinner(squares) || squares[i]) {
37+
return;
38+
}
39+
squares[i] = this.state.xIsNext ? 'X' : 'O';
40+
this.setState({
41+
squares: squares,
42+
xIsNext: !this.state.xIsNext,
43+
});
44+
}
45+
46+
renderSquare(i) {
47+
return (
48+
<Square
49+
value={this.state.squares[i]}
50+
onClick={() => this.handleClick(i)}
51+
/>
52+
);
53+
}
54+
55+
render() {
56+
const winner = calculateWinner(this.state.squares);
57+
let status;
58+
if (winner) {
59+
status = `Winner: ${winner}`;
60+
} else {
61+
status = `Next player: ${(this.state.xIsNext ? 'X' : 'O')}`;
62+
}
63+
64+
return (
65+
<div>
66+
<div className="status">{status}</div>
67+
<div className="board-row">
68+
{this.renderSquare(0)}
69+
{this.renderSquare(1)}
70+
{this.renderSquare(2)}
71+
</div>
72+
<div className="board-row">
73+
{this.renderSquare(3)}
74+
{this.renderSquare(4)}
75+
{this.renderSquare(5)}
76+
</div>
77+
<div className="board-row">
78+
{this.renderSquare(6)}
79+
{this.renderSquare(7)}
80+
{this.renderSquare(8)}
81+
</div>
82+
</div>
83+
);
84+
}
85+
}
86+
87+
export default Board;
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import React from 'react';
2+
import Board from './Board';
3+
4+
class Game extends React.Component {
5+
render() {
6+
return (
7+
<div className="game">
8+
<div className="game-board">
9+
<h1>Game</h1>
10+
<Board />
11+
</div>
12+
<div className="game-info">
13+
<div>{/* status */}</div>
14+
<ol>{/* TODO */}</ol>
15+
</div>
16+
</div>
17+
);
18+
}
19+
}
20+
21+
export default Game;
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import React from 'react';
2+
3+
function Square(props) {
4+
return (
5+
<button className="square" onClick={props.onClick}>
6+
{props.value}
7+
</button>
8+
);
9+
}
10+
11+
export default Square;

app/views/application/index.html.erb

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,55 @@
1+
<style type="text/css">
2+
body {
3+
font: 14px "Century Gothic", Futura, sans-serif;
4+
margin: 20px;
5+
}
6+
7+
ol, ul {
8+
padding-left: 30px;
9+
}
10+
11+
.board-row:after {
12+
clear: both;
13+
content: "";
14+
display: table;
15+
}
16+
17+
.status {
18+
margin-bottom: 10px;
19+
}
20+
21+
.square {
22+
background: #fff;
23+
border: 1px solid #999;
24+
float: left;
25+
font-size: 24px;
26+
font-weight: bold;
27+
line-height: 34px;
28+
height: 34px;
29+
margin-right: -1px;
30+
margin-top: -1px;
31+
padding: 0;
32+
text-align: center;
33+
width: 34px;
34+
}
35+
36+
.square:focus {
37+
outline: none;
38+
}
39+
40+
.kbd-navigation .square:focus {
41+
background: #ddd;
42+
}
43+
44+
.game {
45+
display: flex;
46+
flex-direction: row;
47+
}
48+
49+
.game-info {
50+
margin-left: 20px;
51+
}
52+
</style>
53+
154
<div id="root"></div>
255
<%= javascript_pack_tag 'index' %>

0 commit comments

Comments
 (0)