add day 2 to 7
This commit is contained in:
parent
8c30eb1099
commit
f7d70ba76e
54
Cargo.lock
generated
54
Cargo.lock
generated
@ -4,3 +4,57 @@
|
|||||||
name = "day1"
|
name = "day1"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "day2"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"shared 0.1.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "day3"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "day4"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "day5"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"shared 0.1.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "day6"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "day7"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"shared 0.1.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "either"
|
||||||
|
version = "1.5.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itertools"
|
||||||
|
version = "0.8.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "shared"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3"
|
||||||
|
"checksum itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f56a2d0bc861f9165be4eb3442afd3c236d8a98afd426f65d92324ae1091a484"
|
||||||
|
@ -1,4 +1,11 @@
|
|||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
"day1",
|
"day1",
|
||||||
|
"day2",
|
||||||
|
"day3",
|
||||||
|
"day4",
|
||||||
|
"day5",
|
||||||
|
"day6",
|
||||||
|
"day7",
|
||||||
|
"shared",
|
||||||
]
|
]
|
||||||
|
@ -31,7 +31,7 @@ fn main() {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod day1test {
|
mod day1test {
|
||||||
#[test]
|
#[test]
|
||||||
fn example1() {
|
fn examples1() {
|
||||||
// Original descriptions:
|
// Original descriptions:
|
||||||
// > For a mass of 12, divide by 3 and round down to get 4, then subtract 2 to get 2.
|
// > For a mass of 12, divide by 3 and round down to get 4, then subtract 2 to get 2.
|
||||||
// > For a mass of 14, dividing by 3 and rounding down still yields 4, so the fuel required is also 2.
|
// > For a mass of 14, dividing by 3 and rounding down still yields 4, so the fuel required is also 2.
|
||||||
@ -44,7 +44,7 @@ mod day1test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn example2() {
|
fn examples2() {
|
||||||
// Original descriptions:
|
// Original descriptions:
|
||||||
// > A module of mass 14 requires 2 fuel. This fuel requires no further fuel (2 divided by 3 and rounded down is 0, which would call for a negative fuel), so the total fuel required is still just 2.
|
// > A module of mass 14 requires 2 fuel. This fuel requires no further fuel (2 divided by 3 and rounded down is 0, which would call for a negative fuel), so the total fuel required is still just 2.
|
||||||
// > At first, a module of mass 1969 requires 654 fuel. Then, this fuel requires 216 more fuel (654 / 3 - 2). 216 then requires 70 more fuel, which requires 21 fuel, which requires 5 fuel, which requires no further fuel. So, the total fuel required for a module of mass 1969 is 654 + 216 + 70 + 21 + 5 = 966.
|
// > At first, a module of mass 1969 requires 654 fuel. Then, this fuel requires 216 more fuel (654 / 3 - 2). 216 then requires 70 more fuel, which requires 21 fuel, which requires 5 fuel, which requires no further fuel. So, the total fuel required for a module of mass 1969 is 654 + 216 + 70 + 21 + 5 = 966.
|
||||||
|
10
day2/Cargo.toml
Normal file
10
day2/Cargo.toml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
[package]
|
||||||
|
name = "day2"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Stefan Bühler <stbuehler@web.de>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
shared = { path = "../shared" }
|
1
day2/src/input.txt
Normal file
1
day2/src/input.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
1,0,0,3,1,1,2,3,1,3,4,3,1,5,0,3,2,9,1,19,1,19,5,23,1,9,23,27,2,27,6,31,1,5,31,35,2,9,35,39,2,6,39,43,2,43,13,47,2,13,47,51,1,10,51,55,1,9,55,59,1,6,59,63,2,63,9,67,1,67,6,71,1,71,13,75,1,6,75,79,1,9,79,83,2,9,83,87,1,87,6,91,1,91,13,95,2,6,95,99,1,10,99,103,2,103,9,107,1,6,107,111,1,10,111,115,2,6,115,119,1,5,119,123,1,123,13,127,1,127,5,131,1,6,131,135,2,135,13,139,1,139,2,143,1,143,10,0,99,2,0,14,0
|
60
day2/src/main.rs
Normal file
60
day2/src/main.rs
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
use shared::intcode::{IntCode, CELL};
|
||||||
|
|
||||||
|
fn run(mut ic: IntCode, first: CELL, second: CELL) -> CELL {
|
||||||
|
ic.data[1] = first;
|
||||||
|
ic.data[2] = second;
|
||||||
|
ic.simulate();
|
||||||
|
ic.data[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let ic = include_str!("input.txt").parse::<IntCode>().unwrap();
|
||||||
|
println!("Run 1: {}", run(ic.clone(), 12, 2));
|
||||||
|
for limit in 0.. {
|
||||||
|
for fst in 0..limit {
|
||||||
|
let result = run(ic.clone(), fst, limit);
|
||||||
|
if result == 19690720 {
|
||||||
|
println!("Found parameters: {}", 100*fst + limit);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if limit > 0 {
|
||||||
|
for snd in 0..limit-1 {
|
||||||
|
let result = run(ic.clone(), limit, snd);
|
||||||
|
if result == 19690720 {
|
||||||
|
println!("Found parameters: {}", 100*limit + snd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod day2test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
fn parse(input: &str) -> IntCode {
|
||||||
|
input.parse().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(input: &str) -> IntCode {
|
||||||
|
let mut ic = parse(input);
|
||||||
|
ic.simulate_step().expect_finished();
|
||||||
|
ic
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn examples1() {
|
||||||
|
assert_eq!(run("1,9,10,3,2,3,11,0,99,30,40,50").data, parse("3500,9,10,70,2,3,11,0,99,30,40,50").data);
|
||||||
|
assert_eq!(run("1,0,0,0,99").data, parse("2,0,0,0,99").data);
|
||||||
|
assert_eq!(run("2,3,0,3,99").data, parse("2,3,0,6,99").data);
|
||||||
|
assert_eq!(run("2,4,4,5,99,0").data, parse("2,4,4,5,99,9801").data);
|
||||||
|
assert_eq!(run("1,1,1,4,99,5,6,0,99").data, parse("30,1,1,4,2,5,6,0,99").data);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn examples2() {
|
||||||
|
// no examples present
|
||||||
|
}
|
||||||
|
}
|
9
day3/Cargo.toml
Normal file
9
day3/Cargo.toml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
[package]
|
||||||
|
name = "day3"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Stefan Bühler <stbuehler@web.de>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
2
day3/src/input.txt
Normal file
2
day3/src/input.txt
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
R1005,U563,R417,U509,L237,U555,R397,U414,L490,U336,L697,D682,L180,U951,L189,D547,R697,U583,L172,D859,L370,D114,L519,U829,R389,U608,R66,D634,L320,D49,L931,U137,L349,D689,L351,D829,R819,D138,L118,D849,R230,U858,L509,D311,R815,U217,R359,U840,R77,U230,R361,U322,R300,D646,R348,U815,R793,D752,R967,U128,R948,D499,R359,U572,L566,U815,R630,D290,L829,D736,R358,U778,R891,U941,R544,U889,L920,U913,L447,D604,R538,U818,L215,D437,R447,U576,R452,D794,R864,U269,L325,D35,L268,D639,L101,U777,L776,U958,R105,U517,R667,D423,R603,U469,L125,D919,R879,U994,R665,D377,R456,D570,L685,U291,R261,U846,R840,U418,L974,D270,L312,D426,R621,D334,L855,D378,R694,U845,R481,U895,L362,D840,L712,U57,R276,D643,R566,U348,R361,D144,L287,D864,L556,U610,L927,U322,R271,D90,L741,U446,R181,D527,R56,U805,L907,D406,L286,U873,L79,D280,L153,D377,R253,D61,R475,D804,R788,U393,L660,U314,R489,D491,L234,D712,L253,U651,L777,D726,R146,U47,R630,U517,R226,U624,L834,D153,L513,U799,R287,D868,R982,U390,L296,D373,R9,U994,R105,D673,L657,D868,R738,D277,R374,U828,R860,U247,R484,U986,L723,D847,L578,U487,L51,D865,L328,D199,R812,D726,R355,D463,R761,U69,R508,D753,L81,D50,L345,D66,L764,D466,L975,U619,R59,D788,L737,D360,R14,D253,L512,D417,R828,D188,L394,U212,R658,U369,R920,U927,L339,U552,R856,D458,R407,U41,L930,D460,R809,U467,L410,D800,L135,D596,R678,D4,L771,D637,L876,U192,L406,D136,R666,U730,R711,D291,L586,U845,R606,U2,L228,D759,R244,U946,R948,U160,R397,U134,R188,U850,R623,D315,L219,D450,R489,U374,R299,D474,L767,D679,L160,D403,L708
|
||||||
|
L1003,D878,R937,D979,R921,U572,R4,D959,L884,U394,R221,U206,R806,U912,R345,D290,R65,D996,L411,D157,R590,D557,L32,D360,L691,D861,L156,D603,R733,U444,L433,U144,L238,U213,R827,U949,R384,D409,L727,U923,L98,U781,L201,D200,R749,U288,L486,U158,L494,D522,R636,D330,L507,U691,R918,D706,R163,U609,R559,U674,R784,D87,R670,U401,L85,U981,R848,D579,L882,U777,R671,D385,R913,D899,R92,D780,L795,U821,R956,U446,L109,D955,L570,D874,R499,U845,R769,U88,L529,U657,R553,D357,L83,D324,L273,U689,L715,U933,R161,U561,L603,U349,L445,U781,R299,U26,L212,U429,R763,U116,R961,D258,L518,D668,L767,U587,L654,D24,R318,U35,L9,D199,L161,U419,R6,D707,R944,U499,R207,D349,L727,D637,R735,D137,R18,D214,L531,D327,L916,U440,R859,U483,R952,D631,L96,D320,L192,D985,R330,D196,L345,D575,L535,D868,R376,D126,R903,D619,L126,D624,L990,D67,L927,U685,L200,D759,L157,D816,L585,U910,R587,D598,L398,U706,R847,U682,L919,D291,L932,D54,L314,U430,L60,U206,L997,D487,L874,U957,L753,U999,R156,U102,L826,U923,L204,U293,L244,U787,L273,D687,R134,D167,L287,D459,R875,D32,R635,D400,L179,D19,L576,U60,L182,D409,R114,U329,R207,U525,L295,U305,L861,U280,R531,D49,L890,U521,L283,U37,R344,D867,L474,U893,R140,U289,L67,U490,R121,D34,L696,U902,R288,U249,R107,D750,R389,U125,L406,U950,R932,U795,R205,U583,L665,U214,R806,D409,R832,D39,R207,D977,L873,U645,L762,U847,L725,U397,R414,D558,L669,D736,R897,U464,R207,U359,R257,U304,L932,U240,L582,U409,L493,D481,R48,D537,R893,U48,R707,U630,L70,D289,L769,U98,L679,U504,L337,U117,L343,D574,R595,U168,R498
|
191
day3/src/main.rs
Normal file
191
day3/src/main.rs
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
type Error = Box<dyn std::error::Error>;
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug)]
|
||||||
|
pub enum Move {
|
||||||
|
Right(u32),
|
||||||
|
Left(u32),
|
||||||
|
Up(u32),
|
||||||
|
Down(u32),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug)]
|
||||||
|
pub enum Segment {
|
||||||
|
Horizontal {
|
||||||
|
row: i32,
|
||||||
|
col_start: i32,
|
||||||
|
col_end: i32,
|
||||||
|
steps_start: i32,
|
||||||
|
steps_dir: i32,
|
||||||
|
},
|
||||||
|
Vertical {
|
||||||
|
col: i32,
|
||||||
|
row_start: i32,
|
||||||
|
row_end: i32,
|
||||||
|
steps_start: i32,
|
||||||
|
steps_dir: i32,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Segment {
|
||||||
|
pub fn collision(&self, other: &Self) -> Option<Position> {
|
||||||
|
match (*self, *other) {
|
||||||
|
(Segment::Horizontal {..}, Segment::Horizontal {..}) => None,
|
||||||
|
(Segment::Vertical {..}, Segment::Vertical {..}) => None,
|
||||||
|
(
|
||||||
|
Segment::Horizontal { row, col_start, col_end, steps_start: col_steps_start, steps_dir: col_steps_dir },
|
||||||
|
Segment::Vertical { col, row_start, row_end, steps_start: row_steps_start, steps_dir: row_steps_dir },
|
||||||
|
)
|
||||||
|
|(
|
||||||
|
Segment::Vertical { col, row_start, row_end, steps_start: row_steps_start, steps_dir: row_steps_dir },
|
||||||
|
Segment::Horizontal { row, col_start, col_end, steps_start: col_steps_start, steps_dir: col_steps_dir },
|
||||||
|
)
|
||||||
|
=> {
|
||||||
|
if row_start <= row && row <= row_end && col_start <= col && col <= col_end {
|
||||||
|
let col_steps = col_steps_start + (col - col_start) * col_steps_dir;
|
||||||
|
let row_steps = row_steps_start + (row - row_start) * row_steps_dir;
|
||||||
|
Some(Position { row, col, steps: col_steps + row_steps })
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug, Default)]
|
||||||
|
pub struct Position {
|
||||||
|
row: i32,
|
||||||
|
col: i32,
|
||||||
|
steps: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Position {
|
||||||
|
pub fn manhatten_distance(&self) -> u32 {
|
||||||
|
self.row.abs() as u32 + self.col.abs() as u32
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn trace(&mut self, mov: Move) -> Segment {
|
||||||
|
let start = *self;
|
||||||
|
match mov {
|
||||||
|
Move::Right(off) => {
|
||||||
|
self.col += off as i32;
|
||||||
|
self.steps += off as i32;
|
||||||
|
Segment::Horizontal {
|
||||||
|
row: start.row,
|
||||||
|
col_start: start.col,
|
||||||
|
col_end: self.col,
|
||||||
|
steps_start: start.steps,
|
||||||
|
steps_dir: 1,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Move::Left(off) => {
|
||||||
|
self.col -= off as i32;
|
||||||
|
self.steps += off as i32;
|
||||||
|
Segment::Horizontal {
|
||||||
|
row: start.row,
|
||||||
|
col_start: self.col,
|
||||||
|
col_end: start.col,
|
||||||
|
steps_start: self.steps,
|
||||||
|
steps_dir: -1,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Move::Up(off) => {
|
||||||
|
self.row -= off as i32;
|
||||||
|
self.steps += off as i32;
|
||||||
|
Segment::Vertical {
|
||||||
|
col: start.col,
|
||||||
|
row_start: self.row,
|
||||||
|
row_end: start.row,
|
||||||
|
steps_start: self.steps,
|
||||||
|
steps_dir: -1,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Move::Down(off) => {
|
||||||
|
self.row += off as i32;
|
||||||
|
self.steps += off as i32;
|
||||||
|
Segment::Vertical {
|
||||||
|
col: start.col,
|
||||||
|
row_start: start.row,
|
||||||
|
row_end: self.row,
|
||||||
|
steps_start: start.steps,
|
||||||
|
steps_dir: 1,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::str::FromStr for Move {
|
||||||
|
type Err = Error;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
let e = move || Box::new(std::io::Error::new(std::io::ErrorKind::Other, "invalid move"));
|
||||||
|
let n = s[1..].parse::<u32>()?;
|
||||||
|
if s.is_empty() || !s.is_ascii() {
|
||||||
|
return Err(e());
|
||||||
|
}
|
||||||
|
Ok(match s.as_bytes()[0] {
|
||||||
|
b'R' => Move::Right(n),
|
||||||
|
b'L' => Move::Left(n),
|
||||||
|
b'U' => Move::Up(n),
|
||||||
|
b'D' => Move::Down(n),
|
||||||
|
_ => return Err(e()),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_moves<'a>(input: &'a str) -> impl Iterator<Item=Result<Move, Error>> + 'a {
|
||||||
|
input.split(',').map(str::parse)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn trace_moves<'a>(input: &'a str) -> impl Iterator<Item=Result<Segment, Error>> + 'a {
|
||||||
|
let mut pos = Position::default();
|
||||||
|
parse_moves(input).map(move |m| m.map(|m| pos.trace(m)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn closest_intersection(lines: &[Vec<Segment>; 2]) -> u32 {
|
||||||
|
lines[0][1..].iter().map(|a| lines[1][1..].iter().filter_map(move |b| a.collision(b).map(|p| p.manhatten_distance()))).flatten().min().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn shortest_delay(lines: &[Vec<Segment>; 2]) -> i32 {
|
||||||
|
lines[0][1..].iter().map(|a| lines[1][1..].iter().filter_map(move |b| a.collision(b).map(|p| p.steps))).flatten().min().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse(input: &str) -> [Vec<Segment>; 2] {
|
||||||
|
let mut lines = input.split_whitespace().map(trace_moves).map(Iterator::collect::<Result<Vec<_>, _>>);
|
||||||
|
let result = [
|
||||||
|
lines.next().expect("require two lines").unwrap(),
|
||||||
|
lines.next().expect("require two lines").unwrap(),
|
||||||
|
];
|
||||||
|
assert!(lines.next().is_none(), "require only two lines");
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let input: &str = include_str!("input.txt");
|
||||||
|
let lines = parse(input);
|
||||||
|
|
||||||
|
println!("Distance 1: {}", closest_intersection(&lines));
|
||||||
|
println!("Distance 2: {}", shortest_delay(&lines));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod day3test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn examples1() {
|
||||||
|
assert_eq!(closest_intersection(&parse("R75,D30,R83,U83,L12,D49,R71,U7,L72
|
||||||
|
U62,R66,U55,R34,D71,R55,D58,R83")), 159);
|
||||||
|
assert_eq!(closest_intersection(&parse("R98,U47,R26,D63,R33,U87,L62,D20,R33,U53,R51
|
||||||
|
U98,R91,D20,R16,D67,R40,U7,R15,U6,R7")), 135);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn examples2() {
|
||||||
|
assert_eq!(shortest_delay(&parse("R75,D30,R83,U83,L12,D49,R71,U7,L72
|
||||||
|
U62,R66,U55,R34,D71,R55,D58,R83")), 610);
|
||||||
|
assert_eq!(shortest_delay(&parse("R98,U47,R26,D63,R33,U87,L62,D20,R33,U53,R51
|
||||||
|
U98,R91,D20,R16,D67,R40,U7,R15,U6,R7")), 410);
|
||||||
|
}
|
||||||
|
}
|
9
day4/Cargo.toml
Normal file
9
day4/Cargo.toml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
[package]
|
||||||
|
name = "day4"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Stefan Bühler <stbuehler@web.de>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
80
day4/src/main.rs
Normal file
80
day4/src/main.rs
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
However, they do remember a few key facts about the password:
|
||||||
|
|
||||||
|
It is a six-digit number.
|
||||||
|
The value is within the range given in your puzzle input.
|
||||||
|
Two adjacent digits are the same (like 22 in 122345).
|
||||||
|
Going from left to right, the digits never decrease; they only ever increase or stay the same (like 111123 or 135679).
|
||||||
|
|
||||||
|
Other than the range rule, the following are true:
|
||||||
|
|
||||||
|
111111 meets these criteria (double 11, never decreases).
|
||||||
|
223450 does not meet these criteria (decreasing pair of digits 50).
|
||||||
|
123789 does not meet these criteria (no double).
|
||||||
|
|
||||||
|
How many different passwords within the range given in your puzzle input meet these criteria?
|
||||||
|
|
||||||
|
Your puzzle input is 206938-679128.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
fn valid_password1(number: u32) -> bool {
|
||||||
|
use std::io::Write;
|
||||||
|
if number < 100_000 || number > 999_999 { return false; }
|
||||||
|
let mut digits = [0u8; 6];
|
||||||
|
write!(&mut digits[..], "{}", number).unwrap();
|
||||||
|
let mut have_double_digit = false;
|
||||||
|
for i in 0..5 {
|
||||||
|
if digits[i] > digits[i+1] { return false; }
|
||||||
|
if digits[i] == digits[i+1] { have_double_digit = true }
|
||||||
|
}
|
||||||
|
|
||||||
|
have_double_digit
|
||||||
|
}
|
||||||
|
|
||||||
|
fn valid_password2(number: u32) -> bool {
|
||||||
|
use std::io::Write;
|
||||||
|
if number < 100_000 || number > 999_999 { return false; }
|
||||||
|
let mut digits = [0u8; 6];
|
||||||
|
write!(&mut digits[..], "{}", number).unwrap();
|
||||||
|
let mut have_double_digit = false;
|
||||||
|
let mut current_run = 1;
|
||||||
|
for i in 0..5 {
|
||||||
|
if digits[i] > digits[i+1] { return false; }
|
||||||
|
if digits[i] == digits[i+1] {
|
||||||
|
current_run += 1;
|
||||||
|
} else {
|
||||||
|
if current_run == 2 {
|
||||||
|
have_double_digit = true;
|
||||||
|
}
|
||||||
|
current_run = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if current_run == 2 {
|
||||||
|
have_double_digit = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
have_double_digit
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
println!("Count 1: {}", (206938..=679128).filter(|n| valid_password1(*n)).count());
|
||||||
|
println!("Count 2: {}", (206938..=679128).filter(|n| valid_password2(*n)).count());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod day4test {
|
||||||
|
#[test]
|
||||||
|
fn examples1() {
|
||||||
|
assert!(super::valid_password1(111111));
|
||||||
|
assert!(!super::valid_password1(223450));
|
||||||
|
assert!(!super::valid_password1(123789));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn examples2() {
|
||||||
|
assert!(super::valid_password2(112233));
|
||||||
|
assert!(!super::valid_password2(123444));
|
||||||
|
assert!(super::valid_password2(111122));
|
||||||
|
}
|
||||||
|
}
|
10
day5/Cargo.toml
Normal file
10
day5/Cargo.toml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
[package]
|
||||||
|
name = "day5"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Stefan Bühler <stbuehler@web.de>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
shared = { path = "../shared" }
|
1
day5/src/input.txt
Normal file
1
day5/src/input.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
3,225,1,225,6,6,1100,1,238,225,104,0,1101,9,90,224,1001,224,-99,224,4,224,102,8,223,223,1001,224,6,224,1,223,224,223,1102,26,62,225,1101,11,75,225,1101,90,43,225,2,70,35,224,101,-1716,224,224,4,224,1002,223,8,223,101,4,224,224,1,223,224,223,1101,94,66,225,1102,65,89,225,101,53,144,224,101,-134,224,224,4,224,1002,223,8,223,1001,224,5,224,1,224,223,223,1102,16,32,224,101,-512,224,224,4,224,102,8,223,223,101,5,224,224,1,224,223,223,1001,43,57,224,101,-147,224,224,4,224,102,8,223,223,101,4,224,224,1,223,224,223,1101,36,81,225,1002,39,9,224,1001,224,-99,224,4,224,1002,223,8,223,101,2,224,224,1,223,224,223,1,213,218,224,1001,224,-98,224,4,224,102,8,223,223,101,2,224,224,1,224,223,223,102,21,74,224,101,-1869,224,224,4,224,102,8,223,223,1001,224,7,224,1,224,223,223,1101,25,15,225,1101,64,73,225,4,223,99,0,0,0,677,0,0,0,0,0,0,0,0,0,0,0,1105,0,99999,1105,227,247,1105,1,99999,1005,227,99999,1005,0,256,1105,1,99999,1106,227,99999,1106,0,265,1105,1,99999,1006,0,99999,1006,227,274,1105,1,99999,1105,1,280,1105,1,99999,1,225,225,225,1101,294,0,0,105,1,0,1105,1,99999,1106,0,300,1105,1,99999,1,225,225,225,1101,314,0,0,106,0,0,1105,1,99999,1008,226,677,224,1002,223,2,223,1005,224,329,1001,223,1,223,1007,677,677,224,102,2,223,223,1005,224,344,101,1,223,223,108,226,677,224,102,2,223,223,1006,224,359,101,1,223,223,108,226,226,224,1002,223,2,223,1005,224,374,1001,223,1,223,7,226,226,224,1002,223,2,223,1006,224,389,1001,223,1,223,8,226,677,224,1002,223,2,223,1006,224,404,1001,223,1,223,107,677,677,224,1002,223,2,223,1006,224,419,101,1,223,223,1008,677,677,224,102,2,223,223,1006,224,434,101,1,223,223,1107,226,677,224,102,2,223,223,1005,224,449,1001,223,1,223,107,226,226,224,102,2,223,223,1006,224,464,101,1,223,223,107,226,677,224,102,2,223,223,1005,224,479,1001,223,1,223,8,677,226,224,102,2,223,223,1005,224,494,1001,223,1,223,1108,226,677,224,102,2,223,223,1006,224,509,101,1,223,223,1107,677,226,224,1002,223,2,223,1005,224,524,101,1,223,223,1008,226,226,224,1002,223,2,223,1005,224,539,101,1,223,223,7,226,677,224,1002,223,2,223,1005,224,554,101,1,223,223,1107,677,677,224,1002,223,2,223,1006,224,569,1001,223,1,223,8,226,226,224,1002,223,2,223,1006,224,584,101,1,223,223,1108,677,677,224,102,2,223,223,1005,224,599,101,1,223,223,108,677,677,224,1002,223,2,223,1006,224,614,101,1,223,223,1007,226,226,224,102,2,223,223,1005,224,629,1001,223,1,223,7,677,226,224,1002,223,2,223,1005,224,644,101,1,223,223,1007,226,677,224,102,2,223,223,1005,224,659,1001,223,1,223,1108,677,226,224,102,2,223,223,1006,224,674,101,1,223,223,4,223,99,226
|
82
day5/src/main.rs
Normal file
82
day5/src/main.rs
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
use shared::intcode::{IntCode, SimulateStep, CELL};
|
||||||
|
|
||||||
|
fn run_air_conditioner(mut ic: IntCode) -> (Vec<CELL>, CELL) {
|
||||||
|
let mut test_results = Vec::new();
|
||||||
|
ic.next_input = Some(1); // air conditioner unit ID
|
||||||
|
loop {
|
||||||
|
match ic.simulate_step() {
|
||||||
|
SimulateStep::Finished => {
|
||||||
|
let diagnostic = test_results.pop().expect("missing diagnostic code");
|
||||||
|
return (test_results, diagnostic);
|
||||||
|
},
|
||||||
|
SimulateStep::Output(v) => test_results.push(v),
|
||||||
|
SimulateStep::WaitForInput => panic!("AirConditioner already initialized, no further input"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_thermal_radiator_controller(mut ic: IntCode) -> CELL {
|
||||||
|
ic.next_input = Some(5); // thermal radiator controller ID
|
||||||
|
let diagnostic = ic.simulate_step().expect_output();
|
||||||
|
ic.simulate_step().expect_finished();
|
||||||
|
diagnostic
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let ic = include_str!("input.txt").parse::<IntCode>().unwrap();
|
||||||
|
|
||||||
|
println!("AirConditioner: {:?}", run_air_conditioner(ic.clone()));
|
||||||
|
println!("ThermalRadiatorController: {:?}", run_thermal_radiator_controller(ic));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod day5test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
fn parse(input: &str) -> IntCode {
|
||||||
|
input.parse().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_single_io(code: &str, input: CELL) -> CELL {
|
||||||
|
let mut ic = parse(code);
|
||||||
|
ic.next_input = Some(input);
|
||||||
|
let result = ic.simulate_step().expect_output();
|
||||||
|
ic.simulate_step().expect_finished();
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn examples1() {
|
||||||
|
// no runnable examples
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn examples2() {
|
||||||
|
// position mode: input is 8?
|
||||||
|
assert_eq!(run_single_io("3,9,8,9,10,9,4,9,99,-1,8", 8), 1);
|
||||||
|
assert_eq!(run_single_io("3,9,8,9,10,9,4,9,99,-1,8", 7), 0);
|
||||||
|
assert_eq!(run_single_io("3,9,8,9,10,9,4,9,99,-1,8", 9), 0);
|
||||||
|
// position mode: input less than 8?
|
||||||
|
assert_eq!(run_single_io("3,9,7,9,10,9,4,9,99,-1,8", 8), 0);
|
||||||
|
assert_eq!(run_single_io("3,9,7,9,10,9,4,9,99,-1,8", 7), 1);
|
||||||
|
assert_eq!(run_single_io("3,9,7,9,10,9,4,9,99,-1,8", 9), 0);
|
||||||
|
// immediate mode: input is 8?
|
||||||
|
assert_eq!(run_single_io("3,3,1108,-1,8,3,4,3,99", 8), 1);
|
||||||
|
assert_eq!(run_single_io("3,3,1108,-1,8,3,4,3,99", 7), 0);
|
||||||
|
assert_eq!(run_single_io("3,3,1108,-1,8,3,4,3,99", 9), 0);
|
||||||
|
// immediate mode: input less than 8?
|
||||||
|
assert_eq!(run_single_io("3,3,1107,-1,8,3,4,3,99", 8), 0);
|
||||||
|
assert_eq!(run_single_io("3,3,1107,-1,8,3,4,3,99", 7), 1);
|
||||||
|
assert_eq!(run_single_io("3,3,1107,-1,8,3,4,3,99", 9), 0);
|
||||||
|
// position mode: (bool) input
|
||||||
|
assert_eq!(run_single_io("3,12,6,12,15,1,13,14,13,4,13,99,-1,0,1,9", 0), 0);
|
||||||
|
assert_eq!(run_single_io("3,12,6,12,15,1,13,14,13,4,13,99,-1,0,1,9", 1), 1);
|
||||||
|
assert_eq!(run_single_io("3,12,6,12,15,1,13,14,13,4,13,99,-1,0,1,9", 999), 1);
|
||||||
|
assert_eq!(run_single_io("3,12,6,12,15,1,13,14,13,4,13,99,-1,0,1,9", -1), 1);
|
||||||
|
// immediate mode: (bool) input
|
||||||
|
assert_eq!(run_single_io("3,3,1105,-1,9,1101,0,0,12,4,12,99,1", 0), 0);
|
||||||
|
assert_eq!(run_single_io("3,3,1105,-1,9,1101,0,0,12,4,12,99,1", 1), 1);
|
||||||
|
assert_eq!(run_single_io("3,3,1105,-1,9,1101,0,0,12,4,12,99,1", 999), 1);
|
||||||
|
assert_eq!(run_single_io("3,3,1105,-1,9,1101,0,0,12,4,12,99,1", -1), 1);
|
||||||
|
}
|
||||||
|
}
|
9
day6/Cargo.toml
Normal file
9
day6/Cargo.toml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
[package]
|
||||||
|
name = "day6"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Stefan Bühler <stbuehler@web.de>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
1831
day6/src/input.txt
Normal file
1831
day6/src/input.txt
Normal file
File diff suppressed because it is too large
Load Diff
87
day6/src/main.rs
Normal file
87
day6/src/main.rs
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
use std::cell::Cell;
|
||||||
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
|
fn parse(s: &str) -> impl Iterator<Item=(&str, &str)> {
|
||||||
|
s.split_ascii_whitespace().map(|l| {
|
||||||
|
let mut x = l.splitn(2, ')');
|
||||||
|
let a = x.next().unwrap();
|
||||||
|
let b = x.next().unwrap();
|
||||||
|
(a, b)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn count_orbits_get(orbit_relations: &HashMap<&str, (&str, Cell<Option<u32>>)>, object: &str) -> u32 {
|
||||||
|
if object == "COM" { return 0; }
|
||||||
|
let around = &orbit_relations[object];
|
||||||
|
if let Some(n) = around.1.get() { return n; }
|
||||||
|
let n = count_orbits_get(orbit_relations, around.0) + 1;
|
||||||
|
around.1.set(Some(n));
|
||||||
|
n
|
||||||
|
}
|
||||||
|
|
||||||
|
fn count_orbits(input: &str) -> u32 {
|
||||||
|
let orbit_relations: HashMap<&str, (&str, Cell<Option<u32>>)> = parse(input).map(|(a, b)| (b, (a, Cell::new(None)))).collect();
|
||||||
|
let mut sum = 0;
|
||||||
|
for (_object, around) in &orbit_relations {
|
||||||
|
if let Some(n) = around.1.get() {
|
||||||
|
sum += n;
|
||||||
|
} else {
|
||||||
|
let n = count_orbits_get(&orbit_relations, around.0) + 1;
|
||||||
|
around.1.set(Some(n));
|
||||||
|
sum += n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// println!("Map: {:?}", orbit_relations);
|
||||||
|
sum
|
||||||
|
}
|
||||||
|
|
||||||
|
fn count_orbit_transfers(input: &str) -> u32 {
|
||||||
|
let orbit_relations: HashMap<&str, (&str, Cell<Option<u32>>)> = parse(input).map(|(a, b)| (b, (a, Cell::new(None)))).collect();
|
||||||
|
for (_object, around) in &orbit_relations {
|
||||||
|
if around.1.get().is_none() {
|
||||||
|
let n = count_orbits_get(&orbit_relations, around.0) + 1;
|
||||||
|
around.1.set(Some(n));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// println!("Map: {:?}", orbit_relations);
|
||||||
|
let mut you = HashSet::new();
|
||||||
|
let mut object = "YOU";
|
||||||
|
loop {
|
||||||
|
if "COM" == object { break; }
|
||||||
|
object = orbit_relations[object].0;
|
||||||
|
// println!("YOU orbit (...) {}", object);
|
||||||
|
you.insert(object);
|
||||||
|
}
|
||||||
|
object = "SAN";
|
||||||
|
loop {
|
||||||
|
if you.contains(&object) {
|
||||||
|
let you = orbit_relations["YOU"].1.get().unwrap();
|
||||||
|
let san = orbit_relations["SAN"].1.get().unwrap();
|
||||||
|
let bottom = orbit_relations[object].1.get().unwrap();
|
||||||
|
return (you - bottom - 1) + (san - bottom - 1);
|
||||||
|
}
|
||||||
|
object = orbit_relations[object].0;
|
||||||
|
// println!("SAN orbit (...) {}", object);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let input = include_str!("input.txt");
|
||||||
|
println!("Orbit sum: {}", count_orbits(input));
|
||||||
|
println!("Orbit transfers: {}", count_orbit_transfers(input));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod day6test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn examples1() {
|
||||||
|
assert_eq!(count_orbits("COM)B B)C C)D D)E E)F B)G G)H D)I E)J J)K K)L"), 42);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn examples2() {
|
||||||
|
assert_eq!(count_orbit_transfers("COM)B B)C C)D D)E E)F B)G G)H D)I E)J J)K K)L K)YOU I)SAN"), 4);
|
||||||
|
}
|
||||||
|
}
|
11
day7/Cargo.toml
Normal file
11
day7/Cargo.toml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
[package]
|
||||||
|
name = "day7"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Stefan Bühler <stbuehler@web.de>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
itertools = "0.8.2"
|
||||||
|
shared = { path = "../shared" }
|
1
day7/src/input.txt
Normal file
1
day7/src/input.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
3,8,1001,8,10,8,105,1,0,0,21,34,51,64,73,98,179,260,341,422,99999,3,9,102,4,9,9,1001,9,4,9,4,9,99,3,9,1001,9,4,9,1002,9,3,9,1001,9,5,9,4,9,99,3,9,101,5,9,9,102,5,9,9,4,9,99,3,9,101,5,9,9,4,9,99,3,9,1002,9,5,9,1001,9,3,9,102,2,9,9,101,5,9,9,1002,9,2,9,4,9,99,3,9,1001,9,1,9,4,9,3,9,1002,9,2,9,4,9,3,9,1001,9,2,9,4,9,3,9,1001,9,2,9,4,9,3,9,102,2,9,9,4,9,3,9,102,2,9,9,4,9,3,9,101,1,9,9,4,9,3,9,101,1,9,9,4,9,3,9,102,2,9,9,4,9,3,9,101,2,9,9,4,9,99,3,9,101,1,9,9,4,9,3,9,1001,9,1,9,4,9,3,9,102,2,9,9,4,9,3,9,102,2,9,9,4,9,3,9,101,2,9,9,4,9,3,9,101,1,9,9,4,9,3,9,101,1,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,1002,9,2,9,4,9,3,9,1001,9,2,9,4,9,99,3,9,101,2,9,9,4,9,3,9,102,2,9,9,4,9,3,9,1001,9,2,9,4,9,3,9,1001,9,2,9,4,9,3,9,1001,9,2,9,4,9,3,9,101,2,9,9,4,9,3,9,1001,9,1,9,4,9,3,9,102,2,9,9,4,9,3,9,102,2,9,9,4,9,3,9,101,2,9,9,4,9,99,3,9,1002,9,2,9,4,9,3,9,102,2,9,9,4,9,3,9,1001,9,2,9,4,9,3,9,1002,9,2,9,4,9,3,9,1001,9,2,9,4,9,3,9,1002,9,2,9,4,9,3,9,102,2,9,9,4,9,3,9,102,2,9,9,4,9,3,9,101,2,9,9,4,9,3,9,1001,9,2,9,4,9,99,3,9,1001,9,1,9,4,9,3,9,101,1,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,1001,9,2,9,4,9,3,9,1001,9,1,9,4,9,3,9,101,1,9,9,4,9,3,9,102,2,9,9,4,9,3,9,1001,9,2,9,4,9,3,9,1002,9,2,9,4,9,3,9,1001,9,2,9,4,9,99
|
94
day7/src/main.rs
Normal file
94
day7/src/main.rs
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
use shared::intcode::{IntCode, SimulateStep, CELL};
|
||||||
|
|
||||||
|
pub fn run_stages(ic: &IntCode, phases: &[CELL]) -> CELL {
|
||||||
|
let mut value = 0;
|
||||||
|
for ndx in 0..5 {
|
||||||
|
let mut stage = ic.clone();
|
||||||
|
stage.next_input = Some(phases[ndx]);
|
||||||
|
stage.simulate_step().expect_wait_for_input();
|
||||||
|
stage.next_input = Some(value);
|
||||||
|
value = stage.simulate_step().expect_output();
|
||||||
|
stage.simulate_step().expect_finished();
|
||||||
|
}
|
||||||
|
value
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run_feedback_stages(ic: &IntCode, phases: &[CELL]) -> CELL {
|
||||||
|
let mut stages = [ ic.clone(), ic.clone(), ic.clone(), ic.clone(), ic.clone() ];
|
||||||
|
// init all with phase
|
||||||
|
for ndx in 0..5 {
|
||||||
|
stages[ndx].next_input = Some(phases[ndx]);
|
||||||
|
stages[ndx].simulate_step().expect_wait_for_input();
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut output = 0;
|
||||||
|
stages[0].next_input = Some(output);
|
||||||
|
let mut current_ndx = 0;
|
||||||
|
loop {
|
||||||
|
match stages[current_ndx].simulate_step() {
|
||||||
|
SimulateStep::Output(v) => {
|
||||||
|
current_ndx = (current_ndx + 1) % 5;
|
||||||
|
stages[current_ndx].next_input = Some(v);
|
||||||
|
if current_ndx == 0 {
|
||||||
|
// remember last final output
|
||||||
|
output = v;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
SimulateStep::WaitForInput => {
|
||||||
|
panic!("Can't wait for new input before generating one");
|
||||||
|
},
|
||||||
|
SimulateStep::Finished => break,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(current_ndx, 0, "first amplifiert should be first to stop");
|
||||||
|
for ndx in current_ndx+1..5 {
|
||||||
|
stages[ndx].simulate_step().expect_finished();
|
||||||
|
}
|
||||||
|
|
||||||
|
output
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn best_amplifier(ic: &IntCode) -> (Vec<CELL>, CELL) {
|
||||||
|
use itertools::Itertools;
|
||||||
|
(0..5).permutations(5).map(|phases| {
|
||||||
|
let value = run_stages(ic, &phases);
|
||||||
|
(phases, value)
|
||||||
|
}).max_by_key(|(_, value)| *value).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn best_feedback_amplifier(ic: &IntCode) -> (Vec<CELL>, CELL) {
|
||||||
|
use itertools::Itertools;
|
||||||
|
(5..10).permutations(5).map(|phases| {
|
||||||
|
let value = run_feedback_stages(ic, &phases);
|
||||||
|
(phases, value)
|
||||||
|
}).max_by_key(|(_, value)| *value).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let ic = include_str!("input.txt").parse::<IntCode>().unwrap();
|
||||||
|
|
||||||
|
let (phases, max_value) = best_amplifier(&ic);
|
||||||
|
println!("Max Value: {} (from phases: {:?}", max_value, phases);
|
||||||
|
|
||||||
|
let (phases, max_value) = best_feedback_amplifier(&ic);
|
||||||
|
println!("Max Feedback Value: {} (from phases: {:?}", max_value, phases);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod day7test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn examples1() {
|
||||||
|
assert_eq!(best_amplifier(&"3,15,3,16,1002,16,10,16,1,16,15,15,4,15,99,0,0".parse::<IntCode>().unwrap()), (vec![4,3,2,1,0], 43210));
|
||||||
|
assert_eq!(best_amplifier(&"3,23,3,24,1002,24,10,24,1002,23,-1,23,101,5,23,23,1,24,23,23,4,23,99,0,0".parse::<IntCode>().unwrap()), (vec![0,1,2,3,4], 54321));
|
||||||
|
assert_eq!(best_amplifier(&"3,31,3,32,1002,32,10,32,1001,31,-2,31,1007,31,0,33,1002,33,7,33,1,33,31,31,1,32,31,31,4,31,99,0,0,0".parse::<IntCode>().unwrap()), (vec![1,0,4,3,2], 65210));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn examples2() {
|
||||||
|
assert_eq!(best_feedback_amplifier(&"3,26,1001,26,-4,26,3,27,1002,27,2,27,1,27,26,27,4,27,1001,28,-1,28,1005,28,6,99,0,0,5".parse::<IntCode>().unwrap()), (vec![9,8,7,6,5], 139629729));
|
||||||
|
assert_eq!(best_feedback_amplifier(&"3,52,1001,52,-5,52,3,53,1,52,56,54,1007,54,5,55,1005,55,26,1001,54,-5,54,1105,1,12,1,53,54,53,1008,54,0,55,1001,55,1,55,2,53,55,53,4,53,1001,56,-1,56,1005,56,6,99,0,0,0,0,10".parse::<IntCode>().unwrap()), (vec![9,7,8,5,6], 18216));
|
||||||
|
}
|
||||||
|
}
|
9
shared/Cargo.toml
Normal file
9
shared/Cargo.toml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
[package]
|
||||||
|
name = "shared"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Stefan Bühler <stbuehler@web.de>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
148
shared/src/intcode.rs
Normal file
148
shared/src/intcode.rs
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
const OP_ADD: CELL = 1;
|
||||||
|
const OP_MUL: CELL = 2;
|
||||||
|
const OP_INPUT: CELL = 3;
|
||||||
|
const OP_OUTPUT: CELL = 4;
|
||||||
|
const OP_JUMP_IF_TRUE: CELL = 5;
|
||||||
|
const OP_JUMP_IF_FALSE: CELL = 6;
|
||||||
|
const OP_LESS_THAN: CELL = 7;
|
||||||
|
const OP_EQUAL: CELL = 8;
|
||||||
|
const OP_HALT: CELL = 99;
|
||||||
|
|
||||||
|
pub type CELL = i64;
|
||||||
|
type Mode = u8;
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||||
|
pub enum SimulateStep {
|
||||||
|
Finished,
|
||||||
|
WaitForInput,
|
||||||
|
Output(CELL),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SimulateStep {
|
||||||
|
pub fn expect_output(self) -> CELL {
|
||||||
|
if let Self::Output(v) = self {
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
panic!("Expected Output, got {:?}", self);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn expect_finished(self) {
|
||||||
|
if let Self::Finished = self { return; }
|
||||||
|
panic!("Expected Finished, got {:?}", self);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn expect_wait_for_input(self) {
|
||||||
|
if let Self::WaitForInput = self { return; }
|
||||||
|
panic!("Expected WaitForInput, got {:?}", self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||||
|
pub struct IntCode {
|
||||||
|
pub ip: usize,
|
||||||
|
pub next_input: Option<CELL>,
|
||||||
|
pub data: Vec<CELL>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntCode {
|
||||||
|
#[inline(always)]
|
||||||
|
fn fetch(&mut self, mode: Mode) -> CELL {
|
||||||
|
let imm = self.data[self.ip];
|
||||||
|
self.ip += 1;
|
||||||
|
match mode {
|
||||||
|
1 => imm,
|
||||||
|
_ => self.data[imm as usize],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[inline(always)]
|
||||||
|
fn store(&mut self, mode: Mode, value: CELL) {
|
||||||
|
let addr = self.ip;
|
||||||
|
self.ip += 1;
|
||||||
|
match mode {
|
||||||
|
1 => self.data[addr] = value,
|
||||||
|
_ => {
|
||||||
|
let addr = self.data[addr] as usize;
|
||||||
|
self.data[addr] = value;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn binop<F>(&mut self, op: F, modes: [Mode; 3])
|
||||||
|
where
|
||||||
|
F: FnOnce(CELL, CELL) -> CELL,
|
||||||
|
{
|
||||||
|
let src1 = self.fetch(modes[0]);
|
||||||
|
let src2 = self.fetch(modes[1]);
|
||||||
|
self.store(modes[2], op(src1, src2));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn simulate(&mut self) {
|
||||||
|
assert_eq!(self.ip, 0);
|
||||||
|
assert!(self.next_input.is_none());
|
||||||
|
self.simulate_step().expect_finished();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn simulate_step(&mut self) -> SimulateStep {
|
||||||
|
loop {
|
||||||
|
let modes = self.data[self.ip];
|
||||||
|
self.ip += 1;
|
||||||
|
let op = modes % 100;
|
||||||
|
let modes = modes / 100;
|
||||||
|
let mode1 = (modes % 10) as Mode;
|
||||||
|
let modes = modes / 10;
|
||||||
|
let mode2 = (modes % 10) as Mode;
|
||||||
|
let modes = modes / 10;
|
||||||
|
let mode3 = (modes % 10) as Mode;
|
||||||
|
let modes = [mode1, mode2, mode3];
|
||||||
|
|
||||||
|
match op {
|
||||||
|
OP_ADD => self.binop(|a, b| a + b, modes),
|
||||||
|
OP_MUL => self.binop(|a, b| a * b, modes),
|
||||||
|
OP_LESS_THAN => self.binop(|a, b| if a < b { 1 } else { 0 }, modes),
|
||||||
|
OP_EQUAL => self.binop(|a, b| if a == b { 1 } else { 0 }, modes),
|
||||||
|
OP_INPUT => {
|
||||||
|
if let Some(v) = self.next_input.take() {
|
||||||
|
self.store(mode1, v);
|
||||||
|
} else {
|
||||||
|
self.ip -= 1; // go back to opcode
|
||||||
|
return SimulateStep::WaitForInput;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
OP_OUTPUT => {
|
||||||
|
return SimulateStep::Output(self.fetch(mode1));
|
||||||
|
},
|
||||||
|
OP_HALT => {
|
||||||
|
self.ip -= 1; // make re-running this step end up here again
|
||||||
|
return SimulateStep::Finished;
|
||||||
|
},
|
||||||
|
OP_JUMP_IF_TRUE => {
|
||||||
|
if self.fetch(mode1) != 0 {
|
||||||
|
self.ip = self.fetch(mode2) as usize;
|
||||||
|
} else {
|
||||||
|
self.ip += 1; // skip target
|
||||||
|
}
|
||||||
|
},
|
||||||
|
OP_JUMP_IF_FALSE => {
|
||||||
|
if self.fetch(mode1) == 0 {
|
||||||
|
self.ip = self.fetch(mode2) as usize;
|
||||||
|
} else {
|
||||||
|
self.ip += 1; // skip target
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => panic!("invalid opcode: {}", op),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::str::FromStr for IntCode {
|
||||||
|
type Err = <CELL as std::str::FromStr>::Err;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
Ok(IntCode {
|
||||||
|
ip: 0,
|
||||||
|
next_input: None,
|
||||||
|
data: s.split(',').map(|s| s.trim().parse::<CELL>()).collect::<Result<_, _>>()?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
1
shared/src/lib.rs
Normal file
1
shared/src/lib.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
pub mod intcode;
|
Loading…
Reference in New Issue
Block a user