usize terminal size for width and height

This commit is contained in:
2024-04-03 14:03:38 +02:00
parent 25f568a74d
commit 7604d10c3c

View File

@@ -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<char> {
}
fn move_snake(
snake: &mut VecDeque<(usize, usize)>,
snake: &mut VecDeque<(u16, u16)>,
direction: &Direction,
length: usize,
(width, height): (u16, u16),
) -> Option<CrashLocation> {
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)]);
}
}