diff --git a/Cargo.lock b/Cargo.lock index b9143ad..7d63119 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -86,6 +86,14 @@ dependencies = [ "rayon", ] +[[package]] +name = "day-07" +version = "0.0.0" +dependencies = [ + "indoc", + "itertools", +] + [[package]] name = "either" version = "1.9.0" diff --git a/Cargo.toml b/Cargo.toml index f963a3b..e222399 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,8 @@ members = [ "day-02", "day-03", "day-05", - "day-06" + "day-06", + "day-07" ] [workspace.dependencies] diff --git a/day-07/Cargo.toml b/day-07/Cargo.toml new file mode 100644 index 0000000..69f4a0e --- /dev/null +++ b/day-07/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "day-07" +version = "0.0.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +indoc.workspace = true +itertools.workspace = true diff --git a/day-07/src/bin/input.txt b/day-07/src/bin/input.txt new file mode 100644 index 0000000..6e5e56a --- /dev/null +++ b/day-07/src/bin/input.txt @@ -0,0 +1,1000 @@ +35229 30 +Q379J 837 +88Q8Q 841 +A8725 531 +9959J 588 +Q7AA2 79 +J7Q5J 446 +44644 73 +222J9 43 +475TK 461 +KKA5J 251 +7K49A 760 +T333T 932 +5T8QK 301 +37973 197 +555K2 816 +42422 45 +3AAAA 699 +A77A4 530 +K9QQK 785 +67K36 694 +933J4 320 +QQ98Q 267 +22KK6 306 +2AKAK 77 +7775J 518 +3T586 952 +34J58 132 +3353T 773 +TT353 480 +5777A 459 +79333 280 +7TK8T 242 +K7A3Q 444 +KK6Q4 575 +T5AKA 256 +858TT 670 +A7KA8 731 +67676 92 +T966T 616 +9Q765 566 +23Q92 322 +356A6 957 +996Q9 687 +6398Q 578 +52552 107 +T8558 384 +4A69J 998 +TQT2Q 317 +K56QT 797 +4A2AJ 36 +Q777K 552 +AT6Q4 902 +JJJJJ 358 +K358K 563 +Q94QQ 113 +A28J8 167 +29224 781 +QT66T 135 +2AA26 738 +4K8AT 324 +JT728 511 +7JQTJ 399 +8K94Q 691 +KAA92 818 +8Q846 892 +A66TJ 368 +48QKT 742 +39K99 479 +73T72 868 +J4K37 386 +JK767 405 +75Q4A 850 +35274 184 +72T9T 186 +A9Q7A 291 +A3JAA 263 +57927 766 +9T42Q 485 +6A6AK 165 +T2TTT 600 +753QA 570 +6K27Q 939 +A7A8T 659 +8TQJK 656 +4T922 115 +3K337 719 +56665 134 +T4A22 367 +QQJ5A 776 +89889 919 +54A44 751 +22665 103 +J4QK4 88 +45J44 390 +382A7 305 +8JTTQ 349 +K6KK6 260 +2Q228 625 +39Q44 663 +9K96K 414 +A9JAA 905 +2A8JJ 562 +KT9J4 960 +666K6 678 +TA666 212 +TTT8A 543 +98J28 548 +6QT83 966 +AA58J 933 +77677 199 +JJ222 824 +88J68 763 +9J999 255 +66J6J 163 +TQ3K8 90 +5A6T6 565 +4TT4T 741 +TTKTJ 9 +755AQ 402 +39943 62 +358JJ 295 +QT46K 493 +283TT 334 +2222J 631 +TTKKT 573 +55AA9 857 +725T4 836 +33A23 325 +659Q3 293 +J4747 806 +AJKT8 940 +99449 669 +JQ888 198 +66868 432 +57J42 437 +8T58A 811 +4KK55 595 +K2KKK 7 +KA52J 651 +3T6TT 93 +J6398 392 +78564 992 +385KJ 602 +Q7Q7Q 958 +Q9T79 524 +5Q555 330 +2JQ2Q 619 +7T9K3 698 +J88J8 780 +KKJAA 712 +QQ777 671 +26Q59 18 +2J585 991 +J9969 647 +KQ3A3 586 +KKK44 875 +2TT2T 579 +538J8 515 +5T444 842 +QT4QQ 864 +55553 505 +7KKKQ 125 +47Q47 650 +9Q7Q9 278 +7769K 365 +QTTQQ 177 +Q3A99 38 +888J3 784 +KJK33 921 +65657 848 +26336 594 +K7777 916 +T573J 790 +Q64QQ 234 +66696 2 +36673 329 +QQ5QJ 820 +85J35 156 +K74K7 513 +A8A8J 29 +4TT33 829 +JA9TJ 574 +4ATTT 464 +T6TQ7 104 +452J3 297 +Q9A73 343 +267AK 427 +QTQ3Q 981 +K84J2 100 +4Q333 605 +JK355 164 +5465A 70 +66226 490 +44TAT 666 +88833 851 +A28AA 555 +23982 997 +22232 882 +787KK 81 +T49TJ 274 +55475 249 +88882 982 +74T98 170 +48484 56 +K392T 375 +4TT43 426 +65JQ4 499 +44339 327 +79T77 257 +T6TTA 727 +K9798 660 +Q8T54 855 +8J7TJ 222 +T7776 642 +94T9T 27 +TT3T4 298 +559JQ 819 +96T7T 4 +AJAJJ 89 +87668 644 +33633 47 +87778 695 +45555 488 +87A4K 734 +4JK85 463 +9A5AA 383 +AA32A 713 +6QTT5 339 +J9A98 789 +3KAAK 980 +37525 130 +7J736 484 +22462 606 +9A2TA 483 +7T98J 84 +T22KT 158 +669J6 352 +A5599 271 +K6QJ7 696 +82822 935 +AA3J3 61 +43553 885 +7586K 839 +TQ58A 581 +K4444 924 +55858 928 +AA669 372 +92626 774 +QAQQ6 898 +A6AAA 307 +J9797 796 +54A68 930 +6TT94 487 +K3Q6T 60 +JTK2J 286 +58555 31 +8J292 798 +8QQ53 310 +K4JA4 639 +6J777 64 +A6JQA 252 +6T2QA 248 +45A45 179 +54595 441 +7582K 973 +338Q7 412 +28288 752 +JJK3K 445 +62K2T 993 +44229 724 +59399 521 +53KK2 746 +3A9AQ 550 +6525A 215 +676A2 754 +7KTA6 750 +88889 805 +T9898 457 +J99J9 681 +AA886 24 +522QJ 556 +6666J 955 +J3QA7 988 +87777 214 +52J24 277 +994J9 183 +69559 598 +93339 396 +9JAA2 243 +56636 571 +54554 987 +86T58 48 +34334 259 +7K254 945 +T4T44 203 +AT9J3 447 +8668T 720 +T9T33 645 +8AAAA 80 +Q28J6 350 +2AJ49 560 +778TT 290 +355J3 341 +Q79T3 558 +92222 527 +22262 920 +JTJTT 643 +T23TA 95 +A33K3 869 +222J5 443 +Q4Q44 896 +K522J 308 +J774J 772 +52952 897 +223J2 429 +TTA5T 747 +KA459 13 +2QQJQ 858 +92297 795 +8T888 627 +QA74T 755 +26494 408 +26665 568 +J5J3J 657 +T4Q2T 984 +38223 23 +2TT5T 859 +8JJ4T 541 +JQ662 535 +T8T8T 943 +T6999 400 +25225 311 +66766 99 +KKJ9K 597 +T355T 722 +3J673 68 +5AAAA 679 +3T2K2 941 +Q9T99 244 +2929K 424 +J4JKK 477 +Q66QA 761 +Q5A8J 238 +KTTKK 828 +428JT 910 +KKKJK 497 +K5KK5 433 +QA572 537 +77TJ7 601 +3JA7K 469 +86444 314 +Q4444 917 +65QQJ 508 +KKK37 853 +3388J 331 +J97A2 312 +44J44 783 +JT7JA 191 +7QKQ7 166 +K444K 888 +83QT5 832 +T876T 82 +5J7J7 71 +696J8 974 +KQK54 918 +Q8868 618 +575AA 237 +6463Q 648 +QT5JK 906 +55755 737 +J3T3A 674 +82AA7 716 +JQ86T 801 +QTQKJ 802 +K247Q 740 +39JA3 475 +A5967 478 +4644Q 815 +Q2963 899 +JJK53 58 +K53T7 587 +33377 180 +9299J 379 +775J5 706 +KKQQ2 972 +J5656 353 +TTTT9 395 +2998K 673 +79269 501 +3AT52 303 +7KT77 710 +33539 799 +KJK7K 275 +KK999 374 +66829 413 +TA9QQ 337 +K4556 57 +4T759 745 +TQ7JQ 577 +3793A 346 +88779 615 +9888K 626 +J2K2K 241 +75377 887 +J5635 793 +6Q3T5 415 +97779 182 +T99TK 844 +444QJ 210 +99996 913 +32553 825 +K97T8 732 +JJ555 136 +K8456 239 +52J55 217 +59595 201 +JJT6T 66 +29JTK 211 +333AA 582 +777J9 629 +93653 593 +K5TK5 494 +52QQ5 458 +433JT 621 +T5T55 28 +79A8J 831 +588Q8 514 +5Q4T7 19 +72A8T 791 +73498 967 +TJJJT 35 +94494 770 +2QJ58 569 +64777 630 +9TK74 704 +QQ864 675 +6TQ54 376 +K55K6 335 +9Q8Q8 881 +AAA69 690 +999QJ 922 +K3A8Q 528 +7Q983 97 +62T99 876 +QQQQA 544 +K2885 821 +55656 360 +J6AA8 382 +5658J 739 +78225 453 +KKQKK 72 +9K277 300 +KJ333 119 +J972T 120 +96299 21 +878JJ 822 +JAT4J 730 +TT494 777 +TJ52A 299 +2J72J 884 +QA48K 714 +95Q58 240 +T2K65 536 +3923Q 532 +JKQQ5 91 +922J9 69 +75JA9 838 +A888K 845 +QA3QA 936 +8T9T8 843 +T762J 901 +JAJAQ 51 +T7777 705 +555K3 361 +Q222Q 944 +AJ77A 131 +99J2K 503 +JTJ67 733 +52922 83 +JKKKQ 44 +T4233 143 +35946 728 +AJAJA 911 +33733 50 +5J555 49 +2Q2J2 230 +J277K 633 +JTA88 389 +TAAJ6 510 +96688 40 +K93K5 67 +TJ949 154 +7Q34A 417 +J66JT 968 +9A99A 830 +46Q8T 596 +Q6646 927 +QQ555 846 +3QK2T 152 +J2828 533 +TATKT 946 +KKQ92 326 +5JQ66 849 +J557T 226 +A2883 452 +56Q2A 148 +48888 624 +A22AA 880 +44343 788 +85633 439 +55449 472 +TKATK 344 +T65Q8 576 +A555A 111 +J88A8 995 +T6663 371 +AQA4Q 122 +AA55A 765 +5T5JT 20 +73832 247 +9A9T6 282 +KJ99K 778 +J3338 914 +QQ5QQ 388 +6J464 254 +24A5J 827 +J77J7 559 +Q7Q6Q 874 +74QKJ 261 +QK37K 144 +5649T 655 +TJ746 654 +6A269 623 +226K5 17 +32J5J 953 +QTT47 748 +KK222 150 +QKQJA 507 +6A6Q3 188 +KTTT8 546 +53T99 517 +33A73 871 +89899 767 +K344T 124 +2324Q 220 +7J442 206 +9AAAA 133 +Q99Q9 456 +22233 986 +92284 725 +6347A 701 +73777 990 +TTKTT 422 +TTT87 792 +877K8 431 +5A6QT 800 +85548 677 +53353 208 +33322 965 +AAJ45 866 +2AJAA 153 +4785K 949 +J8J77 187 +9A388 779 +J9QAQ 398 +23A36 909 +92Q95 702 +J2467 296 +A32QQ 181 +93TJ7 721 +9T428 502 +72777 667 +AAAA2 227 +TQTAT 847 +KA777 264 +T4635 744 +A886Q 492 +TQJ3A 449 +JAAA6 729 +QJ86J 840 +JK777 385 +9922A 430 +QKT95 425 +34AKA 551 +5J996 377 +82J87 270 +26T59 173 +AKKKA 294 +K675Q 688 +K79JA 718 +668J8 970 +J7373 520 +A5873 985 +99A79 381 +AA33A 620 +QQ93J 435 +23758 416 +QQ2QQ 672 +48K49 75 +92294 893 +22QQQ 467 +59555 612 +AKAAA 101 +A29Q6 756 +675K3 471 +Q5776 129 +A68T2 890 +Q76J7 599 +84QA9 229 +J68AJ 194 +996A6 661 +888J8 929 +JA8K4 580 +77879 3 +T8J2A 266 +K66AK 810 +899J4 53 +6QQ66 646 +KK3JK 915 +TQQKQ 373 +892TQ 378 +777AJ 689 +7T898 190 +K4QJK 262 +36AK9 5 +78788 189 +8722K 978 +499J4 979 +8QQQ8 407 +T55J3 903 +672Q8 168 +996JJ 357 +555A5 622 +8844J 192 +959QK 348 +QQQQ6 54 +6Q56Q 304 +62TT6 567 +K4QQQ 246 +6T439 963 +JQ2J8 171 +6766J 272 +2T798 592 +4J4AA 591 +38TAJ 224 +45788 276 +56555 110 +T5T5T 354 +78888 106 +737Q6 908 +54454 14 +TTTQT 340 +8K8KK 610 +46454 786 +88JK2 63 +8Q8QJ 316 +KJ88A 549 +K6K45 209 +5Q95A 942 +7J9KK 641 +67767 451 +A2Q5J 37 +JJT22 176 +43JKA 387 +44T2A 409 +2Q222 438 +JT822 245 +577A3 526 +5TJT2 200 +38T43 856 +KJ444 553 +QTTTQ 749 +57477 147 +4T2Q8 878 +2A2KA 436 +AAAQJ 284 +38828 867 +528QK 141 +26TK4 692 +3444J 693 +5Q955 333 +3AK24 460 +7J52Q 185 +22277 542 +AATAT 281 +T57Q2 519 +84483 140 +85436 926 +AKAKA 283 +JK4K8 468 +6JQ6A 196 +34464 481 +JK5Q2 328 +423J3 609 +77A47 614 +22242 279 +99279 608 +89492 529 +3A333 292 +3T5TT 948 +979T9 907 +37322 455 +6QQ68 397 +A66JA 638 +93QA3 833 +TJ8J2 983 +TT5QQ 202 +TT888 1 +QKQTK 852 +JA556 703 +QT345 496 +88Q26 994 +5Q5AA 697 +59429 418 +9939T 318 +Q333Q 370 +Q3AA3 707 +378JQ 572 +2255Q 86 +2JA2A 509 +J5K36 117 +Q5866 861 +Q94Q2 813 +36993 287 +A5574 590 +TQ43K 743 +T66AT 711 +4A6J5 178 +5K5J5 961 +888A3 959 +4777K 554 +T4QKK 637 +JTQQ6 735 +37735 782 +5J9J5 233 +33Q33 607 +9T9T9 250 +A6A66 683 +JAAAA 96 +J63J7 717 +22K4K 870 +T3J6J 169 +8TT33 895 +63339 865 +QT3TT 42 +6TT48 218 +KAK5T 894 +T6922 736 +9AJ9A 102 +KKAKT 151 +QT79A 726 +KA999 442 +99399 315 +224T6 213 +KAKK9 410 +7J7KK 812 +KT859 155 +3AT26 996 +7A6A9 640 +K5368 491 +JQK34 78 +27268 289 +4967K 564 +8K848 268 +626JJ 652 +AKA6K 964 +4J4T4 534 +93939 336 +47876 59 +3J23A 207 +9Q999 126 +22432 265 +K7KKK 205 +AA399 835 +K77K7 112 +3J5K9 762 +36J33 223 +T3TAJ 947 +QQQA8 466 +3434Q 219 +Q4QQ5 764 +QQQJQ 500 +AJAKA 157 +82T96 393 +888KK 85 +3699J 474 +QQQKQ 680 +TTT7J 145 +6Q982 221 +96669 174 +KQ33Q 228 +JJJ8J 450 +368K8 12 +29QJ8 195 +T6TT6 561 +5KA22 522 +777TT 962 +92899 854 +799JJ 10 +Q3Q53 394 +7A745 285 +9Q43K 46 +Q33AQ 355 +7Q9JK 454 +69Q66 956 +7A325 950 +39T4J 470 +336QQ 715 +JA62A 345 +88883 951 +7J777 771 +63878 482 +KAKKK 486 +7TT33 504 +Q9AQA 976 +QAAJQ 98 +69J69 332 +5298Q 160 +27292 273 +T2T4T 448 +2J95K 428 +46646 11 +9JJ33 787 +Q9QQQ 216 +J4455 912 +J96QA 628 +9A49A 676 +64K66 547 +K853T 391 +K4J87 769 +JAA7K 347 +J5535 931 +99222 886 +5K59K 313 +3333K 362 +66J86 434 +48J56 604 +4K39T 775 +4A86Q 495 +T99J9 139 +782T7 823 +T4494 658 +66986 971 +KKK87 25 +52222 269 +3T3TT 236 +5KK74 904 +TK2KJ 860 +T33KQ 969 +727J7 423 +24926 114 +T8965 288 +58K84 462 +43T34 175 +KK77K 768 +33663 41 +Q66J6 231 +2T222 758 +Q4QJ4 411 +QQ99Q 540 +9J698 403 +T99JT 709 +8QKKQ 1000 +AAA48 39 +7Q4J7 636 +T7787 465 +56TT6 225 +Q88TT 611 +6T98Q 516 +834TK 366 +3QJQQ 309 +3A833 15 +JT4Q9 323 +673TT 149 +T8JA5 338 +28222 476 +AA4A4 321 +T9JTT 161 +8573J 753 +6Q44J 363 +A4744 105 +T985J 440 +24J4T 8 +552K3 804 +8TT56 401 +J7Q77 406 +32333 87 +KKKJ5 668 +A44A4 506 +Q767K 138 +TJTTT 632 +TT5TT 613 +6AA6A 937 +KK7K6 94 +46554 862 +3333J 162 +6T666 834 +KK8JK 74 +92J3A 33 +9TT2T 123 +964J6 938 +TTT99 76 +JQJQ8 685 +JT6T8 22 +A5Q2T 977 +77QJQ 6 +62A37 700 +JJ867 925 +3QJ39 872 +2AKKK 934 +44QQ6 873 +4J422 954 +79979 489 +888KJ 889 +Q4A85 759 +AAQK2 52 +54646 232 +99966 172 +33833 538 +Q23T9 351 +34444 380 +QQKK5 421 +TTJ22 32 +336A4 682 +Q2TQ5 525 +J8K4T 809 +47797 523 +K72Q9 665 +J3J33 999 +96A98 55 +98Q34 109 +6J646 26 +96946 235 +24Q75 253 +6A5Q3 404 +K5KK7 342 +JTTT5 653 +5KKQK 118 +2775Q 649 +8T58K 975 +AA5K5 356 +7AAAK 512 +4753K 369 +32335 900 +T7TT5 603 +64825 16 +T5T93 193 +4925J 127 +488A5 757 +39K9K 584 +T77KK 159 +K4KT5 420 +Q746K 65 +JQ6AJ 826 +5T664 807 +95995 808 +85838 794 +J8KQ3 817 +J97A4 891 +4QQ77 146 +T44A6 498 +556Q6 589 +Q6745 617 +TTTT3 883 +A64QK 723 +QAAQQ 684 +72222 116 +A74K3 121 +JK49K 583 +48884 708 +Q9979 302 +888T3 803 +K788K 635 +5A82T 662 +A383Q 557 +K6966 204 +K9999 634 +72774 34 +8TQ7K 585 +79954 664 +3Q42K 879 +QQQQ8 539 +394QQ 108 +Q758K 137 +72727 419 +58835 359 +32726 545 +4J4J4 142 +AJJA9 989 +589KK 686 +7722A 923 +97479 863 +TTTQJ 814 +Q66QQ 258 +T5TJJ 319 +T9A6T 473 +6777A 364 +22T2T 877 +7388J 128 \ No newline at end of file diff --git a/day-07/src/bin/part1.rs b/day-07/src/bin/part1.rs new file mode 100644 index 0000000..d2643bc --- /dev/null +++ b/day-07/src/bin/part1.rs @@ -0,0 +1,150 @@ +use itertools::Itertools; +use std::cmp::Ordering; + +fn main() { + println!("{}", part1(include_str!("./input.txt"))); +} + +fn part1(input: &str) -> u64 { + let hands = input.lines().map(process_hand).collect::>(); + + calc_total_winnings(hands) +} + +fn process_hand(input: &str) -> Hand { + let (hand, bid) = input.split_once(' ').expect("invalid input"); + + let cards = hand.chars().map(Card::from).collect::>(); + let mut card_amounts = cards.clone(); + card_amounts.sort(); + card_amounts.reverse(); + let grouped_cards = card_amounts.into_iter().group_by(|c| *c); + let mut grouped_cards = grouped_cards + .into_iter() + .map(|(c, g)| (c, g.count())) + .collect::>(); + grouped_cards.sort_by(|(c1, g1), (c2, g2)| match g2.cmp(g1) { + Ordering::Equal => c2.cmp(c1), + x => x, + }); + + let mut grouped_cards = grouped_cards.into_iter(); + + let rank = match grouped_cards.next() { + Some((_, 5)) => Rank::FiveOfAKind, + Some((_, 4)) => Rank::FourOfAKind, + Some((_, 3)) => match grouped_cards.next() { + Some((_, 2)) => Rank::FullHouse, + Some((_, 1)) => Rank::ThreeOfAKind, + _ => panic!("invalid hand"), + }, + Some((_, 2)) => match grouped_cards.next() { + Some((_, 2)) => Rank::TwoPair, + Some((_, 1)) => Rank::OnePair, + _ => panic!("invalid hand"), + }, + Some((_, 1)) => Rank::HighCard, + Some((_, _)) => panic!("invalid hand"), + None => panic!("invalid hand"), + }; + + Hand { + bid: bid.parse().expect("invalid bid"), + cards: cards.try_into().expect("invalid hand"), + rank, + } +} + +fn calc_total_winnings(mut hands: Vec) -> u64 { + hands.sort(); + + hands + .into_iter() + .enumerate() + .map(|(i, h)| (i + 1) as u64 * h.bid as u64) + .sum() +} + +#[derive(Debug, PartialEq, Clone, Copy, Eq, PartialOrd, Ord)] +enum Card { + N2, + N3, + N4, + N5, + N6, + N7, + N8, + N9, + T, + J, + Q, + K, + A, +} + +impl From for Card { + fn from(c: char) -> Self { + match c { + '2' => Self::N2, + '3' => Self::N3, + '4' => Self::N4, + '5' => Self::N5, + '6' => Self::N6, + '7' => Self::N7, + '8' => Self::N8, + '9' => Self::N9, + 'T' => Self::T, + 'J' => Self::J, + 'Q' => Self::Q, + 'K' => Self::K, + 'A' => Self::A, + _ => panic!("invalid card"), + } + } +} + +#[derive(Debug, PartialEq, Clone, Copy, Eq, PartialOrd, Ord)] +enum Rank { + HighCard, + OnePair, + TwoPair, + ThreeOfAKind, + FullHouse, + FourOfAKind, + FiveOfAKind, +} + +#[derive(Debug, PartialEq, Clone, Copy, Eq, PartialOrd, Ord)] +struct Hand { + rank: Rank, + cards: [Card; 5], + bid: u32, +} + +impl From<&str> for Hand { + fn from(s: &str) -> Self { + process_hand(s) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use indoc::indoc; + + #[test] + fn test_part1() { + assert_eq!( + part1(indoc!( + " + 32T3K 765 + T55J5 684 + KK677 28 + KTJJT 220 + QQQJA 483 + " + )), + 6440 + ); + } +} diff --git a/day-07/src/bin/part2.rs b/day-07/src/bin/part2.rs new file mode 100644 index 0000000..8e837f3 --- /dev/null +++ b/day-07/src/bin/part2.rs @@ -0,0 +1,158 @@ +use itertools::Itertools; +use std::cmp::Ordering; + +fn main() { + println!("{}", part2(include_str!("./input.txt"))); +} + +fn part2(input: &str) -> u64 { + let hands = input.lines().map(process_hand).collect::>(); + + calc_total_winnings(hands) +} + +fn process_hand(input: &str) -> Hand { + let (hand, bid) = input.split_once(' ').expect("invalid input"); + + let cards = hand.chars().map(Card::from).collect::>(); + let mut card_amounts = cards.clone(); + card_amounts.sort(); + card_amounts.reverse(); + let grouped_cards = card_amounts.into_iter().group_by(|c| *c); + let mut grouped_cards = grouped_cards + .into_iter() + .filter(|(c, _)| *c != Card::J) + .map(|(c, g)| (c, g.count())) + .collect::>(); + grouped_cards.sort_by(|(c1, g1), (c2, g2)| match g2.cmp(g1) { + Ordering::Equal => c2.cmp(c1), + x => x, + }); + + let jokers = cards.iter().filter(|c| **c == Card::J).count(); + + let mut grouped_cards = grouped_cards.into_iter(); + + let rank = if let Some((_, a)) = grouped_cards.next() { + match a + jokers { + 5 => Rank::FiveOfAKind, + 4 => Rank::FourOfAKind, + 3 => match grouped_cards.next() { + Some((_, 2)) => Rank::FullHouse, + Some((_, 1)) => Rank::ThreeOfAKind, + _ => panic!("invalid hand"), + }, + 2 => match grouped_cards.next() { + Some((_, 2)) => Rank::TwoPair, + Some((_, 1)) => Rank::OnePair, + _ => panic!("invalid hand"), + }, + 1 => Rank::HighCard, + _ => panic!("invalid hand"), + } + } else if jokers == 5 { + Rank::FiveOfAKind + } else { + panic!("invalid hand") + }; + + Hand { + bid: bid.parse().expect("invalid bid"), + cards: cards.try_into().expect("invalid hand"), + rank, + } +} + +fn calc_total_winnings(mut hands: Vec) -> u64 { + hands.sort(); + + hands + .into_iter() + .enumerate() + .map(|(i, h)| (i + 1) as u64 * h.bid as u64) + .sum() +} + +#[derive(Debug, PartialEq, Clone, Copy, Eq, PartialOrd, Ord)] +enum Card { + J, + N2, + N3, + N4, + N5, + N6, + N7, + N8, + N9, + T, + Q, + K, + A, +} + +impl From for Card { + fn from(c: char) -> Self { + match c { + '2' => Self::N2, + '3' => Self::N3, + '4' => Self::N4, + '5' => Self::N5, + '6' => Self::N6, + '7' => Self::N7, + '8' => Self::N8, + '9' => Self::N9, + 'T' => Self::T, + 'J' => Self::J, + 'Q' => Self::Q, + 'K' => Self::K, + 'A' => Self::A, + _ => panic!("invalid card"), + } + } +} + +#[derive(Debug, PartialEq, Clone, Copy, Eq, PartialOrd, Ord)] +enum Rank { + HighCard, + OnePair, + TwoPair, + ThreeOfAKind, + FullHouse, + FourOfAKind, + FiveOfAKind, +} + +#[derive(Debug, PartialEq, Clone, Copy, Eq, PartialOrd, Ord)] +struct Hand { + rank: Rank, + cards: [Card; 5], + bid: u32, +} + +impl From<&str> for Hand { + fn from(s: &str) -> Self { + process_hand(s) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use indoc::indoc; + + #[test] + fn test_part2() { + assert_eq!( + part2(indoc!( + " + 32T3K 765 + T55J5 684 + KK677 28 + KTJJT 220 + QQQJA 483 + " + )), + 5905 + ); + } +}