Files
evolution/src/apps/BridgeBuilder/e2e.test.ts
2026-01-17 10:59:57 +11:00

80 lines
3.2 KiB
TypeScript

// E2E Test for Bridge Builder
import { describe, it, expect } from 'bun:test';
import { BridgeSimulation } from './BridgeSimulation';
import { GeneticAlgorithm } from './GeneticAlgo';
import { DEFAULT_BRIDGE_CONFIG, DEFAULT_SIM_CONFIG, DEFAULT_GA_CONFIG } from './types';
import type { BridgeGenome } from './types';
describe('Bridge Builder E2E', () => {
it('should evolve bridges that survive longer than 12 steps', () => {
const ga = new GeneticAlgorithm(DEFAULT_GA_CONFIG);
// Create initial population
const populationSize = 10;
let population: BridgeGenome[] = [];
for (let i = 0; i < populationSize; i++) {
population.push(ga.createRandomGenome(3, 8));
}
console.log('\n=== Bridge Builder E2E Test ===\n');
// Check first genome structure
console.log('First genome sample:');
console.log(` Nodes: ${population[0].nodes.length}`, population[0].nodes.slice(0, 3));
console.log(` Beams: ${population[0].beams.length}`, population[0].beams.slice(0, 5));
// Evolve for 50 generations
for (let gen = 1; gen <= 50; gen++) {
const fitnesses: number[] = [];
const steps: number[] = [];
// Evaluate each genome
for (const genome of population) {
const sim = new BridgeSimulation(genome, DEFAULT_BRIDGE_CONFIG, DEFAULT_SIM_CONFIG);
sim.run(DEFAULT_SIM_CONFIG.maxSteps);
const result = sim.getResult();
fitnesses.push(result.fitness);
steps.push(result.stepsSupported);
}
const maxFitness = Math.max(...fitnesses);
const avgFitness = fitnesses.reduce((a, b) => a + b, 0) / fitnesses.length;
const bestIdx = fitnesses.indexOf(maxFitness);
const maxSteps = Math.max(...steps);
const avgSteps = steps.reduce((a, b) => a + b, 0) / steps.length;
if (gen % 10 === 0 || gen === 1) {
console.log(`Gen ${gen}:`);
console.log(` Fitness: ${avgFitness.toFixed(1)} (best: ${maxFitness.toFixed(1)})`);
console.log(` Steps: ${avgSteps.toFixed(1)} (best: ${maxSteps})`);
console.log(` Best genome: ${population[bestIdx].nodes.length} nodes, ${population[bestIdx].beams.length} beams`);
}
// Evolve population
population = ga.evolve(population, fitnesses);
}
// Final check
const finalFitnesses = population.map(genome => {
const sim = new BridgeSimulation(genome, DEFAULT_BRIDGE_CONFIG, DEFAULT_SIM_CONFIG);
sim.run(DEFAULT_SIM_CONFIG.maxSteps);
return sim.getResult();
});
const bestFinalResult = finalFitnesses.reduce((best, curr) =>
curr.fitness > best.fitness ? curr : best
);
console.log('\n=== Final Results ===');
console.log(`Best fitness: ${bestFinalResult.fitness.toFixed(1)}`);
console.log(`Steps survived: ${bestFinalResult.stepsSupported} / ${DEFAULT_SIM_CONFIG.maxSteps}`);
console.log(`Collapsed: ${bestFinalResult.collapsed}`);
console.log(`Beams: ${bestFinalResult.beamCount}`);
// Test assertions
expect(bestFinalResult.stepsSupported).toBeGreaterThan(12);
expect(bestFinalResult.fitness).toBeGreaterThan(1200);
});
});