Compare commits

..

No commits in common. 'main' and 'sorbet' have entirely different histories.
main ... sorbet

3
.gitmodules vendored

@ -1,3 +0,0 @@
[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 (7.0.3)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 1.6, < 2)
minitest (>= 5.1)
tzinfo (~> 2.0)
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)
awesome_print (1.6.1)
coderay (1.1.0)
colorize (0.7.7)
concurrent-ruby (1.1.10)
i18n (1.10.0)
concurrent-ruby (~> 1.0)
i18n (0.7.0)
json (1.8.3)
letters (0.4.1)
activesupport
awesome_print
@ -24,8 +24,9 @@ GEM
method_source (~> 0.8.1)
slop (~> 3.4)
slop (3.6.0)
tzinfo (2.0.4)
concurrent-ruby (~> 1.0)
thread_safe (0.3.5)
tzinfo (1.2.2)
thread_safe (~> 0.1)
xml-simple (1.1.5)
PLATFORMS

107
2015/rust/Cargo.lock generated

@ -1,145 +1,146 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[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)",
]
[[package]]
name = "advapi32-sys"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "307c92332867e586720c0222ee9d890bbe8431711efed8a1b06bc5b40fc66bd7"
dependencies = [
"winapi",
"winapi-build",
]
[[package]]
name = "advent_of_code"
version = "0.1.0"
dependencies = [
"permutohedron",
"regex",
"rust-crypto",
"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)",
]
[[package]]
name = "aho-corasick"
version = "0.7.18"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
dependencies = [
"memchr",
"memchr 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "gcc"
version = "0.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca10e3e1f1c8278047da19b94dc17c4397861150d5fbcea052eedb1d9847d356"
dependencies = [
"advapi32-sys",
"winapi",
"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)",
]
[[package]]
name = "kernel32-sys"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5b5e7edf375e6d26243bde172f1d5ed1446f4a766fc9b7006e1fd27258243f1"
dependencies = [
"winapi",
"winapi-build",
"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)",
]
[[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 = "2.5.0"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
dependencies = [
"libc 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[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",
"libc 0.2.4",
"winapi",
"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)",
]
[[package]]
name = "regex"
version = "1.5.5"
version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
"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)",
]
[[package]]
name = "regex-syntax"
version = "0.6.26"
version = "0.2.2"
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",
"libc 0.1.12",
"rand",
"rustc-serialize",
"time",
"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)",
]
[[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",
"libc 0.2.4",
"winapi",
"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)",
]
[[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"
checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
[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"

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

144
2016/rust/Cargo.lock generated

@ -1,173 +1,201 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
[root]
name = "advent_of_code_2016"
version = "0.1.0"
dependencies = [
"error-chain",
"regex",
"rust-crypto",
"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)",
]
[[package]]
name = "aho-corasick"
version = "0.7.18"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
dependencies = [
"memchr",
"memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "backtrace"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f551bc2ddd53aea015d453ef0b635af89444afa5ed2405dd0b2062ad5d600d80"
dependencies = [
"backtrace-sys",
"cfg-if",
"dbghelp-sys",
"kernel32-sys",
"libc",
"rustc-demangle",
"winapi",
"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)",
]
[[package]]
name = "backtrace-sys"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3602e8d8c43336088a8505fa55cae2b3884a9be29440863a11528a42f46f6bb7"
dependencies = [
"gcc",
"libc",
"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)",
]
[[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",
"winapi-build",
"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)",
]
[[package]]
name = "error-chain"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1cd681735364a04cd5d69f01a4f6768e70473941f8d86d8c224faf6955a75799"
dependencies = [
"backtrace",
"backtrace 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[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",
"winapi-build",
"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)",
]
[[package]]
name = "libc"
version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a51822fc847e7a8101514d1d44e354ba2ffa7d4c194dcab48870740e327cac70"
[[package]]
name = "memchr"
version = "2.5.0"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
dependencies = [
"libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand"
version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "022e0636ec2519ddae48154b028864bdce4eaf7d35226ab8e65c611be97b189d"
dependencies = [
"libc",
"libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex"
version = "1.5.5"
version = "0.1.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
"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)",
]
[[package]]
name = "regex-syntax"
version = "0.6.26"
version = "0.3.9"
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",
"libc",
"rand",
"rustc-serialize",
"time",
"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)",
]
[[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"
checksum = "bff9fc1c79f2dec76b253273d07682e94a978bd8f132ded071188122b2af9818"
[[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)",
]
[[package]]
name = "time"
version = "0.1.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c7ec6d62a20df54e07ab3b78b9a3932972f4b7981de295563686849eb3989af"
dependencies = [
"kernel32-sys",
"libc",
"winapi",
"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)",
]
[[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"
checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
[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"

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

175
2018/rust/Cargo.lock generated

@ -1,205 +1,252 @@
# 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",
"pest",
"pest_derive",
"regex",
"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)",
]
[[package]]
name = "aho-corasick"
version = "0.7.18"
version = "0.6.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
dependencies = [
"memchr",
"memchr 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[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",
"byte-tools",
"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)",
]
[[package]]
name = "byte-tools"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40"
[[package]]
name = "cfg-if"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "digest"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03b072242a8cbaf9c145665af9d250c59af3b958f83ed6824e13533cf76d5b90"
dependencies = [
"generic-array",
"generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[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.1"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d00328cedcac5e81c683e5620ca6a30756fc23027ebf9bff405c0e8da1fbb7e"
dependencies = [
"typenum",
"typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "lazy_static"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1"
[[package]]
name = "libc"
version = "0.2.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "maplit"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08cbb6b4fef96b6d77bfc40ec491b1690c779e77b05cd9f07f787ed376fd4c43"
[[package]]
name = "memchr"
version = "2.5.0"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
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)",
]
[[package]]
name = "pest"
version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a677051ad923732bb5c70f2d45f8985a96e3eee2e2bff86697e3b11b0c3fcfde"
dependencies = [
"ucd-trie",
"ucd-trie 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "pest_derive"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b76f477146419bc539a63f4ef40e902166cb43b3e51cecc71d9136fd12c567e7"
dependencies = [
"pest",
"pest_generator",
"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)",
]
[[package]]
name = "pest_generator"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ebee4e9680be4fd162e6f3394ae4192a6b60b1e4d17d845e631f0c68d1a3386"
dependencies = [
"pest",
"pest_meta",
"proc-macro2",
"quote",
"syn",
"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)",
]
[[package]]
name = "pest_meta"
version = "2.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f6d5f6f0e6082578c86af197d780dc38328e3f768cec06aac9bc46d714e8221"
dependencies = [
"maplit",
"pest",
"sha-1",
"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)",
]
[[package]]
name = "proc-macro2"
version = "0.4.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77619697826f31a02ae974457af0b29b723e5619e113e9397b8b82c6bd253f09"
dependencies = [
"unicode-xid",
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "quote"
version = "0.6.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53fa22a1994bd0f9372d7a816207d8a2677ad0325b073f5c5332760f0fb62b5c"
dependencies = [
"proc-macro2",
"proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex"
version = "1.5.5"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
"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)",
]
[[package]]
name = "regex-syntax"
version = "0.6.26"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64"
dependencies = [
"ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "sha-1"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51b9d1f3b5de8a167ab06834a7c883bd197f2191e1dda1a22d9ccfeedbf9aded"
dependencies = [
"block-buffer",
"byte-tools",
"digest",
"fake-simd",
"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)",
]
[[package]]
name = "syn"
version = "0.14.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
"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)",
]
[[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"
checksum = "71a9c5b1fe77426cf144cc30e49e955270f5086e31a6441dfa8b32efc09b9d77"
[[package]]
name = "ucd-util"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unicode-xid"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
[[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"

@ -1,13 +0,0 @@
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,7 +1,5 @@
# typed: strict
require "stringio"
require "sorbet-runtime"
AnyIO = T.type_alias { T.any(IO, StringIO) }
@ -11,34 +9,20 @@ 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 => ->(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])
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])
class Parameter
extend T::Sig
@ -46,9 +30,12 @@ class Parameter
sig {params(value: T.any(Parameter, Integer)).returns(Parameter)}
def self.from(value)
case value
when Parameter then value
when Integer then new(Mode::Position, value)
else T.absurd(value)
when Parameter
value
when Integer
new(Mode::Position, value)
else
T.absurd(value)
end
end
@ -73,54 +60,55 @@ class Computer
new(input.split(?,).map(&:to_i))
end
sig {returns(Integer)}
attr_accessor :pc, :rb
sig {returns(AnyIO)}
attr_reader :input, :output
sig {params(program: Memory).void}
def initialize(program)
sig {params(program: Memory, input: AnyIO, output: AnyIO).void}
def initialize(program, input=STDIN, output=STDOUT)
@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: T.untyped, output: AnyIO).returns(Memory)}
sig {params(input: AnyIO, output: AnyIO).returns(Memory)}
def run(input=STDIN, output=STDOUT)
each(input, output).inject(nil) {|_,i| i }
each = T.cast(each(input, output), T::Enumerator[Memory])
each.inject(nil) {|_,i| i }
end
sig {
params(
input: T.untyped,
input: AnyIO,
output: AnyIO,
blk: T.nilable(T.proc.params(m: Memory).returns(T.nilable(Integer)))
).returns(T::Enumerator[Memory])
).returns(T.any(T::Enumerator[Memory], BasicObject))
}
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)
self.pc += 1
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
@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
Parameter.new(mode, value)
}
self.pc += n
@pc += n
opcode.call(self, input, output, *args)
@pc = opcode.call(self, input, output, *args) || @pc
yield @memory
end
end
# Satisfy sorbet:
# https://sorbet-ruby.slack.com/archives/CHN2L03NH/p1575648549254600
Enumerator.new {}
end
sig {params(parameter: Parameter).returns(Integer)}
@ -128,9 +116,8 @@ class Computer
parameter = Parameter.from(parameter)
mode = parameter.mode
case mode
when Mode::Position then @memory[parameter.value] || 0
when Mode::Position then @memory.fetch(parameter.value) || 0
when Mode::Immediate then parameter.value
when Mode::Relative then @memory[rb + parameter.value] || 0
else T.absurd(mode)
end
end
@ -138,17 +125,8 @@ 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
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
@memory[parameter.value] = value
end
end
if __FILE__ == $0
Computer.from(T.cast(ARGF, IO).read || "").run
end

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

@ -1,27 +0,0 @@
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

@ -1,17 +0,0 @@
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")

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

@ -1,32 +0,0 @@
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

@ -1,47 +0,0 @@
# 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

@ -1,126 +0,0 @@
# 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

@ -1,103 +0,0 @@
# 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

@ -1,37 +0,0 @@
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")[50]
assert_equal 1, run_program("3,50,99", input: "1\n")[50]
output = StringIO.new
run_program("4,3,99,50", output: output)
@ -84,21 +84,6 @@ 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)

@ -1,200 +0,0 @@
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

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

@ -1,5 +0,0 @@
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)

@ -1,15 +0,0 @@
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(&:*)

@ -1,25 +0,0 @@
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?
}

@ -1,6 +0,0 @@
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) }

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

@ -1,16 +0,0 @@
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"]

@ -1,55 +0,0 @@
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]

@ -1,18 +0,0 @@
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

@ -1,29 +0,0 @@
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(&:*)

@ -1,90 +0,0 @@
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)

@ -1,54 +0,0 @@
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

@ -1,42 +0,0 @@
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)

@ -1,37 +0,0 @@
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

@ -1,31 +0,0 @@
# 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

@ -1,52 +0,0 @@
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(&:*)

@ -1,33 +0,0 @@
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)

