1764 lines
48 KiB
JavaScript
1764 lines
48 KiB
JavaScript
const chai = require("chai");
|
|
const should = chai.should();
|
|
const { Game, Point } = require("../services/Game");
|
|
|
|
describe("Game", () => {
|
|
it("smoke test Game()", (done) => {
|
|
(typeof Game()).should.eql("object");
|
|
done();
|
|
});
|
|
|
|
it("smoke test Point()", (done) => {
|
|
(typeof Point({ x: 1, y: 1 })).should.eql("object");
|
|
done();
|
|
});
|
|
|
|
it("smoke test initGame()", (done) => {
|
|
(typeof Game().initGame()).should.eql("object");
|
|
done();
|
|
});
|
|
|
|
it("Get meta returns proper data for games with no record", (done) => {
|
|
Game().getMeta().should.eql(initialMeta);
|
|
done();
|
|
});
|
|
});
|
|
|
|
describe("Game().initGame() returns legalMoves", () => {
|
|
it("initGame() returns default 19x19", (done) => {
|
|
Game().initGame().legalMoves.should.eql(emptyBoard);
|
|
done();
|
|
});
|
|
|
|
it("initGame() with 2 handicap returns legalMoves with stones", (done) => {
|
|
Game({ gameData: { handicap: 2 } })
|
|
.initGame()
|
|
.legalMoves.should.eql({ ...emptyBoard, "4-16": 1, "16-4": 1 });
|
|
done();
|
|
});
|
|
|
|
it("handicap stone has proper liberties", (done) => {
|
|
const game = Game({ gameData: { handicap: 2 } }).initGame();
|
|
const group = game.boardState["4-16"].group;
|
|
game.groups[group].liberties.size.should.eql(4);
|
|
done();
|
|
});
|
|
|
|
it("initGame( 19x19 ) with all levels of handicap returns legalMoves with stones", (done) => {
|
|
Game({ gameData: { boardSize: 19, handicap: 2 } })
|
|
.initGame()
|
|
.legalMoves.should.eql({ ...emptyBoard, "4-16": 1, "16-4": 1 });
|
|
Game({ gameData: { boardSize: 19, handicap: 3 } })
|
|
.initGame()
|
|
.legalMoves.should.eql({
|
|
...emptyBoard,
|
|
"16-16": 1,
|
|
"4-16": 1,
|
|
"16-4": 1,
|
|
});
|
|
Game({ gameData: { boardSize: 19, handicap: 4 } })
|
|
.initGame()
|
|
.legalMoves.should.eql({
|
|
...emptyBoard,
|
|
"4-4": 1,
|
|
"16-16": 1,
|
|
"4-16": 1,
|
|
"16-4": 1,
|
|
});
|
|
Game({ gameData: { boardSize: 19, handicap: 5 } })
|
|
.initGame()
|
|
.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.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.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.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.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();
|
|
});
|
|
|
|
it("initGame( 13x13) returns legalMoves", (done) => {
|
|
Game({ gameData: { boardSize: 13 } })
|
|
.initGame()
|
|
.legalMoves.should.eql(emptyBoard13);
|
|
done();
|
|
});
|
|
|
|
it("initGame( 13x13 ) with all levels of handicap returns legalMoves with stones", (done) => {
|
|
Game({ gameData: { boardSize: 13, handicap: 2 } })
|
|
.initGame()
|
|
.legalMoves.should.eql({ ...emptyBoard13, "4-10": 1, "10-4": 1 });
|
|
Game({ gameData: { boardSize: 13, handicap: 3 } })
|
|
.initGame()
|
|
.legalMoves.should.eql({
|
|
...emptyBoard13,
|
|
"10-10": 1,
|
|
"4-10": 1,
|
|
"10-4": 1,
|
|
});
|
|
Game({ gameData: { boardSize: 13, handicap: 4 } })
|
|
.initGame()
|
|
.legalMoves.should.eql({
|
|
...emptyBoard13,
|
|
"4-4": 1,
|
|
"10-10": 1,
|
|
"4-10": 1,
|
|
"10-4": 1,
|
|
});
|
|
Game({ gameData: { boardSize: 13, handicap: 5 } })
|
|
.initGame()
|
|
.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.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.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.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.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();
|
|
});
|
|
|
|
it("initGame( 9x9 ) returns legalMoves", (done) => {
|
|
Game({ gameData: { boardSize: 9 } })
|
|
.initGame()
|
|
.legalMoves.should.eql(emptyBoard9);
|
|
done();
|
|
});
|
|
|
|
it("initGame( 9x9 ) with all levels of handicap returns legalMoves with stones", (done) => {
|
|
Game({ gameData: { boardSize: 9, handicap: 2 } })
|
|
.initGame()
|
|
.legalMoves.should.eql({ ...emptyBoard9, "3-7": 1, "7-3": 1 });
|
|
Game({ gameData: { boardSize: 9, handicap: 3 } })
|
|
.initGame()
|
|
.legalMoves.should.eql({ ...emptyBoard9, "7-7": 1, "3-7": 1, "7-3": 1 });
|
|
Game({ gameData: { boardSize: 9, handicap: 4 } })
|
|
.initGame()
|
|
.legalMoves.should.eql({
|
|
...emptyBoard9,
|
|
"3-3": 1,
|
|
"7-7": 1,
|
|
"3-7": 1,
|
|
"7-3": 1,
|
|
});
|
|
done();
|
|
});
|
|
});
|
|
|
|
describe("Game.makeMove({ player: str, pos: { x: int, y: int } })", () => {
|
|
it("makeMove returns game object with proper board", (done) => {
|
|
Game()
|
|
.initGame()
|
|
.makeMove({ player: "black", pos: { x: 4, y: 4 } })
|
|
.legalMoves.should.eql({ ...emptyBoard, "4-4": 1 });
|
|
Game({ gameData: { handicap: 2 } })
|
|
.initGame()
|
|
.makeMove({ player: "white", pos: { x: 4, y: 4 } })
|
|
.legalMoves.should.eql({
|
|
...emptyBoard,
|
|
"4-16": 1,
|
|
"16-4": 1,
|
|
"4-4": -1,
|
|
});
|
|
done();
|
|
});
|
|
|
|
it("makeMove returns success: false with move out of turn", (done) => {
|
|
Game()
|
|
.initGame()
|
|
.makeMove({ player: "white", pos: { x: 4, y: 4 } })
|
|
.success.should.eql(false);
|
|
Game({ gameData: { handicap: 2 } })
|
|
.initGame()
|
|
.makeMove({ player: "black", pos: { x: 4, y: 4 } })
|
|
.success.should.eql(false);
|
|
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();
|
|
});
|
|
|
|
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 blackGroupKey = game.boardState["4-14"].group;
|
|
const blackGroup = game.groups[blackGroupKey].stones;
|
|
blackGroup.has(game.boardState["4-14"]).should.eql(true);
|
|
blackGroup.has(game.boardState["4-15"]).should.eql(true);
|
|
blackGroup.has(game.boardState["4-16"]).should.eql(true);
|
|
const whiteGroupKey = game.boardState["4-4"].group;
|
|
const whiteGroup = game.groups[whiteGroupKey].stones;
|
|
whiteGroup.has(game.boardState["4-4"]).should.eql(true);
|
|
whiteGroup.has(game.boardState["3-4"]).should.eql(true);
|
|
whiteGroup.has(game.boardState["4-5"]).should.eql(true);
|
|
done();
|
|
});
|
|
|
|
const noGroupGame = 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 } });
|
|
|
|
it("makeMove next to adjacent stone of different color does not join stones as a group", (done) => {
|
|
const hoshiGroupKey = noGroupGame.boardState["4-16"].group;
|
|
const hoshiGroup = noGroupGame.groups[hoshiGroupKey].stones;
|
|
hoshiGroup.has(noGroupGame.boardState["4-16"]).should.eql(true);
|
|
hoshiGroup.has(noGroupGame.boardState["4-15"]).should.eql(false);
|
|
hoshiGroup.has(noGroupGame.boardState["3-14"]).should.eql(false);
|
|
hoshiGroup.has(noGroupGame.boardState["3-15"]).should.eql(false);
|
|
done();
|
|
});
|
|
|
|
it("makeMove next to adjacent stone of different color should yield proper liberties", (done) => {
|
|
const hoshiGroup = noGroupGame.boardState["4-16"].group;
|
|
const hoshiGroupLiberties = noGroupGame.groups[hoshiGroup].liberties;
|
|
hoshiGroupLiberties.size.should.eql(2);
|
|
const fourFifteen = noGroupGame.boardState["4-15"].group;
|
|
const fourFifteenLiberties = noGroupGame.groups[fourFifteen].liberties;
|
|
fourFifteenLiberties.size.should.eql(1);
|
|
done();
|
|
});
|
|
|
|
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
|
|
.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 } });
|
|
point.success.should.eql(false);
|
|
done();
|
|
});
|
|
});
|
|
|
|
describe("makeMove group join and basic capture logic", () => {
|
|
const joinGame = Game()
|
|
.initGame()
|
|
.makeMove({ player: "black", pos: { x: 4, y: 17 } }) // 3 4 5
|
|
.makeMove({ player: "white", pos: { x: 3, y: 16 } }) // 15 -1
|
|
.makeMove({ player: "black", pos: { x: 5, y: 16 } }) // 16 -1 1 1
|
|
.makeMove({ player: "white", pos: { x: 4, y: 15 } }) // 17 1
|
|
.makeMove({ player: "black", pos: { x: 4, y: 16 } });
|
|
|
|
it("gain liberties from group smoke test", (done) => {
|
|
joinGame.success.should.eql(true);
|
|
done();
|
|
});
|
|
|
|
it("stones in group have same group property", (done) => {
|
|
joinGame.boardState["4-16"].group.should.eql(
|
|
joinGame.boardState["5-16"].group
|
|
);
|
|
joinGame.boardState["4-16"].group.should.eql(
|
|
joinGame.boardState["4-17"].group
|
|
);
|
|
joinGame.boardState["4-17"].group.should.eql(
|
|
joinGame.boardState["4-16"].group
|
|
);
|
|
joinGame.boardState["4-17"].group.should.eql(
|
|
joinGame.boardState["5-16"].group
|
|
);
|
|
joinGame.boardState["5-16"].group.should.eql(
|
|
joinGame.boardState["4-17"].group
|
|
);
|
|
joinGame.boardState["5-16"].group.should.eql(
|
|
joinGame.boardState["4-16"].group
|
|
);
|
|
done();
|
|
});
|
|
|
|
it("stones in group should have proper liberties", (done) => {
|
|
const group = joinGame.boardState["4-16"].group;
|
|
joinGame.groups[group].liberties.size.should.eql(5);
|
|
done();
|
|
});
|
|
|
|
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
|
|
.makeMove({ player: "black", pos: { x: 4, y: 4 } }) // 15 -1
|
|
.makeMove({ player: "white", pos: { x: 3, y: 16 } }) // 16 -1 0 -1
|
|
.makeMove({ player: "black", pos: { x: 4, y: 10 } }) // 17 -1
|
|
.makeMove({ player: "white", pos: { x: 5, y: 16 } }) // 4,16 captured
|
|
.makeMove({ player: "black", pos: { x: 10, y: 4 } });
|
|
|
|
it("makeMove capture smoke test", (done) => {
|
|
captureGame()
|
|
.makeMove({ player: "white", pos: { x: 4, y: 17 } })
|
|
.success.should.eql(true);
|
|
done();
|
|
});
|
|
|
|
it("makeMove assesses captures", (done) => {
|
|
captureGame().boardState["4-17"].capturing[-1].size.should.eql(1);
|
|
done();
|
|
});
|
|
|
|
it("makeMove capture removes captured stone", (done) => {
|
|
captureGame()
|
|
.makeMove({ player: "white", pos: { x: 4, y: 17 } })
|
|
.boardState["4-16"].stone.should.eql(0);
|
|
done();
|
|
});
|
|
|
|
it("makeMove capture increases capturing players captures", (done) => {
|
|
captureGame()
|
|
.makeMove({ player: "white", pos: { x: 4, y: 17 } })
|
|
.playerState.wCaptures.should.eql(1);
|
|
done();
|
|
});
|
|
|
|
const traceGame = () =>
|
|
Game()
|
|
.initGame()
|
|
.makeMove({ player: "black", pos: { x: 1, y: 1 } }) // 1 2 3
|
|
.makeMove({ player: "white", pos: { x: 1, y: 2 } }) // 1 1 -1 1
|
|
.makeMove({ player: "black", pos: { x: 2, y: 2 } }) // 2 -1 1
|
|
.makeMove({ player: "white", pos: { x: 2, y: 1 } });
|
|
|
|
it("point at captured stone becomes liberty", (done) => {
|
|
const game = traceGame();
|
|
const group = game.boardState["1-2"].group;
|
|
game.groups[group].liberties.has(game.boardState["1-1"]).should.eql(true);
|
|
done();
|
|
});
|
|
|
|
it("capture does not leave trace filled liberty", (done) => {
|
|
traceGame()
|
|
.makeMove({ player: "black", pos: { x: 1, y: 3 } })
|
|
.boardState["1-2"].stone.should.eql(-1);
|
|
done();
|
|
});
|
|
|
|
const multiCaptureGame = () =>
|
|
Game()
|
|
.initGame()
|
|
.makeMove({ player: "black", pos: { x: 4, y: 17 } })
|
|
.makeMove({ player: "white", pos: { x: 3, y: 16 } })
|
|
.makeMove({ player: "black", pos: { x: 5, y: 16 } })
|
|
.makeMove({ player: "white", pos: { x: 4, y: 15 } })
|
|
.makeMove({ player: "black", pos: { x: 4, y: 16 } })
|
|
.makeMove({ player: "black", pos: { x: 4, y: 10 } }) // 3 4 5 6
|
|
.makeMove({ player: "white", pos: { x: 3, y: 17 } }) // 15 -1 -1
|
|
.makeMove({ player: "black", pos: { x: 10, y: 4 } }) // 16 -1 1 1 -1
|
|
.makeMove({ player: "white", pos: { x: 5, y: 15 } }) // 17 -1 1 -1
|
|
.makeMove({ player: "black", pos: { x: 10, y: 8 } }) // 18 -1
|
|
.makeMove({ player: "white", pos: { x: 4, y: 18 } })
|
|
.makeMove({ player: "black", pos: { x: 3, y: 6 } })
|
|
.makeMove({ player: "white", pos: { x: 5, y: 17 } })
|
|
.makeMove({ player: "black", pos: { x: 6, y: 3 } });
|
|
|
|
it("smoke test multi stone group capture", (done) => {
|
|
multiCaptureGame()
|
|
.makeMove({ player: "white", pos: { x: 6, y: 16 } })
|
|
.success.should.eql(true);
|
|
done();
|
|
});
|
|
|
|
it("multi stone group full group is in capturing", (done) => {
|
|
const game = multiCaptureGame();
|
|
const group = game.boardState["4-16"].group;
|
|
game.boardState["6-16"].capturing[-1].has(group).should.eql(true);
|
|
done();
|
|
});
|
|
|
|
it("multi stone group capture all points are 0", (done) => {
|
|
const game = multiCaptureGame();
|
|
game.makeMove({ player: "white", pos: { x: 6, y: 16 } });
|
|
game.boardState["5-16"].stone.should.eql(0);
|
|
game.boardState["4-16"].stone.should.eql(0);
|
|
game.boardState["4-17"].stone.should.eql(0);
|
|
done();
|
|
});
|
|
|
|
it("multi stone group capture scores points properly", (done) => {
|
|
const game = multiCaptureGame();
|
|
game.makeMove({ player: "white", pos: { x: 6, y: 16 } });
|
|
game.playerState.wCaptures.should.eql(3);
|
|
done();
|
|
});
|
|
});
|
|
|
|
describe("capture logic: snapback, ko and playing in eyes", () => {
|
|
it("playing in an eye formed by capture yields success: true", (done) => {
|
|
Game()
|
|
.initGame()
|
|
.makeMove({ player: "black", pos: { x: 4, y: 4 } }) // 3 4 5
|
|
.makeMove({ player: "white", pos: { x: 5, y: 4 } }) // 4 1
|
|
.makeMove({ player: "black", pos: { x: 5, y: 5 } }) // 5 1 -1 1
|
|
.makeMove({ player: "white", pos: { x: 16, y: 16 } }) // 6 1
|
|
.makeMove({ player: "black", pos: { x: 5, y: 3 } }) // (9) at {5, 4}
|
|
.makeMove({ player: "white", pos: { x: 16, y: 4 } })
|
|
.makeMove({ player: "black", pos: { x: 6, y: 4 } })
|
|
.makeMove({ player: "white", pos: { x: 4, y: 16 } })
|
|
.makeMove({ player: "black", pos: { x: 5, y: 4 } })
|
|
.success.should.eql(true);
|
|
done();
|
|
});
|
|
|
|
const snapbackGame = () =>
|
|
Game()
|
|
.initGame()
|
|
.makeMove({ player: "black", pos: { x: 4, y: 4 } }) // 3 4 5 6 7
|
|
.makeMove({ player: "white", pos: { x: 5, y: 4 } }) // 4 1 1 -1
|
|
.makeMove({ player: "black", pos: { x: 5, y: 6 } }) // 5 1 -1 -1 1 -1
|
|
.makeMove({ player: "white", pos: { x: 5, y: 7 } }) // 6 1 1 -1
|
|
.makeMove({ player: "black", pos: { x: 4, y: 5 } }) // (13) at {5,6}
|
|
.makeMove({ player: "white", pos: { x: 4, y: 6 } })
|
|
.makeMove({ player: "black", pos: { x: 5, y: 3 } })
|
|
.makeMove({ player: "white", pos: { x: 6, y: 6 } })
|
|
.makeMove({ player: "black", pos: { x: 6, y: 5 } })
|
|
.makeMove({ player: "white", pos: { x: 16, y: 16 } })
|
|
.makeMove({ player: "black", pos: { x: 6, y: 4 } })
|
|
.makeMove({ player: "white", pos: { x: 5, y: 5 } })
|
|
.makeMove({ player: "black", pos: { x: 5, y: 6 } });
|
|
|
|
it("snapback functions properly", (done) => {
|
|
snapbackGame().success.should.eql(true);
|
|
done();
|
|
});
|
|
|
|
const koGame = () =>
|
|
Game()
|
|
.initGame()
|
|
.makeMove({ player: "black", pos: { x: 4, y: 4 } }) // 3 4 5 6
|
|
.makeMove({ player: "white", pos: { x: 4, y: 5 } }) // 4 1 -1
|
|
.makeMove({ player: "black", pos: { x: 5, y: 3 } }) // 5 1 -1 1 -1
|
|
.makeMove({ player: "white", pos: { x: 5, y: 6 } }) // 6 1 -1
|
|
.makeMove({ player: "black", pos: { x: 6, y: 4 } })
|
|
.makeMove({ player: "white", pos: { x: 6, y: 5 } })
|
|
.makeMove({ player: "black", pos: { x: 5, y: 5 } })
|
|
.makeMove({ player: "white", pos: { x: 5, y: 4 } });
|
|
|
|
it("ko recognized properly on Point", (done) => {
|
|
koGame().boardState["5-5"].ko.should.eql(true);
|
|
done();
|
|
});
|
|
|
|
it("ko marked on Game object", (done) => {
|
|
koGame().kos.should.eql(["5-5"]);
|
|
done();
|
|
});
|
|
|
|
it("ko marked in legalMoves", (done) => {
|
|
koGame().legalMoves["5-5"].should.eql("k");
|
|
done();
|
|
});
|
|
|
|
it("ko cleared on Point after move", (done) => {
|
|
koGame()
|
|
.makeMove({ player: "black", pos: { x: 16, y: 16 } })
|
|
.makeMove({ player: "white", pos: { x: 4, y: 16 } })
|
|
.boardState["5-5"].ko.should.eql(false);
|
|
done();
|
|
});
|
|
|
|
it("ko cleared on Game after move", (done) => {
|
|
koGame()
|
|
.makeMove({ player: "black", pos: { x: 16, y: 16 } })
|
|
.makeMove({ player: "white", pos: { x: 4, y: 16 } })
|
|
.kos.should.eql([]);
|
|
done();
|
|
});
|
|
|
|
it("ko cleared on legalMoves after move", (done) => {
|
|
koGame()
|
|
.makeMove({ player: "black", pos: { x: 16, y: 16 } })
|
|
.makeMove({ player: "white", pos: { x: 4, y: 16 } })
|
|
.legalMoves["5-5"].should.eql("l");
|
|
done();
|
|
});
|
|
});
|
|
|
|
describe("Game history functionality", () => {
|
|
const firstMove = {
|
|
player: "black",
|
|
pos: { x: 4, y: 4 },
|
|
id: 1,
|
|
prior: null,
|
|
};
|
|
const secondMove = {
|
|
player: "white",
|
|
pos: { x: 16, y: 16 },
|
|
id: 2,
|
|
prior: 1,
|
|
};
|
|
const thirdMove = { player: "black", pos: { x: 16, y: 4 }, id: 3, prior: 2 };
|
|
const fourthMove = { player: "white", pos: { x: 4, y: 16 }, id: 4, prior: 3 };
|
|
const fifthMove = { player: "black", pos: { x: 10, y: 4 }, id: 5, prior: 4 };
|
|
const sixthMove = { player: "white", pos: { x: 4, y: 10 }, id: 6, prior: 5 };
|
|
const seventhMove = {
|
|
player: "black",
|
|
pos: { x: 10, y: 16 },
|
|
id: 7,
|
|
prior: 6,
|
|
};
|
|
const eighthMove = {
|
|
player: "white",
|
|
pos: { x: 16, y: 10 },
|
|
id: 8,
|
|
prior: 7,
|
|
};
|
|
|
|
it("makeMove creates gameRecord item", (done) => {
|
|
Game().initGame().makeMove(firstMove).gameRecord[0].should.eql(firstMove);
|
|
done();
|
|
});
|
|
|
|
it("makeMove holds history", (done) => {
|
|
const game = Game().initGame().makeMove(firstMove).makeMove(secondMove);
|
|
game.gameRecord[0].should.eql(firstMove);
|
|
game.gameRecord[1].should.eql(secondMove);
|
|
done();
|
|
});
|
|
|
|
const rewoundGame = () =>
|
|
Game()
|
|
.initGame()
|
|
.makeMove(firstMove)
|
|
.makeMove(secondMove)
|
|
.makeMove(thirdMove)
|
|
.returnToMove(-1);
|
|
|
|
it("Game.returnToMove returns new Game with gameRecord", (done) => {
|
|
rewoundGame().gameRecord.should.eql([firstMove, secondMove]);
|
|
done();
|
|
});
|
|
|
|
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();
|
|
});
|
|
|
|
const resetGame = () =>
|
|
[
|
|
firstMove,
|
|
secondMove,
|
|
thirdMove,
|
|
fourthMove,
|
|
fifthMove,
|
|
sixthMove,
|
|
seventhMove,
|
|
eighthMove,
|
|
].reduce((game, move) => game.makeMove(move), Game().initGame());
|
|
|
|
it("Game.returnToMove(0) returns to init board state", (done) => {
|
|
const erasedGame = resetGame().returnToMove(0);
|
|
erasedGame.gameRecord.should.eql([]);
|
|
erasedGame.boardState["4-4"].stone.should.eql(0);
|
|
done();
|
|
});
|
|
|
|
it("Game.returnToMove(5) returns to state after 5th move", (done) => {
|
|
const fifthMoveGame = resetGame().returnToMove(5);
|
|
fifthMoveGame.gameRecord.should.eql([
|
|
firstMove,
|
|
secondMove,
|
|
thirdMove,
|
|
fourthMove,
|
|
fifthMove,
|
|
]);
|
|
fifthMoveGame.boardState["10-4"].stone.should.eql(1);
|
|
fifthMoveGame.boardState["4-10"].stone.should.eql(0);
|
|
done();
|
|
});
|
|
});
|
|
|
|
describe("Game end logic", () => {
|
|
it("resignation results in game end", (done) => {
|
|
Game()
|
|
.initGame()
|
|
.submitResign("black")
|
|
.getMeta()
|
|
.should.eql({ ...initialMeta, winner: -1 });
|
|
done();
|
|
});
|
|
|
|
it("pass changes game turn", (done) => {
|
|
Game().initGame().submitPass("black").getMeta().turn.should.eql(-1);
|
|
done();
|
|
});
|
|
|
|
it("pass adds null move to gameRecord", (done) => {
|
|
Game()
|
|
.initGame()
|
|
.submitPass("black")
|
|
.getMeta()
|
|
.gameRecord.should.eql([{ player: "black", pos: { x: null, y: null } }]);
|
|
done();
|
|
});
|
|
|
|
it("move after makes normal change in game state", (done) => {
|
|
Game()
|
|
.initGame()
|
|
.makeMove({ player: "black", pos: { x: 4, y: 4 } })
|
|
.makeMove({ player: "white", pos: { x: 4, y: 5 } })
|
|
.makeMove({ player: "black", pos: { x: 5, y: 3 } })
|
|
.submitPass("white")
|
|
.makeMove({ player: "black", pos: { x: 16, y: 16 } })
|
|
.legalMoves.should.eql({
|
|
...emptyBoard,
|
|
"4-4": 1,
|
|
"4-5": -1,
|
|
"5-3": 1,
|
|
"16-16": 1,
|
|
});
|
|
done();
|
|
});
|
|
|
|
it("two nonconsecutive passes continue game", (done) => {
|
|
Game()
|
|
.initGame()
|
|
.makeMove({ player: "black", pos: { x: 4, y: 4 }, id: 1, prior: null })
|
|
.makeMove({ player: "white", pos: { x: 4, y: 5 }, id: 2, prior: 1 })
|
|
.makeMove({ player: "black", pos: { x: 5, y: 3 }, id: 3, prior: 2 })
|
|
.submitPass("white")
|
|
.makeMove({ player: "black", pos: { x: 16, y: 16 }, id: 4, prior: 3 })
|
|
.submitPass("white")
|
|
.getMeta()
|
|
.should.eql({
|
|
...initialMeta,
|
|
pass: 1,
|
|
turn: 1,
|
|
gameRecord: [
|
|
{
|
|
player: "black",
|
|
pos: { x: 4, y: 4 },
|
|
id: 1,
|
|
prior: null,
|
|
},
|
|
{
|
|
player: "white",
|
|
pos: { x: 4, y: 5 },
|
|
id: 2,
|
|
prior: 1,
|
|
},
|
|
{
|
|
player: "black",
|
|
pos: { x: 5, y: 3 },
|
|
id: 3,
|
|
prior: 2,
|
|
},
|
|
{
|
|
player: "white",
|
|
pos: { x: null, y: null },
|
|
},
|
|
{
|
|
player: "black",
|
|
pos: { x: 16, y: 16 },
|
|
id: 4,
|
|
prior: 3,
|
|
},
|
|
{
|
|
player: "white",
|
|
pos: { x: null, y: null },
|
|
},
|
|
],
|
|
});
|
|
done();
|
|
});
|
|
|
|
it("consecutive passes end game", (done) => {
|
|
Game()
|
|
.initGame()
|
|
.makeMove({ player: "black", pos: { x: 4, y: 4 } })
|
|
.makeMove({ player: "white", pos: { x: 4, y: 5 } })
|
|
.makeMove({ player: "black", pos: { x: 5, y: 3 } })
|
|
.submitPass("white")
|
|
.submitPass("black")
|
|
.turn.should.eql(0);
|
|
done();
|
|
});
|
|
|
|
const honinboGameRecord = [
|
|
{ player: "black", pos: { x: 4, y: 16 } },
|
|
{ player: "white", pos: { x: 3, y: 4 } },
|
|
{ player: "black", pos: { x: 16, y: 4 } },
|
|
{ player: "white", pos: { x: 17, y: 16 } },
|
|
{ player: "black", pos: { x: 15, y: 17 } },
|
|
{ player: "white", pos: { x: 5, y: 3 } },
|
|
{ player: "black", pos: { x: 17, y: 14 } },
|
|
{ player: "white", pos: { x: 16, y: 15 } },
|
|
{ player: "black", pos: { x: 16, y: 14 } },
|
|
{ player: "white", pos: { x: 14, y: 15 } },
|
|
{ player: "black", pos: { x: 15, y: 14 } },
|
|
{ player: "white", pos: { x: 14, y: 17 } },
|
|
{ player: "black", pos: { x: 14, y: 18 } },
|
|
{ player: "white", pos: { x: 13, y: 17 } },
|
|
{ player: "black", pos: { x: 16, y: 17 } },
|
|
{ player: "white", pos: { x: 15, y: 15 } },
|
|
{ player: "black", pos: { x: 13, y: 18 } },
|
|
{ player: "white", pos: { x: 11, y: 17 } },
|
|
{ player: "black", pos: { x: 17, y: 17 } },
|
|
{ player: "white", pos: { x: 18, y: 16 } },
|
|
{ player: "black", pos: { x: 12, y: 17 } },
|
|
{ player: "white", pos: { x: 12, y: 16 } },
|
|
{ player: "black", pos: { x: 12, y: 18 } },
|
|
{ player: "white", pos: { x: 16, y: 10 } },
|
|
{ player: "black", pos: { x: 17, y: 7 } },
|
|
{ player: "white", pos: { x: 13, y: 13 } },
|
|
{ player: "black", pos: { x: 15, y: 11 } },
|
|
{ player: "white", pos: { x: 11, y: 16 } },
|
|
{ player: "black", pos: { x: 15, y: 10 } },
|
|
{ player: "white", pos: { x: 16, y: 8 } },
|
|
{ player: "black", pos: { x: 17, y: 8 } },
|
|
{ player: "white", pos: { x: 15, y: 9 } },
|
|
{ player: "black", pos: { x: 17, y: 9 } },
|
|
{ player: "white", pos: { x: 16, y: 9 } },
|
|
{ player: "black", pos: { x: 13, y: 10 } },
|
|
{ player: "white", pos: { x: 16, y: 7 } },
|
|
{ player: "black", pos: { x: 16, y: 6 } },
|
|
{ player: "white", pos: { x: 15, y: 6 } },
|
|
{ player: "black", pos: { x: 16, y: 5 } },
|
|
{ player: "white", pos: { x: 13, y: 7 } },
|
|
{ player: "black", pos: { x: 11, y: 10 } },
|
|
{ player: "white", pos: { x: 13, y: 4 } },
|
|
{ player: "black", pos: { x: 3, y: 9 } },
|
|
{ player: "white", pos: { x: 10, y: 8 } },
|
|
{ player: "black", pos: { x: 9, y: 10 } },
|
|
{ player: "white", pos: { x: 7, y: 16 } },
|
|
{ player: "black", pos: { x: 4, y: 14 } },
|
|
{ player: "white", pos: { x: 8, y: 9 } },
|
|
{ player: "black", pos: { x: 8, y: 14 } },
|
|
{ player: "white", pos: { x: 8, y: 10 } },
|
|
{ player: "black", pos: { x: 9, y: 11 } },
|
|
{ player: "white", pos: { x: 8, y: 11 } },
|
|
{ player: "black", pos: { x: 10, y: 14 } },
|
|
{ player: "white", pos: { x: 9, y: 15 } },
|
|
{ player: "black", pos: { x: 12, y: 14 } },
|
|
{ player: "white", pos: { x: 11, y: 13 } },
|
|
{ player: "black", pos: { x: 12, y: 13 } },
|
|
{ player: "white", pos: { x: 12, y: 12 } },
|
|
{ player: "black", pos: { x: 13, y: 14 } },
|
|
{ player: "white", pos: { x: 14, y: 14 } },
|
|
{ player: "black", pos: { x: 11, y: 14 } },
|
|
{ player: "white", pos: { x: 14, y: 13 } },
|
|
{ player: "black", pos: { x: 14, y: 9 } },
|
|
{ player: "white", pos: { x: 12, y: 9 } },
|
|
{ player: "black", pos: { x: 12, y: 10 } },
|
|
{ player: "white", pos: { x: 16, y: 12 } },
|
|
{ player: "black", pos: { x: 16, y: 11 } },
|
|
{ player: "white", pos: { x: 17, y: 12 } },
|
|
{ player: "black", pos: { x: 18, y: 11 } },
|
|
{ player: "white", pos: { x: 18, y: 12 } },
|
|
{ player: "black", pos: { x: 15, y: 12 } },
|
|
{ player: "white", pos: { x: 15, y: 13 } },
|
|
{ player: "black", pos: { x: 17, y: 11 } },
|
|
{ player: "white", pos: { x: 15, y: 3 } },
|
|
{ player: "black", pos: { x: 16, y: 3 } },
|
|
{ player: "white", pos: { x: 16, y: 2 } },
|
|
{ player: "black", pos: { x: 17, y: 2 } },
|
|
{ player: "white", pos: { x: 3, y: 7 } },
|
|
{ player: "black", pos: { x: 5, y: 9 } },
|
|
{ player: "white", pos: { x: 8, y: 4 } },
|
|
{ player: "black", pos: { x: 5, y: 11 } },
|
|
{ player: "white", pos: { x: 4, y: 17 } },
|
|
{ player: "black", pos: { x: 3, y: 17 } },
|
|
{ player: "white", pos: { x: 5, y: 17 } },
|
|
{ player: "black", pos: { x: 3, y: 18 } },
|
|
{ player: "white", pos: { x: 5, y: 16 } },
|
|
{ player: "black", pos: { x: 4, y: 15 } },
|
|
{ player: "white", pos: { x: 15, y: 2 } },
|
|
{ player: "black", pos: { x: 4, y: 3 } },
|
|
{ player: "white", pos: { x: 4, y: 4 } },
|
|
{ player: "black", pos: { x: 10, y: 4 } },
|
|
{ player: "white", pos: { x: 8, y: 3 } },
|
|
{ player: "black", pos: { x: 12, y: 7 } },
|
|
{ player: "white", pos: { x: 13, y: 6 } },
|
|
{ player: "black", pos: { x: 5, y: 2 } },
|
|
{ player: "white", pos: { x: 4, y: 2 } },
|
|
{ player: "black", pos: { x: 10, y: 7 } },
|
|
{ player: "white", pos: { x: 9, y: 7 } },
|
|
{ player: "black", pos: { x: 10, y: 6 } },
|
|
{ player: "white", pos: { x: 12, y: 8 } },
|
|
{ player: "black", pos: { x: 9, y: 8 } },
|
|
{ player: "white", pos: { x: 10, y: 9 } },
|
|
{ player: "black", pos: { x: 8, y: 5 } },
|
|
{ player: "white", pos: { x: 9, y: 9 } },
|
|
{ player: "black", pos: { x: 6, y: 3 } },
|
|
{ player: "white", pos: { x: 5, y: 4 } },
|
|
{ player: "black", pos: { x: 7, y: 5 } },
|
|
{ player: "white", pos: { x: 6, y: 4 } },
|
|
{ player: "black", pos: { x: 12, y: 4 } },
|
|
{ player: "white", pos: { x: 11, y: 3 } },
|
|
{ player: "black", pos: { x: 12, y: 3 } },
|
|
{ player: "white", pos: { x: 10, y: 3 } },
|
|
{ player: "black", pos: { x: 14, y: 4 } },
|
|
{ player: "white", pos: { x: 15, y: 4 } },
|
|
{ player: "black", pos: { x: 13, y: 5 } },
|
|
{ player: "white", pos: { x: 15, y: 5 } },
|
|
{ player: "black", pos: { x: 9, y: 4 } },
|
|
{ player: "white", pos: { x: 9, y: 3 } },
|
|
{ player: "black", pos: { x: 7, y: 7 } },
|
|
{ player: "white", pos: { x: 12, y: 6 } },
|
|
{ player: "black", pos: { x: 11, y: 4 } },
|
|
{ player: "white", pos: { x: 8, y: 8 } },
|
|
{ player: "black", pos: { x: 6, y: 8 } },
|
|
{ player: "white", pos: { x: 2, y: 8 } },
|
|
{ player: "black", pos: { x: 2, y: 9 } },
|
|
{ player: "white", pos: { x: 9, y: 12 } },
|
|
{ player: "black", pos: { x: 10, y: 12 } },
|
|
{ player: "white", pos: { x: 10, y: 10 } },
|
|
{ player: "black", pos: { x: 10, y: 11 } },
|
|
{ player: "white", pos: { x: 9, y: 13 } },
|
|
{ player: "black", pos: { x: 9, y: 14 } },
|
|
{ player: "white", pos: { x: 10, y: 13 } },
|
|
{ player: "black", pos: { x: 11, y: 11 } },
|
|
{ player: "white", pos: { x: 7, y: 13 } },
|
|
{ player: "black", pos: { x: 7, y: 14 } },
|
|
{ player: "white", pos: { x: 6, y: 13 } },
|
|
{ player: "black", pos: { x: 6, y: 14 } },
|
|
{ player: "white", pos: { x: 5, y: 13 } },
|
|
{ player: "black", pos: { x: 8, y: 13 } },
|
|
{ player: "white", pos: { x: 8, y: 12 } },
|
|
{ player: "black", pos: { x: 6, y: 11 } },
|
|
{ player: "white", pos: { x: 7, y: 11 } },
|
|
{ player: "black", pos: { x: 6, y: 15 } },
|
|
{ player: "white", pos: { x: 14, y: 8 } },
|
|
{ player: "black", pos: { x: 19, y: 12 } },
|
|
{ player: "white", pos: { x: 19, y: 13 } },
|
|
{ player: "black", pos: { x: 18, y: 13 } },
|
|
{ player: "white", pos: { x: 19, y: 11 } },
|
|
{ player: "black", pos: { x: 19, y: 14 } },
|
|
{ player: "white", pos: { x: 16, y: 13 } },
|
|
{ player: "black", pos: { x: 19, y: 12 } },
|
|
{ player: "white", pos: { x: 13, y: 15 } },
|
|
{ player: "black", pos: { x: 11, y: 18 } },
|
|
{ player: "white", pos: { x: 10, y: 18 } },
|
|
{ player: "black", pos: { x: 19, y: 10 } },
|
|
{ player: "white", pos: { x: 8, y: 18 } },
|
|
{ player: "black", pos: { x: 5, y: 19 } },
|
|
{ player: "white", pos: { x: 13, y: 9 } },
|
|
{ player: "black", pos: { x: 14, y: 10 } },
|
|
{ player: "white", pos: { x: 18, y: 18 } },
|
|
{ player: "black", pos: { x: 18, y: 17 } },
|
|
{ player: "white", pos: { x: 19, y: 17 } },
|
|
{ player: "black", pos: { x: 17, y: 18 } },
|
|
{ player: "white", pos: { x: 8, y: 15 } },
|
|
{ player: "black", pos: { x: 4, y: 13 } },
|
|
{ player: "white", pos: { x: 17, y: 1 } },
|
|
{ player: "black", pos: { x: 18, y: 2 } },
|
|
{ player: "white", pos: { x: 1, y: 9 } },
|
|
{ player: "black", pos: { x: 1, y: 10 } },
|
|
{ player: "white", pos: { x: 1, y: 8 } },
|
|
{ player: "black", pos: { x: 2, y: 10 } },
|
|
{ player: "white", pos: { x: 9, y: 6 } },
|
|
{ player: "black", pos: { x: 9, y: 5 } },
|
|
{ player: "white", pos: { x: 6, y: 6 } },
|
|
{ player: "black", pos: { x: 8, y: 7 } },
|
|
{ player: "white", pos: { x: 5, y: 7 } },
|
|
{ player: "black", pos: { x: 6, y: 18 } },
|
|
{ player: "white", pos: { x: 7, y: 18 } },
|
|
{ player: "black", pos: { x: 10, y: 19 } },
|
|
{ player: "white", pos: { x: 9, y: 19 } },
|
|
{ player: "black", pos: { x: 9, y: 17 } },
|
|
{ player: "white", pos: { x: 11, y: 19 } },
|
|
{ player: "black", pos: { x: 19, y: 18 } },
|
|
{ player: "white", pos: { x: 4, y: 19 } },
|
|
{ player: "black", pos: { x: 4, y: 18 } },
|
|
{ player: "white", pos: { x: 5, y: 18 } },
|
|
{ player: "black", pos: { x: 3, y: 19 } },
|
|
{ player: "white", pos: { x: 6, y: 17 } },
|
|
{ player: "black", pos: { x: 19, y: 16 } },
|
|
{ player: "white", pos: { x: 11, y: 2 } },
|
|
{ player: "black", pos: { x: 12, y: 2 } },
|
|
{ player: "white", pos: { x: 14, y: 5 } },
|
|
{ player: "black", pos: { x: 13, y: 3 } },
|
|
{ player: "white", pos: { x: 6, y: 10 } },
|
|
{ player: "black", pos: { x: 3, y: 8 } },
|
|
{ player: "white", pos: { x: 2, y: 7 } },
|
|
{ player: "black", pos: { x: 5, y: 10 } },
|
|
{ player: "white", pos: { x: 18, y: 15 } },
|
|
{ player: "black", pos: { x: 19, y: 15 } },
|
|
{ player: "white", pos: { x: 6, y: 19 } },
|
|
{ player: "black", pos: { x: 12, y: 19 } },
|
|
{ player: "white", pos: { x: 18, y: 1 } },
|
|
{ player: "black", pos: { x: 10, y: 19 } },
|
|
{ player: "white", pos: { x: 9, y: 18 } },
|
|
{ player: "black", pos: { x: 10, y: 15 } },
|
|
{ player: "white", pos: { x: 10, y: 16 } },
|
|
{ player: "black", pos: { x: 19, y: 2 } },
|
|
{ player: "white", pos: { x: 18, y: 14 } },
|
|
{ player: "black", pos: { x: 17, y: 13 } },
|
|
{ player: "white", pos: { x: 6, y: 9 } },
|
|
{ player: "black", pos: { x: 7, y: 9 } },
|
|
{ player: "white", pos: { x: 7, y: 10 } },
|
|
{ player: "black", pos: { x: 5, y: 8 } },
|
|
{ player: "white", pos: { x: 7, y: 8 } },
|
|
{ player: "black", pos: { x: 6, y: 7 } },
|
|
{ player: "white", pos: { x: 4, y: 7 } },
|
|
{ player: "black", pos: { x: 6, y: 5 } },
|
|
{ player: "white", pos: { x: 5, y: 5 } },
|
|
{ player: "black", pos: { x: 7, y: 4 } },
|
|
{ player: "white", pos: { x: 7, y: 3 } },
|
|
{ player: "black", pos: { x: 11, y: 7 } },
|
|
{ player: "white", pos: { x: 4, y: 8 } },
|
|
{ player: "black", pos: { x: 4, y: 9 } },
|
|
{ player: "white", pos: { x: 5, y: 12 } },
|
|
{ player: "black", pos: { x: 4, y: 12 } },
|
|
{ player: "white", pos: { x: 17, y: 10 } },
|
|
{ player: "black", pos: { x: 18, y: 10 } },
|
|
{ player: "white", pos: { x: 15, y: 16 } },
|
|
{ player: "black", pos: { x: 12, y: 5 } },
|
|
{ player: "white", pos: { x: 11, y: 6 } },
|
|
{ player: "black", pos: { x: 14, y: 2 } },
|
|
{ player: "white", pos: { x: 14, y: 3 } },
|
|
{ player: "black", pos: { x: 11, y: 1 } },
|
|
{ player: "white", pos: { x: 10, y: 1 } },
|
|
{ player: "black", pos: { x: 12, y: 1 } },
|
|
{ player: "white", pos: { x: 17, y: 15 } },
|
|
{ player: "black", pos: { x: 19, y: 13 } },
|
|
{ player: "white", pos: { x: 17, y: 3 } },
|
|
{ player: "black", pos: { x: 18, y: 3 } },
|
|
{ player: "white", pos: { x: 11, y: 8 } },
|
|
{ player: "black", pos: { x: 10, y: 5 } },
|
|
{ player: "white", pos: { x: 14, y: 1 } },
|
|
{ player: "black", pos: { x: 13, y: 1 } },
|
|
{ player: "white", pos: { x: 13, y: 12 } },
|
|
{ player: "black", pos: { x: 15, y: 1 } },
|
|
{ player: "white", pos: { x: 16, y: 1 } },
|
|
{ player: "black", pos: { x: 14, y: 1 } },
|
|
{ player: "white", pos: { x: 4, y: 19 } },
|
|
{ player: "black", pos: { x: 13, y: 4 } },
|
|
{ player: "white", pos: { x: 5, y: 19 } },
|
|
{ player: "black", pos: { x: 11, y: 19 } },
|
|
];
|
|
const honinboGame = Game({
|
|
gameData: { komi: 1.5 },
|
|
gameRecord: honinboGameRecord,
|
|
})
|
|
.submitPass("white")
|
|
.submitPass("black");
|
|
|
|
it("end game returns board state with empty points in groups", (done) => {
|
|
honinboGame.boardState["1-1"].group.should.not.eql(null);
|
|
const group = honinboGame.boardState["19-5"].group;
|
|
// console.log(honinboGame.groups[group]);
|
|
honinboGame.boardState["17-4"].group.should.eql(group);
|
|
done();
|
|
});
|
|
|
|
const isWhite = (x) => x < 0;
|
|
const isBlack = (x) => x > 0;
|
|
const territories = [
|
|
["4-2", isWhite],
|
|
["4-3", isWhite],
|
|
["5-2", isWhite],
|
|
["6-3", isWhite],
|
|
["17-3", isBlack],
|
|
["9-17", isWhite],
|
|
["18-18", isBlack],
|
|
["19-18", isBlack],
|
|
];
|
|
territories.forEach(([point, territoryPredicate]) => {
|
|
it(`end game return board state with ${point} marked with appropriate territory`, (done) => {
|
|
territoryPredicate(honinboGame.boardState[point].territory).should.eql(
|
|
true
|
|
);
|
|
done();
|
|
});
|
|
});
|
|
|
|
it("end game toggleTerritory switches through territory values", (done) => {
|
|
const game = honinboGame;
|
|
const territory = game.toggleTerritory("5-14").toggleTerritory("5-14")
|
|
.territory;
|
|
territory["5-14"].should.eql("d");
|
|
territory["5-15"].should.eql("d");
|
|
done();
|
|
});
|
|
|
|
it("end game counts territory properly", (done) => {
|
|
const game = honinboGame
|
|
.toggleTerritory("6-12")
|
|
.toggleTerritory("6-16")
|
|
.toggleTerritory("7-6")
|
|
.toggleTerritory("7-6")
|
|
.toggleTerritory("11-5")
|
|
.toggleTerritory("11-5")
|
|
.toggleTerritory("11-9")
|
|
.toggleTerritory("12-11")
|
|
.toggleTerritory("12-11")
|
|
.toggleTerritory("16-16")
|
|
.endGame();
|
|
game.score.should.eql(1.5);
|
|
game.winner.should.eql(1);
|
|
done();
|
|
});
|
|
});
|
|
|
|
const initialMeta = {
|
|
winner: null,
|
|
turn: 0,
|
|
pass: 0,
|
|
komi: 6.5,
|
|
handicap: 0,
|
|
boardSize: 19,
|
|
playerState: {
|
|
bCaptures: 0,
|
|
wCaptures: 0,
|
|
bScore: 0,
|
|
wScore: 0,
|
|
},
|
|
gameRecord: [],
|
|
score: 0,
|
|
};
|
|
|
|
const emptyBoard9 = {
|
|
"1-1": "l",
|
|
"1-2": "l",
|
|
"1-3": "l",
|
|
"1-4": "l",
|
|
"1-5": "l",
|
|
"1-6": "l",
|
|
"1-7": "l",
|
|
"1-8": "l",
|
|
"1-9": "l",
|
|
"2-1": "l",
|
|
"2-2": "l",
|
|
"2-3": "l",
|
|
"2-4": "l",
|
|
"2-5": "l",
|
|
"2-6": "l",
|
|
"2-7": "l",
|
|
"2-8": "l",
|
|
"2-9": "l",
|
|
"3-1": "l",
|
|
"3-2": "l",
|
|
"3-3": "l",
|
|
"3-4": "l",
|
|
"3-5": "l",
|
|
"3-6": "l",
|
|
"3-7": "l",
|
|
"3-8": "l",
|
|
"3-9": "l",
|
|
"4-1": "l",
|
|
"4-2": "l",
|
|
"4-3": "l",
|
|
"4-4": "l",
|
|
"4-5": "l",
|
|
"4-6": "l",
|
|
"4-7": "l",
|
|
"4-8": "l",
|
|
"4-9": "l",
|
|
"5-1": "l",
|
|
"5-2": "l",
|
|
"5-3": "l",
|
|
"5-4": "l",
|
|
"5-5": "l",
|
|
"5-6": "l",
|
|
"5-7": "l",
|
|
"5-8": "l",
|
|
"5-9": "l",
|
|
"6-1": "l",
|
|
"6-2": "l",
|
|
"6-3": "l",
|
|
"6-4": "l",
|
|
"6-5": "l",
|
|
"6-6": "l",
|
|
"6-7": "l",
|
|
"6-8": "l",
|
|
"6-9": "l",
|
|
"7-1": "l",
|
|
"7-2": "l",
|
|
"7-3": "l",
|
|
"7-4": "l",
|
|
"7-5": "l",
|
|
"7-6": "l",
|
|
"7-7": "l",
|
|
"7-8": "l",
|
|
"7-9": "l",
|
|
"8-1": "l",
|
|
"8-2": "l",
|
|
"8-3": "l",
|
|
"8-4": "l",
|
|
"8-5": "l",
|
|
"8-6": "l",
|
|
"8-7": "l",
|
|
"8-8": "l",
|
|
"8-9": "l",
|
|
"9-1": "l",
|
|
"9-2": "l",
|
|
"9-3": "l",
|
|
"9-4": "l",
|
|
"9-5": "l",
|
|
"9-6": "l",
|
|
"9-7": "l",
|
|
"9-8": "l",
|
|
"9-9": "l",
|
|
};
|
|
|
|
const emptyBoard13 = {
|
|
"1-1": "l",
|
|
"1-2": "l",
|
|
"1-3": "l",
|
|
"1-4": "l",
|
|
"1-5": "l",
|
|
"1-6": "l",
|
|
"1-7": "l",
|
|
"1-8": "l",
|
|
"1-9": "l",
|
|
"1-10": "l",
|
|
"1-11": "l",
|
|
"1-12": "l",
|
|
"1-13": "l",
|
|
"2-1": "l",
|
|
"2-2": "l",
|
|
"2-3": "l",
|
|
"2-4": "l",
|
|
"2-5": "l",
|
|
"2-6": "l",
|
|
"2-7": "l",
|
|
"2-8": "l",
|
|
"2-9": "l",
|
|
"2-10": "l",
|
|
"2-11": "l",
|
|
"2-12": "l",
|
|
"2-13": "l",
|
|
"3-1": "l",
|
|
"3-2": "l",
|
|
"3-3": "l",
|
|
"3-4": "l",
|
|
"3-5": "l",
|
|
"3-6": "l",
|
|
"3-7": "l",
|
|
"3-8": "l",
|
|
"3-9": "l",
|
|
"3-10": "l",
|
|
"3-11": "l",
|
|
"3-12": "l",
|
|
"3-13": "l",
|
|
"4-1": "l",
|
|
"4-2": "l",
|
|
"4-3": "l",
|
|
"4-4": "l",
|
|
"4-5": "l",
|
|
"4-6": "l",
|
|
"4-7": "l",
|
|
"4-8": "l",
|
|
"4-9": "l",
|
|
"4-10": "l",
|
|
"4-11": "l",
|
|
"4-12": "l",
|
|
"4-13": "l",
|
|
"5-1": "l",
|
|
"5-2": "l",
|
|
"5-3": "l",
|
|
"5-4": "l",
|
|
"5-5": "l",
|
|
"5-6": "l",
|
|
"5-7": "l",
|
|
"5-8": "l",
|
|
"5-9": "l",
|
|
"5-10": "l",
|
|
"5-11": "l",
|
|
"5-12": "l",
|
|
"5-13": "l",
|
|
"6-1": "l",
|
|
"6-2": "l",
|
|
"6-3": "l",
|
|
"6-4": "l",
|
|
"6-5": "l",
|
|
"6-6": "l",
|
|
"6-7": "l",
|
|
"6-8": "l",
|
|
"6-9": "l",
|
|
"6-10": "l",
|
|
"6-11": "l",
|
|
"6-12": "l",
|
|
"6-13": "l",
|
|
"7-1": "l",
|
|
"7-2": "l",
|
|
"7-3": "l",
|
|
"7-4": "l",
|
|
"7-5": "l",
|
|
"7-6": "l",
|
|
"7-7": "l",
|
|
"7-8": "l",
|
|
"7-9": "l",
|
|
"7-10": "l",
|
|
"7-11": "l",
|
|
"7-12": "l",
|
|
"7-13": "l",
|
|
"8-1": "l",
|
|
"8-2": "l",
|
|
"8-3": "l",
|
|
"8-4": "l",
|
|
"8-5": "l",
|
|
"8-6": "l",
|
|
"8-7": "l",
|
|
"8-8": "l",
|
|
"8-9": "l",
|
|
"8-10": "l",
|
|
"8-11": "l",
|
|
"8-12": "l",
|
|
"8-13": "l",
|
|
"9-1": "l",
|
|
"9-2": "l",
|
|
"9-3": "l",
|
|
"9-4": "l",
|
|
"9-5": "l",
|
|
"9-6": "l",
|
|
"9-7": "l",
|
|
"9-8": "l",
|
|
"9-9": "l",
|
|
"9-10": "l",
|
|
"9-11": "l",
|
|
"9-12": "l",
|
|
"9-13": "l",
|
|
"10-1": "l",
|
|
"10-2": "l",
|
|
"10-3": "l",
|
|
"10-4": "l",
|
|
"10-5": "l",
|
|
"10-6": "l",
|
|
"10-7": "l",
|
|
"10-8": "l",
|
|
"10-9": "l",
|
|
"10-10": "l",
|
|
"10-11": "l",
|
|
"10-12": "l",
|
|
"10-13": "l",
|
|
"11-1": "l",
|
|
"11-2": "l",
|
|
"11-3": "l",
|
|
"11-4": "l",
|
|
"11-5": "l",
|
|
"11-6": "l",
|
|
"11-7": "l",
|
|
"11-8": "l",
|
|
"11-9": "l",
|
|
"11-10": "l",
|
|
"11-11": "l",
|
|
"11-12": "l",
|
|
"11-13": "l",
|
|
"12-1": "l",
|
|
"12-2": "l",
|
|
"12-3": "l",
|
|
"12-4": "l",
|
|
"12-5": "l",
|
|
"12-6": "l",
|
|
"12-7": "l",
|
|
"12-8": "l",
|
|
"12-9": "l",
|
|
"12-10": "l",
|
|
"12-11": "l",
|
|
"12-12": "l",
|
|
"12-13": "l",
|
|
"13-1": "l",
|
|
"13-2": "l",
|
|
"13-3": "l",
|
|
"13-4": "l",
|
|
"13-5": "l",
|
|
"13-6": "l",
|
|
"13-7": "l",
|
|
"13-8": "l",
|
|
"13-9": "l",
|
|
"13-10": "l",
|
|
"13-11": "l",
|
|
"13-12": "l",
|
|
"13-13": "l",
|
|
};
|
|
|
|
const emptyBoard = {
|
|
"1-1": "l",
|
|
"1-2": "l",
|
|
"1-3": "l",
|
|
"1-4": "l",
|
|
"1-5": "l",
|
|
"1-6": "l",
|
|
"1-7": "l",
|
|
"1-8": "l",
|
|
"1-9": "l",
|
|
"1-10": "l",
|
|
"1-11": "l",
|
|
"1-12": "l",
|
|
"1-13": "l",
|
|
"1-14": "l",
|
|
"1-15": "l",
|
|
"1-16": "l",
|
|
"1-17": "l",
|
|
"1-18": "l",
|
|
"1-19": "l",
|
|
"2-1": "l",
|
|
"2-2": "l",
|
|
"2-3": "l",
|
|
"2-4": "l",
|
|
"2-5": "l",
|
|
"2-6": "l",
|
|
"2-7": "l",
|
|
"2-8": "l",
|
|
"2-9": "l",
|
|
"2-10": "l",
|
|
"2-11": "l",
|
|
"2-12": "l",
|
|
"2-13": "l",
|
|
"2-14": "l",
|
|
"2-15": "l",
|
|
"2-16": "l",
|
|
"2-17": "l",
|
|
"2-18": "l",
|
|
"2-19": "l",
|
|
"3-1": "l",
|
|
"3-2": "l",
|
|
"3-3": "l",
|
|
"3-4": "l",
|
|
"3-5": "l",
|
|
"3-6": "l",
|
|
"3-7": "l",
|
|
"3-8": "l",
|
|
"3-9": "l",
|
|
"3-10": "l",
|
|
"3-11": "l",
|
|
"3-12": "l",
|
|
"3-13": "l",
|
|
"3-14": "l",
|
|
"3-15": "l",
|
|
"3-16": "l",
|
|
"3-17": "l",
|
|
"3-18": "l",
|
|
"3-19": "l",
|
|
"4-1": "l",
|
|
"4-2": "l",
|
|
"4-3": "l",
|
|
"4-4": "l",
|
|
"4-5": "l",
|
|
"4-6": "l",
|
|
"4-7": "l",
|
|
"4-8": "l",
|
|
"4-9": "l",
|
|
"4-10": "l",
|
|
"4-11": "l",
|
|
"4-12": "l",
|
|
"4-13": "l",
|
|
"4-14": "l",
|
|
"4-15": "l",
|
|
"4-16": "l",
|
|
"4-17": "l",
|
|
"4-18": "l",
|
|
"4-19": "l",
|
|
"5-1": "l",
|
|
"5-2": "l",
|
|
"5-3": "l",
|
|
"5-4": "l",
|
|
"5-5": "l",
|
|
"5-6": "l",
|
|
"5-7": "l",
|
|
"5-8": "l",
|
|
"5-9": "l",
|
|
"5-10": "l",
|
|
"5-11": "l",
|
|
"5-12": "l",
|
|
"5-13": "l",
|
|
"5-14": "l",
|
|
"5-15": "l",
|
|
"5-16": "l",
|
|
"5-17": "l",
|
|
"5-18": "l",
|
|
"5-19": "l",
|
|
"6-1": "l",
|
|
"6-2": "l",
|
|
"6-3": "l",
|
|
"6-4": "l",
|
|
"6-5": "l",
|
|
"6-6": "l",
|
|
"6-7": "l",
|
|
"6-8": "l",
|
|
"6-9": "l",
|
|
"6-10": "l",
|
|
"6-11": "l",
|
|
"6-12": "l",
|
|
"6-13": "l",
|
|
"6-14": "l",
|
|
"6-15": "l",
|
|
"6-16": "l",
|
|
"6-17": "l",
|
|
"6-18": "l",
|
|
"6-19": "l",
|
|
"7-1": "l",
|
|
"7-2": "l",
|
|
"7-3": "l",
|
|
"7-4": "l",
|
|
"7-5": "l",
|
|
"7-6": "l",
|
|
"7-7": "l",
|
|
"7-8": "l",
|
|
"7-9": "l",
|
|
"7-10": "l",
|
|
"7-11": "l",
|
|
"7-12": "l",
|
|
"7-13": "l",
|
|
"7-14": "l",
|
|
"7-15": "l",
|
|
"7-16": "l",
|
|
"7-17": "l",
|
|
"7-18": "l",
|
|
"7-19": "l",
|
|
"8-1": "l",
|
|
"8-2": "l",
|
|
"8-3": "l",
|
|
"8-4": "l",
|
|
"8-5": "l",
|
|
"8-6": "l",
|
|
"8-7": "l",
|
|
"8-8": "l",
|
|
"8-9": "l",
|
|
"8-10": "l",
|
|
"8-11": "l",
|
|
"8-12": "l",
|
|
"8-13": "l",
|
|
"8-14": "l",
|
|
"8-15": "l",
|
|
"8-16": "l",
|
|
"8-17": "l",
|
|
"8-18": "l",
|
|
"8-19": "l",
|
|
"9-1": "l",
|
|
"9-2": "l",
|
|
"9-3": "l",
|
|
"9-4": "l",
|
|
"9-5": "l",
|
|
"9-6": "l",
|
|
"9-7": "l",
|
|
"9-8": "l",
|
|
"9-9": "l",
|
|
"9-10": "l",
|
|
"9-11": "l",
|
|
"9-12": "l",
|
|
"9-13": "l",
|
|
"9-14": "l",
|
|
"9-15": "l",
|
|
"9-16": "l",
|
|
"9-17": "l",
|
|
"9-18": "l",
|
|
"9-19": "l",
|
|
"10-1": "l",
|
|
"10-2": "l",
|
|
"10-3": "l",
|
|
"10-4": "l",
|
|
"10-5": "l",
|
|
"10-6": "l",
|
|
"10-7": "l",
|
|
"10-8": "l",
|
|
"10-9": "l",
|
|
"10-10": "l",
|
|
"10-11": "l",
|
|
"10-12": "l",
|
|
"10-13": "l",
|
|
"10-14": "l",
|
|
"10-15": "l",
|
|
"10-16": "l",
|
|
"10-17": "l",
|
|
"10-18": "l",
|
|
"10-19": "l",
|
|
"11-1": "l",
|
|
"11-2": "l",
|
|
"11-3": "l",
|
|
"11-4": "l",
|
|
"11-5": "l",
|
|
"11-6": "l",
|
|
"11-7": "l",
|
|
"11-8": "l",
|
|
"11-9": "l",
|
|
"11-10": "l",
|
|
"11-11": "l",
|
|
"11-12": "l",
|
|
"11-13": "l",
|
|
"11-14": "l",
|
|
"11-15": "l",
|
|
"11-16": "l",
|
|
"11-17": "l",
|
|
"11-18": "l",
|
|
"11-19": "l",
|
|
"12-1": "l",
|
|
"12-2": "l",
|
|
"12-3": "l",
|
|
"12-4": "l",
|
|
"12-5": "l",
|
|
"12-6": "l",
|
|
"12-7": "l",
|
|
"12-8": "l",
|
|
"12-9": "l",
|
|
"12-10": "l",
|
|
"12-11": "l",
|
|
"12-12": "l",
|
|
"12-13": "l",
|
|
"12-14": "l",
|
|
"12-15": "l",
|
|
"12-16": "l",
|
|
"12-17": "l",
|
|
"12-18": "l",
|
|
"12-19": "l",
|
|
"13-1": "l",
|
|
"13-2": "l",
|
|
"13-3": "l",
|
|
"13-4": "l",
|
|
"13-5": "l",
|
|
"13-6": "l",
|
|
"13-7": "l",
|
|
"13-8": "l",
|
|
"13-9": "l",
|
|
"13-10": "l",
|
|
"13-11": "l",
|
|
"13-12": "l",
|
|
"13-13": "l",
|
|
"13-14": "l",
|
|
"13-15": "l",
|
|
"13-16": "l",
|
|
"13-17": "l",
|
|
"13-18": "l",
|
|
"13-19": "l",
|
|
"14-1": "l",
|
|
"14-2": "l",
|
|
"14-3": "l",
|
|
"14-4": "l",
|
|
"14-5": "l",
|
|
"14-6": "l",
|
|
"14-7": "l",
|
|
"14-8": "l",
|
|
"14-9": "l",
|
|
"14-10": "l",
|
|
"14-11": "l",
|
|
"14-12": "l",
|
|
"14-13": "l",
|
|
"14-14": "l",
|
|
"14-15": "l",
|
|
"14-16": "l",
|
|
"14-17": "l",
|
|
"14-18": "l",
|
|
"14-19": "l",
|
|
"15-1": "l",
|
|
"15-2": "l",
|
|
"15-3": "l",
|
|
"15-4": "l",
|
|
"15-5": "l",
|
|
"15-6": "l",
|
|
"15-7": "l",
|
|
"15-8": "l",
|
|
"15-9": "l",
|
|
"15-10": "l",
|
|
"15-11": "l",
|
|
"15-12": "l",
|
|
"15-13": "l",
|
|
"15-14": "l",
|
|
"15-15": "l",
|
|
"15-16": "l",
|
|
"15-17": "l",
|
|
"15-18": "l",
|
|
"15-19": "l",
|
|
"16-1": "l",
|
|
"16-2": "l",
|
|
"16-3": "l",
|
|
"16-4": "l",
|
|
"16-5": "l",
|
|
"16-6": "l",
|
|
"16-7": "l",
|
|
"16-8": "l",
|
|
"16-9": "l",
|
|
"16-10": "l",
|
|
"16-11": "l",
|
|
"16-12": "l",
|
|
"16-13": "l",
|
|
"16-14": "l",
|
|
"16-15": "l",
|
|
"16-16": "l",
|
|
"16-17": "l",
|
|
"16-18": "l",
|
|
"16-19": "l",
|
|
"17-1": "l",
|
|
"17-2": "l",
|
|
"17-3": "l",
|
|
"17-4": "l",
|
|
"17-5": "l",
|
|
"17-6": "l",
|
|
"17-7": "l",
|
|
"17-8": "l",
|
|
"17-9": "l",
|
|
"17-10": "l",
|
|
"17-11": "l",
|
|
"17-12": "l",
|
|
"17-13": "l",
|
|
"17-14": "l",
|
|
"17-15": "l",
|
|
"17-16": "l",
|
|
"17-17": "l",
|
|
"17-18": "l",
|
|
"17-19": "l",
|
|
"18-1": "l",
|
|
"18-2": "l",
|
|
"18-3": "l",
|
|
"18-4": "l",
|
|
"18-5": "l",
|
|
"18-6": "l",
|
|
"18-7": "l",
|
|
"18-8": "l",
|
|
"18-9": "l",
|
|
"18-10": "l",
|
|
"18-11": "l",
|
|
"18-12": "l",
|
|
"18-13": "l",
|
|
"18-14": "l",
|
|
"18-15": "l",
|
|
"18-16": "l",
|
|
"18-17": "l",
|
|
"18-18": "l",
|
|
"18-19": "l",
|
|
"19-1": "l",
|
|
"19-2": "l",
|
|
"19-3": "l",
|
|
"19-4": "l",
|
|
"19-5": "l",
|
|
"19-6": "l",
|
|
"19-7": "l",
|
|
"19-8": "l",
|
|
"19-9": "l",
|
|
"19-10": "l",
|
|
"19-11": "l",
|
|
"19-12": "l",
|
|
"19-13": "l",
|
|
"19-14": "l",
|
|
"19-15": "l",
|
|
"19-16": "l",
|
|
"19-17": "l",
|
|
"19-18": "l",
|
|
"19-19": "l",
|
|
};
|