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

View file

@ -422,16 +422,27 @@ describe('Game history functionality', () => {
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 => {
Game().initGame()
.makeMove(firstMove)
.makeMove(secondMove)
.makeMove({ player: 'black', pos: { x: 16, y: 4 } })
.returnToMove(-1)
rewoundGame()
.gameRecord.should.eql([ firstMove, secondMove ])
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();
})
})