feat: implement core of the game
This commit is contained in:
parent
54c41c3680
commit
5b66ea248e
@ -3,6 +3,5 @@ name = "rust-wasm-snake"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
rand = "0.8.5"
|
||||||
|
130
src/lib.rs
130
src/lib.rs
@ -1,8 +1,126 @@
|
|||||||
#[cfg(test)]
|
use std::collections::VecDeque;
|
||||||
mod tests {
|
|
||||||
#[test]
|
use rand::prelude::*;
|
||||||
fn it_works() {
|
|
||||||
let result = 2 + 2;
|
pub type Position = (usize, usize);
|
||||||
assert_eq!(result, 4);
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub enum Direction {
|
||||||
|
Up,
|
||||||
|
Down,
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct SnakeGame {
|
||||||
|
width: usize,
|
||||||
|
height: usize,
|
||||||
|
snake: VecDeque<Position>,
|
||||||
|
snake_direction: Direction,
|
||||||
|
food: Position,
|
||||||
|
game_over: bool
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rand_position(width: usize, height: usize) -> Position {
|
||||||
|
let mut rng = thread_rng();
|
||||||
|
(rng.gen_range(0..width), rng.gen_range(0..height))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_opposite_direction(direction: &Direction) -> Direction {
|
||||||
|
match direction {
|
||||||
|
Direction::Up => Direction::Down,
|
||||||
|
Direction::Down => Direction::Up,
|
||||||
|
Direction::Right => Direction::Left,
|
||||||
|
Direction::Left => Direction::Right,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SnakeGame {
|
||||||
|
pub fn new(width: usize, height: usize) -> SnakeGame {
|
||||||
|
Self {
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
snake: VecDeque::from([(width / 2, height / 2)]),
|
||||||
|
snake_direction: Direction::Left,
|
||||||
|
food: rand_position(width, height),
|
||||||
|
game_over: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn change_direction(&mut self, direction: Direction) {
|
||||||
|
// Because you can't start going in the opposite direction you are
|
||||||
|
// currently going
|
||||||
|
if get_opposite_direction(&self.snake_direction) == direction {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.snake_direction = direction
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_valid_move(&self, (x, y): Position, dx: i32, dy: i32) -> bool {
|
||||||
|
let new_x = x as i32 + dx;
|
||||||
|
let new_y = y as i32 + dy;
|
||||||
|
0 <= new_x && new_x < self.width as i32 && 0 <= new_y && new_y < self.height as i32
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_unoccupied_position(&self) -> Option<Position> {
|
||||||
|
let mut rng = thread_rng();
|
||||||
|
(0..self.height)
|
||||||
|
.flat_map(|y| (0..self.width).map(move |x| (x, y)))
|
||||||
|
.filter(|pos| !self.snake.contains(pos))
|
||||||
|
.choose(&mut rng)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tick(&mut self) {
|
||||||
|
if self.game_over {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let head = self.snake.front();
|
||||||
|
if head.is_none() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let head = *head.unwrap();
|
||||||
|
|
||||||
|
let (dx, dy): (i32, i32) = match &self.snake_direction {
|
||||||
|
Direction::Up => (-1, 0),
|
||||||
|
Direction::Down => (1, 0),
|
||||||
|
Direction::Left => (-1, 0),
|
||||||
|
Direction::Right => (1, 0),
|
||||||
|
};
|
||||||
|
|
||||||
|
if !self.is_valid_move(head, dx, dy) {
|
||||||
|
self.game_over = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let new_head = (
|
||||||
|
(head.0 as i32 + dx) as usize,
|
||||||
|
(head.1 as i32 + dy) as usize
|
||||||
|
);
|
||||||
|
self.snake.push_front(new_head);
|
||||||
|
|
||||||
|
if new_head == self.food {
|
||||||
|
let new_food = self.get_unoccupied_position();
|
||||||
|
if let Some(new_food) = new_food {
|
||||||
|
self.food = new_food;
|
||||||
|
} else {
|
||||||
|
self.game_over = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.snake.pop_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
#[test]
|
||||||
|
fn it_works() {
|
||||||
|
let game = SnakeGame::new(10, 10);
|
||||||
|
|
||||||
|
println!("{:?}", game);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user