Skip to content

Instantly share code, notes, and snippets.

@szmeku
Created October 1, 2019 10:45
Show Gist options
  • Save szmeku/11d62d07d53bdcafeab405f715b5a669 to your computer and use it in GitHub Desktop.
Save szmeku/11d62d07d53bdcafeab405f715b5a669 to your computer and use it in GitHub Desktop.
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import * as _ from 'ramda';
class Game extends React.Component {
constructor(props) {
super(props);
const calcNextPlayer = (previousPlayer) => {
return previousPlayer === 0 ? 1 : 0;
};
const calcNextSquares = _.curry((playerSign, squareIndex, squares) => {
return _.over(
_.lensIndex(squareIndex),
v => v === null ? playerSign : v,
squares
);
});
this.playerToSign = (i) => ['X', 'O'][i];
this.createClickHandlerFor = (squareIndex) => () => {
const currentState = _.last(this.state.history);
if (currentState.squares[squareIndex] || this.calculateWinner(currentState.squares)) {
return;
}
this.setState(_.evolve({
history: _.append(_.evolve({
squares: calcNextSquares(this.playerToSign(currentState.currentPlayer), squareIndex),
currentPlayer: calcNextPlayer
}, currentState)),
}, this.state))
};
this.state = {
history: [{
squares: Array(9).fill(null),
currentPlayer: 0
}],
}
}
undo(){
this.setState(_.evolve({
history: _.cond([
[_.propSatisfies(_.gt(_.__, 1), 'length'), _.dropLast(1)],
[_.T, _.identity]
])
}, this.state))
};
jumpTo(stateIndex){
this.setState(_.evolve({
history: _.dropLastWhile(_.pipe(
_.indexOf(_.__, this.state.history),
_.complement(_.equals(stateIndex))
))
}, this.state))
}
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],
];
const allXsOrOs = _.anyPass([
_.all(_.equals('X')),
_.all(_.equals('O'))
]);
const pickLine = _.props(_.__, squares);
return _.pipe(
_.find(_.pipe(pickLine(_.__, squares), allXsOrOs)),
_.cond([
[_.isNil, _.identity],
[_.T, _.pipe(_.head, _.nth(_.__, squares))]
])
)(lines);
};
render() {
const currentState = _.last(this.state.history);
const winner = this.calculateWinner(currentState.squares);
const status = winner ? `And the winner is ${winner}!!!!!` : `Current player: ${this.playerToSign(currentState.currentPlayer)}`;
const moves = this.state.history.map((state, stateIndex) => {
return (
<li key={stateIndex}>
<button onClick={() => this.jumpTo(stateIndex)}>{stateIndex}</button>
</li>
)
});
return (
<div className="game">
<div className="game-board">
<Board
squareOnClick={this.createClickHandlerFor}
squares={_.last(this.state.history).squares}
/>
</div>
<div className="game-info">
<div className="status">{status}</div>
<button onClick={this.undo}>Undo</button>
<ol>{moves}</ol>
</div>
</div>
);
}
}
class Board extends React.Component {
renderSquare(squareIndex) {
return <Square
value={this.props.squares[squareIndex]}
onClick={this.props.squareOnClick(squareIndex)}
/>
}
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>
)
}
}
function Square(props) {
return (
<button className="square" onClick={props.onClick}>
{props.value}
</button>
)
}
ReactDOM.render(
<Game/>,
document.getElementById('root')
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment