Skip to content

Commit 3d342d0

Browse files
authored
docs/roadmap updates (#55)
* chore: resolve rebase conflicts in examples registry * feat(data): add UnionFind (disjoint set union) with path compression; docs + tests * docs(roadmap): mark circle collision, raycasting, union-find, and maxflow as completed * ci: retrigger for clean base * fix: resolve stray conflict markers in spatial exports
1 parent 1e9b7c1 commit 3d342d0

6 files changed

Lines changed: 117 additions & 8 deletions

File tree

ROADMAP.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
- [x] Diamond-square terrain height map generator
4343
- [x] L-system generator for foliage and organic structures
4444
- [x] Dungeon generation suite (BSP subdivision, rooms & corridors variants)
45-
- [ ] Maze algorithms pack (Recursive backtracking ✅, Prim's ✅, Kruskal's ✅, Wilson's ✅, Aldous–Broder ✅, Recursive Division ✅)
45+
- [x] Maze algorithms pack (Recursive backtracking ✅, Prim's ✅, Kruskal's ✅, Wilson's ✅, Aldous–Broder ✅, Recursive Division ✅)
4646
- Gameplay systems & utilities:
4747
- [x] Fixed-timestep game loop utility with interpolation helpers
4848
- [x] Delta-time manager for frame-independent timing
@@ -95,15 +95,15 @@
9595
**Graph algorithms**
9696
- [x] Minimum spanning tree (Kruskal)
9797
- [x] Strongly connected components (Tarjan/Kosaraju)
98-
- [ ] Maximum flow (Dinic preferred; Edmonds–Karp fallback)
98+
- [x] Maximum flow (Dinic preferred; Edmonds–Karp fallback)
9999
**Spatial & collision expansion**
100100
- [ ] Octree partitioning for 3D space
101-
- [ ] Circle collision helpers
102-
- [ ] Raycasting utilities
101+
- [x] Circle collision helpers
102+
- [x] Raycasting utilities
103103
- [ ] Bounding volume hierarchy (BVH) builder
104104
**Data structures**
105105
- [ ] Binary heap priority queue
106-
- [ ] Disjoint set union (union-find)
106+
- [x] Disjoint set union (union-find)
107107
- [ ] Bloom filter probabilistic membership
108108
- [ ] Skip list sorted structure
109109
- [ ] Segment tree range query helper

docs/index.d.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,9 @@ export const examples: {
9494
readonly flatten: 'examples/jsonDiff.ts';
9595
readonly unflatten: 'examples/jsonDiff.ts';
9696
readonly paginate: 'examples/pagination.ts';
97+
readonly diffTree: 'examples/treeDiff.ts';
98+
readonly applyTreeDiff: 'examples/treeDiff.ts';
99+
readonly UnionFind: 'examples/graph.ts';
97100
};
98101
readonly performance: {
99102
readonly debounce: 'examples/requestDedup.ts';
@@ -2926,6 +2929,20 @@ export function groupBy<T>(
29262929
key: keyof T | ((item: T) => string)
29272930
): Record<string, T[]>;
29282931

2932+
/**
2933+
* Disjoint Set Union (Union-Find) with path compression and union by size.
2934+
* Use for: connectivity queries, Kruskal MST, clustering.
2935+
* Import: data/unionFind.ts
2936+
*/
2937+
export class UnionFind<T = number> {
2938+
constructor(elements?: Iterable<T>);
2939+
makeSet(x: T): void;
2940+
find(x: T): T;
2941+
union(a: T, b: T): boolean;
2942+
connected(a: T, b: T): boolean;
2943+
size(x: T): number;
2944+
}
2945+
29292946
// ============================================================================
29302947
// 📈 GRAPH ALGORITHMS
29312948
// ============================================================================

src/data/unionFind.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/**
2+
* Disjoint Set Union (Union-Find) with path compression and union by size.
3+
* Useful for: connectivity queries, Kruskal MST, clustering.
4+
*/
5+
export class UnionFind<T = number> {
6+
private parent = new Map<T, T>();
7+
private compSize = new Map<T, number>();
8+
9+
constructor(elements?: Iterable<T>) {
10+
if (elements) {
11+
for (const el of elements) {
12+
this.makeSet(el);
13+
}
14+
}
15+
}
16+
17+
makeSet(x: T): void {
18+
if (!this.parent.has(x)) {
19+
this.parent.set(x, x);
20+
this.compSize.set(x, 1);
21+
}
22+
}
23+
24+
find(x: T): T {
25+
if (!this.parent.has(x)) this.makeSet(x);
26+
const direct = this.parent.get(x);
27+
let p: T = direct === undefined ? x : (direct as T);
28+
if (p !== x) {
29+
p = this.find(p);
30+
this.parent.set(x, p);
31+
}
32+
return p;
33+
}
34+
35+
union(a: T, b: T): boolean {
36+
let ra = this.find(a);
37+
let rb = this.find(b);
38+
if (ra === rb) return false;
39+
const sa = this.compSize.get(ra)!;
40+
const sb = this.compSize.get(rb)!;
41+
if (sa < sb) {
42+
const tmp = ra;
43+
ra = rb;
44+
rb = tmp;
45+
}
46+
// attach rb under ra
47+
this.parent.set(rb, ra);
48+
this.compSize.set(ra, sa + sb);
49+
this.compSize.delete(rb);
50+
return true;
51+
}
52+
53+
connected(a: T, b: T): boolean {
54+
return this.find(a) === this.find(b);
55+
}
56+
57+
size(x: T): number {
58+
return this.compSize.get(this.find(x)) ?? 1;
59+
}
60+
}

src/index.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ export const examples = {
9494
paginate: 'examples/pagination.ts',
9595
diffTree: 'examples/treeDiff.ts',
9696
applyTreeDiff: 'examples/treeDiff.ts',
97+
UnionFind: 'examples/graph.ts',
9798
},
9899
performance: {
99100
debounce: 'examples/requestDedup.ts',
@@ -412,7 +413,6 @@ export { satCollision } from './spatial/sat.js';
412413
*/
413414
export { circleRayIntersection } from './spatial/circleRay.js';
414415
/**
415-
<<<<<<< HEAD
416416
* Fast circle-circle overlap test.
417417
*
418418
* Example file: examples/circle.ts
@@ -430,7 +430,7 @@ export { circleAabbCollision } from './spatial/circleCollision.js';
430430
* Example file: examples/circle.ts
431431
*/
432432
export { circleSegmentIntersection } from './spatial/circleCollision.js';
433-
=======
433+
/**
434434
* Ray vs. segment intersection test returning closest hit.
435435
*
436436
* Example file: examples/raycast.ts
@@ -442,7 +442,6 @@ export { raycastSegment } from './spatial/raycast.js';
442442
* Example file: examples/raycast.ts
443443
*/
444444
export { raycastAabb } from './spatial/raycast.js';
445-
>>>>>>> 83f962b (feat(spatial): add raycasting utilities (raycastSegment, raycastAabb); docs + tests + example)
446445

447446
/**
448447
* Continuous swept AABB collision detection for moving boxes.
@@ -1021,6 +1020,12 @@ export type {
10211020
* Tree diff helpers for hierarchical data.
10221021
*/
10231022
export { diffTree, applyTreeDiff } from './data/treeDiff.js';
1023+
/**
1024+
* Disjoint Set Union (Union-Find) with path compression and union by size.
1025+
*
1026+
* Example file: examples/graph.ts
1027+
*/
1028+
export { UnionFind } from './data/unionFind.js';
10241029

10251030
export type {
10261031
TreeNode,

tests/index.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ describe('package entry point', () => {
123123
| 'paginate'
124124
| 'diffTree'
125125
| 'applyTreeDiff'
126+
| 'UnionFind'
126127
>();
127128

128129
expectTypeOf<ExampleName<'search'>>().toEqualTypeOf<

tests/unionFind.test.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { describe, it, expect } from 'vitest';
2+
import { UnionFind } from '../src/index.js';
3+
4+
describe('UnionFind', () => {
5+
it('unions and finds components for numbers', () => {
6+
const uf = new UnionFind([0, 1, 2, 3, 4]);
7+
uf.union(0, 1);
8+
uf.union(2, 3);
9+
expect(uf.connected(0, 1)).toBe(true);
10+
expect(uf.connected(0, 2)).toBe(false);
11+
uf.union(1, 2);
12+
expect(uf.connected(0, 3)).toBe(true);
13+
expect(uf.size(0)).toBe(4);
14+
expect(uf.size(4)).toBe(1);
15+
});
16+
17+
it('supports string keys', () => {
18+
const uf = new UnionFind<string>(['a', 'b', 'c']);
19+
uf.union('a', 'b');
20+
expect(uf.connected('a', 'b')).toBe(true);
21+
expect(uf.connected('a', 'c')).toBe(false);
22+
uf.makeSet('d');
23+
expect(uf.size('d')).toBe(1);
24+
});
25+
});
26+

0 commit comments

Comments
 (0)