import { BREEDING_RECIPES, RACE_GEN } from '@domain/value-objects/Race'; export interface Stock { m: number; f: number; n: number; } export interface CrossingDetail { aSex: string; bSex: string; } export interface CrossingResult { name: string; qty: number; parents: readonly [string, string]; gen: number; details: CrossingDetail[]; } export interface GenerationResult { gen: number; crossings: CrossingResult[]; } export interface InventaireResult { generations: GenerationResult[]; remaining: Record; } export class InventaireCalculator { compute(inventaire: Readonly>): InventaireResult { const avail: Record = {}; for (const [k, v] of Object.entries(inventaire)) { if ((v.m + v.f) > 0) avail[k] = { m: v.m, f: v.f, n: 0 }; } if (Object.keys(avail).length === 0) return { generations: [], remaining: {} }; const hasMale = (s: Stock) => s.m > 0 || s.n > 0; const hasFemale = (s: Stock) => s.f > 0 || s.n > 0; const takeMale = (s: Stock) => { if (s.m > 0) s.m--; else s.n--; }; const takeFemale = (s: Stock) => { if (s.f > 0) s.f--; else s.n--; }; const totalOf = (s: Stock) => s.m + s.f + s.n; const generations: GenerationResult[] = []; for (let gen = 2; gen <= 10; gen++) { const crossingsAtGen = Object.entries(BREEDING_RECIPES) .filter(([name]) => (RACE_GEN[name] ?? 0) === gen) .map(([name, parents]) => ({ name, parents })); const genResults: CrossingResult[] = []; let more = true; while (more) { more = false; for (const cr of crossingsAtGen) { const [a, b] = cr.parents; const sa = avail[a] ?? { m: 0, f: 0, n: 0 }; const sb = avail[b] ?? { m: 0, f: 0, n: 0 }; let ok = false, aSex = '', bSex = ''; if (a === b) { if (totalOf(sa) >= 2 && hasMale(sa) && hasFemale(sa)) { takeMale(sa); takeFemale(sa); aSex = '\u2642'; bSex = '\u2640'; ok = true; } } else if (hasMale(sa) && hasFemale(sb)) { takeMale(sa); takeFemale(sb); aSex = '\u2642'; bSex = '\u2640'; ok = true; } else if (hasFemale(sa) && hasMale(sb)) { takeFemale(sa); takeMale(sb); aSex = '\u2640'; bSex = '\u2642'; ok = true; } if (ok) { if (!avail[a]) avail[a] = sa; if (!avail[b]) avail[b] = sb; if (!avail[cr.name]) avail[cr.name] = { m: 0, f: 0, n: 0 }; avail[cr.name]!.n++; let entry = genResults.find(r => r.name === cr.name); if (!entry) { entry = { name: cr.name, qty: 0, parents: cr.parents as [string, string], gen, details: [] }; genResults.push(entry); } entry.qty++; entry.details.push({ aSex, bSex }); more = true; } } } if (genResults.length > 0) generations.push({ gen, crossings: genResults }); } return { generations, remaining: avail }; } }