Skip to content

Commit

Permalink
fix(game_state): partially fix erroneous perform move
Browse files Browse the repository at this point in the history
fixes the incorrect calculation of the field when checking for blocked fields etc. Currently only one error occurs where the wrong vessel ahead is determined
  • Loading branch information
maxblan committed Nov 7, 2023
1 parent 8d3f13d commit ab62319
Show file tree
Hide file tree
Showing 14 changed files with 721 additions and 702 deletions.
6 changes: 3 additions & 3 deletions logic.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
from logging import DEBUG
from socha import GameState, Move, Starter, Advance
from socha import GameState, Move, Starter, Advance, Turn, CubeDirection
from socha.api.networking.game_client import IClientHandler


class Logic(IClientHandler):
game_state: GameState

def calculate_move(self) -> Move:
return Move(actions=[Advance(distance=1)])
return Move(actions=[Advance(1)])

def on_update(self, state: GameState):
self.game_state = state


if __name__ == "__main__":
Starter(logic=Logic(), log_level=DEBUG)
Starter(logic=Logic())
1 change: 1 addition & 0 deletions python/socha/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
'Board',
'CartesianCoordinate',
'CubeCoordinates',
'CubeDirection,'
'PluginConstants',
'Accelerate',
'Advance',
Expand Down
4 changes: 2 additions & 2 deletions python/socha/api/networking/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ def if_not_last_game_state(message) -> GameState:
return GameState(
board=_convert_board(message.data.class_binding.board),
turn=message.data.class_binding.turn,
team_one=first_team,
team_two=second_team,
current_ship=first_team,
other_ship=second_team,
last_move=None,
)
4 changes: 3 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use pyo3::exceptions::PyException;
use plugin::coordinate::CubeCoordinates;
use plugin::field::{ FieldType, Passenger };
use plugin::game_state::TeamPoints;
use plugin::game_state::AdvanceInfo;

