Browse Source

add day 2 to 7

master
Stefan Bühler 1 year ago
parent
commit
f7d70ba76e
23 changed files with 2709 additions and 2 deletions
  1. +54
    -0
      Cargo.lock
  2. +7
    -0
      Cargo.toml
  3. +2
    -2
      day1/src/main.rs
  4. +10
    -0
      day2/Cargo.toml
  5. +1
    -0
      day2/src/input.txt
  6. +60
    -0
      day2/src/main.rs
  7. +9
    -0
      day3/Cargo.toml
  8. +2
    -0
      day3/src/input.txt
  9. +191
    -0
      day3/src/main.rs
  10. +9
    -0
      day4/Cargo.toml
  11. +80
    -0
      day4/src/main.rs
  12. +10
    -0
      day5/Cargo.toml
  13. +1
    -0
      day5/src/input.txt
  14. +82
    -0
      day5/src/main.rs
  15. +9
    -0
      day6/Cargo.toml
  16. +1831
    -0
      day6/src/input.txt
  17. +87
    -0
      day6/src/main.rs
  18. +11
    -0
      day7/Cargo.toml
  19. +1
    -0
      day7/src/input.txt
  20. +94
    -0
      day7/src/main.rs
  21. +9
    -0
      shared/Cargo.toml
  22. +148
    -0
      shared/src/intcode.rs
  23. +1
    -0
      shared/src/lib.rs

+ 54
- 0
Cargo.lock View File

@ -4,3 +4,57 @@
name = "day1"
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"

+ 7
- 0
Cargo.toml View File

@ -1,4 +1,11 @@
[workspace]
members = [
"day1",
"day2",
"day3",
"day4",
"day5",
"day6",
"day7",
"shared",
]

+ 2
- 2
day1/src/main.rs View File

@ -31,7 +31,7 @@ fn main() {
#[cfg(test)]
mod day1test {
#[test]
fn example1() {
fn examples1() {
// 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 14, dividing by 3 and rounding down still yields 4, so the fuel required is also 2.
@ -44,7 +44,7 @@ mod day1test {
}
#[test]
fn example2() {
fn examples2() {
// 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.
// > 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
- 0
day2/Cargo.toml View 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
- 0
day2/src/input.txt View 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
- 0
day2/src/main.rs View 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
- 0
day3/Cargo.toml View 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
- 0
day3/src/input.txt View 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
- 0
day3/src/main.rs View 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
- 0
day4/Cargo.toml View 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
- 0
day4/src/main.rs View 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
- 0
day5/Cargo.toml View 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
- 0
day5/src/input.txt View 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
- 0
day5/src/main.rs View 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
- 0
day6/Cargo.toml View 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
- 0
day6/src/input.txt
File diff suppressed because it is too large
View File


+ 87
- 0
day6/src/main.rs View 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
- 0
day7/Cargo.toml View 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
- 0
day7/src/input.txt View 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
- 0
day7/src/main.rs View 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
- 0
shared/Cargo.toml View 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
- 0
shared/src/intcode.rs View 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
- 0
shared/src/lib.rs View File

@ -0,0 +1 @@
pub mod intcode;

Loading…
Cancel
Save