diff --git a/python/socha/_socha.pyi b/python/socha/_socha.pyi index eacf72a..b105b30 100644 --- a/python/socha/_socha.pyi +++ b/python/socha/_socha.pyi @@ -785,13 +785,48 @@ class RulesEngine: Es wird nicht beachtet, ob die Zahl kleiner 0 oder größer 59 ist. Args: - turn (int): Die Zugzahl + turn (int): Die Zugzahl. Returns: TeamEnum: Das Team, was dran ist. """ ... + @staticmethod + def swarm_from(board: Board, position: Coordinate) -> List[Coordinate]: + """ + Berechnet auf einem Spielbrett von einer Startposition aus, welche Fische + von dort aus in einem Schwarm zusammenhängen. + Dabei werden nur Fische beachtet, die im selben Team sind, wie der auf dem Startfeld. + Gibt eine Liste an Koordinaten zurück, die leer ist, wenn die Startposition + außerhalb des Spielbrettes ist, oder kein Fisch als Start angegeben ist. + + Args: + board (Board): Das Spielbrett. + position (Coordinate): Die Startkoordinate + + Returns: + List[Coordinate]: Die Liste an zusammenhängenden Fischen. + + """ + ... + + @staticmethod + def swarms_of_team(board: Board, team: TeamEnum) -> List[List[Coordinate]]: + """ + Berechnet auf einem Spielbrett alle Schwärme, die ein Team gerade gebildet hat. + Gibt eine 2-Dimensionale Liste zurück, wobei jede Sub-Liste ein einzelner Schwarm ist. + + Args: + board (Board): Das Spielbrett. + team (TeamEnum): Das gewählte Team. + + Returns: + List[List[Coordinate]]: Die Liste an Schwärmen. + + """ + ... + class PluginConstants: """ Hält globale Konstanten. diff --git a/src/plugin2026/rules_engine.rs b/src/plugin2026/rules_engine.rs index 5f9ccd1..bc3fa62 100644 --- a/src/plugin2026/rules_engine.rs +++ b/src/plugin2026/rules_engine.rs @@ -1,9 +1,14 @@ +use std::vec; + use pyo3::*; use crate::plugin2026::{ - board::Board, errors::PiranhasError, field_type::FieldType, r#move::Move, utils::{ + board::Board, errors::PiranhasError, field_type::FieldType, r#move::Move, + utils::{ constants::PluginConstants, - coordinate::Coordinate, team::TeamEnum + coordinate::Coordinate, + direction::Direction, + team::TeamEnum } }; @@ -76,10 +81,87 @@ impl RulesEngine { #[staticmethod] pub fn get_team_on_turn(turn: usize) -> TeamEnum { - if turn % 2 == 0 { + if turn.is_multiple_of(2) { TeamEnum::One } else { TeamEnum::Two } } + + #[staticmethod] + pub fn swarm_from(board: &Board, position: &Coordinate) -> Vec { + + if !RulesEngine::is_in_bounds(position) { + return vec![]; + } + + let Some(this_team) = board.get_field(position).unwrap().get_team() else { + return vec![]; + }; + + let mut todo: Vec = vec![position.to_owned()]; + let mut visited: Vec = Vec::new(); + + while !todo.is_empty() { + + let neighbors = RulesEngine::valid_neighbors(&todo[0]); + for n in neighbors { + if visited.contains(&n) || todo.contains(&n) { + continue; + } + + if let Some(team) = board.get_field(&n).unwrap().get_team() { + if team == this_team { + todo.push(n) + } + } + } + + visited.push(todo[0]); + todo.remove(0); + } + + visited + } + + #[staticmethod] + pub fn swarms_of_team(board: &Board, team: &TeamEnum) -> Vec> { + + let mut team_fish: Vec = Vec::new(); + for f in team.get_fish_types() { + team_fish.extend(board.get_fields_by_type(f)); + } + + let mut swarms: Vec> = Vec::new(); + while !team_fish.is_empty() { + let visited = RulesEngine::swarm_from(board, &team_fish[0]); + + for v in &visited { + if let Some(index) = team_fish.iter().position(|x| x == v) { + team_fish.remove(index); + } + } + + swarms.push(visited) + } + + swarms + } +} + +// rust exclusive methods +impl RulesEngine { + pub fn valid_neighbors(position: &Coordinate) -> Vec { + + let mut coordinates: Vec = Vec::new(); + + for d in Direction::all_directions() { + let neighbor = position.add_vector(&d.to_vector()); + if RulesEngine::is_in_bounds(&neighbor) { + coordinates.push(neighbor); + } + } + + coordinates + } } \ No newline at end of file