Skip to content

Commit d20671d

Browse files
committed
Correctly save and restore source grids (Penrose etc.).
1 parent fd86899 commit d20671d

4 files changed

Lines changed: 54 additions & 25 deletions

File tree

src/game/Game.test.ts

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ import { SquaresAtlas } from "../grid/atlas/SquaresAtlas";
88
import { TileGenerators } from "./TileGenerator";
99
import { Game } from "./Game";
1010
import { AutoPlayer } from "./autoplayer/AutoPlayer";
11+
import { seedPRNG } from "../geom/RandomSampler";
12+
import { TrianglesAtlas } from "../grid/atlas/TrianglesAtlas";
13+
import { Penrose3GridAtlas } from "../grid/atlas/Penrose3GridAtlas";
1114

1215
describe("Game", () => {
1316
test("can be created", () => {
@@ -21,28 +24,34 @@ describe("Game", () => {
2124
const game = new Game(settings);
2225
});
2326

24-
test("can be saved and restored", () => {
27+
const atlases = [SquaresAtlas, TrianglesAtlas, Penrose3GridAtlas];
28+
test.each(atlases)("can be saved and restored: $id", (atlas) => {
29+
const prng = seedPRNG(1234);
30+
2531
const colors = ["red", "blue", "green", "black"];
2632
const settings = {
27-
atlas: SquaresAtlas,
33+
atlas: atlas,
2834
initialTile: colors,
2935
tilesShownOnStack: 3,
3036
tileGenerator: [TileGenerators.permutations(colors)],
3137
};
32-
const game = new Game(settings);
38+
const game = new Game(settings, prng);
3339

3440
const player = new AutoPlayer(game);
35-
player.playOneTile();
36-
player.playOneTile();
37-
player.playOneTile();
41+
player.playOneTile(prng);
42+
player.playOneTile(prng);
43+
player.playOneTile(prng);
3844
expect(game.grid.tiles.size).toBe(4);
3945

4046
const saved = game.saveState();
4147

42-
const game2 = new Game(settings, undefined, saved);
48+
const game2 = new Game(settings, seedPRNG(4321), saved);
4349
expect(game2.points).toBe(game.points);
4450
expect(game2.continued).toBe(game.continued);
4551
expect(game2.tileStack).toEqual(game.tileStack);
4652
expect(game2.grid.tiles.size).toBe(game.grid.tiles.size);
53+
expect(game2.grid.sourceGrid).toEqual(game.grid.sourceGrid);
54+
game2.grid.generatePlaceholders();
55+
expect(game2.grid.tiles.size).toBe(game.grid.tiles.size);
4756
});
4857
});

src/game/Game.ts

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import {
2323
DemoGameSettings,
2424
GameInitializer,
2525
} from "./GameInitializer";
26+
import { SourceGrid } from "../grid/SourceGrid";
2627

2728
export type GameSettings = {
2829
serializedJSON?: string;
@@ -67,6 +68,7 @@ export const GameState_S = zod.object({
6768
continued: zod.boolean(),
6869
tileStack: TileStackWithSlots_S,
6970
tiles: TileSet_S,
71+
sourceGrid: zod.optional(zod.unknown()),
7072
});
7173
export type GameState_S = zod.infer<typeof GameState_S>;
7274

@@ -114,28 +116,37 @@ export class Game extends EventTarget {
114116

115117
this.settings = settings;
116118

117-
this.grid = new Grid(this.settings.atlas);
118-
if (settings.rules) this.grid.rules = settings.rules.create();
119-
this.scorer = (settings.scorer || ConnectedSegmentScorer).create();
120-
119+
let state = null;
120+
let sourceGrid = undefined;
121121
if (restoreState) {
122-
// restore previous game state
123122
try {
124-
const state = GameState_S.parse(restoreState);
125-
this.points = state.points;
126-
this.continued = state.continued;
127-
this.tileStack = TileStackWithSlots.restore(
128-
state.tileStack,
129-
this.grid.atlas.shapes,
130-
);
131-
this.grid.restoreTiles(state.tiles);
132-
return;
123+
state = GameState_S.parse(restoreState);
124+
if (state.sourceGrid && this.settings.atlas.sourceGrid) {
125+
sourceGrid = this.settings.atlas.sourceGrid.restore(
126+
state.sourceGrid,
127+
);
128+
}
133129
} catch (err) {
134130
console.log(err);
135131
// continue with default initialization
136132
}
137133
}
138134

135+
this.grid = new Grid(this.settings.atlas, undefined, sourceGrid);
136+
if (settings.rules) this.grid.rules = settings.rules.create();
137+
this.scorer = (settings.scorer || ConnectedSegmentScorer).create();
138+
139+
if (state) {
140+
this.points = state.points;
141+
this.continued = state.continued;
142+
this.tileStack = TileStackWithSlots.restore(
143+
state.tileStack,
144+
this.grid.atlas.shapes,
145+
);
146+
this.grid.restoreTiles(state.tiles);
147+
return;
148+
}
149+
139150
this.points = 0;
140151
this.continued = false;
141152

@@ -182,6 +193,7 @@ export class Game extends EventTarget {
182193
continued: this.continued,
183194
tileStack: this.tileStack.save(this.grid.atlas.shapes),
184195
tiles: this.grid.saveTilesAndPlaceholders(),
196+
sourceGrid: this.grid.sourceGrid?.save(),
185197
};
186198
}
187199

src/grid/Grid.test.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ import { SquaresAtlas } from "./atlas/SquaresAtlas";
1515
import { TrianglesAtlas } from "./atlas/TrianglesAtlas";
1616
import { Atlas } from "./Atlas";
1717
import { SnubSquareSourceGrid } from "./source/SnubSquareSourceGrid";
18+
import { Penrose3SourceGrid } from "./source/Penrose3SourceGrid";
19+
import { SetupCatalog } from "../saveGames";
20+
import { SnubSquareGridAtlas } from "./atlas/SnubSquareGridAtlas";
1821

1922
const TRIANGLE = TrianglesAtlas.shapes[0];
2023

@@ -467,13 +470,16 @@ describe("Grid", () => {
467470
expect(grid2.placeholders.size).toBe(1);
468471
});
469472

470-
test("can save and restore tiles with a source grid", () => {
471-
const atlas = Atlas.fromSourceGrid("", "", "", SnubSquareSourceGrid);
472-
const grid = new Grid(atlas);
473+
const atlases = [...SetupCatalog.atlas.values()];
474+
test.each(atlases)("can save and restore from $atlas.id", (atlasEntry) => {
475+
const grid = new Grid(atlasEntry.atlas);
473476
const tile = grid.addInitialTile();
474477
const savedTiles = grid.saveTilesAndPlaceholders();
478+
const savedSourceGrid = grid.sourceGrid?.save();
475479

476-
const grid2 = new Grid(atlas);
480+
const sourceGrid2 =
481+
atlasEntry.atlas.sourceGrid?.restore(savedSourceGrid);
482+
const grid2 = new Grid(atlasEntry.atlas, undefined, sourceGrid2);
477483
grid2.restoreTiles(savedTiles);
478484
const restoredTile = [...grid2.tiles][0];
479485
expect(restoredTile.centroid).toEqual(tile.centroid);

src/grid/SourceGrid.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ export abstract class SourceGrid {
1212
static readonly shapes: readonly Shape[];
1313
static readonly shapeFrequencies: ReadonlyMap<Shape, number>;
1414

15+
static restore: (data: unknown) => SourceGrid;
16+
1517
static create(prng?: PRNG): SourceGrid {
1618
throw new Error("Must be implemented in a subclass.");
1719
}

0 commit comments

Comments
 (0)