From 7604d10c3c766bf39c0d8fc40d3d28c005b35637 Mon Sep 17 00:00:00 2001 From: Vegard Matthey Date: Wed, 3 Apr 2024 14:03:38 +0200 Subject: [PATCH] usize terminal size for width and height --- src/main.rs | 84 +++++++++++++++++++++++++++++++++++------------------ 1 file changed, 55 insertions(+), 29 deletions(-) diff --git a/src/main.rs b/src/main.rs index 3b95c10..418a719 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,13 +1,14 @@ use crossterm::{ + cursor::{Hide, Show}, event::{poll, read, Event, KeyCode}, - terminal::{disable_raw_mode, enable_raw_mode}, + terminal::{disable_raw_mode, enable_raw_mode, size}, + ExecutableCommand, }; use rand::prelude::*; use std::collections::VecDeque; +use std::io::stdout; use std::time::{Duration, Instant}; -const WIDTH: usize = 20; -const HEIGHT: usize = 20; const FRAME_TIME: Duration = Duration::from_millis(100); const SNAKE_COLOR: Color = Color { r: 0, g: 255, b: 0 }; const APPLE_COLOR: Color = Color { r: 255, g: 0, b: 0 }; @@ -29,20 +30,29 @@ enum CrashLocation { } fn main() { - let mut snake: VecDeque<(usize, usize)> = vec![(0, 0), (1, 0), (2, 0)].into(); + let mut snake: VecDeque<(u16, u16)> = vec![(0, 0), (1, 0), (2, 0)].into(); let mut direction = Direction::Right; let mut length = snake.len(); + + stdout().execute(Hide).unwrap(); + + let (width, height) = size().unwrap_or((20, 20)); + println!("width {width}, height: {height}"); + let (width, height) = ((width - 2) / 2, height - 5); let mut rng = thread_rng(); - let mut apple = (rng.gen_range(0..WIDTH), rng.gen_range(0..WIDTH)); + let mut apple = ( + rng.gen_range(0..width), + rng.gen_range(0..height), + ); loop { let now = Instant::now(); - render(&snake, apple, length); + render(&snake, apple, length, (width, height)); enable_raw_mode().unwrap(); change_dir(&mut direction); disable_raw_mode().unwrap(); - if let Some(crash) = move_snake(&mut snake, &direction, length) { + if let Some(crash) = move_snake(&mut snake, &direction, length, (width, height)) { match crash { CrashLocation::North => println!("You crashed in the North wall!"), CrashLocation::South => println!("You crashed in the South wall!"), @@ -52,24 +62,36 @@ fn main() { } break; } - eat(&snake, &mut apple, &mut length, &mut rng); + eat(&snake, &mut apple, &mut length, &mut rng, (width, height)); while now.elapsed() < FRAME_TIME {} } + + exit(); } fn eat( - snake: &VecDeque<(usize, usize)>, - apple: &mut (usize, usize), + snake: &VecDeque<(u16, u16)>, + apple: &mut (u16, u16), length: &mut usize, rng: &mut ThreadRng, + (width, height): (u16, u16), ) { - if snake.contains(&apple) { - *apple = (rng.gen_range(0..WIDTH), rng.gen_range(0..WIDTH)); + if snake.contains(apple) { + *apple = ( + rng.gen_range(0..width), + rng.gen_range(0..height), + ); *length += 1; } } +fn exit() { + disable_raw_mode().unwrap(); + stdout().execute(Show).unwrap(); + std::process::exit(0); +} + fn change_dir(direction: &mut Direction) { if let Some(k) = key_input(FRAME_TIME) { match k { @@ -93,10 +115,7 @@ fn change_dir(direction: &mut Direction) { *direction = Direction::Down; } } - 'q' => { - disable_raw_mode().unwrap(); - std::process::exit(0); - } + 'q' => exit(), _ => (), } } @@ -114,9 +133,10 @@ fn key_input(timeout: Duration) -> Option { } fn move_snake( - snake: &mut VecDeque<(usize, usize)>, + snake: &mut VecDeque<(u16, u16)>, direction: &Direction, length: usize, + (width, height): (u16, u16), ) -> Option { if length == snake.len() { snake.pop_front(); @@ -125,7 +145,7 @@ fn move_snake( match direction { Direction::Right => { - if a.0 + 1 < WIDTH { + if a.0 + 1 < width { a.0 += 1 } else { return Some(CrashLocation::East); @@ -139,7 +159,7 @@ fn move_snake( } } Direction::Up => { - if a.1 + 1 < WIDTH { + if a.1 + 1 < height { a.1 += 1 } else { return Some(CrashLocation::North); @@ -162,16 +182,21 @@ fn move_snake( None } -fn render(snake: &VecDeque<(usize, usize)>, apple: (usize, usize), length: usize) { +fn render( + snake: &VecDeque<(u16, u16)>, + apple: (u16, u16), + length: usize, + (width, height): (u16, u16), +) { let mut s = String::new(); s.push_str("\u{001b}c"); s.push_str(&format!("length: {length}\n")); s.push('┏'); - s.push_str(&"━".repeat(WIDTH * 2)); + s.push_str(&"━".repeat(width as usize * 2)); s.push_str("┓\n"); - for y in (0..HEIGHT).rev() { + for y in (0..height).rev() { s.push('┃'); - for x in 0..WIDTH { + for x in 0..width { if snake.contains(&(x, y)) { s.push_str(&" ".bg(SNAKE_COLOR)); } else if (x, y) == apple { @@ -183,7 +208,7 @@ fn render(snake: &VecDeque<(usize, usize)>, apple: (usize, usize), length: usize s.push_str("┃\n"); } s.push('┗'); - s.push_str(&"━".repeat(WIDTH * 2)); + s.push_str(&"━".repeat(width as usize * 2)); s.push('┛'); println!("{s}"); } @@ -212,22 +237,23 @@ mod tests { use super::*; #[test] fn move_test() { - let mut snake: VecDeque<(usize, usize)> = vec![(16, 16), (17, 16), (18, 16)].into(); + let mut snake: VecDeque<(u16, u16)> = vec![(16, 16), (17, 16), (18, 16)].into(); let mut direction = Direction::Up; let length = snake.len(); - move_snake(&mut snake, &direction, length); + let size = size().unwrap_or((20, 20)); + move_snake(&mut snake, &direction, length, size); assert_eq!(snake, vec![(17, 16), (18, 16), (18, 17)]); direction = Direction::Right; - move_snake(&mut snake, &direction, length); + move_snake(&mut snake, &direction, length, size); assert_eq!(snake, vec![(18, 16), (18, 17), (19, 17)]); direction = Direction::Down; - move_snake(&mut snake, &direction, length); + move_snake(&mut snake, &direction, length, size); assert_eq!(snake, vec![(18, 17), (19, 17), (19, 16)]); direction = Direction::Left; - move_snake(&mut snake, &direction, length); + move_snake(&mut snake, &direction, length, size); assert_eq!(snake, vec![(19, 17), (19, 16), (18, 16)]); } }