Compare commits

..

8 commits

Author SHA1 Message Date
Sorrel
08745443ca
Create LICENSE 2021-04-14 20:31:26 -04:00
Sorrel
177d3a4c42
Merge pull request #14 from sorrelbri/dependabot/npm_and_yarn/lodash-4.17.19
Bump lodash from 4.17.15 to 4.17.19
2020-07-20 13:13:50 -04:00
dependabot[bot]
1d804694b7
Bump lodash from 4.17.15 to 4.17.19
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.15 to 4.17.19.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.15...4.17.19)

Signed-off-by: dependabot[bot] <support@github.com>
2020-07-20 17:07:39 +00:00
Sorrel
a40253a4fd
Merge pull request #13 from sorrelbri/dependabot/npm_and_yarn/packages/server/lodash-4.17.19
Bump lodash from 4.17.15 to 4.17.19 in /packages/server
2020-07-20 13:05:21 -04:00
Sorrel
1c470ffec0
Merge pull request #15 from sorrelbri/patch/game-service
patch Game service
2020-07-20 12:35:15 -04:00
Sorrel
27cf281670
patch Game service
Bug where player passes were submitted before `game` object was assigned within `Game.makeMove` patched
2020-07-20 12:20:47 -04:00
dependabot[bot]
0fad98a1d0
Bump lodash from 4.17.15 to 4.17.19 in /packages/server
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.15 to 4.17.19.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.15...4.17.19)

Signed-off-by: dependabot[bot] <support@github.com>
2020-07-19 12:20:31 +00:00
Sorrel
14a94be59e
Merge pull request #12 from sorrelbri/game_record_tree
Game add checkMove hook
2020-07-07 17:30:20 -07:00
11 changed files with 755 additions and 12111 deletions

21
LICENSE Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021 Sorrel
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -36,7 +36,7 @@ Adjacent points without stones are very important to the state of a point as wel
![Image of Game logic](public/game-logic.png)
### Game Records
Game records are modeled as a list where each move has the type `{player: <string: player color>, pos: {x: <integer>, y: <integer>}, number: <integer>}`.
For the moment, game records are modeled as a list where each move has the type `{player: <string: player color>, pos: {x: <integer>, y: <integer>}}`.
The database `move` table contains additional information `number`, `game_record`, and `prior_move` in addition to a foreign key for a `game` row. `number` represents the move number in a game record (for now this corresponds to list position), `game_record` is a boolean representing whether the move was 'official' or is an alternate move used in study, and `prior_move` is a reference to another `move` row allowing for the construction of a tree model for the game (see [Expanding this representation](#expanding-this-representation), below.)
@ -47,7 +47,7 @@ There is a backend service that processes this list of moves into a current boar
This is a customary representation of game records printed in Go literature. A frontend service processes the list of moves and plots each move onto a `<canvas>` element drawn to resemble the grid lines on a board, with moves that are placed at prior points plotted on an additional `<canvas>` element below.
#### Expanding this representation
The list representation is expanded for alternate game paths with the addition of sub-lists in places where paths diverge. Alternate game paths allow users to study completed games by playing out the consequences of moves not in the completed game. Each move with a diverging path contains lists for each path, with the official path being the first.
This representation will be expanded when support for alternate game paths is added. Alternate game paths will allow users to study completed games by playing out the consequences of moves not in the completed game. This feature will require a tree structure for the game record where moves on the main line are referred with a `main` property on each move node and alternate moves with any number of alternate references.
### Caching multiple in-progress games
![Image of Game module in context](public/game-module.png)

12680
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -8500,9 +8500,9 @@
}
},
"lodash": {
"version": "4.17.15",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
"version": "4.17.19",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz",
"integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ=="
},
"lodash._reinterpolate": {
"version": "3.0.0",

View file

@ -48,9 +48,6 @@ const Point = (props) => {
};
return dispatch(action);
}
const priorMove = meta.gameRecord.length
? meta.gameRecord[meta.gameRecord.length - 1].id
: null;
const action = {
type: "SOCKET",
message: "MAKE_MOVE",
@ -59,7 +56,7 @@ const Point = (props) => {
game,
room: game.room,
board: {},
move: { player: turn, pos: { x: posX, y: posY }, priorMove },
move: { player: turn, pos: { x: posX, y: posY } },
},
};
dispatch(action);

View file

