From b3ba53f8466deab1fa83ed56044126c628d19042 Mon Sep 17 00:00:00 2001
From: Vinzenz Schroeter <vinzenz.f.s@gmail.com>
Date: Sun, 19 May 2024 11:28:53 +0200
Subject: [PATCH] add optional high life rule

---
 src/game.rs | 14 ++++++++++++--
 src/main.rs | 34 +++++++++++++++++++++++++++-------
 2 files changed, 39 insertions(+), 9 deletions(-)

diff --git a/src/game.rs b/src/game.rs
index 49d7a36..2580af9 100644
--- a/src/game.rs
+++ b/src/game.rs
@@ -4,6 +4,7 @@ use servicepoint2::{ByteGrid, PixelGrid, TILE_HEIGHT, TILE_WIDTH};
 pub(crate) struct Game {
     pub field: PixelGrid,
     pub luma: ByteGrid,
+    pub high_life: Option<bool>,
 }
 
 impl Game {
@@ -24,8 +25,16 @@ impl Game {
                 let old_state = self.field.get(x, y);
                 let neighbors = self.count_neighbors(x, y);
 
-                let new_state =
-                    matches!((old_state, neighbors), (true, 2) | (true, 3) | (false, 3));
+                let new_state = match (old_state, neighbors) {
+                    (true, 2) | (true, 3) | (false, 3) => true,
+                    (false, 6) => match self.high_life {
+                        None => false,
+                        Some(true) => true,
+                        Some(false) => self.luma.get(x / 8, y / 8) > 128
+                    },
+                    _ => false,
+                };
+
                 next.set(x, y, new_state);
             }
         }
@@ -96,6 +105,7 @@ impl Default for Game {
         Self {
             field: PixelGrid::max_sized(),
             luma: ByteGrid::new(TILE_WIDTH as usize, TILE_HEIGHT as usize),
+            high_life: None,
         }
     }
 }
diff --git a/src/main.rs b/src/main.rs
index c7edfbf..a8f02ce 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -6,7 +6,9 @@ use clap::Parser;
 use crossterm::{event, execute, queue};
 use crossterm::event::{Event, KeyCode, KeyEventKind};
 use crossterm::style::{Print, PrintStyledContent, Stylize};
-use crossterm::terminal::{disable_raw_mode, enable_raw_mode, EnableLineWrap, EnterAlternateScreen, LeaveAlternateScreen};
+use crossterm::terminal::{
+    disable_raw_mode, enable_raw_mode, EnableLineWrap, EnterAlternateScreen, LeaveAlternateScreen,
+};
 use log::LevelFilter;
 use rand::{distributions, Rng};
 use servicepoint2::{
@@ -24,8 +26,6 @@ struct Cli {
     destination: String,
     #[arg(short, long, default_value_t = 0.4f64)]
     probability: f64,
-    #[arg(short, long, default_value_t = true)]
-    extended: bool,
 }
 
 // TODO: itsa spaghetti! 👌
@@ -50,6 +50,7 @@ fn main() {
     let mut luma = ByteGrid::new(TILE_WIDTH as usize, TILE_HEIGHT as usize);
 
     let mut split_pixel = PIXEL_WIDTH as usize / 2;
+    let mut high_life = Option::None;
 
     let mut close_requested = false;
     while !close_requested {
@@ -104,6 +105,7 @@ fn main() {
                             println_info("[q] quit");
                             println_info("[a] reset left field");
                             println_info("[d] reset right field");
+                            println_info("[l] toggle high life rules for bright tiles");
                             println_info("[→] move divider right");
                             println_info("[←] move divider left");
                         }
@@ -113,11 +115,29 @@ fn main() {
                         }
                         KeyCode::Char('a') => {
                             println_debug("generating new random field for left");
-                            left = make_random_field(cli.probability);
+                            left = make_random_field(cli.probability, high_life);
                         }
                         KeyCode::Char('d') => {
                             println_info("generating new random field for right");
-                            right = make_random_field(cli.probability);
+                            right = make_random_field(cli.probability, high_life);
+                        }
+                        KeyCode::Char('l') => {
+                            high_life = match high_life {
+                                None => Some(false),
+                                Some(false) => Some(true),
+                                Some(true) => None,
+                            };
+                            let state_formatted = match high_life {
+                                None => "disabled".red(),
+                                Some(false) => "enabled where bright".yellow(),
+                                Some(true) => "enabled everywhere".green()
+                            };
+                            left.high_life = high_life;
+                            right.high_life = high_life;
+                            queue!(stdout(), 
+                                Print("new high life state: "), 
+                                PrintStyledContent(state_formatted), 
+                                Print("\r\n"));
                         }
                         KeyCode::Right => {
                             split_pixel += 1;
@@ -162,7 +182,7 @@ fn println_command(command: impl crossterm::Command) {
     queue!(stdout(), command, Print("\r\n"));
 }
 
-fn make_random_field(probability: f64) -> Game {
+fn make_random_field(probability: f64, high_life: Option<bool>) -> Game {
     let mut field = PixelGrid::max_sized();
     let mut rng = rand::thread_rng();
     let d = distributions::Bernoulli::new(probability).unwrap();
@@ -179,5 +199,5 @@ fn make_random_field(probability: f64) -> Game {
         }
     }
 
-    Game { field, luma }
+    Game { field, luma, high_life }
 }