Skip to content

Commit

Permalink
Implement move iterator
Browse files Browse the repository at this point in the history
  • Loading branch information
fwcd committed Sep 8, 2023
1 parent 94b44eb commit 18b0ccd
Show file tree
Hide file tree
Showing 5 changed files with 186 additions and 26 deletions.
4 changes: 2 additions & 2 deletions src/game/board.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@ impl Board {
}

/// The effective speed of the given ship, depending on current.
pub fn effective_speed(&self, ship: Ship) -> usize {
ship.speed - (self.does_field_have_current(ship.position) as usize)
pub fn effective_speed(&self, ship: Ship) -> i32 {
ship.speed - (self.does_field_have_current(ship.position) as i32)
}

/// Picks up a passenger.
Expand Down
6 changes: 3 additions & 3 deletions src/game/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ pub const ROUND_LIMIT: usize = 30;

// Ship Properties
pub const START_COAL: usize = 6;
pub const MIN_SPEED: usize = 1;
pub const MAX_SPEED: usize = 6;
pub const FREE_ACC: usize = 1;
pub const MIN_SPEED: i32 = 1;
pub const MAX_SPEED: i32 = 6;
pub const FREE_ACC: i32 = 1;

// Points
pub const FINISH_POINTS: usize = 6;
Expand Down
56 changes: 55 additions & 1 deletion src/game/move.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Ported from https://github.com/software-challenge/backend/blob/be88340f619892fe70c4cbd45e131d5445e883c7/plugin/src/main/kotlin/sc/plugin2024/Field.kt

use crate::util::{Error, Element, Result};
use crate::util::{Error, Element, Result, Perform};

use super::Action;

Expand All @@ -10,6 +10,60 @@ pub struct Move {
pub actions: Vec<Action>,
}

impl Default for Move {
fn default() -> Self {
Self::new()
}
}

impl Move {
/// Creates an empty move.
pub fn new() -> Self {
Move { actions: Vec::new() }
}

/// The last action within the move.
pub fn last(&self) -> Option<&Action> {
self.actions.last()
}

/// An iterator over the actions within this move.
pub fn iter(&self) -> impl Iterator<Item = &Action> {
self.actions.iter()
}

/// A mutable iterator over the actions within this move.
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Action> {
self.actions.iter_mut()
}

/// Whether the move contains no actions.
pub fn is_empty(&self) -> bool {
self.actions.is_empty()
}
}

impl From<Action> for Move {
fn from(action: Action) -> Self {
Self { actions: vec![action] }
}
}

impl Perform<Action> for Move {
fn perform(&mut self, action: Action) {
self.actions.push(action);
}
}

impl IntoIterator for Move {
type Item = Action;
type IntoIter = <Vec<Action> as IntoIterator>::IntoIter;

fn into_iter(self) -> Self::IntoIter {
self.actions.into_iter()
}
}

impl TryFrom<&Element> for Move {
type Error = Error;

Expand Down
15 changes: 11 additions & 4 deletions src/game/ship.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
//! Ported from https://github.com/software-challenge/backend/blob/be88340f619892fe70c4cbd45e131d5445e883c7/plugin/src/main/kotlin/sc/plugin2024/Ship.kt

use crate::util::{Element, Error, Result};
use crate::util::{Element, Error, Result, Perform};

use super::{CubeVec, MIN_SPEED, START_COAL, CubeDir, Team};
use super::{CubeVec, MIN_SPEED, START_COAL, CubeDir, Team, Accelerate};

/// A player's game piece.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Ship {
pub team: Team,
pub position: CubeVec,
pub direction: CubeDir,
pub speed: usize,
pub speed: i32,
pub coal: usize,
pub passengers: usize,
pub free_turns: usize,
Expand All @@ -34,11 +34,18 @@ impl Default for Ship {

impl Ship {
/// The movement reach of the ship, based on the speed.
pub fn movement(self) -> usize {
pub fn movement(self) -> i32 {
self.speed
}
}

impl Perform<Accelerate> for Ship {
/// Accelerates the ship.
fn perform(&mut self, acc: Accelerate) {
self.speed += acc.acc;
}
}

impl TryFrom<&Element> for Ship {
type Error = Error;

Expand Down
131 changes: 115 additions & 16 deletions src/game/state.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
//! Ported from https://github.com/software-challenge/backend/blob/be88340f619892fe70c4cbd45e131d5445e883c7/plugin/src/main/kotlin/sc/plugin2024/GameState.kt

use std::collections::VecDeque;

use arrayvec::ArrayVec;

use crate::util::{Element, Error, Result};
use crate::util::{Element, Error, Result, Perform};

use super::{Board, Move, Team, Ship, Turn, CubeVec, CubeDir, Push, Advance, AdvanceProblem, MAX_SPEED, Field, FREE_ACC, Accelerate, MIN_SPEED};
use super::{Board, Move, Team, Ship, Turn, CubeVec, CubeDir, Push, Advance, AdvanceProblem, MAX_SPEED, Field, FREE_ACC, Accelerate, MIN_SPEED, Action};

/// The state of the game at a point in time.
#[derive(Debug, Clone, PartialEq, Eq)]
Expand All @@ -25,24 +27,31 @@ pub struct State {

impl State {
/// Fetches the board.
#[inline]
pub fn board(&self) -> &Board { &self.board }

/// Fetches the turn of the game.
#[inline]
pub fn turn(&self) -> usize { self.turn }

/// Fetches the most recent move.
#[inline]
pub fn last_move(&self) -> Option<&Move> { self.last_move.as_ref() }

/// Fetches the starting team.
#[inline]
pub fn start_team(&self) -> Team { self.start_team }

/// The next team to make a move.
#[inline]
pub fn current_team(&self) -> Team { self.current_team }

/// The opposing team.
#[inline]
pub fn other_team(&self) -> Team { self.current_team.opponent() }

/// The ship for a team.
#[inline]
pub fn ship(&self, team: Team) -> Ship { self.ships[team.index()] }

/// The current team's ship.
Expand All @@ -64,6 +73,22 @@ impl State {
self.current_ship().position == self.other_ship().position
}

/// Fetches the possible actions for the current player at the given rank in the move.
pub fn possible_actions_at(&self, rank: i32) -> Vec<Action> {
let mut actions: Vec<Action> = Vec::new();

if rank == 0 {
actions.extend(self.possible_accelerations().into_iter().map(Action::Accelerate));
}
actions.extend(self.possible_turns().into_iter().map(Action::Turn));
actions.extend(self.possible_advances().into_iter().map(Action::Advance));
if rank != 0 {
actions.extend(self.possible_pushes().into_iter().map(Action::Push));
}

actions
}

/// Fetches the possible turn actions for the current player.
pub fn possible_turns(&self) -> Vec<Turn> {
self.possible_turns_with(self.current_ship().coal)
Expand Down Expand Up @@ -124,9 +149,9 @@ impl State {
}

let ship = self.current_ship();
return (1..=(max_coal + FREE_ACC) as i32)
return (1..=(max_coal as i32 + FREE_ACC))
.flat_map(|i| [i, -i])
.filter(|&i| if i > 0 { MAX_SPEED >= (ship.speed as i32 + i) as usize } else { MIN_SPEED <= (ship.speed as i32 - i) as usize })
.filter(|&i| if i > 0 { MAX_SPEED >= ship.speed + i } else { MIN_SPEED <= ship.speed - i })
.map(Accelerate::new)
.collect()
}
Expand Down Expand Up @@ -155,12 +180,12 @@ impl State {
}

/// Checks how far of an advancement in the given direction is possible.
fn advance_limit_with(&self, start: CubeVec, dir: CubeDir, max_movement: usize) -> AdvanceLimit {
fn advance_limit_with(&self, start: CubeVec, dir: CubeDir, max_movement: i32) -> AdvanceLimit {
let mut current_pos = start;
let mut total_cost = 0;
let mut has_current = false;
let max_movement = max_movement.min(MAX_SPEED);
let mut costs = Vec::with_capacity(max_movement);
let mut costs = Vec::new();

macro_rules! result {
($problem:expr) => {
Expand Down Expand Up @@ -215,26 +240,30 @@ impl State {
}

/// Fetches the possible moves.
pub fn possible_moves(&self) -> Vec<Move> {
todo!()
pub fn possible_moves(&self) -> MoveIterator {
let mut queue = VecDeque::new();
queue.push_back((self.clone(), Move::new()));
MoveIterator { queue }
}
}

/// Performs the given move.
pub fn perform(&mut self, m: Move) {
impl Perform<Action> for State {
/// Performs the given action.
fn perform(&mut self, action: Action) {
todo!()
}
}

/// Fetches the state after the given move.
pub fn child(&self, m: Move) -> Self {
let mut next = self.clone();
next.perform(m);
next
impl Perform<Move> for State {
/// Performs the given move.
fn perform(&mut self, m: Move) {
todo!()
}
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
struct AdvanceLimit {
costs: Vec<usize>,
costs: Vec<i32>,
problem: AdvanceProblem,
}

Expand All @@ -248,6 +277,76 @@ impl AdvanceLimit {
}
}

pub struct MoveIterator {
queue: VecDeque<(State, Move)>,
}

impl MoveIterator {
fn process(&mut self) -> Option<Move> {
if let Some((state, current_move)) = self.queue.pop_front() {
if !matches!(current_move.last(), Some(Action::Advance(_))) {
for adv in state.possible_advances() {
let adv = Action::Advance(adv);
let child_state = state.child(adv);
let child_move = current_move.child(adv);
let pushes = child_state.possible_pushes();
if pushes.is_empty() {
self.queue.push_back((child_state, child_move));
} else {
for push in pushes {
let push = Action::Push(push);
self.queue.push_back((child_state.child(push), child_move.child(push)));
}
}
}
}

if !matches!(current_move.last(), Some(Action::Turn(_))) {
for turn in state.possible_turns() {
let turn = Action::Turn(turn);
self.queue.push_back((state.child(turn), current_move.child(turn)));
}
}

if current_move.is_empty() {
for acc in state.possible_accelerations() {
let mut new_state = state.clone();
new_state.ships = state.ships.map(|s| {
if s.team == state.current_team() {
s.child(acc)
} else {
s
}
});
self.queue.push_back((new_state, Move::from(Action::Accelerate(acc))))
}
}

Some(current_move)
} else {
None
}
}

fn find_next(&mut self) {
while let Some((state, _)) = self.queue.pop_front() {
if state.current_ship().movement() == 0 {
break;
}
self.process();
}
}
}

impl Iterator for MoveIterator {
type Item = Move;

fn next(&mut self) -> Option<Move> {
self.find_next();
self.process()
}
}

impl TryFrom<&Element> for State {
type Error = Error;

Expand Down

0 comments on commit 18b0ccd

Please sign in to comment.