From 9dbe6ad2ee856719e0771ecfd9b18afe55675b33 Mon Sep 17 00:00:00 2001 From: Mads Jensen Date: Tue, 25 Jun 2024 00:53:51 +0200 Subject: [PATCH] Completed day 7 --- Cargo.lock | 5 + bin/Cargo.toml | 3 +- bin/src/main.rs | 73 +-- inputs/day7.txt | 1000 ++++++++++++++++++++++++++++++++++++ lib/camel_cards/Cargo.toml | 8 + lib/camel_cards/src/lib.rs | 334 ++++++++++++ 6 files changed, 1388 insertions(+), 35 deletions(-) create mode 100644 inputs/day7.txt create mode 100644 lib/camel_cards/Cargo.toml create mode 100644 lib/camel_cards/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 5a8d1ff..58c1b79 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,6 +8,7 @@ version = "0.1.0" dependencies = [ "almanac", "boat_race", + "camel_cards", "cube_game", "gondola_lift", "scratchcard", @@ -22,6 +23,10 @@ version = "0.1.0" name = "boat_race" version = "0.1.0" +[[package]] +name = "camel_cards" +version = "0.1.0" + [[package]] name = "cube_game" version = "0.1.0" diff --git a/bin/Cargo.toml b/bin/Cargo.toml index 4e23ca9..a2e94d5 100644 --- a/bin/Cargo.toml +++ b/bin/Cargo.toml @@ -11,4 +11,5 @@ cube_game = { path = "../lib/cube_game" } gondola_lift = { path = "../lib/gondola_lift" } scratchcard = { path = "../lib/scratchcard" } almanac = { path = "../lib/almanac" } -boat_race = { path = "../lib/boat_race" } \ No newline at end of file +boat_race = { path = "../lib/boat_race" } +camel_cards = { path = "../lib/camel_cards" } \ No newline at end of file diff --git a/bin/src/main.rs b/bin/src/main.rs index a805219..883735a 100644 --- a/bin/src/main.rs +++ b/bin/src/main.rs @@ -4,6 +4,7 @@ use std::str::FromStr; use almanac::Almanac; use boat_race::Races; +use camel_cards::Hands; use cube_game::{cube::Color, Cubes, Game}; use gondola_lift::EngineSchematic; use scratchcard::ScratchCards; @@ -12,10 +13,11 @@ use trebuchet::Trebuchet; macro_rules! time { ($name:expr, $block:block) => {{ let __start = std::time::Instant::now(); - let __result = { $block }; + { + $block + }; let __duration = __start.elapsed(); println!("[TIMING] '{}' took: {:?}", $name, __duration); - __result }}; ($name:expr, $fn:ident) => { @@ -23,16 +25,22 @@ macro_rules! time { }; } +macro_rules! day { + ($day:tt, $fn:ident) => { + time!(format!("Day {}", $day), { + println!("# Day {}", $day); + $fn(get_input!($day)); + }) + }; +} + macro_rules! get_input { ($day:tt) => { - std::fs::read_to_string(&format!("inputs/{}.txt", $day)).expect("Couldn't read input-file!") + std::fs::read_to_string(&format!("inputs/day{}.txt", $day)).expect("Couldn't read input-file!") }; } -fn day_1() { - println!("# Day 1"); - - let input = get_input!("day1"); +fn day1(input: String) { let result = Trebuchet::new(&input) .expect("Failed to create trebuchet") .get_calibration_sum(); @@ -40,11 +48,7 @@ fn day_1() { println!("Result: {result}"); } -fn day_2() { - println!("# Day 2"); - - let input = get_input!("day2"); - +fn day2(input: String) { let mut limits = Cubes::new(); limits.insert(Color::Red, 12); limits.insert(Color::Green, 13); @@ -57,10 +61,7 @@ fn day_2() { println!("Result: {result}") } -fn day_3() { - println!("# Day 3"); - - let input = get_input!("day3"); +fn day3(input: String) { let schem = EngineSchematic::new(&input).expect("Failed to create schematic"); let parts_sum = schem.get_parts().sum(); @@ -70,10 +71,7 @@ fn day_3() { println!("Gear ration: {gear_ratio}"); } -fn day_4() { - println!("# Day 4"); - - let input = get_input!("day4"); +fn day4(input: String) { let mut cards = ScratchCards::from_str(&input).expect("Failed to create scratchcards!"); let total = cards.get_points_worth(); @@ -85,10 +83,7 @@ fn day_4() { println!("Total cards won: {copies}"); } -fn day_5() { - println!("# Day 5"); - - let input = get_input!("day5"); +fn day5(input: String) { let almanac = Almanac::from_str(&input).expect("Failed to create almanac"); let lowest_location = almanac.get_lowest_location().expect("Lowest location not found"); @@ -101,10 +96,7 @@ fn day_5() { println!("Lowest location of ranges: {lowest_location_seed_range}"); } -fn day_6() { - println!("# Day 6"); - - let input = get_input!("day6"); +fn day6(input: String) { let races = Races::from_multiple_races(&input); let winning_product = races.get_winning_product(); @@ -116,14 +108,27 @@ fn day_6() { println!("Winning product for single race: {winning_product}"); } +fn day7(input: String) { + let hands = Hands::::from_str(&input).expect("Failed parsing hands"); + let total_winnings = hands.get_total_winnings(); + + println!("Total winnings: {total_winnings}"); + + let hands = Hands::::from_str(&input).expect("Failed parsing hands with jokers"); + let total_joker_winnings = hands.get_total_winnings(); + + println!("Total winnings with jokers: {total_joker_winnings}"); +} + fn main() { println!("## Advent of Code 2023 solutions ##"); time!("All", { - time!("Day 1", day_1); - time!("Day 2", day_2); - time!("Day 3", day_3); - time!("Day 4", day_4); - time!("Day 5", day_5); - time!("Day 6", day_6); + day!(1, day1); + day!(2, day2); + day!(3, day3); + day!(4, day4); + day!(5, day5); + day!(6, day6); + day!(7, day7); }) } diff --git a/inputs/day7.txt b/inputs/day7.txt new file mode 100644 index 0000000..2d5bff5 --- /dev/null +++ b/inputs/day7.txt @@ -0,0 +1,1000 @@ +AATKJ 840 +27A83 251 +6TT8T 113 +Q6T6T 693 +99K89 553 +777Q7 136 +7227J 782 +TJ2J9 837 +55578 524 +24Q49 919 +AAA2A 709 +KT972 907 +85282 886 +4432J 255 +K6K27 119 +J9Q77 820 +33K3K 48 +T8887 500 +28272 77 +38Q46 287 +KQQAQ 481 +5T2T3 280 +KQQQQ 458 +K82Q3 712 +Q5552 758 +4K87K 174 +7QQJQ 331 +29233 96 +79KA3 65 +J9893 546 +Q5A39 842 +K4K7K 437 +T555T 215 +9A7AA 162 +32AA2 374 +8J222 134 +38376 583 +J5222 962 +J65A9 883 +36338 956 +Q654T 107 +K4KKK 169 +A9A76 710 +9KQ78 183 +88753 577 +K997J 539 +4QA88 914 +K5T3A 401 +8K77K 619 +8888J 400 +TATAT 58 +8T436 279 +3Q28A 659 +3KK4J 54 +QQJ59 903 +44777 779 +53336 477 +22J33 930 +TQ6T2 923 +475TK 633 +5KJ45 980 +47TK6 50 +K8KKK 453 +2TJKA 39 +TJ6K6 380 +4J888 311 +27277 317 +2A2A5 213 +TT7T3 365 +22555 858 +789QQ 421 +937KT 791 +89KT6 732 +3KKKJ 703 +A2T22 896 +6467J 489 +72878 863 +46J5J 283 +TATA6 71 +Q4967 941 +7JT55 232 +9TQQQ 785 +55445 835 +K68KK 256 +TT33T 72 +2A2AQ 435 +9643K 436 +J3282 95 +88TQQ 767 +Q8788 250 +QQ949 62 +4T552 448 +JJ8QQ 476 +2JT22 900 +73T7T 648 +QQQJJ 795 +98A35 589 +94444 479 +44486 465 +7TK86 521 +2JK45 761 +556KT 492 +94K99 144 +2QJ32 637 +66226 538 +933TA 248 +T2234 419 +QAA26 35 +K63K3 853 +5KJK9 970 +KK4QK 636 +8TTTT 69 +5T7J8 161 +239A4 91 +3T823 182 +24A8K 407 +K5A92 330 +KK9K3 599 +2244J 284 +AAJ5Q 794 +44A84 472 +KK2J3 597 +6QQJ6 547 +TAAT4 668 +J4444 827 +QAJ22 200 +KT5J5 80 +7K3J9 517 +3A33T 762 +TT66T 154 +6K972 569 +6378Q 593 +2AQA9 460 +2KKAA 516 +AK45A 978 +QAAA8 568 +83478 234 +33737 491 +Q9Q43 977 +QKQQ7 523 +9T24A 609 +88997 355 +KAKAA 651 +87Q77 665 +JK7A4 268 +68586 44 +4345J 931 +Q29A9 871 +3479K 774 +3TK65 189 +9249Q 319 +27J2Q 656 +333J9 667 +6TJ66 681 +82T96 738 +K3K39 14 +74JK9 297 +8A88A 798 +AT869 987 +9TAT9 996 +33939 684 +4424J 117 +44AJA 422 +646AA 358 +K3T83 218 +KK7K7 495 +A6A6J 731 +3QQ97 381 +43ATK 484 +K9965 982 +9J9JJ 392 +Q2QQQ 420 +58588 433 +9Q955 862 +88777 246 +669J7 438 +9AA2A 733 +8A9K6 175 +Q25JK 459 +JJ2K8 439 +T8K9T 195 +45444 719 +A22A2 403 +6366Q 36 +35366 452 +293J3 576 +JKK3J 402 +425AT 338 +344J4 975 +7K7A8 490 +7QQ7Q 242 +T9T9K 542 +2JJT6 440 +76676 541 +AKA66 361 +7557Q 431 +5K552 511 +997K7 179 +79779 885 +85585 961 +TQQQ8 751 +9TAT6 504 +84248 654 +222JJ 865 +6AKK8 573 +AQ3T8 30 +77676 670 +T44J2 808 +J7J5Q 897 +44343 57 +TJ7T5 945 +JKTTK 60 +3333Q 894 +6886J 473 +8J7J3 990 +77797 915 +77J98 155 +KKQT8 736 +8A8AJ 219 +AQQJA 75 +75J58 349 +78978 898 +48TAA 726 +56A6A 45 +888JJ 170 +Q7KK3 294 +QQA7A 199 +A4653 193 +44545 602 +622K7 612 +T5TJ9 860 +8T888 548 +8TQJ4 410 +TQ578 446 +98988 367 +5989T 151 +QQ35J 679 +73677 416 +J33Q5 137 +6564J 913 +4847Q 807 +39292 874 +JQA45 810 +97975 943 +Q9839 296 +9599T 661 +J9699 723 +44J72 875 +T29A9 889 +QQ53K 1000 +88988 20 +QJQK5 769 +KAKKK 132 +7327J 177 +QQQAQ 704 +2KTK6 257 +474A4 928 +9A748 501 +5A535 469 +2T426 190 +53353 318 +Q7Q78 694 +92738 796 +25995 772 +QQQ22 877 +9K999 238 +JJQ5A 424 +4QA4J 7 +KQT2A 347 +27787 754 +823T5 159 +54347 702 +ATA55 166 +9Q8T7 887 +K8338 631 +945AJ 658 +TJTTJ 16 +7A478 313 +93998 2 +A5A93 342 +KKQQK 921 +3K242 52 +9AAJT 43 +TT33Q 337 +22452 139 +2AQK8 594 +6AQ58 503 +KJ5JQ 122 +9Q787 988 +7626T 228 +J99J9 377 +6J727 378 +45J33 216 +A555K 360 +6J62K 959 +Q7Q47 141 +95644 116 +5K755 56 +7A7QQ 773 +27K92 663 +A4A77 841 +763J4 872 +3493J 478 +42K9K 103 +43433 973 +K6A4K 38 +T257Q 307 +2KQKK 992 +TT553 627 +66664 508 +88A82 243 +QJQQQ 804 +2T99T 150 +2JQT3 245 +44644 786 +675TK 194 +45KKA 1 +JJJJJ 543 +T4TTT 530 +K6KK6 336 +TT8Q3 888 +T999Q 350 +36643 176 +95KKK 832 +J7386 375 +K8KK8 954 +82JK3 411 +AAAAT 571 +3677J 854 +9998J 604 +5JQT4 94 +JAKKQ 635 +TT986 15 +5855Q 756 +243Q8 127 +T69A3 821 +63A7T 902 +QQ8Q8 805 +AQAAK 371 +83J33 981 +AQ525 549 +72486 147 +36664 715 +QQTTQ 312 +686A9 920 +J63J7 486 +4AAAQ 451 +Q5452 84 +66688 191 +3QAQ9 285 +925K6 66 +824Q8 5 +JTQQT 806 +J5J33 344 +A2A35 428 +72943 262 +K9966 581 +66J69 991 +788J7 728 +AA7AA 471 +5555K 167 +J4A62 488 +JJ699 258 +36386 600 +A4AA4 405 +53Q9T 211 +3377A 985 +K7Q83 404 +J3TT7 265 +Q9QQQ 482 +82736 273 +92K4A 771 +68888 417 +A7AA7 625 +29333 630 +558QK 536 +7J9J7 247 +66T66 586 +AKA9A 11 +73J3J 67 +Q6226 570 +885J5 457 +7447J 869 +TA2A2 688 +J9685 254 +4JKK4 275 +8QQQ7 442 +82383 244 +43333 19 +573JT 701 +A666A 777 +999J9 984 +JJ444 822 +KJ3A4 505 +22494 387 +TJT77 301 +K2K2K 112 +88338 844 +5AA5A 388 +33J63 233 +9658Q 432 +797K7 291 +AJ3TT 935 +K2255 483 +66966 286 +33555 101 +AQ4QQ 944 +77K77 575 +4T4QQ 650 +32J6T 948 +AK32Q 666 +57455 685 +9823A 708 +8TTTK 474 +22575 102 +77577 368 +88J28 90 +A4343 610 +24826 82 +QQ8QQ 158 +99QQ9 892 +77468 99 +3T773 4 +4QQ3Q 620 +85437 212 +53655 745 +Q6664 156 +7447Q 320 +673K5 502 +4TJ7Q 917 +4TJ44 281 +53545 186 +TQ54A 957 +8J242 818 +4J75A 938 +95T8A 499 +KJ6KK 657 +T5TTT 12 +AAA4A 878 +6Q66K 788 +7TT22 450 +882QA 880 +5KT99 397 +3955T 263 +J68Q8 939 +6T395 742 +3KQ69 345 +Q9333 425 +J7777 695 +722Q7 130 +T7TT6 775 +TTT88 78 +AQQ22 815 +J8837 616 +223Q3 271 +4KKK4 28 +95999 879 +ATTT6 34 +4J4JA 603 +Q5972 37 +798K6 963 +29J4Q 217 +2AAA3 830 +99J9T 893 +5J2K2 235 +TTT55 937 +9587T 906 +4T3JK 968 +K88K8 734 +JT223 801 +9QJ2Q 418 +K8866 528 +887AA 487 +6733J 426 +82887 17 +54TQK 643 +44J94 639 +58K6A 470 +3TTTT 223 +T4TT4 760 +82435 942 +K494Q 114 +77792 556 +5J82J 118 +2T8AA 559 +9494A 706 +J4666 295 +33J7K 749 +8JQ88 717 +TJTTT 672 +4AAKK 557 +Q77QJ 629 +KKJK5 535 +492JT 834 +9QK74 876 +7QQQQ 308 +622J2 946 +J489Q 160 +A2A2A 647 +845T2 362 +Q7TT4 104 +T7KQA 513 +8T8T8 891 +25J82 6 +3333J 53 +J4544 443 +3377Q 551 +KKTQQ 655 +22822 59 +Q9Q9Q 278 +94JTK 363 +66699 206 +7A499 882 +T3663 677 +4K44Q 21 +82A42 197 +4824Q 566 +T8TT4 624 +KQJ7Q 951 +TJT89 163 +65A5A 884 +3T63A 92 +A3A34 434 +T7J88 202 +4K9A3 969 +52333 814 +J3977 615 +86666 697 +8A987 866 +5434K 464 +75888 974 +4444K 115 +62K32 143 +5J5TT 140 +T4QTQ 324 +K2282 314 +39993 518 +2AJ4J 83 +K96K9 952 +Q683J 851 +JJ4J8 724 +2222T 611 +7J676 595 +3T333 540 +88848 3 +2Q679 463 +J68J6 97 +AAA5A 276 +22272 288 +3353J 171 +KK67J 207 +34QJ7 617 +TTAKK 714 +AA6JA 529 +A8299 373 +5Q222 79 +666J6 953 +KQ29Q 799 +533TT 735 +JQAQQ 901 +995T3 716 +K2AK2 531 +7776Q 68 +94Q4Q 87 +AAA88 999 +T2434 149 +TQTQ7 385 +255T5 302 +99T99 449 +798TA 496 +7T6Q8 746 +Q2QKQ 873 +75776 300 +28588 303 +5KT5A 922 +KJT64 409 +AJAAA 924 +595JA 867 +44J93 27 +2K384 690 +JKKKK 744 +K57KQ 124 +T4464 109 +29AKJ 705 +8JK8K 261 +K6T3J 947 +T5588 125 +6A8K4 316 +35555 305 +63AAJ 560 +66J67 578 +KQ77K 646 +T654J 33 +38AKK 230 +AJ99A 838 +T6TTK 252 +6666K 689 +99A33 965 +88QAJ 764 +T9Q23 899 +8A22T 829 +478Q9 366 +TT2TT 971 +34T2A 259 +AAQAJ 23 +J4T52 776 +9999A 277 +68896 994 +55585 18 +88999 131 +77389 514 +75AQJ 787 +88Q88 51 +3J4JQ 678 +4J643 394 +6634J 757 +74496 249 +555J5 226 +T3TT4 881 +93739 157 +377K8 328 +JJ6J3 81 +8JA9K 720 +T3TT5 828 +33A33 106 +K6KKK 413 +86868 895 +6J3QQ 323 +4JQ93 192 +939J9 729 +7Q77Q 671 +Q2222 676 +8A83Q 823 +TTT3J 74 +94969 816 +5TK77 766 +QKA87 467 +JQ736 427 +JT374 870 +J949J 456 +8AT8A 299 +K9KK8 395 +932TA 669 +J3AAT 105 +474KK 441 +7J738 713 +742AT 793 +K387J 145 +4457A 264 +5T5J5 908 +99996 121 +AAJ4A 817 +J4JJJ 25 +99J59 63 +5TKKA 983 +J454K 396 +K222J 290 +99992 393 +A2JQQ 321 +58AAA 790 +39333 165 +4264T 737 +69969 327 +AQAQA 537 +KT9J8 49 +4QT86 126 +KKAJK 304 +84448 414 +Q2425 444 +6558A 675 +A9QAJ 770 +333QQ 607 +93983 73 +929T9 856 +JJAAA 352 +67TQT 382 +6579K 55 +TT7TT 544 +9AAK6 784 +65A82 855 +48KJ9 111 +388AK 272 +6T677 890 +2AA92 632 +663J3 623 +TTJQT 386 +49475 180 +4TKTT 461 +88333 722 +Q97T4 740 +7T624 315 +66K6K 86 +33398 826 +922J5 912 +93875 89 +KK3AK 447 +32T2T 383 +77KKJ 699 +9T5A7 622 +3J823 750 +8TKJ6 224 +3464T 730 +54555 138 +526J7 389 +A5794 497 +779JK 916 +T333T 545 +74253 743 +29222 227 +TKTJT 552 +9AJ89 574 +637J6 236 +KKQKK 868 +9QQJ4 683 +K42Q6 267 +9243Q 934 +8T98T 210 +T6K58 831 +29J99 29 +JQ4QT 353 +56QTQ 692 +335J9 825 +24J84 208 +A2924 859 +A8888 933 +577K2 148 +5AKKK 429 +23KK3 201 +29229 811 +44T4T 455 +9QT2J 755 +39QAT 172 +A2548 423 +AK692 270 +A44Q4 698 +A4443 510 +69527 415 +4T444 638 +AKJ36 927 +K355A 561 +32Q3Q 220 +22A22 93 +JTQTA 850 +2Q2Q2 188 +77787 135 +68T6T 813 +AAQA7 168 +T4554 967 +K6888 240 +2AA8A 642 +AA333 13 +8KTKK 70 +99K93 686 +89588 949 +K4565 372 +8T9K4 601 +33TJJ 763 +23J33 565 +KQK65 819 +K534J 721 +43385 563 +J5AA5 379 +88222 979 +5JTTJ 515 +2QQ8A 196 +8T756 849 +38288 454 +386QT 310 +Q5TT5 936 +4QQTQ 852 +QQ446 46 +QT6JQ 926 +242Q2 605 +44999 26 +93929 10 +A23A3 925 +66366 564 +88A8Q 809 +93222 356 +45AQ6 800 +QKKAK 359 +7A645 960 +J2KQQ 289 +KKK5K 203 +7QA44 485 +JQQ69 128 +Q2QT5 22 +K84KK 993 +J32A4 430 +999QK 778 +68Q3K 753 +4884J 221 +J44JJ 340 +JTT93 339 +63TT8 348 +4TTT6 725 +6KA2Q 335 +QTKKT 592 +4325K 229 +Q447Q 606 +78TTT 506 +66626 406 +27444 621 +27Q3Q 584 +28T27 964 +QTTTT 598 +8JJA8 649 +Q773K 847 +2AT8Q 231 +39574 241 +34QJ8 239 +J66KK 98 +54J3A 164 +77A87 582 +KJJKK 768 +J6892 846 +77TT7 911 +44834 184 +AJKJT 329 +TTTA4 596 +5453A 792 +5666J 493 +TA3A8 333 +7TA7A 585 +7JJ77 645 +K6KK7 843 +KKK9K 555 +33KT6 123 +5AA84 958 +93798 341 +555AA 783 +TAT33 266 +Q6QQ6 940 +7AJQ6 205 +A6656 572 +J8JJJ 660 +77477 861 +QJ666 173 +Q344J 955 +6699A 332 +529A9 976 +QK6KQ 640 +44QQQ 298 +J399K 9 +7J294 966 +9TAT7 613 +2K3Q7 680 +999Q5 532 +T899T 198 +Q95QK 42 +97947 509 +K777K 682 +K45K4 554 +82333 153 +2J7KK 802 +Q6999 187 +27732 41 +57865 628 +62226 47 +QQKA2 398 +77772 129 +67499 727 +3J8K8 752 +5J27A 833 +84444 741 +8KJKK 567 +AAJJK 904 +87768 780 +66766 534 +AA66A 989 +76868 32 +47TTT 512 +55J53 748 +49249 550 +2566K 812 +5775A 376 +J9K99 399 +9J66J 325 +36JQ6 364 +99979 909 +2A792 608 +J848K 326 +73374 533 +3J655 591 +Q6QQ4 580 +65656 845 +54477 626 +6299Q 225 +Q8768 707 +7989K 408 +7QQ73 525 +76Q2A 653 +A4A44 369 +23737 618 +49696 24 +52542 905 +22262 31 +K686K 346 +5TT8J 185 +76TJ6 494 +TQJ77 711 +33636 120 +4TA97 662 +43946 691 +77262 986 +7J7KJ 370 +TTK9Q 391 +T8387 498 +43J79 781 +66846 133 +2J222 765 +3KTQ3 222 +26KQJ 641 +T94KQ 857 +KKK7K 918 +4644Q 152 +77K6K 282 +A4444 664 +QQ8AA 644 +555JJ 997 +22727 824 +K3K2K 929 +9QK88 696 +44465 480 +K3JK3 110 +22242 718 +KKK9J 998 +QTQTT 462 +TTT6T 214 +5QQTQ 8 +KT593 789 +8QQ68 181 +QKK44 357 +JJQ7J 587 +8858J 522 +55559 351 +93995 673 +9AAT9 700 +78JQJ 739 +32323 950 +3338A 747 +J22TT 803 +T2893 475 +3T36T 292 +JQ5T2 759 +274Q4 142 +7737Q 579 +92T22 343 +Q2QQ8 100 +762J8 309 +A288A 322 +3569Q 932 +59455 972 +6J668 836 +29A84 562 +QQAQA 468 +8QJKA 76 +66JK5 85 +TTT28 634 +2K67T 146 +44A42 674 +K97KT 40 +55942 839 +JQ5QT 306 +22TTT 274 +Q3J6A 61 +65555 204 +9T9T9 260 +J6778 269 +7727J 466 +72T58 995 +3333K 910 +49292 108 +9A292 520 +T7TTK 527 +44888 209 +QT6Q3 848 +2JQ22 354 +73TT3 588 +6KT83 507 +AA8AA 519 +QK4QK 558 +9KA97 390 +6K2KK 526 +47KJ2 590 +666QQ 253 +4AQ8J 88 +AJA82 445 +68AAA 652 +6A42K 64 +K2225 237 +6544K 334 +3685A 178 +44324 797 +Q27K6 687 +TTT42 614 +99595 384 +74474 412 +J5745 293 +Q4444 864 \ No newline at end of file diff --git a/lib/camel_cards/Cargo.toml b/lib/camel_cards/Cargo.toml new file mode 100644 index 0000000..31c8d13 --- /dev/null +++ b/lib/camel_cards/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "camel_cards" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/lib/camel_cards/src/lib.rs b/lib/camel_cards/src/lib.rs new file mode 100644 index 0000000..5fe4d11 --- /dev/null +++ b/lib/camel_cards/src/lib.rs @@ -0,0 +1,334 @@ +use std::{ + collections::{BTreeMap, BTreeSet}, + num::{ParseIntError, TryFromIntError}, + ops::{Deref, DerefMut}, + str::FromStr, +}; + +#[derive(Debug)] +pub enum CardsError { + ParseInt(ParseIntError), + ConvertUsize(TryFromIntError), + InvalidCard(char), + GetLowCount, + GetHighCount, + GetHighCard, +} + +impl From for CardsError { + fn from(value: ParseIntError) -> Self { + Self::ParseInt(value) + } +} + +impl From for CardsError { + fn from(value: TryFromIntError) -> Self { + Self::ConvertUsize(value) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub enum Card { + Joker, + Two, + Three, + Four, + Five, + Six, + Seven, + Eight, + Nine, + Ten, + Jack, + Queen, + King, + Ace, +} + +impl TryFrom for Card { + type Error = CardsError; + + fn try_from(value: char) -> Result { + use Card::*; + + let card = match value { + '2' => Two, + '3' => Three, + '4' => Four, + '5' => Five, + '6' => Six, + '7' => Seven, + '8' => Eight, + '9' => Nine, + 'T' => Ten, + 'J' if JOKERS => Joker, + 'J' if !JOKERS => Jack, + 'Q' => Queen, + 'K' => King, + 'A' => Ace, + + invalid => return Err(CardsError::InvalidCard(invalid)), + }; + + Ok(card) + } +} + +#[derive(Debug, Default)] +pub struct CardCount(BTreeMap, u16>); + +impl CardCount { + pub fn new(cards: &[Card]) -> Result { + let mut counts = Self::default(); + + cards.iter().for_each(|card| counts.count(card)); + + if JOKERS { + let Some(highest_card) = counts.highest_non_joker_card() else { + return Ok(counts); + }; + + let joker_count = counts.get(&Card::::Joker).copied().unwrap_or(0); + + counts.remove(&Card::::Joker); + + let highest_value = counts.get_mut(&highest_card).ok_or(CardsError::GetHighCount)?; + + *highest_value += joker_count; + }; + + Ok(counts) + } + + pub fn count(&mut self, card: &Card) { + self.entry(*card).and_modify(|count| *count += 1).or_insert(1); + } + + pub fn lowest(&self) -> Result<&u16, CardsError> { + self.values().min().ok_or(CardsError::GetLowCount) + } + + pub fn highest(&self) -> Result<&u16, CardsError> { + self.values().max().ok_or(CardsError::GetHighCount) + } + + fn highest_non_joker_card(&self) -> Option> { + self.iter() + .filter(|(card, _)| **card != Card::::Joker) + .max_by(|(_, a), (_, b)| a.cmp(b)) + .map(|(card, _)| *card) + } +} + +impl Deref for CardCount { + type Target = BTreeMap, u16>; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for CardCount { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] +pub enum HandType { + HighCard, + OnePair, + TwoPair, + ThreeOfAKind, + FullHouse, + FourOfAKind, + FiveOfAKind, +} + +#[derive(Debug, PartialEq, Eq)] +pub struct Hand { + cards: [Card; 5], + bid: u64, + typ: HandType, +} + +impl Hand { + pub fn new(cards: [Card; 5], bid: u64) -> Result { + let typ = Self::get_hand_type(&cards)?; + Ok(Self { cards, bid, typ }) + } + + fn get_hand_type(cards: &[Card; 5]) -> Result { + use HandType::*; + + let counts = CardCount::new(cards)?; + + let typ = match counts.len() { + 1 => FiveOfAKind, + 2 => { + let lowest = *counts.lowest()?; + match lowest { + 1 => FourOfAKind, + 2 => FullHouse, + _ => unreachable!("Hands with 2 types should always have a low value of 1 or 2"), + } + } + 3 => { + let highest = *counts.highest()?; + match highest { + 3 => ThreeOfAKind, + 2 => TwoPair, + _ => unreachable!("Hands with 3 types should always have a high value of 3 or 2"), + } + } + 4 => OnePair, + 5 => HighCard, + _ => unreachable!("No more than 5 types are possible in a hand with 5 cards."), + }; + + Ok(typ) + } +} +impl PartialOrd for Hand { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} +impl Ord for Hand { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + use std::cmp::Ordering::*; + + let typ_cmp = self.typ.cmp(&other.typ); + + if typ_cmp != Equal { + return typ_cmp; + } + + for i in 0..5 { + let card_cmp = self.cards[i].cmp(&other.cards[i]); + + if card_cmp != Equal { + return card_cmp; + } + } + + Equal + } +} + +impl FromStr for Hand { + type Err = CardsError; + + fn from_str(s: &str) -> Result { + let hand_str = s.split_ascii_whitespace().collect::>(); + + let cards = hand_str[0] + .chars() + .map(Card::::try_from) + .collect::>, CardsError>>()?; + + let bid = hand_str[1].parse::()?; + + Self::new([cards[0], cards[1], cards[2], cards[3], cards[4]], bid) + } +} + +#[derive(Debug)] +pub struct Hands(BTreeSet>); + +impl Hands { + pub fn get_total_winnings(&self) -> u64 { + (1u64..).zip(self.0.iter()).map(|(rank, hand)| rank * hand.bid).sum() + } +} + +impl FromStr for Hands { + type Err = CardsError; + + fn from_str(s: &str) -> Result { + Ok(Self( + s.lines() + .map(Hand::::from_str) + .collect::>, CardsError>>()?, + )) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + const EXAMPLE: &str = "32T3K 765 +T55J5 684 +KK677 28 +KTJJT 220 +QQQJA 483"; + + #[test] + fn hand_parsing() { + let five_kind = Hand::::from_str("AAAAA 0").expect("Failed parsing five of a kind"); + let four_kind = Hand::::from_str("AA8AA 0").expect("Failed parsing four of a kind"); + let full_house = Hand::::from_str("23332 0").expect("Failed parsing full house"); + let three_kind = Hand::::from_str("TTT98 0").expect("Failed to parse three of a kind"); + let two_pair = Hand::::from_str("23432 0").expect("Failed parsing two pair"); + let one_pair = Hand::::from_str("A23A4 0").expect("Failed parsing one pair"); + let high_card = Hand::::from_str("23456 0").expect("Failed pasing high card"); + + assert_eq!(five_kind.typ, HandType::FiveOfAKind); + assert_eq!(four_kind.typ, HandType::FourOfAKind); + assert_eq!(full_house.typ, HandType::FullHouse); + assert_eq!(three_kind.typ, HandType::ThreeOfAKind); + assert_eq!(two_pair.typ, HandType::TwoPair); + assert_eq!(one_pair.typ, HandType::OnePair); + assert_eq!(high_card.typ, HandType::HighCard); + } + + #[test] + fn hand_ordering() { + let hand_1 = Hand::::from_str("33332 0").expect("Failed parsing hand 1"); + let hand_2 = Hand::::from_str("2AAAA 0").expect("Failed parsing hand 2"); + + assert!(hand_1 > hand_2); + + let hand_3 = Hand::::from_str("77888 0").expect("Failed parsing hand 3"); + let hand_4 = Hand::::from_str("77788 0").expect("Failed parsing hand 4"); + + assert!(hand_3 > hand_4); + + assert!(hand_1 > hand_3 && hand_1 > hand_4); + assert!(hand_2 > hand_3 && hand_2 > hand_4); + } + + #[test] + fn hand_parsing_jokers() { + let five_kind = Hand::::from_str("AAJAA 0").expect("Failed parsing five of a kind"); + let four_kind = Hand::::from_str("QJJQ2 0").expect("Failed parsing four of a kind"); + + assert_eq!(five_kind.typ, HandType::FiveOfAKind); + assert_eq!(four_kind.typ, HandType::FourOfAKind); + + let five_kind_joker = Hand::::from_str("JJJJJ 0").expect("Failed parsing five of a kind jokers"); + + assert_eq!(five_kind_joker.typ, HandType::FiveOfAKind); + assert_eq!(five_kind_joker.cards, [Card::::Joker; 5]) + } + + #[test] + fn hand_ordering_jokers() { + let hand_1 = Hand::::from_str("QQQQ2 0").expect("Failed parsing hand 2"); + let hand_2 = Hand::::from_str("JKKK2 0").expect("Failed parsing hand 1"); + + assert!(hand_1 > hand_2); + } + + #[test] + fn solution_1() { + let hands = Hands::::from_str(EXAMPLE).expect("Failed parsing hands"); + assert_eq!(hands.get_total_winnings(), 6440); + } + + #[test] + fn solution_2() { + let hands = Hands::::from_str(EXAMPLE).expect("Failed parsing hands with jokers"); + assert_eq!(hands.get_total_winnings(), 5905); + } +}