refactor: add some part management utilities
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
import {Part} from "./part";
|
||||
|
||||
export type PartTemplate<TMeta = {}> = Omit<Partial<Part<TMeta>>, 'id'> & TMeta;
|
||||
|
||||
export type PartPool<TMeta = {}> = {
|
||||
parts: Part<TMeta>[];
|
||||
template: PartTemplate<TMeta>;
|
||||
draw(): Part<TMeta> | undefined;
|
||||
return(part: Part<TMeta>): void;
|
||||
remaining(): number;
|
||||
};
|
||||
|
||||
export function createPart<TMeta = {}>(
|
||||
template: PartTemplate<TMeta>,
|
||||
id: string
|
||||
): Part<TMeta> {
|
||||
return {
|
||||
regionId: '',
|
||||
position: [],
|
||||
...template,
|
||||
id,
|
||||
} as Part<TMeta>;
|
||||
}
|
||||
|
||||
export function createParts<TMeta = {}>(
|
||||
template: PartTemplate<TMeta>,
|
||||
count: number,
|
||||
idPrefix: string
|
||||
): Part<TMeta>[] {
|
||||
const parts: Part<TMeta>[] = [];
|
||||
for (let i = 0; i < count; i++) {
|
||||
parts.push(createPart(template, `${idPrefix}-${i + 1}`));
|
||||
}
|
||||
return parts;
|
||||
}
|
||||
|
||||
export function createPartPool<TMeta = {}>(
|
||||
template: PartTemplate<TMeta>,
|
||||
count: number,
|
||||
idPrefix: string
|
||||
): PartPool<TMeta> {
|
||||
const parts = createParts(template, count, idPrefix);
|
||||
const available = [...parts];
|
||||
|
||||
return {
|
||||
parts,
|
||||
template,
|
||||
draw() {
|
||||
return available.pop();
|
||||
},
|
||||
return(part: Part<TMeta>) {
|
||||
part.regionId = '';
|
||||
part.position = [];
|
||||
available.push(part);
|
||||
},
|
||||
remaining() {
|
||||
return available.length;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function mergePartPools<TMeta = {}>(
|
||||
...pools: PartPool<TMeta>[]
|
||||
): PartPool<TMeta> {
|
||||
if (pools.length === 0) {
|
||||
return createPartPool({} as PartTemplate<TMeta>, 0, 'merged');
|
||||
}
|
||||
|
||||
const allParts = pools.flatMap(p => p.parts);
|
||||
const template = pools[0].template;
|
||||
const available = allParts.filter(p => p.regionId === '');
|
||||
|
||||
return {
|
||||
parts: allParts,
|
||||
template,
|
||||
draw() {
|
||||
return available.pop();
|
||||
},
|
||||
return(part: Part<TMeta>) {
|
||||
part.regionId = '';
|
||||
part.position = [];
|
||||
available.push(part);
|
||||
},
|
||||
remaining() {
|
||||
return available.length;
|
||||
},
|
||||
};
|
||||
}
|
||||
+19
-5
@@ -1,6 +1,6 @@
|
||||
import {RNG} from "@/utils/rng";
|
||||
|
||||
export type Part = {
|
||||
export type Part<TMeta = {}> = {
|
||||
id: string;
|
||||
|
||||
sides?: number;
|
||||
@@ -10,19 +10,33 @@ export type Part = {
|
||||
alignment?: string;
|
||||
regionId: string;
|
||||
position: number[];
|
||||
}
|
||||
} & TMeta;
|
||||
|
||||
export function flip(part: Part) {
|
||||
export function flip<TMeta>(part: Part<TMeta>) {
|
||||
if(!part.sides) return;
|
||||
part.side = ((part.side || 0) + 1) % part.sides;
|
||||
}
|
||||
|
||||
export function flipTo(part: Part, side: number) {
|
||||
export function flipTo<TMeta>(part: Part<TMeta>, side: number) {
|
||||
if(!part.sides || side >= part.sides) return;
|
||||
part.side = side;
|
||||
}
|
||||
|
||||
export function roll(part: Part, rng: RNG) {
|
||||
export function roll<TMeta>(part: Part<TMeta>, rng: RNG) {
|
||||
if(!part.sides) return;
|
||||
part.side = rng.nextInt(part.sides);
|
||||
}
|
||||
|
||||
export function findPartById<TMeta>(parts: Part<TMeta>[], id: string): Part<TMeta> | undefined {
|
||||
return parts.find(p => p.id === id);
|
||||
}
|
||||
|
||||
export function isCellOccupied<TMeta>(parts: Part<TMeta>[], regionId: string, position: number[]): boolean {
|
||||
const posKey = position.join(',');
|
||||
return parts.some(p => p.regionId === regionId && p.position.join(',') === posKey);
|
||||
}
|
||||
|
||||
export function getPartAtPosition<TMeta>(parts: Part<TMeta>[], regionId: string, position: number[]): Part<TMeta> | undefined {
|
||||
const posKey = position.join(',');
|
||||
return parts.find(p => p.regionId === regionId && p.position.join(',') === posKey);
|
||||
}
|
||||
|
||||
+14
-10
@@ -24,7 +24,7 @@ export function createRegion(id: string, axes: RegionAxis[]): Region {
|
||||
};
|
||||
}
|
||||
|
||||
function buildPartMap(region: Region, parts: Record<string, Part>) {
|
||||
function buildPartMap<TMeta>(region: Region, parts: Record<string, Part<TMeta>>) {
|
||||
const map: Record<string, string> = {};
|
||||
for (const childId of region.childIds) {
|
||||
const part = parts[childId];
|
||||
@@ -35,7 +35,7 @@ function buildPartMap(region: Region, parts: Record<string, Part>) {
|
||||
return map;
|
||||
}
|
||||
|
||||
export function applyAlign(region: Region, parts: Record<string, Part>) {
|
||||
export function applyAlign<TMeta>(region: Region, parts: Record<string, Part<TMeta>>) {
|
||||
if (region.childIds.length === 0) return;
|
||||
|
||||
for (let axisIndex = 0; axisIndex < region.axes.length; axisIndex++) {
|
||||
@@ -98,7 +98,7 @@ export function applyAlign(region: Region, parts: Record<string, Part>) {
|
||||
region.partMap = buildPartMap(region, parts);
|
||||
}
|
||||
|
||||
export function shuffle(region: Region, parts: Record<string, Part>, rng: RNG){
|
||||
export function shuffle<TMeta>(region: Region, parts: Record<string, Part<TMeta>>, rng: RNG){
|
||||
if (region.childIds.length <= 1) return;
|
||||
|
||||
const childIds = [...region.childIds];
|
||||
@@ -117,9 +117,11 @@ export function shuffle(region: Region, parts: Record<string, Part>, rng: RNG){
|
||||
region.partMap = buildPartMap(region, parts);
|
||||
}
|
||||
|
||||
export function moveToRegion(part: Part, sourceRegion: Region, targetRegion: Region, position?: number[]) {
|
||||
sourceRegion.childIds = sourceRegion.childIds.filter(id => id !== part.id);
|
||||
delete sourceRegion.partMap[part.position.join(',')];
|
||||
export function moveToRegion<TMeta>(part: Part<TMeta>, sourceRegion: Region | null, targetRegion: Region, position?: number[]) {
|
||||
if (sourceRegion && part.regionId === sourceRegion.id) {
|
||||
sourceRegion.childIds = sourceRegion.childIds.filter(id => id !== part.id);
|
||||
delete sourceRegion.partMap[part.position.join(',')];
|
||||
}
|
||||
|
||||
targetRegion.childIds.push(part.id);
|
||||
if (position) {
|
||||
@@ -130,11 +132,13 @@ export function moveToRegion(part: Part, sourceRegion: Region, targetRegion: Reg
|
||||
part.regionId = targetRegion.id;
|
||||
}
|
||||
|
||||
export function moveToRegionAll(parts: Part[], sourceRegion: Region, targetRegion: Region, positions?: number[][]) {
|
||||
export function moveToRegionAll<TMeta>(parts: Part<TMeta>[], sourceRegion: Region | null, targetRegion: Region, positions?: number[][]) {
|
||||
for (let i = 0; i < parts.length; i++) {
|
||||
const part = parts[i];
|
||||
sourceRegion.childIds = sourceRegion.childIds.filter(id => id !== part.id);
|
||||
delete sourceRegion.partMap[part.position.join(',')];
|
||||
if (sourceRegion && part.regionId === sourceRegion.id) {
|
||||
sourceRegion.childIds = sourceRegion.childIds.filter(id => id !== part.id);
|
||||
delete sourceRegion.partMap[part.position.join(',')];
|
||||
}
|
||||
|
||||
targetRegion.childIds.push(part.id);
|
||||
if (positions && positions[i]) {
|
||||
@@ -146,7 +150,7 @@ export function moveToRegionAll(parts: Part[], sourceRegion: Region, targetRegio
|
||||
}
|
||||
}
|
||||
|
||||
export function removeFromRegion(part: Part, region: Region) {
|
||||
export function removeFromRegion<TMeta>(part: Part<TMeta>, region: Region) {
|
||||
region.childIds = region.childIds.filter(id => id !== part.id);
|
||||
delete region.partMap[part.position.join(',')];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user