fix: fixed timing on loop
This commit is contained in:
144
src/main.rs
144
src/main.rs
@@ -6,12 +6,16 @@ use crossterm::{
|
|||||||
ExecutableCommand,
|
ExecutableCommand,
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
cmp::min, collections::VecDeque, io::{Write, stdout}
|
cmp::min,
|
||||||
|
collections::VecDeque,
|
||||||
|
io::{Write, stdout},
|
||||||
|
sync::mpsc,
|
||||||
|
thread,
|
||||||
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
use std::time::Duration;
|
|
||||||
use rand::random_range;
|
use rand::random_range;
|
||||||
|
|
||||||
#[derive(PartialEq, Eq)]
|
#[derive(PartialEq, Eq, Copy, Clone)]
|
||||||
enum Direction {
|
enum Direction {
|
||||||
Up,
|
Up,
|
||||||
Down,
|
Down,
|
||||||
@@ -19,14 +23,26 @@ enum Direction {
|
|||||||
Right,
|
Right,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_inputs() -> Option<KeyCode> {
|
fn spawn_input_handler(tx: mpsc::Sender<KeyCode>) {
|
||||||
if event::poll(Duration::from_millis(300)).unwrap() {
|
thread::spawn(move || {
|
||||||
|
loop {
|
||||||
|
if event::poll(Duration::from_millis(50)).unwrap() {
|
||||||
if let Event::Key(KeyEvent { code, .. }) = event::read().unwrap() {
|
if let Event::Key(KeyEvent { code, .. }) = event::read().unwrap() {
|
||||||
return Some(code);
|
if tx.send(code).is_err() {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
None
|
fn wait_for_restart(rx: &mpsc::Receiver<KeyCode>) {
|
||||||
|
loop {
|
||||||
|
if let Ok(KeyCode::Char('r')) = rx.recv() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_gui(max_x: u16, max_y: u16) {
|
fn draw_gui(max_x: u16, max_y: u16) {
|
||||||
@@ -37,68 +53,91 @@ fn draw_gui(max_x: u16, max_y: u16) {
|
|||||||
stdout.execute(SetForegroundColor(Color::White)).unwrap();
|
stdout.execute(SetForegroundColor(Color::White)).unwrap();
|
||||||
println!("┌{}┐", "──".repeat(max_x as usize + 2));
|
println!("┌{}┐", "──".repeat(max_x as usize + 2));
|
||||||
|
|
||||||
for i in 2..max_y+3 {
|
for i in 2..max_y + 3 {
|
||||||
stdout.execute(cursor::MoveTo(0, i)).unwrap();
|
stdout.execute(cursor::MoveTo(0, i)).unwrap();
|
||||||
println!("│{}│", " ".repeat((max_x as usize+2) * 2))
|
println!("│{}│", " ".repeat((max_x as usize + 2) * 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
stdout.execute(cursor::MoveTo(0, max_y+3)).unwrap();
|
stdout.execute(cursor::MoveTo(0, max_y + 3)).unwrap();
|
||||||
println!("└{}┘", "──".repeat(max_x as usize + 2));
|
println!("└{}┘", "──".repeat(max_x as usize + 2));
|
||||||
|
|
||||||
stdout.execute(ResetColor).unwrap();
|
stdout.execute(ResetColor).unwrap();
|
||||||
stdout.flush().unwrap();
|
stdout.flush().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn win() {
|
fn win(rx: &mpsc::Receiver<KeyCode>) {
|
||||||
let mut stdout = stdout();
|
let mut stdout = stdout();
|
||||||
stdout.execute(cursor::MoveTo(0, 0)).unwrap();
|
stdout.execute(cursor::MoveTo(0, 0)).unwrap();
|
||||||
println!("WIN");
|
println!("WIN");
|
||||||
|
wait_for_restart(rx);
|
||||||
loop {
|
|
||||||
match read_inputs() {
|
|
||||||
Some(KeyCode::Char('r')) => break,
|
|
||||||
_ => {},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn game_over() {
|
fn game_over(rx: &mpsc::Receiver<KeyCode>) {
|
||||||
loop {
|
let mut stdout = stdout();
|
||||||
match read_inputs() {
|
stdout.execute(cursor::MoveTo(0, 0)).unwrap();
|
||||||
Some(KeyCode::Char('r')) => break,
|
println!("LOSE");
|
||||||
_ => {},
|
wait_for_restart(rx);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
const MAX_X : u16 = 7;
|
const MAX_X: u16 = 7;
|
||||||
const MAX_Y: u16 = 7;
|
const MAX_Y: u16 = 7;
|
||||||
|
const TICK_RATE: Duration = Duration::from_millis(300);
|
||||||
|
|
||||||
let mut head_x: u16 = 4;
|
let mut head_x: u16 = 4;
|
||||||
let mut head_y: u16 = 4;
|
let mut head_y: u16 = 4;
|
||||||
let mut body_length: usize = 0;
|
let mut body_length: usize = 0;
|
||||||
let mut body: VecDeque<(u16,u16)> = Default::default();
|
let mut body: VecDeque<(u16, u16)> = Default::default();
|
||||||
let mut direction: Direction = Direction::Up;
|
let mut direction: Direction = Direction::Up;
|
||||||
|
let mut next_direction: Direction = Direction::Up;
|
||||||
|
|
||||||
let mut apple_x: u16 = random_range(0..MAX_X+1);
|
let mut apple_x: u16 = random_range(0..MAX_X + 1);
|
||||||
let mut apple_y: u16 = random_range(0..MAX_Y+1);
|
let mut apple_y: u16 = random_range(0..MAX_Y + 1);
|
||||||
|
|
||||||
let mut stdout = stdout();
|
let mut stdout = stdout();
|
||||||
terminal::enable_raw_mode().unwrap();
|
terminal::enable_raw_mode().unwrap();
|
||||||
stdout.execute(cursor::Hide).unwrap();
|
stdout.execute(cursor::Hide).unwrap();
|
||||||
|
|
||||||
|
let (tx, rx) = mpsc::channel();
|
||||||
|
spawn_input_handler(tx);
|
||||||
|
|
||||||
|
let mut last_tick = Instant::now();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
match read_inputs() {
|
if let Ok(code) = rx.try_recv() {
|
||||||
Some(KeyCode::Up) => direction = if direction != Direction::Down {Direction::Up} else {direction},
|
match code {
|
||||||
Some(KeyCode::Down) => direction = if direction != Direction::Up {Direction::Down} else {direction},
|
KeyCode::Up => next_direction = Direction::Up,
|
||||||
Some(KeyCode::Left) => direction = if direction != Direction::Right {Direction::Left} else {direction},
|
KeyCode::Down => next_direction = Direction::Down,
|
||||||
Some(KeyCode::Right) => direction = if direction != Direction::Left {Direction::Right} else {direction},
|
KeyCode::Left => next_direction = Direction::Left,
|
||||||
Some(KeyCode::Char('q')) => break,
|
KeyCode::Right => next_direction = Direction::Right,
|
||||||
_ => {},
|
KeyCode::Char('q') => {
|
||||||
|
stdout.execute(Clear(ClearType::All)).unwrap();
|
||||||
|
stdout.execute(cursor::MoveTo(0, 0)).unwrap();
|
||||||
|
stdout.execute(cursor::Show).unwrap();
|
||||||
|
terminal::disable_raw_mode().unwrap();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
while rx.try_recv().is_ok() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if last_tick.elapsed() < TICK_RATE {
|
||||||
|
thread::sleep(Duration::from_millis(1));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
last_tick = Instant::now();
|
||||||
|
|
||||||
// MOVE
|
// MOVE
|
||||||
|
direction = match (&next_direction, &direction) {
|
||||||
|
(Direction::Up, Direction::Down) => Direction::Down,
|
||||||
|
(Direction::Down, Direction::Up) => Direction::Up,
|
||||||
|
(Direction::Left, Direction::Right) => Direction::Right,
|
||||||
|
(Direction::Right, Direction::Left) => Direction::Left,
|
||||||
|
_ => next_direction, // valid move, accept it
|
||||||
|
};
|
||||||
|
|
||||||
|
next_direction = direction;
|
||||||
if body.len() > body_length {
|
if body.len() > body_length {
|
||||||
body.pop_back();
|
body.pop_back();
|
||||||
}
|
}
|
||||||
@@ -106,23 +145,21 @@ fn main() {
|
|||||||
|
|
||||||
match direction {
|
match direction {
|
||||||
Direction::Up => head_y = head_y.saturating_sub(1),
|
Direction::Up => head_y = head_y.saturating_sub(1),
|
||||||
Direction::Down => head_y = min(head_y+1, MAX_Y),
|
Direction::Down => head_y = min(head_y + 1, MAX_Y),
|
||||||
Direction::Left => head_x = head_x.saturating_sub(1),
|
Direction::Left => head_x = head_x.saturating_sub(1),
|
||||||
Direction::Right => head_x = min(head_x+1, MAX_X),
|
Direction::Right => head_x = min(head_x + 1, MAX_X),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// CHECKS
|
// CHECKS
|
||||||
if body_length == MAX_X as usize * MAX_Y as usize { win(); }
|
if body_length == MAX_X as usize * MAX_Y as usize {
|
||||||
|
win(&rx);
|
||||||
|
}
|
||||||
if (head_x, head_y) == (apple_x, apple_y) {
|
if (head_x, head_y) == (apple_x, apple_y) {
|
||||||
body_length += 1;
|
body_length += 1;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
apple_x = random_range(0..MAX_X+1);
|
apple_x = random_range(0..MAX_X + 1);
|
||||||
apple_y = random_range(0..MAX_Y+1);
|
apple_y = random_range(0..MAX_Y + 1);
|
||||||
|
if !body.contains(&(apple_x, apple_y)) && (apple_x, apple_y) != (head_x, head_y) {
|
||||||
if !body.contains(&(apple_x, apple_y)) &&
|
|
||||||
(apple_x, apple_y) != (head_x, head_y) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -132,13 +169,11 @@ fn main() {
|
|||||||
stdout.execute(Clear(ClearType::All)).unwrap();
|
stdout.execute(Clear(ClearType::All)).unwrap();
|
||||||
draw_gui(MAX_X, MAX_Y);
|
draw_gui(MAX_X, MAX_Y);
|
||||||
|
|
||||||
// Apple
|
stdout.execute(cursor::MoveTo((apple_x + 1) * 2, apple_y + 2)).unwrap();
|
||||||
stdout.execute(cursor::MoveTo((apple_x+1)*2, apple_y+2)).unwrap();
|
|
||||||
stdout.execute(SetForegroundColor(Color::Red)).unwrap();
|
stdout.execute(SetForegroundColor(Color::Red)).unwrap();
|
||||||
print!("⯀");
|
print!("⯀");
|
||||||
|
|
||||||
// Snake
|
stdout.execute(cursor::MoveTo((head_x + 1) * 2, head_y + 2)).unwrap();
|
||||||
stdout.execute(cursor::MoveTo((head_x+1)*2, head_y+2)).unwrap();
|
|
||||||
stdout.execute(SetForegroundColor(Color::Green)).unwrap();
|
stdout.execute(SetForegroundColor(Color::Green)).unwrap();
|
||||||
match direction {
|
match direction {
|
||||||
Direction::Up => print!("⯅"),
|
Direction::Up => print!("⯅"),
|
||||||
@@ -148,16 +183,11 @@ fn main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (x, y) in &body {
|
for (x, y) in &body {
|
||||||
stdout.execute(cursor::MoveTo((x+1)*2, y+2)).unwrap();
|
stdout.execute(cursor::MoveTo((x + 1) * 2, y + 2)).unwrap();
|
||||||
print!("⯀")
|
print!("⯀");
|
||||||
}
|
}
|
||||||
|
|
||||||
stdout.execute(ResetColor).unwrap();
|
stdout.execute(ResetColor).unwrap();
|
||||||
stdout.flush().unwrap();
|
stdout.flush().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
stdout.execute(Clear(ClearType::All)).unwrap();
|
|
||||||
stdout.execute(cursor::MoveTo(0, 0)).unwrap();
|
|
||||||
stdout.execute(cursor::Show).unwrap();
|
|
||||||
terminal::disable_raw_mode().unwrap();
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user