diff --git a/2022/Cargo.lock b/2022/Cargo.lock index 7d7bd32..a1ea46f 100644 --- a/2022/Cargo.lock +++ b/2022/Cargo.lock @@ -2,6 +2,15 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "aho-corasick" +version = "0.7.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +dependencies = [ + "memchr", +] + [[package]] name = "anyhow" version = "1.0.66" @@ -14,6 +23,7 @@ version = "0.1.0" dependencies = [ "anyhow", "itertools", + "regex", ] [[package]] @@ -30,3 +40,26 @@ checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" dependencies = [ "either", ] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "regex" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" diff --git a/2022/Cargo.toml b/2022/Cargo.toml index 0c7370c..c43c017 100644 --- a/2022/Cargo.toml +++ b/2022/Cargo.toml @@ -6,3 +6,4 @@ edition = "2021" [dependencies] anyhow = "1.0.66" itertools = "0.10.5" +regex = "1.7.0" diff --git a/2022/src/bin/day05.rs b/2022/src/bin/day05.rs new file mode 100644 index 0000000..22aa01c --- /dev/null +++ b/2022/src/bin/day05.rs @@ -0,0 +1,108 @@ +use regex::Regex; + +const INPUT: &str = include_str!("../../input/day05.txt"); + +fn main() { + println!("{}", part1(INPUT)); + println!("{}", part2(INPUT)); +} + +type Crate = String; + +type Stack = Vec; + +#[derive(Debug, Clone)] +struct Ship { + stacks: Vec, +} + +impl Ship { + fn parse(input: &str) -> Self { + let lines: Vec<&str> = input.trim().split('\n').rev().collect(); + + let mut ship = Ship { + stacks: (0..=8).map(|_| Vec::new()).collect(), + }; + + for line in &lines[1..] { + for stk in 0..=8 { + let i = 4 * stk + 1; + let contents = match line.get(i..i + 1) { + None => continue, + Some(" ") => continue, + Some(contents) => contents, + }; + ship.stacks[stk].push(contents.to_string()); + } + } + + ship + } + + fn do_move_1(&mut self, m: Move) { + for _ in 0..(m.count) { + let item = self.stacks[m.from].pop().expect("must have item"); + self.stacks[m.to].push(item); + } + } + + fn do_move_2(&mut self, m: Move) { + let src = &mut self.stacks[m.from]; + let items = src.split_off(src.len() - m.count); + self.stacks[m.to].extend(items.to_vec()); + } + + fn tops(&self) -> String { + let mut s = String::new(); + for stk in &self.stacks { + s += stk.last().unwrap(); + } + s + } +} + +#[derive(Debug, Copy, Clone)] +struct Move { + count: usize, + from: usize, + to: usize, +} + +impl Move { + fn parse(line: &str) -> Self { + let re = Regex::new(r"^move (\d+) from (\d+) to (\d+)$").unwrap(); + let caps = re.captures(line).unwrap(); + + Self { + count: caps[1].parse().unwrap(), + from: caps[2].parse::().unwrap() - 1, // zero-index + to: caps[3].parse::().unwrap() - 1, // zero-index + } + } +} + +fn part1(input: &str) -> String { + let sections: Vec<&str> = input.split("\n\n").collect(); + + let mut ship = Ship::parse(sections[0]); + let moves: Vec = sections[1].trim().split('\n').map(Move::parse).collect(); + + for m in moves { + ship.do_move_1(m); + } + + ship.tops() +} + +fn part2(input: &str) -> String { + let sections: Vec<&str> = input.split("\n\n").collect(); + + let mut ship = Ship::parse(sections[0]); + let moves: Vec = sections[1].trim().split('\n').map(Move::parse).collect(); + + for m in moves { + ship.do_move_2(m); + } + + ship.tops() +}