diff options
author | June McEnroe <june@causal.agency> | 2017-11-27 17:11:18 -0500 |
---|---|---|
committer | June McEnroe <june@causal.agency> | 2020-11-22 00:14:25 -0500 |
commit | 051be932a389b8bc3ea5d4626575454844639066 (patch) | |
tree | 9383502b3205624f7aee8faa014228036b5450f9 /src/bin | |
parent | License ISC (diff) | |
download | aoc-051be932a389b8bc3ea5d4626575454844639066.tar.gz aoc-051be932a389b8bc3ea5d4626575454844639066.zip |
Move to 2016 directory
Diffstat (limited to 'src/bin')
-rw-r--r-- | src/bin/day01.rs | 78 | ||||
-rw-r--r-- | src/bin/day02.rs | 156 | ||||
-rw-r--r-- | src/bin/day03.rs | 62 | ||||
-rw-r--r-- | src/bin/day04.rs | 123 | ||||
-rw-r--r-- | src/bin/day05.rs | 71 | ||||
-rw-r--r-- | src/bin/day06.rs | 87 | ||||
-rw-r--r-- | src/bin/day07.rs | 119 | ||||
-rw-r--r-- | src/bin/day08.rs | 148 | ||||
-rw-r--r-- | src/bin/day09.rs | 124 | ||||
-rw-r--r-- | src/bin/day10.rs | 180 | ||||
-rw-r--r-- | src/bin/day11.rs | 194 | ||||
-rw-r--r-- | src/bin/day12.rs | 143 | ||||
-rw-r--r-- | src/bin/day13.rs | 122 | ||||
-rw-r--r-- | src/bin/day14.rs | 87 | ||||
-rw-r--r-- | src/bin/day15.rs | 103 | ||||
-rw-r--r-- | src/bin/day16.rs | 51 | ||||
-rw-r--r-- | src/bin/day17.rs | 148 | ||||
-rw-r--r-- | src/bin/day18.rs | 88 | ||||
-rw-r--r-- | src/bin/day19.rs | 35 | ||||
-rw-r--r-- | src/bin/day20.rs | 77 | ||||
-rw-r--r-- | src/bin/day21.rs | 144 | ||||
-rw-r--r-- | src/bin/day23.rs | 157 | ||||
-rw-r--r-- | src/bin/day25.rs | 163 |
23 files changed, 0 insertions, 2660 deletions
diff --git a/src/bin/day01.rs b/src/bin/day01.rs deleted file mode 100644 index c596099..0000000 --- a/src/bin/day01.rs +++ /dev/null @@ -1,78 +0,0 @@ -use std::collections::HashSet; -use std::io::{self, Read}; -use std::ops::Add; - -#[derive(Clone, Copy, PartialEq, Eq, Hash)] -struct Point(i32, i32); - -impl Point { - fn left(self) -> Self { - Point(self.1, -self.0) - } - - fn right(self) -> Self { - Point(-self.1, self.0) - } - - fn distance(self) -> i32 { - self.0.abs() + self.1.abs() - } -} - -impl Add for Point { - type Output = Self; - - fn add(self, rhs: Self) -> Self { - Point(self.0 + rhs.0, self.1 + rhs.1) - } -} - -fn solve(input: &str) -> (i32, Option<i32>) { - let mut position = Point(0, 0); - let mut direction = Point(0, -1); - let mut visited = HashSet::new(); - let mut collision = None; - - for instruction in input.trim().split(", ") { - let (turn, count) = instruction.split_at(1); - - if turn == "L" { - direction = direction.left(); - } else { - direction = direction.right(); - } - - let count: i32 = count.parse().unwrap(); - for _ in 0..count { - position = position + direction; - if collision.is_none() && !visited.insert(position) { - collision = Some(position); - } - } - } - - (position.distance(), collision.map(Point::distance)) -} - -fn main() { - let mut input = String::new(); - io::stdin().read_to_string(&mut input).unwrap(); - - let (part1, part2) = solve(&input); - println!("Part 1: {}", part1); - if let Some(part2) = part2 { - println!("Part 2: {}", part2); - } -} - -#[test] -fn part1() { - assert_eq!(5, solve("R2, L3").0); - assert_eq!(2, solve("R2, R2, R2").0); - assert_eq!(12, solve("R5, L5, R5, R3").0); -} - -#[test] -fn part2() { - assert_eq!(Some(4), solve("R8, R4, R4, R8").1); -} diff --git a/src/bin/day02.rs b/src/bin/day02.rs deleted file mode 100644 index f7cc624..0000000 --- a/src/bin/day02.rs +++ /dev/null @@ -1,156 +0,0 @@ -use std::io::{self, Read}; - -trait Pad: Copy + Default { - fn up(self) -> Self; - fn down(self) -> Self; - fn left(self) -> Self; - fn right(self) -> Self; -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -enum Keypad { - K1, K2, K3, - K4, K5, K6, - K7, K8, K9, -} - -impl Default for Keypad { - fn default() -> Self { Keypad::K5 } -} - -impl Pad for Keypad { - fn up(self) -> Self { - use Keypad::*; - match self { - K4 => K1, K5 => K2, K6 => K3, - K7 => K4, K8 => K5, K9 => K6, - _ => self, - } - } - - fn down(self) -> Self { - use Keypad::*; - match self { - K1 => K4, K2 => K5, K3 => K6, - K4 => K7, K5 => K8, K6 => K9, - _ => self, - } - } - - fn left(self) -> Self { - use Keypad::*; - match self { - K2 => K1, K3 => K2, - K5 => K4, K6 => K5, - K8 => K7, K9 => K8, - _ => self, - } - } - - fn right(self) -> Self { - use Keypad::*; - match self { - K1 => K2, K2 => K3, - K4 => K5, K5 => K6, - K7 => K8, K8 => K9, - _ => self, - } - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -enum Wackypad { - K1, - K2, K3, K4, - K5, K6, K7, K8, K9, - KA, KB, KC, - KD, -} - -impl Default for Wackypad { - fn default() -> Self { Wackypad::K5 } -} - -impl Pad for Wackypad { - fn up(self) -> Self { - use Wackypad::*; - match self { - K3 => K1, - K6 => K2, K7 => K3, K8 => K4, - KA => K6, KB => K7, KC => K8, - KD => KB, - _ => self, - } - } - - fn down(self) -> Self { - use Wackypad::*; - match self { - K1 => K3, - K2 => K6, K3 => K7, K4 => K8, - K6 => KA, K7 => KB, K8 => KC, - KB => KD, - _ => self, - } - } - - fn left(self) -> Self { - use Wackypad::*; - match self { - K3 => K2, K4 => K3, - K6 => K5, K7 => K6, K8 => K7, K9 => K8, - KB => KA, KC => KB, - _ => self, - } - } - - fn right(self) -> Self { - use Wackypad::*; - match self { - K2 => K3, K3 => K4, - K5 => K6, K6 => K7, K7 => K8, K8 => K9, - KA => KB, KB => KC, - _ => self, - } - } -} - -fn solve<P: Pad>(input: &str) -> Vec<P> { - let mut code = Vec::new(); - let mut key = P::default(); - - for line in input.lines() { - for direction in line.chars() { - key = match direction { - 'U' => key.up(), - 'D' => key.down(), - 'L' => key.left(), - 'R' => key.right(), - _ => panic!("{} is not a direction", direction), - } - } - code.push(key); - } - - code -} - -fn main() { - let mut input = String::new(); - io::stdin().read_to_string(&mut input).unwrap(); - - println!("Part 1: {:?}", solve::<Keypad>(&input)); - println!("Part 2: {:?}", solve::<Wackypad>(&input)); -} - -#[test] -fn part1() { - use Keypad::*; - assert_eq!(vec![K1, K9, K8, K5], solve("ULL\nRRDDD\nLURDL\nUUUUD")); -} - -#[test] -fn part2() { - use Wackypad::*; - assert_eq!(vec![K5, KD, KB, K3], solve("ULL\nRRDDD\nLURDL\nUUUUD")); -} diff --git a/src/bin/day03.rs b/src/bin/day03.rs deleted file mode 100644 index 76b5aa5..0000000 --- a/src/bin/day03.rs +++ /dev/null @@ -1,62 +0,0 @@ -use std::io::{self, Read}; -use std::str::FromStr; - -struct Triangle(u32, u32, u32); - -impl Triangle { - fn valid(&self) -> bool { - self.0 + self.1 > self.2 - && self.1 + self.2 > self.0 - && self.0 + self.2 > self.1 - } -} - -impl FromStr for Triangle { - type Err = (); - fn from_str(s: &str) -> Result<Self, ()> { - let mut iter = s.split_whitespace().map(str::parse); - match (iter.next(), iter.next(), iter.next()) { - (Some(Ok(a)), Some(Ok(b)), Some(Ok(c))) => Ok(Triangle(a, b, c)), - _ => Err(()), - } - } -} - -fn solve1(input: &str) -> usize { - input.lines() - .map(str::parse) - .map(Result::unwrap) - .filter(Triangle::valid) - .count() -} - -fn solve2(input: &str) -> usize { - let triangles: Vec<Triangle> = input.lines() - .map(str::parse) - .map(Result::unwrap) - .collect(); - - triangles.chunks(3) - .flat_map(|triple| { - vec![ - Triangle(triple[0].0, triple[1].0, triple[2].0), - Triangle(triple[0].1, triple[1].1, triple[2].1), - Triangle(triple[0].2, triple[1].2, triple[2].2), - ] - }) - .filter(Triangle::valid) - .count() -} - -fn main() { - let mut input = String::new(); - io::stdin().read_to_string(&mut input).unwrap(); - - println!("Part 1: {}", solve1(&input)); - println!("Part 2: {}", solve2(&input)); -} - -#[test] -fn part1() { - assert_eq!(0, solve1("5 10 25")); -} diff --git a/src/bin/day04.rs b/src/bin/day04.rs deleted file mode 100644 index 8e724c2..0000000 --- a/src/bin/day04.rs +++ /dev/null @@ -1,123 +0,0 @@ -use std::io::{self, Read}; -use std::str::FromStr; - -struct Room { - name: String, - sector_id: u32, - checksum: String, -} - -impl FromStr for Room { - type Err = (); - fn from_str(s: &str) -> Result<Self, ()> { - let mut iter = s.trim_right_matches(']') - .rsplitn(3, |c| c == '-' || c == '['); - - let checksum = iter.next().ok_or(())?; - let sector_id = iter.next().ok_or(())?; - let name = iter.next().ok_or(())?; - - Ok(Room { - name: name.into(), - sector_id: sector_id.parse().map_err(|_| ())?, - checksum: checksum.into(), - }) - } -} - -impl Room { - fn checksum(&self) -> String { - let mut letters = [ - (0, 'a'), (0, 'b'), (0, 'c'), (0, 'd'), (0, 'e'), (0, 'f'), (0, 'g'), (0, 'h'), - (0, 'i'), (0, 'j'), (0, 'k'), (0, 'l'), (0, 'm'), (0, 'n'), (0, 'o'), (0, 'p'), - (0, 'q'), (0, 'r'), (0, 's'), (0, 't'), (0, 'u'), (0, 'v'), (0, 'w'), (0, 'x'), - (0, 'y'), (0, 'z'), - ]; - - for letter in self.name.chars().filter(|c| c.is_alphabetic()) { - let index = letter as u8 - b'a'; - letters[index as usize].0 -= 1; - } - - letters.sort(); - - letters.into_iter() - .map(|l| l.1) - .take(5) - .collect() - } - - fn verify_checksum(&self) -> bool { - self.checksum == self.checksum() - } - - fn decrypt_name(&self) -> String { - self.name.chars() - .map(|c| { - match c { - '-' => ' ', - _ => rotate(c, self.sector_id), - } - }) - .collect() - } -} - -fn rotate(c: char, n: u32) -> char { - let c = c as u8 + (n % 26) as u8; - if c > b'z' { - (c - 26) as char - } else { - c as char - } -} - -fn solve1(input: &str) -> u32 { - input.lines() - .map(str::parse) - .map(Result::unwrap) - .filter(Room::verify_checksum) - .map(|room| room.sector_id) - .sum() -} - -fn solve2(input: &str) -> Option<u32> { - input.lines() - .map(str::parse) - .map(Result::unwrap) - .filter(Room::verify_checksum) - .filter_map(|r| { - match r.decrypt_name().as_str() { - "northpole object storage" => Some(r.sector_id), - _ => None, - } - }) - .next() -} - -fn main() { - let mut input = String::new(); - io::stdin().read_to_string(&mut input).unwrap(); - - println!("Part 1: {}", solve1(&input)); - if let Some(sector_id) = solve2(&input) { - println!("Part 2: {}", sector_id); - } -} - -#[test] -fn part1() { - let input = " -aaaaa-bbb-z-y-x-123[abxyz] -a-b-c-d-e-f-g-h-987[abcde] -not-a-real-room-404[oarel] -totally-real-room-200[decoy] -"; - assert_eq!(1514, solve1(&input[1..])); -} - -#[test] -fn part2() { - let room: Room = "qzmt-zixmtkozy-ivhz-343[zimth]".parse().unwrap(); - assert_eq!("very encrypted name", room.decrypt_name()); -} diff --git a/src/bin/day05.rs b/src/bin/day05.rs deleted file mode 100644 index eefa3df..0000000 --- a/src/bin/day05.rs +++ /dev/null @@ -1,71 +0,0 @@ -extern crate crypto; - -use std::io::{self, Read}; - -use crypto::digest::Digest; -use crypto::md5::Md5; - -fn solve1(input: &str) -> String { - let mut password = String::new(); - let mut index = 0u64; - - while password.len() < 8 { - let mut md5 = Md5::new(); - md5.input_str(input); - md5.input_str(&index.to_string()); - let digest = md5.result_str(); - - if &digest[0..5] == "00000" { - password.push_str(&digest[5..6]); - } - - index += 1; - } - - password -} - -fn solve2(input: &str) -> String { - let mut password = [None; 8]; - let mut index = 0u64; - - while !password.iter().all(Option::is_some) { - let mut md5 = Md5::new(); - md5.input_str(input); - md5.input_str(&index.to_string()); - let digest = md5.result_str(); - - if &digest[0..5] == "00000" { - if let Some(pos @ 0 ... 7) = digest[5..6].parse().ok() { - password[pos] = password[pos].or(digest[6..7].chars().next()); - } - } - - index += 1; - } - - password.iter() - .cloned() - .map(Option::unwrap) - .collect() -} - -fn main() { - let mut input = String::new(); - io::stdin().read_to_string(&mut input).unwrap(); - - println!("Part 1: {}", solve1(input.trim())); - println!("Part 2: {}", solve2(input.trim())); -} - -#[test] -#[ignore] -fn part1() { - assert_eq!("18f47a30", solve1("abc")); -} - -#[test] -#[ignore] -fn part2() { - assert_eq!("05ace8e3", solve2("abc")); -} diff --git a/src/bin/day06.rs b/src/bin/day06.rs deleted file mode 100644 index 7f8a516..0000000 --- a/src/bin/day06.rs +++ /dev/null @@ -1,87 +0,0 @@ -use std::collections::HashMap; -use std::io::{self, Read}; - -fn frequencies(chars: &[char]) -> HashMap<char, u32> { - let mut map = HashMap::new(); - for &ch in chars { - *map.entry(ch).or_insert(0) += 1; - } - map -} - -fn solve1(input: &str) -> String { - let len = input.find('\n').unwrap_or(input.len()); - let mut columns = vec![Vec::new(); len]; - - for line in input.lines() { - for (i, ch) in line.chars().enumerate() { - columns[i].push(ch); - } - } - - columns.into_iter() - .map(|column| frequencies(&column)) - .map(IntoIterator::into_iter) - .map(|iter| iter.max_by_key(|&(_, v)| v)) - .map(Option::unwrap) - .map(|(ch, _)| ch) - .collect() -} - -fn solve2(input: &str) -> String { - let len = input.find('\n').unwrap_or(input.len()); - let mut columns = vec![Vec::new(); len]; - - for line in input.lines() { - for (i, ch) in line.chars().enumerate() { - columns[i].push(ch); - } - } - - columns.into_iter() - .map(|column| frequencies(&column)) - .map(IntoIterator::into_iter) - .map(|iter| iter.min_by_key(|&(_, v)| v)) - .map(Option::unwrap) - .map(|(ch, _)| ch) - .collect() -} - -fn main() { - let mut input = String::new(); - io::stdin().read_to_string(&mut input).unwrap(); - - println!("Part 1: {}", solve1(&input)); - println!("Part 2: {}", solve2(&input)); -} - -#[cfg(test)] -const TEST_INPUT: &'static str = " -eedadn -drvtee -eandsr -raavrd -atevrs -tsrnev -sdttsa -rasrtv -nssdts -ntnada -svetve -tesnvt -vntsnd -vrdear -dvrsen -enarar -"; - - -#[test] -fn part1() { - assert_eq!("easter", solve1(TEST_INPUT.trim())); -} - -#[test] -fn part2() { - assert_eq!("advent", solve2(TEST_INPUT.trim())); -} diff --git a/src/bin/day07.rs b/src/bin/day07.rs deleted file mode 100644 index b4967ff..0000000 --- a/src/bin/day07.rs +++ /dev/null @@ -1,119 +0,0 @@ -use std::io::{self, Read}; -use std::str::FromStr; - -fn has_abba(s: &str) -> bool { - s.as_bytes() - .windows(4) - .any(|window| { - window[0] == window[3] - && window[1] == window[2] - && window[0] != window[1] - }) -} - -fn abas(s: &str) -> Vec<&[u8]> { - s.as_bytes() - .windows(3) - .filter(|window| { - window[0] == window[2] - && window[0] != window[1] - }) - .collect() -} - -fn has_bab(s: &str, aba: &[u8]) -> bool { - s.as_bytes() - .windows(3) - .any(|window| { - window[0] == aba[1] - && window[1] == aba[0] - && window[2] == aba[1] - }) -} - -#[derive(Default)] -struct Ip { - supernet: Vec<String>, - hypernet: Vec<String>, -} - -impl Ip { - fn supports_tls(&self) -> bool { - self.supernet.iter().any(|s| has_abba(s)) - && !self.hypernet.iter().any(|s| has_abba(s)) - } - - fn supports_ssl(&self) -> bool { - self.supernet - .iter() - .flat_map(|s| abas(s)) - .any(|aba| { - self.hypernet - .iter() - .any(|s| has_bab(s, aba)) - }) - } -} - -impl FromStr for Ip { - type Err = (); - fn from_str(s: &str) -> Result<Ip, ()> { - let mut ip = Ip::default(); - - for (i, seq) in s.split(|ch| ch == '[' || ch == ']').enumerate() { - if i % 2 == 0 { - ip.supernet.push(seq.to_owned()); - } else { - ip.hypernet.push(seq.to_owned()); - } - } - - Ok(ip) - } -} - -fn solve1(input: &str) -> usize { - input.lines() - .map(str::parse) - .map(Result::unwrap) - .filter(Ip::supports_tls) - .count() -} - -fn solve2(input: &str) -> usize { - input.lines() - .map(str::parse) - .map(Result::unwrap) - .filter(Ip::supports_ssl) - .count() -} - -fn main() { - let mut input = String::new(); - io::stdin().read_to_string(&mut input).unwrap(); - - println!("Part 1: {}", solve1(&input)); - println!("Part 2: {}", solve2(&input)); -} - -#[test] -fn part1() { - let input = " -abba[mnop]qrst -abcd[bddb]xyyx -aaaa[qwer]tyui -ioxxoj[asdfgh]zxcvbn -"; - assert_eq!(2, solve1(input.trim())); -} - -#[test] -fn part2() { - let input = " -aba[bab]xyz -xyx[xyx]xyx -aaa[kek]eke -zazbz[bzb]cdb -"; - assert_eq!(3, solve2(input.trim())); -} diff --git a/src/bin/day08.rs b/src/bin/day08.rs deleted file mode 100644 index 1443ec3..0000000 --- a/src/bin/day08.rs +++ /dev/null @@ -1,148 +0,0 @@ -use std::fmt::{Display as FmtDisplay, Error as FmtError, Formatter}; -use std::io::{self, Read}; -use std::ops::{Index, IndexMut}; -use std::str::FromStr; - -enum Operation { - Rect(usize, usize), - RotateRow(usize, usize), - RotateColumn(usize, usize), -} - -impl FromStr for Operation { - type Err = (); - fn from_str(s: &str) -> Result<Self, ()> { - if s.starts_with("rect") { - let mut iter = s[5..].split('x'); - let width = iter.next().ok_or(())?.parse().map_err(|_| ())?; - let height = iter.next().ok_or(())?.parse().map_err(|_| ())?; - Ok(Operation::Rect(width, height)) - - } else if s.starts_with("rotate row") { - let mut iter = s[13..].split(" by "); - let y = iter.next().ok_or(())?.parse().map_err(|_| ())?; - let count = iter.next().ok_or(())?.parse().map_err(|_| ())?; - Ok(Operation::RotateRow(y, count)) - - } else if s.starts_with("rotate column") { - let mut iter = s[16..].split(" by "); - let x = iter.next().ok_or(())?.parse().map_err(|_| ())?; - let count = iter.next().ok_or(())?.parse().map_err(|_| ())?; - Ok(Operation::RotateColumn(x, count)) - - } else { - Err(()) - } - } -} - -struct Display { - width: usize, - height: usize, - pixels: Box<[bool]>, -} - -impl Index<(usize, usize)> for Display { - type Output = bool; - fn index(&self, index: (usize, usize)) -> &bool { - &self.pixels[index.1 * self.width + index.0] - } -} - -impl IndexMut<(usize, usize)> for Display { - fn index_mut(&mut self, index: (usize, usize)) -> &mut bool { - &mut self.pixels[index.1 * self.width + index.0] - } -} - -impl Display { - fn new(width: usize, height: usize) -> Self { - Display { - width: width, - height: height, - pixels: vec![false; width * height].into_boxed_slice(), - } - } - - fn apply(&mut self, operation: Operation) { - match operation { - Operation::Rect(width, height) => { - for y in 0..height { - for x in 0..width { - self[(x, y)] = true; - } - } - }, - - Operation::RotateRow(y, count) => { - for _ in 0..count { - let last = self[(self.width - 1, y)]; - for x in (1..self.width).rev() { - self[(x, y)] = self[(x - 1, y)]; - } - self[(0, y)] = last; - } - }, - - Operation::RotateColumn(x, count) => { - for _ in 0..count { - let last = self[(x, self.height - 1)]; - for y in (1..self.height).rev() { - self[(x, y)] = self[(x, y - 1)]; - } - self[(x, 0)] = last; - } - }, - } - } - - fn pixels_lit(&self) -> usize { - self.pixels.iter().filter(|&&p| p).count() - } -} - -impl FmtDisplay for Display { - fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> { - for y in 0..self.height { - for x in 0..self.width { - if self[(x, y)] { - write!(f, "#")?; - } else { - write!(f, " ")?; - } - } - write!(f, "\n")?; - } - Ok(()) - } -} - -fn solve(width: usize, height: usize, input: &str) -> Display { - let mut display = Display::new(width, height); - - for line in input.lines() { - display.apply(line.parse().unwrap()); - } - - display -} - -fn main() { - let mut input = String::new(); - io::stdin().read_to_string(&mut input).unwrap(); - - let display = solve(50, 6, &input); - println!("Part 1: {}", display.pixels_lit()); - println!("Part 2:\n{}", display); -} - -#[test] -fn part1() { - let input = " -rect 3x2 -rotate column x=1 by 1 -rotate row y=0 by 4 -rotate row x=1 by 1 -"; - assert_eq!(6, solve(7, 3, input.trim()).pixels_lit()); -} diff --git a/src/bin/day09.rs b/src/bin/day09.rs deleted file mode 100644 index f559b47..0000000 --- a/src/bin/day09.rs +++ /dev/null @@ -1,124 +0,0 @@ -use std::io::{self, Read}; - -enum Chunk<'a> { - Literal(&'a str), - Repeat(u32, &'a str), - Recursive(u32, Vec<Chunk<'a>>), -} - -impl<'a> Chunk<'a> { - fn len(&self) -> usize { - match *self { - Chunk::Literal(s) => s.len(), - Chunk::Repeat(n, s) => n as usize * s.len(), - Chunk::Recursive(n, ref cs) => n as usize * cs.iter().map(Chunk::len).sum::<usize>(), - } - } - - fn parse(s: &'a str) -> Result<(Self, &'a str), ()> { - if s.starts_with('(') { - let mut iter = s[1..].splitn(3, |ch| ch == 'x' || ch == ')'); - - let len = iter.next().ok_or(())?.parse().map_err(|_| ())?; - let repeat = iter.next().ok_or(())?.parse().map_err(|_| ())?; - let (data, rest) = iter.next().ok_or(())?.split_at(len); - - Ok((Chunk::Repeat(repeat, data), rest)) - } else { - let paren = s.find('(').unwrap_or(s.len()); - Ok((Chunk::Literal(&s[..paren]), &s[paren..])) - } - } - - fn parse_v2(s: &'a str) -> Result<(Self, &'a str), ()> { - if s.starts_with('(') { - let mut iter = s[1..].splitn(3, |ch| ch == 'x' || ch == ')'); - - let len = iter.next().ok_or(())?.parse().map_err(|_| ())?; - let repeat = iter.next().ok_or(())?.parse().map_err(|_| ())?; - let (mut data, rest) = iter.next().ok_or(())?.split_at(len); - - let mut chunks = Vec::new(); - while !data.is_empty() { - let (chunk, data_rest) = Chunk::parse_v2(data)?; - chunks.push(chunk); - data = data_rest; - } - - Ok((Chunk::Recursive(repeat, chunks), rest)) - } else { - let paren = s.find('(').unwrap_or(s.len()); - Ok((Chunk::Literal(&s[..paren]), &s[paren..])) - } - } -} - -struct File<'a> { - chunks: Vec<Chunk<'a>>, -} - -impl<'a> File<'a> { - fn len(&self) -> usize { - self.chunks.iter().map(Chunk::len).sum() - } - - fn parse(mut s: &'a str) -> Result<Self, ()> { - let mut chunks = Vec::new(); - - while !s.is_empty() { - let (chunk, rest) = Chunk::parse(s)?; - chunks.push(chunk); - s = rest; - } - - Ok(File { chunks: chunks }) - } - - fn parse_v2(mut s: &'a str) -> Result<Self, ()> { - let mut chunks = Vec::new(); - - while !s.is_empty() { - let (chunk, rest) = Chunk::parse_v2(s)?; - chunks.push(chunk); - s = rest; - } - - Ok(File { chunks: chunks }) - } -} - -fn solve1(input: &str) -> usize { - let file = File::parse(input).unwrap(); - file.len() -} - -fn solve2(input: &str) -> usize { - let file = File::parse_v2(input).unwrap(); - file.len() -} - -fn main() { - let mut input = String::new(); - io::stdin().read_to_string(&mut input).unwrap(); - - println!("Part 1: {}", solve1(&input)); - println!("Part 2: {}", solve2(&input)); -} - -#[test] -fn part1() { - assert_eq!(6, solve1("ADVENT")); - assert_eq!(7, solve1("A(1x5)BC")); - assert_eq!(9, solve1("(3x3)XYZ")); - assert_eq!(11, solve1("A(2x2)BCD(2x2)EFG")); - assert_eq!(6, solve1("(6x1)(1x3)A")); - assert_eq!(18, solve1("X(8x2)(3x3)ABCY")); -} - -#[test] -fn part2() { - assert_eq!(9, solve2("(3x3)XYZ")); - assert_eq!(20, solve2("X(8x2)(3x3)ABCY")); - assert_eq!(241920, solve2("(27x12)(20x12)(13x14)(7x10)(1x12)A")); - assert_eq!(445, solve2("(25x3)(3x3)ABC(2x3)XY(5x2)PQRSTX(18x9)(3x2)TWO(5x7)SEVEN")); -} diff --git a/src/bin/day10.rs b/src/bin/day10.rs deleted file mode 100644 index a824f56..0000000 --- a/src/bin/day10.rs +++ /dev/null @@ -1,180 +0,0 @@ -use std::collections::HashMap; -use std::io::{self, Read}; -use std::str::FromStr; - -#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash)] -struct Chip(u32); - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -struct Bot(u32); - -#[derive(Clone, Copy, PartialEq, Eq, Hash)] -struct Output(u32); - -#[derive(Clone, Copy, Default)] -struct BotChips(Option<Chip>, Option<Chip>); - -impl BotChips { - fn add(&mut self, chip: Chip) { - match (self.0, self.1) { - (None, None) => { - self.0 = Some(chip); - }, - (Some(low), None) if low < chip => { - self.1 = Some(chip); - }, - (Some(high), None) => { - self.0 = Some(chip); - self.1 = Some(high); - }, - _ => panic!("bot has too many chips"), - } - } - - fn has_two(&self) -> bool { - self.0.is_some() && self.1.is_some() - } -} - -#[derive(Clone, Copy)] -enum Destination { - Bot(Bot), - Output(Output), -} - -impl Destination { - fn from_pair(ty: &str, value: u32) -> Result<Self, ()> { - match ty { - "bot" => Ok(Destination::Bot(Bot(value))), - "output" => Ok(Destination::Output(Output(value))), - _ => Err(()), - } - } -} - -#[derive(Default)] -struct Instructions { - chips: HashMap<Chip, Bot>, - bots: HashMap<Bot, (Destination, Destination)>, -} - -impl FromStr for Instructions { - type Err = (); - fn from_str(s: &str) -> Result<Self, ()> { - let mut instructions = Instructions::default(); - - for line in s.lines() { - let mut words = line.split(' '); - if words.next() == Some("value") { - let value = words.next().ok_or(())?.parse().map_err(|_| ())?; - let bot = words.nth(3).ok_or(())?.parse().map_err(|_| ())?; - - instructions.chips.insert(Chip(value), Bot(bot)); - } else { - let bot = words.next().ok_or(())?.parse().map_err(|_| ())?; - let low_type = words.nth(3).ok_or(())?; - let low_value = words.next().ok_or(())?.parse().map_err(|_| ())?; - let high_type = words.nth(3).ok_or(())?; - let high_value = words.next().ok_or(())?.parse().map_err(|_| ())?; - - let low = Destination::from_pair(low_type, low_value)?; - let high = Destination::from_pair(high_type, high_value)?; - - instructions.bots.insert(Bot(bot), (low, high)); - } - } - - Ok(instructions) - } -} - -#[derive(Default)] -struct State { - outputs: HashMap<Output, Chip>, - bots: HashMap<Bot, BotChips>, - comparisons: HashMap<(Chip, Chip), Bot>, -} - -impl State { - fn initialize(&mut self, instructions: &Instructions) { - for (&chip, &bot) in &instructions.chips { - self.bots.entry(bot).or_insert_with(Default::default).add(chip); - } - } - - fn step(&mut self, instructions: &Instructions) -> bool { - let active_bots: Vec<Bot> = self.bots.iter() - .filter(|&(_, ref chips)| chips.has_two()) - .map(|(&bot, _)| bot) - .collect(); - - if active_bots.is_empty() { - return false; - } - - for bot in active_bots { - let (low, high) = { - let chips = self.bots.get_mut(&bot).unwrap(); - (chips.0.take().unwrap(), chips.1.take().unwrap()) - }; - self.comparisons.insert((low, high), bot); - - let &(low_dest, high_dest) = instructions.bots.get(&bot).unwrap(); - self.give_to(low_dest, low); - self.give_to(high_dest, high); - } - - true - } - - fn give_to(&mut self, destination: Destination, chip: Chip) { - match destination { - Destination::Bot(bot) => { - self.bots.entry(bot).or_insert_with(Default::default).add(chip); - }, - Destination::Output(output) => { - self.outputs.insert(output, chip); - }, - } - } -} - -fn solve1(comparison: (Chip, Chip), input: &str) -> Option<Bot> { - let instructions = input.parse().unwrap(); - let mut state = State::default(); - state.initialize(&instructions); - while state.step(&instructions) { } - state.comparisons.get(&comparison).cloned() -} - -fn solve2(input: &str) -> u32 { - let instructions = input.parse().unwrap(); - let mut state = State::default(); - state.initialize(&instructions); - while state.step(&instructions) { } - - state.outputs.get(&Output(0)).unwrap().0 - * state.outputs.get(&Output(1)).unwrap().0 - * state.outputs.get(&Output(2)).unwrap().0 -} - -fn main() { - let mut input = String::new(); - io::stdin().read_to_string(&mut input).unwrap(); - - println!("Part 1: {:?}", solve1((Chip(17), Chip(61)), &input)); - println!("Part 2: {}", solve2(&input)); -} - -#[test] -fn part1() { - let input = " -value 5 goes to bot 2 -bot 2 gives low to bot 1 and high to bot 0 -value 3 goes to bot 1 -bot 1 gives low to output 1 and high to bot 0 -bot 0 gives low to output 2 and high to output 0 -value 2 goes to bot 2 -"; - assert_eq!(Some(Bot(2)), solve1((Chip(2), Chip(5)), input.trim())); -} diff --git a/src/bin/day11.rs b/src/bin/day11.rs deleted file mode 100644 index c033766..0000000 --- a/src/bin/day11.rs +++ /dev/null @@ -1,194 +0,0 @@ -use std::collections::{HashSet, VecDeque}; - -#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash)] -enum Object { - Microchip(u8), - Generator(u8), -} - -impl Object { - fn is_microchip(self) -> bool { - match self { - Object::Microchip(_) => true, - _ => false, - } - } - - fn is_generator(self) -> bool { - match self { - Object::Generator(_) => true, - _ => false, - } - } - - fn generator(self) -> Self { - match self { - Object::Microchip(k) => Object::Generator(k), - _ => self, - } - } -} - -#[derive(Default, Clone)] -struct Floor { - objects: HashSet<Object>, -} - -impl Floor { - fn is_empty(&self) -> bool { - self.objects.is_empty() - } - - fn is_safe(&self) -> bool { - for &chip in self.objects.iter().filter(|&&o| o.is_microchip()) { - let accompanied = self.objects.contains(&chip.generator()); - let generator = self.objects.iter().any(|&o| o.is_generator()); - if !accompanied && generator { return false } - } - true - } -} - -#[derive(Clone)] -struct State { - steps: u32, - floors: Box<[Floor]>, - elevator: usize, -} - -impl State { - fn is_goal(&self) -> bool { - self.floors[0..3].iter().all(Floor::is_empty) - } - - fn is_safe(&self) -> bool { - self.floors.iter().all(Floor::is_safe) - } - - fn clone_up(&self) -> Self { - let mut state = self.clone(); - state.steps += 1; - state.elevator += 1; - state - } - - fn clone_down(&self) -> Self { - let mut state = self.clone(); - state.steps += 1; - state.elevator -= 1; - state - } - - fn generate_states(&self, states: &mut VecDeque<State>) { - for &object in &self.floors[self.elevator].objects { - for &other in &self.floors[self.elevator].objects { - if other == object { continue } - if self.elevator != 3 { - let mut state = self.clone_up(); - state.floors[self.elevator].objects.remove(&object); - state.floors[self.elevator].objects.remove(&other); - state.floors[state.elevator].objects.insert(object); - state.floors[state.elevator].objects.insert(other); - if state.is_safe() { states.push_back(state) } - } - if self.elevator != 0 { - let mut state = self.clone_down(); - state.floors[self.elevator].objects.remove(&object); - state.floors[self.elevator].objects.remove(&other); - state.floors[state.elevator].objects.insert(object); - state.floors[state.elevator].objects.insert(other); - if state.is_safe() { states.push_back(state) } - } - } - - if self.elevator != 3 { - let mut state = self.clone_up(); - state.floors[self.elevator].objects.remove(&object); - state.floors[state.elevator].objects.insert(object); - if state.is_safe() { states.push_back(state) } - } - if self.elevator != 0 { - let mut state = self.clone_down(); - state.floors[self.elevator].objects.remove(&object); - state.floors[state.elevator].objects.insert(object); - if state.is_safe() { states.push_back(state) } - } - } - } -} - -fn solve(floors: Vec<Floor>) -> u32 { - let mut visited = HashSet::new(); - let mut states = VecDeque::new(); - states.push_back(State { steps: 0, floors: floors.into_boxed_slice(), elevator: 0 }); - - while let Some(state) = states.pop_front() { - if state.is_goal() { - return state.steps; - } - let visit_floors: Vec<_> = state.floors.iter().map(|floor| { - let mut vec: Vec<_> = floor.objects.iter().cloned().collect(); - vec.sort(); - vec - }).collect(); - if visited.insert((state.elevator, visit_floors)) { - state.generate_states(&mut states); - } - } - - unreachable!() -} - -fn main() { - // The first floor contains a promethium generator and a promethium-compatible microchip. - // The second floor contains a cobalt generator, a curium generator, a ruthenium generator, and a plutonium generator. - // The third floor contains a cobalt-compatible microchip, a curium-compatible microchip, a ruthenium-compatible microchip, and a plutonium-compatible microchip. - // The fourth floor contains nothing relevant. - const PROMETHIUM: u8 = 0; - const COBALT: u8 = 1; - const CURIUM: u8 = 2; - const RUTHENIUM: u8 = 3; - const PLUTONIUM: u8 = 4; - let mut floors = vec![Floor::default(); 4]; - floors[0].objects.insert(Object::Generator(PROMETHIUM)); - floors[0].objects.insert(Object::Microchip(PROMETHIUM)); - floors[1].objects.insert(Object::Generator(COBALT)); - floors[1].objects.insert(Object::Generator(CURIUM)); - floors[1].objects.insert(Object::Generator(RUTHENIUM)); - floors[1].objects.insert(Object::Generator(PLUTONIUM)); - floors[2].objects.insert(Object::Microchip(COBALT)); - floors[2].objects.insert(Object::Microchip(CURIUM)); - floors[2].objects.insert(Object::Microchip(RUTHENIUM)); - floors[2].objects.insert(Object::Microchip(PLUTONIUM)); - - println!("Part 1: {}", solve(floors.clone())); - - - // An elerium generator. - // An elerium-compatible microchip. - // A dilithium generator. - // A dilithium-compatible microchip. - const ELERIUM: u8 = 5; - const DILITHIUM: u8 = 6; - floors[0].objects.insert(Object::Generator(ELERIUM)); - floors[0].objects.insert(Object::Microchip(ELERIUM)); - floors[0].objects.insert(Object::Generator(DILITHIUM)); - floors[0].objects.insert(Object::Microchip(DILITHIUM)); - println!("Part 2: {}", solve(floors)); -} - -#[test] -#[ignore] -fn part1() { - // The first floor contains a hydrogen-compatible microchip and a lithium-compatible microchip. - // The second floor contains a hydrogen generator. - // The third floor contains a lithium generator. - // The fourth floor contains nothing relevant. - let mut floors = vec![Floor::default(); 4]; - floors[0].objects.insert(Object::Microchip(0)); - floors[0].objects.insert(Object::Microchip(1)); - floors[1].objects.insert(Object::Generator(0)); - floors[2].objects.insert(Object::Generator(1)); - - assert_eq!(11, solve(floors)); -} diff --git a/src/bin/day12.rs b/src/bin/day12.rs deleted file mode 100644 index 6655947..0000000 --- a/src/bin/day12.rs +++ /dev/null @@ -1,143 +0,0 @@ -use std::io::{self, Read}; -use std::str::FromStr; - -#[derive(Clone, Copy)] -enum Operand { - Register(u8), - Immediate(i32), -} - -impl FromStr for Operand { - type Err = (); - fn from_str(s: &str) -> Result<Self, ()> { - match s { - "a" => Ok(Operand::Register(0)), - "b" => Ok(Operand::Register(1)), - "c" => Ok(Operand::Register(2)), - "d" => Ok(Operand::Register(3)), - _ => Ok(Operand::Immediate(s.parse().map_err(|_| ())?)), - } - } -} - -#[derive(Clone, Copy)] -enum Operation { - Cpy(Operand, Operand), - Inc(Operand), - Dec(Operand), - Jnz(Operand, Operand), -} - -impl FromStr for Operation { - type Err = (); - fn from_str(s: &str) -> Result<Self, ()> { - let mut iter = s.split(' '); - match iter.next() { - Some("cpy") => { - let src = iter.next().ok_or(())?.parse()?; - let dest = iter.next().ok_or(())?.parse()?; - Ok(Operation::Cpy(src, dest)) - }, - Some("inc") => Ok(Operation::Inc(iter.next().ok_or(())?.parse()?)), - Some("dec") => Ok(Operation::Dec(iter.next().ok_or(())?.parse()?)), - Some("jnz") => { - let cond = iter.next().ok_or(())?.parse()?; - let jump = iter.next().ok_or(())?.parse()?; - Ok(Operation::Jnz(cond, jump)) - }, - _ => Err(()), - } - } -} - -#[derive(Default)] -struct Vm { - registers: [i32; 4], - operations: Vec<Operation>, - index: i32, -} - -impl FromStr for Vm { - type Err = (); - fn from_str(s: &str) -> Result<Self, ()> { - let mut vm = Self::default(); - for line in s.lines() { - vm.operations.push(line.parse()?); - } - Ok(vm) - } -} - -impl Vm { - fn step(&mut self) -> bool { - match self.operations[self.index as usize] { - Operation::Cpy(Operand::Immediate(imm), Operand::Register(reg)) => { - self.registers[reg as usize] = imm; - self.index += 1; - }, - Operation::Cpy(Operand::Register(src), Operand::Register(dest)) => { - self.registers[dest as usize] = self.registers[src as usize]; - self.index += 1; - }, - Operation::Inc(Operand::Register(reg)) => { - self.registers[reg as usize] += 1; - self.index += 1; - }, - Operation::Dec(Operand::Register(reg)) => { - self.registers[reg as usize] -= 1; - self.index += 1; - }, - Operation::Jnz(Operand::Immediate(cond), Operand::Immediate(jump)) => { - if cond != 0 { - self.index += jump; - } else { - self.index += 1; - } - }, - Operation::Jnz(Operand::Register(reg), Operand::Immediate(jump)) => { - if self.registers[reg as usize] != 0 { - self.index += jump; - } else { - self.index += 1; - } - }, - _ => panic!("invalid operation"), - } - - (self.index as usize) < self.operations.len() - } -} - -fn solve1(input: &str) -> i32 { - let mut vm: Vm = input.parse().unwrap(); - while vm.step() { } - vm.registers[0] -} - -fn solve2(input: &str) -> i32 { - let mut vm: Vm = input.parse().unwrap(); - vm.registers[2] = 1; - while vm.step() { } - vm.registers[0] -} - -fn main() { - let mut input = String::new(); - io::stdin().read_to_string(&mut input).unwrap(); - - println!("Part 1: {}", solve1(&input)); - println!("Part 2: {}", solve2(&input)); -} - -#[test] -fn part1() { - let input = " -cpy 41 a -inc a -inc a -dec a -jnz a 2 -dec a -"; - assert_eq!(42, solve1(input.trim())); -} diff --git a/src/bin/day13.rs b/src/bin/day13.rs deleted file mode 100644 index 060f571..0000000 --- a/src/bin/day13.rs +++ /dev/null @@ -1,122 +0,0 @@ -use std::collections::{HashMap, VecDeque}; -use std::io::{self, Read}; - -#[derive(Clone, Copy, PartialEq, Eq, Hash)] -struct Point { - x: u32, - y: u32, -} - -const START: Point = Point { x: 1, y: 1 }; - -impl Point { - fn north(self) -> Option<Point> { - if self.y == 0 { - None - } else { - Some(Point { x: self.x, y: self.y - 1 }) - } - } - - fn east(self) -> Point { - Point { x: self.x + 1, y: self.y } - } - - fn south(self) -> Point { - Point { x: self.x, y: self.y + 1 } - } - - fn west(self) -> Option<Point> { - if self.x == 0 { - None - } else { - Some(Point { x: self.x - 1, y: self.y }) - } - } - - fn neighbors(self) -> [Option<Point>; 4] { - [self.north(), Some(self.east()), Some(self.south()), self.west()] - } -} - -#[derive(Clone, Copy)] -struct Layout { - constant: u32, -} - -impl Layout { - fn is_open(&self, point: Point) -> bool { - let Point { x, y } = point; - let sum = x * x + 3 * x + 2 * x * y + y + y * y + self.constant; - sum.count_ones() % 2 == 0 - } -} - -fn solve1(goal: Point, constant: u32) -> u32 { - let layout = Layout { constant: constant }; - - let mut distance = HashMap::new(); - let mut frontier = VecDeque::new(); - frontier.push_back(START); - distance.insert(START, 0); - - while let Some(current) = frontier.pop_front() { - if current == goal { break; } - let current_distance = *distance.get(¤t).unwrap(); - - let neighbors = current.neighbors(); - let iter = neighbors.iter() - .filter_map(|&p| p) - .filter(|&p| layout.is_open(p)); - - for next in iter { - if !distance.contains_key(&next) { - frontier.push_back(next); - distance.insert(next, current_distance + 1); - } - } - } - - *distance.get(&goal).unwrap() -} - -fn solve2(limit: u32, constant: u32) -> usize { - let layout = Layout { constant: constant }; - - let mut distance = HashMap::new(); - let mut frontier = VecDeque::new(); - frontier.push_back(START); - distance.insert(START, 0); - - while let Some(current) = frontier.pop_front() { - let current_distance = *distance.get(¤t).unwrap(); - if current_distance == limit { continue; } - - let neighbors = current.neighbors(); - let iter = neighbors.iter() - .filter_map(|&p| p) - .filter(|&p| layout.is_open(p)); - - for next in iter { - if !distance.contains_key(&next) { - frontier.push_back(next); - distance.insert(next, current_distance + 1); - } - } - } - - distance.len() -} - -fn main() { - let mut input = String::new(); - io::stdin().read_to_string(&mut input).unwrap(); - - println!("Part 1: {}", solve1(Point { x: 31, y: 39 }, input.trim().parse().unwrap())); - println!("Part 2: {}", solve2(50, input.trim().parse().unwrap())); -} - -#[test] -fn part1() { - assert_eq!(11, solve1(Point { x: 7, y: 4 }, 10)); -} diff --git a/src/bin/day14.rs b/src/bin/day14.rs deleted file mode 100644 index 352982d..0000000 --- a/src/bin/day14.rs +++ /dev/null @@ -1,87 +0,0 @@ -extern crate crypto; - -use std::collections::VecDeque; -use std::io::{self, Read}; -use std::iter; - -use crypto::digest::Digest; -use crypto::md5::Md5; - -trait Hash { - fn hash(salt: &str, index: u32) -> String; -} - -struct Part1; -impl Hash for Part1 { - fn hash(salt: &str, index: u32) -> String { - let mut md5 = Md5::new(); - md5.input_str(salt); - md5.input_str(&index.to_string()); - md5.result_str() - } -} - -struct Part2; -impl Hash for Part2 { - fn hash(salt: &str, index: u32) -> String { - let mut hash = Part1::hash(salt, index); - for _ in 0..2016 { - let mut md5 = Md5::new(); - md5.input_str(&hash); - hash = md5.result_str(); - } - hash - } -} - -fn solve<H: Hash>(salt: &str) -> u32 { - let mut hashes = VecDeque::new(); - for i in 0..1001 { - hashes.push_back(H::hash(salt, i)); - } - - let mut keys = 0; - let mut index = 0; - while let Some(hash) = hashes.pop_front() { - let triple = hash.as_bytes() - .windows(3) - .filter(|w| w[0] == w[1] && w[1] == w[2]) - .map(|w| w[0]) - .next(); - - if let Some(ch) = triple { - let quintuple: String = iter::repeat(ch as char).take(5).collect(); - if hashes.iter().any(|hash| hash.contains(&quintuple)) { - keys += 1; - if keys == 64 { - return index; - } - } - } - - index += 1; - hashes.push_back(H::hash(salt, 1000 + index)); - } - - unreachable!() -} - -fn main() { - let mut input = String::new(); - io::stdin().read_to_string(&mut input).unwrap(); - - println!("Part 1: {}", solve::<Part1>(input.trim())); - println!("Part 2: {}", solve::<Part2>(input.trim())); -} - -#[test] -#[ignore] -fn part1() { - assert_eq!(22728, solve::<Part1>("abc")); -} - -#[test] -#[ignore] -fn part2() { - assert_eq!(22551, solve::<Part2>("abc")); -} diff --git a/src/bin/day15.rs b/src/bin/day15.rs deleted file mode 100644 index ec9df7a..0000000 --- a/src/bin/day15.rs +++ /dev/null @@ -1,103 +0,0 @@ -use std::io::{self, Read}; - -#[derive(Clone, Copy)] -struct Disc { - positions: u32, - position: u32, -} - -impl Disc { - fn rotate(&mut self) { - self.position = (self.position + 1) % self.positions; - } - - fn is_open(&self) -> bool { - self.position == 0 - } -} - -impl<'a> From<&'a str> for Disc { - fn from(s: &'a str) -> Disc { - let mut iter = s.trim_right_matches('.').split_whitespace(); - Disc { - positions: iter.nth(3).unwrap().parse().unwrap(), - position: iter.last().unwrap().parse().unwrap(), - } - } -} - -#[derive(Clone)] -struct Sculpture { - discs: Vec<Disc>, - time: u32, - capsule: usize, -} - -impl Sculpture { - fn tick(&mut self) { - self.time += 1; - for disc in &mut self.discs { - disc.rotate() - } - } - - fn drop_capsule(&mut self) -> bool { - while self.capsule < self.discs.len() { - self.tick(); - if self.discs[self.capsule].is_open() { - self.capsule += 1; - } else { - return false; - } - } - true - } -} - -impl<'a> From<&'a str> for Sculpture { - fn from(s: &'a str) -> Sculpture { - Sculpture { - discs: s.lines().map(Disc::from).collect(), - time: 0, - capsule: 0, - } - } -} - -fn solve1(input: &str) -> u32 { - let mut sculpture = Sculpture::from(input); - loop { - if sculpture.clone().drop_capsule() { - return sculpture.time; - } - sculpture.tick(); - } -} - -fn solve2(input: &str) -> u32 { - let mut sculpture = Sculpture::from(input); - sculpture.discs.push(Disc { positions: 11, position: 0 }); - loop { - if sculpture.clone().drop_capsule() { - return sculpture.time; - } - sculpture.tick(); - } -} - -fn main() { - let mut input = String::new(); - io::stdin().read_to_string(&mut input).unwrap(); - - println!("Part 1: {}", solve1(&input)); - println!("Part 2: {}", solve2(&input)); -} - -#[test] -fn part1() { - let input = " -Disc #1 has 5 positions; at time=0, it is at position 4. -Disc #2 has 2 positions; at time=0, it is at position 1. -"; - assert_eq!(5, solve1(input.trim())); -} diff --git a/src/bin/day16.rs b/src/bin/day16.rs deleted file mode 100644 index 247d9fd..0000000 --- a/src/bin/day16.rs +++ /dev/null @@ -1,51 +0,0 @@ -use std::io::{self, Read}; - -fn fill_disk(initial_state: &str, len: usize) -> String { - let mut state = String::from(initial_state); - while state.len() < len { - let mut b: Vec<u8> = state.bytes() - .map(|b| { - match b { - b'0' => b'1', - b'1' => b'0', - _ => b, - } - }) - .collect(); - b.reverse(); - let b = String::from_utf8(b).unwrap(); - state.push('0'); - state.push_str(&b); - } - state.truncate(len); - state -} - -fn checksum(data: &str) -> String { - let mut sum = String::from(data); - while sum.len() % 2 == 0 { - sum = sum.as_bytes() - .chunks(2) - .map(|c| if c[0] == c[1] { '1' } else { '0' }) - .collect(); - } - sum -} - -fn solve(len: usize, initial_state: &str) -> String { - let data = fill_disk(initial_state, len); - checksum(&data) -} - -fn main() { - let mut input = String::new(); - io::stdin().read_to_string(&mut input).unwrap(); - - println!("Part 1: {}", solve(272, input.trim())); - println!("Part 2: {}", solve(35651584, input.trim())); -} - -#[test] -fn part1() { - assert_eq!("01100", solve(20, "10000")); -} diff --git a/src/bin/day17.rs b/src/bin/day17.rs deleted file mode 100644 index c769f32..0000000 --- a/src/bin/day17.rs +++ /dev/null @@ -1,148 +0,0 @@ -extern crate crypto; - -use std::collections::VecDeque; -use std::io::{self, Read}; - -use crypto::digest::Digest; -use crypto::md5::Md5; - -#[derive(Clone, Copy)] -enum Direction { - Up, - Down, - Left, - Right, -} - -const DIRECTIONS: &'static [Direction] = &[ - Direction::Up, - Direction::Down, - Direction::Left, - Direction::Right, -]; - -impl From<Direction> for char { - fn from(direction: Direction) -> Self { - match direction { - Direction::Up => 'U', - Direction::Down => 'D', - Direction::Left => 'L', - Direction::Right => 'R', - } - } -} - -#[derive(Default, Clone, Copy)] -struct Room { - x: u8, - y: u8, -} - -impl Room { - fn neighbor(self, direction: Direction) -> Option<Room> { - match direction { - Direction::Up if self.y != 0 => Some(Room { x: self.x, y: self.y - 1 }), - Direction::Down if self.y != 3 => Some(Room { x: self.x, y: self.y + 1 }), - Direction::Left if self.x != 0 => Some(Room { x: self.x - 1, y: self.y }), - Direction::Right if self.x != 3 => Some(Room { x: self.x + 1, y: self.y }), - _ => None, - } - } - - fn is_vault(self) -> bool { - self.x == 3 && self.y == 3 - } -} - -#[derive(Default, Clone)] -struct State { - room: Room, - path: Vec<Direction>, -} - -impl<'a> From<&'a State> for String { - fn from(state: &'a State) -> String { - state.path.iter().cloned().map(char::from).collect() - } -} - -impl State { - fn is_vault(&self) -> bool { - self.room.is_vault() - } - - fn generate_states(&self, states: &mut VecDeque<State>, passcode: &str) { - let mut md5 = Md5::new(); - md5.input_str(passcode); - md5.input_str(&String::from(self)); - let hash = md5.result_str(); - - for (direction, ch) in DIRECTIONS.iter().cloned().zip(hash.chars()) { - if ch < 'b' || ch > 'f' { continue } - - let room = match self.room.neighbor(direction) { - Some(r) => r, - None => continue, - }; - - let mut path = self.path.clone(); - path.push(direction); - - states.push_back(State { room: room, path: path }); - } - } -} - -fn solve1(passcode: &str) -> String { - let mut states = VecDeque::new(); - states.push_back(State::default()); - - while let Some(state) = states.pop_front() { - if state.is_vault() { - return String::from(&state); - } - state.generate_states(&mut states, passcode); - } - - panic!("no path to vault") -} - -fn solve2(passcode: &str) -> usize { - let mut states = VecDeque::new(); - states.push_back(State::default()); - - let mut longest = None; - - while let Some(state) = states.pop_front() { - if state.is_vault() { - longest = Some(state.clone()); - } else { - state.generate_states(&mut states, passcode); - } - } - - longest.unwrap().path.len() -} - -fn main() { - let mut input = String::new(); - io::stdin().read_to_string(&mut input).unwrap(); - - println!("Part 1: {}", solve1(input.trim())); - println!("Part 2: {}", solve2(input.trim())); -} - -#[test] -fn part1() { - assert_eq!("DDRRRD", solve1("ihgpwlah")); - assert_eq!("DDUDRLRRUDRD", solve1("kglvqrro")); - assert_eq!("DRURDRUDDLLDLUURRDULRLDUUDDDRR", solve1("ulqzkmiv")); -} - -#[test] -#[ignore] -fn part2() { - assert_eq!(370, solve2("ihgpwlah")); - assert_eq!(492, solve2("kglvqrro")); - assert_eq!(830, solve2("ulqzkmiv")); -} diff --git a/src/bin/day18.rs b/src/bin/day18.rs deleted file mode 100644 index 19f8c91..0000000 --- a/src/bin/day18.rs +++ /dev/null @@ -1,88 +0,0 @@ -use std::io::{self, Read}; - -#[derive(Clone, Copy, PartialEq, Eq)] -enum Tile { - Safe, - Trap, -} - -impl From<char> for Tile { - fn from(ch: char) -> Tile { - match ch { - '.' => Tile::Safe, - '^' => Tile::Trap, - _ => panic!("invalid tile char {}", ch), - } - } -} - -struct Map { - rows: Vec<Box<[Tile]>>, -} - -impl Map { - fn generate_row(&mut self) { - let mut next = Vec::new(); - - { - let previous = self.rows.last().unwrap(); - - for (i, ¢er) in self.rows.last().unwrap().iter().enumerate() { - let left = previous.get(i.wrapping_sub(1)).cloned().unwrap_or(Tile::Safe); - let right = previous.get(i + 1).cloned().unwrap_or(Tile::Safe); - - let tile = match (left, center, right) { - (Tile::Trap, Tile::Trap, Tile::Safe) => Tile::Trap, - (Tile::Safe, Tile::Trap, Tile::Trap) => Tile::Trap, - (Tile::Trap, Tile::Safe, Tile::Safe) => Tile::Trap, - (Tile::Safe, Tile::Safe, Tile::Trap) => Tile::Trap, - _ => Tile::Safe, - }; - next.push(tile); - } - } - - self.rows.push(next.into_boxed_slice()); - } - - fn count_safe(&self) -> usize { - self.rows.iter() - .map(|row| { - row.iter() - .filter(|&&t| t == Tile::Safe) - .count() - }) - .sum() - } -} - -impl<'a> From<&'a str> for Map { - fn from(s: &'a str) -> Map { - let rows = s.lines() - .map(|l| l.chars().map(Tile::from).collect::<Vec<_>>().into_boxed_slice()) - .collect(); - Map { rows: rows } - } -} - -fn solve(rows: u32, input: &str) -> usize { - let mut map = Map::from(input); - for _ in 1..rows { - map.generate_row(); - } - map.count_safe() -} - -fn main() { - let mut input = String::new(); - io::stdin().read_to_string(&mut input).unwrap(); - - println!("Part 1: {}", solve(40, &input)); - println!("Part 2: {}", solve(400000, &input)); -} - -#[test] -fn part1() { - assert_eq!(6, solve(3, "..^^.")); - assert_eq!(38, solve(10, ".^^.^.^^^^")); -} diff --git a/src/bin/day19.rs b/src/bin/day19.rs deleted file mode 100644 index 9afbf39..0000000 --- a/src/bin/day19.rs +++ /dev/null @@ -1,35 +0,0 @@ -use std::collections::VecDeque; -use std::io::{self, Read}; - -#[derive(Clone, Copy)] -struct Elf { - position: usize, - gifts: usize, -} - -fn solve(count: usize) -> usize { - let mut circle: VecDeque<Elf> = (0..count) - .map(|i| Elf { position: i + 1, gifts: 1 }) - .collect(); - - while circle.len() > 1 { - let mut current = circle.pop_front().unwrap(); - let next = circle.pop_front().unwrap(); - current.gifts += next.gifts; - circle.push_back(current); - } - - circle.pop_front().unwrap().position -} - -fn main() { - let mut input = String::new(); - io::stdin().read_to_string(&mut input).unwrap(); - - println!("Part 1: {}", solve(input.trim().parse().unwrap())); -} - -#[test] -fn part1() { - assert_eq!(3, solve(5)); -} diff --git a/src/bin/day20.rs b/src/bin/day20.rs deleted file mode 100644 index 0416ced..0000000 --- a/src/bin/day20.rs +++ /dev/null @@ -1,77 +0,0 @@ -use std::io::{self, Read}; -use std::u32; - -fn parse_ranges(input: &str) -> Vec<(u32, u32)> { - let mut ranges = vec![]; - for line in input.lines() { - let hyphen = line.find('-').unwrap(); - let (start, end) = line.split_at(hyphen); - let start = start.parse().unwrap(); - let end = end[1..].parse().unwrap(); - ranges.push((start, end)); - } - ranges.sort(); - ranges -} - -fn solve1(input: &str) -> u32 { - let ranges = parse_ranges(input); - let mut lowest = 0; - - for &(start, end) in &ranges { - if lowest >= start && lowest <= end { - lowest = end + 1; - } - } - - lowest -} - -fn solve2(input: &str) -> u32 { - let ranges = parse_ranges(input); - let mut merged = vec![]; - - for &(start, end) in &ranges { - if let Some(&mut (ref mut last_start, ref mut last_end)) = merged.last_mut() { - if start >= *last_start && end <= *last_end { - continue; - } else if start >= *last_start && start <= *last_end + 1 && end > *last_end { - *last_end = end; - continue; - } - } - merged.push((start, end)); - } - - let blocked: u32 = merged.iter().map(|&(start, end)| end - start + 1).sum(); - - u32::MAX - blocked + 1 -} - -fn main() { - let mut input = String::new(); - io::stdin().read_to_string(&mut input).unwrap(); - - println!("Part 1: {}", solve1(&input)); - println!("Part 2: {}", solve2(&input)); -} - -#[test] -fn part1() { - let input = " -5-8 -0-2 -4-7 -"; - assert_eq!(3, solve1(input.trim())); -} - -#[test] -fn part2() { - let input = " -5-8 -0-2 -4-7 -"; - assert_eq!(u32::MAX - 7, solve2(input.trim())); -} diff --git a/src/bin/day21.rs b/src/bin/day21.rs deleted file mode 100644 index 982bf8a..0000000 --- a/src/bin/day21.rs +++ /dev/null @@ -1,144 +0,0 @@ -use std::io::{self, Read}; - -#[derive(Clone, Copy)] -enum Operation { - SwapPosition(usize, usize), - SwapLetter(u8, u8), - RotateLeft(usize), - RotateRight(usize), - RotateLetter(u8), - Reverse(usize, usize), - Move(usize, usize), -} - -impl Operation { - fn apply(self, slice: &mut [u8]) { - match self { - Operation::SwapPosition(i, j) => slice.swap(i, j), - Operation::SwapLetter(a, b) => { - let i = slice.iter().position(|&x| x == a).unwrap(); - let j = slice.iter().position(|&x| x == b).unwrap(); - slice.swap(i, j); - }, - Operation::RotateLeft(n) => { - let n = n % slice.len(); - slice[0..n].reverse(); - slice[n..].reverse(); - slice.reverse(); - }, - Operation::RotateRight(n) => { - let n = n % slice.len(); - slice.reverse(); - slice[0..n].reverse(); - slice[n..].reverse(); - }, - Operation::RotateLetter(a) => { - let mut n = 1 + slice.iter().position(|&x| x == a).unwrap(); - if n >= 5 { n += 1 } - n %= slice.len(); - slice.reverse(); - slice[0..n].reverse(); - slice[n..].reverse(); - }, - Operation::Reverse(i, j) => slice[i..(j + 1)].reverse(), - Operation::Move(i, j) if i < j => { - let a = slice[i]; - for k in i..j { - slice[k] = slice[k + 1]; - } - slice[j] = a; - }, - Operation::Move(i, j) => { - let a = slice[i]; - for k in (j..i).rev() { - slice[k + 1] = slice[k]; - } - slice[j] = a; - }, - } - } -} - -impl<'a> From<&'a str> for Operation { - fn from(s: &'a str) -> Self { - let mut iter = s.split_whitespace(); - match (iter.next().unwrap(), iter.next().unwrap()) { - ("swap", "position") => Operation::SwapPosition( - iter.next().unwrap().parse().unwrap(), - iter.nth(2).unwrap().parse().unwrap(), - ), - ("swap", "letter") => Operation::SwapLetter( - iter.next().unwrap().as_bytes()[0], - iter.nth(2).unwrap().as_bytes()[0], - ), - ("rotate", "left") => Operation::RotateLeft(iter.next().unwrap().parse().unwrap()), - ("rotate", "right") => Operation::RotateRight(iter.next().unwrap().parse().unwrap()), - ("rotate", "based") => Operation::RotateLetter(iter.nth(4).unwrap().as_bytes()[0]), - ("reverse", _) => Operation::Reverse( - iter.next().unwrap().parse().unwrap(), - iter.nth(1).unwrap().parse().unwrap(), - ), - ("move", _) => Operation::Move( - iter.next().unwrap().parse().unwrap(), - iter.nth(2).unwrap().parse().unwrap(), - ), - (x, y) => panic!("invalid operation {} {}", x, y), - } - } -} - -fn solve1(password: &str, input: &str) -> String { - let mut password = password.as_bytes().to_owned(); - - for operation in input.lines().map(Operation::from) { - operation.apply(&mut password); - } - - String::from_utf8(password).unwrap() -} - -fn solve2(scrambled: &str, input: &str) -> String { - let operations: Vec<_> = input.lines().map(Operation::from).collect(); - - let mut password = "abcdefgh".as_bytes().to_owned(); - let len = password.len(); - - loop { - let k = (0..(len - 1)).rev().find(|&k| password[k] < password [k + 1]).unwrap(); - let l = ((k + 1)..len).rev().find(|&l| password[k] < password[l]).unwrap(); - password.swap(k, l); - password[(k + 1)..].reverse(); - - let mut candidate = password.clone(); - for operation in &operations { - operation.apply(&mut candidate); - } - - if candidate == scrambled.as_bytes() { - return String::from_utf8(password).unwrap(); - } - } -} - -fn main() { - let mut input = String::new(); - io::stdin().read_to_string(&mut input).unwrap(); - - println!("Part 1: {}", solve1("abcdefgh", &input)); - println!("Part 2: {}", solve2("fbgdceah", &input)); -} - -#[test] -fn part1() { - let input = " -swap position 4 with position 0 -swap letter d with letter b -reverse positions 0 through 4 -rotate left 1 step -move position 1 to position 4 -move position 3 to position 0 -rotate based on position of letter b -rotate based on position of letter d -"; - assert_eq!("decab", solve1("abcde", input.trim())); -} diff --git a/src/bin/day23.rs b/src/bin/day23.rs deleted file mode 100644 index 4a54983..0000000 --- a/src/bin/day23.rs +++ /dev/null @@ -1,157 +0,0 @@ -use std::io::{self, Read}; - -#[derive(Clone, Copy)] -enum Operand { - Register(u8), - Immediate(i32), -} - -impl<'a> From<&'a str> for Operand { - fn from(s: &'a str) -> Self { - match s { - "a" => Operand::Register(0), - "b" => Operand::Register(1), - "c" => Operand::Register(2), - "d" => Operand::Register(3), - _ => Operand::Immediate(s.parse().unwrap()), - } - } -} - -#[derive(Clone, Copy)] -enum Operation { - Cpy(Operand, Operand), - Inc(Operand), - Dec(Operand), - Jnz(Operand, Operand), - Tgl(Operand), -} - -impl<'a> From<&'a str> for Operation { - fn from(s: &'a str) -> Self { - let mut iter = s.split_whitespace(); - match (iter.next().unwrap(), iter.next().unwrap()) { - ("cpy", a) => Operation::Cpy(Operand::from(a), Operand::from(iter.next().unwrap())), - ("inc", a) => Operation::Inc(Operand::from(a)), - ("dec", a) => Operation::Dec(Operand::from(a)), - ("jnz", a) => Operation::Jnz(Operand::from(a), Operand::from(iter.next().unwrap())), - ("tgl", a) => Operation::Tgl(Operand::from(a)), - _ => panic!("invalid instruction {}", s), - } - } -} - -impl Operation { - fn toggle(self) -> Self { - match self { - Operation::Inc(a) => Operation::Dec(a), - Operation::Dec(a) | Operation::Tgl(a) => Operation::Inc(a), - Operation::Jnz(a, b) => Operation::Cpy(a, b), - Operation::Cpy(a, b) => Operation::Jnz(a, b), - } - } -} - -#[derive(Default)] -struct Vm { - registers: [i32; 4], - operations: Vec<Operation>, - index: i32, -} - -impl<'a> From<&'a str> for Vm { - fn from(s: &'a str) -> Self { - let mut vm = Self::default(); - for line in s.lines() { - vm.operations.push(Operation::from(line)); - } - vm - } -} - -impl Vm { - fn step(&mut self) -> bool { - match self.operations[self.index as usize] { - Operation::Cpy(Operand::Immediate(imm), Operand::Register(reg)) => { - self.registers[reg as usize] = imm; - self.index += 1; - }, - Operation::Cpy(Operand::Register(src), Operand::Register(dest)) => { - self.registers[dest as usize] = self.registers[src as usize]; - self.index += 1; - }, - Operation::Inc(Operand::Register(reg)) => { - self.registers[reg as usize] += 1; - self.index += 1; - }, - Operation::Dec(Operand::Register(reg)) => { - self.registers[reg as usize] -= 1; - self.index += 1; - }, - Operation::Jnz(Operand::Immediate(cond), Operand::Immediate(jump)) => { - if cond != 0 { - self.index += jump; - } else { - self.index += 1; - } - }, - Operation::Jnz(Operand::Register(reg), Operand::Immediate(jump)) => { - if self.registers[reg as usize] != 0 { - self.index += jump; - } else { - self.index += 1; - } - }, - Operation::Jnz(Operand::Immediate(cond), Operand::Register(reg)) => { - if cond != 0 { - self.index += self.registers[reg as usize]; - } else { - self.index += 1; - } - }, - Operation::Tgl(Operand::Register(reg)) => { - let index = self.index + self.registers[reg as usize]; - if let Some(operation) = self.operations.get_mut(index as usize) { - *operation = operation.toggle(); - } - self.index += 1; - }, - _ => { - self.index += 1; - }, - } - - (self.index as usize) < self.operations.len() - } -} - -fn solve(initial: i32, input: &str) -> i32 { - let mut vm = Vm::from(input); - vm.registers[0] = initial; - while vm.step() { } - vm.registers[0] -} - -fn main() { - let mut input = String::new(); - io::stdin().read_to_string(&mut input).unwrap(); - - println!("Part 1: {}", solve(7, &input)); - println!("Part 2: {}", solve(12, &input)); -} - -#[test] -fn part1() { - let input = " -cpy 2 a -tgl a -tgl a -tgl a -cpy 1 a -dec a -dec a -"; - let mut vm = Vm::from(input.trim()); - while vm.step() { } - assert_eq!(3, vm.registers[0]); -} diff --git a/src/bin/day25.rs b/src/bin/day25.rs deleted file mode 100644 index 9ecf487..0000000 --- a/src/bin/day25.rs +++ /dev/null @@ -1,163 +0,0 @@ -use std::io::{self, Read}; -use std::iter; - -#[derive(Clone, Copy)] -enum Operand { - Register(u8), - Immediate(i32), -} - -impl<'a> From<&'a str> for Operand { - fn from(s: &'a str) -> Self { - match s { - "a" => Operand::Register(0), - "b" => Operand::Register(1), - "c" => Operand::Register(2), - "d" => Operand::Register(3), - _ => Operand::Immediate(s.parse().unwrap()), - } - } -} - -#[derive(Clone, Copy)] -enum Operation { - Cpy(Operand, Operand), - Inc(Operand), - Dec(Operand), - Jnz(Operand, Operand), - Tgl(Operand), - Out(Operand), -} - -impl<'a> From<&'a str> for Operation { - fn from(s: &'a str) -> Self { - let mut iter = s.split_whitespace(); - match (iter.next().unwrap(), iter.next().unwrap()) { - ("cpy", a) => Operation::Cpy(Operand::from(a), Operand::from(iter.next().unwrap())), - ("inc", a) => Operation::Inc(Operand::from(a)), - ("dec", a) => Operation::Dec(Operand::from(a)), - ("jnz", a) => Operation::Jnz(Operand::from(a), Operand::from(iter.next().unwrap())), - ("tgl", a) => Operation::Tgl(Operand::from(a)), - ("out", a) => Operation::Out(Operand::from(a)), - _ => panic!("invalid instruction {}", s), - } - } -} - -impl Operation { - fn toggle(self) -> Self { - match self { - Operation::Inc(a) => Operation::Dec(a), - Operation::Dec(a) | Operation::Tgl(a) => Operation::Inc(a), - Operation::Jnz(a, b) => Operation::Cpy(a, b), - Operation::Cpy(a, b) => Operation::Jnz(a, b), - _ => unimplemented!(), - } - } -} - -#[derive(Default)] -struct Vm { - registers: [i32; 4], - operations: Vec<Operation>, - index: i32, - output: Vec<i32>, -} - -impl<'a> From<&'a str> for Vm { - fn from(s: &'a str) -> Self { - let mut vm = Self::default(); - for line in s.lines() { - vm.operations.push(Operation::from(line)); - } - vm - } -} - -impl Vm { - fn step(&mut self) -> bool { - match self.operations[self.index as usize] { - Operation::Cpy(Operand::Immediate(imm), Operand::Register(reg)) => { - self.registers[reg as usize] = imm; - self.index += 1; - }, - Operation::Cpy(Operand::Register(src), Operand::Register(dest)) => { - self.registers[dest as usize] = self.registers[src as usize]; - self.index += 1; - }, - Operation::Inc(Operand::Register(reg)) => { - self.registers[reg as usize] += 1; - self.index += 1; - }, - Operation::Dec(Operand::Register(reg)) => { - self.registers[reg as usize] -= 1; - self.index += 1; - }, - Operation::Jnz(Operand::Immediate(cond), Operand::Immediate(jump)) => { - if cond != 0 { - self.index += jump; - } else { - self.index += 1; - } - }, - Operation::Jnz(Operand::Register(reg), Operand::Immediate(jump)) => { - if self.registers[reg as usize] != 0 { - self.index += jump; - } else { - self.index += 1; - } - }, - Operation::Jnz(Operand::Immediate(cond), Operand::Register(reg)) => { - if cond != 0 { - self.index += self.registers[reg as usize]; - } else { - self.index += 1; - } - }, - Operation::Tgl(Operand::Register(reg)) => { - let index = self.index + self.registers[reg as usize]; - if let Some(operation) = self.operations.get_mut(index as usize) { - *operation = operation.toggle(); - } - self.index += 1; - }, - Operation::Out(Operand::Immediate(imm)) => { - self.output.push(imm); - self.index += 1; - }, - Operation::Out(Operand::Register(reg)) => { - self.output.push(self.registers[reg as usize]); - self.index += 1; - }, - _ => { - self.index += 1; - }, - } - - (self.index as usize) < self.operations.len() - } -} - -fn solve(input: &str) -> i32 { - for i in 0.. { - let mut vm = Vm::from(input); - vm.registers[0] = i; - while vm.output.len() < 50 { - assert!(vm.step()); - } - - let target = iter::once(0).chain(iter::once(1)).cycle().take(50); - if vm.output.into_iter().eq(target) { - return i; - } - } - - unreachable!() -} - -fn main() { - let mut input = String::new(); - io::stdin().read_to_string(&mut input).unwrap(); - - println!("Part 1: {}", solve(&input)); -} |