Add neat arena
This commit is contained in:
120
src/lib/neatArena/exportImport.ts
Normal file
120
src/lib/neatArena/exportImport.ts
Normal 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();
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user