From cac159bd892e47dd9b78d44ef40fde4c18e890bf Mon Sep 17 00:00:00 2001 From: Erik Schilling Date: Wed, 16 Dec 2020 20:03:17 +0100 Subject: [PATCH] Implement buffer filling and sequence fulfillment --- src/game/Game.test.ts | 47 ++++++++++++++++++++++++++++++++++--------- src/game/Game.ts | 38 +++++++++++++++++++++++++++++++--- 2 files changed, 73 insertions(+), 12 deletions(-) diff --git a/src/game/Game.test.ts b/src/game/Game.test.ts index dcdd322..4d470c0 100644 --- a/src/game/Game.test.ts +++ b/src/game/Game.test.ts @@ -9,27 +9,27 @@ describe("GameState", () => { ] test("getting size works", () => { - expect((new Game([])).size).toEqual(0) - expect((new Game(["00"])).size).toEqual(1) + expect((new Game([], [])).size).toEqual(0) + expect((new Game(["00"], [])).size).toEqual(1) expect((new Game([ "00", "01", "10", "11", - ])).size).toEqual(2) + ], [])).size).toEqual(2) }); test("getting cell works", () => { - const game = new Game(threeByThreeMatrix); + const game = new Game(threeByThreeMatrix, []); expect(game.getCell(0, 2)).toEqual("02") }); - + describe("picking", () => { test("starts with free pick", () => { - const game = new Game([]); + const game = new Game([], []); expect(game.state).toEqual({selectionMode: SelectionMode.FreePick}) }); - + test("picking cells works", () => { - const game = new Game(threeByThreeMatrix); + const game = new Game(threeByThreeMatrix, []); game.pick(0, 0); expect(game.state).toEqual({selectionMode: SelectionMode.RowPick, column: 0}); expect(() => game.pick(0, 2)).toThrow(); @@ -38,11 +38,40 @@ describe("GameState", () => { }); test("picking outside of range fails", () => { - const game = new Game(threeByThreeMatrix); + const game = new Game(threeByThreeMatrix, []); expect(() => game.pick(-1, 0)).toThrow(); expect(() => game.pick(0, -1)).toThrow(); expect(() => game.pick(3, 0)).toThrow(); expect(() => game.pick(0, 3)).toThrow(); }); + + test("picking fills buffer, fulfills sequence", () => { + const simpleSequence = ["00", "10", "20"] + const game = new Game(threeByThreeMatrix, [simpleSequence]); + expect(game.getSequences()).toEqual([{sequence: simpleSequence, numberOfFulfilled: 0}]) + game.pick(0, 0); + expect(game.buffer).toEqual(["00"]); + expect(game.getSequences()).toEqual([{sequence: simpleSequence, numberOfFulfilled: 1}]) + }); + + test("picking fulfills second sequence occurence", () => { + const sequence = ["AA", "BB", "CC"] + const game = new Game([ + "AA", "AA", "BB", + "BB", "CC", "AA", + "CC", "CC", "CC", + ], [sequence]); + expect(game.getSequences()).toEqual([{sequence: sequence, numberOfFulfilled: 0}]) + game.pick(0, 0); + expect(game.getSequences()).toEqual([{sequence: sequence, numberOfFulfilled: 1}]) + game.pick(2, 0); + expect(game.getSequences()).toEqual([{sequence: sequence, numberOfFulfilled: 2}]) + game.pick(2, 1); + expect(game.getSequences()).toEqual([{sequence: sequence, numberOfFulfilled: 1}]) + game.pick(0, 1); + expect(game.getSequences()).toEqual([{sequence: sequence, numberOfFulfilled: 2}]) + game.pick(0, 2); + expect(game.getSequences()).toEqual([{sequence: sequence, numberOfFulfilled: 3}]) + }); }); }); diff --git a/src/game/Game.ts b/src/game/Game.ts index 7c62e3b..8c5d851 100644 --- a/src/game/Game.ts +++ b/src/game/Game.ts @@ -71,11 +71,17 @@ class IllegalMoveError extends Error { } } +interface Sequence { + sequence: string[] + numberOfFulfilled: number +} + export class Game { state: State = {selectionMode: SelectionMode.FreePick} public readonly size: number + public readonly buffer: string[] = [] - constructor(public readonly matrix: string[]) { + constructor(public readonly matrix: string[], private readonly sequences: string[][]) { this.size = Math.sqrt(matrix.length) } @@ -83,6 +89,29 @@ export class Game { return this.matrix[row + column * this.size] } + getSequences(): Sequence[] { + return this.sequences.map(sequence => { + let longestPrefixLength = 0 + for (let i = 0; i < this.buffer.length; ++i) { + let prefixLength = 0; + for (let j = 0; j < Math.min(sequence.length, this.buffer.length - i); ++j) { + if (this.buffer[i + j] != sequence[j]) { + // abort sequence + prefixLength = 0 + break; + } + ++prefixLength; + } + longestPrefixLength = Math.max(longestPrefixLength, prefixLength); + } + + return { + sequence: sequence, + numberOfFulfilled: longestPrefixLength, + } + }) + } + pick(row: number, column: number): void { if (row < 0 || column < 0 || row >= this.size || column >= this.size) { throw new IllegalMoveError() @@ -91,7 +120,9 @@ export class Game { matchState({ Won: () => {throw new IllegalMoveError()}, Lost: () => {throw new IllegalMoveError()}, - InProgress: (selectionMode) => + InProgress: (selectionMode) => { + this.buffer.push(this.getCell(row, column)) + matchSelectionState({ Free: () => { this.state = { @@ -119,7 +150,8 @@ export class Game { throw new IllegalMoveError() } }, - })(selectionMode), + })(selectionMode) + } })(this.state) } }