idk
idk
This commit is contained in:
Generated
+5
@@ -0,0 +1,5 @@
|
|||||||
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
|
<state>
|
||||||
|
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
|
||||||
|
</state>
|
||||||
|
</component>
|
||||||
@@ -5,7 +5,6 @@ edition = "2021"
|
|||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
|
||||||
[package.metadata.bootimage]
|
[package.metadata.bootimage]
|
||||||
test-args = ["-device", "isa-debug-exit,iobase=0xf4,iosize=0x04", "-serial", "stdio", "-display", "none"]
|
test-args = ["-device", "isa-debug-exit,iobase=0xf4,iosize=0x04", "-serial", "stdio", "-display", "none"]
|
||||||
test-success-exit-code = 33
|
test-success-exit-code = 33
|
||||||
|
|||||||
+159
-89
@@ -1,5 +1,6 @@
|
|||||||
use alloc::string::String;
|
use alloc::string::String;
|
||||||
use alloc::{format, vec, vec::Vec, boxed::Box};
|
use alloc::{format, vec, vec::Vec, boxed::Box};
|
||||||
|
use alloc::borrow::ToOwned;
|
||||||
use core::arch::x86_64::_mm_test_all_ones;
|
use core::arch::x86_64::_mm_test_all_ones;
|
||||||
use core::cell::RefCell;
|
use core::cell::RefCell;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
@@ -9,30 +10,12 @@ use crate::kernel::tasks::keyboard::KEYBOARD;
|
|||||||
use crossbeam_queue::SegQueue;
|
use crossbeam_queue::SegQueue;
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use crate::kernel::render::{ColorCode, ScreenChar};
|
use crate::kernel::render::{ColorCode, ScreenChar};
|
||||||
|
use crate::{println};
|
||||||
use crate::std::application::{Application, Error};
|
use crate::std::application::{Application, Error};
|
||||||
use crate::std::random::Random;
|
use crate::std::random::Random;
|
||||||
use crate::system::std::frame::ColouredElement;
|
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)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
enum Status {
|
enum Status {
|
||||||
@@ -44,7 +27,7 @@ enum Status {
|
|||||||
|
|
||||||
pub struct Game {
|
pub struct Game {
|
||||||
snakes: Vec<Snake>,
|
snakes: Vec<Snake>,
|
||||||
pois: Vec<Point>,
|
pois: Vec<Position>,
|
||||||
score: u8,
|
score: u8,
|
||||||
hardmode: bool,
|
hardmode: bool,
|
||||||
}
|
}
|
||||||
@@ -63,25 +46,26 @@ impl Application for Game {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn run(&mut self, _: Vec<String>) -> Result<(), Error> {
|
async fn run(&mut self, _: Vec<String>) -> 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
|
// make the first poi
|
||||||
|
|
||||||
self.snakes.borrow_mut().push(Snake::player(0));
|
self.snakes.push(Snake::player(0));
|
||||||
|
|
||||||
for i in 0..5 {
|
for i in 0..5 {
|
||||||
self.new_poi();
|
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
|
// run the game
|
||||||
self.gameloop().await?;
|
self.gameloop().await?;
|
||||||
|
|
||||||
// return to the terminal
|
// return to the terminal
|
||||||
Screen::terminal_mode();
|
//Screen::terminal_mode();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -89,36 +73,23 @@ impl Application for Game {
|
|||||||
impl Game {
|
impl Game {
|
||||||
|
|
||||||
async fn gameloop(&mut self) -> Result<(), Error> { // main gameloop
|
async fn gameloop(&mut self) -> Result<(), Error> { // main gameloop
|
||||||
let mut all_points: Vec<Point>;
|
let mut all_points: Vec<Position>;
|
||||||
|
|
||||||
'gameloop: loop {
|
'gameloop: loop {
|
||||||
|
|
||||||
time::wait(0.1);
|
time::wait(0.1);
|
||||||
|
|
||||||
let mut points: Vec<Point>;
|
let mut points: Vec<Position>;
|
||||||
let length = self.snakes.len();
|
let length = self.snakes.len();
|
||||||
let mut status = Vec::new();
|
|
||||||
|
|
||||||
for i in 0..length {
|
for i in 0..length {
|
||||||
let points: Vec<Point> = self.snakes.clone().into_iter().map(|s| s.tail).flatten().collect();
|
let points: Vec<Position> = self.snakes.clone().into_iter().map(|s| s.tail).flatten().collect();
|
||||||
let res = self.snakes[i].next(&self.pois, &points);
|
let res = self.snakes[i].next(&self.pois, &points);
|
||||||
status.push(res);
|
|
||||||
|
|
||||||
|
match res {
|
||||||
|
Status::Lost => {
|
||||||
}
|
if !self.snakes[i].ai_controlled {
|
||||||
|
|
||||||
|
|
||||||
let res = self.snakes.iter_mut().map(|s| {
|
|
||||||
|
|
||||||
let points: Vec<Point> = self.snakes.clone().into_iter().map(|s| s.tail).flatten().collect();
|
|
||||||
s.next(&self.pois, &points)
|
|
||||||
}).collect::<Vec<Status>>();
|
|
||||||
|
|
||||||
|
|
||||||
if res.contains(&Status::Lost) {
|
|
||||||
self.render_end_screen().map_err(|_| Error::ApplicationError(String::from("failed to render end screen")))?;
|
self.render_end_screen().map_err(|_| Error::ApplicationError(String::from("failed to render end screen")))?;
|
||||||
|
|
||||||
// loop triggers when game is lost
|
// loop triggers when game is lost
|
||||||
loop {
|
loop {
|
||||||
match Stdin::keystroke().await {
|
match Stdin::keystroke().await {
|
||||||
@@ -126,11 +97,20 @@ impl Game {
|
|||||||
_ => continue,
|
_ => continue,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if res.contains(&Status::Exited) {
|
}
|
||||||
break 'gameloop;
|
},
|
||||||
} else if res.contains(&Status::Scored) {
|
Status::Exited => {
|
||||||
|
break 'gameloop
|
||||||
|
},
|
||||||
|
Status::Scored => {
|
||||||
|
if !self.snakes[i].ai_controlled {
|
||||||
self.score += 1;
|
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 => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
self.render().map_err(|_| Error::ApplicationError(String::from("failed to render game screen")))?;
|
self.render().map_err(|_| Error::ApplicationError(String::from("failed to render game screen")))?;
|
||||||
};
|
};
|
||||||
@@ -138,22 +118,22 @@ impl Game {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn new_poi(&mut self) {
|
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.pois.remove(self.pois.iter().position(|p| p == poi).unwrap());
|
||||||
self.new_poi();
|
self.new_poi();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render(&mut self) -> Result<(), ()> {
|
fn render(&mut self) -> Result<(), ()> {
|
||||||
let mut frame = vec![vec![ScreenChar::null(); 80]; 25];
|
let mut frame = vec![vec![ScreenChar::null(); 80]; 25];
|
||||||
self.snakes.borrow().clone().into_iter().map(|s| s.tail).flatten().for_each(|p| {
|
self.snakes.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));
|
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| {
|
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);
|
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[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();
|
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));
|
let mut elem = ColouredElement::generate(frame, (80, 25));
|
||||||
elem.render((0,0))
|
elem.render((0,0))
|
||||||
}
|
}
|
||||||
@@ -203,8 +182,8 @@ impl Game {
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
struct Snake {
|
struct Snake {
|
||||||
ai_controlled: bool,
|
ai_controlled: bool,
|
||||||
head: Point,
|
head: Position,
|
||||||
tail: Vec<Point>,
|
tail: Vec<Position>,
|
||||||
dir: Direction,
|
dir: Direction,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,71 +191,69 @@ impl Snake {
|
|||||||
fn ai(id: usize) -> Self {
|
fn ai(id: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
ai_controlled: true,
|
ai_controlled: true,
|
||||||
head: Point { x: 1 + id as i8 * 2, y: 1 },
|
head: Position { x: 4 + 4*id as i64 * 2, y: 9 },
|
||||||
tail: Vec::new(),
|
tail: (1..4).map(|p| Position { x: 4 + 4*id as i64, y: 5 + p}).collect(),
|
||||||
dir: Direction::Up
|
dir: Direction::PosY,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn player(id: usize) -> Self {
|
fn player(id: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
ai_controlled: false,
|
ai_controlled: false,
|
||||||
head: Point { x: 1 + id as i8 * 2, y: 1 },
|
head: Position { x: 4 + 4*id as i64, y: 9 },
|
||||||
tail: Vec::new(),
|
tail: (1..4).map(|p| Position { x: 4 + 4*id as i64, y: 5 + p}).collect(),
|
||||||
dir: Direction::Up,
|
dir: Direction::PosY,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next(&mut self, points_of_interest: &Vec<Point>, tails: &Vec<Point>) -> Status { // returns (lose_condition, scored)
|
fn next(&mut self, points_of_interest: &Vec<Position>, tails: &Vec<Position>) -> Status { // returns (lose_condition, scored)
|
||||||
|
|
||||||
// uses pathing algorithm if ai else keyboard input if human
|
// uses pathing algorithm if ai else keyboard input if human
|
||||||
if self.ai_controlled {
|
if self.ai_controlled {
|
||||||
self.dir = self.decide_dir();
|
self.dir = PathFinder::decide(&self.head, points_of_interest, tails);
|
||||||
} else {
|
} else {
|
||||||
if let Some(c) = Stdin::try_keystroke() {
|
// if let Some(c) = Stdin::try_keystroke() {
|
||||||
self.dir = match c {
|
// self.dir = match c {
|
||||||
'w' => Direction::Up,
|
// 'w' => Direction::PosY,
|
||||||
'a' => Direction::Left,
|
// 'a' => Direction::NegX,
|
||||||
's' => Direction::Down,
|
// 's' => Direction::NegY,
|
||||||
'd' => Direction::Right,
|
// 'd' => Direction::PosX,
|
||||||
'x' => return Status::Exited,
|
// 'x' => return Status::Exited,
|
||||||
_ => self.dir.clone(),
|
// _ => self.dir.clone(),
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
self.dir = Direction::None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.dir != Direction::None {
|
||||||
self.tail.push(self.head.clone());
|
self.tail.push(self.head.clone());
|
||||||
|
}
|
||||||
|
|
||||||
match self.dir {
|
match self.dir {
|
||||||
Direction::Up => self.head.y -= 1,
|
Direction::PosY => self.head.y += 1,
|
||||||
Direction::Down => self.head.y += 1,
|
Direction::NegY => self.head.y -= 1,
|
||||||
Direction::Left => self.head.x -= 1,
|
Direction::NegX => self.head.x -= 1,
|
||||||
Direction::Right => self.head.x += 1,
|
Direction::PosX => self.head.x += 1,
|
||||||
|
Direction::None => {},
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.lose_condition(tails) {
|
if self.lose_condition(tails) {
|
||||||
if !self.ai_controlled {
|
self.tail.remove(0);
|
||||||
return Status::Lost;
|
return Status::Lost;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if points_of_interest.contains(&self.head) {
|
if points_of_interest.contains(&self.head) {
|
||||||
if !self.ai_controlled {
|
|
||||||
return Status::Scored;
|
return Status::Scored;
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
|
if self.dir != Direction::None {
|
||||||
self.tail.remove(0);
|
self.tail.remove(0);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Status::None
|
Status::None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decide_dir(&mut self) -> Direction {
|
fn lose_condition(&mut self, tails: &Vec<Position>) -> bool { // where tails includes the tail of every other snake
|
||||||
unimplemented!() // implement a basic pathfinding or random movement algorithm
|
|
||||||
}
|
|
||||||
|
|
||||||
fn lose_condition(&mut self, tails: &Vec<Point>) -> bool { // where tails includes the tail of every other snake
|
|
||||||
let p = self.head.clone();
|
let p = self.head.clone();
|
||||||
|
|
||||||
let snake_overlaps = tails.contains(&self.head); // checks if any part of the snake overlaps itself
|
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
|
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<Position>, pois: &Vec<Position>) -> 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>) -> 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<Position>) -> bool {
|
||||||
|
tails.contains(&head)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fn round_up(n: f64) -> usize {
|
fn round_up(n: f64) -> usize {
|
||||||
(n + 0.99) as usize
|
(n + 0.99) as usize
|
||||||
@@ -291,3 +360,4 @@ fn round_up(n: f64) -> usize {
|
|||||||
fn round_down(n: f64) -> usize {
|
fn round_down(n: f64) -> usize {
|
||||||
n as usize
|
n as usize
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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>) -> 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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1 +1,2 @@
|
|||||||
pub mod libgui;
|
pub mod libgui;
|
||||||
|
pub mod coords;
|
||||||
|
|||||||
Reference in New Issue
Block a user