@ -3,22 +3,12 @@ const knex = require("../db");
const findGameRecord = async (gameId) => {
return await knex("move")
.where({ game: gameId, game_record: true })
.select(
"player",
"point_x",
"point_y",
"number",
"prior_move",
"placement",
"id"
)
.select("player", "point_x", "point_y", "number", "prior_move", "placement")
.orderBy("number")
.then((record) =>
record.map(({ player, point_x, point_y, id, prior_move }) => ({
record.map(({ player, point_x, point_y }) => ({
player,
pos: { x: point_x, y: point_y },
id,
prior: prior_move,
}))
);
// .then(res => res)
@ -42,10 +32,11 @@ const addMove = async ({ gameId, player, x, y, gameRecord, priorMove }) => {
game_record: gameRecord,
prior_move: priorMove,
})
.then((res) => res[0]);
.then((res) => res);
} catch (e) {
result = e;
} finally {
console.log(result);
return result;
}
};

View file

@ -1359,9 +1359,9 @@
}
},
"lodash": {
"version": "4.17.15",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
"version": "4.17.19",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz",
"integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ=="
},
"lodash.includes": {
"version": "4.3.0",

View file

@ -184,8 +184,7 @@ const Game = ({ gameData = {}, gameRecord = [] } = {}) => {
if (gameRecord.length) {
// play through all the moves
const game = gameRecord.reduce(
(game, move) =>
move.length ? game.makeMove(move[0]) : game.makeMove(move),
(game, move) => game.makeMove(move),
Game({ gameData }).initGame()
);
// ? why is this being wrapped?
@ -263,15 +262,16 @@ const Game = ({ gameData = {}, gameRecord = [] } = {}) => {
return { ...this, success: false };
},
makeMove: function ({ player, pos: { x, y }, id, prior }) {
makeMove: function ({ player, pos: { x, y } }) {
if (this.pass > 1) {
return { ...this, success: false };
}
if (x === 0) return game.submitPass(player);
let success = false;
let game = this;
if (x === 0) return game.submitPass(player);
// if checkMove has not been run, determine legality
if (!game.move) {
game = game.checkMove({ player, pos: { x, y } });
@ -287,7 +287,7 @@ const Game = ({ gameData = {}, gameRecord = [] } = {}) => {
const point = game.boardState[`${x}-${y}`];
game.pass = 0;
// allows for recording of prior move on game record
game.addToRecord({ player, pos: { x, y }, id, prior });
game.addToRecord(game.move);
if (game.kos.length) helper.clearKo.call(game);
point.makeMove(game);
game.turn *= -1;

View file

@ -7,28 +7,22 @@ const GameService = ({ moveQueries, gameQueries }) => {
};
const gamesInProgress = {};
const storeMove = (gameId) => async ({
player,
pos: { x, y },
priorMove,
}) => {
let move = { player, pos: { x, y }, priorMove };
const storeMove = (gameId) => async ({ player, pos: { x, y } }) => {
let move = { player, pos: { x, y } };
try {
if (moveQueries) {
const moveDbResult = await moveQueries.addMove({
const { id } = await moveQueries.addMove({
gameId,
player,
x,
y,
gameRecord: true,
priorMove,
priorMove: null,
});
move.id = moveDbResult.id;
move.prior = moveDbResult.prior_move;
move.id = id;
move.success = true;
}
} catch (e) {
console.log("Exception ------------");
console.log(e);
move.success = false;
} finally {
@ -61,14 +55,23 @@ const GameService = ({ moveQueries, gameQueries }) => {
}
}
gamesInProgress[id] = await gamesInProgress[id].checkMove(move);
gamesInProgress[id] = gamesInProgress[id].makeMove(move);
if (gamesInProgress[id].success === false)
return { message: "illegal move" };
try {
if (moveQueries) {
// todo change prior move
move = await storeMove(id)(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;
moveDbResult = await moveQueries.addMove(moveInsert);
}
gamesInProgress[id] = gamesInProgress[id].makeMove(move);
} catch {
gamesInProgress[id].returnToMove(-1);
} finally {

View file

@ -608,34 +608,14 @@ describe("capture logic: snapback, ko and playing in eyes", () => {
});
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,
};
const firstMove = { player: "black", pos: { x: 4, y: 4 } };
const secondMove = { player: "white", pos: { x: 16, y: 16 } };
const thirdMove = { player: "black", pos: { x: 16, y: 4 } };
const fourthMove = { player: "white", pos: { x: 4, y: 16 } };
const fifthMove = { player: "black", pos: { x: 10, y: 4 } };
const sixthMove = { player: "white", pos: { x: 4, y: 10 } };
const seventhMove = { player: "black", pos: { x: 10, y: 16 } };
const eighthMove = { player: "white", pos: { x: 16, y: 10 } };
it("makeMove creates gameRecord item", (done) => {
Game().initGame().makeMove(firstMove).gameRecord[0].should.eql(firstMove);
@ -748,11 +728,11 @@ describe("Game end logic", () => {
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 })
.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 }, id: 4, prior: 3 })
.makeMove({ player: "black", pos: { x: 16, y: 16 } })
.submitPass("white")
.getMeta()
.should.eql({
@ -760,38 +740,12 @@ describe("Game end logic", () => {
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 },
},
{ player: "black", pos: { x: 4, y: 4 } },
{ player: "white", pos: { x: 4, y: 5 } },
{ player: "black", pos: { x: 5, y: 3 } },
{ player: "white", pos: { x: null, y: null } },
{ player: "black", pos: { x: 16, y: 16 } },
{ player: "white", pos: { x: null, y: null } },
],
});
done();

View file

@ -20,7 +20,7 @@ describe("game services", () => {
it("games services places move", async () => {
gameServices.initGame({ id: 1, handicap: 4 });
const move = { player: "white", pos: { x: 6, y: 3 }, id: 1, prior: null };
const move = { player: "white", pos: { x: 6, y: 3 } };
const afterMove = await gameServices.makeMove({ id: 1, move });
const afterMoveShould = {
board: { ...fourHandicapBoard, "6-3": -1 },