From ac2d6dfb0631cf9a37acd3972f8b5636dc2184d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Agust=C3=ADn=20Ramiro=20D=C3=ADaz?= Date: Wed, 24 Jan 2024 14:59:39 -0300 Subject: [PATCH] feat: make board generic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Agustín Ramiro Díaz --- src/board.rs | 70 +++++++++++++++++++++++++++------------------------- src/game.rs | 26 +++++++++---------- 2 files changed, 49 insertions(+), 47 deletions(-) diff --git a/src/board.rs b/src/board.rs index adee1e9..eccaf4d 100644 --- a/src/board.rs +++ b/src/board.rs @@ -1,4 +1,3 @@ -use crate::piece; use std::{ collections::{HashMap, HashSet}, ops::Sub, @@ -49,28 +48,28 @@ impl std::ops::Sub for Coordinate { } #[derive(PartialEq, Clone)] -pub(crate) struct StackableHexagonalBoard { - cells: HashMap, +pub(crate) struct StackableHexagonalBoard { + cells: HashMap>, } -type Cell = Vec; +type Cell = Vec; -impl StackableHexagonalBoard { +impl StackableHexagonalBoard { 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> { 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]; @@ -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(( @@ -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 { HashSet::from_iter( self.cells @@ -144,7 +135,7 @@ impl StackableHexagonalBoard { let neighbors: HashSet = hive_without .iter() - .flat_map(|&c| Self::neighbor_coordinates(c)) + .flat_map(|&c| CoordinateHandler::neighbor_coordinates(c)) .collect(); neighbors.sub(&hive_without) @@ -155,12 +146,36 @@ impl StackableHexagonalBoard { let neighbors: HashSet = 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(&self, filter: F) -> Vec + 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) -> bool { let relative_position = to - from; @@ -181,23 +196,12 @@ impl StackableHexagonalBoard { return left_neighbor.is_none() || right_neighbor.is_none(); } - - pub(crate) fn find(&self, filter: F) -> Vec - 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() { diff --git a/src/game.rs b/src/game.rs index 5180b05..8ce112d 100644 --- a/src/game.rs +++ b/src/game.rs @@ -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, - board: StackableHexagonalBoard, + board: StackableHexagonalBoard, turn_number: u8, pool: Vec, } @@ -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); } @@ -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 => { @@ -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(); @@ -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) {