diff options
author | cos <cos> | 2022-12-12 17:19:18 +0000 |
---|---|---|
committer | cos <cos> | 2022-12-12 18:00:46 +0000 |
commit | aefd26f3d7bf22bbc3f29c1f2cb18e91c28cf363 (patch) | |
tree | 154fd5994ae58992b3d286a50d8cd7c54b3d84ea /2022 | |
parent | 670d30b709b730000ea7af7057bdf0023c8d7f07 (diff) | |
download | adventofcode-aefd26f3d7bf22bbc3f29c1f2cb18e91c28cf363.zip |
Add day10, 2022
Diffstat (limited to '2022')
-rw-r--r-- | 2022/rust/Cargo.toml | 2 | ||||
-rw-r--r-- | 2022/rust/day10/Cargo.toml | 9 | ||||
-rw-r--r-- | 2022/rust/day10/src/main.rs | 179 |
3 files changed, 189 insertions, 1 deletions
diff --git a/2022/rust/Cargo.toml b/2022/rust/Cargo.toml index f43b72b..6b9f1b1 100644 --- a/2022/rust/Cargo.toml +++ b/2022/rust/Cargo.toml @@ -9,7 +9,7 @@ members = [ "day07", "day08", "day09", -# "day10", + "day10", # "day11", # "day12", # "day13", diff --git a/2022/rust/day10/Cargo.toml b/2022/rust/day10/Cargo.toml new file mode 100644 index 0000000..6dde952 --- /dev/null +++ b/2022/rust/day10/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "day10" +version = "0.1.0" +edition = "2021" + +[dependencies] +aoc = { path = "../../../common/rust/aoc" } +anyhow = "1.0" +regex = "1.7.0" diff --git a/2022/rust/day10/src/main.rs b/2022/rust/day10/src/main.rs new file mode 100644 index 0000000..426be03 --- /dev/null +++ b/2022/rust/day10/src/main.rs @@ -0,0 +1,179 @@ +use { + anyhow::{ + anyhow, + Context, + Result, + }, + regex::Regex, + std::{ + env::args, + fs::File, + io::{ + BufRead, + BufReader, + }, + path::Path, + }, +}; + +#[derive(Clone,Copy)] +enum Instruction { + Addx(isize), + Noop, +} + +impl Instruction { + fn cycles(&self) -> usize { + match self { + Instruction::Addx(_) => 2, + Instruction::Noop => 1, + } + } +} + +#[derive(Clone)] +struct Program { + inner: Vec<Instruction>, +} + +impl Program { + fn instruction(&self, cycle: usize) -> Option<Instruction> { + let mut counter = 0; + + for instruction in self.inner.iter() { + counter += instruction.cycles(); + match counter { + c if c == cycle => return Some(*instruction), + c if c > cycle => return None, + _ => { }, + } + } + None + } +} + +struct Registers { + x: isize, +} + +impl Registers { + fn new() -> Self { + Self { + x: 1, + } + } +} + +struct Cpu { + cycle: usize, + program: Program, + registers: Registers, +} + +impl Cpu { + fn new(program: Program) -> Self { + let registers = Registers::new(); + + Self { + cycle: 0, + program, + registers, + } + } + + fn step(&mut self) { + if let Some(instruction) = self.program.instruction(self.cycle) { + match instruction { + Instruction::Addx(argument) => self.registers.x += argument, + Instruction::Noop => { }, + } + } + self.cycle += 1; + } + + fn signal_strength(&self) -> isize { + self.registers.x * self.cycle as isize + } + + fn pixel(&self) -> String { + if ((self.registers.x - 1)..=(self.registers.x + 1)) + .contains(&((self.cycle - 1) as isize % 40)) + { + String::from("#") + } else { + String::from(".") + } + } +} + +fn read_input<T: AsRef<Path>>(filename: T) -> Result<Program> { + let reader = BufReader::new(File::open(filename)?); + let re = Regex::new(r#"(?x)^ + (?P<instruction>(addx)|(noop)) + ( + \s + (?P<argument>[0-9-]+) + )? + $"#)?; + + let instructions = reader.lines().map( + |v| { + let s = v?; + let caps = re.captures(&s).ok_or_else(|| anyhow!("Could not parse: {s}"))?; + let instruction = caps.name("instruction").unwrap_or_else(|| unreachable!()).as_str(); + let argument = caps.name("argument").map(|a| a.as_str()).unwrap_or_default(); + match instruction { + "addx" => Ok(Instruction::Addx(argument.parse()?)), + "noop" => Ok(Instruction::Noop), + _ => unreachable!(), + } + } + ).collect::<Result<Vec<_>>>()?; + + Ok(Program { inner: instructions }) +} + +fn part1(input: &Program) -> Result<isize> { + let mut cpu = Cpu::new(input.clone()); + let mut sum = 0; + + for i in 0..=220 { + if [20, 60, 100, 140, 180, 220].contains(&i) { + sum += cpu.signal_strength(); + } + cpu.step(); + } + + Ok(sum) +} + +fn part2(input: &Program) -> Result<String> { + let mut cpu = Cpu::new(input.clone()); + let mut output = String::default(); + + for i in 0..240 { + cpu.step(); + if i % 40 == 0 { + output += "\n"; + } + output += &cpu.pixel(); + } + + Ok(output) +} + +fn main() -> Result<()> { + let ( do_part_1, do_part_2 ) = aoc::do_parts(); + + let filename = args().nth(1).ok_or_else(|| anyhow!("Missing input filename"))?; + let input = read_input(filename).context("Could not read input")?; + if do_part_1 { + let solution = part1(&input).context("No solution for part 1")?; + println!("Part1, solution found to be: {}", solution); + } + if do_part_2 { + let solution = part2(&input).context("No solution for part 2")?; + println!("Part2, solution found to be: {}", solution); + } + Ok(()) +} |