Skip to content

Commit

Permalink
Implement day08.
Browse files Browse the repository at this point in the history
  • Loading branch information
Oberacda committed Dec 10, 2023
1 parent 0a20cff commit 63b6e8c
Show file tree
Hide file tree
Showing 5 changed files with 151 additions and 25 deletions.
4 changes: 4 additions & 0 deletions day08/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,7 @@ name = "day08_part1"
name = "day08_part2"

[dependencies]
regex = "1.10.2"
anyhow = "1.0.75"
rayon = "1.8.0"
num = "0.4"
10 changes: 10 additions & 0 deletions day08/resources/test_input03.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
LR

11A = (11B, XXX)
11B = (XXX, 11Z)
11Z = (11B, XXX)
22A = (22B, XXX)
22B = (22C, 22C)
22C = (22Z, 22Z)
22Z = (22B, 22B)
XXX = (XXX, XXX)
24 changes: 15 additions & 9 deletions day08/src/bin/day08_part1.rs
Original file line number Diff line number Diff line change
@@ -1,34 +1,40 @@
use std::time::Instant;
use anyhow::Result;
use day08::{get_moves_to_solve, parse_input};

fn main() {
fn main() -> Result<()> {
let input = include_str!("../../resources/input.txt");
let now = Instant::now();
let map = parse_input(input);
let result = get_moves_to_solve(&map);
let map = parse_input(input)?;
let result = get_moves_to_solve(&map)?;
let elapsed = now.elapsed();
println!("Result: {}, Elapsed: {:?}", result, elapsed);
Ok(())
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn run_test_input_01() {
fn run_test_input_01() -> Result<()>{

let input = include_str!("../../resources/test_input01.txt");
let map = parse_input(input);
let result = get_moves_to_solve(&map);
let map = parse_input(input)?;
println!("Map: {:?}", map);
let result = get_moves_to_solve(&map)?;
assert_eq!(2, result);
Ok(())
}

#[test]
fn run_test_input_02() {
fn run_test_input_02() -> Result<()> {

let input = include_str!("../../resources/test_input02.txt");
let map = parse_input(input);
let result = get_moves_to_solve(&map);
let map = parse_input(input)?;
println!("Map: {:?}", map);
let result = get_moves_to_solve(&map)?;
assert_eq!(6, result);
Ok(())
}
}
24 changes: 20 additions & 4 deletions day08/src/bin/day08_part2.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,27 @@
use std::time::Instant;
use day08::{get_moves_to_solve, parse_input};
use anyhow::Result;
use day08::{get_moves_to_solve_ghost, parse_input};

fn main() {
fn main() -> Result<()> {
let input = include_str!("../../resources/input.txt");
let now = Instant::now();
let map = parse_input(input);
let result = get_moves_to_solve(&map);
let map = parse_input(input)?;
let result = get_moves_to_solve_ghost(&map)?;
let elapsed = now.elapsed();
println!("Result: {}, Elapsed: {:?}", result, elapsed);
Ok(())
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn run_test_input_03() -> Result<()>{
let input = include_str!("../../resources/test_input03.txt");
let map = parse_input(input)?;
let result = get_moves_to_solve_ghost(&map)?;
assert_eq!(6, result);
Ok(())
}
}
114 changes: 102 additions & 12 deletions day08/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,27 +1,117 @@
use std::collections::BTreeMap;
use std::collections::{BTreeMap};
use regex::Regex;
use anyhow::Result;
use std::fmt::Display;
use std::error::Error;
use std::fmt;
use rayon::prelude::*;

#[derive(Eq, PartialEq, Debug, Hash, Copy, Clone)]
pub enum Move {
R,
L
}

#[derive(Debug, Eq, PartialEq, Clone)]
pub struct Location {
left_id: String,
right_id: String
impl TryFrom<char> for Move {
type Error = ();

fn try_from(value: char) -> Result<Self, Self::Error> {
match value {
'R' => Ok(Self::R),
'L' => Ok(Self::L),
_ => Err(())
}
}
}

#[derive(Debug, Eq, PartialEq)]
pub struct Location<'a> {
left_id: & 'a str,
right_id: & 'a str
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Map {
#[derive(Debug, Eq, PartialEq)]
pub struct Map <'a> {
move_sequence: Vec<Move>,
locations: BTreeMap<String, Location>
locations: BTreeMap<& 'a str, Location<'a>>
}

#[derive(Debug, Eq, PartialEq)]
struct ParsingError;

impl Error for ParsingError {}

impl Display for ParsingError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Could not parse input for puzzle!")
}
}

pub fn parse_input(input: &str) -> Map {
todo!("Not Implemented!");
pub fn parse_input(input: &str) -> Result<Map> {
let mapping_re = Regex::new(r"^(?P<id>\w+)\s*=\s*\((?P<left>\w+),\s*(?P<right>\w+)\)$")?;
let mut lines_iter = input.lines();

let moves: Vec<Move>= lines_iter.next().ok_or(ParsingError {})?.chars().filter_map(|x| Move::try_from(x).ok()).collect();
lines_iter.next();
let mut locations = BTreeMap::new();
for line in lines_iter {
let location_line_matches = mapping_re.captures(line).ok_or(ParsingError {})?;
let id = location_line_matches.name("id").ok_or(ParsingError {})?.as_str();
let left = location_line_matches.name("left").ok_or(ParsingError {})?.as_str();
let right = location_line_matches.name("right").ok_or(ParsingError {})?.as_str();

locations.insert(id, Location {
left_id: left,
right_id: right
});
}
Ok(Map {
move_sequence: moves,
locations,
})
}

pub fn get_moves_to_solve(map: &Map) -> Result<u64> {
let mut moves_count = 0_u64;
let mut current_element_id = "AAA";
for map_move in map.move_sequence.iter().cycle() {
let current_location = map.locations.get(current_element_id).ok_or(ParsingError {})?;
current_element_id = match map_move {
Move::R => current_location.right_id,
Move::L => current_location.left_id
};
moves_count += 1;

if current_element_id.eq("ZZZ") {
break;
}
}
Ok(moves_count)
}

fn get_moves_from_location(map: &Map, start_location: &str) -> Option<u64> {
let mut moves_count= 0_u64;
let mut current_element_id = start_location;
for map_move in map.move_sequence.iter().cycle() {
current_element_id = match map.locations.get(current_element_id)
{
Some(current_location) => match map_move {
Move::R => current_location.right_id,
Move::L => current_location.left_id
},
None => return None
};
moves_count += 1;

if current_element_id.ends_with('Z') {
break;
}
}
Some(moves_count)
}

pub fn get_moves_to_solve(map: &Map) -> u64 {
todo!{"Not Implemented!"}
pub fn get_moves_to_solve_ghost(map: &Map) -> Result<u64> {
let moves_to_z_location: Vec<u64> = map.locations.par_iter().filter(|(id, _)| id.ends_with('A')).map(| (x, _)| *x).filter_map(|x| get_moves_from_location(&map, x)).collect();
let moves_count: u64 = moves_to_z_location.par_iter().cloned().reduce(|| 1_u64, |x, y| num::integer::lcm(x, y));
Ok(moves_count)
}

0 comments on commit 63b6e8c

Please sign in to comment.