diff --git a/packages/server/services/Game.v2.js b/packages/server/services/Game.v2.js index 8d9b269..12497a9 100644 --- a/packages/server/services/Game.v2.js +++ b/packages/server/services/Game.v2.js @@ -69,43 +69,49 @@ const pipeMap = (...funcs) => obj => { const checkLegal = ({ point, Game }) => { // if stone (includes ko) return false - let legal = false; if (point.stone) { - point.legal = legal; + point.legal = false; return point; } - const isEmptyAdjacent = Object.values(point.neighbors).filter(pt => pt.stone === 0).length; + const isEmpty = point => point.stone === 0 && point.legal === true; + const isEmptyAdjacent = Object.values(point.neighbors).filter(isEmpty); // if empty point adjacent return true - if (!isEmptyAdjacent) { + if (!isEmptyAdjacent.length) { // if group has liberties return true const isTurnStone = neighbor => neighbor.stone === Game.turn; const getGroupLiberties = point => Array.from(Game.groups[point.group].liberties); - const isInGroupWithLiberties = neighbor => getGroupLiberties(neighbor).filter(({ pos }) => pos.x !== point.pos.x && pos.y !== point.pos.y ); - const isInLiveGroup = () => Object.values(point.neighbors).filter(isTurnStone).filter(isInGroupWithLiberties).length; + const isNotSamePoint = liberty => liberty.pos.x !== point.pos.x && liberty.pos.y !== point.pos.y; + const isInGroupWithLiberties = neighbor => getGroupLiberties(neighbor).filter(isNotSamePoint).length; + const isInLiveGroup = Object.values(point.neighbors).filter(isTurnStone).filter(isInGroupWithLiberties).length; - if (isInLiveGroup()) { + if (isInLiveGroup) { point.legal = true; - return point; + return { ...point, isInLiveGroup }; } - point.legal = legal; - return { ...point, adj: isEmptyAdjacent }; + point.legal = false; + return { ...point, adj: isEmptyAdjacent, isInLiveGroup }; } // if move would capture opposing group // set capturing object and return true - point.legal = !point.stone ? true : false; + point.legal = true; point.adj = isEmptyAdjacent; return point; } const getBoardState = (Game) => { - const getLegal = point => checkLegal({ point, Game }).legal ? 'l' : point.stone; + const getLegal = point => checkLegal({ point, Game }) return pipeMap(getLegal)(Game.boardState); } +const getLegalMoves = (Game) => { + const mapLegal = point => point.legal ? 'l' : point.stone; + return pipeMap(mapLegal)(Game.boardState); +} + const getNeighbors = boardSize => (point, i, boardState) => { const { top, btm, lft, rgt} = point.neighbors; // boardState[0] = [ '1-1', Point({x:1, y:1, boardSize}) ] @@ -132,13 +138,13 @@ const initBoard = (game) => { }); boardState[`${point.pos.x}-${point.pos.y}`] = point; } + const boardStateWithNeighbors = pipeMap(getNeighbors(boardSize))(boardState) if (handicap) { HANDI_PLACE[boardSize][handicap].forEach(pt => { - boardState[pt].makeMove(game); + boardStateWithNeighbors[pt].makeMove(game); }); game.turn *= -1; } - const boardStateWithNeighbors = pipeMap(getNeighbors(boardSize))(boardState) return boardStateWithNeighbors; } @@ -164,8 +170,9 @@ const Game = ({gameData = {}, gameRecord = []} = {}) => ({ this.winner = null; this.pass = 0; this.turn = 1; - this.boardState = initBoard(this) - return { ...this, legalMoves: getBoardState(this)}; + this.boardState = initBoard(this); + this.boardState = getBoardState(this); + return { ...this, legalMoves: getLegalMoves(this)}; }, getMeta: function() { @@ -184,7 +191,8 @@ const Game = ({gameData = {}, gameRecord = []} = {}) => ({ success = true; } } - return {...this, legalMoves: getBoardState(this), success }; + this.boardState = getBoardState(this); + return {...this, legalMoves: getLegalMoves(this), success }; }, initGroup: function(point) { @@ -240,11 +248,18 @@ const Point = ({x, y, boardSize = 19}) => ({ const neighbors = Object.values(this.neighbors); const liberties = game.groups[this.group].liberties; // if point is occupied remove it from liberties set of point group, else add it - neighbors.forEach( pt => pt ? liberties.delete(pt) : liberties.add(pt) ); + neighbors.forEach( pt => { + if (pt.stone) { + liberties.delete(pt); + game.groups[pt.group].liberties.delete(this); + } else { + liberties.add(pt) + } + }); } }); module.exports = { Game, Point -} \ No newline at end of file +} diff --git a/packages/server/test/Game.v2.spec.js b/packages/server/test/Game.v2.spec.js index dcbb464..d12e79a 100644 --- a/packages/server/test/Game.v2.spec.js +++ b/packages/server/test/Game.v2.spec.js @@ -188,12 +188,13 @@ describe('Game.makeMove({ player: str, pos: { x: int, y: int } })', () => { }) it('makeMove returns success: false when move is made in point with no liberties', done => { - const point = Game({ gameData: { handicap: 2 } }).initGame() // 15 16 17 + const point = Game({ gameData: { handicap: 2 } }).initGame() // 15 16 17 .makeMove({ player: 'white', pos: { x: 4, y: 4 } }).makeMove({ player: 'black', pos: { x: 6, y: 16 } }) // 4 1 .makeMove({ player: 'white', pos: { x: 16, y: 16 }}).makeMove({ player: 'black', pos: { x: 5, y: 15 } }) // 5 1 x 1 .makeMove({ player: 'white', pos: { x: 16, y: 10 }}).makeMove({ player: 'black', pos: { x: 5, y: 17 } }) // 6 1 .makeMove({ player: 'white', pos: { x: 5, y: 16 }}) - .success.should.eql(false); + console.log(point.boardState['5-16']) + point.success.should.eql(false); done(); }); }); @@ -207,11 +208,27 @@ describe('makeMove group join and capture logic', () => { .makeMove({ player: 'black', pos: { x: 4, y: 16 } }); it('gain liberties from group smoke test', done => { - joinGame.success.should.eql(true); // to work after + joinGame.success.should.eql(true); done(); }); - // test group with only remaining liberty at point to be played + it('group with only remaining liberty at point to be played returns success: false', done => { + Game({ gameData: { handicap: 2 } }).initGame() + .makeMove({ player: 'white', pos: { x: 4, y: 15 } }) // 3 4 5 6 + .makeMove({ player: 'black', pos: { x: 4, y: 4 } }) // 15 -1 -1 + .makeMove({ player: 'white', pos: { x: 5, y: 15 } }) // 16 -1 1h 0 -1 + .makeMove({ player: 'black', pos: { x: 16, y: 16 } }) // 17 -1 -1 + .makeMove({ player: 'white', pos: { x: 3, y: 16 } }) + .makeMove({ player: 'black', pos: { x: 4, y: 10 } }) + .makeMove({ player: 'white', pos: { x: 6, y: 16 } }) + .makeMove({ player: 'black', pos: { x: 10, y: 4 } }) + .makeMove({ player: 'white', pos: { x: 4, y: 17 } }) + .makeMove({ player: 'black', pos: { x: 10, y: 16 } }) + .makeMove({ player: 'white', pos: { x: 5, y: 17 } }) + .makeMove({ player: 'black', pos: { x: 5, y: 16 } }) + .success.should.eql(false); + done(); + }) // const captureGame = Game({ gameData: { handicap: 2 } }).initGame() // .makeMove({ player: 'white', pos: { x: 4, y: 15 } }) // 3 4 5