2020: day12: impl direction rotation in direction

This commit is contained in:
Antoine Martin 2020-12-12 16:33:33 +01:00
parent 442f4621fb
commit 1f0eeb3b04

View file

@ -51,6 +51,46 @@ enum Direction {
West, West,
} }
impl Direction {
const CLOCKWISE_DIRECTIONS: &'static [Direction] = &[
Direction::North,
Direction::East,
Direction::South,
Direction::West,
];
fn rotate(self, turn_dir: TurnDirection, degrees: u16) -> Direction {
debug_assert!(degrees % 90 == 0, "only right angles are supported");
let quadrants = (degrees / 90) as usize;
let directions_iter = Self::CLOCKWISE_DIRECTIONS.iter().copied();
if turn_dir == TurnDirection::Left {
// go through cardinal directions the other way around, anti-clockwise
Self::find_direction(directions_iter.rev(), quadrants, self)
} else {
Self::find_direction(directions_iter, quadrants, self)
}
}
fn find_direction<I>(iter: I, quarters: usize, current_direction: Direction) -> Direction
where
I: Iterator<Item = Direction>,
I: std::clone::Clone,
{
iter
// this is litteraly a circle, reaching West and turning 90 degrees right means facing
// North again
.cycle()
// find our current ship direction
.skip_while(|dir| *dir != current_direction)
// skip as many quarters as needed
.nth(quarters)
// we can unwrap safely because we called .cycle() on a non empty iterator
.unwrap()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum TurnDirection { enum TurnDirection {
Left, Left,
@ -127,53 +167,16 @@ impl Ship {
} }
} }
const CLOCKWISE_DIRECTIONS: &'static [Direction] = &[
Direction::North,
Direction::East,
Direction::South,
Direction::West,
];
fn manhattan_distance(&self) -> i64 { fn manhattan_distance(&self) -> i64 {
self.x.abs() + self.y.abs() self.x.abs() + self.y.abs()
} }
fn find_direction<I>(iter: I, quarters: usize, current_direction: Direction) -> Direction
where
I: Iterator<Item = Direction>,
I: std::clone::Clone,
{
iter
// this is litteraly a circle, reaching West and turning 90 degrees right means
// facing North again
.cycle()
// find our current ship direction
.skip_while(|dir| *dir != current_direction)
// skip as many quarters as needed
.nth(quarters)
// we can unwrap safely because we called .cycle() on a non empty iterator
.unwrap()
}
fn process(&mut self, action: Action) { fn process(&mut self, action: Action) {
match action.kind { match action.kind {
ActionKind::Move(dir) => self.forward(dir, action.arg), ActionKind::Move(dir) => self.forward(dir, action.arg),
ActionKind::Turn(turn_dir) => { ActionKind::Turn(turn_dir) => {
debug_assert!(action.arg % 90 == 0, "only right angles are supported"); self.direction = self.direction.rotate(turn_dir, action.arg);
let quarters = (action.arg / 90) as usize;
let directions_iter = Self::CLOCKWISE_DIRECTIONS.iter().copied();
let new_dir = if turn_dir == TurnDirection::Left {
// go through cardinal directions the other way around, anti-clockwise
Ship::find_direction(directions_iter.rev(), quarters, self.direction)
} else {
Ship::find_direction(directions_iter, quarters, self.direction)
};
self.direction = new_dir;
} }
ActionKind::Forward => self.forward(self.direction, action.arg), ActionKind::Forward => self.forward(self.direction, action.arg),