decouple gameService from db
This commit is contained in:
parent
3eabf4191a
commit
181554124b
5 changed files with 1960 additions and 782 deletions
|
@ -1,77 +1,68 @@
|
||||||
// index corresponds to difference in player rank
|
// index corresponds to difference in player rank
|
||||||
const KOMI_REC = {
|
const KOMI_REC = {
|
||||||
'9': [
|
"9": [5.5, 2.5, -0.5, -3.5, -6.5, -9.5, 12.5, 15.5, 18.5, 21.5],
|
||||||
5.5, 2.5, -0.5, -3.5, -6.5, -9.5, 12.5, 15.5, 18.5, 21.5
|
"13": [5.5, 0.5, -5.5, 0.5, -5.5, 0.5, -5.5, 0.5, -5.5, 0.5],
|
||||||
],
|
"19": [7.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5],
|
||||||
'13': [
|
};
|
||||||
5.5, 0.5, -5.5, 0.5, -5.5, 0.5, -5.5, 0.5, -5.5, 0.5
|
|
||||||
],
|
|
||||||
'19': [
|
|
||||||
7.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
const HANDI_REC = {
|
const HANDI_REC = {
|
||||||
'9': [
|
"9": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
"13": [0, 0, 0, 2, 2, 3, 3, 4, 4, 5],
|
||||||
],
|
"19": [0, 0, 2, 3, 4, 5, 6, 7, 8, 9],
|
||||||
'13': [
|
};
|
||||||
0, 0, 0, 2, 2, 3, 3, 4, 4, 5
|
|
||||||
],
|
|
||||||
'19': [
|
|
||||||
0, 0, 2, 3, 4, 5, 6, 7, 8, 9
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
// index represents handicap placement for different board-sizes, eg handiPlace['9][1] = { (3, 3), (7, 7) }
|
// index represents handicap placement for different board-sizes, eg handiPlace['9][1] = { (3, 3), (7, 7) }
|
||||||
// last array in each property also used for hoshi rendering
|
// last array in each property also used for hoshi rendering
|
||||||
const HANDI_PLACE = {
|
const HANDI_PLACE = {
|
||||||
9 : [
|
9: [
|
||||||
0, 0,
|
0,
|
||||||
[ '7-3', '3-7' ], // 2
|
0,
|
||||||
[ '7-7', '7-3', '3-7' ],
|
["7-3", "3-7"], // 2
|
||||||
[ '3-3', '7-7', '3-7', '7-3' ]
|
["7-7", "7-3", "3-7"],
|
||||||
|
["3-3", "7-7", "3-7", "7-3"],
|
||||||
],
|
],
|
||||||
13 : [
|
13: [
|
||||||
0, 0,
|
0,
|
||||||
[ '4-10', '10-4' ], // 2
|
0,
|
||||||
[ '10-10', '4-10', '10-4' ],
|
["4-10", "10-4"], // 2
|
||||||
[ '4-4', '10-10', '4-10', '10-4' ],
|
["10-10", "4-10", "10-4"],
|
||||||
[ '7-7', '4-4', '10-10', '4-10', '10-4' ],
|
["4-4", "10-10", "4-10", "10-4"],
|
||||||
[ '7-4', '4-7', '4-4', '10-10', '4-10', '10-4' ],
|
["7-7", "4-4", "10-10", "4-10", "10-4"],
|
||||||
[ '7-7', '7-4', '4-7', '4-4', '10-10', '4-10', '10-4' ],
|
["7-4", "4-7", "4-4", "10-10", "4-10", "10-4"],
|
||||||
[ '10-7', '7-4', '7-10', '4-7', '4-4', '10-10', '4-10', '10-4' ],
|
["7-7", "7-4", "4-7", "4-4", "10-10", "4-10", "10-4"],
|
||||||
[ '7-7', '10-7', '7-4', '7-10', '4-7', '4-4', '10-10', '4-10', '10-4' ],
|
["10-7", "7-4", "7-10", "4-7", "4-4", "10-10", "4-10", "10-4"],
|
||||||
|
["7-7", "10-7", "7-4", "7-10", "4-7", "4-4", "10-10", "4-10", "10-4"],
|
||||||
|
],
|
||||||
|
19: [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
["4-16", "16-4"], // 2
|
||||||
|
["16-16", "4-16", "16-4"],
|
||||||
|
["4-4", "16-16", "4-16", "16-4"],
|
||||||
|
["10-10", "4-4", "16-16", "4-16", "16-4"],
|
||||||
|
["10-4", "4-10", "4-4", "16-16", "4-16", "16-4"],
|
||||||
|
["10-10", "10-4", "4-10", "4-4", "16-16", "4-16", "16-4"],
|
||||||
|
["16-10", "10-4", "10-16", "4-10", "4-4", "16-16", "4-16", "16-4"],
|
||||||
|
["10-10", "16-10", "10-4", "10-16", "4-10", "4-4", "16-16", "4-16", "16-4"],
|
||||||
],
|
],
|
||||||
19 : [
|
|
||||||
0, 0,
|
|
||||||
[ '4-16', '16-4' ], // 2
|
|
||||||
[ '16-16', '4-16', '16-4' ],
|
|
||||||
[ '4-4', '16-16', '4-16', '16-4' ],
|
|
||||||
[ '10-10', '4-4', '16-16', '4-16', '16-4' ],
|
|
||||||
[ '10-4', '4-10', '4-4', '16-16', '4-16', '16-4' ],
|
|
||||||
[ '10-10', '10-4', '4-10', '4-4', '16-16', '4-16', '16-4' ],
|
|
||||||
[ '16-10', '10-4', '10-16', '4-10', '4-4', '16-16', '4-16', '16-4' ],
|
|
||||||
[ '10-10', '16-10', '10-4', '10-16', '4-10', '4-4', '16-16', '4-16', '16-4' ],
|
|
||||||
]
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const getSingleItemFromSet = set => {
|
const getSingleItemFromSet = (set) => {
|
||||||
let entry;
|
let entry;
|
||||||
for (entry of set.entries()) {
|
for (entry of set.entries()) {
|
||||||
}
|
}
|
||||||
return entry[0];
|
return entry[0];
|
||||||
}
|
};
|
||||||
|
|
||||||
const pipeMap = (...funcs) => obj => {
|
const pipeMap = (...funcs) => (obj) => {
|
||||||
const arr = Object.entries(obj).reduce((acc, [key, value], i, arr) => {
|
const arr = Object.entries(obj).reduce((acc, [key, value], i, arr) => {
|
||||||
funcs.forEach(func => value = func(value, i, arr));
|
funcs.forEach((func) => (value = func(value, i, arr)));
|
||||||
return [...acc, [key, value]];
|
return [...acc, [key, value]];
|
||||||
},[]);
|
}, []);
|
||||||
return arr.reduce((acc, [key, value]) => {
|
return arr.reduce((acc, [key, value]) => {
|
||||||
return { ...acc, [key]: value }
|
return { ...acc, [key]: value };
|
||||||
}, {});
|
}, {});
|
||||||
}
|
};
|
||||||
|
|
||||||
const checkLegal = ({ point, Game }) => {
|
const checkLegal = ({ point, Game }) => {
|
||||||
// if stone (includes ko) return false
|
// if stone (includes ko) return false
|
||||||
|
@ -79,20 +70,24 @@ const checkLegal = ({ point, Game }) => {
|
||||||
point.legal = false;
|
point.legal = false;
|
||||||
return point;
|
return point;
|
||||||
}
|
}
|
||||||
const neighbors = getNeighbors({Game, point});
|
const neighbors = getNeighbors({ Game, point });
|
||||||
|
|
||||||
const isEmpty = point => point.stone === 0 && point.legal === true;
|
const isEmpty = (point) => point.stone === 0 && point.legal === true;
|
||||||
const isEmptyAdjacent = neighbors.filter(isEmpty);
|
const isEmptyAdjacent = neighbors.filter(isEmpty);
|
||||||
|
|
||||||
// if empty point adjacent return true
|
// if empty point adjacent return true
|
||||||
if (!isEmptyAdjacent.length) {
|
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) =>
|
||||||
const isNotSamePoint = liberty => liberty.pos.x !== point.pos.x && liberty.pos.y !== point.pos.y;
|
Array.from(Game.groups[point.group].liberties);
|
||||||
const isInGroupWithLiberties = neighbor => getGroupLiberties(neighbor).filter(isNotSamePoint).length;
|
const isNotSamePoint = (liberty) =>
|
||||||
const isInLiveGroup = neighbors.filter(isTurnStone).filter(isInGroupWithLiberties).length;
|
liberty.pos.x !== point.pos.x && liberty.pos.y !== point.pos.y;
|
||||||
|
const isInGroupWithLiberties = (neighbor) =>
|
||||||
|
getGroupLiberties(neighbor).filter(isNotSamePoint).length;
|
||||||
|
const isInLiveGroup = neighbors
|
||||||
|
.filter(isTurnStone)
|
||||||
|
.filter(isInGroupWithLiberties).length;
|
||||||
|
|
||||||
if (isInLiveGroup) {
|
if (isInLiveGroup) {
|
||||||
point.legal = true;
|
point.legal = true;
|
||||||
|
@ -110,36 +105,36 @@ const checkLegal = ({ point, Game }) => {
|
||||||
}
|
}
|
||||||
point.legal = true;
|
point.legal = true;
|
||||||
return point;
|
return point;
|
||||||
}
|
};
|
||||||
|
|
||||||
const getBoardState = (Game) => {
|
const getBoardState = (Game) => {
|
||||||
const getLegal = point => checkLegal({ point, Game })
|
const getLegal = (point) => checkLegal({ point, Game });
|
||||||
const boardState = pipeMap(getLegal)(Game.boardState);
|
const boardState = pipeMap(getLegal)(Game.boardState);
|
||||||
Game.kos.forEach(ko => {
|
Game.kos.forEach((ko) => {
|
||||||
boardState[ko].legal = false;
|
boardState[ko].legal = false;
|
||||||
});
|
});
|
||||||
return boardState;
|
return boardState;
|
||||||
}
|
};
|
||||||
|
|
||||||
const getLegalMoves = (Game) => {
|
const getLegalMoves = (Game) => {
|
||||||
const mapLegal = point => point.legal ? 'l' : point.stone;
|
const mapLegal = (point) => (point.legal ? "l" : point.stone);
|
||||||
const legalMoves = pipeMap(mapLegal)(Game.boardState);
|
const legalMoves = pipeMap(mapLegal)(Game.boardState);
|
||||||
Game.kos.forEach(ko => {
|
Game.kos.forEach((ko) => {
|
||||||
legalMoves[ko] = 'k';
|
legalMoves[ko] = "k";
|
||||||
});
|
});
|
||||||
return legalMoves;
|
return legalMoves;
|
||||||
}
|
};
|
||||||
|
|
||||||
const getNeighbors = ({ Game, point }) => {
|
const getNeighbors = ({ Game, point }) => {
|
||||||
let { top = null, btm = null, lft = null, rgt = null} = point.neighbors;
|
let { top = null, btm = null, lft = null, rgt = null } = point.neighbors;
|
||||||
const { boardState, boardSize } = Game;
|
const { boardState, boardSize } = Game;
|
||||||
// boardState[0] = [ '1-1', Point({x:1, y:1, boardSize}) ]
|
// boardState[0] = [ '1-1', Point({x:1, y:1, boardSize}) ]
|
||||||
if (top) top = boardState[top];
|
if (top) top = boardState[top];
|
||||||
if (btm) btm = boardState[btm];
|
if (btm) btm = boardState[btm];
|
||||||
if (lft) lft = boardState[lft];
|
if (lft) lft = boardState[lft];
|
||||||
if (rgt) rgt = boardState[rgt];
|
if (rgt) rgt = boardState[rgt];
|
||||||
return [ top, btm, lft, rgt ].filter(value => value);
|
return [top, btm, lft, rgt].filter((value) => value);
|
||||||
}
|
};
|
||||||
|
|
||||||
const initBoard = (game) => {
|
const initBoard = (game) => {
|
||||||
const boardState = {};
|
const boardState = {};
|
||||||
|
@ -147,69 +142,76 @@ const initBoard = (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,
|
||||||
y: i % boardSize + 1,
|
y: (i % boardSize) + 1,
|
||||||
boardSize
|
boardSize,
|
||||||
});
|
});
|
||||||
boardState[`${point.pos.x}-${point.pos.y}`] = point;
|
boardState[`${point.pos.x}-${point.pos.y}`] = point;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (handicap) {
|
if (handicap) {
|
||||||
HANDI_PLACE[boardSize][handicap].forEach(pt => {
|
HANDI_PLACE[boardSize][handicap].forEach((pt) => {
|
||||||
boardState[pt].makeMove({...game, boardState});
|
boardState[pt].makeMove({ ...game, boardState });
|
||||||
});
|
});
|
||||||
game.turn *= -1;
|
game.turn *= -1;
|
||||||
}
|
}
|
||||||
return boardState;
|
return boardState;
|
||||||
}
|
};
|
||||||
|
|
||||||
// returns Game object
|
// returns Game object
|
||||||
const Game = ({gameData = {}, gameRecord = []} = {}) => {
|
const Game = ({ gameData = {}, gameRecord = [] } = {}) => {
|
||||||
const helper = {
|
const helper = {
|
||||||
clearKo: function() {
|
clearKo: function () {
|
||||||
this.kos.forEach(ko => {
|
this.kos.forEach((ko) => {
|
||||||
this.boardState[ko] = { ...this.boardState[ko], legal: true, ko: false };
|
this.boardState[ko] = {
|
||||||
})
|
...this.boardState[ko],
|
||||||
|
legal: true,
|
||||||
|
ko: false,
|
||||||
|
};
|
||||||
|
});
|
||||||
this.kos = [];
|
this.kos = [];
|
||||||
},
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
if (gameRecord.length) {
|
if (gameRecord.length) {
|
||||||
// play through all the moves
|
// play through all the moves
|
||||||
return gameRecord.reduce((game, move) => game.makeMove(move), Game({gameData}).initGame())
|
return gameRecord.reduce(
|
||||||
|
(game, move) => game.makeMove(move),
|
||||||
|
Game({ gameData }).initGame()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
winner: gameData.winner ||null,
|
winner: gameData.winner || null,
|
||||||
turn: gameData.turn || 0, // turn logic depends on handicap stones
|
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
|
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
|
komi: gameData.komi || 6.5, // komi depends on handicap stones + player rank
|
||||||
handicap: gameData.handicap || 0,
|
handicap: gameData.handicap || 0,
|
||||||
boardSize: gameData.boardSize || 19,
|
boardSize: gameData.boardSize || 19,
|
||||||
groups: {},
|
groups: {},
|
||||||
boardState: {},
|
boardState: {},
|
||||||
kos: [],
|
kos: [],
|
||||||
gameRecord: gameRecord,
|
gameRecord: gameRecord,
|
||||||
playerState: gameData.playerState || {
|
playerState: gameData.playerState || {
|
||||||
bCaptures: 0,
|
bCaptures: 0,
|
||||||
wCaptures: 0,
|
wCaptures: 0,
|
||||||
bScore: 0,
|
bScore: 0,
|
||||||
wScore: 0
|
wScore: 0,
|
||||||
},
|
},
|
||||||
|
|
||||||
initGame: function() {
|
initGame: function () {
|
||||||
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);
|
||||||
this.boardState = getBoardState(this);
|
this.boardState = getBoardState(this);
|
||||||
this.legalMoves = getLegalMoves(this)
|
this.legalMoves = getLegalMoves(this);
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
|
|
||||||
addToRecord: function(moveObject) {
|
addToRecord: function (moveObject) {
|
||||||
this.gameRecord.push(moveObject);
|
this.gameRecord.push(moveObject);
|
||||||
},
|
},
|
||||||
|
|
||||||
getMeta: function() {
|
getMeta: function () {
|
||||||
// cannot be chained
|
// cannot be chained
|
||||||
// does not affect game object
|
// does not affect game object
|
||||||
return {
|
return {
|
||||||
|
@ -220,16 +222,20 @@ const Game = ({gameData = {}, gameRecord = []} = {}) => {
|
||||||
gameRecord: this.gameRecord,
|
gameRecord: this.gameRecord,
|
||||||
boardSize: this.boardSize,
|
boardSize: this.boardSize,
|
||||||
handicap: this.handicap,
|
handicap: this.handicap,
|
||||||
komi: this.komi
|
komi: this.komi,
|
||||||
}
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
makeMove: function({ player, pos: {x, y}}) {
|
makeMove: function ({ player, pos: { x, y } }) {
|
||||||
|
if (this.pass > 1) {
|
||||||
|
return { ...this, success: false };
|
||||||
|
}
|
||||||
let game = this;
|
let game = this;
|
||||||
let success = false;
|
let success = false;
|
||||||
const point = game.boardState[`${x}-${y}`];
|
const point = game.boardState[`${x}-${y}`];
|
||||||
const isTurn = ( game.turn === 1 && player === 'black' )
|
const isTurn =
|
||||||
|| ( game.turn === -1 && player === 'white' );
|
(game.turn === 1 && player === "black") ||
|
||||||
|
(game.turn === -1 && player === "white");
|
||||||
if (isTurn) {
|
if (isTurn) {
|
||||||
if (point.legal) {
|
if (point.legal) {
|
||||||
game.pass = 0;
|
game.pass = 0;
|
||||||
|
@ -241,20 +247,20 @@ const Game = ({gameData = {}, gameRecord = []} = {}) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
game.boardState = getBoardState(game);
|
game.boardState = getBoardState(game);
|
||||||
return {...game, legalMoves: getLegalMoves(game), success };
|
return { ...game, legalMoves: getLegalMoves(game), success };
|
||||||
},
|
},
|
||||||
|
|
||||||
initGroup: function(point) {
|
initGroup: function (point) {
|
||||||
const group = Symbol(`${point.pos.x}-${point.pos.y}`);
|
const group = Symbol(`${point.pos.x}-${point.pos.y}`);
|
||||||
this.groups[group] = { stones: new Set(), liberties: new Set()};
|
this.groups[group] = { stones: new Set(), liberties: new Set() };
|
||||||
return { game: this, group };
|
return { game: this, group };
|
||||||
},
|
},
|
||||||
|
|
||||||
returnToMove: function(lastMove) {
|
returnToMove: function (lastMove) {
|
||||||
const { komi, handicap, boardSize } = this;
|
const { komi, handicap, boardSize } = this;
|
||||||
if (lastMove === 0) {
|
if (lastMove === 0) {
|
||||||
return Game({
|
return Game({
|
||||||
gameData: { komi, handicap, boardSize }
|
gameData: { komi, handicap, boardSize },
|
||||||
}).initGame();
|
}).initGame();
|
||||||
}
|
}
|
||||||
const length = this.gameRecord.length;
|
const length = this.gameRecord.length;
|
||||||
|
@ -262,12 +268,12 @@ const Game = ({gameData = {}, gameRecord = []} = {}) => {
|
||||||
if (lastMove >= length && lastMove > 0) return this;
|
if (lastMove >= length && lastMove > 0) return this;
|
||||||
return Game({
|
return Game({
|
||||||
gameData: { komi, handicap, boardSize },
|
gameData: { komi, handicap, boardSize },
|
||||||
gameRecord: [...this.gameRecord.slice(0, index)]
|
gameRecord: [...this.gameRecord.slice(0, index)],
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
submitPass: function(player) {
|
submitPass: function (player) {
|
||||||
if (player !== 'black' && player !== 'white') {
|
if (player !== "black" && player !== "white") {
|
||||||
return { ...this, success: false };
|
return { ...this, success: false };
|
||||||
}
|
}
|
||||||
if (this.pass > 0) {
|
if (this.pass > 0) {
|
||||||
|
@ -276,47 +282,56 @@ const Game = ({gameData = {}, gameRecord = []} = {}) => {
|
||||||
this.pass = 1;
|
this.pass = 1;
|
||||||
this.addToRecord({ player, pos: { x: null, y: null } });
|
this.addToRecord({ player, pos: { x: null, y: null } });
|
||||||
if (this.kos.length) helper.clearKo.call(this);
|
if (this.kos.length) helper.clearKo.call(this);
|
||||||
this.turn = player === 'black' ? -1 : 1;
|
this.turn = player === "black" ? -1 : 1;
|
||||||
this.boardState = getBoardState(this);
|
this.boardState = getBoardState(this);
|
||||||
return {...this, legalMoves: getLegalMoves(this), success: true };
|
return { ...this, legalMoves: getLegalMoves(this), success: true };
|
||||||
},
|
},
|
||||||
|
|
||||||
submitResign: function(player) {
|
submitResign: function (player) {
|
||||||
if (player === 'black') this.winner = -1;
|
if (player === "black") this.winner = -1;
|
||||||
if (player === 'white') this.winner = 1;
|
if (player === "white") this.winner = 1;
|
||||||
this.turn = 0;
|
this.turn = 0;
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
|
|
||||||
endGame: function() {
|
endGame: function () {
|
||||||
// TODO manage territory counting
|
// TODO manage territory counting
|
||||||
|
// form groups for empty points
|
||||||
|
// for each empty point group determine territory
|
||||||
|
// for each non-empty point group determine life
|
||||||
|
// submit board state to users
|
||||||
|
// if boardState is approved calculate winner
|
||||||
|
// submit end game board state and data for study
|
||||||
|
// (study module should run client side and only )
|
||||||
|
// if toggleGroups(key) toggle that group
|
||||||
|
// submit board state to winner
|
||||||
this.turn = 0;
|
this.turn = 0;
|
||||||
return this;
|
return this;
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const Point = ({x, y, boardSize = 19}) => {
|
const Point = ({ x, y, boardSize = 19 }) => {
|
||||||
let point = {
|
let point = {
|
||||||
pos: {x, y},
|
pos: { x, y },
|
||||||
key: `${x}-${y}`,
|
key: `${x}-${y}`,
|
||||||
stone: 0, // can be 1, -1, 0,
|
stone: 0, // can be 1, -1, 0,
|
||||||
ko: false,
|
ko: false,
|
||||||
legal: true,
|
legal: true,
|
||||||
territory: 0,
|
territory: 0,
|
||||||
capturing: {
|
capturing: {
|
||||||
'1': new Set(),
|
"1": new Set(),
|
||||||
'-1': new Set()
|
"-1": new Set(),
|
||||||
},
|
},
|
||||||
group: null,
|
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,
|
||||||
rgt: y < boardSize ? `${ x }-${ y + 1 }` : null,
|
rgt: y < boardSize ? `${x}-${y + 1}` : null,
|
||||||
lft: y > 1 ? `${ x }-${ y - 1 }` : null
|
lft: y > 1 ? `${x}-${y - 1}` : null,
|
||||||
},
|
},
|
||||||
|
|
||||||
makeMove: function(Game) {
|
makeMove: function (Game) {
|
||||||
this.stone = Game.turn;
|
this.stone = Game.turn;
|
||||||
this.legal = false;
|
this.legal = false;
|
||||||
if (this.capturing[this.stone].size) {
|
if (this.capturing[this.stone].size) {
|
||||||
|
@ -326,7 +341,7 @@ const Point = ({x, y, boardSize = 19}) => {
|
||||||
return this.checkCaptures(Game);
|
return this.checkCaptures(Game);
|
||||||
},
|
},
|
||||||
|
|
||||||
joinGroup: function({ point, Game }) {
|
joinGroup: function ({ point, Game }) {
|
||||||
if (point.group !== this.group || !point.group) {
|
if (point.group !== this.group || !point.group) {
|
||||||
// if point has no group set current group to new Symbol in game object
|
// if point has no group set current group to new Symbol in game object
|
||||||
if (!point.group) {
|
if (!point.group) {
|
||||||
|
@ -341,35 +356,36 @@ const Point = ({x, y, boardSize = 19}) => {
|
||||||
this.group = point.group;
|
this.group = point.group;
|
||||||
}
|
}
|
||||||
Game = this.setLiberties(Game);
|
Game = this.setLiberties(Game);
|
||||||
getNeighbors({ point:this, Game }).forEach(neighbor => {
|
getNeighbors({ point: this, Game }).forEach((neighbor) => {
|
||||||
if ( neighbor.stone === this.stone
|
if (
|
||||||
|
neighbor.stone === this.stone &&
|
||||||
// this check prevents infinite call chains
|
// this check prevents infinite call chains
|
||||||
&& neighbor.group !== this.group
|
neighbor.group !== this.group
|
||||||
) {
|
) {
|
||||||
Game = neighbor.joinGroup({ point: this, Game });
|
Game = neighbor.joinGroup({ point: this, Game });
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
return Game;
|
return Game;
|
||||||
},
|
},
|
||||||
|
|
||||||
setLiberties: function(Game) {
|
setLiberties: function (Game) {
|
||||||
const neighbors = getNeighbors({ point: this, Game });
|
const neighbors = getNeighbors({ point: this, Game });
|
||||||
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(neighbor => {
|
neighbors.forEach((neighbor) => {
|
||||||
if (neighbor.stone !== 0) {
|
if (neighbor.stone !== 0) {
|
||||||
liberties.delete(neighbor);
|
liberties.delete(neighbor);
|
||||||
Game.groups[neighbor.group].liberties.delete(this);
|
Game.groups[neighbor.group].liberties.delete(this);
|
||||||
}
|
}
|
||||||
if (neighbor.stone === 0) {
|
if (neighbor.stone === 0) {
|
||||||
liberties.add(neighbor)
|
liberties.add(neighbor);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return Game;
|
return Game;
|
||||||
},
|
},
|
||||||
|
|
||||||
checkCaptures: function(game) {
|
checkCaptures: function (game) {
|
||||||
// if this stone has one liberty
|
// if this stone has one liberty
|
||||||
const liberties = game.groups[this.group].liberties;
|
const liberties = game.groups[this.group].liberties;
|
||||||
if (liberties.size === 1) {
|
if (liberties.size === 1) {
|
||||||
|
@ -377,13 +393,18 @@ const Point = ({x, y, boardSize = 19}) => {
|
||||||
lastLiberty.capturing[this.stone * -1].add(this.group);
|
lastLiberty.capturing[this.stone * -1].add(this.group);
|
||||||
}
|
}
|
||||||
if (liberties.size > 1) {
|
if (liberties.size > 1) {
|
||||||
liberties.forEach(liberty => liberty.capturing[this.stone * -1 ].delete(this.group))
|
liberties.forEach((liberty) =>
|
||||||
|
liberty.capturing[this.stone * -1].delete(this.group)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if neighbors have one liberty
|
// if neighbors have one liberty
|
||||||
const neighbors = getNeighbors({point: this, Game: game}).filter(neighbor => neighbor.stone === -1 * this.stone)
|
const neighbors = getNeighbors({ point: this, Game: game }).filter(
|
||||||
neighbors.forEach( neighbor => {
|
(neighbor) => neighbor.stone === -1 * this.stone
|
||||||
const liberties = game.groups[neighbor.group] && game.groups[neighbor.group].liberties;
|
);
|
||||||
|
neighbors.forEach((neighbor) => {
|
||||||
|
const liberties =
|
||||||
|
game.groups[neighbor.group] && game.groups[neighbor.group].liberties;
|
||||||
if (liberties && liberties.size === 1) {
|
if (liberties && liberties.size === 1) {
|
||||||
const lastLiberty = getSingleItemFromSet(liberties);
|
const lastLiberty = getSingleItemFromSet(liberties);
|
||||||
lastLiberty.capturing[neighbor.stone * -1].add(neighbor.group);
|
lastLiberty.capturing[neighbor.stone * -1].add(neighbor.group);
|
||||||
|
@ -392,32 +413,34 @@ const Point = ({x, y, boardSize = 19}) => {
|
||||||
return game;
|
return game;
|
||||||
},
|
},
|
||||||
|
|
||||||
makeCaptures: function(game) {
|
makeCaptures: function (game) {
|
||||||
// for each group
|
// for each group
|
||||||
for (let [captureGroup, _] of this.capturing[this.stone].entries()) {
|
for (let [captureGroup, _] of this.capturing[this.stone].entries()) {
|
||||||
|
|
||||||
const capturesSet = game.groups[captureGroup].stones;
|
const capturesSet = game.groups[captureGroup].stones;
|
||||||
for (let [capture, _] of capturesSet.entries()) {
|
for (let [capture, _] of capturesSet.entries()) {
|
||||||
game = capture.removeStone(game);
|
game = capture.removeStone(game);
|
||||||
if (capturesSet.size === 1) {
|
if (capturesSet.size === 1) {
|
||||||
const neighbors = getNeighbors({ point: this, Game: game })
|
const neighbors = getNeighbors({ point: this, Game: game });
|
||||||
const liberties = neighbors.filter(neighbor => neighbor.stone === 0);
|
const liberties = neighbors.filter(
|
||||||
const groupStones = neighbors.filter(neighbor => neighbor.stone === this.stone);
|
(neighbor) => neighbor.stone === 0
|
||||||
|
);
|
||||||
|
const groupStones = neighbors.filter(
|
||||||
|
(neighbor) => neighbor.stone === this.stone
|
||||||
|
);
|
||||||
if (liberties.length === 1 && groupStones.length === 0) {
|
if (liberties.length === 1 && groupStones.length === 0) {
|
||||||
capture.ko = true;
|
capture.ko = true;
|
||||||
game.kos.push(capture.key)
|
game.kos.push(capture.key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
// points with stones cannot be played to capture
|
// points with stones cannot be played to capture
|
||||||
this.capturing = { '1': new Set(), '-1': new Set() }
|
this.capturing = { "1": new Set(), "-1": new Set() };
|
||||||
return {...game, boardState: { ...game.boardState, [this.key]: this } };
|
return { ...game, boardState: { ...game.boardState, [this.key]: this } };
|
||||||
},
|
},
|
||||||
|
|
||||||
removeStone: function(game) {
|
removeStone: function (game) {
|
||||||
if (this.stone = 0) {
|
if ((this.stone = 0)) {
|
||||||
return game;
|
return game;
|
||||||
}
|
}
|
||||||
// reset point
|
// reset point
|
||||||
|
@ -425,19 +448,21 @@ const Point = ({x, y, boardSize = 19}) => {
|
||||||
this.group = null;
|
this.group = null;
|
||||||
this.capturing[game.turn] = new Set();
|
this.capturing[game.turn] = new Set();
|
||||||
// add captures
|
// add captures
|
||||||
const player = game.turn > 0 ? 'b' : 'w';
|
const player = game.turn > 0 ? "b" : "w";
|
||||||
game.playerState[`${player}Captures`] += 1;
|
game.playerState[`${player}Captures`] += 1;
|
||||||
|
|
||||||
// add as liberty to neighbors
|
// add as liberty to neighbors
|
||||||
const neighbors = getNeighbors({ point: this, Game: game }).filter(neighbor => neighbor.stone !== 0 && neighbor.group);
|
const neighbors = getNeighbors({ point: this, Game: game }).filter(
|
||||||
neighbors.forEach(neighbor => {
|
(neighbor) => neighbor.stone !== 0 && neighbor.group
|
||||||
|
);
|
||||||
|
neighbors.forEach((neighbor) => {
|
||||||
game.groups[neighbor.group].liberties.add(this);
|
game.groups[neighbor.group].liberties.add(this);
|
||||||
neighbor.checkCaptures(game)
|
neighbor.checkCaptures(game);
|
||||||
})
|
});
|
||||||
|
|
||||||
return {...game, boardState: {...game.boardState, [this.key]: this}};
|
return { ...game, boardState: { ...game.boardState, [this.key]: this } };
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
for (let [key, value] of Object.entries(point.neighbors)) {
|
for (let [key, value] of Object.entries(point.neighbors)) {
|
||||||
if (value) continue;
|
if (value) continue;
|
||||||
delete point.neighbors[key];
|
delete point.neighbors[key];
|
||||||
|
@ -447,8 +472,8 @@ const Point = ({x, y, boardSize = 19}) => {
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
Game,
|
Game,
|
||||||
Point
|
Point,
|
||||||
}
|
};
|
||||||
|
|
||||||
// Game().initGame()
|
// Game().initGame()
|
||||||
// .makeMove({ player: 'black', pos: { x: 1, y: 1 } }) // 1 2 3
|
// .makeMove({ player: 'black', pos: { x: 1, y: 1 } }) // 1 2 3
|
||||||
|
|
|
@ -1,63 +1,65 @@
|
||||||
const Game = require('./Game').Game;
|
const Game = require("./Game").Game;
|
||||||
const moveQueries = require('../data/queries/move');
|
|
||||||
|
|
||||||
const gamesInProgress = { }
|
const GameService = (moveQueries) => {
|
||||||
|
const storeGame = (game) => {
|
||||||
const storeGame = (game) => {
|
gamesInProgress[game.id] = Game(game);
|
||||||
gamesInProgress[game.id] = Game(game);
|
return gamesInProgress[game.id];
|
||||||
return gamesInProgress[game.id];
|
|
||||||
}
|
|
||||||
|
|
||||||
const initGame = ({id, gameRecord = [], ...gameData}) => {
|
|
||||||
if (gamesInProgress[id]) return getDataForUI(id);
|
|
||||||
if (gameRecord.length) {
|
|
||||||
console.log('here')
|
|
||||||
gamesInProgress[id] = Game({ gameData, gameRecord })
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
gamesInProgress[id] = Game({gameData}).initGame();
|
|
||||||
}
|
|
||||||
return getDataForUI(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
const makeMove = async ({id, move}) => {
|
|
||||||
if (!gamesInProgress[id]) storeGame({id}).initGame();
|
|
||||||
gamesInProgress[id] = gamesInProgress[id].makeMove(move)
|
|
||||||
if (gamesInProgress[id].success === false) return { message: 'illegal move' };
|
|
||||||
const priorMove = gamesInProgress[id].gameRecord.length;
|
|
||||||
const moveInsert = { gameId: id, player: move.player, x: move.pos.x, y: move.pos.y, gameRecord: true, priorMove };
|
|
||||||
let moveDbResult;
|
|
||||||
try {
|
|
||||||
moveDbResult = await moveQueries.addMove(moveInsert);
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
gamesInProgress[id].returnToMove(-1);
|
|
||||||
} finally {
|
|
||||||
return getDataForUI(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const getDataForUI = (id) => {
|
|
||||||
return {
|
|
||||||
board: gamesInProgress[id].legalMoves,
|
|
||||||
...gamesInProgress[id].getMeta()
|
|
||||||
};
|
};
|
||||||
}
|
const gamesInProgress = {};
|
||||||
|
|
||||||
const dropGame = (id) => {
|
return {
|
||||||
return { message:
|
initGame({ id, gameRecord = [], ...gameData }) {
|
||||||
`${delete gamesInProgress[id]}`
|
if (gamesInProgress[id]) return this.getDataForUI(id);
|
||||||
}
|
if (gameRecord.length) {
|
||||||
}
|
console.log("here");
|
||||||
|
gamesInProgress[id] = Game({ gameData, gameRecord });
|
||||||
|
} else {
|
||||||
|
gamesInProgress[id] = Game({ gameData }).initGame();
|
||||||
|
}
|
||||||
|
return this.getDataForUI(id);
|
||||||
|
},
|
||||||
|
|
||||||
const getAllGames = () => {
|
async makeMove({ id, move }) {
|
||||||
return gamesInProgress;
|
if (!gamesInProgress[id]) storeGame({ id }).initGame();
|
||||||
}
|
gamesInProgress[id] = gamesInProgress[id].makeMove(move);
|
||||||
|
if (gamesInProgress[id].success === false)
|
||||||
|
return { message: "illegal move" };
|
||||||
|
try {
|
||||||
|
if (moveQueries) {
|
||||||
|
const priorMove = gamesInProgress[id].gameRecord.length;
|
||||||
|
const moveInsert = {
|
||||||
|
gameId: id,
|
||||||
|
player: move.player,
|
||||||
|
x: move.pos.x,
|
||||||
|
y: move.pos.y,
|
||||||
|
gameRecord: true,
|
||||||
|
priorMove,
|
||||||
|
};
|
||||||
|
let moveDbResult;
|
||||||
|
moveDbResult = await moveQueries.addMove(moveInsert);
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
gamesInProgress[id].returnToMove(-1);
|
||||||
|
} finally {
|
||||||
|
return this.getDataForUI(id);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
module.exports = {
|
getDataForUI: (id) => {
|
||||||
makeMove,
|
return {
|
||||||
getAllGames,
|
board: gamesInProgress[id].legalMoves,
|
||||||
getDataForUI,
|
...gamesInProgress[id].getMeta(),
|
||||||
initGame,
|
};
|
||||||
dropGame
|
},
|
||||||
}
|
|
||||||
|
dropGame: (id) => {
|
||||||
|
return { message: `${delete gamesInProgress[id]}` };
|
||||||
|
},
|
||||||
|
|
||||||
|
getAllGames: () => {
|
||||||
|
return gamesInProgress;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = GameService;
|
||||||
|
|
|
@ -1,57 +1,63 @@
|
||||||
// TODO const someSocketLogic = require('./middleware/socketssockets/...');
|
// TODO const someSocketLogic = require('./middleware/socketssockets/...');
|
||||||
const socketIO = require('socket.io');
|
const socketIO = require("socket.io");
|
||||||
const io = socketIO({ cookie: false });
|
const io = socketIO({ cookie: false });
|
||||||
|
|
||||||
// const gameQueries = require('./data/queries/game');
|
// const gameQueries = require('./data/queries/game');
|
||||||
const moveQueries = require('./data/queries/move');
|
const moveQueries = require("./data/queries/move");
|
||||||
const gameServices = require('./services/gameServices');
|
const gameServices = require("./services/gameServices")(moveQueries);
|
||||||
|
|
||||||
io.on('connection', async socket=> {
|
io.on("connection", async (socket) => {
|
||||||
socket.emit('connected', {message: 'socket connected'});
|
socket.emit("connected", { message: "socket connected" });
|
||||||
socket.on('connect_room', async data => {
|
socket.on("connect_room", async (data) => {
|
||||||
if (data.user && data.user.email) {
|
if (data.user && data.user.email) {
|
||||||
delete data.user.email;
|
delete data.user.email;
|
||||||
}
|
}
|
||||||
const room = data.room;
|
const room = data.room;
|
||||||
const roomIo = io.of(room);
|
const roomIo = io.of(room);
|
||||||
roomIo.on('connection', async socket => {
|
roomIo.on("connection", async (socket) => {
|
||||||
socket.emit('connected')
|
socket.emit("connected");
|
||||||
socket.emit('new_user', data);
|
socket.emit("new_user", data);
|
||||||
socket.on('connect_game', data => {
|
socket.on("connect_game", (data) => {
|
||||||
const game = `game-${data.game.id}`;
|
const game = `game-${data.game.id}`;
|
||||||
socket.join(game, async () => {
|
socket.join(game, async () => {
|
||||||
// ! temp
|
// ! temp
|
||||||
const gameRecord = await moveQueries.findGameRecord(data.game.id);
|
const gameRecord = await moveQueries.findGameRecord(data.game.id);
|
||||||
console.log(gameRecord)
|
console.log("gameRecord from db");
|
||||||
await gameServices.initGame({id: data.game.id, gameRecord})
|
console.log(gameRecord);
|
||||||
|
await gameServices.initGame({ id: data.game.id, gameRecord });
|
||||||
// ! end-temp
|
// ! end-temp
|
||||||
const { board, ...meta } = await gameServices.getDataForUI(data.game.id);
|
const { board, ...meta } = await gameServices.getDataForUI(
|
||||||
io.of(room).to(game).emit('game_connected', { board, meta });
|
data.game.id
|
||||||
|
);
|
||||||
|
io.of(room).to(game).emit("game_connected", { board, meta });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
socket.on('make_move', async data => {
|
socket.on("make_move", async (data) => {
|
||||||
const { user, move, board, game, room } = data;
|
const { user, move, board, game, room } = data;
|
||||||
const gameNsp = `game-${data.game.id}`;
|
const gameNsp = `game-${data.game.id}`;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { board, message, ...meta } = await gameServices.makeMove({ id: 1, move });
|
const { board, message, ...meta } = await gameServices.makeMove({
|
||||||
const socketAction = message ? 'error' : 'update_board';
|
id: 1,
|
||||||
|
move,
|
||||||
|
});
|
||||||
|
const socketAction = message ? "error" : "update_board";
|
||||||
socket.join(gameNsp, () => {
|
socket.join(gameNsp, () => {
|
||||||
io.of(room).to(gameNsp).emit(socketAction, { board, meta, message })
|
io.of(room)
|
||||||
|
.to(gameNsp)
|
||||||
|
.emit(socketAction, { board, meta, message });
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
socket.join(gameNsp, () => {
|
||||||
|
io.of(room).to(gameNsp).emit("error", e);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
catch (e) {
|
});
|
||||||
console.log(e)
|
|
||||||
socket.join(gameNsp, () => {
|
|
||||||
io.of(room).to(gameNsp).emit('error', e)
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
io
|
io,
|
||||||
}
|
};
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,67 +1,418 @@
|
||||||
const chai = require('chai');
|
const chai = require("chai");
|
||||||
const should = chai.should();
|
const should = chai.should();
|
||||||
const gameServices = require('../services/gameServices');
|
const gameServices = require("../services/gameServices")();
|
||||||
|
|
||||||
describe.skip('game services', () => {
|
describe("game services", () => {
|
||||||
afterEach(() => gameServices.dropGame(1))
|
afterEach(() => gameServices.dropGame(1));
|
||||||
|
|
||||||
it('init game returns game board', done => {
|
it("init game returns game board", (done) => {
|
||||||
gameServices.initGame({ id: 1, handicap: 4 })
|
gameServices
|
||||||
.board.should.eql(fourHandicapBoard)
|
.initGame({ id: 1, handicap: 4 })
|
||||||
|
.board.should.eql(fourHandicapBoard);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('init game returns game metadata', done => {
|
it("init game returns game metadata", (done) => {
|
||||||
const { board, ...game } = gameServices.initGame({ id: 1, handicap: 4 })
|
const { board, ...game } = gameServices.initGame({ id: 1, handicap: 4 });
|
||||||
game.should.eql({...initialMeta, handicap: 4, turn: -1});
|
game.should.eql({ ...initialMeta, handicap: 4, turn: -1 });
|
||||||
done();
|
|
||||||
})
|
|
||||||
|
|
||||||
it('games services places move', done => {
|
|
||||||
gameServices.initGame({ id: 1, handicap: 4 })
|
|
||||||
const move = { player: 'white', pos: { x: 6, y: 3 } }
|
|
||||||
const afterMove = gameServices.makeMove({ id: 1, move });
|
|
||||||
const afterMoveShould = { board: { ...fourHandicapBoard, '6-3': -1}, ...initialMeta, handicap: 4, turn: 1, gameRecord: [ move ] };
|
|
||||||
afterMove.should.eql(afterMoveShould);
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('illegal move returns error message', done => {
|
it("games services places move", async () => {
|
||||||
gameServices.initGame({ id: 1, handicap: 4 });
|
gameServices.initGame({ id: 1, handicap: 4 });
|
||||||
gameServices.makeMove({ id: 1, move: { player: 'white', pos: { x:4, y:4 } } })
|
const move = { player: "white", pos: { x: 6, y: 3 } };
|
||||||
.message.should.equal('illegal move');
|
const afterMove = await gameServices.makeMove({ id: 1, move });
|
||||||
done();
|
const afterMoveShould = {
|
||||||
|
board: { ...fourHandicapBoard, "6-3": -1 },
|
||||||
|
...initialMeta,
|
||||||
|
handicap: 4,
|
||||||
|
turn: 1,
|
||||||
|
gameRecord: [move],
|
||||||
|
};
|
||||||
|
afterMove.should.eql(afterMoveShould);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('game services places move next to stone', done => {
|
it("illegal move returns error message", async () => {
|
||||||
gameServices.initGame({ id: 1, handicap:4 });
|
gameServices.initGame({ id: 1, handicap: 4 });
|
||||||
gameServices.makeMove({ id: 1, move: { player: 'white', pos: { x: 4, y: 3 } } })
|
const afterMove = await gameServices.makeMove({
|
||||||
.board.should.eql({ ...fourHandicapBoard, '4-3': -1 });
|
id: 1,
|
||||||
done();
|
move: { player: "white", pos: { x: 4, y: 4 } },
|
||||||
})
|
});
|
||||||
})
|
afterMove.message.should.equal("illegal move");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("game services places move next to stone", async () => {
|
||||||
|
gameServices.initGame({ id: 1, handicap: 4 });
|
||||||
|
const afterMove = await gameServices.makeMove({
|
||||||
|
id: 1,
|
||||||
|
move: { player: "white", pos: { x: 4, y: 3 } },
|
||||||
|
});
|
||||||
|
afterMove.board.should.eql({ ...fourHandicapBoard, "4-3": -1 });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
const fourHandicapBoard = {
|
const fourHandicapBoard = {
|
||||||
'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',
|
"1-1": "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',
|
"1-2": "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',
|
"1-3": "l",
|
||||||
'4-1': 'l','4-2': 'l','4-3': 'l','4-4': 1,'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': 1,'4-17': 'l','4-18': 'l','4-19': 'l',
|
"1-4": "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',
|
"1-5": "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',
|
"1-6": "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',
|
"1-7": "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',
|
"1-8": "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',
|
"1-9": "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',
|
"1-10": "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',
|
"1-11": "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',
|
"1-12": "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',
|
"1-13": "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',
|
"1-14": "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',
|
"1-15": "l",
|
||||||
'16-1': 'l','16-2': 'l','16-3': 'l','16-4': 1,'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': 1,'16-17': 'l','16-18': 'l','16-19': 'l',
|
"1-16": "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',
|
"1-17": "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',
|
"1-18": "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'
|
"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": 1,
|
||||||
|
"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": 1,
|
||||||
|
"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": 1,
|
||||||
|
"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": 1,
|
||||||
|
"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",
|
||||||
};
|
};
|
||||||
|
|
||||||
const initialMeta = {
|
const initialMeta = {
|
||||||
|
@ -75,7 +426,7 @@ const initialMeta = {
|
||||||
bCaptures: 0,
|
bCaptures: 0,
|
||||||
wCaptures: 0,
|
wCaptures: 0,
|
||||||
bScore: 0,
|
bScore: 0,
|
||||||
wScore: 0
|
wScore: 0,
|
||||||
},
|
},
|
||||||
gameRecord: []
|
gameRecord: [],
|
||||||
}
|
};
|
||||||
|
|
Loading…
Reference in a new issue