calculate valid moves
Some checks failed
Build / build (push) Failing after 1m52s

This commit is contained in:
Max Känner 2025-01-16 21:06:49 +01:00
parent d91d0e0a82
commit 9c76df1f69
5 changed files with 75 additions and 20 deletions

22
Cargo.lock generated
View File

@ -173,8 +173,10 @@ version = "2.0.0"
dependencies = [
"axum",
"bitvec",
"enum-iterator",
"env_logger",
"log",
"rand",
"serde",
"tokio",
]
@ -299,6 +301,26 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "enum-iterator"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c280b9e6b3ae19e152d8e31cf47f18389781e119d4013a2a2bb0180e5facc635"
dependencies = [
"enum-iterator-derive",
]
[[package]]
name = "enum-iterator-derive"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1ab991c1362ac86c61ab6f556cff143daa22e5a15e4e189df818b2fd19fe65b"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "env_filter"
version = "0.1.3"

View File

@ -27,3 +27,5 @@ env_logger = "0.11"
# other
bitvec = "1.0"
enum-iterator = "2.1"
rand = "0.8"

View File

@ -6,7 +6,8 @@ use axum::{
routing::{get, post},
Router,
};
use log::{debug, info};
use log::{debug, info, warn};
use rand::prelude::*;
use serde::Serialize;
use tokio::net::TcpListener;
use types::{
@ -62,8 +63,15 @@ async fn start(request: Json<Request>) {
async fn get_move(request: Json<Request>) -> response::Json<Response> {
let board = Board::from(&*request);
info!("got move request: {board}");
let actions = board.valid_actions(0).collect::<Vec<_>>();
info!("valid actions: {:?}", actions);
let action = actions.choose(&mut thread_rng()).copied();
if action.is_none() {
warn!("unable to find a valid action");
}
info!("chose {action:?}");
response::Json(Response {
direction: Direction::Up,
direction: action.unwrap_or(Direction::Up),
shout: None,
})
}

View File

@ -1,3 +1,4 @@
use enum_iterator::Sequence;
use serde::{Deserialize, Serialize};
pub mod simulation;
@ -9,7 +10,19 @@ pub struct Coord {
y: u8,
}
#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize)]
impl Coord {
pub fn apply(self, direction: Direction) -> Option<Self> {
match direction {
Direction::Up => self.y.checked_add(1).map(|y| Self { y, x: self.x }),
Direction::Down => self.y.checked_sub(1).map(|y| Self { y, x: self.x }),
Direction::Left => self.x.checked_sub(1).map(|x| Self { x, y: self.y }),
Direction::Right => self.x.checked_add(1).map(|x| Self { x, y: self.y }),
}
}
}
#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Sequence)]
#[serde(rename_all = "lowercase")]
pub enum Direction {
/// Move in positive y direction
Up,

View File

@ -1,9 +1,9 @@
use std::{collections::VecDeque, fmt::Display};
use bitvec::prelude::*;
use log::error;
use log::{error, warn};
use super::{wire::Request, Coord};
use super::{wire::Request, Coord, Direction};
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Board {
@ -123,9 +123,31 @@ impl Board {
self.hazard[index]
}
pub fn is_blocked(&self, tile: Coord) -> bool {
pub fn is_free(&self, tile: Coord) -> bool {
let index = usize::from(self.coord_to_linear(tile));
!self.free[index]
self.free[index]
}
pub fn valid_actions(&self, id: u8) -> impl Iterator<Item = Direction> + use<'_> {
let head = self
.snakes
.binary_search_by_key(&id, |snake| snake.id)
.ok()
.map(|index| self.snakes[index].head());
if head.is_none() {
warn!(
"Asked for an action for a snake that doesn't exist: {id} not in {:?}",
self.snakes
);
}
enum_iterator::all::<Direction>()
.filter_map(move |direction| {
head.and_then(|head| head.apply(direction))
.map(|tile| (direction, tile))
})
.filter(|(_, tile)| tile.x < self.width && tile.y < self.height)
.filter(|(_, tile)| self.is_free(*tile))
.map(|(direction, _)| direction)
}
fn coord_to_linear(&self, coord: Coord) -> u16 {
@ -140,18 +162,6 @@ struct Snake {
body: VecDeque<Coord>,
}
impl PartialOrd for Snake {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Snake {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.id.cmp(&other.id)
}
}
impl Snake {
pub fn head(&self) -> Coord {
self.body.front().copied().unwrap_or_else(|| {
@ -161,7 +171,7 @@ impl Snake {
}
pub fn tail(&self) -> Coord {
self.body.front().copied().unwrap_or_else(|| {
self.body.back().copied().unwrap_or_else(|| {
error!("Snake without a tail: {self:?}");
Coord { x: 0, y: 0 }
})