From 320560f3c513b89d41c3c6ee8c4030263d24cba3 Mon Sep 17 00:00:00 2001
From: deadvey <deadvey@nixos>
Date: Mon, 23 Dec 2024 20:38:24 +0000
Subject: [PATCH] improved

---
 falling.rs | 229 +++++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 171 insertions(+), 58 deletions(-)

diff --git a/falling.rs b/falling.rs
index 5f97062..8b7dad7 100644
--- a/falling.rs
+++ b/falling.rs
@@ -1,81 +1,136 @@
-use rand::Rng;
-use console::Term;
-//use termsize::get;
+use rand::Rng; // Allows you to generate random numbers
+use console::Term; // Allows reading key bind input
+use std::io::{stdin,stdout,Write};
 
-fn output_levels(starting_level: u64, ending_level: u64, character_x_coord: u16, character_icon: char, levels: &Vec<Vec<u8>>) {
-    print!("{}[2J", 27 as char);
-    for i in starting_level..ending_level {
-        for j in 0..levels[i as usize].len() {
-            let object = levels[i as usize][j as usize];
-            if i == starting_level && j == character_x_coord as usize { print!("{}",character_icon) }
-            else if object >= 4 { print!(" ") }
-            else if object == 3 { print!("¯") }
-            else if object == 2 { print!("\\") }
-            else if object == 1 { print!("/") }
-            else { print!("|") }
-        }
-        println!("    {}",i);
+// This function is used to Generate the output out a range of levels to the console, it accepts starting and
+// ending levls to print and then it uses a loop to print out each level in between these, each
+// level is comprised of numbers, each having a specific meaning for instance 0 is an obstacle and
+// -2 is a slanted wall "/"
+fn generate_output(starting_level: u64, ending_level: u64, character_x_coord: u16, character_icon: char, levels: &Vec<Vec<i8>>, debug_mode: bool) -> String {
+    let mut output: String = "".to_string();
+    if debug_mode {
+        let pattern = "0123456789";
+        let repeat_count = (levels[0].len() + 9) / 10;
+        let mut repeated = pattern.repeat(repeat_count);
+        repeated += "\n";
+        output += &repeated;
     }
+    for i in starting_level..ending_level {
+        let level = &levels[i as usize]; // Cache the level for quicker access
+        for j in 0..level.len() {
+            let object = level[j as usize];
+            // Directly check the player's position for rendering the icon
+            if i == starting_level && j == character_x_coord as usize {
+                 output = output + &character_icon.to_string();
+            } else {
+                match object {
+                    -3 => output+="|",            // Specific case for -3
+                    0 => output+="¯",             // Specific case for 0
+                    -1 => output+="\\",           // Specific case for -1
+                    -2 => output+="/",            // Specific case for -2
+                    _ => output+=" "                       // Default, no print for other cases
+                }
+            }
+        }
+        output+="    "; // At the end of each level, print that level
+        output+=&i.to_string();
+        output+="\n";
+    }
+    return output;
 }
-fn generate_level(level_to_generate: u64, difficulty: u8, left_wall: &mut i8, right_wall: &mut i8, screen_width: u16, levels: &mut Vec<Vec<u8>>) {
-    let mut new_level: Vec<u8> = Vec::new();
 
-    let left_wall_change = rand::thread_rng().gen_range(-1..2);
-    let right_wall_change = rand::thread_rng().gen_range(-1..2);
-    //println!("lwc: {}, rwc: {}", left_wall_change, right_wall_change);
+fn generate_level(level_to_generate: u64, difficulty: i8, left_wall: &mut i16, right_wall: &mut i16, screen_width: u16, preference:  &mut f32, levels: &mut Vec<Vec<i8>>) {
+    let mut new_level: Vec<i8> = Vec::new();
+
+    let left_wall_change = rand::thread_rng().gen_range(-1..2+(*preference as i16));
+    let right_wall_change = rand::thread_rng().gen_range(-1..2+(*preference as i16));
     *left_wall = *left_wall + left_wall_change;
     *right_wall = *right_wall + right_wall_change;
     if *left_wall <= 0 {
         *left_wall = 1;
     }
     if *right_wall >= screen_width.try_into().unwrap() {
-        *right_wall = screen_width as i8-1
+        *right_wall = screen_width as i16-1
     }
-    //println!("lw: {}, rw: {}", left_wall, right_wall);
     if (*right_wall-*left_wall).abs() < 8 {
-        *left_wall-=2;
-        *right_wall+=2;
+        *left_wall-=3;
+        *right_wall+=3;
     }
-    //let mut left_wall_temp = left_wall as i8 + left_wall_change;
-    //if left_wall_temp >= 0 { left_wall = left_wall_temp as u8 }
-    //right_wall = (right_wall as i8 + right_wall_change) as u8;
 
-    for i in 0..screen_width {
-        new_level.push(4)
+    while new_level.len() <= screen_width as usize {
+        new_level.push(1)
     }
 
     for i in *left_wall+1..*right_wall-1 {
-        let rng = rand::thread_rng();
-        let object: u8 = rand::thread_rng().gen_range(3..difficulty);
+        let object: i8 = rand::thread_rng().gen_range(0..difficulty);
         new_level[i as usize] = object;
     }
     for i in 0..*left_wall {
         if i == *left_wall-1 && left_wall_change > 0 {
-            new_level[i as usize] = 2;
+            new_level[i as usize] = -1;
         }
         else if i == *left_wall-1 && left_wall_change < 0 {
-            new_level[i as usize] = 1;
+            new_level[i as usize] = -2;
         }
         else {
-            new_level[i as usize] = 0;
+            new_level[i as usize] = -3;
         }
     }
-    for i in *right_wall..screen_width as i8 {
+    for i in *right_wall..screen_width as i16 {
         if i == *right_wall && right_wall_change > 0 {
-            new_level[i as usize] = 2;
+            new_level[i as usize] = -1;
         }
         else if i == *right_wall && right_wall_change < 0 {
-            new_level[i as usize] = 1;
+            new_level[i as usize] = -2;
         }
         else {
-            new_level[i as usize] = 0;
+            new_level[i as usize] = -3;
         }
     }
-    levels.push(new_level);
+    while levels.len() <= level_to_generate as usize {
+        levels.push(new_level.clone());
+    }
+    levels[level_to_generate as usize] = new_level;
+
+    // Modification of the directional preference logic
+    *preference = *preference + rand::thread_rng().gen_range(-0.5..0.5);
+    if *preference > 3.0 {
+        *preference = -1.0;
+    }
+    else if *preference < -3.0 {
+        *preference = 1.0;
+    }
+    if *right_wall >= screen_width as i16 - 5 {
+        *preference = -1.0;
+    }
+    else if *left_wall <= 5 {
+        *preference = 1.0;
+    }
 }
 
-fn check_if_alive(levels: &Vec<Vec<u8>>, level: usize, x_coord: usize) -> bool {
-    if levels[level][x_coord] == 0 || levels[level][x_coord] == 1 || levels[level][x_coord] == 2 || levels[level][x_coord] == 3 {
+fn debug_mode_modify_variables(current_level: &mut u64) -> u8 {
+    println!("\n----------------VARIABLE MODIFICATION---------------\n");
+    println!("Variables that can be modified:\ncurrent_level");
+    println!("\nWhat variable do you want to modify? ('N' to return to game without modification)");
+
+    let variable_to_modify = input();
+
+    if variable_to_modify == "N" {
+        return 0;
+    }
+    else {
+        println!("New value for {}",variable_to_modify);
+        let new_value = input();
+
+        if variable_to_modify == "current_level" {
+            *current_level = new_value.parse().unwrap();
+        }
+    }
+    return 1;
+}
+
+fn check_if_alive(levels: &Vec<Vec<i8>>, level: usize, x_coord: usize) -> bool {
+    if levels[level][x_coord] <= 0 {
         println!("GAME OVER");
         return false;
     }
@@ -84,40 +139,98 @@ fn check_if_alive(levels: &Vec<Vec<u8>>, level: usize, x_coord: usize) -> bool {
     }
 }
 
-pub fn main() {
-    let mut levels: Vec<Vec<u8>> = Vec::new();
+fn input() -> String{
+    let mut s=String::new();
+    let _=stdout().flush();
+    stdin().read_line(&mut s).expect("Did not enter a correct string");
+    if let Some('\n')=s.chars().next_back() {
+        s.pop();
+    }
+    if let Some('\r')=s.chars().next_back() {
+        s.pop();
+    }
+    return s;
+}
 
-    let (screen_width, screen_height) = termion::terminal_size().unwrap();
+fn main() {
+    let debug_mode = true; // Enable or disable debugging mode, it will print some useful stats and
+                           // let you modify stats midgame with e
+    let can_die = false; // I can't spell invinsiblitlity but this lets you not die...
 
-    println!("width: {}, height: {}",screen_width, screen_height); 
-    //let screen_height: u8 = 70;
-    //let screen_width: u8 = 100;
-    let difficulty: u8 = 15;
+    let mut levels: Vec<Vec<i8>> = Vec::new(); // Define variables for level
+
+    let (mut screen_width, mut screen_height) = termion::terminal_size().unwrap();
+    screen_width = screen_width - 20;
+    if debug_mode { // Reduce screen height more if debug mode is on as we need space to print
+                    // additional information
+        screen_height = screen_height - 17;
+    }
+    else {
+        screen_height = screen_height - 1;
+    }
+    
     let stdout = Term::buffered_stdout();
 
     let mut current_level: u64 = 0;
-    let character_icon: char = 'µ';
+    let mut character_icon: char = 'µ';
     let mut x_coord: u16 = (screen_width as f32/ 2.0) as u16; // Distance from left wall
-    let mut left_wall: i8 = (screen_width as f32/ 4.0) as i8;
-    let mut right_wall: i8 = ((screen_width as f32 * 3.0)/ 4.0) as i8;
+    let mut left_wall: i16 = rand::thread_rng().gen_range(0..((screen_width as f32/ 2.0)-5.0) as i16) as i16;
+    let mut right_wall: i16 = rand::thread_rng().gen_range(((screen_width as f32 /2.0)+5.0) as i16..screen_width as i16) as i16;
+    let mut preference: f32 = rand::thread_rng().gen_range(-2.0..3.0);
     let mut alive: bool = true;
+    let mut difficulty: i8 = 6;
 
-    for i in 1..screen_height {
-        generate_level(i as u64, difficulty, &mut left_wall, &mut right_wall, screen_width, &mut levels)
+
+    for i in 0..screen_height {
+        generate_level(i as u64, difficulty, &mut left_wall, &mut right_wall, screen_width, &mut preference, &mut levels)
     };
     'game_loop: loop {
-        generate_level(current_level, difficulty, &mut left_wall, &mut right_wall, screen_width, &mut levels);
-        output_levels(current_level, current_level + screen_height as u64, x_coord, character_icon, &levels);
+        let start = std::time::Instant::now();
+        generate_level(current_level + screen_height as u64, difficulty, &mut left_wall, &mut right_wall, screen_width, &mut preference, &mut levels);
+        let end_gen = std::time::Instant::now();
+
+        let output = generate_output(current_level, current_level + screen_height as u64, x_coord, character_icon, &levels, debug_mode);
+        let end_gen_output = std::time::Instant::now();
+        if ! debug_mode { // We don't want to clear screen if debug mode is on as it lets us see
+                          // old stats and see console warnings from rust and stuff
+            print!("{}[2J", 27 as char);
+        }
+        println!("{}",output);
+        let end_output = std::time::Instant::now();
+        
+        if debug_mode { // Print out debug info
+            println!("Time to Generate Level: {:?}\nTime to Generate Output: {:?}\nTime to Output levels: {:?}\nCurrent Level: {}\nCharacter's X coordinate: {}\nLeft Wall Position: {}\nRight Wall Position: {}\nDirectional Preference: {}\nAlive: {}\nDifficulty: {}\nCharcter Icon: {}\nItem Currently Ontop of: {}\nScreen Width: {}\nScreen Height: {}",
+                     end_gen-start,
+                     end_gen_output-end_gen,
+                     end_output-end_gen_output,
+                     current_level,
+                     x_coord,
+                     left_wall,
+                     right_wall,
+                     preference,
+                     alive,
+                     difficulty,
+                     character_icon,
+                     levels[current_level as usize][x_coord as usize],
+                     screen_width,
+                     screen_height
+                     );
+        }
+
         if let Ok(character) = stdout.read_char() {
             match character {
                 'd' => if x_coord < screen_width-1 { x_coord += 1 },
                 'a' => if x_coord > 1 { x_coord -= 1 },
+                'e' => if debug_mode { debug_mode_modify_variables(&mut current_level); continue 'game_loop },
                 'q' => break 'game_loop,
-                _ => continue 'game_loop,
+                _ => (),
             }
         }
+
         current_level+=1;
-        alive = check_if_alive(&levels, current_level as usize, x_coord as usize);
+        if can_die {
+            alive = check_if_alive(&levels, current_level as usize, x_coord as usize);
+        }
         if alive == false {
             break 'game_loop
         }