initial commit
This commit is contained in:
parent
8288f3f628
commit
6198043d76
4 changed files with 213 additions and 1 deletions
10
Cargo.toml
Normal file
10
Cargo.toml
Normal file
|
@ -0,0 +1,10 @@
|
|||
[package]
|
||||
name = "snake-rs"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
crossterm = "0.26.1"
|
||||
rand = "0.8.5"
|
|
@ -1,3 +1,10 @@
|
|||
# snake-rs
|
||||
|
||||
Classic snake game with terminal graphics written in rust.
|
||||
|
||||
This is my first project in rust so the code is probably great.
|
||||
|
||||
Play the game:
|
||||
```
|
||||
cargo run
|
||||
```
|
||||
|
|
195
src/main.rs
Normal file
195
src/main.rs
Normal file
|
@ -0,0 +1,195 @@
|
|||
use crossterm::{*, cursor::*, event::*, style::*, terminal::*};
|
||||
use std::io::{stdout, Stdout, Write};
|
||||
use std::time::Duration;
|
||||
use rand::{Rng, thread_rng};
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
struct Point {
|
||||
x: u16,
|
||||
y: u16
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, std::fmt::Debug, PartialEq, Eq)]
|
||||
enum Direction {
|
||||
Up,
|
||||
Down,
|
||||
Left,
|
||||
Right
|
||||
}
|
||||
|
||||
fn init_screen() -> Result<Stdout> {
|
||||
let mut stdout: Stdout = stdout();
|
||||
|
||||
enable_raw_mode()?;
|
||||
stdout.queue(Clear(ClearType::All))?;
|
||||
stdout.queue(Hide)?;
|
||||
stdout.queue(MoveTo(0, 0))?;
|
||||
|
||||
stdout.flush()?;
|
||||
|
||||
Ok(stdout)
|
||||
}
|
||||
|
||||
fn cleanup(stdout: &mut Stdout) -> Result<()> {
|
||||
stdout.queue(Clear(ClearType::All))?;
|
||||
stdout.queue(Show)?;
|
||||
stdout.queue(MoveTo(0, 0))?;
|
||||
disable_raw_mode()?;
|
||||
|
||||
stdout.flush()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn move_snake(snake: &mut Vec<Point>, direction: Direction, cols: u16, rows: u16) {
|
||||
for i in (0..(*snake).len()).rev() {
|
||||
if i == 0 {
|
||||
match direction {
|
||||
Direction::Up => {
|
||||
if snake[0].y == 0 {
|
||||
snake[0].y = rows-1;
|
||||
} else {
|
||||
snake[0].y -= 1;
|
||||
}
|
||||
},
|
||||
Direction::Down => {
|
||||
if snake[0].y == rows-1 {
|
||||
snake[0].y = 0;
|
||||
} else {
|
||||
snake[0].y += 1;
|
||||
}
|
||||
},
|
||||
Direction::Left => {
|
||||
if snake[0].x == 0 {
|
||||
snake[0].x = cols-1;
|
||||
} else {
|
||||
snake[0].x -= 1;
|
||||
}
|
||||
},
|
||||
Direction::Right => {
|
||||
if snake[0].x == cols-1 {
|
||||
snake[0].x = 0;
|
||||
} else {
|
||||
snake[0].x += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
snake[i] = snake[i-1];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn print_snake(snake: &Vec<Point>, screen: &mut Stdout) -> Result<()> {
|
||||
for seg in (*snake).iter() {
|
||||
(*screen).queue(MoveTo(seg.x, seg.y))?;
|
||||
(*screen).queue(Print("#".to_string()))?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let mut screen = init_screen()?;
|
||||
let (cols, rows) = size()?;
|
||||
|
||||
let mut snake: Vec<Point> = Vec::new();
|
||||
let mut apples: Vec<Point> = Vec::new();
|
||||
|
||||
let inital_length = 5;
|
||||
let num_apples = 10;
|
||||
let mut head_x = cols/2 - inital_length/2;
|
||||
let mut head_y = rows/2;
|
||||
let mut direction: Direction = Direction::Left;
|
||||
let mut score = 0;
|
||||
let mut lost = false;
|
||||
|
||||
screen.queue(MoveTo(head_x, head_y))?;
|
||||
|
||||
// create snake
|
||||
for i in 0..inital_length {
|
||||
snake.push(Point { x: head_x + i, y: head_y });
|
||||
screen.queue(Print("#".to_string()))?;
|
||||
}
|
||||
|
||||
// create apples
|
||||
for i in 0..num_apples {
|
||||
apples.push(Point { x: thread_rng().gen_range(0..cols), y: thread_rng().gen_range(0..rows-1)});
|
||||
screen.queue(MoveTo(apples[i].x, apples[i].y))?;
|
||||
screen.queue(Print("*".to_string()))?;
|
||||
}
|
||||
|
||||
'main: loop {
|
||||
screen.queue(MoveTo(head_x, head_y))?;
|
||||
|
||||
match direction {
|
||||
Direction::Up => {move_snake(&mut snake, direction, cols, rows);},
|
||||
Direction::Down => {move_snake(&mut snake, direction, cols, rows);},
|
||||
Direction::Left => {move_snake(&mut snake, direction, cols, rows);},
|
||||
Direction::Right => {move_snake(&mut snake, direction, cols, rows);}
|
||||
}
|
||||
|
||||
head_x = snake[0].x;
|
||||
head_y = snake[0].y;
|
||||
|
||||
for i in 1..snake.len() {
|
||||
if head_x == snake[i].x && head_y == snake[i].y {
|
||||
lost = true;
|
||||
break 'main;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for i in 0..num_apples {
|
||||
if head_x == apples[i].x && head_y == apples[i].y {
|
||||
score += 1;
|
||||
apples[i] = Point { x: thread_rng().gen_range(0..cols), y: thread_rng().gen_range(0..rows)};
|
||||
snake.push(Point { x: 0, y: 0 });
|
||||
}
|
||||
screen.queue(MoveTo(apples[i].x, apples[i].y))?;
|
||||
screen.queue(Print("*".to_string()))?;
|
||||
}
|
||||
|
||||
print_snake(&snake, &mut screen)?;
|
||||
|
||||
screen.queue(MoveTo(0, rows))?;
|
||||
|
||||
screen.queue(Print(format!("SCORE: {} | <q> to quit | arrow keys to move", score)))?;
|
||||
|
||||
screen.flush()?;
|
||||
screen.queue(Clear(ClearType::All))?;
|
||||
|
||||
if poll(Duration::from_millis(150))? {
|
||||
match read()? {
|
||||
Event::Key(e) => match e.code {
|
||||
KeyCode::Char('q') => break 'main,
|
||||
KeyCode::Up => direction =
|
||||
if direction != Direction::Down { Direction::Up }
|
||||
else { direction },
|
||||
KeyCode::Down => direction =
|
||||
if direction != Direction::Up { Direction::Down }
|
||||
else { direction },
|
||||
KeyCode::Left => direction =
|
||||
if direction != Direction::Right { Direction::Left }
|
||||
else { direction },
|
||||
KeyCode::Right => direction =
|
||||
if direction != Direction::Left { Direction::Right }
|
||||
else { direction },
|
||||
_ => ()
|
||||
},
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cleanup(&mut screen)?;
|
||||
|
||||
if lost {
|
||||
println!("You loose. Final Score: {}", score);
|
||||
} else {
|
||||
println!("Goodbye! Final Score: {}", score);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
}
|
0
src/snake.rs
Normal file
0
src/snake.rs
Normal file
Loading…
Reference in a new issue