@mborecki/geo2d 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/node_modules/@mb-puzzle/grid/package.json +22 -0
- package/node_modules/@mb-puzzle/grid/src/grid.test.ts +26 -0
- package/node_modules/@mb-puzzle/grid/src/grid.ts +75 -0
- package/node_modules/@mb-puzzle/grid/tsconfig.json +44 -0
- package/node_modules/@mb-puzzle/grid/vitest.config.ts +5 -0
- package/node_modules/@mb-puzzle/vec2/package.json +19 -0
- package/node_modules/@mb-puzzle/vec2/src/vec2.test.ts +55 -0
- package/node_modules/@mb-puzzle/vec2/src/vec2.ts +83 -0
- package/node_modules/@mb-puzzle/vec2/tsconfig.json +44 -0
- package/node_modules/@mb-puzzle/vec2/vitest.config.ts +5 -0
- package/package.json +5 -1
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mb-puzzle/grid",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"description": "",
|
|
6
|
+
"main": "./src/grid.ts",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"test": "vitest"
|
|
10
|
+
},
|
|
11
|
+
"keywords": [],
|
|
12
|
+
"author": "",
|
|
13
|
+
"license": "ISC",
|
|
14
|
+
"packageManager": "pnpm@10.15.0",
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"@mb-puzzle/vec2": "workspace:*"
|
|
17
|
+
},
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"vitest": "catalog:",
|
|
20
|
+
"typescript": "catalog:"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { describe, expect, test } from "vitest";
|
|
2
|
+
import { Grid } from "./grid.js";
|
|
3
|
+
import { Vec2 } from "@mb-puzzle/vec2";
|
|
4
|
+
|
|
5
|
+
describe('Grid', () => {
|
|
6
|
+
describe('static', () => {
|
|
7
|
+
describe('getAllIndexes', () => {
|
|
8
|
+
test('2,2', () => {
|
|
9
|
+
const result = Grid.getAllIndexes(new Vec2(2, 2));
|
|
10
|
+
expect(result).toMatchObject([0, 1, 2, 3]);
|
|
11
|
+
})
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
describe('getAllCells', () => {
|
|
15
|
+
test('2,2', () => {
|
|
16
|
+
const result = Grid.getAllCells(new Vec2(2, 2));
|
|
17
|
+
expect(result).toMatchObject([
|
|
18
|
+
new Vec2(0,0),
|
|
19
|
+
new Vec2(1,0),
|
|
20
|
+
new Vec2(0,1),
|
|
21
|
+
new Vec2(1,1),
|
|
22
|
+
]);
|
|
23
|
+
})
|
|
24
|
+
})
|
|
25
|
+
})
|
|
26
|
+
})
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { Vec2 } from '@mb-puzzle/vec2';
|
|
2
|
+
|
|
3
|
+
export class Grid {
|
|
4
|
+
private size: Vec2;
|
|
5
|
+
constructor(size: Vec2) {
|
|
6
|
+
if (size.x <= 0 || size.y <= 0) {
|
|
7
|
+
throw new Error(`Invalid grid size: width and height must be positive (got ${size.x}x${size.y})`);
|
|
8
|
+
}
|
|
9
|
+
this.size = size;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
getIndexFromVec(v: Vec2): number {
|
|
13
|
+
return Grid.getIndexFromVec(v, this.size.width);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
getVecFromIndex(index: number): Vec2 {
|
|
17
|
+
return Grid.getVecFromIndex(index, this.size.width);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
getAllIndexes(): number[] {
|
|
21
|
+
return Grid.getAllIndexes(this.size);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
getAllCells(): Vec2[] {
|
|
25
|
+
return Grid.getAllCells(this.size);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
isBlack(v: Vec2): boolean {
|
|
29
|
+
return Boolean((v.x + v.y) % 2)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
isWhite(v: Vec2): boolean {
|
|
33
|
+
return !Boolean((v.x + v.y) % 2)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
isInGrid(v: Vec2) {
|
|
37
|
+
return Grid.isInGrid(v, this.size);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
static getAllIndexes(v: Vec2): number[] {
|
|
41
|
+
return Array(v.width * v.height).fill(true).map((_, i) => i);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
static getAllCells(v: Vec2): Vec2[] {
|
|
45
|
+
return Array(v.width * v.height).fill(true).map((_, i) => Grid.getVecFromIndex(i, v.width));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
static getVecFromIndex(index: number, width: number | Vec2): Vec2 {
|
|
49
|
+
const _w = width instanceof Vec2 ? width.width : width;
|
|
50
|
+
const x = index % _w;
|
|
51
|
+
const y = Math.floor(index / _w);
|
|
52
|
+
return new Vec2(x, y)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
static getIndexFromVec(v: Vec2, width: number | Vec2): number {
|
|
56
|
+
const _w = width instanceof Vec2 ? width.width : width;
|
|
57
|
+
return v.y * _w + v.x;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
static isInGrid(v: Vec2, size: Vec2) {
|
|
61
|
+
return v.x >= 0 && size.x > v.x && v.y >= 0 && size.y > v.y;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
static getOrtoSiblings(v: Vec2, size: Vec2): Vec2[] {
|
|
65
|
+
const dirs = [
|
|
66
|
+
new Vec2(-1, 0),
|
|
67
|
+
new Vec2(1, 0),
|
|
68
|
+
new Vec2(0, -1),
|
|
69
|
+
new Vec2(0, 1),
|
|
70
|
+
]
|
|
71
|
+
|
|
72
|
+
return dirs.map(d => d.add(v))
|
|
73
|
+
.filter(v => Grid.isInGrid(v, size));
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
// Visit https://aka.ms/tsconfig to read more about this file
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
// File Layout
|
|
5
|
+
// "rootDir": "./src",
|
|
6
|
+
// "outDir": "./dist",
|
|
7
|
+
|
|
8
|
+
// Environment Settings
|
|
9
|
+
// See also https://aka.ms/tsconfig/module
|
|
10
|
+
"module": "nodenext",
|
|
11
|
+
"moduleResolution": "nodenext",
|
|
12
|
+
"target": "esnext",
|
|
13
|
+
"types": [],
|
|
14
|
+
// For nodejs:
|
|
15
|
+
// "lib": ["esnext"],
|
|
16
|
+
// "types": ["node"],
|
|
17
|
+
// and npm install -D @types/node
|
|
18
|
+
|
|
19
|
+
// Other Outputs
|
|
20
|
+
"sourceMap": true,
|
|
21
|
+
"declaration": true,
|
|
22
|
+
"declarationMap": true,
|
|
23
|
+
|
|
24
|
+
// Stricter Typechecking Options
|
|
25
|
+
"noUncheckedIndexedAccess": true,
|
|
26
|
+
"exactOptionalPropertyTypes": true,
|
|
27
|
+
|
|
28
|
+
// Style Options
|
|
29
|
+
// "noImplicitReturns": true,
|
|
30
|
+
// "noImplicitOverride": true,
|
|
31
|
+
// "noUnusedLocals": true,
|
|
32
|
+
// "noUnusedParameters": true,
|
|
33
|
+
// "noFallthroughCasesInSwitch": true,
|
|
34
|
+
// "noPropertyAccessFromIndexSignature": true,
|
|
35
|
+
|
|
36
|
+
// Recommended Options
|
|
37
|
+
"strict": true,
|
|
38
|
+
"jsx": "react-jsx",
|
|
39
|
+
"isolatedModules": true,
|
|
40
|
+
"noUncheckedSideEffectImports": true,
|
|
41
|
+
"moduleDetection": "force",
|
|
42
|
+
"skipLibCheck": true,
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mb-puzzle/vec2",
|
|
3
|
+
"version": "0.5.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"description": "",
|
|
6
|
+
"main": "./src/vec2.ts",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"test": "vitest"
|
|
10
|
+
},
|
|
11
|
+
"keywords": [],
|
|
12
|
+
"author": "",
|
|
13
|
+
"license": "ISC",
|
|
14
|
+
"packageManager": "pnpm@10.15.0",
|
|
15
|
+
"devDependencies": {
|
|
16
|
+
"vitest": "catalog:",
|
|
17
|
+
"typescript": "catalog:"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { Vec2 } from "./vec2"
|
|
3
|
+
|
|
4
|
+
describe('Vec2', () => {
|
|
5
|
+
describe('getters', () => {
|
|
6
|
+
it('[0]', () => {
|
|
7
|
+
const v = new Vec2(1, 2);
|
|
8
|
+
expect(v[0]).toBe(1);
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
it('[1]', () => {
|
|
12
|
+
const v = new Vec2(1, 2);
|
|
13
|
+
expect(v[1]).toBe(2);
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
it('x', () => {
|
|
17
|
+
const v = new Vec2(1, 2);
|
|
18
|
+
expect(v.x).toBe(1);
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
it('y', () => {
|
|
22
|
+
const v = new Vec2(1, 2);
|
|
23
|
+
expect(v.y).toBe(2);
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
it('iterator', () => {
|
|
27
|
+
const v = new Vec2(1, 2);
|
|
28
|
+
expect([...v]).toMatchObject([1, 2]);
|
|
29
|
+
})
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
describe('from()', () => {
|
|
33
|
+
it('number', () => {
|
|
34
|
+
const v = Vec2.from(3);
|
|
35
|
+
expect(v.x).toBe(3);
|
|
36
|
+
expect(v.y).toBe(3);
|
|
37
|
+
})
|
|
38
|
+
it('array', () => {
|
|
39
|
+
const v = Vec2.from([1, 2]);
|
|
40
|
+
expect(v.x).toBe(1);
|
|
41
|
+
expect(v.y).toBe(2);
|
|
42
|
+
})
|
|
43
|
+
it('object', () => {
|
|
44
|
+
const v = Vec2.from({ x: 1, y: 2 });
|
|
45
|
+
expect(v.x).toBe(1);
|
|
46
|
+
expect(v.y).toBe(2);
|
|
47
|
+
})
|
|
48
|
+
it('object+', () => {
|
|
49
|
+
const obj = { x: 1, y: 2, id: 'foobar' }
|
|
50
|
+
const v = Vec2.from(obj);
|
|
51
|
+
expect(v.x).toBe(1);
|
|
52
|
+
expect(v.y).toBe(2);
|
|
53
|
+
})
|
|
54
|
+
})
|
|
55
|
+
})
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
export interface Vec2ParsableObject {x: number, y: number}
|
|
2
|
+
|
|
3
|
+
export type Vec2Source = number | number[] | Required<Vec2ParsableObject>;
|
|
4
|
+
|
|
5
|
+
export class Vec2 {
|
|
6
|
+
|
|
7
|
+
x: number;
|
|
8
|
+
y: number;
|
|
9
|
+
|
|
10
|
+
get 0(): number {
|
|
11
|
+
return this.x;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
set 0(x: number) {
|
|
15
|
+
this.x = x;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
get 1(): number {
|
|
19
|
+
return this.y;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
set 1(y: number) {
|
|
23
|
+
this.y = y;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
get width() {
|
|
27
|
+
return this.x;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
set width(x: number) {
|
|
31
|
+
this.x = x;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
get height() {
|
|
35
|
+
return this.y;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
set height(y: number) {
|
|
39
|
+
this.y = y;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
get xy() {
|
|
43
|
+
return [this.x, this.y]
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
*[Symbol.iterator]() {
|
|
47
|
+
yield this.x;
|
|
48
|
+
yield this.y;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
constructor(x: number, y: number) {
|
|
52
|
+
this.x = x;
|
|
53
|
+
this.y = y;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
add(v: Vec2): Vec2 {
|
|
57
|
+
return new Vec2(this.x + v.x, this.y + v.y);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
eq(v: Vec2): boolean {
|
|
61
|
+
return this.x === v.x && this.y === v.y;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
clone(): Vec2 {
|
|
65
|
+
return new Vec2(this.x, this.y);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
static from(source: Vec2Source): Vec2 {
|
|
69
|
+
if (typeof source === 'number') {
|
|
70
|
+
return new Vec2(source, source);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (Array.isArray(source)) {
|
|
74
|
+
return new Vec2(source[0] ?? 0, source[1] ?? 0);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (typeof source === 'object' && typeof source.x === 'number' && typeof source.y === 'number') {
|
|
78
|
+
return new Vec2(source.x, source.y);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
throw new Error('Wrong Vec2 source');
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
// Visit https://aka.ms/tsconfig to read more about this file
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
// File Layout
|
|
5
|
+
// "rootDir": "./src",
|
|
6
|
+
// "outDir": "./dist",
|
|
7
|
+
|
|
8
|
+
// Environment Settings
|
|
9
|
+
// See also https://aka.ms/tsconfig/module
|
|
10
|
+
"module": "nodenext",
|
|
11
|
+
"moduleResolution": "nodenext",
|
|
12
|
+
"target": "esnext",
|
|
13
|
+
"types": [],
|
|
14
|
+
// For nodejs:
|
|
15
|
+
// "lib": ["esnext"],
|
|
16
|
+
// "types": ["node"],
|
|
17
|
+
// and npm install -D @types/node
|
|
18
|
+
|
|
19
|
+
// Other Outputs
|
|
20
|
+
"sourceMap": true,
|
|
21
|
+
"declaration": true,
|
|
22
|
+
"declarationMap": true,
|
|
23
|
+
|
|
24
|
+
// Stricter Typechecking Options
|
|
25
|
+
"noUncheckedIndexedAccess": true,
|
|
26
|
+
"exactOptionalPropertyTypes": true,
|
|
27
|
+
|
|
28
|
+
// Style Options
|
|
29
|
+
// "noImplicitReturns": true,
|
|
30
|
+
// "noImplicitOverride": true,
|
|
31
|
+
// "noUnusedLocals": true,
|
|
32
|
+
// "noUnusedParameters": true,
|
|
33
|
+
// "noFallthroughCasesInSwitch": true,
|
|
34
|
+
// "noPropertyAccessFromIndexSignature": true,
|
|
35
|
+
|
|
36
|
+
// Recommended Options
|
|
37
|
+
"strict": true,
|
|
38
|
+
"jsx": "react-jsx",
|
|
39
|
+
"isolatedModules": true,
|
|
40
|
+
"noUncheckedSideEffectImports": true,
|
|
41
|
+
"moduleDetection": "force",
|
|
42
|
+
"skipLibCheck": true,
|
|
43
|
+
}
|
|
44
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mborecki/geo2d",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "index.ts",
|
|
6
6
|
"keywords": [],
|
|
@@ -10,5 +10,9 @@
|
|
|
10
10
|
"@mb-puzzle/vec2": "",
|
|
11
11
|
"@mb-puzzle/grid": ""
|
|
12
12
|
},
|
|
13
|
+
"bundleDependencies": [
|
|
14
|
+
"@mb-puzzle/vec2",
|
|
15
|
+
"@mb-puzzle/grid"
|
|
16
|
+
],
|
|
13
17
|
"scripts": {}
|
|
14
18
|
}
|