Skip to content

Commit

Permalink
Extract action from move and fix format
Browse files Browse the repository at this point in the history
  • Loading branch information
fwcd committed Sep 5, 2023
1 parent 8b0b992 commit 1ba42fb
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 65 deletions.
93 changes: 93 additions & 0 deletions src/game/action.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
//! Ported from https://github.com/software-challenge/backend/blob/be88340f619892fe70c4cbd45e131d5445e883c7/plugin/src/main/kotlin/sc/plugin2024/actions

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

use super::CubeDir;

/// An action to take during a move.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum Action {
/// Acceleration by the given amount.
Accelerate {
/// The amount to accelerate by. May be negative, but not zero.
acc: i32
},
/// Advancement in the direction of movement.
Advance {
/// The number of fields to move.
distance: usize,
},
/// Nudging another ship.
Push {
/// The direction to nudge in.
direction: CubeDir,
},
/// A turn of the ship.
Turn {
/// The direction to turn into.
direction: CubeDir,
},
}

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

fn try_from(elem: &Element) -> Result<Self> {
match elem.attribute("class")? {
"acceleration" => Ok(Self::Accelerate { acc: elem.attribute("acc")?.parse()? }),
"advance" => Ok(Self::Advance { distance: elem.attribute("distance")?.parse()? }),
"push" => Ok(Self::Push { direction: elem.attribute("direction")?.parse()? }),
"turn" => Ok(Self::Turn { direction: elem.attribute("direction")?.parse()? }),
class => Err(Error::UnknownVariant(format!("Unknown move class: {}", class))),
}
}
}

impl From<Action> for Element {
fn from(m: Action) -> Self {
let base = Element::new("data");
match m {
Action::Accelerate { acc } => base
.attribute("class", "acceleration")
.attribute("acc", acc)
.build(),
Action::Advance { distance } => base
.attribute("class", "advance")
.attribute("distance", distance)
.build(),
Action::Push { direction } => base
.attribute("class", "push")
.attribute("direction", direction)
.build(),
Action::Turn { direction } => base
.attribute("class", "turn")
.attribute("direction", direction)
.build(),
}
}
}

#[cfg(test)]
mod tests {
use crate::{util::assert_xml_format, game::{Action, CubeDir}};

// TODO: Add parse and/or roundtrip tests

#[test]
fn test_to_xml() {
assert_xml_format!(
Action::Accelerate { acc: -2 },
r#"<acceleration acc="-2" />"#
);

assert_xml_format!(
Action::Advance { distance: 10 },
r#"<advance distance="10" />"#
);

assert_xml_format!(
Action::Push { direction: CubeDir::Left },
r#"<push direction="LEFT" />"#
);
}
}
2 changes: 2 additions & 0 deletions src/game/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
mod action;
mod board;
mod constants;
mod dir;
Expand All @@ -9,6 +10,7 @@ mod state;
mod team;
mod vec;

pub use action::*;
pub use board::*;
pub use constants::*;
pub use dir::*;
Expand Down
96 changes: 34 additions & 62 deletions src/game/move.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,92 +2,64 @@

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

use super::CubeDir;
use super::Action;

/// A game move.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum Move {
/// Acceleration by the given amount.
Accelerate {
/// The amount to accelerate by. May be negative, but not zero.
acc: i32
},
/// Advancement in the direction of movement.
Advance {
/// The number of fields to move.
distance: usize,
},
/// Nudging another ship.
Push {
/// The direction to nudge in.
direction: CubeDir,
},
/// A turn of the ship.
Turn {
/// The direction to turn into.
direction: CubeDir,
},
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Move {
pub actions: Vec<Action>,
}

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

fn try_from(elem: &Element) -> Result<Self> {
match elem.attribute("class")? {
"acceleration" => Ok(Self::Accelerate { acc: elem.attribute("acc")?.parse()? }),
"advance" => Ok(Self::Advance { distance: elem.attribute("distance")?.parse()? }),
"push" => Ok(Self::Push { direction: elem.attribute("direction")?.parse()? }),
"turn" => Ok(Self::Turn { direction: elem.attribute("direction")?.parse()? }),
class => Err(Error::UnknownVariant(format!("Unknown move class: {}", class))),
}
Ok(Self {
actions: elem.child_by_name("actions")?
.childs()
.map(Action::try_from)
.collect::<Result<Vec<_>>>()?
})
}
}

impl From<Move> for Element {
fn from(m: Move) -> Self {
let base = Element::new("move");
match m {
Move::Accelerate { acc } => base
.attribute("class", "acceleration")
.attribute("acc", acc)
.build(),
Move::Advance { distance } => base
.attribute("class", "advance")
.attribute("distance", distance)
.build(),
Move::Push { direction } => base
.attribute("class", "push")
.attribute("direction", direction)
.build(),
Move::Turn { direction } => base
.attribute("class", "turn")
.attribute("direction", direction)
.build(),
}
Element::new("data")
.attribute("class", "move")
.child(Element::new("actions")
.childs(m.actions.into_iter().map(Element::from)))
.build()
}
}

#[cfg(test)]
mod tests {
use crate::{util::assert_xml_format, game::{Move, CubeDir}};
use indoc::indoc;

use crate::{util::assert_xml_format, game::{Move, CubeDir, Action}};

// TODO: Add parse and/or roundtrip tests

#[test]
fn test_to_xml() {
assert_xml_format!(
Move::Accelerate { acc: -2 },
r#"<move class="acceleration" acc="-2" />"#
);

assert_xml_format!(
Move::Advance { distance: 10 },
r#"<move class="advance" distance="10" />"#
);

assert_xml_format!(
Move::Push { direction: CubeDir::Left },
r#"<move class="push" direction="LEFT" />"#
Move {
actions: vec![
Action::Accelerate { acc: -1 },
Action::Turn { direction: CubeDir::DownRight },
Action::Advance { distance: 2 },
]
},
indoc! {r#"
<data class="move">
<actions>
<acceleration acc="-1"/>
<turn direction="DOWN_RIGHT"/>
<advance distance="2"/>
</actions>
</data>
"#}
);
}
}
2 changes: 1 addition & 1 deletion src/game/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ impl State {
pub fn turn(&self) -> usize { self.turn }

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

/// Fetches the starting team.
pub fn start_team(&self) -> Team { self.start_team }
Expand Down
5 changes: 3 additions & 2 deletions src/logic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ pub struct OwnLogic;
impl GameClientDelegate for OwnLogic {
fn request_move(&mut self, state: &State, _my_team: Team) -> Move {
info!("Requested move");
let chosen_move = *state.possible_moves()
let chosen_move = state.possible_moves()
.choose(&mut rand::thread_rng())
.expect("No move found!");
.expect("No move found!")
.clone();
info!("Chose move {:?}", chosen_move);
chosen_move
}
Expand Down

0 comments on commit 1ba42fb

Please sign in to comment.