Compare commits
3 commits
Author | SHA1 | Date | |
---|---|---|---|
074d8df6c5 | |||
b7025c1dc2 | |||
e8894ad31d |
16 changed files with 75 additions and 1965 deletions
32
Cargo.lock
generated
32
Cargo.lock
generated
|
@ -3,35 +3,3 @@
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aoc2019"
|
name = "aoc2019"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
|
||||||
"ncurses",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cc"
|
|
||||||
version = "1.0.54"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7bbb73db36c1246e9034e307d0fba23f9a2e251faa47ade70c1bd252220c8311"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "libc"
|
|
||||||
version = "0.2.71"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ncurses"
|
|
||||||
version = "5.99.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "15699bee2f37e9f8828c7b35b2bc70d13846db453f2d507713b758fabe536b82"
|
|
||||||
dependencies = [
|
|
||||||
"cc",
|
|
||||||
"libc",
|
|
||||||
"pkg-config",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pkg-config"
|
|
||||||
version = "0.3.17"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677"
|
|
||||||
|
|
25
Cargo.toml
25
Cargo.toml
|
@ -4,8 +4,7 @@ version = "0.1.0"
|
||||||
authors = ["Stefan Schwarz <stefan@f2o.io>"]
|
authors = ["Stefan Schwarz <stefan@f2o.io>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
ncurses = "5.99.0"
|
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "day1"
|
name = "day1"
|
||||||
|
@ -37,24 +36,4 @@ path = "src/day9/main.rs"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "day10"
|
name = "day10"
|
||||||
path = "src/day10/main.rs"
|
path = "src/day10/main.rs"
|
||||||
|
|
||||||
[[bin]]
|
|
||||||
name = "day11"
|
|
||||||
path = "src/day11/main.rs"
|
|
||||||
|
|
||||||
[[bin]]
|
|
||||||
name = "day12"
|
|
||||||
path = "src/day12/main.rs"
|
|
||||||
|
|
||||||
[[bin]]
|
|
||||||
name = "day13"
|
|
||||||
path = "src/day13/main.rs"
|
|
||||||
|
|
||||||
[[bin]]
|
|
||||||
name = "day14"
|
|
||||||
path = "src/day14/main.rs"
|
|
||||||
|
|
||||||
[[bin]]
|
|
||||||
name = "day15"
|
|
||||||
path = "src/day15/main.rs"
|
|
|
@ -1 +0,0 @@
|
||||||
# Advent of Code 2019
|
|
1
input11
1
input11
|
@ -1 +0,0 @@
|
||||||
3,8,1005,8,320,1106,0,11,0,0,0,104,1,104,0,3,8,1002,8,-1,10,101,1,10,10,4,10,1008,8,1,10,4,10,102,1,8,29,2,1005,1,10,1006,0,11,3,8,1002,8,-1,10,101,1,10,10,4,10,108,0,8,10,4,10,102,1,8,57,1,8,15,10,1006,0,79,1,6,3,10,3,8,102,-1,8,10,101,1,10,10,4,10,108,0,8,10,4,10,101,0,8,90,2,103,18,10,1006,0,3,2,105,14,10,3,8,102,-1,8,10,1001,10,1,10,4,10,108,0,8,10,4,10,101,0,8,123,2,9,2,10,3,8,102,-1,8,10,1001,10,1,10,4,10,1008,8,1,10,4,10,1001,8,0,150,1,2,2,10,2,1009,6,10,1,1006,12,10,1006,0,81,3,8,102,-1,8,10,1001,10,1,10,4,10,1008,8,1,10,4,10,102,1,8,187,3,8,102,-1,8,10,1001,10,1,10,4,10,1008,8,0,10,4,10,101,0,8,209,3,8,1002,8,-1,10,1001,10,1,10,4,10,1008,8,1,10,4,10,101,0,8,231,1,1008,11,10,1,1001,4,10,2,1104,18,10,3,8,102,-1,8,10,1001,10,1,10,4,10,108,1,8,10,4,10,1001,8,0,264,1,8,14,10,1006,0,36,3,8,1002,8,-1,10,1001,10,1,10,4,10,108,0,8,10,4,10,101,0,8,293,1006,0,80,1006,0,68,101,1,9,9,1007,9,960,10,1005,10,15,99,109,642,104,0,104,1,21102,1,846914232732,1,21102,1,337,0,1105,1,441,21102,1,387512115980,1,21101,348,0,0,1106,0,441,3,10,104,0,104,1,3,10,104,0,104,0,3,10,104,0,104,1,3,10,104,0,104,1,3,10,104,0,104,0,3,10,104,0,104,1,21102,209533824219,1,1,21102,1,395,0,1106,0,441,21101,0,21477985303,1,21102,406,1,0,1106,0,441,3,10,104,0,104,0,3,10,104,0,104,0,21101,868494234468,0,1,21101,429,0,0,1106,0,441,21102,838429471080,1,1,21102,1,440,0,1106,0,441,99,109,2,21201,-1,0,1,21101,0,40,2,21102,472,1,3,21101,0,462,0,1106,0,505,109,-2,2106,0,0,0,1,0,0,1,109,2,3,10,204,-1,1001,467,468,483,4,0,1001,467,1,467,108,4,467,10,1006,10,499,1102,1,0,467,109,-2,2106,0,0,0,109,4,2101,0,-1,504,1207,-3,0,10,1006,10,522,21101,0,0,-3,21202,-3,1,1,22101,0,-2,2,21102,1,1,3,21102,541,1,0,1106,0,546,109,-4,2105,1,0,109,5,1207,-3,1,10,1006,10,569,2207,-4,-2,10,1006,10,569,22102,1,-4,-4,1105,1,637,22102,1,-4,1,21201,-3,-1,2,21202,-2,2,3,21102,588,1,0,1105,1,546,22101,0,1,-4,21102,1,1,-1,2207,-4,-2,10,1006,10,607,21101,0,0,-1,22202,-2,-1,-2,2107,0,-3,10,1006,10,629,21201,-1,0,1,21102,629,1,0,105,1,504,21202,-2,-1,-2,22201,-4,-2,-4,109,-5,2105,1,0
|
|
1
input13
1
input13
File diff suppressed because one or more lines are too long
56
input14
56
input14
|
@ -1,56 +0,0 @@
|
||||||
18 FHWM => 1 XGQNZ
|
|
||||||
4 FVPWN, 9 CQGW => 7 QGHT
|
|
||||||
22 KZMS, 1 DMCJL => 8 TWGCK
|
|
||||||
1 LMGQN, 1 DSWDM, 1 GKGZ => 1 TGPH
|
|
||||||
22 WCSW => 1 LVTG
|
|
||||||
13 JSWR => 4 GKGZ
|
|
||||||
162 ORE => 3 FVPWN
|
|
||||||
59 CQGW, 15 MSNG, 6 XGKRF, 10 LJRQ, 1 HRKGV, 15 RKVC => 1 FUEL
|
|
||||||
5 DMCJL => 1 QBLH
|
|
||||||
2 XDRJ, 2 RKVC => 8 CTCNL
|
|
||||||
1 QXHX => 5 GFPSK
|
|
||||||
22 QGHT, 6 GFPSK, 5 DHTPL => 3 CSDR
|
|
||||||
4 QGHT, 2 HFXD => 4 XDRJ
|
|
||||||
10 WQCGV, 1 JSWR, 21 RHTLN => 7 VTPC
|
|
||||||
11 CQGW, 1 FVPWN => 3 HFXD
|
|
||||||
5 VTPC => 2 NCXW
|
|
||||||
8 LDZVS => 6 DQLH
|
|
||||||
117 ORE => 2 KWZNB
|
|
||||||
3 TGPH, 1 JPFQ, 2 WHWLK, 5 RKVC, 16 DQLH => 9 LJRQ
|
|
||||||
14 KWZNB, 2 CQGW => 8 MLPK
|
|
||||||
6 LDZVS => 2 JSWR
|
|
||||||
1 RKVC, 8 HCGT, 9 DHTPL => 6 FHWM
|
|
||||||
3 DHTPL, 1 HWSR, 36 LDZVS => 6 DSWDM
|
|
||||||
5 WHWLK, 1 LJHWT, 8 HSTHS => 7 VMPX
|
|
||||||
22 ZJCDZ, 3 WQCGV => 5 DHTPL
|
|
||||||
10 LJHWT, 32 GFPSK, 2 RHTLN => 4 HFRMP
|
|
||||||
2 FKVD, 3 TWGCK, 1 HWSR => 1 RNLZW
|
|
||||||
2 CSDR, 3 DQLH, 2 HSTHS => 9 JPFQ
|
|
||||||
1 JSWR, 1 PCWS, 1 HFRMP => 3 XGKRF
|
|
||||||
2 QGHT, 9 LVTG, 3 QBLH => 7 RHTLN
|
|
||||||
10 LJHWT, 4 CTCNL => 8 QXHX
|
|
||||||
16 MLPK, 1 HFXD => 9 ZJCDZ
|
|
||||||
6 QGHT => 9 WCSW
|
|
||||||
4 HWSR, 4 MLPK, 1 KZMS => 3 BGZHQ
|
|
||||||
12 MLPK => 8 RKVC
|
|
||||||
1 HWSR, 1 VNWFS => 7 BGFJ
|
|
||||||
7 FHWM, 11 CTDF, 1 LDZVS => 2 VNWFS
|
|
||||||
4 CTDF => 4 HSTHS
|
|
||||||
2 ZJCDZ => 6 LJHWT
|
|
||||||
1 VMPX, 1 NCXW, 1 HSTHS, 41 XGKRF, 30 HLNG, 1 GKGZ => 7 HRKGV
|
|
||||||
1 XGQNZ, 10 PCWS, 3 BGFJ => 8 FKVD
|
|
||||||
1 GFPSK, 1 DMCJL, 1 LVTG => 5 XDTZB
|
|
||||||
3 WCSW => 5 KZMS
|
|
||||||
6 TWGCK, 1 QXHX, 4 BGFJ => 2 LMGQN
|
|
||||||
1 WCSW => 7 LDZVS
|
|
||||||
1 XDTZB, 9 VNWFS => 3 WHWLK
|
|
||||||
3 HFXD, 4 WCSW, 1 MLPK => 5 WQCGV
|
|
||||||
2 BGFJ, 1 HSTHS, 22 MDCB, 10 HWSR, 6 RNLZW, 8 GKGZ => 5 MSNG
|
|
||||||
4 QGHT, 1 FKVD => 7 MDCB
|
|
||||||
9 MLPK, 3 LJHWT => 7 DMCJL
|
|
||||||
121 ORE => 2 CQGW
|
|
||||||
9 DHTPL, 2 BGZHQ => 8 CTDF
|
|
||||||
2 JSWR, 30 RHTLN => 7 HLNG
|
|
||||||
2 QBLH => 7 PCWS
|
|
||||||
14 LVTG => 8 HWSR
|
|
||||||
7 DMCJL => 1 HCGT
|
|
1
input15
1
input15
|
@ -1 +0,0 @@
|
||||||
3,1033,1008,1033,1,1032,1005,1032,31,1008,1033,2,1032,1005,1032,58,1008,1033,3,1032,1005,1032,81,1008,1033,4,1032,1005,1032,104,99,1002,1034,1,1039,102,1,1036,1041,1001,1035,-1,1040,1008,1038,0,1043,102,-1,1043,1032,1,1037,1032,1042,1106,0,124,1002,1034,1,1039,1001,1036,0,1041,1001,1035,1,1040,1008,1038,0,1043,1,1037,1038,1042,1105,1,124,1001,1034,-1,1039,1008,1036,0,1041,1001,1035,0,1040,1002,1038,1,1043,101,0,1037,1042,1105,1,124,1001,1034,1,1039,1008,1036,0,1041,102,1,1035,1040,1001,1038,0,1043,101,0,1037,1042,1006,1039,217,1006,1040,217,1008,1039,40,1032,1005,1032,217,1008,1040,40,1032,1005,1032,217,1008,1039,1,1032,1006,1032,165,1008,1040,9,1032,1006,1032,165,1102,1,2,1044,1105,1,224,2,1041,1043,1032,1006,1032,179,1102,1,1,1044,1106,0,224,1,1041,1043,1032,1006,1032,217,1,1042,1043,1032,1001,1032,-1,1032,1002,1032,39,1032,1,1032,1039,1032,101,-1,1032,1032,101,252,1032,211,1007,0,35,1044,1106,0,224,1101,0,0,1044,1105,1,224,1006,1044,247,102,1,1039,1034,1002,1040,1,1035,1002,1041,1,1036,102,1,1043,1038,101,0,1042,1037,4,1044,1105,1,0,1,5,41,19,22,1,39,81,29,20,15,82,33,18,45,30,32,55,28,26,70,13,56,32,28,18,3,59,90,11,95,15,85,8,61,25,59,24,34,1,85,5,25,54,57,18,20,54,80,91,28,65,36,12,44,36,13,92,24,56,13,39,69,29,79,10,41,27,23,25,72,20,3,61,15,51,11,12,12,48,10,45,13,29,49,90,30,17,9,41,21,18,7,30,48,17,83,71,4,10,31,10,96,81,77,9,50,39,21,36,33,72,12,3,23,79,18,4,75,17,58,64,8,7,97,60,72,72,1,94,55,42,2,94,2,21,88,19,82,57,96,19,25,27,41,62,15,40,23,61,86,27,73,61,13,46,52,81,12,34,23,73,23,59,1,30,47,9,99,10,37,17,28,98,5,92,73,8,63,4,86,76,79,7,30,68,28,91,12,12,98,74,4,22,44,10,23,45,37,16,90,76,23,74,75,12,21,38,14,15,76,28,49,71,7,6,6,71,53,33,12,87,15,92,66,21,38,13,53,92,34,49,25,6,67,21,27,89,24,61,25,30,41,30,99,28,19,41,90,51,74,14,33,54,48,10,14,42,2,67,76,10,21,2,67,43,27,69,11,16,78,7,36,9,24,48,63,81,53,29,94,34,25,99,66,47,17,97,33,52,11,62,22,52,30,23,89,95,15,13,50,48,26,10,6,69,78,13,6,94,1,28,67,10,70,16,50,19,24,15,79,50,27,3,19,62,4,31,83,20,17,83,67,5,80,26,36,62,87,3,10,80,22,65,60,10,78,4,20,60,30,11,7,83,10,13,72,81,37,22,14,55,63,51,27,32,77,52,20,50,16,48,2,55,10,53,26,84,6,87,43,37,26,3,85,62,25,78,50,16,10,37,22,54,5,80,24,7,32,49,18,27,12,41,70,82,20,34,91,15,98,77,22,6,79,3,8,54,17,32,4,44,2,97,14,15,65,30,97,14,79,75,11,77,5,61,37,20,91,20,45,74,19,40,2,41,89,12,34,44,18,62,57,17,68,22,96,7,59,63,2,60,70,2,26,75,26,3,53,19,80,16,97,7,34,58,52,66,24,75,25,30,75,42,13,12,89,13,3,84,92,1,75,30,54,43,2,56,15,1,15,84,99,6,98,42,17,29,1,18,26,70,71,29,91,23,21,87,66,18,38,32,18,81,65,2,58,99,12,4,84,24,32,88,30,67,49,29,59,64,18,70,10,24,56,5,27,97,50,4,28,85,65,16,67,83,15,16,61,18,86,8,36,25,36,29,97,45,19,81,41,29,45,30,69,26,57,93,27,72,34,30,99,61,2,48,16,12,76,98,28,14,32,32,90,48,10,30,57,23,39,2,8,39,33,13,88,34,31,74,15,60,8,47,60,31,5,79,1,98,86,33,3,99,33,62,11,96,25,22,38,98,84,3,56,70,49,3,8,56,87,4,29,59,65,26,34,77,7,14,78,26,25,70,49,3,31,45,92,24,95,17,4,9,4,96,64,92,27,67,4,99,6,44,7,16,86,2,75,1,6,68,81,4,1,44,49,7,92,8,40,36,25,81,13,56,99,10,2,30,72,6,43,30,12,43,93,19,20,23,95,10,19,66,63,28,96,40,50,8,15,56,38,13,93,42,71,12,18,87,8,4,21,85,9,2,66,77,10,80,26,61,9,43,20,88,10,39,67,55,31,49,17,58,26,80,20,84,54,49,5,73,11,52,15,63,7,62,24,57,92,61,25,87,56,37,31,38,14,99,0,0,21,21,1,10,1,0,0,0,0,0,0
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use std::cmp::Ordering;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{BufRead, BufReader};
|
use std::io::{BufRead, BufReader};
|
||||||
|
@ -45,6 +46,18 @@ impl Sub for &XY {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PartialOrd for XY {
|
||||||
|
fn partial_cmp(&self, other: &XY) -> Option<Ordering> {
|
||||||
|
self.angle().partial_cmp(&other.angle())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ord for XY {
|
||||||
|
fn cmp(&self, other: &XY) -> Ordering {
|
||||||
|
self.angle().partial_cmp(&other.angle()).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl XY {
|
impl XY {
|
||||||
fn direction(&self) -> Self {
|
fn direction(&self) -> Self {
|
||||||
let d = gcd(self.y, self.x).abs();
|
let d = gcd(self.y, self.x).abs();
|
||||||
|
@ -58,88 +71,70 @@ impl XY {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn distance(&self) -> f64 {
|
|
||||||
let sum = (self.x.pow(2) + self.y.pow(2)) as f64;
|
|
||||||
(sum as f64).sqrt()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn angle(&self) -> f64 {
|
fn angle(&self) -> f64 {
|
||||||
let a = (-self.y as f64).atan2(-self.x as f64) * (180 as f64 / std::f64::consts::PI)
|
(self.y as f64).atan2(self.x as f64) * (180 as f64 / std::f64::consts::PI)
|
||||||
- 90 as f64;
|
|
||||||
if a < 0 as f64 {
|
|
||||||
a + 360 as f64
|
|
||||||
} else {
|
|
||||||
a
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct MonitoringStation {
|
struct MonitoringStation {
|
||||||
map: Vec<XY>,
|
map: HashMap<XY, Position>,
|
||||||
|
size_x: usize,
|
||||||
|
size_y: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MonitoringStation {
|
impl MonitoringStation {
|
||||||
fn laser(&self, root: &XY, skip: usize, n: usize) -> Vec<XY> {
|
fn laser(&self, root: &XY) -> impl Iterator<Item = XY> + '_ {
|
||||||
let mut map: HashMap<XY, Vec<&XY>> = HashMap::new();
|
let mut map: HashMap<XY, Vec<XY>> = HashMap::new();
|
||||||
// collect vec for each direction
|
|
||||||
map = self
|
map = self
|
||||||
.map
|
.map
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|xy| {
|
.filter_map(|(xy, pos)| {
|
||||||
if xy == root {
|
if *pos == Position::Empty {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let rel = xy - &root;
|
let rel = xy - &root;
|
||||||
Some((xy, rel.direction()))
|
Some((xy, rel.direction()))
|
||||||
})
|
})
|
||||||
.fold(map, |mut acc, (xy, dir)| {
|
.fold(map, |mut acc, (xy, dir)| {
|
||||||
acc.entry(dir).or_insert(vec![]).push(xy);
|
acc.entry(dir).or_insert(vec![]).push(xy.clone());
|
||||||
acc
|
acc
|
||||||
});
|
});
|
||||||
|
|
||||||
// order angle vecs by distance
|
|
||||||
map.iter_mut().for_each(|(_, val)| {
|
|
||||||
val.sort_by(|a, b| {
|
|
||||||
((root - b).distance().partial_cmp(&(root - a).distance())).unwrap()
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// lets iterate over sorted angles
|
|
||||||
let mut angles = map.keys().cloned().collect::<Vec<XY>>();
|
let mut angles = map.keys().cloned().collect::<Vec<XY>>();
|
||||||
angles.sort_by(|a, b| a.angle().partial_cmp(&b.angle()).unwrap());
|
angles.sort();
|
||||||
|
|
||||||
// cycle around and return first element of each vec
|
let mut popped = true;
|
||||||
angles
|
let mut cycles = 0;
|
||||||
.iter()
|
while popped {
|
||||||
.cycle()
|
popped = false;
|
||||||
.map(|xy| match map.get_mut(xy) {
|
cycles += 1;
|
||||||
|
angles.iter().for_each(|xy| match map.get_mut(xy) {
|
||||||
Some(xy) => {
|
Some(xy) => {
|
||||||
if let Some(xy) = xy.pop() {
|
if let Some(xy) = xy.pop() {
|
||||||
Some(xy)
|
popped = true;
|
||||||
} else {
|
println!("{:?}", xy)
|
||||||
None
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => None,
|
None => (),
|
||||||
})
|
});
|
||||||
.flatten()
|
}
|
||||||
.skip(skip)
|
println!("cycles: {}", cycles);
|
||||||
.take(n)
|
self.map.iter().map(|(xy, _)| xy.clone())
|
||||||
.cloned()
|
|
||||||
.collect::<Vec<XY>>()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find(&self) -> (usize, XY) {
|
fn find(&self) -> (usize, XY) {
|
||||||
let best = (0, &XY::from((0, 0)));
|
let best = (0, XY::from((0, 0)));
|
||||||
let best = self
|
self.map
|
||||||
.map
|
|
||||||
.iter()
|
.iter()
|
||||||
.map(|root| {
|
.filter(|(_, pos)| **pos == Position::Astroid)
|
||||||
|
.map(|(root, _)| {
|
||||||
let insight = self
|
let insight = self
|
||||||
.map
|
.map
|
||||||
.iter()
|
.iter()
|
||||||
// get direction to any of the astroids
|
// get direction to any of the astroids
|
||||||
.filter_map(|xy| {
|
.filter_map(|(xy, pos)| {
|
||||||
|
if *pos == Position::Empty {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
let rel = xy - root;
|
let rel = xy - root;
|
||||||
Some(rel.direction())
|
Some(rel.direction())
|
||||||
})
|
})
|
||||||
|
@ -152,17 +147,12 @@ impl MonitoringStation {
|
||||||
- 1;
|
- 1;
|
||||||
(insight, root)
|
(insight, root)
|
||||||
})
|
})
|
||||||
.fold(
|
.fold(best, |acc, astroid| {
|
||||||
best,
|
if astroid.0 > acc.0 {
|
||||||
|acc, astroid| {
|
return (astroid.0, astroid.1.clone());
|
||||||
if astroid.0 > acc.0 {
|
}
|
||||||
astroid
|
acc
|
||||||
} else {
|
})
|
||||||
acc
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
(best.0, best.1.clone())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,23 +161,33 @@ where
|
||||||
T: BufRead,
|
T: BufRead,
|
||||||
{
|
{
|
||||||
fn from(reader: T) -> Self {
|
fn from(reader: T) -> Self {
|
||||||
|
let map: HashMap<XY, Position> = HashMap::new();
|
||||||
|
let mut size_y = 0;
|
||||||
let map = reader
|
let map = reader
|
||||||
.split(b'\n')
|
.split(b'\n')
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.flat_map(|(y, line)| {
|
.flat_map(|(y, line)| {
|
||||||
|
size_y += 1;
|
||||||
line.unwrap()
|
line.unwrap()
|
||||||
.into_iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.filter_map(move |(x, c)| {
|
.map(|(x, c)| {
|
||||||
let xy = XY::from((x, y));
|
let xy = XY::from((x, y));
|
||||||
match Position::from(&c) {
|
let p = Position::from(c);
|
||||||
Position::Astroid => Some(xy),
|
(xy, p)
|
||||||
Position::Empty => None,
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
.collect::<Vec<(XY, Position)>>()
|
||||||
})
|
})
|
||||||
.collect::<Vec<XY>>();
|
.fold(map, |mut map, (xy, p)| {
|
||||||
MonitoringStation { map }
|
map.insert(xy.clone(), p.clone());
|
||||||
|
map
|
||||||
|
});
|
||||||
|
let size_x = map.iter().count() / size_y;
|
||||||
|
MonitoringStation {
|
||||||
|
map,
|
||||||
|
size_x,
|
||||||
|
size_y,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,10 +196,9 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let reader = BufReader::new(f);
|
let reader = BufReader::new(f);
|
||||||
let station = MonitoringStation::from(reader);
|
let station = MonitoringStation::from(reader);
|
||||||
let best = station.find();
|
let best = station.find();
|
||||||
|
let test = station.laser(&best.1).next();
|
||||||
println!("best: {:?}", best);
|
println!("best: {:?}", best);
|
||||||
let lasered = station.laser(&best.1, 199, 1);
|
println!("test: {:?}", test);
|
||||||
let lasered = lasered.iter().next().unwrap();
|
|
||||||
println!("lasered: {:?}", lasered);
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -323,62 +322,4 @@ mod tests {
|
||||||
assert_eq!(xy, XY { x: 11, y: 13 });
|
assert_eq!(xy, XY { x: 11, y: 13 });
|
||||||
assert_eq!(count, 210);
|
assert_eq!(count, 210);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn example6() {
|
|
||||||
let reader = BufReader::new(
|
|
||||||
"
|
|
||||||
.#....#####...#..
|
|
||||||
##...##.#####..##
|
|
||||||
##...#...#.#####.
|
|
||||||
..#.....#...###..
|
|
||||||
..#.#.....#....##
|
|
||||||
"
|
|
||||||
.trim()
|
|
||||||
.as_bytes(),
|
|
||||||
);
|
|
||||||
let ms = MonitoringStation::from(reader);
|
|
||||||
ms.find();
|
|
||||||
assert_eq!(
|
|
||||||
ms.laser(&XY::from((8, 3)), 0, 36),
|
|
||||||
vec![
|
|
||||||
XY { x: 8, y: 1 },
|
|
||||||
XY { x: 9, y: 0 },
|
|
||||||
XY { x: 9, y: 1 },
|
|
||||||
XY { x: 10, y: 0 },
|
|
||||||
XY { x: 9, y: 2 },
|
|
||||||
XY { x: 11, y: 1 },
|
|
||||||
XY { x: 12, y: 1 },
|
|
||||||
XY { x: 11, y: 2 },
|
|
||||||
XY { x: 15, y: 1 },
|
|
||||||
XY { x: 12, y: 2 },
|
|
||||||
XY { x: 13, y: 2 },
|
|
||||||
XY { x: 14, y: 2 },
|
|
||||||
XY { x: 15, y: 2 },
|
|
||||||
XY { x: 12, y: 3 },
|
|
||||||
XY { x: 16, y: 4 },
|
|
||||||
XY { x: 15, y: 4 },
|
|
||||||
XY { x: 10, y: 4 },
|
|
||||||
XY { x: 4, y: 4 },
|
|
||||||
XY { x: 2, y: 4 },
|
|
||||||
XY { x: 2, y: 3 },
|
|
||||||
XY { x: 0, y: 2 },
|
|
||||||
XY { x: 1, y: 2 },
|
|
||||||
XY { x: 0, y: 1 },
|
|
||||||
XY { x: 1, y: 1 },
|
|
||||||
XY { x: 5, y: 2 },
|
|
||||||
XY { x: 1, y: 0 },
|
|
||||||
XY { x: 5, y: 1 },
|
|
||||||
XY { x: 6, y: 1 },
|
|
||||||
XY { x: 6, y: 0 },
|
|
||||||
XY { x: 7, y: 0 },
|
|
||||||
XY { x: 8, y: 0 },
|
|
||||||
XY { x: 10, y: 1 },
|
|
||||||
XY { x: 14, y: 0 },
|
|
||||||
XY { x: 16, y: 1 },
|
|
||||||
XY { x: 13, y: 3 },
|
|
||||||
XY { x: 14, y: 3 }
|
|
||||||
]
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,186 +0,0 @@
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::env;
|
|
||||||
use std::fs::File;
|
|
||||||
use std::io;
|
|
||||||
|
|
||||||
use aoc2019::intcode;
|
|
||||||
|
|
||||||
#[derive(Hash, Default, PartialEq, Eq, Clone)]
|
|
||||||
struct Panel {
|
|
||||||
x: isize,
|
|
||||||
y: isize,
|
|
||||||
}
|
|
||||||
|
|
||||||
enum Color {
|
|
||||||
Black,
|
|
||||||
White,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<isize> for Color {
|
|
||||||
fn from(color: isize) -> Self {
|
|
||||||
match color {
|
|
||||||
0 => Color::Black,
|
|
||||||
1 => Color::White,
|
|
||||||
_ => panic!("invalid color"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Into<isize> for &Color {
|
|
||||||
fn into(self) -> isize {
|
|
||||||
match self {
|
|
||||||
Color::Black => 0,
|
|
||||||
Color::White => 1,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Color {
|
|
||||||
fn char(&self) -> char {
|
|
||||||
match self {
|
|
||||||
Color::Black => ' ',
|
|
||||||
Color::White => '\u{2588}',
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum Direction {
|
|
||||||
Up,
|
|
||||||
Down,
|
|
||||||
Left,
|
|
||||||
Right,
|
|
||||||
}
|
|
||||||
|
|
||||||
enum Turn {
|
|
||||||
Left,
|
|
||||||
Right,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<isize> for Turn {
|
|
||||||
fn from(turn: isize) -> Self {
|
|
||||||
match turn {
|
|
||||||
0 => Turn::Left,
|
|
||||||
1 => Turn::Right,
|
|
||||||
_ => panic!("invalid turn direction"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Robot {
|
|
||||||
panel: Panel,
|
|
||||||
direction: Direction,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Robot {
|
|
||||||
fn turn(&mut self, direction: Turn) {
|
|
||||||
self.direction = match self.direction {
|
|
||||||
Direction::Up => match direction {
|
|
||||||
Turn::Left => Direction::Left,
|
|
||||||
Turn::Right => Direction::Right,
|
|
||||||
},
|
|
||||||
Direction::Right => match direction {
|
|
||||||
Turn::Left => Direction::Up,
|
|
||||||
Turn::Right => Direction::Down,
|
|
||||||
},
|
|
||||||
Direction::Down => match direction {
|
|
||||||
Turn::Left => Direction::Right,
|
|
||||||
Turn::Right => Direction::Left,
|
|
||||||
},
|
|
||||||
Direction::Left => match direction {
|
|
||||||
Turn::Left => Direction::Down,
|
|
||||||
Turn::Right => Direction::Up,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn step(&mut self) {
|
|
||||||
self.panel = match self.direction {
|
|
||||||
Direction::Up => Panel {
|
|
||||||
x: self.panel.x,
|
|
||||||
y: self.panel.y + 1,
|
|
||||||
},
|
|
||||||
Direction::Left => Panel {
|
|
||||||
x: self.panel.x + 1,
|
|
||||||
y: self.panel.y,
|
|
||||||
},
|
|
||||||
Direction::Down => Panel {
|
|
||||||
x: self.panel.x,
|
|
||||||
y: self.panel.y - 1,
|
|
||||||
},
|
|
||||||
Direction::Right => Panel {
|
|
||||||
x: self.panel.x - 1,
|
|
||||||
y: self.panel.y,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() -> io::Result<()> {
|
|
||||||
let filename = env::args().nth(1).expect("provide file as first param");
|
|
||||||
let mut computer = intcode::Computer::from(File::open(filename)?);
|
|
||||||
|
|
||||||
let mut canvas: HashMap<Panel, Color> = HashMap::new();
|
|
||||||
canvas.insert(Panel { x: 0, y: 0 }, Color::White);
|
|
||||||
let mut robot = Robot {
|
|
||||||
panel: Panel::default(),
|
|
||||||
direction: Direction::Up,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut input: isize = canvas
|
|
||||||
.get(&robot.panel)
|
|
||||||
.or_else(|| Some(&Color::Black))
|
|
||||||
.unwrap()
|
|
||||||
.into();
|
|
||||||
while let Some(output) = computer.run_io(input) {
|
|
||||||
canvas.insert(robot.panel.clone(), Color::from(output));
|
|
||||||
|
|
||||||
let output = computer.run_must_output();
|
|
||||||
robot.turn(Turn::from(output));
|
|
||||||
robot.step();
|
|
||||||
|
|
||||||
input = canvas
|
|
||||||
.get(&robot.panel)
|
|
||||||
.or_else(|| Some(&Color::Black))
|
|
||||||
.unwrap()
|
|
||||||
.into();
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut xmin: isize = 0;
|
|
||||||
let mut xmax: isize = 0;
|
|
||||||
let mut ymin: isize = 0;
|
|
||||||
let mut ymax: isize = 0;
|
|
||||||
let painted = canvas
|
|
||||||
.iter()
|
|
||||||
.map(|(k, _)| {
|
|
||||||
if k.x < xmin {
|
|
||||||
xmin = k.x;
|
|
||||||
}
|
|
||||||
if k.x > xmax {
|
|
||||||
xmax = k.x;
|
|
||||||
}
|
|
||||||
if k.y < ymin {
|
|
||||||
ymin = k.y;
|
|
||||||
}
|
|
||||||
if k.y > ymax {
|
|
||||||
ymax = k.y;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.count();
|
|
||||||
println!("painted: {}", painted);
|
|
||||||
println!("canvas: x:{}-{} y:{}-{}", xmin, xmax, ymin, ymax);
|
|
||||||
|
|
||||||
for y in (ymin..=ymax).rev() {
|
|
||||||
for x in (xmin..=xmax).rev() {
|
|
||||||
print!(
|
|
||||||
"{}",
|
|
||||||
canvas
|
|
||||||
.get(&Panel { x, y })
|
|
||||||
.unwrap_or_else(|| &Color::Black)
|
|
||||||
.char()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
println!()
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
|
@ -1,332 +0,0 @@
|
||||||
use std::cmp::Ordering;
|
|
||||||
use std::collections::hash_map::DefaultHasher;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::hash::{Hash, Hasher};
|
|
||||||
use std::iter::FromIterator;
|
|
||||||
|
|
||||||
#[derive(PartialEq, Debug, Default, Clone, Hash)]
|
|
||||||
struct Object {
|
|
||||||
x: isize,
|
|
||||||
y: isize,
|
|
||||||
z: isize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<(isize, isize, isize)> for Object {
|
|
||||||
fn from(o: (isize, isize, isize)) -> Self {
|
|
||||||
Object {
|
|
||||||
x: o.0,
|
|
||||||
y: o.1,
|
|
||||||
z: o.2,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Object {
|
|
||||||
fn attract(&self, other: &Object, v: &mut Object) {
|
|
||||||
v.x += Object::cmp(self.x, other.x);
|
|
||||||
v.y += Object::cmp(self.y, other.y);
|
|
||||||
v.z += Object::cmp(self.z, other.z);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn apply(&mut self, v: &Object) {
|
|
||||||
self.x += v.x;
|
|
||||||
self.y += v.y;
|
|
||||||
self.z += v.z;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cmp(a: isize, b: isize) -> isize {
|
|
||||||
match b.cmp(&a) {
|
|
||||||
Ordering::Less => -1,
|
|
||||||
Ordering::Equal => 0,
|
|
||||||
Ordering::Greater => 1,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn energy(&self) -> usize {
|
|
||||||
return (self.x.abs() + self.y.abs() + self.z.abs()) as usize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Space {
|
|
||||||
iteration: u128,
|
|
||||||
moons: Vec<Object>,
|
|
||||||
velocy: Vec<Object>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Vec<Object>> for Space {
|
|
||||||
fn from(moons: Vec<Object>) -> Self {
|
|
||||||
let iteration = 0;
|
|
||||||
let velocy = Vec::from_iter((0..moons.len()).map(|_| Object::default()));
|
|
||||||
Space {
|
|
||||||
iteration,
|
|
||||||
moons,
|
|
||||||
velocy,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Hash for Space {
|
|
||||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
|
||||||
self.moons.iter().for_each(|m| m.hash(state));
|
|
||||||
self.velocy.iter().for_each(|v| v.hash(state));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Space {
|
|
||||||
fn step(&mut self) {
|
|
||||||
self.iteration += 1;
|
|
||||||
let moons: &mut Vec<Object> = self.moons.as_mut();
|
|
||||||
let velocy: &mut Vec<Object> = self.velocy.as_mut();
|
|
||||||
|
|
||||||
moons.iter().enumerate().for_each(|(idx, a)| {
|
|
||||||
moons.iter().for_each(|b| {
|
|
||||||
if a == b {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
a.attract(b, velocy.get_mut(idx).unwrap())
|
|
||||||
})
|
|
||||||
});
|
|
||||||
moons
|
|
||||||
.iter_mut()
|
|
||||||
.enumerate()
|
|
||||||
.for_each(|(idx, m)| m.apply(velocy.get(idx).unwrap()));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn status(&self) -> impl Iterator<Item = (&'_ Object, &'_ Object)> {
|
|
||||||
self.moons
|
|
||||||
.iter()
|
|
||||||
.zip(self.velocy.iter())
|
|
||||||
.map(|(a, b)| (a, b))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn iteration(&self) -> u128 {
|
|
||||||
return self.iteration;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn hashed(&self) -> u64 {
|
|
||||||
let mut hash = DefaultHasher::new();
|
|
||||||
self.hash(&mut hash);
|
|
||||||
hash.finish()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn reapeats(mut self) -> u128 {
|
|
||||||
let mut known: HashMap<u64, u128> = HashMap::new();
|
|
||||||
loop {
|
|
||||||
println!("a lot");
|
|
||||||
known.insert(self.hashed(), self.iteration());
|
|
||||||
// 4686774924
|
|
||||||
for _ in 0..10000000 {
|
|
||||||
self.step();
|
|
||||||
if let Some(iteration) = known.get(&self.hashed()) {
|
|
||||||
let ago = self.iteration() - iteration;
|
|
||||||
return ago;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Eq, PartialEq, Clone)]
|
|
||||||
struct Axis {
|
|
||||||
p: isize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<isize> for Axis {
|
|
||||||
fn from(p: isize) -> Self {
|
|
||||||
Axis { p }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Axis {
|
|
||||||
fn attract(&self, other: &Axis, v: &mut Axis) {
|
|
||||||
v.p += Axis::cmp(self.p, other.p);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn apply(&mut self, v: &Axis) {
|
|
||||||
self.p += v.p;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cmp(a: isize, b: isize) -> isize {
|
|
||||||
match b.cmp(&a) {
|
|
||||||
Ordering::Less => -1,
|
|
||||||
Ordering::Equal => 0,
|
|
||||||
Ordering::Greater => 1,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn energy(&self) -> usize {
|
|
||||||
return self.p.abs() as usize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct AxisSpace {
|
|
||||||
iteration: usize,
|
|
||||||
moons: Vec<Axis>,
|
|
||||||
velocy: Vec<Axis>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Vec<isize>> for AxisSpace {
|
|
||||||
fn from(moons: Vec<isize>) -> Self {
|
|
||||||
let iteration = 0;
|
|
||||||
let moons = Vec::from_iter(moons.iter().map(|i| Axis::from(*i)));
|
|
||||||
let velocy = Vec::from_iter((0..moons.len()).map(|_| Axis::from(0)));
|
|
||||||
AxisSpace {
|
|
||||||
iteration,
|
|
||||||
moons,
|
|
||||||
velocy,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AxisSpace {
|
|
||||||
fn step(&mut self) {
|
|
||||||
self.iteration += 1;
|
|
||||||
let moons: &mut Vec<Axis> = self.moons.as_mut();
|
|
||||||
let velocy: &mut Vec<Axis> = self.velocy.as_mut();
|
|
||||||
moons.iter().enumerate().for_each(|(idx, a)| {
|
|
||||||
moons.iter().for_each(|b| {
|
|
||||||
if a == b {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
a.attract(&b, &mut velocy[idx])
|
|
||||||
})
|
|
||||||
});
|
|
||||||
moons
|
|
||||||
.iter_mut()
|
|
||||||
.enumerate()
|
|
||||||
.for_each(|(idx, m)| m.apply(velocy.get(idx).unwrap()));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn iteration(&self) -> usize {
|
|
||||||
return self.iteration;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn reapeats(mut self) -> usize {
|
|
||||||
let want = self.moons.clone();
|
|
||||||
self.step();
|
|
||||||
while self.moons != want {
|
|
||||||
self.step();
|
|
||||||
}
|
|
||||||
return self.iteration() + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gcd(x: usize, y: usize) -> usize {
|
|
||||||
let mut x = x;
|
|
||||||
let mut y = y;
|
|
||||||
while y != 0 {
|
|
||||||
let t = y;
|
|
||||||
y = x % y;
|
|
||||||
x = t;
|
|
||||||
}
|
|
||||||
x
|
|
||||||
}
|
|
||||||
|
|
||||||
fn lcm(a: usize, b: usize) -> usize {
|
|
||||||
a * b / gcd(a, b)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn lcm3(a: usize, b: usize, c: usize) -> usize {
|
|
||||||
lcm(a, lcm(b, c))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
// part1
|
|
||||||
let moons = vec![
|
|
||||||
Object::from((17, 5, 1)),
|
|
||||||
Object::from((-2, -8, 8)),
|
|
||||||
Object::from((7, -6, 14)),
|
|
||||||
Object::from((1, -10, 4)),
|
|
||||||
];
|
|
||||||
let mut space = Space::from(moons);
|
|
||||||
let mut step_energy = 0;
|
|
||||||
(1..=100).for_each(|_i| {
|
|
||||||
(1..=10).for_each(|_| {
|
|
||||||
space.step();
|
|
||||||
});
|
|
||||||
step_energy = space
|
|
||||||
.status()
|
|
||||||
.map(|(o, v)| o.energy() * v.energy())
|
|
||||||
.fold(0, |mut acc, c| {
|
|
||||||
acc += c;
|
|
||||||
acc
|
|
||||||
});
|
|
||||||
});
|
|
||||||
println!("energy: {}", step_energy);
|
|
||||||
|
|
||||||
// part2
|
|
||||||
let xspace = AxisSpace::from(vec![-1, 2, 4, 3]);
|
|
||||||
let yspace = AxisSpace::from(vec![0, -10, -8, 5]);
|
|
||||||
let zspace = AxisSpace::from(vec![2, -7, 8, -1]);
|
|
||||||
let total = lcm3(xspace.reapeats(), yspace.reapeats(), zspace.reapeats());
|
|
||||||
println!("matching space found {} iterations ago", total);
|
|
||||||
|
|
||||||
let xspace = AxisSpace::from(vec![-8, 5, 2, 9]);
|
|
||||||
let yspace = AxisSpace::from(vec![-10, 5, -7, -8]);
|
|
||||||
let zspace = AxisSpace::from(vec![0, 10, 3, -3]);
|
|
||||||
let total = lcm3(xspace.reapeats(), yspace.reapeats(), zspace.reapeats());
|
|
||||||
println!("matching space found {} iterations ago", total);
|
|
||||||
|
|
||||||
let xspace = AxisSpace::from(vec![17, -2, 7, 1]);
|
|
||||||
let yspace = AxisSpace::from(vec![5, -8, -6, -10]);
|
|
||||||
let zspace = AxisSpace::from(vec![1, 8, 14, 4]);
|
|
||||||
let total = lcm3(xspace.reapeats(), yspace.reapeats(), zspace.reapeats());
|
|
||||||
println!("matching space found {} iterations ago", total);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn day12example1() {
|
|
||||||
let space = Space::from(vec![
|
|
||||||
Object::from((-1, 0, 2)),
|
|
||||||
Object::from((2, -10, -7)),
|
|
||||||
Object::from((4, -8, 8)),
|
|
||||||
Object::from((3, 5, -1)),
|
|
||||||
]);
|
|
||||||
assert!(space.status().eq(vec![
|
|
||||||
(&Object::from((-1, 0, 2)), &Object::default()),
|
|
||||||
(&Object::from((2, -10, -7)), &Object::from((0, 0, 0))),
|
|
||||||
(&Object::from((4, -8, 8)), &Object::from((0, 0, 0))),
|
|
||||||
(&Object::from((3, 5, -1)), &Object::from((0, 0, 0))),
|
|
||||||
]));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn day12part1() {
|
|
||||||
let mut space = Space::from(vec![
|
|
||||||
Object::from((17, 5, 1)),
|
|
||||||
Object::from((-2, -8, 8)),
|
|
||||||
Object::from((7, -6, 14)),
|
|
||||||
Object::from((1, -10, 4)),
|
|
||||||
]);
|
|
||||||
(1..=1000).for_each(|_| {
|
|
||||||
space.step();
|
|
||||||
});
|
|
||||||
|
|
||||||
let energy = space
|
|
||||||
.status()
|
|
||||||
.map(|(o, v)| {
|
|
||||||
println!("{:?} {:?}", o, v);
|
|
||||||
o.energy() * v.energy()
|
|
||||||
})
|
|
||||||
.fold(0, |mut acc, c| {
|
|
||||||
acc += c;
|
|
||||||
acc
|
|
||||||
});
|
|
||||||
assert_eq!(energy, 9876)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn day12example2() {
|
|
||||||
let space = Space::from(vec![
|
|
||||||
Object::from((-1, 0, 2)),
|
|
||||||
Object::from((2, -10, -7)),
|
|
||||||
Object::from((4, -8, 8)),
|
|
||||||
Object::from((3, 5, -1)),
|
|
||||||
]);
|
|
||||||
assert_eq!(space.reapeats(), 2772)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,135 +0,0 @@
|
||||||
use aoc2019::intcode;
|
|
||||||
use std::cmp::Ordering;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::error::Error;
|
|
||||||
use std::fs::File;
|
|
||||||
|
|
||||||
use ncurses;
|
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn Error>> {
|
|
||||||
let f = File::open("input13")?;
|
|
||||||
let mut computer = intcode::Computer::from(f);
|
|
||||||
let mut grid: Grid = HashMap::new();
|
|
||||||
while let Some(output) = computer.run_until_n_output(3) {
|
|
||||||
let mut output = output.into_iter();
|
|
||||||
let xy = XY {
|
|
||||||
x: output.next().unwrap(),
|
|
||||||
y: output.next().unwrap(),
|
|
||||||
};
|
|
||||||
let tile = Tile::from(output.next().unwrap());
|
|
||||||
grid.insert(xy, tile);
|
|
||||||
}
|
|
||||||
|
|
||||||
// part 1
|
|
||||||
let blocks = grid.iter().filter(|(_, v)| **v == Tile::Block).count();
|
|
||||||
println!("blocks: {}", blocks);
|
|
||||||
|
|
||||||
// part2
|
|
||||||
ncurses::initscr();
|
|
||||||
ncurses::noecho();
|
|
||||||
let mut computer = computer.clone_with_modified_program(vec![(0, 2)]);
|
|
||||||
let mut paddlex = 0;
|
|
||||||
let mut score = 0;
|
|
||||||
while !computer.halted {
|
|
||||||
if let Some(output) = &computer.run_until_input() {
|
|
||||||
output.chunks(3).for_each(|c| {
|
|
||||||
if let &[x, y, value] = c {
|
|
||||||
if x == -1 && y == 0 {
|
|
||||||
score = value;
|
|
||||||
} else {
|
|
||||||
let tile = Tile::from(value);
|
|
||||||
if Tile::from(value) == Tile::HorizontalPaddle {
|
|
||||||
paddlex = x;
|
|
||||||
}
|
|
||||||
ncurses::mvprintw((y + 1) as i32, x as i32, tile.char());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
let np = next_pos(&mut computer.clone());
|
|
||||||
ncurses::mvprintw(
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
&format!(
|
|
||||||
"willx: {:0>2} paddlex: {:0>2} score: {:0>7}",
|
|
||||||
np, paddlex, score
|
|
||||||
),
|
|
||||||
);
|
|
||||||
let joystick = match np.cmp(&paddlex) {
|
|
||||||
Ordering::Less => -1,
|
|
||||||
Ordering::Equal => 0,
|
|
||||||
Ordering::Greater => 1,
|
|
||||||
};
|
|
||||||
computer.push_input_and_step(joystick);
|
|
||||||
ncurses::refresh();
|
|
||||||
}
|
|
||||||
ncurses::endwin();
|
|
||||||
println!("score: {}", score);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn next_pos(computer: &mut intcode::Computer) -> isize {
|
|
||||||
while !computer.halted {
|
|
||||||
if let Some(output) = computer.run_until_input() {
|
|
||||||
for c in output.chunks(3) {
|
|
||||||
if let &[x, y, value] = c {
|
|
||||||
if x == -1 && y == 0 {
|
|
||||||
// skip score
|
|
||||||
} else if Tile::from(value) == Tile::Ball && y == 23 {
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
computer.push_input_and_step(0);
|
|
||||||
}
|
|
||||||
0
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Eq, PartialEq)]
|
|
||||||
enum Tile {
|
|
||||||
Empty,
|
|
||||||
Wall,
|
|
||||||
Block,
|
|
||||||
HorizontalPaddle,
|
|
||||||
Ball,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<isize> for Tile {
|
|
||||||
fn from(i: isize) -> Self {
|
|
||||||
match i {
|
|
||||||
0 => Tile::Empty,
|
|
||||||
1 => Tile::Wall,
|
|
||||||
2 => Tile::Block,
|
|
||||||
3 => Tile::HorizontalPaddle,
|
|
||||||
4 => Tile::Ball,
|
|
||||||
_ => unreachable!("there are only 5 tiles..."),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Tile {
|
|
||||||
fn char(&self) -> &str {
|
|
||||||
match self {
|
|
||||||
Tile::Empty => " ",
|
|
||||||
Tile::Wall => "X",
|
|
||||||
Tile::Block => "O",
|
|
||||||
Tile::HorizontalPaddle => "-",
|
|
||||||
Tile::Ball => "*",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Eq, PartialEq, Hash)]
|
|
||||||
struct XY {
|
|
||||||
x: isize,
|
|
||||||
y: isize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<(isize, isize)> for XY {
|
|
||||||
fn from(xy: (isize, isize)) -> Self {
|
|
||||||
XY { x: xy.0, y: xy.1 }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type Grid = HashMap<XY, Tile>;
|
|
|
@ -1,385 +0,0 @@
|
||||||
use std::cmp::Ordering;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::convert::*;
|
|
||||||
use std::fs::File;
|
|
||||||
use std::io::{BufRead, BufReader};
|
|
||||||
|
|
||||||
type Resource = String;
|
|
||||||
type Pipeline = HashMap<Resource, ResourceBuilder>;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct ResourceBuilder {
|
|
||||||
requirements: Vec<Resource>,
|
|
||||||
out_count: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<(Vec<Resource>, usize)> for ResourceBuilder {
|
|
||||||
fn from(build: (Vec<Resource>, usize)) -> Self {
|
|
||||||
ResourceBuilder {
|
|
||||||
requirements: build.0,
|
|
||||||
out_count: build.1,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default, Debug)]
|
|
||||||
struct NanoFactory {
|
|
||||||
pipeline: Pipeline,
|
|
||||||
ordered: Vec<Resource>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
enum NanoFactoryBuildState {
|
|
||||||
InputCount,
|
|
||||||
InputResource,
|
|
||||||
OutputArrow,
|
|
||||||
OutputCount,
|
|
||||||
OutputResource,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl NanoFactory {
|
|
||||||
/// sort resources
|
|
||||||
fn resolve_order(&mut self) {
|
|
||||||
self.ordered = vec![Resource::from("ORE")];
|
|
||||||
let mut sortable: HashMap<Resource, Vec<Resource>> = self
|
|
||||||
.pipeline
|
|
||||||
.iter()
|
|
||||||
.map(|(k, v)| (k.clone(), v.requirements.clone()))
|
|
||||||
.collect();
|
|
||||||
while sortable.len() > 0 {
|
|
||||||
sortable = sortable
|
|
||||||
.into_iter()
|
|
||||||
.filter_map(|(k, v)| {
|
|
||||||
if v.iter().all(|i| self.ordered.contains(i)) {
|
|
||||||
self.ordered.push(k);
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some((k, v))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
}
|
|
||||||
self.ordered.reverse();
|
|
||||||
self.ordered.retain(|res| res != "ORE");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// calculate how much ores are required for required_fuel
|
|
||||||
fn resource_usage(&self, required_fuel: u128) -> usize {
|
|
||||||
// create storage to track leftover resources
|
|
||||||
let mut storage: HashMap<Resource, u128> = HashMap::new();
|
|
||||||
storage.insert(Resource::from("FUEL"), required_fuel);
|
|
||||||
|
|
||||||
// calculate resource costs
|
|
||||||
self.ordered.iter().for_each(|res| {
|
|
||||||
let rb = self.pipeline.get(res).unwrap();
|
|
||||||
let count = (storage.get(res).unwrap().clone() + (rb.out_count as u128) - 1)
|
|
||||||
/ (rb.out_count as u128);
|
|
||||||
rb.requirements.iter().for_each(|req| {
|
|
||||||
storage
|
|
||||||
.entry(req.clone())
|
|
||||||
.and_modify(|v| *v += count)
|
|
||||||
.or_insert(count);
|
|
||||||
storage.insert(res.clone(), 0);
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
// return cost for ore
|
|
||||||
println!("{:?}", storage);
|
|
||||||
*storage.get("ORE").unwrap() as usize
|
|
||||||
}
|
|
||||||
|
|
||||||
/// generate a single fuel
|
|
||||||
fn generate_fuel(&self) -> usize {
|
|
||||||
let mut storage: HashMap<Resource, usize> = HashMap::new();
|
|
||||||
self.lookup_resource(&mut storage, "FUEL")
|
|
||||||
}
|
|
||||||
|
|
||||||
/// recursively calculate the cost of a resource in ores
|
|
||||||
fn lookup_resource(&self, storage: &mut HashMap<Resource, usize>, resource: &str) -> usize {
|
|
||||||
if resource == "ORE" {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// use from storage
|
|
||||||
if let Some(count) = storage.get_mut(resource) {
|
|
||||||
if *count > 0 {
|
|
||||||
*count -= 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// initialize storage with zero
|
|
||||||
if storage.get(resource).is_none() {
|
|
||||||
storage.insert(resource.into(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// build resource and and to storage
|
|
||||||
let required = self
|
|
||||||
.pipeline
|
|
||||||
.get(resource)
|
|
||||||
.expect("unable to find resource");
|
|
||||||
let cost = required.requirements.iter().fold(0, |mut acc, c| {
|
|
||||||
acc += self.lookup_resource(storage, c);
|
|
||||||
acc
|
|
||||||
});
|
|
||||||
|
|
||||||
// update storage
|
|
||||||
let stored = storage.get_mut(resource).unwrap();
|
|
||||||
*stored += required.out_count - 1;
|
|
||||||
|
|
||||||
cost
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> From<T> for NanoFactory
|
|
||||||
where
|
|
||||||
T: BufRead,
|
|
||||||
{
|
|
||||||
fn from(bufreader: T) -> Self {
|
|
||||||
let mut f = NanoFactory::default();
|
|
||||||
let mut state = NanoFactoryBuildState::InputCount;
|
|
||||||
bufreader.split(b'\n').enumerate().for_each(|(nr, line)| {
|
|
||||||
let line = line.unwrap();
|
|
||||||
let mut line = line.into_iter().peekable();
|
|
||||||
let mut count_var = 0;
|
|
||||||
let mut cur_requirements = Vec::new();
|
|
||||||
loop {
|
|
||||||
match state {
|
|
||||||
// numeric input
|
|
||||||
NanoFactoryBuildState::InputCount | NanoFactoryBuildState::OutputCount => {
|
|
||||||
while let Some(c) = next_if_in_range(&mut line, 48..=57) {
|
|
||||||
count_var = count_var * 10 + (c as usize) - 48;
|
|
||||||
}
|
|
||||||
assert_eq!(line.next().unwrap(), b' ');
|
|
||||||
state = match state {
|
|
||||||
NanoFactoryBuildState::InputCount => {
|
|
||||||
NanoFactoryBuildState::InputResource
|
|
||||||
}
|
|
||||||
NanoFactoryBuildState::OutputCount => {
|
|
||||||
NanoFactoryBuildState::OutputResource
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// input resouce name
|
|
||||||
NanoFactoryBuildState::InputResource => {
|
|
||||||
let mut r = Resource::new();
|
|
||||||
while let Some(c) = next_if_in_range(&mut line, 65..=90) {
|
|
||||||
r.push(c.into());
|
|
||||||
}
|
|
||||||
for _ in 0..count_var {
|
|
||||||
cur_requirements.push(r.clone());
|
|
||||||
}
|
|
||||||
r.truncate(0);
|
|
||||||
count_var = 0;
|
|
||||||
let next = line.next();
|
|
||||||
match next {
|
|
||||||
Some(b',') => {
|
|
||||||
assert_eq!(line.next().unwrap(), b' ');
|
|
||||||
state = NanoFactoryBuildState::InputCount;
|
|
||||||
}
|
|
||||||
Some(b' ') => state = NanoFactoryBuildState::OutputArrow,
|
|
||||||
_ => panic!(
|
|
||||||
"invalid format in line {}, expected ' ' or ',', got '{:?}'",
|
|
||||||
nr, next
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// output resource name
|
|
||||||
NanoFactoryBuildState::OutputResource => {
|
|
||||||
let mut r = Resource::new();
|
|
||||||
while let Some(c) = next_if_in_range(&mut line, 65..=90) {
|
|
||||||
r.push(c.into());
|
|
||||||
}
|
|
||||||
f.pipeline
|
|
||||||
.insert(r, ResourceBuilder::from((cur_requirements, count_var)));
|
|
||||||
state = NanoFactoryBuildState::InputCount;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// arrow between input and output ' => '
|
|
||||||
NanoFactoryBuildState::OutputArrow => {
|
|
||||||
assert_eq!(line.next().unwrap(), b'=');
|
|
||||||
assert_eq!(line.next().unwrap(), b'>');
|
|
||||||
assert_eq!(line.next().unwrap(), b' ');
|
|
||||||
state = NanoFactoryBuildState::OutputCount
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
f
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn next_if_in_range<I, T>(
|
|
||||||
peekable: &mut std::iter::Peekable<I>,
|
|
||||||
range: std::ops::RangeInclusive<T>,
|
|
||||||
) -> Option<T>
|
|
||||||
where
|
|
||||||
I: std::iter::Iterator<Item = T>,
|
|
||||||
T: Copy + std::cmp::PartialOrd,
|
|
||||||
{
|
|
||||||
if let Some(peeked) = peekable.peek() {
|
|
||||||
if range.contains(peeked) {
|
|
||||||
peekable.next()
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let f = File::open("input14").unwrap();
|
|
||||||
let bufreader = BufReader::new(f);
|
|
||||||
let mut factory = NanoFactory::from(bufreader);
|
|
||||||
|
|
||||||
// part1
|
|
||||||
println!("ores: {}", factory.generate_fuel());
|
|
||||||
|
|
||||||
// part2 as binary search
|
|
||||||
factory.resolve_order();
|
|
||||||
let mut min = 1;
|
|
||||||
let mut max = 1_000_000_000_000;
|
|
||||||
let mut fuel;
|
|
||||||
loop {
|
|
||||||
fuel = (min + max) / 2;
|
|
||||||
let ore = factory.resource_usage(fuel);
|
|
||||||
match 1_000_000_000_000.cmp(&ore) {
|
|
||||||
Ordering::Less => max = fuel - 1,
|
|
||||||
Ordering::Greater => {
|
|
||||||
min = fuel + 1;
|
|
||||||
if min > max {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ordering::Equal => {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
println!("ammount: {}", fuel);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn example1() {
|
|
||||||
let bufreader = BufReader::new(
|
|
||||||
"10 ORE => 10 A
|
|
||||||
1 ORE => 1 B
|
|
||||||
7 A, 1 B => 1 C
|
|
||||||
7 A, 1 C => 1 D
|
|
||||||
7 A, 1 D => 1 E
|
|
||||||
7 A, 1 E => 1 FUEL
|
|
||||||
"
|
|
||||||
.trim()
|
|
||||||
.as_bytes(),
|
|
||||||
);
|
|
||||||
let mut factory = NanoFactory::from(bufreader);
|
|
||||||
factory.resolve_order();
|
|
||||||
assert_eq!(factory.generate_fuel(), 31);
|
|
||||||
assert_eq!(factory.resource_usage(1), 31);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn example2() {
|
|
||||||
let bufreader = BufReader::new(
|
|
||||||
"
|
|
||||||
9 ORE => 2 A
|
|
||||||
8 ORE => 3 B
|
|
||||||
7 ORE => 5 C
|
|
||||||
3 A, 4 B => 1 AB
|
|
||||||
5 B, 7 C => 1 BC
|
|
||||||
4 C, 1 A => 1 CA
|
|
||||||
2 AB, 3 BC, 4 CA => 1 FUEL
|
|
||||||
"
|
|
||||||
.trim()
|
|
||||||
.as_bytes(),
|
|
||||||
);
|
|
||||||
let mut factory = NanoFactory::from(bufreader);
|
|
||||||
factory.resolve_order();
|
|
||||||
assert_eq!(factory.generate_fuel(), 165);
|
|
||||||
assert_eq!(factory.resource_usage(1), 165);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn example3() {
|
|
||||||
let bufreader = BufReader::new(
|
|
||||||
"
|
|
||||||
157 ORE => 5 NZVS
|
|
||||||
165 ORE => 6 DCFZ
|
|
||||||
44 XJWVT, 5 KHKGT, 1 QDVJ, 29 NZVS, 9 GPVTF, 48 HKGWZ => 1 FUEL
|
|
||||||
12 HKGWZ, 1 GPVTF, 8 PSHF => 9 QDVJ
|
|
||||||
179 ORE => 7 PSHF
|
|
||||||
177 ORE => 5 HKGWZ
|
|
||||||
7 DCFZ, 7 PSHF => 2 XJWVT
|
|
||||||
165 ORE => 2 GPVTF
|
|
||||||
3 DCFZ, 7 NZVS, 5 HKGWZ, 10 PSHF => 8 KHKGT
|
|
||||||
"
|
|
||||||
.trim()
|
|
||||||
.as_bytes(),
|
|
||||||
);
|
|
||||||
let factory = NanoFactory::from(bufreader);
|
|
||||||
assert_eq!(factory.generate_fuel(), 13312);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn example4() {
|
|
||||||
let bufreader = BufReader::new(
|
|
||||||
"
|
|
||||||
2 VPVL, 7 FWMGM, 2 CXFTF, 11 MNCFX => 1 STKFG
|
|
||||||
17 NVRVD, 3 JNWZP => 8 VPVL
|
|
||||||
53 STKFG, 6 MNCFX, 46 VJHF, 81 HVMC, 68 CXFTF, 25 GNMV => 1 FUEL
|
|
||||||
22 VJHF, 37 MNCFX => 5 FWMGM
|
|
||||||
139 ORE => 4 NVRVD
|
|
||||||
144 ORE => 7 JNWZP
|
|
||||||
5 MNCFX, 7 RFSQX, 2 FWMGM, 2 VPVL, 19 CXFTF => 3 HVMC
|
|
||||||
5 VJHF, 7 MNCFX, 9 VPVL, 37 CXFTF => 6 GNMV
|
|
||||||
145 ORE => 6 MNCFX
|
|
||||||
1 NVRVD => 8 CXFTF
|
|
||||||
1 VJHF, 6 MNCFX => 4 RFSQX
|
|
||||||
176 ORE => 6 VJHF
|
|
||||||
"
|
|
||||||
.trim()
|
|
||||||
.as_bytes(),
|
|
||||||
);
|
|
||||||
let mut factory = NanoFactory::from(bufreader);
|
|
||||||
factory.resolve_order();
|
|
||||||
assert_eq!(factory.generate_fuel(), 180697);
|
|
||||||
assert_eq!(factory.resource_usage(1), 180697);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn example5() {
|
|
||||||
let bufreader = BufReader::new(
|
|
||||||
"
|
|
||||||
171 ORE => 8 CNZTR
|
|
||||||
7 ZLQW, 3 BMBT, 9 XCVML, 26 XMNCP, 1 WPTQ, 2 MZWV, 1 RJRHP => 4 PLWSL
|
|
||||||
114 ORE => 4 BHXH
|
|
||||||
14 VRPVC => 6 BMBT
|
|
||||||
6 BHXH, 18 KTJDG, 12 WPTQ, 7 PLWSL, 31 FHTLT, 37 ZDVW => 1 FUEL
|
|
||||||
6 WPTQ, 2 BMBT, 8 ZLQW, 18 KTJDG, 1 XMNCP, 6 MZWV, 1 RJRHP => 6 FHTLT
|
|
||||||
15 XDBXC, 2 LTCX, 1 VRPVC => 6 ZLQW
|
|
||||||
13 WPTQ, 10 LTCX, 3 RJRHP, 14 XMNCP, 2 MZWV, 1 ZLQW => 1 ZDVW
|
|
||||||
5 BMBT => 4 WPTQ
|
|
||||||
189 ORE => 9 KTJDG
|
|
||||||
1 MZWV, 17 XDBXC, 3 XCVML => 2 XMNCP
|
|
||||||
12 VRPVC, 27 CNZTR => 2 XDBXC
|
|
||||||
15 KTJDG, 12 BHXH => 5 XCVML
|
|
||||||
3 BHXH, 2 VRPVC => 7 MZWV
|
|
||||||
121 ORE => 7 VRPVC
|
|
||||||
7 XCVML => 6 RJRHP
|
|
||||||
5 BHXH, 4 VRPVC => 5 LTCX
|
|
||||||
"
|
|
||||||
.trim()
|
|
||||||
.as_bytes(),
|
|
||||||
);
|
|
||||||
let mut factory = NanoFactory::from(bufreader);
|
|
||||||
factory.resolve_order();
|
|
||||||
assert_eq!(factory.generate_fuel(), 2210736);
|
|
||||||
assert_eq!(factory.resource_usage(1), 2210736);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,205 +0,0 @@
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::error::Error;
|
|
||||||
use std::fs::File;
|
|
||||||
|
|
||||||
use aoc2019::intcode;
|
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn Error>> {
|
|
||||||
let f = File::open("input15")?;
|
|
||||||
let computer = intcode::Computer::from(f);
|
|
||||||
let mut map = Map::new();
|
|
||||||
let steps = map.walk(&XY { x: 0, y: 0 }, &computer, 0).unwrap();
|
|
||||||
|
|
||||||
for y in map.ymin..=map.ymax {
|
|
||||||
for x in map.xmin..=map.xmax {
|
|
||||||
if x == 0 && y == 0 {
|
|
||||||
print!("0");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let status = map.m.get(&XY { x, y }).unwrap_or(&Status::Empty);
|
|
||||||
let c = match status {
|
|
||||||
Status::HitWall => "#",
|
|
||||||
Status::MoveComplete => ".",
|
|
||||||
Status::Finished => "X",
|
|
||||||
Status::Empty => " ",
|
|
||||||
Status::Oxigenated => "o",
|
|
||||||
};
|
|
||||||
print!("{}", c);
|
|
||||||
}
|
|
||||||
println!("");
|
|
||||||
}
|
|
||||||
|
|
||||||
println!("i walked {} steps", steps);
|
|
||||||
let steps = map.fill();
|
|
||||||
println!("filled with oxygen after {} minutes", steps);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default, Debug)]
|
|
||||||
struct Map {
|
|
||||||
m: HashMap<XY, Status>,
|
|
||||||
xmin: isize,
|
|
||||||
xmax: isize,
|
|
||||||
ymin: isize,
|
|
||||||
ymax: isize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Map {
|
|
||||||
fn new() -> Self {
|
|
||||||
Map::default()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn walk(&mut self, start: &XY, computer: &intcode::Computer, steps: usize) -> Option<usize> {
|
|
||||||
let steps = steps + 1;
|
|
||||||
let mut result = None;
|
|
||||||
for dir in 1..=4 {
|
|
||||||
let direction = Direction::from(dir);
|
|
||||||
let xy = start.add((&direction).into());
|
|
||||||
if self.m.contains_key(&xy) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
self.update_limits(&xy);
|
|
||||||
let mut computer = computer.clone();
|
|
||||||
if let Some(status) = computer.run_io(dir) {
|
|
||||||
let status = Status::from(status);
|
|
||||||
self.m.insert(xy.clone(), status.clone());
|
|
||||||
match status {
|
|
||||||
Status::HitWall => (),
|
|
||||||
Status::MoveComplete => match self.walk(&xy, &computer, steps) {
|
|
||||||
Some(i) => result = Some(i + 1),
|
|
||||||
None => (),
|
|
||||||
},
|
|
||||||
Status::Finished => result = Some(1),
|
|
||||||
_ => unreachable!("unknown status"),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
unreachable!("computer unexpectedly halted");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fill(&mut self) -> usize {
|
|
||||||
let mut src: Vec<XY> = self
|
|
||||||
.m
|
|
||||||
.iter()
|
|
||||||
.filter_map(|(xy, status)| match status {
|
|
||||||
Status::Finished => Some(xy),
|
|
||||||
_ => None,
|
|
||||||
})
|
|
||||||
.cloned()
|
|
||||||
.collect();
|
|
||||||
let mut steps = 0;
|
|
||||||
while src.len() > 0 {
|
|
||||||
steps += 1;
|
|
||||||
src.iter()
|
|
||||||
.for_each(|xy| *self.m.get_mut(xy).unwrap() = Status::Oxigenated);
|
|
||||||
src = src
|
|
||||||
.into_iter()
|
|
||||||
.map(|xy| {
|
|
||||||
(1..=4)
|
|
||||||
.map(Direction::from)
|
|
||||||
.map(move |d| xy.add((&d).into()))
|
|
||||||
})
|
|
||||||
.flatten()
|
|
||||||
.filter(|xy| match self.m.get(xy) {
|
|
||||||
Some(Status::MoveComplete) => true,
|
|
||||||
_ => false,
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
}
|
|
||||||
assert_eq!(
|
|
||||||
self.m
|
|
||||||
.values()
|
|
||||||
.filter(|status| match status {
|
|
||||||
Status::MoveComplete => true,
|
|
||||||
_ => false,
|
|
||||||
})
|
|
||||||
.count(),
|
|
||||||
0
|
|
||||||
);
|
|
||||||
steps - 1
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update_limits(&mut self, xy: &XY) {
|
|
||||||
if self.xmin > xy.x {
|
|
||||||
self.xmin = xy.x
|
|
||||||
}
|
|
||||||
if self.xmax < xy.x {
|
|
||||||
self.xmax = xy.x
|
|
||||||
}
|
|
||||||
if self.ymin > xy.y {
|
|
||||||
self.ymin = xy.y
|
|
||||||
}
|
|
||||||
if self.ymax < xy.y {
|
|
||||||
self.ymax = xy.y
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
enum Direction {
|
|
||||||
North = 1,
|
|
||||||
South = 2,
|
|
||||||
West = 3,
|
|
||||||
East = 4,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<isize> for Direction {
|
|
||||||
fn from(i: isize) -> Self {
|
|
||||||
match i {
|
|
||||||
1 => Direction::North,
|
|
||||||
2 => Direction::South,
|
|
||||||
3 => Direction::West,
|
|
||||||
4 => Direction::East,
|
|
||||||
_ => unreachable!("no status for computer output"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Into<(isize, isize)> for &Direction {
|
|
||||||
fn into(self) -> (isize, isize) {
|
|
||||||
match self {
|
|
||||||
Direction::North => (0, 1),
|
|
||||||
Direction::South => (0, -1),
|
|
||||||
Direction::West => (-1, 0),
|
|
||||||
Direction::East => (1, 0),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
enum Status {
|
|
||||||
HitWall = 0,
|
|
||||||
MoveComplete = 1,
|
|
||||||
Finished = 2,
|
|
||||||
Empty = 3,
|
|
||||||
Oxigenated = 4,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<isize> for Status {
|
|
||||||
fn from(i: isize) -> Self {
|
|
||||||
match i {
|
|
||||||
0 => Status::HitWall,
|
|
||||||
1 => Status::MoveComplete,
|
|
||||||
2 => Status::Finished,
|
|
||||||
_ => unreachable!("no status for computer output"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Hash, Clone, Debug)]
|
|
||||||
struct XY {
|
|
||||||
x: isize,
|
|
||||||
y: isize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl XY {
|
|
||||||
fn add(&self, delta: (isize, isize)) -> XY {
|
|
||||||
XY {
|
|
||||||
x: self.x + delta.0,
|
|
||||||
y: self.y + delta.1,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
477
src/intcode.rs
477
src/intcode.rs
|
@ -1,477 +0,0 @@
|
||||||
use std::collections::VecDeque;
|
|
||||||
use std::fs::File;
|
|
||||||
use std::io::{BufRead, BufReader};
|
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
enum Var {
|
|
||||||
A = 1,
|
|
||||||
B,
|
|
||||||
C,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
|
||||||
enum Mode {
|
|
||||||
Position,
|
|
||||||
Immediate,
|
|
||||||
Relative,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Mode {
|
|
||||||
fn default() -> Self {
|
|
||||||
Mode::Position
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<isize> for Mode {
|
|
||||||
fn from(b: isize) -> Self {
|
|
||||||
match b {
|
|
||||||
0 => Mode::Position,
|
|
||||||
1 => Mode::Immediate,
|
|
||||||
2 => Mode::Relative,
|
|
||||||
_ => panic!("invalid mode {}", b),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Default, Debug)]
|
|
||||||
struct Modes {
|
|
||||||
a: Mode,
|
|
||||||
b: Mode,
|
|
||||||
c: Mode,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Modes {
|
|
||||||
fn mode_for(&self, v: &Var) -> Mode {
|
|
||||||
match v {
|
|
||||||
Var::A => self.a,
|
|
||||||
Var::B => self.b,
|
|
||||||
Var::C => self.c,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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,
|
|
||||||
RelativeAdj,
|
|
||||||
Halt,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<&ModedOpcode> for Opcode {
|
|
||||||
fn from(mo: &ModedOpcode) -> Self {
|
|
||||||
mo.op
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<isize> for Opcode {
|
|
||||||
fn from(i: isize) -> 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,
|
|
||||||
9 => Opcode::RelativeAdj,
|
|
||||||
99 => Opcode::Halt,
|
|
||||||
_ => panic!("invalid opcode {}", i),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ModedOpcode {
|
|
||||||
modes: Modes,
|
|
||||||
op: Opcode,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<isize> for ModedOpcode {
|
|
||||||
fn from(i: isize) -> Self {
|
|
||||||
let code = i % 100;
|
|
||||||
let modes = i / 100;
|
|
||||||
let a = (modes % 10) / 1;
|
|
||||||
let b = (modes % 100) / 10;
|
|
||||||
let c = (modes % 1000) / 100;
|
|
||||||
let modes = (Mode::from(a), Mode::from(b), Mode::from(c));
|
|
||||||
ModedOpcode {
|
|
||||||
modes: Modes::from(modes),
|
|
||||||
op: Opcode::from(code),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Computer {
|
|
||||||
pos: usize,
|
|
||||||
rel: isize,
|
|
||||||
program: Vec<isize>,
|
|
||||||
modes: Modes,
|
|
||||||
inputs: VecDeque<isize>,
|
|
||||||
outputs: VecDeque<isize>,
|
|
||||||
pub halted: 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<isize> = 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 isize + 10 * s))
|
|
||||||
* sign
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
Computer::from(program)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Vec<isize>> for Computer {
|
|
||||||
fn from(program: Vec<isize>) -> Self {
|
|
||||||
Computer {
|
|
||||||
pos: 0,
|
|
||||||
rel: 0,
|
|
||||||
program,
|
|
||||||
modes: Default::default(),
|
|
||||||
inputs: VecDeque::new(),
|
|
||||||
outputs: VecDeque::new(),
|
|
||||||
halted: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Computer {
|
|
||||||
pub fn get_outputs(&self) -> &VecDeque<isize> {
|
|
||||||
&self.outputs
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn pop_output(&mut self) -> Option<isize> {
|
|
||||||
self.outputs.pop_front()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn push_input_and_step(&mut self, input: isize) {
|
|
||||||
self.inputs.push_back(input);
|
|
||||||
self.step()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn clone_with_modified_program(&self, u: Vec<(usize, isize)>) -> Computer {
|
|
||||||
let mut computer = self.clone();
|
|
||||||
for (pos, val) in u {
|
|
||||||
computer.program[pos] = val;
|
|
||||||
}
|
|
||||||
computer
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn clone_with_input(&self, input: Vec<isize>) -> Computer {
|
|
||||||
let mut computer = self.clone();
|
|
||||||
computer.inputs = VecDeque::from(input);
|
|
||||||
computer
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn run(&mut self) {
|
|
||||||
while !self.halted {
|
|
||||||
self.step();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn run_until_input(&mut self) -> Option<Vec<isize>> {
|
|
||||||
self.step_until_input();
|
|
||||||
if self.outputs.len() > 0 {
|
|
||||||
return Some(self.outputs.split_off(0).into_iter().collect());
|
|
||||||
}
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn run_until_n_output(&mut self, n: usize) -> Option<Vec<isize>> {
|
|
||||||
loop {
|
|
||||||
self.step();
|
|
||||||
if self.outputs.len() >= n {
|
|
||||||
return Some(self.outputs.split_off(0).into_iter().collect());
|
|
||||||
}
|
|
||||||
if self.halted {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn run_until_output(&mut self) -> Option<isize> {
|
|
||||||
loop {
|
|
||||||
self.step();
|
|
||||||
if self.outputs.len() > 0 {
|
|
||||||
return self.outputs.pop_front();
|
|
||||||
}
|
|
||||||
if self.halted {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn run_must_output(&mut self) -> isize {
|
|
||||||
self.run_until_output()
|
|
||||||
.expect("computer halted without output")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn run_io(&mut self, input: isize) -> Option<isize> {
|
|
||||||
self.inputs.push_back(input);
|
|
||||||
self.run_until_output()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn step_until_input(&mut self) {
|
|
||||||
while !self.halted {
|
|
||||||
let instruction = self.program[self.pos];
|
|
||||||
let instruction = ModedOpcode::from(instruction);
|
|
||||||
self.modes = Modes::from(&instruction);
|
|
||||||
let advance = match Opcode::from(&instruction) {
|
|
||||||
Opcode::Add => self.add(),
|
|
||||||
Opcode::Multiply => self.multiply(),
|
|
||||||
Opcode::Input => return,
|
|
||||||
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::RelativeAdj => self.relative_adj(),
|
|
||||||
Opcode::Halt => self.halt(),
|
|
||||||
};
|
|
||||||
self.pos += advance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn step(&mut self) {
|
|
||||||
let instruction = self.program[self.pos];
|
|
||||||
let instruction = ModedOpcode::from(instruction);
|
|
||||||
self.modes = Modes::from(&instruction);
|
|
||||||
let advance = match Opcode::from(&instruction) {
|
|
||||||
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::RelativeAdj => self.relative_adj(),
|
|
||||||
Opcode::Halt => self.halt(),
|
|
||||||
};
|
|
||||||
self.pos += advance;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_pos(&self, pos: usize) -> isize {
|
|
||||||
*self.program.get(pos).unwrap_or(&0)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get(&self, v: &Var) -> isize {
|
|
||||||
let want = self.pos + *v as usize;
|
|
||||||
let want = match self.modes.mode_for(v) {
|
|
||||||
Mode::Position => self.get_pos(want as usize) as usize,
|
|
||||||
Mode::Immediate => want,
|
|
||||||
Mode::Relative => (self.rel + self.get_pos(want)) as usize,
|
|
||||||
};
|
|
||||||
self.get_pos(want)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_a(&self) -> isize {
|
|
||||||
self.get(&Var::A)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_b(&self) -> isize {
|
|
||||||
self.get(&Var::B)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set(&mut self, v: &Var, value: isize) {
|
|
||||||
let length = self.program.len();
|
|
||||||
let want = self.pos + *v as usize;
|
|
||||||
let want = match self.modes.mode_for(v) {
|
|
||||||
Mode::Position => self.get_pos(want) as usize,
|
|
||||||
Mode::Immediate => want,
|
|
||||||
Mode::Relative => (self.rel + self.get_pos(want)) as usize,
|
|
||||||
};
|
|
||||||
if length <= want {
|
|
||||||
self.program.resize(want + 1, 0);
|
|
||||||
}
|
|
||||||
self.program[want] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_a(&mut self, value: isize) {
|
|
||||||
self.set(&Var::A, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_c(&mut self, value: isize) {
|
|
||||||
self.set(&Var::C, 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 relative_adj(&mut self) -> usize {
|
|
||||||
self.rel = self.rel + self.get_a();
|
|
||||||
2
|
|
||||||
}
|
|
||||||
|
|
||||||
fn halt(&mut self) -> usize {
|
|
||||||
self.halted = true;
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn example1() {
|
|
||||||
let program = vec![
|
|
||||||
109, 1, 204, -1, 1001, 100, 1, 100, 1008, 100, 16, 101, 1006, 101, 0, 99,
|
|
||||||
];
|
|
||||||
let mut computer = Computer::from(program.clone());
|
|
||||||
computer.run();
|
|
||||||
assert_eq!(computer.get_outputs().iter().eq(program.iter()), true)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn example2() {
|
|
||||||
assert_eq!(
|
|
||||||
Computer::from(vec![1102, 34915192, 34915192, 7, 4, 7, 99, 0]).run_must_output(),
|
|
||||||
1219070632396864
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn example3() {
|
|
||||||
assert_eq!(
|
|
||||||
Computer::from(vec![104, 1125899906842624, 99]).run_must_output(),
|
|
||||||
1125899906842624
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn day5exampe1() {
|
|
||||||
let computer = Computer::from(vec![3, 9, 8, 9, 10, 9, 4, 9, 99, -1, 8]);
|
|
||||||
assert_eq!(computer.clone_with_input(vec![1]).run_must_output(), 0);
|
|
||||||
assert_eq!(computer.clone_with_input(vec![8]).run_must_output(), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn day5exampe2() {
|
|
||||||
let computer = Computer::from(vec![3, 3, 1108, -1, 8, 3, 4, 3, 99]);
|
|
||||||
assert_eq!(computer.clone_with_input(vec![1]).run_must_output(), 0);
|
|
||||||
assert_eq!(computer.clone_with_input(vec![8]).run_must_output(), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn day5exampe3() {
|
|
||||||
let computer = Computer::from(vec![
|
|
||||||
3, 12, 6, 12, 15, 1, 13, 14, 13, 4, 13, 99, -1, 0, 1, 9,
|
|
||||||
]);
|
|
||||||
assert_eq!(computer.clone_with_input(vec![0]).run_must_output(), 0);
|
|
||||||
assert_eq!(computer.clone_with_input(vec![8]).run_must_output(), 1);
|
|
||||||
let computer = Computer::from(vec![3, 3, 1105, -1, 9, 1101, 0, 0, 12, 4, 12, 99, 1]);
|
|
||||||
assert_eq!(computer.clone_with_input(vec![0]).run_must_output(), 0);
|
|
||||||
assert_eq!(computer.clone_with_input(vec![8]).run_must_output(), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn day5exampe4() {
|
|
||||||
let computer = Computer::from(vec![
|
|
||||||
3, 21, 1008, 21, 8, 20, 1005, 20, 22, 107, 8, 21, 20, 1006, 20, 31, 1106, 0, 36, 98, 0,
|
|
||||||
0, 1002, 21, 125, 20, 4, 20, 1105, 1, 46, 104, 999, 1105, 1, 46, 1101, 1000, 1, 20, 4,
|
|
||||||
20, 1105, 1, 46, 98, 99,
|
|
||||||
]);
|
|
||||||
assert_eq!(computer.clone_with_input(vec![0]).run_must_output(), 999);
|
|
||||||
assert_eq!(computer.clone_with_input(vec![8]).run_must_output(), 1000);
|
|
||||||
assert_eq!(computer.clone_with_input(vec![9]).run_must_output(), 1001);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn day9part1() {
|
|
||||||
let computer = Computer::from(File::open("input9").unwrap());
|
|
||||||
assert_eq!(
|
|
||||||
computer.clone_with_input(vec![1]).run_must_output(),
|
|
||||||
3063082071
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
pub mod intcode;
|
|
3
src/main.rs
Normal file
3
src/main.rs
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
fn main() {
|
||||||
|
println!("Hello, world!");
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue