init Game.returnToMove(x) where x < 0 rewinds x number of moves

This commit is contained in:
Sorrel Bri 2020-05-02 21:25:54 -07:00
parent bdeb9c9d86
commit d51e3f72f4
2 changed files with 96 additions and 79 deletions

View file

@ -163,86 +163,92 @@ const initBoard = (game) => {
} }
// returns Game object // returns Game object
const Game = ({gameData = {}, gameRecord = []} = {}) => ({ const Game = ({gameData = {}, gameRecord = []} = {}) => {
winner: gameData.winner ||null, if (gameRecord.length) {
turn: gameData.turn || 0, // turn logic depends on handicap stones // play through all the moves
pass: gameData.pass || 0, // -1 represents state in which resignation has been submitted, not confirmed return gameRecord.reduce((game, move) => game.makeMove(move), Game({gameData}).initGame())
komi: gameData.komi || 6.5, // komi depends on handicap stones + player rank }
handicap: gameData.handicap || 0, return {
boardSize: gameData.boardSize || 19, winner: gameData.winner ||null,
groups: {}, turn: gameData.turn || 0, // turn logic depends on handicap stones
boardState: {}, pass: gameData.pass || 0, // -1 represents state in which resignation has been submitted, not confirmed
kos: [], komi: gameData.komi || 6.5, // komi depends on handicap stones + player rank
gameRecord: gameRecord, handicap: gameData.handicap || 0,
playerState: gameData.playerState || { boardSize: gameData.boardSize || 19,
bCaptures: 0, groups: {},
wCaptures: 0, boardState: {},
bScore: 0, kos: [],
wScore: 0 gameRecord: gameRecord,
}, playerState: gameData.playerState || {
bCaptures: 0,
wCaptures: 0,
bScore: 0,
wScore: 0
},
initGame: function() { initGame: function() {
this.winner = null; this.winner = null;
this.pass = 0; this.pass = 0;
this.turn = 1; this.turn = 1;
this.boardState = initBoard(this); this.boardState = initBoard(this);
this.boardState = getBoardState(this); this.boardState = getBoardState(this);
this.legalMoves = getLegalMoves(this) this.legalMoves = getLegalMoves(this)
return this; return this;
}, },
addToRecord: function(moveObject) { addToRecord: function(moveObject) {
this.gameRecord.push(moveObject); this.gameRecord.push(moveObject);
}, },
getMeta: function() { getMeta: function() {
// cannot be chained // cannot be chained
// does not affect game object // does not affect game object
return { winner: this.winner, turn: this.turn, pass: this.pass, playerState: this.playerState, gameRecord: this.gameRecord } return { winner: this.winner, turn: this.turn, pass: this.pass, playerState: this.playerState, gameRecord: this.gameRecord }
}, },
clearKo: function() { clearKo: function() {
this.kos.forEach(ko => { this.kos.forEach(ko => {
this.boardState[ko] = { ...this.boardState[ko], legal: true, ko: false }; this.boardState[ko] = { ...this.boardState[ko], legal: true, ko: false };
}) })
this.kos = []; this.kos = [];
}, },
makeMove: function({ player, pos: {x, y}}) { makeMove: function({ player, pos: {x, y}}) {
let game = this; let game = this;
let success = false; let success = false;
const point = game.boardState[`${x}-${y}`]; const point = game.boardState[`${x}-${y}`];
const isTurn = ( game.turn === 1 && player === 'black' ) const isTurn = ( game.turn === 1 && player === 'black' )
|| ( game.turn === -1 && player === 'white' ); || ( game.turn === -1 && player === 'white' );
if (isTurn) { if (isTurn) {
if (point.legal) { if (point.legal) {
game.addToRecord({ player, pos: { x, y } }); game.addToRecord({ player, pos: { x, y } });
if (this.kos.length) this.clearKo(); if (this.kos.length) this.clearKo();
point.makeMove(game); point.makeMove(game);
game.turn *= -1; game.turn *= -1;
success = true; success = true;
}
}
game.boardState = getBoardState(game);
return {...game, legalMoves: getLegalMoves(game), success };
},
initGroup: function(point) {
const group = Symbol(`${point.pos.x}-${point.pos.y}`);
this.groups[group] = { stones: new Set(), liberties: new Set()};
return { game: this, group };
},
returnToMove: function(idx) {
if (idx < 0) {
const { komi, handicap, boardSize } = this;
return Game({
gameData: { komi, handicap, boardSize },
gameRecord: [...this.gameRecord.slice(0, this.gameRecord.length + idx)]
})
} }
} }
game.boardState = getBoardState(game);
return {...game, legalMoves: getLegalMoves(game), success };
},
initGroup: function(point) {
const group = Symbol(`${point.pos.x}-${point.pos.y}`);
this.groups[group] = { stones: new Set(), liberties: new Set()};
return { game: this, group };
},
returnToMove: function(idx) {
if (idx < 0) {
const { komi, handicap, boardSize } = this;
return Game({
gameData: { komi, handicap, boardSize },
gameRecord: [...this.gameRecord.slice(0, this.gameRecord.length + idx)]
})
}
} }
}); };
const Point = ({x, y, boardSize = 19}) => { const Point = ({x, y, boardSize = 19}) => {
let point = { let point = {

View file

@ -422,16 +422,27 @@ describe('Game history functionality', () => {
done(); done();
}); });
const rewoundGame = () => Game().initGame()
.makeMove(firstMove)
.makeMove(secondMove)
.makeMove({ player: 'black', pos: { x: 16, y: 4 } })
.returnToMove(-1);
it('Game.returnToMove returns new Game with gameRecord', done => { it('Game.returnToMove returns new Game with gameRecord', done => {
Game().initGame() rewoundGame()
.makeMove(firstMove)
.makeMove(secondMove)
.makeMove({ player: 'black', pos: { x: 16, y: 4 } })
.returnToMove(-1)
.gameRecord.should.eql([ firstMove, secondMove ]) .gameRecord.should.eql([ firstMove, secondMove ])
done(); done();
}) })
// .boardState['16-4'].stone.should.eql(0)
it('Game.returnToMove returns new Game with new board state', done => {
rewoundGame()
.boardState['16-4'].stone.should.eql(0);
rewoundGame()
.boardState['4-4'].stone.should.eql(1);
rewoundGame()
.boardState['16-16'].stone.should.eql(-1);
done();
})
}) })