Compare commits
11 commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
655b99da1b | ||
![]() |
244e308200 | ||
![]() |
0bd196febf | ||
![]() |
a9b5197ca7 | ||
![]() |
e16cafaa52 | ||
![]() |
e27c10d3b0 | ||
b851d2bbe6 | |||
![]() |
9b09b974eb | ||
f12c16a06a | |||
ccc5c8038a | |||
4e908b8bf9 |
25 changed files with 2407 additions and 62 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,2 +1 @@
|
|||
/input*
|
||||
/target/
|
||||
|
|
32
Cargo.lock
generated
32
Cargo.lock
generated
|
@ -3,3 +3,35 @@
|
|||
[[package]]
|
||||
name = "aoc2019"
|
||||
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"
|
||||
|
|
29
Cargo.toml
29
Cargo.toml
|
@ -4,7 +4,8 @@ version = "0.1.0"
|
|||
authors = ["Stefan Schwarz <stefan@f2o.io>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
[dependencies]
|
||||
ncurses = "5.99.0"
|
||||
|
||||
[[bin]]
|
||||
name = "day1"
|
||||
|
@ -32,4 +33,28 @@ path = "src/day7/main.rs"
|
|||
|
||||
[[bin]]
|
||||
name = "day9"
|
||||
path = "src/day9/main.rs"
|
||||
path = "src/day9/main.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "day10"
|
||||
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
README.md
Normal file
1
README.md
Normal file
|
@ -0,0 +1 @@
|
|||
# Advent of Code 2019
|
100
input1
Normal file
100
input1
Normal file
|
@ -0,0 +1,100 @@
|
|||
119606
|
||||
94066
|
||||
80497
|
||||
136413
|
||||
83710
|
||||
136098
|
||||
113785
|
||||
100655
|
||||
148973
|
||||
78186
|
||||
75572
|
||||
68954
|
||||
140581
|
||||
76963
|
||||
123969
|
||||
111620
|
||||
106957
|
||||
80469
|
||||
140605
|
||||
119650
|
||||
112495
|
||||
124851
|
||||
119725
|
||||
93118
|
||||
123105
|
||||
92952
|
||||
131053
|
||||
74500
|
||||
135647
|
||||
107536
|
||||
56501
|
||||
64458
|
||||
115542
|
||||
111894
|
||||
51608
|
||||
85570
|
||||
133474
|
||||
118513
|
||||
109296
|
||||
128000
|
||||
87127
|
||||
146391
|
||||
149508
|
||||
107219
|
||||
70461
|
||||
85261
|
||||
137378
|
||||
138297
|
||||
106834
|
||||
112664
|
||||
53841
|
||||
124055
|
||||
96992
|
||||
91394
|
||||
135390
|
||||
119457
|
||||
84966
|
||||
110652
|
||||
138798
|
||||
65060
|
||||
108499
|
||||
126384
|
||||
116976
|
||||
135353
|
||||
52801
|
||||
53139
|
||||
54144
|
||||
69494
|
||||
52068
|
||||
61600
|
||||
62762
|
||||
102578
|
||||
100023
|
||||
119232
|
||||
97153
|
||||
94554
|
||||
114131
|
||||
54643
|
||||
65729
|
||||
124430
|
||||
106513
|
||||
133856
|
||||
96803
|
||||
132140
|
||||
113994
|
||||
65320
|
||||
123970
|
||||
115693
|
||||
129066
|
||||
132805
|
||||
143283
|
||||
132702
|
||||
109683
|
||||
126041
|
||||
63310
|
||||
82628
|
||||
68097
|
||||
58927
|
||||
123635
|
||||
117809
|
24
input10
Normal file
24
input10
Normal file
|
@ -0,0 +1,24 @@
|
|||
.###.#...#.#.##.#.####..
|
||||
.#....#####...#.######..
|
||||
#.#.###.###.#.....#.####
|
||||
##.###..##..####.#.####.
|
||||
###########.#######.##.#
|
||||
##########.#########.##.
|
||||
.#.##.########.##...###.
|
||||
###.#.##.#####.#.###.###
|
||||
##.#####.##..###.#.##.#.
|
||||
.#.#.#####.####.#..#####
|
||||
.###.#####.#..#..##.#.##
|
||||
########.##.#...########
|
||||
.####..##..#.###.###.#.#
|
||||
....######.##.#.######.#
|
||||
###.####.######.#....###
|
||||
############.#.#.##.####
|
||||
##...##..####.####.#..##
|
||||
.###.#########.###..#.##
|
||||
#.##.#.#...##...#####..#
|
||||
##.#..###############.##
|
||||
##.###.#####.##.######..
|
||||
##.#####.#.#.##..#######
|
||||
...#######.######...####
|
||||
#....#.#.#.####.#.#.#.##
|
1
input11
Normal file
1
input11
Normal file
|
@ -0,0 +1 @@
|
|||
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
Normal file
1
input13
Normal file
File diff suppressed because one or more lines are too long
56
input14
Normal file
56
input14
Normal file
|
@ -0,0 +1,56 @@
|
|||
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
Normal file
1
input15
Normal file
|
@ -0,0 +1 @@
|
|||
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
input2
Normal file
1
input2
Normal file
|
@ -0,0 +1 @@
|
|||
1,0,0,3,1,1,2,3,1,3,4,3,1,5,0,3,2,1,10,19,1,6,19,23,1,10,23,27,2,27,13,31,1,31,6,35,2,6,35,39,1,39,5,43,1,6,43,47,2,6,47,51,1,51,5,55,2,55,9,59,1,6,59,63,1,9,63,67,1,67,10,71,2,9,71,75,1,6,75,79,1,5,79,83,2,83,10,87,1,87,5,91,1,91,9,95,1,6,95,99,2,99,10,103,1,103,5,107,2,107,6,111,1,111,5,115,1,9,115,119,2,119,10,123,1,6,123,127,2,13,127,131,1,131,6,135,1,135,10,139,1,13,139,143,1,143,13,147,1,5,147,151,1,151,2,155,1,155,5,0,99,2,0,14,0
|
2
input3
Normal file
2
input3
Normal file
|
@ -0,0 +1,2 @@
|
|||
R1009,D117,L888,D799,L611,U766,L832,U859,L892,D79,R645,U191,L681,D787,R447,D429,L988,U536,L486,D832,R221,D619,R268,D545,L706,U234,L528,D453,R493,D24,L688,U658,L74,D281,R910,D849,L5,U16,R935,D399,L417,U609,R22,D782,L432,D83,L357,D982,L902,U294,L338,U102,R342,D621,R106,U979,L238,U158,R930,D948,L700,D808,R445,U897,R980,U227,L466,D416,R244,U396,R576,U157,R548,U795,R709,U550,R137,U212,L977,U786,L423,D792,R391,D974,R390,U771,R270,D409,L917,D9,R412,D699,L170,D276,L912,U710,R814,U656,R4,D800,R596,U970,L194,U315,L845,D490,L303,U514,L675,D737,L880,D86,L253,D525,R861,D5,R424,D113,L764,D900,R485,D421,R125,U684,R53,U96,L871,U260,R456,U378,L448,D450,L903,D482,R750,U961,R264,D501,R605,D367,R550,U642,R228,U164,L343,U868,R595,D318,R452,U845,L571,D281,R49,D889,L481,U963,R182,U358,R454,U267,L790,D252,R455,D188,L73,U256,L835,D816,R503,U895,L259,U418,R642,U818,L187,U355,R772,U466,R21,U91,R707,D349,L200,U305,R931,D982,L334,D416,L247,D935,L326,U449,L398,D914,R602,U10,R762,D944,L639,D141,L457,U579,L198,U527,R750,U167,R816,D753,R850,D281,L712,D583,L172,D254,L544,D456,R966,U839,R673,D479,R730,D912,R992,D969,R766,U205,R477,D719,R172,D735,R998,D687,R698,D407,R172,U945,R199,U348,L256,D876,R580,U770,L483,D437,R353,D214,R619,U541,R234,D962,R842,U639,R520,D354,L279,D15,R42,U138,L321,D376,L628,D893,L670,D574,L339,U298,L321,D120,L370,U408,L333,D353,L263,D79,R535,D487,R113,D638,R623,D59,L508,D866,R315,U166,L534,U927,L401,D626,L19,D994,L778,D317,L936,U207,L768,U948,R452,U165,R864,D283,L874
|
||||
L995,D93,L293,U447,L793,D605,R497,D155,L542,D570,R113,D779,L510,U367,L71,D980,R237,U290,L983,U49,R745,U182,L922,D174,L189,D629,R315,D203,R533,U72,L981,D848,L616,U654,R445,D864,R526,D668,L678,U378,L740,D840,L202,D429,R136,D998,L116,D554,L893,U759,R617,U942,R999,U582,L220,U447,R895,D13,R217,U743,L865,U950,R91,D381,R662,D518,L798,D637,L213,D93,L231,D185,R704,U581,L268,U773,R405,U862,R796,U73,L891,U553,L952,U450,R778,D868,R329,D669,L182,U378,L933,D83,R574,U807,R785,D278,R139,D362,R8,U546,R651,U241,L462,D309,L261,D307,L85,U701,L913,U271,R814,U723,L777,D256,R417,U814,L461,U652,R198,D747,R914,U520,R806,U956,L771,D229,R984,U685,R663,D812,R650,U214,R839,U574,L10,U66,R644,D371,L917,D819,L73,D236,R277,U611,R390,U723,L129,D496,L552,D451,R584,U105,L805,U165,R179,D372,L405,D702,R14,U332,L893,D419,R342,D146,R907,D672,L316,U257,L903,U919,L942,U771,R879,U624,L280,U150,L320,U220,R590,D242,R744,U291,R562,U418,L898,U66,L564,U495,R837,D555,L739,D780,R409,D122,L426,D857,R937,D600,R428,D592,R727,U917,R256,D680,L422,U630,L14,U240,R617,D664,L961,D554,L302,U925,L376,D187,L700,D31,L762,U397,L554,D217,R679,D683,R680,D572,R54,D164,L940,D523,R140,U52,L506,D638,R331,D415,R389,D884,R410,D62,R691,U665,R889,U864,L663,D690,R487,U811,L190,U780,L758,U267,R155,D344,L133,D137,R93,D229,L729,U878,L889,D603,R288,U890,R251,U531,L249,D995,R863,D257,R655,D311,R874,U356,L833,U151,L741,U246,R694,D899,L48,U915,L900,U757,L861,U402,R971,U537,R460,D844,R54,U956,L151,U74,R892,U248,R677,D881,R99,D931,R427
|
1
input5
Normal file
1
input5
Normal file
|
@ -0,0 +1 @@
|
|||
3,225,1,225,6,6,1100,1,238,225,104,0,1001,92,74,224,1001,224,-85,224,4,224,1002,223,8,223,101,1,224,224,1,223,224,223,1101,14,63,225,102,19,83,224,101,-760,224,224,4,224,102,8,223,223,101,2,224,224,1,224,223,223,1101,21,23,224,1001,224,-44,224,4,224,102,8,223,223,101,6,224,224,1,223,224,223,1102,40,16,225,1102,6,15,225,1101,84,11,225,1102,22,25,225,2,35,96,224,1001,224,-350,224,4,224,102,8,223,223,101,6,224,224,1,223,224,223,1101,56,43,225,101,11,192,224,1001,224,-37,224,4,224,102,8,223,223,1001,224,4,224,1,223,224,223,1002,122,61,224,1001,224,-2623,224,4,224,1002,223,8,223,101,7,224,224,1,223,224,223,1,195,87,224,1001,224,-12,224,4,224,1002,223,8,223,101,5,224,224,1,223,224,223,1101,75,26,225,1101,6,20,225,1102,26,60,224,101,-1560,224,224,4,224,102,8,223,223,101,3,224,224,1,223,224,223,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,108,677,226,224,102,2,223,223,1006,224,329,1001,223,1,223,1108,226,677,224,1002,223,2,223,1006,224,344,101,1,223,223,7,226,677,224,102,2,223,223,1006,224,359,1001,223,1,223,1007,226,677,224,1002,223,2,223,1006,224,374,1001,223,1,223,1108,677,226,224,102,2,223,223,1005,224,389,1001,223,1,223,107,226,226,224,102,2,223,223,1006,224,404,101,1,223,223,1107,226,226,224,1002,223,2,223,1005,224,419,1001,223,1,223,1007,677,677,224,102,2,223,223,1006,224,434,101,1,223,223,1107,226,677,224,1002,223,2,223,1006,224,449,101,1,223,223,107,677,677,224,102,2,223,223,1005,224,464,1001,223,1,223,1008,226,226,224,1002,223,2,223,1005,224,479,101,1,223,223,1007,226,226,224,102,2,223,223,1005,224,494,1001,223,1,223,8,677,226,224,1002,223,2,223,1005,224,509,1001,223,1,223,108,677,677,224,1002,223,2,223,1005,224,524,1001,223,1,223,1008,677,677,224,102,2,223,223,1006,224,539,1001,223,1,223,7,677,226,224,1002,223,2,223,1005,224,554,101,1,223,223,1108,226,226,224,1002,223,2,223,1005,224,569,101,1,223,223,107,677,226,224,102,2,223,223,1005,224,584,101,1,223,223,8,226,226,224,1002,223,2,223,1005,224,599,101,1,223,223,108,226,226,224,1002,223,2,223,1006,224,614,1001,223,1,223,7,226,226,224,102,2,223,223,1006,224,629,1001,223,1,223,1107,677,226,224,102,2,223,223,1005,224,644,101,1,223,223,8,226,677,224,102,2,223,223,1006,224,659,1001,223,1,223,1008,226,677,224,1002,223,2,223,1006,224,674,1001,223,1,223,4,223,99,226
|
1
input7
Normal file
1
input7
Normal file
|
@ -0,0 +1 @@
|
|||
3,8,1001,8,10,8,105,1,0,0,21,46,59,72,93,110,191,272,353,434,99999,3,9,101,4,9,9,1002,9,3,9,1001,9,5,9,102,2,9,9,1001,9,5,9,4,9,99,3,9,1002,9,5,9,1001,9,5,9,4,9,99,3,9,101,4,9,9,1002,9,4,9,4,9,99,3,9,102,3,9,9,101,3,9,9,1002,9,2,9,1001,9,5,9,4,9,99,3,9,1001,9,2,9,102,4,9,9,101,2,9,9,4,9,99,3,9,1002,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,102,2,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,101,2,9,9,4,9,3,9,101,2,9,9,4,9,3,9,1001,9,2,9,4,9,3,9,101,2,9,9,4,9,99,3,9,101,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,101,2,9,9,4,9,3,9,102,2,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,102,2,9,9,4,9,3,9,101,1,9,9,4,9,99,3,9,101,2,9,9,4,9,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,102,2,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,1002,9,2,9,4,9,3,9,1001,9,1,9,4,9,3,9,101,2,9,9,4,9,99,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,1002,9,2,9,4,9,3,9,1002,9,2,9,4,9,3,9,1002,9,2,9,4,9,3,9,1001,9,1,9,4,9,3,9,101,2,9,9,4,9,3,9,102,2,9,9,4,9,3,9,1001,9,2,9,4,9,99,3,9,1001,9,1,9,4,9,3,9,1001,9,1,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,1002,9,2,9,4,9,3,9,1002,9,2,9,4,9,3,9,1001,9,1,9,4,9,99
|
1
input9
Normal file
1
input9
Normal file
|
@ -0,0 +1 @@
|
|||
1102,34463338,34463338,63,1007,63,34463338,63,1005,63,53,1101,0,3,1000,109,988,209,12,9,1000,209,6,209,3,203,0,1008,1000,1,63,1005,63,65,1008,1000,2,63,1005,63,904,1008,1000,0,63,1005,63,58,4,25,104,0,99,4,0,104,0,99,4,17,104,0,99,0,0,1102,1,432,1027,1101,439,0,1026,1101,0,36,1010,1101,0,34,1018,1102,278,1,1029,1101,0,24,1002,1102,1,20,1016,1102,1,31,1011,1102,319,1,1024,1102,21,1,1012,1102,1,763,1022,1102,1,25,1007,1101,0,287,1028,1102,32,1,1008,1101,0,22,1013,1102,38,1,1001,1101,0,314,1025,1102,35,1,1009,1102,1,23,1015,1102,39,1,1019,1102,27,1,1000,1102,1,37,1003,1102,1,28,1017,1101,0,0,1020,1101,0,29,1004,1102,1,30,1006,1102,1,756,1023,1102,1,33,1005,1101,0,1,1021,1102,26,1,1014,109,13,2108,28,-7,63,1005,63,201,1001,64,1,64,1105,1,203,4,187,1002,64,2,64,109,8,21107,40,41,-3,1005,1018,225,4,209,1001,64,1,64,1105,1,225,1002,64,2,64,109,-3,1206,2,239,4,231,1105,1,243,1001,64,1,64,1002,64,2,64,109,-21,1201,6,0,63,1008,63,35,63,1005,63,267,1001,64,1,64,1105,1,269,4,249,1002,64,2,64,109,35,2106,0,-4,4,275,1001,64,1,64,1105,1,287,1002,64,2,64,109,-11,1205,-1,303,1001,64,1,64,1105,1,305,4,293,1002,64,2,64,109,8,2105,1,-5,4,311,1106,0,323,1001,64,1,64,1002,64,2,64,109,-7,21108,41,38,-6,1005,1016,339,1106,0,345,4,329,1001,64,1,64,1002,64,2,64,109,2,21102,42,1,-8,1008,1016,45,63,1005,63,369,1001,64,1,64,1105,1,371,4,351,1002,64,2,64,109,-14,21101,43,0,1,1008,1011,43,63,1005,63,397,4,377,1001,64,1,64,1106,0,397,1002,64,2,64,109,-8,21101,44,0,8,1008,1010,47,63,1005,63,417,1105,1,423,4,403,1001,64,1,64,1002,64,2,64,109,25,2106,0,0,1001,64,1,64,1105,1,441,4,429,1002,64,2,64,109,-20,2107,37,-6,63,1005,63,463,4,447,1001,64,1,64,1106,0,463,1002,64,2,64,109,8,2108,25,-8,63,1005,63,485,4,469,1001,64,1,64,1106,0,485,1002,64,2,64,109,-1,21107,45,44,-1,1005,1013,505,1001,64,1,64,1106,0,507,4,491,1002,64,2,64,109,-11,1207,-1,25,63,1005,63,529,4,513,1001,64,1,64,1106,0,529,1002,64,2,64,109,23,1206,-5,545,1001,64,1,64,1106,0,547,4,535,1002,64,2,64,109,-31,2102,1,5,63,1008,63,27,63,1005,63,569,4,553,1106,0,573,1001,64,1,64,1002,64,2,64,109,27,21102,46,1,-9,1008,1013,46,63,1005,63,595,4,579,1105,1,599,1001,64,1,64,1002,64,2,64,109,-26,2101,0,6,63,1008,63,24,63,1005,63,625,4,605,1001,64,1,64,1106,0,625,1002,64,2,64,109,5,1208,0,37,63,1005,63,645,1001,64,1,64,1105,1,647,4,631,1002,64,2,64,109,7,2102,1,-3,63,1008,63,31,63,1005,63,671,1001,64,1,64,1105,1,673,4,653,1002,64,2,64,109,2,1202,-5,1,63,1008,63,33,63,1005,63,699,4,679,1001,64,1,64,1105,1,699,1002,64,2,64,109,-4,2101,0,-3,63,1008,63,35,63,1005,63,719,1105,1,725,4,705,1001,64,1,64,1002,64,2,64,109,-5,1207,4,32,63,1005,63,741,1106,0,747,4,731,1001,64,1,64,1002,64,2,64,109,29,2105,1,-7,1001,64,1,64,1106,0,765,4,753,1002,64,2,64,109,-26,2107,36,5,63,1005,63,781,1105,1,787,4,771,1001,64,1,64,1002,64,2,64,109,10,1201,-6,0,63,1008,63,32,63,1005,63,809,4,793,1106,0,813,1001,64,1,64,1002,64,2,64,109,3,21108,47,47,-5,1005,1012,835,4,819,1001,64,1,64,1106,0,835,1002,64,2,64,109,-24,1202,9,1,63,1008,63,25,63,1005,63,859,1001,64,1,64,1106,0,861,4,841,1002,64,2,64,109,19,1205,9,875,4,867,1106,0,879,1001,64,1,64,1002,64,2,64,109,-3,1208,-1,32,63,1005,63,897,4,885,1106,0,901,1001,64,1,64,4,64,99,21102,27,1,1,21101,915,0,0,1105,1,922,21201,1,60043,1,204,1,99,109,3,1207,-2,3,63,1005,63,964,21201,-2,-1,1,21102,1,942,0,1106,0,922,21202,1,1,-1,21201,-2,-3,1,21101,957,0,0,1106,0,922,22201,1,-1,-2,1105,1,968,22102,1,-2,-2,109,-3,2105,1,0
|
384
src/day10/main.rs
Normal file
384
src/day10/main.rs
Normal file
|
@ -0,0 +1,384 @@
|
|||
use std::collections::{HashMap, HashSet};
|
||||
use std::fs::File;
|
||||
use std::io::{BufRead, BufReader};
|
||||
use std::ops::Sub;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
enum Position {
|
||||
Empty,
|
||||
Astroid,
|
||||
}
|
||||
|
||||
impl From<&u8> for Position {
|
||||
fn from(c: &u8) -> Self {
|
||||
match c {
|
||||
b'.' => Position::Empty,
|
||||
b'#' => Position::Astroid,
|
||||
_ => panic!("invalid input"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
|
||||
struct XY {
|
||||
x: isize,
|
||||
y: isize,
|
||||
}
|
||||
|
||||
impl From<(usize, usize)> for XY {
|
||||
fn from((x, y): (usize, usize)) -> Self {
|
||||
XY {
|
||||
x: x as isize,
|
||||
y: y as isize,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub for &XY {
|
||||
type Output = XY;
|
||||
fn sub(self, other: &XY) -> Self::Output {
|
||||
let xy = XY {
|
||||
x: self.x - other.x,
|
||||
y: self.y - other.y,
|
||||
};
|
||||
xy
|
||||
}
|
||||
}
|
||||
|
||||
impl XY {
|
||||
fn direction(&self) -> Self {
|
||||
let d = gcd(self.y, self.x).abs();
|
||||
if d != 0 {
|
||||
XY {
|
||||
x: self.x / d,
|
||||
y: self.y / d,
|
||||
}
|
||||
} else {
|
||||
self.clone()
|
||||
}
|
||||
}
|
||||
|
||||
fn distance(&self) -> f64 {
|
||||
let sum = (self.x.pow(2) + self.y.pow(2)) as f64;
|
||||
(sum as f64).sqrt()
|
||||
}
|
||||
|
||||
fn angle(&self) -> f64 {
|
||||
let a = (-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 {
|
||||
map: Vec<XY>,
|
||||
}
|
||||
|
||||
impl MonitoringStation {
|
||||
fn laser(&self, root: &XY, skip: usize, n: usize) -> Vec<XY> {
|
||||
let mut map: HashMap<XY, Vec<&XY>> = HashMap::new();
|
||||
// collect vec for each direction
|
||||
map = self
|
||||
.map
|
||||
.iter()
|
||||
.filter_map(|xy| {
|
||||
if xy == root {
|
||||
return None;
|
||||
}
|
||||
let rel = xy - &root;
|
||||
Some((xy, rel.direction()))
|
||||
})
|
||||
.fold(map, |mut acc, (xy, dir)| {
|
||||
acc.entry(dir).or_insert(vec![]).push(xy);
|
||||
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>>();
|
||||
angles.sort_by(|a, b| a.angle().partial_cmp(&b.angle()).unwrap());
|
||||
|
||||
// cycle around and return first element of each vec
|
||||
angles
|
||||
.iter()
|
||||
.cycle()
|
||||
.map(|xy| match map.get_mut(xy) {
|
||||
Some(xy) => {
|
||||
if let Some(xy) = xy.pop() {
|
||||
Some(xy)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
None => None,
|
||||
})
|
||||
.flatten()
|
||||
.skip(skip)
|
||||
.take(n)
|
||||
.cloned()
|
||||
.collect::<Vec<XY>>()
|
||||
}
|
||||
|
||||
fn find(&self) -> (usize, XY) {
|
||||
let best = (0, &XY::from((0, 0)));
|
||||
let best = self
|
||||
.map
|
||||
.iter()
|
||||
.map(|root| {
|
||||
let insight = self
|
||||
.map
|
||||
.iter()
|
||||
// get direction to any of the astroids
|
||||
.filter_map(|xy| {
|
||||
let rel = xy - root;
|
||||
Some(rel.direction())
|
||||
})
|
||||
// and keep only one in each direction
|
||||
.fold(HashSet::new(), |mut acc, xy| {
|
||||
acc.insert(xy);
|
||||
acc
|
||||
})
|
||||
.len()
|
||||
- 1;
|
||||
(insight, root)
|
||||
})
|
||||
.fold(
|
||||
best,
|
||||
|acc, astroid| {
|
||||
if astroid.0 > acc.0 {
|
||||
astroid
|
||||
} else {
|
||||
acc
|
||||
}
|
||||
},
|
||||
);
|
||||
(best.0, best.1.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<T> for MonitoringStation
|
||||
where
|
||||
T: BufRead,
|
||||
{
|
||||
fn from(reader: T) -> Self {
|
||||
let map = reader
|
||||
.split(b'\n')
|
||||
.enumerate()
|
||||
.flat_map(|(y, line)| {
|
||||
line.unwrap()
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.filter_map(move |(x, c)| {
|
||||
let xy = XY::from((x, y));
|
||||
match Position::from(&c) {
|
||||
Position::Astroid => Some(xy),
|
||||
Position::Empty => None,
|
||||
}
|
||||
})
|
||||
})
|
||||
.collect::<Vec<XY>>();
|
||||
MonitoringStation { map }
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let f = File::open("input10")?;
|
||||
let reader = BufReader::new(f);
|
||||
let station = MonitoringStation::from(reader);
|
||||
let best = station.find();
|
||||
println!("best: {:?}", best);
|
||||
let lasered = station.laser(&best.1, 199, 1);
|
||||
let lasered = lasered.iter().next().unwrap();
|
||||
println!("lasered: {:?}", lasered);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn gcd(x: isize, y: isize) -> isize {
|
||||
let mut x = x;
|
||||
let mut y = y;
|
||||
while y != 0 {
|
||||
let t = y;
|
||||
y = x % y;
|
||||
x = t;
|
||||
}
|
||||
x
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn example1() {
|
||||
let reader = BufReader::new(".#..#\n.....\n#####\n....#\n...##".as_bytes());
|
||||
let (count, xy) = MonitoringStation::from(reader).find();
|
||||
assert_eq!(xy, XY { x: 3, y: 4 });
|
||||
assert_eq!(count, 8);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn example2() {
|
||||
let reader = BufReader::new(
|
||||
"
|
||||
......#.#.
|
||||
#..#.#....
|
||||
..#######.
|
||||
.#.#.###..
|
||||
.#..#.....
|
||||
..#....#.#
|
||||
#..#....#.
|
||||
.##.#..###
|
||||
##...#..#.
|
||||
.#....####"
|
||||
.trim()
|
||||
.as_bytes(),
|
||||
);
|
||||
let (count, xy) = MonitoringStation::from(reader).find();
|
||||
assert_eq!(xy, XY { x: 5, y: 8 });
|
||||
assert_eq!(count, 33);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn example3() {
|
||||
let reader = BufReader::new(
|
||||
"
|
||||
#.#...#.#.
|
||||
.###....#.
|
||||
.#....#...
|
||||
##.#.#.#.#
|
||||
....#.#.#.
|
||||
.##..###.#
|
||||
..#...##..
|
||||
..##....##
|
||||
......#...
|
||||
.####.###."
|
||||
.trim()
|
||||
.as_bytes(),
|
||||
);
|
||||
let (count, xy) = MonitoringStation::from(reader).find();
|
||||
assert_eq!(xy, XY { x: 1, y: 2 });
|
||||
assert_eq!(count, 35);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn example4() {
|
||||
let reader = BufReader::new(
|
||||
"
|
||||
.#..#..###
|
||||
####.###.#
|
||||
....###.#.
|
||||
..###.##.#
|
||||
##.##.#.#.
|
||||
....###..#
|
||||
..#.#..#.#
|
||||
#..#.#.###
|
||||
.##...##.#
|
||||
.....#.#.."
|
||||
.trim()
|
||||
.as_bytes(),
|
||||
);
|
||||
let (count, xy) = MonitoringStation::from(reader).find();
|
||||
assert_eq!(xy, XY { x: 6, y: 3 });
|
||||
assert_eq!(count, 41);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn example5() {
|
||||
let reader = BufReader::new(
|
||||
"
|
||||
.#..##.###...#######
|
||||
##.############..##.
|
||||
.#.######.########.#
|
||||
.###.#######.####.#.
|
||||
#####.##.#.##.###.##
|
||||
..#####..#.#########
|
||||
####################
|
||||
#.####....###.#.#.##
|
||||
##.#################
|
||||
#####.##.###..####..
|
||||
..######..##.#######
|
||||
####.##.####...##..#
|
||||
.#####..#.######.###
|
||||
##...#.##########...
|
||||
#.##########.#######
|
||||
.####.#.###.###.#.##
|
||||
....##.##.###..#####
|
||||
.#.#.###########.###
|
||||
#.#.#.#####.####.###
|
||||
###.##.####.##.#..##"
|
||||
.trim()
|
||||
.as_bytes(),
|
||||
);
|
||||
let (count, xy) = MonitoringStation::from(reader).find();
|
||||
assert_eq!(xy, XY { x: 11, y: 13 });
|
||||
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 }
|
||||
]
|
||||
)
|
||||
}
|
||||
}
|
186
src/day11/main.rs
Normal file
186
src/day11/main.rs
Normal file
|
@ -0,0 +1,186 @@
|
|||
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(())
|
||||
}
|
332
src/day12/main.rs
Normal file
332
src/day12/main.rs
Normal file
|
@ -0,0 +1,332 @@
|
|||
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)
|
||||
}
|
||||
}
|
135
src/day13/main.rs
Normal file
135
src/day13/main.rs
Normal file
|
@ -0,0 +1,135 @@
|
|||
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>;
|
385
src/day14/main.rs
Normal file
385
src/day14/main.rs
Normal file
|
@ -0,0 +1,385 @@
|
|||
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);
|
||||
}
|
||||
}
|
205
src/day15/main.rs
Normal file
205
src/day15/main.rs
Normal file
|
@ -0,0 +1,205 @@
|
|||
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,
|
||||
}
|
||||
}
|
||||
}
|
109
src/day9/main.rs
109
src/day9/main.rs
|
@ -10,29 +10,6 @@ enum Var {
|
|||
C,
|
||||
}
|
||||
|
||||
// impl From<usize> for Var {
|
||||
// fn from(i: usize) -> Self {
|
||||
// match i {
|
||||
// 0 => Var::Opcode,
|
||||
// 1 => Var::A,
|
||||
// 2 => Var::B,
|
||||
// 3 => Var::C,
|
||||
// _ => panic!("invalid variable")
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// impl Into<usize> for Var {
|
||||
// fn into(self) -> usize {
|
||||
// match self {
|
||||
// Var::Opcode => 0,
|
||||
// Var::A => 1,
|
||||
// Var::B => 2,
|
||||
// Var::C => 3,
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
enum Mode {
|
||||
Position,
|
||||
|
@ -263,12 +240,13 @@ impl Computer {
|
|||
}
|
||||
|
||||
fn get(&self, v: &Var) -> i64 {
|
||||
let x = *self.program.get(self.pos + *v as usize).unwrap_or(&0);
|
||||
match self.modes.mode_for(v) {
|
||||
Mode::Position => self.get_pos(x as usize),
|
||||
Mode::Immediate => x,
|
||||
Mode::Relative => self.get_pos((self.rel + x) as usize),
|
||||
}
|
||||
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) -> i64 {
|
||||
|
@ -283,12 +261,12 @@ impl Computer {
|
|||
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),
|
||||
Mode::Immediate => want as i64,
|
||||
Mode::Relative => self.get_pos((self.rel + want as i64) as usize),
|
||||
} as usize;
|
||||
Mode::Position => self.get_pos(want) as usize,
|
||||
Mode::Immediate => want,
|
||||
Mode::Relative => (self.rel + self.get_pos(want)) as usize,
|
||||
};
|
||||
if length < want {
|
||||
let missing = (want - length) + 2;
|
||||
let missing = (want - length) + 5;
|
||||
self.program.extend_from_slice(&vec![0; missing])
|
||||
}
|
||||
self.program[want] = value;
|
||||
|
@ -371,9 +349,15 @@ impl Computer {
|
|||
fn main() -> io::Result<()> {
|
||||
let filename = env::args().nth(1).expect("provide file as first param");
|
||||
let computer = Computer::from(File::open(filename)?);
|
||||
|
||||
// part1
|
||||
let result = computer.clone_with_input(vec![1]).run_must_output();
|
||||
println!("{:?}", result);
|
||||
|
||||
// part2
|
||||
let result = computer.clone_with_input(vec![2]).run_must_output();
|
||||
println!("{:?}", result);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -401,43 +385,56 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn example3() {
|
||||
assert_eq!(
|
||||
Computer::from(vec![104,1125899906842624,99]).run_must_output(),
|
||||
1125899906842624
|
||||
)
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
477
src/intcode.rs
Normal file
477
src/intcode.rs
Normal file
|
@ -0,0 +1,477 @@
|
|||
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
src/lib.rs
Normal file
1
src/lib.rs
Normal file
|
@ -0,0 +1 @@
|
|||
pub mod intcode;
|
|
@ -1,3 +0,0 @@
|
|||
fn main() {
|
||||
println!("Hello, world!");
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue