use core::f32;
use germterm::{
color::{Color, ColorRgb}, crossterm::{self, event::{Event, KeyCode, KeyEvent, KeyEventKind}}, draw::{Layer, draw_rect, draw_text, draw_twoxel}, engine::{Engine, end_frame, exit_cleanup, init, start_frame}, fps_counter::get_fps, input::poll_input
};
fn update_grid(grid: &mut Vec<Vec<bool>>, w: usize, h: usize, b_thresh: u8, s_thresh: u8) {
let mut next_grid = vec![vec![true; w]; h];
for x in 1..w-1 {
for y in 1..h-1 {
let mut neighbours: u8 = 0;
for dy in -1..=1 {
for dx in -1..=1 {
if dx == 0 && dy == 0 {
continue;
}
let nx = x as isize + dx;
let ny = y as isize + dy;
if nx >= 0 && ny >= 0 && nx < w as isize && ny < h as isize {
if grid[ny as usize][nx as usize] {
neighbours += 1;
}
}
}
}
if grid[y][x] && neighbours >= s_thresh {
next_grid[y][x] = true;
} else if !grid[y][x] && neighbours >= b_thresh {
next_grid[y][x] = true;
} else {
next_grid[y][x] = false;
}
}
}
*grid = next_grid;
}
fn generate_map(wall_density: f32, w: usize, h: usize) -> Vec<Vec<bool>> {
(0..h)
.map(|_| (0..w).map(|_| rand::random::<f32>() < wall_density).collect())
.collect()
}
fn main() {
let (term_w, term_h) = crossterm::terminal::size().unwrap();
let w = term_w as usize;
let h = term_h as usize * 2 - 2;
let wall_color = Color::from(ColorRgb::new(131, 87, 31));
let bg_color = Color::from(ColorRgb::new(178, 123, 31));
let mut ticks: u64 = 0;
let mut wall_density = 0.50;
let mut thresh = 4;
let mut grid: Vec<Vec<bool>> = generate_map(wall_density, w, h);
let mut engine = Engine::new(term_w, term_h).limit_fps(0);
let mut layer = Layer::new(&mut engine, 0);
let _ = init(&mut engine);
'update_loop: loop {
start_frame(&mut engine);
ticks += 1;
for event in poll_input() {
if let Event::Key(KeyEvent { code, kind, .. }) = event {
if kind != KeyEventKind::Press { continue; }
match code {
KeyCode::Char('q') => break 'update_loop,
KeyCode::Char('r') => {
ticks = 0;
grid = generate_map(wall_density, w, h);
}
KeyCode::Char('e') => {
let new_density = (wall_density + 0.01).min(1.0);
if new_density != wall_density {
wall_density = new_density;
ticks = 0;
grid = generate_map(wall_density, w, h);
}
}
KeyCode::Char('d') => {
let new_density = (wall_density - 0.01).max(0.0);
if new_density != wall_density {
wall_density = new_density;
ticks = 0;
grid = generate_map(wall_density, w, h);
}
}
KeyCode::Char('s') => {
let new_thresh = (thresh + 1).min(8);
if new_thresh != thresh {
thresh = new_thresh;
ticks = 0;
grid = generate_map(wall_density, w, h);
}
}
KeyCode::Char('w') => {
let new_thresh = (thresh as i32 - 1).max(0) as u8;
if new_thresh != thresh {
thresh = new_thresh;
ticks = 0;
grid = generate_map(wall_density, w, h);
}
}
_ => {}
}
}
}
for x in 0..w {
for y in 0..h {
let cell = grid[y][x];
let color = if cell { wall_color } else { bg_color };
draw_twoxel(&mut layer, x as f32, y as f32 / 2.0, color);
}
}
draw_rect(&mut layer, 0, (term_h - 2) as i16, term_w as i16, 2, Color::BLACK);
let s_thresh = thresh.min(4).max(0);
let b_thresh = thresh.min(8).max(5);
let status_text = format!("Progressive wall density: {} (0-8) | Init wall density: {:.2} | Ticks: {} ({:.0} t/s)", 8 - thresh as u8, wall_density, ticks, get_fps(&engine));
let x = ((term_w as usize).saturating_sub(status_text.chars().count())) / 2;
draw_text(&mut layer, x as i16, (term_h - 2) as i16, status_text);
let controls = "W/S: Progressive wall density | E/D: Init wall density | R: Reset | Q: Quit";
let x_controls = ((term_w as usize).saturating_sub(controls.chars().count())) / 2;
draw_text(&mut layer, x_controls as i16, (term_h - 1) as i16, controls);
update_grid(&mut grid, w, h, b_thresh, s_thresh);
let _ = end_frame(&mut engine);
}
let _ = exit_cleanup(&mut engine);
}