This repository has been archived by the owner on Aug 7, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
jwcub
committed
Apr 21, 2024
1 parent
a99d311
commit c9449cf
Showing
10 changed files
with
977 additions
and
606 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import { expect, it } from "vitest"; | ||
|
||
import { Land } from "./land"; | ||
|
||
it("creates a land", () => { | ||
const land = new Land(1, 2, 3); | ||
|
||
expect(land.color).toBe(1); | ||
expect(land.type).toBe(2); | ||
expect(land.amount).toBe(3); | ||
}); | ||
|
||
it("serializes a land", () => { | ||
const land = new Land(1, 2, 3); | ||
const exported = [1, 2, 3]; | ||
|
||
expect(JSON.stringify(land)).toBe(JSON.stringify(exported)); | ||
}); | ||
|
||
it("deserializes a land", () => { | ||
const exported = [1, 2, 3] as const; | ||
const land = new Land(1, 2, 3); | ||
|
||
expect(Land.from(exported)).toStrictEqual(land); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
/** | ||
* Map land. | ||
*/ | ||
export class Land extends Array<number> { | ||
/** | ||
* Land types. | ||
*/ | ||
static Type = { | ||
Land: 0, | ||
General: 1, | ||
City: 2, | ||
Mountain: 3, | ||
UnknownCity: 4, | ||
Unknown: 5, | ||
UnknownMountain: 6, | ||
Swamp: 7 | ||
} as const; | ||
|
||
/** | ||
* Land color. | ||
*/ | ||
get color() { | ||
return this[0]; | ||
} | ||
|
||
/** | ||
* Land type. | ||
*/ | ||
get type() { | ||
return this[1]; | ||
} | ||
|
||
/** | ||
* Land amount. | ||
*/ | ||
get amount() { | ||
return this[2]; | ||
} | ||
|
||
/** | ||
* Creates a Land with given color, type and amount. | ||
*/ | ||
constructor(color = 0, type = 0, amount = 0) { | ||
super(color, type, amount); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
import { expect, it } from "vitest"; | ||
|
||
import { Matrix } from "./matrix"; | ||
|
||
it("creates a matrix", () => { | ||
const height = 2, | ||
width = 1; | ||
const items = [ | ||
[0, 0], | ||
[0, 0], | ||
[0, 0] | ||
]; | ||
const matrix = Matrix.default(height, width, 0); | ||
|
||
expect(matrix.width).toBe(width); | ||
expect(matrix.height).toBe(height); | ||
expect(matrix).toEqual(items); | ||
}); | ||
|
||
it("serializes a matrix", () => { | ||
const matrix = Matrix.default(2, 1, 0); | ||
const items = [ | ||
[0, 0], | ||
[0, 0], | ||
[0, 0] | ||
]; | ||
|
||
expect(JSON.stringify(matrix)).toBe(JSON.stringify(items)); | ||
}); | ||
|
||
it("deserializes a matrix", () => { | ||
const items = [ | ||
[0, 0], | ||
[0, 0], | ||
[0, 0] | ||
]; | ||
const matrix = Matrix.default(2, 1, 0); | ||
|
||
expect(Matrix.from(items)).toStrictEqual(matrix); | ||
}); | ||
|
||
it("gets an item", () => { | ||
const matrix = Matrix.default(2, 1, 0); | ||
|
||
expect(matrix.get([1, 1])).toStrictEqual(0); | ||
}); | ||
|
||
it("sets an item", () => { | ||
const matrix = Matrix.default(2, 2, 0); | ||
matrix.set([1, 1], 1); | ||
const items = [ | ||
[0, 0, 0], | ||
[0, 1, 0], | ||
[0, 0, 0] | ||
]; | ||
|
||
expect(matrix).toEqual(items); | ||
}); | ||
|
||
it("checks a pos", () => { | ||
const matrix = Matrix.default(1, 2, 0); | ||
|
||
expect(matrix.check([1, 1])).toBe(true); | ||
expect(matrix.check([1, 2])).toBe(true); | ||
|
||
expect(matrix.check([1, 3])).toBe(false); | ||
expect(matrix.check([0, 1])).toBe(false); | ||
expect(matrix.check([2, 1])).toBe(false); | ||
expect(matrix.check([1, 0])).toBe(false); | ||
}); | ||
|
||
it("returns all positions", () => { | ||
const matrix = Matrix.default(1, 2, 0); | ||
const positions = [ | ||
[1, 1], | ||
[1, 2] | ||
]; | ||
|
||
expect(matrix.positions()).toStrictEqual(positions); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
import { isEqual } from "lodash"; | ||
|
||
import { Patch } from "./patch"; | ||
|
||
/** | ||
* Positions in a Matrix. | ||
*/ | ||
export type Pos = [number, number]; | ||
|
||
/** | ||
* Basic matrix extended from two-dimensional Array. | ||
* | ||
* A Matrix supports indexing, updating, diffing and patching. | ||
*/ | ||
export class Matrix<Item> extends Array<Item[]> { | ||
/** | ||
* Matrix height. | ||
*/ | ||
get height() { | ||
return this.length - 1; | ||
} | ||
|
||
/** | ||
* Matrix width. | ||
*/ | ||
get width() { | ||
return this[0].length - 1; | ||
} | ||
|
||
/** | ||
* Not meant to be called directly. | ||
*/ | ||
private constructor(...args: ConstructorParameters<typeof Array<Item[]>>) { | ||
super(...args); | ||
} | ||
|
||
/** | ||
* Creates a Matrix from iterables. | ||
*/ | ||
static from<Item>(iterables: Item[][]) { | ||
return new this(...iterables); | ||
} | ||
|
||
/** | ||
* Creates a Matrix with the given width and height, | ||
* filling in the default value resolved by a function provided by the caller. | ||
* | ||
* The function will be called each time to produce an isolated value. | ||
*/ | ||
static defaultWith<Item>( | ||
height: number, | ||
width: number, | ||
defaultFunction: () => Item | ||
) { | ||
const matrix = new this<Item>(); | ||
|
||
for (let i = 0; i <= height; i++) { | ||
matrix.push([]); | ||
|
||
for (let j = 0; j <= width; j++) { | ||
matrix[i].push(defaultFunction()); | ||
} | ||
} | ||
|
||
return matrix; | ||
} | ||
|
||
/** | ||
* Creates a Matrix with the given width and height, | ||
* filling in the default value provided by the caller. | ||
* | ||
* This function uses Matrix.defaultWith internally. | ||
*/ | ||
static default<Item>(height: number, width: number, defaultValue: Item) { | ||
return this.defaultWith(height, width, () => defaultValue); | ||
} | ||
|
||
/** | ||
* Gets a particular item. | ||
*/ | ||
get([x, y]: Pos) { | ||
return this[x][y]; | ||
} | ||
|
||
/** | ||
* Updates a particular item. | ||
*/ | ||
set([x, y]: Pos, item: Item) { | ||
this[x][y] = item; | ||
} | ||
|
||
/** | ||
* Checks whether the position is in the Matrix. | ||
*/ | ||
check([x, y]: Pos) { | ||
return x >= 1 && x <= this.height && y >= 1 && y <= this.width; | ||
} | ||
|
||
/** | ||
* Returns an array of all positions in the Matrix for iterating. | ||
*/ | ||
positions() { | ||
const ans = []; | ||
|
||
for (let i = 1; i <= this.height; i++) { | ||
for (let j = 1; j <= this.width; j++) { | ||
ans.push([i, j] as Pos); | ||
} | ||
} | ||
|
||
return ans; | ||
} | ||
|
||
/** | ||
* Diffs two matrices and returns the Patch array. | ||
*/ | ||
diff(other: Matrix<Item>) { | ||
return this.positions() | ||
.filter(pos => !isEqual(this.get(pos), other.get(pos))) | ||
.map(pos => new Patch(pos, other.get(pos))); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import { expect, it } from "vitest"; | ||
|
||
import type { Pos } from "./matrix"; | ||
import { Matrix } from "./matrix"; | ||
import { Patch } from "./patch"; | ||
|
||
it("creates a patch", () => { | ||
const pos: Pos = [1, 2], | ||
item = 0; | ||
const patch = new Patch(pos, item); | ||
|
||
expect(patch.pos).toBe(pos); | ||
expect(patch.item).toBe(item); | ||
}); | ||
|
||
it("diffs two matrices", () => { | ||
const a = Matrix.from([ | ||
[0, 0, 0], | ||
[0, 1, 0], | ||
[0, 1, 0] | ||
]); | ||
|
||
const b = Matrix.from([ | ||
[0, 0, 0], | ||
[0, 1, 0], | ||
[0, 2, 3] | ||
]); | ||
|
||
const aDiffB = [ | ||
[[2, 1], 2], | ||
[[2, 2], 3] | ||
]; | ||
|
||
const bDiffA = [ | ||
[[2, 1], 1], | ||
[[2, 2], 0] | ||
]; | ||
|
||
expect(a.diff(b)).toEqual(aDiffB); | ||
expect(b.diff(a)).toEqual(bDiffA); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import type { Pos } from "./matrix"; | ||
|
||
/** | ||
* A single patch object consisting of a position and an item. | ||
*/ | ||
export class Patch<Item> extends Array<Pos | Item> { | ||
/** | ||
* Patch position. | ||
*/ | ||
get pos() { | ||
return this[0] as Pos; | ||
} | ||
|
||
/** | ||
* Patch item. | ||
*/ | ||
get item() { | ||
return this[1] as Item; | ||
} | ||
|
||
/** | ||
* Creates a new Patch with the given position and item. | ||
*/ | ||
constructor(pos: Pos, item: Item) { | ||
super(pos, item); | ||
} | ||
} |
Oops, something went wrong.