Compare commits

...

201 Commits
sorbet ... main

Author SHA1 Message Date
Alpha Chen babaaebb45
mu
6 months ago
Alpha Chen 2364abf76a
[2023][ruby][19.1]
10 months ago
Alpha Chen 48b7acdcea
[2023][ruby][18.x]
10 months ago
Alpha Chen 6f332e48d1
[2023][ruby][17.2]
10 months ago
Alpha Chen 51c91ab2f2
[2023][ruby][17.1]
10 months ago
Alpha Chen 2ac1c6069a
[2023][ruby][16.x] golfing
10 months ago
Alpha Chen efda4ecb16
[2023][ruby][16.2] shameless green
10 months ago
Alpha Chen b7a02fda85
[2023][ruby][16.1] shameless green
10 months ago
Alpha Chen 957435a8ca
[2023][uiua][15] @\0 = @\x00
10 months ago
Alpha Chen af98c2abc5
[2023][uiua][15.1]
10 months ago
Alpha Chen 10da9e80a0
[2023][ruby][15.2]
10 months ago
Alpha Chen 5bbeb5d969
[2023][ruby][15.1]
10 months ago
Alpha Chen 4fa0141f5f
[2023][uiua][14.1]
10 months ago
Alpha Chen 16677ad6a4
[2023][ruby][14.x] clean up part one
10 months ago
Alpha Chen 74bf4a5213
[2023][ruby][14.2]
10 months ago
Alpha Chen cba5517ee9
[2023][ruby][14.1]
10 months ago
Alpha Chen 06068a3114
[2023][ruby][13.2]
10 months ago
Alpha Chen 21e4174051
[2023][ruby][13.1]
10 months ago
Alpha Chen 31afd41329
[2023][ruby][12.2]
10 months ago
Alpha Chen 2928c03ce0
[2023][ruby][12.1]
10 months ago
Alpha Chen eeb3633702
[2023][uiua][11.x] shortening
10 months ago
Alpha Chen 0da7444be5
[2023][uiua][11.x]
10 months ago
Alpha Chen 28e35196f5
[2023][ruby][11.2]
10 months ago
Alpha Chen 1118280a6e
[2023][ruby][11.1]
10 months ago
Alpha Chen 47ca37d8c2
[2023][ruby][8.x] remove unnecessary require
10 months ago
Alpha Chen ed02032839
[2023][ruby][10.x] one more comment
10 months ago
Alpha Chen a3706096c3
[2023][ruby][10.x] lol
10 months ago
Alpha Chen 95a6798f7f
[2023][ruby][10.x]
10 months ago
Alpha Chen b5bfbcff0b
[2023][ruby][9.x] dry
10 months ago
Alpha Chen 7f25d2bde6
[2023][ruby][9.x]
10 months ago
Alpha Chen ca65631b37
[2023][ruby][8.2] til about Integer#lcm
10 months ago
Alpha Chen 5d7fc5b308
[2023][ruby][8.2]
10 months ago
Alpha Chen 794e3db35a
[2023][ruby][8.1]
10 months ago
Alpha Chen ee07a6130e
[2023][ruby][7.x] refactoring
10 months ago
Alpha Chen 8b21d78e9a
[2023][ruby][6.x] perf
10 months ago
Alpha Chen 8a81e989da
[2023][ruby][7.x] remove unnecessary lexographic sorting
11 months ago
Alpha Chen cc41e835ac
[2023][ruby][7.x] refactoring
11 months ago
Alpha Chen 9b6dd4cc53
[2023][ruby][7.x]
11 months ago
Alpha Chen c87d7854bf
uiua
11 months ago
Alpha Chen b8cd0faa3e
[2023][ruby][6.x]
11 months ago
Alpha Chen 1931b227df
[2023][ruby][5.x] remove more duplicate code
11 months ago
Alpha Chen 5525e8b7e5
[2023][ruby][5.x] remove duplicate code
11 months ago
Alpha Chen 1815ec7b1a
[2023][ruby][5.x]
11 months ago
Alpha Chen eb21642bf4
[2023][ruby][4.2] cleanup
11 months ago
Alpha Chen 0d0cc439b0
[2023][ruby][4.*]
11 months ago
Alpha Chen e6ae06a605
[2023][ruby][3.*] clean up parsing
11 months ago
Alpha Chen 8c72adad6d
[2023][ruby][3.*] remove hack
11 months ago
Alpha Chen fc5821b277
[2023][ruby][3.2]
11 months ago
Alpha Chen 6581325e8f
[2023][ruby][3.1]
11 months ago
Alpha Chen 5e542d90aa
[2023][ruby][2.*]
11 months ago
Alpha Chen 8677078287
[2023][uiua][01.1]
11 months ago
Alpha Chen 37ac8ad85b
[2023][ruby][1.*]
11 months ago
Alpha Chen 5c2f1eb45f
mu
11 months ago
Alpha Chen 6db3326726
[2022][ruby][16.2]
2 years ago
Alpha Chen b32bf143f9
[2022][ruby][16.1]
2 years ago
Alpha Chen 5c4b1cb37e
[2022][ruby][25.1]
2 years ago
Alpha Chen a0a54eefff
[2022][ruby] update Gemfile
2 years ago
Alpha Chen a3bded6091
[2022][ruby][21.x] use z3 for part two
2 years ago
Alpha Chen b62bf80b86
[2022][ruby][23.x]
2 years ago
Alpha Chen 6fb92a59ab
[2022][ruby][21.x]
2 years ago
Alpha Chen 7ced4db4a4
[2022][ruby][20.x]
2 years ago
Alpha Chen ce623e16d1
[2022][ruby][18.x]
2 years ago
Alpha Chen da36d561b8
[2022][ruby][15.x]
2 years ago
Alpha Chen 4129a82f26
[2022][ruby][14.x] refactored
2 years ago
Alpha Chen adff292d00
[2022][ruby][14.x]
2 years ago
Alpha Chen c5846c52e9
[2022][ruby][13.x] refactored
2 years ago
Alpha Chen d246206681
[2022][ruby][13.x]
2 years ago
Alpha Chen c3c34b998c
[2022][ruby][12.x] refactoring
2 years ago
Alpha Chen 220c8853de
[2022][ruby][12.x] backwards
2 years ago
Alpha Chen e12d4d7c63
[2022][ruby][12.x] refactored
2 years ago
Alpha Chen 44936f2906
[2022][ruby][12.x]
2 years ago
Alpha Chen 7e89a0122f
[2022][ruby][11.x] parslet
2 years ago
Alpha Chen 38b2c310a8
[2022][ruby][11.x] clean up parsing
2 years ago
Alpha Chen b8a4ca01b4
[2022][ruby][11.x]
2 years ago
Alpha Chen 762e65126a
[2022][ruby][10.x] refactor
2 years ago
Alpha Chen f871f28d27
[2022][ruby][10.x]
2 years ago
Alpha Chen 88c3c73d2f
[2022][bqn][6.x] refactor
2 years ago
Alpha Chen cdbcffdda5
[2022][ruby][9.x] refactoring
2 years ago
Alpha Chen 3782908dbb
[2022][ruby][9.2]
2 years ago
Alpha Chen caaa3da525
[2022][ruby][9.1]
2 years ago
Alpha Chen ea26a19bc0
[2022][ruby][8.x] refactored
2 years ago
Alpha Chen f67bc7bd27
[2022][ruby][8.x]
2 years ago
Alpha Chen 1fa98d82d6
[2022][ruby][7.x] refactoring
2 years ago
Alpha Chen fac81cb212
[2022][ruby][7.x]
2 years ago
Alpha Chen f8a61202fc
[2022][bqn][5.0] parsing only
2 years ago
Alpha Chen e666ab9344
[2022][bqn][6.x]
2 years ago
Alpha Chen 34ce71c8b6
[2022][ruby][6.x]
2 years ago
Alpha Chen c92d5a4346
[2022][ruby][5.x] refactor
2 years ago
Alpha Chen a8f19091f7
[2022][ruby][5.x]
2 years ago
Alpha Chen e9093934cf
[2022][ruby][4.x] cleanup
2 years ago
Alpha Chen 74d3bef510
[2022][ruby][3.x,4.x]
2 years ago
Alpha Chen ccdfedbbb6
[2022][ruby][3.x]
2 years ago
Alpha Chen e1016ab913
mu
2 years ago
Alpha Chen 049eedabf4
mu
2 years ago
dependabot[bot] b61b268c6e Bump i18n from 0.7.0 to 1.10.0 in /2015/ruby
2 years ago
dependabot[bot] 7b145e68f7 Bump regex from 1.1.0 to 1.5.5 in /2018/rust
2 years ago
dependabot[bot] b8a3ca273b Bump regex from 0.1.44 to 1.5.5 in /2015/rust
2 years ago
dependabot[bot] 31a381eb5d Bump regex from 0.1.80 to 1.5.5 in /2016/rust
2 years ago
dependabot[bot] e8eeea82d4 Bump generic-array from 0.9.0 to 0.9.1 in /2018/rust
2 years ago
Alpha Chen 1fb181e7d2 [2021][ruby][22.x]
3 years ago
Alpha Chen 76266b5bf3 [2021][ruby][21.x]
3 years ago
Alpha Chen a0ff324262 [2021][ruby][20.x]
3 years ago
Alpha Chen 289d452904 [2021][ruby][18.x] small refactoring
3 years ago
Alpha Chen 2196242eea [2021][ruby][18.x]
3 years ago
Alpha Chen 169491113a [2021][ruby][17.x] a bit of refactoring
3 years ago
Alpha Chen 8c5c67ae24 [2021][ruby][17.x]
3 years ago
Alpha Chen 28d2d2ca0c [2021][ruby][16.x] refactor
3 years ago
Alpha Chen f274c589c0 [2021][ruby][16.x]
3 years ago
Alpha Chen cd8a8345b3 [2021][ruby][15.x] use a Set for a minor speedup
3 years ago
Alpha Chen f23af95c02 [2021][ruby][15.x]
3 years ago
Alpha Chen 8e38040c04 [2021][ruby][14.x]
3 years ago
Alpha Chen b7e00339a3 [2021][ruby][13.x] clean up getting the dir index
3 years ago
Alpha Chen 4d7ad2055f [2021][ruby][13.x] refactor
3 years ago
Alpha Chen 963a61b14e [2021][ruby][13.x]
3 years ago
Alpha Chen 8f7c9985a5 [2021][ruby][12.x] tweak
3 years ago
Alpha Chen d40179f8c1 [2021][ruby][12.x]
3 years ago
Alpha Chen d29ae63a86 [2021][ruby][11.x] tweak loop
3 years ago
Alpha Chen 212ef6a381 [2021][ruby][11.x]
3 years ago
Alpha Chen 5145a17ba2 [2021][ruby][10.x] result type?
3 years ago
Alpha Chen aa66d3ed86 [2021][ruby][10.x] refactoring?
3 years ago
Alpha Chen 96072c90c3 [2021][ruby][10.x]
3 years ago
Alpha Chen 1a3d489be8 [2021][ruby][8.2] clean up minizinc solver
3 years ago
Alpha Chen 038495b353 [2021][ruby][9.x]
3 years ago
Alpha Chen 1aeb80d0eb [2021][ruby][8.2] minizinc
3 years ago
Alpha Chen 63778c56b7 [2021][ruby][8.x]
3 years ago
Alpha Chen 0c92ce7de7 [2021][ruby][7.x]
3 years ago
Alpha Chen ff6f142e2b [2021][ruby][6.x]
3 years ago
Alpha Chen 367a35f400 [2021][ruby][4.x..=5.x]
3 years ago
Alpha Chen c6e95f860f [2021][ruby][3.x]
3 years ago
Alpha Chen ea42e4bbc8 [2021][ruby][2.x]
3 years ago
Alpha Chen 86cd480264 [2021][ruby][01.x]
3 years ago
Alpha Chen ce57cc41da [2020][ruby] set ruby version to 3
4 years ago
Alpha Chen 24a173d106 [2020][ruby][20] remove unused code
4 years ago
Alpha Chen bb763d6644 [2020][ruby][25]
4 years ago
Alpha Chen 1a30bb23a1 [2020][ruby][24.x] use axial coordinates
4 years ago
Alpha Chen 319dd0129b [2020][ruby][24.x] refactor
4 years ago
Alpha Chen a9797560cf [2020][ruby][24.x]
4 years ago
Alpha Chen f057404538 [2020][ruby][23.2]
4 years ago
Alpha Chen 45212a6916 [2020][ruby][23.1]
4 years ago
Alpha Chen 5bcd40bef6 [2020][ruby][18] refactor
4 years ago
Alpha Chen 5ecce65bb5 [2020][ruby][18] playing around
4 years ago
Alpha Chen 969f06d4d0 [2020][ruby][16] removed commented out code
4 years ago
Alpha Chen f40f2356d3 [2020][ruby][22.x]
4 years ago
Alpha Chen 2c8cff45b0 [2020][ruby][20.x] refactor
4 years ago
Alpha Chen e1d1092a8b [2020][ruby][20.2]
4 years ago
Alpha Chen 35b1015882 [2020][ruby][21.2]
4 years ago
Alpha Chen 9919db1887 [2020][ruby][21.1]
4 years ago
Alpha Chen 1f6f3b62f6 [2020][ruby][20.1]
4 years ago
Alpha Chen be245847a2 [2020][ruby][19.x]
4 years ago
Alpha Chen 019d9eae12 [2020][ruby][18.x]
4 years ago
Alpha Chen 5949372ee0 [2020][ruby][17.x] refactor
4 years ago
Alpha Chen f668b8256d [2020][ruby][17.x]
4 years ago
Alpha Chen b727f41bd0 [2020][ruby][16.x]
4 years ago
Alpha Chen c9ad797075 [2020][ruby][15.x]
4 years ago
Alpha Chen 900a3e13b2 [2020][ruby][14.x] refactor
4 years ago
Alpha Chen a17445636d [2020][ruby][14.x]
4 years ago
Alpha Chen ffcf15c67e [2020][ruby][13.x]
4 years ago
Alpha Chen ad8fb67c6c [2020][ruby][12.x]
4 years ago
Alpha Chen 47b07ceb34 [2020][ruby][11.x] refactor
4 years ago
Alpha Chen 77256e1bf8 [2020][ruby][11.x]
4 years ago
Alpha Chen 771ad5c052 [2020][ruby][10.x] refactor
4 years ago
Alpha Chen 074fbc54d6 [2020][ruby][10.x] refactor
4 years ago
Alpha Chen 231f971888 [2020][ruby][10.x]
4 years ago
Alpha Chen 7521f3c9d4 [2020][ruby][9.x] refactor
4 years ago
Alpha Chen 7f46f39d8d [2020][ruby][9.x] refactor
4 years ago
Alpha Chen 95b912211d [2020][ruby][9.x]
4 years ago
Alpha Chen 8d30b0713c [2020][ruby][8.x] refactor
4 years ago
Alpha Chen 73ca0bca60 [2020][ruby][8.x]
4 years ago
Alpha Chen 7a2dee465d [2020][ruby][7.x]
4 years ago
Alpha Chen e49d6c4bef [2020][ruby][6.x] refactor
4 years ago
Alpha Chen 5fa382329f [2020] move input files to root dir
4 years ago
Alpha Chen f5660e8938 [2020][ruby][6.x]
4 years ago
Alpha Chen cccdf1e45e [2020][ruby][5.x] too clever
4 years ago
Alpha Chen a369ffb751 [2020][ruby][5.x]
4 years ago
Alpha Chen eea91b1ed5 [2020][ruby][4.x]
4 years ago
Alpha Chen 3601c50b22 [2020][ruby][3.x] this is better
4 years ago
Alpha Chen ea6d3fed3b [2020][ruby][3.x] too clever
4 years ago
Alpha Chen 4dd5e8d920 [2020][ruby][3.x]
4 years ago
Alpha Chen a9f664f3f3 [2020][ruby][2.x]
4 years ago
Alpha Chen 25d32aa998 [2020][ruby][1-2]
4 years ago
Alpha Chen 61afcde94e [2019][ruby][14.1]
5 years ago
Alpha Chen f0c024d28f [2019][ruby][14.1]
5 years ago
Alpha Chen 6fa37294de [2019][ruby][13.x]
5 years ago
Alpha Chen 850d181bdc [2019][ruby][12.2]
5 years ago
Alpha Chen 85cdc38184 [2019][ruby][12.1]
5 years ago
Alpha Chen 975834ce55 [2019][ruby][11.x] use trig
5 years ago
Alpha Chen 10ace7d99a [2019][ruby][11.x] use sum instead of a block
5 years ago
Alpha Chen cb2379477b [2019][ruby][11.x]
5 years ago
Alpha Chen df20ad0139 [2019][ruby] make computer.rb runnable
5 years ago
Alpha Chen 7f751bdfee [2019][ruby][10.x]
5 years ago
Alpha Chen cfef580250 [2019][ruby] extract Parameter creation
5 years ago
Alpha Chen dc76d7df9d [2019][ruby] refactor computer
5 years ago
Alpha Chen 43356b2e0c [2019][ruby][9.x]
5 years ago
Alpha Chen 5beb8a1276 [2019][ruby][8.x]
5 years ago
Alpha Chen 33786055b9 [2019][ruby] explain the 3
5 years ago
Alpha Chen a577d0b72c [2019][ruby] align opcodes
5 years ago
Alpha Chen 2329172f86 [2019][ruby] simplify getting the parameter mode
5 years ago
Alpha Chen a28f8de0b2 [2019][ruby][7.b]
5 years ago
Alpha Chen 631b2642b4 [2019][ruby][7.a]
5 years ago
Alpha Chen 2c8fca3bd5 [2019][ruby] add rakefile
5 years ago
Alpha Chen d0feb92fff [2019][ruby] more sorbet
5 years ago

3
.gitmodules vendored

@ -0,0 +1,3 @@
[submodule "2022/bqn/lib"]
path = 2022/bqn/lib
url = https://github.com/mlochbaum/bqn-libs.git

@ -1,17 +1,17 @@
GEM
remote: https://rubygems.org/
specs:
activesupport (4.2.5)
i18n (~> 0.7)
json (~> 1.7, >= 1.7.7)
minitest (~> 5.1)
thread_safe (~> 0.3, >= 0.3.4)
tzinfo (~> 1.1)
activesupport (7.0.3)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 1.6, < 2)
minitest (>= 5.1)
tzinfo (~> 2.0)
awesome_print (1.6.1)
coderay (1.1.0)
colorize (0.7.7)
i18n (0.7.0)
json (1.8.3)
concurrent-ruby (1.1.10)
i18n (1.10.0)
concurrent-ruby (~> 1.0)
letters (0.4.1)
activesupport
awesome_print
@ -24,9 +24,8 @@ GEM
method_source (~> 0.8.1)
slop (~> 3.4)
slop (3.6.0)
thread_safe (0.3.5)
tzinfo (1.2.2)
thread_safe (~> 0.1)
tzinfo (2.0.4)
concurrent-ruby (~> 1.0)
xml-simple (1.1.5)
PLATFORMS

107
2015/rust/Cargo.lock generated

@ -1,146 +1,145 @@
[root]
name = "advent_of_code"
version = "0.1.0"
dependencies = [
"permutohedron 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)",
"rust-crypto 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
]
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "advapi32-sys"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "307c92332867e586720c0222ee9d890bbe8431711efed8a1b06bc5b40fc66bd7"
dependencies = [
"winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi",
"winapi-build",
]
[[package]]
name = "advent_of_code"
version = "0.1.0"
dependencies = [
"permutohedron",
"regex",
"rust-crypto",
]
[[package]]
name = "aho-corasick"
version = "0.4.0"
version = "0.7.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
dependencies = [
"memchr 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr",
]
[[package]]
name = "gcc"
version = "0.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca10e3e1f1c8278047da19b94dc17c4397861150d5fbcea052eedb1d9847d356"
dependencies = [
"advapi32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"advapi32-sys",
"winapi",
]
[[package]]
name = "kernel32-sys"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5b5e7edf375e6d26243bde172f1d5ed1446f4a766fc9b7006e1fd27258243f1"
dependencies = [
"winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi",
"winapi-build",
]
[[package]]
name = "libc"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e32a70cf75e5846d53a673923498228bbec6a8624708a9ea5645f075d6276122"
[[package]]
name = "libc"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10569e57695cc2c91ca4214357907649c9e242dc822c9ae623d0e0b0d68aa4d9"
[[package]]
name = "memchr"
version = "0.1.7"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "permutohedron"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abf78a1e8b52782de92fc4f361362a62bcf5fd5718b5432b48cb381485740b83"
[[package]]
name = "rand"
version = "0.3.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5eee40bdf3d293e1648490ab47e5471d9ab3e455e6b0bd48e558c454be4a015e"
dependencies = [
"advapi32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"advapi32-sys",
"libc 0.2.4",
"winapi",
]
[[package]]
name = "regex"
version = "0.1.44"
version = "1.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286"
dependencies = [
"aho-corasick 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-syntax 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.2.2"
version = "0.6.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64"
[[package]]
name = "rust-crypto"
version = "0.2.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8672a8eb8db93d0938972e391159ba66912b415285ee5cf0ebe732df9e53b70"
dependencies = [
"gcc 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)",
"gcc",
"libc 0.1.12",
"rand",
"rustc-serialize",
"time",
]
[[package]]
name = "rustc-serialize"
version = "0.3.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a48546a64cae47d06885e9bccadb99d0547d877a94c5167fa451ea33a484456"
[[package]]
name = "time"
version = "0.1.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c4aeaa1c95974f5763c3a5ac0db95a19793589bcea5d22e161b5587e3aad029"
dependencies = [
"kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"kernel32-sys",
"libc 0.2.4",
"winapi",
]
[[package]]
name = "winapi"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc3583688b861fcd83c2823d37cf2cd2446c233dd7ba3f97884d1a7302817537"
[[package]]
name = "winapi-build"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum advapi32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "307c92332867e586720c0222ee9d890bbe8431711efed8a1b06bc5b40fc66bd7"
"checksum aho-corasick 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8f36f237c490deb976b38aca6369182dceb5a7af249aabf41c0ba5a964bac5ed"
"checksum gcc 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)" = "ca10e3e1f1c8278047da19b94dc17c4397861150d5fbcea052eedb1d9847d356"
"checksum kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b5b5e7edf375e6d26243bde172f1d5ed1446f4a766fc9b7006e1fd27258243f1"
"checksum libc 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "e32a70cf75e5846d53a673923498228bbec6a8624708a9ea5645f075d6276122"
"checksum libc 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "10569e57695cc2c91ca4214357907649c9e242dc822c9ae623d0e0b0d68aa4d9"
"checksum memchr 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "dc66b0957bf6ae6590681ceac49b0df16823d43037d49aaf2ee658d483af30ab"
"checksum permutohedron 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "abf78a1e8b52782de92fc4f361362a62bcf5fd5718b5432b48cb381485740b83"
"checksum rand 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)" = "5eee40bdf3d293e1648490ab47e5471d9ab3e455e6b0bd48e558c454be4a015e"
"checksum regex 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)" = "e0940ad6bf8abf79e3210809a6a49e199fc8e00b7deafc0d9394157f56f5401e"
"checksum regex-syntax 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fcf1e805b0a23c845be2a303136d840a1511284727bc1f1fc32d079552ef901f"
"checksum rust-crypto 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)" = "b8672a8eb8db93d0938972e391159ba66912b415285ee5cf0ebe732df9e53b70"
"checksum rustc-serialize 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "1a48546a64cae47d06885e9bccadb99d0547d877a94c5167fa451ea33a484456"
"checksum time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)" = "8c4aeaa1c95974f5763c3a5ac0db95a19793589bcea5d22e161b5587e3aad029"
"checksum winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "dc3583688b861fcd83c2823d37cf2cd2446c233dd7ba3f97884d1a7302817537"
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"

@ -4,6 +4,6 @@ version = "0.1.0"
authors = ["Alpha Chen <alpha.chen@gmail.com>"]
[dependencies]
regex = "0.1"
regex = "1.5"
rust-crypto = "^0.2"
permutohedron = "0.2"

144
2016/rust/Cargo.lock generated

@ -1,201 +1,173 @@
[root]
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "advent_of_code_2016"
version = "0.1.0"
dependencies = [
"error-chain 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)",
"rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
"error-chain",
"regex",
"rust-crypto",
]
[[package]]
name = "aho-corasick"
version = "0.5.3"
version = "0.7.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
dependencies = [
"memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr",
]
[[package]]
name = "backtrace"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f551bc2ddd53aea015d453ef0b635af89444afa5ed2405dd0b2062ad5d600d80"
dependencies = [
"backtrace-sys 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-demangle 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"backtrace-sys",
"cfg-if",
"dbghelp-sys",
"kernel32-sys",
"libc",
"rustc-demangle",
"winapi",
]
[[package]]
name = "backtrace-sys"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3602e8d8c43336088a8505fa55cae2b3884a9be29440863a11528a42f46f6bb7"
dependencies = [
"gcc 0.3.39 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
"gcc",
"libc",
]
[[package]]
name = "cfg-if"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de1e760d7b6535af4241fca8bd8adf68e2e7edacc6b29f5d399050c5e48cf88c"
[[package]]
name = "dbghelp-sys"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97590ba53bcb8ac28279161ca943a924d1fd4a8fb3fa63302591647c4fc5b850"
dependencies = [
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi",
"winapi-build",
]
[[package]]
name = "error-chain"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1cd681735364a04cd5d69f01a4f6768e70473941f8d86d8c224faf6955a75799"
dependencies = [
"backtrace 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"backtrace",
]
[[package]]
name = "gcc"
version = "0.3.39"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "771e4a97ff6f237cf0f7d5f5102f6e28bb9743814b6198d684da5c58b76c11e0"
[[package]]
name = "kernel32-sys"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
dependencies = [
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi",
"winapi-build",
]
[[package]]
name = "libc"
version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a51822fc847e7a8101514d1d44e354ba2ffa7d4c194dcab48870740e327cac70"
[[package]]
name = "memchr"
version = "0.1.11"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
]
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "rand"
version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "022e0636ec2519ddae48154b028864bdce4eaf7d35226ab8e65c611be97b189d"
dependencies = [
"libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
"libc",
]
[[package]]
name = "regex"
version = "0.1.80"
version = "1.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286"
dependencies = [
"aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
"utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.3.9"
version = "0.6.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64"
[[package]]
name = "rust-crypto"
version = "0.2.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a"
dependencies = [
"gcc 0.3.39 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
"gcc",
"libc",
"rand",
"rustc-serialize",
"time",
]
[[package]]
name = "rustc-demangle"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1430d286cadb237c17c885e25447c982c97113926bb579f4379c0eca8d9586dc"
[[package]]
name = "rustc-serialize"
version = "0.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "thread-id"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "thread_local"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
checksum = "bff9fc1c79f2dec76b253273d07682e94a978bd8f132ded071188122b2af9818"
[[package]]
name = "time"
version = "0.1.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c7ec6d62a20df54e07ab3b78b9a3932972f4b7981de295563686849eb3989af"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"kernel32-sys",
"libc",
"winapi",
]
[[package]]
name = "utf8-ranges"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
[[package]]
name = "winapi-build"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ca972c2ea5f742bfce5687b9aef75506a764f61d37f8f649047846a9686ddb66"
"checksum backtrace 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f551bc2ddd53aea015d453ef0b635af89444afa5ed2405dd0b2062ad5d600d80"
"checksum backtrace-sys 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3602e8d8c43336088a8505fa55cae2b3884a9be29440863a11528a42f46f6bb7"
"checksum cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de1e760d7b6535af4241fca8bd8adf68e2e7edacc6b29f5d399050c5e48cf88c"
"checksum dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97590ba53bcb8ac28279161ca943a924d1fd4a8fb3fa63302591647c4fc5b850"
"checksum error-chain 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1cd681735364a04cd5d69f01a4f6768e70473941f8d86d8c224faf6955a75799"
"checksum gcc 0.3.39 (registry+https://github.com/rust-lang/crates.io-index)" = "771e4a97ff6f237cf0f7d5f5102f6e28bb9743814b6198d684da5c58b76c11e0"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
"checksum libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "a51822fc847e7a8101514d1d44e354ba2ffa7d4c194dcab48870740e327cac70"
"checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20"
"checksum rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "022e0636ec2519ddae48154b028864bdce4eaf7d35226ab8e65c611be97b189d"
"checksum regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)" = "4fd4ace6a8cf7860714a2c2280d6c1f7e6a413486c13298bbc86fd3da019402f"
"checksum regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ec002c35e86791825ed294b50008eea9ddfc8def4420124fbc6b08db834957"
"checksum rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a"
"checksum rustc-demangle 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1430d286cadb237c17c885e25447c982c97113926bb579f4379c0eca8d9586dc"
"checksum rustc-serialize 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)" = "bff9fc1c79f2dec76b253273d07682e94a978bd8f132ded071188122b2af9818"
"checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03"
"checksum thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8576dbbfcaef9641452d5cf0df9b0e7eeab7694956dd33bb61515fb8f18cfdd5"
"checksum time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "3c7ec6d62a20df54e07ab3b78b9a3932972f4b7981de295563686849eb3989af"
"checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f"
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"

@ -5,5 +5,5 @@ authors = ["Alpha Chen <alpha.chen@gmail.com>"]
[dependencies]
error-chain = "0.7"
regex = "0.1"
regex = "1.5"
rust-crypto = "0.2"

175
2018/rust/Cargo.lock generated

