Add neat arena

This commit is contained in:
Peter Stockings
2026-01-12 08:58:45 +11:00
parent e9cb8b52df
commit 840e597413
39 changed files with 5717 additions and 193 deletions

View File

@@ -0,0 +1,120 @@
import type { Genome } from './genome';
import type { EvolutionConfig } from './evolution';
/**
* Export/Import system for trained genomes.
*
* Allows saving champion genomes as JSON files and loading them back
* for exhibition matches or continued training.
*/
export interface ExportedGenome {
version: string;
timestamp: number;
config: {
inputCount: number;
outputCount: number;
};
genome: Genome;
metadata?: {
generation?: number;
fitness?: number;
speciesCount?: number;
};
}
const EXPORT_VERSION = '1.0.0';
/**
* Export a genome to a downloadable JSON format
*/
export function exportGenome(
genome: Genome,
config: EvolutionConfig,
metadata?: ExportedGenome['metadata']
): ExportedGenome {
return {
version: EXPORT_VERSION,
timestamp: Date.now(),
config: {
inputCount: config.inputCount,
outputCount: config.outputCount,
},
genome: {
nodes: genome.nodes,
connections: genome.connections,
fitness: genome.fitness,
},
metadata,
};
}
/**
* Import a genome from JSON
*/
export function importGenome(exported: ExportedGenome): {
genome: Genome;
config: { inputCount: number; outputCount: number };
} {
// Version check
if (exported.version !== EXPORT_VERSION) {
console.warn(`Imported genome version ${exported.version} may be incompatible with current version ${EXPORT_VERSION}`);
}
return {
genome: exported.genome,
config: exported.config,
};
}
/**
* Download genome as JSON file
*/
export function downloadGenomeAsFile(exported: ExportedGenome, filename?: string): void {
const json = JSON.stringify(exported, null, 2);
const blob = new Blob([json], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = filename || `neat-champion-${Date.now()}.json`;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(url);
}
/**
* Upload and parse genome from file
*/
export function uploadGenomeFromFile(): Promise<ExportedGenome> {
return new Promise((resolve, reject) => {
const input = document.createElement('input');
input.type = 'file';
input.accept = 'application/json,.json';
input.onchange = (e) => {
const file = (e.target as HTMLInputElement).files?.[0];
if (!file) {
reject(new Error('No file selected'));
return;
}
const reader = new FileReader();
reader.onload = (event) => {
try {
const json = event.target?.result as string;
const exported = JSON.parse(json) as ExportedGenome;
resolve(exported);
} catch (err) {
reject(new Error('Failed to parse genome file'));
}
};
reader.onerror = () => reject(new Error('Failed to read file'));
reader.readAsText(file);
};
input.click();
});
}