Files
feuerwerk/tests/core/tilemap-fill.test.ts
T

75 lines
3.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* The fill of a tilemap layer (#133): the cells reached from the one clicked through their four
* edge neighbours that hold the same tile – empty included – and nothing outside the grid.
*/
import { describe, expect, it } from 'vitest';
import type { TilemapLayer } from '../../src/core/model/Asset';
import { cellKey, floodFill } from '../../src/core/model/tilemap';
/** A layer drawn as text: one row per line, `.` empty, any other letter the tile of that name. */
function layerOf(rows: string[]): TilemapLayer {
const cells: Record<string, string> = {};
rows.forEach((row, y) =>
[...row].forEach((c, x) => {
if (c !== '.') cells[cellKey(x, y)] = c;
}),
);
return { id: 'l', name: 'Layer', cells };
}
/** The filled cells as text again, `*` where the fill landed – easier to read than a list. */
function shown(rows: string[], filled: { x: number; y: number }[]): string[] {
const out = rows.map((row) => [...row]);
for (const { x, y } of filled) out[y]![x] = '*';
return out.map((row) => row.join(''));
}
const GRID = { columns: 5, rows: 4 };
describe('filling a tilemap layer', () => {
it('takes the connected cells through edges, not through corners', () => {
const rows = ['..w..', '.w.w.', 'w...w', '.w.w.'];
const cells = floodFill(GRID, layerOf(rows), { x: 2, y: 2 }, 'g');
expect(shown(rows, cells)).toEqual(['..w..', '.w*w.', 'w***w', '.w*w.']);
});
it('fills a whole empty grid and stops at its edge', () => {
const cells = floodFill(GRID, layerOf([]), { x: 0, y: 0 }, 'g');
expect(cells).toHaveLength(20);
expect(cells.every(({ x, y }) => x >= 0 && y >= 0 && x < 5 && y < 4)).toBe(true);
});
it('replaces one tile with another and leaves the empty cells beside it', () => {
const rows = ['aa...', 'a.bb.', 'aaab.', '.....'];
const cells = floodFill(GRID, layerOf(rows), { x: 0, y: 0 }, 'b');
expect(shown(rows, cells)).toEqual(['**...', '*.bb.', '***b.', '.....']);
});
it('ignores cells outside the grid, even when they hold the same tile', () => {
const layer = layerOf(['aaaaa']);
layer.cells[cellKey(5, 0)] = 'a';
layer.cells[cellKey(-1, 0)] = 'a';
const cells = floodFill(GRID, layer, { x: 2, y: 0 }, 'g');
expect(cells.map((c) => c.x).sort()).toEqual([0, 1, 2, 3, 4]);
expect(floodFill(GRID, layer, { x: 5, y: 0 }, 'g')).toEqual([]);
});
it('changes nothing when the cell already holds the tile', () => {
expect(floodFill(GRID, layerOf(['aaaaa']), { x: 1, y: 0 }, 'a')).toEqual([]);
expect(floodFill(GRID, layerOf([]), { x: 1, y: 1 }, '')).toEqual([]);
});
it('can empty a region, too', () => {
const rows = ['aa.a.'];
const cells = floodFill(GRID, layerOf(rows), { x: 1, y: 0 }, '');
expect(shown(rows, cells)).toEqual(['**.a.']);
});
it('fills a large map in one go', () => {
const props = { columns: 300, rows: 300 };
const started = performance.now();
expect(floodFill(props, layerOf([]), { x: 150, y: 150 }, 'g')).toHaveLength(90_000);
expect(performance.now() - started).toBeLessThan(2000);
});
});