diff --git a/packages/core/src/animation/PitAnimator.ts b/packages/core/src/animation/PitAnimator.ts index 219cb8c..035e309 100644 --- a/packages/core/src/animation/PitAnimator.ts +++ b/packages/core/src/animation/PitAnimator.ts @@ -7,6 +7,7 @@ import { GAME_STEP_LAST_STONE_IN_BANK, GAME_STEP_DOUBLE_STONE_IN_PIT, MancalaGame, + MoveHistoryItem, } from "mancala.js"; import { v4 } from "uuid"; import { BoardViewModel } from "../viewmodel/BoardViewModel"; @@ -92,12 +93,6 @@ export class PitAnimator { this.animationIndex++; } - getGameMoveStepCount(historyItem: HistoryItem) { - return historyItem.gameSteps.filter( - (gameStep) => gameStep.type === GAME_STEP_GAME_MOVE - ).length; - } - animatePit( index: number, boardViewModel: BoardViewModel, @@ -106,15 +101,9 @@ export class PitAnimator { if (!this.currentHistoryItem || !this.game || !this.mancalaGame) return; const pitViewModel = boardViewModel.pits[index]; if (this.animationIndex === 0) { - //This is one stone move case, TODO: beautify it later - if (this.getGameMoveStepCount(this.currentHistoryItem) === 1) { - const previousPitIndex = gameStep.index - 1; - if (previousPitIndex > 0) { - boardViewModel.pits[previousPitIndex].stoneCount = 0; - } - } else { - pitViewModel.stoneCount = 0; - } + // The played pit empties before its stones are sown (a single stone goes on to the next pit). + const { moveIndex } = this.currentHistoryItem as MoveHistoryItem; + boardViewModel.pits[moveIndex].stoneCount = 0; } const theme = this.themeManager.theme; if (gameStep.type === GAME_STEP_GAME_MOVE) { diff --git a/packages/core/tests/animation/PitAnimator.test.ts b/packages/core/tests/animation/PitAnimator.test.ts new file mode 100644 index 0000000..7a3f3af --- /dev/null +++ b/packages/core/tests/animation/PitAnimator.test.ts @@ -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(); + 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]); + }); +});