use crate::plugin::actions::accelerate::Accelerate;
use crate::plugin::actions::advance::Advance;
Expand All @@ -32,7 +33,7 @@ pyo3::create_exception!(_socha, TurnProblem, PyException);
#[pymodule]
fn _socha(_py: Python, m: &PyModule) -> PyResult<()> {
pyo3_log::init();

m.add_class::<Accelerate>()?;
m.add_class::<Advance>()?;
m.add_class::<Push>()?;
Expand All @@ -59,6 +60,7 @@ fn _socha(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<Segment>()?;
m.add_class::<Board>()?;
m.add_class::<TeamPoints>()?;
m.add_class::<AdvanceInfo>()?;
m.add_class::<GameState>()?;

Ok(())
Expand Down
50 changes: 17 additions & 33 deletions src/plugin/actions/accelerate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use pyo3::prelude::*;

use crate::plugin::{ errors::acceleration_errors::AccelerationProblem, game_state::GameState };
use crate::plugin::field::FieldType;
use crate::plugin::ship::{ Ship, TeamEnum };
use crate::plugin::ship::Ship;

/// `Accelerate` is representing a ship's ability to change its speed and acceleration.
/// It contains methods for initiating and managing the acceleration process.
Expand Down Expand Up @@ -35,8 +35,8 @@ impl Accelerate {
Self { acc }
}

pub fn perform(&self, state: &GameState) -> Result<GameState, PyErr> {
let mut ship: Ship = state.current_ship();
pub fn perform(&self, state: &GameState) -> Result<Ship, PyErr> {
let mut ship: Ship = state.current_ship.clone();
let mut speed = ship.speed;
speed += self.acc;

Expand All @@ -54,29 +54,19 @@ impl Accelerate {
if new_ship.coal < 0 {
Err(PyBaseException::new_err(AccelerationProblem::InsufficientCoal.message()))
} else {
let new_state: &mut GameState = &mut state.clone();
match new_ship.team {
TeamEnum::One => {
new_state.team_one = new_ship;
}
TeamEnum::Two => {
new_state.team_two = new_ship;
}
}
Ok(new_state.clone())
Ok(ship)
}
}
}
}

fn accelerate(&self, ship: &Ship) -> Ship {
let new_ship: &mut Ship = &mut ship.clone();
let used_coal: i32 = self.acc.abs() - new_ship.free_acc;
new_ship.coal -= used_coal.max(0);
new_ship.free_acc = (-used_coal).max(0);
new_ship.accelerate_by(self.acc);
fn accelerate(&self, ship: &mut Ship) -> Ship {
let used_coal: i32 = self.acc.abs() - ship.free_acc;
ship.coal -= used_coal.max(0);
ship.free_acc = (-used_coal).max(0);
ship.accelerate_by(self.acc);

return new_ship.clone();
return ship.clone();
}

fn __repr__(&self) -> PyResult<String> {
Expand Down Expand Up @@ -119,9 +109,7 @@ mod tests {
None,
None,
None,
None,
None
);
None);
let team_two: Ship = Ship::new(
CubeCoordinates::new(-1, 1),
TeamEnum::Two,
Expand All @@ -131,9 +119,7 @@ mod tests {
None,
None,
None,
None,
None
);
None);
let game_state: GameState = GameState::new(board, 0, team_one.clone(), team_two, None);
(accelerate, game_state)
}
Expand Down Expand Up @@ -179,8 +165,8 @@ mod tests {
let (accelerate, game_state) = setup(2);

let mute_state: &mut GameState = &mut game_state.clone();
mute_state.team_one.coal = 0;
mute_state.team_two.coal = 0;
mute_state.current_ship.coal = 0;
mute_state.other_ship.coal = 0;

let result = accelerate.perform(&mute_state).unwrap_err();

Expand All @@ -196,8 +182,8 @@ mod tests {
fn test_perform_success() {
let (accelerate, game_state) = setup(2);

let result: GameState = accelerate.perform(&game_state).unwrap();
assert_eq!(result.current_ship().speed, 3);
let result: Ship = accelerate.perform(&game_state).unwrap();
assert_eq!(result.speed, 3);
}

#[test]
Expand All @@ -213,9 +199,7 @@ mod tests {
None,
None,
None,
None,
None
);
None);

assert_eq!(ship.speed, PluginConstants::MIN_SPEED);
assert_eq!(ship.coal, PluginConstants::START_COAL);
Expand Down
82 changes: 40 additions & 42 deletions src/plugin/actions/advance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ use pyo3::prelude::*;

use log::{ error, debug };

use crate::plugin::ship::{ TeamEnum, Ship };
use crate::plugin::ship::Ship;
use crate::plugin::{
constants::PluginConstants,
errors::advance_errors::AdvanceProblem,
game_state::GameState,
game_state::AdvanceInfo,
};
use crate::plugin::field::FieldType;

Expand All @@ -26,11 +27,16 @@ impl Advance {
Advance { distance }
}

pub fn perform(&self, state: &GameState) -> Result<GameState, PyErr> {
debug!("Performing advance action");
pub fn perform(&self, state: &GameState) -> Result<Ship, PyErr> {
debug!(
"Performing advance action of a distance {} with ship: {:?}",
self.distance,
state.current_ship
);
let mut current_ship: Ship = state.current_ship.clone();
if
(self.distance < PluginConstants::MIN_SPEED &&
state.board.get(&state.current_ship().position).unwrap().field_type !=
state.board.get(&current_ship.position).unwrap().field_type !=
FieldType::Sandbank) ||
self.distance > PluginConstants::MAX_SPEED
{
Expand All @@ -41,46 +47,40 @@ impl Advance {
return Err(PyBaseException::new_err(AdvanceProblem::InvalidDistance.message()));
}

if self.distance > state.current_ship().movement {
if self.distance > current_ship.movement {
error!("Movement points missing: {}", self.distance);
return Err(PyBaseException::new_err(AdvanceProblem::MovementPointsMissing.message()));
}

let result: Vec<Advance> = state.check_advance_limit(
&state.current_ship().position,
&(match self.distance > 0 {
true => state.current_ship().direction,
false => state.current_ship().direction.opposite(),
let result: AdvanceInfo = state.calculate_advance_info(
&current_ship.position,
&(if self.distance < 0 {
current_ship.direction.opposite()
} else {
current_ship.direction
}),
state.current_ship().movement
current_ship.movement
);

if (result.len() as i32) < self.distance.abs() {
error!(
"Invalid distance: {}. Due to blocked field after {} fields.",
self.distance,
result.len()
);
return Err(PyBaseException::new_err(AdvanceProblem::InvalidDistance.message()));
}
let new_ship: &mut Ship = &mut state.current_ship().clone();
new_ship.position += new_ship.direction.vector() * self.distance;
new_ship.movement -= result[(self.distance.abs() as usize) - 1].distance;

let new_state: &mut GameState = &mut state.clone();

match new_ship.team {
TeamEnum::One => {
new_state.team_one = new_ship.clone();
}
TeamEnum::Two => {
new_state.team_two = new_ship.clone();
}
debug!("Advance result: {:?}", result);

if (result.distance() as i32) < self.distance.abs() {
debug!("Distance too long: {} for {}", result.distance(), self.distance.abs());
return Err(PyBaseException::new_err(result.problem.message()));
}

debug!("Advance action performed with new ship: {:?}", new_ship);
current_ship.position += current_ship.direction.vector() * self.distance;
current_ship.movement -= result.cost_until(self.distance as usize);

Ok(new_state.clone())
debug!(
"New ship movement: {}, position: {:?}",
current_ship.movement,
current_ship.position
);

debug!("Advance action performed with new ship: {:?}", current_ship);

Ok(current_ship)
}

fn __repr__(&self) -> PyResult<String> {
Expand Down Expand Up @@ -120,7 +120,6 @@ mod tests {
None,
None,
None,
None,
None
);
team_one.speed = 5;
Expand All @@ -134,7 +133,6 @@ mod tests {
None,
None,
None,
None,
None
);
team_two.speed = 5;
Expand All @@ -154,20 +152,20 @@ mod tests {
let advance: Advance = Advance::new(2);
let state: GameState = setup();

let result: Result<GameState, PyErr> = advance.perform(&state);
let result: Result<Ship, PyErr> = advance.perform(&state);

assert!(result.is_ok());
let new_state: GameState = result.unwrap();
assert_eq!(new_state.current_ship().position, CubeCoordinates::new(2, -1));
assert_eq!(new_state.current_ship().movement, 3);
let new_ship: Ship = result.unwrap();
assert_eq!(new_ship.position, CubeCoordinates::new(2, -1));
assert_eq!(new_ship.movement, 3);
}

#[test]
fn test_advance_perform_invalid_distance() {
let advance: Advance = Advance::new(4);
let state: GameState = setup();

let result: Result<GameState, PyErr> = advance.perform(&state);
let result: Result<Ship, PyErr> = advance.perform(&state);

assert!(result.is_err());
let error: PyErr = result.unwrap_err();
Expand All @@ -182,7 +180,7 @@ mod tests {
let advance: Advance = Advance::new(6);
let state: GameState = setup();

let result: Result<GameState, PyErr> = advance.perform(&state);
let result: Result<Ship, PyErr> = advance.perform(&state);

assert!(result.is_err());
let error: PyErr = result.unwrap_err();
Expand Down
Loading

0 comments on commit ab62319

Please sign in to comment.