@ -1,252 +1,205 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "advent_of_code"
version = "0.1.0"
dependencies = [
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"pest 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"pest_derive 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static",
"pest",
"pest_derive",
"regex",
]
[[package]]
name = "aho-corasick"
version = "0.6.9"
version = "0.7.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
dependencies = [
"memchr 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr",
]
[[package]]
name = "arrayref"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee"
[[package]]
name = "block-buffer"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a076c298b9ecdb530ed9d967e74a6027d6a7478924520acddcddc24c1c8ab3ab"
dependencies = [
"arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"arrayref",
"byte-tools",
]
[[package]]
name = "byte-tools"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "cfg-if"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40"
[[package]]
name = "digest"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03b072242a8cbaf9c145665af9d250c59af3b958f83ed6824e13533cf76d5b90"
dependencies = [
"generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"generic-array",
]
[[package]]
name = "fake-simd"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
[[package]]
name = "generic-array"
version = "0.9.0"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d00328cedcac5e81c683e5620ca6a30756fc23027ebf9bff405c0e8da1fbb7e"
dependencies = [
"typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
"typenum",
]
[[package]]
name = "lazy_static"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "libc"
version = "0.2.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1"
[[package]]
name = "maplit"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08cbb6b4fef96b6d77bfc40ec491b1690c779e77b05cd9f07f787ed376fd4c43"
[[package]]
name = "memchr"
version = "2.1.1"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
"version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "pest"
version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a677051ad923732bb5c70f2d45f8985a96e3eee2e2bff86697e3b11b0c3fcfde"
dependencies = [
"ucd-trie 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"ucd-trie",
]
[[package]]
name = "pest_derive"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b76f477146419bc539a63f4ef40e902166cb43b3e51cecc71d9136fd12c567e7"
dependencies = [
"pest 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"pest_generator 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"pest",
"pest_generator",
]
[[package]]
name = "pest_generator"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ebee4e9680be4fd162e6f3394ae4192a6b60b1e4d17d845e631f0c68d1a3386"
dependencies = [
"pest 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"pest_meta 2.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)",
"pest",
"pest_meta",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "pest_meta"
version = "2.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f6d5f6f0e6082578c86af197d780dc38328e3f768cec06aac9bc46d714e8221"
dependencies = [
"maplit 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"pest 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"sha-1 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"maplit",
"pest",
"sha-1",
]
[[package]]
name = "proc-macro2"
version = "0.4.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77619697826f31a02ae974457af0b29b723e5619e113e9397b8b82c6bd253f09"
dependencies = [
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid",
]
[[package]]
name = "quote"
version = "0.6.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53fa22a1994bd0f9372d7a816207d8a2677ad0325b073f5c5332760f0fb62b5c"
dependencies = [
"proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2",
]
[[package]]
name = "regex"
version = "1.1.0"
version = "1.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286"
dependencies = [
"aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-syntax 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
"thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.6.4"
version = "0.6.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64"
[[package]]
name = "sha-1"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51b9d1f3b5de8a167ab06834a7c883bd197f2191e1dda1a22d9ccfeedbf9aded"
dependencies = [
"block-buffer 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)",
"fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"block-buffer",
"byte-tools",
"digest",
"fake-simd",
]
[[package]]
name = "syn"
version = "0.14.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741"
dependencies = [
"proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "thread_local"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
name = "typenum"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169"
[[package]]
name = "ucd-trie"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "ucd-util"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71a9c5b1fe77426cf144cc30e49e955270f5086e31a6441dfa8b32efc09b9d77"
[[package]]
name = "unicode-xid"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "utf8-ranges"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "version_check"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1e9a933f4e58658d7b12defcf96dc5c720f20832deebe3e0a19efd3b6aaeeb9e"
"checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee"
"checksum block-buffer 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a076c298b9ecdb530ed9d967e74a6027d6a7478924520acddcddc24c1c8ab3ab"
"checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40"
"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4"
"checksum digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "03b072242a8cbaf9c145665af9d250c59af3b958f83ed6824e13533cf76d5b90"
"checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
"checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d"
"checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1"
"checksum libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)" = "10923947f84a519a45c8fefb7dd1b3e8c08747993381adee176d7a82b4195311"
"checksum maplit 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08cbb6b4fef96b6d77bfc40ec491b1690c779e77b05cd9f07f787ed376fd4c43"
"checksum memchr 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0a3eb002f0535929f1199681417029ebea04aadc0c7a4224b46be99c7f5d6a16"
"checksum pest 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a677051ad923732bb5c70f2d45f8985a96e3eee2e2bff86697e3b11b0c3fcfde"
"checksum pest_derive 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b76f477146419bc539a63f4ef40e902166cb43b3e51cecc71d9136fd12c567e7"
"checksum pest_generator 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ebee4e9680be4fd162e6f3394ae4192a6b60b1e4d17d845e631f0c68d1a3386"
"checksum pest_meta 2.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1f6d5f6f0e6082578c86af197d780dc38328e3f768cec06aac9bc46d714e8221"
"checksum proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)" = "77619697826f31a02ae974457af0b29b723e5619e113e9397b8b82c6bd253f09"
"checksum quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "53fa22a1994bd0f9372d7a816207d8a2677ad0325b073f5c5332760f0fb62b5c"
"checksum regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "37e7cbbd370869ce2e8dff25c7018702d10b21a20ef7135316f8daecd6c25b7f"
"checksum regex-syntax 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4e47a2ed29da7a9e1960e1639e7a982e6edc6d49be308a3b02daf511504a16d1"
"checksum sha-1 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "51b9d1f3b5de8a167ab06834a7c883bd197f2191e1dda1a22d9ccfeedbf9aded"
"checksum syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)" = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741"
"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169"
"checksum ucd-trie 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "71a9c5b1fe77426cf144cc30e49e955270f5086e31a6441dfa8b32efc09b9d77"
"checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86"
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
"checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737"
"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"

@ -0,0 +1,13 @@
require "rake/testtask"
task default: [:test, :srb]
Rake::TestTask.new do |t|
t.libs << "test"
t.test_files = FileList["test_*.rb"]
t.verbose = true
end
task :srb do
sh "srb tc"
end

@ -1,5 +1,7 @@
# typed: strict
require "stringio"
require "sorbet-runtime"
AnyIO = T.type_alias { T.any(IO, StringIO) }
@ -9,20 +11,34 @@ class Mode < T::Enum
enums do
Position = new
Immediate = new
Relative = new
end
extend T::Sig
sig {params(value: String).returns(Mode)}
def self.from(value)
case value
when ?0 then Mode::Position
when ?1 then Mode::Immediate
when ?2 then Mode::Relative
else fail "unexpected mode: #{value}"
end
end
end
OPCODES = T.let({
1 => ->(m, _, _, a, b, c) { m[c] = m[a] + m[b] ; nil }, # add
2 => ->(m, _, _, a, b, c) { m[c] = m[a] * m[b] ; nil }, # multiply
3 => ->(m, i, _, a) { m[a] = i.gets.to_i ; nil }, # input
4 => ->(m, _, o, a) { o.puts(m[a]) ; nil }, # output
5 => ->(m, _, _, a, b) { m[a].nonzero? ? m[b] : nil }, # jump-if-true
6 => ->(m, _, _, a, b) { m[a].zero? ? m[b] : nil }, # jump-if-false
7 => ->(m, _, _, a, b, c) { m[c] = (m[a] < m[b]) ? 1 : 0; nil }, # less than
8 => ->(m, _, _, a, b, c) { m[c] = (m[a] == m[b]) ? 1 : 0; nil }, # equals
99 => ->(*) { throw :halt },
}, T::Hash[T.untyped, T.untyped])
1 => ->(x, _, _, a, b, c) { x[c] = x[a] + x[b] }, # add
2 => ->(x, _, _, a, b, c) { x[c] = x[a] * x[b] }, # multiply
3 => ->(x, i, _, a) { x[a] = i.gets.to_i }, # input
4 => ->(x, _, o, a) { o.puts(x[a]) }, # output
5 => ->(x, _, _, a, b) { x.pc = x[b] if x[a].nonzero? }, # jump-if-true
6 => ->(x, _, _, a, b) { x.pc = x[b] if x[a].zero? }, # jump-if-false
7 => ->(x, _, _, a, b, c) { x[c] = (x[a] < x[b]) ? 1 : 0 }, # less than
8 => ->(x, _, _, a, b, c) { x[c] = (x[a] == x[b]) ? 1 : 0 }, # equals
9 => ->(x, _, _, a) { x.rb += x[a] }, # adjust relative base
99 => ->(*) { throw :halt }, # halt
}, T::Hash[Integer, T.untyped])
class Parameter
extend T::Sig
@ -30,12 +46,9 @@ class Parameter
sig {params(value: T.any(Parameter, Integer)).returns(Parameter)}
def self.from(value)
case value
when Parameter
value
when Integer
new(Mode::Position, value)
else
T.absurd(value)
when Parameter then value
when Integer then new(Mode::Position, value)
else T.absurd(value)
end
end
@ -60,55 +73,54 @@ class Computer
new(input.split(?,).map(&:to_i))
end
sig {returns(AnyIO)}
attr_reader :input, :output
sig {returns(Integer)}
attr_accessor :pc, :rb
sig {params(program: Memory, input: AnyIO, output: AnyIO).void}
def initialize(program, input=STDIN, output=STDOUT)
sig {params(program: Memory).void}
def initialize(program)
@memory = T.let(program.dup, Memory)
@input = T.let(input, AnyIO)
@output = T.let(output, AnyIO)
@pc = T.let(0, Integer)
@rb = T.let(0, Integer)
end
sig {params(input: AnyIO, output: AnyIO).returns(Memory)}
sig {params(input: T.untyped, output: AnyIO).returns(Memory)}
def run(input=STDIN, output=STDOUT)
each = T.cast(each(input, output), T::Enumerator[Memory])
each.inject(nil) {|_,i| i }
each(input, output).inject(nil) {|_,i| i }
end
sig {
params(
input: AnyIO,
input: T.untyped,
output: AnyIO,
blk: T.nilable(T.proc.params(m: Memory).returns(T.nilable(Integer)))
).returns(T.any(T::Enumerator[Memory], BasicObject))
).returns(T::Enumerator[Memory])
}
def each(input, output, &blk)
return enum_for(T.must(__method__), input, output) unless block_given?
catch(:halt) do
loop do
instruction = @memory[@pc].to_s.rjust(5, ?0)
instruction = @memory[pc].to_s.rjust(5, ?0)
opcode = OPCODES.fetch(instruction[-2..-1].to_i)
@pc += 1
self.pc += 1
n = opcode.arity - 3
args = (0...n).zip(T.must(instruction[0..2]).reverse.chars.map(&:to_i)).map {|i, mode|
value = @memory.fetch(@pc + i) || 0
mode = case mode
when 0 then Mode::Position
when 1 then Mode::Immediate
end
n = opcode.arity - 3 # subtract the computer, input, and output params
args = (0...n).map {|i|
mode = Mode.from(T.must(instruction[2-i]))
value = @memory[pc + i] || 0
Parameter.new(mode, value)
}
@pc += n
self.pc += n
@pc = opcode.call(self, input, output, *args) || @pc
opcode.call(self, input, output, *args)
yield @memory
end
end
# Satisfy sorbet:
# https://sorbet-ruby.slack.com/archives/CHN2L03NH/p1575648549254600
Enumerator.new {}
end
sig {params(parameter: Parameter).returns(Integer)}
@ -116,8 +128,9 @@ class Computer
parameter = Parameter.from(parameter)
mode = parameter.mode
case mode
when Mode::Position then @memory.fetch(parameter.value) || 0
when Mode::Position then @memory[parameter.value] || 0
when Mode::Immediate then parameter.value
when Mode::Relative then @memory[rb + parameter.value] || 0
else T.absurd(mode)
end
end
@ -125,8 +138,17 @@ class Computer
sig {params(parameter: Parameter, value: Integer).void}
def []=(parameter, value)
raise "writes should never be in immediate mode" if parameter.mode == Mode::Immediate
@memory[parameter.value] = value
mode = parameter.mode
case mode
when Mode::Position then @memory[parameter.value] = value
when Mode::Immediate then raise "writes should never be in immediate mode"
when Mode::Relative then @memory[rb + parameter.value] = value
else T.absurd(mode)
end
end
end
if __FILE__ == $0
Computer.from(T.cast(ARGF, IO).read || "").run
end

@ -1,3 +1,4 @@
# typed: false
orbits = ARGF
.read.split("\n").map {|l| l.split(?)) }
.each.with_object(Hash.new {|h,k| h[k] = []}) {|(a, b), o|

@ -0,0 +1,27 @@
require_relative "computer"
program = ARGF.read
p (5..9).to_a.permutation.map {|phase_settings|
amplifiers = Array.new(5) { Computer.from(program) }
pipes = Array.new(5) { IO.pipe }
# input phase settings
pipes.zip(phase_settings).each do |(_, w), ps|
w.puts(ps)
end
# first 0 signal
pipes.first.last.puts(?0)
ios = pipes.cycle.each_cons(2).take(5).map {|(r, _), (_, w)| [r, w] }
ts = amplifiers.zip(ios).map {|(a, (i, o))|
Thread.new { a.run(i, o) }
}
ts.each(&:join)
thrusters_input = ios.first.first
thrusters_input.gets.to_i
}.max

@ -0,0 +1,17 @@
image = ARGF.read.scan(/\d/).map(&:to_i)
w = 25
h = 6
# l = image.each_slice(w*h).min_by {|l| l.count(0) }
# p l.count(1) * l.count(2)
layers = image.each_slice(w*h)
puts layers
.inject {|n,l| n.zip(l) }
.map(&:flatten)
.map {|layers| layers.drop_while {|p| p == 2 }.first }
.map {|p| p.zero? ? "" : " " }
.each_slice(w)
.map(&:join)
.join("\n")

@ -0,0 +1,6 @@
require_relative "computer"
program = ARGF.read
c = Computer.from(program)
c.run(StringIO.new("2"))

@ -0,0 +1,32 @@
require "pp"
asteroids = ARGF.read.strip.lines.map(&:strip).map {|l| l.chars }
max_y = asteroids.size
max_x = asteroids.first.size
asteroids = asteroids.flat_map.with_index {|row, y|
row.filter_map.with_index {|l, x| l == ?. ? nil : [x, y] }
}
asteroids = asteroids.each.with_object({}) {|(x, y), h|
visible = asteroids
.reject {|ax, ay| [x, y] == [ax, ay] }
.each.with_object(Hash.new {|h,k| h[k] = [] }) {|(ax, ay), ah|
rad = (Math.atan2(ax - x, y - ay) + 2*Math::PI) % (2*Math::PI)
ah[rad] << [ax, ay]
}
h[[x, y]] = visible
}
station = asteroids.max_by {|_,v| v.size }
# p station.last.size
asteroids = station.last.to_h.sort_by(&:first).map(&:last)
199.times do
a = asteroids.shift
asteroids.concat(a[1..-1]) if a.first.is_a?(Array)
end
x, y = asteroids.first.first
p 100*x + y

@ -0,0 +1,47 @@
# typed: ignore
require "stringio"
require_relative "computer"
include Math
panels = Hash.new {|h,k| h[k] = [0]}
panels[[0, 0]] = [1]
i_r, i_w = IO.pipe
o_r, o_w = IO.pipe
Robot = Struct.new(:panel, :rad)
robot = Robot.new([0, 0], PI/2)
t = Thread.new {
loop do
i_w.puts(panels[robot.panel].last)
panels[robot.panel] << o_r.gets.to_i
dir = o_r.gets.to_i
raise "unexpected direction: #{dir}" unless [0, 1].include?(dir)
robot.rad += -(2*dir - 1) * (PI/2)
delta = [cos(robot.rad).to_i, sin(robot.rad).to_i]
robot.panel = robot.panel.zip(delta).map(&:sum)
end
}
Thread.new { Computer.from(ARGF.read).run(i_r, o_w) }.join
# p panels.values.count {|v| v.size > 1 }
min_x, max_x = panels.keys.map(&:first).minmax
min_y, max_y = panels.keys.map(&:last).minmax
letters = (min_y..max_y).map {|y|
(min_x..max_x).map {|x|
(panels[[x, y]].last == 1) ? ?█ : " "
}.join
}.reverse.join("\n")
puts letters

@ -0,0 +1,126 @@
# typed: ignore
require "matrix"
require "prime"
require "set"
V = Vector
Moon = Struct.new(:id, :pos, :vel) do
def potential_energy
pos.map(&:abs).sum
end
def kinetic_energy
vel.map(&:abs).sum
end
end
class Moons < SimpleDelegator
def self.from(input)
moons = input
.scan(/x=(-?\d+), y=(-?\d+), z=(-?\d+)/)
.map.with_index {|x,i| Moon.new(i, V[*x.map(&:to_i)], V.zero(3)) }
new(moons)
end
def step
# apply gravity
deltas = Hash.new {|h,k| h[k] = V.zero(3) }
combination(2).each do |a, b|
delta = V[*a.pos.zip(b.pos).map {|a,b| a <=> b }]
deltas[a] -= delta
deltas[b] += delta
end
# apply velocity
Moons.new(map {|m|
v = m.vel + deltas.fetch(m)
Moon.new(m.id, m.pos + v, v)
})
end
def energy
map {|m| m.potential_energy * m.kinetic_energy }.sum
end
def fingerprint(axis)
map {|m| [m.pos[axis], m.vel[axis]] }
end
end
require "minitest"
class TestMoons < Minitest::Test
def setup
@moons = Moons.from(<<~MOONS)
<x=-1, y=0, z=2>
<x=2, y=-10, z=-7>
<x=4, y=-8, z=8>
<x=3, y=5, z=-1>
MOONS
end
def test_from
assert_equal Moon.new(0, V[-1, 0, 2], V[0, 0, 0]), @moons.fetch(0)
assert_equal Moon.new(3, V[3, 5, -1], V[0, 0, 0]), @moons.fetch(3)
end
def test_step
moons = @moons.step
assert_equal Moon.new(0, V[2, -1, 1], V[3, -1, -1]), moons.fetch(0)
assert_equal Moon.new(3, V[2, 2, 0], V[-1, -3, 1]), moons.fetch(3)
9.times do
moons = moons.step
end
assert_equal Moon.new(0, V[2, 1, -3], V[-3, -2, 1]), moons.fetch(0)
assert_equal Moon.new(3, V[2, 0, 4], V[1, -1, -1]), moons.fetch(3)
end
def test_energy
10.times do
@moons = @moons.step
end
assert_equal 179, @moons.energy
end
end
def gcd(*n)
n.map {|c| Prime.prime_division(c).to_h }
.inject {|h,p| h.merge(p) {|_, a, b| [a, b].max }}
.map {|n,e| n**e }
.inject(&:*)
end
if ARGF.to_io.tty?
require "minitest/autorun"
else
moons = Moons.from(ARGF.read)
# 1000.times do
# moons = moons.step
# end
# puts moons.energy
seen = [{}, {}, {}]
cycles = [nil, nil, nil]
(0..).each do |step|
if cycles.none?(&:nil?)
puts gcd(*cycles.map(&:size))
exit
end
(0..2).each do |i|
seen[i][moons.fingerprint(i)] ||= step
end
moons = moons.step
(0..2).each do |i|
cycles[i] ||= (seen[i][moons.fingerprint(i)]..step) if seen[i].include?(moons.fingerprint(i))
end
end
end

@ -0,0 +1,103 @@
# typed: ignore
require "stringio"
require_relative "computer"
class Game
def initialize
@output = Hash.new(0)
@min_x, @max_x, @min_y, @max_y = 0, 0, 0, 0
end
def []=(x, y, value)
@output[[x, y]] = value
@min_x = [@min_x, x].min
@max_x = [@max_x, x].max
@min_y = [@min_y, y].min
@max_y = [@max_y, y].max
end
def ball_pos
@output.key(4)
end
def paddle_pos
@output.key(3)
end
def score
@output[[-1, 0]]
end
def to_s
min_x = [0, @min_x].max
screen = (@min_y..@max_y).map {|y|
(min_x..@max_x).map {|x|
tile(@output[[x, y]])
}.join
}.join("\n")
score = @output[[-1, 0]] || 0
"#{screen}\n#{score}"
end
private
def tile(id)
case id
when 0 then " "
when 1 then ?█
when 2 then ?▒
when 3 then ?▄
when 4 then ?@
else fail "unexpected tile id: #{id}"
end
end
end
class FollowBall
def initialize(game)
@game = game
@last_ball = nil
end
def gets
ball, paddle = nil, nil
until [ball, paddle].none?(&:nil?) && ball != @last_ball
ball = @game.ball_pos
paddle = @game.paddle_pos
end
@last_ball = ball
# puts @game
# STDIN.gets
ball[0] <=> paddle[0]
end
end
game = Game.new
follow_ball = FollowBall.new(game)
output, output_writer = IO.pipe
Thread.new do
loop do
x, y, tile_id = 3.times.map { output.gets.to_i }
game[x, y] = tile_id
end
end
Thread.new do
program = File.read("day_13.txt").split(?,).map(&:to_i)
program[0] = 2
Computer.new(program).run(follow_ball, output_writer)
sleep 1
puts game.score
end.join

File diff suppressed because one or more lines are too long

@ -0,0 +1,37 @@
reactions = ARGF.read.strip.lines.each.with_object({}) {|line, h|
reactands = line.scan(/(\d+) (\w+)/).map {|q,c| [c,q.to_i] }
c, q = reactands.pop
h[c] = { quantity: q, inputs: reactands }
}.to_h
Factory = Struct.new(:reactions, :supply, :ores_used) do
def produce(chemical)
self.ores_used ||= 0
case reaction = reactions[chemical]
in { quantity: quantity, inputs: inputs }
until inputs.all? {|c,q| supply[c] >= q }
inputs
.select {|c,q| supply[c] < q }
.each do |c,_|
produce(c)
end
end
inputs.each do |c,q|
self.ores_used += q if c == "ORE"
supply[c] -= q
end
supply[chemical] += quantity
else
fail "unexpected reaction: #{reaction}"
end
end
end
supply = Hash.new(0)
supply["ORE"] = Float::INFINITY
factory = Factory.new(reactions, supply)
factory.produce("FUEL")

@ -25,7 +25,7 @@ class TestComputer < Minitest::Test
end
def test_input_output
assert_equal 1, run_program("3,50,99", input: "1\n")[50]
assert_equal 1, run_program("3,50,99", input: "1")[50]
output = StringIO.new
run_program("4,3,99,50", output: output)
@ -84,6 +84,21 @@ class TestComputer < Minitest::Test
end
end
def test_relative_base
program = "109,1,204,-1,1001,100,1,100,1008,100,16,101,1006,101,0,99"
output = StringIO.new
run_program(program, output: output)
assert_equal program.split(?,).join("\n"), output.string.strip
output = StringIO.new
run_program("1102,34915192,34915192,7,4,7,99,0", output: output)
assert_equal 16, output.string.strip.size
output = StringIO.new
run_program("104,1125899906842624,99", output: output)
assert_equal 1125899906842624, output.string.to_i
end
private
def run_program(p, input: "", output: StringIO.new)

@ -0,0 +1,200 @@
1567
1223
1758
1842
1933
1898
1409
1058
1533
1417
1032
1634
1477
1394
1888
1972
1237
1390
1677
1546
1302
1070
1369
1455
1065
1924
1593
1131
1064
1346
1914
1129
1830
1450
1278
1740
1809
1176
1734
1102
1807
1982
1603
1736
2008
1980
1905
1633
1732
1350
1865
1988
1805
1998
1152
1046
1870
1557
1789
1766
1945
1359
1002
1126
1719
1497
1296
1560
1936
1929
1464
2005
1281
618
1257
1107
1632
1688
1964
1803
1360
1384
1889
1411
1328
1452
1868
1515
1586
1631
1618
1087
1710
1094
1774
1295
1700
1636
1230
1421
1910
1522
1366
1144
1757
1493
1316
1103
687
1371
1720
1155
1559
1900
989
1367
1999
1066
1773
1787
1402
1047
1806
1956
1219
1555
1307
1419
1706
1884
1109
1181
2010
1298
1730
1078
1848
1398
1687
2007
1550
1664
1225
1079
1698
350
1222
1377
1977
1510
1571
1630
1029
1379
1942
1949
1249
1829
1297
1530
1607
1324
1069
1476
928
1039
1855
1644
1454
1310
1172
547
1034
1878
1479
1457
1319
1810
1759
1439
1851
545
1470
2003
1908
1564
1491
1174
1301
1689
1276
1781
1392
1499
1962
1653
1823
1381
1827
1974

File diff suppressed because it is too large Load Diff

@ -0,0 +1,3 @@
n = 3
x = ARGF.read.split.map(&:to_i).combination(n).find {|x| x.sum == 2020 }
p x.reduce(&:*)

@ -0,0 +1,5 @@
day1 = proc {|min,max,char,pass| (min..max).cover?(pass.count(char)) }
day2 = proc {|p1,p2,char,pass| [pass[p1-1], pass[p2-1]].count(char) == 1 }
puts ARGF.read.scan(/^(\d+)-(\d+)\s*(\w):\s*(\w+)$/)
.map {|a,b,c,d| [a.to_i, b.to_i, c, d] }
.count(&day2)

@ -0,0 +1,15 @@
map = ARGF.read.split("\n").map(&:chars)
rows = map.size
cols = map[0].size
slopes = [
[1, 1],
[3, 1],
[5, 1],
[7, 1],
[1, 2],
]
puts slopes.map {|dx,dy|
Array.new(rows / dy) {|i| [dx*i % cols, dy*i] }
.map {|x,y| map[y][x] }
.count(?#)
}.reduce(&:*)

@ -0,0 +1,25 @@
FIELDS = {
byr: ->(s) { s =~ /^\d{4}$/ && (1920..2002).cover?(s.to_i) },
iyr: ->(s) { s =~ /^\d{4}$/ && (2010..2020).cover?(s.to_i) },
eyr: ->(s) { s =~ /^\d{4}$/ && (2020..2030).cover?(s.to_i) },
hgt: ->(s) {
s =~ /^(\d+)(cm|in)$/
case $2
when "cm"
(150..193).cover?($1.to_i)
when "in"
(59..76).cover?($1.to_i)
else
false
end
},
hcl: ->(s) { s =~ /^#[0-9a-f]{6}$/ },
ecl: ->(s) { s =~ /^(amb|blu|brn|gry|grn|hzl|oth)$/ },
pid: ->(s) { s =~ /^\d{9}$/ },
cid: ->(s) { true },
}
puts ARGF.read.split("\n\n").map {|line| line.scan(/(\w+):(\S+)/).to_h }
.count {|passport|
FIELDS.map {|k,v| v[passport.fetch(k.to_s, "")] }.all?
}

@ -0,0 +1,6 @@
seats = ARGF.read.split("\n")
.map {|pass| pass.tr("FB", "01").tr("LR", "01") }
.map {|pass| pass.to_i(2) }
p seats.max # day 1
p (0b1000..).find {|id| !seats.include?(id) }

@ -0,0 +1,6 @@
p ARGF.read.split("\n\n").map {|group|
group.split("\n").map(&:chars)
}.map {|group|
# group.inject(&:|)
group.inject(&:&)
}.map(&:size).sum

@ -0,0 +1,16 @@
require "set"
rules = ARGF.read.split("\n")
.map {|line| line.split(" bags contain") }.to_h
.transform_values {|v| v.scan(/(\d+) ([\w ]+) bags?/).map(&:reverse).to_h }
# bags = rules.select {|_,v| v.has_key?("shiny gold") }.map(&:first).to_set
# while true
# bags.merge(bags.flat_map {|bag| rules.select {|_,v| v.has_key?(bag) }.map(&:first) })
# p bags.size
# end
bags = Hash.new {|h,k|
h[k] = rules.fetch(k).map {|k,v| v.to_i + h[k] * v.to_i }.sum
}
p bags["shiny gold"]

@ -0,0 +1,55 @@
require "set"
execute = ->(r, op, arg) {
delta = case op
when :acc
{ acc: arg, pc: 1 }
when :jmp
{ pc: arg }
when :nop
{ pc: 1 }
else
fail
end
r.merge(delta) {|_, old, new| old + new }
}
# part 1
seen = Set.new
detect_loop = ->(r, op, arg) {
throw :halt if seen.include?(r[:pc])
seen << r[:pc]
execute[r, op, arg]
}
instructions = ARGF.read.scan(/(\w+) ([-+]\d+)/).map {|op,arg| [op.to_sym, arg.to_i] }
registers = Hash.new(0)
swaps = { nop: :jmp, jmp: :nop }
candidates = instructions.filter_map.with_index {|(op, arg), i|
swap = swaps[op]
if swap.nil?
nil
else
[i, [swap, arg]]
end
}.map {|i, swap|
candidate = instructions.clone
candidate[i] = swap
candidate
}
candidates.each do |candidate|
seen = Set.new
registers = Hash.new(0)
catch(:halt) do
while instruction = candidate[registers[:pc]]
registers = detect_loop[registers, *instruction]
end
end
break if registers[:pc] == candidate.size
end
p registers[:acc]

@ -0,0 +1,18 @@
N = 25
data = ARGF.read.scan(/\d+/).map(&:to_i)
invalid = data.each_cons(N+1).filter_map {|range|
n = range.pop
range.combination(2).map(&:sum).include?(n) ? nil : n
}.first
weakness = (0..).lazy.flat_map {|start|
(2..data.size-start-1).map {|len|
data[start, len]
}
}.find {|range|
range.sum == invalid
}.minmax.sum
p weakness

@ -0,0 +1,29 @@
adapters = ARGF.read.scan(/\d+/).map(&:to_i)
outlet = 0
device = adapters.max + 3
dist = (adapters + [outlet, device]).sort.each_cons(2).map {|a,b| b - a }
# part 1
# tally = dist.tally
# p dist[1] * dist[3]
# programmatically figuring out the arrangements
# arrangements = Hash.new {|h,k|
# h[k] = (0..k-1).flat_map {|n| (2..k).to_a.combination(n).to_a }
# .reject {|c| (c << 1 << k+1).sort.each_cons(2).any? {|a,b| b-a > 3 }}
# .count
# }
# tribonacci
arrangements = Hash.new {|h,k| h[k] = h[k-1] + h[k-2] + h[k-3] }
arrangements[0] = 1
arrangements[1] = 1
arrangements[2] = 2
p dist
.slice_when {|a,b| a != b }
.select {|run| run.first == 1 }
.map {|run| arrangements[run.size] }
.inject(&:*)

@ -0,0 +1,90 @@
class Layout
def self.from(raw, &logic)
seats = Hash.new
raw.split("\n").each.with_index do |row,y|
row.chars.each.with_index do |pos,x|
seats[[y,x]] = false if pos == ?L
end
end
self.new(seats, &logic)
end
attr_reader :seats, :y_max, :x_max
def initialize(seats, &logic)
@seats, @logic = seats, logic
@y_max = @seats.keys.map(&:first).max
@x_max = @seats.keys.map(&:last).max
end
def [](yx)
@seats[yx]
end
def each
return enum_for(__method__) unless block_given?
loop do
yield self
seats = tick(&@logic)
break if seats == @seats
@seats = seats
end
end
def tick
@seats.keys.map {|yx|
[yx, @logic[self, yx]]
}.to_h
end
def to_s
(0..@y_max).map {|y|
(0..@x_max).map {|x|
case @seats[[y,x]]
when true then ?#
when false then ?L
when nil then ?.
else fail
end
}.join
}.join("\n")
end
end
NEIGHBORS = (-1..1).flat_map {|y| (-1..1).map {|x| [y, x] }} - [[0, 0]]
day1 = ->(layout, yx) {
y, x = yx
occupied_neighbors = NEIGHBORS.filter_map {|dy,dx| layout[[y+dy, x+dx]] }
if !layout[yx] && occupied_neighbors.empty?
true
elsif layout[yx] && occupied_neighbors.size >= 4
false
else
layout[yx]
end
}
day2 = ->(layout, yx) {
y, x = yx
occupied_neighbors = NEIGHBORS.filter_map {|dy,dx|
(1..).lazy
.map {|i| [y+dy*i, x+dx*i] }
.find {|y,x|
!(0..layout.y_max).cover?(y) ||
!(0..layout.x_max).cover?(x) ||
layout.seats.has_key?([y, x])
}
}.filter_map {|yx| layout[yx] }
if !layout[yx] && occupied_neighbors.empty?
true
elsif layout[yx] && occupied_neighbors.size >= 5
false
else
layout[yx]
end
}
layout = Layout.from(ARGF.read, &day2)
layout.each.take_while(&:itself).last
puts layout.seats.count(&:last)

@ -0,0 +1,54 @@
actions = ARGF.read.scan(/(\w)(\d+)/).map {|a,v| [a, v.to_i] }
dir = 0
pos = [0, 0]
way = [10, 1]
actions.each do |a,v|
# delta = case a
# when ?N
# [ 0, v]
# when ?S
# [ 0, -v]
# when ?E
# [ v, 0]
# when ?W
# [-v, 0]
# when ?L
# dir += v
# [0, 0]
# when ?R
# dir -= v
# [0, 0]
# when ?F
# rad = dir * Math::PI / 180.0
# [v * Math.cos(rad), v * Math.sin(rad)].map(&:round)
# else
# fail
# end
case a
when ?N
way[1] += v
when ?S
way[1] -= v
when ?E
way[0] += v
when ?W
way[0] -= v
when ?L
rad = Math.atan2(*way.reverse)
dis = Math.sqrt(way.map {|x| x**2 }.sum)
rad += v * Math::PI / 180
way = [dis * Math.cos(rad), dis * Math.sin(rad)].map(&:round)
when ?R
rad = Math.atan2(*way.reverse)
dis = Math.sqrt(way.map {|x| x**2 }.sum)
rad -= v * Math::PI / 180
way = [dis * Math.cos(rad), dis * Math.sin(rad)].map(&:round)
when ?F
delta = way.map {|i| v * i }
pos = pos.zip(delta).map {|a,b| a + b }
else
fail
end
end
p pos.map(&:abs).sum

@ -0,0 +1,42 @@
input = ARGF.read.split("\n")
depart_time = input.shift.to_i
buses = input.shift.split(?,).map {|b| b != ?x ? b.to_i : nil }
# p buses.compact.map {|bus|
# d = bus * ((depart_time / bus) + 1)
# [bus, d - depart_time]
# }.min_by(&:last).inject {|a,b| a * b }
# shamelessly copied from https://rosettacode.org/wiki/Chinese_remainder_theorem#Ruby
def extended_gcd(a, b)
last_remainder, remainder = a.abs, b.abs
x, last_x, y, last_y = 0, 1, 1, 0
while remainder != 0
last_remainder, (quotient, remainder) = remainder, last_remainder.divmod(remainder)
x, last_x = last_x - quotient*x, x
y, last_y = last_y - quotient*y, y
end
return last_remainder, last_x * (a < 0 ? -1 : 1)
end
def invmod(e, et)
g, x = extended_gcd(e, et)
if g != 1
raise 'Multiplicative inverse modulo does not exist!'
end
x % et
end
def chinese_remainder(mods, remainders)
max = mods.inject( :* ) # product of all moduli
series = remainders.zip(mods).map{ |r,m| (r * max * invmod(max/m, m) / m) }
series.inject( :+ ) % max
end
buses = buses.map.with_index.select {|b,_| b }
# p 0.step(by: buses[0][0]).lazy.find {|depart_time|
# buses.all? {|b,i| (depart_time + i) % b == 0 }
# }
mods, remainders = buses.map {|b,i| [b, b-i] }.transpose
p chinese_remainder(mods, remainders)

@ -0,0 +1,37 @@
require "strscan"
mem = Hash.new(0)
mask = nil
ss = StringScanner.new(ARGF.read)
until ss.eos?
case
when ss.scan(/mask = ([10X]+)\n/)
mask = ss.captures.fetch(0)
when ss.scan(/mem\[(\d+)\] = (\d+)\n/)
addr, value = ss.captures.map(&:to_i)
# part 1
# value &= mask.gsub(?X, ?1).to_i(2)
# value |= mask.gsub(?X, ?0).to_i(2)
# mem[addr] = value
masked = ("%036b" % addr).chars.zip(mask.chars).map {|a,m|
case m
when ?X then ?X
when ?1 then ?1
when ?0 then a
else fail
end
}.join
floating = masked.count(?X)
(0...2**floating).map {|i| i.to_s(2).chars }.each do |i|
floated = masked.gsub(?X) { i.pop || "0" }.to_i(2)
mem[floated] = value
end
else
fail
end
end
p mem.values.sum

@ -0,0 +1,31 @@
# turns = ARGF.read.scan(/\d+/).map(&:to_i)
# until turns.size == 2020
# turns << if turns.count(turns.last) == 1
# 0
# else
# a, b = turns.filter_map.with_index {|x,i|
# x == turns.last ? i : nil
# }[-2,2]
# b - a
# end
# end
start = ARGF.read.scan(/\d+/).map(&:to_i)
turns = Hash.new
last = start.pop
start.each.with_index do |x,i|
turns[x] = i+1
end
(start.size+1...30000000).each do |turn|
if n = turns[last]
turns[last] = turn
last = turn - n
else
turns[last] = turn
last = 0
end
end
p last

@ -0,0 +1,52 @@
require "strscan"
ss = StringScanner.new(ARGF.read)
rules = {}
mine = []
nearby = []
while ss.scan(/([\w\s]+): (\d+)-(\d+) or (\d+)-(\d+)\n/)
c = ss.captures
field = c.shift
rules[field] = c.map(&:to_i).each_slice(2).map {|a,b| a..b }
end
ss.scan(/\n/)
ss.scan(/your ticket:\n/)
mine = ss.scan(/(?~\n)\n/).scan(/\d+/).map(&:to_i)
ss.scan(/\nnearby tickets:\n/)
nearby = ss.rest.split("\n").map {|line| line.split(?,).map(&:to_i) }
# part one
# p nearby.flat_map {|fields|
# fields.reject {|field|
# rules.values.any? {|values| values.any? {|range| range.cover?(field) }}
# }
# }.sum
nearby.select! {|fields|
fields.all? {|field|
rules.values.any? {|values| values.any? {|range| range.cover?(field) }}
}
}
valid = (0...mine.size).map {|i|
rules.select {|name, ranges|
nearby.map {|n| n[i] }.all? {|n| ranges.any? {|range| range.cover?(n) }}
}
}.map.with_index {|v,i| [i, v.keys] }.to_h
order = {}
until valid.values.all?(&:empty?)
k, f = valid.find {|_,v| v.size == 1 }
order[k] = f[0]
valid.transform_values! {|v| v - f }
end
p order
.select {|_,v| v.start_with?("departure") }
.map(&:first)
.map {|i| mine[i] }
.inject(&:*)

@ -0,0 +1,33 @@
DIMENSIONS = 4
state = ARGF.read.strip.split("\n").flat_map.with_index {|line,y|
line.chars.map.with_index {|c,x|
[[x,y].fill(0, 2, DIMENSIONS-2), c == "#"]
}
}.to_h
NEIGHBORS = (0...3**DIMENSIONS)
.reject {|n| n == 3**DIMENSIONS / 2 }
.map {|n| n.digits(3) }
.map {|n| (0...DIMENSIONS).map {|x| n.fetch(x, 0) - 1 }}
def tick(state)
actives = state.select {|_,c| c }.keys
minmaxes = actives
.transpose.map(&:minmax)
.map {|min,max| (min-1..max+1).to_a }
coords = minmaxes.inject {|n,x|
n.flat_map {|nn| x.map {|xx| [nn, xx] }}
}.map(&:flatten)
coords.map {|coord|
active_neighbors = NEIGHBORS.count {|delta| state[coord.zip(delta).map {|a,b| a + b }] }
[ coord,
state[coord] ? (2..3).cover?(active_neighbors) : active_neighbors == 3
]
}.to_h
end
6.times do
state = tick(state)
end
p state.values.count(&:itself)

@ -0,0 +1,58 @@
require "strscan"
# def evaluate(input)
# while input.include?(?()
# input = input.gsub(/\((?~[()])+\)/) {|m| evaluate(m[1..-2]) }
# end
# # part one
# # ss = StringScanner.new(input)
# # n = ss.scan(/\d+/).to_i
# # until ss.eos?
# # case
# # when ss.scan(/\s*\+\s*(\d+)/)
# # n += ss.captures[0].to_i
# # when ss.scan(/\s*\*\s*(\d+)/)
# # n *= ss.captures[0].to_i
# # else
# # fail
# # end
# # end
# # n
# while input.include?(?+)
# input = input.gsub(/\d+\s*\+\s*\d+/) {|m| eval(m) }
# end
# while input.include?(?*)
# input = input.gsub(/\d+\s*\*\s*\d+/) {|m| eval(m) }
# end
# input.to_i
# end
def evaluate(input)
stack = [->(x) { x }]
ss = StringScanner.new(input)
until ss.eos?
ss.scan(/\s*/)
stack << case
when n = ss.scan(/\d+/)
stack.pop[n.to_i]
when ss.scan(/\+/)
->(x) { stack.pop + x }
when ss.scan(/\*/)
->(x) { stack.pop * x }
when ss.scan(/\(/)
->(x) { x }
when ss.scan(/\)/)
n = stack.pop
stack.pop[n]
else
fail
end
end
stack.pop
end
p ARGF.read.split("\n").map {|line| evaluate(line) }.sum

@ -0,0 +1,67 @@
# require "bundler/inline"
# gemfile do
# source "https://rubygems.org"
# gem "parslet"
# end
rules, messages = ARGF.read.split("\n\n")
# class Day19 < Parslet::Parser
# root(:rule_0)
# end
# rules = rules.split("\n").map {|rule| rule.split(": ") }.to_h
# rules["8"] = "42 | 42 8"
# rules["11"] = "42 31 | 42 11 31"
# rules.each do |rule, sub_rules|
# sub_rules = sub_rules.split(" | ").map {|sub_rule|
# sub_rule.split(/\s+/).map {|sub_sub_rule|
# sub_sub_rule =~ /^\d+$/ ? "rule_#{sub_sub_rule}" : "str(#{sub_sub_rule})"
# }.join(" >> ")
# }.join(" | ")
# rule = "rule(:rule_#{rule}) { #{sub_rules} }"
# p rule
# Day19.class_eval(rule)
# end
# PARSER = Day19.new
# def parsable?(input)
# !!PARSER.parse(input)
# rescue
# false
# end
# puts messages.split("\n").select {|line| parsable?(line) }
# begin
# p PARSER.parse("bbbbbbbaaaabbbbaaabbabaaa")
# rescue Parslet::ParseFailed => failure
# puts failure.parse_failure_cause.ascii_tree
# end
rules = rules.split("\n").map {|line|
line.split(": ")
}.to_h
rule = rules["0"]
while rule =~ /\d/
rule.gsub!(/\d+/) {|r|
case r
when "8"
"(?:42)+"
when "11"
"(?:#{(1..5).map {|i| (Array.new(i, "42") + Array.new(i, "31")).join(" ") }.join(" | ")})"
else
value = rules.fetch(r)
value = value[1..-2] if value =~ /^"\w+"$/
"(?:#{value})"
end
}
end
rule.gsub!(" ", "")
while rule =~ /\(\?:\w+\)/
rule.gsub!(/\(\?:(\w+)\)/, '\1')
end
p messages.split("\n").count {|m| m =~ /^#{rule}$/ }

@ -0,0 +1,107 @@
# all rotations are clockwise
# all flips are vertical
class Tile
attr_reader :id, :raw
def initialize(id, raw)
@id, @raw = id, raw
end
def [](y, x)
@raw.fetch(y).fetch(x)
end
def edge_keys
{
top: @raw.first,
down: @raw.last,
left: @raw.transpose.first,
right: @raw.transpose.last,
}.transform_values(&:join)
end
def permutations
(0..3).map {|i|
i.times.inject(self) {|x,_| x.rotated }
}.flat_map {|x| [x, x.flipped] }
end
def rotated
self.class.new(@id, @raw.reverse.transpose)
end
def flipped
self.class.new(@id, @raw.reverse)
end
def to_s
@raw.map(&:join).join("\n")
end
end
tiles = ARGF.read
.scan(/Tile (\d+):\n((?:[.#]+\n)+)/m)
.to_h
.transform_values {|v| v.split("\n").map {|row| row.chars } }
.map {|k,v| [k, Tile.new(k, v)] }
.to_h
keys_to_tiles = Hash.new {|h,k| h[k] = [] }
tiles.values.each do |tile|
tile.edge_keys.values.each do |key|
keys_to_tiles[key] << tile.id
keys_to_tiles[key.reverse] << tile.id
end
end
start_corner = tiles.values.find {|tile|
tile.edge_keys.values_at(:left, :top).all? {|key| keys_to_tiles.fetch(key).size == 1 }
}
image = [[start_corner]]
until image.map(&:size).sum == tiles.size
current = image.last.last
right_key = current.edge_keys.fetch(:right)
if right_id = keys_to_tiles.fetch(right_key, nil).find {|id| id != current.id }
right_tile = tiles.fetch(right_id).permutations.find {|p| p.edge_keys.fetch(:left) == right_key }
image.last << right_tile
else
current = image.last.first
down_key = current.edge_keys.fetch(:down)
break unless down_id = keys_to_tiles.fetch(down_key).find {|id| id != current.id }
down_tile = tiles.fetch(down_id).permutations.find {|p| p.edge_keys.fetch(:top) == down_key }
image << [down_tile]
end
end
full_raw = image.map {|row| row.map {|tile|
tile.raw[1..-2].map {|row| row[1..-2] }
}}.flat_map {|row| row.inject(&:zip).map(&:flatten) }
full_tile = Tile.new(nil, full_raw)
sea_monster = <<~SEA_MONSTER.split("\n").map(&:chars)
#
# ## ## ###
# # # # # #
SEA_MONSTER
needle = sea_monster.flat_map.with_index {|row,y|
row.filter_map.with_index {|c,x|
c == ?# ? [y,x] : nil
}
}
num_monsters = full_tile.permutations.map {|tile|
needle_maxes = needle.transpose.map(&:max)
haystack = (0...tile.raw.size-needle_maxes.first).flat_map {|y|
(0...tile.raw.first.size-needle_maxes.last).map {|x|
[y, x]
}
}
haystack.count {|y,x|
needle.all? {|dy,dx| tile[y+dy, x+dx] == ?# }
}
}.sum
puts full_tile.raw.map {|row| row.count(?#) }.sum - (num_monsters * needle.size)

@ -0,0 +1,39 @@
require "set"
Food = Struct.new(:id, :ingredients, :allergens)
foods = ARGF.read
.scan(/(.+) \(contains (.+)\)/)
.map.with_index {|(ingredients, allergens), i|
ingredients, allergens = [ ingredients.split(" "), allergens.split(", ") ].map {|x| Set.new(x) }
Food.new(i, ingredients, allergens)
}
all_ingredients = foods.map(&:ingredients).inject(&:|)
all_allergens = foods.map(&:allergens).inject(&:|)
no_allergens = all_ingredients.select {|ingredient|
possible_allergens = foods
.select {|food| food.ingredients.include?(ingredient) }
.map(&:allergens)
.inject(&:|)
possible_allergens.none? {|allergen|
foods_with_allergen = foods.select {|f| f.allergens.include?(allergen) }
foods_with_allergen.all? {|f| f.ingredients.include?(ingredient) }
}
}
# part one
# p foods.map {|f| f.ingredients.count {|i| no_allergens.include?(i) }}.sum
known, unknown = all_allergens.map {|a|
[a, foods.select {|f| f.allergens.include?(a) }.map(&:ingredients).inject(&:&) ]
}.to_h.partition {|_,v| v.size == 1 }.map(&:to_h)
until unknown.empty?
unknown.transform_values! {|v| v - known.values.inject(&:|) }
new_known, unknown = unknown.partition {|_,v| v.size == 1 }.map(&:to_h)
known.merge!(new_known)
end
p known.transform_values {|v| v.to_a.first }.sort_by(&:first).map(&:last).join(?,)

@ -0,0 +1,46 @@
require "set"
decks = ARGF.read.split("\n\n").map {|players| players.split("\n")[1..].map(&:to_i) }
# part one
# until decks.any?(&:empty?)
# p decks
# top_cards = decks.map(&:shift)
# fail if top_cards.tally.size == 1
# if top_cards.first > top_cards.last
# decks.first.concat(top_cards)
# else
# decks.last.concat(top_cards.reverse)
# end
# end
SEEN = Set.new
def recursive_combat!(decks)
until decks.any?(&:empty?)
return 0 if SEEN.include?(decks)
SEEN << decks
top_cards = decks.map(&:shift)
winner = if decks.zip(top_cards).all? {|d,tc| d.size >= tc }
recursive_combat!(decks.zip(top_cards).map {|d,tc| d[0,tc] })
elsif top_cards.first > top_cards.last
0
else
1
end
if winner == 0
decks.first.concat(top_cards)
else
decks.last.concat(top_cards.reverse)
end
end
decks.index {|d| !d.empty? }
end
recursive_combat!(decks)
p decks.flatten.reverse.map.with_index {|v,i| v * (i+1) }.sum

@ -0,0 +1,32 @@
cups = Hash.new {|h,k|
fail if k > 1000000
h[k] = k + 1
}
cup_values = ARGF.read.chars.map(&:to_i)
current = cup_values.first
cup_values = [1_000_000, *cup_values, cup_values.max + 1]
cup_values.each_cons(2) do |a,b|
cups[a] = b
end
cups_range = Range.new(*cups.keys.minmax)
10_000_000.times do |i|
pickup = 2.times.inject([cups[current]]) {|p,_| p << cups[p.last] }
cups[current] = cups[pickup.last]
dest_value = current - 1
loop do
dest_value = cups_range.max if dest_value == 0
break unless pickup.include?(dest_value)
dest_value -= 1
end
cups[pickup.last] = cups[dest_value]
cups[dest_value] = pickup.first
current = cups[current]
end
p 1.times.inject([cups[1]]) {|p,_| p << cups[p.last] }.inject(&:*)

@ -0,0 +1,55 @@
require "set"
require "strscan"
def parse(line)
deltas = []
ss = StringScanner.new(line)
until ss.eos?
deltas << case
when ss.scan(/e/) then [ 1, 0]
when ss.scan(/se/) then [ 0, 1]
when ss.scan(/sw/) then [-1, 1]
when ss.scan(/w/) then [-1, 0]
when ss.scan(/nw/) then [ 0, -1]
when ss.scan(/ne/) then [ 1, -1]
else fail
end
end
deltas.inject {|c,d| c.zip(d).map {|c,d| c+d }}
end
NEIGHBORS = %w[ e se sw w nw ne ].map {|dir| parse(dir) }
def tick(tiles)
coords = Set.new(tiles.flat_map {|coord|
[
coord,
*NEIGHBORS.map {|n| coord.zip(n).map {|c,d| c+d }},
]
})
Set.new(coords.select {|coord|
live_neighbors = NEIGHBORS.map {|n| coord.zip(n).map {|c,d| c+d }}.count {|c| tiles.include?(c) }
if tiles.include?(coord)
(1..2).cover?(live_neighbors)
else
live_neighbors == 2
end
})
end
tiles = Set.new
ARGF.read.split("\n").each do |line|
tile = parse(line)
if tiles.include?(tile)
tiles.delete(tile)
else
tiles << tile
end
end
100.times do |i|
tiles = tick(tiles)
end
p tiles.size

@ -0,0 +1,17 @@
def transform(subject_number)
return enum_for(__method__, subject_number) unless block_given?
value = 1
(0..).each do |loop_size|
yield [loop_size, value]
value *= subject_number
value %= 20201227
end
end
public_keys = ARGF.read.scan(/\d+/).map(&:to_i)
loop_size, _ = transform(7).find {|_,v| v == public_keys.first }
_, encryption_key = transform(public_keys.last).find {|i,_| i == loop_size }
p encryption_key

@ -0,0 +1,4 @@
#!/usr/bin/env jconsole
echo stdin
exit''

@ -0,0 +1,2 @@
p ARGF.read.split("\n").map(&:to_i).each_cons(2).count {|x,y| x < y }
p ARGF.read.split("\n").map(&:to_i).each_cons(3).map(&:sum).each_cons(2).count {|x,y| x < y }

@ -0,0 +1,35 @@
# h = 0
# d = 0
# ARGF.read.split("\n").map(&:split).each do |dir, n|
# n = n.to_i
# case dir
# when "forward"
# h += n
# when "down"
# d += n
# when "up"
# d -= n
# else
# fail dir
# end
# end
# p h, d, h*d
h = 0
d = 0
aim = 0
ARGF.read.split("\n").map(&:split).each do |dir, n|
n = n.to_i
case dir
when "forward"
h += n
d += aim * n
when "down"
aim += n
when "up"
aim -= n
else
fail dir
end
end
p h, d, h*d

@ -0,0 +1,23 @@
bits = ARGF.read.split("\n").map(&:chars)
gamma = bits.transpose.map {|a| a.tally.max_by(&:last).first }.join
epsilon = bits.transpose.map {|a| a.tally.min_by(&:last).first }.join
p gamma.to_i(2) * epsilon.to_i(2)
oxy = bits.clone
(0..oxy.first.length).each do |i|
b = oxy.transpose.map {|a| a.tally.sort.reverse.max_by(&:last).first }[i]
oxy.select! {|x| x[i] == b }
break if oxy.length == 1
end
oxy = oxy.join.to_i(2)
co2 = bits.clone
(0..co2.first.length).each do |i|
b = co2.transpose.map {|a| a.tally.sort.min_by(&:last).first }[i]
co2.select! {|x| x[i] == b }
break if co2.length == 1
end
co2 = co2.join.to_i(2)
p oxy * co2

@ -0,0 +1,29 @@
input = ARGF.read
numbers, *cards = input.split("\n\n")
numbers = numbers.split(?,).map(&:to_i)
cards = cards.map {|c| c.split("\n").map {|r| r.split(/\s+/).reject(&:empty?).map(&:to_i) }}
def win?(card, drawn)
return true if card.any? {|row| row.all? {|c| drawn.include?(c) }}
return true if card.transpose.any? {|col| col.all? {|c| drawn.include?(c) }}
# return true if (0..4).all? {|x| drawn.include?(card.fetch(x).fetch(x)) }
# return true if (0..4).all? {|x| drawn.include?(card.fetch(x).fetch(4-x)) }
return false
end
(0..numbers.length).each do |i|
drawn = numbers[0..i]
# winning_card = cards.find {|c| win?(c, drawn) }
# if winning_card
# p winning_card.flatten.reject {|x| drawn.include?(x) }.sum * drawn.last
# exit
# end
if cards.length == 1 && winning_card = cards.find {|c| win?(c, drawn) }
p winning_card.flatten.reject {|x| drawn.include?(x) }.sum * drawn.last
exit
else
cards = cards.reject {|c| win?(c, drawn) }
end
end

@ -0,0 +1,29 @@
vents = ARGF.read.split("\n").map {|l| l.split(" -> ").map {|x| x.split(?,).map(&:to_i) }}
straights = vents.select {|(x1,y1),(x2,y2)| x1 == x2 || y1 == y2 }
points = Hash.new(0)
straights.each do |(x1,y1),(x2,y2)|
x = [x1, x2].minmax
y = [y1, y2].minmax
(x[0]..x[1]).each do |x|
(y[0]..y[1]).each do |y|
points[[x,y]] += 1
end
end
end
diagonals = vents - straights
diagonals.each do |(x1,y1),(x2,y2)|
if x1 > x2
x1,x2 = x2,x1
y1,y2 = y2,y1
end
sign = (y1 < y2) ? 1 : -1
(x1..x2).each.with_index do |x,i|
delta = i * sign
points[[x,y1+delta]] += 1
end
end
p points.count {|_,v| v > 1 }

@ -0,0 +1,22 @@
ages = ARGF.read.split(?,).map(&:to_i)
# 80.times do
# new_fish = 0
# ages.map! {|age|
# if age.zero?
# new_fish += 1
# 6
# else
# age - 1
# end
# }
# ages.concat(Array.new(new_fish) { 8 })
# end
# p ages.count
DURATION = 256
DESCENDANTS = Hash.new {|h,k|
children = (k...DURATION).step(7)
h[k] = children.count + children.map {|d| d + 9 }.select {|d| d < DURATION }.sum {|d| h[d] }
}
p ages.count + ages.sum {|age| DESCENDANTS[age] }

@ -0,0 +1,9 @@
positions = ARGF.read.split(?,).map(&:to_i)
min, max = positions.minmax
pos = (min..max).min_by {|i|
# positions.sum {|p| (p - i).abs }
positions.sum {|p| n = (p - i).abs; (n * (n + 1)) / 2 }
}
# p positions.sum {|p| (p - pos).abs }
p positions.sum {|p| n = (p - pos).abs; (n * (n + 1)) / 2 }

@ -0,0 +1,38 @@
include "globals.mzn";
enum Signals = { A, B, C, D, E, F, G };
set of Signals: Zero = { A, B, C, E, F, G };
set of Signals: One = { C, F };
set of Signals: Two = { A, C, D, E, G };
set of Signals: Three = { A, C, D, F, G };
set of Signals: Four = { B, C, D, F };
set of Signals: Five = { A, B, D, F, G };
set of Signals: Six = { A, B, D, E, F, G };
set of Signals: Seven = { A, C, F };
set of Signals: Eight = { A, B, C, D, E, F, G };
set of Signals: Nine = { A, B, C, D, F, G };
array[1..10] of set of Signals: AllSignals = [ Zero, One, Two, Three, Four, Five, Six, Seven, Eight, Nine ];
array[1..10] of set of Signals: Patterns;
% Patterns = [
% { A, C, E, D, G, F, B },
% { C, D, F, B, E },
% { G, C, D, F, A },
% { F, B, C, A, D },
% { D, A, B },
% { C, E, F, A, B, D },
% { C, D, F, G, E, B },
% { E, A, F, B },
% { C, A, G, E, D, B },
% { A, B },
% ];
array [Signals] of var Signals: Map;
constraint alldifferent(Map);
constraint forall(pattern in [ { Map[x] | x in pattern } | pattern in Patterns])(
exists(digit in AllSignals)(pattern = digit)
);
output [show(Map)];

@ -0,0 +1,51 @@
require "set"
input = ARGF.read.split("\n").map {|x| x.split(/\s+\|\s+/).map {|x| x.split(/\s+/) } }
# output = input.map(&:last)
# p output.flatten.count {|x| [2, 4, 3, 7].include?(x.length) }
MAP = {
%w[ a b c e f g ] => 0,
%w[ c f ] => 1,
%w[ a c d e g ] => 2,
%w[ a c d f g ] => 3,
%w[ b c d f ] => 4,
%w[ a b d f g ] => 5,
%w[ a b d e f g ] => 6,
%w[ a c f ] => 7,
%w[ a b c d e f g ] => 8,
%w[ a b c d f g ] => 9,
# 8 6 8 7 4 9 7
}.transform_keys(&:to_set)
# # My original solution to part two
# def solve(signals, output)
# all = signals + output
# one = all.find {|x| x.length == 2 }
# four = all.find {|x| x.length == 4 }
# seven = all.find {|x| x.length == 3 }
# eight = all.find {|x| x.length == 7 }
# b = (?a..?g).find {|x| signals.count {|s| s.include?(x) } == 6 }
# e = (?a..?g).find {|x| signals.count {|s| s.include?(x) } == 4 }
# f = (?a..?g).find {|x| signals.count {|s| s.include?(x) } == 9 }
# a = (seven.chars - one.chars)[0]
# c = (one.chars - [f])[0]
# d = (four.chars - [b, c, f])[0]
# g = (eight.chars - [a, b, c, d, e, f])[0]
# map = { a: a, b: b, c: c, d: d, e: e, f: f, g: g }.invert
# output.map {|x| MAP.fetch(x.chars.map {|c| map.fetch(c).to_s }.to_set) }.join.to_i
# end
# Here it is with a solver, but much, much slower!
def solve(signals, output)
data = "Patterns = [ #{signals.map { "{ #{_1.upcase.chars.join(" ,")} }" }.join(", ")} ]"
solution = `minizinc --cmdline-data "#{data}" day_08.mzn`.scan(/[A-G]/)
map = (?a..?g).zip(solution.map(&:downcase)).to_h
output.map {|x| MAP.fetch(x.chars.map {|c| map.fetch(c).to_s }.to_set) }.join.to_i
end
p input.sum {|x| solve(*x) }

@ -0,0 +1,31 @@
require "set"
INPUT = ARGF.read.split("\n").map {|l| l.chars.map(&:to_i) }
NEIGHBORS = [[0,-1], [-1, 0], [1, 0], [0, 1]]
def neighbors(y,x)
NEIGHBORS
.map {|dy,dx| [y+dy, x+dx] }
.select {|y,x| (0...INPUT.size).cover?(y) && (0...INPUT[0].size).cover?(x) }
end
all = (0...INPUT.size).flat_map {|y| (0...INPUT[0].size).map {|x| [y, x]}}
lows = all.select {|y,x| neighbors(y,x).all? {|yy,xx| INPUT[yy][xx] > INPUT[y][x] }}
# p lows.sum {|y,x| INPUT[y][x] + 1 }
def fill_basin(low)
basin = Set.new([low])
stack = [low]
until stack.empty?
y,x = stack.shift
new_neighbors = neighbors(y,x).reject {|y,x| basin.include?([y,x]) || INPUT[y][x] == 9 }
stack.concat(new_neighbors)
basin.merge(new_neighbors)
end
basin
end
p lows.map { fill_basin(_1) }.map(&:size).sort[-3, 3].inject(:*)

@ -0,0 +1,51 @@
input = ARGF.read.split("\n")
COMPLEMENTS = %w[ () [] {} <> ].map(&:chars).to_h
OPENING_REGEXP = Regexp.new("[#{Regexp.escape(COMPLEMENTS.keys.join)}]")
CLOSING_REGEXP = Regexp.new("[#{Regexp.escape(COMPLEMENTS.values.join)}]")
def parse(line)
stack = []
s = line.chars
until s.empty?
case char = s.shift
when OPENING_REGEXP
stack << char
when CLOSING_REGEXP
return { err: char } unless stack.pop == COMPLEMENTS.invert.fetch(char)
end
end
{ ok: stack }
end
# points = {
# ?) => 3,
# ?] => 57,
# ?} => 1197,
# ?> => 25137,
# }
# p input.sum {|line|
# case parse(line)
# in { ok: } then 0
# in { err: } then points.fetch(err)
# else fail
# end
# }
def score(closing) = closing
.map { COMPLEMENTS.values.index(_1) + 1 }
.inject(0) {|n,i| n*5 + i }
scores = input
.filter_map {|line|
case parse(line)
in { ok: } then ok
in { err: } then nil
else fail
end
}
.map {|remaining| remaining.reverse.map { COMPLEMENTS.fetch(_1) }}
.map { score(_1) }
p scores.sort.fetch(scores.length / 2)

@ -0,0 +1,36 @@
input = ARGF.read.split("\n").map { _1.chars.map(&:to_i) }
ys = (0...input.size)
xs = (0...input.fetch(0).size)
coords = ys.flat_map {|y| xs.map {|x| [y,x] }}
octopuses = coords.to_h {|y,x| [[y,x], input.fetch(y).fetch(x)] }
deltas = (-1..1).flat_map {|dy| (-1..1).map {|dx| [dy, dx] }}.reject { _1 == [0, 0] }
neighbors = ->(y, x) {
deltas
.map {|dy,dx| [y+dy, x+dx] }
.select {|y,x| ys.cover?(y) && xs.cover?(x) }
}
# flashes = 0
# 100.times do
(1..).each do |i|
octopuses.transform_values! { _1 + 1 }
until (flashing = octopuses.select { _2 == 10 }).empty?
flashing.each do |(y,x),_|
octopuses[[y,x]] += 1
neighbors.(y,x)
.select {|y,x| octopuses.fetch([y,x]) < 10 }
.each do |y,x|
octopuses[[y,x]] += 1
end
end
end
if octopuses.values.all? { _1 > 9 }
puts i
exit
end
# flashes += octopuses.count { _2 > 9 }
octopuses.transform_values! { _1 > 10 ? 0 : _1 }
end
# p flashes

@ -0,0 +1,25 @@
cave = Hash.new {|h,k| h[k] = [] }
ARGF.read.scan(/(\w+)-(\w+)/).each do
cave[_1] << _2
cave[_2] << _1
end
paths = [ %w[start] ]
loop do
closed, open = paths.partition { _1.last == "end" }
break if open.empty?
paths = closed + open.flat_map {|path|
cave.fetch(path.last)
# .reject { _1 =~ /^[a-z]+$/ && path.include?(_1) }
.reject { _1 == "start" }
.reject {|cave|
smalls = path.tally.select { _1 =~ /^[a-z]+$/ }
smalls.fetch(cave, 0) > (smalls.any? { _2 > 1 } ? 0 : 1)
}
.map { path + [_1] }
}
end
p paths.count

@ -0,0 +1,18 @@
dots, folds = ARGF.read.split("\n\n")
dots = dots.scan(/(\d+),(\d+)/).map { _1.map(&:to_i) }
folds = folds.scan(/(x|y)=(\d+)/).map { [_1, _2.to_i] }
dirs = { ?x => 0, ?y => 1 }
folds.each do |dir, axis|
index = dirs.fetch(dir)
dots.select { _1[index] > axis }.each do |dot|
dot[index] = axis - (dot[index] - axis)
end
dots.uniq!
# p dots.size or exit
end
xx = Range.new(*dots.map(&:first).minmax)
yy = Range.new(*dots.map(&:last).minmax)
puts yy.map {|y| xx.map {|x| dots.include?([x,y]) ? "" : " " }.join }.join("\n")

@ -0,0 +1,41 @@
template, rules = ARGF.read.split("\n\n")
template = template.chars
rules = rules.scan(/(\w{2}) -> (\w)/).to_h
# polymer = template
# 10.times do
# polymer = polymer.each_cons(2).flat_map {|a,b|
# [a, rules.fetch("#{a}#{b}")]
# } << polymer.last
# end
# min, max = polymer.tally.values.minmax
# p max - min
tally = Hash.new {|h,k|
polymer, steps = k
new_elements = polymer.each_cons(2).map(&:join).map { rules.fetch(_1) }
h[k] = case steps
when 1
(polymer + new_elements).tally
when (2..)
initial = new_elements.tally.transform_values { -_1 }
polymer.zip(new_elements)
.flatten[0..-2]
.each_cons(2)
.map { h[[_1, steps-1]] }
.inject(initial) {|final,tally| final.merge(tally) { _2 + _3 } }
else
fail
end
}
final = tally[[template, 40]]
# correct for internal elements being double-counted
template[1..-2].each do
final[_1] -= 1
end
min, max = final.values.minmax
p max - min

@ -0,0 +1,38 @@
require "set"
cavern = ARGF.read.split("\n").map { _1.chars.map(&:to_i) }
cavern = (0..4).flat_map {|i| cavern.map {|row|
row.map { (_1 + i - 1) % 9 + 1 }
}}
cavern = cavern.map {|row| (0..4).flat_map {|i|
row.map { (_1 + i - 1) % 9 + 1 }
}}
cavern = cavern
.flat_map.with_index {|row,y| row.map.with_index {|risk,x| [[y,x], risk] }}
.to_h
bottom_right = cavern.keys.max
risks = Hash.new(0)
risks[[0,0]] = 0
edges = Set[[0,0]]
until risks.has_key?(bottom_right)
yx = edges.min_by { risks.fetch(_1) }
edges.delete(yx)
y,x = yx
neighbors = [[-1, 0], [1, 0], [0, 1], [0, -1]]
.map {|dy,dx| [y+dy, x+dx] }
.select { cavern.has_key?(_1) }
.reject { risks.has_key?(_1) }
risk = risks.fetch(yx)
neighbors.each do
risks[_1] = risk + cavern.fetch(_1)
end
edges.merge(neighbors)
end
p risks[bottom_right]

@ -0,0 +1,79 @@
require "strscan"
Packet = Struct.new(:version, :type_id, :content) do
include Enumerable
def self.parse(ss)
version = ss.scan(/.{3}/).to_i(2)
type_id = ss.scan(/.{3}/).to_i(2)
case type_id
when 4 # literal value
value = ss.scan(/(1.{4})*(0.{4})/).chars
.each_slice(5).flat_map { _1[1..4] }.join
.to_i(2)
Literal.new(version, type_id, value)
else # operator
sub_packets = case
when ss.scan(/0(.{15})/)
length = ss.captures[0].to_i(2)
sub_packet = ss.scan(/.{#{length}}/)
sss = StringScanner.new(sub_packet)
sub_packets = []
until sss.eos?
sub_packets << parse(sss)
end
sub_packets
when ss.scan(/1(.{11})/)
n = ss.captures[0].to_i(2)
n.times.map { parse(ss) }
else
fail
end
Operator.new(version, type_id, sub_packets)
end
end
def each
return enum_for(__method__) unless block_given?
yield self
end
end
class Literal < Packet
def value = content
end
class Operator < Packet
def each(&block)
super
content.each do |sub_packet|
sub_packet.each(&block)
end
end
def value
values = content.map(&:value)
case type_id
when 0 then values.sum
when 1 then values.inject(:*)
when 2 then values.min
when 3 then values.max
when 4 then fail
when 5 then values.inject(:>) ? 1 : 0
when 6 then values.inject(:<) ? 1 : 0
when 7 then values.inject(:==) ? 1 : 0
else fail
end
end
end
message = ARGF.read.chomp.chars.map { _1.to_i(16).to_s(2).rjust(4, ?0) }.join
ss = StringScanner.new(message)
packet = Packet.parse(ss)
p packet.sum(&:version)
p packet.value

@ -0,0 +1,29 @@
def fire(v, target)
return enum_for(__method__, v, target) unless block_given?
pos = [0,0]
v_x, v_y = v
loop do
yield pos
return if target.zip(pos).all? { _1.cover?(_2) }
pos = pos.zip([v_x, v_y]).map { _1.sum }
v_x -= 1 if v_x > 0
v_y -= 1
return if pos[0] > target[0].end
return if pos[1] < target[1].begin
end
end
input = ARGF.read.scan(/x=(.+), y=(.+)/)
target = input[0].map { eval(_1) }
xs = (0..target[0].end).select { (1.._1).sum > target[0].begin }
haystack = xs.flat_map {|x| (-256..256).map {|y| [x, y] }}
haystack.select! {|v| fire(v, target).each.any? {|pos| target.zip(pos).all? { _1.cover?(_2) }}}
# p haystack.map {|v| fire(v, target).each.map { _2 }.max }.max
p haystack.count

@ -0,0 +1,75 @@
require "strscan"
def add(a, b)
reduced("[#{a},#{b}]")
end
def reduced(s)
last_s = ""
until s == last_s
last_s = s
to_explode = find_nested(s)
if to_explode
s = explode(s, to_explode)
next
end
s = s.sub(/[1-9]\d+/) {|n|
half = n.to_i / 2.0
pair = [half.floor, half.ceil]
"[#{pair.join(?,)}]"
}
end
s
end
def find_nested(s)
ss = StringScanner.new(s)
depth = 0
until ss.eos?
case
when ss.scan(/\[/)
if depth == 4
a = ss.pos-1
ss.scan(/\d+,\d+\]/)
b = ss.pos-1
return [a, b]
end
depth += 1
when ss.scan(/\]/)
depth -= 1
when ss.scan(/\d+|,/)
# no-op
else
fail
end
end
nil
end
def explode(s, pair_range)
a, b = pair_range
pair = s[a..b].scan(/\d+/).map(&:to_i)
[
s[0...a].reverse.sub(/\d+/) { (_1.reverse.to_i + pair[0]).to_s.reverse }.reverse,
0,
s[b+1..].sub(/(\d+)/) { _1.to_i + pair[1] },
].join
end
class Array
def magnitude = 3*self[0].magnitude + 2*self[1].magnitude
end
class Integer
def magnitude = self
end
# sum = ARGF.read.split("\n").reject(&:empty?).inject {|sum,num| add(sum, num) }
# p eval(sum).magnitude
p ARGF.read.split("\n").reject(&:empty?).permutation(2).map { eval(add(*_1)).magnitude }.max

@ -0,0 +1,52 @@
require "matrix"
require "set"
scanners = ARGF.read.strip.split("\n\n").to_h {|scanner|
id, *rest = scanner.split("\n")
id = id.scan(/\d+/)[0].to_i
coords = rest.map { _1.split(?,).map(&:to_i) }
[id, coords.map { Matrix.column_vector(_1) }]
}
first_scanner = scanners.shift
origin_beacon = first_scanner[1].first
origin_beacon = Matrix.column_vector([-618,-824,-621])
known_scanners = {
first_scanner[0] => [ origin_beacon.map { -_1 }, Matrix.identity(3) ],
}
known_beacons = Set.new(first_scanner[1].map {|beacon| beacon - origin_beacon })
rot_x = Matrix[ [1, 0, 0], [0, 0, -1], [0, 1, 0] ]
rot_y = Matrix[ [0, 0, 1], [0, 1, 0], [-1, 0, 0] ]
rot_z = Matrix[ [0, -1, 0], [1, 0, 0], [0, 0, 1] ]
id = Matrix.identity(3)
ROTATIONS = Set.new(
Array.new(4) { rot_x ** _1 }.flat_map {|x|
Array.new(4) { rot_y ** _1 }.flat_map {|y|
Array.new(4) { rot_z ** _1 }.map {|z| x * y * z }}}
)
def find_overlapping_scanner(known_beacons, scanners)
scanners.filter_map {|id, beacons|
haystack = ROTATIONS.flat_map {|r| beacons.map {|b| [ r*b, r ] }}
# haystack.select { _2 == Matrix.identity(3) }.map(&:first).each { p _1 }
haystack.find {|position, rotation|
translated_beacons = beacons.map { (rotation * _1) - position }
(known_beacons & translated_beacons).size >= 12
}&.then {|p,o| [id, p, o] }
}.first
end
until scanners.empty?
id, position, orientation = find_overlapping_scanner(known_beacons, scanners)
p [id, position, orientation]
known_scanners[id] = [position, orientation]
translated_beacons = scanners[id].map {|b| b.zip(position).map { _2 - _1 }.zip(orientation).map { _1 * _2 }}
known_beacons.merge(translated_beacons)
scanners.delete(id)
end

@ -0,0 +1,50 @@
algorithm, image = ARGF.read.strip.split("\n\n")
algorithm = algorithm.delete("\n") # for the example
algorithm = algorithm.chars.map.with_index { [_2, _1 == ?#] }.to_h
image = image.split("\n").flat_map.with_index {|row, y|
row.chars.map.with_index {|pixel, x| [[y, x], pixel == ?#] }
}.to_h
image.default = false
def each(image)
return enum_for(__method__, image) unless block_given?
ys = image.keys.map(&:first).minmax
xs = image.keys.map(&:last).minmax
(ys[0]-1..ys[1]+1).each do |y|
(xs[0]-1..xs[1]+1).each do |x|
yield [y, x]
end
end
end
def debug(image)
ys = image.keys.map(&:first).minmax
xs = image.keys.map(&:last).minmax
puts (ys[0]-1..ys[1]+1).map {|y|
(xs[0]-1..xs[1]+1).map {|x|
image[[y,x]] ? ?# : ?.
}.join
}.join("\n")
end
50.times {
ys = image.keys.map(&:first).minmax
xs = image.keys.map(&:last).minmax
prev_default = image.default
image = each(image).to_h {|y,x|
area = (-1..1).flat_map {|dy| (-1..1).map {|dx| image[[y+dy, x+dx]] }}
index = area.map { _1 ? 1 : 0 }.join.to_i(2)
pixel = algorithm.fetch(index)
[[y,x], pixel]
}
image.default = prev_default ? algorithm.fetch(511) : algorithm.fetch(0)
}
p image.count { _2 }

@ -0,0 +1,76 @@
# Player = Struct.new(:space, :score)
# one = Player.new(7, 0)
# two = Player.new(3, 0)
# class Die
# def initialize
# @value = 0
# @rolls = 0
# end
# attr_reader :rolls
# def roll
# value = @value
# @value += 1
# @value %= 100
# @rolls += 1
# value
# end
# end
# die = Die.new
# loop do
# one.space += 3.times.sum { die.roll + 1 }
# one.space %= 10
# one.score += one.space + 1
# break if one.score >= 1000
# two.space += 3.times.sum { die.roll + 1 }
# two.space %= 10
# two.score += two.space + 1
# break if two.score >= 1000
# end
# p [one, two].map(&:score).min * die.rolls
ROLLS = (1..3).flat_map {|a| (1..3).flat_map {|b| (1..3).map {|c|
[a, b, c].sum
}}}.tally
Player = Struct.new(:score, :space, keyword_init: true)
wins = Hash.new {|h,k|
one, two = k
multiverse = ROLLS.map {|delta,n|
space = (one.space + delta) % 10
[Player.new(score: one.score + space + 1, space: space), n]
}
one_wins, one_ongoing = multiverse.partition {|player,_| player.score >= 21 }
one_wins = one_wins.sum(&:last)
multiverse = ROLLS.map {|delta,n|
space = (two.space + delta) % 10
[Player.new(score: two.score + space + 1, space: space), n]
}
wins = one_ongoing.flat_map {|one, n_one| multiverse.map {|two, n_two|
n = n_one * n_two
if two.score >= 21
{ one: 0, two: n }
else
h[[one, two]].map { [_1, _2 * n] }.to_h
end
}}
wins = wins.inject({one: 0, two: 0}) {|acc,wins| acc.merge(wins) { _2 + _3 }}
h[k] = {
one: one_wins + wins.fetch(:one),
two: wins.fetch(:two),
}
}
# p wins[[Player.new(score: 0, space: 3), Player.new(score: 0, space: 7)]]
p wins[[Player.new(score: 0, space: 7), Player.new(score: 0, space: 3)]].values.max

@ -0,0 +1,109 @@
require "set"
steps = ARGF.read.scan(/(on|off) x=(.+),y=(.+),z=(.+)/)
.map {|power, *ranges| [power == "on", *ranges.map { eval(_1) }] }
# .select {|_, *ranges| ranges.all? { _1.begin >= -50 && _1.end <= 50 }}
# reactor = Hash.new(false)
# steps.each do |power,x,y,z|
# x.each do |x|
# y.each do |y|
# z.each do |z|
# reactor[[x,y,z]] = power
# end
# end
# end
# end
# p reactor.count { _2 }
# xs = steps.flat_map { [_2.begin, _2.end] }.minmax
# ys = steps.flat_map { [_3.begin, _3.end] }.minmax
# zs = steps.flat_map { [_4.begin, _4.end] }.minmax
# ons = Range.new(*xs).sum {|x| Range.new(*ys).sum {|y| Range.new(*zs).count {|z|
# step = steps.find { _2.cover?(x) && _3.cover?(y) && _4.cover?(z) }
# step ? step[0] : false
# }}}
# p ons
class Range
def overlap(other)
if cover?(other.begin)
min = other.begin
max = [self.end, other.end].min
(min..max)
elsif cover?(other.end)
min = [self.begin, other.begin].max
max = other.end
(min..max)
elsif other.cover?(self.begin)
min = self.begin
max = [self.end, other.end].min
(min..max)
elsif other.cover?(self.end)
min = [self.begin, other.begin].max
max = self.end
(min..max)
else
nil
end
end
def split(other)
overlap = self.overlap(other)
return [] if overlap.nil?
splits = [ overlap ]
splits << (self.begin..overlap.begin-1) if overlap.begin > self.begin
splits << (overlap.end+1..self.end) if overlap.end < self.end
splits
end
end
Cube = Struct.new(:xs, :ys, :zs) do
def -(other)
return self unless o = overlap(other)
xxs = xs.split(other.xs)
yys = ys.split(other.ys)
zzs = zs.split(other.zs)
cuboids = xxs.flat_map {|x| yys.flat_map {|y| zzs.map {|z|
Cube.new(x, y, z)
}}}
cuboids.delete(o)
cuboids
end
def overlap(other)
overlaps = to_a.zip(other.to_a).map { _1.overlap(_2) }
return nil if overlaps.any?(&:nil?)
Cube.new(*overlaps)
end
def overlap?(other) = !overlap(other).nil?
def volume = (xs.end - xs.begin + 1) * (ys.end - ys.begin + 1) * (zs.end - zs.begin + 1)
def to_s = "[#{[xs, ys, zs].map(&:to_s).join(", ")}]"
alias_method :inspect, :to_s
end
steps = steps.map {|power, *ranges| [power, Cube.new(*ranges)] }
reactor = Set.new
steps.each do |power, cube|
reactor
.select { _1.overlap?(cube) }
.each do |overlap|
reactor.delete(overlap)
reactor.merge(overlap - cube)
end
reactor << cube if power
end
p reactor.sum(&:volume)

@ -0,0 +1,35 @@
#############
#...........#
###B#C#B#D###
#A#D#C#A#
#########
#############
#...........#
###D#D#A#A###
#C#C#B#B#
#########
State = Struct.new(:spaces, :energy) do
ENERGY = { A: 1, B: 10, C: 100, D: 1000 }.transform_keys(&:to_s)
ROOMS = [2, 4, 6, 8]
def rooms = ROOMS.to_h { [_1, spaces.fetch(_1)] }
def valid_moves
end
end
spaces = Array.new(11) { [] }
# input = "DC DC AB AB"
input = "BA CD BC DA"
input.split(" ").map(&:chars).each.with_index do |amphipods, i|
spaces[(i+1) * 2] = amphipods
end
start = State.new(spaces, 0)
p start
p start.rooms
p start.valid_moves

@ -0,0 +1,58 @@
INSTRUCTIONS = ARGF.read.split("\n").map { _1.split(/\s+/) }
# INSTRUCTIONS.each do |instruction, *args|
# a, b = *args
# case instruction
# when "inp"
# puts "#{a} = input.shift"
# when "add"
# puts "#{a} += #{b}"
# when "mul"
# puts "#{a} *= #{b}"
# when "div"
# puts "#{a} = (#{a} / #{b}.to_f).floor"
# when "mod"
# puts "#{a} %= #{b}"
# when "eql"
# puts "#{a} = #{a} == #{b} ? 1 : 0"
# else
# fail
# end
# end
# exit
VARS = %w[ w x y z ]
def run(input)
vars = Hash.new(0)
INSTRUCTIONS.each do |instruction, *args|
a, b = *args
b = VARS.include?(b) ? vars[b] : b.to_i
case instruction
when "inp"
vars[a] = input.shift
when "add"
vars[a] += b
when "mul"
vars[a] *= b
when "div"
vars[a] = (vars[a] / b.to_f).floor
when "mod"
vars[a] %= b
when "eql"
vars[a] = vars[a] == b ? 1 : 0
else
fail
end
end
vars
end
99999999999999.downto(11111111111111).lazy.map(&:to_s).reject { _1.include?(?0) }.each do |input|
vars = run(input.chars.map(&:to_i))
if vars[?z].zero?
puts input
exit
end
end

@ -0,0 +1,262 @@
def run(input)
w, x, y, z = 0, 0, 0, 0
# w = input.shift
# x = z % 26
# z = (z / 1.to_f).floor
# x += 13
# x = x == w ? 0 : 1
# y = 25 * x + 1 # either y = 26 or y = 1
# z *= y # 0
# # p [w, x, y, z]
# y = (w + 13) * x
# z += y
# # p [w, x, y, z]
# # puts
# w = input.shift
# x = z % 26
# z = (z / 1.to_f).floor
# x += 11
# x = x == w ? 0 : 1
# y = 25 * x + 1
# z *= y
# # p [w, x, y, z]
# y = (w + 10) * x
# z += y
# # p [w, x, y, z]
# # puts
# w = input.shift
# x = z % 26
# z = (z / 1.to_f).floor
# x += 15
# x = x == w ? 0 : 1
# y = (25 * x) + 1
# z *= y
# # p [w, x, y, z]
# y = (w + 5) * x
# z += y
# # p [w, x, y, z]
# # puts
# w = input.shift
# x = z % 26
# z = (z / 26.to_f).floor
# x += -11
# x = x == w ? 0 : 1
# y = (25 * x) + 1
# z *= y
# # p [w, x, y, z]
# y = (w + 14) * x
# z += y
# # p [w, x, y, z]
# # puts
# return [w, x, y, z]
# w = input.shift
# x = z % 26
# z = (z / 1.to_f).floor
# x += 14
# x = x == w ? 0 : 1
# y = 25 * x + 1
# z *= y
# # p [w, x, y, z]
# y = (w + 5) * x
# z += y
# # p [w, x, y, z]
# # puts
# # puts
# w = input.shift
# x = z % 26
# z = (z / 26.to_f).floor
# x += 0
# x = x == w ? 0 : 1
# y = 25 * x + 1
# z *= y
# # p [w, x, y, z]
# y = (w + 15) * x
# z += y
# # p [w, x, y, z]
# # puts
# return [w, x, y, z]
# w = input.shift
# x = z % 26
# z = (z / 1.to_f).floor
# x += 12
# x = x == w ? 0 : 1
# y = 25 * x + 1
# z *= y
# # p [w, x, y, z]
# y *= 0
# y += w
# y += 4
# y *= x
# z += y
# # p [w, x, y, z]
# w = input.shift
# x *= 0
# x += z
# x %= 26
# z = (z / 1.to_f).floor
# x += 12
# x = x == w ? 1 : 0
# x = x == 0 ? 1 : 0
# y *= 0
# y += 25
# y *= x
# y += 1
# z *= y
# # p [w, x, y, z]
# y *= 0
# y += w
# y += 11
# y *= x
# z += y
# # p [w, x, y, z]
# w = input.shift
# x *= 0
# x += z
# x %= 26
# z = (z / 1.to_f).floor
# x += 14
# x = x == w ? 1 : 0
# x = x == 0 ? 1 : 0
# y *= 0
# y += 25
# y *= x
# y += 1
# z *= y
# # p [w, x, y, z]
# y *= 0
# y += w
# y += 1
# y *= x
# z += y
# # p [w, x, y, z]
# # puts
# # puts
# w = input.shift
# x *= 0
# x += z
# x %= 26
# z = (z / 26.to_f).floor
# x += -6
# x = x == w ? 1 : 0
# x = x == 0 ? 1 : 0
# y *= 0
# y += 25
# y *= x
# y += 1
# z *= y
# # p [w, x, y, z]
# y *= 0
# y += w
# y += 15
# y *= x
# z += y
# # p [w, x, y, z]
# return [w, x, y, z]
# w = input.shift
# x *= 0
# x += z
# x %= 26
# z = (z / 26.to_f).floor
# x += -10
# x = x == w ? 1 : 0
# x = x == 0 ? 1 : 0
# y *= 0
# y += 25
# y *= x
# y += 1
# z *= y
# # p [w, x, y, z]
# y *= 0
# y += w
# y += 12
# y *= x
# z += y
# # p [w, x, y, z]
# return [w, x, y, z]
w = input.shift
x *= 0
x += z
x %= 26
z = (z / 26.to_f).floor
x += -12
x = x == w ? 1 : 0
x = x == 0 ? 1 : 0
y *= 0
y += 25
y *= x
y += 1
z *= y
# p [w, x, y, z]
y *= 0
y += w
y += 8
y *= x
z += y
# p [w, x, y, z]
return [w, x, y, z]
w = input.shift
x = z % 26
z = (z / 26.to_f).floor
x += -3
x = x == w ? 0 : 1
y = 25 * x + 1
z *= y
# p [w, x, y, z]
y = (w + 14) * x
z += y
# p [w, x, y, z]
w = input.shift
x = z % 26 # z - 5 must be w
z = (z / 26.to_f).floor # z must be < 26
x += -5 # w must be x - 5
x = x == w ? 0 : 1 # x must be w
y = 25 * x + 1
z *= y # z must be 0
# p [w, x, y, z]
y = (w + 9) * x # x must be 0
z += y # y must be 0
[w, x, y, z]
end
# 99999999999999.downto(11111111111111).lazy.map(&:to_s).reject { _1.include?(?0) }.each do |input|
vars = run(input.chars.map(&:to_i))
p [input, vars[3]] if vars[3] < 400
if vars[3].zero?
puts input
exit
end
end

1
2022/.gitignore vendored

@ -0,0 +1 @@
day_*.txt

@ -0,0 +1,4 @@
Split {𝕩˜(-˜+`׬)0=¨𝕩}
ParseInt 10×+˜´-'0'
in ParseInt¨ ¨Split •Flines "../day_01.txt"
•Out¨ ,+´3 {𝕎𝕩}¨ <+´¨in

@ -0,0 +1,8 @@
Split {𝕩˜(-˜+`׬)0=¨𝕩}
Transpose ={<𝕨𝕨>𝕩}
OnlyCrates ('A'+26)/
RejectEmpty {((¨𝕩) > 0) / 𝕩}
stacks, moves Split •Flines "../day_05.txt"
stacks RejectEmpty OnlyCrates¨ Transpose stacks
•Show stacks

@ -0,0 +1,11 @@
# •Show 4 + ⊐⟜1 ⍷⊸≡¨ <˘ 4↕ •FChars "../day_06.txt"
# •Show 14 + ⊐⟜1 ⍷⊸≡¨ <˘ 14↕ •FChars "../day_06.txt"
n 4
input •FChars "../day_06.txt"
windows n input
uniq ˘ windows
index uniq 1
•Show n + index
# PktN←{𝕨+⊑1⊐˜(∧´∊)˘𝕨↕𝕩}

@ -0,0 +1 @@
Subproject commit b90e26c29b1742bf164b6121275b5e1ee8a56365

@ -0,0 +1,19 @@
(fn dbg [tbl]
(each [_ chunk (ipairs tbl)]
(print (accumulate [x "" _ i (ipairs chunk)]
(.. x ", " i)))))
(local input (accumulate [input [[]] line (io.lines :../day_01.txt)]
(do
(if (= (length line) 0)
(table.insert input [])
(table.insert (. input (length input)) (tonumber line)))
input)))
(fn sum [l]
(accumulate [sum 0 _ n (ipairs l)]
(+ sum n)))
(local l (icollect [_ l (ipairs input)] (sum l)))
(table.sort l)
(print (. l (length l)))

@ -0,0 +1,8 @@
# frozen_string_literal: true
source "https://rubygems.org"
gem "minitest"
gem "parslet"
gem "ruby-lsp"
gem "z3"

@ -0,0 +1,29 @@
GEM
remote: https://rubygems.org/
specs:
ffi (1.15.5)
language_server-protocol (3.17.0.2)
minitest (5.16.3)
parslet (2.0.0)
prettier_print (1.2.0)
ruby-lsp (0.3.7)
language_server-protocol (~> 3.17.0)
sorbet-runtime
syntax_tree (>= 4.0.2, < 5.0.0)
sorbet-runtime (0.5.10597)
syntax_tree (4.3.0)
prettier_print (>= 1.0.2)
z3 (0.0.20221020)
ffi (~> 1.9)
PLATFORMS
arm64-darwin-21
DEPENDENCIES
minitest
parslet
ruby-lsp
z3
BUNDLED WITH
2.3.18

@ -0,0 +1,2 @@
# p ARGF.read.split("\n\n").map { _1.each_line.map(&:to_i).sum }.max
p ARGF.read.split("\n\n").map { _1.each_line.map(&:to_i).sum }.sort[-3..-1].sum

@ -0,0 +1,14 @@
p ARGF.read.strip.lines(chomp: true).map(&:split).map {|a,b|
a = a.ord - ?A.ord
b = b.ord - ?X.ord
# part 2
b = (a + b - 1) % 3
outcome = case
when (a + 1) % 3 == b then 6
when a == b then 3
else 0
end
outcome + b + 1
}.sum

@ -0,0 +1,8 @@
priorities = (?a..?z).chain(?A..?Z).each.with_index.to_h { [_1, _2+1] }
input = ARGF.read.lines(chomp: true).map(&:chars)
# part 1
p input.sum { priorities.fetch(_1.each_slice(_1.length/2).inject(&:&)[0]) }
# part 2
p input.each_slice(3).sum { priorities.fetch(_1.inject(&:&)[0]) }

@ -0,0 +1,6 @@
p ARGF.read
.scan(/(\d+)-(\d+),(\d+)-(\d+)/)
.map { _1.map(&:to_i) }
.map {|a,b,c,d| [(a..b), (c..d)] }
# .count {|a,b| a.cover?(b) || b.cover?(a) } # part 1
.count {|a,b| a.minmax.any? { b.cover?(_1) } || b.minmax.any? { a.cover?(_1) }}

@ -0,0 +1,18 @@
setup, moves = ARGF.read.split("\n\n")
setup = setup
.lines(chomp: true)
.map(&:chars)
.transpose
.map {|col| col.select { _1 =~ /[A-Z]/ }}
.reject(&:empty?)
moves = moves.scan(/move (\d+) from (\d+) to (\d+)/).map { _1.map(&:to_i) }
moves.each do |n,from,to|
# n.times {
# setup[to-1].unshift(setup[from-1].shift)
# }
setup[to-1].unshift(*setup[from-1].shift(n))
end
p setup.map(&:first).join

@ -0,0 +1,2 @@
# p ARGF.read.chars.each_cons(4).with_index.find {|a,i| a.uniq.size == 4 }.last + 4
p ARGF.read.chars.each_cons(14).with_index.find {|a,i| a.uniq.size == 14 }.last + 14

@ -0,0 +1,61 @@
input = ARGF.read.lines(chomp: true)
Dir = Struct.new(:parent, :name, :children) do
def size = children.sum(&:size)
def each
return enum_for(__method__) unless block_given?
yield self
children.each do |child|
case child
when Dir
child.each { yield _1 }
when File
yield child
else
fail child.inspect
end
end
end
end
File = Struct.new(:parent, :name, :size)
root = Dir.new(nil, ?/, [])
pwd = root
input.each do |line|
case line
when /\$ cd \//
# no-op
when /\$ cd \.\./
pwd = pwd.parent
when /\$ cd (.+)/
pwd = pwd.children.find { _1.name == $1 }
when /\$ ls/
# no-op
when /dir (.+)/
pwd.children << Dir.new(pwd, $1, [])
when /(\d+) (.+)/
pwd.children << File.new(pwd, $2, $1.to_i)
else
fail line
end
end
# part 1
p root.each
.select { Dir === _1 }
.map(&:size)
.select { _1 < 100_000 }
.sum
# part 2
p root.each
.select { Dir === _1 }
.map(&:size)
.sort
.find { _1 >= 30_000_000 - (70_000_000 - root.size) }

@ -0,0 +1,34 @@
grid = ARGF.read.lines(chomp: true).map { _1.chars.map(&:to_i) }
def each(grid)
return enum_for(__method__, grid) unless block_given?
transposed = grid.transpose
grid.each.with_index do |row, y|
row.each.with_index do |tree, x|
col = transposed[x]
sight_lines = [
(0...x).map { row[_1] }.reverse,
(x+1...row.size).map { row[_1] },
(0...y).map { col[_1] }.reverse,
(y+1...row.size).map { col[_1] },
]
yield tree, sight_lines
end
end
end
p each(grid).count {|tree, sight_lines|
sight_lines.any? { _1.empty? || tree > _1.max }
}
p each(grid).map {|tree, sight_lines|
sight_lines
.map {|sl| sl.slice_after { _1 >= tree }.first }
.compact
.map(&:size)
.inject(:*)
}.max

@ -0,0 +1,44 @@
require "set"
motions = ARGF.read.scan(/([RLUD])\s+(\d+)/).map { [_1, _2.to_i] }
class Snake
def initialize
@knots = Array.new(10) { [0, 0] }
end
def tail = @knots.last
def move!(dir)
delta = case dir
when ?L then [ 0, -1]
when ?U then [ 1, 0]
when ?R then [ 0, 1]
when ?D then [-1, 0]
else fail dir.inspect
end
@knots[0] = @knots[0].zip(delta).map { _1 + _2 }
@knots = @knots[1..].inject([@knots[0]]) {|knots, tail|
head = knots.last
delta = head.zip(tail).map { _1 - _2 }
knots << if delta.any? { _1.abs > 1 }
tail.zip(delta.map { _1.clamp(-1, 1) }).map { _1 + _2 }
else
tail
end
}
end
end
snake = Snake.new
seen = Set.new
motions.each do |dir, distance|
distance.times do
snake.move!(dir)
seen << snake.tail
end
end
p seen.size

@ -0,0 +1,42 @@
instructions = ARGF.read.lines(chomp: true)
def exec(instructions)
return enum_for(__method__, instructions) unless block_given?
x = 1
instructions.each do |instruction|
case instruction
when /noop/
yield x
when /addx (-?\d+)/
yield x
yield x
x += $1.to_i
else
fail "invalid instruction: #{instruction}"
end
end
yield x
end
x_hist = exec(instructions).to_a
# part one
p 20.step(by: 40, to: 220).sum { x_hist[_1-1] * _1 }
# part two
puts x_hist.each_slice(40).map {|row|
row.each.with_index.map {|x, cycle|
(-1..1).cover?(cycle - x) ? ?# : ?.
}.join
}.join("\n")
# a functional version of part two, but I think
# the imperative version feels closer to the domain
#
# x_hist.each_slice(40) do |row|
# row.each.with_index do |x, cycle|
# putc (-1..1).cover?(cycle - x) ? ?# : ?.
# end
# puts
# end

@ -0,0 +1,48 @@
Monkey = Struct.new(:id, :items, :operation, :test, :t, :f) do
def throw_to(item)
(item % test).zero? ? t : f
end
end
MONKEY_RE = /Monkey (?<id>\d+):
Starting items: (?<items>(?~\n))
Operation: new = (?<op>(?~\n))
Test: divisible by (?<test>\d+)
If true: throw to monkey (?<t>\d+)
If false: throw to monkey (?<f>\d+)/m
monkeys = ARGF.read.split("\n\n").map {|monkey|
md = MONKEY_RE.match(monkey)
fail if md.nil?
Monkey.new(
md[:id].to_i,
md[:items].split(", ").map(&:to_i),
md[:op],
md[:test].to_i,
md[:t].to_i,
md[:f].to_i,
)
}
max_worry = monkeys.map(&:test).inject(:*)
inspections = Hash.new(0)
# 20.times do
10_000.times do
monkeys.each do |monkey|
until monkey.items.empty?
inspections[monkey.id] += 1
item = monkey.items.shift
old = item
item = eval(monkey.operation)
# item /= 3
item %= max_worry
to = monkey.throw_to(item)
monkeys[to].items << item
end
end
end
p inspections.values.max(2).inject(:*)

@ -0,0 +1,49 @@
class HeightMap
NEIGHBORS = [[0, -1], [-1, 0], [0, 1], [1, 0]]
def initialize(heights)
@heights = heights
end
def shortest(from:, to:, &cond)
frontier = [from]
visited = { from => 0 }
until frontier.empty? || to.any? { visited.has_key?(_1) }
current = frontier.shift
NEIGHBORS.each do |delta|
candidate = current.zip(delta).map { _1 + _2 }
next if visited.has_key?(candidate)
next unless cand_height = @heights[candidate]
next unless cond.(@heights.fetch(current), cand_height)
visited[candidate] = visited.fetch(current) + 1
frontier << candidate
end
frontier.sort_by { visited.fetch(_1) }
end
visited.find {|k,v| to.include?(k) }.last
end
end
heights = ARGF.read.lines(chomp: true).map(&:chars)
.flat_map.with_index {|row,y|
row.map.with_index {|height,x| [[y, x], height] }
}.to_h
s, e = heights.invert.values_at(?S, ?E)
heights[s] = ?a
heights[e] = ?z
hm = HeightMap.new(heights)
# part one
p hm.shortest(from: s, to: [e]) { _1.ord + 1 >= _2.ord }
# part two
as = heights.select { _2 == ?a }.map(&:first)
p hm.shortest(from: e, to: as) { _1.ord - 1 <= _2.ord }

@ -0,0 +1,37 @@
def compare(left, right)
case [left, right]
in [left, nil]
1
in [Integer, Integer]
left <=> right
in [Array, Array]
left.zip(right).each do |left, right|
case compare(left, right)
when -1 then return -1
when 0 # keep going
when 1 then return 1
end
end
(left.size == right.size) ? 0 : -1
else
compare(Array(left), Array(right))
end
end
# part one
pairs = ARGF.read.split("\n\n")
pairs = pairs.map {|pair| pair.lines(chomp: true).map { eval(_1) }}
p pairs.map.with_index
.select {|(l,r),_| compare(l, r) == -1 }
.sum { _1.last + 1 }
# part two
pairs = pairs.flatten(1)
dividers = [[[2]], [[6]]]
pairs.concat(dividers)
pairs = pairs.sort { compare(_1, _2) }
p dividers
.map { pairs.index(_1) + 1 }
.inject(:*)

@ -0,0 +1,52 @@
scan = ARGF.read.lines(chomp: true)
cave = scan.each.with_object({}) {|line, cave|
line.split(" -> ")
.map { _1.split(?,).map(&:to_i) }
.each_cons(2) {|(ax,ay),(bx,by)|
Range.new(*[ax, bx].sort).each do |x|
Range.new(*[ay, by].sort).each do |y|
cave[[x, y]] = ?#
end
end
}
}
def cave.to_s
x_min, x_max = keys.map(&:first).minmax
y_min, y_max = keys.map(&:last).minmax
(0..y_max+1).map {|y|
(x_min-1..x_max+1).map {|x|
self.fetch([x, y], ?.)
}.join
}.join("\n")
end
def pour_sand(cave, stop:)
return enum_for(__method__, cave, stop:) unless block_given?
loop do
# puts cave
pos = [500, 0]
while next_pos = [0, -1, 1].map {|dx| pos.zip([dx, 1]).map { _1 + _2 }}.find { cave[_1].nil? }
pos = next_pos
break if stop.(*pos)
end
break if stop.(*pos)
cave[pos] = ?o
yield pos
end
end
y_max = cave.keys.map(&:last).max
# part one
p pour_sand(cave, stop: ->(_, y) { y >= y_max }).count
# part two
cave.delete_if { _2 == ?o } # reset cave
cave.default_proc = ->(_,(_,y)) { y == y_max + 2 ? ?# : nil }
p pour_sand(cave, stop: ->(x, y) { [x, y] == [500, 0] }).count + 1

@ -0,0 +1,87 @@
require "set"
sensors_and_beacons = ARGF.read
.scan(/Sensor at x=(-?\d+), y=(-?\d+): closest beacon is at x=(-?\d+), y=(-?\d+)/)
.map { _1.map(&:to_i) }
.flatten
.each_slice(2)
# part one
row = 2_000_000
# row = 10
no_beacons = []
sensors_and_beacons.each_slice(2) do |sensor, beacon|
dist = sensor.zip(beacon).sum { (_1 - _2).abs }
dy = (row - sensor[1]).abs
next if dy > dist
dx = dist - dy
x_min, x_max = [sensor[0]-dx, sensor[0]+dx].sort
no_beacons << (x_min..x_max)
end
# remove covered ranges
no_beacons = no_beacons.reject {|x| (no_beacons - [x]).any? { _1.cover?(x) }}
# merge ranges
no_beacons = no_beacons.inject([no_beacons.shift]) {|no_beacons, range|
next no_beacons if no_beacons.any? { _1.cover?(range) }
if overlap = no_beacons.find { _1.cover?(range.begin) }
range = (overlap.end + 1..range.end)
end
if overlap = no_beacons.find { _1.cover?(range.end) }
range = (range.begin..overlap.begin-1)
end
no_beacons << range
}
p no_beacons.sum(&:size) - sensors_and_beacons.to_a.select { _2 == row }.uniq.size
# part two
find_sab = ->(x, y) {
sensors_and_beacons.each_slice(2).find {|sensor, beacon|
dist = sensor.zip(beacon).sum { (_1 - _2).abs }
dist >= sensor.zip([x, y]).sum { (_1 - _2).abs }
}
}
max = 4_000_000
# max = 20
x = 0
y = 0
loop do
p y if (y % 10_000).zero?
sensor, _ = find_sab.(x, y)
dx = sensor[0] - x
if dx >= max / 2
dy = sensor[1] - y
y += dy.positive? ? 2 * dy + 1 : 1
end
loop do
sensor, beacon = find_sab.(x, y)
if sensor.nil?
p 4_000_000 * x + y
exit
end
dist = sensor.zip(beacon).sum { (_1 - _2).abs }
dy = (sensor[1] - y).abs
dx = (dist - dy).abs
x = sensor[0] + dx + 1
if x > max
x = 0
break
end
end
y += 1
break if y > max
end

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save