mirror of
https://github.com/Smaug123/advent-of-code-2017
synced 2025-10-08 21:18:39 +00:00
Split days 12 through 23 into lib/main (#4)
This commit is contained in:
331
day_23/src/lib.rs
Normal file
331
day_23/src/lib.rs
Normal file
@@ -0,0 +1,331 @@
|
||||
pub mod day_23 {
|
||||
|
||||
pub enum Instruction {
|
||||
Set(char, i32),
|
||||
SetTo(char, char),
|
||||
Sub(char, i32),
|
||||
SubBy(char, char),
|
||||
Mul(char, i32),
|
||||
MulBy(char, char),
|
||||
Jnz(char, i32),
|
||||
JnzExact(i32, i32),
|
||||
}
|
||||
|
||||
fn parse(s: &str) -> Instruction {
|
||||
let mut s = s.split_whitespace();
|
||||
match s.next().unwrap() {
|
||||
"sub" => {
|
||||
let register = {
|
||||
let mut chars = s.next().unwrap().chars();
|
||||
let result = chars.next().unwrap();
|
||||
match chars.next() {
|
||||
Some(i) => panic!("Expected a register, got another char: {}", i),
|
||||
None => result,
|
||||
}
|
||||
};
|
||||
let last = s.next().unwrap();
|
||||
match s.next() {
|
||||
Some(i) => panic!("Expected no more tokens, got {}", i),
|
||||
None => match last.parse::<i32>() {
|
||||
Ok(i) => Instruction::Sub(register, i),
|
||||
Err(_) => {
|
||||
let mut chars = last.chars();
|
||||
let target = chars.next().unwrap();
|
||||
match chars.next() {
|
||||
Some(i) => panic!(
|
||||
"Expected only a one-length register, got another char: {}",
|
||||
i
|
||||
),
|
||||
None => Instruction::SubBy(register, target),
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
"set" => {
|
||||
let register = {
|
||||
let mut chars = s.next().unwrap().chars();
|
||||
let result = chars.next().unwrap();
|
||||
match chars.next() {
|
||||
Some(i) => panic!("Expected a register, got another char: {}", i),
|
||||
None => result,
|
||||
}
|
||||
};
|
||||
let last = s.next().unwrap();
|
||||
match s.next() {
|
||||
Some(i) => panic!("Expected no more tokens, got {}", i),
|
||||
None => match last.parse::<i32>() {
|
||||
Ok(i) => Instruction::Set(register, i),
|
||||
Err(_) => {
|
||||
let mut chars = last.chars();
|
||||
let target = chars.next().unwrap();
|
||||
match chars.next() {
|
||||
Some(i) => panic!(
|
||||
"Expected only a one-length register, got another char: {}",
|
||||
i
|
||||
),
|
||||
None => Instruction::SetTo(register, target),
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
"mul" => {
|
||||
let register = {
|
||||
let mut chars = s.next().unwrap().chars();
|
||||
let result = chars.next().unwrap();
|
||||
match chars.next() {
|
||||
Some(i) => panic!("Expected a register, got another char: {}", i),
|
||||
None => result,
|
||||
}
|
||||
};
|
||||
let last = s.next().unwrap();
|
||||
match s.next() {
|
||||
Some(i) => panic!("Expected no more tokens, got {}", i),
|
||||
None => match last.parse::<i32>() {
|
||||
Ok(i) => Instruction::Mul(register, i),
|
||||
Err(_) => {
|
||||
let mut chars = last.chars();
|
||||
let target = chars.next().unwrap();
|
||||
match chars.next() {
|
||||
Some(i) => panic!(
|
||||
"Expected only a one-length register, got another char: {}",
|
||||
i
|
||||
),
|
||||
None => Instruction::MulBy(register, target),
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
"jnz" => {
|
||||
let register = s.next().unwrap();
|
||||
let last = s.next().unwrap().parse::<i32>().unwrap();
|
||||
if let Some(i) = s.next() {
|
||||
panic!("Expected no more tokens, got {}", i);
|
||||
}
|
||||
match register.parse::<i32>() {
|
||||
Ok(register) => Instruction::JnzExact(register, last),
|
||||
Err(_) => {
|
||||
let mut chars = register.chars();
|
||||
let result = chars.next().unwrap();
|
||||
match chars.next() {
|
||||
Some(i) => panic!("Expected a register, got another char: {}", i),
|
||||
None => Instruction::Jnz(result, last),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
instr => panic!("Unrecognised instruction: {}", instr),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn input() -> Vec<Instruction> {
|
||||
let input = include_str!("../input.txt");
|
||||
input
|
||||
.lines()
|
||||
.map(|l| parse(l.trim()))
|
||||
.collect::<Vec<Instruction>>()
|
||||
}
|
||||
|
||||
struct Machine<'a> {
|
||||
registers: Vec<i32>,
|
||||
pc: usize,
|
||||
program: &'a [Instruction],
|
||||
}
|
||||
|
||||
fn to_index(i: char) -> usize {
|
||||
((i as u8) - b'a') as usize
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
struct Registers {
|
||||
a: i32,
|
||||
b: i32,
|
||||
c: i32,
|
||||
d: i32,
|
||||
e: i32,
|
||||
f: i32,
|
||||
g: i32,
|
||||
h: i32,
|
||||
}
|
||||
|
||||
fn return_it(registers: &[i32]) -> Registers {
|
||||
Registers {
|
||||
a: registers[0],
|
||||
b: registers[1],
|
||||
c: registers[2],
|
||||
d: registers[3],
|
||||
e: registers[4],
|
||||
f: registers[5],
|
||||
g: registers[6],
|
||||
h: registers[7],
|
||||
}
|
||||
}
|
||||
|
||||
// Performs one step, and returns true for a `mul` and false otherwise.
|
||||
impl Iterator for Machine<'_> {
|
||||
type Item = (bool, Registers);
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.pc >= self.program.len() {
|
||||
return None;
|
||||
}
|
||||
match self.program[self.pc] {
|
||||
Instruction::Sub(r, i) => {
|
||||
self.registers[to_index(r)] -= i;
|
||||
self.pc += 1;
|
||||
Some((false, return_it(&self.registers)))
|
||||
}
|
||||
Instruction::SubBy(r, s) => {
|
||||
self.registers[to_index(r)] -= self.registers[to_index(s)];
|
||||
self.pc += 1;
|
||||
Some((false, return_it(&self.registers)))
|
||||
}
|
||||
Instruction::Mul(r, i) => {
|
||||
self.registers[to_index(r)] *= i;
|
||||
self.pc += 1;
|
||||
Some((true, return_it(&self.registers)))
|
||||
}
|
||||
Instruction::MulBy(r, s) => {
|
||||
self.registers[to_index(r)] *= self.registers[to_index(s)];
|
||||
self.pc += 1;
|
||||
Some((true, return_it(&self.registers)))
|
||||
}
|
||||
Instruction::Set(r, i) => {
|
||||
self.registers[to_index(r)] = i;
|
||||
self.pc += 1;
|
||||
Some((false, return_it(&self.registers)))
|
||||
}
|
||||
Instruction::SetTo(r, s) => {
|
||||
self.registers[to_index(r)] = self.registers[to_index(s)];
|
||||
self.pc += 1;
|
||||
Some((false, return_it(&self.registers)))
|
||||
}
|
||||
Instruction::Jnz(r, offset) => {
|
||||
if self.registers[to_index(r)] != 0 {
|
||||
let target = self.pc as i32 + offset;
|
||||
if target < 0 || target >= self.program.len() as i32 {
|
||||
None
|
||||
} else {
|
||||
self.pc = target as usize;
|
||||
Some((false, return_it(&self.registers)))
|
||||
}
|
||||
} else {
|
||||
self.pc += 1;
|
||||
Some((false, return_it(&self.registers)))
|
||||
}
|
||||
}
|
||||
Instruction::JnzExact(r, offset) => {
|
||||
if r != 0 {
|
||||
let target = self.pc as i32 + offset;
|
||||
if target < 0 || target >= self.program.len() as i32 {
|
||||
None
|
||||
} else {
|
||||
self.pc = target as usize;
|
||||
Some((false, return_it(&self.registers)))
|
||||
}
|
||||
} else {
|
||||
self.pc += 1;
|
||||
Some((false, return_it(&self.registers)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn part_1(instructions: &[Instruction]) -> usize {
|
||||
let machine = Machine {
|
||||
registers: vec![0; 8],
|
||||
pc: 0,
|
||||
program: instructions,
|
||||
};
|
||||
machine.filter(|(i, _)| *i).count()
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn part_2_dumb(instructions: &[Instruction]) -> i32 {
|
||||
let mut registers = vec![0; 8];
|
||||
registers[0] = 1;
|
||||
let machine = Machine {
|
||||
registers,
|
||||
pc: 0,
|
||||
program: instructions,
|
||||
};
|
||||
machine.map(|(_, registers)| registers.h).last().unwrap()
|
||||
}
|
||||
|
||||
fn is_composite(i: u32) -> bool {
|
||||
if i % 2 == 0 {
|
||||
return i != 2;
|
||||
}
|
||||
if i % 3 == 0 {
|
||||
return i != 3;
|
||||
}
|
||||
let mut factor = 5;
|
||||
while factor * factor <= i {
|
||||
if i % factor == 0 {
|
||||
return true;
|
||||
}
|
||||
factor += 2;
|
||||
if factor * factor <= i && i % factor == 0 {
|
||||
return true;
|
||||
}
|
||||
factor += 4;
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
struct StepUp {
|
||||
value: u32,
|
||||
increment: u32,
|
||||
max: u32,
|
||||
}
|
||||
|
||||
fn new_stepup(b: u32, c: u32, step: u32) -> StepUp {
|
||||
StepUp {
|
||||
value: b - step,
|
||||
increment: step,
|
||||
max: c - step,
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for StepUp {
|
||||
type Item = u32;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.value > self.max {
|
||||
None
|
||||
} else {
|
||||
self.value += self.increment;
|
||||
Some(self.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn part_2(instructions: &[Instruction]) -> usize {
|
||||
let mut registers = vec![0; 8];
|
||||
registers[0] = 1;
|
||||
let machine = Machine {
|
||||
registers,
|
||||
pc: 0,
|
||||
program: instructions,
|
||||
};
|
||||
let (_, registers) = machine.take(10).last().unwrap();
|
||||
|
||||
new_stepup(registers.b as u32, registers.c as u32, 17)
|
||||
.filter(|i| is_composite(*i))
|
||||
.count()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::day_23::*;
|
||||
|
||||
#[test]
|
||||
fn test_day_23() {
|
||||
let input = input();
|
||||
assert_eq!(part_1(&input), 5929);
|
||||
assert_eq!(part_2(&input), 907);
|
||||
}
|
||||
}
|
@@ -1,334 +1,7 @@
|
||||
enum Instruction {
|
||||
Set(char, i32),
|
||||
SetTo(char, char),
|
||||
Sub(char, i32),
|
||||
SubBy(char, char),
|
||||
Mul(char, i32),
|
||||
MulBy(char, char),
|
||||
Jnz(char, i32),
|
||||
JnzExact(i32, i32),
|
||||
}
|
||||
|
||||
fn parse(s: &str) -> Instruction {
|
||||
let mut s = s.split_whitespace();
|
||||
match s.next().unwrap() {
|
||||
"sub" => {
|
||||
let register = {
|
||||
let mut chars = s.next().unwrap().chars();
|
||||
let result = chars.next().unwrap();
|
||||
match chars.next() {
|
||||
Some(i) => panic!("Expected a register, got another char: {}", i),
|
||||
None => result,
|
||||
}
|
||||
};
|
||||
let last = s.next().unwrap();
|
||||
match s.next() {
|
||||
Some(i) => panic!("Expected no more tokens, got {}", i),
|
||||
None => match last.parse::<i32>() {
|
||||
Ok(i) => Instruction::Sub(register, i),
|
||||
Err(_) => {
|
||||
let mut chars = last.chars();
|
||||
let target = chars.next().unwrap();
|
||||
match chars.next() {
|
||||
Some(i) => panic!(
|
||||
"Expected only a one-length register, got another char: {}",
|
||||
i
|
||||
),
|
||||
None => Instruction::SubBy(register, target),
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
"set" => {
|
||||
let register = {
|
||||
let mut chars = s.next().unwrap().chars();
|
||||
let result = chars.next().unwrap();
|
||||
match chars.next() {
|
||||
Some(i) => panic!("Expected a register, got another char: {}", i),
|
||||
None => result,
|
||||
}
|
||||
};
|
||||
let last = s.next().unwrap();
|
||||
match s.next() {
|
||||
Some(i) => panic!("Expected no more tokens, got {}", i),
|
||||
None => match last.parse::<i32>() {
|
||||
Ok(i) => Instruction::Set(register, i),
|
||||
Err(_) => {
|
||||
let mut chars = last.chars();
|
||||
let target = chars.next().unwrap();
|
||||
match chars.next() {
|
||||
Some(i) => panic!(
|
||||
"Expected only a one-length register, got another char: {}",
|
||||
i
|
||||
),
|
||||
None => Instruction::SetTo(register, target),
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
"mul" => {
|
||||
let register = {
|
||||
let mut chars = s.next().unwrap().chars();
|
||||
let result = chars.next().unwrap();
|
||||
match chars.next() {
|
||||
Some(i) => panic!("Expected a register, got another char: {}", i),
|
||||
None => result,
|
||||
}
|
||||
};
|
||||
let last = s.next().unwrap();
|
||||
match s.next() {
|
||||
Some(i) => panic!("Expected no more tokens, got {}", i),
|
||||
None => match last.parse::<i32>() {
|
||||
Ok(i) => Instruction::Mul(register, i),
|
||||
Err(_) => {
|
||||
let mut chars = last.chars();
|
||||
let target = chars.next().unwrap();
|
||||
match chars.next() {
|
||||
Some(i) => panic!(
|
||||
"Expected only a one-length register, got another char: {}",
|
||||
i
|
||||
),
|
||||
None => Instruction::MulBy(register, target),
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
"jnz" => {
|
||||
let register = s.next().unwrap();
|
||||
let last = s.next().unwrap().parse::<i32>().unwrap();
|
||||
if let Some(i) = s.next() {
|
||||
panic!("Expected no more tokens, got {}", i);
|
||||
}
|
||||
match register.parse::<i32>() {
|
||||
Ok(register) => Instruction::JnzExact(register, last),
|
||||
Err(_) => {
|
||||
let mut chars = register.chars();
|
||||
let result = chars.next().unwrap();
|
||||
match chars.next() {
|
||||
Some(i) => panic!("Expected a register, got another char: {}", i),
|
||||
None => Instruction::Jnz(result, last),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
instr => panic!("Unrecognised instruction: {}", instr),
|
||||
}
|
||||
}
|
||||
|
||||
fn input() -> Vec<Instruction> {
|
||||
let input = include_str!("../input.txt");
|
||||
input
|
||||
.lines()
|
||||
.map(|l| parse(l.trim()))
|
||||
.collect::<Vec<Instruction>>()
|
||||
}
|
||||
|
||||
struct Machine<'a> {
|
||||
registers: Vec<i32>,
|
||||
pc: usize,
|
||||
program: &'a [Instruction],
|
||||
}
|
||||
|
||||
fn to_index(i: char) -> usize {
|
||||
((i as u8) - b'a') as usize
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
struct Registers {
|
||||
a: i32,
|
||||
b: i32,
|
||||
c: i32,
|
||||
d: i32,
|
||||
e: i32,
|
||||
f: i32,
|
||||
g: i32,
|
||||
h: i32,
|
||||
}
|
||||
|
||||
fn return_it(registers: &[i32]) -> Registers {
|
||||
Registers {
|
||||
a: registers[0],
|
||||
b: registers[1],
|
||||
c: registers[2],
|
||||
d: registers[3],
|
||||
e: registers[4],
|
||||
f: registers[5],
|
||||
g: registers[6],
|
||||
h: registers[7],
|
||||
}
|
||||
}
|
||||
|
||||
// Performs one step, and returns true for a `mul` and false otherwise.
|
||||
impl Iterator for Machine<'_> {
|
||||
type Item = (bool, Registers);
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.pc >= self.program.len() {
|
||||
return None;
|
||||
}
|
||||
match self.program[self.pc] {
|
||||
Instruction::Sub(r, i) => {
|
||||
self.registers[to_index(r)] -= i;
|
||||
self.pc += 1;
|
||||
Some((false, return_it(&self.registers)))
|
||||
}
|
||||
Instruction::SubBy(r, s) => {
|
||||
self.registers[to_index(r)] -= self.registers[to_index(s)];
|
||||
self.pc += 1;
|
||||
Some((false, return_it(&self.registers)))
|
||||
}
|
||||
Instruction::Mul(r, i) => {
|
||||
self.registers[to_index(r)] *= i;
|
||||
self.pc += 1;
|
||||
Some((true, return_it(&self.registers)))
|
||||
}
|
||||
Instruction::MulBy(r, s) => {
|
||||
self.registers[to_index(r)] *= self.registers[to_index(s)];
|
||||
self.pc += 1;
|
||||
Some((true, return_it(&self.registers)))
|
||||
}
|
||||
Instruction::Set(r, i) => {
|
||||
self.registers[to_index(r)] = i;
|
||||
self.pc += 1;
|
||||
Some((false, return_it(&self.registers)))
|
||||
}
|
||||
Instruction::SetTo(r, s) => {
|
||||
self.registers[to_index(r)] = self.registers[to_index(s)];
|
||||
self.pc += 1;
|
||||
Some((false, return_it(&self.registers)))
|
||||
}
|
||||
Instruction::Jnz(r, offset) => {
|
||||
if self.registers[to_index(r)] != 0 {
|
||||
let target = self.pc as i32 + offset;
|
||||
if target < 0 || target >= self.program.len() as i32 {
|
||||
None
|
||||
} else {
|
||||
self.pc = target as usize;
|
||||
Some((false, return_it(&self.registers)))
|
||||
}
|
||||
} else {
|
||||
self.pc += 1;
|
||||
Some((false, return_it(&self.registers)))
|
||||
}
|
||||
}
|
||||
Instruction::JnzExact(r, offset) => {
|
||||
if r != 0 {
|
||||
let target = self.pc as i32 + offset;
|
||||
if target < 0 || target >= self.program.len() as i32 {
|
||||
None
|
||||
} else {
|
||||
self.pc = target as usize;
|
||||
Some((false, return_it(&self.registers)))
|
||||
}
|
||||
} else {
|
||||
self.pc += 1;
|
||||
Some((false, return_it(&self.registers)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn part_1(instructions: &[Instruction]) -> usize {
|
||||
let machine = Machine {
|
||||
registers: vec![0; 8],
|
||||
pc: 0,
|
||||
program: instructions,
|
||||
};
|
||||
machine.filter(|(i, _)| *i).count()
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn part_2_dumb(instructions: &[Instruction]) -> i32 {
|
||||
let mut registers = vec![0; 8];
|
||||
registers[0] = 1;
|
||||
let machine = Machine {
|
||||
registers,
|
||||
pc: 0,
|
||||
program: instructions,
|
||||
};
|
||||
machine.map(|(_, registers)| registers.h).last().unwrap()
|
||||
}
|
||||
|
||||
fn is_composite(i: u32) -> bool {
|
||||
if i % 2 == 0 {
|
||||
return i != 2;
|
||||
}
|
||||
if i % 3 == 0 {
|
||||
return i != 3;
|
||||
}
|
||||
let mut factor = 5;
|
||||
while factor * factor <= i {
|
||||
if i % factor == 0 {
|
||||
return true;
|
||||
}
|
||||
factor += 2;
|
||||
if factor * factor <= i && i % factor == 0 {
|
||||
return true;
|
||||
}
|
||||
factor += 4;
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
struct StepUp {
|
||||
value: u32,
|
||||
increment: u32,
|
||||
max: u32,
|
||||
}
|
||||
|
||||
fn new_stepup(b: u32, c: u32, step: u32) -> StepUp {
|
||||
StepUp {
|
||||
value: b - step,
|
||||
increment: step,
|
||||
max: c - step,
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for StepUp {
|
||||
type Item = u32;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.value > self.max {
|
||||
None
|
||||
} else {
|
||||
self.value += self.increment;
|
||||
Some(self.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn part_2(instructions: &[Instruction]) -> usize {
|
||||
let mut registers = vec![0; 8];
|
||||
registers[0] = 1;
|
||||
let machine = Machine {
|
||||
registers,
|
||||
pc: 0,
|
||||
program: instructions,
|
||||
};
|
||||
let (_, registers) = machine.take(10).last().unwrap();
|
||||
|
||||
new_stepup(registers.b as u32, registers.c as u32, 17)
|
||||
.filter(|i| is_composite(*i))
|
||||
.count()
|
||||
}
|
||||
use day_23::day_23;
|
||||
|
||||
fn main() {
|
||||
let input = input();
|
||||
println!("part 1 => {}", part_1(&input));
|
||||
println!("part 2 => {}", part_2(&input));
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_day_23() {
|
||||
let input = input();
|
||||
assert_eq!(part_1(&input), 5929);
|
||||
assert_eq!(part_2(&input), 907);
|
||||
}
|
||||
let input = day_23::input();
|
||||
println!("part 1 => {}", day_23::part_1(&input));
|
||||
println!("part 2 => {}", day_23::part_2(&input));
|
||||
}
|
||||
|
Reference in New Issue
Block a user