1
1
mirror of https://github.com/theoludwig/advent_of_code_2023.git synced 2024-10-29 22:17:19 +01:00

feat: add day 5

This commit is contained in:
Théo LUDWIG 2023-12-09 20:22:46 +01:00
parent 755e211f3f
commit 45eca9020d
Signed by: theoludwig
GPG Key ID: ADFE5A563D718F3B
9 changed files with 912 additions and 4 deletions

232
Cargo.lock generated
View File

@ -2,6 +2,64 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "console"
version = "0.15.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c926e00cc70edefdc64d3a5ff31cc65bb97a3460097762bd23afb4d8145fccf8"
dependencies = [
"encode_unicode",
"lazy_static",
"libc",
"unicode-width",
"windows-sys",
]
[[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 = "day_1"
version = "1.0.0"
@ -17,3 +75,177 @@ version = "1.0.0"
[[package]]
name = "day_4"
version = "1.0.0"
[[package]]
name = "day_5"
version = "1.0.0"
dependencies = [
"indicatif",
"rayon",
]
[[package]]
name = "either"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
[[package]]
name = "encode_unicode"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
[[package]]
name = "indicatif"
version = "0.17.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb28741c9db9a713d93deb3bb9515c20788cef5815265bee4980e87bde7e0f25"
dependencies = [
"console",
"instant",
"number_prefix",
"portable-atomic",
"rayon",
"unicode-width",
]
[[package]]
name = "instant"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
dependencies = [
"cfg-if",
]
[[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 = "memoffset"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c"
dependencies = [
"autocfg",
]
[[package]]
name = "number_prefix"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
[[package]]
name = "portable-atomic"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0"
[[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 = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "unicode-width"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
[[package]]
name = "windows-sys"
version = "0.45.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
[[package]]
name = "windows_aarch64_msvc"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
[[package]]
name = "windows_i686_gnu"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
[[package]]
name = "windows_i686_msvc"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
[[package]]
name = "windows_x86_64_gnu"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
[[package]]
name = "windows_x86_64_msvc"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"

View File

@ -1,8 +1,9 @@
[workspace]
members = [
"day_1",
"day_2",
"day_3",
"day_4",
"day_*",
]
resolver = "2"
[workspace.dependencies]
rayon = { version = "=1.8.0" }
indicatif = { version = "=0.17.7", features = ["rayon"] }

1
day_5/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/target

8
day_5/Cargo.toml Normal file
View File

@ -0,0 +1,8 @@
[package]
name = "day_5"
version = "1.0.0"
edition = "2021"
[dependencies]
rayon = { workspace = true }
indicatif = { workspace = true }

128
day_5/README.md Normal file
View File

@ -0,0 +1,128 @@
# - Day 5: If You Give A Seed A Fertilizer -
Source: <https://adventofcode.com/2023/day/5>
## Instructions - Part 1
You take the boat and find the gardener right where you were told he would be: managing a giant "garden" that looks more to you like a farm.
"A water source? Island Island **is** the water source!" You point out that Snow Island isn't receiving any water.
"Oh, we had to stop the water because we **ran out of sand** to [filter](https://en.wikipedia.org/wiki/Sand_filter) it with! Can't make snow with dirty water. Don't worry, I'm sure we'll get more sand soon; we only turned off the water a few days... weeks... oh no." His face sinks into a look of horrified realization.
"I've been so busy making sure everyone here has food that I completely forgot to check why we stopped getting more sand! There's a ferry leaving soon that is headed over in that direction - it's much faster than your boat. Could you please go check it out?"
You barely have time to agree to this request when he brings up another. "While you wait for the ferry, maybe you can help us with our **food production problem**. The latest Island Island [Almanac](https://en.wikipedia.org/wiki/Almanac) just arrived and we're having trouble making sense of it."
The almanac (your puzzle input) lists all of the seeds that need to be planted. It also lists what type of soil to use with each kind of seed, what type of fertilizer to use with each kind of soil, what type of water to use with each kind of fertilizer, and so on. Every type of seed, soil, fertilizer and so on is identified with a number, but numbers are reused by each category - that is, soil `123` and fertilizer `123` aren't necessarily related to each other.
For example:
```txt
seeds: 79 14 55 13
seed-to-soil map:
50 98 2
52 50 48
soil-to-fertilizer map:
0 15 37
37 52 2
39 0 15
fertilizer-to-water map:
49 53 8
0 11 42
42 0 7
57 7 4
water-to-light map:
88 18 7
18 25 70
light-to-temperature map:
45 77 23
81 45 19
68 64 13
temperature-to-humidity map:
0 69 1
1 0 69
humidity-to-location map:
60 56 37
56 93 4
```
The almanac starts by listing which seeds need to be planted: seeds `79`, `14`, `55`, and `13`.
The rest of the almanac contains a list of **maps** which describe how to convert numbers from a **source category** into numbers in a **destination category**. That is, the section that starts with `seed-to-soil map:` describes how to convert a **seed number** (the source) to a **soil number** (the destination). This lets the gardener and his team know which soil to use with which seeds, which water to use with which fertilizer, and so on.
Rather than list every source number and its corresponding destination number one by one, the maps describe entire **ranges** of numbers that can be converted. Each line within a map contains three numbers: the **destination range start**, the **source range start**, and the **range length**.
Consider again the example seed-to-soil map:
```txt
50 98 2
52 50 48
```
The first line has a **destination range start** of `50`, a **source range start** of `98`, and a **range length** of `2`. This line means that the source range starts at `98` and contains two values: `98` and `99`. The destination range is the same length, but it starts at `50`, so its two values are `50` and `51`. With this information, you know that seed number `98` corresponds to soil number `50` and that seed number `99` corresponds to soil number `51`.
The second line means that the source range starts at `50` and contains `48` values: `50`, `51`, ..., `96`, `97`. This corresponds to a destination range starting at 52 and also containing `48` values: `52`, `53`, ..., `98`, `99`. So, seed number `53` corresponds to soil number `55`.
Any source numbers that **aren't mapped** correspond to the same destination number. So, seed number `10` corresponds to soil number `10`.
So, the entire list of seed numbers and their corresponding soil numbers looks like this:
```txt
seed soil
0 0
1 1
... ...
48 48
49 49
50 52
51 53
... ...
96 98
97 99
98 50
99 51
```
With this map, you can look up the soil number required for each initial seed number:
- Seed number `79` corresponds to soil number `81`.
- Seed number `14` corresponds to soil number `14`.
- Seed number `55` corresponds to soil number `57`.
- Seed number `13` corresponds to soil number `13`.
The gardener and his team want to get started as soon as possible, so they'd like to know the closest location that needs a seed. Using these maps, find **the lowest location number that corresponds to any of the initial seeds**. To do this, you'll need to convert each seed number through other categories until you can find its corresponding **location number**. In this example, the corresponding types are:
- Seed `79`, soil `81`, fertilizer `81`, water `81`, light `74`, temperature `78`, humidity `78`, **location `82`**.
- Seed `14`, soil `14`, fertilizer `53`, water `49`, light `42`, temperature `42`, humidity `43`, **location `43`**.
- Seed `55`, soil `57`, fertilizer `57`, water `53`, light `46`, temperature `82`, humidity `82`, **location `86`**.
- Seed `13`, soil `13`, fertilizer `52`, water `41`, light `34`, temperature `34`, humidity `35`, **location `35`**.
So, the lowest location number in this example is **`35`**.
**What is the lowest location number that corresponds to any of the initial seed numbers?**
## Instructions - Part 2
Everyone will starve if you only plant such a small number of seeds. Re-reading the almanac, it looks like the `seeds:` line actually describes **ranges of seed numbers**.
The values on the initial seeds: line come in pairs. Within each pair, the first value is the start of the range and the second value is the **length** of the range. So, in the first line of the example above:
```txt
seeds: 79 14 55 13
```
This line describes two ranges of seed numbers to be planted in the garden. The first range starts with seed number `79` and contains `14` values: `79`, `80`, ..., `91`, `92`. The second range starts with seed number `55` and contains `13` values: `55`, `56`, ..., `66`, `67`.
Now, rather than considering four seed numbers, you need to consider a total of **27** seed numbers.
In the above example, the lowest location number can be obtained from seed number `82`, which corresponds to soil `84`, fertilizer `84`, water `84`, light `77`, temperature `45`, humidity `46`, and location `46`. So, the lowest location number is **`46`**`.
Consider all of the initial seed numbers listed in the ranges on the first line of the almanac. **What is the lowest location number that corresponds to any of the initial seed numbers?**

221
day_5/input.txt Normal file
View File

@ -0,0 +1,221 @@
seeds: 2019933646 2719986 2982244904 337763798 445440 255553492 1676917594 196488200 3863266382 36104375 1385433279 178385087 2169075746 171590090 572674563 5944769 835041333 194256900 664827176 42427020
seed-to-soil map:
3566547172 3725495029 569472267
2346761246 1249510998 267846697
1812605508 937956667 271194541
1421378697 1209151208 40359790
2083800049 2788751092 262961197
2938601691 473979048 463977619
473979048 1517357695 947399649
4136019439 3566547172 158947857
1461738487 3051712289 350867021
2614607943 2464757344 323993748
soil-to-fertilizer map:
3107230831 2583931429 576709409
970181981 608291332 1441137369
743954495 3859046283 158951815
3683940240 3227916509 91282070
608291332 2448268266 135663163
3775222310 2049428701 398839565
2411319350 3319198579 539847704
2951167054 4017998098 156063777
902906310 3160640838 67275671
fertilizer-to-water map:
1257642402 395703749 69589612
1800674 2215701547 90550534
2757853693 358464863 37238886
3285451399 181079109 43937782
2346544130 3513448371 192150886
3866348216 4231433060 63534236
1327232014 1560332334 90281838
2538695016 616206288 114467702
255018176 225016891 46372244
1171065990 3705599257 27021880
1070753744 730673990 442780
221369008 3479799203 33649168
2987721226 271389135 80072982
1198087870 732917444 24556356
199036270 2306252081 22332738
0 731116770 1800674
3929882452 3989920675 212758268
631506549 757473800 322942578
301390420 0 157952443
2795092579 157952443 1997721
1222644226 2619085211 34998176
954449127 499901671 116304617
1429766246 159950164 21128945
2205492221 2074649638 141051909
2749302577 3732621137 8551116
459342863 1219863414 57737723
3329389181 3741172253 59047790
2797090300 2328584819 190630926
3278448653 351462117 7002746
126959518 1277601137 72076752
92351208 465293361 34608310
4142640720 3866348216 123572459
2143980560 1080416378 43307177
1450895191 2672287871 693085369
517080586 3365373240 114425963
3388436971 1662866566 411783072
2187287737 2654083387 18204484
1417513852 1650614172 12252394
3067794208 1349677889 210654445
4266213179 4202678943 28754117
2653162718 1123723555 96139859
1071196524 2519215745 99869466
water-to-light map:
512627839 90187036 1196629
3379634653 2059506154 33434334
3286651054 4276482087 18485209
4233695090 28914830 61272206
3413068987 3322576776 23288997
3736304424 3345865773 43267308
1246285471 2994853001 251748584
3779571732 1946298040 113208114
390808412 3287769466 34807310
1881283842 2879009693 106527924
3964031050 2506138169 12994476
3436357984 793897944 162691614
2255160753 2092940488 151061610
853985057 3506201042 119010035
301385394 1856875022 89423018
972995092 658665705 34308693
4159948022 1315925500 65322692
640912738 250463411 213072319
1761800914 91383665 102591221
450345319 3246601585 5793995
3186220306 4173678310 91115364
28914830 3633635453 176360375
456139314 193974886 56488525
2523290324 3809995828 187303152
2406222363 3389133081 117067961
205275205 2782899504 96110189
2135785589 1100569535 119375164
1121466033 533846267 124819438
1007303785 2244002098 114162248
3599049598 3997298980 137254826
4077949072 463535730 70310537
4225270714 3625211077 8424376
1498034055 2519132645 263766859
2710593476 1381248192 475626830
3977025526 692974398 100923546
4148259609 4264793674 11688413
1987811766 2358164346 147973823
3892779846 1244674296 71251204
3340510149 4134553806 39124504
1864392135 956589558 16891707
425615722 1219944699 24729597
513824468 973481265 127088270
3277335670 2985537617 9315384
3305136263 3252395580 35373886
light-to-temperature map:
1094191559 698410082 28110394
383870732 1189042355 107231661
3711052230 2164474756 34756304
745558539 170241759 7170863
491102393 503970250 194439832
4034618875 3142749029 146609939
3781998432 1718948669 129329785
2440091414 3071819711 70929318
1301358031 55123603 115118156
0 2789116652 87933685
770729148 177412622 48955790
3772681560 3886204605 9316872
752729402 37123857 17999746
3745808534 2137385460 7147939
2028807236 3677936618 208267987
2237075223 3289358968 92979022
88764920 1960439220 176946240
3568470355 2258695303 142581875
3276170082 1848278454 112160766
2637902204 1129503077 39814191
3000547589 892603630 188042422
2511020732 226368412 126881472
1122301953 1296274016 52818372
1440958847 1353023078 243104929
2963423732 0 37123857
3388330848 2199231060 48304954
1175120325 377732544 126237706
819684938 1349092388 3930690
3752956473 1169317268 19725087
3911328217 2144533399 19941357
1416476187 353249884 24482660
2677716395 3895521477 285707337
265711160 2413138935 118159572
685542225 1080646052 48857025
3556608598 2401277178 11861757
734399250 2247536014 11159289
87933685 3677105383 831235
3188590011 1596128007 87580071
836373414 2531298507 257818145
3471876393 2877050337 84732205
1684063776 726520476 166083154
823615628 3560998296 12757786
3436635802 1683708078 35240591
3931269574 3573756082 103349301
1850146930 3382337990 178660306
2330054245 2961782542 110037169
temperature-to-humidity map:
1773059646 4122818507 172148789
2417158855 2859734866 110076859
977168274 1576624124 28149321
4275291678 3797606290 19675618
1141296808 749646180 267286171
3592756112 2969811725 273274339
0 19621130 7167651
2059084943 2697725300 48133058
2107218001 3920609496 145140777
1453481278 1152911564 151292167
1408582979 1465584228 44898299
7167651 0 19621130
2907567891 1829621431 240604380
2252358778 3652347291 145258999
1005317595 1016932351 135979213
1945208435 2745858358 113876508
2397617777 4065750273 16506015
3251499859 1776094709 53526722
2867005672 4082256288 40562219
26788781 1304203731 161380497
3305026581 2409995769 287729531
3866030451 3243086064 409261227
2414123792 1773059646 3035063
911026677 1510482527 66141597
3148172271 3817281908 103327588
2527235714 2070225811 339769958
188169278 26788781 722857399
humidity-to-location map:
3907319746 3137303541 31421983
3085093695 1018495475 286155292
2898003508 2491485887 87665522
2546787368 2901838353 7997221
3835317650 2829836257 72002096
2554784589 3509894030 133012322
3487595595 3719561871 104747874
3714670750 2667334372 120646900
975094571 2909835574 227467967
2985669030 3864000834 99424665
3672962118 2449777255 41708632
3631107133 2787981272 41854985
3938741729 3963425499 15057061
3447904506 3824309745 39691089
1824175159 1304650767 641793976
242892183 0 6504921
3371248987 3642906352 76655519
1698833898 2258930589 81940357
0 6504921 242892183
2465969135 3978482560 80818233
3592343469 4256203632 38763664
3953798790 3168725524 341168506
2775979874 4134179998 122023634
1780774255 975094571 43400904
1311468847 1946444743 312485846
2687796911 2579151409 88182963
1202562538 2340870946 108906309
1623954693 4059300793 74879205

33
day_5/input_example_1.txt Normal file
View File

@ -0,0 +1,33 @@
seeds: 79 14 55 13
seed-to-soil map:
50 98 2
52 50 48
soil-to-fertilizer map:
0 15 37
37 52 2
39 0 15
fertilizer-to-water map:
49 53 8
0 11 42
42 0 7
57 7 4
water-to-light map:
88 18 7
18 25 70
light-to-temperature map:
45 77 23
81 45 19
68 64 13
temperature-to-humidity map:
0 69 1
1 0 69
humidity-to-location map:
60 56 37
56 93 4

276
day_5/src/lib.rs Normal file
View File

@ -0,0 +1,276 @@
use indicatif::ParallelProgressIterator;
use rayon::prelude::*;
use std::ops::Range;
use std::str::FromStr;
#[derive(Debug, Default, PartialEq, Clone)]
pub struct RangeConverter {
pub source_range: Range<usize>,
pub destination_range: Range<usize>,
}
impl FromStr for RangeConverter {
type Err = &'static str;
/// Parses a string `string` to return a value of [`RangeConverter`]
///
/// If parsing succeeds, return the value inside [`Ok`], otherwise
/// when the string is ill-formatted return an error specific to the
/// inside [`Err`].
///
/// # Examples
///
/// ```
/// use std::str::FromStr;
/// use day_5::RangeConverter;
///
/// let string = "50 98 2 ";
/// let expected_result = RangeConverter {
/// source_range: 98..100,
/// destination_range: 50..52,
/// };
/// let actual_result = RangeConverter::from_str(string).unwrap();
///
/// assert_eq!(actual_result, expected_result);
/// ```
fn from_str(string: &str) -> Result<Self, Self::Err> {
let numbers = string
.trim()
.split_ascii_whitespace()
.map(|string| {
let result: usize = string.trim().parse().unwrap_or_default();
result
})
.collect::<Vec<usize>>();
let destination_range_start = *numbers.first().unwrap_or(&0);
let source_range_start = *numbers.get(1).unwrap_or(&0);
let range_length = *numbers.get(2).unwrap_or(&0);
let result = RangeConverter {
source_range: source_range_start..(source_range_start + range_length),
destination_range: destination_range_start..(destination_range_start + range_length),
};
Ok(result)
}
}
#[derive(Debug, Default, PartialEq, Clone)]
pub struct CategoryConverter {
pub name: String,
pub ranges_converters: Vec<RangeConverter>,
}
impl FromStr for CategoryConverter {
type Err = &'static str;
/// Parses a string `string` to return a value of [`CategoryConverter`]
///
/// If parsing succeeds, return the value inside [`Ok`], otherwise
/// when the string is ill-formatted return an error specific to the
/// inside [`Err`].
///
/// # Examples
///
/// ```
/// use std::str::FromStr;
/// use day_5::{CategoryConverter, RangeConverter};
///
/// let string = "
/// seed-to-soil map:
/// 50 98 2
/// 52 50 48
/// ";
/// let expected_result = CategoryConverter {
/// name: String::from("seed-to-soil map:"),
/// ranges_converters: vec![
/// RangeConverter {
/// source_range: 98..100,
/// destination_range: 50..52,
/// },
/// RangeConverter {
/// source_range: 50..98,
/// destination_range: 52..100,
/// },
/// ],
/// };
/// let actual_result = CategoryConverter::from_str(string).unwrap();
///
/// assert_eq!(actual_result, expected_result);
/// ```
fn from_str(string: &str) -> Result<Self, Self::Err> {
let mut lines = string.trim().lines();
let name = lines.next().unwrap_or_default();
let mut ranges_converters = vec![];
for line in lines {
ranges_converters.push(RangeConverter::from_str(line).unwrap_or_default());
}
let result = CategoryConverter {
name: String::from(name),
ranges_converters,
};
Ok(result)
}
}
impl CategoryConverter {
pub fn convert(&self, number: usize) -> usize {
self.ranges_converters
.iter()
.find_map(|range_converter| {
if range_converter.source_range.contains(&number) {
Some(
range_converter.destination_range.start
+ (number - range_converter.source_range.start),
)
} else {
None
}
})
.unwrap_or(number)
}
}
#[derive(Debug, Default, PartialEq, Clone)]
pub struct Almanac {
pub seeds: Vec<usize>,
pub categories_converters: Vec<CategoryConverter>,
}
impl FromStr for Almanac {
type Err = &'static str;
/// Parses a string `string` to return a value of [`Almanac`]
///
/// If parsing succeeds, return the value inside [`Ok`], otherwise
/// when the string is ill-formatted return an error specific to the
/// inside [`Err`].
///
/// # Examples
///
/// ```
/// use std::str::FromStr;
/// use day_5::{Almanac, CategoryConverter, RangeConverter};
///
/// let string = "
/// seeds: 79 14 55 13
///
/// seed-to-soil map:
/// 50 98 2
/// 52 50 48
/// ";
/// let expected_result = Almanac {
/// seeds: vec![79, 14, 55, 13],
/// categories_converters: vec![CategoryConverter {
/// name: String::from("seed-to-soil map:"),
/// ranges_converters: vec![
/// RangeConverter {
/// source_range: 98..100,
/// destination_range: 50..52,
/// },
/// RangeConverter {
/// source_range: 50..98,
/// destination_range: 52..100,
/// },
/// ],
/// }],
/// };
/// let actual_result = Almanac::from_str(string).unwrap();
///
/// assert_eq!(actual_result, expected_result);
/// ```
fn from_str(string: &str) -> Result<Self, Self::Err> {
let mut categories = string.trim().split("\n\n");
let seeds = categories
.next()
.unwrap_or_default()
.strip_prefix("seeds: ")
.unwrap_or_default()
.split_ascii_whitespace()
.map(|string| {
let result: usize = string.trim().parse().unwrap_or_default();
result
})
.collect::<Vec<usize>>();
let categories_converters = categories
.map(|category_string| CategoryConverter::from_str(category_string).unwrap_or_default())
.collect::<Vec<CategoryConverter>>();
let result = Almanac {
seeds,
categories_converters,
};
Ok(result)
}
}
impl Almanac {
pub fn minimum_location(&self) -> usize {
self.seeds
.par_iter()
.map(|&seed| {
self.categories_converters
.iter()
.fold(seed, |accumulator, category_converter| {
category_converter.convert(accumulator)
})
})
.progress()
.min()
.unwrap_or_default()
}
pub fn set_seeds_as_range_pairs(&mut self) {
self.seeds = self
.seeds
.par_chunks(2)
.progress()
.flat_map(|chunk| {
if let [range_start, range_length] = chunk {
let start = *range_start;
let length = *range_length;
let range = start..(start + length);
range.into_iter()
} else {
let empty_range = 0..0;
empty_range.into_iter()
}
})
.collect();
}
}
pub fn part_1(input: &str) -> usize {
let almanac = Almanac::from_str(input).unwrap_or_default();
almanac.minimum_location()
}
pub fn part_2(input: &str) -> usize {
let mut almanac = Almanac::from_str(input).unwrap_or_default();
almanac.set_seeds_as_range_pairs();
almanac.minimum_location()
}
#[cfg(test)]
mod day_5_tests {
use super::*;
#[test]
fn test_part_1_example() {
assert_eq!(part_1(include_str!("../input_example_1.txt")), 35);
}
#[test]
fn test_part_2_example() {
assert_eq!(part_2(include_str!("../input_example_1.txt")), 46);
}
#[test]
fn test_part_1() {
assert_eq!(part_1(include_str!("../input.txt")), 313045984);
}
#[test]
#[ignore]
/// Ignored because it is a expensive/slow test to run.
fn test_part_2() {
assert_eq!(part_2(include_str!("../input.txt")), 20283860);
}
}

8
day_5/src/main.rs Normal file
View File

@ -0,0 +1,8 @@
use day_5::{part_1, part_2};
fn main() {
let input = include_str!("../input.txt");
println!("- Day 5: If You Give A Seed A Fertilizer -");
println!("Answer Part 1: {}", part_1(input));
println!("Answer Part 2: {}", part_2(input));
}