From 4547803969d66f835fda34b7919b1c0aaea8e2af Mon Sep 17 00:00:00 2001 From: Parnic Date: Wed, 22 Nov 2023 15:06:15 -0600 Subject: [PATCH] Initial commit, prep --- .gitignore | 6 + .../.idea/.gitignore | 10 + .idea/.idea.advent-of-code-2023/.idea/.name | 1 + .../.idea/encodings.xml | 4 + .../.idea/indexLayout.xml | 8 + .idea/.idea.advent-of-code-2023/.idea/vcs.xml | 6 + GlobalSuppressions.cs | 8 + Properties/launchSettings.json | 32 + README.md | 3 + advent-of-code-2023.csproj | 36 + advent-of-code-2023.sln | 25 + global.json | 7 + inputs/01.txt | 2253 +++++++++++++++++ inputs/01a.txt | 14 + src/01.cs | 23 + src/Day.cs | 65 + src/Extensions.cs | 41 + src/Logger.cs | 72 + src/Template.cs | 23 + src/Timer.cs | 48 + src/Util/Bisect.cs | 49 + src/Util/Combinatorics.cs | 39 + src/Util/Math.cs | 65 + src/Util/Parsing.cs | 91 + src/Util/Testing.cs | 35 + src/Util/Vec2.cs | 162 ++ src/Util/Vec3.cs | 171 ++ src/main.cs | 78 + 28 files changed, 3375 insertions(+) create mode 100644 .gitignore create mode 100644 .idea/.idea.advent-of-code-2023/.idea/.gitignore create mode 100644 .idea/.idea.advent-of-code-2023/.idea/.name create mode 100644 .idea/.idea.advent-of-code-2023/.idea/encodings.xml create mode 100644 .idea/.idea.advent-of-code-2023/.idea/indexLayout.xml create mode 100644 .idea/.idea.advent-of-code-2023/.idea/vcs.xml create mode 100644 GlobalSuppressions.cs create mode 100644 Properties/launchSettings.json create mode 100644 README.md create mode 100644 advent-of-code-2023.csproj create mode 100644 advent-of-code-2023.sln create mode 100644 global.json create mode 100644 inputs/01.txt create mode 100644 inputs/01a.txt create mode 100644 src/01.cs create mode 100644 src/Day.cs create mode 100644 src/Extensions.cs create mode 100644 src/Logger.cs create mode 100644 src/Template.cs create mode 100644 src/Timer.cs create mode 100644 src/Util/Bisect.cs create mode 100644 src/Util/Combinatorics.cs create mode 100644 src/Util/Math.cs create mode 100644 src/Util/Parsing.cs create mode 100644 src/Util/Testing.cs create mode 100644 src/Util/Vec2.cs create mode 100644 src/Util/Vec3.cs create mode 100644 src/main.cs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..07d28ef --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +/target +/.vs/ +*.user +/bin/ +/obj/ +*.exe diff --git a/.idea/.idea.advent-of-code-2023/.idea/.gitignore b/.idea/.idea.advent-of-code-2023/.idea/.gitignore new file mode 100644 index 0000000..ffb8a9e --- /dev/null +++ b/.idea/.idea.advent-of-code-2023/.idea/.gitignore @@ -0,0 +1,10 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Rider ignored files +/.idea.advent-of-code-2023.iml +/projectSettingsUpdater.xml +/modules.xml +/contentModel.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/.idea/.idea.advent-of-code-2023/.idea/.name b/.idea/.idea.advent-of-code-2023/.idea/.name new file mode 100644 index 0000000..d144c14 --- /dev/null +++ b/.idea/.idea.advent-of-code-2023/.idea/.name @@ -0,0 +1 @@ +advent-of-code-2023 \ No newline at end of file diff --git a/.idea/.idea.advent-of-code-2023/.idea/encodings.xml b/.idea/.idea.advent-of-code-2023/.idea/encodings.xml new file mode 100644 index 0000000..df87cf9 --- /dev/null +++ b/.idea/.idea.advent-of-code-2023/.idea/encodings.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/.idea.advent-of-code-2023/.idea/indexLayout.xml b/.idea/.idea.advent-of-code-2023/.idea/indexLayout.xml new file mode 100644 index 0000000..7b08163 --- /dev/null +++ b/.idea/.idea.advent-of-code-2023/.idea/indexLayout.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/.idea.advent-of-code-2023/.idea/vcs.xml b/.idea/.idea.advent-of-code-2023/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/.idea.advent-of-code-2023/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/GlobalSuppressions.cs b/GlobalSuppressions.cs new file mode 100644 index 0000000..97e9ae3 --- /dev/null +++ b/GlobalSuppressions.cs @@ -0,0 +1,8 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("CodeQuality", "IDE0052:Remove unread private members", Justification = "", Scope = "member", Target = "~F:aoc2023.DayTemplate.lines")] diff --git a/Properties/launchSettings.json b/Properties/launchSettings.json new file mode 100644 index 0000000..68ad4d8 --- /dev/null +++ b/Properties/launchSettings.json @@ -0,0 +1,32 @@ +{ + "profiles": { + "all days": { + "commandName": "Project", + "commandLineArgs": "all" + }, + "current day": { + "commandName": "Project", + "commandLineArgs": "" + }, + "current day part 1": { + "commandName": "Project", + "commandLineArgs": "-part1" + }, + "current day part 2": { + "commandName": "Project", + "commandLineArgs": "-part2" + }, + "all days part 1": { + "commandName": "Project", + "commandLineArgs": "all -part1" + }, + "all days part 2": { + "commandName": "Project", + "commandLineArgs": "all -part2" + }, + "specific day": { + "commandName": "Project", + "commandLineArgs": "1" + } + } +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..c483333 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# Advent of Code 2023 + +My solutions to [Advent of Code 2023](https://adventofcode.com/2023). diff --git a/advent-of-code-2023.csproj b/advent-of-code-2023.csproj new file mode 100644 index 0000000..9be92fe --- /dev/null +++ b/advent-of-code-2023.csproj @@ -0,0 +1,36 @@ + + + + Exe + net8.0 + aoc2023 + enable + enable + False + True + latest + + + + 9999 + True + 1701;1702;8981 + + + + 9999 + True + 1701;1702;8981 + + + + + + + + + + + + + diff --git a/advent-of-code-2023.sln b/advent-of-code-2023.sln new file mode 100644 index 0000000..6082be5 --- /dev/null +++ b/advent-of-code-2023.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "advent-of-code-2023", "advent-of-code-2023.csproj", "{1B54D933-507B-4F44-9BE3-F1794B593AF7}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1B54D933-507B-4F44-9BE3-F1794B593AF7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1B54D933-507B-4F44-9BE3-F1794B593AF7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1B54D933-507B-4F44-9BE3-F1794B593AF7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1B54D933-507B-4F44-9BE3-F1794B593AF7}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {17D280F0-AD9F-481E-8687-28AAB4A54437} + EndGlobalSection +EndGlobal diff --git a/global.json b/global.json new file mode 100644 index 0000000..dad2db5 --- /dev/null +++ b/global.json @@ -0,0 +1,7 @@ +{ + "sdk": { + "version": "8.0.0", + "rollForward": "latestMajor", + "allowPrerelease": true + } +} \ No newline at end of file diff --git a/inputs/01.txt b/inputs/01.txt new file mode 100644 index 0000000..621c20a --- /dev/null +++ b/inputs/01.txt @@ -0,0 +1,2253 @@ +13399 +13677 +11945 +9861 +6484 +4257 + +6616 +7349 +7758 +1591 +6068 +9217 +6924 +6766 + +10040 +9088 +11305 +5867 +10766 +9996 +11092 + +1320 +4921 +2338 +1351 +3462 +5916 +3124 +1416 +3655 +4886 +1135 +5171 +5020 +5099 +4785 + +1702 +5083 +3852 +3361 +2505 +3767 +1069 +3564 +3189 +5950 +2250 +2053 +1639 +1430 +4586 + +4135 +7033 +4649 +3126 +1136 +1435 +3825 +2205 +1259 +5473 +1803 +6406 + +2466 +30094 + +3122 +2983 +5988 +4214 +5278 +1974 +7109 +2419 +3777 +8299 + +10191 +6122 +7298 +7855 +8666 +4777 +6833 +8862 + +6100 +5332 +1908 +2796 +1818 +4657 +1650 +5560 +8447 +8619 + +9547 +1354 +1561 +2943 +2547 +9313 +9649 + +1323 +1200 +2514 +1412 +1381 +2310 +6201 +3257 +1747 +1295 +2507 +5594 +6010 +3422 + +1995 +3514 +8434 +1625 +2257 +3551 +6881 + +12256 +1829 +11123 +18829 + +11790 +1786 +13935 +10088 +3486 +2981 + +5046 +1306 +4328 +7100 +6000 +6287 +3624 +6521 +3952 +3107 +3846 +2762 + +21245 +8245 + +14395 +8107 +4730 +15633 + +1648 +2062 +4574 +2446 +5471 +3973 +5319 +1370 +4113 +1784 +5596 +3336 +4557 +5690 +4259 + +9587 +3062 +5611 +10487 +2759 + +69383 + +4683 +4950 +1709 +6063 +2338 +4583 +4749 +6431 +4269 +1193 +6012 +5525 +2704 +2462 + +1627 +7447 +8071 +6915 +7021 +7778 +6861 +4647 +4006 +3953 + +1866 +9649 + +10777 +2179 +5406 +1772 +3472 +8632 + +5609 +7270 +9122 +4723 +8155 +3113 +6348 +6468 + +5029 +3416 +7531 +8764 +9506 +2104 +7992 +9329 +2530 + +36312 +11422 + +5790 +3655 +2172 +6254 +11150 +1624 +1014 + +6789 +2406 +6639 +4712 +4219 +2880 +5426 +6339 +1460 +1188 +5297 +4006 +2118 + +3351 +1304 +5559 +3742 +4749 +3648 +5671 +4213 +4047 +1243 +1674 +1943 +4974 +3576 +2816 + +4949 +6136 +6448 +1652 +2764 +6968 +5423 +3887 +6863 +3628 +4183 + +2857 +5671 +3486 +4910 +2913 +6441 +5863 +3306 +6473 +2428 +2509 +1188 +3289 +4418 + +2509 +8521 +2190 +8998 +7303 +5667 + +3486 +8687 +2976 +5155 +1013 +9599 +8559 + +9018 +10121 +9235 +5724 +10350 + +2389 +9061 +8031 +6711 +6046 +3058 +1890 +6047 +7664 + +1286 +1915 +6597 + +6012 +6146 +9585 +12335 +3708 +7652 + +4501 +3470 +3260 +6125 +3718 +3379 +5225 +4673 +5943 +1010 +2057 +3389 +2009 + +4640 +2437 +4673 +2628 +5333 +7027 +8001 +7678 +4903 +7670 +1898 + +47670 + +3884 +23968 +11759 + +4154 +5214 +2482 +4226 +3115 +2272 +1209 +2525 +2985 +3399 +3140 +4385 +1291 +3911 + +15947 +12913 +12250 + +7196 +3574 +6499 +2127 +4295 +6611 +3292 +6542 +1280 +4757 +6430 +7364 + +36842 +21414 + +15106 +26273 + +2751 +1089 +2380 +3818 +1737 +1247 +3897 +1466 +3772 +3890 +4032 +6280 +5202 +3879 + +4406 +7919 +7174 +7182 +2076 +4281 +9077 +1814 +5768 + +4183 +5280 +5978 +3859 +1915 +2297 +1478 +3486 +2438 +4829 +2279 +5057 +2625 +5242 +2532 + +1699 +2463 +5703 +5850 +6899 +2344 +7855 +6715 +6421 +5289 +3702 + +11196 +4585 +9888 +10474 +10927 +9486 +1240 + +9145 +35500 + +9017 +8861 +1486 +5209 +9027 +7222 +8914 +8981 + +10200 +6668 +9301 +4127 +9401 +5308 +7425 +4684 + +7333 +10840 +14603 +10690 + +15280 +12623 + +2628 +4448 +6702 +5674 +4786 +1955 +5817 +7391 + +2930 +5391 +1057 +5093 +9249 +5111 +8526 + +11978 +1172 +12728 +10126 +14320 + +9024 +10561 +11219 +10949 +9775 +1630 +5280 + +2785 +6174 +1854 +1905 +6071 +2125 +5350 +1186 +3905 +6166 +2533 +4059 +6731 + +9855 +3487 +3393 +1922 +3413 +10109 +5879 +1927 + +24634 +17427 + +6916 +5891 +4324 +4270 +1627 +3428 +3616 +7358 + +1720 +7552 +2489 +7386 +2502 +5020 +8134 +6329 +1752 +3651 + +2666 +4269 +5480 +3812 +1161 +4880 +2090 +1374 +4834 +4310 + +7381 +7578 +10690 +9863 + +4168 +6628 +8779 +4512 +9607 +13236 + +8983 +7035 + +5321 +6790 +7229 +4435 +4513 +1969 +4220 +6666 +1310 +5702 +2815 +3337 + +8165 +8740 +12582 +7713 + +6807 +7574 +2110 +8248 +3745 +8562 +4020 +4169 +1765 +4891 + +17008 +3541 +13728 +10051 + +9546 +3634 +11918 +10456 +6942 +8063 + +8529 +13227 +7794 +1031 +4572 +11405 + +4153 +6659 +22281 + +11515 +2370 + +5548 +1377 +1211 +6916 +1775 +6326 +4643 +5420 +2426 +1870 +6828 +4954 +4020 + +17677 +4591 +11515 + +27640 + +1151 +2701 +3155 +4768 +5921 +1581 +2137 +4733 +5815 +4884 +2760 +2365 +5740 +5709 +4972 + +8728 +6887 +3823 +2605 +5475 +3860 +6041 +6430 +7326 +1646 + +4335 +2773 +5938 +2121 +4260 +6369 +6997 +3884 +4772 +1516 +2081 + +6213 +8805 +7238 +5345 +1192 +4939 +2806 +7313 + +4753 +6108 +7647 +3770 +1151 +3026 +7908 +4970 +7434 +7037 +2897 + +5302 +9296 +11044 +7970 +13693 + +7211 +1990 +3859 +6882 +3344 +4598 +2233 +2877 +2708 +3417 +6936 +2253 + +6373 +6764 +3884 +7391 +5533 +1137 +2496 +7434 +5125 +3866 +1692 +1925 + +4935 +6462 +6626 +2070 +1478 +6686 +4058 +2785 +1455 +3868 + +9644 +4807 +8557 +9675 +3245 +8615 +2544 + +4673 +6408 +7255 +2955 +8642 +8242 +6319 +4034 +1881 + +4863 +3401 +1929 +7349 +2101 +3531 +6030 +1829 +2810 +6337 +2740 +3333 + +2544 +3546 +4223 +3984 +5038 +3259 +3726 +6850 +6201 +2285 +2743 +2805 + +2831 +5952 +4857 +5209 +3788 +7752 +1897 +5149 +1566 +5627 +1744 + +13339 +25673 + +6041 +5270 +3150 +5930 +3880 +7634 +4617 +3736 +1598 +3545 + +12877 +3897 +16515 + +8603 +11316 +15009 +14921 +11366 + +29818 + +6943 +6084 +3655 +2357 +6786 +4932 +4144 +1856 +6735 +5396 +1969 +3564 +6248 + +21889 +22636 +7127 + +5436 +2129 +3427 +4028 +1375 +5428 +3513 +2017 +2241 +2350 +4854 +4469 +6433 +4620 + +8399 +5055 +7440 +1229 +5012 +8573 +8127 + +6239 +5302 +1102 +3281 +5757 +5335 +4485 +4455 +4786 +3304 +2231 +1380 +3369 +1580 + +7307 +4830 +3948 +3827 +1887 +4315 +7452 +4969 +5245 +4550 +7218 +2174 + +7447 +1081 +4264 +7055 +3586 +5229 +7455 +6934 +6149 +3960 + +15053 +15764 +7760 +4107 + +3289 +4370 +9653 +10131 +7939 +7051 +9606 +8231 + +9300 +8135 +7629 +9080 +3896 +1975 +8696 +1182 + +3985 +4089 +4921 +5219 +6964 +6433 +6509 +4185 +1005 +1026 +7124 +2661 + +6051 +14787 +7797 +15612 +10055 + +4012 +4017 +2304 +2605 +5743 +1403 +1125 +8710 +7720 +8718 + +6678 +4366 +4875 +6185 +3490 +1883 +3966 +1955 +6868 +2049 +3847 +2604 +5276 + +3260 +5099 +1168 +4772 +6425 +2118 +4669 +2970 +2545 +2870 +2477 +3117 +5656 +1638 + +3476 +16997 +3993 + +1125 +1370 +4944 +8135 +3965 +4389 +9460 +3168 +1910 + +2953 +1838 +3452 +7390 +5918 +6095 +6666 +7163 +6031 +3723 + +7718 +1141 +1675 +8446 +5294 + +5377 +6680 +7310 +6375 +5910 +2649 +9240 + +7748 +6530 +10511 +12346 +9936 +1147 + +5383 +2504 +2837 +4482 +2089 +5223 +5901 +2419 +2722 +1275 +5022 +4864 +1186 +3471 + +1424 +4107 +5138 +6033 +1772 +4181 +3155 +1846 +6531 +6357 +3427 +6064 + +6840 +12459 +10532 +13685 +7208 + +10299 +9237 +1345 +5427 +7106 +2016 +1041 +7238 + +3221 +8456 +3885 +7423 +6113 +4968 +9018 +5032 +6529 + +33934 +7098 + +7112 +24553 + +11885 +11364 +7529 +7103 +8676 +6579 +3688 + +25617 +10321 + +4047 +3253 +1844 +2799 +1668 +2965 +4873 +6097 +6295 +6440 +5524 +2244 +5140 +1709 + +2615 +2931 +3283 +6939 +4277 +2219 +6990 +6804 +6249 +5762 +1461 +1084 + +32423 +27423 + +14517 +13142 +10941 +19562 + +5455 +1050 +5920 +5358 +1310 +4716 +3229 +1832 +4729 +1023 +3679 +2541 +3880 +1570 +3417 + +16181 +14620 +16387 +14881 +13553 + +5812 +2876 +4562 +3768 +3935 +5042 +7771 +6679 +7969 +4621 +7996 + +21785 + +2879 +3483 +14624 +15533 + +3101 +1823 +3319 +1134 +5269 +2554 +1437 +6490 +1859 +5525 +1183 +7439 + +5209 +6916 +5888 +1564 +5739 +6298 +4936 +5691 +3928 +4678 +4320 +1645 + +2079 +4168 +3031 +2456 +5446 +2338 +1479 +2522 +2715 +1725 +1596 +5845 +5028 +1472 +4262 + +26049 +35356 + +7064 +5479 +7564 +6219 +1482 +3370 +2480 +6777 +2460 +4600 +1526 + +58980 + +6251 +4189 +4778 +4814 +5817 +1498 +1721 +2071 +1297 +3638 +4299 +6097 +1840 +5523 + +6232 +2066 +5782 +6549 +2873 +3707 +1461 +3857 +7477 + +10217 +4464 +7487 +5948 +2641 +6622 +5401 +3488 + +39956 + +4731 +4717 +3048 +1349 +1819 +2364 +3993 +4572 +4118 +3673 +2932 +3557 +1818 +4040 +1809 + +7128 +2747 +10012 +9847 +11104 + +5461 +8787 +11013 +2435 +7903 +6058 +9698 + +6006 +2230 +1588 +3453 +1979 +4157 +4378 +2516 +3326 +4336 +5900 +4330 +3758 +1876 + +6303 +1498 +5453 +3870 +6501 +7204 +7517 +4713 +6341 +2922 + +7334 +4897 +4402 +10953 +11054 +10268 +9793 + +4308 +2009 +2882 +6288 +2014 +6973 +5200 +5629 +1899 +5681 +4634 +2955 + +64804 + +2857 +3134 +5935 +4192 +3976 +3585 +2199 +4054 +4975 +3372 +1872 +4617 +1449 +2854 +1817 + +25804 +30702 + +3722 +15874 +21786 + +3532 +2397 +6481 +6355 +3696 +6585 +6740 +6653 +1094 +3088 +3531 + +5927 +6252 +1132 +5256 +2514 +6460 +3890 +5604 +5112 +2472 +2584 +6801 +6849 + +10325 +4424 +2601 +3731 +1337 +2744 +9597 +7075 + +8526 +2577 +13053 +18958 + +4560 +2559 +1153 +4408 +4988 +5067 +5099 +2303 +5451 +5604 +2316 +3957 +4706 +1424 + +9698 +14099 +2964 +11611 +6559 + +33997 +17918 + +3078 +10535 +5480 +8484 + +9256 +15323 +22521 + +6174 +1290 + +2650 +3963 +5043 +2957 +2425 +1608 +5621 +3002 +4820 +7220 +5857 +2229 + +1787 +9599 +6118 +5536 +10061 +4869 +7507 +10471 + +6642 +9476 +8827 +1134 +8236 +3198 +9233 +1183 +2111 + +2519 +13308 +4466 +7787 +11427 +10148 + +2051 +8362 +3560 +8921 +11983 +10986 + +17512 +16150 +16427 +4874 + +1907 +4166 +3506 +3711 +6450 +1079 +6463 +1540 +3003 +1552 +2365 +2677 +6334 + +5683 +5447 +7822 +1999 +5990 +3230 +6628 +8877 + +4759 +3993 +1209 +6762 +3003 +6471 +4859 +4760 +1740 +4548 +2611 +4958 +2878 + +3511 +5142 +2343 +6232 +1655 +7021 +1258 +6838 +6246 +3258 +2833 +5692 + +14573 +6206 +7184 + +12569 +12014 +8487 + +5170 +3993 +2230 +8236 +1047 +2335 +7772 +10473 + +6108 +6449 +1413 +6964 +3161 +6252 +2130 +2719 +5420 +7277 + +1583 +8946 +17657 +13041 + +4422 +2025 +6174 +5449 +3686 +2354 +1209 +4111 +4326 +5606 +2071 +4023 +2194 +1317 + +4962 +7063 +5352 +4226 +2665 +3288 +6487 +4746 +1582 +3126 +5662 +6864 + +19194 +18115 +9773 +13571 + +3436 +3246 +1528 +2100 +5781 +2942 +1985 +3354 +5996 +6033 +4556 +4816 +3445 +5674 + +7953 +1275 +11734 +3295 +8462 +12028 +10019 + +1766 +2223 +3111 +3804 +3618 +4227 +2342 +2235 +3909 +2615 +4193 +2296 + +2843 +1898 +4501 +3483 +6084 +5807 +2422 +5786 +4145 +2572 +5803 +2697 +3218 +2038 + +11871 +1625 +13110 +12275 +12224 +3092 + +8174 +8230 +16977 + +4156 +3989 +4409 +2022 +4922 +5252 +3871 +5072 +4632 +5995 +1056 +4716 +3767 +5414 +1228 + +1282 +6053 +3736 +2202 +10695 +6392 +1384 +7369 + +28681 +29246 + +15208 +21904 +5766 + +46708 + +1735 +2394 +6503 +2545 +5642 +1806 +1340 +4804 +5163 +2480 +1842 +5795 +6230 + +5446 +4579 +4336 +1438 +3998 +2294 +3765 +5777 +4731 +1789 +3080 +5658 +6020 +2542 +3306 + +11770 +7451 +8351 +7333 + +25818 + +23933 +30654 + +8503 +3608 +18443 + +1571 +2813 +4847 +5863 +3118 +5888 +5529 +2732 +3260 +6378 +2254 +5451 +3926 +1217 + +5575 +12012 +8351 +6175 +4427 +5625 +9866 + +5468 +12325 +21005 + +5021 +3035 +3699 +1104 +6148 +6925 +6800 +4144 +4039 +5334 +3422 +3349 +2141 + +18504 +6184 +17915 +17015 + +2611 +3005 +2768 +2554 +5186 +5515 +4370 +4778 +2033 +4594 +4747 +5050 +6011 +1241 +3687 + +3572 +2053 +3035 +1019 +4649 +6236 +3675 +1697 +1756 +1384 +6392 +5508 +4879 +2579 + +17516 +1817 +4564 + +13428 +11868 + +2268 +3943 +1945 +4773 +1588 +3347 +2407 +5519 +4959 +2050 +1151 +5578 +3798 +3568 + +13729 + +2625 +13582 +7466 +6119 +6529 +8200 + +5149 +1177 +5792 +7468 +5574 +6245 +5567 +2265 +4336 +7321 +1343 +5623 + +3722 +8530 +2506 +5780 +5469 +6498 +7749 +2505 + +22983 +5225 +23416 + +12172 + +7005 +2913 +5003 +4441 +8602 +4818 +4073 +7066 + +2419 +3295 +4377 +5033 +4805 +3757 +1084 +4820 +2652 +4324 +3036 +4980 +1027 + +4367 +1801 +6250 +7051 +3410 +5676 +3559 +3589 +5903 +4154 +1524 +5197 + +6557 +4333 +4119 +5285 +4462 +6582 +6615 +5425 +6027 + +2623 +3519 +4234 +2637 +3220 +2879 +3305 +4309 +2591 +4333 +1030 +2778 +2065 +6071 +2426 + +8003 +2935 + +16146 +2907 +25872 + +2523 +4191 +3738 +5966 +3177 +4487 +4176 +4140 +3472 +1368 +3634 +4151 +3101 +3554 +1097 + +8706 +7566 +2050 +5536 +1457 +3515 +4303 +9118 + +2406 +1427 +5485 +14192 + +6581 +5469 +6933 +5186 +4634 +2457 +8450 + +6198 +10223 +9913 +1278 +10083 +10253 +8975 +8519 + +54888 + +1972 +4402 +4773 +5630 +5896 +6420 +1553 +4579 +1803 +1853 +4043 +5563 +2463 + +5240 +4200 +2061 +3277 +1346 +2627 +2714 +4837 +4338 +2206 +2051 +5209 +1106 +4793 +3229 + +6183 +4027 +4577 +4944 +1637 +4339 +2064 +4443 +1125 +2905 +2998 +5512 +6309 +4497 + +6302 +5477 +3874 +7152 +4289 +1502 +6993 +1968 +8201 +3361 + +3169 +5005 +1366 +1187 +2960 +4402 +7829 +4494 +4550 +4155 + +1670 +31707 + +2778 +6497 +2950 +7022 +3037 +5025 +3920 +1107 +5544 +4234 +1330 +6182 + +6093 +7193 +1472 +7313 +12034 + +11527 +11667 + +8122 +4849 +11876 +6439 +13482 +4171 + +2510 +5344 +6308 +5470 +3694 +3904 +3060 +1957 +3652 +2225 +1192 +3659 +3671 +2842 + +5014 +1665 +2556 +1066 +2900 +1324 +2125 +3245 +2785 +3922 +3338 +2431 +2794 + +6335 +1225 +2642 +6364 +4160 +3309 + +6834 +12081 +3435 + +7505 +8207 +3934 +8305 +10764 +11568 +3353 + +7731 +7976 +3563 +1029 +5288 +1333 +6704 +6018 +1413 + +1780 +11061 +12941 +5784 +6913 +8216 + +12014 +5836 +11487 +8744 +10846 +2219 +5146 + +5868 +3033 +6833 +5479 +5133 +4490 +6107 +5144 +4442 +5649 +2533 +5321 +1877 \ No newline at end of file diff --git a/inputs/01a.txt b/inputs/01a.txt new file mode 100644 index 0000000..ff79f64 --- /dev/null +++ b/inputs/01a.txt @@ -0,0 +1,14 @@ +1000 +2000 +3000 + +4000 + +5000 +6000 + +7000 +8000 +9000 + +10000 \ No newline at end of file diff --git a/src/01.cs b/src/01.cs new file mode 100644 index 0000000..818ee84 --- /dev/null +++ b/src/01.cs @@ -0,0 +1,23 @@ +namespace aoc2023; + +internal class Day01 : Day +{ + internal override void Parse() + { + var lines = Util.Parsing.ReadAllLines($"{GetDay()}"); + } + + internal override string Part1() + { + + + return $"<+white>"; + } + + internal override string Part2() + { + + + return $"<+white>"; + } +} diff --git a/src/Day.cs b/src/Day.cs new file mode 100644 index 0000000..04b8512 --- /dev/null +++ b/src/Day.cs @@ -0,0 +1,65 @@ +namespace aoc2023; + +internal abstract class Day : IDisposable +{ + public void Dispose() + { + Logger.Log(""); + } + + internal void Go(bool runPart1, bool runPart2) + { + Logger.Log($"{GetType().Name}"); + + using (new Timer("Parsing")) + { + Parse(); + } + + if (runPart1) + { + using var stopwatch = new Timer(); + var response = Part1(); + stopwatch.Stop(); + if (!string.IsNullOrEmpty(response)) + { + Logger.Log($"<+black>> part1: {response}"); + } + else + { + stopwatch.Disabled = true; + } + } + + if (runPart2) + { + using var stopwatch = new Timer(); + var response = Part2(); + stopwatch.Stop(); + if (!string.IsNullOrEmpty(response)) + { + Logger.Log($"<+black>> part2: {response}"); + } + else + { + stopwatch.Disabled = true; + } + } + } + + internal int GetDayNum() + { + if (int.TryParse(GetType().Name["Day".Length..], out int dayNum)) + { + return dayNum; + } + + return -1; + } + + internal string GetDay() => $"{GetDayNum():00}"; + + internal virtual void Parse() { } + internal virtual string Part1() { return string.Empty; } + internal virtual string Part2() { return string.Empty; } +} diff --git a/src/Extensions.cs b/src/Extensions.cs new file mode 100644 index 0000000..5b2e46f --- /dev/null +++ b/src/Extensions.cs @@ -0,0 +1,41 @@ +using System.Diagnostics; + +namespace aoc2023; + +internal static class Extensions +{ + public static void ForEach(this IEnumerable enumeration, Action action) + { + foreach (T item in enumeration) + { + action(item); + } + } + + public static (double elapsed, string unit) ConvertToHumanReadable(this Stopwatch stopwatch) + { + var elapsed = 1.0d * stopwatch.ElapsedTicks / Stopwatch.Frequency; + var unit = "s"; + if (elapsed < 0.001) + { + elapsed *= 1e+6; + unit = "us"; + } + else if (elapsed < 1) + { + elapsed *= 1000; + unit = "ms"; + } + else if (elapsed < 60) + { + unit = "s"; + } + else if (elapsed < 60 * 60) + { + elapsed /= 60; + unit = "m"; + } + + return (elapsed, unit); + } +} diff --git a/src/Logger.cs b/src/Logger.cs new file mode 100644 index 0000000..7c696b7 --- /dev/null +++ b/src/Logger.cs @@ -0,0 +1,72 @@ +using System.Diagnostics; + +namespace aoc2023; + +internal class Logger +{ + private static readonly Dictionary colorCodes = new() + { + { "r", "\u001b[0m" }, + { "black", "\u001b[30m" }, + { "red", "\u001b[31m" }, + { "green", "\u001b[32m" }, + { "yellow", "\u001b[33m" }, + { "blue", "\u001b[34m" }, + { "magenta", "\u001b[35m" }, + { "cyan", "\u001b[36m" }, + { "white", "\u001b[37m" }, + { "+black", "\u001b[30;1m" }, + { "+red", "\u001b[31;1m" }, + { "+green", "\u001b[32;1m" }, + { "+yellow", "\u001b[33;1m" }, + { "+blue", "\u001b[34;1m" }, + { "+magenta", "\u001b[35;1m" }, + { "+cyan", "\u001b[36;1m" }, + { "+white", "\u001b[37;1m" }, + { "bgBlack", "\u001b[40m" }, + { "bgRed", "\u001b[41m" }, + { "bgGreen", "\u001b[42m" }, + { "bgYellow", "\u001b[43m" }, + { "bgBlue", "\u001b[44m" }, + { "bgMagenta", "\u001b[45m" }, + { "bgCyan", "\u001b[46m" }, + { "bgWhite", "\u001b[47m" }, + { "+bgBlack", "\u001b[40;1m" }, + { "+bgRed", "\u001b[41;1m" }, + { "+bgGreen", "\u001b[42;1m" }, + { "+bgYellow", "\u001b[43;1m" }, + { "+bgBlue", "\u001b[44;1m" }, + { "+bgMagenta", "\u001b[45;1m" }, + { "+bgCyan", "\u001b[46;1m" }, + { "+bgWhite", "\u001b[47;1m" }, + { "bold", "\u001b[1m" }, + { "underline", "\u001b[4m" }, + { "reverse", "\u001b[7m" }, + }; + + public static void Log(string msg) + { + Console.WriteLine(InsertColorCodes(msg)); + Debug.WriteLine(StripColorCodes(msg)); + } + + private static string InsertColorCodes(string msg) + { + foreach (var code in colorCodes) + { + msg = msg.Replace($"<{code.Key}>", code.Value, StringComparison.CurrentCultureIgnoreCase); + } + + return msg; + } + + private static string StripColorCodes(string msg) + { + foreach (var code in colorCodes) + { + msg = msg.Replace($"<{code.Key}>", string.Empty, StringComparison.CurrentCultureIgnoreCase); + } + + return msg; + } +} diff --git a/src/Template.cs b/src/Template.cs new file mode 100644 index 0000000..de13394 --- /dev/null +++ b/src/Template.cs @@ -0,0 +1,23 @@ +namespace aoc2023; + +internal class DayTemplate : Day +{ + internal override void Parse() + { + var lines = Util.Parsing.ReadAllLines($"{GetDay()}"); + } + + internal override string Part1() + { + + + return $"<+white>"; + } + + internal override string Part2() + { + + + return $"<+white>"; + } +} diff --git a/src/Timer.cs b/src/Timer.cs new file mode 100644 index 0000000..abd1d20 --- /dev/null +++ b/src/Timer.cs @@ -0,0 +1,48 @@ +using System.Diagnostics; + +namespace aoc2023; + +internal class Timer : IDisposable +{ + private readonly Stopwatch stopwatch = Stopwatch.StartNew(); + private readonly string? name; + private bool stopped; + public bool Disabled { get; set; } + + public Timer(string? inName = null) + { + name = inName; + } + + public void Stop() + { + if (stopped) + { + return; + } + + stopwatch.Stop(); + stopped = true; + } + + public void Dispose() + { + Stop(); + if (Disabled) + { + return; + } + + var (elapsed, unit) = stopwatch.ConvertToHumanReadable(); + var color = ""; + if (unit == "us" || (unit == "ms" && elapsed < 10)) + { + color = ""; + } + else if (unit == "ms" && elapsed < 250) + { + color = ""; + } + Logger.Log($"{name}{(!string.IsNullOrEmpty(name) ? " t" : "T")}ook {color}{elapsed:N1}{unit}"); + } +} diff --git a/src/Util/Bisect.cs b/src/Util/Bisect.cs new file mode 100644 index 0000000..f6c6b3a --- /dev/null +++ b/src/Util/Bisect.cs @@ -0,0 +1,49 @@ +namespace aoc2023.Util; + +public static class Bisect +{ + // Bisect takes a known-good low and known-bad high value as the bounds + // to bisect, and a function to test each value for success or failure. + // If the function succeeds, the value is adjusted toward the maximum, + // and if the function fails, the value is adjusted toward the minimum. + // The final value is returned when the difference between the success + // and the failure is less than or equal to the acceptance threshold + // (usually 1, for integers). + public static double Find(double low, double high, double threshold, Func tryFunc) + { + while (System.Math.Abs(high - low) > threshold) + { + var currVal = low + ((high - low) / 2); + var success = tryFunc(currVal); + if (success) + { + low = currVal; + } + else + { + high = currVal; + } + } + + return low; + } + + public static double Find(long low, long high, long threshold, Func tryFunc) + { + while (System.Math.Abs(high - low) > threshold) + { + var currVal = low + ((high - low) / 2); + var success = tryFunc(currVal); + if (success) + { + low = currVal; + } + else + { + high = currVal; + } + } + + return low; + } +} \ No newline at end of file diff --git a/src/Util/Combinatorics.cs b/src/Util/Combinatorics.cs new file mode 100644 index 0000000..4640199 --- /dev/null +++ b/src/Util/Combinatorics.cs @@ -0,0 +1,39 @@ +namespace aoc2023.Util; + +public static class Combinatorics +{ + public static IEnumerable> GetPermutations(IList list) + { + Action, int>? helper = null; + List> res = new(); + + helper = (arr, n) => + { + if (n == 1) + { + var tmp = new T[arr.Count]; + arr.CopyTo(tmp, 0); + res.Add(tmp); + } + else + { + for (var i = 0; i < n; i++) + { + // ReSharper disable once AccessToModifiedClosure + helper!(arr, n - 1); + if (n % 2 == 1) + { + (arr[i], arr[n - 1]) = (arr[n - 1], arr[i]); + } + else + { + (arr[0], arr[n - 1]) = (arr[n - 1], arr[0]); + } + } + } + }; + + helper(list, list.Count); + return res; + } +} diff --git a/src/Util/Math.cs b/src/Util/Math.cs new file mode 100644 index 0000000..67103d7 --- /dev/null +++ b/src/Util/Math.cs @@ -0,0 +1,65 @@ +namespace aoc2023.Util; + +public static class Math +{ + public static ulong GCD(ulong a, ulong b) + { + while (true) + { + if (b == 0) + { + return a; + } + + var a1 = a; + a = b; + b = a1 % b; + } + } + + public static ulong LCM(params ulong[] nums) + { + var num = nums.Length; + switch (num) + { + case 0: + return 0; + case 1: + return nums[0]; + } + + var ret = lcm(nums[0], nums[1]); + for (var i = 2; i < num; i++) + { + ret = lcm(nums[i], ret); + } + + return ret; + } + + private static ulong lcm(ulong a, ulong b) + { + return (a * b) / GCD(a, b); + } + + public static long Modulo(long numer, long denom) + { + // long q = numer / denom; + long r = numer % denom; + if (r < 0) + { + if (denom > 0) + { + // q = q - 1; + r = r + denom; + } + else + { + // q = q + 1; + r = r - denom; + } + } + + return r; + } +} \ No newline at end of file diff --git a/src/Util/Parsing.cs b/src/Util/Parsing.cs new file mode 100644 index 0000000..16d6eed --- /dev/null +++ b/src/Util/Parsing.cs @@ -0,0 +1,91 @@ +using System.Reflection; +using System.Text; + +namespace aoc2023.Util; + +public static class Parsing +{ + private static readonly char[] StripPreamble = { (char)8745, (char)9559, (char)9488, }; + private static readonly Encoding[] StripBOMsFromEncodings = { Encoding.UTF8, Encoding.Unicode, Encoding.BigEndianUnicode, }; + private static void ReadData(string inputName, Action processor) + { + if (Console.IsInputRedirected) + { + bool processedSomething = false; + for (int i = 0; Console.In.ReadLine() is { } line; i++) + { + if (i == 0) + { + if (line[0..StripPreamble.Length].SequenceEqual(StripPreamble)) + { + line = line[StripPreamble.Length..]; + } + else + { + foreach (var encoding in StripBOMsFromEncodings) + { + if (line.StartsWith(encoding.GetString(encoding.GetPreamble()), StringComparison.Ordinal)) + { + line = line.Replace(encoding.GetString(encoding.GetPreamble()), "", StringComparison.Ordinal); + } + } + } + } + processor(line); + if (!string.IsNullOrEmpty(line)) + { + processedSomething = true; + } + } + + if (processedSomething) + { + return; + } + } + + var filename = $"inputs/{inputName}.txt"; + if (File.Exists(filename)) + { + if (Directory.Exists(Path.GetDirectoryName(filename)!) && File.Exists(filename)) + { + foreach (var line in File.ReadLines(filename)) + { + processor(line); + } + + return; + } + } + + // typeof(Logger) is not technically correct since what we need is the "default namespace," + // but "default namespace" is a Project File concept, not a C#/.NET concept, so it's not + // accessible at runtime. instead, we assume Logger is also part of the "default namespace" + var resourceName = $"{typeof(Logger).Namespace}.inputs.{inputName}.txt"; + using var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName); + using StreamReader reader = new(stream!); + while (reader.ReadLine() is { } readLine) + { + processor(readLine); + } + } + + internal static string ReadAllText(string filename) + { + string contents = string.Empty; + ReadData(filename, (line) => contents = line); + return contents; + } + + internal static IEnumerable ReadAllLines(string filename) + { + List lines = new(); + ReadData(filename, (line) => lines.Add(line)); + return lines; + } + + internal static IEnumerable ReadAllLinesAsInts(string filename) + { + return ReadAllLines(filename).Select(long.Parse); + } +} \ No newline at end of file diff --git a/src/Util/Testing.cs b/src/Util/Testing.cs new file mode 100644 index 0000000..4831311 --- /dev/null +++ b/src/Util/Testing.cs @@ -0,0 +1,35 @@ +using System.Diagnostics; + +namespace aoc2023.Util; + +public static class Testing +{ + internal static void StartTestSet(string name) + { + Logger.Log($"test: {name}"); + } + + internal static void StartTest(string label) + { + Logger.Log($"{label}"); + } + + internal static void TestCondition(Func a, bool printResult = true) + { + if (a.Invoke() == false) + { + Debug.Assert(false); + if (printResult) + { + Logger.Log("x"); + } + } + else + { + if (printResult) + { + Logger.Log(""); + } + } + } +} \ No newline at end of file diff --git a/src/Util/Vec2.cs b/src/Util/Vec2.cs new file mode 100644 index 0000000..ea3c224 --- /dev/null +++ b/src/Util/Vec2.cs @@ -0,0 +1,162 @@ +namespace aoc2023.Util; + +public readonly struct ivec2 : IEquatable, IComparable, IComparable +{ + public readonly long x = 0; + public readonly long y = 0; + + public static readonly ivec2 ZERO = new ivec2(0, 0); + public static readonly ivec2 ONE = new ivec2(1, 1); + + public static readonly ivec2 LEFT = new ivec2(-1, 0); + public static readonly ivec2 RIGHT = new ivec2(1, 0); + public static readonly ivec2 UP = new ivec2(0, -1); + public static readonly ivec2 DOWN = new ivec2(0, 1); + public static readonly ivec2[] FOURWAY = {RIGHT, LEFT, UP, DOWN}; + public static readonly ivec2[] EIGHTWAY = {UP, UP + RIGHT, RIGHT, RIGHT + DOWN, DOWN, DOWN + LEFT, LEFT, LEFT + UP}; + + public ivec2(long xv, long yv) + { + x = xv; + y = yv; + } + + public bool IsZero() => x == 0 && y == 0; + public long Sum => x + y; + public long Product => x * y; + public long MaxElement => System.Math.Max(x, y); + + public ivec2 GetRotatedLeft() => new ivec2(y, -x); + + public ivec2 GetRotatedRight() => new ivec2(-y, x); + + public long Dot(ivec2 v) => (x * v.x) + (y * v.y); + public long LengthSquared => (x * x) + (y * y); + public float Length => MathF.Sqrt(LengthSquared); + + public long ManhattanDistance => Abs(this).Sum; + public long ManhattanDistanceTo(ivec2 other) => System.Math.Abs(x - other.x) + System.Math.Abs(y - other.y); + + public ivec2 GetBestDirectionTo(ivec2 p) + { + ivec2 diff = p - this; + if (diff.IsZero()) + { + return ZERO; + } + + ivec2 dir = diff / Abs(diff).MaxElement; + return Sign(dir); + } + + // get a point in the 8 cells around me closest to p + public ivec2 GetNearestNeighbor(ivec2 p) + { + ivec2 dir = GetBestDirectionTo(p); + return this + dir; + } + + public IEnumerable GetOrthogonalNeighbors() + { + foreach (var dir in FOURWAY) + { + yield return this + dir; + } + } + + public IEnumerable GetNeighbors() + { + foreach (var dir in EIGHTWAY) + { + yield return this + dir; + } + } + + public long this[long i] => (i == 0) ? x : y; + + public static ivec2 operator +(ivec2 v) => v; + public static ivec2 operator -(ivec2 v) => new ivec2(-v.x, -v.y); + public static ivec2 operator +(ivec2 a, ivec2 b) => new ivec2(a.x + b.x, a.y + b.y); + public static ivec2 operator -(ivec2 a, ivec2 b) => new ivec2(a.x - b.x, a.y - b.y); + public static ivec2 operator *(ivec2 a, ivec2 b) => new ivec2(a.x * b.x, a.y * b.y); + public static ivec2 operator *(long a, ivec2 v) => new ivec2(a * v.x, a * v.y); + public static ivec2 operator *(ivec2 v, long a) => new ivec2(a * v.x, a * v.y); + public static ivec2 operator /(ivec2 v, long a) => new ivec2(v.x / a, v.y / a); + public static bool operator ==(ivec2 a, ivec2 b) => (a.x == b.x) && (a.y == b.y); + public static bool operator !=(ivec2 a, ivec2 b) => (a.x != b.x) || (a.y != b.y); + public static bool operator <(ivec2 a, ivec2 b) => (a.x < b.x) && (a.y < b.y); + public static bool operator <=(ivec2 a, ivec2 b) => (a.x <= b.x) && (a.y <= b.y); + public static bool operator >(ivec2 a, ivec2 b) => (a.x > b.x) && (a.y > b.y); + public static bool operator >=(ivec2 a, ivec2 b) => (a.x >= b.x) && (a.y >= b.y); + + public bool Equals(ivec2 other) + { + return x == other.x && y == other.y; + } + + public override bool Equals(object? obj) + { + return obj is ivec2 other && Equals(other); + } + + public int CompareTo(ivec2 other) + { + if (this < other) + { + return -1; + } + + if (this > other) + { + return 1; + } + + return 0; + } + + public int CompareTo(object? obj) + { + if (ReferenceEquals(null, obj)) return 1; + return obj is ivec2 other ? CompareTo(other) : throw new ArgumentException($"Object must be of type {nameof(ivec2)}"); + } + + public static ivec2 Sign(ivec2 v) => new ivec2(System.Math.Sign(v.x), System.Math.Sign(v.y)); + public static ivec2 Min(ivec2 a, ivec2 b) => new ivec2(System.Math.Min(a.x, b.x), System.Math.Min(a.y, b.y)); + public static ivec2 Max(ivec2 a, ivec2 b) => new ivec2(System.Math.Max(a.x, b.x), System.Math.Max(a.y, b.y)); + + public static ivec2 Clamp(ivec2 v, ivec2 lh, ivec2 rh) => Min(rh, Max(lh, v)); + + public static ivec2 Abs(ivec2 v) => new ivec2(System.Math.Abs(v.x), System.Math.Abs(v.y)); + + public static ivec2 Mod(ivec2 val, long den) + { + long x = val.x % den; + long y = val.y % den; + + if (x < 0) + { + x += den; + } + + if (y < 0) + { + y += den; + } + + return new ivec2(x, y); + } + + public static long Dot(ivec2 a, ivec2 b) => (a.x * b.x) + (a.y * b.y); + + public static ivec2 Parse(string s) + { + string[] parts = s.Split(',', 2); + long x = long.Parse(parts[0]); + long y = long.Parse(parts[1]); + return new ivec2(x, y); + } + + public override int GetHashCode() => HashCode.Combine(x, y); + + public override string ToString() => $"{x},{y}"; +} diff --git a/src/Util/Vec3.cs b/src/Util/Vec3.cs new file mode 100644 index 0000000..ab4aee1 --- /dev/null +++ b/src/Util/Vec3.cs @@ -0,0 +1,171 @@ +namespace aoc2023.Util; + +public readonly struct ivec3 : IEquatable, IComparable, IComparable +{ + public readonly long x = 0; + public readonly long y = 0; + public readonly long z = 0; + + public static readonly ivec3 ZERO = new ivec3(0, 0, 0); + public static readonly ivec3 ONE = new ivec3(1, 1, 1); + + public static readonly ivec3 LEFT = new ivec3(-1, 0, 0); + public static readonly ivec3 RIGHT = new ivec3(1, 0, 0); + public static readonly ivec3 UP = new ivec3(0, -1, 0); + public static readonly ivec3 DOWN = new ivec3(0, 1, 0); + public static readonly ivec3 FORWARD = new ivec3(0, 0, 1); + public static readonly ivec3 BACKWARD = new ivec3(0, 0, -1); + public static readonly ivec3[] DIRECTIONS = {LEFT, RIGHT, UP, DOWN, FORWARD, BACKWARD}; + + public ivec3(long xv, long yv, long zv) + { + x = xv; + y = yv; + z = zv; + } + + public bool IsZero() => x == 0 && y == 0 && z == 0; + public long Sum => x + y + z; + public long Product => x * y * z; + public long MaxElement => System.Math.Max(x, System.Math.Max(y, z)); + public long MinElement => System.Math.Min(x, System.Math.Min(y, z)); + + public ivec3 GetRotatedLeft() => new ivec3(y, -x, z); + + public ivec3 GetRotatedRight() => new ivec3(-y, x, z); + + public long Dot(ivec3 v) => (x * v.x) + (y * v.y) + (z * v.z); + public long LengthSquared => (x * x) + (y * y) + (z * z); + public float Length => MathF.Sqrt(LengthSquared); + + public long ManhattanDistance => Abs(this).Sum; + public long ManhattanDistanceTo(ivec3 other) => System.Math.Abs(x - other.x) + System.Math.Abs(y - other.y) + System.Math.Abs(z - other.z); + + public bool IsTouching(ivec3 other) => ManhattanDistanceTo(other) == 1; + + public IEnumerable GetNeighbors(ivec3? min = null, ivec3? max = null) + { + foreach (var d in DIRECTIONS) + { + var n = this + d; + if ((min == null || n >= min) && (max == null || n <= max)) + { + yield return n; + } + } + } + + public ivec3 GetBestDirectionTo(ivec3 p) + { + ivec3 diff = p - this; + if (diff.IsZero()) + { + return ZERO; + } + + ivec3 dir = diff / Abs(diff).MaxElement; + return Sign(dir); + } + + // get a point in the 8 cells around me closest to p + public ivec3 GetNearestNeighbor(ivec3 p) + { + ivec3 dir = GetBestDirectionTo(p); + return this + dir; + } + + public long this[long i] => (i == 0) ? x : (i == 1) ? y : z; + + public static ivec3 operator +(ivec3 v) => v; + public static ivec3 operator -(ivec3 v) => new ivec3(-v.x, -v.y, -v.z); + public static ivec3 operator +(ivec3 a, ivec3 b) => new ivec3(a.x + b.x, a.y + b.y, a.z + b.z); + public static ivec3 operator -(ivec3 a, ivec3 b) => new ivec3(a.x - b.x, a.y - b.y, a.z - b.z); + public static ivec3 operator *(ivec3 a, ivec3 b) => new ivec3(a.x * b.x, a.y * b.y, a.z * b.z); + public static ivec3 operator *(long a, ivec3 v) => new ivec3(a * v.x, a * v.y, a * v.z); + public static ivec3 operator *(ivec3 v, long a) => new ivec3(a * v.x, a * v.y, a * v.z); + public static ivec3 operator /(ivec3 v, long a) => new ivec3(v.x / a, v.y / a, v.z / a); + public static bool operator ==(ivec3 a, ivec3 b) => (a.x == b.x) && (a.y == b.y) && (a.z == b.z); + public static bool operator !=(ivec3 a, ivec3 b) => (a.x != b.x) || (a.y != b.y) || (a.z != b.z); + public static bool operator <(ivec3 a, ivec3 b) => (a.x < b.x) && (a.y < b.y) && (a.z < b.z); + public static bool operator <=(ivec3 a, ivec3 b) => (a.x <= b.x) && (a.y <= b.y) && (a.z <= b.z); + public static bool operator >(ivec3 a, ivec3 b) => (a.x > b.x) && (a.y > b.y) && (a.z > b.z); + public static bool operator >=(ivec3 a, ivec3 b) => (a.x >= b.x) && (a.y >= b.y) && (a.z >= b.z); + + public bool Equals(ivec3 other) + { + return x == other.x && y == other.y && z == other.z; + } + + public override bool Equals(object? obj) + { + return obj is ivec3 other && Equals(other); + } + + public int CompareTo(ivec3 other) + { + if (this < other) + { + return -1; + } + + if (this > other) + { + return 1; + } + + return 0; + } + + public int CompareTo(object? obj) + { + if (ReferenceEquals(null, obj)) return 1; + return obj is ivec3 other ? CompareTo(other) : throw new ArgumentException($"Object must be of type {nameof(ivec3)}"); + } + + public static ivec3 Sign(ivec3 v) => new ivec3(System.Math.Sign(v.x), System.Math.Sign(v.y), System.Math.Sign(v.z)); + public static ivec3 Min(ivec3 a, ivec3 b) => new ivec3(System.Math.Min(a.x, b.x), System.Math.Min(a.y, b.y), System.Math.Min(a.z, b.z)); + public static ivec3 Max(ivec3 a, ivec3 b) => new ivec3(System.Math.Max(a.x, b.x), System.Math.Max(a.y, b.y), System.Math.Max(a.z, b.z)); + + public static ivec3 Clamp(ivec3 v, ivec3 lh, ivec3 rh) => Min(rh, Max(lh, v)); + + public static ivec3 Abs(ivec3 v) => new ivec3(System.Math.Abs(v.x), System.Math.Abs(v.y), System.Math.Abs(v.z)); + + public static ivec3 Mod(ivec3 val, long den) + { + long x = val.x % den; + long y = val.y % den; + long z = val.z % den; + + if (x < 0) + { + x += den; + } + + if (y < 0) + { + y += den; + } + + if (z < 0) + { + z += den; + } + + return new ivec3(x, y, z); + } + + public static long Dot(ivec3 a, ivec3 b) => (a.x * b.x) + (a.y * b.y) + (a.z * b.z); + + public static ivec3 Parse(string s) + { + string[] parts = s.Split(',', 3); + long x = long.Parse(parts[0]); + long y = long.Parse(parts[1]); + long z = long.Parse(parts[2]); + return new ivec3(x, y, z); + } + + public override int GetHashCode() => HashCode.Combine(x, y, z); + + public override string ToString() => $"{x},{y},{z}"; +} diff --git a/src/main.cs b/src/main.cs new file mode 100644 index 0000000..35c2ee3 --- /dev/null +++ b/src/main.cs @@ -0,0 +1,78 @@ +using aoc2023; + +using aoc2023.Timer t = new("Full program"); +var types = System.Reflection.Assembly + .GetExecutingAssembly() + .GetTypes() + .Where(ty => ty.IsSubclassOf(typeof(Day)) && !ty.IsAbstract && ty.Name != "DayTemplate") + .OrderBy(ty => ty.Name).ToList(); + +bool runAll = false; +bool? runPart1 = null; +bool? runPart2 = null; +List desiredDays = new(); +foreach (var arg in args) +{ + if (arg.Equals("-part1", StringComparison.CurrentCultureIgnoreCase)) + { + runPart1 = true; + } + else if (arg.Equals("-part2", StringComparison.CurrentCultureIgnoreCase)) + { + runPart2 = true; + } + else if (arg.Equals("all", StringComparison.CurrentCultureIgnoreCase)) + { + runAll = true; + } + else + { + desiredDays.Add(arg); + } +} + +if (runPart1 != null || runPart2 != null) +{ + runPart1 ??= false; + runPart2 ??= false; +} + +if (runAll) +{ + foreach (var type in types) + { + using var day = (Day)Activator.CreateInstance(type)!; + day.Go(runPart1 ?? true, runPart2 ?? true); + } +} +else +{ + if (desiredDays.Count == 0) + { + desiredDays.Add(""); + } + + foreach (var desiredDay in desiredDays) + { + Day? day = null; + if (string.IsNullOrEmpty(desiredDay)) + { + day = (Day) Activator.CreateInstance(types.Last())!; + } + else + { + var type = types.FirstOrDefault(x => x.Name == $"Day{desiredDay.PadLeft(2, '0')}"); + if (type == null) + { + Logger.Log($"Unknown day {desiredDay}"); + } + else + { + day = (Day?) Activator.CreateInstance(type); + } + } + + day?.Go(runPart1 ?? true, runPart2 ?? true); + day?.Dispose(); + } +}