Make the expand and collapse interactions inverses of one another
For the most part, at least. If the edge cases where they differ still feel weird, I can iterate on this further. The diff is unfortunately a bit impenetrable, because I had to change both the fillGaps and cycleTileSize core algorithms used by the big grid layout. But: the main change of significance is the addition of a function vacateArea, which clears out an area within the grid in a specific way that mirrors the motion performed by fillGaps.
This commit is contained in:
parent
aab08d2bf1
commit
3ac98c8865
3 changed files with 543 additions and 321 deletions
|
@ -22,10 +22,10 @@ limitations under the License.
|
||||||
// Array.prototype.findLastIndex
|
// Array.prototype.findLastIndex
|
||||||
export function findLastIndex<T>(
|
export function findLastIndex<T>(
|
||||||
array: T[],
|
array: T[],
|
||||||
predicate: (item: T) => boolean
|
predicate: (item: T, index: number) => boolean
|
||||||
): number | null {
|
): number | null {
|
||||||
for (let i = array.length - 1; i >= 0; i--) {
|
for (let i = array.length - 1; i >= 0; i--) {
|
||||||
if (predicate(array[i])) return i;
|
if (predicate(array[i], i)) return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
@ -34,5 +34,11 @@ export function findLastIndex<T>(
|
||||||
/**
|
/**
|
||||||
* Counts the number of elements in an array that satsify the given predicate.
|
* Counts the number of elements in an array that satsify the given predicate.
|
||||||
*/
|
*/
|
||||||
export const count = <T>(array: T[], predicate: (item: T) => boolean): number =>
|
export const count = <T>(
|
||||||
array.reduce((acc, item) => (predicate(item) ? acc + 1 : acc), 0);
|
array: T[],
|
||||||
|
predicate: (item: T, index: number) => boolean
|
||||||
|
): number =>
|
||||||
|
array.reduce(
|
||||||
|
(acc, item, index) => (predicate(item, index) ? acc + 1 : acc),
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -20,7 +20,7 @@ import {
|
||||||
cycleTileSize,
|
cycleTileSize,
|
||||||
fillGaps,
|
fillGaps,
|
||||||
forEachCellInArea,
|
forEachCellInArea,
|
||||||
BigGridState,
|
Grid,
|
||||||
resize,
|
resize,
|
||||||
row,
|
row,
|
||||||
moveTile,
|
moveTile,
|
||||||
|
@ -30,13 +30,13 @@ import { TileDescriptor } from "../../src/video-grid/VideoGrid";
|
||||||
/**
|
/**
|
||||||
* Builds a grid from a string specifying the contents of each cell as a letter.
|
* Builds a grid from a string specifying the contents of each cell as a letter.
|
||||||
*/
|
*/
|
||||||
function mkGrid(spec: string): BigGridState {
|
function mkGrid(spec: string): Grid {
|
||||||
const secondNewline = spec.indexOf("\n", 1);
|
const secondNewline = spec.indexOf("\n", 1);
|
||||||
const columns = secondNewline === -1 ? spec.length : secondNewline - 1;
|
const columns = secondNewline === -1 ? spec.length : secondNewline - 1;
|
||||||
const cells = spec.match(/[a-z ]/g) ?? ([] as string[]);
|
const cells = spec.match(/[a-z ]/g) ?? ([] as string[]);
|
||||||
const areas = new Set(cells);
|
const areas = new Set(cells);
|
||||||
areas.delete(" "); // Space represents an empty cell, not an area
|
areas.delete(" "); // Space represents an empty cell, not an area
|
||||||
const grid: BigGridState = { columns, cells: new Array(cells.length) };
|
const grid: Grid = { columns, cells: new Array(cells.length) };
|
||||||
|
|
||||||
for (const area of areas) {
|
for (const area of areas) {
|
||||||
const start = cells.indexOf(area);
|
const start = cells.indexOf(area);
|
||||||
|
@ -60,7 +60,7 @@ function mkGrid(spec: string): BigGridState {
|
||||||
/**
|
/**
|
||||||
* Turns a grid into a string showing the contents of each cell as a letter.
|
* Turns a grid into a string showing the contents of each cell as a letter.
|
||||||
*/
|
*/
|
||||||
function showGrid(g: BigGridState): string {
|
function showGrid(g: Grid): string {
|
||||||
let result = "\n";
|
let result = "\n";
|
||||||
for (let i = 0; i < g.cells.length; i++) {
|
for (let i = 0; i < g.cells.length; i++) {
|
||||||
if (i > 0 && i % g.columns == 0) result += "\n";
|
if (i > 0 && i % g.columns == 0) result += "\n";
|
||||||
|
@ -116,11 +116,11 @@ mno`,
|
||||||
`
|
`
|
||||||
aebch
|
aebch
|
||||||
difgl
|
difgl
|
||||||
monjk`
|
mjnok`
|
||||||
);
|
);
|
||||||
|
|
||||||
testFillGaps(
|
testFillGaps(
|
||||||
"fills a big gap",
|
"fills a big gap with 1×1 tiles",
|
||||||
`
|
`
|
||||||
abcd
|
abcd
|
||||||
e f
|
e f
|
||||||
|
@ -128,19 +128,19 @@ g h
|
||||||
ijkl`,
|
ijkl`,
|
||||||
`
|
`
|
||||||
abcd
|
abcd
|
||||||
elhf
|
ehkf
|
||||||
gkji`
|
glji`
|
||||||
);
|
);
|
||||||
|
|
||||||
testFillGaps(
|
testFillGaps(
|
||||||
"only moves 1×1 tiles",
|
"fills a big gap with a large tile",
|
||||||
`
|
`
|
||||||
|
|
||||||
aa
|
aa
|
||||||
bc`,
|
bc`,
|
||||||
`
|
`
|
||||||
bc
|
aa
|
||||||
aa`
|
cb`
|
||||||
);
|
);
|
||||||
|
|
||||||
testFillGaps(
|
testFillGaps(
|
||||||
|
@ -186,7 +186,7 @@ iief`
|
||||||
);
|
);
|
||||||
|
|
||||||
testFillGaps(
|
testFillGaps(
|
||||||
"pushes a chain of large tiles upwards",
|
"collapses large tiles trapped at the bottom",
|
||||||
`
|
`
|
||||||
abcd
|
abcd
|
||||||
e fg
|
e fg
|
||||||
|
@ -195,24 +195,24 @@ hh
|
||||||
ii
|
ii
|
||||||
ii`,
|
ii`,
|
||||||
`
|
`
|
||||||
hhcd
|
abcd
|
||||||
hhfg
|
hhfg
|
||||||
aiib
|
hhie`
|
||||||
eii`
|
|
||||||
);
|
);
|
||||||
|
|
||||||
testFillGaps(
|
testFillGaps(
|
||||||
"gives up on pushing large tiles upwards when not possible",
|
"gives up on pushing large tiles upwards when not possible",
|
||||||
`
|
`
|
||||||
aabb
|
aa
|
||||||
aabb
|
aa
|
||||||
cc
|
bccd
|
||||||
cc`,
|
eccf
|
||||||
|
ghij`,
|
||||||
`
|
`
|
||||||
aabb
|
aadf
|
||||||
aabb
|
aaji
|
||||||
cc
|
bcch
|
||||||
cc`
|
eccg`
|
||||||
);
|
);
|
||||||
|
|
||||||
function testCycleTileSize(
|
function testCycleTileSize(
|
||||||
|
@ -237,9 +237,9 @@ def
|
||||||
ghi`,
|
ghi`,
|
||||||
`
|
`
|
||||||
acc
|
acc
|
||||||
bcc
|
dcc
|
||||||
def
|
gbe
|
||||||
ghi`
|
ifh`
|
||||||
);
|
);
|
||||||
|
|
||||||
testCycleTileSize(
|
testCycleTileSize(
|
||||||
|
@ -249,10 +249,10 @@ testCycleTileSize(
|
||||||
abcd
|
abcd
|
||||||
efgh`,
|
efgh`,
|
||||||
`
|
`
|
||||||
abcd
|
acdh
|
||||||
eggg
|
bggg
|
||||||
fggg
|
fggg
|
||||||
h`
|
e`
|
||||||
);
|
);
|
||||||
|
|
||||||
testCycleTileSize(
|
testCycleTileSize(
|
||||||
|
@ -264,9 +264,9 @@ dbbe
|
||||||
fghi
|
fghi
|
||||||
jk`,
|
jk`,
|
||||||
`
|
`
|
||||||
akbc
|
abhc
|
||||||
djhe
|
djge
|
||||||
fig`
|
fik`
|
||||||
);
|
);
|
||||||
|
|
||||||
testCycleTileSize(
|
testCycleTileSize(
|
||||||
|
@ -284,9 +284,9 @@ abb
|
||||||
gbb
|
gbb
|
||||||
dde
|
dde
|
||||||
ddf
|
ddf
|
||||||
cci
|
ccm
|
||||||
cch
|
cch
|
||||||
klm`
|
lik`
|
||||||
);
|
);
|
||||||
|
|
||||||
testCycleTileSize(
|
testCycleTileSize(
|
||||||
|
@ -304,6 +304,34 @@ dde
|
||||||
ddf`
|
ddf`
|
||||||
);
|
);
|
||||||
|
|
||||||
|
test("cycleTileSize is its own inverse", () => {
|
||||||
|
const input = `
|
||||||
|
abc
|
||||||
|
def
|
||||||
|
ghi
|
||||||
|
jk`;
|
||||||
|
|
||||||
|
const grid = mkGrid(input);
|
||||||
|
let gridAfter = grid;
|
||||||
|
|
||||||
|
const toggle = (tileId: string) => {
|
||||||
|
const tile = grid.cells.find((c) => c?.item.id === tileId)!.item;
|
||||||
|
gridAfter = cycleTileSize(gridAfter, tile);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Toggle a series of tiles
|
||||||
|
toggle("j");
|
||||||
|
toggle("h");
|
||||||
|
toggle("a");
|
||||||
|
// Now do the same thing in reverse
|
||||||
|
toggle("a");
|
||||||
|
toggle("h");
|
||||||
|
toggle("j");
|
||||||
|
|
||||||
|
// The grid should be back to its original state
|
||||||
|
expect(showGrid(gridAfter)).toBe(input);
|
||||||
|
});
|
||||||
|
|
||||||
function testAddItems(
|
function testAddItems(
|
||||||
title: string,
|
title: string,
|
||||||
items: TileDescriptor<unknown>[],
|
items: TileDescriptor<unknown>[],
|
||||||
|
@ -437,9 +465,9 @@ gh`,
|
||||||
af
|
af
|
||||||
bb
|
bb
|
||||||
bb
|
bb
|
||||||
|
dd
|
||||||
|
dd
|
||||||
ch
|
ch
|
||||||
dd
|
|
||||||
dd
|
|
||||||
eg`
|
eg`
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -455,9 +483,8 @@ dd
|
||||||
dd
|
dd
|
||||||
eg`,
|
eg`,
|
||||||
`
|
`
|
||||||
bbbc
|
afcd
|
||||||
bbbf
|
bbbg
|
||||||
addd
|
bbbe
|
||||||
hddd
|
h`
|
||||||
ge`
|
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in a new issue