From 97aa78cd76f2c9e666abbd6a569bc2845796e12a Mon Sep 17 00:00:00 2001 From: Zev Averbach Date: Tue, 6 Dec 2022 07:14:27 +0100 Subject: [PATCH] readme --- .gitignore | 5 + Makefile | 2 + README.md | 5 + day01/__init__.py | 0 day01/input.txt | 2250 ++++++++++++++++++++++++++++++++++++++++ day01/part1.py | 62 ++ day01/part2.py | 61 ++ day02/Makefile | 4 + day02/__init__.py | 0 day02/input.txt | 2500 +++++++++++++++++++++++++++++++++++++++++++++ day02/part1.py | 79 ++ day02/part2.py | 82 ++ day03/Makefile | 6 + day03/__init__.py | 0 day03/input.txt | 300 ++++++ day03/part1.py | 60 ++ day03/part2.py | 63 ++ day04/Makefile | 10 + day04/README.md | 9 + day04/TODO.md | 31 + day04/__init__.py | 0 day04/input.txt | 1000 ++++++++++++++++++ day04/part1.py | 78 ++ day04/part2.py | 58 ++ day05/Makefile | 10 + day05/README.md | 9 + day05/TODO.md | 31 + day05/__init__.py | 0 day05/input.txt | 511 +++++++++ day05/part1.py | 92 ++ day05/part2.py | 100 ++ day06/Makefile | 10 + day06/input.txt | 1 + day06/part1.py | 165 +++ day06/part2.py | 47 + make_new_day.py | 28 + 36 files changed, 7669 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 README.md create mode 100644 day01/__init__.py create mode 100644 day01/input.txt create mode 100644 day01/part1.py create mode 100644 day01/part2.py create mode 100644 day02/Makefile create mode 100644 day02/__init__.py create mode 100644 day02/input.txt create mode 100644 day02/part1.py create mode 100644 day02/part2.py create mode 100644 day03/Makefile create mode 100644 day03/__init__.py create mode 100644 day03/input.txt create mode 100644 day03/part1.py create mode 100644 day03/part2.py create mode 100644 day04/Makefile create mode 100644 day04/README.md create mode 100644 day04/TODO.md create mode 100644 day04/__init__.py create mode 100644 day04/input.txt create mode 100644 day04/part1.py create mode 100644 day04/part2.py create mode 100644 day05/Makefile create mode 100644 day05/README.md create mode 100644 day05/TODO.md create mode 100644 day05/__init__.py create mode 100644 day05/input.txt create mode 100644 day05/part1.py create mode 100644 day05/part2.py create mode 100644 day06/Makefile create mode 100644 day06/input.txt create mode 100644 day06/part1.py create mode 100644 day06/part2.py create mode 100644 make_new_day.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12621bb --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +*.egg-info +*.pyc +/env +/__pycache__ +.env diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..c613691 --- /dev/null +++ b/Makefile @@ -0,0 +1,2 @@ +n: + python3 make_new_day.py && cd "$(\ls -1dt ./*/ | head -n 1)" diff --git a/README.md b/README.md new file mode 100644 index 0000000..6ac6db0 --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +This was a fork of Anthony Sottile's excellent [2015 AoC repo](https://github.com/anthonywritescode/aoc2015), which I've repurposed for my own workflow. + +Note that between day06 and day07 I ripped out `support.py`, so only on day07 will it work with the included items. + +These are my submissions to Advent of Code 2022, done in Python. This is the first year I'm trying to do it every day. diff --git a/day01/__init__.py b/day01/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/day01/input.txt b/day01/input.txt new file mode 100644 index 0000000..e8ac86c --- /dev/null +++ b/day01/input.txt @@ -0,0 +1,2250 @@ +5800 +2273 +1315 +5801 +6352 +2649 +4140 +2115 +5298 +4441 +4428 +3773 +1076 + +8063 +10386 +5705 +8397 +1084 +7661 + +3661 +5756 +3231 +5162 +4930 +4675 +1113 +6795 +6415 +1144 +2900 +5147 +2966 + +35187 + +12434 +2038 +12435 +8757 +6976 +4532 + +4642 +4431 +5126 +4672 +1724 +3012 + +3801 +6564 +5401 +3913 +3090 +1484 +6227 +1283 +2501 +4601 +5860 +7036 + +19257 +31867 + +4292 +4518 +1298 +13147 +7463 + +6784 +1065 +4015 +3154 +6429 +5067 +6535 +5731 +1270 +5870 +4934 +2800 + +5227 +6294 +6733 +5177 +2773 +6553 +3219 +1446 +7005 +6036 +6872 + +1721 +4408 +5577 +2799 +2257 +3149 +2389 +3713 +5588 +2324 +4595 +6018 +4926 + +1233 +4799 +3380 +1975 +1924 +1578 +2338 +1546 +3708 +4020 +5872 +2519 +5334 +4416 + +18103 +1692 +10497 +6786 + +4837 +12315 +6510 +9221 +10023 +5698 + +9781 +18818 +19784 +5100 + +7596 +14668 +18708 + +1932 +18024 +6361 + +7302 +5163 +9039 +4774 +8726 +6538 +2054 +7238 +4233 + +3375 +6049 +4925 +7129 +6075 +1262 +3836 +5878 +3292 +1316 +3924 +3530 + +8653 +21172 +18837 + +8052 +1672 +2962 +3270 +8160 +3033 +2004 +7774 +8182 +3047 + +7917 +2458 +1040 +7210 +7742 +4296 +2861 +9324 +5721 + +17851 +11236 +7107 + +6962 +4498 +10042 +4539 +10759 +8378 +5781 + +7156 +10063 +5329 +2449 +4749 +6498 +6493 +1924 + +2161 +1309 +1770 +3195 +1581 +1194 +1455 +1350 +5298 +5290 +1872 +2155 +3060 +1514 +1872 + +9664 +14392 +10201 +12693 +8817 + +4960 +2281 +6321 +4953 +1439 +1372 +5253 +2338 +2516 +6332 +2760 +6702 +2354 + +1341 +1489 +7110 +2267 +6809 +4198 +1137 +2526 +2087 +3885 +4952 +3056 + +6561 +1313 +6624 + +11571 +3452 +15300 +1518 +14811 + +3421 +5270 +1676 +6712 +6231 +6617 +6775 +5428 +3497 +5598 +3723 + +7879 +7984 +2678 +5770 +4217 +5323 +3708 +2799 +5466 + +2895 +3934 +4468 +6864 +4531 +5622 +3281 +6518 +4313 +5273 +3945 +5378 +2585 + +3486 +6101 +1036 +1079 +3380 +4542 +3617 +4279 +2397 +2172 +3711 +6251 +1219 +6320 + +6785 +4840 +4314 +3647 +4660 +5968 +1932 +3144 +2131 +6556 +5107 +2018 +4441 + +2958 +2812 +1812 +4047 +4055 +11311 +7254 + +2563 +1559 +6369 +4595 +3617 +1979 +1988 +1648 +2520 +5216 +6227 +6239 +6469 +3824 + +4417 +5913 +2444 +6808 +4742 +2422 +5153 +6707 +6968 +6663 +2355 + +9949 +19801 +14001 +15160 + +1166 +12942 +15632 +3266 +16053 + +7820 +7480 +1377 +4492 +5371 +1411 +2455 +8883 + +17669 +8092 + +8706 +7270 +2362 +3278 +7920 +6014 +2647 +1328 +6135 +4121 + +1300 +5806 +9993 +5891 +1588 +11239 +10363 + +6375 +2494 +2291 +5069 +2878 +4995 +3716 +7152 +2761 + +6224 +1559 +2918 +8131 +7509 +5718 +3661 +3544 +1823 +7656 + +16526 +11469 +1419 + +53687 + +2857 +2808 +4648 +8455 +9957 +3914 + +7762 +5994 +6047 +8806 +5176 +7275 +4551 +4066 + +5763 +3134 +1326 +1673 +1473 +3568 +3500 +3148 +6480 +6968 +5409 + +3964 +30423 + +4429 +15272 +5536 +17259 + +12059 +2888 +23495 + +6809 +1963 +3840 +3427 +4613 +3621 +6088 +1689 +7164 +1066 +2414 +1709 + +3278 +10853 +4541 +8619 +8481 +5872 + +12075 +14580 + +7950 +6716 +2477 +3646 +5451 +4247 +5960 +1059 +1421 +5363 +2927 + +6077 +3404 +5644 +3187 +8654 +2732 +6190 +2191 +3446 + +13528 +10960 +12280 + +35272 +23802 + +2178 +2098 +2920 +4938 +6504 +1060 +4419 +4813 +5278 +2795 +3169 +3632 +2780 +5275 + +4649 +1930 +1983 +3098 +4015 +2875 +2805 +5216 +3560 +5647 +2568 +5779 +6049 + +27045 +16939 + +10445 +10797 +10108 +2466 +2246 +5724 +7331 + +4442 +7590 +1569 +7171 +2642 +2514 +3817 +9721 + +8791 +7994 +2284 +2030 +8332 +6368 +4957 +7785 +1048 +4729 + +9724 +7501 +5505 +9879 +9365 +9333 +4116 +8176 + +9566 +3327 +7777 +11637 +2558 + +33212 + +3528 +6544 +1465 +6135 +6022 +2179 +5929 +3589 +5116 + +1295 +20019 +23243 + +10512 +14094 +8100 +10837 +1990 + +8004 +5887 +5776 +3619 +5955 +1823 +3549 +1608 +5574 +2536 + +21105 + +1121 +3374 +6887 +7477 +1559 +8129 +2568 +2267 +4276 +5654 + +13156 +11437 +2579 +13990 +4857 + +4870 +5826 +5900 +2870 +4855 +5032 +4549 +3334 +4392 +6687 +1419 +2931 +5741 + +3388 +1796 +3472 +1643 +1332 +2683 +4063 +3896 +5532 +4179 +3293 +2287 + +3917 +4479 +4607 +3161 +1568 +5766 +1114 +5629 +4985 +4126 +6032 +5801 +4563 +4102 +5414 + +1680 +7168 +4035 +7272 +1069 +5464 +3362 +8014 +6102 +3438 + +12897 +4134 +5080 +5112 +1382 +8072 + +6459 +1052 +7860 +6344 +11275 +7862 + +7127 +5350 +4677 +6080 +7389 +6254 +1762 +3744 + +2309 +9952 +1649 +3813 +10728 +9047 +10324 +7166 + +10873 +3572 +12788 +4164 + +4454 +4712 +3474 +2168 +5914 +2979 +4481 +3906 +1923 +3666 +1563 +4974 +2768 +3148 +4075 + +8824 +14894 +10182 + +27925 +27484 + +10626 +19944 +5603 +2536 + +6931 +14574 +6857 +2887 +4086 + +18693 +15550 +9475 +16434 + +6759 +6343 +4255 +3838 +6209 +3314 +2508 +3168 +4738 +4613 +1326 +5034 +1437 + +1822 +10438 +9137 +7846 +8451 +9397 +7729 + +2326 +3628 +5120 +2662 +3814 +3761 +1462 +1878 +6003 +2927 +1345 +2849 +6064 +5540 +2435 + +3680 +3813 +4824 +5499 +9998 +2233 +9012 + +30259 +24718 + +10326 +6960 +7198 +14566 +13123 + +6018 +6875 +5608 +1167 +6331 +5020 +3796 +4878 +6180 +2043 +2419 + +6676 +7795 +6677 + +3188 +4992 +3958 +1837 +3146 +4012 +2109 +4262 +6831 +2423 +1716 +5367 + +5837 +1616 +6477 +5255 +1808 +5473 +5978 +5139 +4689 +5701 +3022 +2911 +5043 + +9217 +16226 + +1105 +6108 +3893 +5617 +1700 +4762 +2230 +4590 +6602 +5875 +4648 +2742 +1623 + +7941 +5740 +6709 +4488 +7148 +6554 +4125 +5040 +8310 +5795 + +4126 +2456 +6279 +2323 +4295 +2384 +5372 +4833 +3379 +4984 +3094 +3085 + +4134 +7845 +5029 +9865 +8431 +7084 +4411 +7765 + +9573 +10031 +11504 +18955 + +65758 + +10933 +23224 +9234 + +9163 +8764 +4788 +8189 +11424 +1888 + +7361 +7393 +11150 +11767 +10104 +11200 +5473 + +1033 +5952 +4635 +3781 +5088 +3479 +4403 +6264 +2437 +1437 +6677 + +15877 +15511 +7676 +11138 +14878 + +3345 +2250 +4913 +5217 +1510 +4379 +4549 +1731 +4827 +2068 +2835 +5467 +1749 + +4448 +3042 +5305 +1516 +4014 +1408 +6255 +1208 +6206 +3580 +6247 +1620 + +2712 +10639 +6856 +8948 +1911 +1404 + +9349 +18213 + +2373 +6003 +5216 +2901 +8754 +2517 +4093 +2475 +5071 +3175 + +5235 +1935 +7751 +12132 +1739 +8963 +1855 + +3890 +4106 +3949 +4795 +2816 +1100 +1278 +2287 +2066 +5351 +4113 +4714 +4410 +2178 + +3575 +5434 +8010 +4677 +4524 +7438 +7363 +2150 +8133 +2840 + +3184 +4657 +5941 +4474 +4399 +5675 +5088 +2875 +5175 +1441 +2924 +5509 +6037 +1228 +3596 + +10076 +14846 +19534 +16135 + +3832 +5882 +5111 +2141 +1925 +4174 +2729 +5974 +1425 +4740 +2013 +5110 +5262 +3245 +2533 + +5321 +5818 +2415 +6348 +5720 +1424 +2960 +6265 +1630 +5768 +5328 +2655 +6323 +6363 + +6956 +5122 +15372 +14713 +7784 + +32625 +11125 + +5349 +3235 +5669 +6210 +5007 +5300 +2283 +2824 +5185 +6222 +5394 +4139 +1300 +1677 + +6416 +8235 +5091 +7099 +8016 +5993 +5297 +4554 +1919 + +7685 +8321 +8192 +8798 +3673 +5084 +8042 +7700 +9121 + +16486 +10677 + +9499 +5512 +13379 +13851 +12439 + +4919 +9292 +5319 +5220 +8546 +2005 +6429 +5510 + +1977 +1671 +2792 +6173 +3483 +1069 +1892 +4190 +6263 +6184 +3514 +5813 + +3784 +6795 +1693 +2493 +5963 +3511 +6278 +2558 +4924 +1523 +5279 + +2053 +1812 +1696 +1917 +6417 +6031 +7956 +7385 +2764 + +4899 +2174 +15256 +8489 +4745 + +4366 +2569 +8990 +4173 +8144 +6488 +1033 + +7989 +8202 +3781 +1358 +6093 +8358 +4047 +4562 +4289 + +5660 +8763 +7099 +12118 +4652 +6537 + +5511 +1780 +4502 +4999 +1990 +2554 +3552 +3589 +1418 +1354 +4151 +5500 +1057 +5282 + +5675 +1099 +4235 +3506 +3293 +4472 +3878 +5262 +3734 +5692 +4205 +3469 +2879 + +2747 +2909 +2608 +2324 +1421 +2801 +1022 +4630 +2335 +5494 +2780 +3638 + +4808 +5061 +4974 +2064 +4797 +5901 +4819 +6736 +5356 +4876 +6530 +6011 +4317 + +3044 +2230 +2371 +4651 +3437 +4759 +4145 +1845 +1327 +4512 +6172 +3741 +2817 +4810 + +3319 +5963 +5235 +2536 +6866 +4904 +3523 +4587 +4877 +6773 +2652 +2462 +3030 + +3231 +7432 +6805 +5632 +1398 +5278 +6545 +2076 +4940 +2754 + +2990 +7260 +4550 +2885 +8785 +5737 +3501 +2019 +8647 + +4493 +8668 +5035 +9120 +9324 +2968 +2428 + +6289 +3485 +2200 +3382 +5783 +6146 +3018 +4079 +4596 +1116 +3919 +2760 +2861 + +7625 +12909 +13695 +7903 +4340 + +4798 +4783 +6796 +6200 +5999 +6061 +3060 +3896 +7634 +7644 +1794 + +8485 +10545 +13132 +5653 +13306 +8014 + +5758 +3284 +6741 +2987 +3970 +4669 +4410 +5673 +5765 +6895 +1887 +4852 +4019 + +4657 +8052 +6669 +3467 +8919 +2273 +1255 + +6289 +6824 +6157 +5043 +4502 +5268 +3889 +2896 +1904 +5278 +1395 +4423 +3589 + +4372 + +49650 + +3641 +1463 +2529 +2741 +2626 +1104 +6111 +4427 +6694 +6265 +2993 +3122 +1431 + +1098 +4751 +3778 +1188 +2895 +1855 +5950 +1761 +2264 +2581 +5002 +2820 +2688 +4309 +5021 + +5561 +4720 +8271 +2578 +5086 +5081 +9935 + +5993 +5237 +4986 +2470 +4081 +2107 +5118 +1436 +2722 +3317 +5135 +1687 +6081 +2281 + +2848 +10385 +11585 +8479 +7000 + +9106 +3499 +14806 +14856 +14270 + +10741 +4152 +1465 +2692 +6622 +7357 +4795 +9761 + +8661 +15426 +4510 +16351 +9036 + +2728 +5277 +6437 +3607 +4858 +5174 +5124 +6278 +4115 +3943 +2548 +4946 +5169 +4707 + +61072 + +9226 +2700 +4012 +8201 +9552 +3895 +8835 +2748 +9567 + +10717 +1581 +10024 +6404 + +5376 +1151 +3132 +5017 +5373 +4282 +3484 +5596 +4456 +6121 +2714 +6212 + +27894 +35903 + +4917 +8413 +2371 +5101 +6183 +2951 +2248 +8656 +9266 + +2625 +6275 +7478 +4337 +1541 +1213 +3955 +4757 +8046 +7255 +1971 + +2777 +2409 +2353 +5879 +5503 +4098 +2158 +3969 +1368 +4135 +1226 +1285 +4840 +2038 +1757 + +8863 +9589 +3253 +5275 +7203 +7360 +9066 +8794 + +1470 +7260 +2185 +3035 +5968 +7504 +8342 +5621 + +10611 +7460 +3736 +4146 +10173 +12291 + +3680 +12376 +13226 +1889 + +3439 +7329 +3377 +6639 +6283 +2887 +2653 +3499 +3625 +6361 +3250 +6882 + +7470 +4047 +1714 +6357 +5267 +7577 +3495 +6565 +2349 +3850 +1759 + +8099 +8009 +19118 +14120 + +2826 +7174 +2774 +2989 +7176 +7625 +3899 +4002 +4849 + +7983 +10730 +2709 +4285 +12607 +7955 + +13822 + +1234 +4277 +2621 +2723 +6879 +4385 +2232 +5996 +5136 +3369 +7149 +2219 + +66306 + +5829 +6255 +4929 +8250 +3516 + +4857 +6895 +4273 +7081 +2989 +5846 +2961 +7846 +2255 +4802 +1670 + +8191 +1267 +6985 +4747 + +6734 +4762 +1304 +7783 + +7646 +1419 +3729 +7973 +3350 +5737 +3883 +1428 +5432 +4835 + +13785 +12814 +5626 +11147 +5700 +9402 + +3500 +9350 +11011 +8174 +9828 +6832 +1068 + +40289 + +5599 +4191 +3625 +8604 +1087 +6751 +6020 +7519 +7000 +1554 + +31342 + +6840 +2096 +2482 +8269 +3005 +6414 +3823 +6976 +9302 + +7401 +2825 +6693 +3785 +3653 +1608 +5157 + +3109 +1332 +3032 +6908 +2446 +6437 +1527 +2876 +3124 +5905 +3888 +1027 +2056 + +13859 +19777 + +2156 +5880 +5299 +8558 +1170 +8369 +2384 +4922 +3540 +4069 + +2520 +8578 +6988 +4589 +2808 +8622 +7274 +1485 +3425 +2048 + +1975 +7298 +4361 +2127 +5352 +6143 +5553 +6939 +1970 +4892 +1193 +2763 + +2681 +5649 +3986 +3879 +1710 +1749 +5178 +5919 +6788 +2577 +7406 + +6714 +1132 +4707 +8859 +9325 +7255 +7746 +7393 + +4925 +2772 +6414 +2083 +5913 +6499 +1838 +5955 +2627 +3507 +3485 +1041 +2445 +2860 + +5739 +1228 +3578 +7053 +1333 +7932 +2778 +1264 +3221 +4462 + +1702 +1263 +24430 + +6711 +14533 +14161 +3384 +1798 + +6650 +8334 +2502 +6261 +3300 +8793 +3729 +2148 +7511 +4702 + +5263 +2653 +2646 +10475 +5210 + +6124 +9121 +12762 +5131 +15866 + +20098 +17049 +6082 +12356 + +4615 +11397 +6506 +16351 + +2167 +3926 +4256 +5477 +5085 +1270 +4992 +2015 +3316 +3057 +6018 +2026 +4406 +2973 +4209 + +21818 +5205 + +9308 +4553 +4209 +2899 +5831 +11175 + +2175 +5686 +3649 +4884 +2654 +6049 +3099 +5191 +5017 +5553 +3016 +2743 +2211 +5615 +2750 + +5895 +5859 +2391 +1786 +1219 +4664 +4385 +3571 +6747 + +21656 +6158 + +2384 +4885 +4143 +2965 +5009 +1963 +2434 +3975 +4187 +6320 +2693 +2514 +5190 +1337 + +3558 +13277 +5659 +12432 +6800 +1444 + +5684 +3966 +3790 +5530 +1018 +5860 +1260 +2663 +3382 +1699 +3573 +5785 +4221 +3293 +2612 + +6842 +7855 +10358 +7499 +4828 +9999 +6736 +10306 + +4733 +7411 +2214 +3289 +8075 +4328 +5529 +1376 +6701 +3311 +1550 + +10753 +2816 +5490 +9546 +9574 +8698 +9240 + +35760 + +11913 +9817 +5260 +11404 +14859 + +8190 +3694 +7646 +9332 +3588 +8608 +3521 +5167 +2193 + +4743 +4120 +1931 +3477 +3687 +2453 +2666 +7001 +1895 +4923 +3035 +2630 + +4468 +2828 +13485 +3277 +3154 +11675 + +7051 +2700 +9410 +6504 +6826 +10176 + +9119 +1701 +10677 +7991 +2200 +8689 +2906 +4077 + +37282 +7225 + +1662 +5592 +4997 +5548 +3677 +4294 +2937 +1170 +5407 +2368 +3726 +6589 +6229 + +12729 +13674 +10641 +6837 +6046 +1022 + +5812 +5667 +1796 +6701 +3055 +3362 +6757 +3056 +1043 +4129 +4237 +3907 +4784 + +8330 +5270 +4031 +9506 +9062 +2762 +5838 +7955 + +5869 +1162 +3744 +3349 +5621 +7359 +4782 +1259 +3904 +3692 +3836 +5684 + +1077 +1738 +1787 +4504 +5669 +5257 +2325 +2813 +4297 +1652 +4500 +5801 +4297 +2362 +1616 + +6720 +2446 +4444 +4132 +4665 +2280 +4203 +6500 +6941 +6667 +1867 + +3560 +3111 +5179 +1352 +6779 +11684 +2498 + +6316 +1792 +4065 +3358 +4597 +5573 +3097 +1235 +4623 +2981 +6725 +1251 + +2218 +4275 +5627 +2334 +2954 +4955 +2480 +2248 +1305 +3325 +2974 +2971 +1400 +5745 +5606 + +5511 +5981 +1117 +4137 +5442 +3205 +1798 +3667 +4508 +2507 +3980 +5785 +2912 +5664 +2775 diff --git a/day01/part1.py b/day01/part1.py new file mode 100644 index 0000000..96c7dfb --- /dev/null +++ b/day01/part1.py @@ -0,0 +1,62 @@ +from __future__ import annotations + +import argparse +import os.path + +import pytest + +import support + +INPUT_TXT = os.path.join(os.path.dirname(__file__), 'input.txt') + + +def compute(s: str) -> int: + n = 0 + largest = 0 + curr = 0 + for c in s.split('\n'): + if c.strip() == "": + if curr > largest: + largest = curr + curr = 0 + else: + curr += int(c) + return largest + + +INPUT_S = '''\ +1000 + +2000 + +5000 + +1000 +4001 +''' +EXPECTED = 5001 + + +@pytest.mark.parametrize( + ('input_s', 'expected'), + ( + (INPUT_S, EXPECTED), + ), +) +def test(input_s: str, expected: int) -> None: + assert compute(input_s) == expected + + +def main() -> int: + parser = argparse.ArgumentParser() + parser.add_argument('data_file', nargs='?', default=INPUT_TXT) + args = parser.parse_args() + + with open(args.data_file) as f, support.timing(): + print(compute(f.read())) + + return 0 + + +if __name__ == '__main__': + raise SystemExit(main()) diff --git a/day01/part2.py b/day01/part2.py new file mode 100644 index 0000000..a47952f --- /dev/null +++ b/day01/part2.py @@ -0,0 +1,61 @@ +from __future__ import annotations + +import argparse +import os.path + +import pytest + +import support + +INPUT_TXT = os.path.join(os.path.dirname(__file__), 'input.txt') + + +def compute(s: str) -> int: + elves_totals = [] + curr = 0 + for c in s.split('\n'): + if c.strip() == "": + elves_totals.append(curr) + curr = 0 + else: + curr += int(c) + sor = sorted(elves_totals) + return sor[-3] + sor[-2] + sor[-1] + + +INPUT_S = '''\ +1000 + +2000 + +5000 + +1000 +4001 +''' +EXPECTED = 5001 + + +@pytest.mark.parametrize( + ('input_s', 'expected'), + ( + (INPUT_S, EXPECTED), + ), +) +def test(input_s: str, expected: int) -> None: + assert compute(input_s) == expected + + +def main() -> int: + parser = argparse.ArgumentParser() + parser.add_argument('data_file', nargs='?', default=INPUT_TXT) + args = parser.parse_args() + + with open(args.data_file) as f, support.timing(): + print(compute(f.read())) + + return 0 + + +if __name__ == '__main__': + raise SystemExit(main()) diff --git a/day02/Makefile b/day02/Makefile new file mode 100644 index 0000000..61e0407 --- /dev/null +++ b/day02/Makefile @@ -0,0 +1,4 @@ +s1: + /Users/zev/Documents/repos/advent/2015/env/bin/python3.10 part1.py input.txt | aoc-submit --part 1 +s2: + /Users/zev/Documents/repos/advent/2015/env/bin/python3.10 part2.py input.txt | aoc-submit --part 2 diff --git a/day02/__init__.py b/day02/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/day02/input.txt b/day02/input.txt new file mode 100644 index 0000000..d9dd32c --- /dev/null +++ b/day02/input.txt @@ -0,0 +1,2500 @@ +A X +A Z +A Z +A X +A X +B X +C Y +B X +A Z +A X +A X +A X +A X +B X +A X +B X +A Z +A Z +A X +A X +A Z +A Z +A Z +A X +A Z +A X +C Y +C Z +A X +B X +A X +A X +A X +A Z +B X +A X +B X +C Y +A X +A Z +A Y +A X +A Z +A X +A Z +B X +A X +A Z +B X +A X +A Z +A X +A Z +A Z +A X +B X +B X +B X +B Z +A Z +B Z +A X +A X +A Z +A X +B Z +B Y +A Z +B X +A Y +B X +C X +B Z +B X +C Y +A Z +A X +A X +C Y +B X +A X +A Y +A X +A X +A Y +A Z +C Z +A Z +B X +B X +A X +B X +A X +A X +B Y +B X +A Z +B X +B X +A X +B Z +C Z +A Z +C Z +B X +B X +A Z +A X +A X +B X +A Z +B X +A Z +A X +A X +A X +B X +B X +B X +B X +A X +A Y +A X +B X +A Z +A X +A X +A X +C Y +A X +B X +A X +A Z +A X +B X +A Y +B X +C Z +A Y +A X +B Y +A X +B X +A X +A X +A X +B X +A X +A X +A Z +A Z +A X +C Y +B X +B X +A Z +B X +B Y +C Y +A X +A X +B Y +A X +B Y +B X +B X +A X +A Z +B X +B X +A Y +A X +C Y +C Y +C Y +A X +B X +A X +A X +A X +B X +B X +C Y +A X +A Z +A Z +A X +B X +A Z +A Z +A X +B X +A X +A Z +A X +C Z +B X +A X +C Y +C Y +A Z +B X +B Z +C Y +B X +A Y +B Y +A Z +A X +A X +B X +B Y +A Z +A X +B X +A X +C X +C Y +A X +B X +A Z +A X +B X +A X +C Y +C Y +C Y +A X +A X +A Z +A X +C Y +A Z +B Y +A X +C Y +B Z +B X +B X +A Z +B X +A Y +C X +A X +B X +A Z +C Y +A X +A Z +C Z +A X +C Y +B X +C Y +C Z +A Y +A Z +C Y +A X +A X +A X +A Y +B X +B X +C Y +C Y +A X +A Z +C Y +B Z +B X +C Z +B X +B X +C Z +A X +A X +B X +B X +A X +A X +B X +B X +B X +C Y +A X +A X +A X +A X +B X +A X +A X +B X +B Z +A X +B X +A X +C Y +B Y +A X +B X +A Y +B Z +B X +A X +B Z +B X +A Y +A X +B X +A X +A Z +B X +A X +A X +C Z +A X +B X +A X +B Y +A Z +A X +B X +A X +A Z +B X +B X +B Y +B X +A X +C Y +A X +A X +B X +B Y +A X +A X +A X +C Z +C Z +B Y +B X +B Z +A X +A Y +A X +C Y +B X +A X +A X +A X +A Z +C Y +A X +A X +C Y +A X +A X +A X +A Z +A Y +A X +A Y +C Z +A Z +A X +B X +A Z +C Z +C Y +A Z +A Z +C Y +C Z +C Z +A X +B X +B X +B Z +C Y +A X +A X +A X +A Z +A X +B X +B X +C X +A X +A X +B X +A Y +A X +A X +B Y +C Z +A X +A X +A Y +B X +B X +B X +C Z +A Z +A Y +B Y +A X +B X +B X +B X +B Z +A Y +B Y +A Z +A Z +C Z +B X +A X +A Y +A Y +C Y +B Y +A X +A X +A X +A X +B Y +A X +A Y +A X +A Z +B X +B X +A Y +A X +A Y +A Y +A Z +B X +B X +A Z +B X +A X +A Z +A Z +B X +A Z +A X +A Y +A Z +A X +A Z +B Y +A X +C Y +B X +C X +C Y +B Z +C Y +C Y +A X +A X +A Y +B X +C Z +B X +C Y +A X +A Z +C Y +A X +A Z +A Z +B Y +A X +A X +B X +B Y +A X +A X +B X +A X +B X +A X +B X +A X +B Y +A Z +B X +B X +B X +B X +A Y +A X +A Y +A Y +C Z +B Z +A X +B Y +A X +C Z +B X +A X +A X +A X +A X +A X +C Z +C Z +C Z +A X +C Y +A X +C X +C Z +A X +B X +A Z +A Z +A Z +A X +A Z +A Z +B Z +A X +B X +A Z +C Y +A X +A Z +A Z +A Z +B Z +B X +A X +B X +B X +B X +B X +B Y +B X +A X +A X +A Z +A Z +A Z +B Y +A X +A X +A Y +B X +B X +A Z +A X +B X +A X +A X +A Z +C Y +A X +B X +A X +B X +A X +B X +A Z +B X +A X +A Z +A Z +B X +A Y +A X +A Z +C Y +A X +A X +A X +B Y +B X +A Y +A Z +C X +B X +C Y +A X +B X +C Z +C Z +A X +B X +B X +B Y +B X +B X +A X +A Z +B Z +B X +A X +B X +B X +B X +A Z +A X +A X +A Z +B Y +B Z +A X +A Z +A Z +A Z +A X +A X +A X +A X +A X +A X +B X +A Z +B Z +A X +A Z +C Y +A Z +A X +A Y +A Y +B X +B Y +A Z +A X +B X +B Y +A X +B X +A X +B X +B X +C Y +A Z +B X +A X +B X +A X +A Z +A X +A Z +A X +A X +A X +B X +A Y +A X +A X +B X +C Z +B X +A X +C Y +A X +B X +A Z +B Y +B Z +A X +A X +A X +C Y +A X +A X +A X +B X +C Z +A Z +A X +C Z +B X +A Z +A Y +C Y +C Y +A Z +B X +C Z +C Z +A X +A X +A X +A X +A X +B X +C Y +A Z +A X +B X +A Z +A X +A Y +A X +B Z +A X +B X +A X +A X +A X +A Y +B X +C Y +A X +A Z +C Y +A Z +A X +A Y +A X +A Z +A X +A Y +C Y +A Y +A Z +A X +A X +A X +A Z +A X +B X +A Y +A X +B X +A X +A X +B X +A X +B X +C Z +B X +A Z +A Z +C Y +B Y +B X +A Y +B X +B X +A Y +A X +C X +C Y +B X +A X +C X +C Z +A X +A Z +B X +B Z +C Y +A X +C Y +A Y +B X +B Y +A X +C Y +A Z +A X +A X +C Y +C Y +A X +A Z +B X +A Y +B X +A Z +A Z +A Z +A Z +A X +C Z +B X +B Y +A X +A Y +A X +B X +C Y +C Z +B Z +B X +B Z +A X +A Z +C Y +A X +B Y +A X +A Z +A X +C Z +A X +A Y +B Y +A X +A X +A X +A Z +B X +B X +B X +A X +C Y +C X +C Y +C Z +A X +A X +A Z +A Z +A X +A X +A X +A X +A X +A X +A X +C Z +A X +B X +A Z +B X +B X +B X +A Y +A X +A X +B X +A X +B X +A Z +C Y +B Y +C Z +B Y +B X +B X +A X +C Z +A X +B Y +C Y +B Y +A Z +A Y +A X +A X +C Y +B X +B X +A Z +A X +C Y +C Y +A Y +A Z +B X +C Z +A Z +C Y +A X +A X +A Z +B X +A X +A X +A Z +B X +C Z +A X +A X +B X +B Y +A Z +A X +B X +A X +C Y +B X +B X +B Z +C Y +A X +B X +A X +A X +A Y +A Y +A Z +B X +A Z +B Y +B X +A X +B Y +A X +A X +A Z +A X +B X +A Z +A X +A Z +B X +B X +B X +B Z +C Y +A Y +A Y +A Z +A X +B X +B X +A X +A X +B Y +A X +B X +A Z +B Z +B X +C Y +A Z +A X +C Z +A Y +A Y +B X +A Y +C Z +A Z +A X +B X +A Z +C Y +C X +B X +B Z +A X +A Y +A X +B X +A X +A X +C Y +B Z +B Z +B Y +C Z +C Y +B X +B Y +C Y +A Z +B X +A X +A X +A X +A X +A X +A X +B X +B X +B X +A X +C Y +A X +A Y +A Z +B Y +C Y +A Z +A X +A X +A Z +A Y +B X +A Y +A X +A X +C Z +A X +A X +B X +A X +A Z +A Z +A X +A X +A X +B X +A X +A X +A X +A Z +A X +B X +B Z +C Y +A X +A Z +B X +B X +B X +A X +B X +A X +B X +A Y +B Y +C Y +A X +C Z +B Z +A Z +A X +A X +A Z +A Y +A Z +A X +A X +B X +A X +A X +A Z +C Z +B X +B Y +A Z +B X +A Z +A X +A X +A X +C Y +C Y +A Z +A X +A X +B Y +A Y +A X +B Z +B X +B Z +B X +B Y +B X +A Y +A Z +C Y +B X +A X +A X +B X +B Z +A X +C X +A X +A X +A X +A X +A X +A X +B X +A X +C Z +A Y +B X +B X +B Z +A X +B X +B Z +B X +A Z +A X +B X +A X +A Y +B X +A Z +C Z +B X +C Z +A X +A X +C Y +A Z +C Y +A Z +A X +B X +A X +C Y +A Z +A X +A X +B X +B X +A Z +B Y +B X +A X +A Z +A X +B X +A X +A Z +A Z +A Y +A Y +A X +C Z +A Z +A Z +A X +B X +A Y +B Z +A X +A Z +A X +C Z +B X +A Z +C Z +A X +C X +A Z +A X +A X +B Z +A X +B X +A X +B X +C Z +A X +B X +A Z +B X +C Y +B X +A Z +A X +A Y +C Z +A Z +B X +A Z +A Y +A Z +B X +A X +B X +C Y +B X +A X +C Y +A X +A X +B Y +A X +B Y +A X +A X +A X +B X +A X +A X +C Z +A X +B X +A Y +A Y +B Z +A Z +A Y +A X +B X +B Y +A Z +B Y +A X +A Z +A X +A Z +B X +A X +A X +B X +A Y +B X +B X +A X +A Z +B X +A Y +B X +A Z +B X +B X +B X +B X +A Y +A Z +B X +B Y +B X +C Y +C Y +C Y +B X +B X +A Y +A X +B X +B X +A X +B X +A X +A Z +A Z +A Z +B X +A X +A X +A Y +A X +A X +C Y +B X +C Y +A X +A Y +C Z +A X +B X +A Z +A X +A X +A Z +A X +B Z +A X +A Z +A X +C Y +A Y +C X +A X +C Y +B X +B X +A Z +A X +A X +A X +B X +A X +C Y +C Y +A Y +A X +C Z +A X +B X +B Y +A Z +A X +B X +B X +A X +A Z +C Y +B X +A Y +A X +A Z +B X +A X +A Z +B X +A Y +B Z +A Z +C Z +C Y +A Z +A X +A X +A Z +B X +A X +B X +A X +A X +B X +A Z +A X +C Z +B X +A Z +B Y +A Z +A X +A Z +B X +A X +A X +A Y +B X +C Z +B X +A X +A X +A Z +B X +C X +B X +B X +A Z +B Y +B X +A Z +C Y +A X +A X +B X +B X +A X +B X +A Z +A X +A X +A Z +A X +A X +B X +B X +A X +A Z +A Y +A X +A X +C Y +B X +A X +B X +C Z +A Z +B X +A X +A X +A X +C Y +A X +A X +A X +A Z +B Y +B X +A X +A X +A Z +B X +C Z +B X +A Z +A Z +A X +A Y +B Y +B X +A Z +A Z +A X +A Y +B X +A X +A Z +B X +A Y +A Z +A Z +B X +C Z +A X +A X +B X +B X +A X +A Y +A Y +C Z +B X +A X +A Z +C Y +B X +A Z +A X +B X +B Y +A X +B X +A Y +B X +A X +A Z +B X +B X +C Y +B X +B X +B Y +A X +A X +B X +B X +A X +B X +C Y +A X +A X +A Z +A Z +B X +A Y +B X +B Y +A X +A Z +A X +A Z +A X +B Y +B X +B X +A X +B X +A X +B X +B X +A X +B X +C X +A Z +A Z +A X +A X +A Z +A X +B X +A X +A X +A Z +A Z +A X +A X +B X +C Y +A Z +A X +A X +A Y +A X +B Z +C Z +A Z +B X +A X +B X +A X +B X +B X +A Y +B Y +A X +B X +B Y +C Y +B Z +B Y +B Y +A Z +A X +A Y +A X +A Z +A Z +A X +A X +A X +A X +A Y +C Y +A X +A Y +A Z +A Z +B X +A X +A X +A Z +B Y +B X +B X +A X +B Z +B Z +A Y +B X +A Y +A X +B X +C Z +A X +A Y +B X +A X +B Z +C Y +A Z +A X +A Z +A X +A X +A X +A X +C Y +B X +A X +A X +C Y +C Y +A Z +C Y +A Z +A Y +C X +B X +C Y +A Z +A X +B X +B Z +B X +B X +B X +B X +B X +A X +A Z +B X +A Y +A X +A Y +B X +A X +A X +A X +B Z +B Z +B X +B X +A Y +A X +B Y +B X +B Y +C Y +A X +A X +C Y +A X +B X +B X +B X +C Z +B X +A Z +B X +B X +A X +B Z +A Z +A Z +A X +A Z +A Y +A Z +B X +A X +B X +A X +A X +A X +B X +A X +B X +A X +A X +B X +A Z +A X +A Z +C Y +A X +B X +A X +A X +B X +B X +C Z +A X +A X +B X +A X +A Y +A X +A X +A Z +A X +A X +B X +A X +A X +A X +A Y +C Z +A Z +A Z +A X +B X +A Z +A X +A X +A X +C Y +C Y +A Z +C Y +B X +A X +B X +B X +A Z +A Z +A Y +B X +A Z +A X +A Z +A X +A X +A X +A Z +A Z +B X +A X +A X +B X +B X +A Z +B X +A X +A X +B X +B X +B X +A X +A X +A Z +A X +A X +B Y +B Y +C Y +A Y +A Y +B X +B X +C Y +A X +B X +A X +A X +A Z +A Y +A X +B X +A X +B X +A X +A Z +A X +C Y +B X +B X +A X +B X +A X +A X +A Z +C Y +B X +B X +A X +A X +A Z +A Z +B Y +A X +B X +A Y +C Z +B X +A X +A Z +B Y +A Z +B X +B X +B X +A X +A Z +A Z +B Y +A Y +B X +B Y +A Y +A Z +A X +A X +B X +B X +A Y +B X +A X +A X +C Y +B X +A X +C X +C Z +A X +A X +C Y +C Z +A Z +A X +C Y +C Y +C Y +A X +A Y +A Z +A X +C Z +A X +C X +B X +B Y +B Z +A X +A X +A X +A Z +B X +B X +C X +A X +C Z +C Y +A X +A X +B X +B X +A X +A X +A X +A Z +A Z +B X +A Z +B Y +A Y +A Y +A Z +B X +A Y +A X +A X +B X +A Z +B X +A Y +A X +B X +A X +B X +A X +B X +B Z +A Z +A Y +A Z +A X +B X +B X +C Y +B X +A X +B X +A Y +B X +B X +C Y +B X +A Z +A Z +C Y +A X +B X +B X +A X +B X +A Z +A X +A X +A Z +A Z +C Z +A X +A X +A X +A X +A X +A X +A Z +C Y +A X +C Y +A X +B X +C Y +B X +A Y +B X +B X +B X +A X +A X +A X +C Y +A Z +A Z +B X +A X +A Z +B X +B X +A X +A X +B Z +A X +B Z +B X +A X +A X +A X +B X +A X +C Y +A Y +A X +A X +B X +A Y +A X +C Y +C Y +B X +B X +A X +A X +C Y +B Y +C Y +A X +B X +A Y +B Z +B X +B X +A Y +B X +A Z +C Y +B X +B X +B Y +A X +A X +A X +C Y +B X +A Y +B X +A Z +B Y +A X +A X +A X +A X +A X +A X +B X +C Z +B X +B X +A X +A X +C Y +A X +A X +A X +A X +B Z +B X +A Z +B Z +C Z +C Y +B X +B X +C Z +A Z +A Y +A Z +A Y +C Z +A X +A X +A Z +A X +A Z +A X +B Z +B X +B X +C Z +B X +C Y +C Y +B X +A X +A X +A X +B Y +A X +C Y +B Y +C Y +B Y +A Z +B X +A X +A Z +B X +B Z +A Z +A X +A X +A Y +A X +A X +A Z +B X +B X +B X +B X +B X +A X +A X +A X +A Z +A Z +A Y +A X +A Z +A Z +B X +A X +B X +B X +A Z +B Y +A X +A X +A X +A X +B X +A Y +A X +C X +A Z +A X +C Z +C Y +B X +A Z +A Z +B X +C Y +A X +A Z +A X +B Y +C Y +A X +A X +A Z +A X +C Y +A Z +A X +A X +A X +C Y +B X +A X +B Y +A Z +A X +A Z +B X +A Z +A Z +A X +A X +C Z +B X +A Z +A X +B Z +A Z +A Z +B X +A X +A Z +A Y +A X +A Z +A Z +C X +C Z +B X +B X +A Z +A X +B X +A X +A X +A X +A Z +B X +A Z +A X +B X +A X +A X +C Z +B X +C Y +A X +B X +A Z +A Z +A X +B Z +B X +A Z +A Z +A X +C Y +A X +B X +C Y +B X +B X +A Z +B X +A Z +C Y +B X +A Y +B X +A Z +B Z +A Z +B X +A X +B Z +A X +A Y +B Z +C Y +C Y +B X +A X +A X +A X +A X +B Z +A X +A X +A X +C Y +C X +B Y +B X +B X +B X +A Y +A X +A Z +A X +B X +A Z +C Y +A X +A Z +A Z +A X +A X +A X +A X +A Z +A X +A X +B X +C Z +B X +C Z +B Y +B X +A Z +A Z +A Z +B Y +A Y +A Z +B X +C Y +A X +B X +A Z +C Y +A Y +B X +A X +A Y +A X +A Z +B X +A Z +B Y +B X +A X +B X +A X +A X +A X +A Y +B X +A Y +A X +B X +A X +A X +C Y +A X +A X +B Z +A Z +A Z +A X +C Y +B X +B X +C Y +A Z +C Y +A X +A X +B X +B X +A X +A Z +B Y +B X +A Z +B X +A X +B X +A Z +C Y +A X +B X +A X +A X +A Z +A X +B X +C Z +A X +A X +A Y +B X +A Z +B X +B X +B Y +A X +A Z +A X +A Z +B X +B X +A X +A X +B Z +A X +C Y +B X +A X +A Z +A Z +B X +C Y +C Y +B Y +A Z +C Z +A X +B X +A X +A X +B Y +B X +A X +A X +A Y +A Z +B X +A X +A X +A Z +A X +A X +B X +B X +A Y +A X +B X +A Z +B Z +B X +A Z +A X +A Z +B X +C Y +A X +A X +B X +A Z +B X +A Z +C Z +A Z +A X +C Y +A X +B X +B Z +A X +B X +C X +A X +B Y +A X +A X +C Y +A X +B Y +A X +A X +A X +B X +A X +B X +A Z +C Y +A X +C Z +A X +B X +A Z +A X +C Z +C Z +A X +A Y +A Z +A X +B X +B X +A Z +B X +A X +B X +B Y +B X +B X +C Z +A Y +A X +A Z +B Z +A X +A Z +A Z +A Y +B X +A Y +A X +A X +B X +A Z +B Z +A X +A Z +A Z +A Z +C Y +A X +B Z +B X +A Z +B X +A Z +A Y +A X +C Z +C X +A Y +A X +A Z +A X +A X +A Z +A Y +A Z +A Y +A X +C Y +B X +A Z +A X +A X +C Y +A X +A X +B Z +A Z +C Y +A X +A X +A X +B X +C Y +A X +A Y +B X +A X +A X +B Y +A Z +A X +A X +B X +A Z +A Y +C Y +C Z +C Y +A X +C Y +C Y +A X +A Y +C Y +B X +A X +B X +A X +A X +B X +A X +A Z +C Y +C Y +B X +A X +B X +C Z +C Y +B X +A X +A X +A Y +A X +A Y +A Z +B X +A Z +A Z +A X +A X +B X +C Y +B X +A Z +A X +A X +A X +B X +B Z +B X +B X +B X +A Z +A X +B Z +A X +B Z +A X +B Y +C Z +B Y +C Z +B Y +B X +A X +A X +C Y +B X +B X +A X +B Z +A Z +A Z +A X +A X +A X +B X +B X +B X +C Y +A X +B X +B X +B Z +B X +A Z +C Y +A X +C Z +A Z diff --git a/day02/part1.py b/day02/part1.py new file mode 100644 index 0000000..b4e590b --- /dev/null +++ b/day02/part1.py @@ -0,0 +1,79 @@ +from __future__ import annotations + +import argparse +import os.path + +import pytest + +import support + +INPUT_TXT = os.path.join(os.path.dirname(__file__), 'input.txt') + + +def compute(s: str) -> int: + """ + A for Rock, B for Paper, and C for Scissors. The second column--" Suddenly, the Elf is called away to help with someone's tent. + + The second column, you reason, must be what you should play in response: X for Rock, Y for Paper, and Z for Scissors. + + The score for a single round is the score for the shape you selected (1 for Rock, 2 for Paper, and 3 for Scissors) plus the score for the outcome of the round (0 if you lost, 3 if the round was a draw, and 6 if you won). + """ + score = 0 + me_lu = {"X": 1, "Y": 2, "Z": 3} + lu = {"A": 1, "B": 2, "C": 3} + # 2 > 1 + # 3 > 2 + # 1 > 3 + for line in s.split('\n'): + if line.strip() == "": + continue + elf, _, me = line + score += me_lu[me] + if me_lu[me] == lu[elf]: + score += 3 + if me_lu[me] == 1 and lu[elf] == 3: + score += 6 + elif me_lu[me] == 3 and lu[elf] == 1: + score += 0 + elif me_lu[me] > lu[elf]: + score += 6 + + return score + + +INPUT_S = '''\ +1000 + +2000 + +5000 + +1000 +4001 +''' +EXPECTED = 5001 + + +@pytest.mark.parametrize( + ('input_s', 'expected'), + ( + (INPUT_S, EXPECTED), + ), +) +def test(input_s: str, expected: int) -> None: + assert compute(input_s) == expected + + +def main() -> int: + parser = argparse.ArgumentParser() + parser.add_argument('data_file', nargs='?', default=INPUT_TXT) + args = parser.parse_args() + + with open(args.data_file) as f, support.timing(): + print(compute(f.read())) + + return 0 + + +if __name__ == '__main__': + raise SystemExit(main()) diff --git a/day02/part2.py b/day02/part2.py new file mode 100644 index 0000000..2ad16fe --- /dev/null +++ b/day02/part2.py @@ -0,0 +1,82 @@ +from __future__ import annotations + +import argparse +import os.path + +import pytest + +import support + +INPUT_TXT = os.path.join(os.path.dirname(__file__), 'input.txt') + + +def compute(s: str) -> int: + """ + A for Rock, B for Paper, and C for Scissors. The second column--" Suddenly, the Elf is called away to help with someone's tent. + + The second column, you reason, must be what you should play in response: X for Rock, Y for Paper, and Z for Scissors. + + The score for a single round is the score for the shape you selected (1 for Rock, 2 for Paper, and 3 for Scissors) plus the score for the outcome of the round (0 if you lost, 3 if the round was a draw, and 6 if you won). + """ + score = 0 + me_lu = {"X": "lose", "Y": "draw", "Z": "win"} + lu = {"A": 1, "B": 2, "C": 3} + # 2 > 1 + # 3 > 2 + # 1 > 3 + for line in s.split('\n'): + if line.strip() == "": + continue + elf, _, me = line + goal = me_lu[me] + if goal == "draw": + score += lu[elf] + 3 + elif goal == "lose": + if lu[elf] == 1: + score += 3 + else: + score += lu[elf] - 1 + else: + if lu[elf] == 3: + score += 6 + 1 + else: + score += 6 + lu[elf] + 1 + return score + + +INPUT_S = '''\ +1000 + +2000 + +5000 + +1000 +4001 +''' +EXPECTED = 5001 + + +@pytest.mark.parametrize( + ('input_s', 'expected'), + ( + (INPUT_S, EXPECTED), + ), +) +def test(input_s: str, expected: int) -> None: + assert compute(input_s) == expected + + +def main() -> int: + parser = argparse.ArgumentParser() + parser.add_argument('data_file', nargs='?', default=INPUT_TXT) + args = parser.parse_args() + + with open(args.data_file) as f, support.timing(): + print(compute(f.read())) + + return 0 + + +if __name__ == '__main__': + raise SystemExit(main()) diff --git a/day03/Makefile b/day03/Makefile new file mode 100644 index 0000000..b24396f --- /dev/null +++ b/day03/Makefile @@ -0,0 +1,6 @@ +s1: + /Users/zev/Documents/repos/advent/2015/env/bin/python3.10 part1.py input.txt | aoc-submit --part 1 +s2: + /Users/zev/Documents/repos/advent/2015/env/bin/python3.10 part2.py input.txt | aoc-submit --part 2 +d: + aoc-download-input diff --git a/day03/__init__.py b/day03/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/day03/input.txt b/day03/input.txt new file mode 100644 index 0000000..d0ad78f --- /dev/null +++ b/day03/input.txt @@ -0,0 +1,300 @@ +PcPlnShmrLmBnmcwBhrmcmbHNGFGpwdFFwGNjNbGqNHH +tzQfRJfWZZztWzVtCTfRzFZjpFjNZjGLHbdHLDdjpb +CCQTzRLzvQVVfRzJfMPsnBlglgPmBgPmvSrl +RMfvbbszHTsssFPzDQPggpQJPQ +NSNcqVtLVGgDlpQBClVB +hmStGNNLhjNrpWLGSjWrZssbZTMMvTfMnThbRRTs +fTrTPGTbfftWBBmLjrJL +DqHwVMqVplDslmlZmpHVwNnShWZFdBBdjWBtWtdtWJSSLS +MNslpDvVHlwsmpQRgQgCfTTcvcRQ +pBBhRgDsMsswprBhvgRglZtFGFFRqZtZmRtNqtZPPN +TdmmzzmdZdqdGFtF +nmSccCVmSCpDCswMwl +NptqDsQtDTQzCvlzCpRlRp +jmZcndmjbZcjrmDvFMFFlwCvzFnF +jjgLVLrGcdDBNhWQTgHg +mLVhhfSMSTmMwClHGdpjDHjGdV +zPrZgJCgbsnrPtZzsCsbpRDjBRHnjGDRldRHppcG +JJrbsFrZqrgWbbqbrgWzJPNTwhTNCmmvfWCShhhmwwfm +ftgfljvgfgBTNvtggFDDGLGRDnMDzcQzncGt +VdbpbVdZwdwrsVVLRrMrDLDBGnBGcM +wmpWwWsHWBCCCPPvjvmSqlfTTmSNgN +jSqmzmmSSDRjLMLDwqjNcMMLTTflffWCCsRsTHnHVrfHWTsr +tdbgZpgBPdgGZGGFTHVpCsCVfVsJpnWl +FnPQFvbvhFFFbvBwScjhzcqSLLSzSN +bWdgrWwwFWbgzFWzrmNbdPqttChMSRnmqSPSnqtMRM +lcPJLDDPPfpMBCRJBtQtMh +lGDGjTGLLDHPPGjlPTsswsbHNFsNrFNFsrzr +VmtHfVhBLHVtlhphjZMdnQQZZqZmQDdzQQ +CPFwPWrvWgrfNgFPCMqZzMDDbznFTqqzDQ +NNPsfffPCsBLjpVltV +ssdBBJqJhlTJLsjTJqFFmnmmnnrcmpprmmmPcRlf +gqtqzSgWQWqmnRPPcNmmQM +GqbSVtGzvgvgWbZjjBhTdhBsTZBJBZ +jhNBsPDzLjsVhLSNzgvcvbcwbBWFcgtWCc +ZQQTTHHnGpMtnpdHpQJfMgrvWWFqbcWWGgrgwCCwwF +nHpmMnQQMmHpRnHRmMJnnTShPzljzjSNmSDhLsNSPtSh +GdqnBGFdlqzFnwdSCQZjZLLDZjZRvZLDVvgQ +PsptsTcftMfcTfhTghVDvvjnRNjVZnvV +WtPfJTfftJcMTrMnpccFwlCSCGFGCbCwJSbqBl +GjFLGhjRwFjNSjSdJCBBdQJddbBc +MVvMMHRzVtHlvlcQBQJHqdpQqCBC +vDgVztvvmrgrVRrMmsrsmZzZnWhGnNhGWTLfnLwTLhLTjngL +VljjQJSsrjjrCglsCjsgjVVfDLdZGMdvvGdQMzmvzcDQMc +HqPBtcpRWwtHbbFwBHZfmfpDfvffDfMfmGvM +PwHNbcwtqFqnwtNNqPNPPWBTThjhhVTCSJTThssVnSlJJV +GCccNCrrnCrpnzrnCDPcDDrvHHTBqTPhswqhPTBTTwBhTj +VfNmRtZgWWHdBdswdjZv +SmtQfgNmVFgVLVLVmrnMpcDLGCGLGDMpCp +CrdZdZmPPjrQdRPRDqDLBqBLBSWgWgLDzF +sQhTNphsVbhhhMJfhNVGqltVSzSllBzStlzFFFWB +hsMpwQhNMZmPmrwHRj +cNVpSVRpLHRLsVWWfnfsCshW +jvqjTgqZPlJZmbPPfbpswsPb +vlqdTZdtJvqdZjgqZrtRpQFtLFRQczHGzt +JJQndVQnQgTfNvGf +ljpbWbmNbDlGTvggGvZf +mpmRbMmmNDFDmScpzCsdzrnJrsCzrrnM +tNFtNFFzzjjzjBtVNZVbjZGlpSvTllpWwvnBlWGGBGCC +fPdcrrgPHrHMMMWlppGJSPwGSnGv +fmrqrhhfhdRddHrhQqQrfnLZjLtNttZjjRtzjFtRNj +sphRcpQRhfmnmfpptg +WVPlGLlSjCjSlGSHJJWZdmbmfvPmmnftbbgDdt +LJjjqVNjlnCTRcRhhsNcFF +vwwqttFjwgClRNCCvGNmZZMmJsPJjJpTdMpsZd +fBLVHHHrFnhHhnrVSTmfdPdPccTTPsMfsJ +QzVWzznzFbWNGNlt +vjMddVVmnWpdMndjvhhWfNLpfBsfLLZLBBSqqTZq +RFlrzQJPSRGzzzzgBZNsgBZTBflfgf +cQFDRHFDDGCJShCnvwVnnhCn +hgjlpRRLlPJJhTLJMDnwBndSPBNvMqnN +FGWVfZsmCbmVzrvtwCSMtMdnDMCw +VsVmVZfVQDmVFrrmzmGrHHTJgJjhHJcllglLQJRL +rrTVcTBgsjTffmfWHZTv +JLdnDlpGlGSLlpwJpHZfFvRZnWzWrHWqFH +wQDpDrdSlSCblCdwdSLlwQGBthPMsghNsVNVtCNNhNPjhs +CtCMvNhDMHfDDdffqtDtCflpJlBpvmWWJWwlpwFFvjwB +rGSbVGZrSsFJjlmBFZWp +rbbQgzVGrFVSPPGqfhftfqztNtqHtt +lMGZCGphllZDNshNNmHHND +PLwjVwJVsHmRrZZw +ffSdzjfZSjtjSjLtLLFFFGqFzznCpCnCBblQ +CqRnlzHCRWTlHPTZVQrcQtFsQFTcrQ +DfJcdBDBcftQjsrsBtjZ +JDfdGhSvNGhNfffGSfRznPvcRWcqCqmlvlcn +JPhBBBQCnCJCMhnhMZRrRZgbDgrWrNbglDgR +jLtSTwtsShwRNpRWrh +FLLSHsjGLGczvfPfJdfhddnHPC +BjHBNrWmTjFgJngbJhWd +vsGttMDtwCMQCJnqqqFJsggqdg +GFtDSwwMpTrzSSfcfm +rnWDQvpwWpDDcPjFPPHZjVDZ +CTJCRmCJcZZZHCCQ +LdlmdQJNpnLWbrfL +VdTdcVTZwCRGVGGMVmttlF +gnrsbngfgQSpBfpMBBBpSgMNNJbmGmlqGDqDNlFFJlGNFz +gprgQhgpMMMPsrRTCdPZwCwZZCRH +cHlCVGbbWHWqRNThhcNcmh +MwQDzpwdJwpBpPDQvrhShfLTTRLfLdjfNRqS +JwMBBrPsPDwQMDPPBPQJwMrvWHFbHHlgbsGnnWHnFnRGlblF +PQPjPDjRRQSFLSlgSmLlfh +zpLdBddbNCdqGbWJGWpJWWlsFsmmFpwfflFgfHwFhgmh +nJLdLVnzqqbjRctcPDQVTP +JdztScztPdSWLJLtgMbCjhvlbPRbjbMvCh +VZrqfQcFQwGVVFqfrTFTNqhljRHDMvMMGhRDRRHGbDhG +NZQNVQQpQmrZFQQFwQQVVZgBszJJgznstnmtcztdBSgs +nFHLNJzFbLJGGLMlTTRZbZRhWRTr +wVmgBBmtmwlqlWTwTM +sdvmgcPsCPPQQSMz +SccCqmQmgBmppLQmpSMjjlJzzsNPMDRbPNPlJM +VHZvwtZwhZHtdTwrVbNsljlRDlJPDhzsbN +dZwftVRftmcgpBCmBf +NTTlVlgNSflqbphFFhNbFp +wmmLmjwzwbWGLjRmtZZdhZLFtQQLQBFh +RvjbMjjvMzMWbDWwvzPjvmWSfVfsTlVVPVgTgPfVsnnnsJ +BsBsZHZNdWwsNdrzgCrMMqsjzzMC +flfhVWFmLrhQzCCh +fVbmFSpnSSmtnPZvdWbwvdvdHZ +NsZWWWWLsBZPhfsLmPhcFCCHCMMrqfqcvHMfHH +nThSllnplGlMpvFRcCqrrr +DnTwSztgzlDnVGTwztmdZhmLdJdNDshBdsWs +RBBGTFZGglMHvrtcgSdnNgjg +DmVcbmbJmwJDJzVVwzJfmfstnztvjnNjvNSpdptvzCnpjj +DsLcfLmbhVQssQJQscWRPBZZMMRLHFHZBGMG +FVvhVnhFnFhmvFhVcMBHLgcPClrqqrtqCppldrRRTppldg +QLWfDNwsQLtlrrCtDdpq +sJwZwLsGJWGGwzzWZNbWNLjQHSVhvHSnhcMFcbVmnvcchSBS +jTMNMrHBJWWDffRqfDBqfD +QmSFphtQqQmVmqVnPnPlpwgfnRnDPl +VqFmLFbLhmZhGFGmCmGtZLtJWzWHcJrNrHMccjMscMHzMZ +hGPGmbfPzbPfgdMdWGqBGQcqpp +nvFTvDrTdNZZlrjnMHHHpBBcppqq +rNlZZNLvRdRCRFFwZwhgbmSJPSmPfhfwhS +vjdbFWTtFRRvtvZZvdWJWbGjLhCcnrrrNqLNCPqchShNqc +QHQVlDsMfmmDMHDBdLdCSLnhNLNNfqCd +VQHsMDpHlzMBBwlsmMzmmlVwptvTWdvJdbvJtRTWgGFJJGtR +nSScBcnbbFSQVdBFBtWpwtvtPbTZthtTvT +pRzHpGjCDGzHGCGsThqqwZwPhCtvhTqZ +NzlzjDDpNldBFrlfFQ +qJlDlPPWppgppqPlplpfdvgnbMfGbdgCghMdCM +QWTWZcSsWbvVvTnhfC +tRFLwZrcrWzzlJmtBqlm +HMNMvvzzNcmfNmfbhs +qVcwCgjCLtWRSLsTPbmPfmTh +RtWCJgddWRtCJdWWgdBjwWWwpzMFpHGprcBGFFnGHQZHQGpF +gZgBDgDVGDGjmDZRtgjvVvtQdnLrcRcrdfdfCcnlscsJsn +WTqzqHqNzpHpwzNhMHNwWPbQCQcCLsnCrLLfcrffNflcNn +zHTwwpTPzTTwlFTFzwqzPbwZGgGZZBtmGGvGmBGZVFStFZ +znlSSzfzTcmmfcCt +PHWWGpqgPShPMwGwqJFTVtwtCVTCmTJcFc +qHqqSggLrRLBbvDDdndzRQ +WBddBQWZWWQqqQFMWfmrWsJnmVJJNDDVJGsLmHmLDN +PTgCjvCCPPPzSZGJVLsVZCHHnH +pzwtPTvzTjRTPtwSjPSzRgBbWMBfMwwZfbWrMrZFqFFM +BqDwVqdqlDlblQMf +ZcCWWcWzvJZjcPjZZZfTHfQJQHThqpMbQQJf +LPCcZcczZLgCjvPWgvstjsjmRRBdmGrdGdmSFGnFrtGmqr +CBvgQssVzfCBQSgvvvfmrlGrCtMGwthJlJtbrh +TpLqLRFpqdRpRTfNPtRmrMMtMlMMmlMJlt +PZTjqFFTHZZNZpqcVWzVvgzcWnSWfBDD +SVSTpgpVpdNbpcVdfjcNfbcJnqsltcJPvRJqRwQqlQsJls +zhWzDLmFHhmrWZmmzHJJQlnswqsvttrstQqs +zGtZFGGCmZmGGFhLBWBGGFdgVjgppMTSTgMfCNfVVSdj +CzjNJGcnzQJltPHttcPHTP +bLVsqLbLmSSVrqmdhVSmsVFFprfrFWrwTTWWWZpFPtlP +ssDsMqLqhvmvhdmdvzRCnQgRzzBjgnlNCM +TzTLzzSGRlRSjWzlWRzHGTpNhPhJPmdnNPPbhlbPbdhfPh +mBCDBVrCqVQvQMBcVcqBrBDsbtJfnZNbJndNNhthZNJfPZPs +wMCrqVvBzmzHTGLw +NbfwfZPPdVNPdBdQBcmQzrQz +nnWqHLWGFMDFDLDjsqnHLsrQGzmJczmQrgJmJGZmQrgJ +FFWRsHMHCZCWFwRwphpvlfTTpp +PclPlVZvLDNvVZSLSMvvDttmtfzFtzHqtqtzzccCFc +jrggQGhjQsTDbrbJjJQqzzCsdtzzFCdHqmBBHz +WGDgngwrQggZMNvMWPMRRV +wNgpMdMMcdSscccNcLLTbtQJtQJQltJwFtlBlzBt +HHGhrLrCvHWHCPhrWDtnBllnQbfQftGnfnBF +HvLjWCLHPZvHHHZjjrqVTTZVcppMgNNNNSpS +QQrwQmvWQjgTfvBjfffrSDcrqSqDDVLctqqcVd +GnHFnGhGplGMlHMNhzBzlLPLVcVNCPDqVNdcqLdqtV +GnMGpslMhGsRzzHzGsZFZQJTTmWfBbvfgfgJRfbwbW +MRCtSwMhvjCGtvMZDVWpVZJlVccNDlpb +gdLQFFwwLfHJWnQlcJJbWc +rdqdmqHLTLmsswsFHLFtMPRMCSSRtSjTPMPSCR +jmCCnLCLZjZjRjQTLZQhGPGhhzHhDRGRDzwzwh +stlJlrlJJcSSfSMMzPfhhGhzpwhpNwhD +rbrbBcSlWmdZWjDnTm +PNBRNnnqQRNfVfRtVVzgFLLttpSwgzzzmFFF +fcWlcbvvCFzLbwLw +rlrMrhTJhDcTTfhRNqHRQPQRQNQB +TrprpprRVVfpRpVqTVpzDdvmvbbCchhcttqcthSMdd +JlnZnFlsMBZnJHlsLsCLbSNtbNhdbbShCScm +FlZjjsHHsnQFQwTDzMRRpGRR +wHWzwCTTqJhzzvJhWHWhqJWrFsFQrrrFCfFfgjjgjprfsp +DBRmZRtZLbnRBGSBmtGSLpjBrrsfrgsTQVrVrrPrgr +DLnbcbtLtmNNmbRcGbcGmHzlThNNhqJTHdvqvWlHJh +GSNqjRcqflNLnCTTWrWn +BmwQtmtJwPwmzMwQtHtVssvrnpWTTnsTTgpVCLCs +DBBQHJJrzhzQDDfSljRfhccfcdZf +wtgtChCwzqgLzjggqtHtjFHHFcnPfdRDfZZVcPfVZZfGnfdm +vBTrRTTWGGmcTDVD +SJMbbpWslJblSSNzNsztRChzqRCj +gBHHCtVCSHMQlfFTQqCfmq +WrpdwjbwbwQGlPqSqblP +wWDncWrDDNdWNRjScScjpzvHZtBMZtJsvLVgvzssBsvs +VppWpVfmZPBlnmrGBzhttMzMpctLLcChSh +FwgLJvRdHcwMzSzjzc +QvbgdQLQgDvsqvqRHRDdDQDBWmBGBflnVbZmZmmnBBWrmW +SqShwLFCQGpDHCtZCWpW +bdHPHjTbJdsMnPHPbdjgtnBlVlBnVgtZpDBpWV +bdmPcjbjMNMvvHbTcQRNfRwRwLffwwqwNF +zdRHTpQTQHQnpnnQRHTsNNlJSJWmzJmJllNmSG +FBbRvLbFRwLqbbVgBVqqLFqJtJNcltsSGmgmGtNtgWmstm +FLhhfvvVwvjqfLRBqLVqbwqZQrTTpHMHjdrpnnDPDQCdCrpC +JgjzvbJCWgbjgGbJWjRhgNPGHHBMtqBStZZsHMSsBqtD +cfQdwQFdQQppnVVnlFLLBsBZMhqPlPMMqBSHDtHM +wnQhcnVddmdWgjvjmvRjjJ +QpcRtndvsLcVJtRSzWSlWjzSbjjWBv +qGZPqCTmGPqgGTCqHgCqZCPFWbbBNBMNBbdBMlWWrbjlMbFl +qhHDGhCmPhZHgDmDVQthttRchLwLdwcc +srpPMwlMmsrGFGswvDRhRWRDJJJchJ +fSgBbCBNnBTTgCNLTCRJhRJVWhTcVVVFFJdR +SbBnnLNZCLFQCZjnCnZFjPrzqmlMmmsrpzrlsmtt +BBsfDfsBDSWRwlLqmWCpWcllrl +nQMgMnnnhdntgMBrCdpNNLNlNqLqLl +FnQFHzPQJjJGRBGvfR +lRnVRFFlgMCRVwLgFZRnZQHWdcftHdmcJHmmMdzzfz +DGBqGQbhhBDbSBpGDBzqdNHJdtmcWdqdmtcm +bjbsBvjhSlVsPRgLQl +dDLbRdTMRJMbFRzZBfzNSjtNBzBD +PmgspqqVrppTVrvrsPhhfQwZBwNjNtNffzqqfwwN +mCcmsngrPvpVTssCVsvsPLRRJllGFlnRGbMJMWWlJJ +fGlGZHRRbwgPbZRRNCdcSWpncnQtQWlWcWpW +JrTLJgVvVLQQvtSvQncQ +JrrrmMTBVTmjBMrVjrshmJzgCfzRPCRZPGHfbwNPzbZHNH +qqqlDDZzVVnNqHDDFFFNlQpzjrTvsvzTbgJQQggjJp +cWPWcCmMfCMWdtPMhMbQQQjGGjpdvjTbjgjr +WtMSBCtCwchChMfBWtcPnNVNqZZLDRNqTRnnlwHn +mvQQnhBvhmvBmncmZBclTZTQccRFNFFdqFFgVqSRrgFrppNR +MjzJPzGPfffMCjVVjfPHLCFRNFStqrdRSdqdNGRqNptq +HDJHPjDJLfjbzfwPjCzCWWTwlmQhBnsWBvVsvBvZ +RVjcshhscQhrVjhvzjVfDNnzGtftmDHFttFGGf +qLcBCCMBJJbTdBDnNtdfnmDG +WpZgLLclTclRwgjgsrwsvj +shhhltNPcDtlNcNMcsctNtppLZvWWFLTFFZpTZDQgFLT +dRgJVzRHbqnLpTWQvLLJfp +mCVCdzqHndbqHCrVqRrmbwtNBsmPwNmScPgtPhBclw +bDDZMDrFPsrsMcsrbJZJdMMGpSzpSbwRSSRGpCHCGzlhCC +BWWNQjBLQVHhlGpSCmwj +ffwnNwfgtnNgVVwfNWBWnFsMJTJTcPFJcTFDsrJstJ +vQbQLQBpBvbvpHplHNTHWGZDngntZCQGgZhGhtjG +rqccPPmcrffRmsmCjVgnrGChChDjgW +fqRJsJMSlSzSWTbT +brsjjJPJwrJJsrRRlllNQGWQpwppCtfGGtWzGGMQ +ncBqqLTDnmLgVDZVnBDmdtVVtMzWWdMCQdpQWdVz +hDZgTSSnTzNPNFSFPF +VZVJJtWTsfTVVWsJhPWrCjzSBJlHSmjJCRlNSSlz +CqMpwccgvvgLnvLbMMRRjBNHzjmGmwNHlmlN +gLqqvpCDfVDrTfVW +CNMDGNPPNJCGbLnTffsTLT +tcBBRlrBdQrtmtWFjjbnrTjjFbjr +cTQQhcmvcBRcwDMVDZZPPCJh +mBCdgPLgZmLfGmfvGhtRQJWjtjQGQhtN +pMwrVwbwHMsqcTWQhQWzggTTWp +nnSMwrlrsmSZgvvmDd +WNSzpCzNzqzNdmqrRHrrLHFrJH +MtPfvnGMPnMcbnRtDHTRFFDrmJRQ +PcBsfPPHPGGfcSzZjNjpNZZdCs +mDCZVLDhWVSDCRvGtsGgGRHl +JjPwPNdcPnjPdcwNltHzzGmgGJzQJJRQ +dqfjnNmwmbmWrZMbMrThhB +qtBpNZFpBGFNfZNPmZPmQmHrmPPPTz +LLwJLvDvlWWLHdwDrVcCRcDVzzVVcV +sMMwvgjnMvjvnlsvNFBqfGHFqHGjtSpS +MmZZsFgwJTdTMdgmZdZRgFhDHhPQPPnRPhCrHhnnrPDD +fBcLlNNpQCDLDJJC +jSbWWlWpBpclWlWpNWlVBbWVdgwswFJmFJsGtdMggZFGbZwd +CMVQVMLLMFGRCMWQttnqqwQwhqsm +pJzlczSpPpPgmsqNhmPGDstq +gZgTccZGGpzdpjclGRVMVRFRMFvHRLRdLf +FMWMSBtStZqZWQtFtScWWSZmHPVJJVHwwlTgmgbzQwbwTJ +jhGLhdjNjsLvLsshzHJPVdVmmbzHzdHJ +jvDRNjnDNGRCzjLzZZpqnrFBSccWrMcB +zggmthDDghHvtrdgrVWfSBRwTHLWHwsBWw +PGGjpCjQnJQGJcJnnQpjFWVSsZWVLRZLBcsWSZBRWS +FGQlpnJCbqqGGRCjjnlCqGMtdNmmmvdNmmmzvhbrmgMz +TstvBTdgBhqTsdTcPlfCSrNMrNnrCNNSNNgp +HwLQwQDZzDjnDbmMhNSnmm +FZLVzLLQHRRzwWHjdPlJctlJtlsllhRs +fBtPsMDDswHvBmmVdBlSBRcGGnhVhg +LWJbrpFqpTLTTjqqNWlhnRGGSnhrcSdlRlsh +JWNbbpjJzTbNNNJNJMvmvfZHvzDsHDCsZw +LPGnPNLtwGhFFnJPfsqpVVszzpsP +TcWdvlrcWddggrDBDDdDMmWzRJqfVQZqmsfZsRQzZfZzQJ +TldWrMrDdlDCDdMTcwSLVCSShLNSwHjhGF +JGsWWWQsJmPwQWbBPmccbcbqFfMMpFDVCDFVFVCDqqfFwD +ZtLnlvLnNtvLndnCmfMVSmVCClfpVp +zTzZtjnZNLNmZvdtznntHHZJbBRGBRQWcJGbGsbsJRPQWT +MLmlMTPtQtMNlhbqbbqhflBB +rcrvjpSvScbRbBvbDBPG +ZZJzSHpzPrJzHFmMVMFmHCLNtV diff --git a/day03/part1.py b/day03/part1.py new file mode 100644 index 0000000..14cbb9e --- /dev/null +++ b/day03/part1.py @@ -0,0 +1,60 @@ +from __future__ import annotations + +import argparse +import os.path + +import pytest + +import support + +INPUT_TXT = os.path.join(os.path.dirname(__file__), 'input.txt') + +from string import ascii_letters + + +def compute(s: str) -> int: + total_priorities = 0 + for line in s.split('\n'): + print(line) + c1, c2 = line[:int(len(line) / 2)], line[int(len(line)/2):] + common = None + for char in c1: + if char in c2: + common = char + break + if common is None: + continue + total_priorities += ascii_letters.find(common) + 1 + + return total_priorities + + + +@pytest.mark.parametrize( + ('input_s', 'expected'), + ( + ('vJrwpWtwJgWrhcsFMMfFFhFp', ascii_letters.find('p') + 1), + ('jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL', ascii_letters.find('L') + 1), + ('PmmdzqPrVvPwwTWBwg', ascii_letters.find('P') + 1), + ('wMqvLMZHhHMvwLHjbvcjnnSBnvTQFn', ascii_letters.find('v') + 1), + ('ttgJtRGJQctTZtZT', ascii_letters.find('t') + 1), + ('CrZsJsPPZsGzwwsLwLmpwMDw', ascii_letters.find('s') + 1), + ) +) +def test(input_s: str, expected: int) -> None: + assert compute(input_s) == expected + + +def main() -> int: + parser = argparse.ArgumentParser() + parser.add_argument('data_file', nargs='?', default=INPUT_TXT) + args = parser.parse_args() + + with open(args.data_file) as f, support.timing(): + print(compute(f.read())) + + return 0 + + +if __name__ == '__main__': + raise SystemExit(main()) diff --git a/day03/part2.py b/day03/part2.py new file mode 100644 index 0000000..62e552f --- /dev/null +++ b/day03/part2.py @@ -0,0 +1,63 @@ +from __future__ import annotations + +import argparse +import os.path + +import pytest + +import support + +INPUT_TXT = os.path.join(os.path.dirname(__file__), 'input.txt') + +from string import ascii_letters + + +def compute(s: str) -> int: + total_priorities = 0 + lines = s.split('\n') + common = None + for idx in range(len(lines) + 1): + if (idx + 1) % 3 == 0: + l1, l2, l3 = lines[idx], lines[idx - 1], lines[idx - 2] + else: + continue + for char in l1: + if char in l2 and char in l3: + common = char + break + if common is None: + continue + total_priorities += ascii_letters.find(common) + 1 + + return total_priorities + + + +@pytest.mark.parametrize( + ('input_s', 'expected'), + ( + ('vJrwpWtwJgWrhcsFMMfFFhFp', 'p'), + ('jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL', 'L'), + ('PmmdzqPrVvPwwTWBwg', 'P'), + ('wMqvLMZHhHMvwLHjbvcjnnSBnvTQFn', 'v'), + ('ttgJtRGJQctTZtZT', 't'), + ('CrZsJsPPZsGzwwsLwLmpwMDw', 's'), + ) +) +def test(input_s: str, expected: int) -> None: + assert compute(input_s) == expected + + +def main() -> int: + parser = argparse.ArgumentParser() + parser.add_argument('data_file', nargs='?', default=INPUT_TXT) + args = parser.parse_args() + + with open(args.data_file) as f, support.timing(): + print(compute(f.read())) + + return 0 + + +if __name__ == '__main__': + raise SystemExit(main()) diff --git a/day04/Makefile b/day04/Makefile new file mode 100644 index 0000000..4d25d9a --- /dev/null +++ b/day04/Makefile @@ -0,0 +1,10 @@ +s1: + /Users/zev/Documents/repos/advent/2015/env/bin/python3.10 part1.py input.txt | aoc-submit --part 1 +s2: + /Users/zev/Documents/repos/advent/2015/env/bin/python3.10 part2.py input.txt | aoc-submit --part 2 +d: + aoc-download-input +t1: + pytest part1.py +t2: + pytest part2.py diff --git a/day04/README.md b/day04/README.md new file mode 100644 index 0000000..a29b6f5 --- /dev/null +++ b/day04/README.md @@ -0,0 +1,9 @@ +I went for a fast solution in part 1, which in retrospect I regret since the `range` and `in` approach of part2.py is easier to reason about and works for both parts. + +Another regret: I used AoC for testing instead of writing actual tests. This cost me a five-minute timeout after I made too many submissions. + +Something to research: There's probably something in Python builtins or stdlib which can make this one a really fast calculation. + +Some optimizations I added to the Makefile today, it ultimately didn't contribute much performance though: + +`make t1` and `make t2` to run tests for part 1 or 2, respectively. diff --git a/day04/TODO.md b/day04/TODO.md new file mode 100644 index 0000000..0355b7b --- /dev/null +++ b/day04/TODO.md @@ -0,0 +1,31 @@ +# How it Should Work + +```console +> today +created directory `day04`, we're ready to go! +downloaded input +opening `day04/part1.py`... +> done +testing part1.py... +sorry, the tests failed with output '...' +> done +there aren't any tests, submitting to AoC... +sorry, but 'you gave an answer too recently...' +> done +testing part1.py... +passed! +submitting to AoC +sorry, but 'your answer is incorrect.' +> done +testing part1.py +passed! +submitting to AoC +your answer is correct! +copying part1.py to part2.py +opening `day04/part2.py` +``` + +# TODO + +- [ ] possibly scrape the problem too: + - [tesseract in browser](https://towardsdatascience.com/image-to-text-ocr-with-tesseract-js-3540b420e0e7) diff --git a/day04/__init__.py b/day04/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/day04/input.txt b/day04/input.txt new file mode 100644 index 0000000..0f2f19d --- /dev/null +++ b/day04/input.txt @@ -0,0 +1,1000 @@ +23-33,24-65 +10-24,23-88 +71-92,18-71 +2-2,10-95 +24-26,25-66 +19-93,36-99 +12-99,5-13 +13-88,14-94 +4-85,5-84 +78-88,79-87 +13-82,13-83 +3-98,3-99 +27-69,28-89 +24-47,23-66 +43-48,29-49 +2-99,2-98 +3-77,21-65 +10-90,89-93 +64-75,63-75 +97-99,1-97 +48-65,49-64 +18-26,25-28 +85-86,26-85 +82-89,69-83 +21-93,93-98 +73-79,46-81 +33-52,32-51 +1-99,99-99 +11-36,34-40 +31-88,32-89 +9-19,18-35 +9-84,83-83 +34-82,4-83 +33-33,24-33 +34-83,83-90 +11-86,10-86 +48-48,3-50 +8-92,9-91 +16-38,15-37 +4-84,5-93 +70-75,41-79 +40-48,47-92 +37-41,52-89 +3-3,4-91 +27-77,27-77 +64-90,33-52 +28-40,9-64 +2-73,3-95 +17-94,7-75 +6-71,7-71 +11-69,10-70 +4-40,4-40 +9-54,30-44 +92-93,4-92 +62-63,63-67 +7-34,16-34 +54-55,31-54 +12-90,11-91 +11-13,12-53 +10-73,9-64 +13-18,13-84 +6-82,16-81 +52-78,18-53 +22-82,23-74 +90-91,3-90 +92-93,70-93 +18-44,19-45 +20-20,20-67 +31-93,76-93 +25-86,86-86 +6-73,5-94 +75-84,74-86 +50-51,50-51 +56-86,57-86 +18-81,13-18 +3-9,8-93 +31-36,34-34 +19-88,18-87 +10-95,54-79 +83-85,66-86 +32-68,31-49 +14-97,12-99 +42-42,42-53 +27-32,28-69 +96-98,15-96 +25-49,25-48 +71-81,15-92 +19-83,15-19 +14-99,6-14 +52-90,53-94 +5-98,85-96 +18-30,10-15 +4-86,4-98 +54-55,30-78 +85-99,62-86 +10-99,10-98 +4-96,5-95 +6-59,7-18 +6-86,1-7 +28-85,5-84 +3-82,2-82 +73-92,87-87 +2-3,2-89 +4-5,4-8 +21-96,69-97 +89-90,4-89 +28-79,29-80 +35-58,40-48 +96-96,3-97 +17-27,16-96 +7-99,8-94 +26-92,25-92 +17-24,17-25 +44-44,40-47 +57-64,57-65 +60-91,59-79 +23-79,22-71 +34-37,31-70 +22-60,22-59 +44-99,98-98 +9-57,49-55 +61-64,33-62 +15-68,4-15 +53-55,34-55 +13-13,9-15 +2-43,3-81 +17-56,16-99 +1-4,3-92 +76-77,73-83 +2-97,2-96 +44-45,44-55 +8-89,8-97 +23-73,22-88 +23-90,79-93 +23-87,86-91 +3-45,17-44 +7-99,8-98 +92-97,14-92 +85-89,59-90 +7-8,7-89 +5-90,49-89 +28-30,29-63 +38-61,38-60 +32-98,5-75 +22-87,71-76 +5-85,5-88 +16-96,18-88 +39-51,40-90 +21-21,19-23 +22-55,15-56 +1-75,35-59 +13-84,12-85 +11-83,23-27 +11-98,11-97 +35-92,34-92 +8-96,8-30 +48-72,33-60 +9-83,10-82 +97-97,10-98 +5-7,9-98 +1-44,3-43 +7-85,8-85 +12-32,12-52 +1-86,86-86 +3-63,4-63 +3-83,83-91 +74-88,38-74 +92-95,6-98 +11-19,10-20 +6-94,7-94 +39-90,38-42 +60-92,61-92 +43-94,44-98 +23-98,22-99 +31-41,27-32 +9-79,9-78 +63-64,11-64 +82-82,83-98 +78-79,77-78 +19-63,4-27 +26-62,27-44 +91-91,91-93 +16-94,31-93 +23-25,24-99 +78-79,11-78 +30-30,29-31 +34-85,35-84 +4-78,4-5 +42-84,43-85 +39-87,40-86 +49-84,50-84 +67-67,7-67 +38-38,62-67 +2-83,3-82 +14-33,32-68 +18-76,17-75 +68-77,68-76 +4-97,53-73 +53-97,54-96 +53-55,54-98 +35-95,75-83 +2-3,2-78 +3-97,15-96 +26-87,26-92 +4-10,9-48 +3-89,22-96 +10-85,10-84 +1-93,2-2 +24-37,37-62 +32-68,48-53 +33-96,95-97 +9-26,14-31 +16-66,13-14 +85-86,78-85 +65-82,64-81 +5-85,31-49 +47-88,59-91 +34-71,70-76 +14-14,14-14 +45-46,45-97 +63-73,63-64 +16-54,17-53 +87-88,51-87 +20-79,19-98 +3-96,2-95 +86-86,60-86 +82-82,67-82 +12-35,11-35 +15-31,26-52 +1-2,1-99 +3-96,2-2 +91-97,11-92 +41-89,42-96 +62-64,41-65 +54-54,16-55 +28-41,40-97 +15-89,89-90 +50-71,55-70 +30-66,30-93 +89-92,84-89 +25-27,26-84 +59-91,60-91 +4-11,4-98 +5-48,10-44 +53-80,77-79 +20-21,10-20 +14-86,14-85 +32-70,33-69 +94-94,26-95 +5-57,5-97 +38-50,38-92 +48-50,49-51 +13-98,12-98 +90-95,24-88 +90-94,67-91 +1-11,10-91 +48-59,59-91 +26-68,31-55 +15-56,21-57 +6-69,7-69 +6-8,5-95 +32-93,33-94 +13-73,14-42 +1-4,3-98 +30-62,29-62 +57-64,61-99 +12-27,11-46 +28-99,98-98 +7-83,8-92 +56-77,56-76 +30-89,31-51 +69-83,37-72 +11-78,11-65 +61-61,60-62 +38-65,65-66 +20-44,21-97 +39-76,40-75 +10-94,11-93 +33-90,89-96 +23-77,22-78 +63-86,62-73 +42-81,35-43 +34-91,34-55 +12-97,4-13 +1-98,1-97 +23-72,24-73 +14-99,13-99 +17-97,18-96 +65-85,14-66 +68-77,67-69 +8-96,9-9 +28-57,29-56 +14-26,14-26 +6-72,6-72 +49-49,1-48 +4-65,65-65 +53-92,54-91 +48-87,15-48 +51-54,20-72 +65-75,64-64 +4-92,3-93 +42-70,30-98 +15-71,14-15 +29-62,28-63 +6-92,6-93 +37-84,83-83 +1-99,23-98 +23-82,24-88 +2-60,61-74 +3-5,17-93 +50-63,51-62 +51-55,52-52 +30-82,5-83 +5-77,4-42 +44-99,3-99 +18-81,5-18 +2-32,32-32 +50-59,58-87 +23-30,24-40 +70-70,9-71 +40-62,49-62 +2-29,1-3 +48-69,48-49 +48-48,47-93 +5-42,17-41 +11-95,12-92 +9-66,8-65 +32-84,33-84 +16-69,15-99 +12-96,9-12 +69-91,68-70 +14-69,15-81 +96-99,50-96 +35-62,35-61 +6-22,22-60 +20-76,73-74 +4-21,4-22 +22-30,21-76 +5-90,1-6 +82-96,82-95 +18-31,19-71 +29-56,50-59 +11-21,1-61 +15-76,30-81 +1-1,2-83 +11-90,90-91 +40-90,40-41 +68-83,68-83 +25-81,25-81 +87-88,22-87 +31-65,32-64 +17-90,16-90 +11-65,11-12 +35-60,36-93 +5-93,4-94 +28-29,27-75 +12-38,37-45 +39-46,32-44 +12-89,12-97 +4-54,52-52 +5-94,94-94 +30-31,29-31 +18-82,74-76 +80-80,59-81 +3-65,54-54 +20-31,19-23 +82-87,32-82 +41-41,41-42 +6-6,6-81 +2-98,98-98 +84-94,6-95 +29-89,28-92 +27-30,28-34 +5-86,4-86 +32-96,50-96 +28-93,69-90 +75-75,27-82 +9-30,30-36 +76-76,61-77 +74-80,11-74 +48-61,48-60 +64-98,64-99 +83-87,5-88 +23-25,25-98 +55-55,39-55 +5-36,5-36 +45-57,46-85 +4-86,3-85 +19-58,20-58 +25-83,14-26 +27-74,27-27 +17-18,17-45 +81-88,62-84 +84-96,21-85 +3-81,1-2 +54-93,1-94 +1-1,3-66 +69-78,49-78 +47-93,47-93 +13-13,13-66 +18-78,18-73 +11-20,15-18 +52-99,51-99 +2-57,1-58 +9-97,10-97 +80-80,24-80 +33-77,34-47 +68-75,67-73 +20-95,19-95 +4-99,5-98 +8-85,7-85 +42-80,66-82 +22-47,31-47 +22-26,24-24 +4-98,38-44 +92-94,92-95 +82-92,71-94 +6-10,1-5 +3-92,1-92 +72-76,71-74 +6-69,7-69 +25-75,26-66 +15-51,15-63 +14-99,14-98 +7-89,6-70 +58-66,62-85 +7-11,15-23 +42-62,42-63 +1-4,4-91 +1-3,3-97 +49-79,48-80 +15-95,16-77 +6-99,5-99 +6-79,8-27 +47-69,46-68 +20-21,24-96 +13-71,60-92 +69-94,36-69 +66-86,33-67 +34-47,34-47 +4-4,4-93 +22-68,68-68 +42-90,43-90 +74-74,74-94 +3-72,3-62 +63-75,64-67 +16-48,7-48 +2-89,3-99 +2-98,3-97 +41-94,42-95 +45-93,44-98 +16-18,17-64 +69-70,47-69 +2-93,93-94 +65-94,66-95 +54-56,55-57 +5-92,2-92 +48-92,28-45 +67-68,48-67 +7-12,6-8 +7-8,6-8 +94-99,16-95 +13-49,14-48 +25-48,48-48 +6-51,7-18 +46-83,15-97 +34-57,34-58 +16-89,9-17 +41-74,41-42 +13-32,13-97 +90-99,99-99 +7-99,7-98 +78-79,63-78 +4-98,64-79 +49-75,50-80 +40-75,40-52 +14-72,6-14 +5-91,91-91 +27-55,27-27 +20-22,27-37 +35-71,34-96 +2-52,1-1 +3-87,2-87 +2-70,36-69 +38-90,39-89 +67-79,67-80 +5-77,77-78 +26-32,2-34 +10-43,43-85 +55-84,84-85 +24-59,24-58 +43-49,44-48 +60-81,59-80 +52-91,91-92 +44-62,42-63 +3-96,3-97 +29-45,30-45 +64-92,6-93 +89-96,4-90 +71-91,71-90 +50-64,60-63 +49-88,49-89 +18-98,18-90 +30-74,72-77 +32-88,4-76 +22-58,22-23 +5-71,5-18 +8-90,7-98 +4-78,4-79 +54-87,54-55 +3-91,3-92 +14-92,89-91 +41-95,42-42 +74-75,53-77 +12-90,3-12 +5-50,3-51 +27-67,66-68 +10-42,24-38 +20-79,20-81 +10-78,78-97 +26-47,35-46 +34-82,34-63 +2-94,3-98 +19-87,19-87 +4-42,6-90 +13-49,12-14 +75-75,3-76 +55-70,54-56 +86-92,85-93 +31-38,28-46 +7-90,6-91 +33-72,32-50 +22-46,45-99 +45-53,46-51 +90-91,6-90 +13-87,14-45 +41-95,14-42 +90-95,76-95 +51-70,15-89 +15-49,25-95 +15-15,15-98 +20-88,14-33 +2-67,67-70 +88-93,78-96 +77-91,53-84 +53-88,52-98 +24-96,25-25 +40-40,26-40 +3-15,9-25 +35-99,36-97 +61-61,4-62 +5-95,6-6 +52-56,52-95 +22-30,23-23 +40-44,43-63 +13-16,5-14 +18-90,89-89 +5-88,4-88 +78-83,82-82 +6-80,1-1 +15-31,14-32 +13-96,13-13 +68-76,68-69 +56-67,67-90 +24-92,92-93 +16-29,17-90 +2-99,1-90 +12-75,1-13 +21-91,20-90 +1-99,11-97 +94-94,25-95 +2-91,3-92 +95-95,2-95 +2-99,1-97 +28-98,27-29 +6-26,2-67 +20-58,19-71 +32-87,49-86 +13-57,14-56 +2-55,11-44 +13-61,12-61 +33-81,80-80 +39-91,41-44 +40-93,39-47 +83-95,40-93 +20-79,24-78 +52-93,6-94 +96-96,3-97 +44-55,36-87 +43-44,13-43 +19-99,19-98 +6-17,17-97 +91-99,88-91 +31-51,52-77 +1-97,1-2 +26-86,26-87 +50-53,40-81 +40-89,89-93 +78-83,1-79 +9-89,8-73 +6-38,7-21 +19-20,18-21 +97-97,35-97 +28-57,20-28 +3-86,86-87 +53-53,2-52 +59-99,60-99 +75-84,76-95 +20-93,21-94 +29-29,29-30 +34-92,15-58 +11-58,11-59 +11-11,10-98 +19-77,77-77 +38-56,38-71 +83-86,12-88 +8-73,5-6 +5-7,7-93 +18-79,19-72 +4-99,2-2 +5-82,5-81 +24-37,37-95 +11-63,9-12 +6-99,7-98 +92-92,91-91 +58-91,2-95 +23-98,24-59 +2-90,3-89 +54-71,1-81 +22-98,48-97 +14-49,13-76 +5-52,6-89 +6-88,76-86 +3-85,6-97 +87-94,86-88 +30-46,31-45 +63-95,9-97 +19-94,94-98 +71-75,72-74 +48-89,49-89 +27-52,52-54 +21-99,41-94 +5-96,3-5 +40-69,38-40 +74-99,73-98 +6-31,22-85 +13-76,12-75 +29-74,29-74 +10-86,11-86 +40-41,33-40 +63-94,29-94 +55-85,55-55 +14-20,18-19 +52-78,1-79 +92-96,7-92 +12-89,14-57 +32-49,49-82 +36-63,43-62 +20-94,41-93 +79-95,7-97 +5-60,5-22 +29-93,28-93 +18-68,18-67 +12-37,13-36 +12-64,12-46 +1-99,2-2 +61-92,61-82 +14-16,15-68 +68-83,67-77 +24-93,93-93 +33-99,32-33 +93-93,11-94 +27-37,26-37 +7-31,6-31 +1-45,2-67 +5-99,5-99 +20-21,18-22 +22-89,23-88 +53-58,53-56 +48-91,48-86 +11-11,10-12 +33-50,50-81 +11-47,7-20 +51-71,71-72 +15-89,15-88 +6-90,2-15 +7-88,18-91 +4-98,4-98 +9-19,3-19 +29-58,57-83 +16-34,15-33 +13-50,12-89 +17-60,17-17 +90-94,91-98 +52-77,52-76 +97-99,5-97 +42-86,53-76 +4-7,19-56 +23-63,2-41 +15-43,43-44 +19-23,22-97 +47-48,45-49 +31-73,32-73 +57-72,21-38 +54-97,53-96 +2-29,3-64 +53-79,13-77 +63-77,4-63 +94-94,4-95 +5-44,4-98 +5-99,4-98 +31-96,32-96 +44-89,43-90 +1-63,2-63 +31-60,8-32 +48-88,55-62 +36-85,35-85 +7-98,97-97 +3-52,4-99 +19-57,1-20 +65-96,66-97 +61-95,43-62 +4-94,93-93 +14-97,58-96 +26-46,6-47 +79-96,81-95 +30-88,30-87 +27-97,26-96 +24-88,24-25 +27-95,28-51 +22-24,23-76 +40-44,44-52 +4-37,3-38 +6-7,4-8 +22-24,16-25 +59-73,58-73 +2-14,3-40 +20-65,65-65 +58-87,58-86 +99-99,26-98 +10-17,16-91 +52-71,59-70 +3-87,2-87 +22-95,95-96 +55-55,10-54 +52-84,82-96 +5-82,81-81 +9-95,7-7 +53-88,88-90 +5-6,5-63 +11-68,10-85 +8-12,10-11 +40-92,43-49 +19-35,20-34 +44-46,45-85 +10-25,12-26 +63-85,54-80 +10-97,91-94 +41-50,40-42 +7-72,8-71 +1-15,12-92 +22-93,54-99 +82-94,30-83 +7-89,6-89 +6-69,5-7 +8-25,24-24 +8-47,8-47 +21-25,24-92 +81-81,81-86 +6-15,44-68 +82-82,34-82 +29-86,2-87 +37-54,20-57 +56-97,1-96 +65-65,6-65 +4-81,5-82 +78-85,37-78 +18-99,19-97 +31-97,34-96 +41-58,40-77 +11-96,10-97 +18-35,7-24 +5-75,3-74 +2-53,15-47 +9-17,9-85 +20-26,21-26 +23-70,67-68 +23-72,23-73 +36-81,9-93 +25-76,25-26 +77-77,46-77 +78-98,78-87 +91-91,14-92 +22-92,21-93 +3-3,3-87 +99-99,61-99 +18-28,19-29 +44-45,19-44 +17-60,11-17 +35-97,36-36 +58-58,11-58 +24-62,23-63 +18-56,55-81 +7-31,8-30 +60-61,1-65 +8-99,7-31 +2-4,5-6 +4-93,48-92 +2-87,1-98 +3-75,3-4 +1-53,53-54 +57-73,57-68 +11-60,2-61 +51-70,43-52 +4-33,3-34 +29-68,67-68 +75-86,28-71 +4-84,3-83 +12-96,51-96 +30-98,71-94 +54-62,60-62 +13-66,14-86 +14-42,12-43 +47-69,48-69 +58-89,86-96 +27-96,27-95 +6-66,6-16 +2-30,1-37 +27-91,27-38 +46-52,45-49 +9-64,8-75 +53-92,54-93 +35-91,35-72 +66-91,91-97 +46-81,49-81 +3-90,1-3 +53-54,52-56 +4-92,3-5 +42-84,42-77 +1-3,2-95 +8-73,9-90 +17-69,16-70 +9-20,2-10 +97-99,96-97 +1-86,2-91 +17-66,9-95 +9-10,9-97 +19-40,39-54 +5-94,5-91 +33-33,18-34 +2-3,2-3 +22-66,21-84 +37-90,37-81 +6-93,6-93 +64-81,65-78 +57-59,57-67 +69-94,68-68 +39-97,38-98 +74-79,71-79 +2-80,41-80 +5-91,28-89 +1-97,2-97 +24-61,25-94 +76-81,76-97 +48-56,48-49 +25-81,7-12 +42-99,41-41 +45-60,46-59 +19-85,57-84 +8-8,7-98 +14-53,13-54 +17-82,69-84 +73-86,24-90 +78-80,6-78 +2-76,3-26 +1-33,33-89 +12-48,48-75 +25-87,21-88 +22-68,22-71 +2-91,1-91 +59-79,7-60 +6-70,4-4 +47-94,27-94 +23-50,10-49 +2-85,2-83 +2-96,7-96 +21-93,22-92 +27-67,28-67 +32-38,32-33 +15-94,93-94 +36-74,36-37 +33-84,43-83 +5-98,2-2 +1-93,2-92 +37-97,42-70 +81-82,21-81 +14-94,13-15 +5-45,4-87 +44-96,45-95 +2-7,6-14 +14-73,25-77 +83-83,84-99 +13-62,21-73 +91-98,22-91 +19-96,86-93 +5-78,6-77 +3-97,4-98 +8-54,17-83 +9-94,10-10 +36-96,35-37 +8-93,7-98 +48-60,48-61 +17-97,9-18 +73-87,74-88 +19-63,19-63 +21-73,20-74 +1-89,26-89 +44-50,48-55 +43-70,70-71 +5-14,6-63 +23-82,22-94 +20-67,18-94 +36-52,47-51 +10-84,9-83 +18-96,18-71 +3-64,4-65 +4-7,6-89 +62-89,73-99 +4-92,3-5 +3-62,45-59 +9-98,10-97 +12-80,12-89 +14-15,18-85 +7-18,6-23 +14-70,15-24 +24-52,21-78 +63-92,32-93 +47-91,42-48 +16-91,91-95 +31-66,30-65 +52-91,5-91 +85-85,11-86 +22-69,68-68 +11-58,10-21 +47-76,42-47 +63-64,43-66 +17-29,4-66 +19-19,18-86 +33-70,33-70 +33-38,32-38 +3-5,4-99 +14-55,13-55 +4-48,4-4 +80-96,79-98 +99-99,5-29 +48-72,49-72 +5-91,3-92 +10-25,10-26 +9-11,10-28 +29-39,28-38 +19-55,55-56 +1-14,1-2 +21-81,21-81 +32-89,38-86 +31-79,31-39 +66-72,67-73 +3-3,2-29 +9-67,10-10 +24-96,23-25 +90-94,90-93 +91-91,7-92 +45-98,44-93 +1-76,3-75 +14-59,22-60 +12-70,4-21 +30-93,25-98 +18-30,9-19 +1-4,3-90 +9-95,9-22 +92-96,59-92 +26-67,22-25 +7-9,8-30 +74-82,82-83 +92-92,4-93 +14-76,2-63 +52-86,51-82 +11-98,10-12 +2-97,96-96 +18-91,18-99 +15-36,17-92 +14-90,13-91 +14-88,87-99 +47-92,48-92 +3-97,10-93 +9-87,80-98 +4-96,3-5 +89-99,3-89 +11-65,10-66 +4-52,52-93 +29-31,12-28 diff --git a/day04/part1.py b/day04/part1.py new file mode 100644 index 0000000..d06a207 --- /dev/null +++ b/day04/part1.py @@ -0,0 +1,78 @@ +from __future__ import annotations + +import argparse +import os.path + +import pytest + +import support + +INPUT_TXT = os.path.join(os.path.dirname(__file__), 'input.txt') + +from string import ascii_letters + + +def compute(s: str): + counter = 0 + for line in s.split('\n'): + try: + first, second = line.split(',') + except ValueError: + continue + start, end = first.split('-') + enc_start, enc_end = second.split('-') + start, end, enc_start, enc_end = int(start), int(end), int(enc_start), int(enc_end) + rg = range(start, end + 1) + enc_rg = list(range(enc_start, enc_end + 1)) + for i in rg: + if i in enc_rg: + counter += 1 + break + return counter + +def _compute(s: str): + """ + actual submission, I pasted `compute()` from part2.py to see if it + works here, and it does. + """ + counter = 0 + for line in s.split('\n'): + try: + first, second = line.split(',') + except ValueError: + continue + start, end = first.split('-') + enc_start, enc_end = second.split('-') + start, end, enc_start, enc_end = int(start), int(end), int(enc_start), int(enc_end) + if ( + (start >= enc_start and end <= enc_end) + or (enc_start >= start and enc_end <= end) + ): + counter += 1 + return counter + + + +@pytest.mark.parametrize( + ('input_s', 'expected'), + ( + ('2-8,3-7', 1), + ) +) +def test(input_s: str, expected: int) -> None: + assert compute(input_s) == expected + + +def main() -> int: + parser = argparse.ArgumentParser() + parser.add_argument('data_file', nargs='?', default=INPUT_TXT) + args = parser.parse_args() + + with open(args.data_file) as f, support.timing(): + print(compute(f.read())) + + return 0 + + +if __name__ == '__main__': + raise SystemExit(main()) diff --git a/day04/part2.py b/day04/part2.py new file mode 100644 index 0000000..fa6d813 --- /dev/null +++ b/day04/part2.py @@ -0,0 +1,58 @@ +from __future__ import annotations + +import argparse +import os.path + +import pytest + +import support + +INPUT_TXT = os.path.join(os.path.dirname(__file__), 'input.txt') + +from string import ascii_letters + + +def compute(s: str): + counter = 0 + for line in s.split('\n'): + try: + first, second = line.split(',') + except ValueError: + continue + start, end = first.split('-') + enc_start, enc_end = second.split('-') + start, end, enc_start, enc_end = int(start), int(end), int(enc_start), int(enc_end) + rg = range(start, end + 1) + enc_rg = list(range(enc_start, enc_end + 1)) + for i in rg: + if i in enc_rg: + counter += 1 + break + return counter + + + +@pytest.mark.parametrize( + ('input_s', 'expected'), + ( + ('2-8,3-7', 1), + ('2-6,4-8\n2-8,3-7', 2), + ) +) +def test(input_s: str, expected: int) -> None: + assert compute(input_s) == expected + + +def main() -> int: + parser = argparse.ArgumentParser() + parser.add_argument('data_file', nargs='?', default=INPUT_TXT) + args = parser.parse_args() + + with open(args.data_file) as f, support.timing(): + print(compute(f.read())) + + return 0 + + +if __name__ == '__main__': + raise SystemExit(main()) diff --git a/day05/Makefile b/day05/Makefile new file mode 100644 index 0000000..4d25d9a --- /dev/null +++ b/day05/Makefile @@ -0,0 +1,10 @@ +s1: + /Users/zev/Documents/repos/advent/2015/env/bin/python3.10 part1.py input.txt | aoc-submit --part 1 +s2: + /Users/zev/Documents/repos/advent/2015/env/bin/python3.10 part2.py input.txt | aoc-submit --part 2 +d: + aoc-download-input +t1: + pytest part1.py +t2: + pytest part2.py diff --git a/day05/README.md b/day05/README.md new file mode 100644 index 0000000..a29b6f5 --- /dev/null +++ b/day05/README.md @@ -0,0 +1,9 @@ +I went for a fast solution in part 1, which in retrospect I regret since the `range` and `in` approach of part2.py is easier to reason about and works for both parts. + +Another regret: I used AoC for testing instead of writing actual tests. This cost me a five-minute timeout after I made too many submissions. + +Something to research: There's probably something in Python builtins or stdlib which can make this one a really fast calculation. + +Some optimizations I added to the Makefile today, it ultimately didn't contribute much performance though: + +`make t1` and `make t2` to run tests for part 1 or 2, respectively. diff --git a/day05/TODO.md b/day05/TODO.md new file mode 100644 index 0000000..0355b7b --- /dev/null +++ b/day05/TODO.md @@ -0,0 +1,31 @@ +# How it Should Work + +```console +> today +created directory `day04`, we're ready to go! +downloaded input +opening `day04/part1.py`... +> done +testing part1.py... +sorry, the tests failed with output '...' +> done +there aren't any tests, submitting to AoC... +sorry, but 'you gave an answer too recently...' +> done +testing part1.py... +passed! +submitting to AoC +sorry, but 'your answer is incorrect.' +> done +testing part1.py +passed! +submitting to AoC +your answer is correct! +copying part1.py to part2.py +opening `day04/part2.py` +``` + +# TODO + +- [ ] possibly scrape the problem too: + - [tesseract in browser](https://towardsdatascience.com/image-to-text-ocr-with-tesseract-js-3540b420e0e7) diff --git a/day05/__init__.py b/day05/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/day05/input.txt b/day05/input.txt new file mode 100644 index 0000000..68c5587 --- /dev/null +++ b/day05/input.txt @@ -0,0 +1,511 @@ + [J] [B] [W] + [T] [W] [F] [R] [Z] + [Q] [M] [J] [R] [W] [H] + [F] [L] [P] [R] [N] [Z] [G] +[F] [M] [S] [Q] [M] [P] [S] [C] +[L] [V] [R] [V] [W] [P] [C] [P] [J] +[M] [Z] [V] [S] [S] [V] [Q] [H] [M] +[W] [B] [H] [F] [L] [F] [J] [V] [B] + 1 2 3 4 5 6 7 8 9 + +move 3 from 5 to 7 +move 2 from 8 to 9 +move 4 from 3 to 5 +move 2 from 1 to 7 +move 1 from 3 to 6 +move 2 from 1 to 7 +move 1 from 8 to 7 +move 4 from 2 to 8 +move 10 from 9 to 1 +move 6 from 6 to 2 +move 1 from 6 to 7 +move 9 from 8 to 6 +move 4 from 2 to 4 +move 2 from 4 to 1 +move 6 from 1 to 6 +move 1 from 3 to 2 +move 2 from 1 to 4 +move 2 from 4 to 3 +move 2 from 1 to 3 +move 4 from 3 to 1 +move 15 from 7 to 9 +move 4 from 5 to 9 +move 13 from 9 to 4 +move 10 from 4 to 8 +move 1 from 7 to 4 +move 6 from 9 to 5 +move 11 from 6 to 7 +move 4 from 5 to 7 +move 3 from 8 to 7 +move 4 from 2 to 4 +move 1 from 5 to 1 +move 5 from 8 to 4 +move 1 from 5 to 4 +move 10 from 7 to 1 +move 8 from 7 to 9 +move 12 from 1 to 9 +move 8 from 9 to 1 +move 2 from 6 to 9 +move 2 from 8 to 4 +move 1 from 6 to 9 +move 13 from 4 to 2 +move 13 from 4 to 2 +move 1 from 6 to 1 +move 1 from 6 to 4 +move 1 from 4 to 5 +move 14 from 1 to 8 +move 1 from 5 to 4 +move 13 from 9 to 5 +move 9 from 8 to 2 +move 8 from 2 to 1 +move 5 from 8 to 2 +move 5 from 1 to 6 +move 3 from 1 to 3 +move 1 from 4 to 8 +move 9 from 5 to 9 +move 18 from 2 to 8 +move 3 from 3 to 5 +move 2 from 6 to 4 +move 14 from 2 to 7 +move 1 from 4 to 2 +move 1 from 6 to 9 +move 1 from 2 to 5 +move 1 from 6 to 2 +move 1 from 4 to 6 +move 6 from 8 to 1 +move 2 from 6 to 9 +move 5 from 5 to 3 +move 1 from 7 to 8 +move 10 from 9 to 7 +move 13 from 8 to 5 +move 5 from 5 to 2 +move 6 from 5 to 7 +move 1 from 8 to 5 +move 5 from 5 to 9 +move 5 from 9 to 7 +move 4 from 3 to 8 +move 6 from 1 to 6 +move 4 from 2 to 4 +move 3 from 7 to 5 +move 2 from 2 to 9 +move 1 from 3 to 7 +move 29 from 7 to 9 +move 4 from 5 to 2 +move 5 from 6 to 4 +move 3 from 7 to 9 +move 3 from 8 to 6 +move 1 from 2 to 6 +move 3 from 2 to 5 +move 1 from 8 to 4 +move 1 from 5 to 9 +move 8 from 4 to 9 +move 15 from 9 to 2 +move 1 from 5 to 1 +move 10 from 9 to 4 +move 5 from 4 to 5 +move 5 from 5 to 4 +move 1 from 1 to 9 +move 1 from 4 to 3 +move 8 from 2 to 4 +move 7 from 2 to 7 +move 1 from 3 to 8 +move 1 from 5 to 6 +move 4 from 7 to 3 +move 1 from 8 to 2 +move 7 from 4 to 7 +move 11 from 9 to 7 +move 5 from 4 to 2 +move 3 from 9 to 6 +move 3 from 3 to 8 +move 4 from 2 to 4 +move 5 from 9 to 5 +move 1 from 2 to 1 +move 3 from 8 to 5 +move 2 from 9 to 1 +move 1 from 2 to 5 +move 2 from 9 to 6 +move 3 from 7 to 5 +move 7 from 4 to 1 +move 4 from 4 to 9 +move 3 from 7 to 2 +move 3 from 1 to 9 +move 1 from 2 to 3 +move 2 from 7 to 9 +move 6 from 5 to 4 +move 6 from 4 to 3 +move 5 from 5 to 1 +move 6 from 7 to 8 +move 1 from 5 to 1 +move 2 from 9 to 4 +move 1 from 4 to 3 +move 10 from 6 to 4 +move 2 from 2 to 1 +move 6 from 4 to 1 +move 5 from 8 to 3 +move 1 from 8 to 2 +move 7 from 3 to 9 +move 1 from 6 to 9 +move 2 from 7 to 3 +move 20 from 1 to 6 +move 7 from 3 to 8 +move 2 from 9 to 6 +move 1 from 2 to 3 +move 2 from 3 to 6 +move 1 from 1 to 4 +move 6 from 4 to 7 +move 5 from 8 to 3 +move 22 from 6 to 4 +move 2 from 9 to 7 +move 3 from 3 to 4 +move 6 from 4 to 2 +move 11 from 9 to 3 +move 9 from 3 to 7 +move 5 from 4 to 2 +move 5 from 7 to 2 +move 5 from 7 to 6 +move 10 from 2 to 4 +move 3 from 2 to 1 +move 1 from 6 to 3 +move 1 from 1 to 7 +move 17 from 4 to 1 +move 1 from 8 to 4 +move 2 from 7 to 5 +move 3 from 2 to 5 +move 3 from 3 to 8 +move 4 from 5 to 1 +move 3 from 3 to 7 +move 1 from 4 to 5 +move 21 from 1 to 5 +move 3 from 8 to 3 +move 4 from 7 to 5 +move 1 from 1 to 7 +move 1 from 6 to 3 +move 4 from 4 to 1 +move 1 from 8 to 1 +move 3 from 4 to 9 +move 5 from 1 to 8 +move 3 from 9 to 3 +move 5 from 6 to 1 +move 5 from 1 to 4 +move 6 from 3 to 2 +move 1 from 3 to 2 +move 3 from 8 to 1 +move 7 from 2 to 1 +move 10 from 5 to 2 +move 12 from 5 to 7 +move 2 from 8 to 3 +move 5 from 5 to 8 +move 8 from 1 to 6 +move 5 from 4 to 5 +move 3 from 8 to 6 +move 1 from 8 to 3 +move 6 from 6 to 7 +move 2 from 3 to 8 +move 3 from 2 to 1 +move 6 from 2 to 9 +move 2 from 8 to 4 +move 1 from 3 to 9 +move 1 from 8 to 6 +move 1 from 6 to 9 +move 7 from 9 to 5 +move 1 from 9 to 7 +move 1 from 4 to 6 +move 2 from 6 to 5 +move 1 from 4 to 1 +move 1 from 2 to 7 +move 5 from 1 to 2 +move 10 from 7 to 4 +move 12 from 5 to 7 +move 6 from 4 to 8 +move 2 from 5 to 6 +move 1 from 8 to 9 +move 1 from 9 to 5 +move 30 from 7 to 9 +move 4 from 8 to 4 +move 1 from 8 to 7 +move 2 from 1 to 4 +move 6 from 6 to 3 +move 1 from 4 to 1 +move 1 from 1 to 2 +move 8 from 4 to 8 +move 1 from 4 to 5 +move 2 from 5 to 6 +move 2 from 9 to 8 +move 3 from 2 to 1 +move 4 from 3 to 2 +move 1 from 6 to 4 +move 1 from 7 to 1 +move 2 from 8 to 2 +move 1 from 9 to 2 +move 2 from 3 to 2 +move 1 from 4 to 2 +move 4 from 9 to 6 +move 3 from 6 to 4 +move 21 from 9 to 8 +move 13 from 2 to 7 +move 9 from 8 to 5 +move 3 from 1 to 4 +move 14 from 7 to 2 +move 5 from 8 to 9 +move 1 from 1 to 2 +move 7 from 8 to 6 +move 2 from 8 to 2 +move 8 from 6 to 9 +move 1 from 4 to 5 +move 5 from 8 to 2 +move 4 from 5 to 9 +move 9 from 9 to 6 +move 2 from 7 to 6 +move 1 from 8 to 7 +move 9 from 6 to 4 +move 1 from 6 to 5 +move 1 from 7 to 3 +move 1 from 4 to 7 +move 1 from 7 to 2 +move 9 from 2 to 3 +move 8 from 4 to 1 +move 8 from 9 to 2 +move 2 from 6 to 5 +move 4 from 5 to 2 +move 2 from 9 to 5 +move 1 from 4 to 9 +move 10 from 3 to 7 +move 1 from 9 to 2 +move 1 from 5 to 3 +move 7 from 2 to 8 +move 7 from 1 to 5 +move 1 from 1 to 2 +move 2 from 8 to 2 +move 1 from 3 to 5 +move 2 from 8 to 6 +move 2 from 8 to 9 +move 2 from 4 to 6 +move 3 from 2 to 8 +move 3 from 6 to 7 +move 7 from 5 to 8 +move 7 from 2 to 7 +move 1 from 6 to 8 +move 5 from 2 to 7 +move 6 from 8 to 3 +move 2 from 7 to 1 +move 7 from 2 to 5 +move 1 from 3 to 5 +move 1 from 1 to 5 +move 2 from 9 to 7 +move 4 from 3 to 7 +move 2 from 4 to 6 +move 1 from 1 to 6 +move 1 from 2 to 4 +move 16 from 5 to 6 +move 1 from 4 to 9 +move 19 from 6 to 1 +move 1 from 3 to 5 +move 1 from 9 to 1 +move 1 from 8 to 5 +move 5 from 8 to 3 +move 5 from 7 to 2 +move 3 from 2 to 9 +move 5 from 1 to 7 +move 2 from 5 to 1 +move 3 from 9 to 4 +move 4 from 1 to 9 +move 2 from 2 to 8 +move 2 from 8 to 6 +move 1 from 6 to 9 +move 4 from 3 to 8 +move 4 from 8 to 3 +move 2 from 3 to 8 +move 1 from 8 to 2 +move 1 from 9 to 7 +move 10 from 1 to 7 +move 26 from 7 to 6 +move 3 from 9 to 3 +move 1 from 4 to 6 +move 2 from 1 to 4 +move 1 from 1 to 6 +move 1 from 9 to 3 +move 1 from 2 to 3 +move 4 from 4 to 9 +move 10 from 7 to 8 +move 3 from 7 to 4 +move 4 from 9 to 4 +move 4 from 4 to 7 +move 4 from 3 to 9 +move 5 from 7 to 5 +move 3 from 5 to 1 +move 3 from 9 to 8 +move 3 from 1 to 5 +move 2 from 3 to 5 +move 7 from 8 to 1 +move 7 from 8 to 9 +move 4 from 6 to 3 +move 3 from 3 to 6 +move 1 from 3 to 4 +move 2 from 4 to 1 +move 1 from 9 to 6 +move 4 from 1 to 3 +move 3 from 5 to 1 +move 1 from 5 to 2 +move 6 from 1 to 2 +move 6 from 2 to 7 +move 2 from 7 to 4 +move 1 from 2 to 6 +move 1 from 1 to 4 +move 3 from 5 to 7 +move 6 from 7 to 4 +move 1 from 9 to 3 +move 1 from 3 to 6 +move 4 from 4 to 3 +move 9 from 6 to 1 +move 10 from 1 to 6 +move 7 from 4 to 5 +move 28 from 6 to 4 +move 3 from 6 to 7 +move 3 from 3 to 8 +move 4 from 5 to 7 +move 1 from 8 to 4 +move 18 from 4 to 7 +move 8 from 7 to 6 +move 6 from 4 to 1 +move 2 from 5 to 4 +move 8 from 6 to 1 +move 2 from 8 to 9 +move 1 from 5 to 3 +move 1 from 9 to 1 +move 5 from 9 to 2 +move 2 from 9 to 3 +move 1 from 2 to 5 +move 2 from 1 to 5 +move 6 from 7 to 5 +move 1 from 6 to 4 +move 6 from 5 to 9 +move 2 from 4 to 1 +move 8 from 1 to 8 +move 4 from 9 to 7 +move 1 from 5 to 6 +move 1 from 1 to 6 +move 2 from 1 to 2 +move 1 from 9 to 7 +move 3 from 2 to 4 +move 2 from 8 to 3 +move 5 from 8 to 2 +move 4 from 2 to 5 +move 1 from 8 to 9 +move 12 from 3 to 2 +move 2 from 6 to 2 +move 12 from 2 to 4 +move 6 from 2 to 3 +move 4 from 1 to 9 +move 8 from 4 to 7 +move 3 from 3 to 4 +move 1 from 5 to 4 +move 5 from 9 to 6 +move 3 from 5 to 8 +move 1 from 9 to 1 +move 2 from 8 to 5 +move 3 from 5 to 6 +move 1 from 8 to 4 +move 4 from 7 to 8 +move 1 from 1 to 3 +move 2 from 8 to 3 +move 7 from 6 to 7 +move 1 from 3 to 7 +move 2 from 8 to 6 +move 22 from 7 to 8 +move 6 from 4 to 8 +move 5 from 8 to 6 +move 5 from 6 to 2 +move 4 from 2 to 3 +move 6 from 8 to 5 +move 4 from 4 to 7 +move 1 from 3 to 7 +move 4 from 4 to 5 +move 1 from 5 to 4 +move 2 from 6 to 5 +move 9 from 5 to 6 +move 10 from 6 to 7 +move 1 from 2 to 1 +move 3 from 4 to 8 +move 16 from 7 to 9 +move 1 from 7 to 8 +move 1 from 1 to 8 +move 1 from 8 to 3 +move 2 from 7 to 4 +move 15 from 8 to 1 +move 1 from 8 to 1 +move 4 from 8 to 4 +move 7 from 9 to 7 +move 3 from 5 to 9 +move 10 from 9 to 6 +move 2 from 9 to 2 +move 7 from 7 to 4 +move 9 from 3 to 2 +move 8 from 2 to 7 +move 1 from 8 to 4 +move 3 from 2 to 1 +move 9 from 7 to 1 +move 9 from 4 to 1 +move 2 from 7 to 5 +move 1 from 5 to 4 +move 1 from 5 to 2 +move 6 from 1 to 3 +move 16 from 1 to 2 +move 9 from 2 to 1 +move 5 from 6 to 9 +move 2 from 1 to 9 +move 1 from 2 to 5 +move 4 from 4 to 8 +move 2 from 8 to 2 +move 2 from 2 to 3 +move 17 from 1 to 2 +move 2 from 1 to 9 +move 13 from 2 to 8 +move 1 from 2 to 4 +move 11 from 8 to 3 +move 3 from 3 to 4 +move 3 from 9 to 2 +move 1 from 5 to 2 +move 1 from 9 to 3 +move 3 from 4 to 3 +move 1 from 4 to 9 +move 3 from 3 to 4 +move 1 from 8 to 7 +move 7 from 2 to 9 +move 3 from 1 to 7 +move 3 from 2 to 8 +move 3 from 7 to 9 +move 10 from 3 to 5 +move 3 from 6 to 9 +move 8 from 9 to 4 +move 1 from 2 to 1 +move 1 from 7 to 9 +move 2 from 2 to 3 +move 4 from 4 to 8 +move 1 from 6 to 2 +move 7 from 5 to 3 +move 1 from 5 to 2 +move 9 from 8 to 9 +move 12 from 3 to 8 +move 1 from 1 to 9 +move 9 from 8 to 6 +move 1 from 5 to 7 +move 1 from 5 to 4 +move 2 from 2 to 9 +move 1 from 2 to 6 +move 2 from 4 to 3 +move 9 from 4 to 8 +move 6 from 3 to 6 +move 12 from 6 to 2 +move 2 from 6 to 7 +move 8 from 8 to 3 +move 5 from 8 to 7 +move 3 from 6 to 5 +move 6 from 3 to 7 +move 6 from 7 to 6 +move 1 from 4 to 9 +move 4 from 6 to 5 +move 20 from 9 to 6 +move 4 from 9 to 8 +move 2 from 8 to 7 +move 4 from 6 to 4 +move 10 from 6 to 1 diff --git a/day05/part1.py b/day05/part1.py new file mode 100644 index 0000000..e838af5 --- /dev/null +++ b/day05/part1.py @@ -0,0 +1,92 @@ +from __future__ import annotations + +import argparse +import os.path +import re + +import pytest + +import support + +INPUT_TXT = os.path.join(os.path.dirname(__file__), 'input.txt') + + +def compute(s: str): + _stacks = [] + for _ in range(9): + _stacks.append([]) + stopped_at_idx = None + for i, line in enumerate(s.split('\n')): + if not line.strip().startswith("["): + stopped_at_idx = i + break + for idx, char in enumerate(line): + if char in "[]": + continue + elif char != " ": + if idx == 1: + stack_idx = 0 + else: + stack_idx = ((idx - 1) // 4) + _stacks[stack_idx].append(char) + stacks = [] + for st in _stacks: + stacks.append(list(reversed(st))) + + if stopped_at_idx is None: + raise Exception + for line in s.split('\n'): + if not line.strip().startswith("move"): + print(line) + continue + match = re.match(r".* ([0-9]+).*([0-9]+).*([0-9]+)", line) + quantity, fr, t = match[1], match[2], match[3] # type: ignore + print(quantity, fr, t) + fr = int(fr) - 1 + t = int(t) - 1 + print(stacks[fr], stacks[t]) + for _ in range(int(quantity)): + if not stacks[fr]: + break + stacks[t].append(stacks[fr].pop()) + print(stacks[fr], stacks[t]) + answer = '' + for stack in stacks: + if stack: + answer += stack[-1] + else: + print('appending a blank') + answer += " " + return answer + + + +@pytest.mark.parametrize( + ('input_s', 'expected'), + ((""" [D] +[N] [C] +[Z] [M] [P] + 1 2 3 + +move 1 from 2 to 1 +move 3 from 1 to 3 +move 2 from 2 to 1 +move 1 from 1 to 2""", "CMZ"), +)) +def test(input_s: str, expected: int) -> None: + assert compute(input_s) == expected + + +def main() -> int: + parser = argparse.ArgumentParser() + parser.add_argument('data_file', nargs='?', default=INPUT_TXT) + args = parser.parse_args() + + with open(args.data_file) as f, support.timing(): + print(compute(f.read())) + + return 0 + + +if __name__ == '__main__': + raise SystemExit(main()) diff --git a/day05/part2.py b/day05/part2.py new file mode 100644 index 0000000..36b66cd --- /dev/null +++ b/day05/part2.py @@ -0,0 +1,100 @@ +from __future__ import annotations + +import argparse +import os.path +import re + +import pytest + +import support + +INPUT_TXT = os.path.join(os.path.dirname(__file__), 'input.txt') + + +def compute(s: str): + _stacks = [] + for _ in range(9): + _stacks.append([]) + stopped_at_idx = None + for i, line in enumerate(s.split('\n')): + if not line.strip().startswith("["): + stopped_at_idx = i + break + for idx, char in enumerate(line): + if char in "[]": + continue + elif char != " ": + if idx == 1: + stack_idx = 0 + else: + stack_idx = ((idx - 1) // 4) + _stacks[stack_idx].append(char) + stacks = [] + for st in _stacks: + stacks.append(list(reversed(st))) + + if stopped_at_idx is None: + raise Exception + for line in s.split('\n'): + if not line.strip().startswith("move"): + print(line) + continue + match = re.match(r".* ([0-9]+).*([0-9]+).*([0-9]+)", line) + quantity, fr, t = match[1], match[2], match[3] # type: ignore + print(quantity, fr, t) + fr = int(fr) - 1 + t = int(t) - 1 + q = int(quantity) + print(stacks[fr], stacks[t]) + + if len(stacks[fr]) < q: + to_move = stacks[fr] + stacks[t] += to_move + stacks[fr] = [] + else: + to_move = stacks[fr][-q:] + stacks[t] += to_move + stacks[fr] = stacks[fr][:-q] + + print(stacks[fr], stacks[t]) + answer = '' + for stack in stacks: + if stack: + answer += stack[-1] + else: + print('appending a blank') + answer += " " + print('answer:', answer) + return answer + + + +@pytest.mark.parametrize( + ('input_s', 'expected'), + ((""" [D] +[N] [C] +[Z] [M] [P] + 1 2 3 + +move 1 from 2 to 1 +move 3 from 1 to 3 +move 2 from 2 to 1 +move 1 from 1 to 2""", "CMZ"), +)) +def test(input_s: str, expected: int) -> None: + assert compute(input_s) == expected + + +def main() -> int: + parser = argparse.ArgumentParser() + parser.add_argument('data_file', nargs='?', default=INPUT_TXT) + args = parser.parse_args() + + with open(args.data_file) as f, support.timing(): + print(compute(f.read())) + + return 0 + + +if __name__ == '__main__': + raise SystemExit(main()) diff --git a/day06/Makefile b/day06/Makefile new file mode 100644 index 0000000..b2405fa --- /dev/null +++ b/day06/Makefile @@ -0,0 +1,10 @@ +s1: + python3 part1.py submit +s2: + python3 part2.py submit +d: + python3 part1.py get_input +t1: + pytest part1.py +t2: + pytest part2.py diff --git a/day06/input.txt b/day06/input.txt new file mode 100644 index 0000000..a293ff0 --- /dev/null +++ b/day06/input.txt @@ -0,0 +1 @@ +bhzhtzzsczszsjjjzddfzdfzfjfzfbbnntnzznwzzvfvrrqmrmmdzzfqfhqhsqqpwpgwpppbtbnnstthmhrrsmmvsmmhjmjfmfsfjfnfnjjvcjjszjszjsszbznzbnzndzzmlldsdgdcddmqmfqqlcllbvllztzctzczdzttlmtlthtmhtmhmmszsllvzvdzzzsqzqbqccvfvcffzsfslfsllcglclwlvwvzzdsslggtzzgzdzmzddjljvvztttsgscsstztjztjztzvzwwthtftppnmpmmcpmmjlmjjjsfjsjppgcgwcggzffzwzbbmbrbprpqqpccfncfnffvcffsqqtzqzqwzwvzwwwbjbfbcbfblltnlnhhcthtvvzzfcfgfddlggbbshsggplglqqbrbggsvvzdvvlfvlvpvhhmggbrrnppjfjhffttfpffbdfbfvfqvvtcvvbvnnhbhhglgjgzzghhwrrtntrtwwfdfdmmcmtctftpptllzqllzflfrrgqgvgdvdfdbddprrrgccqvqnnmtmvmffpzzqggfbfnfwwqdqldqqlnqnttnbttrffnmmzwzjjtrjtrtmmqsmqmffqmfqfhhbthbhdhvdhvdvmvdmdhdshsqslldzztvvmzzdcccmbbhfhshrrrpsrrqqmdmmgdmmwdmdjdqqmcmttpgtgwgpwpprbrprhrsrllhsllprlplhppfzpffbhbccwdwbbrpbpvpqqmsspjssmbbmfmrmnrnwwgbwwbpwpjwwhqqgcqcvqccgffzpfftcffqlqjjznnlflhhlcczhzvhzhmzhmhfhnnqznntstwtggqjgjhggsvslltjlttfjjgffjzjwzzqzrrhlhzhbhphmhlmlzmzsmzmccvllgrrpbrbfbjfjttqjttdrdhhggqgddppqgpqgpgtptjptpllwccmwcmcpmcppdrrtstqqczqzvvlsltlddnvdvggcqqblqqsjqjttzhtzzszllqsqfqddqdbqddwqddfzzlczcscfsfpfdpdrpddsggcqchcfcpcssstwstwtggghvhqhzzqssjddwjwbjjsnjnfnwwglwwfnfhnnscsggzgjzzhzmmqfqsqwqrwqqqdtdcttzvvnbngbbcdbdggddnmddgzghhzgghwwbjbttlwlcctlccwwdhhrqrvrjjlglssgttpllwclwwtptwptwtvthtbhbzhbzhhrsrwwwnrwrfwfnwnhhnqqdjqjpqqwdwttzhttcdttvztzltzlzmzddrsdsfdsfftdfffmwffrjrffqrfqfsfqqqgqjggwzzrnnqfnqffdbfbtbbrpbrpbptpwttjmjjzrrhhqppdzdtdjttqwwtddjdzzmgzzhwwwdsdgssprsrgsgbbphhdpdwppnfppdqqwzzpbzzqwqpqsqhqdhqqtwwjnnmvmwvmmwwgjgzjjvcjcvcjcnjcncmmphmmvmwmwpwbbtbffhnhshgssgvgvrrbwbtbddqmqfqvvfqvqdvvdbvdbdcdfdlflmffrwwgmmttrztrrfrqrpqrrzjrjpjdpjprrnhhbhcbbcwwqlwwcssbddfrfjrfjfrjfjvvdmdtdzzlvzlzhzmhmhphchnnfqnffvccfpfbfpfqpprrmttzrzzjzmjmzjmmfvmmrzrqqdllgjlglcchssgllsbllrbrlrjlrrhhfwwsqwsstpssznzcznzqzssvtvtrrqwqvvtssgfsfhssljjnwjnjddjdggclcrrfsfhsstgtdtctfttvvsbvvbtbttcgcssjlslhlpljpppwzwnwdnngmgjjbzznwwdllrrfppshhvdhhldhdbbdbjbdjjrnjjzhzfhhsqqbqgmsbvnjsptlrsszlqfmgprvscphmqztbgtlrqvcgdzcptcqjncrdtfqnghnbmwwmcjgtjlbvqqzslgbbntrdfnvfjvfgcgngndjcspgwmpnsrqzzvzljbzlzzrwflrqqqmhsvqwbmdftnhwwzgqrlhddbbtwvbphljmstcjzvpjqwcnhlvpqvqdgvntgqzqwrlwbwvngwtqgrhznlzcvbwqmwncccjctrdzrmzjsvrmcfpjjcczhbvdfwhqvczggfmrspvprvvthvtqnsphpcsdmbrtbdqljvssdrhwjsrrlzprstpgqcbpmnpdgzgjttwcfrgjnsghmszlclgvmlsjrqfvflbnhwwphtvrnrbhdvdglcvgpzfsjpwwhtlvvdzthsrldfzhnlrblzsjjnwclqsqzgdbflhvpwcrtfbfbjcjttbjpvfgvfcswnqqwshbmqlscdzzwshfqwsvwnwzltbnrmzzhzvtwpzqcgwshpvzgtcmwrtrwctnpzbznnwqphnrgwljtrcwlqmvlndwrdrctztnmswslqmbjcmtlrmcpjvzccqszrnflqnqzttbhqlrhbmqdpscqvfgtdbnwjdcljwcbgbgjfzgrgpwqzqgbnrtpntfthhdbqmswvhnmwmszpghgjjzrbnbbfjblpstdfslmmmqfdcrhblqjqfphnldrvvfpnfrcvprjnqbzbspfpjtgqhnjbhnrwzcjvdbshhqpgrmzqpmjfmqwqvvdbddbsldwzzsrhnhsjjnvljrbwcnjrnjpmrrvfthftgptgtlpbgqffthflgftwcrqcqwqwrmrcmfrcqgmrnqjbscdcgrqlhjzthvzdgjbvpswflqcgsnlmgmvcsttsgmnqdtvwdvrndvfdcvrcwmqlmlhtrvthsndsrmnsfmdmfnpfmfhzjqmtcjzcrnsjdztztvgdtlrmbdmmstbfgpmmzthcslpvgrpgfljfgqlqhldfwvvvdvbzjtdtppbtrnqwsqztjrsjhtfrgmvsdngvsdzjgpwrldqpzdpvhljzpjvttwltdwcrhcbrgrvdrmpwvdwjchqsjfprbgtjtzggvgrgmlvvwqrjfprbbgjjqrtdfnrdffwbswbvqtqtfsrhsgrjhftqldhmcnmsnfflmdrzqdjmbqqgqsttdmtrrvfsjnccnhcpcvqtrzdjzrpwswmjvvgsgwvnmdgqwlctrlhqnsmczbwsjhmtgvdcgsndzlstcwchcztqqbtdwfvlljdvdlzljslgnzpmqvzfcvqhdzvgchffqgfwrnmwqzwgbzblpmvddlvnhglrhdnwzqwztzgjczjpwcjwmpnrnrhncfjfggrbphrjztwtfqmfjlwfhnqfftfghbnvtwgtmdzzrdrtmfrwhrrbhzmcllsgqzwzzqtgdggvzptvtdcpzmtmsfcfbjtzlbdrwhdbtdhhrgggmddnzsvjwgcdcqfppqwphfvlhmgqsznlhmgpnjvcvrwwppnphchgsrhjwjcpjggsrcwrvnllfgrmjltfzwhmbqwpwwzmrtlqcprrqztcgnghcbvzrbfptjmhtdcfhhffdbrswqpnpppnpqwtflrrmqgjzctmmvvvwzllbsfdvpqjtmvpjcpmjztscsgbdznfgcmtjzdqzwqrsvstnnvddcstzqjtnbsnlptpmbmfqmhppgnjrffqrtchgptbmwlwbwbcqqfngpbwtwdmlmdstmqwcwjtbwbbbhghgptmvhfmvqfvpwqzwnbjdhpwlgjgvprdjbnlzhnllssbpvzfzspwsscfpqtpdvtzvqncfrfrgddsdglqvpblmpcczlqfdmwzmgvrljhqtcglcvfhbdwhbttqqrjbqwhsrhrbjwmtqwqddvdggdwfsmnpbpvvgsqnvvrqntwmbzdnqpmmqtbnlsbmslpfmqjtgvbddhwvlvjtlrhqdpfnjwtbhwjwdrpgctbbrdqvbbnvgqwngrhqfvwzmlqtmhfqphnmczlbdpnbmpvwrsjbcnjnvcfgnsvlhpzdgdzgvfbgwdcrswznrggnghzssdwqvvlwftqhbnwdvghhvjlqqmcnqmvbwhrrnsswlwmwbsmpcpdzzgmcmqnzpvjpzqbwcsgdhqtqhcpbtqftvscmntsbdcbrndvlfhprpblzbjcpqhfljtvnvtgvrcgqbsgl diff --git a/day06/part1.py b/day06/part1.py new file mode 100644 index 0000000..7930578 --- /dev/null +++ b/day06/part1.py @@ -0,0 +1,165 @@ +from __future__ import annotations + +from collections import deque +import os.path +import pathlib as pl +import re +import sys +import time +import typing as t +import urllib.error +import urllib.parse +import urllib.request + +import pytest + +INPUT_TXT = os.path.join(os.path.dirname(__file__), 'input.txt') + + +def compute(s: str): + four_window = deque(maxlen=4) + for idx, char in enumerate(s): + if char in four_window: + four_window.clear() + elif len(four_window) == 3: + return idx + four_window.append(char) + raise Exception('no answer') + + + +@pytest.mark.parametrize( + ('input_s', 'expected'), + (("mjqjpqmgbljsphdztnvjfqwrcgsmlb", 7)) +) + +#### HELPERS + +def test(input_s: str, expected: int) -> None: + assert compute(input_s) == expected + + +def main() -> None: + print(compute(pl.Path("input.txt").read_text())) + + +HERE = os.path.dirname(os.path.abspath(__file__)) + + +def _get_cookie_headers() -> dict[str, str]: + with open(os.path.join(HERE, '../.env')) as f: + contents = f.read().strip() + return {'Cookie': contents} + + +def get_input(year: int, day: int) -> str: + url = f'https://adventofcode.com/{year}/day/{day}/input' + req = urllib.request.Request(url, headers=_get_cookie_headers()) + return urllib.request.urlopen(req).read().decode() + + +def get_year_day() -> tuple[int, int]: + cwd = os.getcwd() # type: ignore + day_s = os.path.basename(cwd) + year_s = os.path.basename(os.path.dirname(cwd)) + + if not day_s.startswith('day') or not year_s.startswith('20'): + raise AssertionError(f'unexpected working dir: {cwd}') + + return int(year_s), int(day_s[len('day'):]) + + +def download_input() -> int: + year, day = get_year_day() + + for _ in range(5): + try: + s = get_input(year, day) + except urllib.error.URLError as e: + print(f'zzz: not ready yet: {e}') + time.sleep(1) + else: + break + else: + raise SystemExit('timed out after attempting many times') + + with open('input.txt', 'w') as f: + f.write(s) + inputs = s + if '\n' in inputs.strip(): + print('splitting') + inputs = inputs.split('\n') + print(inputs[0]) + if inputs[0].isnumeric(): + print('ints') + inputs = list(map(int, inputs)) + inputs = str(inputs).replace("'", '"') + + lines = s.splitlines() + if len(lines) > 10: + for line in lines[:10]: + print(line) + print('...') + else: + print(lines[0][:80]) + print('...') + + return 0 + + +TOO_QUICK = re.compile('You gave an answer too recently.*to wait.') +WRONG = re.compile(r"That's not the right answer.*?\.") +RIGHT = "That's the right answer!" +ALREADY_DONE = re.compile(r"You don't seem to be solving.*\?") + + +def _post_answer(year: int, day: int, part: int, answer: int) -> str: + params = urllib.parse.urlencode({'level': part, 'answer': answer}) + req = urllib.request.Request( + f'https://adventofcode.com/{year}/day/{day}/answer', + method='POST', + data=params.encode(), + headers=_get_cookie_headers(), + ) + resp = urllib.request.urlopen(req) + + return resp.read().decode() + + +def submit_solution() -> int: + year, day = get_year_day() + part = get_part() + answer = compute(pl.Path("input.txt").read_text()) + + print(f'answer: {answer}') + + contents = _post_answer(year=year, day=day, part=part, answer=answer) + + for error_regex in (WRONG, TOO_QUICK, ALREADY_DONE): + error_match = error_regex.search(contents) + if error_match: + print(f'\033[41m{error_match[0]}\033[m') + return 1 + + if RIGHT in contents: + print(RIGHT) + return 0 + else: + # unexpected output? + print(contents) + return 1 + + +def get_part() -> t.Literal[1, 2]: + if __file__.endswith("2.py"): + return 2 + return 1 + + +if __name__ == '__main__': + if sys.argv[1] == "get_input": + print('getting input data...') + download_input() + elif sys.argv[1] == "submit": + submit_solution() + raise SystemExit(main()) diff --git a/day06/part2.py b/day06/part2.py new file mode 100644 index 0000000..64488fa --- /dev/null +++ b/day06/part2.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +import argparse +import os.path +from collections import deque + +import pytest + +import support + +INPUT_TXT = os.path.join(os.path.dirname(__file__), 'input.txt') + + +def compute(s: str): + four_window = deque(maxlen=14) + for idx, char in enumerate(s): + if char in four_window: + four_window.clear() + elif len(four_window) == 13: + return idx + four_window.append(char) + raise Exception('no answer') + + + +@pytest.mark.parametrize( + ('input_s', 'expected'), + (("mjqjpqmgbljsphdztnvjfqwrcgsmlb", 7)) +) + +def test(input_s: str, expected: int) -> None: + assert compute(input_s) == expected + + +def main() -> int: + parser = argparse.ArgumentParser() + parser.add_argument('data_file', nargs='?', default=INPUT_TXT) + args = parser.parse_args() + + with open(args.data_file) as f, support.timing(): + print(compute(f.read())) + + return 0 + + +if __name__ == '__main__': + raise SystemExit(main()) diff --git a/make_new_day.py b/make_new_day.py new file mode 100644 index 0000000..7814a7b --- /dev/null +++ b/make_new_day.py @@ -0,0 +1,28 @@ +import pathlib as pl +import subprocess as sp + + +def main(): + most_recent_day = get_most_recent_day() + sp.call(shell=True, args=f"cp -r day{most_recent_day:02} day{most_recent_day + 1:02}") + sp.call(shell=True, args=f"rm day{most_recent_day + 1:02}/part2.py") + sp.call(shell=True, args=f"cd day{most_recent_day + 1:02}/ && make d") + + +def get_most_recent_day() -> int: + most_recent = None + for item in pl.Path().iterdir(): + if item.is_dir() and not item.name.startswith('.') and not item.name.startswith('_'): + day_num_str = item.name.split("day")[-1] + if day_num_str.startswith('0'): + day_num_str = day_num_str[-1] + day_num = int(day_num_str) + if most_recent is None or day_num > most_recent: + most_recent = day_num + if most_recent is None: + raise Exception + return most_recent + + +if __name__ == "__main__": + main()