1616
1717import numpy as np
1818import matplotlib .pyplot as plt
19- import matplotlib . animation as animation
19+ from matplotlib import animation
2020from matplotlib .colors import ListedColormap
2121
2222
@@ -567,276 +567,108 @@ def run_interactive_simulation(
567567 return anim
568568
569569
570- def demonstrate_cellular_automaton_features ():
571- """
572- Comprehensive demonstration of Von Neumann cellular automaton capabilities.
573-
574- This function showcases different rule sets, visualization options, and
575- analysis techniques. Perfect for learning how the system works and
576- exploring different configurations.
577- """
578- print ("=" * 80 )
579- print ("VON NEUMANN CELLULAR AUTOMATON - FEATURE DEMONSTRATION" )
580- print ("=" * 80 )
581-
582- # Example 1: Game of Life-like Rules
583- print ("\n 🎮 EXAMPLE 1: Game of Life-like Rules" )
584- print ("-" * 50 )
585- print ("Rules: Birth on 3 neighbors, Survival on 2-3 neighbors" )
586- print ("Effect: Creates stable patterns and oscillators" )
570+ # -------------------------------------------------------------------------
571+ # Helper demo functions
572+ # -------------------------------------------------------------------------
587573
574+ def demo_game_of_life ():
575+ """Example 1: Conway's Game of Life (B3/S23)."""
588576 try :
589- history_gol = simulate_von_neumann_cellular_automaton (
590- grid_rows = 20 ,
591- grid_columns = 30 ,
592- generations = 50 ,
593- birth_rules = {3 },
594- survival_rules = {2 , 3 },
595- maximum_cell_age = 5 ,
596- initial_alive_probability = 0.25 ,
597- random_seed = 42 ,
577+ visualize_cellular_automaton (
578+ rule_b = [3 ],
579+ rule_s = [2 , 3 ],
580+ size = 50 ,
581+ steps = 100 ,
582+ title = "Game of Life (B3/S23)" ,
598583 )
584+ except (ValueError , RuntimeError ) as e :
585+ print (f"Error in Game of Life demo: { e } " )
599586
600- print (f"✓ Simulated { len (history_gol )} generations" )
601- print ("📊 Showing static comparison..." )
602- plot_static_generations (
603- history_gol , generations_to_show = [0 , 10 , 20 , 30 , 49 ], figsize = (18 , 4 )
604- )
605587
606- print ("🎬 Creating animation..." )
607- anim1 = visualize_cellular_automaton (
608- history_gol ,
609- max_age = 5 ,
610- interval = 200 ,
611- title = "Game of Life-like Rules (B3/S23)" ,
612- show_grid = True ,
588+ def demo_highlife ():
589+ """Example 2: HighLife (B36/S23)."""
590+ try :
591+ visualize_cellular_automaton (
592+ rule_b = [3 , 6 ],
593+ rule_s = [2 , 3 ],
594+ size = 50 ,
595+ steps = 100 ,
596+ title = "HighLife (B36/S23)" ,
613597 )
614- plt .show ()
615-
616- except Exception as e :
617- print (f"❌ Error in Example 1: { e } " )
598+ except (ValueError , RuntimeError ) as e :
599+ print (f"Error in HighLife demo: { e } " )
618600
619- # Example 2: High-Life Rules
620- print ("\n 🌟 EXAMPLE 2: High-Life Rules" )
621- print ("-" * 50 )
622- print ("Rules: Birth on 3,6 neighbors, Survival on 2-3 neighbors" )
623- print ("Effect: More dynamic with replicator patterns" )
624601
602+ def demo_oscillator ():
603+ """Example 3: Oscillator (blinker)."""
625604 try :
626- history_highlife = simulate_von_neumann_cellular_automaton (
627- grid_rows = 25 ,
628- grid_columns = 35 ,
629- generations = 60 ,
630- birth_rules = {3 , 6 },
631- survival_rules = {2 , 3 },
632- maximum_cell_age = 4 ,
633- initial_alive_probability = 0.2 ,
634- random_seed = 123 ,
605+ initial_state = np .zeros ((10 , 10 ), dtype = int )
606+ initial_state [4 :7 , 5 ] = 1 # vertical line
607+ visualize_cellular_automaton (
608+ rule_b = [3 ],
609+ rule_s = [2 , 3 ],
610+ initial_state = initial_state ,
611+ steps = 10 ,
612+ title = "Oscillator: Blinker" ,
635613 )
614+ except (ValueError , RuntimeError ) as e :
615+ print (f"Error in Oscillator demo: { e } " )
636616
637- print (f"✓ Simulated { len (history_highlife )} generations" )
638- print ("🎬 Showing animated evolution..." )
639- anim2 = visualize_cellular_automaton (
640- history_highlife ,
641- max_age = 4 ,
642- interval = 150 ,
643- title = "High-Life Rules (B36/S23)" ,
644- show_grid = False ,
645- )
646- plt .show ()
647-
648- except Exception as e :
649- print (f"❌ Error in Example 2: { e } " )
650-
651- # Example 3: Seeds Rules (Explosive Growth)
652- print ("\n 💥 EXAMPLE 3: Seeds Rules" )
653- print ("-" * 50 )
654- print ("Rules: Birth on 2 neighbors, No survival" )
655- print ("Effect: Explosive growth patterns, very dynamic" )
656617
618+ def demo_randomized ():
619+ """Example 4: Randomized automaton (B2/S23)."""
657620 try :
658- history_seeds = simulate_von_neumann_cellular_automaton (
659- grid_rows = 30 ,
660- grid_columns = 40 ,
661- generations = 25 , # Shorter due to explosive nature
662- birth_rules = {2 },
663- survival_rules = set (), # No survival
664- maximum_cell_age = 6 ,
665- initial_alive_probability = 0.1 , # Lower initial density
666- random_seed = 456 ,
667- )
668-
669- print (f"✓ Simulated { len (history_seeds )} generations" )
670- print ("📊 Static snapshots of explosive growth..." )
671- plot_static_generations (
672- history_seeds , generations_to_show = [0 , 5 , 10 , 15 , 24 ], figsize = (20 , 4 )
621+ visualize_cellular_automaton (
622+ rule_b = [2 ],
623+ rule_s = [2 , 3 ],
624+ size = 50 ,
625+ steps = 50 ,
626+ title = "Randomized Automaton (B2/S23)" ,
673627 )
628+ except (ValueError , RuntimeError ) as e :
629+ print (f"Error in Randomized demo: { e } " )
674630
675- except Exception as e :
676- print (f"❌ Error in Example 3: { e } " )
677-
678- # Example 4: Custom Stable Rules
679- print ("\n 🏛️ EXAMPLE 4: Custom Stable Rules" )
680- print ("-" * 50 )
681- print ("Rules: Birth on 2,4 neighbors, Survival on 1-4 neighbors" )
682- print ("Effect: Creates stable, maze-like structures" )
683631
632+ def demo_statistics ():
633+ """Example 5: Print statistics about automaton evolution."""
684634 try :
685- history_stable = simulate_von_neumann_cellular_automaton (
686- grid_rows = 25 ,
687- grid_columns = 35 ,
688- generations = 40 ,
689- birth_rules = {2 , 4 },
690- survival_rules = {1 , 2 , 3 , 4 },
691- maximum_cell_age = 7 ,
692- initial_alive_probability = 0.3 ,
693- random_seed = 789 ,
694- use_wraparound_edges = False , # No wraparound for cleaner boundaries
695- )
696-
697- print (f"✓ Simulated { len (history_stable )} generations" )
698- anim4 = visualize_cellular_automaton (
699- history_stable ,
700- max_age = 7 ,
701- interval = 250 ,
702- title = "Custom Stable Rules (B24/S1234)" ,
703- show_grid = True ,
635+ final_state = run_cellular_automaton (
636+ rule_b = [3 ],
637+ rule_s = [2 , 3 ],
638+ size = 50 ,
639+ steps = 50 ,
640+ return_states = True ,
704641 )
705- plt .show ()
642+ alive_counts = [np .sum (state ) for state in final_state ]
643+ density = [count / (50 * 50 ) * 100 for count in alive_counts ]
706644
707- except Exception as e :
708- print (f"❌ Error in Example 4: { e } " )
645+ print ("Statistics Example:" )
646+ print (f"-Average population: { np .mean (alive_counts ):.1f} cells" )
647+ print (f"-Average density: { np .mean (density ):.1f} %" )
648+ print (f"-Max population: { np .max (alive_counts )} " )
649+ print (f"-Min population: { np .min (alive_counts )} " )
650+ except (ValueError , RuntimeError ) as e :
651+ print (f"Error in Statistics demo: { e } " )
709652
710- # Example 5: Analysis and Statistics
711- print ("\n 📈 EXAMPLE 5: Population Analysis" )
712- print ("-" * 50 )
713- print ("Analyzing population dynamics over time..." )
714653
715- try :
716- # Use the Game of Life-like rules for analysis
717- analysis_history = simulate_von_neumann_cellular_automaton (
718- grid_rows = 30 ,
719- grid_columns = 40 ,
720- generations = 100 ,
721- birth_rules = {3 },
722- survival_rules = {2 , 3 },
723- maximum_cell_age = 5 ,
724- initial_alive_probability = 0.25 ,
725- random_seed = 42 ,
726- )
654+ # -------------------------------------------------------------------------
655+ # Main demo orchestrator
656+ # -------------------------------------------------------------------------
727657
728- # Calculate population statistics
729- alive_counts = [np .sum (gen > 0 ) for gen in analysis_history ]
730- total_cells = analysis_history [0 ].shape [0 ] * analysis_history [0 ].shape [1 ]
731-
732- # Plot population over time
733- plt .figure (figsize = (12 , 6 ))
734-
735- plt .subplot (1 , 2 , 1 )
736- plt .plot (alive_counts , "b-" , linewidth = 2 , label = "Living Cells" )
737- plt .axhline (
738- y = np .mean (alive_counts ),
739- color = "r" ,
740- linestyle = "--" ,
741- alpha = 0.7 ,
742- label = f"Average: { np .mean (alive_counts ):.1f} " ,
743- )
744- plt .xlabel ("Generation" )
745- plt .ylabel ("Number of Living Cells" )
746- plt .title ("Population Over Time" )
747- plt .legend ()
748- plt .grid (True , alpha = 0.3 )
749-
750- plt .subplot (1 , 2 , 2 )
751- density = [count / total_cells * 100 for count in alive_counts ]
752- plt .plot (density , "g-" , linewidth = 2 , label = "Density %" )
753- plt .axhline (
754- y = np .mean (density ),
755- color = "r" ,
756- linestyle = "--" ,
757- alpha = 0.7 ,
758- label = f"Average: { np .mean (density ):.1f} %" ,
759- )
760- plt .xlabel ("Generation" )
761- plt .ylabel ("Population Density (%)" )
762- plt .title ("Population Density Over Time" )
763- plt .legend ()
764- plt .grid (True , alpha = 0.3 )
765-
766- plt .tight_layout ()
767- plt .show ()
768-
769- print (f"📊 Population Statistics:" )
770- print (f" • Initial population: { alive_counts [0 ]} cells ({ density [0 ]:.1f} %)" )
771- print (f" • Final population: { alive_counts [- 1 ]} cells ({ density [- 1 ]:.1f} %)" )
772- print (
773- f" • Average population: { np .mean (alive_counts ):.1f} cells ({ np .mean (density ):.1f} %)"
774- )
775- print (
776- f" • Maximum population: { max (alive_counts )} cells ({ max (density ):.1f} %)"
777- )
778- print (
779- f" • Minimum population: { min (alive_counts )} cells ({ min (density ):.1f} %)"
780- )
781-
782- except Exception as e :
783- print (f"❌ Error in Example 5: { e } " )
658+ def demonstrate_cellular_automaton_features ():
659+ """Runs a set of cellular automaton demonstrations."""
660+ print ("=" * 80 )
661+ print ("VON NEUMANN CELLULAR AUTOMATON - FEATURE DEMONSTRATION" )
662+ print ("=" * 80 )
784663
785- # Example 6: Comparative Rule Analysis
786- print ("\n 🔬 EXAMPLE 6: Rule Comparison" )
787- print ("-" * 50 )
788- print ("Comparing different rule sets side by side..." )
664+ demo_game_of_life ()
665+ demo_highlife ()
666+ demo_oscillator ()
667+ demo_randomized ()
668+ demo_statistics ()
789669
790- try :
791- rule_sets = [
792- ({"birth" : {3 }, "survival" : {2 , 3 }, "name" : "Conway B3/S23" }),
793- ({"birth" : {2 , 3 }, "survival" : {1 , 2 }, "name" : "Dynamic B23/S12" }),
794- ({"birth" : {1 }, "survival" : {1 , 2 }, "name" : "Minimal B1/S12" }),
795- ]
796-
797- fig , axes = plt .subplots (len (rule_sets ), 4 , figsize = (16 , 3 * len (rule_sets )))
798- if len (rule_sets ) == 1 :
799- axes = axes .reshape (1 , - 1 )
800-
801- for i , rule_set in enumerate (rule_sets ):
802- print (f" Analyzing: { rule_set ['name' ]} " )
803-
804- history = simulate_von_neumann_cellular_automaton (
805- grid_rows = 20 ,
806- grid_columns = 25 ,
807- generations = 30 ,
808- birth_rules = rule_set ["birth" ],
809- survival_rules = rule_set ["survival" ],
810- maximum_cell_age = 4 ,
811- initial_alive_probability = 0.25 ,
812- random_seed = 42 ,
813- )
814-
815- # Show generations 0, 10, 20, 29
816- for j , gen_idx in enumerate ([0 , 10 , 20 , 29 ]):
817- if gen_idx < len (history ):
818- im = axes [i , j ].imshow (
819- history [gen_idx ],
820- cmap = create_heatmap_colormap (4 ),
821- vmin = 0 ,
822- vmax = 4 ,
823- )
824- axes [i , j ].set_title (f"Gen { gen_idx } " )
825- axes [i , j ].set_xticks ([])
826- axes [i , j ].set_yticks ([])
827-
828- # Label the row
829- axes [i , 0 ].set_ylabel (rule_set ["name" ], rotation = 90 , va = "center" )
830-
831- plt .suptitle ("Rule Set Comparison" , fontsize = 16 )
832- plt .tight_layout ()
833- plt .show ()
834-
835- except Exception as e :
836- print (f"❌ Error in Example 6: { e } " )
837-
838- print ("\n " + "=" * 80 )
839- print ("🎉 DEMONSTRATION COMPLETE!" )
670+ print ("=" * 80 )
671+ print ("Demonstration complete." )
840672 print ("=" * 80 )
841673
842674
@@ -879,12 +711,12 @@ def quick_demo(rule_name: str = "conway"):
879711 }
880712
881713 if rule_name not in rule_configs :
882- print (f"❌ Unknown rule set: { rule_name } " )
714+ print (f"Unknown rule set: { rule_name } " )
883715 print (f"Available: { ', ' .join (rule_configs .keys ())} " )
884716 return
885717
886718 config = rule_configs [rule_name ]
887- print (f"🎮 Running quick demo: { config ['title' ]} " )
719+ print (f"Running quick demo: { config ['title' ]} " )
888720
889721 try :
890722 run_interactive_simulation (
@@ -897,8 +729,8 @@ def quick_demo(rule_name: str = "conway"):
897729 animation_speed = 150 ,
898730 show_static = True ,
899731 )
900- except Exception as e :
901- print (f"❌ Error running demo: { e } " )
732+ except ( ValueError , RuntimeError ) as e :
733+ print (f"Error running demo: { e } " )
902734
903735
904736if __name__ == "__main__" :
0 commit comments