Skip to content

Commit

Permalink
Merge pull request #301 from zarns/feature/zarns/catanatron_rust
Browse files Browse the repository at this point in the history
Feature/zarns/catanatron rust
  • Loading branch information
bcollazo authored Jan 23, 2025
2 parents 6cc44c1 + 6ce7c12 commit 454a908
Show file tree
Hide file tree
Showing 6 changed files with 975 additions and 82 deletions.
8 changes: 4 additions & 4 deletions catanatron_rust/src/enums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,18 +75,18 @@ pub enum Action {
// The first value in all these is the color of the player.
Roll(u8, Option<(u8, u8)>), // None. Log instead sets it to (int, int) rolled.
MoveRobber(u8, Coordinate, Option<u8>), // Log has extra element of card stolen.
Discard(u8), // value is None|Resource[].
Discard(u8), // value is None|Resource[].
BuildRoad(u8, EdgeId),
BuildSettlement(u8, NodeId),
BuildCity(u8, NodeId),
BuyDevelopmentCard(u8), // value is None. Log value is card.
PlayKnight(u8),
PlayYearOfPlenty(u8, (Option<u8>, Option<u8>)),
PlayMonopoly(u8, u8), // value is Resource
PlayYearOfPlenty(u8, [u8; 2]), // Two resources to take from bank
PlayMonopoly(u8, u8), // value is Resource
PlayRoadBuilding(u8),

// First element of tuples is in, last is out.
MaritimeTrade(u8, (FreqDeck, u8)),
MaritimeTrade(u8, (u8, u8, u8)), // (Give Resource, Get Resource, Ratio)
OfferTrade(u8, (FreqDeck, FreqDeck)),
AcceptTrade(u8, (FreqDeck, FreqDeck)),
RejectTrade(u8),
Expand Down
9 changes: 8 additions & 1 deletion catanatron_rust/src/map_instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,13 @@ impl MapInstance {
pub fn get_adjacent_tiles(&self, node_id: NodeId) -> Option<&Vec<LandTile>> {
self.adjacent_land_tiles.get(&node_id)
}

pub fn get_tiles_by_number(&self, number: u8) -> Vec<&LandTile> {
self.land_tiles
.values()
.filter(|&tile| tile.number == Some(number))
.collect()
}
}

impl MapInstance {
Expand All @@ -192,7 +199,7 @@ impl MapInstance {
let mut autoinc = 0;
let mut tile_autoinc = 0;
let mut port_autoinc = 0;

for (&coordinate, &tile_slot) in map_template.topology.iter() {
let (nodes, edges, new_autoinc) = get_nodes_edges(&hexagons, coordinate, autoinc);
autoinc = new_autoinc;
Expand Down
110 changes: 100 additions & 10 deletions catanatron_rust/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ use crate::{
map_instance::{EdgeId, MapInstance, NodeId},
state_vector::{
actual_victory_points_index, initialize_state, player_devhand_slice, player_hand_slice,
seating_order_slice, StateVector, CURRENT_TICK_SEAT_INDEX, FREE_ROADS_AVAILABLE_INDEX,
HAS_PLAYED_DEV_CARD, HAS_ROLLED_INDEX, IS_DISCARDING_INDEX, IS_INITIAL_BUILD_PHASE_INDEX,
IS_MOVING_ROBBER_INDEX,
player_played_devhand_slice, seating_order_slice, StateVector, BANK_RESOURCE_SLICE,
CURRENT_TICK_SEAT_INDEX, FREE_ROADS_AVAILABLE_INDEX, HAS_PLAYED_DEV_CARD, HAS_ROLLED_INDEX,
IS_DISCARDING_INDEX, IS_INITIAL_BUILD_PHASE_INDEX, IS_MOVING_ROBBER_INDEX,
},
};

Expand Down Expand Up @@ -39,6 +39,8 @@ pub struct State {
connected_components: HashMap<u8, Vec<HashSet<NodeId>>>,
longest_road_color: Option<u8>,
longest_road_length: u8,
largest_army_color: Option<u8>,
largest_army_count: u8,
}

mod move_application;
Expand All @@ -56,6 +58,8 @@ impl State {
let connected_components = HashMap::new();
let longest_road_color = None;
let longest_road_length = 0;
let largest_army_color = None;
let largest_army_count = 0;

Self {
config,
Expand All @@ -69,6 +73,8 @@ impl State {
connected_components,
longest_road_color,
longest_road_length,
largest_army_color,
largest_army_count,
}
}

Expand Down Expand Up @@ -134,7 +140,8 @@ impl State {
pub fn can_play_dev(&self, dev_card: u8) -> bool {
let color = self.get_current_color();
let dev_card_index = dev_card as usize;
let has_one = self.vector[player_devhand_slice(self.config.num_players, color)][dev_card_index] > 0;
let has_one =
self.vector[player_devhand_slice(self.config.num_players, color)][dev_card_index] > 0;
let has_played_in_turn = self.vector[HAS_PLAYED_DEV_CARD] == 1;
has_one && !has_played_in_turn
}
Expand Down Expand Up @@ -234,7 +241,7 @@ impl State {
buildable.into_iter().collect()
}

pub fn buildable_node_ids(&self, color: u8,) -> Vec<u8> {
pub fn buildable_node_ids(&self, color: u8) -> Vec<u8> {
let road_subgraphs = match self.connected_components.get(&color) {
Some(components) => components,
None => &vec![],
Expand All @@ -245,7 +252,8 @@ impl State {
road_connected_nodes.extend(component);
}

road_connected_nodes.intersection(&self.board_buildable_ids)
road_connected_nodes
.intersection(&self.board_buildable_ids)
.copied()
.collect()
}
Expand Down Expand Up @@ -317,12 +325,23 @@ impl State {

// Move forward
current_path.push(edge);
self.dfs_longest_path(neighbor, Some(node), connected_set, color, current_path, best_path);
self.dfs_longest_path(
neighbor,
Some(node),
connected_set,
color,
current_path,
best_path,
);
current_path.pop();
}
}

pub fn longest_acyclic_path(&self, connected_node_set: &HashSet<NodeId>, color: u8) -> Vec<EdgeId> {
pub fn longest_acyclic_path(
&self,
connected_node_set: &HashSet<NodeId>,
color: u8,
) -> Vec<EdgeId> {
if connected_node_set.is_empty() {
return vec![];
}
Expand All @@ -333,13 +352,84 @@ impl State {
let mut current_path = Vec::new();
let mut best_path = Vec::new();

self.dfs_longest_path(start_node, None, connected_node_set, color, &mut current_path, &mut best_path);
self.dfs_longest_path(
start_node,
None,
connected_node_set,
color,
&mut current_path,
&mut best_path,
);
if best_path.len() > overall_best_path.len() {
overall_best_path = best_path;
}
}
overall_best_path
}

pub fn add_dev_card(&mut self, color: u8, card_idx: usize) {
self.vector[player_devhand_slice(self.config.num_players, color)][card_idx] += 1;
}

pub fn get_dev_card_count(&self, color: u8, card_idx: usize) -> u8 {
self.vector[player_devhand_slice(self.config.num_players, color)][card_idx]
}

pub fn get_played_dev_card_count(&self, color: u8, card_idx: usize) -> u8 {
self.vector[player_played_devhand_slice(self.config.num_players, color)][card_idx]
}

pub fn add_played_dev_card(&mut self, color: u8, card_idx: usize) {
self.vector[player_played_devhand_slice(self.config.num_players, color)][card_idx] += 1;
}

pub fn remove_dev_card(&mut self, color: u8, card_idx: usize) {
self.vector[player_devhand_slice(self.config.num_players, color)][card_idx] -= 1;
}

pub fn set_has_played_dev_card(&mut self) {
self.vector[HAS_PLAYED_DEV_CARD] = 1;
}

pub fn set_is_moving_robber(&mut self) {
self.vector[IS_MOVING_ROBBER_INDEX] = 1;
}

pub fn clear_is_moving_robber(&mut self) {
self.vector[IS_MOVING_ROBBER_INDEX] = 0;
}

pub fn bank_has_resource(&self, resource: u8) -> bool {
self.vector[BANK_RESOURCE_SLICE][resource as usize] > 0
}

pub fn take_from_bank_give_to_player(&mut self, color: u8, resource: u8) {
let resource_idx = resource as usize;
self.vector[BANK_RESOURCE_SLICE][resource_idx] -= 1;
self.get_mut_player_hand(color)[resource_idx] += 1;
}

pub fn take_from_player_give_to_bank(&mut self, color: u8, resource: u8, amount: u8) {
let resource_idx = resource as usize;
self.get_mut_player_hand(color)[resource_idx] -= amount;
self.vector[BANK_RESOURCE_SLICE][resource_idx] += amount;
}

pub fn get_player_resource_count(&self, color: u8, resource: u8) -> u8 {
self.get_player_hand(color)[resource as usize]
}

pub fn take_from_player_give_to_player(
&mut self,
from_color: u8,
to_color: u8,
resource: u8,
amount: u8,
) {
let resource_idx = resource as usize;
self.get_mut_player_hand(from_color)[resource_idx] -= amount;
self.get_mut_player_hand(to_color)[resource_idx] += amount;
}
}

#[cfg(test)]
Expand All @@ -361,7 +451,7 @@ mod tests {
assert!(!state.is_moving_robber());
assert!(!state.is_discarding());
}

#[test]
fn test_longest_acyclic_path() {
let mut state = State::new_base();
Expand Down
Loading

0 comments on commit 454a908

Please sign in to comment.