@@ -436,19 +436,15 @@ function nouvelleGeneration(population, scores, tauxMutationSur1000, graine) {
436436}
437437
438438function evaluerFitness ( univers , poidsObj ) {
439- // Computes metrics from univers and returns weighted fitness score
440- const lignes = univers && univers . lignes ? univers . lignes : [ ] ;
441- const totalCells = lignes . length > 0 ? lignes [ 0 ] . length : 1 ;
442- const liveCells = lignes . flat ( ) . filter ( ( v ) => v !== 0 ) . length ;
443-
444- const densite = totalCells > 0 ? liveCells / totalCells : 0 ;
445- const entropie = densite > 0 && densite < 1 ? - ( densite * Math . log2 ( densite ) + ( 1 - densite ) * Math . log2 ( 1 - densite ) ) : 0 ;
446- const compacite = liveCells > 0 ? Math . sqrt ( liveCells ) / ( liveCells + 1 ) : 0 ;
447-
448- // Placeholder values for oscillation (would require historical data)
449- const oscillation = 0 ;
450- const complexite = Math . max ( 0 , entropie * ( 1 - compacite ) ) ;
451- const croissance = 0 ; // Would need frame history
439+ const {
440+ entropie,
441+ densite,
442+ compacite,
443+ symetrie,
444+ oscillation,
445+ complexite,
446+ tauxCroissance,
447+ } = metriquesUnivers ( univers ) ;
452448
453449 const poids = [
454450 poidsObj . symetrie || 5 ,
@@ -459,12 +455,12 @@ function evaluerFitness(univers, poidsObj) {
459455 poidsObj . croissance || 5 ,
460456 ] ;
461457
462- const fSym = callPacked ( "fitness_symetrie_scalaire" , [ 0.5 ] , 0.5 ) ;
458+ const fSym = callPacked ( "fitness_symetrie_scalaire" , [ symetrie ] , symetrie ) ;
463459 const fDen = callPacked ( "fitness_densite_scalaire" , [ densite , 0.45 ] , Math . abs ( densite - 0.45 ) < 0.2 ? 0.8 : 0.2 ) ;
464- const fSta = callPacked ( "fitness_stabilite_scalaire" , [ 0 , compacite ] , compacite * 0.5 ) ;
460+ const fSta = callPacked ( "fitness_stabilite_scalaire" , [ Math . abs ( tauxCroissance ) , compacite ] , ( ( 1 - Math . abs ( tauxCroissance ) ) * 0.5 ) + ( compacite * 0.5 ) ) ;
465461 const fOsc = oscillation ;
466462 const fCmp = callPacked ( "fitness_complexite_scalaire" , [ entropie , compacite ] , complexite ) ;
467- const fCro = croissance ;
463+ const fCro = callPacked ( "fitness_croissance_scalaire" , [ Math . max ( 0 , tauxCroissance ) ] , Math . max ( 0 , tauxCroissance ) ) ;
468464
469465 const score = callPacked ( "fitness_ponderee_scalaire" ,
470466 [ fSym , fDen , fSta , fOsc , fCmp , fCro , ...poids ] ,
@@ -474,7 +470,16 @@ function evaluerFitness(univers, poidsObj) {
474470
475471 return {
476472 score : Math . max ( 0 , Math . min ( 1 , score ) ) ,
477- metriques : { entropie, densite, compacite, oscillation, complexite, croissance } ,
473+ metriques : {
474+ entropie,
475+ densite,
476+ compacite,
477+ symetrie,
478+ oscillation,
479+ complexite,
480+ croissance : Math . max ( 0 , tauxCroissance ) ,
481+ tauxCroissance,
482+ } ,
478483 } ;
479484}
480485
@@ -595,16 +600,109 @@ function calculerCentreDesMasse(ligne) {
595600 return vivants . reduce ( ( a , b ) => a + b , 0 ) / vivants . length ;
596601}
597602
603+ function clamp01 ( value ) {
604+ return Math . max ( 0 , Math . min ( 1 , value ) ) ;
605+ }
606+
607+ function celluleVivante ( value , valeurVide ) {
608+ return String ( value ) !== String ( valeurVide ) ;
609+ }
610+
611+ function calculerDensiteLigne ( ligne , valeurVide ) {
612+ if ( ! ligne || ligne . length === 0 ) return 0 ;
613+ const actives = ligne . filter ( ( value ) => celluleVivante ( value , valeurVide ) ) . length ;
614+ return actives / ligne . length ;
615+ }
616+
617+ function calculerSymetrieLigne ( ligne ) {
618+ if ( ! ligne || ligne . length <= 1 ) return 1 ;
619+ let accords = 0 ;
620+ const paires = Math . floor ( ligne . length / 2 ) ;
621+ for ( let i = 0 ; i < paires ; i += 1 ) {
622+ if ( String ( ligne [ i ] ) === String ( ligne [ ligne . length - 1 - i ] ) ) accords += 1 ;
623+ }
624+ return paires > 0 ? accords / paires : 1 ;
625+ }
626+
627+ function calculerCompaciteLigne ( ligne , valeurVide ) {
628+ if ( ! ligne || ligne . length === 0 ) return 0 ;
629+ const indicesVivants = ligne
630+ . map ( ( value , index ) => ( celluleVivante ( value , valeurVide ) ? index : - 1 ) )
631+ . filter ( ( index ) => index >= 0 ) ;
632+ if ( indicesVivants . length === 0 ) return 0 ;
633+ const debut = indicesVivants [ 0 ] ;
634+ const fin = indicesVivants [ indicesVivants . length - 1 ] ;
635+ const etendue = Math . max ( 1 , fin - debut + 1 ) ;
636+ return indicesVivants . length / etendue ;
637+ }
638+
639+ function varianceDensite ( historiqueDensites ) {
640+ if ( ! historiqueDensites || historiqueDensites . length < 2 ) return 0 ;
641+ const moyenne = historiqueDensites . reduce ( ( sum , value ) => sum + value , 0 ) / historiqueDensites . length ;
642+ const sommeCarres = historiqueDensites . reduce ( ( sum , value ) => sum + ( ( value - moyenne ) ** 2 ) , 0 ) ;
643+ return Math . sqrt ( sommeCarres / historiqueDensites . length ) ;
644+ }
645+
646+ function detecterPeriode ( historiqueDensites , fenetre ) {
647+ if ( ! historiqueDensites || historiqueDensites . length < fenetre || fenetre < 2 ) return 0 ;
648+ const derniers = historiqueDensites . slice ( - fenetre ) ;
649+ for ( let periode = 1 ; periode <= Math . floor ( fenetre / 2 ) ; periode += 1 ) {
650+ let correlation = 0 ;
651+ let compte = 0 ;
652+ for ( let i = 0 ; i < derniers . length - periode ; i += 1 ) {
653+ correlation += Math . abs ( derniers [ i ] - derniers [ i + periode ] ) ;
654+ compte += 1 ;
655+ }
656+ const correlationMoyenne = compte > 0 ? correlation / compte : 0 ;
657+ if ( correlationMoyenne < 0.1 ) return periode ;
658+ }
659+ return 0 ;
660+ }
661+
598662function metriquesUnivers ( univers ) {
599663 const lignes = univers && univers . lignes ? univers . lignes : [ ] ;
600- const totalCells = lignes . length > 0 ? lignes [ 0 ] . length : 1 ;
601- const liveCells = lignes . flat ( ) . filter ( ( v ) => v !== 0 ) . length ;
664+ const configuration = univers && univers . configuration ? univers . configuration : { } ;
665+ const valeurVide = configuration . alphabet_entree ? configuration . alphabet_entree [ 0 ] : 0 ;
666+ const totalCells = lignes . reduce ( ( sum , ligne ) => sum + ligne . length , 0 ) ;
667+ const liveCells = lignes . flat ( ) . filter ( ( value ) => celluleVivante ( value , valeurVide ) ) . length ;
602668 const densite = totalCells > 0 ? liveCells / totalCells : 0 ;
603669 const entropie = densite > 0 && densite < 1 ? - ( densite * Math . log2 ( densite ) + ( 1 - densite ) * Math . log2 ( 1 - densite ) ) : 0 ;
604- const compacite = liveCells > 0 ? Math . sqrt ( liveCells ) / ( liveCells + 1 ) : 0 ;
605- const symetrie = 0.5 ; // Placeholder
606- const tauxCroissance = 0 ; // Placeholder
607- return { entropie, compacite, symetrie, tauxCroissance, densite } ;
670+
671+ const densitesParGeneration = lignes . map ( ( ligne ) => calculerDensiteLigne ( ligne , valeurVide ) ) ;
672+ const compacites = lignes . map ( ( ligne ) => calculerCompaciteLigne ( ligne , valeurVide ) ) ;
673+ const symetries = lignes . map ( ( ligne ) => calculerSymetrieLigne ( ligne ) ) ;
674+
675+ const compacite = compacites . length > 0
676+ ? compacites . reduce ( ( sum , value ) => sum + value , 0 ) / compacites . length
677+ : 0 ;
678+ const symetrie = symetries . length > 0
679+ ? symetries . reduce ( ( sum , value ) => sum + value , 0 ) / symetries . length
680+ : 0.5 ;
681+
682+ const tranche = Math . max ( 1 , Math . floor ( densitesParGeneration . length / 5 ) ) ;
683+ const densiteDebut = densitesParGeneration . slice ( 0 , tranche ) . reduce ( ( sum , value ) => sum + value , 0 ) / tranche ;
684+ const densiteFin = densitesParGeneration . slice ( - tranche ) . reduce ( ( sum , value ) => sum + value , 0 ) / tranche ;
685+ const tauxCroissance = Math . max ( - 1 , Math . min ( 1 , densiteFin - densiteDebut ) ) ;
686+
687+ const variance = clamp01 ( varianceDensite ( densitesParGeneration ) * 4 ) ;
688+ const fenetre = Math . min ( 24 , densitesParGeneration . length ) ;
689+ const periodeDetectee = detecterPeriode ( densitesParGeneration , fenetre ) ;
690+ const scoreVariance = 1 - Math . min ( 1 , Math . abs ( variance - 0.5 ) * 2 ) ;
691+ const scorePeriode = periodeDetectee > 0 ? 1 : 0 ;
692+ const oscillation = clamp01 ( ( scoreVariance * 0.7 ) + ( scorePeriode * 0.3 ) ) ;
693+ const complexite = clamp01 ( entropie * ( 1 - compacite ) ) ;
694+
695+ return {
696+ entropie,
697+ compacite,
698+ symetrie,
699+ tauxCroissance,
700+ densite,
701+ oscillation,
702+ complexite,
703+ varianceDensite : variance ,
704+ periodeDetectee,
705+ } ;
608706}
609707
610708window . AutomaginariumCore = {
0 commit comments