From 136802984d02d0e6d12dd61522c5c0fba57d59fe Mon Sep 17 00:00:00 2001
From: Pim Kunis <pim@kunis.nl>
Date: Thu, 7 Dec 2023 12:08:34 +0100
Subject: [PATCH 1/2] add day7 with elixir

---
 23/elixir/.formatter.exs          |    4 +
 23/elixir/.gitignore              |   26 +
 23/elixir/Makefile                |    2 +
 23/elixir/README.md               |   21 +
 23/elixir/inputs/day7.txt         | 1000 +++++++++++++++++++++++++++++
 23/elixir/inputs/day7_example.txt |    5 +
 23/elixir/lib/day.ex              |   46 ++
 23/elixir/lib/days/day7.ex        |  170 +++++
 23/elixir/mix.exs                 |   28 +
 23/elixir/test/aoc_test.exs       |    8 +
 23/elixir/test/test_helper.exs    |    1 +
 11 files changed, 1311 insertions(+)
 create mode 100644 23/elixir/.formatter.exs
 create mode 100644 23/elixir/.gitignore
 create mode 100644 23/elixir/Makefile
 create mode 100644 23/elixir/README.md
 create mode 100644 23/elixir/inputs/day7.txt
 create mode 100644 23/elixir/inputs/day7_example.txt
 create mode 100644 23/elixir/lib/day.ex
 create mode 100644 23/elixir/lib/days/day7.ex
 create mode 100644 23/elixir/mix.exs
 create mode 100644 23/elixir/test/aoc_test.exs
 create mode 100644 23/elixir/test/test_helper.exs

diff --git a/23/elixir/.formatter.exs b/23/elixir/.formatter.exs
new file mode 100644
index 0000000..d2cda26
--- /dev/null
+++ b/23/elixir/.formatter.exs
@@ -0,0 +1,4 @@
+# Used by "mix format"
+[
+  inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
+]
diff --git a/23/elixir/.gitignore b/23/elixir/.gitignore
new file mode 100644
index 0000000..e23ab19
--- /dev/null
+++ b/23/elixir/.gitignore
@@ -0,0 +1,26 @@
+# The directory Mix will write compiled artifacts to.
+/_build/
+
+# If you run "mix test --cover", coverage assets end up here.
+/cover/
+
+# The directory Mix downloads your dependencies sources to.
+/deps/
+
+# Where third-party dependencies like ExDoc output generated docs.
+/doc/
+
+# Ignore .fetch files in case you like to edit your project deps locally.
+/.fetch
+
+# If the VM crashes, it generates a dump, let's ignore it too.
+erl_crash.dump
+
+# Also ignore archive artifacts (built via "mix archive.build").
+*.ez
+
+# Ignore package tarball (built via "mix hex.build").
+aoc-*.tar
+
+# Temporary files, for example, from tests.
+/tmp/
diff --git a/23/elixir/Makefile b/23/elixir/Makefile
new file mode 100644
index 0000000..369016a
--- /dev/null
+++ b/23/elixir/Makefile
@@ -0,0 +1,2 @@
+day%:
+	mix run -e "AOC.Day$*.solve()"
diff --git a/23/elixir/README.md b/23/elixir/README.md
new file mode 100644
index 0000000..7069072
--- /dev/null
+++ b/23/elixir/README.md
@@ -0,0 +1,21 @@
+# Aoc
+
+**TODO: Add description**
+
+## Installation
+
+If [available in Hex](https://hex.pm/docs/publish), the package can be installed
+by adding `aoc` to your list of dependencies in `mix.exs`:
+
+```elixir
+def deps do
+  [
+    {:aoc, "~> 0.1.0"}
+  ]
+end
+```
+
+Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc)
+and published on [HexDocs](https://hexdocs.pm). Once published, the docs can
+be found at <https://hexdocs.pm/aoc>.
+
diff --git a/23/elixir/inputs/day7.txt b/23/elixir/inputs/day7.txt
new file mode 100644
index 0000000..00fdfcc
--- /dev/null
+++ b/23/elixir/inputs/day7.txt
@@ -0,0 +1,1000 @@
+7227Q 52
+67Q64 732
+33Q33 573
+58ATQ 939
+93K53 840
+55AJ8 496
+6ATAT 863
+26J77 1
+TTQAT 381
+2J2J2 322
+342Q2 409
+3444Q 864
+77J67 31
+772QJ 796
+5388J 956
+7JJ7J 88
+5Q555 626
+77AK8 588
+J2222 661
+36T93 934
+5Q365 343
+K3K3K 283
+5959A 537
+44477 560
+6AA5K 208
+5J445 262
+28228 61
+646A6 503
+KK4Q8 471
+A426T 500
+AQ9JA 643
+J784T 348
+22J48 6
+A5AJ5 220
+62235 545
+84JJJ 206
+48464 669
+44844 637
+Q8537 969
+95663 751
+JTQK7 305
+33TTT 335
+4T925 32
+9777Q 738
+2QQ66 971
+TQQ9T 657
+69437 176
+2555J 849
+55AAA 26
+94TT4 531
+89T66 55
+387J8 663
+KKKKJ 198
+K4KK4 870
+622J2 330
+6283A 337
+JQQQ2 349
+666AA 706
+9794J 966
+99A9T 771
+53J53 477
+7JT3J 829
+KK524 765
+Q4QQ4 486
+J7367 519
+KK4TJ 937
+Q4983 168
+74A77 997
+Q2244 464
+242J4 625
+J2839 326
+T927T 773
+2Q992 875
+77722 467
+8K645 959
+AJTJ3 650
+64Q35 98
+QQTQ4 973
+24492 438
+T8AK7 983
+K439T 924
+7AJ7J 426
+T88T5 801
+9J939 267
+7K557 458
+T9KQ3 231
+34444 720
+44TTT 781
+AA3A9 177
+78878 479
+4K474 932
+3TT65 634
+98898 113
+26286 702
+37736 673
+9Q9K3 103
+9TT92 755
+8AAJ8 845
+55A55 356
+K2222 184
+7777Q 950
+64392 649
+36653 891
+22AA2 201
+55943 367
+AQA2Q 178
+4T693 806
+385J5 429
+246Q6 930
+32J2Q 428
+59Q83 128
+8684Q 828
+482Q9 668
+243QA 250
+JQTQQ 656
+45645 354
+7J648 534
+44633 638
+A3283 284
+38262 830
+QAT67 976
+7662Q 241
+266T2 355
+3AA67 958
+JTTTT 51
+A3T22 739
+6A45J 978
+969JJ 965
+69K98 413
+8Q33Q 239
+886QQ 135
+Q44JK 525
+TT6TT 64
+77773 451
+8AKK8 172
+QTQ2T 872
+QQTQ7 642
+44666 387
+J4Q74 225
+4J968 542
+Q6939 831
+2773T 420
+55565 313
+76666 9
+5J4J4 212
+TTJQJ 601
+358K2 725
+JQ78Q 597
+3K3TK 685
+QKQQQ 261
+5Q59Q 762
+Q77QQ 756
+KK2J2 728
+TKKK5 879
+9KQ9K 785
+Q83JK 96
+39998 256
+TTJ3T 852
+66866 192
+2567T 211
+76969 20
+KAKKK 735
+9Q5QQ 808
+JQ87K 67
+J8887 320
+J9763 36
+A6464 75
+K5AA5 996
+TTJ7T 890
+7KKK7 450
+72752 817
+K2J32 915
+T25J7 72
+QQ6Q6 53
+27T7J 577
+98J89 236
+23525 404
+44244 34
+2K8J7 509
+AK427 108
+7K6KA 466
+374J7 553
+533K3 78
+8J6K2 301
+J7577 995
+T88T8 903
+626K6 265
+2A96A 462
+T4987 279
+JJTKJ 69
+77767 641
+2Q232 210
+444JJ 133
+7Q7JQ 508
+5555K 888
+46462 874
+KQKKK 474
+96737 10
+7AT28 234
+2QJTA 229
+9T8T8 111
+373KJ 263
+95599 605
+A7Q66 719
+82555 291
+9KK8T 810
+Q87KK 102
+TT2TT 792
+888T8 772
+9J767 972
+9496J 774
+4KJ44 511
+KA5KK 790
+4J222 944
+2325A 961
+AQJ5A 118
+J555J 698
+9899J 862
+5496K 590
+A97J4 287
+77JA3 695
+959Q9 79
+29927 516
+K88A3 400
+9997J 541
+58A6J 452
+2QTKA 447
+777KK 154
+47J2K 907
+QJ5A4 592
+JAA8J 730
+K5J55 982
+3QQQ3 85
+725QK 140
+5KK55 678
+A5AQ9 871
+3J639 149
+99899 623
+7AAA7 152
+7777J 401
+75492 895
+TQ549 900
+2A7TT 991
+2J36J 559
+95K83 433
+44TTA 778
+98J9Q 378
+55TQ9 581
+3AK7T 50
+94399 869
+Q43JA 109
+34KKJ 569
+88499 27
+22525 737
+7T9K6 523
+337J9 141
+99959 339
+JK9K9 444
+5T55T 680
+339T9 562
+JJKKK 366
+KJTJK 814
+9KJ55 299
+5969J 672
+92273 416
+6TQ68 107
+T36K5 938
+K26K6 884
+5625J 93
+44393 196
+55558 100
+96666 521
+4938T 813
+2QQ8Q 244
+8887T 885
+KT92Q 189
+6K766 60
+67676 481
+QQ524 427
+58598 520
+4J454 777
+6Q82Q 303
+6Q6J3 435
+83993 670
+32232 873
+T488T 795
+622J6 893
+53323 914
+J77J7 205
+55954 385
+KJK48 251
+96AQK 861
+QJT45 653
+K3826 835
+44447 546
+4T877 793
+88333 701
+QQQJ8 566
+36663 799
+66Q5Q 41
+A44Q9 43
+47KKK 783
+23J22 3
+67JQQ 289
+K43J7 484
+QJQQQ 89
+32T65 709
+4646T 515
+T3A29 535
+75665 952
+KQQ2T 837
+AJTT4 578
+QK4Q4 288
+6J6JJ 312
+28887 138
+33TK4 599
+77J2J 946
+566J5 63
+333A5 457
+A2A66 575
+6296T 611
+3TQ46 373
+J888J 726
+KKJ4K 948
+J5T4A 455
+4T74T 962
+473A8 431
+ATATA 514
+4Q385 269
+K65K6 383
+398K4 715
+65JT7 630
+8A6J9 419
+QA5JQ 585
+Q45KA 754
+AAA66 173
+4949Q 733
+K9972 22
+KTKKK 422
+5JQ22 502
+K787K 302
+TT8TJ 527
+265KA 363
+KK7KK 745
+6263K 498
+65J2K 565
+26322 104
+44Q74 731
+23383 276
+KQ948 687
+9552J 504
+75JA6 95
+3JJ33 994
+28824 716
+2A8JK 13
+22868 38
+88388 987
+A955Q 963
+54T86 547
+55547 671
+5TK7Q 417
+4Q35K 842
+33353 492
+96A85 878
+Q6QAQ 867
+K55KJ 822
+97QK2 398
+K6229 162
+4TT84 518
+Q67AJ 628
+2TT22 776
+2QJ24 766
+A8TT8 418
+A74Q2 704
+77T7T 399
+774JT 789
+6A845 371
+8JQ5Q 970
+55645 757
+68788 896
+5J2J7 350
+K88J6 853
+3AAA3 160
+3J777 125
+3666K 247
+5QA98 887
+QJ272 106
+45555 767
+3T3T3 441
+4448T 260
+A9A9A 550
+76JA6 591
+6T4T8 984
+KT7JK 748
+727T2 253
+8Q77A 364
+Q8448 507
+T3JJ9 707
+8Q88Q 555
+A84AA 370
+7QQ26 804
+35377 616
+TK3KK 87
+T764T 688
+AT9A8 45
+A6AA5 328
+57T63 315
+62622 627
+66366 788
+JKQKQ 980
+6T5AQ 841
+58585 693
+3KA73 411
+44884 949
+AA958 615
+4Q26A 886
+57AJ7 564
+84J48 342
+633TJ 295
+29222 606
+Q222Q 453
+JAQAA 818
+T6TTJ 290
+Q3KAJ 563
+666TT 844
+K28QQ 286
+KK46K 811
+T2222 714
+8A883 463
+JJ73J 83
+AJK26 538
+72A34 266
+TKK9Q 877
+333AA 382
+8T28T 470
+888A5 910
+5A365 664
+88JKK 310
+55235 551
+K2KKK 308
+AA688 809
+62T6Q 57
+AA2A4 336
+9999K 268
+44J8T 227
+67877 461
+K33QK 21
+Q44JQ 423
+TK787 71
+A78A6 749
+QJAQQ 331
+J2A52 935
+965TT 54
+598J5 729
+K8KKJ 857
+K5J6K 340
+QJQ22 47
+685QA 230
+9999J 617
+A9339 321
+953T4 920
+33373 859
+8JJ8T 922
+42K39 116
+QQ432 449
+K24K2 345
+4A442 802
+3JKK3 758
+6JTTQ 185
+5K9J7 124
+7A779 325
+68868 998
+JQ355 224
+TK456 568
+93793 150
+449J9 33
+57777 248
+666KK 750
+T333J 703
+466AA 613
+5JJ8Q 226
+AQTQT 779
+33355 23
+33TQ3 974
+8J588 992
+KJKKQ 832
+34J97 694
+K9993 70
+QQQ9Q 228
+4K9AQ 148
+7KKJ9 379
+99944 571
+TT3Q8 297
+T2QA9 921
+JJ55T 561
+J6KAQ 607
+4735Q 259
+3J547 223
+64464 574
+77J94 919
+626Q6 923
+J3832 631
+96QK3 391
+A4J4A 421
+J77KK 723
+K8354 285
+JATQ9 273
+28732 209
+72779 666
+4J255 243
+777K7 202
+JJQ5J 645
+82A47 612
+888T4 97
+22K2K 736
+T35Q8 752
+94238 700
+5K242 324
+5QJ5A 927
+4T6KA 892
+74J8A 960
+4J4JK 791
+A76QQ 159
+988A8 143
+86J32 39
+7QK32 512
+7TTTT 483
+KK27K 252
+8A366 529
+8333J 182
+52QQ5 164
+95926 219
+AK33A 977
+A368K 988
+QQA5Q 858
+5999J 848
+KK9JK 110
+6Q2Q2 570
+AAKK7 600
+555Q3 277
+2A2A6 614
+38853 2
+JTA82 608
+8J668 636
+J999K 30
+QJ35T 505
+AQ7AA 121
+777KJ 389
+J6282 465
+8K2T3 332
+43Q82 760
+66T6K 734
+7A77A 454
+A98AA 99
+QQ7QQ 362
+99J9J 129
+444TJ 74
+A7263 16
+74749 699
+2K2KK 137
+8K6JQ 146
+6TJ58 902
+72222 123
+9A97A 415
+37TT6 380
+88882 651
+66555 311
+55J55 270
+77A72 430
+33Q5Q 193
+TTQ44 369
+3TT8T 278
+428T3 132
+AK897 214
+7QQQJ 697
+9AK62 157
+96466 487
+J522J 238
+9J7A9 394
+QQK77 584
+Q72T4 24
+26662 169
+9KK32 908
+45QJ6 576
+45QKJ 690
+KK248 696
+AAAA4 652
+2T2QQ 681
+9992J 216
+47777 929
+KJT5J 73
+5TA64 593
+55AA5 780
+7QT35 58
+8JTJ6 648
+K4K54 712
+44Q49 539
+KT427 665
+TJ3T3 191
+T7758 945
+A9347 609
+942J2 386
+QQ9J9 81
+J7445 957
+7A54J 889
+QK44K 207
+7KJ99 683
+7888Q 925
+44J44 583
+365K8 794
+88983 675
+2T2QJ 375
+28K2J 222
+84A8T 372
+72796 264
+3KKAK 708
+59559 722
+7JK35 5
+J8Q88 913
+QA543 942
+86A68 866
+T4A4A 746
+QAQQQ 640
+J8T8T 408
+77JT6 679
+J5779 323
+86AA3 803
+TAAA3 376
+5J6K5 217
+78253 787
+TTTK3 357
+Q8599 368
+QTTTT 199
+77K3K 309
+TKJKK 644
+7Q554 307
+KKQKQ 445
+77866 403
+44355 272
+J6969 968
+985A3 667
+JJQQQ 333
+5J9JT 281
+6T4A4 156
+KA9J2 999
+22329 405
+3QK93 692
+2T2TT 827
+22999 240
+TK7JJ 101
+7287A 567
+J4J24 360
+AAJ53 424
+JAA45 769
+77282 981
+7777T 548
+43533 572
+93932 180
+7AAAA 926
+8K888 782
+4747J 495
+684QJ 40
+73495 855
+2552J 293
+7QKT2 497
+AA4A6 163
+2T8TT 897
+7J746 407
+3J234 807
+Q3QQQ 358
+AJAJA 66
+8K5Q5 115
+K9TTJ 485
+33Q7Q 186
+T7797 604
+69989 443
+J666T 11
+J2233 532
+94969 410
+889Q8 17
+K97A6 298
+73T3J 334
+663J6 821
+54QQT 770
+4AAA4 432
+4334A 967
+JJJJJ 647
+JK2TT 904
+2774A 280
+K8KJA 834
+AJ38A 763
+3KKKJ 836
+69693 1000
+48J47 955
+7KA7K 905
+33244 691
+5A435 557
+87KA8 472
+J2484 341
+K35K5 815
+K8Q2A 29
+KK3Q4 390
+7J77A 300
+84T5T 589
+7893T 964
+22AAA 235
+QKK6Q 142
+T6A48 122
+T22T9 167
+KA53Q 686
+68J5K 947
+64625 727
+3T5T3 120
+2992J 846
+A3K8J 145
+QK99J 838
+4A4AQ 91
+KKK8K 491
+AAA28 480
+42772 304
+T222A 204
+K6Q37 558
+Q5K6A 352
+8QJQ8 682
+832J8 147
+Q388T 170
+9555J 12
+7KTT9 658
+KAAKK 911
+TKTTT 174
+44TJ2 993
+6KK6K 136
+5A5TA 494
+AAJ22 15
+633Q3 740
+QQQ4Q 933
+4A4Q2 237
+33555 402
+Q9A23 549
+3Q343 936
+9Q799 14
+3KKKQ 618
+JKK54 876
+96996 25
+2T374 439
+4QJAQ 374
+JQ64K 718
+464Q6 187
+J9252 271
+88Q38 396
+K4J55 912
+5JT73 434
+KK6J4 195
+A8AAA 388
+79793 353
+877J7 943
+J4484 662
+A434J 812
+TTQJ7 493
+63333 711
+22262 540
+474QQ 975
+Q22K2 393
+K5KK2 621
+QQ62T 524
+J6666 188
+AAQAA 883
+65666 126
+778K8 65
+8A3T9 90
+AA392 392
+T593T 151
+QQ2KK 654
+765KA 953
+Q5QQ7 475
+4KTK4 677
+66243 580
+895TJ 175
+QT345 436
+3332T 865
+2T5J9 414
+24J9K 181
+5557A 249
+J3J5J 513
+75555 741
+659T2 689
+TQ5TJ 530
+7T48A 194
+23332 629
+KJKK6 490
+43J33 344
+K55KK 624
+A8JAA 622
+68J89 880
+KJQT9 44
+98989 526
+Q3QT4 602
+764QQ 134
+772Q7 127
+6K6T5 274
+383Q8 139
+JK677 764
+TTT4T 56
+76K82 153
+JAAAA 717
+33JJ5 684
+8TTKT 985
+8T74T 928
+88J88 916
+74938 660
+3TK74 338
+T98K5 397
+99A69 488
+24A6K 197
+43A42 144
+TT9J9 579
+J837Q 552
+44464 820
+82A5A 329
+ATAAJ 183
+83899 190
+88TQT 292
+69482 130
+36J36 4
+458T7 860
+4Q29Q 473
+KKK4K 676
+4K756 800
+8J8JJ 898
+TTTT9 881
+88J28 203
+42422 744
+QQQKK 112
+4J2Q7 327
+57922 582
+44A44 37
+35559 705
+T8TQQ 246
+JQ29K 536
+9A999 825
+62TT2 499
+K3567 218
+72J22 215
+87487 377
+5J655 489
+26769 816
+577A7 851
+44T86 131
+7QQ72 460
+28QJ3 954
+243K7 979
+24J97 724
+4QKT3 742
+A88AA 619
+363AA 610
+T24TJ 117
+92AJ6 587
+J666J 596
+Q7J36 850
+Q3968 901
+8J7JK 798
+5J9T3 84
+29Q22 674
+5588J 598
+7747T 833
+735A6 384
+44944 68
+44J26 365
+52555 77
+Q4TT3 476
+K88TK 440
+6JJTT 632
+KTA54 759
+KKT5T 254
+A85A5 80
+96J6J 469
+9KKKK 556
+37733 18
+KJJ66 282
+2Q882 989
+JJ8JJ 868
+TTJTJ 603
+AKAAA 710
+J6TT6 49
+Q7JT7 448
+8T728 319
+86J55 161
+8K5KK 805
+KKATT 459
+T929J 743
+2238J 86
+99929 119
+82Q5T 314
+22297 7
+Q58QQ 437
+8A8Q5 46
+87J2Q 761
+T2A35 823
+9TQQQ 395
+2KT69 232
+5T566 506
+J33QQ 179
+2T652 275
+KT228 909
+9T229 82
+TA696 986
+Q3585 317
+AQKAA 42
+J9JJ9 713
+QQ448 951
+T664T 786
+J2J5J 824
+67677 635
+QQQQT 899
+333J3 442
+Q2QQ2 753
+8K79T 917
+J82A2 839
+T5TTT 155
+4K4Q8 721
+A7JAJ 306
+4Q44Q 940
+2J6KJ 854
+77979 59
+57575 296
+QK66Q 166
+Q5QQK 257
+8Q5J2 528
+TKJ27 882
+TT7T5 843
+2227A 94
+45784 594
+AQK97 468
+98TTT 446
+2886T 346
+JAA66 826
+44333 478
+A33J3 114
+Q82T6 620
+J833Q 165
+4T98J 105
+44499 775
+Q5Q5Q 245
+37477 931
+28QKT 655
+3K388 213
+J3838 19
+83444 48
+7TTAT 316
+87777 768
+KJTK5 639
+QQQ27 200
+22299 797
+99K9A 412
+44454 586
+J689T 894
+86888 294
+TATTA 456
+24452 517
+54Q42 62
+T97TT 646
+QJAAJ 533
+23K8Q 359
+AAJ5A 941
+59985 747
+6TT55 510
+Q6892 784
+Q66Q7 595
+A2223 28
+6989J 221
+944A6 659
+7K524 171
+49498 544
+55Q29 8
+8A787 351
+A7Q7Q 242
+92444 406
+558J2 255
+7JT77 258
+493K9 233
+7A333 501
+9TQ9Q 554
+J92KT 76
+9TJ67 522
+43443 906
+9TTT9 92
+66266 918
+AKKAA 543
+7ATJJ 361
+K86J6 482
+22422 633
+AAATQ 318
+64637 856
+72777 347
+6QQ66 158
+37377 990
+A8624 35
+27276 847
+22954 425
+TK4JT 819
diff --git a/23/elixir/inputs/day7_example.txt b/23/elixir/inputs/day7_example.txt
new file mode 100644
index 0000000..e3500c3
--- /dev/null
+++ b/23/elixir/inputs/day7_example.txt
@@ -0,0 +1,5 @@
+32T3K 765
+T55J5 684
+KK677 28
+KTJJT 220
+QQQJA 483
diff --git a/23/elixir/lib/day.ex b/23/elixir/lib/day.ex
new file mode 100644
index 0000000..db3ec5d
--- /dev/null
+++ b/23/elixir/lib/day.ex
@@ -0,0 +1,46 @@
+defmodule AOC.Day do
+  defmacro __using__(opts) do
+    day = Keyword.get(opts, :day)
+    debug = Keyword.get(opts, :debug, false)
+    trim = Keyword.get(opts, :trim, true)
+    input_file = Keyword.get(opts, :input, nil)
+
+    quote do
+      def solve do
+        input =
+          AOC.Day.input_lines(unquote(day), unquote(trim), unquote(input_file))
+          |> parse_input()
+
+        if unquote(debug) do
+          IO.inspect(input)
+        end
+
+        part1_solution = part1(input)
+        IO.puts("Part 1: #{part1_solution}")
+
+        part2_solution = part2(input)
+        IO.puts("Part 2: #{part2_solution}")
+      end
+    end
+  end
+
+  def input_lines(day, trim, input_file) do
+    lines =
+      input_file_name(day, input_file)
+      |> File.stream!()
+
+    if trim do
+      Enum.map(lines, &String.trim/1)
+    else
+      lines
+    end
+  end
+
+  def input_file_name(day, input_file) do
+    if input_file do
+      Path.join([File.cwd!(), "inputs", "day#{day}_#{input_file}.txt"])
+    else
+      Path.join([File.cwd!(), "inputs", "day#{day}.txt"])
+    end
+  end
+end
diff --git a/23/elixir/lib/days/day7.ex b/23/elixir/lib/days/day7.ex
new file mode 100644
index 0000000..b8faa44
--- /dev/null
+++ b/23/elixir/lib/days/day7.ex
@@ -0,0 +1,170 @@
+defmodule AOC.Day7 do
+  # use AOC.Day, day: 7, input: "example"
+  use AOC.Day, day: 7
+
+  @type_to_power %{
+    five_of_a_kind: 6,
+    four_of_a_kind: 5,
+    full_house: 4,
+    three_of_a_kind: 3,
+    two_pair: 2,
+    one_pair: 1,
+    high_card: 0
+  }
+
+  @card_to_power %{
+    ?A => 14,
+    ?K => 13,
+    ?Q => 12,
+    ?J => 11,
+    ?T => 10,
+    ?9 => 9,
+    ?8 => 8,
+    ?7 => 7,
+    ?6 => 6,
+    ?5 => 5,
+    ?4 => 4,
+    ?3 => 3,
+    ?2 => 2
+  }
+
+  def parse_input(lines) do
+    lines
+    |> Enum.map(fn line ->
+      [hand, bid] = String.split(line, " ")
+
+      {hand, String.to_integer(bid)}
+    end)
+  end
+
+  def replace_jokers(hand, card) do
+    Enum.map(hand, fn
+      ?J -> card
+      c -> c
+    end)
+  end
+
+  def best_joker_replacement(hand) do
+    freqs = Enum.frequencies(hand)
+            |> Enum.reject(fn {card, count} -> card == ?J end)
+
+    cond do
+      Enum.any?(freqs, fn {card, count} -> count == 4 end) -> 
+        {card, _} = Enum.find(freqs, fn {card, count} -> count == 4 end)
+        card
+      Enum.any?(freqs, fn {card, count} -> count == 3 end) -> 
+        {card, _} = Enum.find(freqs, fn {card, count} -> count == 3 end)
+        card
+      Enum.any?(freqs, fn {card, count} -> count == 2 end) -> 
+        doubles = Enum.filter(freqs, fn {card, count} -> count == 2 end)
+        if length(doubles) == 1 do
+          hd(doubles) |> elem(0)
+        else
+          [{double1, _}, {double2, _}] = doubles
+          if Map.fetch!(@card_to_power, double1) >= Map.fetch!(@card_to_power, double2) do
+            double1
+          else
+            double2
+          end
+        end
+      true ->
+        freqs
+        |> Enum.map(fn {card, count} -> card end)
+        |> Enum.sort(fn card1, card2 -> 
+          Map.fetch!(@card_to_power, card1) >= Map.fetch!(@card_to_power, card2)
+        end)
+        |> hd()
+    end
+  end
+
+  def find_best_joker_configuration(hand) do
+    freqs = Enum.frequencies(hand)
+    joker_count = Map.get(freqs, ?J, 0)
+    
+    case joker_count do
+      0 -> hand
+      5 -> 'AAAAA'
+      _ ->
+        joker_replacement = best_joker_replacement(hand)
+        
+        replace_jokers(hand, joker_replacement)
+    end
+  end
+
+  def hand_to_type(hand, joker_rule) do
+    freqs = hand
+    |> String.to_charlist()
+    |> then(fn hand ->
+      if joker_rule do
+        find_best_joker_configuration(hand)
+      else
+        hand
+      end
+    end)
+    |> Enum.frequencies()
+    |> Enum.map(fn {_k, v} -> v end)
+
+    cond do
+      Enum.member?(freqs, 5) -> :five_of_a_kind
+      Enum.member?(freqs, 4) -> :four_of_a_kind
+      Enum.member?(freqs, 3) and Enum.member?(freqs, 2) -> :full_house
+      Enum.member?(freqs, 3) -> :three_of_a_kind
+      Enum.count(freqs, & &1==2) == 2 -> :two_pair
+      Enum.member?(freqs, 2) -> :one_pair
+      true -> :high_card
+    end
+  end
+
+  def compare_same_type_hands(hand1, hand2, joker_rule) do
+    hand1 = String.to_charlist(hand1)
+    hand2 = String.to_charlist(hand2)
+
+    Enum.zip(hand1, hand2)
+    |> compare_same_type_hands2(joker_rule)
+  end
+
+  def compare_same_type_hands2([], _), do: true
+
+  def compare_same_type_hands2([{card1, card2} | tl], joker_rule) do
+    if card1 == card2 do
+      compare_same_type_hands2(tl, joker_rule)
+    else
+      cond do
+        joker_rule and card1 == ?J -> false
+        joker_rule and card2 == ?J -> true
+        true -> Map.fetch!(@card_to_power, card1) >= Map.fetch!(@card_to_power, card2)
+      end
+    end
+  end
+
+  def sort_hands(hands, joker_rule \\ false) do
+    Enum.sort(hands, fn {hand1, _bid1}, {hand2, _bid2} ->
+      type1 = hand_to_type(hand1, joker_rule)
+      type2 = hand_to_type(hand2, joker_rule)
+
+      if type1 == type2 do
+        compare_same_type_hands(hand1, hand2, joker_rule)
+      else
+        Map.fetch!(@type_to_power, type1) >= Map.fetch!(@type_to_power, type2)
+      end
+    end)
+  end
+
+  def part1(input) do
+    input
+    |> sort_hands()
+    |> Enum.reverse()
+    |> Enum.with_index(1)
+    |> Enum.map(fn {{_card, bid}, rank} -> rank * bid end)
+    |> Enum.sum()
+  end
+
+  def part2(input) do
+    input
+    |> sort_hands(true)
+    |> Enum.reverse()
+    |> Enum.with_index(1)
+    |> Enum.map(fn {{_card, bid}, rank} -> rank * bid end)
+    |> Enum.sum()
+  end
+end
diff --git a/23/elixir/mix.exs b/23/elixir/mix.exs
new file mode 100644
index 0000000..333c6a7
--- /dev/null
+++ b/23/elixir/mix.exs
@@ -0,0 +1,28 @@
+defmodule AOC.MixProject do
+  use Mix.Project
+
+  def project do
+    [
+      app: :aoc,
+      version: "0.1.0",
+      elixir: "~> 1.15",
+      start_permanent: Mix.env() == :prod,
+      deps: deps()
+    ]
+  end
+
+  # Run "mix help compile.app" to learn about applications.
+  def application do
+    [
+      extra_applications: [:logger]
+    ]
+  end
+
+  # Run "mix help deps" to learn about dependencies.
+  defp deps do
+    [
+      # {:dep_from_hexpm, "~> 0.3.0"},
+      # {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}
+    ]
+  end
+end
diff --git a/23/elixir/test/aoc_test.exs b/23/elixir/test/aoc_test.exs
new file mode 100644
index 0000000..a426096
--- /dev/null
+++ b/23/elixir/test/aoc_test.exs
@@ -0,0 +1,8 @@
+defmodule AocTest do
+  use ExUnit.Case
+  doctest Aoc
+
+  test "greets the world" do
+    assert Aoc.hello() == :world
+  end
+end
diff --git a/23/elixir/test/test_helper.exs b/23/elixir/test/test_helper.exs
new file mode 100644
index 0000000..869559e
--- /dev/null
+++ b/23/elixir/test/test_helper.exs
@@ -0,0 +1 @@
+ExUnit.start()

From 9504b4ecabd17bc2bf8e0001ae32cdf7872b4f05 Mon Sep 17 00:00:00 2001
From: Pim Kunis <pim@kunis.nl>
Date: Fri, 8 Dec 2023 10:00:27 +0100
Subject: [PATCH 2/2] add day 8

---
 23/.envrc                          |   1 +
 23/elixir/inputs/day8.txt          | 796 +++++++++++++++++++++++++++++
 23/elixir/inputs/day8_example1.txt |   9 +
 23/elixir/inputs/day8_example2.txt |   5 +
 23/elixir/inputs/day8_example3.txt |  10 +
 23/elixir/lib/days/day7.ex         |  16 +-
 23/elixir/lib/days/day8.ex         |  81 +++
 23/elixir/mix.lock                 |   3 +
 23/flake.lock                      |  27 +
 23/flake.nix                       |  22 +
 10 files changed, 962 insertions(+), 8 deletions(-)
 create mode 100644 23/.envrc
 create mode 100644 23/elixir/inputs/day8.txt
 create mode 100644 23/elixir/inputs/day8_example1.txt
 create mode 100644 23/elixir/inputs/day8_example2.txt
 create mode 100644 23/elixir/inputs/day8_example3.txt
 create mode 100644 23/elixir/lib/days/day8.ex
 create mode 100644 23/elixir/mix.lock
 create mode 100644 23/flake.lock
 create mode 100644 23/flake.nix

diff --git a/23/.envrc b/23/.envrc
new file mode 100644
index 0000000..3550a30
--- /dev/null
+++ b/23/.envrc
@@ -0,0 +1 @@
+use flake
diff --git a/23/elixir/inputs/day8.txt b/23/elixir/inputs/day8.txt
new file mode 100644
index 0000000..2937e6c
--- /dev/null
+++ b/23/elixir/inputs/day8.txt
@@ -0,0 +1,796 @@
+LLRLRRLLRLRRLLRLRRLRRRLRLRLRRRLLRLRRRLRLRRRLRLRLLLRRLRLRLLRLRRLRRRLRRRLLRRLRLRRRLRRLRRRLRLLRRLRRRLRRRLRRLRLRRLLLRLRLLRRRLRRLLRLRLRRLLRLRRLLRLRRLRRLLRRRLRLRLRRRLLRRRLRRLRRRLRRRLRLRRRLRRLLLRRRLRLLLRRRLRLLRLLRRRLLRRLRRRLRRRLRLLRLRLRRRLLRRLRRRLRRLRLLRRRLRRLRRRLRRRLRRRLRLRRRLRRRLRLRRRR
+
+XGS = (FDM, XCS)
+PJD = (XJN, PCV)
+FLJ = (VRH, NBF)
+RXS = (DNN, DHH)
+DQD = (NTV, CRQ)
+HGJ = (QJF, JTK)
+JDL = (QHC, TKN)
+VMX = (DVX, KDB)
+SPX = (FMD, MQS)
+DSQ = (BNF, PDJ)
+XJQ = (QST, MFT)
+BGX = (MSH, JQQ)
+CMT = (FSP, SCN)
+BVV = (LPL, LPL)
+MBR = (BHB, RMB)
+VVP = (QTP, TJC)
+BFC = (SMR, SMR)
+DTN = (CMN, NVG)
+BVN = (BKM, KPN)
+BCR = (MHM, MPT)
+NDK = (NHG, RVN)
+FRR = (NKL, KKN)
+XDP = (GBQ, VGF)
+KCS = (CXN, GGR)
+HLG = (FMQ, NXV)
+MTP = (KFV, QCH)
+VFH = (GPQ, RFK)
+HSG = (JKV, KNK)
+THL = (CPG, BBF)
+FJP = (CVM, BVF)
+TGR = (LNL, JGD)
+JJD = (QLT, QMC)
+DQK = (NDK, NFS)
+KFN = (PJK, XSJ)
+QLN = (NKV, MGT)
+GJR = (HBJ, HLG)
+JXD = (NFK, KMD)
+CGM = (QHF, PJR)
+FPM = (DHB, VBS)
+NMK = (MVX, MFM)
+SJQ = (VBD, GKP)
+XVX = (KCS, TNV)
+FNC = (BCR, LQB)
+KLA = (XKM, DNG)
+CHD = (TPM, BHH)
+RMV = (PBC, QPM)
+BXH = (QDC, LKX)
+VQK = (HRJ, LBX)
+VNR = (SDB, JQL)
+TQS = (JPX, NLL)
+RPK = (KTX, XKP)
+AAA = (XMG, HJX)
+NQS = (TGB, RDK)
+JKK = (SFX, VDH)
+DKM = (RXJ, DXF)
+VGF = (MXT, LKT)
+KQN = (KTG, NCT)
+MXV = (HFT, QJM)
+CKP = (FMC, JPT)
+HGP = (JMV, DXV)
+VRC = (NVR, NHK)
+DPR = (VBV, FLJ)
+VBL = (PXB, BVN)
+GSG = (KSL, VSX)
+FNK = (VPD, NKN)
+LVB = (SQB, SQB)
+PRF = (HNP, TDG)
+TGV = (NVR, NHK)
+DXV = (QNK, PKL)
+KMP = (KVB, VMR)
+BTR = (LKF, PJD)
+QHC = (DFT, DTJ)
+RXM = (LRG, NPH)
+KTX = (RFR, QRT)
+JHR = (BRV, QRB)
+JDH = (BFX, DTN)
+JLQ = (TTV, GKH)
+CMQ = (HQL, PJP)
+DJF = (JTK, QJF)
+KVB = (MXL, PTK)
+DMD = (HXP, ZZZ)
+XJV = (CRV, JLM)
+JXR = (JMQ, LQM)
+DFT = (DRN, JQM)
+JSC = (XFX, XFX)
+CKB = (VVK, XBK)
+RFJ = (CKP, QMH)
+HRP = (LQT, CJV)
+HXJ = (CKB, FCT)
+DMX = (CRV, JLM)
+XBK = (LVB, FXN)
+JVP = (SKF, LCK)
+JLV = (VPT, DMK)
+SXK = (TNR, MTF)
+DTJ = (JQM, DRN)
+KLN = (FDX, NPN)
+SKG = (BTR, HXG)
+RFR = (XCT, FHN)
+FKB = (JJL, CGM)
+HNP = (DKR, JLQ)
+HKC = (FDM, XCS)
+QQN = (MTP, DCG)
+QRX = (RPJ, PQM)
+SMD = (BBD, DSQ)
+SFJ = (JMR, JMR)
+CJZ = (QMH, CKP)
+PGB = (SDJ, LQF)
+CMS = (XSG, TFG)
+JMV = (PKL, QNK)
+GHH = (RHT, RXS)
+NLN = (XJX, MVC)
+RCG = (DCG, MTP)
+XHF = (SSF, CBS)
+PNC = (GPB, MJJ)
+RXC = (XHF, LDN)
+XVM = (NKR, KQG)
+MTF = (FKN, FKV)
+FGM = (JPJ, DFG)
+MTG = (RRX, FFL)
+HCC = (RFS, PBH)
+TJL = (RPJ, PQM)
+RDK = (RLT, MMJ)
+CSD = (MDQ, HSG)
+KVP = (VRC, TGV)
+QJM = (LSF, DQK)
+TTV = (RCC, LXJ)
+TJC = (RDG, LFV)
+BFS = (FFL, RRX)
+BRV = (NRJ, HCN)
+HXP = (XMG, HJX)
+NJK = (MJT, GBX)
+DGV = (NDH, DPB)
+RGD = (KBH, XDP)
+CRV = (QBD, QLJ)
+RPS = (LPH, PRR)
+PLF = (BHH, TPM)
+SJF = (LFB, NMD)
+HLQ = (XJX, MVC)
+SJR = (XKM, DNG)
+TQP = (BTG, QJG)
+MTJ = (JPJ, DFG)
+SQB = (RFJ, RFJ)
+KPN = (VTC, LDH)
+BDZ = (CQP, HRP)
+QFC = (XJQ, PMR)
+XMV = (HTS, RXT)
+MQS = (FXV, VCL)
+TLQ = (XMV, TSC)
+TCQ = (CXH, RCV)
+KNK = (CBD, VQK)
+GHD = (DBJ, VPK)
+TKP = (TXK, MPJ)
+CCC = (NKL, KKN)
+QFN = (TJD, JDJ)
+DVJ = (GQM, QKJ)
+TNC = (PVV, PMJ)
+HJX = (DQD, JDR)
+NFF = (JMR, GTZ)
+JSB = (SLS, HSC)
+NVR = (CTV, PNS)
+FNV = (XLK, FNC)
+JVR = (TGB, RDK)
+TXM = (SNN, DMZ)
+CNF = (KLN, BDB)
+QRG = (PDS, MHP)
+QVV = (JJD, RLL)
+XML = (VMR, KVB)
+TLB = (NTD, VKD)
+SDJ = (CNQ, FNV)
+TKN = (DTJ, DFT)
+HFK = (LPF, XPH)
+LJP = (SFJ, SFJ)
+SMX = (RQV, DDH)
+JBL = (XML, KMP)
+NDA = (PBF, FHP)
+LRP = (XKP, KTX)
+JCK = (BGC, CNF)
+XCF = (SPJ, CVR)
+VNV = (CMQ, JPQ)
+BPJ = (XVP, DXQ)
+MVC = (QFC, DLV)
+QRK = (SDJ, LQF)
+BFX = (CMN, NVG)
+JMQ = (MFC, RXD)
+JPQ = (PJP, HQL)
+FCN = (NPH, LRG)
+RXQ = (FMG, GJF)
+DVX = (GSS, CFM)
+CSH = (VQF, PTV)
+STM = (CFH, BMQ)
+NVF = (CSH, VHC)
+CKG = (VSX, KSL)
+BLG = (QHJ, DLB)
+RCB = (VVX, XCF)
+MGX = (HGT, HGP)
+NVG = (KMC, VSM)
+JLM = (QBD, QLJ)
+NKR = (HCD, RQC)
+QKJ = (VXK, TRR)
+XSJ = (TCQ, PCL)
+HQP = (HSJ, DGV)
+NPQ = (RBR, FNB)
+DDH = (PTQ, KQN)
+KTG = (DHL, KSX)
+MHP = (FCX, VCB)
+LBA = (CKP, QMH)
+GBX = (DLC, JRX)
+TKX = (RNJ, PPC)
+FHK = (KCV, NBK)
+CJV = (RCG, QQN)
+PPC = (JDH, SBM)
+KKN = (KVP, HBC)
+HBT = (XDM, PGN)
+CNC = (FVV, TCX)
+MXL = (BMP, BPJ)
+XVP = (TRL, HVN)
+XLX = (JSK, KNX)
+FCT = (VVK, XBK)
+CFH = (VRX, XMK)
+TNV = (CXN, GGR)
+JHK = (VQR, LDL)
+JPJ = (JBL, NBC)
+TNR = (FKV, FKN)
+RXJ = (SKG, BFK)
+QDV = (RHT, RXS)
+QQQ = (XHH, JVP)
+HGS = (MFV, DKC)
+NBK = (LNV, QLN)
+LDL = (CRJ, PRF)
+JRL = (KJS, PVK)
+FXR = (HCS, CMT)
+NVX = (GJR, GTQ)
+CFM = (SMT, SXK)
+TFG = (SPN, TLF)
+PPF = (KJN, NXJ)
+VPV = (HQP, KRB)
+MGT = (TJL, QRX)
+LGB = (KBH, XDP)
+BNS = (CTP, CBL)
+KSX = (BFS, MTG)
+GDD = (NBP, STP)
+CJQ = (VHM, JNQ)
+GQC = (NTD, VKD)
+FMC = (SKX, LRF)
+PTQ = (KTG, NCT)
+KNG = (BRV, QRB)
+KQG = (RQC, HCD)
+NSG = (HXJ, LBP)
+QPM = (KPK, XVX)
+CXH = (LGS, LQR)
+LCF = (GBS, MHB)
+VBD = (MBR, NBJ)
+SDB = (SVM, JJM)
+DCR = (FVK, KGG)
+BDJ = (XRG, CQL)
+JMR = (VRM, NFN)
+XFR = (LQM, JMQ)
+MBP = (CBL, CTP)
+GVD = (CLB, FMF)
+MFH = (PPC, RNJ)
+PTK = (BMP, BPJ)
+LGJ = (PXP, HJK)
+GKP = (MBR, NBJ)
+HXG = (LKF, PJD)
+NBC = (XML, KMP)
+SJG = (LPF, XPH)
+BKM = (VTC, LDH)
+DKC = (NQS, JVR)
+JSJ = (TQP, RLR)
+PMR = (QST, MFT)
+BRM = (PRR, LPH)
+KRL = (BGX, XNX)
+TCX = (GQC, TLB)
+QLJ = (FPS, JFN)
+HCD = (FXR, PJJ)
+TBN = (DSJ, VPV)
+FFL = (NBB, FKB)
+GRN = (HCC, NJF)
+LQB = (MHM, MPT)
+SFX = (LGB, RGD)
+HJB = (VNR, KFT)
+HRJ = (GLC, CHR)
+MJT = (DLC, JRX)
+FHN = (HHG, RMV)
+VTJ = (BFC, JTL)
+CQP = (CJV, LQT)
+VCB = (NGR, JRL)
+VNN = (JKK, SCK)
+XNT = (RXQ, LJS)
+SCN = (TNC, LGP)
+FMF = (TKP, NNT)
+VSM = (HNF, RLF)
+CNQ = (FNC, XLK)
+MPT = (TLQ, SBG)
+DSJ = (KRB, HQP)
+CXV = (QRK, PGB)
+LBX = (GLC, CHR)
+VBV = (NBF, VRH)
+TJQ = (LCH, HTJ)
+CPG = (QVC, CJQ)
+KJN = (PLB, DGH)
+NCM = (VTJ, SXJ)
+FXV = (NCM, SDH)
+XRG = (DPR, MXD)
+LCM = (PMN, VCS)
+SHN = (SMK, PHG)
+MXD = (FLJ, VBV)
+FDJ = (LKV, BKX)
+JDR = (NTV, CRQ)
+XDR = (LPV, XTH)
+RNJ = (JDH, SBM)
+FHP = (MGQ, HJB)
+PVH = (GPQ, GPQ)
+MGM = (RBS, HPR)
+VFQ = (RBR, FNB)
+XRV = (LCH, HTJ)
+DGP = (FDJ, GTJ)
+HJV = (DHB, VBS)
+KPK = (TNV, KCS)
+CMX = (DBJ, VPK)
+BHH = (VRN, SMX)
+PJL = (NLS, SCL)
+SPJ = (RXM, FCN)
+NTV = (TSJ, BSR)
+FXN = (SQB, GLR)
+DTK = (VVP, TCD)
+DBJ = (MFH, TKX)
+DCJ = (BTP, GVD)
+NMD = (DJB, MGC)
+PBC = (XVX, KPK)
+FRS = (KMD, NFK)
+LNL = (SQC, DTK)
+NGH = (XKL, HPT)
+RFS = (CHD, PLF)
+DMK = (JJT, FHK)
+SNS = (SHN, BMD)
+RLR = (BTG, QJG)
+FDM = (GRN, CBK)
+PLB = (CCT, JTT)
+VTC = (CMS, XSC)
+XKM = (QGF, TBN)
+MVJ = (SLB, TXM)
+PKL = (CSQ, SJQ)
+SLB = (SNN, SNN)
+JKV = (VQK, CBD)
+BBD = (BNF, PDJ)
+GSS = (SXK, SMT)
+LRG = (SPB, TGR)
+FDN = (JXD, FRS)
+XKX = (HXC, PGT)
+PDJ = (FRR, CCC)
+HXM = (VNN, VJG)
+QMC = (CXV, TLH)
+GLG = (GGV, VBL)
+RXT = (LCF, GBT)
+TGL = (NXJ, KJN)
+JPT = (SKX, LRF)
+NLL = (SPX, DDQ)
+BHB = (RGP, FQL)
+XKN = (HBT, XXG)
+RLT = (JLB, BDJ)
+SHF = (HGP, HGT)
+HKV = (DLB, QHJ)
+SVM = (XDR, BLN)
+PMN = (QTL, QRG)
+CXN = (JLV, FMT)
+GQV = (PJK, XSJ)
+HMM = (MGX, SHF)
+VSC = (PDH, XVM)
+LCK = (NSG, JPR)
+JQL = (JJM, SVM)
+FRQ = (SVG, DCR)
+TDG = (JLQ, DKR)
+SMT = (TNR, MTF)
+GBT = (GBS, MHB)
+QMH = (JPT, FMC)
+DXJ = (CMQ, JPQ)
+JJM = (XDR, BLN)
+DDQ = (FMD, MQS)
+NDH = (VVQ, DCM)
+LSF = (NFS, NDK)
+VGM = (STS, XNT)
+PJR = (GXF, JDL)
+XFC = (XVM, PDH)
+LBP = (CKB, FCT)
+KFT = (SDB, JQL)
+TTT = (QLS, GCV)
+LPH = (SJF, BPT)
+JGS = (XKL, HPT)
+VDH = (LGB, RGD)
+VHC = (VQF, PTV)
+NKN = (GDD, XDC)
+RND = (VGM, PSD)
+QVC = (VHM, JNQ)
+JJL = (QHF, PJR)
+QRB = (NRJ, HCN)
+MJJ = (FQT, RXC)
+NNA = (HRP, CQP)
+PBF = (MGQ, HJB)
+VRT = (DSS, FDN)
+DCM = (CLV, JCK)
+QLS = (SJR, SJR)
+RMT = (XHH, JVP)
+DMR = (MLF, MVJ)
+QJG = (NLN, HLQ)
+DLV = (XJQ, PMR)
+LKF = (XJN, PCV)
+VQR = (PRF, CRJ)
+SXJ = (BFC, JTL)
+MDQ = (KNK, JKV)
+QVD = (BVF, CVM)
+TGG = (LPL, BDZ)
+HDJ = (HGB, HSH)
+HTT = (LHQ, HGS)
+SKX = (HXM, JMF)
+FCX = (NGR, JRL)
+HSJ = (NDH, DPB)
+BFK = (HXG, BTR)
+XSG = (SPN, TLF)
+NCD = (MFM, MVX)
+PHG = (BKS, SMD)
+XMK = (QVD, FJP)
+FXL = (PGT, HXC)
+KBH = (VGF, GBQ)
+CBG = (QDC, LKX)
+LDN = (SSF, CBS)
+SVG = (FVK, KGG)
+BVF = (GHH, QDV)
+SPB = (LNL, JGD)
+LQR = (QXX, LCM)
+KHV = (JSK, KNX)
+LFV = (XFJ, XKN)
+QHG = (JJD, RLL)
+HGB = (LRP, RPK)
+NRJ = (DXJ, VNV)
+LKT = (PNC, LJX)
+MSH = (CDN, DMS)
+MLF = (SLB, SLB)
+MMJ = (JLB, BDJ)
+VRM = (HSR, HTT)
+MHM = (TLQ, SBG)
+LRF = (HXM, JMF)
+VHM = (PVH, VFH)
+FQL = (XRV, TJQ)
+MPJ = (LFS, CFJ)
+LMF = (CNC, KCC)
+JTK = (XJR, DGP)
+HFT = (DQK, LSF)
+RQV = (PTQ, KQN)
+LDT = (BMQ, CFH)
+RGP = (TJQ, XRV)
+SDH = (VTJ, SXJ)
+LKV = (JVB, TFD)
+KDD = (XFX, XGV)
+CVM = (GHH, QDV)
+PLS = (DVX, KDB)
+VCL = (NCM, SDH)
+SCK = (SFX, VDH)
+LJX = (MJJ, GPB)
+JTT = (LMF, SVS)
+PHV = (KRL, SVD)
+PDS = (VCB, FCX)
+VPD = (XDC, GDD)
+VRJ = (HXP, HXP)
+LPV = (HKC, XGS)
+BDB = (FDX, NPN)
+DXF = (BFK, SKG)
+FMG = (JGS, NGH)
+NXV = (LJP, SBT)
+PQM = (QVV, QHG)
+SNN = (PBF, FHP)
+LGP = (PMJ, PVV)
+FKV = (CBG, BXH)
+VJG = (JKK, SCK)
+JPR = (HXJ, LBP)
+TPM = (SMX, VRN)
+KXT = (VQR, LDL)
+NPN = (FRQ, SRD)
+TRL = (DCJ, BLS)
+CBK = (NJF, HCC)
+KMD = (GQV, KFN)
+GQM = (TRR, VXK)
+QST = (RMT, QQQ)
+XDM = (KXT, JHK)
+TLH = (QRK, PGB)
+VRH = (BNS, MBP)
+VVK = (LVB, LVB)
+HVN = (BLS, DCJ)
+TLJ = (HSG, MDQ)
+QLQ = (STM, LDT)
+LKX = (DBT, XTS)
+VXK = (DKM, KKV)
+XKL = (NPQ, VFQ)
+LDP = (BPH, RCB)
+VRN = (RQV, DDH)
+LJS = (FMG, GJF)
+FMT = (DMK, VPT)
+BPT = (LFB, NMD)
+RLL = (QMC, QLT)
+JNQ = (PVH, VFH)
+HJK = (JSC, KDD)
+QHF = (JDL, GXF)
+DGH = (JTT, CCT)
+PVV = (RND, XCQ)
+XFX = (VRJ, VRJ)
+NRN = (GQM, QKJ)
+VPK = (TKX, MFH)
+GLC = (PPF, TGL)
+JJT = (KCV, NBK)
+FVK = (XQS, PJL)
+VRD = (RCB, BPH)
+GPQ = (BVV, BVV)
+XCT = (HHG, RMV)
+VMR = (PTK, MXL)
+NTD = (XJV, DMX)
+CBS = (GHD, CMX)
+SNZ = (DNG, XKM)
+QTP = (LFV, RDG)
+DMZ = (FHP, PBF)
+LQT = (RCG, QQN)
+FPS = (RBX, DMR)
+LGS = (LCM, QXX)
+ZZZ = (HJX, XMG)
+RCV = (LQR, LGS)
+PBH = (CHD, PLF)
+JPX = (DDQ, SPX)
+DNN = (MXV, DVB)
+QRT = (XCT, FHN)
+HHG = (PBC, QPM)
+SBM = (BFX, DTN)
+JVB = (VSC, XFC)
+QNK = (CSQ, SJQ)
+BPM = (KNG, JHR)
+HBC = (TGV, VRC)
+MGQ = (VNR, KFT)
+BTP = (CLB, FMF)
+SVD = (BGX, XNX)
+RHT = (DHH, DNN)
+KJS = (FRN, JSB)
+BLS = (GVD, BTP)
+TJD = (JXR, XFR)
+RMS = (HJV, FPM)
+MFV = (JVR, NQS)
+DXQ = (HVN, TRL)
+HSC = (BRM, RPS)
+CCP = (GGV, VBL)
+GTB = (QKQ, PHV)
+RBX = (MLF, MLF)
+MDN = (GBX, MJT)
+HXC = (KPF, DJL)
+HSR = (HGS, LHQ)
+BMD = (PHG, SMK)
+GTZ = (NFN, VRM)
+LDH = (CMS, XSC)
+NXJ = (PLB, DGH)
+FGR = (GJR, GTQ)
+KKV = (RXJ, DXF)
+XCQ = (PSD, VGM)
+JQQ = (DMS, CDN)
+XCS = (GRN, CBK)
+JQM = (FNK, DKQ)
+DNG = (QGF, TBN)
+GBQ = (MXT, LKT)
+QLT = (TLH, CXV)
+HTL = (NLL, JPX)
+DLB = (VRF, THL)
+GTQ = (HBJ, HLG)
+NBB = (CGM, JJL)
+GPB = (FQT, RXC)
+QBD = (FPS, JFN)
+NHG = (NRN, DVJ)
+TRR = (KKV, DKM)
+DJB = (XKX, FXL)
+CBD = (HRJ, LBX)
+CFJ = (BPM, RPN)
+TXK = (CFJ, LFS)
+TCD = (QTP, TJC)
+XTS = (GLG, CCP)
+PGN = (KXT, JHK)
+BMP = (XVP, DXQ)
+CQL = (MXD, DPR)
+HGT = (DXV, JMV)
+JDJ = (XFR, JXR)
+KRB = (HSJ, DGV)
+BSR = (VRT, GTK)
+RMB = (RGP, FQL)
+BKS = (BBD, DSQ)
+LQM = (RXD, MFC)
+RQC = (FXR, PJJ)
+TSC = (RXT, HTS)
+XPH = (HGJ, DJF)
+NPH = (TGR, SPB)
+SCL = (HDJ, PQL)
+XHH = (LCK, SKF)
+CBL = (MTJ, FGM)
+VQF = (QLQ, XLH)
+LPL = (HRP, CQP)
+VKD = (DMX, XJV)
+XJX = (DLV, QFC)
+KCC = (TCX, FVV)
+GJK = (RMS, RFL)
+JTL = (SMR, TTT)
+XMG = (JDR, DQD)
+PQL = (HSH, HGB)
+LCH = (GJK, DMM)
+PMJ = (RND, XCQ)
+FRN = (SLS, HSC)
+CHR = (PPF, TGL)
+DFG = (NBC, JBL)
+PJJ = (HCS, CMT)
+CRJ = (HNP, TDG)
+RLF = (JSJ, GMJ)
+GKH = (LXJ, RCC)
+RNT = (TJD, JDJ)
+CLV = (CNF, BGC)
+DRN = (FNK, DKQ)
+RDG = (XKN, XFJ)
+BNF = (CCC, FRR)
+HQH = (HPR, RBS)
+QJF = (DGP, XJR)
+NJF = (PBH, RFS)
+FKN = (CBG, BXH)
+FSP = (LGP, TNC)
+RXD = (SJG, HFK)
+PCL = (RCV, CXH)
+CLB = (NNT, TKP)
+XNX = (JQQ, MSH)
+VVQ = (JCK, CLV)
+DHH = (DVB, MXV)
+MXT = (LJX, PNC)
+MFC = (SJG, HFK)
+QKQ = (SVD, KRL)
+CVR = (FCN, RXM)
+RFK = (BVV, TGG)
+NBP = (HQH, MGM)
+QXX = (VCS, PMN)
+PVK = (FRN, JSB)
+HCN = (DXJ, VNV)
+XLK = (LQB, BCR)
+HPR = (HMM, CNT)
+VDF = (PHV, QKQ)
+KNX = (LGJ, CMC)
+PXB = (KPN, BKM)
+HNF = (GMJ, JSJ)
+DKR = (GKH, TTV)
+NGR = (KJS, PVK)
+QDC = (XTS, DBT)
+LPF = (DJF, HGJ)
+LXJ = (FGR, NVX)
+NBJ = (RMB, BHB)
+QGF = (DSJ, VPV)
+KSL = (QFN, RNT)
+DHL = (BFS, MTG)
+STP = (MGM, HQH)
+FMQ = (LJP, LJP)
+TGB = (RLT, MMJ)
+TLF = (NCD, NMK)
+NLS = (PQL, HDJ)
+HRG = (SHN, BMD)
+DMM = (RMS, RFL)
+VPT = (JJT, FHK)
+SKF = (JPR, NSG)
+NFN = (HTT, HSR)
+KGG = (PJL, XQS)
+DHB = (CSD, TLJ)
+QVA = (VRM, NFN)
+SSF = (GHD, CMX)
+LFB = (DJB, MGC)
+GMJ = (TQP, RLR)
+HTS = (GBT, LCF)
+FQT = (LDN, XHF)
+TFD = (VSC, XFC)
+CMC = (PXP, HJK)
+VBS = (CSD, TLJ)
+DLC = (KHV, XLX)
+NKV = (TJL, QRX)
+KFV = (GSG, CKG)
+GGV = (BVN, PXB)
+DKQ = (NKN, VPD)
+SLS = (RPS, BRM)
+PJP = (VDF, GTB)
+BTG = (NLN, HLQ)
+VCS = (QTL, QRG)
+CSQ = (GKP, VBD)
+CCT = (LMF, SVS)
+NNT = (TXK, MPJ)
+XTH = (XGS, HKC)
+SMK = (BKS, SMD)
+HCS = (SCN, FSP)
+HPT = (NPQ, VFQ)
+KPF = (NVF, CDF)
+PDH = (KQG, NKR)
+PCV = (NJK, MDN)
+XXG = (PGN, XDM)
+MGC = (FXL, XKX)
+QTL = (PDS, MHP)
+JLB = (CQL, XRG)
+RVN = (DVJ, NRN)
+CTP = (FGM, MTJ)
+RCC = (FGR, NVX)
+CDF = (VHC, CSH)
+NKL = (HBC, KVP)
+PTV = (XLH, QLQ)
+BBF = (QVC, CJQ)
+TSJ = (VRT, GTK)
+GCV = (SJR, SNZ)
+NBF = (MBP, BNS)
+PSD = (XNT, STS)
+XLH = (LDT, STM)
+NFK = (GQV, KFN)
+VVX = (CVR, SPJ)
+PNS = (VMX, PLS)
+RBR = (HRG, SNS)
+SBT = (SFJ, NFF)
+DBT = (CCP, GLG)
+RPN = (KNG, JHR)
+XFJ = (HBT, XXG)
+JSK = (LGJ, CMC)
+CNT = (SHF, MGX)
+HBJ = (FMQ, NXV)
+VRX = (FJP, QVD)
+RBS = (CNT, HMM)
+STS = (RXQ, LJS)
+DVB = (QJM, HFT)
+JRX = (XLX, KHV)
+RPJ = (QHG, QVV)
+KDB = (GSS, CFM)
+LHQ = (MFV, DKC)
+RRX = (FKB, NBB)
+HTJ = (GJK, DMM)
+CDN = (VRD, LDP)
+NFS = (RVN, NHG)
+XJR = (GTJ, FDJ)
+NCT = (DHL, KSX)
+NHK = (CTV, PNS)
+BGC = (KLN, BDB)
+XJN = (MDN, NJK)
+MFT = (RMT, QQQ)
+RFL = (HJV, FPM)
+XQS = (NLS, SCL)
+BPH = (XCF, VVX)
+SBG = (TSC, XMV)
+LNV = (MGT, NKV)
+QCH = (CKG, GSG)
+JMF = (VNN, VJG)
+LQF = (FNV, CNQ)
+MVX = (HKV, BLG)
+SQC = (VVP, TCD)
+PGT = (DJL, KPF)
+MFM = (BLG, HKV)
+FMD = (VCL, FXV)
+VRF = (BBF, CPG)
+GTJ = (LKV, BKX)
+XGV = (VRJ, DMD)
+CTV = (PLS, VMX)
+GLR = (RFJ, CJZ)
+PXP = (JSC, KDD)
+SRD = (SVG, DCR)
+GGR = (FMT, JLV)
+HSH = (RPK, LRP)
+GXF = (QHC, TKN)
+GBS = (TQS, HTL)
+MHB = (HTL, TQS)
+GTK = (DSS, FDN)
+DJL = (CDF, NVF)
+DPB = (VVQ, DCM)
+DCG = (KFV, QCH)
+FDX = (SRD, FRQ)
+XKP = (QRT, RFR)
+FVV = (GQC, TLB)
+DMS = (VRD, LDP)
+SVS = (KCC, CNC)
+PRR = (SJF, BPT)
+LFS = (RPN, BPM)
+BLN = (XTH, LPV)
+SPN = (NMK, NCD)
+CMN = (KMC, VSM)
+QHJ = (THL, VRF)
+JGD = (DTK, SQC)
+KCV = (QLN, LNV)
+CRQ = (TSJ, BSR)
+JFN = (RBX, DMR)
+GJF = (NGH, JGS)
+VSX = (RNT, QFN)
+HQL = (VDF, GTB)
+KMC = (HNF, RLF)
+XSC = (TFG, XSG)
+XDC = (STP, NBP)
+PJK = (TCQ, PCL)
+DSS = (JXD, FRS)
+SMR = (QLS, QLS)
+BMQ = (VRX, XMK)
+FNB = (SNS, HRG)
+BKX = (TFD, JVB)
diff --git a/23/elixir/inputs/day8_example1.txt b/23/elixir/inputs/day8_example1.txt
new file mode 100644
index 0000000..9029a1b
--- /dev/null
+++ b/23/elixir/inputs/day8_example1.txt
@@ -0,0 +1,9 @@
+RL
+
+AAA = (BBB, CCC)
+BBB = (DDD, EEE)
+CCC = (ZZZ, GGG)
+DDD = (DDD, DDD)
+EEE = (EEE, EEE)
+GGG = (GGG, GGG)
+ZZZ = (ZZZ, ZZZ)
diff --git a/23/elixir/inputs/day8_example2.txt b/23/elixir/inputs/day8_example2.txt
new file mode 100644
index 0000000..7d1b58d
--- /dev/null
+++ b/23/elixir/inputs/day8_example2.txt
@@ -0,0 +1,5 @@
+LLR
+
+AAA = (BBB, BBB)
+BBB = (AAA, ZZZ)
+ZZZ = (ZZZ, ZZZ)
diff --git a/23/elixir/inputs/day8_example3.txt b/23/elixir/inputs/day8_example3.txt
new file mode 100644
index 0000000..5b3fa58
--- /dev/null
+++ b/23/elixir/inputs/day8_example3.txt
@@ -0,0 +1,10 @@
+LR
+
+11A = (11B, XXX)
+11B = (XXX, 11Z)
+11Z = (11B, XXX)
+22A = (22B, XXX)
+22B = (22C, 22C)
+22C = (22Z, 22Z)
+22Z = (22B, 22B)
+XXX = (XXX, XXX)
diff --git a/23/elixir/lib/days/day7.ex b/23/elixir/lib/days/day7.ex
index b8faa44..e03d7b5 100644
--- a/23/elixir/lib/days/day7.ex
+++ b/23/elixir/lib/days/day7.ex
@@ -46,17 +46,17 @@ defmodule AOC.Day7 do
 
   def best_joker_replacement(hand) do
     freqs = Enum.frequencies(hand)
-            |> Enum.reject(fn {card, count} -> card == ?J end)
+            |> Enum.reject(fn {card, _count} -> card == ?J end)
 
     cond do
-      Enum.any?(freqs, fn {card, count} -> count == 4 end) -> 
-        {card, _} = Enum.find(freqs, fn {card, count} -> count == 4 end)
+      Enum.any?(freqs, fn {_card, count} -> count == 4 end) -> 
+        {card, _} = Enum.find(freqs, fn {_card, count} -> count == 4 end)
         card
-      Enum.any?(freqs, fn {card, count} -> count == 3 end) -> 
-        {card, _} = Enum.find(freqs, fn {card, count} -> count == 3 end)
+      Enum.any?(freqs, fn {_card, count} -> count == 3 end) -> 
+        {card, _} = Enum.find(freqs, fn {_card, count} -> count == 3 end)
         card
-      Enum.any?(freqs, fn {card, count} -> count == 2 end) -> 
-        doubles = Enum.filter(freqs, fn {card, count} -> count == 2 end)
+      Enum.any?(freqs, fn {_card, count} -> count == 2 end) -> 
+        doubles = Enum.filter(freqs, fn {_card, count} -> count == 2 end)
         if length(doubles) == 1 do
           hd(doubles) |> elem(0)
         else
@@ -69,7 +69,7 @@ defmodule AOC.Day7 do
         end
       true ->
         freqs
-        |> Enum.map(fn {card, count} -> card end)
+        |> Enum.map(fn {card, _count} -> card end)
         |> Enum.sort(fn card1, card2 -> 
           Map.fetch!(@card_to_power, card1) >= Map.fetch!(@card_to_power, card2)
         end)
diff --git a/23/elixir/lib/days/day8.ex b/23/elixir/lib/days/day8.ex
new file mode 100644
index 0000000..9cd8794
--- /dev/null
+++ b/23/elixir/lib/days/day8.ex
@@ -0,0 +1,81 @@
+defmodule AOC.Day8 do
+  # use AOC.Day, day: 8, input: "example1"
+  # use AOC.Day, day: 8, input: "example2"
+  # use AOC.Day, day: 8, input: "example3"
+  use AOC.Day, day: 8
+
+  @start "AAA"
+  @stop "ZZZ"
+
+  def parse_input([instructions, _ | nodes]) do
+    instructions = instructions |> String.to_charlist() |> Stream.cycle()
+    nodes = Enum.map(nodes, fn s ->
+      %{"id" => id, "left" => left, "right" => right} = Regex.named_captures(~r/^(?<id>[[:alnum:]]{3}) = \((?<left>[[:alnum:]]{3}), (?<right>[[:alnum:]]{3})\)$/, s)
+
+      {id, {left, right}}
+    end)
+    |> Enum.into(%{})
+
+    {instructions, nodes}
+  end
+
+  def reach_end(instructions, nodes) do
+    Enum.reduce_while(instructions, {@start, 0}, fn instruction, {current_node, step_count} ->
+      if current_node == @stop do
+        {:halt, step_count}
+      else
+        {left, right} = Map.fetch!(nodes, current_node)
+        next_node = case instruction do
+          ?L -> left
+          ?R -> right
+        end
+
+        {:cont, {next_node, step_count + 1}}
+      end
+    end)
+  end
+
+  def part1({instructions, nodes}) do
+    reach_end(instructions, nodes)
+  end
+
+  def find_cycle(instructions, nodes, start) do
+    Enum.reduce_while(instructions, {start, 0, nil}, fn instruction, {current_node, step_count, last_end_count}->
+      if String.ends_with?(current_node, "Z") and last_end_count != nil do
+        {:halt, {last_end_count, step_count - last_end_count}}
+      else
+        last_end_count = if String.ends_with?(current_node, "Z"), do: step_count, else: last_end_count
+        {left, right} = Map.fetch!(nodes, current_node)
+        next_node = case instruction do
+          ?L -> left
+          ?R -> right
+        end
+
+        {:cont, {next_node, step_count + 1, last_end_count}}
+      end
+    end)
+  end
+
+  def brute_force_find_cycle(cycles) do
+    Stream.repeatedly(fn -> nil end) |> Enum.reduce_while(cycles, fn _, cycles ->
+      all_ended = cycles |> Enum.map(&elem(&1, 0)) |> Enum.uniq() |> length() == 1
+
+      if all_ended do
+        {:halt, cycles |> hd() |> elem(0)}
+      else
+        [{count, cycle_count} | tl] = Enum.sort(cycles)
+        IO.inspect(count)
+        {:cont, [{count + cycle_count, cycle_count} | tl]}
+      end
+    end)
+  end
+
+  def part2({instructions, nodes}) do
+    IO.puts("Use LCM for the following numbers :)")
+    Enum.filter(nodes, fn {k, _v} -> String.ends_with?(k, "A") end)
+    |> Enum.map(fn {k, _v} -> find_cycle(instructions, nodes, k) end)
+    |> Enum.map(&elem(&1, 0))
+    |> Enum.map(&Integer.to_string/1)
+    |> Enum.join(" ")
+  end
+end
diff --git a/23/elixir/mix.lock b/23/elixir/mix.lock
new file mode 100644
index 0000000..5823706
--- /dev/null
+++ b/23/elixir/mix.lock
@@ -0,0 +1,3 @@
+%{
+  "math": {:hex, :math, "0.7.0", "12af548c3892abf939a2e242216c3e7cbfb65b9b2fe0d872d05c6fb609f8127b", [:mix], [], "hexpm", "7987af97a0c6b58ad9db43eb5252a49fc1dfe1f6d98f17da9282e297f594ebc2"},
+}
diff --git a/23/flake.lock b/23/flake.lock
new file mode 100644
index 0000000..f09ea9c
--- /dev/null
+++ b/23/flake.lock
@@ -0,0 +1,27 @@
+{
+  "nodes": {
+    "nixpkgs": {
+      "locked": {
+        "lastModified": 1701693815,
+        "narHash": "sha256-7BkrXykVWfkn6+c1EhFA3ko4MLi3gVG0p9G96PNnKTM=",
+        "owner": "NixOS",
+        "repo": "nixpkgs",
+        "rev": "09ec6a0881e1a36c29d67497693a67a16f4da573",
+        "type": "github"
+      },
+      "original": {
+        "owner": "NixOS",
+        "ref": "nixpkgs-unstable",
+        "repo": "nixpkgs",
+        "type": "github"
+      }
+    },
+    "root": {
+      "inputs": {
+        "nixpkgs": "nixpkgs"
+      }
+    }
+  },
+  "root": "root",
+  "version": 7
+}
diff --git a/23/flake.nix b/23/flake.nix
new file mode 100644
index 0000000..c370c6c
--- /dev/null
+++ b/23/flake.nix
@@ -0,0 +1,22 @@
+{
+  description = "A Nix-flake-based Elixir development environment";
+
+  inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
+
+  outputs = { self, nixpkgs }:
+    let
+      supportedSystems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ];
+      forEachSupportedSystem = f: nixpkgs.lib.genAttrs supportedSystems (system: f {
+        pkgs = import nixpkgs { inherit system; };
+      });
+    in
+    {
+      devShells = forEachSupportedSystem ({ pkgs }: {
+        default = pkgs.mkShell {
+          packages = (with pkgs; [ elixir_1_15 gnumake ]) ++
+            # Linux only
+            pkgs.lib.optionals (pkgs.stdenv.isLinux) (with pkgs; [ gigalixir inotify-tools libnotify ]);
+        };
+      });
+    };
+}