Skip to content

Instantly share code, notes, and snippets.

@rodrigonehring
Created July 21, 2020 16:58
Show Gist options
  • Save rodrigonehring/b1086ddd167c8473fbb105009189ecc4 to your computer and use it in GitHub Desktop.
Save rodrigonehring/b1086ddd167c8473fbb105009189ecc4 to your computer and use it in GitHub Desktop.
import React, { useReducer, useEffect } from 'react';
import ReactDOM from 'react-dom';
const rowStyle = {
display: 'flex'
}
const squareStyle = {
'width':'60px',
'height':'60px',
'backgroundColor': '#ddd',
'margin': '4px',
'display': 'flex',
'justifyContent': 'center',
'alignItems': 'center',
'fontSize': '20px',
'color': 'white'
}
const boardStyle = {
'backgroundColor': '#eee',
'width': '208px',
'alignItems': 'center',
'justifyContent': 'center',
'display': 'flex',
'flexDirection': 'column',
'border': '3px #eee solid'
}
const containerStyle = {
'display': 'flex',
'alignItems': 'center',
'flexDirection': 'column'
}
const instructionsStyle = {
'marginTop': '5px',
'marginBottom': '5px',
'fontWeight': 'bold',
'fontSize': '16px',
}
const buttonStyle = {
'marginTop': '15px',
'marginBottom': '16px',
'width': '80px',
'height': '40px',
'backgroundColor': '#8acaca',
'color': 'white',
'fontSize': '16px',
}
const PLAYER_A = 'X'
const PLAYER_B = 'O'
function Square({ id, squares, dispatch, disabled }) {
const selected = squares[id]
const bg = selected ? selected.player === PLAYER_A ? 'blue' : 'red' : '#ddd'
const handleClick = () => dispatch({ type: 'select', id })
return (
<div
className="square"
onClick={!disabled && !selected ? handleClick : undefined}
style={{ ...squareStyle, backgroundColor: bg }}>
{selected && selected.player}
</div>
)
}
function Board({ state, dispatch }) {
const allLoss = Object.keys(state.squares).length === 9
const commonProps = {
squares: state.squares,
dispatch,
disabled: state.winner || allLoss
}
return (
<div style={containerStyle} className="gameBoard">
{state.winner
? <div className="winner" style={instructionsStyle}>Winner: {state.winner}</div>
: !allLoss && <div className="status" style={instructionsStyle}>Next player: {state.currentPlayer}</div>
}
<button style={buttonStyle} onClick={() => dispatch({ type: 'reset' })}>Reset</button>
<div style={boardStyle}>
<div className="board-row" style={rowStyle}>
<Square id="A" {...commonProps} />
<Square id="B" {...commonProps} />
<Square id="C" {...commonProps} />
</div>
<div className="board-row" style={rowStyle}>
<Square id="D" {...commonProps} />
<Square id="E" {...commonProps} />
<Square id="F" {...commonProps} />
</div>
<div className="board-row" style={rowStyle}>
<Square id="G" {...commonProps} />
<Square id="H" {...commonProps} />
<Square id="I" {...commonProps} />
</div>
</div>
</div>
);
}
const initialState = {
currentPlayer: PLAYER_A,
squares: {
// A: undefined, // without click
// B: { player: PLAYER_B },
// I: { player: PLAYER_A }
},
}
function reducer(state, {type, ...action}) {
if (type === 'reset') {
return initialState
}
if (type === 'select') {
return {
...state,
currentPlayer: state.currentPlayer === PLAYER_A ? PLAYER_B : PLAYER_A,
squares: {
...state.squares,
[action.id]: { player: state.currentPlayer }
}
}
}
return { ...state, ...action }
}
function checkRows(options, ...rows) {
let count = 0
let player
for (const i of rows) {
if (!options[i]) return false
if (!player) {
player = options[i].player
count++
continue
}
if (player !== options[i].player) return false
count++
}
if (count === 3) {
return player
}
}
function checkWinner(options) {
const winner =
checkRows(options, 'A','B','C') ||
checkRows(options, 'D','E','F') ||
checkRows(options, 'G','H','I') ||
checkRows(options, 'A','D','G') ||
checkRows(options, 'B','E','H') ||
checkRows(options, 'C','F','I') ||
checkRows(options, 'A','E','I') ||
checkRows(options, 'G','E','C')
return winner
}
function Game() {
const [state, dispatch] = useReducer(reducer, initialState)
useEffect(() => {
const winner = checkWinner(state.squares)
if (winner) {
dispatch({ type: 'winner', winner })
}
}, [state.squares])
return (
<div className="game">
<div className="game-board">
<Board state={state} dispatch={dispatch} />
</div>
</div>
)
}
ReactDOM.render(<Game />, document.getElementById('root'))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment