Skip to content

Commit

Permalink
feat: make board generic
Browse files Browse the repository at this point in the history
Signed-off-by: Agustín Ramiro Díaz <[email protected]>
  • Loading branch information
AgustinRamiroDiaz committed Jan 24, 2024
1 parent d9fce14 commit ac2d6df
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 47 deletions.
70 changes: 37 additions & 33 deletions src/board.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use crate::piece;
use std::{
collections::{HashMap, HashSet},
ops::Sub,
Expand Down Expand Up @@ -49,28 +48,28 @@ impl std::ops::Sub for Coordinate {
}

#[derive(PartialEq, Clone)]
pub(crate) struct StackableHexagonalBoard {
cells: HashMap<Coordinate, Cell>,
pub(crate) struct StackableHexagonalBoard<T> {
cells: HashMap<Coordinate, Cell<T>>,
}

type Cell = Vec<piece::Piece>;
type Cell<T> = Vec<T>;

impl StackableHexagonalBoard {
impl<T> StackableHexagonalBoard<T> {
pub(crate) fn new() -> Self {
StackableHexagonalBoard {
cells: HashMap::new(),
}
}

pub(crate) fn get_cell(&self, coordinate: Coordinate) -> Option<&Cell> {
pub(crate) fn get_cell(&self, coordinate: Coordinate) -> Option<&Cell<T>> {
self.cells.get(&coordinate)
}

pub(crate) fn get_top_piece(&self, coordinate: Coordinate) -> Option<&piece::Piece> {
pub(crate) fn get_top_piece(&self, coordinate: Coordinate) -> Option<&T> {
self.get_cell(coordinate)?.last()
}

pub(crate) fn put_piece(&mut self, p: piece::Piece, coordinate: Coordinate) {
pub(crate) fn put_piece(&mut self, p: T, coordinate: Coordinate) {
match self.cells.get_mut(&coordinate) {
None => {
let cell = vec![p];
Expand All @@ -95,8 +94,8 @@ impl StackableHexagonalBoard {
Ok(())
}

fn neighbors(&self, from: Coordinate) -> Vec<(Coordinate, &piece::Piece)> {
Self::neighbor_coordinates(from)
fn neighbors(&self, from: Coordinate) -> Vec<(Coordinate, &T)> {
CoordinateHandler::neighbor_coordinates(from)
.into_iter()
.flat_map(|neighbor_coordinate| {
Some((
Expand All @@ -107,21 +106,13 @@ impl StackableHexagonalBoard {
.collect()
}

pub(crate) fn neighbor_pieces(&self, coordinate: Coordinate) -> Vec<&piece::Piece> {
pub(crate) fn neighbor_pieces(&self, coordinate: Coordinate) -> Vec<&T> {
self.neighbors(coordinate)
.iter()
.map(|(_, piece)| *piece)
.collect()
}

pub(crate) fn neighbor_coordinates(from: Coordinate) -> [Coordinate; 6] {
RELATIVE_NEIGHBORS_CLOCKWISE.map(|delta| from + delta)
}

pub(crate) fn is_neighboor(a: Coordinate, b: Coordinate) -> bool {
RELATIVE_NEIGHBORS_CLOCKWISE.contains(&(a - b))
}

pub(crate) fn hive(&self) -> HashSet<Coordinate> {
HashSet::from_iter(
self.cells
Expand All @@ -144,7 +135,7 @@ impl StackableHexagonalBoard {

let neighbors: HashSet<Coordinate> = hive_without
.iter()
.flat_map(|&c| Self::neighbor_coordinates(c))
.flat_map(|&c| CoordinateHandler::neighbor_coordinates(c))
.collect();

neighbors.sub(&hive_without)
Expand All @@ -155,12 +146,36 @@ impl StackableHexagonalBoard {

let neighbors: HashSet<Coordinate> = hive_without
.iter()
.flat_map(|&c| Self::neighbor_coordinates(c))
.flat_map(|&c| CoordinateHandler::neighbor_coordinates(c))
.collect();

neighbors.union(&hive_without).copied().collect()
}

pub(crate) fn find<F>(&self, filter: F) -> Vec<Coordinate>
where
F: Fn(&T) -> bool,
{
self.cells
.iter()
.flat_map(|(&c, cell)| Some((c, cell.last()?)))
.filter(|(_, p)| filter(p))
.map(|(c, _)| c)
.collect()
}
}

pub(crate) struct CoordinateHandler {}

impl CoordinateHandler {
pub(crate) fn neighbor_coordinates(from: Coordinate) -> [Coordinate; 6] {
RELATIVE_NEIGHBORS_CLOCKWISE.map(|delta| from + delta)
}

pub(crate) fn is_neighboor(a: Coordinate, b: Coordinate) -> bool {
RELATIVE_NEIGHBORS_CLOCKWISE.contains(&(a - b))
}

pub(crate) fn can_slide(from: Coordinate, to: Coordinate, hive: &HashSet<Coordinate>) -> bool {
let relative_position = to - from;

Expand All @@ -181,23 +196,12 @@ impl StackableHexagonalBoard {

return left_neighbor.is_none() || right_neighbor.is_none();
}

pub(crate) fn find<F>(&self, filter: F) -> Vec<Coordinate>
where
F: Fn(&piece::Piece) -> bool,
{
self.cells
.iter()
.flat_map(|(&c, cell)| Some((c, cell.last()?)))
.filter(|(_, p)| filter(p))
.map(|(c, _)| c)
.collect()
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::piece;

#[test]
fn simple_board() {
Expand Down
26 changes: 12 additions & 14 deletions src/game.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
use std::collections::HashSet;
use std::vec;

use crate::board::{self, Coordinate, StackableHexagonalBoard};
use crate::board::{self, Coordinate, CoordinateHandler, StackableHexagonalBoard};
use crate::piece::{Bug, Color, Piece};

#[derive(PartialEq, Clone)]
pub(crate) struct Game {
turn: Color,
won: Option<Color>,
board: StackableHexagonalBoard,
board: StackableHexagonalBoard<Piece>,
turn_number: u8,
pool: Vec<Piece>,
}
Expand Down Expand Up @@ -147,7 +147,7 @@ impl Game {
let mut to_visit = vec![to];
while let Some(coordinate) = to_visit.pop() {
reachable.insert(coordinate);
for neighbor in StackableHexagonalBoard::neighbor_coordinates(coordinate) {
for neighbor in CoordinateHandler::neighbor_coordinates(coordinate) {
if !reachable.contains(&neighbor) && hive.contains(&neighbor) {
to_visit.push(neighbor);
}
Expand Down Expand Up @@ -176,18 +176,17 @@ impl Game {

let hive = self.board.hive_without(from);

let neighbor_coordinates =
StackableHexagonalBoard::neighbor_coordinates(from).into();
let neighbor_coordinates = CoordinateHandler::neighbor_coordinates(from).into();
let slidable_neighbors = walkable
.intersection(&neighbor_coordinates)
.filter(|&c| StackableHexagonalBoard::can_slide(from, *c, &hive));
.filter(|&c| CoordinateHandler::can_slide(from, *c, &hive));

slidable_neighbors.cloned().collect()
}
Bug::Beetle => self
.board
.hive_and_walkable_without(from)
.intersection(&StackableHexagonalBoard::neighbor_coordinates(from).into())
.intersection(&CoordinateHandler::neighbor_coordinates(from).into())
.cloned()
.collect(),
Bug::Grasshopper => {
Expand Down Expand Up @@ -224,11 +223,11 @@ impl Game {
let last = *path.last().ok_or(())?; // TODO: this should never fail

let neighbor_coordinates =
StackableHexagonalBoard::neighbor_coordinates(last).into();
CoordinateHandler::neighbor_coordinates(last).into();
let walkable_neighbors = walkable.intersection(&neighbor_coordinates);
let slidable_neighbors = walkable_neighbors
.filter(|&c| !path.contains(c))
.filter(|&c| StackableHexagonalBoard::can_slide(last, *c, &walkable));
.filter(|&c| CoordinateHandler::can_slide(last, *c, &walkable));

for &neighbor in slidable_neighbors {
let mut new_path = path.clone();
Expand All @@ -251,11 +250,10 @@ impl Game {

while let Some(current) = to_check.pop() {
let neighbor_coordinates =
StackableHexagonalBoard::neighbor_coordinates(current).into();
let slidable_neighbors =
walkable.intersection(&neighbor_coordinates).filter(|&&c| {
StackableHexagonalBoard::can_slide(current, c, &self.board.hive())
});
CoordinateHandler::neighbor_coordinates(current).into();
let slidable_neighbors = walkable
.intersection(&neighbor_coordinates)
.filter(|&&c| CoordinateHandler::can_slide(current, c, &self.board.hive()));

for &neighbor in slidable_neighbors {
if !reachable.contains(&neighbor) {
Expand Down

0 comments on commit ac2d6df

Please sign in to comment.