Add snake gui app and update os/usr parts. Now snake can run!
This commit is contained in:
parent
b40120f8ff
commit
2cbd237260
14 changed files with 457 additions and 15 deletions
|
@ -15,9 +15,8 @@ xmas-elf = "0.7.0"
|
||||||
volatile = "0.3"
|
volatile = "0.3"
|
||||||
#virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers", rev = "4ee80e5" }
|
#virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers", rev = "4ee80e5" }
|
||||||
virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers", rev = "70b5850" }
|
virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers", rev = "70b5850" }
|
||||||
|
|
||||||
easy-fs = { path = "../easy-fs" }
|
easy-fs = { path = "../easy-fs" }
|
||||||
virtio-input-decoder = "0.1.4"
|
#virtio-input-decoder = "0.1.4"
|
||||||
embedded-graphics = "0.7.1"
|
embedded-graphics = "0.7.1"
|
||||||
tinybmp = "0.3.1"
|
tinybmp = "0.3.1"
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ pub type CharDeviceImpl = crate::drivers::chardev::NS16550a<VIRT_UART>;
|
||||||
|
|
||||||
pub const VIRT_PLIC: usize = 0xC00_0000;
|
pub const VIRT_PLIC: usize = 0xC00_0000;
|
||||||
pub const VIRT_UART: usize = 0x1000_0000;
|
pub const VIRT_UART: usize = 0x1000_0000;
|
||||||
|
#[allow(unused)]
|
||||||
pub const VIRTGPU_XRES: u32 = 1280;
|
pub const VIRTGPU_XRES: u32 = 1280;
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub const VIRTGPU_YRES: u32 = 800;
|
pub const VIRTGPU_YRES: u32 = 800;
|
||||||
|
|
|
@ -131,7 +131,7 @@ pub struct NS16550a<const BASE_ADDR: usize> {
|
||||||
|
|
||||||
impl<const BASE_ADDR: usize> NS16550a<BASE_ADDR> {
|
impl<const BASE_ADDR: usize> NS16550a<BASE_ADDR> {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let mut inner = NS16550aInner {
|
let inner = NS16550aInner {
|
||||||
ns16550a: NS16550aRaw::new(BASE_ADDR),
|
ns16550a: NS16550aRaw::new(BASE_ADDR),
|
||||||
read_buffer: VecDeque::new(),
|
read_buffer: VecDeque::new(),
|
||||||
};
|
};
|
||||||
|
@ -141,6 +141,10 @@ impl<const BASE_ADDR: usize> NS16550a<BASE_ADDR> {
|
||||||
condvar: Condvar::new(),
|
condvar: Condvar::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn read_buffer_is_empty(&self) -> bool {
|
||||||
|
self.inner.exclusive_session(|inner| inner.read_buffer.is_empty())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<const BASE_ADDR: usize> CharDevice for NS16550a<BASE_ADDR> {
|
impl<const BASE_ADDR: usize> CharDevice for NS16550a<BASE_ADDR> {
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
use crate::drivers::bus::virtio::VirtioHal;
|
use crate::drivers::bus::virtio::VirtioHal;
|
||||||
use crate::sync::{Condvar, UPIntrFreeCell};
|
use crate::sync::{Condvar, UPIntrFreeCell};
|
||||||
use crate::task::schedule;
|
use crate::task::schedule;
|
||||||
use alloc::collections::BTreeMap;
|
|
||||||
use alloc::collections::VecDeque;
|
use alloc::collections::VecDeque;
|
||||||
use alloc::sync::Arc;
|
use alloc::sync::Arc;
|
||||||
use core::any::Any;
|
use core::any::Any;
|
||||||
use virtio_drivers::{VirtIOHeader, VirtIOInput};
|
use virtio_drivers::{VirtIOHeader, VirtIOInput};
|
||||||
use virtio_input_decoder::{Decoder, Key, KeyType};
|
|
||||||
|
|
||||||
const VIRTIO5: usize = 0x10005000;
|
const VIRTIO5: usize = 0x10005000;
|
||||||
const VIRTIO6: usize = 0x10006000;
|
const VIRTIO6: usize = 0x10006000;
|
||||||
|
@ -112,7 +110,8 @@ impl InputDevice for VirtIOInputWrapper {
|
||||||
| (event.code as u64) << 32
|
| (event.code as u64) << 32
|
||||||
| (event.value) as u64;
|
| (event.value) as u64;
|
||||||
inner.events.push_back(result);
|
inner.events.push_back(result);
|
||||||
println!("[KERN] inputdev_handle_irq: event: {:x}", result);
|
// for test
|
||||||
|
//println!("[KERN] inputdev_handle_irq: event: {:x}", result);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if count > 0 {
|
if count > 0 {
|
||||||
|
|
|
@ -96,4 +96,4 @@ pub fn sys_dup(fd: usize) -> isize {
|
||||||
let new_fd = inner.alloc_fd();
|
let new_fd = inner.alloc_fd();
|
||||||
inner.fd_table[new_fd] = Some(Arc::clone(inner.fd_table[fd].as_ref().unwrap()));
|
inner.fd_table[new_fd] = Some(Arc::clone(inner.fd_table[fd].as_ref().unwrap()));
|
||||||
new_fd as isize
|
new_fd as isize
|
||||||
}
|
}
|
|
@ -14,4 +14,16 @@ pub fn sys_event_get() ->isize {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
use crate::drivers::chardev::UART;
|
||||||
|
|
||||||
|
/// check UART's read-buffer is empty or not
|
||||||
|
pub fn sys_key_pressed() -> isize {
|
||||||
|
let res =!UART.read_buffer_is_empty();
|
||||||
|
if res {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -28,6 +28,7 @@ const SYSCALL_CONDVAR_WAIT: usize = 1032;
|
||||||
const SYSCALL_FRAMEBUFFER: usize = 2000;
|
const SYSCALL_FRAMEBUFFER: usize = 2000;
|
||||||
const SYSCALL_FRAMEBUFFER_FLUSH: usize = 2001;
|
const SYSCALL_FRAMEBUFFER_FLUSH: usize = 2001;
|
||||||
const SYSCALL_EVENT_GET: usize = 3000;
|
const SYSCALL_EVENT_GET: usize = 3000;
|
||||||
|
const SYSCALL_KEY_PRESSED: usize = 3001;
|
||||||
|
|
||||||
mod fs;
|
mod fs;
|
||||||
mod process;
|
mod process;
|
||||||
|
@ -75,6 +76,7 @@ pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize {
|
||||||
SYSCALL_FRAMEBUFFER => sys_framebuffer(),
|
SYSCALL_FRAMEBUFFER => sys_framebuffer(),
|
||||||
SYSCALL_FRAMEBUFFER_FLUSH => sys_framebuffer_flush(),
|
SYSCALL_FRAMEBUFFER_FLUSH => sys_framebuffer_flush(),
|
||||||
SYSCALL_EVENT_GET => sys_event_get(),
|
SYSCALL_EVENT_GET => sys_event_get(),
|
||||||
|
SYSCALL_KEY_PRESSED => sys_key_pressed(),
|
||||||
_ => panic!("Unsupported syscall_id: {}", syscall_id),
|
_ => panic!("Unsupported syscall_id: {}", syscall_id),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,11 +11,6 @@ buddy_system_allocator = "0.6"
|
||||||
bitflags = "1.2.1"
|
bitflags = "1.2.1"
|
||||||
riscv = { git = "https://github.com/rcore-os/riscv", features = ["inline-asm"] }
|
riscv = { git = "https://github.com/rcore-os/riscv", features = ["inline-asm"] }
|
||||||
embedded-graphics = "0.7.1"
|
embedded-graphics = "0.7.1"
|
||||||
# lazy_static = { version = "1.4.0", features = ["spin_no_std"] }
|
oorandom ="11"
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
debug = true
|
debug = true
|
||||||
|
|
||||||
# [features]
|
|
||||||
# board_qemu = []
|
|
||||||
# board_k210 = []
|
|
403
user/src/bin/gui_snake.rs
Normal file
403
user/src/bin/gui_snake.rs
Normal file
|
@ -0,0 +1,403 @@
|
||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate user_lib;
|
||||||
|
extern crate alloc;
|
||||||
|
|
||||||
|
use user_lib::console::getchar;
|
||||||
|
use user_lib::{framebuffer, framebuffer_flush, key_pressed, sleep};
|
||||||
|
|
||||||
|
use embedded_graphics::pixelcolor::*;
|
||||||
|
use embedded_graphics::prelude::{Drawable, Point, RgbColor, Size};
|
||||||
|
use embedded_graphics::primitives::Primitive;
|
||||||
|
use embedded_graphics::primitives::{PrimitiveStyle, Rectangle};
|
||||||
|
use embedded_graphics::Pixel;
|
||||||
|
use embedded_graphics::{draw_target::DrawTarget, prelude::OriginDimensions};
|
||||||
|
use oorandom; //random generator
|
||||||
|
|
||||||
|
pub const VIRTGPU_XRES: usize = 1280;
|
||||||
|
pub const VIRTGPU_YRES: usize = 800;
|
||||||
|
pub const VIRTGPU_LEN: usize = VIRTGPU_XRES * VIRTGPU_YRES * 4;
|
||||||
|
|
||||||
|
pub struct Display {
|
||||||
|
pub size: Size,
|
||||||
|
pub point: Point,
|
||||||
|
pub fb: &'static mut [u8],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display {
|
||||||
|
pub fn new(size: Size, point: Point) -> Self {
|
||||||
|
let fb_ptr = framebuffer() as *mut u8;
|
||||||
|
println!(
|
||||||
|
"Hello world from user mode program! 0x{:X} , len {}",
|
||||||
|
fb_ptr as usize, VIRTGPU_LEN
|
||||||
|
);
|
||||||
|
let fb =
|
||||||
|
unsafe { core::slice::from_raw_parts_mut(fb_ptr as *mut u8, VIRTGPU_LEN as usize) };
|
||||||
|
Self { size, point, fb }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OriginDimensions for Display {
|
||||||
|
fn size(&self) -> Size {
|
||||||
|
self.size
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DrawTarget for Display {
|
||||||
|
type Color = Rgb888;
|
||||||
|
type Error = core::convert::Infallible;
|
||||||
|
|
||||||
|
fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
|
||||||
|
where
|
||||||
|
I: IntoIterator<Item = embedded_graphics::Pixel<Self::Color>>,
|
||||||
|
{
|
||||||
|
pixels.into_iter().for_each(|px| {
|
||||||
|
let idx = ((self.point.y + px.0.y) * VIRTGPU_XRES as i32 + self.point.x + px.0.x)
|
||||||
|
as usize
|
||||||
|
* 4;
|
||||||
|
if idx + 2 >= self.fb.len() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.fb[idx] = px.1.b();
|
||||||
|
self.fb[idx + 1] = px.1.g();
|
||||||
|
self.fb[idx + 2] = px.1.r();
|
||||||
|
});
|
||||||
|
framebuffer_flush();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
struct Snake<T: PixelColor, const MAX_SIZE: usize> {
|
||||||
|
parts: [Pixel<T>; MAX_SIZE],
|
||||||
|
len: usize,
|
||||||
|
direction: Direction,
|
||||||
|
size_x: u32,
|
||||||
|
size_y: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SnakeIntoIterator<'a, T: PixelColor, const MAX_SIZE: usize> {
|
||||||
|
snake: &'a Snake<T, MAX_SIZE>,
|
||||||
|
index: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: PixelColor, const MAX_SIZE: usize> IntoIterator for &'a Snake<T, MAX_SIZE> {
|
||||||
|
type Item = Pixel<T>;
|
||||||
|
type IntoIter = SnakeIntoIterator<'a, T, MAX_SIZE>;
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
SnakeIntoIterator {
|
||||||
|
snake: self,
|
||||||
|
index: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: PixelColor, const MAX_SIZE: usize> Iterator for SnakeIntoIterator<'a, T, MAX_SIZE> {
|
||||||
|
type Item = Pixel<T>;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
let cur = self.snake.parts[self.index];
|
||||||
|
if self.index < self.snake.len {
|
||||||
|
self.index += 1;
|
||||||
|
return Some(cur);
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: PixelColor, const MAX_SIZE: usize> Snake<T, MAX_SIZE> {
|
||||||
|
fn new(color: T, size_x: u32, size_y: u32) -> Snake<T, MAX_SIZE> {
|
||||||
|
Snake {
|
||||||
|
parts: [Pixel::<T>(Point { x: 0, y: 0 }, color); MAX_SIZE],
|
||||||
|
len: 1,
|
||||||
|
direction: Direction::None,
|
||||||
|
size_x,
|
||||||
|
size_y,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn set_direction(&mut self, direction: Direction) {
|
||||||
|
self.direction = direction;
|
||||||
|
}
|
||||||
|
fn contains(&self, this: Point) -> bool {
|
||||||
|
for part in self.into_iter() {
|
||||||
|
if part.0 == this {
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
fn grow(&mut self) {
|
||||||
|
if self.len < MAX_SIZE - 1 {
|
||||||
|
self.len += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn make_step(&mut self) {
|
||||||
|
let mut i = self.len;
|
||||||
|
while i > 0 {
|
||||||
|
self.parts[i] = self.parts[i - 1];
|
||||||
|
i -= 1;
|
||||||
|
}
|
||||||
|
match self.direction {
|
||||||
|
Direction::Left => {
|
||||||
|
if self.parts[0].0.x == 0 {
|
||||||
|
self.parts[0].0.x = (self.size_x - 1) as i32;
|
||||||
|
} else {
|
||||||
|
self.parts[0].0.x -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Direction::Right => {
|
||||||
|
if self.parts[0].0.x == (self.size_x - 1) as i32 {
|
||||||
|
self.parts[0].0.x = 0;
|
||||||
|
} else {
|
||||||
|
self.parts[0].0.x += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Direction::Up => {
|
||||||
|
if self.parts[0].0.y == 0 {
|
||||||
|
self.parts[0].0.y = (self.size_y - 1) as i32;
|
||||||
|
} else {
|
||||||
|
self.parts[0].0.y -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Direction::Down => {
|
||||||
|
if self.parts[0].0.y == (self.size_y - 1) as i32 {
|
||||||
|
self.parts[0].0.y = 0;
|
||||||
|
} else {
|
||||||
|
self.parts[0].0.y += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Direction::None => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Food<T: PixelColor> {
|
||||||
|
size_x: u32,
|
||||||
|
size_y: u32,
|
||||||
|
place: Pixel<T>,
|
||||||
|
rng: oorandom::Rand32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: PixelColor> Food<T> {
|
||||||
|
pub fn new(color: T, size_x: u32, size_y: u32) -> Self {
|
||||||
|
let seed = 4;
|
||||||
|
let rng = oorandom::Rand32::new(seed);
|
||||||
|
Food {
|
||||||
|
size_x,
|
||||||
|
size_y,
|
||||||
|
place: Pixel(Point { x: 0, y: 0 }, color),
|
||||||
|
rng,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn replace<'a, const MAX_SIZE: usize>(&mut self, iter_source: &Snake<T, MAX_SIZE>) {
|
||||||
|
let mut p: Point;
|
||||||
|
'outer: loop {
|
||||||
|
let random_number = self.rng.rand_u32();
|
||||||
|
let blocked_positions = iter_source.into_iter();
|
||||||
|
p = Point {
|
||||||
|
x: ((random_number >> 24) as u16 % self.size_x as u16).into(),
|
||||||
|
y: ((random_number >> 16) as u16 % self.size_y as u16).into(),
|
||||||
|
};
|
||||||
|
for blocked_position in blocked_positions {
|
||||||
|
if p == blocked_position.0 {
|
||||||
|
continue 'outer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
self.place = Pixel::<T> {
|
||||||
|
0: p,
|
||||||
|
1: self.place.1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn get_pixel(&self) -> Pixel<T> {
|
||||||
|
self.place
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Debug, Clone, Copy)]
|
||||||
|
pub enum Direction {
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
Up,
|
||||||
|
Down,
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SnakeGame<const MAX_SNAKE_SIZE: usize, T: PixelColor> {
|
||||||
|
snake: Snake<T, MAX_SNAKE_SIZE>,
|
||||||
|
food: Food<T>,
|
||||||
|
food_age: u32,
|
||||||
|
food_lifetime: u32,
|
||||||
|
size_x: u32,
|
||||||
|
size_y: u32,
|
||||||
|
scale_x: u32,
|
||||||
|
scale_y: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const MAX_SIZE: usize, T: PixelColor> SnakeGame<MAX_SIZE, T> {
|
||||||
|
pub fn new(
|
||||||
|
size_x: u32,
|
||||||
|
size_y: u32,
|
||||||
|
scale_x: u32,
|
||||||
|
scale_y: u32,
|
||||||
|
snake_color: T,
|
||||||
|
food_color: T,
|
||||||
|
food_lifetime: u32,
|
||||||
|
) -> Self {
|
||||||
|
let snake = Snake::<T, MAX_SIZE>::new(snake_color, size_x / scale_x, size_y / scale_y);
|
||||||
|
let mut food = Food::<T>::new(food_color, size_x / scale_x, size_y / scale_y);
|
||||||
|
food.replace(&snake);
|
||||||
|
SnakeGame {
|
||||||
|
snake,
|
||||||
|
food,
|
||||||
|
food_age: 0,
|
||||||
|
food_lifetime,
|
||||||
|
size_x,
|
||||||
|
size_y,
|
||||||
|
scale_x,
|
||||||
|
scale_y,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn set_direction(&mut self, direction: Direction) {
|
||||||
|
self.snake.set_direction(direction);
|
||||||
|
}
|
||||||
|
pub fn draw<D>(&mut self, target: &mut D) -> ()
|
||||||
|
where
|
||||||
|
D: DrawTarget<Color = T>,
|
||||||
|
{
|
||||||
|
self.snake.make_step();
|
||||||
|
let hit = self.snake.contains(self.food.get_pixel().0);
|
||||||
|
if hit {
|
||||||
|
self.snake.grow();
|
||||||
|
}
|
||||||
|
self.food_age += 1;
|
||||||
|
if self.food_age >= self.food_lifetime || hit {
|
||||||
|
self.food.replace(&self.snake);
|
||||||
|
self.food_age = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut scaled_display = ScaledDisplay::<D> {
|
||||||
|
real_display: target,
|
||||||
|
size_x: self.size_x / self.scale_x,
|
||||||
|
size_y: self.size_y / self.scale_y,
|
||||||
|
scale_x: self.scale_x,
|
||||||
|
scale_y: self.scale_y,
|
||||||
|
};
|
||||||
|
|
||||||
|
for part in self.snake.into_iter() {
|
||||||
|
_ = part.draw(&mut scaled_display);
|
||||||
|
}
|
||||||
|
_ = self.food.get_pixel().draw(&mut scaled_display);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A dummy DrawTarget implementation that can magnify each pixel so the user code does not need to adapt for scaling things
|
||||||
|
struct ScaledDisplay<'a, T: DrawTarget> {
|
||||||
|
real_display: &'a mut T,
|
||||||
|
size_x: u32,
|
||||||
|
size_y: u32,
|
||||||
|
scale_x: u32,
|
||||||
|
scale_y: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: DrawTarget> DrawTarget for ScaledDisplay<'a, T> {
|
||||||
|
type Color = T::Color;
|
||||||
|
type Error = T::Error;
|
||||||
|
|
||||||
|
fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
|
||||||
|
where
|
||||||
|
I: IntoIterator<Item = Pixel<Self::Color>>,
|
||||||
|
{
|
||||||
|
for pixel in pixels {
|
||||||
|
let style = PrimitiveStyle::with_fill(pixel.1);
|
||||||
|
Rectangle::new(
|
||||||
|
Point::new(
|
||||||
|
pixel.0.x * self.scale_x as i32,
|
||||||
|
pixel.0.y * self.scale_y as i32,
|
||||||
|
),
|
||||||
|
Size::new(self.scale_x as u32, self.scale_y as u32),
|
||||||
|
)
|
||||||
|
.into_styled(style)
|
||||||
|
.draw(self.real_display)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: DrawTarget> OriginDimensions for ScaledDisplay<'a, T> {
|
||||||
|
fn size(&self) -> Size {
|
||||||
|
Size::new(self.size_x as u32, self.size_y as u32)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
|
||||||
|
use crate::Snake;
|
||||||
|
use embedded_graphics::pixelcolor::*;
|
||||||
|
use embedded_graphics::prelude::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn snake_basic() {
|
||||||
|
let mut snake = Snake::<Rgb888, 20>::new(Rgb888::RED, 8, 8);
|
||||||
|
snake.set_direction(crate::Direction::Right);
|
||||||
|
assert_eq!(
|
||||||
|
Pixel::<Rgb888>(Point { x: 0, y: 0 }, Rgb888::RED),
|
||||||
|
snake.into_iter().next().unwrap()
|
||||||
|
);
|
||||||
|
snake.make_step();
|
||||||
|
assert_eq!(
|
||||||
|
Pixel::<Rgb888>(Point { x: 1, y: 0 }, Rgb888::RED),
|
||||||
|
snake.into_iter().nth(0).unwrap()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
Pixel::<Rgb888>(Point { x: 0, y: 0 }, Rgb888::RED),
|
||||||
|
snake.into_iter().nth(1).unwrap()
|
||||||
|
);
|
||||||
|
snake.set_direction(crate::Direction::Down);
|
||||||
|
snake.make_step();
|
||||||
|
assert_eq!(
|
||||||
|
Pixel::<Rgb888>(Point { x: 1, y: 1 }, Rgb888::RED),
|
||||||
|
snake.into_iter().nth(0).unwrap()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
Pixel::<Rgb888>(Point { x: 1, y: 0 }, Rgb888::RED),
|
||||||
|
snake.into_iter().nth(1).unwrap()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
Pixel::<Rgb888>(Point { x: 0, y: 0 }, Rgb888::RED),
|
||||||
|
snake.into_iter().nth(2).unwrap()
|
||||||
|
);
|
||||||
|
assert_eq!(true, snake.contains(Point { x: 0, y: 0 }));
|
||||||
|
assert_eq!(true, snake.contains(Point { x: 1, y: 0 }));
|
||||||
|
assert_eq!(true, snake.contains(Point { x: 1, y: 1 }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const LF: u8 = 0x0au8;
|
||||||
|
const CR: u8 = 0x0du8;
|
||||||
|
#[no_mangle]
|
||||||
|
pub fn main() -> i32 {
|
||||||
|
let mut disp = Display::new(Size::new(1280, 800), Point::new(0, 0));
|
||||||
|
let mut game = SnakeGame::<20, Rgb888>::new(1280, 800, 20, 20, Rgb888::RED, Rgb888::YELLOW, 50);
|
||||||
|
loop {
|
||||||
|
if key_pressed() {
|
||||||
|
let c = getchar();
|
||||||
|
match c {
|
||||||
|
LF => break,
|
||||||
|
CR => break,
|
||||||
|
b'w' => game.set_direction(Direction::Up),
|
||||||
|
b's' => game.set_direction(Direction::Down),
|
||||||
|
b'a' => game.set_direction(Direction::Left),
|
||||||
|
b'd' => game.set_direction(Direction::Right),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let _ = disp.clear(Rgb888::BLACK).unwrap();
|
||||||
|
game.draw(&mut disp);
|
||||||
|
sleep(10);
|
||||||
|
}
|
||||||
|
0
|
||||||
|
}
|
16
user/src/bin/random_num.rs
Normal file
16
user/src/bin/random_num.rs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate user_lib;
|
||||||
|
use oorandom;
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub fn main() -> i32 {
|
||||||
|
println!("random num program!");
|
||||||
|
let seed = 4;
|
||||||
|
let mut rng = oorandom::Rand32::new(seed);
|
||||||
|
println!("OORandom: Random number 32bit: {}", rng.rand_i32());
|
||||||
|
println!("OORandom: Random number range: {}", rng.rand_range(1..100));
|
||||||
|
0
|
||||||
|
}
|
|
@ -209,6 +209,13 @@ pub fn event_get() -> isize {
|
||||||
sys_event_get()
|
sys_event_get()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn key_pressed() -> bool {
|
||||||
|
if sys_key_pressed() == 1 {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! vstore {
|
macro_rules! vstore {
|
||||||
|
|
|
@ -28,6 +28,7 @@ const SYSCALL_CONDVAR_WAIT: usize = 1032;
|
||||||
const SYSCALL_FRAMEBUFFER: usize = 2000;
|
const SYSCALL_FRAMEBUFFER: usize = 2000;
|
||||||
const SYSCALL_FRAMEBUFFER_FLUSH: usize = 2001;
|
const SYSCALL_FRAMEBUFFER_FLUSH: usize = 2001;
|
||||||
const SYSCALL_EVENT_GET: usize = 3000;
|
const SYSCALL_EVENT_GET: usize = 3000;
|
||||||
|
const SYSCALL_KEY_PRESSED: usize = 3001;
|
||||||
|
|
||||||
fn syscall(id: usize, args: [usize; 3]) -> isize {
|
fn syscall(id: usize, args: [usize; 3]) -> isize {
|
||||||
let mut ret: isize;
|
let mut ret: isize;
|
||||||
|
@ -169,4 +170,8 @@ pub fn sys_framebuffer_flush() -> isize {
|
||||||
|
|
||||||
pub fn sys_event_get() -> isize {
|
pub fn sys_event_get() -> isize {
|
||||||
syscall(SYSCALL_EVENT_GET, [0, 0, 0])
|
syscall(SYSCALL_EVENT_GET, [0, 0, 0])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sys_key_pressed() -> isize {
|
||||||
|
syscall(SYSCALL_KEY_PRESSED, [0, 0, 0])
|
||||||
}
|
}
|
Loading…
Add table
Add a link
Reference in a new issue