Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ x86_64 = "0.14.2"
uart_16550 = "0.2.0"
pic8259 = "0.10.1"
pc-keyboard = "0.7.0"
nanorand = { version = "0.7.0", default-features = false, features = ["alloc", "wyrand"] }
linked_list_allocator = "0.10.0"
embedded-timers = "0.4.0"

[dependencies.lazy_static]
version = "1.0"
Expand Down
16 changes: 16 additions & 0 deletions src/clock.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
static TICKS: core::sync::atomic::AtomicU32 = core::sync::atomic::AtomicU32::new(0);

pub fn tick_handler() {
TICKS.fetch_add(1, core::sync::atomic::Ordering::Relaxed);
}

pub struct MilliSecondClock32;

impl embedded_timers::clock::Clock for MilliSecondClock32 {
type Instant = embedded_timers::instant::Instant32<1000>;

fn now(&self) -> Self::Instant {
let ticks = TICKS.load(core::sync::atomic::Ordering::Relaxed);
embedded_timers::instant::Instant32::<1000>::new(ticks)
}
}
18 changes: 17 additions & 1 deletion src/interrupts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,21 @@ lazy_static! {

pub fn init_idt() {
IDT.load();
set_timer_speed();
}

fn set_timer_speed() {
use x86_64::instructions::port::Port;

let mut port = Port::new(0x43);

unsafe { port.write(0x36 as u8); }
port = Port::new(0x40);
unsafe {
port.write(4 as u8);
port.write(169 as u8);
}

}

extern "x86-interrupt" fn breakpoint_handler(stack_frame: InterruptStackFrame) {
Expand All @@ -70,7 +85,8 @@ extern "x86-interrupt" fn page_fault_handler(stack_frame: InterruptStackFrame, e
}

extern "x86-interrupt" fn timer_interrupt_handler(_stack_frame: InterruptStackFrame) {
print!(".");
// print!(".");
crate::clock::tick_handler();
unsafe {
PICS.lock()
.notify_end_of_interrupt(InterruptIndex::Timer.as_u8());
Expand Down
3 changes: 3 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,15 @@ use core::panic::PanicInfo;
extern crate alloc;

pub mod allocator;
pub mod snake_game;
pub mod os_mode;
pub mod gdt;
pub mod interrupts;
pub mod memory;
pub mod serial;
pub mod task;
pub mod vga_buffer;
pub mod clock;

pub trait Testable {
fn run(&self) -> ();
Expand Down
4 changes: 3 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ extern crate alloc;

use bootloader::{entry_point, BootInfo};
use core::panic::PanicInfo;
use milly_os::task::{executor::Executor, Task, keyboard};
use milly_os::task::{executor::Executor, keyboard, Task};
use x86_64::VirtAddr;

mod serial;
Expand All @@ -31,7 +31,9 @@ entry_point!(kernel_main);

fn kernel_main(boot_info: &'static BootInfo) -> ! {
use milly_os::allocator;
use milly_os::clock::MilliSecondClock32;
use milly_os::memory::{self, BootInfoFrameAllocator};
use embedded_timers::delay::Delay;

println!("Hello world{}", "!");
milly_os::init();
Expand Down
4 changes: 4 additions & 0 deletions src/os_mode.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
pub enum OsMode {
KernelMode,
SnakeMode,
}
2 changes: 2 additions & 0 deletions src/snake_game.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
mod game_main;
mod snake;
176 changes: 176 additions & 0 deletions src/snake_game/game_main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
use crate::clock::MilliSecondClock32;
use crate::println;
use crate::snake_game::snake::Command;
use crate::snake_game::snake::Direction;
use crate::snake_game::snake::Point;
use crate::snake_game::snake::Snake;
use crate::vga_buffer;
use crate::vga_buffer::BUFFER_HEIGHT;
use crate::vga_buffer::BUFFER_WIDTH;
use core::time::Duration;
use embedded_timers::clock::Clock;
use embedded_timers::instant::Instant;
use nanorand::{Rng, WyRand};

const MAX_INTERVAL: u16 = 700;
const MIN_INTERVAL: u16 = 200;
const MAX_SPEED: u16 = 20;

#[derive(Debug)]
pub struct Game {
buffer_size: (u16, u16),
width: u16,
height: u16,
food: Option<Point>,
snake: Snake,
speed: u16,
score: u16,
}

impl Game {
pub fn new(width: u16, height: u16) -> Self {
let buffer_size = (
vga_buffer::BUFFER_WIDTH as u16,
vga_buffer::BUFFER_HEIGHT as u16,
);
Self {
buffer_size,
width,
height,
food: None,
snake: Snake::new(
Point::new(width / 2, height / 2),
3,
match WyRand::new().generate_range(0..4) {
0 => Direction::Up,
1 => Direction::Right,
2 => Direction::Down,
_ => Direction::Left,
},
),
speed: 0,
score: 0,
}
}

pub fn run(&mut self) {
self.place_food();
self.prepare_ui();
self.render();

let clock = MilliSecondClock32;

let mut done = false;
while !done {
let interval = self.calculate_interval();
let direction = self.snake.get_direction();
let now = clock.now();

while clock.elapsed(now) < interval {
if let Some(command) = self.get_command(interval - clock.elapsed(now)) {
match command {
Command::Quit => {
done = true;
break;
}
Command::Turn(towards) => {
if direction != towards && direction.opposite() != towards {
self.snake.set_direction(towards);
}
}
}
}
}

if self.has_collided_with_wall() || self.has_bitten_itself() {
done = true;
} else {
self.snake.slither();

if let Some(food_point) = self.food {
if self.snake.get_head_point() == food_point {
self.snake.grow();
self.place_food();
self.score += 1;

if self.score % ((self.width * self.height) / MAX_SPEED) == 0 {
self.speed += 1;
}
}
}

self.render();
}
}

println!("Game Over! Your score is {}", self.score);
}

fn place_food(&mut self) {
loop {
let random_x = WyRand::new().generate_range(0..self.width);
let random_y = WyRand::new().generate_range(0..self.height);
let point = Point::new(random_x, random_y);
if !self.snake.contains_point(&point) {
self.food = Some(point);
break;
}
}
}

fn prepare_ui(&mut self) {}

fn calculate_interval(&self) -> Duration {
let speed = MAX_SPEED - self.speed;
Duration::from_millis(
(MIN_INTERVAL + (((MAX_INTERVAL - MIN_INTERVAL) / MAX_SPEED) * speed)) as u64,
)
}

fn get_command(&self, wait_for: Duration) -> Option<Command> {
None
}

fn wait_for_key_event(&self, wait_for: Duration) -> ! {
loop {}
}

fn has_collided_with_wall(&self) -> bool {
let head_point = self.snake.get_head_point();

match self.snake.get_direction() {
Direction::Up => head_point.y == 0,
Direction::Right => head_point.x == self.width - 1,
Direction::Down => head_point.y == self.height - 1,
Direction::Left => head_point.x == 0,
}
}

fn has_bitten_itself(&self) -> bool {
let next_head_point = self
.snake
.get_head_point()
.transform(self.snake.get_direction(), 1);
let mut next_body_points = self.snake.get_body_points().clone();
next_body_points.remove(next_body_points.len() - 1);
next_body_points.remove(0);

next_body_points.contains(&next_head_point)
}

fn render(&self) {
use vga_buffer::ScreenChar;
use vga_buffer::{Color, ColorCode};
use volatile::Volatile;

vga_buffer::print_buffer(core::array::from_fn::<_, BUFFER_HEIGHT, _>(|_| {
core::array::from_fn::<_, BUFFER_WIDTH, _>(|_| {
Volatile::new(ScreenChar {
ascii_character: 0,
color_code: ColorCode::new(Color::Red, Color::White),
})
})
}));
todo!()
}
}
Loading