diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..c040c24 --- /dev/null +++ b/.envrc @@ -0,0 +1,2 @@ +export RUST_BACKTRACE=1 +export RUST_LOG=trace diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..29a3bb3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +/target + +# ignore user-specific inputs +/inputs/*.txt + +# ignore file with ‹get_input› cookies +/.env.yaml \ No newline at end of file diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..16816a5 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,87 @@ +variables: + TIMEOUT_SECONDS: 10 + RUSTFLAGS: "-C instrument-coverage -Dwarnings" + LLVM_PROFILE_FILE: "coverage-%p-%m.profraw" + RUST_BACKTRACE: "full" + RUSTDOCFLAGS: "-Dwarnings" + +image: "rustdocker/rust:nightly" + +cache: + key: "$CI_JOB_NAME" + untracked: true + paths: + - $HOME/.cache/ + - $HOME/.cargo/ + # - target/ + + +default: + before_script: + - rustc --version + - cargo --version + +stages: + - test + - build + - extras + +cargo-test: + stage: test + script: + - cargo install cargo2junit + - cargo test --all --all-features -- -Z unstable-options --format json | cargo2junit > .cargo-test-report.xml + artifacts: + reports: + junit: .cargo-test-report.xml + +cargo-coverage: + stage: test + needs: ["cargo-test"] + script: + - apt-get update && apt-get install -yqq --no-install-recommends python3-pip python3-setuptools lcov + - rustup component add llvm-tools-preview + - (cargo test -- -Z unstable-options) || true + # generate html report + - cargo install grcov + - grcov . --binary-path ./target/debug/ -s . -t html --branch --ignore-not-existing --ignore "*cargo*" --ignore "*main*" -o ./coverage/ + # generate cobertura report for gitlab integration + - pip3 install lcov_cobertura + - grcov . --binary-path ./target/debug/ -s . -t lcov --llvm --branch --ignore-not-existing --ignore "*cargo*" --ignore "*main*" -o coverage.lcov + - lcov --summary coverage.lcov + - lcov_cobertura coverage.lcov + coverage: '/\s*lines\.*:\s*([\d\.]+%)/' + artifacts: + paths: + - 'coverage' + reports: + coverage_report: + coverage_format: cobertura + path: coverage.xml + +# cargo-doc: +# stage: test +# needs: ["cargo-test"] +# script: +# - cargo doc --no-deps --all-features + +# pages: +# stage: test +# needs: [ "cargo-test" ] +# script: +# - cargo doc --no-deps --all-features +# - cp -R target/doc/ ./public +# artifacts: +# paths: +# - 'public' +# rules: +# - if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH + +# lint-code: +# stage: extras +# needs: [ "cargo-test" ] +# script: +# - rustup component add rustfmt +# - cargo fmt -- --check +# - rustup component add clippy +# - cargo clippy -- -D warnings diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..4dd572a --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,584 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + +[[package]] +name = "aoc-2023" +version = "0.1.0" +dependencies = [ + "color-eyre", + "itertools", + "lazy_static", + "rayon", + "regex", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "backtrace" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "cc" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "color-eyre" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a667583cca8c4f8436db8de46ea8233c42a7d9ae424a82d338f2e4675229204" +dependencies = [ + "backtrace", + "color-spantrace", + "eyre", + "indenter", + "once_cell", + "owo-colors", + "tracing-error", +] + +[[package]] +name = "color-spantrace" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd6be1b2a7e382e2b98b43b2adcca6bb0e465af0bdd38123873ae61eb17a72c2" +dependencies = [ + "once_cell", + "owo-colors", + "tracing-core", + "tracing-error", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "deranged" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f32d04922c60427da6f9fef14d042d9edddef64cb9d4ce0d64d0685fbeb1fd3" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + +[[package]] +name = "eyre" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80f656be11ddf91bd709454d15d5bd896fbaf4cc3314e69349e4d1569f5b46cd" +dependencies = [ + "indenter", + "once_cell", +] + +[[package]] +name = "gimli" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" + +[[package]] +name = "indenter" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" + +[[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.150" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + +[[package]] +name = "memchr" +version = "2.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" + +[[package]] +name = "memoffset" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +dependencies = [ + "autocfg", +] + +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", +] + +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + +[[package]] +name = "num_threads" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" +dependencies = [ + "libc", +] + +[[package]] +name = "object" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[package]] +name = "owo-colors" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" + +[[package]] +name = "pin-project-lite" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "proc-macro2" +version = "1.0.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rayon" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "regex" +version = "1.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata 0.4.3", + "regex-syntax 0.8.2", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", +] + +[[package]] +name = "regex-automata" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.2", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "serde" +version = "1.0.193" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.193" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "smallvec" +version = "1.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" + +[[package]] +name = "syn" +version = "2.0.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thread_local" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "time" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5" +dependencies = [ + "deranged", + "itoa", + "libc", + "num_threads", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20" +dependencies = [ + "time-core", +] + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-error" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e" +dependencies = [ + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "time", + "tracing", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[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-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..e17065a --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "aoc-2023" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +itertools = "0.10.2" +tracing = "0.1.37" +color-eyre = "0.6.2" +# thiserror = "1.0.37" +tracing-subscriber = { version = "0.3.16", default-features = true, features = ["env-filter", "local-time"] } +regex = "1.7.0" +lazy_static = "1.4.0" +rayon = "1.6.1" +# bitvec = "1.0.1" + +[profile.dev.package.backtrace] +opt-level = 3 diff --git a/get_input.py b/get_input.py new file mode 100755 index 0000000..935ddb3 --- /dev/null +++ b/get_input.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python3 + +import datetime +import yaml +import requests +import sys + + +def load_config(): + with open(".env.yaml", "r") as f: + js = yaml.load(f, Loader=yaml.Loader) + return js["session"], js["year"] + + +def get_input(session, year, day): + return requests.get( + f"https://adventofcode.com/{year}/day/{day}/input", + cookies={"session": session}, + headers={ + "User-Agent": "{repo} by {mail}".format( + repo="gitlab.com/mfocko/advent-of-code-2022", + mail="me@mfocko.xyz", + ) + }, + ).content.decode("utf-8") + + +def main(): + day = datetime.datetime.now().day + if len(sys.argv) == 2: + day = sys.argv[1] + + session, year = load_config() + problem_input = get_input(session, year, day) + + with open(f"./inputs/day{day:>02}.txt", "w") as f: + f.write(problem_input) + + +if __name__ == "__main__": + main() diff --git a/inputs/.gitkeep b/inputs/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/samples/.gitkeep b/samples/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/data_structures/min_heap.rs b/src/data_structures/min_heap.rs new file mode 100644 index 0000000..2996a82 --- /dev/null +++ b/src/data_structures/min_heap.rs @@ -0,0 +1,28 @@ +use std::cmp::{Ord, Reverse}; +use std::collections::BinaryHeap; + +pub struct MinHeap { + heap: BinaryHeap>, +} + +impl MinHeap { + pub fn new() -> MinHeap { + MinHeap { + heap: BinaryHeap::new(), + } + } + + pub fn push(&mut self, item: T) { + self.heap.push(Reverse(item)) + } + + pub fn pop(&mut self) -> Option { + self.heap.pop().map(|Reverse(x)| x) + } +} + +impl Default for MinHeap { + fn default() -> Self { + Self::new() + } +} diff --git a/src/data_structures/mod.rs b/src/data_structures/mod.rs new file mode 100644 index 0000000..07186ff --- /dev/null +++ b/src/data_structures/mod.rs @@ -0,0 +1,2 @@ +mod min_heap; +pub use min_heap::*; diff --git a/src/input.rs b/src/input.rs new file mode 100644 index 0000000..d290eaa --- /dev/null +++ b/src/input.rs @@ -0,0 +1,56 @@ +//! # Input-related utilities + +use std::fmt::Debug; +use std::fs::read_to_string; +use std::ops::Deref; +use std::path::Path; +use std::str::FromStr; + +/// Reads file to the string. +pub fn file_to_string>(pathname: P) -> String { + read_to_string(pathname).expect("Unable to open file") +} + +/// Reads file and returns it as a vector of characters. +pub fn file_to_chars>(pathname: P) -> Vec { + read_to_string(pathname) + .expect("Unable to open file") + .chars() + .collect() +} + +/// Reads file and returns a vector of parsed structures. Expects each structure +/// on its own line in the file. And `T` needs to implement `FromStr` trait. +pub fn file_to_structs, T: FromStr>(pathname: P) -> Vec +where + ::Err: Debug, +{ + strings_to_structs( + read_to_string(pathname) + .expect("Unable to open files") + .lines(), + ) +} + +/// Converts iterator over strings to a vector of parsed structures. `T` needs +/// to implement `FromStr` trait and its error must derive `Debug` trait. +pub fn strings_to_structs(iter: impl Iterator) -> Vec +where + ::Err: std::fmt::Debug, + U: Deref, +{ + iter.map(|line| { + line.parse() + .expect("Could not parse the struct from the line") + }) + .collect() +} + +/// Reads file and returns it as a vector of its lines. +pub fn file_to_lines>(pathname: P) -> Vec { + read_to_string(pathname) + .expect("Unable to open file") + .lines() + .map(str::to_string) + .collect() +} diff --git a/src/iterators/column_iterator.rs b/src/iterators/column_iterator.rs new file mode 100644 index 0000000..119d8fe --- /dev/null +++ b/src/iterators/column_iterator.rs @@ -0,0 +1,25 @@ +pub struct ColumnIterator<'a, T> { + map: &'a [Vec], + column: usize, + + i: usize, +} + +impl<'a, T> ColumnIterator<'a, T> { + pub fn new(map: &'a [Vec], column: usize) -> ColumnIterator<'a, T> { + Self { map, column, i: 0 } + } +} + +impl<'a, T> Iterator for ColumnIterator<'a, T> { + type Item = &'a T; + + fn next(&mut self) -> Option { + if self.i >= self.map.len() { + return None; + } + + self.i += 1; + Some(&self.map[self.i - 1][self.column]) + } +} diff --git a/src/iterators/mod.rs b/src/iterators/mod.rs new file mode 100644 index 0000000..c28d744 --- /dev/null +++ b/src/iterators/mod.rs @@ -0,0 +1,2 @@ +mod column_iterator; +pub use column_iterator::*; diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..d962d55 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,17 @@ +mod input; +pub use input::*; + +mod solution; +pub use solution::*; + +mod testing; +pub use testing::*; + +mod vectors; +pub use vectors::*; + +mod iterators; +pub use iterators::*; + +mod data_structures; +pub use data_structures::*; diff --git a/src/solution.rs b/src/solution.rs new file mode 100644 index 0000000..9e0ce2c --- /dev/null +++ b/src/solution.rs @@ -0,0 +1,77 @@ +use std::any::type_name; +use std::fmt::Display; +pub use std::path::Path; + +pub use color_eyre::eyre::{eyre, Report, Result}; +pub use itertools::Itertools; +pub use lazy_static::lazy_static; +pub use regex::Regex; +pub use tracing::{debug, error, info, trace, warn}; +use tracing_subscriber::EnvFilter; + +pub trait Solution { + fn day() -> String { + let mut day = String::from(type_name::().split("::").next().unwrap()); + day.make_ascii_lowercase(); + + day.to_string() + } + + fn parse_input>(pathname: P) -> Input; + + fn part_1(input: &Input) -> Output; + fn part_2(input: &Input) -> Output; + + fn run(type_of_input: &str) -> Result<()> + where + Self: Sized, + { + tracing_subscriber::fmt() + .with_env_filter(EnvFilter::from_default_env()) + .with_target(false) + .with_file(true) + .with_line_number(true) + .without_time() + .compact() + .init(); + color_eyre::install()?; + + let input = Self::parse_input(format!("{}s/{}.txt", type_of_input, Self::day())); + + info!("Part 1: {}", Self::part_1(&input)); + info!("Part 2: {}", Self::part_2(&input)); + + Ok(()) + } + + fn main() -> Result<()> + where + Self: Sized, + { + Self::run("input") + } +} + +#[macro_export] +macro_rules! test_sample { + ($mod_name:ident, $day_struct:tt, $part_1:expr, $part_2:expr) => { + #[cfg(test)] + mod $mod_name { + use super::*; + + #[test] + fn test_part_1() { + let sample = + $day_struct::parse_input(&format!("samples/{}.txt", $day_struct::day())); + assert_eq!($day_struct::part_1(&sample), $part_1); + } + + #[test] + fn test_part_2() { + let sample = + $day_struct::parse_input(&format!("samples/{}.txt", $day_struct::day())); + assert_eq!($day_struct::part_2(&sample), $part_2); + } + } + }; +} diff --git a/src/testing.rs b/src/testing.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/testing.rs @@ -0,0 +1 @@ + diff --git a/src/vectors/mod.rs b/src/vectors/mod.rs new file mode 100644 index 0000000..46b4f7e --- /dev/null +++ b/src/vectors/mod.rs @@ -0,0 +1,5 @@ +mod vec2d; +pub use vec2d::*; + +mod vec3d; +pub use vec3d::*; diff --git a/src/vectors/vec2d.rs b/src/vectors/vec2d.rs new file mode 100644 index 0000000..7700688 --- /dev/null +++ b/src/vectors/vec2d.rs @@ -0,0 +1,135 @@ +use std::cmp::Eq; +use std::collections::VecDeque; +use std::fmt::Debug; +use std::hash::Hash; +use std::ops::{Add, Index, IndexMut, Mul, Sub}; + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct Vector2D { + x: T, + y: T, +} + +impl Vector2D { + pub fn new(x: T, y: T) -> Vector2D { + Vector2D { x, y } + } +} + +impl Vector2D { + pub fn swap(&self) -> Self { + Self { + x: self.y, + y: self.x, + } + } + + pub fn x(&self) -> T { + self.x + } + + pub fn y(&self) -> T { + self.y + } +} + +macro_rules! generate_indices { + ($container:ty) => { + impl Index> for $container + where + I: Copy + TryInto, + >::Error: Debug, + C: Index, + { + type Output = C::Output; + + fn index(&self, index: Vector2D) -> &Self::Output { + let (x, y): (usize, usize) = + (index.x.try_into().unwrap(), index.y.try_into().unwrap()); + &self[y][x] + } + } + + impl IndexMut> for $container + where + I: Copy + TryInto, + >::Error: Debug, + C: IndexMut, + { + fn index_mut(&mut self, index: Vector2D) -> &mut Self::Output { + let (x, y): (usize, usize) = + (index.x.try_into().unwrap(), index.y.try_into().unwrap()); + &mut self[y][x] + } + } + }; +} + +generate_indices!(VecDeque); +generate_indices!([C]); +generate_indices!(Vec); +// generate_indices!([C; N], const N: usize); + +pub fn in_range(v: &[Vec], idx: &Vector2D) -> bool +where + I: Copy, + usize: TryFrom, +{ + usize::try_from(idx.y) + .and_then(|y| usize::try_from(idx.x).map(|x| y < v.len() && x < v[y].len())) + .unwrap_or(false) +} + +// See: https://github.com/rust-lang/rust/issues/102731 +// impl, T> From> for Vector2D { +// fn from(value: Vector2D) -> Self { +// Self { +// x: U::from(value.x), +// y: U::from(value.y), +// } +// } +// } + +impl, U> Add for Vector2D { + type Output = Vector2D; + + fn add(self, rhs: Self) -> Self::Output { + Vector2D { + x: self.x + rhs.x, + y: self.y + rhs.y, + } + } +} + +impl, U> Sub for Vector2D { + type Output = Vector2D; + + fn sub(self, rhs: Self) -> Self::Output { + Vector2D { + x: self.x - rhs.x, + y: self.y - rhs.y, + } + } +} + +impl, U> Mul for Vector2D { + type Output = Vector2D; + + fn mul(self, rhs: Self) -> Self::Output { + Vector2D { + x: self.x * rhs.x, + y: self.y * rhs.y, + } + } +} + +impl + Copy, U> Mul for Vector2D { + type Output = Vector2D; + + fn mul(self, rhs: T) -> Self::Output { + Vector2D { + x: self.x * rhs, + y: self.y * rhs, + } + } +} diff --git a/src/vectors/vec3d.rs b/src/vectors/vec3d.rs new file mode 100644 index 0000000..55cea8f --- /dev/null +++ b/src/vectors/vec3d.rs @@ -0,0 +1,138 @@ +use std::cmp::Eq; +// use std::collections::VecDeque; +use std::fmt::Debug; +use std::hash::Hash; +use std::ops::{Add, /* Index, IndexMut, */ Mul, Sub}; + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct Vector3D { + x: T, + y: T, + z: T, +} + +impl Vector3D { + pub fn new(x: T, y: T, z: T) -> Vector3D { + Vector3D { x, y, z } + } +} + +impl Vector3D { + pub fn x(&self) -> T { + self.x + } + + pub fn y(&self) -> T { + self.y + } + + pub fn z(&self) -> T { + self.z + } +} + +// [TODO] Implement indexing +// macro_rules! generate_indices { +// ($container:ty) => { +// impl Index> for $container +// where +// I: Copy + TryInto, +// >::Error: Debug, +// C: Index, +// { +// type Output = C::Output; + +// fn index(&self, index: Vector3D) -> &Self::Output { +// let (x, y): (usize, usize) = +// (index.x.try_into().unwrap(), index.y.try_into().unwrap()); +// &self[y][x] +// } +// } + +// impl IndexMut> for $container +// where +// I: Copy + TryInto, +// >::Error: Debug, +// C: IndexMut, +// { +// fn index_mut(&mut self, index: Vector3D) -> &mut Self::Output { +// let (x, y): (usize, usize) = +// (index.x.try_into().unwrap(), index.y.try_into().unwrap()); +// &mut self[y][x] +// } +// } +// }; +// } + +// generate_indices!(VecDeque); +// generate_indices!([C]); +// generate_indices!(Vec); +// // generate_indices!([C; N], const N: usize); + +// pub fn in_range(v: &[Vec], idx: &Vector3D) -> bool +// where +// I: Copy, +// usize: TryFrom, +// { +// usize::try_from(idx.y) +// .and_then(|y| usize::try_from(idx.x).map(|x| y < v.len() && x < v[y].len())) +// .unwrap_or(false) +// } + +// See: https://github.com/rust-lang/rust/issues/102731 +// impl, T> From> for Vector3D { +// fn from(value: Vector3D) -> Self { +// Self { +// x: U::from(value.x), +// y: U::from(value.y), +// } +// } +// } + +impl, U> Add for Vector3D { + type Output = Vector3D; + + fn add(self, rhs: Self) -> Self::Output { + Vector3D { + x: self.x + rhs.x, + y: self.y + rhs.y, + z: self.z + rhs.z, + } + } +} + +impl, U> Sub for Vector3D { + type Output = Vector3D; + + fn sub(self, rhs: Self) -> Self::Output { + Vector3D { + x: self.x - rhs.x, + y: self.y - rhs.y, + z: self.z - rhs.z, + } + } +} + +impl, U> Mul for Vector3D { + type Output = Vector3D; + + fn mul(self, rhs: Self) -> Self::Output { + Vector3D { + x: self.x * rhs.x, + y: self.y * rhs.y, + z: self.z * rhs.z, + } + } +} + +impl + Copy, U> Mul for Vector3D { + type Output = Vector3D; + + fn mul(self, rhs: T) -> Self::Output { + Vector3D { + x: self.x * rhs, + y: self.y * rhs, + z: self.z * rhs, + } + } +}