@@ 0,0 1,246 @@
+use std::{
+ fs::File,
+ io::{BufRead, BufReader},
+ path::Path,
+ str::FromStr,
+};
+
+pub fn solve(input: &Path) -> anyhow::Result<()> {
+ println!("part one: {}", part_one(input)?);
+ println!("part two: {}", part_two(input)?);
+
+ Ok(())
+}
+
+#[derive(Debug)]
+enum ProgramPart {
+ Instruction(Ins),
+ LiteralOperand(usize),
+}
+
+#[derive(Debug)]
+enum Ins {
+ Adv,
+ Bxl,
+ Bst,
+ Jnz,
+ Bxc,
+ Out,
+ Bdv,
+ Cdv,
+}
+
+impl FromStr for Ins {
+ type Err = Box<dyn std::error::Error>;
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ match s {
+ "0" => Ok(Self::Adv),
+ "1" => Ok(Self::Bxl),
+ "2" => Ok(Self::Bst),
+ "3" => Ok(Self::Jnz),
+ "4" => Ok(Self::Bxc),
+ "5" => Ok(Self::Out),
+ "6" => Ok(Self::Bdv),
+ "7" => Ok(Self::Cdv),
+ _ => unreachable!(),
+ }
+ }
+}
+
+#[derive(Debug)]
+enum Copr {
+ Literal(usize),
+ RA,
+ RB,
+ RC,
+}
+
+impl Copr {
+ fn from_usize(n: usize) -> Self {
+ match n {
+ 0 => Self::Literal(0),
+ 1 => Self::Literal(1),
+ 2 => Self::Literal(2),
+ 3 => Self::Literal(3),
+ 4 => Self::RA,
+ 5 => Self::RB,
+ 6 => Self::RC,
+ _ => unreachable!(),
+ }
+ }
+
+ fn real(&self, ra: i32, rb: i32, rc: i32) -> i32 {
+ match self {
+ Self::Literal(n) => *n as i32,
+ Self::RA => ra,
+ Self::RB => rb,
+ Self::RC => rc,
+ }
+ }
+}
+
+fn part_one(input: &Path) -> anyhow::Result<String> {
+ let reader = BufReader::new(File::open(input)?);
+
+ let mut ra: i32 = 0;
+ let mut rb: i32 = 0;
+ let mut rc: i32 = 0;
+ let mut program: Vec<ProgramPart> = vec![];
+ for line in reader.lines() {
+ let line = line?;
+ if line.starts_with("Register A") {
+ ra = line.split_whitespace().last().unwrap().parse()?;
+ } else if line.starts_with("Register B") {
+ rb = line.split_whitespace().last().unwrap().parse()?;
+ } else if line.starts_with("Register C") {
+ rc = line.split_whitespace().last().unwrap().parse()?;
+ } else if line.starts_with("Program") {
+ program.append(
+ &mut line
+ .split_whitespace()
+ .last()
+ .unwrap()
+ .split(",")
+ .enumerate()
+ .filter_map(|(i, c)| {
+ if c == "," {
+ None
+ } else if i % 2 == 0 {
+ Some(ProgramPart::Instruction(c.parse().unwrap()))
+ } else {
+ Some(ProgramPart::LiteralOperand(c.parse().unwrap()))
+ }
+ })
+ .collect::<Vec<_>>(),
+ );
+ }
+ }
+
+ let mut out: Vec<i32> = vec![];
+ let mut ptr = 0;
+ while ptr < program.len() {
+ let mut incr = true;
+
+ if let ProgramPart::Instruction(ins) = &program[ptr] {
+ if let ProgramPart::LiteralOperand(lit_opr) = &program[ptr + 1] {
+ let combo_opr = Copr::from_usize(*lit_opr).real(ra, rb, rc);
+ match &ins {
+ Ins::Adv => ra /= 2_i32.pow(combo_opr as u32),
+ Ins::Bxl => rb ^= *lit_opr as i32,
+ Ins::Bst => rb = combo_opr % 8,
+ Ins::Jnz => {
+ if ra != 0 {
+ ptr = *lit_opr;
+ incr = false;
+ }
+ }
+ Ins::Bxc => rb ^= rc,
+ Ins::Out => out.push(combo_opr % 8),
+ Ins::Bdv => rb = ra / 2_i32.pow(combo_opr as u32),
+ Ins::Cdv => rc = ra / 2_i32.pow(combo_opr as u32),
+ }
+ } else {
+ unreachable!();
+ }
+ } else {
+ unreachable!();
+ }
+
+ if incr {
+ ptr += 2;
+ }
+ }
+
+ Ok(out
+ .iter()
+ .map(|o| o.to_string())
+ .collect::<Vec<_>>()
+ .join(","))
+}
+
+fn part_two(input: &Path) -> anyhow::Result<i32> {
+ let reader = BufReader::new(File::open(input)?);
+
+ let mut original_program = String::new();
+ let mut program: Vec<ProgramPart> = vec![];
+ for line in reader.lines() {
+ let line = line?;
+ if line.starts_with("Program") {
+ original_program = line.split_whitespace().last().unwrap().into();
+ program = original_program
+ .clone()
+ .split(",")
+ .enumerate()
+ .filter_map(|(i, c)| {
+ if c == "," {
+ None
+ } else if i % 2 == 0 {
+ Some(ProgramPart::Instruction(c.parse().unwrap()))
+ } else {
+ Some(ProgramPart::LiteralOperand(c.parse().unwrap()))
+ }
+ })
+ .collect::<Vec<_>>();
+ }
+ }
+
+ let mut ra_init = 8;
+ let mut ra: i32;
+ let mut rb: i32;
+ let mut rc: i32;
+ loop {
+ ra_init += 1;
+ ra = ra_init;
+ rb = 0;
+ rc = 0;
+
+ println!("trying {}", ra_init);
+
+ let mut out: Vec<i32> = vec![];
+ let mut ptr = 0;
+ while ptr < program.len() {
+ let mut incr = true;
+
+ if let ProgramPart::Instruction(ins) = &program[ptr] {
+ if let ProgramPart::LiteralOperand(lit_opr) = &program[ptr + 1] {
+ let combo_opr = Copr::from_usize(*lit_opr).real(ra, rb, rc);
+ match &ins {
+ Ins::Adv => ra /= 2_i32.pow(combo_opr as u32),
+ Ins::Bxl => rb ^= *lit_opr as i32,
+ Ins::Bst => rb = combo_opr % 8,
+ Ins::Jnz => {
+ if ra != 0 {
+ ptr = *lit_opr;
+ incr = false;
+ }
+ }
+ Ins::Bxc => rb ^= rc,
+ Ins::Out => out.push(combo_opr % 8),
+ Ins::Bdv => rb = ra / 2_i32.pow(combo_opr as u32),
+ Ins::Cdv => rc = ra / 2_i32.pow(combo_opr as u32),
+ }
+ } else {
+ unreachable!();
+ }
+ } else {
+ unreachable!();
+ }
+
+ if incr {
+ ptr += 2;
+ }
+ }
+
+ let out_str = out
+ .iter()
+ .map(|o| o.to_string())
+ .collect::<Vec<_>>()
+ .join(",");
+
+ if out_str == original_program {
+ break;
+ }
+ }
+
+ Ok(ra_init)
+}
@@ 9,6 9,7 @@ mod day12;
mod day13;
mod day14;
mod day15;
+mod day17;
mod day2;
mod day3;
mod day4;
@@ 86,6 87,10 @@ enum DayArgs {
#[arg(short)]
input: PathBuf,
},
+ Day17 {
+ #[arg(short)]
+ input: PathBuf,
+ },
}
fn main() -> anyhow::Result<()> {
@@ 137,6 142,9 @@ fn main() -> anyhow::Result<()> {
DayArgs::Day15 { input } => {
day15::solve(&input)?;
}
+ DayArgs::Day17 { input } => {
+ day17::solve(&input)?;
+ }
}
Ok(())