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: { id: genome.id, 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 { 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(); }); }