From 550b61e07e64bf82606a1914f07722dece82cd7d Mon Sep 17 00:00:00 2001
From: FantasyPvP <80643031+FantasyPvP@users.noreply.github.com>
Date: Sat, 7 Oct 2023 14:04:05 +0100
Subject: [PATCH] idk
idk
---
.idea/codeStyles/codeStyleConfig.xml | 5 +
Cargo.toml | 1 -
src/user/bin/snake.rs | 272 +++++++++++++++++----------
src/user/lib/coords.rs | 75 ++++++++
src/user/lib/mod.rs | 1 +
5 files changed, 252 insertions(+), 102 deletions(-)
create mode 100644 .idea/codeStyles/codeStyleConfig.xml
create mode 100644 src/user/lib/coords.rs
diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml
new file mode 100644
index 0000000..a55e7a1
--- /dev/null
+++ b/.idea/codeStyles/codeStyleConfig.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/Cargo.toml b/Cargo.toml
index d267b3f..ac1e823 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -5,7 +5,6 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
-
[package.metadata.bootimage]
test-args = ["-device", "isa-debug-exit,iobase=0xf4,iosize=0x04", "-serial", "stdio", "-display", "none"]
test-success-exit-code = 33
diff --git a/src/user/bin/snake.rs b/src/user/bin/snake.rs
index 3784e39..98eeb27 100644
--- a/src/user/bin/snake.rs
+++ b/src/user/bin/snake.rs
@@ -1,5 +1,6 @@
use alloc::string::String;
use alloc::{format, vec, vec::Vec, boxed::Box};
+use alloc::borrow::ToOwned;
use core::arch::x86_64::_mm_test_all_ones;
use core::cell::RefCell;
use async_trait::async_trait;
@@ -9,30 +10,12 @@ use crate::kernel::tasks::keyboard::KEYBOARD;
use crossbeam_queue::SegQueue;
use lazy_static::lazy_static;
use crate::kernel::render::{ColorCode, ScreenChar};
+use crate::{println};
use crate::std::application::{Application, Error};
use crate::std::random::Random;
use crate::system::std::frame::ColouredElement;
+use super::super::lib::coords::{Line, Position, Direction};
-#[derive(Clone, Debug, PartialEq)]
-struct Point {
- x: i8,
- y: i8,
-}
-
-#[derive(Clone, Debug, PartialEq)]
-struct Position {
- x: i8,
- y: i8,
- dir: Direction,
-}
-
-#[derive(Clone, Debug, PartialEq)]
-enum Direction {
- Up,
- Down,
- Left,
- Right,
-}
#[derive(Clone, Debug, PartialEq)]
enum Status {
@@ -44,7 +27,7 @@ enum Status {
pub struct Game {
snakes: Vec,
- pois: Vec,
+ pois: Vec,
score: u8,
hardmode: bool,
}
@@ -63,25 +46,26 @@ impl Application for Game {
}
async fn run(&mut self, _: Vec) -> Result<(), Error> {
- Screen::application_mode();
+ //Screen::application_mode();
- // render the initial state of the screen.
- self.render().map_err(|_| Error::ApplicationError(String::from("failed to render game screen")))?;
// make the first poi
- self.snakes.borrow_mut().push(Snake::player(0));
+ self.snakes.push(Snake::player(0));
for i in 0..5 {
self.new_poi();
- self.snakes.borrow_mut().push(Snake::ai(i + 1));
+ self.snakes.push(Snake::ai(i + 1));
}
+ // render the initial state of the screen.
+ self.render().map_err(|_| Error::ApplicationError(String::from("failed to render game screen")))?;
+
// run the game
self.gameloop().await?;
// return to the terminal
- Screen::terminal_mode();
+ //Screen::terminal_mode();
Ok(())
}
}
@@ -89,47 +73,43 @@ impl Application for Game {
impl Game {
async fn gameloop(&mut self) -> Result<(), Error> { // main gameloop
- let mut all_points: Vec;
+ let mut all_points: Vec;
'gameloop: loop {
time::wait(0.1);
- let mut points: Vec;
+ let mut points: Vec;
let length = self.snakes.len();
- let mut status = Vec::new();
for i in 0..length {
- let points: Vec = self.snakes.clone().into_iter().map(|s| s.tail).flatten().collect();
+ let points: Vec = self.snakes.clone().into_iter().map(|s| s.tail).flatten().collect();
let res = self.snakes[i].next(&self.pois, &points);
- status.push(res);
-
-
- }
-
-
- let res = self.snakes.iter_mut().map(|s| {
-
- let points: Vec = self.snakes.clone().into_iter().map(|s| s.tail).flatten().collect();
- s.next(&self.pois, &points)
- }).collect::>();
-
-
- if res.contains(&Status::Lost) {
- self.render_end_screen().map_err(|_| Error::ApplicationError(String::from("failed to render end screen")))?;
-
- // loop triggers when game is lost
- loop {
- match Stdin::keystroke().await {
- 'x' => break 'gameloop,
- _ => continue,
- }
+ match res {
+ Status::Lost => {
+ if !self.snakes[i].ai_controlled {
+ self.render_end_screen().map_err(|_| Error::ApplicationError(String::from("failed to render end screen")))?;
+ // loop triggers when game is lost
+ loop {
+ match Stdin::keystroke().await {
+ 'x' => break 'gameloop,
+ _ => continue,
+ }
+ }
+ }
+ },
+ Status::Exited => {
+ break 'gameloop
+ },
+ Status::Scored => {
+ if !self.snakes[i].ai_controlled {
+ self.score += 1;
+ }
+ self.replace_poi(&self.snakes[i].clone().head); // passes a reference to the location of the current snake's head
+ },
+ Status::None => {},
}
- } else if res.contains(&Status::Exited) {
- break 'gameloop;
- } else if res.contains(&Status::Scored) {
- self.score += 1;
}
self.render().map_err(|_| Error::ApplicationError(String::from("failed to render game screen")))?;
@@ -138,22 +118,22 @@ impl Game {
}
fn new_poi(&mut self) {
- self.pois.push(Point { x: Random::int(3, 76) as i8, y: Random::int(3, 21) as i8 });
+ self.pois.push(Position { x: Random::int(3, 76) as i64, y: Random::int(3, 21) as i64 });
}
- fn replace_poi(&mut self, poi: &Point) {
+ fn replace_poi(&mut self, poi: &Position) {
self.pois.remove(self.pois.iter().position(|p| p == poi).unwrap());
self.new_poi();
}
fn render(&mut self) -> Result<(), ()> {
let mut frame = vec![vec![ScreenChar::null(); 80]; 25];
- self.snakes.borrow().clone().into_iter().map(|s| s.tail).flatten().for_each(|p| {
- frame[p.y as usize][p.x as usize] = ScreenChar::new('@' as u8, ColorCode::new(Color::Cyan, Color::Black));
+ self.snakes.clone().into_iter().map(|s| s.tail).flatten().for_each(|p| {
+ frame[24 - p.y as usize][p.x as usize] = ScreenChar::new('@' as u8, ColorCode::new(Color::Cyan, Color::Black));
});
self.pois.iter().for_each(|poi| {
- frame[poi.y as usize][poi.x as usize] = ScreenChar::new('o' as u8, ColorCode::new(Color::Red, Color::Black));
+ frame[24 - poi.y as usize][poi.x as usize] = ScreenChar::new('o' as u8, ColorCode::new(Color::Red, Color::Black));
});
let literal = format!("snake go brr score: {}", self.score);
@@ -183,7 +163,6 @@ impl Game {
frame[12] = Game::centre_text(80, String::from(format!("ur score was {}", self.score))).chars().map(|c| ScreenChar::new(c as u8, ColorCode::new(Color::LightGreen, Color::Black))).collect();
frame[14] = Game::centre_text(80, String::from("L bozo")).chars().map(|c| ScreenChar::new(c as u8, ColorCode::new(Color::Red, Color::Black))).collect();
-
let mut elem = ColouredElement::generate(frame, (80, 25));
elem.render((0,0))
}
@@ -203,8 +182,8 @@ impl Game {
#[derive(Debug, Clone)]
struct Snake {
ai_controlled: bool,
- head: Point,
- tail: Vec,
+ head: Position,
+ tail: Vec,
dir: Direction,
}
@@ -212,71 +191,69 @@ impl Snake {
fn ai(id: usize) -> Self {
Self {
ai_controlled: true,
- head: Point { x: 1 + id as i8 * 2, y: 1 },
- tail: Vec::new(),
- dir: Direction::Up
+ head: Position { x: 4 + 4*id as i64 * 2, y: 9 },
+ tail: (1..4).map(|p| Position { x: 4 + 4*id as i64, y: 5 + p}).collect(),
+ dir: Direction::PosY,
}
}
fn player(id: usize) -> Self {
Self {
ai_controlled: false,
- head: Point { x: 1 + id as i8 * 2, y: 1 },
- tail: Vec::new(),
- dir: Direction::Up,
+ head: Position { x: 4 + 4*id as i64, y: 9 },
+ tail: (1..4).map(|p| Position { x: 4 + 4*id as i64, y: 5 + p}).collect(),
+ dir: Direction::PosY,
}
}
- fn next(&mut self, points_of_interest: &Vec, tails: &Vec) -> Status { // returns (lose_condition, scored)
+ fn next(&mut self, points_of_interest: &Vec, tails: &Vec) -> Status { // returns (lose_condition, scored)
// uses pathing algorithm if ai else keyboard input if human
if self.ai_controlled {
- self.dir = self.decide_dir();
+ self.dir = PathFinder::decide(&self.head, points_of_interest, tails);
} else {
- if let Some(c) = Stdin::try_keystroke() {
- self.dir = match c {
- 'w' => Direction::Up,
- 'a' => Direction::Left,
- 's' => Direction::Down,
- 'd' => Direction::Right,
- 'x' => return Status::Exited,
- _ => self.dir.clone(),
- }
- }
+ // if let Some(c) = Stdin::try_keystroke() {
+ // self.dir = match c {
+ // 'w' => Direction::PosY,
+ // 'a' => Direction::NegX,
+ // 's' => Direction::NegY,
+ // 'd' => Direction::PosX,
+ // 'x' => return Status::Exited,
+ // _ => self.dir.clone(),
+ // }
+ // }
+ self.dir = Direction::None;
}
- self.tail.push(self.head.clone());
+ if self.dir != Direction::None {
+ self.tail.push(self.head.clone());
+ }
match self.dir {
- Direction::Up => self.head.y -= 1,
- Direction::Down => self.head.y += 1,
- Direction::Left => self.head.x -= 1,
- Direction::Right => self.head.x += 1,
+ Direction::PosY => self.head.y += 1,
+ Direction::NegY => self.head.y -= 1,
+ Direction::NegX => self.head.x -= 1,
+ Direction::PosX => self.head.x += 1,
+ Direction::None => {},
}
if self.lose_condition(tails) {
- if !self.ai_controlled {
- return Status::Lost;
- }
+ self.tail.remove(0);
+ return Status::Lost;
}
if points_of_interest.contains(&self.head) {
- if !self.ai_controlled {
- return Status::Scored;
- }
+ return Status::Scored;
} else {
- self.tail.remove(0);
+ if self.dir != Direction::None {
+ self.tail.remove(0);
+ }
}
Status::None
}
- fn decide_dir(&mut self) -> Direction {
- unimplemented!() // implement a basic pathfinding or random movement algorithm
- }
-
- fn lose_condition(&mut self, tails: &Vec) -> bool { // where tails includes the tail of every other snake
+ fn lose_condition(&mut self, tails: &Vec) -> bool { // where tails includes the tail of every other snake
let p = self.head.clone();
-
let snake_overlaps = tails.contains(&self.head); // checks if any part of the snake overlaps itself
let out_of_bounds = p.x < 0 || p.y < 0 || p.x > 79 || p.y > 24; // checks if the snake goes out of bounds
@@ -284,6 +261,98 @@ impl Snake {
}
}
+struct PathFinder {}
+
+impl PathFinder {
+ fn decide(head: &Position, tails: &Vec, pois: &Vec) -> Direction {
+ let nearest_poi = head.nearest(pois);
+ let rel_pos = head.distance(&nearest_poi);
+
+ // check actions don't lose them the game
+ let mut possible_moves = Vec::new();
+ let mut h: Position;
+
+ h = Position { x: head.x + 1, y: head.y };
+ if !(PathFinder::check_bounds(&h) || PathFinder::check_collision(&h, &tails)) {
+ possible_moves.push(Direction::PosX);
+ }
+ h = Position { x: head.x - 1, y: head.y };
+ if !(PathFinder::check_bounds(&h) || PathFinder::check_collision(&h, &tails)) {
+ possible_moves.push(Direction::NegX);
+ }
+ h = Position { x: head.x, y: head.y + 1 };
+ if !(PathFinder::check_bounds(&h) || PathFinder::check_collision(&h, &tails)) {
+ possible_moves.push(Direction::PosY);
+ }
+ h = Position { x: head.x, y: head.y - 1 };
+ if !(PathFinder::check_bounds(&h) || PathFinder::check_collision(&h, &tails)) {
+ possible_moves.push(Direction::NegY);
+ }
+
+ if possible_moves.is_empty() {
+ panic!("no possible moves");
+ return Direction::None;
+ } else {
+ let optimal = PathFinder::optimal_move(head, &rel_pos, &possible_moves);
+ println!("{:?} {:?} {:?} {:?}", nearest_poi, rel_pos, head, optimal);
+ }
+
+ Direction::None
+ }
+
+ fn optimal_move(head: &Position, rel_pos: &Position, moves: &Vec) -> Direction {
+ let mut optimal_moves = vec![Direction::None; 4];
+
+ let x_offset: usize;
+ let y_offset: usize;
+
+ if rel_pos.x.abs() > rel_pos.y.abs() {
+ y_offset = 1;
+ x_offset = 0;
+ } else {
+ x_offset = 1;
+ y_offset = 0;
+ }
+
+ if rel_pos.x < 0 {
+ optimal_moves[x_offset] = Direction::NegX;
+ optimal_moves[x_offset + 2] = Direction::PosX;
+ } else {
+ optimal_moves[x_offset] = Direction::PosX;
+ optimal_moves[x_offset + 2] = Direction::NegX;
+ }
+
+ if rel_pos.y < 0 {
+ optimal_moves[y_offset] = Direction::NegY;
+ optimal_moves[y_offset + 2] = Direction::PosY;
+ } else {
+ optimal_moves[y_offset] = Direction::PosY;
+ optimal_moves[y_offset + 2] = Direction::NegY;
+ }
+ //println!("moves: {:?}, optimal_moves: {:?}, rel_pos: {:?}", moves, optimal_moves, rel_pos);
+ for m in optimal_moves {
+ if moves.contains(&m) {
+ return m;
+ }
+ };
+
+ // this should never be used, the above statement should always return a value.
+ panic!("No optimal move found (this should not happen)");
+ }
+
+
+ fn check_bounds(head: &Position) -> bool {
+ head.x < 0 || head.y < 0 || head.x > 79 || head.y > 24
+ }
+
+ fn check_collision(head: &Position, tails: &Vec) -> bool {
+ tails.contains(&head)
+ }
+}
+
+
+
+
fn round_up(n: f64) -> usize {
(n + 0.99) as usize
@@ -291,3 +360,4 @@ fn round_up(n: f64) -> usize {
fn round_down(n: f64) -> usize {
n as usize
}
+
diff --git a/src/user/lib/coords.rs b/src/user/lib/coords.rs
new file mode 100644
index 0000000..ee6c0bb
--- /dev/null
+++ b/src/user/lib/coords.rs
@@ -0,0 +1,75 @@
+use alloc::borrow::ToOwned;
+use alloc::vec::Vec;
+use crate::println;
+
+
+#[derive(Clone, Debug, PartialEq)]
+pub enum Line {
+ Vertical(i64),
+ Horizontal(i64),
+}
+
+#[derive(Clone, Debug, PartialEq)]
+pub struct Position {
+ pub x: i64,
+ pub y: i64,
+}
+
+impl Position {
+ pub fn touches_line(&self, line: &Line) -> bool {
+ match line {
+ Line::Vertical(y) => self.y == *y,
+ Line::Horizontal(x) => self.x == *x,
+ }
+ }
+
+ pub fn aligns(&self, other: &Position) -> (bool, bool) {
+ (self.x == other.x, self.y == other.y)
+ }
+
+ pub fn distance(&self, other: &Position) -> Position {
+ Position {
+ x: other.x - self.x,
+ y: other.y - self.y
+ }
+ }
+
+ pub fn as_usize(&self) -> (usize, usize) {
+ (self.x as usize, self.y as usize)
+ }
+
+ pub fn magnitude(&self) -> i64 {
+ (self.x.abs() + self.y.abs())
+ }
+
+ pub fn nearest(&self, points: &Vec) -> Position {
+
+ let mut points = points.clone();
+ points.sort_by_key(|p| {
+ let p = self.distance(p);
+ p.x.abs() + p.y.abs()
+ });
+ points.first().unwrap().to_owned()
+ }
+}
+
+#[derive(Clone, Debug, PartialEq)]
+pub enum Direction {
+ PosY,
+ NegY,
+ PosX,
+ NegX,
+ None,
+}
+
+impl Direction {
+ pub fn rev(&self) -> Direction {
+ match self {
+ Direction::PosY => Direction::NegY,
+ Direction::NegY => Direction::PosY,
+ Direction::PosX => Direction::NegX,
+ Direction::NegX => Direction::PosX,
+ Direction::None => Direction::None,
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/user/lib/mod.rs b/src/user/lib/mod.rs
index da1a9da..001acf5 100644
--- a/src/user/lib/mod.rs
+++ b/src/user/lib/mod.rs
@@ -1 +1,2 @@
pub mod libgui;
+pub mod coords;