add day7
This commit is contained in:
parent
dadd414faa
commit
01e15eccec
2 changed files with 359 additions and 1 deletions
|
@ -25,3 +25,7 @@ path = "src/day4/main.rs"
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "day5"
|
name = "day5"
|
||||||
path = "src/day5/main.rs"
|
path = "src/day5/main.rs"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "day7"
|
||||||
|
path = "src/day7/main.rs"
|
354
src/day7/main.rs
Normal file
354
src/day7/main.rs
Normal file
|
@ -0,0 +1,354 @@
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
use std::env;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{self, BufRead, BufReader};
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
enum Mode {
|
||||||
|
Position,
|
||||||
|
Immediate,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Mode {
|
||||||
|
fn default() -> Self {
|
||||||
|
Mode::Position
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<bool> for Mode {
|
||||||
|
fn from(b: bool) -> Self {
|
||||||
|
match b {
|
||||||
|
false => Mode::Position,
|
||||||
|
true => Mode::Immediate,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Default, Debug)]
|
||||||
|
struct Modes {
|
||||||
|
a: Mode,
|
||||||
|
b: Mode,
|
||||||
|
c: Mode,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<(Mode, Mode, Mode)> for Modes {
|
||||||
|
fn from(modes: (Mode, Mode, Mode)) -> Self {
|
||||||
|
Modes {
|
||||||
|
a: modes.0,
|
||||||
|
b: modes.1,
|
||||||
|
c: modes.2,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&ModedOpcode> for Modes {
|
||||||
|
fn from(mo: &ModedOpcode) -> Self {
|
||||||
|
mo.modes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
enum Opcode {
|
||||||
|
Add,
|
||||||
|
Multiply,
|
||||||
|
Input,
|
||||||
|
Output,
|
||||||
|
JumpIfTrue,
|
||||||
|
JumpIfFalse,
|
||||||
|
LessThan,
|
||||||
|
Equals,
|
||||||
|
Halt,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&ModedOpcode> for Opcode {
|
||||||
|
fn from(mo: &ModedOpcode) -> Self {
|
||||||
|
mo.op
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<i64> for Opcode {
|
||||||
|
fn from(i: i64) -> Self {
|
||||||
|
match i {
|
||||||
|
1 => Opcode::Add,
|
||||||
|
2 => Opcode::Multiply,
|
||||||
|
3 => Opcode::Input,
|
||||||
|
4 => Opcode::Output,
|
||||||
|
5 => Opcode::JumpIfTrue,
|
||||||
|
6 => Opcode::JumpIfFalse,
|
||||||
|
7 => Opcode::LessThan,
|
||||||
|
8 => Opcode::Equals,
|
||||||
|
99 => Opcode::Halt,
|
||||||
|
_ => panic!("invalid opcode {}", i),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ModedOpcode {
|
||||||
|
modes: Modes,
|
||||||
|
op: Opcode,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<i64> for ModedOpcode {
|
||||||
|
fn from(i: i64) -> Self {
|
||||||
|
let code = i % 100;
|
||||||
|
let a = i % 1000 >= 100;
|
||||||
|
let b = i % 10000 >= 1000;
|
||||||
|
let c = i > 10000;
|
||||||
|
let modes = (Mode::from(a), Mode::from(b), Mode::from(c)).into();
|
||||||
|
ModedOpcode {
|
||||||
|
modes: modes,
|
||||||
|
op: Opcode::from(code),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Computer {
|
||||||
|
pos: usize,
|
||||||
|
program: Vec<i64>,
|
||||||
|
modes: Modes,
|
||||||
|
inputs: VecDeque<i64>,
|
||||||
|
outputs: VecDeque<i64>,
|
||||||
|
|
||||||
|
halted: bool,
|
||||||
|
paused: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Clone for Computer {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Computer::from(self.program.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<File> for Computer {
|
||||||
|
fn from(f: File) -> Self {
|
||||||
|
let f = BufReader::new(f);
|
||||||
|
let program: Vec<i64> = f
|
||||||
|
.split(b',')
|
||||||
|
.map(|o| {
|
||||||
|
let o = o.unwrap();
|
||||||
|
let mut o = o.iter().peekable();
|
||||||
|
let sign = if o.peek() == Some(&&b'-') { -1 } else { 1 };
|
||||||
|
o.filter(|i| **i >= b'0' && **i <= b'9')
|
||||||
|
.fold(0, |s, i| ((i - b'0') as i64 + 10 * s))
|
||||||
|
* sign
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
program.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Vec<i64>> for Computer {
|
||||||
|
fn from(program: Vec<i64>) -> Self {
|
||||||
|
Computer {
|
||||||
|
pos: 0,
|
||||||
|
program: program,
|
||||||
|
modes: Default::default(),
|
||||||
|
inputs: VecDeque::new(),
|
||||||
|
outputs: VecDeque::new(),
|
||||||
|
halted: false,
|
||||||
|
paused: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Computer {
|
||||||
|
fn clone_with_modified_program(&self, u: Vec<(usize, i64)>) -> Computer {
|
||||||
|
let mut computer = self.clone();
|
||||||
|
for (pos, val) in u {
|
||||||
|
computer.program[pos] = val;
|
||||||
|
}
|
||||||
|
computer
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clone_with_input(&self, input: Vec<i64>) -> Computer {
|
||||||
|
let mut computer = self.clone();
|
||||||
|
computer.inputs = input.into();
|
||||||
|
computer
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(&mut self) {
|
||||||
|
loop {
|
||||||
|
self.step();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_until_output(&mut self) -> i64 {
|
||||||
|
loop {
|
||||||
|
self.step();
|
||||||
|
if self.outputs.len() > 0 {
|
||||||
|
return self.outputs.pop_front().unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn step(&mut self) {
|
||||||
|
let instruction = self.program[self.pos];
|
||||||
|
let instruction = ModedOpcode::from(instruction);
|
||||||
|
self.modes = (&instruction).into();
|
||||||
|
let advance = match (&instruction).into() {
|
||||||
|
Opcode::Add => self.add(),
|
||||||
|
Opcode::Multiply => self.multiply(),
|
||||||
|
Opcode::Input => self.input(),
|
||||||
|
Opcode::Output => self.output(),
|
||||||
|
Opcode::JumpIfTrue => self.jump_if_true(),
|
||||||
|
Opcode::JumpIfFalse => self.jump_if_false(),
|
||||||
|
Opcode::LessThan => self.less_than(),
|
||||||
|
Opcode::Equals => self.equals(),
|
||||||
|
Opcode::Halt => self.halt(),
|
||||||
|
};
|
||||||
|
self.pos += advance;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_a(&self) -> i64 {
|
||||||
|
let a = self.program[self.pos + 1];
|
||||||
|
match self.modes.a {
|
||||||
|
Mode::Position => self.program[a as usize],
|
||||||
|
Mode::Immediate => a,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_a(&mut self, value: i64) {
|
||||||
|
let a = self.program[self.pos + 1];
|
||||||
|
match self.modes.a {
|
||||||
|
Mode::Position => self.program[a as usize] = value,
|
||||||
|
Mode::Immediate => self.program[self.pos] = value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_b(&self) -> i64 {
|
||||||
|
let b = self.program[self.pos + 2];
|
||||||
|
match self.modes.b {
|
||||||
|
Mode::Position => self.program[b as usize],
|
||||||
|
Mode::Immediate => b,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_c(&mut self, value: i64) {
|
||||||
|
let c = self.program[self.pos + 3];
|
||||||
|
match self.modes.c {
|
||||||
|
Mode::Position => self.program[c as usize] = value,
|
||||||
|
Mode::Immediate => self.program[self.pos] = value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add(&mut self) -> usize {
|
||||||
|
self.set_c(self.get_a() + self.get_b());
|
||||||
|
4
|
||||||
|
}
|
||||||
|
|
||||||
|
fn multiply(&mut self) -> usize {
|
||||||
|
self.set_c(self.get_a() * self.get_b());
|
||||||
|
4
|
||||||
|
}
|
||||||
|
|
||||||
|
fn input(&mut self) -> usize {
|
||||||
|
let value = self.inputs.pop_front().expect("no input provided");
|
||||||
|
self.set_a(value);
|
||||||
|
2
|
||||||
|
}
|
||||||
|
|
||||||
|
fn output(&mut self) -> usize {
|
||||||
|
self.outputs.push_back(self.get_a());
|
||||||
|
2
|
||||||
|
}
|
||||||
|
|
||||||
|
fn jump_if_true(&mut self) -> usize {
|
||||||
|
if self.get_a() > 0 {
|
||||||
|
self.pos = self.get_b() as usize;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
3
|
||||||
|
}
|
||||||
|
|
||||||
|
fn jump_if_false(&mut self) -> usize {
|
||||||
|
if self.get_a() == 0 {
|
||||||
|
self.pos = self.get_b() as usize;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
3
|
||||||
|
}
|
||||||
|
|
||||||
|
fn less_than(&mut self) -> usize {
|
||||||
|
if self.get_a() < self.get_b() {
|
||||||
|
self.set_c(1)
|
||||||
|
} else {
|
||||||
|
self.set_c(0)
|
||||||
|
}
|
||||||
|
4
|
||||||
|
}
|
||||||
|
|
||||||
|
fn equals(&mut self) -> usize {
|
||||||
|
if self.get_a() == self.get_b() {
|
||||||
|
self.set_c(1)
|
||||||
|
} else {
|
||||||
|
self.set_c(0)
|
||||||
|
}
|
||||||
|
4
|
||||||
|
}
|
||||||
|
|
||||||
|
fn halt(&mut self) -> usize {
|
||||||
|
self.halted = true;
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_args(elements: Vec<i64>, length: usize) -> Vec<Vec<i64>> {
|
||||||
|
let mut outs: Vec<Vec<i64>> = Vec::new();
|
||||||
|
if length == 1 {
|
||||||
|
for e in elements {
|
||||||
|
outs.push(vec![e]);
|
||||||
|
}
|
||||||
|
return outs;
|
||||||
|
}
|
||||||
|
for i in 0..length {
|
||||||
|
let current: Vec<i64> = vec![elements[i]];
|
||||||
|
let mut child_elements = elements.clone();
|
||||||
|
child_elements.remove(i);
|
||||||
|
for child in build_args(child_elements, length - 1) {
|
||||||
|
let mut current = current.clone();
|
||||||
|
current.append(&mut child.clone());
|
||||||
|
outs.push(current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
outs
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> io::Result<()> {
|
||||||
|
let filename = env::args().nth(1).expect("provide file as first param");
|
||||||
|
let computer = Computer::from(File::open(filename)?);
|
||||||
|
|
||||||
|
let orders = build_args(vec![0, 1, 2, 3, 4], 5);
|
||||||
|
let results: (i64, String) = orders
|
||||||
|
.iter()
|
||||||
|
.map(|order| {
|
||||||
|
let mut amp_a = computer.clone_with_input(vec![order[0], 0]);
|
||||||
|
let mut amp_b = computer.clone_with_input(vec![order[1], amp_a.run_until_output()]);
|
||||||
|
let mut amp_c = computer.clone_with_input(vec![order[2], amp_b.run_until_output()]);
|
||||||
|
let mut amp_d = computer.clone_with_input(vec![order[3], amp_c.run_until_output()]);
|
||||||
|
let mut amp_e = computer.clone_with_input(vec![order[4], amp_d.run_until_output()]);
|
||||||
|
(
|
||||||
|
amp_e.run_until_output(),
|
||||||
|
order
|
||||||
|
.iter()
|
||||||
|
.map(|i| i.to_string())
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
.join(""),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.fold(None, |max, (output, order)| {
|
||||||
|
Some(match max {
|
||||||
|
None => (output, order),
|
||||||
|
Some((output_max, order_max)) => {
|
||||||
|
if output > output_max {
|
||||||
|
(output, order)
|
||||||
|
} else {
|
||||||
|
(output_max, order_max)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
println!("{:?}", results);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue