add join group logic to Point, triggered by Game.makeMove
This commit is contained in:
parent
b1f29f3d2d
commit
e553601af7
2 changed files with 143 additions and 67 deletions
|
@ -95,8 +95,9 @@ const getNeighbors = boardSize => (point, i, boardState) => {
|
||||||
return point;
|
return point;
|
||||||
}
|
}
|
||||||
|
|
||||||
const initBoard = ({ boardSize, handicap }) => {
|
const initBoard = (game) => {
|
||||||
const boardState = {};
|
const boardState = {};
|
||||||
|
const { boardSize, handicap } = game;
|
||||||
for (let i = 0; i < Math.pow(boardSize, 2); i++) {
|
for (let i = 0; i < Math.pow(boardSize, 2); i++) {
|
||||||
const point = Point({
|
const point = Point({
|
||||||
x: Math.floor(i / boardSize) + 1,
|
x: Math.floor(i / boardSize) + 1,
|
||||||
|
@ -107,8 +108,9 @@ const initBoard = ({ boardSize, handicap }) => {
|
||||||
}
|
}
|
||||||
if (handicap) {
|
if (handicap) {
|
||||||
HANDI_PLACE[boardSize][handicap].forEach(pt => {
|
HANDI_PLACE[boardSize][handicap].forEach(pt => {
|
||||||
boardState[pt].stone = 1;
|
boardState[pt].makeMove(game);
|
||||||
});
|
});
|
||||||
|
game.turn *= -1;
|
||||||
}
|
}
|
||||||
const boardStateWithNeighbors = pipeMap(getNeighbors(boardSize))(boardState)
|
const boardStateWithNeighbors = pipeMap(getNeighbors(boardSize))(boardState)
|
||||||
return boardStateWithNeighbors;
|
return boardStateWithNeighbors;
|
||||||
|
@ -135,9 +137,8 @@ const Game = ({gameData = {}, gameRecord = []} = {}) => ({
|
||||||
initGame: function() {
|
initGame: function() {
|
||||||
this.winner = null;
|
this.winner = null;
|
||||||
this.pass = 0;
|
this.pass = 0;
|
||||||
this.turn = this.handicap ? -1 : 1;
|
this.turn = 1;
|
||||||
this.boardState = initBoard({ boardSize: this.boardSize, handicap: this.handicap})
|
this.boardState = initBoard(this)
|
||||||
// return this.boardState
|
|
||||||
return { ...this, legalMoves: getBoardState(this)};
|
return { ...this, legalMoves: getBoardState(this)};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -152,12 +153,18 @@ const Game = ({gameData = {}, gameRecord = []} = {}) => ({
|
||||||
|| ( this.turn === -1 && player === 'white' );
|
|| ( this.turn === -1 && player === 'white' );
|
||||||
if (isTurn) {
|
if (isTurn) {
|
||||||
if (point.legal) {
|
if (point.legal) {
|
||||||
point.makeMove(this.turn);
|
point.makeMove(this);
|
||||||
this.turn *= -1;
|
this.turn *= -1;
|
||||||
success = true;
|
success = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {...this, legalMoves: getBoardState(this), success };
|
return {...this, legalMoves: getBoardState(this), success };
|
||||||
|
},
|
||||||
|
|
||||||
|
initGroup: function(point) {
|
||||||
|
const newSymbol = Symbol(`${point.pos.x}-${point.pos.y}`);
|
||||||
|
this.groups[newSymbol] = new Set();
|
||||||
|
return newSymbol;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -167,7 +174,7 @@ const Point = ({x, y, boardSize = 19}) => ({
|
||||||
legal: true,
|
legal: true,
|
||||||
territory: 0,
|
territory: 0,
|
||||||
capturing: [],
|
capturing: [],
|
||||||
groupMembers: [ this ],
|
group: null,
|
||||||
neighbors: {
|
neighbors: {
|
||||||
top: x > 1 ? `${ x - 1 }-${ y }` : null,
|
top: x > 1 ? `${ x - 1 }-${ y }` : null,
|
||||||
btm: x < boardSize ? `${ x + 1 }-${ y }` : null,
|
btm: x < boardSize ? `${ x + 1 }-${ y }` : null,
|
||||||
|
@ -175,9 +182,30 @@ const Point = ({x, y, boardSize = 19}) => ({
|
||||||
lft: y > 1 ? `${ x }-${ y - 1 }` : null
|
lft: y > 1 ? `${ x }-${ y - 1 }` : null
|
||||||
},
|
},
|
||||||
|
|
||||||
makeMove: function(turn) {
|
makeMove: function(game) {
|
||||||
this.stone = turn;
|
this.stone = game.turn;
|
||||||
this.legal = false;
|
this.legal = false;
|
||||||
|
return this.joinGroup({ point: this, game });
|
||||||
|
},
|
||||||
|
|
||||||
|
joinGroup: function({ point, game }) {
|
||||||
|
if (point.group !== this.group || !point.group) {
|
||||||
|
// if point has no group set current group to new Symbol in game object
|
||||||
|
if (!point.group) {
|
||||||
|
point.group = game.initGroup(point);
|
||||||
|
}
|
||||||
|
|
||||||
|
// add current point to global group
|
||||||
|
game.groups[point.group].add(this);
|
||||||
|
this.group = point.group;
|
||||||
|
for (let neighbor of Object.values(this.neighbors)) {
|
||||||
|
if (neighbor.stone === this.stone
|
||||||
|
&& neighbor.group !== this.group) {
|
||||||
|
neighbor.joinGroup({ point: this, game });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -32,14 +32,14 @@ describe('Game', () => {
|
||||||
|
|
||||||
describe('Game().initGame() returns boardState', () => {
|
describe('Game().initGame() returns boardState', () => {
|
||||||
it('initGame() returns default 19x19', done => {
|
it('initGame() returns default 19x19', done => {
|
||||||
Game().initGame().legalMoves
|
Game().initGame()
|
||||||
.should.eql(emptyBoard);
|
.legalMoves.should.eql(emptyBoard);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('initGame() with 2 handicap returns legalMoves with stones', done => {
|
it('initGame() with 2 handicap returns legalMoves with stones', done => {
|
||||||
Game({gameData: { handicap: 2 }}).initGame().legalMoves
|
Game({gameData: { handicap: 2 }}).initGame()
|
||||||
.should.eql({...emptyBoard, '4-16': 1, '16-4': 1});
|
.legalMoves.should.eql({...emptyBoard, '4-16': 1, '16-4': 1});
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -65,87 +65,135 @@ describe('Game().initGame() returns boardState', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('initGame( 19x19 ) with all levels of handicap returns legalMoves with stones', done => {
|
it('initGame( 19x19 ) with all levels of handicap returns legalMoves with stones', done => {
|
||||||
Game({gameData: { boardSize: 19, handicap: 2 }}).initGame().legalMoves
|
Game({gameData: { boardSize: 19, handicap: 2 }}).initGame()
|
||||||
.should.eql({...emptyBoard, '4-16': 1, '16-4': 1 });
|
.legalMoves.should.eql({...emptyBoard, '4-16': 1, '16-4': 1 });
|
||||||
Game({gameData: { boardSize: 19, handicap: 3 }}).initGame().legalMoves
|
Game({gameData: { boardSize: 19, handicap: 3 }}).initGame()
|
||||||
.should.eql({...emptyBoard, '16-16': 1, '4-16': 1, '16-4': 1 });
|
.legalMoves.should.eql({...emptyBoard, '16-16': 1, '4-16': 1, '16-4': 1 });
|
||||||
Game({gameData: { boardSize: 19, handicap: 4 }}).initGame().legalMoves
|
Game({gameData: { boardSize: 19, handicap: 4 }}).initGame()
|
||||||
.should.eql({...emptyBoard, '4-4': 1, '16-16': 1, '4-16': 1, '16-4': 1 });
|
.legalMoves.should.eql({...emptyBoard, '4-4': 1, '16-16': 1, '4-16': 1, '16-4': 1 });
|
||||||
Game({gameData: { boardSize: 19, handicap: 5 }}).initGame().legalMoves
|
Game({gameData: { boardSize: 19, handicap: 5 }}).initGame()
|
||||||
.should.eql({...emptyBoard, '10-10': 1, '4-4': 1, '16-16': 1, '4-16': 1, '16-4': 1 });
|
.legalMoves.should.eql({...emptyBoard, '10-10': 1, '4-4': 1, '16-16': 1, '4-16': 1, '16-4': 1 });
|
||||||
Game({gameData: { boardSize: 19, handicap: 6 }}).initGame().legalMoves
|
Game({gameData: { boardSize: 19, handicap: 6 }}).initGame()
|
||||||
.should.eql({...emptyBoard, '10-4': 1, '4-10': 1, '4-4': 1, '16-16': 1, '4-16': 1, '16-4': 1 });
|
.legalMoves.should.eql({...emptyBoard, '10-4': 1, '4-10': 1, '4-4': 1, '16-16': 1, '4-16': 1, '16-4': 1 });
|
||||||
Game({gameData: { boardSize: 19, handicap: 7 }}).initGame().legalMoves
|
Game({gameData: { boardSize: 19, handicap: 7 }}).initGame()
|
||||||
.should.eql({...emptyBoard, '10-10': 1, '10-4': 1, '4-10': 1, '4-4': 1, '16-16': 1, '4-16': 1, '16-4': 1 });
|
.legalMoves.should.eql({...emptyBoard, '10-10': 1, '10-4': 1, '4-10': 1, '4-4': 1, '16-16': 1, '4-16': 1, '16-4': 1 });
|
||||||
Game({gameData: { boardSize: 19, handicap: 8 }}).initGame().legalMoves
|
Game({gameData: { boardSize: 19, handicap: 8 }}).initGame()
|
||||||
.should.eql({...emptyBoard, '16-10': 1, '10-4': 1, '10-16': 1, '4-10': 1, '4-4': 1, '16-16': 1, '4-16': 1, '16-4': 1 });
|
.legalMoves.should.eql({...emptyBoard, '16-10': 1, '10-4': 1, '10-16': 1, '4-10': 1, '4-4': 1, '16-16': 1, '4-16': 1, '16-4': 1 });
|
||||||
Game({gameData: { boardSize: 19, handicap: 9 }}).initGame().legalMoves
|
Game({gameData: { boardSize: 19, handicap: 9 }}).initGame()
|
||||||
.should.eql({...emptyBoard, '10-10': 1, '16-10': 1, '10-4': 1, '10-16': 1, '4-10': 1, '4-4': 1, '16-16': 1, '4-16': 1, '16-4': 1 });
|
.legalMoves.should.eql({...emptyBoard, '10-10': 1, '16-10': 1, '10-4': 1, '10-16': 1, '4-10': 1, '4-4': 1, '16-16': 1, '4-16': 1, '16-4': 1 });
|
||||||
done();
|
done();
|
||||||
})
|
})
|
||||||
|
|
||||||
it('initGame( 13x13) returns legalMoves', done => {
|
it('initGame( 13x13) returns legalMoves', done => {
|
||||||
Game({gameData: { boardSize: 13 }}).initGame().legalMoves
|
Game({gameData: { boardSize: 13 }}).initGame()
|
||||||
.should.eql(emptyBoard13);
|
.legalMoves.should.eql(emptyBoard13);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('initGame( 13x13 ) with all levels of handicap returns legalMoves with stones', done => {
|
it('initGame( 13x13 ) with all levels of handicap returns legalMoves with stones', done => {
|
||||||
Game({gameData: { boardSize: 13, handicap: 2 }}).initGame().legalMoves
|
Game({gameData: { boardSize: 13, handicap: 2 }}).initGame()
|
||||||
.should.eql({...emptyBoard13, '4-10': 1, '10-4': 1 });
|
.legalMoves.should.eql({...emptyBoard13, '4-10': 1, '10-4': 1 });
|
||||||
Game({gameData: { boardSize: 13, handicap: 3 }}).initGame().legalMoves
|
Game({gameData: { boardSize: 13, handicap: 3 }}).initGame()
|
||||||
.should.eql({...emptyBoard13, '10-10': 1, '4-10': 1, '10-4': 1 });
|
.legalMoves.should.eql({...emptyBoard13, '10-10': 1, '4-10': 1, '10-4': 1 });
|
||||||
Game({gameData: { boardSize: 13, handicap: 4 }}).initGame().legalMoves
|
Game({gameData: { boardSize: 13, handicap: 4 }}).initGame()
|
||||||
.should.eql({...emptyBoard13, '4-4': 1, '10-10': 1, '4-10': 1, '10-4': 1 });
|
.legalMoves.should.eql({...emptyBoard13, '4-4': 1, '10-10': 1, '4-10': 1, '10-4': 1 });
|
||||||
Game({gameData: { boardSize: 13, handicap: 5 }}).initGame().legalMoves
|
Game({gameData: { boardSize: 13, handicap: 5 }}).initGame()
|
||||||
.should.eql({...emptyBoard13, '7-7': 1, '4-4': 1, '10-10': 1, '4-10': 1, '10-4': 1 });
|
.legalMoves.should.eql({...emptyBoard13, '7-7': 1, '4-4': 1, '10-10': 1, '4-10': 1, '10-4': 1 });
|
||||||
Game({gameData: { boardSize: 13, handicap: 6 }}).initGame().legalMoves
|
Game({gameData: { boardSize: 13, handicap: 6 }}).initGame()
|
||||||
.should.eql({...emptyBoard13, '7-4': 1, '4-7': 1, '4-4': 1, '10-10': 1, '4-10': 1, '10-4': 1 });
|
.legalMoves.should.eql({...emptyBoard13, '7-4': 1, '4-7': 1, '4-4': 1, '10-10': 1, '4-10': 1, '10-4': 1 });
|
||||||
Game({gameData: { boardSize: 13, handicap: 7 }}).initGame().legalMoves
|
Game({gameData: { boardSize: 13, handicap: 7 }}).initGame()
|
||||||
.should.eql({...emptyBoard13, '7-7': 1, '7-4': 1, '4-7': 1, '4-4': 1, '10-10': 1, '4-10': 1, '10-4': 1 });
|
.legalMoves.should.eql({...emptyBoard13, '7-7': 1, '7-4': 1, '4-7': 1, '4-4': 1, '10-10': 1, '4-10': 1, '10-4': 1 });
|
||||||
Game({gameData: { boardSize: 13, handicap: 8 }}).initGame().legalMoves
|
Game({gameData: { boardSize: 13, handicap: 8 }}).initGame()
|
||||||
.should.eql({...emptyBoard13, '10-7': 1, '7-4': 1, '7-10': 1, '4-7': 1, '4-4': 1, '10-10': 1, '4-10': 1, '10-4': 1 });
|
.legalMoves.should.eql({...emptyBoard13, '10-7': 1, '7-4': 1, '7-10': 1, '4-7': 1, '4-4': 1, '10-10': 1, '4-10': 1, '10-4': 1 });
|
||||||
Game({gameData: { boardSize: 13, handicap: 9 }}).initGame().legalMoves
|
Game({gameData: { boardSize: 13, handicap: 9 }}).initGame()
|
||||||
.should.eql({...emptyBoard13, '7-7': 1, '10-7': 1, '7-4': 1, '7-10': 1, '4-7': 1, '4-4': 1, '10-10': 1, '4-10': 1, '10-4': 1 });
|
.legalMoves.should.eql({...emptyBoard13, '7-7': 1, '10-7': 1, '7-4': 1, '7-10': 1, '4-7': 1, '4-4': 1, '10-10': 1, '4-10': 1, '10-4': 1 });
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('initGame( 9x9 ) returns legalMoves', done => {
|
it('initGame( 9x9 ) returns legalMoves', done => {
|
||||||
Game({gameData: { boardSize: 9 }}).initGame().legalMoves
|
Game({gameData: { boardSize: 9 }}).initGame()
|
||||||
.should.eql(emptyBoard9);
|
.legalMoves.should.eql(emptyBoard9);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('initGame( 9x9 ) with all levels of handicap returns legalMoves with stones', done => {
|
it('initGame( 9x9 ) with all levels of handicap returns legalMoves with stones', done => {
|
||||||
Game({gameData: { boardSize: 9, handicap: 2 }}).initGame().legalMoves
|
Game({gameData: { boardSize: 9, handicap: 2 }}).initGame()
|
||||||
.should.eql({...emptyBoard9, '3-7': 1, '7-3': 1 });
|
.legalMoves.should.eql({...emptyBoard9, '3-7': 1, '7-3': 1 });
|
||||||
Game({gameData: { boardSize: 9, handicap: 3 }}).initGame().legalMoves
|
Game({gameData: { boardSize: 9, handicap: 3 }}).initGame()
|
||||||
.should.eql({...emptyBoard9, '7-7': 1, '3-7': 1, '7-3': 1 });
|
.legalMoves.should.eql({...emptyBoard9, '7-7': 1, '3-7': 1, '7-3': 1 });
|
||||||
Game({gameData: { boardSize: 9, handicap: 4 }}).initGame().legalMoves
|
Game({gameData: { boardSize: 9, handicap: 4 }}).initGame()
|
||||||
.should.eql({...emptyBoard9, '3-3': 1, '7-7': 1, '3-7': 1, '7-3': 1 });
|
.legalMoves.should.eql({...emptyBoard9, '3-3': 1, '7-7': 1, '3-7': 1, '7-3': 1 });
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Game.makeMove({ player: str, pos: { x: int, y: int } })', () => {
|
describe('Game.makeMove({ player: str, pos: { x: int, y: int } })', () => {
|
||||||
it('place move returns game object with proper board', done => {
|
it('makeMove returns game object with proper board', done => {
|
||||||
Game().initGame().makeMove({ player: 'black', pos: { x: 4, y: 4 } }).legalMoves
|
Game().initGame().makeMove({ player: 'black', pos: { x: 4, y: 4 } })
|
||||||
.should.eql({ ...emptyBoard, '4-4': 1 });
|
.legalMoves.should.eql({ ...emptyBoard, '4-4': 1 });
|
||||||
Game({ gameData: { handicap: 2 } }).initGame().makeMove({ player: 'white', pos: { x: 4, y: 4 } }).legalMoves
|
Game({ gameData: { handicap: 2 } }).initGame().makeMove({ player: 'white', pos: { x: 4, y: 4 } })
|
||||||
.should.eql({ ...emptyBoard, '4-16': 1, '16-4': 1, '4-4': -1 });
|
.legalMoves.should.eql({ ...emptyBoard, '4-16': 1, '16-4': 1, '4-4': -1 });
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('make move returns success: false with move out of turn', done => {
|
it('makeMove returns success: false with move out of turn', done => {
|
||||||
Game().initGame().makeMove({ player: 'white', pos: { x: 4, y: 4 } }).success
|
Game().initGame().makeMove({ player: 'white', pos: { x: 4, y: 4 } })
|
||||||
.should.eql(false);
|
.success.should.eql(false);
|
||||||
Game({ gameData: { handicap: 2 } }).initGame().makeMove({ player: 'black', pos: { x: 4, y: 4 } }).success
|
Game({ gameData: { handicap: 2 } }).initGame().makeMove({ player: 'black', pos: { x: 4, y: 4 } })
|
||||||
.should.eql(false);
|
.success.should.eql(false);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('makeMove returns success: false when move is at occupied point', done => {
|
||||||
|
Game({ gameData: { handicap: 2 } }).initGame().makeMove({ player: 'white', pos: { x: 4, y: 16 } })
|
||||||
|
.success.should.eql(false);
|
||||||
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
// describe('Point.joinGroup() ')
|
it('makeMove next to adjacent stone of the same color joins stones as a group', done => {
|
||||||
|
const game = Game({ gameData: { handicap: 2 } }).initGame() // 4 3 4
|
||||||
|
.makeMove({ player: 'white', pos: { x: 4, y: 4 } }) // 14 1 4 -1 -1
|
||||||
|
.makeMove({ player: 'black', pos: { x: 4, y: 15 }}) // 15 1 5 -1
|
||||||
|
.makeMove({ player: 'white', pos: { x: 3, y: 4 } }) // 16 1h
|
||||||
|
.makeMove({ player: 'black', pos: { x: 4, y: 14 }})
|
||||||
|
.makeMove({ player: 'white', pos: { x: 4, y: 5 }})
|
||||||
|
|
||||||
|
const blackGroup = game.boardState['4-14'].group;
|
||||||
|
game.groups[blackGroup].has(game.boardState['4-14']).should.eql(true);
|
||||||
|
game.groups[blackGroup].has(game.boardState['4-15']).should.eql(true);
|
||||||
|
game.groups[blackGroup].has(game.boardState['4-16']).should.eql(true);
|
||||||
|
const whiteGroup = game.boardState['4-4'].group;
|
||||||
|
game.groups[whiteGroup].has(game.boardState['4-4']).should.eql(true);
|
||||||
|
game.groups[whiteGroup].has(game.boardState['3-4']).should.eql(true);
|
||||||
|
game.groups[whiteGroup].has(game.boardState['4-5']).should.eql(true);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('makeMove next to adjacent stone of different color does not join stones as a group', done => {
|
||||||
|
const game = Game({ gameData: { handicap: 2 } }).initGame() // 3 4
|
||||||
|
.makeMove({ player: 'white', pos: { x: 4, y: 15 } }) // 14 1
|
||||||
|
.makeMove({ player: 'black', pos: { x: 4, y: 14 }}) // 15 1 -1 no groups
|
||||||
|
.makeMove({ player: 'white', pos: { x: 3, y: 16 } }) // 16 -1 1h
|
||||||
|
.makeMove({ player: 'black', pos: { x: 3, y: 15 }})
|
||||||
|
|
||||||
|
const hoshiGroup = game.boardState['4-16'].group;
|
||||||
|
game.groups[hoshiGroup].has(game.boardState['4-16']).should.eql(true);
|
||||||
|
game.groups[hoshiGroup].has(game.boardState['4-15']).should.eql(false);
|
||||||
|
game.groups[hoshiGroup].has(game.boardState['3-14']).should.eql(false);
|
||||||
|
game.groups[hoshiGroup].has(game.boardState['3-15']).should.eql(false);
|
||||||
|
done();
|
||||||
|
})
|
||||||
|
|
||||||
|
// it('makeMove returns success: false when move is made in point with no liberties', done => {
|
||||||
|
// Game({ gameData: { handicap: 2 } }).initGame()
|
||||||
|
// .makeMove({ player: 'white', pos: { x: 4, y: 4 } }).makeMove({ player: 'black', pos: { x: 6, y: 16 } })
|
||||||
|
// .makeMove({ player: 'white', pos: { x: 16, y: 16 }}).makeMove({ player: 'black', pos: { x: 5, y: 15 } })
|
||||||
|
// .makeMove({ player: 'white', pos: { x: 16, y: 10 }}).makeMove({ player: 'black', pos: { x: 5, y: 17 } })
|
||||||
|
// .makeMove({ player: 'white', pos: { x: 5, y: 16 }})
|
||||||
|
// .success.should.eql(false);
|
||||||
|
// done();
|
||||||
|
// })
|
||||||
|
});
|
||||||
|
|
||||||
const initialMeta = {
|
const initialMeta = {
|
||||||
winner: null,
|
winner: null,
|
||||||
|
|
Loading…
Reference in a new issue