I hate doing this as one giant commit, but I was under the gun and had to just code as fast as I could, so some common software development things had to be skipped. Mostly git commits. Here we have several mini applications that reside on the microbit. * Menu - The main app switching presentation. * Badge - A name scroller. * Snake - A snake game. The switcher task is the main running task of the program. All the logic goes through here. It will pass the running off to different apps. When an app returns from its main function it will return the next app to switch to. The display task is a PWM LED matrix updater. It will turn on the LEDs for what ever frame is passed to it. It keeps a backing frame for draw calls that occur between new frames arriving. There are several button listeners for input handling. Everything is sent using channels, button input and presentation frames.
128 lines
2.4 KiB
Rust
128 lines
2.4 KiB
Rust
use crate::bounded::WrappedU8;
|
|
|
|
|
|
|
|
/// Global game Direction.
|
|
#[derive(Clone, Copy, PartialEq)]
|
|
pub enum Direction
|
|
{
|
|
/// Towards the top of the board.
|
|
Up,
|
|
|
|
/// Towarfs the bottom of the board.
|
|
Down,
|
|
|
|
/// Towards the Left of the board.
|
|
Left,
|
|
|
|
/// Towards the Right of the board.
|
|
Right
|
|
}
|
|
|
|
|
|
/// The way to Turn the Snake relative to it's global Direction.
|
|
///
|
|
/// For example if the Snake is heading Right and it is told to go Left then
|
|
/// it's next Direction would be Up.
|
|
#[derive(Clone, Copy, PartialEq)]
|
|
pub enum Turn
|
|
{
|
|
/// Turn left!
|
|
Left,
|
|
|
|
/// Turn right!
|
|
Right,
|
|
|
|
/// Go straight.
|
|
Straight
|
|
}
|
|
|
|
|
|
/// Defines a position on the Game board.
|
|
///
|
|
/// The game board is a grid with the upper left being (0, 0)
|
|
/// with positive X to the right and positive y going down.
|
|
///
|
|
/// Below is a 5x5 representation.
|
|
///
|
|
/// [ (0,0) (1,0), (2,0), (3,0), (4,0) ]
|
|
/// [ (0,1) (1,1), (2,1), (3,1), (4,1) ]
|
|
/// [ (0,2) (1,2), (2,2), (3,2), (4,2) ]
|
|
/// [ (0,3) (1,3), (2,3), (3,3), (4,3) ]
|
|
/// [ (0,4) (1,4), (2,4), (3,4), (4,4) ]
|
|
#[derive(Clone, Copy, Default, PartialEq)]
|
|
pub struct Position
|
|
{
|
|
/// The column we are in.
|
|
pub x: WrappedU8<0, 4>,
|
|
|
|
/// The row we are in.
|
|
pub y: WrappedU8<0, 4>
|
|
}
|
|
|
|
impl Position
|
|
{
|
|
pub fn new(x: u8, y: u8) -> Self
|
|
{
|
|
Position { x: x.into(),
|
|
y: y.into() }
|
|
}
|
|
|
|
pub fn set(&mut self, new_x: u8, new_y: u8)
|
|
{
|
|
self.x = new_x.into();
|
|
self.y = new_y.into();
|
|
}
|
|
}
|
|
|
|
|
|
impl From<&Position> for (usize, usize)
|
|
{
|
|
fn from(pos: &Position) -> Self
|
|
{
|
|
(pos.x.get() as usize, pos.y.get() as usize)
|
|
}
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
mod tests
|
|
{
|
|
// use super::bounded::WrappedU8;
|
|
use super::Position;
|
|
|
|
#[test]
|
|
fn position_new_sets_coordinates_correctly()
|
|
{
|
|
let pos = Position::new(2, 3);
|
|
assert_eq!(pos.x.get(), 2);
|
|
assert_eq!(pos.y.get(), 3);
|
|
}
|
|
|
|
#[test]
|
|
fn position_set_updates_coordinates()
|
|
{
|
|
let mut pos = Position::new(0, 0);
|
|
pos.set(4, 1);
|
|
assert_eq!(pos.x.get(), 4);
|
|
assert_eq!(pos.y.get(), 1);
|
|
}
|
|
|
|
#[test]
|
|
fn position_new_wraps_coordinates()
|
|
{
|
|
let pos = Position::new(5, 6);
|
|
assert_eq!(pos.x.get(), 1);
|
|
assert_eq!(pos.y.get(), 2);
|
|
}
|
|
|
|
#[test]
|
|
fn position_default_is_zero_zero()
|
|
{
|
|
let pos = Position::default();
|
|
assert_eq!(pos.x.get(), 0);
|
|
assert_eq!(pos.y.get(), 0);
|
|
}
|
|
}
|