diff --git a/ReadMe.md b/ReadMe.md index 00cfd98e..ffeb7664 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -12,6 +12,7 @@ | 2023-04 | [Scratchcards](https://adventofcode.com/2023/day/4) | [Scala](scala2/src/main/scala/jurisk/adventofcode/y2023/Advent04.scala) | | | | 2023-05 | [If You Give A Seed A Fertilizer](https://adventofcode.com/2023/day/5) | [Scala](scala2/src/main/scala/jurisk/adventofcode/y2023/Advent05.scala) | | | | 2023-06 | [Wait For It](https://adventofcode.com/2023/day/6) | [Scala](scala2/src/main/scala/jurisk/adventofcode/y2023/Advent06.scala) | | | +| 2023-07 | [Camel Cards](https://adventofcode.com/2023/day/7) | [Scala](scala2/src/main/scala/jurisk/adventofcode/y2023/Advent07.scala) | | | | 2022-01 | [Calorie Counting](https://adventofcode.com/2022/day/1) | [Scala](scala2/src/main/scala/jurisk/adventofcode/y2022/Advent01.scala) | | | | 2022-02 | [Rock Paper Scissors](https://adventofcode.com/2022/day/2) | [Scala](scala2/src/main/scala/jurisk/adventofcode/y2022/Advent02.scala) | | | | 2022-03 | [Rucksack Reorganization](https://adventofcode.com/2022/day/3) | [Scala](scala2/src/main/scala/jurisk/adventofcode/y2022/Advent03.scala) | | | diff --git a/scala2/src/main/resources/2023/07-test.txt b/scala2/src/main/resources/2023/07-test.txt new file mode 100644 index 00000000..bf2815e0 --- /dev/null +++ b/scala2/src/main/resources/2023/07-test.txt @@ -0,0 +1,5 @@ +32T3K 765 +T55J5 684 +KK677 28 +KTJJT 220 +QQQJA 483 \ No newline at end of file diff --git a/scala2/src/main/resources/2023/07.txt b/scala2/src/main/resources/2023/07.txt new file mode 100644 index 00000000..deba3178 --- /dev/null +++ b/scala2/src/main/resources/2023/07.txt @@ -0,0 +1,1000 @@ +A2T63 467 +4854J 948 +TJTT3 229 +69664 839 +ATT9A 340 +69959 997 +39666 4 +JJA59 528 +A7799 27 +T8JTA 71 +3333J 50 +43Q48 897 +66266 574 +65TTT 572 +TT222 608 +JAAQT 98 +9Q959 610 +27573 537 +J2228 504 +AJ555 447 +KJK6K 283 +2J57T 183 +4444Q 500 +66696 353 +J7988 941 +79TJK 744 +24244 107 +K9625 958 +4A2AA 814 +6Q566 494 +7QA77 586 +9KTK9 510 +44QQQ 101 +Q9T9Q 746 +A9299 272 +Q656J 536 +29999 874 +Q2T49 811 +777T7 928 +28288 198 +44634 249 +5Q96T 484 +Q257J 83 +63636 568 +58J59 174 +QQAQQ 633 +3J84J 73 +2TTJT 684 +898A9 751 +J9638 917 +5546J 118 +JJ897 738 +AA33A 927 +77JTT 603 +79799 439 +23J23 228 +7QQ6T 33 +92585 468 +98998 685 +TT2TT 378 +K999K 327 +88A59 163 +46666 60 +37TT7 957 +7QJ35 209 +33934 333 +TTTT8 154 +3932K 813 +QA6AT 791 +66T34 128 +39939 277 +J34J4 175 +9KA99 964 +94444 763 +JJK4A 236 +67AJK 28 +4QTQT 299 +8TK4Q 526 +KAK4K 253 +3K7A2 918 +49399 112 +TTQQQ 845 +J999J 418 +K44KK 677 +4AK2J 61 +9J959 475 +J8838 387 +66676 102 +T63A6 264 +34483 865 +QKQKQ 692 +J6669 952 +K286T 436 +666JT 472 +J9872 303 +ATTTT 543 +22J52 577 +A447Q 493 +74TQ3 698 +68T88 759 +5TT5T 668 +777KA 470 +AA3AQ 104 +76Q6A 902 +T536Q 784 +5Q66T 2 +7A72A 765 +T5455 462 +TT39K 629 +J73JA 419 +T77T7 993 +22K78 357 +83Q33 13 +54T84 531 +44AA4 167 +QTJ38 100 +6665J 70 +5957T 313 +J884A 56 +T6T99 944 +TKK6K 265 +265K7 850 +22325 109 +QQQ55 195 +7TATT 513 +4999Q 575 +56TQK 688 +62266 553 +27252 663 +K87A3 311 +J2AAJ 647 +77737 19 +Q4T4J 979 +2QK7Q 852 +Q2Q42 7 +89J77 924 +QT66T 992 +288A8 593 +QQQQ2 509 +58329 622 +5JAAA 356 +97364 999 +38576 806 +55K67 491 +KKK8K 215 +T2TT4 398 +6666K 412 +Q9829 583 +385K8 348 +88A48 235 +76K8K 656 +K4K44 204 +A42TQ 712 +49K4K 245 +22266 297 +T3AAA 177 +72294 636 +TTQTT 907 +5JQ95 762 +KK777 824 +4Q294 835 +T9722 79 +55Q6Q 683 +666JK 726 +27A64 457 +494J4 561 +52255 230 +37335 675 +T9383 911 +8543K 247 +67QA8 659 +QJ886 886 +2QJJ7 261 +K29K9 339 +64Q84 497 +6T6TT 203 +K88K8 25 +AA5AA 882 +59925 256 +K995T 382 +K7777 734 +55888 371 +A7J28 710 +JTATT 480 +T7JKJ 817 +A4Q46 887 +KJ4JK 827 +JJ8JJ 589 +4A766 878 +36596 511 +A4QQ6 266 +5JK32 669 +7J372 521 +K949J 325 +3A633 218 +25Q6K 110 +44K48 406 +69668 893 +2QJT6 864 +4QQQQ 216 +5K555 184 +TA969 616 +3T573 876 +A5K9J 160 +J22KA 637 +48575 316 +75997 391 +38558 903 +35535 793 +J2J42 933 +J74A5 92 +9K457 771 +T57K7 111 +TJ926 978 +89K4A 274 +2Q344 153 +TJTTJ 199 +994AA 259 +3Q724 421 +66366 34 +Q444J 909 +3QQQJ 188 +9AAAA 769 +A974K 35 +99959 922 +99646 159 +22225 46 +9A3JJ 257 +T2J9A 133 +7527A 171 +88868 36 +23322 341 +T99J7 797 +QQ8A7 461 +AJ2A3 138 +55AJ2 16 +AAAQA 254 +57332 623 +A3333 22 +T37K9 597 +44QT4 713 +J7T6T 516 +Q888Q 896 +Q22QQ 222 +2783Q 11 +75779 959 +642J5 842 +T9TT4 580 +6JQ95 392 +A355A 649 +53676 271 +3J353 643 +Q28Q4 499 +44J5J 702 +Q97K2 833 +433A5 570 +99979 459 +AJT44 652 +663K6 789 +63399 994 +AATJT 65 +4J8J2 212 +KQ353 373 +A53K4 180 +J9797 846 +TTT98 686 +7KKKA 868 +88J3J 372 +9T5KQ 482 +J5Q8A 514 +9588K 695 +JA73Q 752 +97TTJ 779 +QT888 405 +QJ9Q5 293 +T3489 481 +AAAAT 940 +KK4KK 662 +84A9Q 841 +2Q224 278 +A2K84 548 +66569 232 +4T4QQ 5 +AAAA8 17 +K95AK 617 +97858 892 +88A2K 72 +42J2Q 448 +993K3 740 +7T97T 150 +444T3 393 +333JA 700 +J7Q4A 90 +4KQ3Q 402 +T3TJ9 844 +44864 820 +J29AA 913 +23293 651 +Q9939 777 +666Q6 191 +A2288 745 +8338K 796 +3J9Q7 241 +48854 85 +J6266 305 +9QQ53 821 +AT497 655 +ATAA8 943 +6AA66 627 +9Q999 895 +A563K 24 +22722 221 +7J35J 336 +76687 826 +6A79A 487 +94944 148 +22A28 223 +J55TQ 829 +39K92 306 +86667 178 +QQQQ3 8 +93A33 413 +JQ777 930 +K8TQ8 440 +JJJJJ 666 +68T72 432 +577J4 828 +72275 926 +9K85T 975 +T4J27 618 +J882Q 725 +23323 308 +T55TJ 977 +23272 408 +48QQQ 260 +J5565 45 +Q98Q9 262 +444T4 540 +88K48 424 +3J3J3 890 +TQ353 786 +9Q222 201 +5T443 142 +AA6A6 14 +Q7447 136 +7T55K 196 +79433 818 +3QT3J 602 +Q7QQQ 114 +77877 410 +33955 485 +474A7 193 +7KA7K 530 +33993 626 +6QQQQ 694 +2J248 956 +62A28 639 +TJ9QQ 696 +6JK52 569 +42844 76 +44322 519 +Q22J2 840 +J6J66 805 +Q5Q5J 185 +QAJA6 750 +48896 95 +2T2TT 57 +243J7 182 +49279 231 +99J99 377 +JQ324 243 +55984 407 +QJ68T 290 +5Q47K 324 +A349Q 170 +8Q8QQ 469 +K2JJK 625 +TTJTT 501 +J4444 81 +47A44 812 +2TJ23 594 +Q622A 873 +JJ8AK 587 +5T5TK 197 +899Q7 606 +8TJK9 380 +K68Q5 454 +KQTK6 335 +6K668 207 +QQ6T6 164 +38J37 682 +2JJ2K 506 +72277 650 +7J728 934 +883T8 62 +Q2T72 985 +J25T9 464 +85657 429 +J2AA2 780 +66668 206 +KAKAK 291 +3KKKK 279 +5K33A 234 +82228 757 +J6QQ4 251 +Q3Q57 973 +QT342 80 +33Q8Q 869 +28546 515 +443KK 296 +44785 172 +JKT56 438 +27A47 179 +64789 925 +Q6KQ5 642 +227J2 488 +5264T 86 +2A57A 628 +A64TK 369 +4T42T 77 +6595J 108 +38247 91 +J5K8K 730 +5AQJQ 723 +K8KKA 604 +92226 705 +2J2AQ 676 +6AQQA 870 +TTTK9 147 +A28K3 984 +K2K2T 670 +2TT35 135 +JQT42 546 +JA696 9 +K3K39 815 +89T2J 880 +4J3TT 132 +K4K62 560 +8742Q 242 +K75K5 403 +5J55T 301 +33733 718 +7Q777 507 +878JT 355 +8J53J 598 +2J442 512 +AAJAJ 26 +69966 252 +6AJ2A 654 +A5A55 329 +578A3 214 +QTJT9 955 +86838 525 +78KAJ 843 +66J79 557 +J22T2 573 +K77T7 141 +6Q568 1000 +KKKK5 741 +8426K 921 +2K69Q 539 +6AKT2 258 +Q33Q6 559 +T627Q 389 +Q2489 856 +44544 456 +AQQQ7 116 +Q6J76 965 +TQTQT 808 +QQ35K 838 +37T5Q 155 +KKKKJ 281 +4Q4JK 632 +8A8A8 384 +98T82 365 +33JKT 404 +2A868 474 +3J8J2 505 +2K22Q 145 +9T9TT 74 +78888 298 +86A5Q 571 +6K56T 648 +24727 263 +KK9AA 809 +6T6T6 638 +67K9A 319 +22T22 415 +A92QQ 127 +8J9J9 400 +Q59QQ 862 +73337 75 +QQQQJ 761 +8JK42 233 +3K6K3 15 +5T737 381 +2QT24 395 +88J8Q 93 +AK747 37 +42747 798 +92666 54 +K6AKA 490 +QQ235 782 +AA4AQ 139 +J22TT 954 +66JTJ 68 +K9A5T 792 +9Q56Q 837 +63365 889 +K53A8 82 +28886 810 +46626 47 +AJ443 442 +TJT33 386 +A4822 338 +K22J2 238 +99323 961 +J632Q 479 +Q6222 848 +3JQQ3 119 +9QQQQ 703 +22388 900 +333J8 803 +88333 950 +73K47 280 +67KJ4 30 +7QA7A 716 +J864Q 974 +Q5T75 565 +777JJ 787 +99899 288 +76Q77 971 +29442 679 +TTTT7 126 +A448T 317 +97Q4K 347 +729JQ 200 +T8T8T 664 +77747 894 +K6AA6 55 +88848 48 +8QQQJ 743 +KQQQQ 310 +J78TT 43 +66K6K 323 +23J39 292 +7Q49A 937 +32T95 951 +A3A92 211 +3QJ5J 12 +77KAT 304 +44763 715 +8QTT7 366 +45JQT 320 +QQ6KK 620 +3T7JT 465 +Q866J 538 +J6T94 409 +2222J 270 +38982 321 +JJ2QT 332 +ATT8A 69 +QQA4J 542 +TKJKK 801 +5A5T5 884 +TT9TT 23 +7K343 719 +33453 96 +K82QK 349 +Q6KTT 859 +477TJ 674 +QQAAQ 754 +4J5AK 105 +2JA22 224 +QJJAK 449 +QKT4A 929 +KKA9K 968 +J399J 788 +J333T 162 +A394A 699 +QQTAJ 783 +2976Q 949 +75575 658 +J4KKK 137 +Q44TT 309 +5555A 872 +4A444 78 +5KJ5K 385 +3AK32 967 +Q55J7 898 +222A3 428 +76787 158 +52623 1 +72Q8A 267 +55Q55 756 +36363 282 +4444K 661 +6KJ44 857 +9KKJK 220 +9T7AJ 165 +44QQ3 970 +67746 794 +5A2K2 736 +75559 582 +88988 166 +58533 720 +77792 51 +6Q22J 665 +TA77T 275 +2K86A 478 +566QK 799 +9KJ79 289 +55646 120 +AAAKQ 383 +3A23J 942 +54225 646 +8AAA8 103 +6T256 946 +82J66 240 +T69J7 463 +555T5 202 +99888 219 +75936 64 +37K99 747 +43A44 58 +652TQ 981 +2JJ43 947 +4A25K 520 +K9J99 989 +22223 144 +4433Q 225 +2KKK5 352 +53577 226 +888TT 581 +KKKQQ 244 +JQ5QJ 129 +7KKK2 822 +66976 595 +74774 708 +T23QA 49 +68A6A 529 +A3Q3A 885 +4Q8J4 39 +3JK44 547 +A4KAK 755 +QT736 414 +QQTQQ 527 +77757 342 +KJKKJ 161 +T4TA4 541 +Q2583 417 +88K2K 605 +ATK5J 89 +88T77 315 +K54K7 441 +Q3994 276 +J3666 370 +89K89 861 +3564A 831 +AK394 194 +6J76K 709 +2T748 343 +4KJ69 550 +TKKTT 653 +K5K55 399 +T6T75 192 +6T226 248 +KJ665 330 +5J55J 853 +Q7577 552 +74Q4Q 115 +JA8AT 879 +KKQJQ 285 +33633 599 +586KK 434 +4334J 374 +4785K 987 +K45K5 963 +J3T4Q 915 +JT498 32 +88828 492 +JA87T 766 +TAA3T 443 +J4729 210 +7369Q 584 +64446 94 +33T33 146 +35Q5Q 190 +82878 972 +8QJ55 566 +8888J 326 +KT2QQ 640 +3JAA3 273 +J787J 564 +74KQJ 904 +87K36 237 +KKAKK 697 +35335 854 +66556 590 +KA575 998 +6495A 758 +K99QQ 181 +3223K 635 +Q6444 189 +9QKA5 563 +6Q6Q6 609 +2KJQA 156 +92292 176 +7QQQ7 804 +82TA4 816 +J6A6A 67 +TQJ8T 693 +56KJK 518 +89589 966 +6QA8J 396 +93333 450 +QQQQ8 851 +QKKKK 722 +A4AJT 778 +7J7T7 667 +JQQJQ 836 +7T4T4 430 +8QTJA 671 +353A7 125 +66343 871 +556Q5 431 +388J3 522 +T6636 704 +2TKJ3 140 +77KJ8 800 +56AA6 217 +T349A 205 +KKK22 770 +J6AKA 379 +JT2TJ 496 +TQ69J 832 +9KK9K 916 +3524J 691 +JAQQA 124 +33Q66 362 +J7A4A 149 +6846A 753 +88838 613 +6QQ96 914 +2888J 908 +QJQ4Q 819 +89K7K 742 +5J86A 995 +55559 113 +2JKJ4 41 +68866 524 +22999 375 +4533T 486 +27975 991 +22A22 795 +KQKAK 781 +JTKT3 363 +9T943 919 +58585 714 +54J45 143 +Q4664 657 +JK663 416 +28Q22 517 +65KK3 168 +KQ7JQ 477 +QKQJA 455 +62T97 458 +Q2KJK 938 +23K7J 678 +36796 721 +79268 612 +9Q5QA 567 +89Q88 768 +KTJTQ 681 +KA639 97 +32J85 134 +J96A5 532 +88885 269 +T69JT 823 +KQ6Q6 733 +AT2AA 63 +2QJ69 84 +99A9A 748 +TAQJK 830 +K5T88 446 +42449 790 +33335 578 +96J24 10 +J8K4T 358 +548J5 615 +339A8 855 +AJAA6 498 +37J32 508 +666J8 735 +3A7JA 760 +KAK57 729 +J226J 899 +28JKQ 591 +7J75Q 312 +Q282Q 66 +6J222 545 +727A7 775 +55KKK 433 +868JJ 29 +6JK87 186 +9KKKK 641 +4T4J2 727 +79JK4 556 +J99A9 923 +TTJJK 21 +TJ685 345 +QA9QQ 645 +66323 3 +66665 910 +73A7J 388 +KJ3K2 732 +77793 660 +QTA6T 988 +66888 920 +Q3393 208 +J4TJT 600 +88J8J 701 +82T3J 53 +KK7A8 772 +J77KK 425 +K7TTT 337 +K58Q3 802 +6T4T4 737 +KKKK7 453 +K9599 99 +AAAA7 476 +TKATT 728 +3QQ3Q 346 +49A98 123 +95599 286 +7K7Q4 38 +AA644 634 +J9J8T 40 +4JJ48 246 +77J22 986 +6J633 906 +ATA6A 376 +646A3 359 +KKQT7 535 +Q22Q6 785 +6J666 502 +28755 607 +852K5 44 +AA2TJ 213 +A6TJT 847 +J6A44 452 +9T982 687 +6K8K8 59 +TT6AT 87 +63222 776 +39JK3 849 +J5575 834 +8JAQA 503 +49JAK 614 +3T34T 544 +87788 451 +3475Q 351 +836J7 990 +8Q585 866 +48389 368 +2AAAA 534 +786K4 489 +785Q2 689 +A9A59 706 +9KJ22 891 +T4698 621 +63TQQ 334 +264A5 596 +4T3AQ 394 +655A4 331 +45TQ9 52 +A5999 630 +77337 858 +KT479 707 +58778 152 +79869 881 +JKQ84 344 +279T7 495 +8388Q 551 +3QJ38 877 +T3TTA 445 +6Q6QA 905 +94426 619 +79669 576 +75577 774 +8T888 962 +46J44 773 +74J88 268 +AA23A 690 +9666Q 996 +A8T82 969 +Q54Q5 932 +32942 420 +777J7 173 +J452K 466 +T85T8 322 +6556A 807 +22727 287 +2J22J 250 +3264Q 401 +Q7366 939 +4QKK4 875 +53528 295 +99963 294 +K5AQ7 20 +7A9JQ 523 +2779Q 437 +K2J44 300 +AK4Q5 426 +2A9AK 471 +77997 239 +22422 549 +3T338 151 +5T4J4 42 +3K23K 680 +82J28 901 +AQQQ8 423 +KKK29 427 +T8TJT 187 +23333 314 +84JA7 931 +Q5TJT 122 +2222Q 169 +K2937 888 +6969J 980 +QQ2Q7 328 +K7436 435 +AJAAA 724 +7Q5QQ 302 +TKKK3 131 +K5QKJ 673 +45229 588 +33J32 982 +2AK9K 558 +8A88K 444 +T26K9 411 +Q9653 117 +QJJJT 860 +37Q33 554 +396KT 130 +68262 983 +44J4J 672 +77827 106 +266Q6 367 +842AJ 749 +76363 644 +448A6 631 +22622 121 +QJ39A 361 +73376 318 +ATAAT 354 +A2KAA 390 +93T3T 562 +76TKA 307 +JAK83 18 +2684T 825 +K7T36 284 +7J3A3 483 +49TA8 953 +Q343Q 6 +JJQQK 592 +55255 945 +K8K8K 867 +53555 717 +AA36A 227 +69A48 555 +K8885 767 +9929J 364 +64999 460 +J9333 157 +49994 397 +JTKJ6 764 +TTT4T 422 +3K334 935 +5J555 711 +JK863 960 +Q8J9K 624 +Q5QQQ 473 +9988J 88 +AA99A 976 +54542 611 +4Q8Q9 31 +9AJ89 912 +5T52J 533 +K4K22 360 +54555 579 +53993 255 +44446 863 +J373Q 731 +22525 601 +Q7JQQ 350 +5J597 883 +QAQQK 936 +42434 585 +6TT6J 739 \ No newline at end of file diff --git a/scala2/src/main/scala/jurisk/adventofcode/Advent00.scala b/scala2/src/main/scala/jurisk/adventofcode/Advent00.scala index ace94b0f..d2132581 100644 --- a/scala2/src/main/scala/jurisk/adventofcode/Advent00.scala +++ b/scala2/src/main/scala/jurisk/adventofcode/Advent00.scala @@ -27,7 +27,7 @@ object Advent00 { } def parse(input: String): Input = - input.parseList("\n", Command.parse) + input.parseLines(Command.parse) def part1(data: Input): Int = data.length + 1234567 diff --git a/scala2/src/main/scala/jurisk/adventofcode/y2018/Advent10.scala b/scala2/src/main/scala/jurisk/adventofcode/y2018/Advent10.scala index 1a5bcc56..2de80b2e 100644 --- a/scala2/src/main/scala/jurisk/adventofcode/y2018/Advent10.scala +++ b/scala2/src/main/scala/jurisk/adventofcode/y2018/Advent10.scala @@ -27,7 +27,7 @@ object Advent10 { } def parse(data: String): Parsed = - data.parseList("\n", PointWithVelocity.parse) + data.parseLines(PointWithVelocity.parse) def solve(data: Parsed, limit: Int): Result1 = { val field = data.toSet diff --git a/scala2/src/main/scala/jurisk/adventofcode/y2018/Advent12.scala b/scala2/src/main/scala/jurisk/adventofcode/y2018/Advent12.scala index d84fd01e..a1bba0b2 100644 --- a/scala2/src/main/scala/jurisk/adventofcode/y2018/Advent12.scala +++ b/scala2/src/main/scala/jurisk/adventofcode/y2018/Advent12.scala @@ -83,7 +83,7 @@ object Advent12 { def parse(data: String): Parsed = { val (a, b) = data.splitPairUnsafe("\n\n"); - (State.parse(a), b.parseList("\n", parsePattern).toMap) + (State.parse(a), b.parseLines(parsePattern).toMap) } def solve(data: Parsed, iterations: Long): Long = { diff --git a/scala2/src/main/scala/jurisk/adventofcode/y2018/Advent17.scala b/scala2/src/main/scala/jurisk/adventofcode/y2018/Advent17.scala index 8d96a753..1421234f 100644 --- a/scala2/src/main/scala/jurisk/adventofcode/y2018/Advent17.scala +++ b/scala2/src/main/scala/jurisk/adventofcode/y2018/Advent17.scala @@ -154,7 +154,7 @@ object Advent17 { private val SpringOfWater: Coords2D = Coords2D.of(500, 0) def parse(data: String): Field2D[Square] = { - val points = data.parseList("\n", parsePoints).flatten + val points = data.parseLines(parsePoints).flatten val boundingBox = Coords2D .boundingBoxInclusive(SpringOfWater :: points) diff --git a/scala2/src/main/scala/jurisk/adventofcode/y2018/Advent25.scala b/scala2/src/main/scala/jurisk/adventofcode/y2018/Advent25.scala index 8c7999de..0cbb46b7 100644 --- a/scala2/src/main/scala/jurisk/adventofcode/y2018/Advent25.scala +++ b/scala2/src/main/scala/jurisk/adventofcode/y2018/Advent25.scala @@ -9,7 +9,7 @@ object Advent25 { type Parsed = List[Coords4D] def parse(data: String): Parsed = - data.parseList("\n", Coords4D.parse) + data.parseLines(Coords4D.parse) private def belongsTo( point: Coords4D, diff --git a/scala2/src/main/scala/jurisk/adventofcode/y2022/Advent10.scala b/scala2/src/main/scala/jurisk/adventofcode/y2022/Advent10.scala index 0613f5a5..cb417d06 100644 --- a/scala2/src/main/scala/jurisk/adventofcode/y2022/Advent10.scala +++ b/scala2/src/main/scala/jurisk/adventofcode/y2022/Advent10.scala @@ -23,7 +23,7 @@ object Advent10 { } def parse(data: String): Parsed = - data.parseList("\n", Op.parse) + data.parseLines(Op.parse) final case class State(x: Int, stack: List[Op]) { def next: State = diff --git a/scala2/src/main/scala/jurisk/adventofcode/y2022/Advent14.scala b/scala2/src/main/scala/jurisk/adventofcode/y2022/Advent14.scala index 33ac50d5..06af18c4 100644 --- a/scala2/src/main/scala/jurisk/adventofcode/y2022/Advent14.scala +++ b/scala2/src/main/scala/jurisk/adventofcode/y2022/Advent14.scala @@ -83,7 +83,7 @@ object Advent14 { } def parse(data: String): Parsed = - data.parseList("\n", Path.parse) + data.parseLines(Path.parse) private def printField(field: Field2D[Square]): Unit = { val display = field.map { diff --git a/scala2/src/main/scala/jurisk/adventofcode/y2022/Advent15.scala b/scala2/src/main/scala/jurisk/adventofcode/y2022/Advent15.scala index a3c4817e..3a7b316d 100644 --- a/scala2/src/main/scala/jurisk/adventofcode/y2022/Advent15.scala +++ b/scala2/src/main/scala/jurisk/adventofcode/y2022/Advent15.scala @@ -44,7 +44,7 @@ object Advent15 { } def parse(data: String): Parsed = - data.parseList("\n", Entry.parse) + data.parseLines(Entry.parse) private def impossibleToHaveBeacon(data: Parsed, c: Coords2D): Boolean = data.exists(_.impossibleToHaveBeacon(c)) diff --git a/scala2/src/main/scala/jurisk/adventofcode/y2022/Advent18.scala b/scala2/src/main/scala/jurisk/adventofcode/y2022/Advent18.scala index 59411bba..63078044 100644 --- a/scala2/src/main/scala/jurisk/adventofcode/y2022/Advent18.scala +++ b/scala2/src/main/scala/jurisk/adventofcode/y2022/Advent18.scala @@ -11,7 +11,7 @@ object Advent18 { cube.adjacent6.count(n => !cubes.contains(n)) def parse(data: String): Set[Coords3D] = - data.parseList("\n", Coords3D.parse).toSet + data.parseLines(Coords3D.parse).toSet def part1(points: Set[Coords3D]): Int = points.toList.map(sidesFree(_, points)).sum diff --git a/scala2/src/main/scala/jurisk/adventofcode/y2022/Advent19.scala b/scala2/src/main/scala/jurisk/adventofcode/y2022/Advent19.scala index 98ccff1f..20736dfe 100644 --- a/scala2/src/main/scala/jurisk/adventofcode/y2022/Advent19.scala +++ b/scala2/src/main/scala/jurisk/adventofcode/y2022/Advent19.scala @@ -189,7 +189,7 @@ object Advent19 extends IOApp { } def parse(data: String): Parsed = - data.parseList("\n", Blueprint.parse) + data.parseLines(Blueprint.parse) def part1(data: Parsed): IO[Int] = for { _ <- Console[IO].println(s"Blueprint count: ${data.length}") diff --git a/scala2/src/main/scala/jurisk/adventofcode/y2022/Advent20.scala b/scala2/src/main/scala/jurisk/adventofcode/y2022/Advent20.scala index 797b2212..b5bc8bfe 100644 --- a/scala2/src/main/scala/jurisk/adventofcode/y2022/Advent20.scala +++ b/scala2/src/main/scala/jurisk/adventofcode/y2022/Advent20.scala @@ -8,7 +8,7 @@ object Advent20 { type Index = Int def parse(data: String): Vector[Long] = - data.parseList("\n", _.toLong).toVector + data.parseLines(_.toLong).toVector private def moveNumber( vector: Vector[Index], diff --git a/scala2/src/main/scala/jurisk/adventofcode/y2022/Advent21.scala b/scala2/src/main/scala/jurisk/adventofcode/y2022/Advent21.scala index d7ce43e9..a6eb938d 100644 --- a/scala2/src/main/scala/jurisk/adventofcode/y2022/Advent21.scala +++ b/scala2/src/main/scala/jurisk/adventofcode/y2022/Advent21.scala @@ -33,7 +33,7 @@ object Advent21 { } def parse(data: String): Parsed = - data.parseList("\n", Monkey.parse) + data.parseLines(Monkey.parse) sealed trait Operation { def execute(a: Value, b: Value): Value diff --git a/scala2/src/main/scala/jurisk/adventofcode/y2022/Advent25.scala b/scala2/src/main/scala/jurisk/adventofcode/y2022/Advent25.scala index 9b889008..3a0e6114 100644 --- a/scala2/src/main/scala/jurisk/adventofcode/y2022/Advent25.scala +++ b/scala2/src/main/scala/jurisk/adventofcode/y2022/Advent25.scala @@ -56,7 +56,7 @@ object Advent25 { } def parse(input: String): Parsed = - input.parseList("\n", SnafuNumber.parse) + input.parseLines(SnafuNumber.parse) def solve(data: Parsed): SnafuNumber = SnafuNumber.fromDecimal(data.map(_.toDecimal).sum) diff --git a/scala2/src/main/scala/jurisk/adventofcode/y2023/Advent02.scala b/scala2/src/main/scala/jurisk/adventofcode/y2023/Advent02.scala index 7debc276..69743d3e 100644 --- a/scala2/src/main/scala/jurisk/adventofcode/y2023/Advent02.scala +++ b/scala2/src/main/scala/jurisk/adventofcode/y2023/Advent02.scala @@ -62,7 +62,7 @@ object Advent02 { } def parse(input: String): Parsed = - input.parseList("\n", Game.parse) + input.parseLines(Game.parse) def part1(data: Parsed): Int = { val bag = Cubes(12, 13, 14) diff --git a/scala2/src/main/scala/jurisk/adventofcode/y2023/Advent04.scala b/scala2/src/main/scala/jurisk/adventofcode/y2023/Advent04.scala index 73479800..568e5049 100644 --- a/scala2/src/main/scala/jurisk/adventofcode/y2023/Advent04.scala +++ b/scala2/src/main/scala/jurisk/adventofcode/y2023/Advent04.scala @@ -30,7 +30,7 @@ object Advent04 { } def parse(input: String): Parsed = - input.parseList("\n", Card.parse) + input.parseLines(Card.parse) def part1(cards: Parsed): Int = { def part1Worth(card: Card): Int = diff --git a/scala2/src/main/scala/jurisk/adventofcode/y2023/Advent07.scala b/scala2/src/main/scala/jurisk/adventofcode/y2023/Advent07.scala new file mode 100644 index 00000000..75ab6714 --- /dev/null +++ b/scala2/src/main/scala/jurisk/adventofcode/y2023/Advent07.scala @@ -0,0 +1,175 @@ +package jurisk.adventofcode.y2023 + +import jurisk.utils.FileInput._ +import jurisk.utils.Parsing.StringOps + +import cats.implicits._ +import Ordering.Implicits.seqOrdering + +object Advent07 { + type Input = List[HandWithBid] + + sealed trait PokerGame { + def handValue(hand: Hand): Value + } + + object PokerGame { + final case object Camel1 extends PokerGame { + override def handValue(hand: Hand): Value = + Value(Value.determineKind(hand.ranks), hand.ranks) + } + + final case object Camel2 extends PokerGame { + override def handValue(hand: Hand): Value = { + val ranks = hand.ranks.map { r => + if (r == Rank.parse('J')) Rank.Wildcard else r + } + + // We could do something faster instead, but this works + def expandWildcards( + ranks: List[Rank] + ): List[List[Rank]] = + ranks match { + case h :: t if h == Rank.Wildcard => + Rank.NonWildCardRanks flatMap { r => + expandWildcards(t) map { x => r :: x } + } + + case h :: t => expandWildcards(t) map { x => h :: x } + case Nil => Nil :: Nil + } + + val options = expandWildcards(ranks) + val bestValue = options + .map(Value.determineKind) + .max + + Value(bestValue, ranks) + } + } + } + + final case class Rank(value: Char, strength: Int) + + object Rank { + implicit val ordering: Ordering[Rank] = Ordering.by(_.strength) + + val Ordered: List[Rank] = "*23456789TJQKA".toList.zipWithIndex.map { + case (ch, idx) => + Rank(ch, idx) + } + + val Wildcard: Rank = Rank.parse('*') + val NonWildCardRanks: List[Rank] = + Rank.Ordered.filterNot(_ == Rank.Wildcard) + + def parse(x: Char): Rank = + Ordered + .find(_.value === x) + .getOrElse(sys.error(s"Failed to parse Rank $x")) + } + + final case class Hand(ranks: List[Rank]) + + object Hand { + def parse(x: String): Hand = + Hand((x map Rank.parse).toList) + } + + final case class Value(kind: ValueKind, ranks: List[Rank]) + + object Value { + def orderingForGame(pokerGame: PokerGame): Ordering[Hand] = + Ordering.by(pokerGame.handValue) + + def determineKind(ranks: List[Rank]): ValueKind = { + require(ranks.size === 5, s"Only 5 card evaluations are allowed: $ranks") + + val counts = ranks + .groupBy(identity) + .map { case (_, v) => + v.length + } + .toList + .sorted(Ordering[Int].reverse) + + val mapping = Map( + (5 :: Nil) -> ValueKind.FiveOfAKind, + (4 :: 1 :: Nil) -> ValueKind.FourOfAKind, + (3 :: 2 :: Nil) -> ValueKind.FullHouse, + (3 :: 1 :: 1 :: Nil) -> ValueKind.ThreeOfAKind, + (2 :: 2 :: 1 :: Nil) -> ValueKind.TwoPairs, + (2 :: 1 :: 1 :: 1 :: Nil) -> ValueKind.Pair, + (1 :: 1 :: 1 :: 1 :: 1 :: Nil) -> ValueKind.HighCard, + ) + + mapping.getOrElse( + counts, + sys.error(s"Unrecognized rank counts $counts for $ranks"), + ) + } + + implicit val ordering: Ordering[Value] = + Ordering.by[Value, ValueKind](_.kind) orElse Ordering.by(_.ranks) + } + + sealed abstract class ValueKind(val strength: Int) + + object ValueKind { + implicit val ordering: Ordering[ValueKind] = Ordering.by(_.strength) + + final case object HighCard extends ValueKind(0) + final case object Pair extends ValueKind(1) + final case object TwoPairs extends ValueKind(2) + final case object ThreeOfAKind extends ValueKind(3) + final case object FullHouse extends ValueKind(4) + final case object FourOfAKind extends ValueKind(5) + final case object FiveOfAKind extends ValueKind(6) + } + + final case class HandWithBid( + hand: Hand, + bid: Int, + ) + + object HandWithBid { + def parse(s: String): HandWithBid = + s match { + case s"$hand $bid" => + HandWithBid( + Hand.parse(hand), + bid.toInt, + ) + case _ => s.failedToParse + } + } + + def parse(input: String): Input = + input.parseLines(HandWithBid.parse) + + def solve(data: Input, game: PokerGame): Int = { + implicit val ordering: Ordering[Hand] = + Value.orderingForGame(game) + + data + .sortBy(_.hand) + .zipWithIndex + .map { case (x, idx) => + x.bid * (idx + 1) + } + .sum + } + + def part1(data: Input): Int = solve(data, PokerGame.Camel1) + def part2(data: Input): Int = solve(data, PokerGame.Camel2) + + def parseFile(fileName: String): Input = + parse(readFileText(fileName)) + + def main(args: Array[String]): Unit = { + val realData: Input = parseFile("2023/07.txt") + + println(s"Part 1: ${part1(realData)}") + println(s"Part 2: ${part2(realData)}") + } +} diff --git a/scala2/src/main/scala/jurisk/utils/Parsing.scala b/scala2/src/main/scala/jurisk/utils/Parsing.scala index 40a7b0c9..cb24bd30 100644 --- a/scala2/src/main/scala/jurisk/utils/Parsing.scala +++ b/scala2/src/main/scala/jurisk/utils/Parsing.scala @@ -75,6 +75,10 @@ object Parsing { ): List[T] = s.split(separator).toList.map(parser) + def parseLines[T]( + parser: String => T + ): List[T] = parseList("\n", parser) + def extractInts: List[Int] = { val RegEx = """([-+]?\d+)""".r RegEx.findAllIn(s).map(_.toInt).toList diff --git a/scala2/src/test/scala/jurisk/adventofcode/y2023/Advent07Spec.scala b/scala2/src/test/scala/jurisk/adventofcode/y2023/Advent07Spec.scala new file mode 100644 index 00000000..3a67d40e --- /dev/null +++ b/scala2/src/test/scala/jurisk/adventofcode/y2023/Advent07Spec.scala @@ -0,0 +1,40 @@ +package jurisk.adventofcode.y2023 + +import Advent07._ +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers._ + +class Advent07Spec extends AnyFlatSpec { + private def parseValue(game: PokerGame, ranks: String): Value = + game.handValue(Hand.parse(ranks)) + + "Camel 1" should "compare 33332 and 2AAAA" in { + val a = parseValue(PokerGame.Camel1, "33332") + val b = parseValue(PokerGame.Camel1, "2AAAA") + + a should be > b + } + + it should "compare 77888 and 77788" in { + val a = parseValue(PokerGame.Camel1, "77888") + val b = parseValue(PokerGame.Camel1, "77788") + + a should be > b + } + + "Advent07" should "test part 1" in { + part1(parseFile("2023/07-test.txt")) shouldEqual 6440 + } + + it should "real part 1" in { + part1(parseFile("2023/07.txt")) shouldEqual 248559379 + } + + it should "test part 2" in { + part2(parseFile("2023/07-test.txt")) shouldEqual 5905 + } + + it should "real part 2" ignore { + part2(parseFile("2023/07.txt")) shouldEqual 249631254 + } +}