Release: Quarkus backend, Keycloak login, game history, clock, bot, tutorial and rematch #3
@ -7,6 +7,7 @@ import {
|
|||||||
GAME_STEP_LAST_STONE_IN_BANK,
|
GAME_STEP_LAST_STONE_IN_BANK,
|
||||||
GAME_STEP_DOUBLE_STONE_IN_PIT,
|
GAME_STEP_DOUBLE_STONE_IN_PIT,
|
||||||
MancalaGame,
|
MancalaGame,
|
||||||
|
MoveHistoryItem,
|
||||||
} from "mancala.js";
|
} from "mancala.js";
|
||||||
import { v4 } from "uuid";
|
import { v4 } from "uuid";
|
||||||
import { BoardViewModel } from "../viewmodel/BoardViewModel";
|
import { BoardViewModel } from "../viewmodel/BoardViewModel";
|
||||||
@ -92,12 +93,6 @@ export class PitAnimator {
|
|||||||
this.animationIndex++;
|
this.animationIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
getGameMoveStepCount(historyItem: HistoryItem) {
|
|
||||||
return historyItem.gameSteps.filter(
|
|
||||||
(gameStep) => gameStep.type === GAME_STEP_GAME_MOVE
|
|
||||||
).length;
|
|
||||||
}
|
|
||||||
|
|
||||||
animatePit(
|
animatePit(
|
||||||
index: number,
|
index: number,
|
||||||
boardViewModel: BoardViewModel,
|
boardViewModel: BoardViewModel,
|
||||||
@ -106,15 +101,9 @@ export class PitAnimator {
|
|||||||
if (!this.currentHistoryItem || !this.game || !this.mancalaGame) return;
|
if (!this.currentHistoryItem || !this.game || !this.mancalaGame) return;
|
||||||
const pitViewModel = boardViewModel.pits[index];
|
const pitViewModel = boardViewModel.pits[index];
|
||||||
if (this.animationIndex === 0) {
|
if (this.animationIndex === 0) {
|
||||||
//This is one stone move case, TODO: beautify it later
|
// The played pit empties before its stones are sown (a single stone goes on to the next pit).
|
||||||
if (this.getGameMoveStepCount(this.currentHistoryItem) === 1) {
|
const { moveIndex } = this.currentHistoryItem as MoveHistoryItem;
|
||||||
const previousPitIndex = gameStep.index - 1;
|
boardViewModel.pits[moveIndex].stoneCount = 0;
|
||||||
if (previousPitIndex > 0) {
|
|
||||||
boardViewModel.pits[previousPitIndex].stoneCount = 0;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
pitViewModel.stoneCount = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
const theme = this.themeManager.theme;
|
const theme = this.themeManager.theme;
|
||||||
if (gameStep.type === GAME_STEP_GAME_MOVE) {
|
if (gameStep.type === GAME_STEP_GAME_MOVE) {
|
||||||
|
|||||||
68
packages/core/tests/animation/PitAnimator.test.ts
Normal file
68
packages/core/tests/animation/PitAnimator.test.ts
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
import { CommonMancalaGame, MancalaGame } from "mancala.js";
|
||||||
|
import { PitAnimator } from "../../src/animation/PitAnimator";
|
||||||
|
import { Game } from "../../src/models";
|
||||||
|
import { ThemeManager } from "../../src/theme";
|
||||||
|
import { BoardViewModel } from "../../src/viewmodel/BoardViewModel";
|
||||||
|
|
||||||
|
const P1 = "player-1";
|
||||||
|
const P2 = "player-2";
|
||||||
|
|
||||||
|
const memoryStorage = () => {
|
||||||
|
const values = new Map<string, string>();
|
||||||
|
return {
|
||||||
|
getString: (key: string) => values.get(key),
|
||||||
|
setString: (key: string, value: string) => void values.set(key, value),
|
||||||
|
deleteString: (key: string) => void values.delete(key),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const asGame = (mancalaGame: MancalaGame): Game => ({
|
||||||
|
id: mancalaGame.id,
|
||||||
|
mancalaGame,
|
||||||
|
gameUsersConnectionInfo: {
|
||||||
|
user1ConnectionInfo: { userId: P1, isOnline: true },
|
||||||
|
user2ConnectionInfo: { userId: P2, isOnline: true },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Plays the move on a copy of the game and returns the stones the animator shows after each step.
|
||||||
|
const animateMove = (setUp: (game: MancalaGame) => void, playerId: string, pit: number): number[][] => {
|
||||||
|
jest.useFakeTimers();
|
||||||
|
const createGame = () => {
|
||||||
|
const game = new CommonMancalaGame("game-1", P1, P2);
|
||||||
|
game.turnPlayerId = playerId;
|
||||||
|
setUp(game);
|
||||||
|
return game;
|
||||||
|
};
|
||||||
|
const before = createGame();
|
||||||
|
const after = createGame();
|
||||||
|
after.moveByPlayerPit(playerId, pit);
|
||||||
|
|
||||||
|
const frames: number[][] = [];
|
||||||
|
const animator = new PitAnimator(new ThemeManager(memoryStorage()), (boardViewModel: BoardViewModel) =>
|
||||||
|
frames.push(boardViewModel.pits.map((pitViewModel) => pitViewModel.stoneCount)), 10);
|
||||||
|
animator.setNewGame(asGame(before));
|
||||||
|
frames.length = 0;
|
||||||
|
animator.setUpdatedGame(asGame(after));
|
||||||
|
jest.advanceTimersByTime(10 * (after.history[0].gameSteps.length + 1));
|
||||||
|
jest.useRealTimers();
|
||||||
|
return frames.slice(1);
|
||||||
|
};
|
||||||
|
|
||||||
|
describe("PitAnimator", () => {
|
||||||
|
it("empties the played pit when a single stone moves on", () => {
|
||||||
|
for (const pit of [0, 3]) {
|
||||||
|
const frames = animateMove((game) => {
|
||||||
|
game.board.pits[pit].stoneCount = 1;
|
||||||
|
}, P1, pit);
|
||||||
|
expect(frames[0][pit]).toBe(0);
|
||||||
|
expect(frames[0][pit + 1]).toBe(5);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it("empties the played pit and sows from it when several stones move", () => {
|
||||||
|
const frames = animateMove(() => undefined, P1, 0);
|
||||||
|
expect(frames[0].slice(0, 4)).toEqual([1, 4, 4, 4]);
|
||||||
|
expect(frames[3].slice(0, 4)).toEqual([1, 5, 5, 5]);
|
||||||
|
});
|
||||||
|
});
|
||||||
Loading…
Reference in New Issue
Block a user