add logic to prevent move at group's final liberty
This commit is contained in:
parent
9164ee5987
commit
96af52823d
2 changed files with 55 additions and 23 deletions
|
@ -69,43 +69,49 @@ const pipeMap = (...funcs) => obj => {
|
||||||
|
|
||||||
const checkLegal = ({ point, Game }) => {
|
const checkLegal = ({ point, Game }) => {
|
||||||
// if stone (includes ko) return false
|
// if stone (includes ko) return false
|
||||||
let legal = false;
|
|
||||||
if (point.stone) {
|
if (point.stone) {
|
||||||
point.legal = legal;
|
point.legal = false;
|
||||||
return point;
|
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 empty point adjacent return true
|
||||||
if (!isEmptyAdjacent) {
|
if (!isEmptyAdjacent.length) {
|
||||||
|
|
||||||
// if group has liberties return true
|
// if group has liberties return true
|
||||||
const isTurnStone = neighbor => neighbor.stone === Game.turn;
|
const isTurnStone = neighbor => neighbor.stone === Game.turn;
|
||||||
const getGroupLiberties = point => Array.from(Game.groups[point.group].liberties);
|
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 isNotSamePoint = liberty => liberty.pos.x !== point.pos.x && liberty.pos.y !== point.pos.y;
|
||||||
const isInLiveGroup = () => Object.values(point.neighbors).filter(isTurnStone).filter(isInGroupWithLiberties).length;
|
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;
|
point.legal = true;
|
||||||
return point;
|
return { ...point, isInLiveGroup };
|
||||||
}
|
}
|
||||||
|
|
||||||
point.legal = legal;
|
point.legal = false;
|
||||||
return { ...point, adj: isEmptyAdjacent };
|
return { ...point, adj: isEmptyAdjacent, isInLiveGroup };
|
||||||
}
|
}
|
||||||
// if move would capture opposing group
|
// if move would capture opposing group
|
||||||
// set capturing object and return true
|
// set capturing object and return true
|
||||||
point.legal = !point.stone ? true : false;
|
point.legal = true;
|
||||||
point.adj = isEmptyAdjacent;
|
point.adj = isEmptyAdjacent;
|
||||||
return point;
|
return point;
|
||||||
}
|
}
|
||||||
|
|
||||||
const getBoardState = (Game) => {
|
const getBoardState = (Game) => {
|
||||||
const getLegal = point => checkLegal({ point, Game }).legal ? 'l' : point.stone;
|
const getLegal = point => checkLegal({ point, Game })
|
||||||
return pipeMap(getLegal)(Game.boardState);
|
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 getNeighbors = boardSize => (point, i, boardState) => {
|
||||||
const { top, btm, lft, rgt} = point.neighbors;
|
const { top, btm, lft, rgt} = point.neighbors;
|
||||||
// boardState[0] = [ '1-1', Point({x:1, y:1, boardSize}) ]
|
// 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;
|
boardState[`${point.pos.x}-${point.pos.y}`] = point;
|
||||||
}
|
}
|
||||||
|
const boardStateWithNeighbors = pipeMap(getNeighbors(boardSize))(boardState)
|
||||||
if (handicap) {
|
if (handicap) {
|
||||||
HANDI_PLACE[boardSize][handicap].forEach(pt => {
|
HANDI_PLACE[boardSize][handicap].forEach(pt => {
|
||||||
boardState[pt].makeMove(game);
|
boardStateWithNeighbors[pt].makeMove(game);
|
||||||
});
|
});
|
||||||
game.turn *= -1;
|
game.turn *= -1;
|
||||||
}
|
}
|
||||||
const boardStateWithNeighbors = pipeMap(getNeighbors(boardSize))(boardState)
|
|
||||||
return boardStateWithNeighbors;
|
return boardStateWithNeighbors;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,8 +170,9 @@ const Game = ({gameData = {}, gameRecord = []} = {}) => ({
|
||||||
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);
|
||||||
return { ...this, legalMoves: getBoardState(this)};
|
this.boardState = getBoardState(this);
|
||||||
|
return { ...this, legalMoves: getLegalMoves(this)};
|
||||||
},
|
},
|
||||||
|
|
||||||
getMeta: function() {
|
getMeta: function() {
|
||||||
|
@ -184,7 +191,8 @@ const Game = ({gameData = {}, gameRecord = []} = {}) => ({
|
||||||
success = true;
|
success = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {...this, legalMoves: getBoardState(this), success };
|
this.boardState = getBoardState(this);
|
||||||
|
return {...this, legalMoves: getLegalMoves(this), success };
|
||||||
},
|
},
|
||||||
|
|
||||||
initGroup: function(point) {
|
initGroup: function(point) {
|
||||||
|
@ -240,7 +248,14 @@ const Point = ({x, y, boardSize = 19}) => ({
|
||||||
const neighbors = Object.values(this.neighbors);
|
const neighbors = Object.values(this.neighbors);
|
||||||
const liberties = game.groups[this.group].liberties;
|
const liberties = game.groups[this.group].liberties;
|
||||||
// if point is occupied remove it from liberties set of point group, else add it
|
// 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)
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -193,7 +193,8 @@ describe('Game.makeMove({ player: str, pos: { x: int, y: int } })', () => {
|
||||||
.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: 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: 16, y: 10 }}).makeMove({ player: 'black', pos: { x: 5, y: 17 } }) // 6 1
|
||||||
.makeMove({ player: 'white', pos: { x: 5, y: 16 }})
|
.makeMove({ player: 'white', pos: { x: 5, y: 16 }})
|
||||||
.success.should.eql(false);
|
console.log(point.boardState['5-16'])
|
||||||
|
point.success.should.eql(false);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -207,11 +208,27 @@ describe('makeMove group join and capture logic', () => {
|
||||||
.makeMove({ player: 'black', pos: { x: 4, y: 16 } });
|
.makeMove({ player: 'black', pos: { x: 4, y: 16 } });
|
||||||
|
|
||||||
it('gain liberties from group smoke test', done => {
|
it('gain liberties from group smoke test', done => {
|
||||||
joinGame.success.should.eql(true); // to work after
|
joinGame.success.should.eql(true);
|
||||||
done();
|
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()
|
// const captureGame = Game({ gameData: { handicap: 2 } }).initGame()
|
||||||
// .makeMove({ player: 'white', pos: { x: 4, y: 15 } }) // 3 4 5
|
// .makeMove({ player: 'white', pos: { x: 4, y: 15 } }) // 3 4 5
|
||||||
|
|
Loading…
Reference in a new issue