Complete day 12.1
This commit is contained in:
parent
0355eeccb4
commit
c0a6391e85
4 changed files with 1020 additions and 0 deletions
day-12/src
161
day-12/src/main.rs
Normal file
161
day-12/src/main.rs
Normal file
|
@ -0,0 +1,161 @@
|
|||
use std::fs;
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let input = fs::read_to_string("input")?;
|
||||
let actions = parse_actions(&input)?;
|
||||
|
||||
// Part 1
|
||||
let location = simulate_ship_movement(&actions);
|
||||
println!("{}", location.0.abs() + location.1.abs());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
enum Action {
|
||||
North(u32),
|
||||
South(u32),
|
||||
East(u32),
|
||||
West(u32),
|
||||
Left(u32),
|
||||
Right(u32),
|
||||
Forward(u32),
|
||||
}
|
||||
|
||||
impl Action {
|
||||
fn new(input: &str) -> Result<Self, String> {
|
||||
if input.len() < 2 {
|
||||
Err(format!("Invalud input line: {}", input))?;
|
||||
}
|
||||
|
||||
let (action, value) = input.split_at(1);
|
||||
let value = value
|
||||
.parse()
|
||||
.map_err(|e| format!("Could not parse value: {}", e))?;
|
||||
|
||||
Ok(match action {
|
||||
"N" => Self::North(value),
|
||||
"S" => Self::South(value),
|
||||
"E" => Self::East(value),
|
||||
"W" => Self::West(value),
|
||||
"L" => Self::Left(value),
|
||||
"R" => Self::Right(value),
|
||||
"F" => Self::Forward(value),
|
||||
_ => Err(format!("Could not parse action: {}", action))?,
|
||||
})
|
||||
}
|
||||
|
||||
fn opposite_direction(self) -> Self {
|
||||
match self {
|
||||
Action::North(x) => Action::South(x),
|
||||
Action::South(x) => Action::North(x),
|
||||
Action::East(x) => Action::West(x),
|
||||
Action::West(x) => Action::East(x),
|
||||
_ => panic!("Invalid direction"),
|
||||
}
|
||||
}
|
||||
|
||||
fn right_direction(self) -> Self {
|
||||
match self {
|
||||
Action::North(x) => Action::East(x),
|
||||
Action::South(x) => Action::West(x),
|
||||
Action::East(x) => Action::South(x),
|
||||
Action::West(x) => Action::North(x),
|
||||
_ => panic!("Invalid direction"),
|
||||
}
|
||||
}
|
||||
|
||||
fn left_direction(self) -> Self {
|
||||
match self {
|
||||
Action::North(x) => Action::West(x),
|
||||
Action::South(x) => Action::East(x),
|
||||
Action::East(x) => Action::North(x),
|
||||
Action::West(x) => Action::South(x),
|
||||
_ => panic!("Invalid direction"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_actions(input: &str) -> Result<Vec<Action>, String> {
|
||||
input.lines().map(Action::new).collect()
|
||||
}
|
||||
|
||||
fn simulate_ship_movement(actions: &Vec<Action>) -> (i64, i64) {
|
||||
let mut coords: (i64, i64) = (0, 0);
|
||||
let mut direction = Action::East(0);
|
||||
|
||||
for action in actions {
|
||||
// If the action is Action::Forward, we instead want to move
|
||||
// in a direction determined by our current angle.
|
||||
//
|
||||
// So we convert Action::Forward to a concrete direction.
|
||||
|
||||
let converted_action = if let &Action::Forward(amount) = action {
|
||||
match direction {
|
||||
Action::North(_) => Action::North(amount),
|
||||
Action::South(_) => Action::South(amount),
|
||||
Action::East(_) => Action::East(amount),
|
||||
Action::West(_) => Action::West(amount),
|
||||
_ => unreachable!("Direction can only be NSEW."),
|
||||
}
|
||||
} else {
|
||||
*action
|
||||
};
|
||||
|
||||
match converted_action {
|
||||
Action::North(amount) => {
|
||||
coords.1 += amount as i64;
|
||||
}
|
||||
Action::South(amount) => {
|
||||
coords.1 -= amount as i64;
|
||||
}
|
||||
Action::East(amount) => {
|
||||
coords.0 += amount as i64;
|
||||
}
|
||||
Action::West(amount) => {
|
||||
coords.0 -= amount as i64;
|
||||
}
|
||||
Action::Left(amount) => match amount % 360 {
|
||||
0 => direction = direction,
|
||||
90 => direction = direction.left_direction(),
|
||||
180 => direction = direction.opposite_direction(),
|
||||
270 => direction = direction.right_direction(),
|
||||
_ => panic!("Only 90 degree turns allowed"),
|
||||
},
|
||||
Action::Right(amount) => match amount % 360 {
|
||||
0 => direction = direction,
|
||||
90 => direction = direction.right_direction(),
|
||||
180 => direction = direction.opposite_direction(),
|
||||
270 => direction = direction.left_direction(),
|
||||
_ => panic!("Only 90 degree turns allowed"),
|
||||
},
|
||||
Action::Forward(_) => unreachable!("Converted previously"),
|
||||
}
|
||||
}
|
||||
|
||||
coords
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use indoc::indoc;
|
||||
|
||||
#[test]
|
||||
fn test_simple() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let input = indoc!(
|
||||
"F10
|
||||
N3
|
||||
F7
|
||||
R90
|
||||
F11
|
||||
"
|
||||
);
|
||||
|
||||
let actions = parse_actions(&input)?;
|
||||
let location = simulate_ship_movement(&actions);
|
||||
assert_eq!(location.0.abs() + location.1.abs(), 25);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue