Skip to content

Commit acbfd60

Browse files
committed
Add actual snake source files
Signed-off-by: Daniel Schaefer <[email protected]>
1 parent 7d9ab73 commit acbfd60

File tree

2 files changed

+141
-0
lines changed

2 files changed

+141
-0
lines changed

src/games/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pub mod snake;

src/games/snake.rs

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
use crate::control::GameControlArg;
2+
use crate::matrix::{GameState, Grid, State, HEIGHT, LEDS, WIDTH};
3+
4+
use heapless::Vec;
5+
6+
// Wrap around the edges
7+
const WRAP_ENABLE: bool = false;
8+
9+
#[derive(Clone, Debug, Copy)]
10+
pub enum HeadDirection {
11+
Up,
12+
Down,
13+
Left,
14+
Right,
15+
}
16+
17+
type Position = (i8, i8);
18+
19+
#[derive(Clone)]
20+
pub struct SnakeState {
21+
head: Position,
22+
pub direction: HeadDirection,
23+
// Unrealistic that the body will ever get this long
24+
pub body: Vec<Position, LEDS>,
25+
pub game_over: bool,
26+
food: Position,
27+
}
28+
29+
fn place_food(random: u8) -> Position {
30+
// TODO: while food == head:
31+
let x = ((random & 0xF0) >> 4) % WIDTH as u8;
32+
let y = (random & 0x0F) % HEIGHT as u8;
33+
(x as i8, y as i8)
34+
}
35+
36+
pub fn start_game(state: &mut State, random: u8) {
37+
state.game = Some(GameState::Snake(SnakeState {
38+
head: (4, 0),
39+
direction: HeadDirection::Down,
40+
body: Vec::new(),
41+
game_over: false,
42+
food: place_food(random),
43+
}));
44+
}
45+
pub fn handle_control(state: &mut State, arg: &GameControlArg) {
46+
if let Some(GameState::Snake(ref mut snake_state)) = state.game {
47+
match arg {
48+
GameControlArg::Up => snake_state.direction = HeadDirection::Up,
49+
GameControlArg::Down => snake_state.direction = HeadDirection::Down,
50+
GameControlArg::Left => snake_state.direction = HeadDirection::Left,
51+
GameControlArg::Right => snake_state.direction = HeadDirection::Right,
52+
//GameControlArg::Exit => {
53+
_ => {
54+
// TODO
55+
}
56+
}
57+
}
58+
}
59+
60+
pub fn game_step(state: &mut State, random: u8) -> (HeadDirection, bool, usize, Position) {
61+
if let Some(GameState::Snake(ref mut snake_state)) = state.game {
62+
if snake_state.game_over {
63+
return (
64+
snake_state.direction,
65+
snake_state.game_over,
66+
snake_state.body.len(),
67+
snake_state.head,
68+
);
69+
}
70+
71+
let (x, y) = snake_state.head;
72+
let oldhead = snake_state.head.clone();
73+
snake_state.head = match snake_state.direction {
74+
// (0, 0) is at the top right corner
75+
HeadDirection::Right => (x - 1, y),
76+
HeadDirection::Left => (x + 1, y),
77+
HeadDirection::Down => (x, y + 1),
78+
HeadDirection::Up => (x, y - 1),
79+
};
80+
let (x, y) = snake_state.head;
81+
let width = WIDTH as i8;
82+
let height = HEIGHT as i8;
83+
84+
if snake_state.body.contains(&snake_state.head) {
85+
// Ran into itself
86+
snake_state.game_over = true
87+
} else if x >= width || x < 0 || y >= height || y < 0 {
88+
// Hit an edge
89+
if WRAP_ENABLE {
90+
snake_state.head = if x >= width {
91+
(0, y)
92+
} else if x < 0 {
93+
(width - 1, y)
94+
} else if y >= height {
95+
(x, 0)
96+
} else if y < 0 {
97+
(x, height - 1)
98+
} else {
99+
(x, y)
100+
};
101+
} else {
102+
snake_state.game_over = true
103+
}
104+
} else if snake_state.head == snake_state.food {
105+
// Eating food and growing
106+
snake_state.body.insert(0, oldhead).unwrap();
107+
snake_state.food = place_food(random);
108+
} else if !snake_state.body.is_empty() {
109+
// Move body along
110+
snake_state.body.pop();
111+
snake_state.body.insert(0, oldhead).unwrap();
112+
}
113+
114+
if !snake_state.game_over {
115+
state.grid = draw_matrix(&snake_state);
116+
}
117+
(
118+
snake_state.direction,
119+
snake_state.game_over,
120+
snake_state.body.len(),
121+
snake_state.head,
122+
)
123+
} else {
124+
(HeadDirection::Down, true, 0, (0, 0))
125+
}
126+
}
127+
128+
fn draw_matrix(state: &SnakeState) -> Grid {
129+
let (x, y) = state.head;
130+
let mut grid = Grid::default();
131+
132+
grid.0[x as usize][y as usize] = 0xFF;
133+
grid.0[state.food.0 as usize][state.food.1 as usize] = 0xFF;
134+
for bodypart in &state.body {
135+
let (x, y) = bodypart;
136+
grid.0[*x as usize][*y as usize] = 0xFF;
137+
}
138+
139+
grid
140+
}

0 commit comments

Comments
 (0)