mirror of
https://github.com/Smaug123/advent-of-code-2017
synced 2025-10-05 19:48:40 +00:00
Move up to day 11 to the lib/main format, and benchmark day 5 (#3)
This commit is contained in:
620
Cargo.lock
generated
620
Cargo.lock
generated
@@ -1,5 +1,181 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||
|
||||
[[package]]
|
||||
name = "bstr"
|
||||
version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90682c8d613ad3373e66de8c6411e0ae2ab2571e879d2efbf73558cc66f21279"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "63396b8a4b9de3f4fdfb320ab6080762242f66a8ef174c49d8e19b674db4cdbe"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
||||
|
||||
[[package]]
|
||||
name = "cast"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc38c385bfd7e444464011bb24820f40dd1c76bcdfa1b78611cb7c2e5cafab75"
|
||||
dependencies = [
|
||||
"rustc_version",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.33.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"textwrap",
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "criterion"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab327ed7354547cc2ef43cbe20ef68b988e70b4b593cbd66a2a61733123a3d23"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"cast",
|
||||
"clap",
|
||||
"criterion-plot",
|
||||
"csv",
|
||||
"itertools 0.10.0",
|
||||
"lazy_static",
|
||||
"num-traits",
|
||||
"oorandom",
|
||||
"plotters",
|
||||
"rayon",
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_cbor",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"tinytemplate",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "criterion-plot"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e022feadec601fba1649cfa83586381a4ad31c6bf3a9ab7d408118b05dd9889d"
|
||||
dependencies = [
|
||||
"cast",
|
||||
"itertools 0.9.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-channel"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-epoch",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "52fb27eab85b17fbb9f6fd667089e07d6a2eb8743d02639ee7f6a7a7729c9c94"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
"lazy_static",
|
||||
"memoffset",
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4feb231f0d4d6af81aed15928e58ecf5816aa62a2393e2c82f46973e92a9a278"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cfg-if",
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "csv"
|
||||
version = "1.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"csv-core",
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "csv-core"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "day_1"
|
||||
version = "0.1.0"
|
||||
@@ -59,6 +235,9 @@ version = "0.1.0"
|
||||
[[package]]
|
||||
name = "day_5"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"criterion",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "day_6"
|
||||
@@ -71,3 +250,444 @@ version = "0.1.0"
|
||||
[[package]]
|
||||
name = "day_8"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
|
||||
|
||||
[[package]]
|
||||
name = "half"
|
||||
version = "1.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62aca2aba2d62b4a7f5b33f3712cb1b0692779a56fb510499d5c0aa594daeaf3"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37d572918e350e82412fe766d24b15e6682fb2ed2bbe018280caa810397cb319"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.51"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "83bdfbace3a0e81a4253f73b49e960b053e396a11012cbd49b9b74d6a2b67062"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.94"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "18794a8ad5b29321f790b55d93dfba91e125cb1a9edbd4f8e3150acc771c1a5e"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc"
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f83fb6581e8ed1f85fd45c116db8405483899489e38406156c25eb743554361d"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "oorandom"
|
||||
version = "11.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
|
||||
|
||||
[[package]]
|
||||
name = "plotters"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "45ca0ae5f169d0917a7c7f5a9c1a3d3d9598f18f529dd2b8373ed988efea307a"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
"plotters-backend",
|
||||
"plotters-svg",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "plotters-backend"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b07fffcddc1cb3a1de753caa4e4df03b79922ba43cf882acc1bdd7e8df9f4590"
|
||||
|
||||
[[package]]
|
||||
name = "plotters-svg"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b38a02e23bd9604b842a812063aec4ef702b57989c37b655254bb61c471ad211"
|
||||
dependencies = [
|
||||
"plotters-backend",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b0d8e0819fadc20c74ea8373106ead0600e3a67ef1fe8da56e39b9ae7275674"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"crossbeam-deque",
|
||||
"either",
|
||||
"rayon-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon-core"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ab346ac5921dc62ffa9f89b7a773907511cdfa5490c572ae9be1be33e8afa4a"
|
||||
dependencies = [
|
||||
"crossbeam-channel",
|
||||
"crossbeam-deque",
|
||||
"crossbeam-utils",
|
||||
"lazy_static",
|
||||
"num_cpus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
|
||||
dependencies = [
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae1ded71d66a4a97f5e961fd0cb25a5f366a42a41570d16a763a69c092c26ae4"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
||||
dependencies = [
|
||||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
|
||||
dependencies = [
|
||||
"semver-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver-parser"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.126"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03"
|
||||
|
||||
[[package]]
|
||||
name = "serde_cbor"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e18acfa2f90e8b735b2836ab8d538de304cbb6729a7360729ea5a895d15a622"
|
||||
dependencies = [
|
||||
"half",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.126"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.64"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.72"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1e8cdbefb79a9a5a65e0db8b47b723ee907b7c7f8496c76a1770b5c310bab82"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||
dependencies = [
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinytemplate"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56"
|
||||
dependencies = [
|
||||
"same-file",
|
||||
"winapi",
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.74"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d54ee1d4ed486f78874278e63e4069fc1ab9f6a18ca492076ffb90c5eb2997fd"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"wasm-bindgen-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.74"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b33f6a0694ccfea53d94db8b2ed1c3a8a4c86dd936b13b9f0a15ec4a451b900"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.74"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "088169ca61430fe1e58b8096c24975251700e7b1f6fd91cc9d59b04fb9b18bd4"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.74"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be2241542ff3d9f241f5e2cb6dd09b37efe786df8851c54957683a49f0987a97"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.74"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d7cff876b8f18eed75a66cf49b65e7f967cb354a7aa16003fb55dbfd25b44b4f"
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.51"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e828417b379f3df7111d3a2a9e5753706cae29c41f7c4029ee9fd77f3e09e582"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
77
day_1/src/lib.rs
Normal file
77
day_1/src/lib.rs
Normal file
@@ -0,0 +1,77 @@
|
||||
pub mod day_1 {
|
||||
|
||||
pub fn input() -> Vec<u32> {
|
||||
let input = include_str!("../input.txt");
|
||||
input
|
||||
.trim()
|
||||
.chars()
|
||||
.map(|l| {
|
||||
l.to_digit(10)
|
||||
.unwrap_or_else(|| panic!("{} wasn't a valid u32", l))
|
||||
})
|
||||
.collect::<Vec<u32>>()
|
||||
}
|
||||
|
||||
pub fn part_1(numbers: &[u32]) -> u32 {
|
||||
let mut sum = 0;
|
||||
let mut previous = numbers[0];
|
||||
let len = numbers.len();
|
||||
for &item in numbers.iter().skip(1) {
|
||||
if item == previous {
|
||||
sum += previous;
|
||||
}
|
||||
previous = item;
|
||||
}
|
||||
if len <= 1 {
|
||||
// Start = end, so no need to compare last with first
|
||||
return sum;
|
||||
}
|
||||
|
||||
if previous == numbers[0] {
|
||||
sum += previous;
|
||||
}
|
||||
|
||||
sum
|
||||
}
|
||||
|
||||
pub fn part_2(numbers: &[u32]) -> u32 {
|
||||
let mut sum = 0;
|
||||
let len = numbers.len();
|
||||
for i in 0..len / 2 {
|
||||
if numbers[i] == numbers[len / 2 + i] {
|
||||
sum += 2 * numbers[i];
|
||||
}
|
||||
}
|
||||
|
||||
sum
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::day_1::*;
|
||||
|
||||
#[test]
|
||||
fn part1_known() {
|
||||
assert_eq!(part_1(&[1, 1, 2, 2]), 3);
|
||||
assert_eq!(part_1(&[1, 1, 1, 1]), 4);
|
||||
assert_eq!(part_1(&[1, 2, 3, 4]), 0);
|
||||
assert_eq!(part_1(&[9, 1, 2, 1, 2, 1, 2, 9]), 9);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn part2_known() {
|
||||
assert_eq!(part_2(&[1, 2, 1, 2]), 6);
|
||||
assert_eq!(part_2(&[1, 2, 2, 1]), 0);
|
||||
assert_eq!(part_2(&[1, 2, 3, 4, 2, 5]), 4);
|
||||
assert_eq!(part_2(&[1, 2, 3, 1, 2, 3]), 12);
|
||||
assert_eq!(part_2(&[1, 2, 1, 3, 1, 4, 1, 5]), 4);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_day_1() {
|
||||
let input = input();
|
||||
assert_eq!(part_1(&input), 1223);
|
||||
assert_eq!(part_2(&input), 1284);
|
||||
}
|
||||
}
|
@@ -1,80 +1,7 @@
|
||||
fn input() -> Vec<u32> {
|
||||
let input = include_str!("../input.txt");
|
||||
input
|
||||
.trim()
|
||||
.chars()
|
||||
.map(|l| {
|
||||
l.to_digit(10)
|
||||
.unwrap_or_else(|| panic!("{} wasn't a valid u32", l))
|
||||
})
|
||||
.collect::<Vec<u32>>()
|
||||
}
|
||||
|
||||
pub fn part_1(numbers: &[u32]) -> u32 {
|
||||
let mut sum = 0;
|
||||
let mut previous = numbers[0];
|
||||
let len = numbers.len();
|
||||
for &item in numbers.iter().skip(1) {
|
||||
if item == previous {
|
||||
sum += previous;
|
||||
}
|
||||
previous = item;
|
||||
}
|
||||
if len <= 1 {
|
||||
// Start = end, so no need to compare last with first
|
||||
return sum;
|
||||
}
|
||||
|
||||
if previous == numbers[0] {
|
||||
sum += previous;
|
||||
}
|
||||
|
||||
sum
|
||||
}
|
||||
|
||||
pub fn part_2(numbers: &[u32]) -> u32 {
|
||||
let mut sum = 0;
|
||||
let len = numbers.len();
|
||||
for i in 0..len / 2 {
|
||||
if numbers[i] == numbers[len / 2 + i] {
|
||||
sum += 2 * numbers[i];
|
||||
}
|
||||
}
|
||||
|
||||
sum
|
||||
}
|
||||
use day_1::day_1;
|
||||
|
||||
fn main() {
|
||||
let input = input();
|
||||
println!("part 1 => {}", part_1(&input));
|
||||
println!("part 2 => {}", part_2(&input));
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn part1_known() {
|
||||
assert_eq!(part_1(&[1, 1, 2, 2]), 3);
|
||||
assert_eq!(part_1(&[1, 1, 1, 1]), 4);
|
||||
assert_eq!(part_1(&[1, 2, 3, 4]), 0);
|
||||
assert_eq!(part_1(&[9, 1, 2, 1, 2, 1, 2, 9]), 9);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn part2_known() {
|
||||
assert_eq!(part_2(&[1, 2, 1, 2]), 6);
|
||||
assert_eq!(part_2(&[1, 2, 2, 1]), 0);
|
||||
assert_eq!(part_2(&[1, 2, 3, 4, 2, 5]), 4);
|
||||
assert_eq!(part_2(&[1, 2, 3, 1, 2, 3]), 12);
|
||||
assert_eq!(part_2(&[1, 2, 1, 3, 1, 4, 1, 5]), 4);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_day_1() {
|
||||
let input = input();
|
||||
assert_eq!(part_1(&input), 1223);
|
||||
assert_eq!(part_2(&input), 1284);
|
||||
}
|
||||
let input = day_1::input();
|
||||
println!("part 1 => {}", day_1::part_1(&input));
|
||||
println!("part 2 => {}", day_1::part_2(&input));
|
||||
}
|
||||
|
134
day_10/src/lib.rs
Normal file
134
day_10/src/lib.rs
Normal file
@@ -0,0 +1,134 @@
|
||||
pub mod day_10 {
|
||||
|
||||
pub fn input_1() -> Vec<u8> {
|
||||
let input = include_str!("../input.txt");
|
||||
input
|
||||
.trim()
|
||||
.split(',')
|
||||
.map(|l| l.parse().unwrap())
|
||||
.collect::<Vec<u8>>()
|
||||
}
|
||||
|
||||
pub fn input_2() -> Vec<u8> {
|
||||
let input = include_str!("../input.txt");
|
||||
input.trim().chars().map(|c| c as u8).collect::<Vec<u8>>()
|
||||
}
|
||||
|
||||
fn rev<T>(start: usize, length: usize, b: &mut [T])
|
||||
where
|
||||
T: Copy,
|
||||
{
|
||||
for j in 0..(length / 2) {
|
||||
let tmp = b[(start + j) % b.len()];
|
||||
b[(start + j) % b.len()] = b[(start + length - j - 1) % b.len()];
|
||||
b[(start + length - j - 1) % b.len()] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct HashState {
|
||||
pub(crate) v: Vec<u8>,
|
||||
pub(crate) curr_pos: usize,
|
||||
pub(crate) skip_size: usize,
|
||||
}
|
||||
|
||||
pub(crate) fn new_state(size: usize) -> HashState {
|
||||
HashState {
|
||||
v: (0..size).map(|i| i as u8).collect(),
|
||||
curr_pos: 0,
|
||||
skip_size: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn execute_round(state: &mut HashState, input: &[u8]) {
|
||||
for &i in input {
|
||||
let i = i as usize;
|
||||
rev(state.curr_pos, i, &mut state.v);
|
||||
state.curr_pos = (state.curr_pos + i + state.skip_size) % state.v.len();
|
||||
state.skip_size += 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn part_1(size: usize, input: &[u8]) -> u32 {
|
||||
let mut state = new_state(size);
|
||||
execute_round(&mut state, input);
|
||||
state.v[0] as u32 * state.v[1] as u32
|
||||
}
|
||||
|
||||
fn densify(v: &[u8]) -> Vec<u8> {
|
||||
v.chunks_exact(16)
|
||||
.map(|i| i.iter().fold(0, |x, y| x ^ y))
|
||||
.collect()
|
||||
}
|
||||
|
||||
// Convert a number from 0 to 15 into an ASCII hex char
|
||||
fn to_hex(i: u8) -> u8 {
|
||||
if i < 10 {
|
||||
i + b'0'
|
||||
} else {
|
||||
i - 10 + b'a'
|
||||
}
|
||||
}
|
||||
|
||||
pub fn knot_hash_unsalted(bytes: &[u8]) -> String {
|
||||
let mut state = new_state(256);
|
||||
for _ in 0..64 {
|
||||
execute_round(&mut state, &bytes);
|
||||
}
|
||||
let dense = densify(&state.v);
|
||||
let mut answer = vec![0u8; 2 * dense.len()];
|
||||
for (i, b) in dense.iter().enumerate() {
|
||||
answer[2 * i] = to_hex(b / 16);
|
||||
answer[2 * i + 1] = to_hex(b % 16);
|
||||
}
|
||||
String::from_utf8(answer).unwrap()
|
||||
}
|
||||
|
||||
pub fn knot_hash(bytes: &[u8]) -> String {
|
||||
let mut copy: Vec<u8> = bytes.to_vec();
|
||||
copy.extend(vec![17, 31, 73, 47, 23]);
|
||||
knot_hash_unsalted(©)
|
||||
}
|
||||
|
||||
pub fn part_2(input: &[u8]) -> String {
|
||||
knot_hash(input)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::day_10::*;
|
||||
|
||||
#[test]
|
||||
fn part1_known() {
|
||||
let mut state = new_state(5);
|
||||
execute_round(&mut state, &[3, 4, 1, 5]);
|
||||
assert_eq!(state.v, vec![3, 4, 2, 1, 0]);
|
||||
assert_eq!(state.skip_size, 4);
|
||||
assert_eq!(state.curr_pos, 4);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn part2_known() {
|
||||
assert_eq!(knot_hash("".as_bytes()), "a2582a3a0e66e6e86e3812dcb672a272");
|
||||
assert_eq!(
|
||||
knot_hash("AoC 2017".as_bytes()),
|
||||
"33efeb34ea91902bb2f59c9920caa6cd"
|
||||
);
|
||||
assert_eq!(
|
||||
knot_hash("1,2,3".as_bytes()),
|
||||
"3efbe78a8d82f29979031a4aa0b16a9d"
|
||||
);
|
||||
assert_eq!(
|
||||
knot_hash("1,2,4".as_bytes()),
|
||||
"63960835bcdc130f0b66d7ff4f6a5a8e"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_day_10() {
|
||||
let input = input_1();
|
||||
assert_eq!(part_1(256, &input), 4114);
|
||||
let input = input_2();
|
||||
assert_eq!(part_2(&input), "2f8c3d2100fdd57cec130d928b0fd2dd");
|
||||
}
|
||||
}
|
@@ -1,140 +1,10 @@
|
||||
fn input_1() -> Vec<u8> {
|
||||
let input = include_str!("../input.txt");
|
||||
input
|
||||
.trim()
|
||||
.split(',')
|
||||
.map(|l| l.parse().unwrap())
|
||||
.collect::<Vec<u8>>()
|
||||
}
|
||||
|
||||
fn input_2() -> Vec<u8> {
|
||||
let input = include_str!("../input.txt");
|
||||
input.trim().chars().map(|c| c as u8).collect::<Vec<u8>>()
|
||||
}
|
||||
|
||||
fn rev<T>(start: usize, length: usize, b: &mut [T])
|
||||
where
|
||||
T: Copy,
|
||||
{
|
||||
for j in 0..(length / 2) {
|
||||
let tmp = b[(start + j) % b.len()];
|
||||
b[(start + j) % b.len()] = b[(start + length - j - 1) % b.len()];
|
||||
b[(start + length - j - 1) % b.len()] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
struct HashState {
|
||||
v: Vec<u8>,
|
||||
curr_pos: usize,
|
||||
skip_size: usize,
|
||||
}
|
||||
|
||||
fn new_state(size: usize) -> HashState {
|
||||
HashState {
|
||||
v: (0..size).map(|i| i as u8).collect(),
|
||||
curr_pos: 0,
|
||||
skip_size: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn execute_round(state: &mut HashState, input: &[u8]) {
|
||||
for &i in input {
|
||||
let i = i as usize;
|
||||
rev(state.curr_pos, i, &mut state.v);
|
||||
state.curr_pos = (state.curr_pos + i + state.skip_size) % state.v.len();
|
||||
state.skip_size += 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn part_1(size: usize, input: &[u8]) -> u32 {
|
||||
let mut state = new_state(size);
|
||||
execute_round(&mut state, input);
|
||||
state.v[0] as u32 * state.v[1] as u32
|
||||
}
|
||||
|
||||
fn densify(v: &[u8]) -> Vec<u8> {
|
||||
v.chunks_exact(16)
|
||||
.map(|i| i.iter().fold(0, |x, y| x ^ y))
|
||||
.collect()
|
||||
}
|
||||
|
||||
// Convert a number from 0 to 15 into an ASCII hex char
|
||||
fn to_hex(i: u8) -> u8 {
|
||||
if i < 10 {
|
||||
i + b'0'
|
||||
} else {
|
||||
i - 10 + b'a'
|
||||
}
|
||||
}
|
||||
|
||||
pub fn knot_hash_unsalted(bytes: &[u8]) -> String {
|
||||
let mut state = new_state(256);
|
||||
for _ in 0..64 {
|
||||
execute_round(&mut state, &bytes);
|
||||
}
|
||||
let dense = densify(&state.v);
|
||||
let mut answer = vec![0u8; 2 * dense.len()];
|
||||
for (i, b) in dense.iter().enumerate() {
|
||||
answer[2 * i] = to_hex(b / 16);
|
||||
answer[2 * i + 1] = to_hex(b % 16);
|
||||
}
|
||||
String::from_utf8(answer).unwrap()
|
||||
}
|
||||
|
||||
pub fn knot_hash(bytes: &[u8]) -> String {
|
||||
let mut copy: Vec<u8> = bytes.to_vec();
|
||||
copy.extend(vec![17, 31, 73, 47, 23]);
|
||||
knot_hash_unsalted(©)
|
||||
}
|
||||
|
||||
fn part_2(input: &[u8]) -> String {
|
||||
knot_hash(input)
|
||||
}
|
||||
use day_10::day_10;
|
||||
|
||||
fn main() {
|
||||
let input = input_1();
|
||||
println!("part 1 => {}", part_1(256, &input));
|
||||
let input = day_10::input_1();
|
||||
println!("part 1 => {}", day_10::part_1(256, &input));
|
||||
|
||||
let mut input = input_2();
|
||||
let mut input = day_10::input_2();
|
||||
input.extend(vec![17, 31, 73, 47, 23]);
|
||||
println!("part 2 => {}", part_2(&input));
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn part1_known() {
|
||||
let mut state = new_state(5);
|
||||
execute_round(&mut state, &[3, 4, 1, 5]);
|
||||
assert_eq!(state.v, vec![3, 4, 2, 1, 0]);
|
||||
assert_eq!(state.skip_size, 4);
|
||||
assert_eq!(state.curr_pos, 4);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn part2_known() {
|
||||
assert_eq!(knot_hash("".as_bytes()), "a2582a3a0e66e6e86e3812dcb672a272");
|
||||
assert_eq!(
|
||||
knot_hash("AoC 2017".as_bytes()),
|
||||
"33efeb34ea91902bb2f59c9920caa6cd"
|
||||
);
|
||||
assert_eq!(
|
||||
knot_hash("1,2,3".as_bytes()),
|
||||
"3efbe78a8d82f29979031a4aa0b16a9d"
|
||||
);
|
||||
assert_eq!(
|
||||
knot_hash("1,2,4".as_bytes()),
|
||||
"63960835bcdc130f0b66d7ff4f6a5a8e"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_day_10() {
|
||||
let input = input_1();
|
||||
assert_eq!(part_1(256, &input), 4114);
|
||||
let input = input_2();
|
||||
assert_eq!(part_2(&input), "2f8c3d2100fdd57cec130d928b0fd2dd");
|
||||
}
|
||||
println!("part 2 => {}", day_10::part_2(&input));
|
||||
}
|
||||
|
138
day_11/src/lib.rs
Normal file
138
day_11/src/lib.rs
Normal file
@@ -0,0 +1,138 @@
|
||||
pub mod day_11 {
|
||||
pub enum Direction {
|
||||
South,
|
||||
North,
|
||||
NorthEast,
|
||||
NorthWest,
|
||||
SouthEast,
|
||||
SouthWest,
|
||||
}
|
||||
|
||||
fn parse(s: &str) -> Direction {
|
||||
let mut chars = s.chars();
|
||||
let c1 = chars.next().unwrap();
|
||||
match chars.next() {
|
||||
None => match c1 {
|
||||
's' => Direction::South,
|
||||
'n' => Direction::North,
|
||||
c1 => panic!("Expected south or north, got: {}", c1),
|
||||
},
|
||||
Some(c2) => match c1 {
|
||||
's' => match c2 {
|
||||
'e' => Direction::SouthEast,
|
||||
'w' => Direction::SouthWest,
|
||||
c2 => panic!("Expected SE or SW, got s{}", c2),
|
||||
},
|
||||
'n' => match c2 {
|
||||
'e' => Direction::NorthEast,
|
||||
'w' => Direction::NorthWest,
|
||||
c2 => panic!("Expected NE or NW, got n{}", c2),
|
||||
},
|
||||
c1 => panic!("Expected north or south for first direction, got: {}", c1),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn input() -> Vec<Direction> {
|
||||
let input = include_str!("../input.txt");
|
||||
input
|
||||
.trim()
|
||||
.split(',')
|
||||
.map(parse)
|
||||
.collect::<Vec<Direction>>()
|
||||
}
|
||||
|
||||
fn abs(i: i32) -> u32 {
|
||||
if i >= 0 {
|
||||
i as u32
|
||||
} else {
|
||||
-i as u32
|
||||
}
|
||||
}
|
||||
|
||||
fn steps_to(x: i32, y: i32) -> u32 {
|
||||
let x = abs(x);
|
||||
let y = abs(y);
|
||||
y + if 2 * y < x { (x - y) / 2 } else { 0 }
|
||||
}
|
||||
|
||||
pub fn part_1(steps: &[Direction]) -> u32 {
|
||||
let (final_x, final_y) = steps.iter().fold((0, 0), |(x, y), dir| match *dir {
|
||||
Direction::SouthEast => (x - 1, y + 1),
|
||||
Direction::NorthEast => (x + 1, y + 1),
|
||||
Direction::SouthWest => (x - 1, y - 1),
|
||||
Direction::NorthWest => (x + 1, y - 1),
|
||||
Direction::South => (x - 2, y),
|
||||
Direction::North => (x + 2, y),
|
||||
});
|
||||
steps_to(final_x, final_y)
|
||||
}
|
||||
|
||||
pub fn part_2(steps: &[Direction]) -> u32 {
|
||||
let (best, _, _) = steps.iter().fold((0, 0, 0), |(best, x, y), dir| {
|
||||
let (new_x, new_y) = match *dir {
|
||||
Direction::SouthEast => (x - 1, y + 1),
|
||||
Direction::NorthEast => (x + 1, y + 1),
|
||||
Direction::SouthWest => (x - 1, y - 1),
|
||||
Direction::NorthWest => (x + 1, y - 1),
|
||||
Direction::South => (x - 2, y),
|
||||
Direction::North => (x + 2, y),
|
||||
};
|
||||
let new_steps = steps_to(new_x, new_y);
|
||||
(std::cmp::max(new_steps, best), new_x, new_y)
|
||||
});
|
||||
best
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::day_11::*;
|
||||
|
||||
#[test]
|
||||
fn part1_known() {
|
||||
assert_eq!(
|
||||
part_1(&[
|
||||
Direction::NorthEast,
|
||||
Direction::NorthEast,
|
||||
Direction::NorthEast
|
||||
]),
|
||||
3
|
||||
);
|
||||
assert_eq!(
|
||||
part_1(&[
|
||||
Direction::NorthEast,
|
||||
Direction::NorthEast,
|
||||
Direction::SouthWest,
|
||||
Direction::SouthWest
|
||||
]),
|
||||
0
|
||||
);
|
||||
assert_eq!(
|
||||
part_1(&[
|
||||
Direction::NorthEast,
|
||||
Direction::NorthEast,
|
||||
Direction::South,
|
||||
Direction::South
|
||||
]),
|
||||
2
|
||||
);
|
||||
assert_eq!(
|
||||
part_1(&[
|
||||
Direction::SouthEast,
|
||||
Direction::SouthWest,
|
||||
Direction::SouthEast,
|
||||
Direction::SouthWest,
|
||||
Direction::SouthWest
|
||||
]),
|
||||
3
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_day_11() {
|
||||
let input = input();
|
||||
assert_eq!(part_1(&input), 743);
|
||||
assert_eq!(part_2(&input), 1493);
|
||||
}
|
||||
}
|
@@ -1,141 +1,7 @@
|
||||
pub enum Direction {
|
||||
South,
|
||||
North,
|
||||
NorthEast,
|
||||
NorthWest,
|
||||
SouthEast,
|
||||
SouthWest,
|
||||
}
|
||||
|
||||
fn parse(s: &str) -> Direction {
|
||||
let mut chars = s.chars();
|
||||
let c1 = chars.next().unwrap();
|
||||
match chars.next() {
|
||||
None => match c1 {
|
||||
's' => Direction::South,
|
||||
'n' => Direction::North,
|
||||
c1 => panic!("Expected south or north, got: {}", c1),
|
||||
},
|
||||
Some(c2) => match c1 {
|
||||
's' => match c2 {
|
||||
'e' => Direction::SouthEast,
|
||||
'w' => Direction::SouthWest,
|
||||
c2 => panic!("Expected SE or SW, got s{}", c2),
|
||||
},
|
||||
'n' => match c2 {
|
||||
'e' => Direction::NorthEast,
|
||||
'w' => Direction::NorthWest,
|
||||
c2 => panic!("Expected NE or NW, got n{}", c2),
|
||||
},
|
||||
c1 => panic!("Expected north or south for first direction, got: {}", c1),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn input() -> Vec<Direction> {
|
||||
let input = include_str!("../input.txt");
|
||||
input
|
||||
.trim()
|
||||
.split(',')
|
||||
.map(parse)
|
||||
.collect::<Vec<Direction>>()
|
||||
}
|
||||
|
||||
fn abs(i: i32) -> u32 {
|
||||
if i >= 0 {
|
||||
i as u32
|
||||
} else {
|
||||
-i as u32
|
||||
}
|
||||
}
|
||||
|
||||
fn steps_to(x: i32, y: i32) -> u32 {
|
||||
let x = abs(x);
|
||||
let y = abs(y);
|
||||
y + if 2 * y < x { (x - y) / 2 } else { 0 }
|
||||
}
|
||||
|
||||
pub fn part_1(steps: &[Direction]) -> u32 {
|
||||
let (final_x, final_y) = steps.iter().fold((0, 0), |(x, y), dir| match *dir {
|
||||
Direction::SouthEast => (x - 1, y + 1),
|
||||
Direction::NorthEast => (x + 1, y + 1),
|
||||
Direction::SouthWest => (x - 1, y - 1),
|
||||
Direction::NorthWest => (x + 1, y - 1),
|
||||
Direction::South => (x - 2, y),
|
||||
Direction::North => (x + 2, y),
|
||||
});
|
||||
steps_to(final_x, final_y)
|
||||
}
|
||||
|
||||
pub fn part_2(steps: &[Direction]) -> u32 {
|
||||
let (best, _, _) = steps.iter().fold((0, 0, 0), |(best, x, y), dir| {
|
||||
let (new_x, new_y) = match *dir {
|
||||
Direction::SouthEast => (x - 1, y + 1),
|
||||
Direction::NorthEast => (x + 1, y + 1),
|
||||
Direction::SouthWest => (x - 1, y - 1),
|
||||
Direction::NorthWest => (x + 1, y - 1),
|
||||
Direction::South => (x - 2, y),
|
||||
Direction::North => (x + 2, y),
|
||||
};
|
||||
let new_steps = steps_to(new_x, new_y);
|
||||
(std::cmp::max(new_steps, best), new_x, new_y)
|
||||
});
|
||||
best
|
||||
}
|
||||
use day_11::day_11;
|
||||
|
||||
fn main() {
|
||||
let input = input();
|
||||
println!("part 1 => {}", part_1(&input));
|
||||
println!("part 2 => {}", part_2(&input));
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn part1_known() {
|
||||
assert_eq!(
|
||||
part_1(&[
|
||||
Direction::NorthEast,
|
||||
Direction::NorthEast,
|
||||
Direction::NorthEast
|
||||
]),
|
||||
3
|
||||
);
|
||||
assert_eq!(
|
||||
part_1(&[
|
||||
Direction::NorthEast,
|
||||
Direction::NorthEast,
|
||||
Direction::SouthWest,
|
||||
Direction::SouthWest
|
||||
]),
|
||||
0
|
||||
);
|
||||
assert_eq!(
|
||||
part_1(&[
|
||||
Direction::NorthEast,
|
||||
Direction::NorthEast,
|
||||
Direction::South,
|
||||
Direction::South
|
||||
]),
|
||||
2
|
||||
);
|
||||
assert_eq!(
|
||||
part_1(&[
|
||||
Direction::SouthEast,
|
||||
Direction::SouthWest,
|
||||
Direction::SouthEast,
|
||||
Direction::SouthWest,
|
||||
Direction::SouthWest
|
||||
]),
|
||||
3
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_day_1() {
|
||||
let input = input();
|
||||
assert_eq!(part_1(&input), 743);
|
||||
}
|
||||
let input = day_11::input();
|
||||
println!("part 1 => {}", day_11::part_1(&input));
|
||||
println!("part 2 => {}", day_11::part_2(&input));
|
||||
}
|
||||
|
139
day_2/src/lib.rs
Normal file
139
day_2/src/lib.rs
Normal file
@@ -0,0 +1,139 @@
|
||||
pub mod day_2 {
|
||||
|
||||
use std::cmp::Ordering;
|
||||
use std::collections::HashSet;
|
||||
|
||||
pub fn input() -> Vec<Vec<u32>> {
|
||||
let input = include_str!("../input.txt");
|
||||
input
|
||||
.lines()
|
||||
.map(|l| {
|
||||
l.trim()
|
||||
.split_whitespace()
|
||||
.map(|i| {
|
||||
i.parse()
|
||||
.unwrap_or_else(|_| panic!("{} wasn't a valid u32", i))
|
||||
})
|
||||
.collect::<Vec<u32>>()
|
||||
})
|
||||
.collect::<Vec<Vec<u32>>>()
|
||||
}
|
||||
|
||||
fn min_max<T, I>(i: &mut I) -> Option<(T, T)>
|
||||
where
|
||||
I: Iterator<Item = T>,
|
||||
T: Copy + Ord,
|
||||
{
|
||||
if let Some(fst) = i.next() {
|
||||
let mut top = fst;
|
||||
let mut bot = fst;
|
||||
for next in i {
|
||||
if next > top {
|
||||
top = next;
|
||||
}
|
||||
if next < bot {
|
||||
bot = next;
|
||||
}
|
||||
}
|
||||
Some((bot, top))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn even_divisor<I>(iter: &mut I) -> Option<(u32, u32)>
|
||||
where
|
||||
I: Iterator<Item = u32>,
|
||||
{
|
||||
let mut seen: HashSet<u32> = HashSet::new();
|
||||
for i in iter {
|
||||
for s in &seen {
|
||||
let s = *s;
|
||||
match u32::cmp(&s, &i) {
|
||||
Ordering::Less => {
|
||||
if i % s == 0 {
|
||||
return Some((i, s));
|
||||
};
|
||||
}
|
||||
Ordering::Greater => {
|
||||
if s % i == 0 {
|
||||
return Some((s, i));
|
||||
};
|
||||
}
|
||||
Ordering::Equal => {
|
||||
return Some((i, s));
|
||||
}
|
||||
}
|
||||
}
|
||||
seen.insert(i);
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn part_1<I, J>(numbers: &mut I) -> u32
|
||||
where
|
||||
I: Iterator<Item = J>,
|
||||
J: Iterator<Item = u32>,
|
||||
{
|
||||
numbers
|
||||
.map(|mut row| {
|
||||
if let Some((min, max)) = min_max(&mut row) {
|
||||
max - min
|
||||
} else {
|
||||
0
|
||||
}
|
||||
})
|
||||
.sum()
|
||||
}
|
||||
|
||||
pub fn part_2<I, J>(numbers: &mut I) -> u32
|
||||
where
|
||||
I: Iterator<Item = J>,
|
||||
J: Iterator<Item = u32>,
|
||||
{
|
||||
numbers
|
||||
.map(|mut row| {
|
||||
let (bigger, smaller) = even_divisor(&mut row).unwrap();
|
||||
bigger / smaller
|
||||
})
|
||||
.sum()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::day_2::*;
|
||||
|
||||
#[test]
|
||||
fn part1_known() {
|
||||
assert_eq!(
|
||||
part_1(
|
||||
&mut vec![vec![5, 1, 9, 5], vec![7, 5, 3], vec![2, 4, 6, 8]]
|
||||
.iter()
|
||||
.map(|r| r.iter().cloned())
|
||||
),
|
||||
18
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn part2_known() {
|
||||
assert_eq!(
|
||||
part_2(
|
||||
&mut vec![vec![5, 9, 2, 8], vec![9, 4, 7, 3], vec![3, 8, 6, 5]]
|
||||
.iter()
|
||||
.map(|r| r.iter().cloned())
|
||||
),
|
||||
9
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_day_2() {
|
||||
let input = input();
|
||||
let answer = part_1(&mut input.iter().map(|r| r.iter().cloned()));
|
||||
assert_eq!(answer, 44887);
|
||||
let answer = part_2(&mut input.iter().map(|r| r.iter().cloned()));
|
||||
assert_eq!(answer, 242);
|
||||
}
|
||||
}
|
@@ -1,148 +1,13 @@
|
||||
use std::cmp::Ordering;
|
||||
use std::collections::HashSet;
|
||||
|
||||
fn input() -> Vec<Vec<u32>> {
|
||||
let input = include_str!("../input.txt");
|
||||
input
|
||||
.lines()
|
||||
.map(|l| {
|
||||
l.trim()
|
||||
.split_whitespace()
|
||||
.map(|i| {
|
||||
i.parse()
|
||||
.unwrap_or_else(|_| panic!("{} wasn't a valid u32", i))
|
||||
})
|
||||
.collect::<Vec<u32>>()
|
||||
})
|
||||
.collect::<Vec<Vec<u32>>>()
|
||||
}
|
||||
|
||||
fn min_max<T, I>(i: &mut I) -> Option<(T, T)>
|
||||
where
|
||||
I: Iterator<Item = T>,
|
||||
T: Copy + Ord,
|
||||
{
|
||||
if let Some(fst) = i.next() {
|
||||
let mut top = fst;
|
||||
let mut bot = fst;
|
||||
for next in i {
|
||||
if next > top {
|
||||
top = next;
|
||||
}
|
||||
if next < bot {
|
||||
bot = next;
|
||||
}
|
||||
}
|
||||
Some((bot, top))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn even_divisor<I>(iter: &mut I) -> Option<(u32, u32)>
|
||||
where
|
||||
I: Iterator<Item = u32>,
|
||||
{
|
||||
let mut seen: HashSet<u32> = HashSet::new();
|
||||
for i in iter {
|
||||
for s in &seen {
|
||||
let s = *s;
|
||||
match u32::cmp(&s, &i) {
|
||||
Ordering::Less => {
|
||||
if i % s == 0 {
|
||||
return Some((i, s));
|
||||
};
|
||||
}
|
||||
Ordering::Greater => {
|
||||
if s % i == 0 {
|
||||
return Some((s, i));
|
||||
};
|
||||
}
|
||||
Ordering::Equal => {
|
||||
return Some((i, s));
|
||||
}
|
||||
}
|
||||
}
|
||||
seen.insert(i);
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn part_1<I, J>(numbers: &mut I) -> u32
|
||||
where
|
||||
I: Iterator<Item = J>,
|
||||
J: Iterator<Item = u32>,
|
||||
{
|
||||
numbers
|
||||
.map(|mut row| {
|
||||
if let Some((min, max)) = min_max(&mut row) {
|
||||
max - min
|
||||
} else {
|
||||
0
|
||||
}
|
||||
})
|
||||
.sum()
|
||||
}
|
||||
|
||||
pub fn part_2<I, J>(numbers: &mut I) -> u32
|
||||
where
|
||||
I: Iterator<Item = J>,
|
||||
J: Iterator<Item = u32>,
|
||||
{
|
||||
numbers
|
||||
.map(|mut row| {
|
||||
let (bigger, smaller) = even_divisor(&mut row).unwrap();
|
||||
bigger / smaller
|
||||
})
|
||||
.sum()
|
||||
}
|
||||
use day_2::day_2;
|
||||
|
||||
fn main() {
|
||||
let input = input();
|
||||
let input = day_2::input();
|
||||
println!(
|
||||
"part 1 => {}",
|
||||
part_1(&mut input.iter().map(|r| r.iter().cloned()))
|
||||
day_2::part_1(&mut input.iter().map(|r| r.iter().cloned()))
|
||||
);
|
||||
println!(
|
||||
"part 2 => {}",
|
||||
part_2(&mut input.iter().map(|r| r.iter().cloned()))
|
||||
day_2::part_2(&mut input.iter().map(|r| r.iter().cloned()))
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn part1_known() {
|
||||
assert_eq!(
|
||||
part_1(
|
||||
&mut vec![vec![5, 1, 9, 5], vec![7, 5, 3], vec![2, 4, 6, 8]]
|
||||
.iter()
|
||||
.map(|r| r.iter().cloned())
|
||||
),
|
||||
18
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn part2_known() {
|
||||
assert_eq!(
|
||||
part_2(
|
||||
&mut vec![vec![5, 9, 2, 8], vec![9, 4, 7, 3], vec![3, 8, 6, 5]]
|
||||
.iter()
|
||||
.map(|r| r.iter().cloned())
|
||||
),
|
||||
9
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_day_2() {
|
||||
let input = input();
|
||||
let answer = part_1(&mut input.iter().map(|r| r.iter().cloned()));
|
||||
assert_eq!(answer, 44887);
|
||||
let answer = part_2(&mut input.iter().map(|r| r.iter().cloned()));
|
||||
assert_eq!(answer, 242);
|
||||
}
|
||||
}
|
||||
|
287
day_3/src/lib.rs
Normal file
287
day_3/src/lib.rs
Normal file
@@ -0,0 +1,287 @@
|
||||
pub mod day_3 {
|
||||
|
||||
pub fn input() -> u32 {
|
||||
let input = include_str!("../input.txt");
|
||||
input
|
||||
.trim()
|
||||
.parse()
|
||||
.unwrap_or_else(|_| panic!("{} wasn't a valid u32", input))
|
||||
}
|
||||
|
||||
fn layer(input: u32) -> u32 {
|
||||
f32::ceil((f32::sqrt(input as f32) + 1.0) / 2.0) as u32
|
||||
}
|
||||
|
||||
pub fn part_1(input: u32) -> u32 {
|
||||
if input == 1 {
|
||||
return 0;
|
||||
}
|
||||
// Which layer are we in?
|
||||
let layer = layer(input);
|
||||
// Where did this layer start?
|
||||
let start = (2 * layer - 3) * (2 * layer - 3) + 1;
|
||||
let right_middle = start + layer - 2;
|
||||
if input <= right_middle {
|
||||
return right_middle - input + layer - 1;
|
||||
}
|
||||
let right_top = right_middle + layer - 1;
|
||||
if input <= right_top {
|
||||
return input - right_middle + layer - 1;
|
||||
}
|
||||
let middle_top = right_top + layer - 1;
|
||||
if input <= middle_top {
|
||||
return middle_top - input + layer - 1;
|
||||
}
|
||||
let left_top = middle_top + layer - 1;
|
||||
if input <= left_top {
|
||||
return input - middle_top + layer - 1;
|
||||
}
|
||||
let left_middle = left_top + layer - 1;
|
||||
if input <= left_middle {
|
||||
return left_middle - input + layer - 1;
|
||||
}
|
||||
let left_bottom = left_middle + layer - 1;
|
||||
if input <= left_bottom {
|
||||
return input - left_middle + layer - 1;
|
||||
}
|
||||
let middle_bottom = left_bottom + layer - 1;
|
||||
if input <= middle_bottom {
|
||||
return middle_bottom - input + layer - 1;
|
||||
}
|
||||
input - middle_bottom + layer - 1
|
||||
}
|
||||
|
||||
fn layer_size(layer: usize) -> usize {
|
||||
if layer == 1 {
|
||||
1
|
||||
} else {
|
||||
let s = 2 * layer - 1;
|
||||
let t = 2 * (layer - 1) - 1;
|
||||
(s * s) - (t * t)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod layer_test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn layer_test_1() {
|
||||
assert_eq!(layer_size(1), 1);
|
||||
assert_eq!(layer_size(2), 8);
|
||||
assert_eq!(layer_size(3), 16);
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! set_or_return {
|
||||
( $x:expr, $input:ident, $val: expr) => {{
|
||||
$x = $val;
|
||||
if $x > $input {
|
||||
return $x;
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
pub fn part_2(input: u32) -> u32 {
|
||||
let mut prev_layer: Vec<u32> = vec![1, 2, 4, 5, 10, 11, 23, 25];
|
||||
if input < 25 {
|
||||
return prev_layer.iter().cloned().find(|&i| i > input).unwrap();
|
||||
}
|
||||
|
||||
for layer in 3.. {
|
||||
let mut curr_layer = vec![0; layer_size(layer)];
|
||||
|
||||
// Starting one place above the bottom-right, fill in anticlockwise.
|
||||
// The right-hand edge, where for the purposes of this loop only,
|
||||
// our `i` is viewing itself as ranging over the actual indices.
|
||||
// So i = 1 means we're one step above the bottom of the layer (i.e. it's
|
||||
// the smallest element in the layer).
|
||||
// As this loop views things, i = 0 would be the largest element in the layer.
|
||||
// Note, though, that `curr_layer` is still indexed from 0 being the smallest
|
||||
// element.
|
||||
set_or_return!(
|
||||
curr_layer[0],
|
||||
input,
|
||||
prev_layer[0] + prev_layer[prev_layer.len() - 1]
|
||||
);
|
||||
set_or_return!(
|
||||
curr_layer[1],
|
||||
input,
|
||||
prev_layer[0] + prev_layer[1] + curr_layer[0] + prev_layer[prev_layer.len() - 1]
|
||||
);
|
||||
// 3 -> 2
|
||||
// 4 -> 4
|
||||
for i in 2..(2 * layer - 4) {
|
||||
set_or_return!(
|
||||
curr_layer[i],
|
||||
input,
|
||||
curr_layer[i - 1] + prev_layer[i - 2] + prev_layer[i - 1] + prev_layer[i]
|
||||
);
|
||||
}
|
||||
// Top-right corner and its neighbours
|
||||
set_or_return!(
|
||||
curr_layer[2 * layer - 4],
|
||||
input,
|
||||
curr_layer[2 * layer - 5]
|
||||
+ prev_layer[2 * (layer - 1) - 3]
|
||||
+ prev_layer[2 * (layer - 1) - 4]
|
||||
);
|
||||
set_or_return!(
|
||||
curr_layer[2 * layer - 3],
|
||||
input,
|
||||
curr_layer[2 * layer - 4] + prev_layer[2 * (layer - 1) - 3]
|
||||
);
|
||||
|
||||
// Walking along the top edge now
|
||||
set_or_return!(
|
||||
curr_layer[2 * layer - 2],
|
||||
input,
|
||||
curr_layer[2 * layer - 3]
|
||||
+ curr_layer[2 * layer - 4]
|
||||
+ prev_layer[2 * (layer - 1) - 3]
|
||||
+ prev_layer[2 * (layer - 1) - 2]
|
||||
);
|
||||
|
||||
for i in 2..(2 * layer - 3) {
|
||||
set_or_return!(
|
||||
curr_layer[2 * layer - 3 + i],
|
||||
input,
|
||||
curr_layer[2 * layer - 4 + i]
|
||||
+ prev_layer[2 * (layer - 2) + i - 3]
|
||||
+ prev_layer[2 * (layer - 2) + i - 2]
|
||||
+ prev_layer[2 * (layer - 2) + i - 1]
|
||||
);
|
||||
}
|
||||
// The top-left corner, and its two surrounding squares
|
||||
set_or_return!(
|
||||
curr_layer[4 * (layer - 1) - 2],
|
||||
input,
|
||||
curr_layer[4 * (layer - 1) - 3]
|
||||
+ prev_layer[4 * (layer - 2) - 2]
|
||||
+ prev_layer[4 * (layer - 2) - 1]
|
||||
);
|
||||
set_or_return!(
|
||||
curr_layer[4 * (layer - 1) - 1],
|
||||
input,
|
||||
curr_layer[4 * (layer - 1) - 2] + prev_layer[4 * (layer - 2) - 1]
|
||||
);
|
||||
set_or_return!(
|
||||
curr_layer[4 * (layer - 1)],
|
||||
input,
|
||||
curr_layer[4 * (layer - 1) - 1]
|
||||
+ curr_layer[4 * (layer - 1) - 2]
|
||||
+ prev_layer[4 * (layer - 2) - 1]
|
||||
+ prev_layer[4 * (layer - 2)]
|
||||
);
|
||||
|
||||
// Walk along the left edge
|
||||
for i in 2..(2 * layer - 3) {
|
||||
set_or_return!(
|
||||
curr_layer[4 * (layer - 1) + i - 1],
|
||||
input,
|
||||
curr_layer[4 * (layer - 1) + i - 2]
|
||||
+ prev_layer[4 * (layer - 2) + i - 3]
|
||||
+ prev_layer[4 * (layer - 2) + i - 2]
|
||||
+ prev_layer[4 * (layer - 2) + i - 1]
|
||||
);
|
||||
}
|
||||
|
||||
// The bottom-left corner, and its two surrounding squares
|
||||
set_or_return!(
|
||||
curr_layer[6 * layer - 8],
|
||||
input,
|
||||
curr_layer[6 * layer - 9] + prev_layer[6 * layer - 14] + prev_layer[6 * layer - 13]
|
||||
);
|
||||
set_or_return!(
|
||||
curr_layer[6 * layer - 7],
|
||||
input,
|
||||
curr_layer[6 * layer - 8] + prev_layer[6 * layer - 13]
|
||||
);
|
||||
set_or_return!(
|
||||
curr_layer[6 * layer - 6],
|
||||
input,
|
||||
curr_layer[6 * layer - 7]
|
||||
+ curr_layer[6 * layer - 8]
|
||||
+ prev_layer[6 * layer - 13]
|
||||
+ prev_layer[6 * layer - 12]
|
||||
);
|
||||
|
||||
// Walk along the bottom edge
|
||||
for i in 2..(2 * layer - 3) {
|
||||
set_or_return!(
|
||||
curr_layer[6 * (layer - 1) + i - 1],
|
||||
input,
|
||||
curr_layer[6 * (layer - 1) + i - 2]
|
||||
+ prev_layer[6 * (layer - 2) + i - 3]
|
||||
+ prev_layer[6 * (layer - 2) + i - 2]
|
||||
+ prev_layer[6 * (layer - 2) + i - 1]
|
||||
);
|
||||
}
|
||||
|
||||
// The bottom-left corner and the square one to its left
|
||||
set_or_return!(
|
||||
curr_layer[8 * layer - 10],
|
||||
input,
|
||||
curr_layer[8 * layer - 11]
|
||||
+ prev_layer[prev_layer.len() - 1]
|
||||
+ prev_layer[prev_layer.len() - 2]
|
||||
+ curr_layer[0]
|
||||
);
|
||||
set_or_return!(
|
||||
curr_layer[8 * layer - 9],
|
||||
input,
|
||||
curr_layer[8 * layer - 10] + prev_layer[prev_layer.len() - 1] + curr_layer[0]
|
||||
);
|
||||
|
||||
prev_layer = curr_layer;
|
||||
}
|
||||
|
||||
panic!("How could we have broken out of this infinite loop?!")
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::day_3::*;
|
||||
|
||||
#[test]
|
||||
fn part1_known() {
|
||||
assert_eq!(part_1(1), 0);
|
||||
assert_eq!(part_1(2), 1);
|
||||
assert_eq!(part_1(3), 2);
|
||||
assert_eq!(part_1(4), 1);
|
||||
assert_eq!(part_1(5), 2);
|
||||
assert_eq!(part_1(6), 1);
|
||||
assert_eq!(part_1(7), 2);
|
||||
assert_eq!(part_1(8), 1);
|
||||
assert_eq!(part_1(9), 2);
|
||||
assert_eq!(part_1(10), 3);
|
||||
assert_eq!(part_1(11), 2);
|
||||
assert_eq!(part_1(12), 3);
|
||||
assert_eq!(part_1(13), 4);
|
||||
assert_eq!(part_1(14), 3);
|
||||
assert_eq!(part_1(15), 2);
|
||||
assert_eq!(part_1(16), 3);
|
||||
assert_eq!(part_1(17), 4);
|
||||
assert_eq!(part_1(18), 3);
|
||||
assert_eq!(part_1(19), 2);
|
||||
assert_eq!(part_1(20), 3);
|
||||
assert_eq!(part_1(21), 4);
|
||||
assert_eq!(part_1(22), 3);
|
||||
assert_eq!(part_1(23), 2);
|
||||
assert_eq!(part_1(24), 3);
|
||||
assert_eq!(part_1(25), 4);
|
||||
assert_eq!(part_1(26), 5);
|
||||
assert_eq!(part_1(1024), 31);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_day_3() {
|
||||
let input = input();
|
||||
let answer = part_1(input);
|
||||
assert_eq!(answer, 438);
|
||||
let answer = part_2(input);
|
||||
assert_eq!(answer, 266330);
|
||||
}
|
||||
}
|
@@ -1,290 +1,7 @@
|
||||
fn input() -> u32 {
|
||||
let input = include_str!("../input.txt");
|
||||
input
|
||||
.trim()
|
||||
.parse()
|
||||
.unwrap_or_else(|_| panic!("{} wasn't a valid u32", input))
|
||||
}
|
||||
|
||||
fn layer(input: u32) -> u32 {
|
||||
f32::ceil((f32::sqrt(input as f32) + 1.0) / 2.0) as u32
|
||||
}
|
||||
|
||||
pub fn part_1(input: u32) -> u32 {
|
||||
if input == 1 {
|
||||
return 0;
|
||||
}
|
||||
// Which layer are we in?
|
||||
let layer = layer(input);
|
||||
// Where did this layer start?
|
||||
let start = (2 * layer - 3) * (2 * layer - 3) + 1;
|
||||
let right_middle = start + layer - 2;
|
||||
if input <= right_middle {
|
||||
return right_middle - input + layer - 1;
|
||||
}
|
||||
let right_top = right_middle + layer - 1;
|
||||
if input <= right_top {
|
||||
return input - right_middle + layer - 1;
|
||||
}
|
||||
let middle_top = right_top + layer - 1;
|
||||
if input <= middle_top {
|
||||
return middle_top - input + layer - 1;
|
||||
}
|
||||
let left_top = middle_top + layer - 1;
|
||||
if input <= left_top {
|
||||
return input - middle_top + layer - 1;
|
||||
}
|
||||
let left_middle = left_top + layer - 1;
|
||||
if input <= left_middle {
|
||||
return left_middle - input + layer - 1;
|
||||
}
|
||||
let left_bottom = left_middle + layer - 1;
|
||||
if input <= left_bottom {
|
||||
return input - left_middle + layer - 1;
|
||||
}
|
||||
let middle_bottom = left_bottom + layer - 1;
|
||||
if input <= middle_bottom {
|
||||
return middle_bottom - input + layer - 1;
|
||||
}
|
||||
input - middle_bottom + layer - 1
|
||||
}
|
||||
|
||||
fn layer_size(layer: usize) -> usize {
|
||||
if layer == 1 {
|
||||
1
|
||||
} else {
|
||||
let s = 2 * layer - 1;
|
||||
let t = 2 * (layer - 1) - 1;
|
||||
(s * s) - (t * t)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod layer_test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn layer_test_1() {
|
||||
assert_eq!(layer_size(1), 1);
|
||||
assert_eq!(layer_size(2), 8);
|
||||
assert_eq!(layer_size(3), 16);
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! set_or_return {
|
||||
( $x:expr, $input:ident, $val: expr) => {{
|
||||
$x = $val;
|
||||
if $x > $input {
|
||||
return $x;
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
pub fn part_2(input: u32) -> u32 {
|
||||
let mut prev_layer: Vec<u32> = vec![1, 2, 4, 5, 10, 11, 23, 25];
|
||||
if input < 25 {
|
||||
return prev_layer.iter().cloned().find(|&i| i > input).unwrap();
|
||||
}
|
||||
|
||||
for layer in 3.. {
|
||||
let mut curr_layer = vec![0; layer_size(layer)];
|
||||
|
||||
// Starting one place above the bottom-right, fill in anticlockwise.
|
||||
// The right-hand edge, where for the purposes of this loop only,
|
||||
// our `i` is viewing itself as ranging over the actual indices.
|
||||
// So i = 1 means we're one step above the bottom of the layer (i.e. it's
|
||||
// the smallest element in the layer).
|
||||
// As this loop views things, i = 0 would be the largest element in the layer.
|
||||
// Note, though, that `curr_layer` is still indexed from 0 being the smallest
|
||||
// element.
|
||||
set_or_return!(
|
||||
curr_layer[0],
|
||||
input,
|
||||
prev_layer[0] + prev_layer[prev_layer.len() - 1]
|
||||
);
|
||||
set_or_return!(
|
||||
curr_layer[1],
|
||||
input,
|
||||
prev_layer[0] + prev_layer[1] + curr_layer[0] + prev_layer[prev_layer.len() - 1]
|
||||
);
|
||||
// 3 -> 2
|
||||
// 4 -> 4
|
||||
for i in 2..(2 * layer - 4) {
|
||||
set_or_return!(
|
||||
curr_layer[i],
|
||||
input,
|
||||
curr_layer[i - 1] + prev_layer[i - 2] + prev_layer[i - 1] + prev_layer[i]
|
||||
);
|
||||
}
|
||||
// Top-right corner and its neighbours
|
||||
set_or_return!(
|
||||
curr_layer[2 * layer - 4],
|
||||
input,
|
||||
curr_layer[2 * layer - 5]
|
||||
+ prev_layer[2 * (layer - 1) - 3]
|
||||
+ prev_layer[2 * (layer - 1) - 4]
|
||||
);
|
||||
set_or_return!(
|
||||
curr_layer[2 * layer - 3],
|
||||
input,
|
||||
curr_layer[2 * layer - 4] + prev_layer[2 * (layer - 1) - 3]
|
||||
);
|
||||
|
||||
// Walking along the top edge now
|
||||
set_or_return!(
|
||||
curr_layer[2 * layer - 2],
|
||||
input,
|
||||
curr_layer[2 * layer - 3]
|
||||
+ curr_layer[2 * layer - 4]
|
||||
+ prev_layer[2 * (layer - 1) - 3]
|
||||
+ prev_layer[2 * (layer - 1) - 2]
|
||||
);
|
||||
|
||||
for i in 2..(2 * layer - 3) {
|
||||
set_or_return!(
|
||||
curr_layer[2 * layer - 3 + i],
|
||||
input,
|
||||
curr_layer[2 * layer - 4 + i]
|
||||
+ prev_layer[2 * (layer - 2) + i - 3]
|
||||
+ prev_layer[2 * (layer - 2) + i - 2]
|
||||
+ prev_layer[2 * (layer - 2) + i - 1]
|
||||
);
|
||||
}
|
||||
// The top-left corner, and its two surrounding squares
|
||||
set_or_return!(
|
||||
curr_layer[4 * (layer - 1) - 2],
|
||||
input,
|
||||
curr_layer[4 * (layer - 1) - 3]
|
||||
+ prev_layer[4 * (layer - 2) - 2]
|
||||
+ prev_layer[4 * (layer - 2) - 1]
|
||||
);
|
||||
set_or_return!(
|
||||
curr_layer[4 * (layer - 1) - 1],
|
||||
input,
|
||||
curr_layer[4 * (layer - 1) - 2] + prev_layer[4 * (layer - 2) - 1]
|
||||
);
|
||||
set_or_return!(
|
||||
curr_layer[4 * (layer - 1)],
|
||||
input,
|
||||
curr_layer[4 * (layer - 1) - 1]
|
||||
+ curr_layer[4 * (layer - 1) - 2]
|
||||
+ prev_layer[4 * (layer - 2) - 1]
|
||||
+ prev_layer[4 * (layer - 2)]
|
||||
);
|
||||
|
||||
// Walk along the left edge
|
||||
for i in 2..(2 * layer - 3) {
|
||||
set_or_return!(
|
||||
curr_layer[4 * (layer - 1) + i - 1],
|
||||
input,
|
||||
curr_layer[4 * (layer - 1) + i - 2]
|
||||
+ prev_layer[4 * (layer - 2) + i - 3]
|
||||
+ prev_layer[4 * (layer - 2) + i - 2]
|
||||
+ prev_layer[4 * (layer - 2) + i - 1]
|
||||
);
|
||||
}
|
||||
|
||||
// The bottom-left corner, and its two surrounding squares
|
||||
set_or_return!(
|
||||
curr_layer[6 * layer - 8],
|
||||
input,
|
||||
curr_layer[6 * layer - 9] + prev_layer[6 * layer - 14] + prev_layer[6 * layer - 13]
|
||||
);
|
||||
set_or_return!(
|
||||
curr_layer[6 * layer - 7],
|
||||
input,
|
||||
curr_layer[6 * layer - 8] + prev_layer[6 * layer - 13]
|
||||
);
|
||||
set_or_return!(
|
||||
curr_layer[6 * layer - 6],
|
||||
input,
|
||||
curr_layer[6 * layer - 7]
|
||||
+ curr_layer[6 * layer - 8]
|
||||
+ prev_layer[6 * layer - 13]
|
||||
+ prev_layer[6 * layer - 12]
|
||||
);
|
||||
|
||||
// Walk along the bottom edge
|
||||
for i in 2..(2 * layer - 3) {
|
||||
set_or_return!(
|
||||
curr_layer[6 * (layer - 1) + i - 1],
|
||||
input,
|
||||
curr_layer[6 * (layer - 1) + i - 2]
|
||||
+ prev_layer[6 * (layer - 2) + i - 3]
|
||||
+ prev_layer[6 * (layer - 2) + i - 2]
|
||||
+ prev_layer[6 * (layer - 2) + i - 1]
|
||||
);
|
||||
}
|
||||
|
||||
// The bottom-left corner and the square one to its left
|
||||
set_or_return!(
|
||||
curr_layer[8 * layer - 10],
|
||||
input,
|
||||
curr_layer[8 * layer - 11]
|
||||
+ prev_layer[prev_layer.len() - 1]
|
||||
+ prev_layer[prev_layer.len() - 2]
|
||||
+ curr_layer[0]
|
||||
);
|
||||
set_or_return!(
|
||||
curr_layer[8 * layer - 9],
|
||||
input,
|
||||
curr_layer[8 * layer - 10] + prev_layer[prev_layer.len() - 1] + curr_layer[0]
|
||||
);
|
||||
|
||||
prev_layer = curr_layer;
|
||||
}
|
||||
|
||||
panic!("How could we have broken out of this infinite loop?!")
|
||||
}
|
||||
use day_3::day_3;
|
||||
|
||||
fn main() {
|
||||
let input = input();
|
||||
println!("part 1 => {}", part_1(input));
|
||||
println!("part 2 => {}", part_2(input));
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn part1_known() {
|
||||
assert_eq!(part_1(1), 0);
|
||||
assert_eq!(part_1(2), 1);
|
||||
assert_eq!(part_1(3), 2);
|
||||
assert_eq!(part_1(4), 1);
|
||||
assert_eq!(part_1(5), 2);
|
||||
assert_eq!(part_1(6), 1);
|
||||
assert_eq!(part_1(7), 2);
|
||||
assert_eq!(part_1(8), 1);
|
||||
assert_eq!(part_1(9), 2);
|
||||
assert_eq!(part_1(10), 3);
|
||||
assert_eq!(part_1(11), 2);
|
||||
assert_eq!(part_1(12), 3);
|
||||
assert_eq!(part_1(13), 4);
|
||||
assert_eq!(part_1(14), 3);
|
||||
assert_eq!(part_1(15), 2);
|
||||
assert_eq!(part_1(16), 3);
|
||||
assert_eq!(part_1(17), 4);
|
||||
assert_eq!(part_1(18), 3);
|
||||
assert_eq!(part_1(19), 2);
|
||||
assert_eq!(part_1(20), 3);
|
||||
assert_eq!(part_1(21), 4);
|
||||
assert_eq!(part_1(22), 3);
|
||||
assert_eq!(part_1(23), 2);
|
||||
assert_eq!(part_1(24), 3);
|
||||
assert_eq!(part_1(25), 4);
|
||||
assert_eq!(part_1(26), 5);
|
||||
assert_eq!(part_1(1024), 31);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_day_3() {
|
||||
let input = input();
|
||||
let answer = part_1(input);
|
||||
assert_eq!(answer, 438);
|
||||
let answer = part_2(input);
|
||||
assert_eq!(answer, 266330);
|
||||
}
|
||||
let input = day_3::input();
|
||||
println!("part 1 => {}", day_3::part_1(input));
|
||||
println!("part 2 => {}", day_3::part_2(input));
|
||||
}
|
||||
|
85
day_4/src/lib.rs
Normal file
85
day_4/src/lib.rs
Normal file
@@ -0,0 +1,85 @@
|
||||
pub mod day_4 {
|
||||
|
||||
use std::collections::HashSet;
|
||||
use std::hash::Hash;
|
||||
|
||||
pub fn input() -> Vec<Vec<&'static str>> {
|
||||
let input = include_str!("../input.txt");
|
||||
input
|
||||
.lines()
|
||||
.map(|l| l.split_whitespace().collect())
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn contains_duplicate<I, X>(i: &mut I) -> bool
|
||||
where
|
||||
I: Iterator<Item = X>,
|
||||
X: Eq + Hash,
|
||||
{
|
||||
let mut so_far = HashSet::new();
|
||||
for elt in i {
|
||||
if !so_far.insert(elt) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
pub fn part_1(input: &[Vec<&str>]) -> usize {
|
||||
input
|
||||
.iter()
|
||||
.filter(|words| !contains_duplicate(&mut words.iter()))
|
||||
.count()
|
||||
}
|
||||
|
||||
pub fn part_2(input: &[Vec<&str>]) -> usize {
|
||||
input
|
||||
.iter()
|
||||
.filter(|words| {
|
||||
!contains_duplicate(&mut words.iter().map(|&w| {
|
||||
let mut w = w.chars().collect::<Vec<char>>();
|
||||
w.sort_unstable();
|
||||
w
|
||||
}))
|
||||
})
|
||||
.count()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::day_4::*;
|
||||
|
||||
#[test]
|
||||
fn part1_known() {
|
||||
assert_eq!(
|
||||
part_1(&vec![
|
||||
vec!["aa", "bb", "cc", "dd", "ee"],
|
||||
vec!["aa", "bb", "cc", "dd", "aa"],
|
||||
vec!["aa", "bb", "cc", "dd", "aaa"]
|
||||
]),
|
||||
2
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn part2_known() {
|
||||
assert_eq!(
|
||||
part_2(&vec![
|
||||
vec!["abcde", "fghij"],
|
||||
vec!["abcde", "xyz", "ecdab"],
|
||||
vec!["a", "ab", "abc", "abd", "abf", "abj"],
|
||||
vec!["iiii", "oiii", "ooii", "oooi", "oooo"],
|
||||
vec!["oiii", "ioii", "iioi", "iiio"]
|
||||
]),
|
||||
3
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_day_4() {
|
||||
let input = input();
|
||||
assert_eq!(part_1(&input), 325);
|
||||
assert_eq!(part_2(&input), 119);
|
||||
}
|
||||
}
|
@@ -1,88 +1,7 @@
|
||||
use std::collections::HashSet;
|
||||
use std::hash::Hash;
|
||||
|
||||
fn input() -> Vec<Vec<&'static str>> {
|
||||
let input = include_str!("../input.txt");
|
||||
input
|
||||
.lines()
|
||||
.map(|l| l.split_whitespace().collect())
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn contains_duplicate<I, X>(i: &mut I) -> bool
|
||||
where
|
||||
I: Iterator<Item = X>,
|
||||
X: Eq + Hash,
|
||||
{
|
||||
let mut so_far = HashSet::new();
|
||||
for elt in i {
|
||||
if !so_far.insert(elt) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
pub fn part_1(input: &[Vec<&str>]) -> usize {
|
||||
input
|
||||
.iter()
|
||||
.filter(|words| !contains_duplicate(&mut words.iter()))
|
||||
.count()
|
||||
}
|
||||
|
||||
pub fn part_2(input: &[Vec<&str>]) -> usize {
|
||||
input
|
||||
.iter()
|
||||
.filter(|words| {
|
||||
!contains_duplicate(&mut words.iter().map(|&w| {
|
||||
let mut w = w.chars().collect::<Vec<char>>();
|
||||
w.sort_unstable();
|
||||
w
|
||||
}))
|
||||
})
|
||||
.count()
|
||||
}
|
||||
use day_4::day_4;
|
||||
|
||||
fn main() {
|
||||
let input = input();
|
||||
println!("part 1 => {}", part_1(&input));
|
||||
println!("part 2 => {}", part_2(&input));
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn part1_known() {
|
||||
assert_eq!(
|
||||
part_1(&vec![
|
||||
vec!["aa", "bb", "cc", "dd", "ee"],
|
||||
vec!["aa", "bb", "cc", "dd", "aa"],
|
||||
vec!["aa", "bb", "cc", "dd", "aaa"]
|
||||
]),
|
||||
2
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn part2_known() {
|
||||
assert_eq!(
|
||||
part_2(&vec![
|
||||
vec!["abcde", "fghij"],
|
||||
vec!["abcde", "xyz", "ecdab"],
|
||||
vec!["a", "ab", "abc", "abd", "abf", "abj"],
|
||||
vec!["iiii", "oiii", "ooii", "oooi", "oooo"],
|
||||
vec!["oiii", "ioii", "iioi", "iiio"]
|
||||
]),
|
||||
3
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_day_4() {
|
||||
let input = input();
|
||||
assert_eq!(part_1(&input), 325);
|
||||
assert_eq!(part_2(&input), 119);
|
||||
}
|
||||
let input = day_4::input();
|
||||
println!("part 1 => {}", day_4::part_1(&input));
|
||||
println!("part 2 => {}", day_4::part_2(&input));
|
||||
}
|
||||
|
@@ -7,3 +7,9 @@ edition = "2018"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
[dev_dependencies]
|
||||
criterion = "0.3"
|
||||
|
||||
[[bench]]
|
||||
name = "day_5_part_2"
|
||||
harness = false
|
||||
|
15
day_5/benches/day_5_part_2.rs
Normal file
15
day_5/benches/day_5_part_2.rs
Normal file
@@ -0,0 +1,15 @@
|
||||
use criterion::{criterion_group, criterion_main, Criterion};
|
||||
use day_5::day_5::{input, part_2};
|
||||
|
||||
fn criterion_benchmark(c: &mut Criterion) {
|
||||
c.bench_function("part 2", |b| {
|
||||
let input = input();
|
||||
b.iter(|| {
|
||||
let mut input = input.to_vec();
|
||||
part_2(&mut input);
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
criterion_group!(benches, criterion_benchmark);
|
||||
criterion_main!(benches);
|
73
day_5/src/lib.rs
Normal file
73
day_5/src/lib.rs
Normal file
@@ -0,0 +1,73 @@
|
||||
pub mod day_5 {
|
||||
use std::convert::TryFrom;
|
||||
|
||||
pub fn input() -> Vec<i32> {
|
||||
let input = include_str!("../input.txt");
|
||||
input
|
||||
.lines()
|
||||
.map(|l| {
|
||||
l.parse()
|
||||
.unwrap_or_else(|_| panic!("{} wasn't a valid u32", l))
|
||||
})
|
||||
.collect::<Vec<i32>>()
|
||||
}
|
||||
|
||||
pub fn part_1(v: &mut Vec<i32>) -> u32 {
|
||||
let mut count = 0;
|
||||
let mut index: usize = 0;
|
||||
while index < v.len() {
|
||||
let bounce = v[index];
|
||||
v[index] = bounce + 1;
|
||||
let test = i32::try_from(index).unwrap() + bounce;
|
||||
if test < 0 {
|
||||
return count;
|
||||
}
|
||||
index = usize::try_from(test).unwrap();
|
||||
count += 1;
|
||||
}
|
||||
count
|
||||
}
|
||||
|
||||
pub fn part_2(v: &mut Vec<i32>) -> u32 {
|
||||
let mut count = 0;
|
||||
let mut index: usize = 0;
|
||||
while index < v.len() {
|
||||
let bounce = v[index];
|
||||
if bounce >= 3 {
|
||||
v[index] = bounce - 1;
|
||||
} else {
|
||||
v[index] = bounce + 1;
|
||||
}
|
||||
let test = i32::try_from(index).unwrap() + bounce;
|
||||
if test < 0 {
|
||||
return count;
|
||||
}
|
||||
index = usize::try_from(test).unwrap();
|
||||
count += 1;
|
||||
}
|
||||
count
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::day_5::*;
|
||||
|
||||
#[test]
|
||||
fn part1_known() {
|
||||
assert_eq!(part_1(&mut vec![0, 3, 0, 1, -3]), 5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn part2_known() {
|
||||
assert_eq!(part_2(&mut vec![0, 3, 0, 1, -3]), 10);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_day_5() {
|
||||
let input = input();
|
||||
assert_eq!(part_1(&mut input.clone()), 391540);
|
||||
let mut input = input;
|
||||
assert_eq!(part_2(&mut input), 30513679);
|
||||
}
|
||||
}
|
@@ -1,78 +1,8 @@
|
||||
use std::convert::TryFrom;
|
||||
|
||||
fn input() -> Vec<i32> {
|
||||
let input = include_str!("../input.txt");
|
||||
input
|
||||
.lines()
|
||||
.map(|l| {
|
||||
l.parse()
|
||||
.unwrap_or_else(|_| panic!("{} wasn't a valid u32", l))
|
||||
})
|
||||
.collect::<Vec<i32>>()
|
||||
}
|
||||
|
||||
pub fn part_1(v: &mut Vec<i32>) -> u32 {
|
||||
let mut count = 0;
|
||||
let mut index: usize = 0;
|
||||
while index < v.len() {
|
||||
let bounce = v[index];
|
||||
v[index] = bounce + 1;
|
||||
let test = i32::try_from(index).unwrap() + bounce;
|
||||
if test < 0 {
|
||||
return count;
|
||||
}
|
||||
index = usize::try_from(test).unwrap();
|
||||
count += 1;
|
||||
}
|
||||
count
|
||||
}
|
||||
|
||||
pub fn part_2(v: &mut Vec<i32>) -> u32 {
|
||||
let mut count = 0;
|
||||
let mut index: usize = 0;
|
||||
while index < v.len() {
|
||||
let bounce = v[index];
|
||||
if bounce >= 3 {
|
||||
v[index] = bounce - 1;
|
||||
} else {
|
||||
v[index] = bounce + 1;
|
||||
}
|
||||
let test = i32::try_from(index).unwrap() + bounce;
|
||||
if test < 0 {
|
||||
return count;
|
||||
}
|
||||
index = usize::try_from(test).unwrap();
|
||||
count += 1;
|
||||
}
|
||||
count
|
||||
}
|
||||
use day_5::day_5;
|
||||
|
||||
fn main() {
|
||||
let input = input();
|
||||
println!("part 1 => {}", part_1(&mut input.clone()));
|
||||
let input = day_5::input();
|
||||
println!("part 1 => {}", day_5::part_1(&mut input.clone()));
|
||||
let mut input = input;
|
||||
println!("part 2 => {}", part_2(&mut input));
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn part1_known() {
|
||||
assert_eq!(part_1(&mut vec![0, 3, 0, 1, -3]), 5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn part2_known() {
|
||||
assert_eq!(part_2(&mut vec![0, 3, 0, 1, -3]), 10);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_day_5() {
|
||||
let input = input();
|
||||
assert_eq!(part_1(&mut input.clone()), 391540);
|
||||
let mut input = input;
|
||||
assert_eq!(part_2(&mut input), 30513679);
|
||||
}
|
||||
println!("part 2 => {}", day_5::part_2(&mut input));
|
||||
}
|
||||
|
103
day_6/src/lib.rs
Normal file
103
day_6/src/lib.rs
Normal file
@@ -0,0 +1,103 @@
|
||||
pub mod day_6 {
|
||||
use std::collections::HashMap;
|
||||
use std::collections::HashSet;
|
||||
|
||||
pub fn input() -> Vec<u32> {
|
||||
let input = include_str!("../input.txt");
|
||||
input
|
||||
.trim()
|
||||
.split_whitespace()
|
||||
.map(|i| {
|
||||
i.parse()
|
||||
.unwrap_or_else(|_| panic!("{} wasn't a valid u32", i))
|
||||
})
|
||||
.collect::<Vec<u32>>()
|
||||
}
|
||||
|
||||
pub fn part_1(v: &mut [u32]) -> u32 {
|
||||
let len = v.len() as u32;
|
||||
let mut seen: HashSet<Vec<u32>> = HashSet::new();
|
||||
let mut count = 0;
|
||||
let (mut max_pos, mut max) = v
|
||||
.iter()
|
||||
.cloned()
|
||||
.enumerate()
|
||||
.max_by_key(|(_, x)| *x)
|
||||
.unwrap();
|
||||
while seen.insert(v.to_vec()) {
|
||||
let extras = max % len;
|
||||
let all = max / len;
|
||||
v[max_pos] = 0;
|
||||
for i in 0..(extras as usize) {
|
||||
v[(max_pos + i + 1) % v.len()] += 1;
|
||||
}
|
||||
max = 0;
|
||||
for (i, item) in v.iter_mut().enumerate() {
|
||||
*item += all;
|
||||
if *item > max {
|
||||
max = *item;
|
||||
max_pos = i;
|
||||
}
|
||||
}
|
||||
count += 1;
|
||||
}
|
||||
count
|
||||
}
|
||||
|
||||
pub fn part_2(v: &mut [u32]) -> u32 {
|
||||
let len = v.len() as u32;
|
||||
let mut seen: HashMap<Vec<u32>, u32> = HashMap::new();
|
||||
let mut count = 0;
|
||||
let (mut max_pos, mut max) = v
|
||||
.iter()
|
||||
.cloned()
|
||||
.enumerate()
|
||||
.max_by_key(|(_, x)| *x)
|
||||
.unwrap();
|
||||
loop {
|
||||
if let Some(existing) = seen.insert(v.to_vec(), count) {
|
||||
return count - existing;
|
||||
}
|
||||
let extras = max % len;
|
||||
let all = max / len;
|
||||
v[max_pos] = 0;
|
||||
for i in 0..(extras as usize) {
|
||||
v[(max_pos + i + 1) % v.len()] += 1;
|
||||
}
|
||||
max = 0;
|
||||
for (i, item) in v.iter_mut().enumerate() {
|
||||
*item += all;
|
||||
if *item > max {
|
||||
max = *item;
|
||||
max_pos = i;
|
||||
}
|
||||
}
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::day_6::*;
|
||||
|
||||
#[test]
|
||||
fn part1_known() {
|
||||
assert_eq!(part_1(&mut vec![0, 2, 7, 0]), 5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn part2_known() {
|
||||
assert_eq!(part_2(&mut vec![0, 2, 7, 0]), 4);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_day_6() {
|
||||
let input = input();
|
||||
let answer = part_1(&mut input.clone());
|
||||
assert_eq!(answer, 4074);
|
||||
let mut input = input;
|
||||
let answer = part_2(&mut input);
|
||||
assert_eq!(answer, 2793);
|
||||
}
|
||||
}
|
@@ -1,108 +1,8 @@
|
||||
use std::collections::HashMap;
|
||||
use std::collections::HashSet;
|
||||
|
||||
fn input() -> Vec<u32> {
|
||||
let input = include_str!("../input.txt");
|
||||
input
|
||||
.trim()
|
||||
.split_whitespace()
|
||||
.map(|i| {
|
||||
i.parse()
|
||||
.unwrap_or_else(|_| panic!("{} wasn't a valid u32", i))
|
||||
})
|
||||
.collect::<Vec<u32>>()
|
||||
}
|
||||
|
||||
pub fn part_1(v: &mut [u32]) -> u32 {
|
||||
let len = v.len() as u32;
|
||||
let mut seen: HashSet<Vec<u32>> = HashSet::new();
|
||||
let mut count = 0;
|
||||
let (mut max_pos, mut max) = v
|
||||
.iter()
|
||||
.cloned()
|
||||
.enumerate()
|
||||
.max_by_key(|(_, x)| *x)
|
||||
.unwrap();
|
||||
while seen.insert(v.to_vec()) {
|
||||
let extras = max % len;
|
||||
let all = max / len;
|
||||
v[max_pos] = 0;
|
||||
for i in 0..(extras as usize) {
|
||||
v[(max_pos + i + 1) % v.len()] += 1;
|
||||
}
|
||||
max = 0;
|
||||
for (i, item) in v.iter_mut().enumerate() {
|
||||
*item += all;
|
||||
if *item > max {
|
||||
max = *item;
|
||||
max_pos = i;
|
||||
}
|
||||
}
|
||||
count += 1;
|
||||
}
|
||||
count
|
||||
}
|
||||
|
||||
pub fn part_2(v: &mut [u32]) -> u32 {
|
||||
let len = v.len() as u32;
|
||||
let mut seen: HashMap<Vec<u32>, u32> = HashMap::new();
|
||||
let mut count = 0;
|
||||
let (mut max_pos, mut max) = v
|
||||
.iter()
|
||||
.cloned()
|
||||
.enumerate()
|
||||
.max_by_key(|(_, x)| *x)
|
||||
.unwrap();
|
||||
loop {
|
||||
if let Some(existing) = seen.insert(v.to_vec(), count) {
|
||||
return count - existing;
|
||||
}
|
||||
let extras = max % len;
|
||||
let all = max / len;
|
||||
v[max_pos] = 0;
|
||||
for i in 0..(extras as usize) {
|
||||
v[(max_pos + i + 1) % v.len()] += 1;
|
||||
}
|
||||
max = 0;
|
||||
for (i, item) in v.iter_mut().enumerate() {
|
||||
*item += all;
|
||||
if *item > max {
|
||||
max = *item;
|
||||
max_pos = i;
|
||||
}
|
||||
}
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
use day_6::day_6;
|
||||
|
||||
fn main() {
|
||||
let input = input();
|
||||
println!("part 1 => {}", part_1(&mut input.clone()));
|
||||
let input = day_6::input();
|
||||
println!("part 1 => {}", day_6::part_1(&mut input.clone()));
|
||||
let mut input = input;
|
||||
println!("part 2 => {}", part_2(&mut input));
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn part1_known() {
|
||||
assert_eq!(part_1(&mut vec![0, 2, 7, 0]), 5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn part2_known() {
|
||||
assert_eq!(part_2(&mut vec![0, 2, 7, 0]), 4);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_day_6() {
|
||||
let input = input();
|
||||
let answer = part_1(&mut input.clone());
|
||||
assert_eq!(answer, 4074);
|
||||
let mut input = input;
|
||||
let answer = part_2(&mut input);
|
||||
assert_eq!(answer, 2793);
|
||||
}
|
||||
println!("part 2 => {}", day_6::part_2(&mut input));
|
||||
}
|
||||
|
370
day_7/src/lib.rs
Normal file
370
day_7/src/lib.rs
Normal file
@@ -0,0 +1,370 @@
|
||||
pub mod day_7 {
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct Node<'a> {
|
||||
pub(crate) name: &'a str,
|
||||
pub(crate) weight: u32,
|
||||
pub(crate) children: Vec<&'a str>,
|
||||
}
|
||||
|
||||
struct TreeNode<'a> {
|
||||
children: Vec<usize>,
|
||||
name: &'a str,
|
||||
weight: u32,
|
||||
}
|
||||
|
||||
struct Tree<'a> {
|
||||
nodes: Vec<TreeNode<'a>>,
|
||||
root: usize,
|
||||
}
|
||||
|
||||
enum ParserState {
|
||||
Name,
|
||||
ExpectBracket,
|
||||
Weight,
|
||||
AnyChildren(usize),
|
||||
ParseChild(usize),
|
||||
ExpectSpace,
|
||||
}
|
||||
|
||||
pub fn parse_line(s: &str) -> Node {
|
||||
let mut state = ParserState::Name;
|
||||
let mut count: usize = 0;
|
||||
let mut name_end = 0;
|
||||
let mut weight: u32 = 0;
|
||||
let mut children: Vec<&str> = vec![];
|
||||
|
||||
for chr in s.chars() {
|
||||
match state {
|
||||
ParserState::Name => {
|
||||
if chr == ' ' {
|
||||
state = ParserState::ExpectBracket;
|
||||
name_end = count;
|
||||
}
|
||||
}
|
||||
ParserState::ExpectBracket => {
|
||||
if chr != '(' {
|
||||
panic!("Malformed string! {}", s)
|
||||
}
|
||||
state = ParserState::Weight;
|
||||
}
|
||||
ParserState::Weight => {
|
||||
if chr == ')' {
|
||||
state = ParserState::AnyChildren(0);
|
||||
} else {
|
||||
weight = weight * 10
|
||||
+ chr
|
||||
.to_digit(10)
|
||||
.unwrap_or_else(|| panic!("Expected a digit, got {}", chr));
|
||||
}
|
||||
}
|
||||
ParserState::AnyChildren(i) => {
|
||||
if i < 3 {
|
||||
state = ParserState::AnyChildren(i + 1);
|
||||
} else {
|
||||
state = ParserState::ParseChild(count + 1);
|
||||
}
|
||||
}
|
||||
ParserState::ParseChild(start) => {
|
||||
if chr == ',' {
|
||||
children.push(&s[start..count]);
|
||||
state = ParserState::ExpectSpace;
|
||||
}
|
||||
}
|
||||
ParserState::ExpectSpace => {
|
||||
if chr != ' ' {
|
||||
panic!("Parse failure, expected space, got {}", chr);
|
||||
}
|
||||
state = ParserState::ParseChild(count + 1);
|
||||
}
|
||||
}
|
||||
count += 1;
|
||||
}
|
||||
|
||||
let name = &s[0..name_end];
|
||||
match state {
|
||||
ParserState::AnyChildren(0) => {
|
||||
// No children
|
||||
Node {
|
||||
name,
|
||||
weight,
|
||||
children,
|
||||
}
|
||||
}
|
||||
ParserState::ParseChild(start) => {
|
||||
children.push(&s[start..count]);
|
||||
Node {
|
||||
name,
|
||||
weight,
|
||||
children,
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
panic!("Parse failure");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn input() -> Vec<Node<'static>> {
|
||||
let input = include_str!("../input.txt");
|
||||
input.lines().map(|l| parse_line(l)).collect::<Vec<Node>>()
|
||||
}
|
||||
|
||||
fn tree_it<'a>(nodes: &[Node<'a>]) -> Tree<'a> {
|
||||
let nodes_by_name: HashMap<&'a str, (&Node<'a>, usize)> = nodes
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(count, i)| (i.name, (i, count)))
|
||||
.collect();
|
||||
let mut built: Vec<TreeNode<'a>> = nodes
|
||||
.iter()
|
||||
.map(|n| TreeNode {
|
||||
name: n.name,
|
||||
weight: n.weight,
|
||||
children: vec![],
|
||||
})
|
||||
.collect();
|
||||
let mut is_set: Vec<bool> = vec![false; nodes.len()];
|
||||
|
||||
let mut stack: Vec<usize> = vec![];
|
||||
for parent_node_index in 0..nodes.len() {
|
||||
if !is_set[parent_node_index] {
|
||||
stack.push(parent_node_index);
|
||||
while let Some(node_index) = stack.pop() {
|
||||
if is_set[node_index] {
|
||||
continue;
|
||||
}
|
||||
let node = &nodes[node_index];
|
||||
let children = (*node).children.iter().map(|&i| {
|
||||
let (_, child_index) = nodes_by_name.get(i).unwrap();
|
||||
*child_index
|
||||
});
|
||||
built[node_index].children.extend(children);
|
||||
stack.extend(built[node_index].children.iter());
|
||||
is_set[node_index] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We'll reuse the is_set array for an "is possibly the root" array.
|
||||
// They're all true now.
|
||||
for node in built.iter() {
|
||||
for child in node.children.iter() {
|
||||
is_set[*child] = false;
|
||||
}
|
||||
}
|
||||
let (top_node, _) = is_set.iter().enumerate().find(|(_, v)| **v).unwrap();
|
||||
Tree {
|
||||
nodes: built,
|
||||
root: top_node,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn part_1<'a>(nodes: &[Node<'a>]) -> &'a str {
|
||||
let tree = tree_it(nodes);
|
||||
tree.nodes[tree.root].name
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct BalancedWeight {
|
||||
child_weights: u32,
|
||||
self_weight: u32,
|
||||
child_count: usize,
|
||||
}
|
||||
|
||||
fn total_weight(b: &BalancedWeight) -> u32 {
|
||||
b.child_weights * (b.child_count as u32) + b.self_weight
|
||||
}
|
||||
|
||||
fn weight(tree: &Tree, node: usize) -> Result<BalancedWeight, i32> {
|
||||
let node = &tree.nodes[node];
|
||||
let children: Vec<_> = node
|
||||
.children
|
||||
.iter()
|
||||
.map(|node| weight(&tree, *node))
|
||||
.collect();
|
||||
|
||||
let count = children.len();
|
||||
let mut c = children.iter();
|
||||
let mut different_child = None;
|
||||
if let Some(child) = c.next() {
|
||||
match child {
|
||||
Err(e) => Err(*e),
|
||||
Ok(child) => {
|
||||
for other in c {
|
||||
match other {
|
||||
Err(e) => return Err(*e),
|
||||
Ok(other) => {
|
||||
if total_weight(other) != total_weight(child) {
|
||||
match different_child {
|
||||
None => {
|
||||
different_child = Some(other);
|
||||
}
|
||||
Some(different_child) => {
|
||||
if total_weight(other) == total_weight(different_child)
|
||||
{
|
||||
// The bad one is `child`.
|
||||
return Err(total_weight(other) as i32
|
||||
- (child.child_weights
|
||||
* child.child_count as u32)
|
||||
as i32);
|
||||
} else {
|
||||
// The bad one is `other`.
|
||||
return Err(total_weight(child) as i32
|
||||
- (other.child_weights
|
||||
* other.child_count as u32)
|
||||
as i32);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
match different_child {
|
||||
None => Ok(BalancedWeight {
|
||||
self_weight: node.weight,
|
||||
child_weights: total_weight(child),
|
||||
child_count: count,
|
||||
}),
|
||||
Some(different_child) => {
|
||||
// The bad one is `different_child`.
|
||||
Err(total_weight(child) as i32
|
||||
- (different_child.child_weights
|
||||
* different_child.child_count as u32)
|
||||
as i32)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Ok(BalancedWeight {
|
||||
self_weight: node.weight,
|
||||
child_weights: 0,
|
||||
child_count: 0,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn part_2(nodes: &[Node]) -> i32 {
|
||||
let tree = tree_it(nodes);
|
||||
let result = weight(&tree, tree.root);
|
||||
match result {
|
||||
Err(e) => e,
|
||||
Ok(w) => panic!("Expected unbalanced tree, got {:?}", w),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::day_7::*;
|
||||
|
||||
fn test_inputs() -> Vec<Node<'static>> {
|
||||
vec![
|
||||
Node {
|
||||
name: "pbga",
|
||||
weight: 66,
|
||||
children: vec![],
|
||||
},
|
||||
Node {
|
||||
name: "xhth",
|
||||
weight: 57,
|
||||
children: vec![],
|
||||
},
|
||||
Node {
|
||||
name: "ebii",
|
||||
weight: 61,
|
||||
children: vec![],
|
||||
},
|
||||
Node {
|
||||
name: "havc",
|
||||
weight: 66,
|
||||
children: vec![],
|
||||
},
|
||||
Node {
|
||||
name: "ktlj",
|
||||
weight: 57,
|
||||
children: vec![],
|
||||
},
|
||||
Node {
|
||||
name: "fwft",
|
||||
weight: 72,
|
||||
children: vec!["ktlj", "cntj", "xhth"],
|
||||
},
|
||||
Node {
|
||||
name: "qoyq",
|
||||
weight: 66,
|
||||
children: vec![],
|
||||
},
|
||||
Node {
|
||||
name: "padx",
|
||||
weight: 45,
|
||||
children: vec!["pbga", "havc", "qoyq"],
|
||||
},
|
||||
Node {
|
||||
name: "tknk",
|
||||
weight: 41,
|
||||
children: vec!["ugml", "padx", "fwft"],
|
||||
},
|
||||
Node {
|
||||
name: "jptl",
|
||||
weight: 61,
|
||||
children: vec![],
|
||||
},
|
||||
Node {
|
||||
name: "ugml",
|
||||
weight: 68,
|
||||
children: vec!["gyxo", "ebii", "jptl"],
|
||||
},
|
||||
Node {
|
||||
name: "gyxo",
|
||||
weight: 61,
|
||||
children: vec![],
|
||||
},
|
||||
Node {
|
||||
name: "cntj",
|
||||
weight: 57,
|
||||
children: vec![],
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse() {
|
||||
assert_eq!(
|
||||
parse_line("vvwrg (51)"),
|
||||
Node {
|
||||
name: "vvwrg",
|
||||
weight: 51,
|
||||
children: vec![]
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
parse_line("uglvj (99) -> ymfjt, gkpgf"),
|
||||
Node {
|
||||
name: "uglvj",
|
||||
weight: 99,
|
||||
children: vec!["ymfjt", "gkpgf"]
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn part1_known() {
|
||||
assert_eq!(part_1(&test_inputs()), "tknk");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn part2_known() {
|
||||
assert_eq!(part_2(&test_inputs()), 60);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_day_7() {
|
||||
let input = input();
|
||||
assert_eq!(part_1(&input), "dgoocsw");
|
||||
assert_eq!(part_2(&input), 1275);
|
||||
}
|
||||
}
|
@@ -1,370 +1,7 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
struct Node<'a> {
|
||||
name: &'a str,
|
||||
weight: u32,
|
||||
children: Vec<&'a str>,
|
||||
}
|
||||
|
||||
struct TreeNode<'a> {
|
||||
children: Vec<usize>,
|
||||
name: &'a str,
|
||||
weight: u32,
|
||||
}
|
||||
|
||||
struct Tree<'a> {
|
||||
nodes: Vec<TreeNode<'a>>,
|
||||
root: usize,
|
||||
}
|
||||
|
||||
enum ParserState {
|
||||
Name,
|
||||
ExpectBracket,
|
||||
Weight,
|
||||
AnyChildren(usize),
|
||||
ParseChild(usize),
|
||||
ExpectSpace,
|
||||
}
|
||||
|
||||
fn parse_line(s: &str) -> Node {
|
||||
let mut state = ParserState::Name;
|
||||
let mut count: usize = 0;
|
||||
let mut name_end = 0;
|
||||
let mut weight: u32 = 0;
|
||||
let mut children: Vec<&str> = vec![];
|
||||
|
||||
for chr in s.chars() {
|
||||
match state {
|
||||
ParserState::Name => {
|
||||
if chr == ' ' {
|
||||
state = ParserState::ExpectBracket;
|
||||
name_end = count;
|
||||
}
|
||||
}
|
||||
ParserState::ExpectBracket => {
|
||||
if chr != '(' {
|
||||
panic!("Malformed string! {}", s)
|
||||
}
|
||||
state = ParserState::Weight;
|
||||
}
|
||||
ParserState::Weight => {
|
||||
if chr == ')' {
|
||||
state = ParserState::AnyChildren(0);
|
||||
} else {
|
||||
weight = weight * 10
|
||||
+ chr
|
||||
.to_digit(10)
|
||||
.unwrap_or_else(|| panic!("Expected a digit, got {}", chr));
|
||||
}
|
||||
}
|
||||
ParserState::AnyChildren(i) => {
|
||||
if i < 3 {
|
||||
state = ParserState::AnyChildren(i + 1);
|
||||
} else {
|
||||
state = ParserState::ParseChild(count + 1);
|
||||
}
|
||||
}
|
||||
ParserState::ParseChild(start) => {
|
||||
if chr == ',' {
|
||||
children.push(&s[start..count]);
|
||||
state = ParserState::ExpectSpace;
|
||||
}
|
||||
}
|
||||
ParserState::ExpectSpace => {
|
||||
if chr != ' ' {
|
||||
panic!("Parse failure, expected space, got {}", chr);
|
||||
}
|
||||
state = ParserState::ParseChild(count + 1);
|
||||
}
|
||||
}
|
||||
count += 1;
|
||||
}
|
||||
|
||||
let name = &s[0..name_end];
|
||||
match state {
|
||||
ParserState::AnyChildren(0) => {
|
||||
// No children
|
||||
Node {
|
||||
name,
|
||||
weight,
|
||||
children,
|
||||
}
|
||||
}
|
||||
ParserState::ParseChild(start) => {
|
||||
children.push(&s[start..count]);
|
||||
Node {
|
||||
name,
|
||||
weight,
|
||||
children,
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
panic!("Parse failure");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn input() -> Vec<Node<'static>> {
|
||||
let input = include_str!("../input.txt");
|
||||
input.lines().map(|l| parse_line(l)).collect::<Vec<Node>>()
|
||||
}
|
||||
|
||||
fn tree_it<'a>(nodes: &[Node<'a>]) -> Tree<'a> {
|
||||
let nodes_by_name: HashMap<&'a str, (&Node<'a>, usize)> = nodes
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(count, i)| (i.name, (i, count)))
|
||||
.collect();
|
||||
let mut built: Vec<TreeNode<'a>> = nodes
|
||||
.iter()
|
||||
.map(|n| TreeNode {
|
||||
name: n.name,
|
||||
weight: n.weight,
|
||||
children: vec![],
|
||||
})
|
||||
.collect();
|
||||
let mut is_set: Vec<bool> = vec![false; nodes.len()];
|
||||
|
||||
let mut stack: Vec<usize> = vec![];
|
||||
for parent_node_index in 0..nodes.len() {
|
||||
if !is_set[parent_node_index] {
|
||||
stack.push(parent_node_index);
|
||||
while let Some(node_index) = stack.pop() {
|
||||
if is_set[node_index] {
|
||||
continue;
|
||||
}
|
||||
let node = &nodes[node_index];
|
||||
let children = (*node).children.iter().map(|&i| {
|
||||
let (_, child_index) = nodes_by_name.get(i).unwrap();
|
||||
*child_index
|
||||
});
|
||||
built[node_index].children.extend(children);
|
||||
stack.extend(built[node_index].children.iter());
|
||||
is_set[node_index] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We'll reuse the is_set array for an "is possibly the root" array.
|
||||
// They're all true now.
|
||||
for node in built.iter() {
|
||||
for child in node.children.iter() {
|
||||
is_set[*child] = false;
|
||||
}
|
||||
}
|
||||
let (top_node, _) = is_set.iter().enumerate().find(|(_, v)| **v).unwrap();
|
||||
Tree {
|
||||
nodes: built,
|
||||
root: top_node,
|
||||
}
|
||||
}
|
||||
|
||||
fn part_1<'a>(nodes: &[Node<'a>]) -> &'a str {
|
||||
let tree = tree_it(nodes);
|
||||
tree.nodes[tree.root].name
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct BalancedWeight {
|
||||
child_weights: u32,
|
||||
self_weight: u32,
|
||||
child_count: usize,
|
||||
}
|
||||
|
||||
fn total_weight(b: &BalancedWeight) -> u32 {
|
||||
b.child_weights * (b.child_count as u32) + b.self_weight
|
||||
}
|
||||
|
||||
fn weight(tree: &Tree, node: usize) -> Result<BalancedWeight, i32> {
|
||||
let node = &tree.nodes[node];
|
||||
let children: Vec<_> = node
|
||||
.children
|
||||
.iter()
|
||||
.map(|node| weight(&tree, *node))
|
||||
.collect();
|
||||
|
||||
let count = children.len();
|
||||
let mut c = children.iter();
|
||||
let mut different_child = None;
|
||||
if let Some(child) = c.next() {
|
||||
match child {
|
||||
Err(e) => Err(*e),
|
||||
Ok(child) => {
|
||||
for other in c {
|
||||
match other {
|
||||
Err(e) => return Err(*e),
|
||||
Ok(other) => {
|
||||
if total_weight(other) != total_weight(child) {
|
||||
match different_child {
|
||||
None => {
|
||||
different_child = Some(other);
|
||||
}
|
||||
Some(different_child) => {
|
||||
if total_weight(other) == total_weight(different_child) {
|
||||
// The bad one is `child`.
|
||||
return Err(total_weight(other) as i32
|
||||
- (child.child_weights * child.child_count as u32)
|
||||
as i32);
|
||||
} else {
|
||||
// The bad one is `other`.
|
||||
return Err(total_weight(child) as i32
|
||||
- (other.child_weights * other.child_count as u32)
|
||||
as i32);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
match different_child {
|
||||
None => Ok(BalancedWeight {
|
||||
self_weight: node.weight,
|
||||
child_weights: total_weight(child),
|
||||
child_count: count,
|
||||
}),
|
||||
Some(different_child) => {
|
||||
// The bad one is `different_child`.
|
||||
Err(total_weight(child) as i32
|
||||
- (different_child.child_weights * different_child.child_count as u32)
|
||||
as i32)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Ok(BalancedWeight {
|
||||
self_weight: node.weight,
|
||||
child_weights: 0,
|
||||
child_count: 0,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn part_2(nodes: &[Node]) -> i32 {
|
||||
let tree = tree_it(nodes);
|
||||
let result = weight(&tree, tree.root);
|
||||
match result {
|
||||
Err(e) => e,
|
||||
Ok(w) => panic!("Expected unbalanced tree, got {:?}", w),
|
||||
}
|
||||
}
|
||||
use day_7::day_7;
|
||||
|
||||
fn main() {
|
||||
let input = input();
|
||||
println!("part 1 => {}", part_1(&input));
|
||||
println!("part 2 => {}", part_2(&input));
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
fn test_inputs() -> Vec<Node<'static>> {
|
||||
vec![
|
||||
Node {
|
||||
name: "pbga",
|
||||
weight: 66,
|
||||
children: vec![],
|
||||
},
|
||||
Node {
|
||||
name: "xhth",
|
||||
weight: 57,
|
||||
children: vec![],
|
||||
},
|
||||
Node {
|
||||
name: "ebii",
|
||||
weight: 61,
|
||||
children: vec![],
|
||||
},
|
||||
Node {
|
||||
name: "havc",
|
||||
weight: 66,
|
||||
children: vec![],
|
||||
},
|
||||
Node {
|
||||
name: "ktlj",
|
||||
weight: 57,
|
||||
children: vec![],
|
||||
},
|
||||
Node {
|
||||
name: "fwft",
|
||||
weight: 72,
|
||||
children: vec!["ktlj", "cntj", "xhth"],
|
||||
},
|
||||
Node {
|
||||
name: "qoyq",
|
||||
weight: 66,
|
||||
children: vec![],
|
||||
},
|
||||
Node {
|
||||
name: "padx",
|
||||
weight: 45,
|
||||
children: vec!["pbga", "havc", "qoyq"],
|
||||
},
|
||||
Node {
|
||||
name: "tknk",
|
||||
weight: 41,
|
||||
children: vec!["ugml", "padx", "fwft"],
|
||||
},
|
||||
Node {
|
||||
name: "jptl",
|
||||
weight: 61,
|
||||
children: vec![],
|
||||
},
|
||||
Node {
|
||||
name: "ugml",
|
||||
weight: 68,
|
||||
children: vec!["gyxo", "ebii", "jptl"],
|
||||
},
|
||||
Node {
|
||||
name: "gyxo",
|
||||
weight: 61,
|
||||
children: vec![],
|
||||
},
|
||||
Node {
|
||||
name: "cntj",
|
||||
weight: 57,
|
||||
children: vec![],
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse() {
|
||||
assert_eq!(
|
||||
parse_line("vvwrg (51)"),
|
||||
Node {
|
||||
name: "vvwrg",
|
||||
weight: 51,
|
||||
children: vec![]
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
parse_line("uglvj (99) -> ymfjt, gkpgf"),
|
||||
Node {
|
||||
name: "uglvj",
|
||||
weight: 99,
|
||||
children: vec!["ymfjt", "gkpgf"]
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn part1_known() {
|
||||
assert_eq!(part_1(&test_inputs()), "tknk");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn part2_known() {
|
||||
assert_eq!(part_2(&test_inputs()), 60);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_day_7() {
|
||||
let input = input();
|
||||
assert_eq!(part_1(&input), "dgoocsw");
|
||||
assert_eq!(part_2(&input), 1275);
|
||||
}
|
||||
let input = day_7::input();
|
||||
println!("part 1 => {}", day_7::part_1(&input));
|
||||
println!("part 2 => {}", day_7::part_2(&input));
|
||||
}
|
||||
|
148
day_8/src/lib.rs
Normal file
148
day_8/src/lib.rs
Normal file
@@ -0,0 +1,148 @@
|
||||
pub mod day_8 {
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
enum Operation {
|
||||
Incr,
|
||||
Decr,
|
||||
}
|
||||
|
||||
enum Comparison {
|
||||
Greater,
|
||||
Equal,
|
||||
Less,
|
||||
LessEqual,
|
||||
GreaterEqual,
|
||||
NotEqual,
|
||||
}
|
||||
|
||||
struct Condition<'a> {
|
||||
register: &'a str,
|
||||
comparison: Comparison,
|
||||
number: i32,
|
||||
}
|
||||
|
||||
pub struct Instruction<'a> {
|
||||
register: &'a str,
|
||||
op: Operation,
|
||||
amount: i32,
|
||||
condition: Condition<'a>,
|
||||
}
|
||||
|
||||
pub fn parse(s: &str) -> Instruction {
|
||||
let mut iter = s.split_whitespace();
|
||||
let register = iter.next().unwrap();
|
||||
let op = match iter.next().unwrap() {
|
||||
"inc" => Operation::Incr,
|
||||
"dec" => Operation::Decr,
|
||||
s => panic!("Bad! {}", s),
|
||||
};
|
||||
let amount: i32 = iter.next().unwrap().parse().unwrap();
|
||||
let if_clause = iter.next().unwrap();
|
||||
if if_clause != "if" {
|
||||
panic!("Expected 'if', got: {}", if_clause);
|
||||
}
|
||||
let cmp_variable = iter.next().unwrap();
|
||||
let cmp_operator = match iter.next().unwrap() {
|
||||
"<=" => Comparison::LessEqual,
|
||||
">=" => Comparison::GreaterEqual,
|
||||
"==" => Comparison::Equal,
|
||||
"<" => Comparison::Less,
|
||||
">" => Comparison::Greater,
|
||||
"!=" => Comparison::NotEqual,
|
||||
s => panic!("Expected comparison, got: {}", s),
|
||||
};
|
||||
let cmp_num: i32 = iter.next().unwrap().parse().unwrap();
|
||||
let condition = Condition {
|
||||
register: cmp_variable,
|
||||
comparison: cmp_operator,
|
||||
number: cmp_num,
|
||||
};
|
||||
match iter.next() {
|
||||
None => Instruction {
|
||||
register,
|
||||
op,
|
||||
amount,
|
||||
condition,
|
||||
},
|
||||
Some(s) => panic!("Exp ected end of line, got {}", s),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn input() -> Vec<Instruction<'static>> {
|
||||
let input = include_str!("../input.txt");
|
||||
input.lines().map(|l| parse(l)).collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
fn process<'a>(instructions: &[Instruction<'a>]) -> HashMap<&'a str, (i32, i32)> {
|
||||
let mut registers = HashMap::new();
|
||||
for instruction in instructions {
|
||||
let original = registers
|
||||
.get(instruction.condition.register)
|
||||
.map_or(0, |&(_, v)| v);
|
||||
let proceed = match instruction.condition.comparison {
|
||||
Comparison::Greater => original > instruction.condition.number,
|
||||
Comparison::Less => original < instruction.condition.number,
|
||||
Comparison::GreaterEqual => original >= instruction.condition.number,
|
||||
Comparison::LessEqual => original <= instruction.condition.number,
|
||||
Comparison::Equal => original == instruction.condition.number,
|
||||
Comparison::NotEqual => original != instruction.condition.number,
|
||||
};
|
||||
if proceed {
|
||||
let (original_max, original_val) =
|
||||
registers.get(instruction.register).map_or((0, 0), |i| *i);
|
||||
let new_val = match instruction.op {
|
||||
Operation::Incr => original_val + instruction.amount,
|
||||
Operation::Decr => original_val - instruction.amount,
|
||||
};
|
||||
let new_max = std::cmp::max(original_max, new_val);
|
||||
registers.insert(instruction.register, (new_max, new_val));
|
||||
}
|
||||
}
|
||||
registers
|
||||
}
|
||||
|
||||
pub fn part_1(instructions: &[Instruction]) -> i32 {
|
||||
let map = process(instructions);
|
||||
map.values().map(|&(_, i)| i).max().unwrap()
|
||||
}
|
||||
|
||||
pub fn part_2(instructions: &[Instruction]) -> i32 {
|
||||
let map = process(instructions);
|
||||
map.values().map(|&(i, _)| i).max().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::day_8::*;
|
||||
|
||||
fn data() -> Vec<Instruction<'static>> {
|
||||
vec![
|
||||
"b inc 5 if a > 1",
|
||||
"a inc 1 if b < 5",
|
||||
"c dec -10 if a >= 1",
|
||||
"c inc -20 if c == 10",
|
||||
]
|
||||
.iter()
|
||||
.map(|s| parse(s))
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn part1_known() {
|
||||
assert_eq!(part_1(&data()), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn part2_known() {
|
||||
assert_eq!(part_2(&data()), 10);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_day_8() {
|
||||
let input = input();
|
||||
assert_eq!(part_1(&input), 5752);
|
||||
assert_eq!(part_2(&input), 6366);
|
||||
}
|
||||
}
|
@@ -1,151 +1,7 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
enum Operation {
|
||||
Incr,
|
||||
Decr,
|
||||
}
|
||||
|
||||
enum Comparison {
|
||||
Greater,
|
||||
Equal,
|
||||
Less,
|
||||
LessEqual,
|
||||
GreaterEqual,
|
||||
NotEqual,
|
||||
}
|
||||
|
||||
struct Condition<'a> {
|
||||
register: &'a str,
|
||||
comparison: Comparison,
|
||||
number: i32,
|
||||
}
|
||||
|
||||
struct Instruction<'a> {
|
||||
register: &'a str,
|
||||
op: Operation,
|
||||
amount: i32,
|
||||
condition: Condition<'a>,
|
||||
}
|
||||
|
||||
fn parse(s: &str) -> Instruction {
|
||||
let mut iter = s.split_whitespace();
|
||||
let register = iter.next().unwrap();
|
||||
let op = match iter.next().unwrap() {
|
||||
"inc" => Operation::Incr,
|
||||
"dec" => Operation::Decr,
|
||||
s => panic!("Bad! {}", s),
|
||||
};
|
||||
let amount: i32 = iter.next().unwrap().parse().unwrap();
|
||||
let if_clause = iter.next().unwrap();
|
||||
if if_clause != "if" {
|
||||
panic!("Expected 'if', got: {}", if_clause);
|
||||
}
|
||||
let cmp_variable = iter.next().unwrap();
|
||||
let cmp_operator = match iter.next().unwrap() {
|
||||
"<=" => Comparison::LessEqual,
|
||||
">=" => Comparison::GreaterEqual,
|
||||
"==" => Comparison::Equal,
|
||||
"<" => Comparison::Less,
|
||||
">" => Comparison::Greater,
|
||||
"!=" => Comparison::NotEqual,
|
||||
s => panic!("Expected comparison, got: {}", s),
|
||||
};
|
||||
let cmp_num: i32 = iter.next().unwrap().parse().unwrap();
|
||||
let condition = Condition {
|
||||
register: cmp_variable,
|
||||
comparison: cmp_operator,
|
||||
number: cmp_num,
|
||||
};
|
||||
match iter.next() {
|
||||
None => Instruction {
|
||||
register,
|
||||
op,
|
||||
amount,
|
||||
condition,
|
||||
},
|
||||
Some(s) => panic!("Exp ected end of line, got {}", s),
|
||||
}
|
||||
}
|
||||
|
||||
fn input() -> Vec<Instruction<'static>> {
|
||||
let input = include_str!("../input.txt");
|
||||
input.lines().map(|l| parse(l)).collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
fn process<'a>(instructions: &[Instruction<'a>]) -> HashMap<&'a str, (i32, i32)> {
|
||||
let mut registers = HashMap::new();
|
||||
for instruction in instructions {
|
||||
let original = registers
|
||||
.get(instruction.condition.register)
|
||||
.map_or(0, |&(_, v)| v);
|
||||
let proceed = match instruction.condition.comparison {
|
||||
Comparison::Greater => original > instruction.condition.number,
|
||||
Comparison::Less => original < instruction.condition.number,
|
||||
Comparison::GreaterEqual => original >= instruction.condition.number,
|
||||
Comparison::LessEqual => original <= instruction.condition.number,
|
||||
Comparison::Equal => original == instruction.condition.number,
|
||||
Comparison::NotEqual => original != instruction.condition.number,
|
||||
};
|
||||
if proceed {
|
||||
let (original_max, original_val) =
|
||||
registers.get(instruction.register).map_or((0, 0), |i| *i);
|
||||
let new_val = match instruction.op {
|
||||
Operation::Incr => original_val + instruction.amount,
|
||||
Operation::Decr => original_val - instruction.amount,
|
||||
};
|
||||
let new_max = std::cmp::max(original_max, new_val);
|
||||
registers.insert(instruction.register, (new_max, new_val));
|
||||
}
|
||||
}
|
||||
registers
|
||||
}
|
||||
|
||||
fn part_1(instructions: &[Instruction]) -> i32 {
|
||||
let map = process(instructions);
|
||||
map.values().map(|&(_, i)| i).max().unwrap()
|
||||
}
|
||||
|
||||
fn part_2(instructions: &[Instruction]) -> i32 {
|
||||
let map = process(instructions);
|
||||
map.values().map(|&(i, _)| i).max().unwrap()
|
||||
}
|
||||
use day_8::day_8;
|
||||
|
||||
fn main() {
|
||||
let input = input();
|
||||
println!("part 1 => {}", part_1(&input));
|
||||
println!("part 2 => {}", part_2(&input));
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
fn data() -> Vec<Instruction<'static>> {
|
||||
vec![
|
||||
"b inc 5 if a > 1",
|
||||
"a inc 1 if b < 5",
|
||||
"c dec -10 if a >= 1",
|
||||
"c inc -20 if c == 10",
|
||||
]
|
||||
.iter()
|
||||
.map(|s| parse(s))
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn part1_known() {
|
||||
assert_eq!(part_1(&data()), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn part2_known() {
|
||||
assert_eq!(part_2(&data()), 10);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_day_1() {
|
||||
let input = input();
|
||||
assert_eq!(part_1(&input), 5752);
|
||||
assert_eq!(part_2(&input), 6366);
|
||||
}
|
||||
let input = day_8::input();
|
||||
println!("part 1 => {}", day_8::part_1(&input));
|
||||
println!("part 2 => {}", day_8::part_2(&input));
|
||||
}
|
||||
|
Reference in New Issue
Block a user