Skip to content

Commit 9727218

Browse files
authored
feat(rulesengine): add 2 swarm methods for python (#100)
* feat(rulesengine): add 2 swarm methods for python to get closer to java api (performance wise) * chore: fix ci/cd error which not raised locally
1 parent 8f51a5e commit 9727218

File tree

2 files changed

+121
-4
lines changed

2 files changed

+121
-4
lines changed

python/socha/_socha.pyi

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -785,13 +785,48 @@ class RulesEngine:
785785
Es wird nicht beachtet, ob die Zahl kleiner 0 oder größer 59 ist.
786786
787787
Args:
788-
turn (int): Die Zugzahl
788+
turn (int): Die Zugzahl.
789789
790790
Returns:
791791
TeamEnum: Das Team, was dran ist.
792792
"""
793793
...
794794

795+
@staticmethod
796+
def swarm_from(board: Board, position: Coordinate) -> List[Coordinate]:
797+
"""
798+
Berechnet auf einem Spielbrett von einer Startposition aus, welche Fische
799+
von dort aus in einem Schwarm zusammenhängen.
800+
Dabei werden nur Fische beachtet, die im selben Team sind, wie der auf dem Startfeld.
801+
Gibt eine Liste an Koordinaten zurück, die leer ist, wenn die Startposition
802+
außerhalb des Spielbrettes ist, oder kein Fisch als Start angegeben ist.
803+
804+
Args:
805+
board (Board): Das Spielbrett.
806+
position (Coordinate): Die Startkoordinate
807+
808+
Returns:
809+
List[Coordinate]: Die Liste an zusammenhängenden Fischen.
810+
811+
"""
812+
...
813+
814+
@staticmethod
815+
def swarms_of_team(board: Board, team: TeamEnum) -> List[List[Coordinate]]:
816+
"""
817+
Berechnet auf einem Spielbrett alle Schwärme, die ein Team gerade gebildet hat.
818+
Gibt eine 2-Dimensionale Liste zurück, wobei jede Sub-Liste ein einzelner Schwarm ist.
819+
820+
Args:
821+
board (Board): Das Spielbrett.
822+
team (TeamEnum): Das gewählte Team.
823+
824+
Returns:
825+
List[List[Coordinate]]: Die Liste an Schwärmen.
826+
827+
"""
828+
...
829+
795830
class PluginConstants:
796831
"""
797832
Hält globale Konstanten.

src/plugin2026/rules_engine.rs

Lines changed: 85 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
1+
use std::vec;
2+
13
use pyo3::*;
24

35
use crate::plugin2026::{
4-
board::Board, errors::PiranhasError, field_type::FieldType, r#move::Move, utils::{
6+
board::Board, errors::PiranhasError, field_type::FieldType, r#move::Move,
7+
utils::{
58
constants::PluginConstants,
6-
coordinate::Coordinate, team::TeamEnum
9+
coordinate::Coordinate,
10+
direction::Direction,
11+
team::TeamEnum
712
}
813
};
914

@@ -76,10 +81,87 @@ impl RulesEngine {
7681

7782
#[staticmethod]
7883
pub fn get_team_on_turn(turn: usize) -> TeamEnum {
79-
if turn % 2 == 0 {
84+
if turn.is_multiple_of(2) {
8085
TeamEnum::One
8186
} else {
8287
TeamEnum::Two
8388
}
8489
}
90+
91+
#[staticmethod]
92+
pub fn swarm_from(board: &Board, position: &Coordinate) -> Vec<Coordinate> {
93+
94+
if !RulesEngine::is_in_bounds(position) {
95+
return vec![];
96+
}
97+
98+
let Some(this_team) = board.get_field(position).unwrap().get_team() else {
99+
return vec![];
100+
};
101+
102+
let mut todo: Vec<Coordinate> = vec![position.to_owned()];
103+
let mut visited: Vec<Coordinate> = Vec::new();
104+
105+
while !todo.is_empty() {
106+
107+
let neighbors = RulesEngine::valid_neighbors(&todo[0]);
108+
for n in neighbors {
109+
if visited.contains(&n) || todo.contains(&n) {
110+
continue;
111+
}
112+
113+
if let Some(team) = board.get_field(&n).unwrap().get_team() {
114+
if team == this_team {
115+
todo.push(n)
116+
}
117+
}
118+
}
119+
120+
visited.push(todo[0]);
121+
todo.remove(0);
122+
}
123+
124+
visited
125+
}
126+
127+
#[staticmethod]
128+
pub fn swarms_of_team(board: &Board, team: &TeamEnum) -> Vec<Vec<Coordinate>> {
129+
130+
let mut team_fish: Vec<Coordinate> = Vec::new();
131+
for f in team.get_fish_types() {
132+
team_fish.extend(board.get_fields_by_type(f));
133+
}
134+
135+
let mut swarms: Vec<Vec<Coordinate>> = Vec::new();
136+
while !team_fish.is_empty() {
137+
let visited = RulesEngine::swarm_from(board, &team_fish[0]);
138+
139+
for v in &visited {
140+
if let Some(index) = team_fish.iter().position(|x| x == v) {
141+
team_fish.remove(index);
142+
}
143+
}
144+
145+
swarms.push(visited)
146+
}
147+
148+
swarms
149+
}
150+
}
151+
152+
// rust exclusive methods
153+
impl RulesEngine {
154+
pub fn valid_neighbors(position: &Coordinate) -> Vec<Coordinate> {
155+
156+
let mut coordinates: Vec<Coordinate> = Vec::new();
157+
158+
for d in Direction::all_directions() {
159+
let neighbor = position.add_vector(&d.to_vector());
160+
if RulesEngine::is_in_bounds(&neighbor) {
161+
coordinates.push(neighbor);
162+
}
163+
}
164+
165+
coordinates
166+
}
85167
}

0 commit comments

Comments
 (0)