16
16
17
17
import numpy as np
18
18
import matplotlib .pyplot as plt
19
- import matplotlib . animation as animation
19
+ from matplotlib import animation
20
20
from matplotlib .colors import ListedColormap
21
21
22
22
@@ -567,276 +567,108 @@ def run_interactive_simulation(
567
567
return anim
568
568
569
569
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
+ # -------------------------------------------------------------------------
587
573
574
+ def demo_game_of_life ():
575
+ """Example 1: Conway's Game of Life (B3/S23)."""
588
576
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)" ,
598
583
)
584
+ except (ValueError , RuntimeError ) as e :
585
+ print (f"Error in Game of Life demo: { e } " )
599
586
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
- )
605
587
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)" ,
613
597
)
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 } " )
618
600
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" )
624
601
602
+ def demo_oscillator ():
603
+ """Example 3: Oscillator (blinker)."""
625
604
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" ,
635
613
)
614
+ except (ValueError , RuntimeError ) as e :
615
+ print (f"Error in Oscillator demo: { e } " )
636
616
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" )
656
617
618
+ def demo_randomized ():
619
+ """Example 4: Randomized automaton (B2/S23)."""
657
620
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)" ,
673
627
)
628
+ except (ValueError , RuntimeError ) as e :
629
+ print (f"Error in Randomized demo: { e } " )
674
630
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" )
683
631
632
+ def demo_statistics ():
633
+ """Example 5: Print statistics about automaton evolution."""
684
634
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 ,
704
641
)
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 ]
706
644
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 } " )
709
652
710
- # Example 5: Analysis and Statistics
711
- print ("\n 📈 EXAMPLE 5: Population Analysis" )
712
- print ("-" * 50 )
713
- print ("Analyzing population dynamics over time..." )
714
653
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
+ # -------------------------------------------------------------------------
727
657
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 )
784
663
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 ()
789
669
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." )
840
672
print ("=" * 80 )
841
673
842
674
@@ -879,12 +711,12 @@ def quick_demo(rule_name: str = "conway"):
879
711
}
880
712
881
713
if rule_name not in rule_configs :
882
- print (f"❌ Unknown rule set: { rule_name } " )
714
+ print (f"Unknown rule set: { rule_name } " )
883
715
print (f"Available: { ', ' .join (rule_configs .keys ())} " )
884
716
return
885
717
886
718
config = rule_configs [rule_name ]
887
- print (f"🎮 Running quick demo: { config ['title' ]} " )
719
+ print (f"Running quick demo: { config ['title' ]} " )
888
720
889
721
try :
890
722
run_interactive_simulation (
@@ -897,8 +729,8 @@ def quick_demo(rule_name: str = "conway"):
897
729
animation_speed = 150 ,
898
730
show_static = True ,
899
731
)
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 } " )
902
734
903
735
904
736
if __name__ == "__main__" :
0 commit comments