From d51e3f72f47f80e31f155a1a0346612e55966e46 Mon Sep 17 00:00:00 2001 From: Sorrel Bri Date: Sat, 2 May 2020 21:25:54 -0700 Subject: [PATCH] init Game.returnToMove(x) where x < 0 rewinds x number of moves --- packages/server/services/Game.v2.js | 152 ++++++++++++++------------- packages/server/test/Game.v2.spec.js | 23 ++-- 2 files changed, 96 insertions(+), 79 deletions(-) diff --git a/packages/server/services/Game.v2.js b/packages/server/services/Game.v2.js index 262f737..9232357 100644 --- a/packages/server/services/Game.v2.js +++ b/packages/server/services/Game.v2.js @@ -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 = { diff --git a/packages/server/test/Game.v2.spec.js b/packages/server/test/Game.v2.spec.js index f429d2a..c609a06 100644 --- a/packages/server/test/Game.v2.spec.js +++ b/packages/server/test/Game.v2.spec.js @@ -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(); + }) })