@ -1,58 +0,0 @@
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

@ -1,67 +0,0 @@
# 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}$/ }

@ -1,107 +0,0 @@
# 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)

@ -1,39 +0,0 @@
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(?,)

@ -1,46 +0,0 @@
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

@ -1,32 +0,0 @@
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(&:*)

@ -1,55 +0,0 @@
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

@ -1,17 +0,0 @@
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

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

@ -1,2 +0,0 @@
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 }

@ -1,35 +0,0 @@
# 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

@ -1,23 +0,0 @@
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

@ -1,29 +0,0 @@
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

@ -1,29 +0,0 @@
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 }

@ -1,22 +0,0 @@
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] }

@ -1,9 +0,0 @@
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 }

@ -1,38 +0,0 @@
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)];

@ -1,51 +0,0 @@
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) }

@ -1,31 +0,0 @@
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(:*)

@ -1,51 +0,0 @@
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)

@ -1,36 +0,0 @@
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

@ -1,25 +0,0 @@
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

@ -1,18 +0,0 @@
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")

@ -1,41 +0,0 @@
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

@ -1,38 +0,0 @@
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]

@ -1,79 +0,0 @@
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

@ -1,29 +0,0 @@
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

@ -1,75 +0,0 @@
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

@ -1,52 +0,0 @@
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

@ -1,50 +0,0 @@
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 }

@ -1,76 +0,0 @@
# 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

@ -1,109 +0,0 @@
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)

@ -1,35 +0,0 @@
#############
#...........#
###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

@ -1,58 +0,0 @@
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

@ -1,262 +0,0 @@
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

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

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

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

@ -1,11 +0,0 @@
# •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⊐˜(∧´∊)˘𝕨↕𝕩}

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

@ -1,19 +0,0 @@
(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)))

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

@ -1,29 +0,0 @@
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

@ -1,2 +0,0 @@
# 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

@ -1,14 +0,0 @@
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

@ -1,8 +0,0 @@
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]) }

@ -1,6 +0,0 @@
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) }}

@ -1,18 +0,0 @@
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

@ -1,2 +0,0 @@
# 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

@ -1,61 +0,0 @@
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) }

@ -1,34 +0,0 @@
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

@ -1,44 +0,0 @@
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

@ -1,42 +0,0 @@
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

@ -1,48 +0,0 @@
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(:*)

@ -1,49 +0,0 @@
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 }

@ -1,37 +0,0 @@
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(:*)

@ -1,52 +0,0 @@
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

@ -1,87 +0,0 @@
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