Advent-of-Code-2023/chicken.org

239 KiB

Advent Of Code with Chicken Scheme

Prelude

I don't know why I am spending my time this way, but I am trying to get through this year's Advent of Code. I decided to use Chicken Scheme, and I am trying to use as few (if any) extensions, for an extra challenge.

Day 1: Trebuchet?!

Part One

Quest

Something is wrong with global snow production, and you've been selected to take a look. The Elves have even given you a map; on it, they've used stars to mark the top fifty locations that are likely to be having problems.

You've been doing this long enough to know that to restore snow operations, you need to check all fifty stars by December 25th.

Collect stars by solving puzzles. Two puzzles will be made available on each day in the Advent calendar; the second puzzle is unlocked when you complete the first. Each puzzle grants one star. Good luck!

You try to ask why they can't just use a weather machine ("not powerful enough") and where they're even sending you ("the sky") and why your map looks mostly blank ("you sure ask a lot of questions") and hang on did you just say the sky ("of course, where do you think snow comes from") when you realize that the Elves are already loading you into a trebuchet ("please hold still, we need to strap you in").

As they're making the final adjustments, they discover that their calibration document (your puzzle input) has been amended by a very young Elf who was apparently just excited to show off her art skills. Consequently, the Elves are having trouble reading the values on the document.

The newly-improved calibration document consists of lines of text; each line originally contained a specific calibration value that the Elves now need to recover. On each line, the calibration value can be found by combining the first digit and the last digit (in that order) to form a single two-digit number.

For example:

  1abc2
  pqr3stu8vwx
  a1b2c3d4e5f
  treb7uchet

In this example, the calibration values of these four lines are 12, 38, 15, and 77. Adding these together produces 142.

Consider your entire calibration document. What is the sum of all of the calibration values?

Puzzle Solution

  (import (chicken string)
          (chicken irregex))
  (let ((lines (string-split input "\n")))
    (foldl + 0
           (map
            (lambda (line)
              (let ((digits (irregex-extract '(/ #\0 #\9) line)))
                (if (= 0 (length digits))
                    0
                    (let ((first-digit (car digits))
                          (last-digit (car (reverse digits))))
                      (string->number (string-append first-digit last-digit))))))
            lines)))

Part Two

Quest

Your calculation isn't quite right. It looks like some of the digits are actually spelled out with letters: one, two, three, four, five, six, seven, eight, and nine also count as valid "digits".

Equipped with this new information, you now need to find the real first and last digit on each line. For example:

  two1nine
  eightwothree
  abcone2threexyz
  xtwone3four
  4nineeightseven2
  zoneight234
  7pqrstsixteen

In this example, the calibration values are 29, 83, 13, 24, 42, 14, and 76. Adding these together produces 281.

What is the sum of all of the calibration values?

Puzzle Solution

  (import (chicken string)
          (chicken irregex))

  (define (extract-digits input-string)
    (irregex-extract '(or (/ #\0 #\9)
                          "one"
                          "two"
                          "three"
                          "four"
                          "five"
                          "six"
                          "seven"
                          "eight"
                          "nine"
                          ; Duplicates
                          "twone"
                          "eightwo"
                          "nineight"
                          "eighthree"
                          "threeight"
                          "fiveight"
                          "oneight"
                          "sevenine")
                     input-string))

  (define (translate-code digit)
    (case (string->symbol digit)
      ((|0|)       "0")
      ((|1| one)   "1")
      ((|2| two)   "2")
      ((|3| three) "3")
      ((|4| four)  "4")
      ((|5| five)  "5")
      ((|6| six)   "6")
      ((|7| seven) "7")
      ((|8| eight) "8")
      ((|9| nine)  "9")
      ; Again, duplicates
      ((twone)     "21")
      ((eightwo)   "82")
      ((nineight)  "98")
      ((eighthree) "83")
      ((threeight) "38")
      ((fiveight)  "58")
      ((oneight)   "18")
      ((sevenine)  "79")
      ))

  (let ((lines (string-split input "\n")))
    (foldl + 0
           (map
            (lambda (line)
              (let ((digits (string->list
                             (foldl string-append ""
                                    (map translate-code (extract-digits line))))))
                (if (= 0 (length digits))
                    0
                    (let ((first-digit (car digits))
                          (last-digit (car (reverse digits))))
                      (string->number (string first-digit last-digit))))))
                lines)))

Puzzle Input

Jump to day 2.

  eightqrssm9httwogqshfxninepnfrppfzhsc
  one111jxlmc7tvklrmhdpsix
  bptwone4sixzzppg
  ninezfzseveneight5kjrjvtfjqt5nineone
  58kk
  5b32
  1dtwo
  six7two7sixtwo78
  mvhsixpptztjh13sixthree2
  six1bqqvrxndt
  fourmk5grmqone944nbvtj
  twofiveqxfivezpkvfvxt5eightjhnpl
  fpfqp7three7
  scmlf76ninegjzjkj97two
  fivetkhfnnx22
  sevenxvbcbsvxr7eighttwo
  1hvhqqmrs1bgttshthg6
  4bvnccbdh4onefztdrpq62vvbnvpxxvgrngnfjgfk
  653spgrvd
  sixctlhkjmmxh2fourfivenine37
  229mjp3txmqsxxqdbnnnbrtrcctgzseven
  jfourdbpcjc39bhglgnine
  bvnltxdmsp7twoxzpdjdvkxeight4twothree
  jlvcdrkhzh8seven3
  418oneeight
  53flcrlvqdeight84frmdcsixchcbc
  114sixone1eight2
  xrbtzbklqsl11
  bhfhszrhzgrhsfd2threeseventwosevenoneseven
  four9one
  5p
  twovhjpdxmcxshnhv5vs
  qkkqeightcxcltnn7one9pmhlmvsxnine
  4cbptmvp1
  84xgm
  bzsmqhkrdtdmhhjgrjsdfour1ninetwo61
  onetwoeightgflhlgksevennine7two6
  mbjhkhfour6
  8cvqk6eightonethree1
  qhbllbnlkr3rcsmjvztgd
  18eight4
  hhc6onegvkgkqs5mvsone
  66bnfj
  one99xvrhninefive
  eight96nxcjjddmseightxvgsixfiverrzpvmgnl
  rpgpczdsxpjgql39
  855dnthhxld6eight
  four29twosspz1
  sixfiveqvrbcdr9fourlrkpkmxphlsbone
  341
  mhqjjg9six9nine
  7pvjctsgvsix64
  75twotwothreegcvssgbvhpzcnbgteight
  7keight8eight
  52threerhfmklssxcptmnlr4hqc4
  xndfqvgxn3five
  974lknineseven
  rlnsix3
  771m1
  xvtjhq7six64threeeightgspmxgv
  4sbqdxbmmzj6fiveone
  onesvvch4rvhmvncnk
  mkzsftp69six6
  fiveptnn7
  94lsgsjxrrghxxsr4
  1grnvgpeightjthqmrfnszpfhfninefive9mbtf
  qtsdfour2
  5mfhmskpcvqbxjzzxt4lq3sevenkv
  rbhjk1cdzjhtzkcbtvmfm
  nine4eightpmrptkb
  bfiveeight1lxzkzvbtkkgxxs38
  mxcgbjqvhd1sevensevenrgp7two
  fourxrdzzmjfmtr62one
  sevenppqtlhvtwo7phlrbssxb
  dhbnjmxg3bsgbhmlfiveseventwo
  twoonemrbftgtzeightqjmjctmq55
  ggk2lt586dfzqbjsvj1one
  jtgpzjjtwo86seventwo
  37nine4onebqvsnmvg277
  hmpnzmqsfour6
  xzfhgzllmcbc56vpbpbbjffmgr3jrc
  5lclone
  hjbvkdtmrgvpfive9sevenfive1nlzqlkfrg
  htwonetgxvjdkrvjsfjjbfmcthseven29
  six89bdlssd
  3eight6one
  vtbsix2twolzrhfr1
  vhdcvtj5
  167nsnmgxhtvn54fivedcbgrhm
  4three1five82four
  15eightonethreesixthree
  dvhtsccljt51
  pbnfrxblk3sevenxjcmcvhlgrghpbgdnpl8xsr3fiveoneightq
  242three8
  2fivehgqfxgl8kpdknxhmk5bmmsbz
  fivejvjeight6fsqgtpvcb
  1threelgkbhlhhlmrbvxqqgf
  klmqfgfg1gnine253psn8
  47eight
  eight83mvdtsqppjhgjnsvngfive
  7mcmzvsv6seven
  56seven98three4three
  pfnbthreegthreefknjm4five
  2nqgrdcshfpjfpqdrvnq1twoccpmxpxvv
  xtwo7threemxbtpsvjkgrfivethree2
  9pkdfourfour1zjvczkhpbj
  1three2
  pkkbphkgqfivellrnvnkdxpql3
  ppc62
  one73ptfxsbbpqqgctdjhzjsjc91
  nine7threefourvvk
  six59542xcxqcbnrvzfbshcxxddz2
  ftsfj2ninesix1hdjsrpkonelklfpltv
  ninehmxgkqbmhvtlvdmdtvpeighttqfour1three
  frbnineeight4168ksmjstpqvzhnn
  rgnrntwohvqhgxxfkonefour4mfdr5ftgtjjv
  3ninejbszdvdgznfourxpcxspqxnthlngkncvnineccq
  threemjglxtp5cqmtwotwo2seventwonerkl
  eightsevensevenlmbjzprggthree1eight
  57nineninezdcf
  cqoneighteightjnrfkplvninefivemck18mnhszhkv4
  tbvdcsjsvmxtshv3fourseven4kmxvvfour9
  bxcsix19six8dnqsbx
  7five81ncchkdk
  four4ck7rtjmjpccpeightone
  fivetwo6nine1tdczktmfninelrbnnine
  onetwo9twoeight5sevensix
  cvvtbmninebneightsix1dnnfkgmnm
  h7three3
  tpnzsdm9sixtg5sixqvcqsq3
  1sevenzmbcpgtfrjvq
  r8757
  fournineseven6fourfour
  798dpbrkfourtwoxdrgqkrkmfeight7
  threebvqqjcldjx4nine5
  3hbl
  twodndcfddkvfivermvkrfzsnqthree5
  mhdcvsixmnqlvmvxmxfour3ct
  25dpfsrbcllhtwothree2pthreezfhjx
  dcfggnine1onetwoone
  vtbmbpgffive2hdmzjzqqqc4one
  zg11
  txrknhvhbv183
  dlvscqszz82nvtpb7tktvtgjbml
  twofour5sevensmqfjrjcndmvcvqdfsrsix
  446sixeight6rbrltdzf
  132ncq1
  4ninezdfzgvzf4four7qkzstcq
  7rx5xntgxfpmvsevenzmzmbjlc3fivefive
  threeseven7tshthree
  gnbqhninecjnhlpcfivenine18
  gjntwonenllmzgqsvq36lc45fourdrtzlctr
  3tqgbfrk
  zldl3zxpfbpveight
  2ninetgppcvqrq
  7one1sixeighttxcnhltwooneeight
  bsm3hslqcr8xslndqnnvfpzvprlkt
  khvptwo7kkbznndpqsevensevenvlr
  sevenscneight8one4qnkc
  2v
  2threerjnineonev
  68qhknonebtxvmqh
  3btb
  kcxbqzbjqt3twofourfxdlprsxkzlmflbveight
  9bmdcninecjdv7
  ceightwoninelkbbfxgsv9fb5n
  ztwo2
  7four9cpkclqxtrmpdgzxgtwo
  8dghrmgprdjeight8knnb852one
  2three36eightfournone2
  6ztwofkzlhvjdrxtsmlbgczf
  knine6ninebpmzjbkg9tttkhtgcklbfive
  sevenv3
  411one4483
  88jvjggxqfour3zrbvbxjzmthree
  fivelqcnqfvgp18t
  fivejceightqlsdrmrnbzfbjskstzrllxrdlcxpjkvf1
  832
  sixfive77rhkjdhvbpdfjxpkmfdq66qqtfpfs
  fv6svkbnsgtpznblnvkvk5
  sixsevenfoursixeight486
  gsbfrjpngshpmlxf2
  gbmmmvdhffbbcq3
  5fivehxx28
  snjxttwo1zd5sixklfl
  szsvdzsix3nine32nine
  onervkhknmnsix3four363
  1btphrrvxdeightonekdhv8
  gkphmq73lfhflk66xpfive2
  611four3gnjsdkvksjdxfiveeight
  klbvb9zk4eightninetwo
  mreight59sevengqbhnspvhqcj2six
  hnvgkmljlpthsgjrzmsevensix6fcvtxddbnx5
  ckfvkblhvv6gbsnlsevenktblt29three
  eightfoursevendnsghkfsg8fivextnnine
  5hrdqmfjq
  twojcvkkjklzmfive2fourxqgdsdgzrjltwo7
  onetwonvxnxnntxcthree3
  threentwonine6
  sprfmxlqvb9jnbzltskxppqzdscrvhpfvjjcqhxcf
  sixhfour95
  41fourqhpjbztknqnfpxvzc
  two23sevenfgmmnszone113
  one41seven57
  oneninebqqklhk6gmdzddbhgzqcmxxfnmrvr
  4mkpgv87eightckzjjfm
  vhgdmvncxn88ldbt7464
  gcczfprplf7
  6eightninesxthreefive99
  two69fivecjxjhgjmgvttl9
  mztbzjmgxnpkfrqnrbgkgfourjjfjtone8eight
  63mggldkcprlz
  6sevenfourfive
  1zvmrdnpzcsqqmxscn
  five5tkgb8rrztmcfivebknjd
  7pscpfive
  eight9sixgfvhvlcnineeight
  seven99fourtwojvxfrqmrdlthree
  sppcgnjzeight93j
  fivek7seventhree
  twornbhtrlnznpctrxhqtngzdtnvfb2
  sevenfivefour63five38nlrxfcjpm
  qvtdcspc4zxmmhpklhcdlznqfg46lct5one
  1bnndtnsfjdsevenfivetwo3k85
  8five9six
  3ltcc7trmmhbbbpjfive
  cmbchhhczmqlp3
  nctz78twodljcqvplcqg
  nine4sevenpnbbztpvkbgztb
  zseven9eight
  fourktzscmnrvddnnzsqfnfctzpdvtwo9
  nrtbgdjpm2ldcfdm5jjhx9
  jq9two68kjttwo67
  lnneightfourzqz6lgvxnthreeseven7
  fiveglp85
  ninefouronesix7k1three
  3five5sevendhtmjhbh2
  rbjhnmmgsvmtk8four
  vtrvvjsixhnctwocvskgzt3two3
  kxfive5threezgtd2
  2fivemcnngtzxsgbxmvbl
  eightlrlztkvhfivefour5
  2twojcq7qrrbddmpsb
  3twosixthreebqtoneone2
  nine9six3vlmpqbgjjqdftldpq
  tgrglqfxxc2onetwo76oneonex
  one48one
  fivesgsnrzsms6one
  fiveseven1tzhxdknkseven4
  3sprtonefivelxg47
  twotwoseven3ninenqdvxgm
  nskjpvvqeightnine93fivecngkjcd3
  ltfxscllxk9pjznpnmhfmrzmqbq
  4nineeight6four7
  fjtpj763
  four6six73htbstbbpztwofj
  oneonetwo2five43three
  five8bgcjnlzcgqpfkn
  11mcn
  9twovhkltdpkqzc65six
  8fkprfkg9xfjxspqpshlfkqpnrt
  4sblrf7745
  lblxmbzfour6187tggqllj
  dhdmlx71mbbxtvhszhsvcm
  six1qbqglfsssx
  164tsthbb2
  8nineldrtltqfivebqnrthrm
  sevenlsjbsklhxxfiveclbldxxtrdllxzthree6eight
  18gnkrxfmnineone
  six4threetwoeightgcn
  vmknclnmnphb2czdbjmcone
  eightq67
  eighthnzslhbblr85eight3
  3457kdzhnppqz5four8two
  crcskvmhthree41
  8pccnsbv8ln3
  4eightonevd
  pdz9threenine
  3sg5gkrncz
  6dxnslkl3xqlnm965twonexxn
  9nlhmmkzsdbpdctd7ninec
  62eightnine7nine3lrd
  qbprlzczreight7threegqnrshrhc
  3qlmr
  three1twojgptkzgxmf
  twosvdsfourone8
  5sixfourzvjtkpk
  six418
  five523fivecbs
  nineninesevenztfggvfkgkzfcm2
  qnsix5dnv7three
  three5twofour
  hlmtnzsmlnjxdtwo6
  9sixnglrctg
  onecrgfq5hdldpc
  nhzctlx94eight
  19djvld
  tzp8zzv8six1
  1nsnine5sixhqxfk
  33sixtwojrdvksrfsnltglggxdhbsxf
  bbvtpxptrnvjqzl3rldseventhree6
  2lcntfphb2lgpjbdeight
  fivetwo1jjgkt9kltwo1nc
  7xnmrscpfkthreejqbhlrtf4sixrbfrone
  3threetqfkv1twofive
  95ninejlftlxrs1nxxfsqz
  hrsrszgrcl9seven8eightksdnhqsq7eight
  5436ninefour
  one5five
  prcmxone8lhkblvr714three
  92btgsllktgf7fivejhgsg2eight5
  fourmm61nine558nine
  bxjx2
  one6onetwotjxthreefour8
  threedkpnpfvgt1one3nine1
  bxfour3two2sb4twondmfdpsz
  11sevennrpxftwooneeightmx6
  9mqxcrjxnp7hdjgqktxm
  2rnjlg7mbxstzbdh
  qmsixhckzone1
  qzsnq6sixtwosixtwohhgbsrqgnine3
  foureight7scksqtkmnfiveseven765
  15oneckvshqd
  41tzlxsfivebsckffdps
  threefivefournine7
  5fiveonefour8lhqmltwoeighttwo
  four5six
  mhnrspfourmflmvkc52cjkvxheightsevendtddjdcnb
  vxrrlfnlqf1twoeightninesixonetwo
  8xonetwo2
  rveightwo79three
  onebjlr9sixldqrbtwo4
  f1lhrbsix
  mbbkv7ffpk
  8twofourmxqvkqfcjfoureightplgpmrtxm3
  2rtrxjzqeighteightqtmsfnpdscpgqvxd7
  nineqggljvzvxltwozsvsfournine9
  ninexpmnnvqsfhnprqrqlcgfive9mtnflvttwoqlgphhb
  11kbpmv1
  htspdnh1xhbbh3lzcjjx1
  five6fivefive5six
  sxtbktj7
  ncvkgvgbeightfour89ttbrjthree
  xcgxzxbfnkxdqn73eight
  5nine4fivesixtwotwo1
  ffgzdfhn6
  fourzvtfcczlxhnnx5three
  threednfntx4eightwovql
  sixtwoveightnine7twonineseven
  seveneightcclmgknrgninemnjsrsqsevenfftmlqkch7
  pvqnltjs2hghkrphnine3scngkjfcsn
  62vdnbzrcrjsndqqr2
  5cxhscqpgdzbrnnq1m9b
  gnkclhmbjfourfivemmxpqx2qlxvsix
  sevenxcp4fourdlqgpxcl
  8eighttwoone
  bjslbfrspcnffnine9rvnjjrvcsix2
  six7tfive6hkllf56six
  km3
  sixtjt2threefour2vqqcxj84
  9vflltwo4five
  nineprprrcjt3eightmxfour
  4twoninehvsbszqr
  dtdmkcsd41eightfourxppqzkjb
  xmdmghzdp9sevennine94
  2bbjsdlxoneeight
  ninefivetwonine8
  68four
  ninepdjpfmzxthree3dkxgttvncbr
  52threesevenninefour6lfrlrsgzk
  ghkczjt86bdk3czvhcone
  cdjsd6jhnnnhzbzllqdjgpgnninevmcvbcxxltsix
  1mxfsrninegfmgvnine14hbfnshgbprone
  39four8
  bxnnjqkninetwotwo58txgvrbxvq
  k4bftq68seven4nineseven
  seven97fivekxjnseven4fourfour
  drgttpqpsevenvrkxdlmvtctsc72seven
  eight298
  2zsqmjskp
  six5bgdkhzqt
  fournlknxg35vqdqmnln6f
  565rqtzdpqhlldxgnine7oneeight
  3jfthree7vlkpfour1
  fourgngnqtgd675vgrrjf
  25nrfive
  kmlbnrm5dtvqndldh
  vgbzkpnltxrp5tpvb
  5mbzzk3nine7cqkngz1mm
  sevenfive952
  4pxk8four
  seven87fourlzlnineone
  zxllsctgqmsevensix72
  9ggkqvsrhftwobndlt
  8sixsfzlfpztjtwofourqvnptkgllxcf
  5dvsjvtm
  29dsvjrl3pvgjqncbgcxc
  9mhvrb8fbtppbhm2s
  eightninel5
  jltnzpcdr8one5szgf3nine88
  8xzgs4chdkfour
  three7vgnbtqvhthree8sixq
  2onesix354jj58
  175rpdmxfeightwos
  gmngst7hpfvgmtfrqbb
  9hd2lsxprdvtqxcv55
  four13cjqkvgxvbseven8
  1kqfrqsevenqgjttjrspd
  7seveneight6zfmdbzdj2
  9sixpfjbnthreedgbhblmr
  7hdqqqkone6htzthree
  hmnxstkbzlhqjpdn3three2
  dpbjgmnn1
  ninefivecznsbttpcvkthreeoneeight1zqtxb
  6hlxdlpgrl7six
  fourdhczrzd9mmmdthcngsmdqkq9fivetwofkb
  7fbcrzcxjvxtqbfive168
  sevenhlrkxgrggkqgd12
  vzmpvhqvkpdfmthreetwo9
  21cqxtjtwoljsixxbf3
  bzzxkxtl3rhsrpnnzseven
  threevhdqqvtwothreenine48frqsfhgsgptbbn
  foureighteight3pgbcftjdbbsmcqjcrmt21
  twovpfbsd42five
  6foureightwofh
  5185cbhgvkvpfzk1
  1one3two5
  seven3mdjks6kctnnchjgpnineeight
  sixfivecjfkx5
  sccbfqfive28bhconexmztpcftrbz
  qfzhgl1nine5four59nbxhclpk
  mjrvgdz3nine6gkvznv83
  mfxqslvpzeight2
  ztwoneeightknnjh4nine
  onefivesevenfsmmhkbcplj6seven
  2lfgzblvdflgxnsqfxtksbb
  blmvzczjs61fourmtds
  5two2
  jqppjfxfour2
  3five2bcrn653
  86five6bseven
  rzztlcbvteight135
  1sjngcngjrsht3ninehninefive
  81sixkrhvrhxqhn65
  dkrgmnlcbjdjxblbfnp5
  three85xrckdqtjqphjsjqflmt
  5fmptvmz19fourmbzrttnxnk
  dptwonefbqhrxtljddtkhh6four23
  xfvgkfive69
  cbtfrbpxphj2sevenmmzrpccnine
  5twotwoseven
  fivetwoeightonefive954
  zxccrkvgdqtklbnhtdtdsghcseventwo6
  three6vqmtchfdjxveightone
  onenine39twodksvrdsxflthree
  threesbpseven5zqtwobtmpgqjg1
  326dgjmzzfivehkhsjrseven
  dgthreeeightthreefbhbltbdjnineseven3klvx
  4xkcqeighttwo2
  eightonerhlnchp17
  2jcmzbczstsrmbpzxpftkmznzckhv7three
  7foursixbrcc6twosixgnf
  4lqxfourtvxhqtlhlx7xcfxhmqzbone
  2sevenz6sixtwo
  nine1pv
  95jzlkxn
  onerzfnqhmtjpqff93lrctjgqhseveneight
  5eightrdjnine3
  threetwo6fourrcrq9dfmbsznshkfqmpvcb
  five3hpjznhbtjonecvfgfsk9n9
  2gkbqpqn31
  sevenfivefgcvtpsxjprfh8nine
  lvfxml6992
  5threexmjjgkv8985zzjqdbtwo
  eight3bkqdnbmrtb5
  7sevenoneznpx
  9hjg4eightrcsvdkbmldjclfqfm
  9four2one4
  koneightonecdfcrjkqtcsevennlvr8hbrc
  seven3lthbv8
  ninexzznsix5nine
  ninentdd6qvkclninefivenine
  four11pgmxz7pnjfiveeight
  threeninefourpmtmlgllftnvxzn5twonine
  four46eight9sevenfive3three
  blztvfkqggcbshlzxppxgrxsr4three3
  one9pvlnv
  8l37
  brjvlvjrhbfourxshh1vlclvrz2
  5flqnkntnxkzhcftmzb9rlfzxlg
  sixfourseven77onekone
  6xfmdgjfeight4qzrncxdpmb4four
  four28
  seven74zrtpftdldc7fqlseven5
  6gxjzskpkfvmmd
  zkoneight99jrrmgsfpsixfiveone
  9jbbdtdxjsm8szxblgjppx4tpnvqvtlrj
  rsrlrcb32ngsixfourfivenine
  6seven9one7threegrfqpncjthree
  onebjvpzzqhvlhg1pxkvmgqvxsrglb8fourptbjs
  1fch
  njhs4p86n22
  two1one6four1six
  fourphxjkjtwo8eight
  3svqrzd1fourcmlcknhvninetddpbcmbtgqpcjms
  vkndzm684sixjlgkcvz4
  25five
  pkzt2fivetwo2zffkjqrhgfive4jpsj
  sevenmpfcthreembjgbfpkdzqlr4
  49four1mpldzb3
  hdzddkxf1cxftflb73
  zrmhdlhk2v7
  25zcd
  11eighteight5qcqzpvvk
  38nine43
  8lstwo
  12sixnfbrgbhdpn1three3
  8eightcd82rzkzlvthqnvhjvgfour
  24jcbjplcnqbcrxs25
  3fivebfkgpkglfchbmbfps
  pgmvbnhskgzdmz2sixeightcjq5
  cdpmrlj1one
  6hxqoneightjjv
  34gxbjzrtg5
  pvddskbslqnrfngmcjgsdthree3
  6nkjjlknp9
  hflkjhgjmeightc5n1
  dmkeight1223
  five9three8
  eight7mqfsjplfprrfpkzctgtdvrmxphm
  phbs2fck4sixfourqvqbr
  2bnvktn
  sfvkgzone83
  2threetqnthdnq32ninetwo9
  sixhdkvdcmp5three23j
  8615four
  twosix54vrrbvzszk9
  53671
  threevklcphgkjsnine4eight4fmtffknglthree
  sixninethreeh4dj
  oneone1pmdthreesrfsssbkt8
  7foureighteight3
  srpvkzrqfive378
  6twodnnrvfjrjv
  4kpxlslqfbktwo
  bvzpgrc9twotqsvdztwoseven8
  xkjdltjgzbjhxkjvtwo6
  five27sixsevensixtwo9nine
  jk468qgkr
  fourtwo89
  fourthreethreedtnzbmlfhmgjr5nineseven7
  44seven
  two3psfive122jps
  sevensevenghzmpdvrffive9nine3eight
  497ftdf9five
  gklfive6rnvpnvvkqheight
  2hvdfiveprrdqspsix6
  5m8nine
  bnctbninexsixonesix8five8
  xkqqlmfmrveightsix4nine93nine
  6k
  3foursevensix6cksix5six
  7twoone
  three73lfddzhd1fkxmjdzsix7twonex
  sthjlrjrhd741prcsqh3rmllvjmtvgfour
  4dvffpjkn
  tpbttcslvz7twoneq
  fourtwoninej5snfxnqzthree
  n7cmsfsqd
  eightssrzkxj5
  239
  three8five7xxthreebqrbx
  zrlchvsevenfournine4ktvskhjgh3h
  7fourfdjsnhdbgqjvnltzj6three
  mrjsndmzkz7rszqnbhxt3fvsix1
  neight85eightggtnxtgljsevenfivekz
  6vknslh4onetwonrlzm
  37zlrksix1skbsdkpjf6twonejtx
  three2843five6
  txgdvvdg959
  zfjrs2zvtbqctcdqgrpfmqsjbdone5
  six9eightninetwo72sxxnzvblthree
  2jdpslvbnpqjpglczkmzggkfkdkx8hgpxtcz
  threefive5eight5mnbllfpcsp29vlnbrntt
  gfxndggbs16twozpcsckzqcj3sthsgq6
  gcjjvqkvzdbcsnmqqhnzzqvj4
  flcpl3btfmbbpnkjvnlmcthreetwo1eightwops
  bdmeight67tvkfh2
  three645qcv1zbbheight
  3ninethvbxxppxgqcqrclptxczgrcneighttwofivebrqxl
  25eight41
  six22
  pcp5
  dtmgxkdqsixdhmsbj821
  eightprbxpj5oneightcxj
  qvrn3jbhlxjsdq
  oneclvhjhr5
  9nkmqpjjxxhvtpndls9
  215ltwo75
  threeeight16nine2mzhxnine
  ktfxkmdvzprhkpdhvxhzsc68
  fivesix8five
  4z1eighttwofive
  73twotwo4
  gmjlpchdzfthreesix1vljxdqsrlxmmqs2
  twofxh3
  threeqzcglsdcfm4four
  three1eight8
  seven7dtqhr7
  4xbjlxlptj8hzfjnz
  37jzgxbjcggone
  81fouronenine489four
  eight3fiveoneseven135
  stzts59zqdvrdcqrc
  sixnklrjbeightn2six
  bqdtntwonine1eightttzlzvzfn54xmj
  sjk6
  qmrbnhczj624394sevenseven
  kkjdcjhfh93eight
  3ptmslnconethree
  cfjgdffcgvldsnvkbjqrxhxcl7fjlxdrlrrthreeseventwo
  187oneseven6
  fiveprnppdg2tjfbfmlvhpmkggjc
  9onetwo4
  fivesvjxkzzm59vtsevenhzxtkggdhr8hvjtjvv
  kpxkbbxseveneight89sevenrbhqqpk
  drhkpssxqvvnssq59four4
  oneeight17
  gteightwoone268four
  eight7fourbjnlzfiveczlzppnxck
  jdqpxsevenone2eight
  pvh5six4hddrhfzpxfmtwo
  5six56nineone2
  v96k9115three
  phqhhthree5ksqhfjlbfg
  gpsskbfhhllnxfvjspkjndtlfour5
  three5zqbnsrdthree8
  b4mkfpkltlfdfive4mdqxjnb8tdpnpf3
  qfivejjggrpktxponetrjzceightseven9xhdf
  34cpfxc
  jl9
  84four
  fourthree9three48
  7threevgvtj2five4pbq
  7kjkjc
  seventfsvjbsh5smmdd3frthree
  smgmzqzn5
  gmtd5kvglxsixeight8twothvkprlbc5
  twofour62
  nine5k
  hbxnpb4four4h
  6sixgnmnjv4fourone1
  9eightseventhree
  9jpvccsvhqpnhsl8
  nvcnninefour9
  v237ppqbhb
  78six
  four165oneightxcm
  9pjcsfbrghnineqzth4smx
  46fpfptrq1mbqmbnktqeight
  stbxvlcqz5krd1threethreeonefour
  48six5seven
  6bmltlrvrgpcfhjhmfiveqzfxptjtwo4zvsqqxgbrdlzsfmtzdd
  jeightwo47three86twoseven
  njxzmthree8fivevvchvjqdvn3foursix
  83t34
  oneznzqptpxbrtqxstkmz3kmtstds
  1sixsfrnqd
  brs7fgkbhntv5s5
  twohs7m
  gfljsixseventmgdvhqthree3threefive
  f1twonekdh
  oneone735eightnine
  pfjvfspsseven9qgfrnmckxzsix94
  7nineninelrcqqcgcnmmqf3
  1vjdhjtrfourfive2nine278
  oneone7
  threelcxlqrzhdghp4zkjfivepjj
  hcshggsmzpdmkvtdvdgqtfxlt8
  1vdjtvpfhkhfive1
  2eightstnj6three
  93threeeightntjblpljbv
  onermlmtncmj6pxkmhmqchzvzf
  4eightfnjzfzhvg
  hmjvmtwovnl8nine84
  threets6
  six9twofivexgz63
  692five
  fkgblptntvhvmlv8threethreenine
  seven86
  nine1n7
  97two
  4threebqqnmvmqleightthreefiveszppmbhxrxvpxz
  6bxbmbdkxqmzeightlrqdqvrkr5threethree
  llqcbpeight1vpjninekpdvzg
  6qgtdqvtvkcbcskfqtq
  6threegrrmxxxqkflltr3
  312
  hqmhsxpmkxtwosix3
  rpzqtmzgdfdxcgsix1six63lxjpbxfq8
  zzkbtkghmmqfourrtsixxxfjnvvccmpsd5six
  13two4bxdcqzrkqtxm1mplvqxcfhcjsc
  threesixqj8two
  9seventhree
  dtnine5twoseven6zxd
  lsqbvgjnznineone7lxtvmkmflrfcqdjmjtwo
  zpkjlfp6onevxtdtdzmcqjprfive
  gxplqqsz412sevenninejs1
  psvjsvvnrv796
  69tfxkbkchvlhkjbrmone
  fivehnrvtb6
  eightzdlqrbzxteightptlgmcmvtwothreergcddqxf2twonepxh
  343sevenxsffneightdvft
  fivednmrpmvv8fiveninesevenzbggk
  seventwot3hpfrzbhxlhfivetwo7zvmpmq
  xnsxz8fivezhzdcbzsvp
  sfzch8twoned
  5rstpx
  12six
  gqznine5gpg
  6zrmsp825seven
  2493twothree
  9fivemksdnmgbvx
  6dvdpdpkmqpxvfive28six
  dzvnrdksixonetwoonetr4
  7fncndxbqj6onetwosixsixthree
  7cnprcdgk2three2dvtccqnskvzfsevenxdrnqf
  cxfcdvbsjqjbnxddlggjfourtnfzvtgx4twoddkkpdd
  pxjgqrmdg5mpcgcdmfeight825jxxqcnfive
  1tkhgtzzfrbdvnbft
  hgxfive14ddcfhshfd4
  onenzlhvtdgkjmjgldmddhngdv9onebkt
  foureight8rzxkktk9eighteight1
  478nshqhnhjrmlqbmp
  ddjzzxgj75zktccgqrltfivethree
  eightmcnmt5jnmnqhqdfive
  rcdxshk1seven5
  rdcmbznk79
  2gtbskjxpmmvdclgmfjrc48one
  8mqgnfive7chknsixrfourseven
  4hgdxjgbn1sixseven7twosixseven
  mkjslkltjd59
  fourfoursixfkjrcfsfivenrtzv4eight
  five8threeseven4
  81821tcmfourddhmzvzfive
  onesix943fivejld
  5eighteight3cmvvpqmdq72vrvb
  two86
  nqjrpqvgqr7rjjjxglqzrmt
  5kqjjvzxt
  6fourvstjrlnvone3ndphzphkrnsqmkmsthreep
  six8four7
  two1dntwo
  eightgmcgrnptrcvztbdp4three
  xxbpnnztr5eightpnqeight
  three9pfpnjx6rkphpjeight3five
  sevendzstsjl3krspscb1
  fsevenfqtxxhjzvnineninesixeight8
  kznjhnxbnk7qbxjrztltv
  rkeightwo6zfpvrfgqr7qxbkkg43lrjqtzjrprqttxmbrzg
  mcfive77vgzxonehglbj
  9319
  4mzds
  sevensixthree5sixdvzxkndhvjfive
  9mjhfkeight88v
  seven5zhdthbmrkdpdxfcp8njtqvpnjj14
  8ninetwo
  95tnjldjqcrzdxlm3
  fourgffour8
  nine821qbv6five
  jbtfg83two
  twozcpjrcnplnz5bdtgpdctb87lzlvqhtrjj
  tr4
  5foureightfourfcs
  1cqjts1jgzkfm
  66threetwo
  jsdpkfnineeightzpjdmrvxkbhdntj9
  pgcqrsix6mqrr8threeqxgkftbmzninevndn
  kmvqsqhbrcnbqqgninet6
  bxtstqzpqfzqnhjfb8htszvgqhpnggvqt
  ninecpqpffivehg8
  kxmstxkffourqmx41
  scfourlkfbrjvbtwo5
  qr88fivenine1lfvksgrtqseven
  four6foursix
  twoqmnxrjql5fourpdlstnnsfkdjgt9
  4zsvbsjqv97bpxvncr
  xhqlhsbqjhvdqqonesevenfive3qvrtbkhhlfbzsj9
  sixeight4six5szgzcjhpj1
  7vpjq9hjtrjgone
  f92eight
  eighteightnc8134
  22onespjpxlttsqsix8eighthxdfvsdx
  5ninefourgrrmxsxjfxk
  threeninepmvsv763xlxjp
  oneone7lzzhjqqrg
  9fourtqqmhrpmkxhrvlnjvvhsevenseven
  threethreetvjpnoneseven8
  two46onetwoqbvntlxbrftpjf9
  8one5nine1three8
  three69sgdkstpqbqdz
  q8rzcl
  onepjmchxtlqnmrcrvm6
  61fivegjjsevenqgdkq
  49fxhdzfntmk6tb8dpdkknzsb
  bbseven1xvqmlrhx
  2j
  seventwozjqszlhzxlpgphnkz2foursixfour
  1sixhgvhrbonetwom
  fournine8gvmrpgdxvcbdspzdcqt87bdzvxbf5
  3sevennine2fzpt
  threedcdlq9kcjhtmtz
  86five
  tpfqhqs3977
  8four1cgmm12shfl58
  xlkrrkpkqjtslblqfnxp7two16jzpmpkrfvdzh
  243
  three9hkgnmrh6lqrsx5
  fivexsczpmltrmcgrvfc58
  mxngrsh2sevensixthreelgrmg
  ljqmflvone76
  ksponeightthree2ninenine
  tdsdmjznr5nine7fourtwojgjsdfsevenone
  eightfive1fourseven3gsqhtv
  1xfdmqtmgkmjkthree
  rztwonelztpgkxzzcbn1eightttssdpone71
  zthhsgvmhqsgvdponetwo9p
  293rmjjjpmjchjnbdcssfrneightvdzrkbhdln
  7nfkdntfourthreefzrfxmxgqone5
  tkgrnhbflp7zltmbdoneeightwoh
  7bspgfklffgsix4
  eighthcmlrpbhjjmvbjrleightgd94
  sixbgfjzgzbxsb4qsixthreehbbn
  ninerhzjpjdfnsevenonenine8
  38kqzjxqmmm
  jngngvc412
  4twosponesixdpj15five
  41four2oneonekr2
  cpsixjnlhkthree353seven
  bknflgv1sixfivefive5
  3qkhnsjqkcjmlg7gl4jthreethree
  dhlngstrvbxjjll2979kjsttsfgjkc
  4kkq7rqlxcldqqtwo
  jfh74
  lkfpcdghgq8gpgldrsnzkzzzzskrvcvsjthree
  57fivefive3cxqj2
  ztwone7vcd37122
  4qrrhhlxgpr4
  twokzfjg2sevenlnvlpzxknznpsc1
  4jjbcdbfm8six6four
  5eightninesixvzvf98two
  8flntwomkktkpvsone78sixone
  sevenzltjhkptjfjbrppm85eight
  fivemfrmnqptthreepninepd5
  6one9
  vkqxgzmbm2b4pjqjddsbjnjcqqvm9
  5443nfkv
  leightwo5
  8fiveeightonetwovgvhzgzfjh16eightwohlk
  fivexnbhkzjfg1
  chkxvgrgb1sqxsnhngnrtqsnqgjkd
  96twoone5553dv
  36pfltskrbcmlmnspn
  4jbbrh95249
  xfzspqssdfourhnmtzfive2pfzczh
  onexzbzhddkqgfr2
  sevenninerrlveight5nine3
  eight7qvgkbk238fiveeight
  sevenseveneightgtxtxkjsgdgklzzxxc3two8
  tvfjhvtclm75skqdxsskqhrjkbg
  45
  sevenfive82
  425zkhjhmk
  onexdchhtxmhsevenbczrslrppneightonenbnhfmbsvdcnzjx1
  zfkscdbmtwoeightrksdmgx4
  lnseightnine9eight
  fourhmbhlcpht53ngkbzjmfivesixg
  threestrhbj9sixggczcg
  9twoskgrps8
  3four6xdqczgtzlzf
  ldfn2
  qlzjsnbzfourfdq476
  tpkczdh5hdbxvvmmt3sixsix
  tdpxzld5
  lnveightwohdkgcvvrjs38
  zz8eightstvmhvrh7hftdhkrjcneight1
  9kdbcpqtx15
  rbqgdbvrstgninefive4bqq2six
  nine3psmkzkgnjbndrcninesevenzvcr6
  eight4jfrqcbqfninedxmdtjgqgtrg6four5
  3mmnineninenjjpmfivetwo
  cv4znxcjthreeqqtdqmzxfknnp
  8pjkm
  ptwonethreegrgvseven7
  onethree1bgjsix5sevengpts
  96xlmmthreeeightcbdnrstvpncmr
  rtc94tcninefive
  onespqnnptpdbrgqsqrldstl1
  qkeightwotwocjcngknkztwo7
  gzjhzlf4fdglcrzckbrlkmg
  3eighttwopninefour
  2seven1c
  17nine447qkmfour2
  six6xfgqddnfpsc
  mkbgbkvzdpzxfmrhdcjklxfoureightzzpn3eight
  95ninevhctbgznbzz871sixoneightr
  31onekmseveneight2four
  mlxqgmvj2six6
  2sixgvsbmrhtwofour
  eight221three99two3
  88xrrbjdlzrfour8plv
  xdglmrpxbz5xpjxzpmvrgsixthreeseven7threebtqfkqp
  lbd2onethree
  seventwoseven7threesixbpld
  1pstwofour8eight3dsdfrseven
  gnvzm19htsbvcsfmlrmbgtstzmm3twoqzffkrrq
  94nvrbbj
  one71rsfbpnnbkrklmxqfive
  4six1
  eight48chsrmsix
  vqxrnmsix98hlzdgvd3sevenninekng
  12threehscqzvzcbgfive6three2zhtthr
  6sixkzrnv
  5gmnhhzkfmp
  four35seven7onenvdsevenftnpbcj
  6zxrhcxxkppkn2
  dgshxchmhgtgjk281seven
  lbdsmfvdsfzlp6dfpgd3
  three2dpsdhfld95eightwoht
  jbktdklsqkgnhnfmseven1lhdsbjksixtwo
  3fdqfour
  5jpljkkpmdsix
  qfeightwo9threethree
  hpqdx4911tzfcxlrtccqf9one
  q79zspgmjpdzs63
  344zk5xbthreezgbffcb
  nlzmjfqxmneightxqjdnjvr21
  8cxtrkpvzj21xfgbdgcvgrztwo
  three18444
  sntrptktwo2one1five
  qxjrgfcnpcjtnfjljqnq1onehzfcqlnine
  kflgzv58dbzbjjdvclgtseven
  twofive4eightwozz
  eightfive365
  7nqnksvphhnine88
  t8eight
  bjd6five
  khbrbtsx5jqxmbsqtf5nine3sevenskhfg6
  seventlkmfhqkgxkbhqr6ncjztnfive
  152one
  three5cbpqkzb4eightseventgmqzflsfksix
  seven32threegfddgtf
  two5twofivexzkkvcqs3
  tvvdgrnqlmkfour1zrcznqkhseveneight1q
  92threesix89
  3zbdlttpbh7fivepgxmrvbzlnfgmbkzknndfqk5
  threefnhxtdbl1jtxeightwol
  5vgthldgfmgdjphvcgh53dshmdkc
  3nineeightwokh
  57eighttddbcdsjdss
  tkcgn86xfgbmzt7rksvnchnrh
  five3dn5
  three2eighteight15nine
  49bn1zvbm57
  351six6xfzfjvpz
  5one5zchddj4dkksn
  xfhtwonesevenfivethreepqzmrzrrfourthree5
  ninetzmcgp47four
  sevenbcfbpnrvkkscrjtpctdtb69bvvnvlgsmjltlvs
  6threev
  ninerlsbznvfn9
  fourbm2
  sdxd22
  n7
  7sixcjdsxfourfmvzrbvlnine5
  threeqtbhgznine7one
  ftmkmxkd9fvvlg353rp51
  9zjhmpnjv5jvndz
  58three59nineonesix
  rmjvhrjjmkqsn6gqthreeonefivemxqhrzvffone
  xsslv7gpgkbzdmr434four
  pnzxp4nbtsjqctkvqncxzxzj
  eightseven52five4ninekntfjrdt
  4sixldsmv
  pknxkqgdpnc7fivedbvhkn
  qkpjhjlxone4sixpfkvhlmxmd3
  four3ninerkrcvgcmbb2qm
  fivenine6six1eight
  69sixnine
  bvjx5lg5vgrqq
  21ninegnhdkcxhzkcfdksvsmdthree
  zjrnmhclxhrkjpffhxkthnvj83jnshbqvx
  bzfphcg9fourthreegkchdvrgsx
  2ninebvgdcfxtktqjxjqvxfgjdqfhv5threegqtsfhtfxg
  6rqskvckjzq2qzrnbxjmlthreeeight6hrs
  sixthree6lxcrsevenseven69twonegs
  2dcvcqcbpshsixone3
  drkdbmv4zbjbznsqtj
  eightbqfhnmvqsoneninezbrzcqkz4ftv
  1eightcrcjcbdthreebscfpvznqfrj6

Day 2: Cube Conundrum

Part One

Quest

You're launched high into the atmosphere! The apex of your trajectory just barely reaches the surface of a large island floating in the sky. You gently land in a fluffy pile of leaves. It's quite cold, but you don't see much snow. An Elf runs over to greet you.

The Elf explains that you've arrived at Snow Island and apologizes for the lack of snow. He'll be happy to explain the situation, but it's a bit of a walk, so you have some time. They don't get many visitors up here; would you like to play a game in the meantime?

As you walk, the Elf shows you a small bag and some cubes which are either red, green, or blue. Each time you play this game, he will hide a secret number of cubes of each color in the bag, and your goal is to figure out information about the number of cubes.

To get information, once a bag has been loaded with cubes, the Elf will reach into the bag, grab a handful of random cubes, show them to you, and then put them back in the bag. He'll do this a few times per game.

You play several games and record the information from each game (your puzzle input). Each game is listed with its ID number (like the 11 in Game 11: ...) followed by a semicolon-separated list of subsets of cubes that were revealed from the bag (like 3 red, 5 green, 4 blue).

For example, the record of a few games might look like this:

  Game 1: 3 blue, 4 red; 1 red, 2 green, 6 blue; 2 green
  Game 2: 1 blue, 2 green; 3 green, 4 blue, 1 red; 1 green, 1 blue
  Game 3: 8 green, 6 blue, 20 red; 5 blue, 4 red, 13 green; 5 green, 1 red
  Game 4: 1 green, 3 red, 6 blue; 3 green, 6 red; 3 green, 15 blue, 14 red
  Game 5: 6 red, 1 blue, 3 green; 2 blue, 1 red, 2 green

In game 1, three sets of cubes are revealed from the bag (and then put back again). The first set is 3 blue cubes and 4 red cubes; the second set is 1 red cube, 2 green cubes, and 6 blue cubes; the third set is only 2 green cubes.

The Elf would first like to know which games would have been possible if the bag contained only 12 red cubes, 13 green cubes, and 14 blue cubes?

In the example above, games 1, 2, and 5 would have been possible if the bag had been loaded with that configuration. However, game 3 would have been impossible because at one point the Elf showed you 20 red cubes at once; similarly, game 4 would also have been impossible because the Elf showed you 15 blue cubes at once. If you add up the IDs of the games that would have been possible, you get 8.

Determine which games would have been possible if the bag had been loaded with only 12 red cubes, 13 green cubes, and 14 blue cubes. What is the sum of the IDs of those games?

Puzzle Solution

I decided to make the code for this as readable as possible. I've split the process into multiple parts:

Record Splitting

Here, I am turning the input data into an alist with the game number as key, and the draws as value of the entries, by using irregex matches.

  ;; Records
  (define record-pattern
    '(: bol
        "Game "
        (submatch-named game-no (+ (/ #\0 #\9)))
        ":"
        (submatch-named draws (*? any))
        eol))

  (define (record-kons from-index match seed)
    (cons
     (cons (string->number (irregex-match-substring match 'game-no))
           (draws-fold (irregex-match-substring match 'draws)))
     seed))

  (define (record-fold input)
    (irregex-fold record-pattern record-kons '() input))
Draw Splitting

Next, as already called inside record-kons, the list of draws has to be split and processed into individual draws. Here, I simply split them.

  ;; Draws
  (define draws-pattern
    '(: " " (* (~ #\;))))

  (define (draws-kons from-index match seed)
    (cons
     (draw-fold (irregex-match-substring match))
     seed))

  (define (draws-fold line)
    (irregex-fold draws-pattern draws-kons '() line))
Draw Processing

And as the last pre-processing step, I take apart the individual draws, and assign each amount to its respective colour keyword.

  ;; Draw
  (define draw-pattern
    '(: " "
        (submatch-named amount (+ (/ #\0 #\9)))
        " "
        (submatch-named colour (or "red" "green" "blue"))
        (? ",")))

  (define (draw-kons from-index match seed)
    (cons
     (cons (string->keyword (irregex-match-substring match 'colour))
           (string->number (irregex-match-substring match 'amount)))
     seed))

  (define (draw-fold draw)
    (irregex-fold draw-pattern draw-kons '() draw))
Main Program

I check the possibility of a game by folding over its draws, starting with a #t (true) value; basically, it is nothing more than a recursive and statement.

  ;; Game success check
  (define (game-possible? draws)
    (foldl (lambda (seed draw)
             (and seed
                  (>= 12 (alist-ref #:red draw eqv? 0))
                  (>= 13 (alist-ref #:green draw eqv? 0))
                  (>= 14 (alist-ref #:blue draw eqv? 0))))
           #t draws))

Then, I put everything together in a main function, preprocessing the input and summing up all game ids for which game-possible? returns #t.

  ;; Main function
  (define (sum-of-valid-games input)
    (let ((games (record-fold input)))
      (foldl
       (lambda (seed game)
         (let ((game-id (car game))
               (draws (cdr game)))
           (if (game-possible? draws)
               (+ seed game-id)
               seed)))
       0 games)))

And now, everything can be put together:

  (import (chicken string)
          (chicken keyword)
          (chicken irregex))

  ;; Draw
  (define draw-pattern
    '(: " "
        (submatch-named amount (+ (/ #\0 #\9)))
        " "
        (submatch-named colour (or "red" "green" "blue"))
        (? ",")))

  (define (draw-kons from-index match seed)
    (cons
     (cons (string->keyword (irregex-match-substring match 'colour))
           (string->number (irregex-match-substring match 'amount)))
     seed))

  (define (draw-fold draw)
    (irregex-fold draw-pattern draw-kons '() draw))
  ;; Draws
  (define draws-pattern
    '(: " " (* (~ #\;))))

  (define (draws-kons from-index match seed)
    (cons
     (draw-fold (irregex-match-substring match))
     seed))

  (define (draws-fold line)
    (irregex-fold draws-pattern draws-kons '() line))
  ;; Records
  (define record-pattern
    '(: bol
        "Game "
        (submatch-named game-no (+ (/ #\0 #\9)))
        ":"
        (submatch-named draws (*? any))
        eol))

  (define (record-kons from-index match seed)
    (cons
     (cons (string->number (irregex-match-substring match 'game-no))
           (draws-fold (irregex-match-substring match 'draws)))
     seed))

  (define (record-fold input)
    (irregex-fold record-pattern record-kons '() input))
  ;; Game success check
  (define (game-possible? draws)
    (foldl (lambda (seed draw)
             (and seed
                  (>= 12 (alist-ref #:red draw eqv? 0))
                  (>= 13 (alist-ref #:green draw eqv? 0))
                  (>= 14 (alist-ref #:blue draw eqv? 0))))
           #t draws))
  ;; Main function
  (define (sum-of-valid-games input)
    (let ((games (record-fold input)))
      (foldl
       (lambda (seed game)
         (let ((game-id (car game))
               (draws (cdr game)))
           (if (game-possible? draws)
               (+ seed game-id)
               seed)))
       0 games)))

Part Two

Quest

The Elf says they've stopped producing snow because they aren't getting any water! He isn't sure why the water stopped; however, he can show you how to get to the water source to check it out for yourself. It's just up ahead!

As you continue your walk, the Elf poses a second question: in each game you played, what is the fewest number of cubes of each color that could have been in the bag to make the game possible?

Again consider the example games from earlier:

  Game 1: 3 blue, 4 red; 1 red, 2 green, 6 blue; 2 green
  Game 2: 1 blue, 2 green; 3 green, 4 blue, 1 red; 1 green, 1 blue
  Game 3: 8 green, 6 blue, 20 red; 5 blue, 4 red, 13 green; 5 green, 1 red
  Game 4: 1 green, 3 red, 6 blue; 3 green, 6 red; 3 green, 15 blue, 14 red
  Game 5: 6 red, 1 blue, 3 green; 2 blue, 1 red, 2 green
  • In game 1, the game could have been played with as few as 4 red, 2 green, and 6 blue cubes. If any color had even one fewer cube, the game would have been impossible.
  • Game 2 could have been played with a minimum of 1 red, 3 green, and 4 blue cubes.
  • Game 3 must have been played with at least 20 red, 13 green, and 6 blue cubes.
  • Game 4 required at least 14 red, 3 green, and 15 blue cubes.
  • Game 5 needed no fewer than 6 red, 3 green, and 2 blue cubes in the bag.

The power of a set of cubes is equal to the numbers of red, green, and blue cubes multiplied together. The power of the minimum set of cubes in game 1 is 48. In games 2-5 it was 12, 1560, 630, and 36, respectively. Adding up these five powers produces the sum 2286.

For each game, find the minimum set of cubes that must have been present. What is the sum of the power of these sets?

Puzzle Solution

Most code can be reused from the first part; only the success check and the main function have to be rewritten to accommodate the new requirements.

The success check gets replaced by a function that multiplies the maxima together.

  (define (powercalc draws)
    (* (apply max (map (lambda (draw)
                         (alist-ref #:red draw eqv? 1))
                       draws))
       (apply max (map (lambda (draw)
                         (alist-ref #:green draw eqv? 1))
                       draws))
       (apply max (map (lambda (draw)
                         (alist-ref #:blue draw eqv? 1))
                       draws))))

And the main function gets modified to sum everything up.

  (define (game-set-power input)
    (let ((games (record-fold input)))
      (foldl + 0
             (map (lambda (game)
                    (powercalc (cdr game)))
                  games))))

The full thing put together:

  (import (chicken string)
          (chicken keyword)
          (chicken irregex))

  ;; Draw
  (define draw-pattern
    '(: " "
        (submatch-named amount (+ (/ #\0 #\9)))
        " "
        (submatch-named colour (or "red" "green" "blue"))
        (? ",")))

  (define (draw-kons from-index match seed)
    (cons
     (cons (string->keyword (irregex-match-substring match 'colour))
           (string->number (irregex-match-substring match 'amount)))
     seed))

  (define (draw-fold draw)
    (irregex-fold draw-pattern draw-kons '() draw))
  ;; Draws
  (define draws-pattern
    '(: " " (* (~ #\;))))

  (define (draws-kons from-index match seed)
    (cons
     (draw-fold (irregex-match-substring match))
     seed))

  (define (draws-fold line)
    (irregex-fold draws-pattern draws-kons '() line))
  ;; Records
  (define record-pattern
    '(: bol
        "Game "
        (submatch-named game-no (+ (/ #\0 #\9)))
        ":"
        (submatch-named draws (*? any))
        eol))

  (define (record-kons from-index match seed)
    (cons
     (cons (string->number (irregex-match-substring match 'game-no))
           (draws-fold (irregex-match-substring match 'draws)))
     seed))

  (define (record-fold input)
    (irregex-fold record-pattern record-kons '() input))
  (define (powercalc draws)
    (* (apply max (map (lambda (draw)
                         (alist-ref #:red draw eqv? 1))
                       draws))
       (apply max (map (lambda (draw)
                         (alist-ref #:green draw eqv? 1))
                       draws))
       (apply max (map (lambda (draw)
                         (alist-ref #:blue draw eqv? 1))
                       draws))))
  (define (game-set-power input)
    (let ((games (record-fold input)))
      (foldl + 0
             (map (lambda (game)
                    (powercalc (cdr game)))
                  games))))
78375

Puzzle Input

Jump to day 3.

  Game 1: 2 blue, 4 green; 7 blue, 1 red, 14 green; 5 blue, 13 green, 1 red; 1 red, 7 blue, 11 green
  Game 2: 6 blue, 3 green; 4 red, 1 green, 7 blue; 2 green
  Game 3: 4 blue, 3 red; 2 blue, 4 red, 7 green; 1 blue, 6 red, 7 green; 5 green, 10 blue; 9 green, 1 blue, 6 red; 8 blue, 1 red, 12 green
  Game 4: 15 blue, 4 green, 5 red; 2 red, 2 green, 5 blue; 3 green, 13 blue; 17 blue, 1 green, 5 red
  Game 5: 11 green, 4 red, 3 blue; 8 blue, 6 green; 8 green, 2 red, 9 blue; 4 red, 16 blue; 8 blue, 10 red, 6 green; 9 blue, 3 red, 10 green
  Game 6: 4 green, 9 red, 2 blue; 7 red, 2 green, 15 blue; 13 red, 2 green, 6 blue; 5 green, 7 blue, 6 red; 19 red, 15 blue, 4 green
  Game 7: 12 blue, 5 red; 5 green, 6 blue; 5 red, 15 blue; 5 blue, 5 red, 5 green; 1 green, 11 blue, 2 red
  Game 8: 6 red, 11 green; 5 red, 2 blue, 7 green; 7 red, 6 green
  Game 9: 5 red, 1 blue, 11 green; 4 green, 1 blue; 8 green, 2 red; 1 green, 2 red, 2 blue; 3 green, 2 red
  Game 10: 7 blue, 4 red, 11 green; 13 green, 1 red, 1 blue; 7 blue, 6 green
  Game 11: 4 blue, 7 red, 2 green; 1 green, 14 red, 3 blue; 2 green, 5 red, 3 blue
  Game 12: 6 green, 6 blue, 1 red; 1 green, 3 red, 2 blue; 2 blue, 6 red, 7 green
  Game 13: 6 red, 10 green, 13 blue; 3 red, 12 green, 9 blue; 11 blue, 1 green; 4 red, 3 blue, 13 green; 12 green, 10 blue, 6 red; 13 blue, 3 green, 3 red
  Game 14: 8 green, 1 blue, 17 red; 7 green, 11 blue, 19 red; 19 red, 9 blue, 2 green; 8 green, 20 red, 12 blue; 16 red, 3 green, 11 blue
  Game 15: 3 red, 1 green, 5 blue; 9 blue, 4 green; 6 blue, 5 green, 9 red
  Game 16: 13 blue, 1 red; 2 blue, 2 green; 1 green; 10 blue, 8 red; 4 red, 3 green, 9 blue
  Game 17: 10 blue, 2 red; 3 green, 4 red; 6 blue, 1 red, 6 green; 5 green, 7 blue, 5 red
  Game 18: 3 red, 1 green; 2 red, 5 blue; 5 blue, 2 red
  Game 19: 7 green, 4 blue, 1 red; 1 green, 4 blue, 4 red; 6 blue, 8 green; 4 green, 2 blue, 1 red; 1 red, 1 blue, 2 green
  Game 20: 13 green, 1 red, 1 blue; 12 green, 1 blue; 5 green, 1 blue, 2 red; 16 green, 3 red; 2 red, 9 green
  Game 21: 8 red, 2 green, 2 blue; 5 red, 3 blue; 2 blue, 5 red, 2 green; 7 blue
  Game 22: 9 red, 12 blue, 7 green; 7 red, 13 blue, 4 green; 9 blue, 13 red, 1 green; 3 blue, 4 red, 5 green
  Game 23: 7 green, 12 red; 6 red, 7 green, 4 blue; 1 blue, 11 red, 5 green; 4 green, 2 blue, 6 red; 12 green, 6 red, 3 blue
  Game 24: 11 red, 4 blue; 9 blue, 6 green, 17 red; 8 green, 2 red; 16 blue, 6 red, 2 green
  Game 25: 7 red, 4 blue; 7 blue, 4 green; 10 blue, 4 red, 2 green; 6 green, 4 blue, 1 red; 10 blue, 2 red, 4 green
  Game 26: 7 green, 8 red, 6 blue; 5 red, 3 green, 2 blue; 13 blue, 6 green, 5 red; 10 blue, 4 red, 8 green; 2 red, 2 blue, 1 green; 8 blue, 1 green, 4 red
  Game 27: 7 green, 3 blue, 13 red; 1 green, 17 red, 1 blue; 16 red, 3 blue, 3 green; 5 green, 3 red, 5 blue; 13 red, 4 green, 8 blue; 6 blue, 2 green, 15 red
  Game 28: 8 blue, 5 red, 18 green; 1 green, 6 red; 7 blue, 18 green, 5 red; 16 green, 3 red, 7 blue; 6 blue, 18 green; 8 blue, 8 green, 7 red
  Game 29: 4 blue, 1 red; 6 blue, 1 red; 17 blue, 1 green
  Game 30: 1 red, 2 green, 5 blue; 2 blue, 7 green, 6 red; 11 blue, 4 red, 2 green; 5 green, 6 blue, 4 red; 5 red, 8 blue, 7 green
  Game 31: 10 green, 9 blue; 5 green, 9 blue, 1 red; 1 red, 8 blue
  Game 32: 3 red, 5 green; 5 red, 5 blue, 14 green; 2 red, 2 green; 11 green, 3 red, 5 blue
  Game 33: 7 blue, 10 green, 8 red; 18 blue, 15 green, 4 red; 6 red, 1 green; 18 blue, 8 red, 11 green
  Game 34: 3 green; 2 red, 5 green; 5 blue, 3 green; 3 blue, 5 green, 1 red
  Game 35: 1 blue, 5 green, 6 red; 3 green, 2 red, 3 blue; 4 red, 9 blue, 3 green; 1 green, 12 blue, 1 red
  Game 36: 14 green, 3 blue, 16 red; 1 green, 2 red, 4 blue; 4 blue, 9 green, 18 red; 4 blue, 4 green, 14 red; 4 blue, 11 green
  Game 37: 7 green, 2 blue, 3 red; 8 green, 9 red, 2 blue; 4 blue, 15 green, 18 red
  Game 38: 11 red, 1 blue, 6 green; 6 green, 2 blue, 1 red; 6 blue, 17 red, 2 green; 17 red, 9 blue, 3 green; 7 red, 7 blue, 3 green; 3 green, 7 red, 7 blue
  Game 39: 1 blue, 2 green; 1 blue, 2 green, 7 red; 1 blue, 4 red, 2 green; 1 blue, 12 red
  Game 40: 1 blue, 4 red, 15 green; 12 green, 1 blue, 15 red; 15 red, 8 green
  Game 41: 5 blue, 5 green, 1 red; 9 red, 8 green, 9 blue; 10 red, 10 blue, 4 green; 3 blue, 17 red, 3 green; 3 blue, 4 red, 2 green
  Game 42: 2 blue, 10 red, 17 green; 6 red, 10 green, 10 blue; 3 blue, 6 green, 8 red; 9 green, 2 blue, 8 red; 13 green, 5 blue; 4 red, 18 green, 11 blue
  Game 43: 8 red, 3 blue, 6 green; 2 red, 8 green, 10 blue; 5 blue, 9 red, 9 green; 1 green, 15 red, 8 blue
  Game 44: 11 green, 19 red, 14 blue; 1 red, 19 green, 9 blue; 7 green, 8 red, 10 blue; 14 green, 8 blue, 15 red; 7 green, 3 red, 2 blue
  Game 45: 4 green, 9 blue, 4 red; 7 blue, 13 green, 2 red; 12 green, 10 blue, 10 red
  Game 46: 10 red, 2 green, 1 blue; 10 red, 10 green, 1 blue; 1 blue, 13 green; 1 blue, 2 green, 10 red; 1 blue, 7 red, 11 green; 10 red, 5 green
  Game 47: 3 blue, 2 green, 12 red; 5 blue, 7 red; 5 green, 14 red; 12 red, 7 green, 5 blue
  Game 48: 5 red, 1 blue, 3 green; 7 red, 8 green, 4 blue; 4 blue, 5 green, 17 red; 1 blue, 12 red
  Game 49: 2 green, 7 red, 1 blue; 11 green, 5 red; 4 red, 1 blue, 1 green; 11 green, 1 blue, 7 red
  Game 50: 10 red, 3 blue, 6 green; 1 blue, 5 red, 3 green; 6 blue, 11 red, 12 green; 10 green
  Game 51: 18 blue, 1 green, 1 red; 15 blue; 13 blue, 11 green, 4 red; 8 red, 1 green, 18 blue; 10 green, 7 blue, 8 red
  Game 52: 13 green, 15 blue; 6 blue, 4 red, 8 green; 6 red, 13 green, 11 blue; 2 red, 7 green, 13 blue; 12 green, 2 blue, 3 red; 6 red, 11 green, 1 blue
  Game 53: 2 red, 2 green; 3 green, 1 blue, 1 red; 1 blue, 4 green, 7 red; 4 red, 1 blue; 4 red, 5 green, 2 blue
  Game 54: 8 blue, 2 red, 5 green; 6 green, 2 blue, 3 red; 1 blue, 8 green, 4 red
  Game 55: 6 green, 6 blue, 3 red; 13 green, 1 red; 2 blue, 1 red, 1 green; 14 green, 1 blue, 1 red; 1 blue, 2 red, 9 green; 9 green, 2 blue, 4 red
  Game 56: 4 green, 6 blue, 1 red; 5 red, 3 blue; 6 red, 1 blue; 9 green, 5 blue, 7 red
  Game 57: 5 red, 5 green, 8 blue; 11 red, 3 blue, 8 green; 7 green, 9 blue, 11 red; 3 green, 2 blue, 12 red
  Game 58: 3 green, 3 red; 4 red, 1 green; 1 red, 6 green; 5 green; 5 red, 1 blue, 3 green; 3 red, 1 blue
  Game 59: 2 green, 2 blue; 7 red, 18 green; 2 blue, 7 red, 16 green; 7 red, 10 green
  Game 60: 3 blue, 4 red; 4 blue, 3 red, 3 green; 16 green
  Game 61: 1 blue, 2 red, 8 green; 9 blue, 4 green, 12 red; 10 green, 2 red; 5 blue, 11 red, 1 green; 10 green, 3 blue, 8 red; 5 red, 2 green
  Game 62: 15 red, 10 blue, 7 green; 4 blue, 9 red, 4 green; 4 red, 2 blue, 2 green; 11 green, 2 red; 8 blue, 2 green; 2 green, 8 red, 8 blue
  Game 63: 2 green, 3 blue, 1 red; 7 blue, 5 red; 7 blue
  Game 64: 3 green, 5 blue, 6 red; 9 green, 4 red; 13 red, 1 blue, 5 green; 4 blue, 13 red, 8 green
  Game 65: 7 green, 1 blue; 1 red, 14 blue, 4 green; 8 blue, 6 red; 14 green, 4 red
  Game 66: 6 red, 11 green, 7 blue; 1 blue, 6 red; 13 red, 7 blue, 3 green; 8 red, 6 blue, 15 green; 7 green, 6 blue, 4 red; 4 red, 1 blue, 20 green
  Game 67: 4 blue, 9 green; 15 red, 16 green, 3 blue; 1 green, 14 red, 3 blue; 3 red, 2 blue, 3 green; 4 green, 3 blue, 12 red
  Game 68: 5 green, 3 blue, 2 red; 4 green, 8 blue, 11 red; 6 red, 6 blue, 4 green; 8 red, 5 blue, 7 green; 6 blue, 6 green, 11 red; 2 blue, 3 green, 3 red
  Game 69: 15 blue, 16 green, 5 red; 10 blue, 3 red, 13 green; 4 red, 5 blue, 2 green; 1 red; 11 green, 5 red, 15 blue
  Game 70: 8 red, 9 blue, 12 green; 3 red, 2 blue, 14 green; 10 blue, 1 red, 18 green; 1 blue, 7 red, 16 green; 3 green, 4 red, 16 blue; 10 green, 6 red
  Game 71: 12 blue, 7 red, 16 green; 2 red, 9 blue, 15 green; 1 red, 11 blue, 11 green; 15 red, 16 blue, 2 green
  Game 72: 1 blue, 11 red, 6 green; 1 red, 2 blue, 5 green; 4 green, 2 red; 2 green, 12 red
  Game 73: 1 blue, 1 red; 2 red, 4 blue, 2 green; 1 blue, 2 green, 10 red; 8 red
  Game 74: 12 red, 1 green, 4 blue; 1 red, 5 blue, 1 green; 11 green, 16 red, 7 blue; 7 red, 1 blue, 1 green; 12 red, 11 green, 12 blue; 11 green, 6 red
  Game 75: 12 green, 8 red, 3 blue; 7 red, 10 green; 1 green, 7 blue, 1 red
  Game 76: 4 green, 1 red, 3 blue; 7 blue, 3 green, 3 red; 4 blue, 2 red, 3 green; 4 blue, 1 green
  Game 77: 2 green, 12 blue, 10 red; 5 blue, 7 red; 2 red, 6 green; 1 blue, 2 red, 6 green
  Game 78: 2 green, 4 blue, 4 red; 8 green, 10 red, 10 blue; 5 green, 8 blue, 10 red; 6 green, 2 red
  Game 79: 3 green, 2 blue, 11 red; 8 red, 11 green, 1 blue; 1 blue, 16 red; 5 red, 7 green, 16 blue; 12 red, 7 green, 9 blue; 4 red, 20 blue, 12 green
  Game 80: 3 red, 5 green; 2 blue, 4 green; 2 red, 12 green, 4 blue; 10 green, 1 blue, 1 red; 4 blue, 3 red
  Game 81: 1 blue, 1 green, 1 red; 5 green, 3 red, 1 blue; 1 blue, 6 green; 1 green; 1 red, 5 green, 2 blue; 1 blue, 1 red, 3 green
  Game 82: 7 green, 10 blue, 3 red; 10 green, 12 red, 12 blue; 18 red, 8 green, 14 blue; 3 red, 3 green, 10 blue; 3 red, 1 blue, 5 green; 1 green, 8 blue
  Game 83: 9 red, 3 blue; 14 blue, 8 red, 3 green; 14 blue, 5 green, 4 red
  Game 84: 2 blue, 3 red, 6 green; 11 green, 2 red, 1 blue; 17 green, 3 blue, 3 red; 1 red, 1 blue; 1 red, 2 blue, 19 green
  Game 85: 3 green, 2 blue, 3 red; 4 red, 5 blue, 8 green; 15 green, 1 red, 9 blue; 12 green, 3 blue, 2 red
  Game 86: 15 green, 7 red, 10 blue; 2 blue, 2 red, 1 green; 4 red, 1 green, 9 blue; 7 red, 14 blue, 5 green
  Game 87: 1 green, 3 blue, 1 red; 2 blue, 1 green; 1 blue, 2 green, 1 red
  Game 88: 2 green, 6 blue, 5 red; 5 blue, 2 red; 3 red, 13 blue; 9 blue, 10 red, 1 green
  Game 89: 6 green, 10 red, 2 blue; 7 red, 1 blue, 8 green; 4 blue, 3 red, 5 green; 4 green, 4 blue, 10 red
  Game 90: 8 red, 7 blue; 4 green, 3 red, 1 blue; 5 blue, 2 green
  Game 91: 15 green, 14 red; 12 red, 16 green, 2 blue; 8 red, 10 green; 1 green, 6 red; 8 green, 12 red
  Game 92: 4 blue, 4 green, 9 red; 1 blue, 17 green; 1 green; 15 green, 3 blue, 12 red; 11 red, 1 blue, 7 green; 7 blue, 13 red, 8 green
  Game 93: 10 blue, 12 red; 10 blue, 11 green, 8 red; 1 blue, 11 green, 7 red; 10 blue, 15 red, 5 green; 11 red, 8 green, 9 blue; 10 green, 3 blue
  Game 94: 1 blue, 2 red; 4 red, 1 green, 5 blue; 3 red, 2 green; 2 green, 2 blue; 1 red, 5 blue, 1 green; 4 blue, 1 red, 2 green
  Game 95: 1 red, 1 blue, 3 green; 2 green, 6 blue; 1 green, 13 blue, 1 red; 3 green, 15 blue
  Game 96: 16 blue, 7 green, 5 red; 5 green, 5 blue, 6 red; 3 green, 17 blue, 10 red; 13 blue, 2 red, 1 green
  Game 97: 12 red; 1 blue, 6 red, 1 green; 9 red, 2 blue, 1 green; 1 green, 2 blue, 1 red; 15 red, 1 blue; 1 blue
  Game 98: 11 red, 6 blue, 13 green; 4 blue, 2 red, 12 green; 2 blue, 8 green, 10 red
  Game 99: 2 red, 1 blue; 4 green; 7 green, 1 blue, 1 red; 5 green, 2 red; 1 blue, 2 red, 9 green; 2 green, 3 red
  Game 100: 7 red, 11 blue; 10 red, 5 blue, 1 green; 7 red, 1 green, 13 blue; 9 red; 9 red, 19 blue; 9 red, 9 blue

Day 3: Gear Ratios

Get the puzzle solution as tangled .scm file.

Part One

Quest

You and the Elf eventually reach a gondola lift station; he says the gondola lift will take you up to the water source, but this is as far as he can bring you. You go inside.

It doesn't take long to find the gondolas, but there seems to be a problem: they're not moving.

"Aaah!"

You turn around to see a slightly-greasy Elf with a wrench and a look of surprise. "Sorry, I wasn't expecting anyone! The gondola lift isn't working right now; it'll still be a while before I can fix it." You offer to help.

The engineer explains that an engine part seems to be missing from the engine, but nobody can figure out which one. If you can add up all the part numbers in the engine schematic, it should be easy to work out which part is missing.

The engine schematic (your puzzle input) consists of a visual representation of the engine. There are lots of numbers and symbols you don't really understand, but apparently any number adjacent to a symbol, even diagonally, is a "part number" and should be included in your sum. (Periods (.) do not count as a symbol.)

Here is an example engine schematic:

  467..114..
  ...*......
  ..35..633.
  ......#...
  617*......
  .....+.58.
  ..592.....
  ......755.
  ...$.*....
  .664.598..

In this schematic, two numbers are not part numbers because they are not adjacent to a symbol: 114 (top right) and 58 (middle right). Every other number is adjacent to a symbol and so is a part number; their sum is 4361.

Of course, the actual engine schematic is much larger. What is the sum of all of the part numbers in the engine schematic?

Puzzle Solution

Records
  (define-record part-number number line start-col end-col)
  (define-record part-symbol sym line start-col end-col)
  (define-record buffer-char char line col)
Indexing the Input
  (define (index-input input #!optional (indexed-input '()) (line-index 0) (col-index 0))
    (if (= 0 (length input))
        (reverse indexed-input)
        (let ((next-char (car input))
              (new-rest-input (cdr input)))
          (if (eqv? #\newline next-char)
              (index-input new-rest-input
                           indexed-input
                           (+ line-index 1)
                           0)
              (index-input new-rest-input
                           (cons (make-buffer-char next-char line-index col-index)
                                 indexed-input)
                           line-index
                           (+ col-index 1))))))
Tokenizing the Indexed Input
  (define (number-char? c)
    (case (buffer-char-char c)
      ((#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9) #t)
      (else #f)))
  (define (finalize-token buffer)
    (let* ((rev-buffer (reverse buffer))
           (line (buffer-char-line (car buffer)))
           (start-col (buffer-char-col (car buffer)))
           (end-col (buffer-char-col (car rev-buffer))))
      (if (number-char? (car buffer))
          (make-part-number (string->number
                             (apply string (map buffer-char-char buffer)))
                            line start-col end-col)
          (make-part-symbol (string->symbol
                             (apply string (map buffer-char-char buffer)))
                            line start-col end-col))))
  (define (compatible-with-buffer? buffer char)
    (and
     (not (eqv? #\. (buffer-char-char char)))
     (or (= 0 (length buffer))
         (and (number-char? (car buffer))
              (number-char? char))
         (and (not (number-char? (car buffer)))
              (not (number-char? char))))))
  (define (tokenize-indexed-input indexed-input #!optional (token-buffer '()) (part-nums '()) (part-syms '()))
    (if (= 0 (length indexed-input))
        (values (reverse part-nums)
                (reverse part-syms))
        (let ((next-char (car indexed-input)))
          (cond
             ((compatible-with-buffer? token-buffer (car indexed-input))
              (tokenize-indexed-input (cdr indexed-input)
                                      (cons (car indexed-input) token-buffer)
                                      part-nums part-syms))
             ((= 0 (length token-buffer))
              (tokenize-indexed-input
                (cdr indexed-input)
                (if (eqv? #\. (buffer-char-char (car indexed-input)))
                  token-buffer (list (car indexed-input)))
                part-nums part-syms))
             (else
              (let ((token (finalize-token (reverse token-buffer))))
                (tokenize-indexed-input
                 (cdr indexed-input)
                 (if (eqv? #\. (buffer-char-char next-char)) '() (list (car indexed-input)))
                 (if (part-number? token) (cons token part-nums) part-nums)
                 (if (part-symbol? token) (cons token part-syms) part-syms))))))))
Checking for Part Neighbours
  (define (neighbours? part-num part-sym)
    (let ((part-num-line (part-number-line part-num))
          (col-min (- (part-number-start-col part-num) 1))
          (col-max (+ (part-number-end-col part-num) 1)))
      (and (>= (part-symbol-line part-sym) (- part-num-line 1))
           (<= (part-symbol-line part-sym) (+ part-num-line 1))
           (>= (part-symbol-start-col part-sym) col-min)
           (<= (part-symbol-start-col part-sym) col-max)
           (>= (part-symbol-end-col part-sym) col-min)
           (<= (part-symbol-end-col part-sym) col-max))))
Folding Everything Together
  (define (is-real-part-number? part-num part-syms)
    (and (< 0 (length part-syms))
         (or (neighbours? part-num (car part-syms))
             (is-real-part-number? part-num (cdr part-syms)))))
  (define (fold-part-numbers part-nums part-syms)
    (foldl (lambda (output input)
             (if (is-real-part-number? input part-syms)
                 (+ output (part-number-number input))
                 output))
           0 part-nums))
  (let-values (((part-nums part-syms) (tokenize-indexed-input (index-input (string->list input)))))
    (fold-part-numbers part-nums part-syms))
509115

Part Two

Quest

The engineer finds the missing part and installs it in the engine! As the engine springs to life, you jump in the closest gondola, finally ready to ascend to the water source.

You don't seem to be going very fast, though. Maybe something is still wrong? Fortunately, the gondola has a phone labeled "help", so you pick it up and the engineer answers.

Before you can explain the situation, she suggests that you look out the window. There stands the engineer, holding a phone in one hand and waving with the other. You're going so slowly that you haven't even left the station. You exit the gondola.

The missing part wasn't the only issue - one of the gears in the engine is wrong. A gear is any * symbol that is adjacent to exactly two part numbers. Its gear ratio is the result of multiplying those two numbers together.

This time, you need to find the gear ratio of every gear and add them all up so that the engineer can figure out which gear needs to be replaced.

Consider the same engine schematic again:

  467..114..
  ...*......
  ..35..633.
  ......#...
  617*......
  .....+.58.
  ..592.....
  ......755.
  ...$.*....
  .664.598..

In this schematic, there are two gears. The first is in the top left; it has part numbers 467 and 35, so its gear ratio is 16345. The second gear is in the lower right; its gear ratio is 451490. (The * adjacent to 617 is not a gear because it is only adjacent to one part number.) Adding up all of the gear ratios produces 467835.

What is the sum of all of the gear ratios in your engine schematic?

Puzzle Solution

Gather Symbol Neighbours
  (define (gather-neighbours part-sym part-nums)
    (foldl (lambda (output input)
             (if (neighbours? input part-sym)
                 (cons input output)
                 output))
           (list) part-nums))
Put Everything Together
  (define (filter-gear-candidates part-syms)
    (foldl (lambda (output input)
             (if (eqv? '* (part-symbol-sym input))
                 (cons input output) output))
           (list) part-syms))
  (define (calc-gear-ratio gears)
    (foldl (lambda (output input)
             (if (= 2 (length input))
                 (+ output (apply * (map part-number-number input)))
                 output))
           0 gears))
  (let-values (((part-nums part-syms) (tokenize-indexed-input (index-input (string->list input)))))
    (let ((gear-candidates (map (lambda (x) (gather-neighbours x part-nums)) (filter-gear-candidates part-syms))))
      (calc-gear-ratio gears)))
75220503

Puzzle Input

Jump to day 4.

  .....664...998........343...............851............................2............414.....................3....................948.164....
  ......*..................*617....885...*....................-......250.........536..........470...#..................../4......=.....*......
  ...407...570..218................-.....654........776.....920.........*753...........566......*..347.....61.-979..786........935...42.......
  .......%....*...$..311.102..........................*.907.....723...............622-....*..354..............................................
  .....266..............*....987.554...........&....288...#......#.......................69......41..........486..-...........................
  .849................................&........781...........978......724*..196..../767................725..../...892.....*355.....815.390....
  ....*......@.....*988......%........704...............*......&...........*...................826.....................243.......#....*.......
  ...796......729.9.........490..721....................438.=....272..54&...926..481..............*..523......&.785...........766.......*493..
  ........281.........706...........=.666.......505.........579.*................./...669.........73...*...639...*.......479.........514......
  ...........*...386.......375..................................525.926..$120............&.580.........457........325.......*829..............
  .....758..662.......937....%...661.24......749*323...444.............*.............583....*.........................................223.....
  .......*........665....*...........*................@.................154......965..*....119.......620*............347.................*470.
  ........391.........183.........75..783../....................209.312............*...362........./.....667..........*....77.................
  ...379=..........................$......261..228........907......*.......+591...178.........227.704........@771..667..........268......543..
  .......................#.....................*..........*....................................-........*581...........101........*.....*.....
  ................471...545..135........432..178....$225..143...973#..322............2.................................*...........239...985..
  ......728*612...*.........*.....65....................................*...........*................&..............527....255+../............
  ..255.........435.304....854...................-............=........261......&...749....+......196....694......................779..271.374
  ......604.........*.....................708.....922.......76..82*554......991..19........456............*..582.........597@.................
  .................374..*........*707........................................*....................609...52....%.................483...........
  ..../..................739......................$..........649...973.*511.861..20%.................=.....................148....*......343..
  ...978.................................282&...401......961....-.*.........................................499%.........../.....347..........
  .................+..174..315.-819.................841.....*66......820.836......8....60....456........*........434..........................
  ....62%.......908......./.................770....../..................*.....852......&.....*........317...%......@.......+.......691........
  ........793......../......411......963.......*594..................@........@......*.......45.............729...........306.148....*..@.....
  626.......$......35..........*........*...........................77.134........584.....23....35................589........./...482..853....
  .......................366..668.........................238...........*..265.........*..........*...........&......*...471..................
  ..741.............679.................@.807...76....185*...........211..%.........507....178..583....*.561...521..620...*....865.$247.494...
  .....*.....383.....%..183..876......179..$..................254.........................$..........697.*..............935...*...............
  ...50..390..*.........*.........917.........904/..50+.........................96...............960......701...............464....*.......947
  .........*..53........270..........*647.342......................778............$..$684..+279...*....#.........................393..........
  ......151.......490...........352*.........*........................#............................594.732.........11....#....................
  ........................$.........306....805..................832...................859..../.#53.........953*228...*....217.................
  ......37....349....391.739.......................................*286..........558......516.......647........................%........847...
  ..346.../....*......&.......855.........732....586...353.................43....*..............598.&...798.719.........671.....881...........
  ..........561................=..........................*..........52....*.....727............./.....$....*..........*......................
  999*..........746...158........534............927.....587.....521......511...........448%...89...........52..557......211..356.344...116....
  ........*.....................%........732....*..............*...............................*..................*806.......$.....*..*.......
  .....575.515.......922..........410.......*................564...............+503...........297................................132.667......
  .../.............-..#.....69*82....*.......842......248..&.......630.@........................................500...........................
  ..916.........944...................586.................647.......*...21....&419..........=....699.......766...%.......152.......315*101....
  ......*436...........987#.....*....................188.............81.............87..-..109......*.........-..........*....349.............
  ...553..........570-.......442.197.......115...590....*.......284.......478...459..#.6.........946...............945-..192............292...
  22.......+..............................%......../...865........*......*........*..........900......950.......................*449...$......
  .......780..........435...*................................371...588...727.....213.....496.............-.845*..../173......688..............
  713........923..../.*......289....38.....408.552.141*476..*..................................619....6........238...................633......
  ...*821.......*..57.8............../..46*......*..........38.........%..................$...*.......*....201......=.............61...-..%86.
  ...........361......../12..39.51............903..................380..659........905+.28....256.............*......215.....=.../............
  ...-..577.......553...............749.246.........34....................................................311..282........894.................
  .960.....@...........661.....558...&......239*..........482......574=..269..........289..../...............*.................323............
  ...........292................%.................#........../............*......452/.-......132.....=..342.721..335.....426....*.....516.....
  ................967.......=.......900...........925..........476.252/...861.....................891.....*.........*315.&.....130...=........
  ..955..........=........584.......*...-................600............$..........940.=348...............733...754...........................
  .....*..123.....................76...36...430-......&...............524.........*............706..............#.....*.....849*......162*129.
  ..543.....*........903..290.........................42.......................649...$............+...78.*648......180.979......353...........
  ...........91.642.../....*........443/.........206...........#.......219............134............*..............................798..344..
  ......759................144..............................455........*...906...............195......924....502.405....802.400.......*.......
  .812..............-..........394.............$771.245..............116........................*.+.........#....../...*.....*...448...883....
  ..................784................................*.....&.................809.......616..109.496.................89.....592...*..........
  ...596........671......527..483.197......-965.231.918.......921.452-.538.......*..763.........................162............../..479../685.
  ......*....46...#......*......*.@.............................................839.*......172.....................*374........927............
  .....383............649.....783..........=981.........44..159.....94...............769......*..............#..........*.............748*993.
  ..................................................607.+...*......*.......................755..810........539.......728.98.....425...........
  ......32......35....99...233..............275.337.&......437..630...........423.84...........-............................163........578....
  ................+.....*.....+.....334.......*.-................................*..................110.....358....115..566....*648.......*...
  ....................471............*......384....81...190.606..=714....673.198.......57..#761........=..........*.....*..................618
  ..........847.755..................963..........*........*................*......251*....................#592.222....107...991..557.........
  ....236-.....*.................569.....311....584.............*958..........923%........................................./.......*....=.....
  ................../.835...................*........157*324.840......../415...................408...........212......-..573.549.770.995......
  ............312.34..............&.377...287.461..................+.................33*555...*................@.315.720......%...............
  .......614.*.................309.....*........*..758............811..........................259.................+..................-627....
  .........*.....*.....757.................684.527..*.......408.........999...............524..............570...............995..............
  ...835..415.345.822...............495.....*.......138...........966....*..................#...............*....560.........*................
  ...#.................806..954......*.......51...........+.......*.....910..436.477..............*150.....510...*.....#....537...........434.
  ......................*...-........871.743.........643...234...844............*....705..959..360................454..402..........984.......
  ....................491.................+..675...........................$........*........-................................487...*...876...
  ....191........%559.......................*........250..................965......556..&...........521.......365.......994%.%....923.....$...
  .....*........................238..257...631..........*....*.....&...........346......366...150....*........*...............................
  .....532....584....800.......*.................603.452..155.42..272..267.295*.....52...........*....672..743...830.....395.......862........
  ...............#....*.....347...................*......................@.......................487...................................671*973
  ......=340.......&..667...................*......413.........................576*888......706.......487..502..........22....................
  ................649..........&./426....286.............149........690..............................&..........765.....*..............321....
  389........304/............200...................660...*.............*253...........129..#30.........................710.../................
  ...@..............408.............258*246....136.....614..531..-.....................*.........253&..........421...........939.....+.357....
  .....%..............*...........................*............*..313..+418.47...931...329............974.........=...847..........166.*......
  834..6.............346....505....164............833........66.....................*.......367..95......*211..............-............888...
  .........535....=......+.....$.......770......+....................................5.......*.....*36..................547...+...............
  .....115.*...471......863.............#.....75..364...........=842..974......722........581............$..........588.......557....760......
  987..=...780...............$...................*......................................+......869.......591.......&................-.........
  ........................15.484..........640...768.@710.353.......=.585......&91....996..712..=...............548...680........661...939.....
  ...630...........186=...*......575.....*................#.....662..$.................................+......*.........+........../.....*....
  .........116*235........138...*....................644....................*853...............210...719......503.....................453.....
  .....................=.........480..%................=...........429...478.....695.....789..$..........19&............216...................
  ......506.........101...189.........232....951.........706....43...*.......943.........%...........935.......160..........+20..152.16.......
  ..............789...........654...............*648.............*...........*....=.............398...*........*................*.............
  ..............*.........509...@.....$...............746.....645...........607..336.................488....285....$..944......298.$..........
  ..........23...642.374.............913................*.327....................................................263.....*182......822........
  ......94....*......*.......942*.............596....285.....*..............177...........86...................................477......702...
  ..243..+.....220.838.637.......481....301..+...............717...................394......................782/.......*..........%.872.*.....
  .........../.........%...../...........$...........239...........209......*........-...............153............100.700...........*..708..
  ............499.........235..........................*....939*......*..227.293.-.....805.785.........#..250.................423....954......
  .......570........................................837..@......748..56..........782.....*....*..........*......552...........................
  872%..*......%.......88*484....805....178...704........282............387...........562....614..559...750..*...........@.....417......762...
  ......745.....3...98....................*..*...............................@....329........................130.......134....$...........*...
  .814.............%......829.268........220...441.316.............*740......607........*831..............*......................529.......410
  ......=...687...........*.....*................*...*..........369.....332..........798...............956.932......................=.........
  .....856.*............858....283.........43.594...292................*....*.604*.........217....................44*.....676*.........752.571
  ..........489....................951...................83...........262.243........681....*.................373....493...........-...@......
  349................................*..................@.....................444.......*......../951..810.......#.......184....227...........
  .................958..574....313...312...909....204/....................674*...........146...........=...=..................................
  .....*.438...512*.....*.....*...........*.............484&.25..........................................851...........534@.$720.719..........
  ...254.*...........167..@...7............22....681...........*684........7.696.135.207.......177............749*670............*.....681....
  ..........733...........659.........527............645*215.........850.....*..........*.........*....822........................787.........
  ..37*58.....*.................562....*........232..........610.321*.....148.......416............514.....703......54...................310..
  ..........638....223.........*........296............452....................152....#...678..........................*...+...692.........*...
  ..911...........*.........594.......*......589........*..........186........................219...........344.927.324.525..*............753.
  .....*..144.247.493...............351.........*....994...........*......738..107.......235...*....937.......-.*...........171....634........
  ....756..*..../.....626..131+.@..............770..........70...11........*...............*..533...*...181......861..................*.......
  .........755...................637./15.....................=.........217..407......146...........402.#..................11...436..535.......
  ..........................&592.............367.636...........830........*..........*..........................................+.........%...
  ..........420*.27....954..........314.............=...........*......791...$.......718........828.....9@..449...................868...110...
  ..................*..........835...&...417*...........895......747..........785.........128....*..80........*.....................*.........
  ........475@...285...700.............*.....846....561...*.723.............................&.436...*......728................&....389........
  ....................*.............610.266...........@.351.*..........308...931...490...............50........*487.....958.500...............
  ..................335...736.....................285.......294..510*....*........*.....103.....139.........920...........=...................
  .............*...........*..........343............*..692..........57.741.....@..314...*.....*......*835......738.=............582.....295..
  ...437....215..........185...............58.......654...&.....603..........505.......97...224..@..........766.....508.....+317....#.........
  ...............................52.............1...........777........704........372.............23....652...=...........@...............620.
  ............83..481..917......*........36$...../......=...=.............*...471*.....171.680.............*.......635...28...127.....272.....
  ...262.183..*......*..=..56*.72...................812.317.......454.....1.............*.............................*.........*.......*.....
  ....*........299..246...........190#...........%...+..............*.224..............664......897....407.155*....407...........406..581.....
  ......691.................869..........439.....385....@.........26.....*........863.......402*.........-.............*28...332..............
  ........*.......159*638......*....38....*..209......578.963........592..875......*...................*.....$......596........-..............
  ......90................424.640.....*.272.................$..........*.........134...........624..158.907..964.................291..........
  ................410....&..........972.......................$..305..683..743........551.338.&..................................*............
  ...........................%..........213.................164.....*.......+..........*........751..............................10....710.387
  ......%................&....314........-..376.......833*.......494..821...........829......%.....#........582..............&............*...
  ......87...318......472...........%449.....=............720.........%.................257...29...........*.........-.....656................
  ..666........*....*.....920.....................................................&......*........................759..........875$...........
  ......138....366..797...........584.......247.........................427..206..843...618.....530......................................172..

Day 4: Scratchcards

Get the puzzle solution as tangled .scm file.

Part One

Quest

The gondola takes you up. Strangely, though, the ground doesn't seem to be coming with you; you're not climbing a mountain. As the circle of Snow Island recedes below you, an entire new landmass suddenly appears above you! The gondola carries you to the surface of the new island and lurches into the station.

As you exit the gondola, the first thing you notice is that the air here is much warmer than it was on Snow Island. It's also quite humid. Is this where the water source is?

The next thing you notice is an Elf sitting on the floor across the station in what seems to be a pile of colorful square cards.

"Oh! Hello!" The Elf excitedly runs over to you. "How may I be of service?" You ask about water sources.

"I'm not sure; I just operate the gondola lift. That does sound like something we'd have, though - this is Island Island, after all! I bet the gardener would know. He's on a different island, though - er, the small kind surrounded by water, not the floating kind. We really need to come up with a better naming scheme. Tell you what: if you can help me with something quick, I'll let you borrow my boat and you can go visit the gardener. I got all these scratchcards as a gift, but I can't figure out what I've won."

The Elf leads you over to the pile of colorful cards. There, you discover dozens of scratchcards, all with their opaque covering already scratched off. Picking one up, it looks like each card has two lists of numbers separated by a vertical bar (|): a list of winning numbers and then a list of numbers you have. You organize the information into a table (your puzzle input).

As far as the Elf has been able to figure out, you have to figure out which of the numbers you have appear in the list of winning numbers. The first match makes the card worth one point and each match after the first doubles the point value of that card.

For example:

  Card 1: 41 48 83 86 17 | 83 86  6 31 17  9 48 53
  Card 2: 13 32 20 16 61 | 61 30 68 82 17 32 24 19
  Card 3:  1 21 53 59 44 | 69 82 63 72 16 21 14  1
  Card 4: 41 92 73 84 69 | 59 84 76 51 58  5 54 83
  Card 5: 87 83 26 28 32 | 88 30 70 12 93 22 82 36
  Card 6: 31 18 13 56 72 | 74 77 10 23 35 67 36 11

In the above example, card 1 has five winning numbers (41, 48, 83, 86, and 17) and eight numbers you have (83, 86, 6, 31, 17, 9, 48, and 53). Of the numbers you have, four of them (48, 83, 17, and 86) are winning numbers! That means card 1 is worth 8 points (1 for the first match, then doubled three times for each of the three matches after the first).

Card 2 has two winning numbers (32 and 61), so it is worth 2 points. Card 3 has two winning numbers (1 and 21), so it is worth 2 points. Card 4 has one winning number (84), so it is worth 1 point. Card 5 has no winning numbers, so it is worth no points. Card 6 has no winning numbers, so it is worth no points.

So, in this example, the Elf's pile of scratchcards is worth 13 points.

Take a seat in the large pile of colorful cards. How many points are they worth in total?

Puzzle Solution

A Record For The Start

Records are always useful, so let's create one to represent an individual card. We want to store the card's id (it might be useful in part 2), the winning numbers, and the card's numbers.

Since it could potentially be relevant, I also add a slot for the matches.

UPDATE: I also added a slot for the number of copies of the scratch card - relevant for part 2.

  (define-record scratchcard id winning-numbers card-numbers match-numbers copies)
Parsing The Input

We know the drill by now, we have to take apart the input strings, and parse them into an easy format for us - in our case, this is the scratchcard record.

For that, I first create the pattern for a card.

  (define card-irregex
    '(: bol
        (* whitespace)
        "Card"
        (+ whitespace)
        (submatch-named card-no (+ numeric))
        ": "
        (submatch-named winning-numbers-str (+ (or numeric whitespace)))
        " | "
        (submatch-named card-numbers-str (+ (or numeric whitespace)))
        eol))

The pattern is then used to extract every scratch card which is then being parsed in a fold statement.

  (define (input->cards input-str)
    (irregex-fold card-irregex
      (lambda (from-index match seed)
        (cons
         (make-scratchcard
          (string->number (irregex-match-substring match 'card-no))
          (map string->number
               (string-split (irregex-match-substring match 'winning-numbers-str)))
          (map string->number
               (string-split (irregex-match-substring match 'card-numbers-str)))
          '() 1)
         seed))
      '() input-str))
Processing The Cards

I compare every card number with every winning number on a card, and put every card number with at least one match into the special slot of the record. Note that this is a non-functional operation, and thus modifies the original record! That is also the reason why the procedure name ends with an !.

  (define (calc-card-matches card)
    (let ((winning-nums (scratchcard-winning-numbers card))
          (card-nums (scratchcard-card-numbers card)))
      (for-each (lambda (card-num)
                  (when (foldl (lambda (matches? winning-num)
                                 (or matches?
                                     (= card-num winning-num)))
                               #f winning-nums)
                    (scratchcard-match-numbers-set!
                     card (cons card-num (scratchcard-match-numbers card)))))
                card-nums)))

As a next step, I calculate the points for each card.

  (define (card-points card)
    (let ((match-nums (scratchcard-match-numbers card)))
      (foldl (lambda (points num)
               (if (= 0 points)
                   1
                   (* points 2)))
             0 match-nums)))

And now, we can put everything together and sum up the points:

  (foldl
   (lambda (sum card)
     (calc-card-matches card)
     (+ sum
        (card-points card)))
   0 (input->cards input))
23441

Part Two

Quest

Just as you're about to report your findings to the Elf, one of you realizes that the rules have actually been printed on the back of every card this whole time.

There's no such thing as "points". Instead, scratchcards only cause you to win more scratchcards equal to the number of winning numbers you have.

Specifically, you win copies of the scratchcards below the winning card equal to the number of matches. So, if card 10 were to have 5 matching numbers, you would win one copy each of cards 11, 12, 13, 14, and 15.

Copies of scratchcards are scored like normal scratchcards and have the same card number as the card they copied. So, if you win a copy of card 10 and it has 5 matching numbers, it would then win a copy of the same cards that the original card 10 won: cards 11, 12, 13, 14, and 15. This process repeats until none of the copies cause you to win any more cards. (Cards will never make you copy a card past the end of the table.)

This time, the above example goes differently:

  Card 1: 41 48 83 86 17 | 83 86  6 31 17  9 48 53
  Card 2: 13 32 20 16 61 | 61 30 68 82 17 32 24 19
  Card 3:  1 21 53 59 44 | 69 82 63 72 16 21 14  1
  Card 4: 41 92 73 84 69 | 59 84 76 51 58  5 54 83
  Card 5: 87 83 26 28 32 | 88 30 70 12 93 22 82 36
  Card 6: 31 18 13 56 72 | 74 77 10 23 35 67 36 11
  • Card 1 has four matching numbers, so you win one copy each of the next four cards: cards 2, 3, 4, and 5.
  • Your original card 2 has two matching numbers, so you win one copy each of cards 3 and 4.
  • Your copy of card 2 also wins one copy each of cards 3 and 4.
  • Your four instances of card 3 (one original and three copies) have two matching numbers, so you win four copies each of cards 4 and 5.
  • Your eight instances of card 4 (one original and seven copies) have one matching number, so you win eight copies of card 5.
  • Your fourteen instances of card 5 (one original and thirteen copies) have no matching numbers and win no more cards.
  • Your one instance of card 6 (one original) has no matching numbers and wins no more cards.

Once all of the originals and copies have been processed, you end up with 1 instance of card 1, 2 instances of card 2, 4 instances of card 3, 8 instances of card 4, 14 instances of card 5, and 1 instance of card 6. In total, this example pile of scratchcards causes you to ultimately have 30 scratchcards!

Process all of the original and copied scratchcards until no more scratchcards are won. Including the original set of scratchcards, how many total scratchcards do you end up with?

Puzzle Solution

  (define (card-alist cards)
    (foldl (lambda (alist card)
             (calc-card-matches card)
             (alist-update (scratchcard-id card)
                           card
                           alist))
           '() (reverse cards)))
  (define (generate-copies cardlist #!optional (index 1))
    (let ((index-card (alist-ref index cardlist)))
      (if index-card
          (let* ((matches (scratchcard-match-numbers index-card))
                 (copies  (scratchcard-copies index-card))
                 (copy-indexes (foldl (lambda (indexes match)
                                        (cons (+ 1 index (length indexes))
                                              indexes))
                                      (list) matches)))
            (for-each (lambda (card-id)
                        (let ((target-card (alist-ref card-id cardlist)))
                          (scratchcard-copies-set!
                           target-card
                           (+ (scratchcard-copies target-card) copies))))
                      copy-indexes)
            (generate-copies
             cardlist
             (+ index 1)))
        cardlist)))
  (define (count-scratchcards cardlist)
    (foldl + 0 (map (compose scratchcard-copies cdr) cardlist)))
  (let ((cardlist (card-alist (input->cards input))))
    (generate-copies cardlist)
    (count-scratchcards cardlist))
5923918

Puzzle Input

Jump to day 5.

  Card   1: 33 56 23 64 92 86 94  7 59 13 | 86 92 64 43 10 70 16 55 79 33 56  8  7 25 82 14 31 96 94 13 99 29 69 75 23
  Card   2: 61 66 75  1 27 38 93 90 34 43 | 94 46 62 49 35 88 45 70 15 22 20 86 56 38 64 98 50  6 79 11 13 93 92 60 16
  Card   3: 57  7 33 56 85  6 88 34 80  8 | 92 42  7 60 61 51 40  6 67 35  3 25 87  2 98 75 97 54 10 68 73 83  4 62 56
  Card   4: 79 85 94 74 15 62 84 88 76 56 | 56  9 22 57  4 92 62 79 84 64 72 55 34 88 66 15 45 18 76 73 85 94  8 78 74
  Card   5: 57 94 99 25 52 67 69 31 26 78 | 94 52 31 83 70 45 40 67 89 11 81 24 25 61 26 72 50 12 27 69 91 57 55 34 78
  Card   6:  5 96  3 19 98 25 13 59 94  8 | 36 55 22 76 86 19 10  8 59  9 87 40  2 71 13 98 12 77  3 70  5 25 34 41 88
  Card   7: 35 52 84 36 72 53 76 88 41 14 | 57 34 14 39 44 71 51  1 67 30 16 77 23 66 45 74 37 55 38 69 33 31 98 72 36
  Card   8:  7 70 72 13 23  1 48 18 40 94 | 48 70 93 99 20 23 17 40 72 35 21  7 71  3 42 59 87 55 18 41 94  1 13 22 90
  Card   9: 40  2 46 38 86 16 62 78 29 13 | 26 46 47 29 99 51 25 57 66 86 62  2 22 70 41  3 78 13 74 15 16 90 43 40 38
  Card  10: 35 71 99 87 81 58  5 83 55 73 | 90 34 71 10 96 38 39 29 69 93 35 51 86 12 76 91 80 36 17 59 64 68 58 15 82
  Card  11: 35 89 27 73 65 46 39 86 81 90 | 86 90 50 35 73 31 92 65 18 81 30 37 21 76 89 56 64 71 49 12 27 82 16 32 29
  Card  12: 15 77 35 41 38 93 63 30 39 18 | 90 69 65 93 13  4 64 51 72 57 96 91 75 14 58 94 28 38 63 97 86 84 50 15 21
  Card  13: 10 82 16 85 74 38 95 51 54 94 | 66 29 85 73 54  8 51 14 56 74 46 42 10 67 16 59 23  7 95 48 94  6 82 68 88
  Card  14: 77 53 62 72 97  7 36 96 67 28 | 30 24 28 44 39 77 15 88 92  4 60 66 11 21 20 42 55 53  6 12 95 87 37 58 85
  Card  15: 89 74 36  8 27 73 90 60 48 56 | 56 45 74 78 39  7 15  6 89 88  8 76 90 16 22 36 17 10 99 79 71 59 46 96 49
  Card  16: 82 64 99 10 32 65 20 78 29 31 | 49 59  4 78 22 18 95 82 54 72 39 41 35 14 98  1 84 92 58 64 28 83 50  7 65
  Card  17: 25  1 40 66 84 24 19 17 10 46 | 22 40  8 87 17 38  6 95 36 51 15 93 18 73 56  9 13 57 63 10 78 37 48  1 84
  Card  18: 18 14 27 40 80 47  9 65 22  5 | 90 59 72 36 33 31 93 55 75  3 56 37 27 87 10 23 47 19 99 85 35 48 18 62 69
  Card  19: 63 16 71 14  1 89 61 55 62 44 | 32  5 64 82 94 77 11 90 54 47 49 29 97 78 57 68 92 33 44 28 59 30 72 18  8
  Card  20: 60 21 85  8 35 66 70 36  2 58 | 10 37 36 64 72 98 60 19 55 45 30 33 31 94 90 49 71 57 81 17 91 29 68 86 39
  Card  21:  4 25 18  6 56 62 97  1 83 30 | 42 66 83 75 14 50 26 24 90 36 46 87 49 84 53 65 80 17 92 70 19 95  9 27 32
  Card  22: 53 91 82 19 43 83 65 46  4 85 | 97 67 90 39 16  1 54 64 10 77 99 71 28 94 30 45 84 95 21 35 13 61 29 11 33
  Card  23: 65 66 83 69 23 16 13  3 29 68 |  6 54 27 65 16 68 13 69 29 14 91 23 37 61 39 74 66 77 83 11 26 40 92  3 49
  Card  24: 43 97 61 35 69 20 65  3 23 79 |  3 69 20 80 98 92 18 61 91 96 86 88 19 25 43 97 17 79 47 55 11 35 23 77 65
  Card  25: 94 30 47 27  2 80 76 75 82 67 | 28 12 96 27  2 20  4 29 58 18 93 75 62 38 30 72 94 80 76 91 47 14 67 82 46
  Card  26: 51 47 45 64  9 53 16 80 61 94 | 88 28 84 45 61 51 70 18  4 21 94 62  5 53 32 10 20 86 47 46 43  9 66 83 80
  Card  27: 31  5 15 38 10 61 33 92 26 47 | 60 49 54 69  1 99 85 29 95 34 84 81 36 11 57 67 14 55 90 51 17  7 37 35 48
  Card  28: 25 69 85 59 82 16  6 17 49 62 | 80 17 62 69 16 46 87 29 59 64 97 85 45 30  6 82 47 75 25 43 72 14  2 23 49
  Card  29: 58 97 36 33 62 27 74 38 68 23 | 51 20 85 47 44 67 48 25 39 36 17 61 52 22 79  6 64 57 95 56 71 33 98 34 42
  Card  30: 74 96 56 34 64 54 26 22 62 59 | 32 74 61  7 34 47 83 94 27 26 66 54 87 75 56 65 49 13 64 70 96 62 53 22 59
  Card  31: 26  6 14 82 12 60 16  4 92 87 | 16 33 76 55 54 39 27 26 17 83  6 18 94 77  3 40 81 92  1 69 25 19 71 99  2
  Card  32: 15  3 33 16 13 65  8 44 40 96 | 22 15 46 89 16 50  6 33 53 24 96 40  8 35 97 13  3 55 43 14 65 66 34 60 44
  Card  33: 41 61 28 60 85 69 87 62 91 18 | 49 88 84 73 20 45 75 99 27 25  3 65 66 30 50 54 97 57 76 96  2  6 39  5 18
  Card  34: 12 72 20 48 49 77 38 86 68 92 |  6 56 30 68 95 87 42 16 59 10  7 22 82 74  2 71 19 48 50  1 40 37 24 80 72
  Card  35: 97 86 21 45 10 30 63  8 36 91 | 33 31 67 77 29 24 10 79 21 25 12 71 30  1 68 56 46 94 51 64  8 14 45  4 41
  Card  36: 90 75 80 95 49 87  2 88 50 42 | 77 85 53 76 52 72 32 42 79 65 50 25 19 14 37 11 35 63 29 75 49 98 96 54 95
  Card  37: 19 84 30 59 86 49 31 40 14 50 | 20 92 36 43 82 18 86 47 73 30 84 19 99  5 48 34 68 63 61 46 53 75 16 28 45
  Card  38: 39 47 28 13 75 89 76 93 15 14 | 36 94 51 97 49 16 66 60 72 30 52  5  3 17 23  7 58 14 63 87 54  8 56 13 35
  Card  39: 70 22  9 80 89 51 43 64 57 37 | 23 39  5 27 98 11 29 73 72 10 63 79 59 58 46 96  2 86 50 19 67 41 95 66 82
  Card  40: 94 95  1 39 64 63 54 19 17 38 | 44 53 12 92 11 34 42 67 93 36  6  3 29 60  7 62 85  4 33 83  2  9 10 82 51
  Card  41: 69 12 36 48 67  7 52 89 63 73 | 11 61 81 93 47 20 27 31 66 64 45 38  2 59 46  5 73  7 87 22  6 52 36 10 54
  Card  42: 17 93  3 90 91 59  6 57 54 65 | 22 17 99 16  6 77 38 46 43 59 41 47 12  2 86  4 40 56 80 82 11 98 23 20 85
  Card  43:  1 68 36 70 24 83 86 94 52  7 | 38  9 64 12 10 60 92 81 77 98 59 23 79 91 65 28 13 15  6 69 24 40 19 16 99
  Card  44:  3 45 25  7 57 67 62 36 40 44 | 51 23 88 52 68 11 89 84 59 54 10 77 73 96 46 44 17 85 91 12 80 74  5 27 39
  Card  45: 14 68 88 27 44 83 37 22 65  7 | 78 61 91 48 92 21 52 49 77 74 46 24 33 28 36 89 53 39 93 23 72 95  2 63 67
  Card  46: 20 59 75 43 98 38 85 46 74 57 |  3 34 11  7 98 64 52 89 43 41 87 57 19 56 37 68 20  2 99 91 23 17 74 48 78
  Card  47: 87 20 73 47 82 37  3 68 29 65 | 15 53 58 25 62 13 31 59 11 63  2 89 30 71 35 36 82 37 75 67 17 12 34 90 19
  Card  48: 63 11 55 53 44  7  3 41 60 40 | 73 61 87 91 46 60 51 31 11 32  7 44 41 78 55 14 59  3 63 53 74 94 62 65 40
  Card  49: 30 62 35  9 40 51 68 55 79 97 | 53 87 77 97 63 11 52 67 51 35 68 79 99 98  5  9 40 37 19 49 30 16 55 75 62
  Card  50: 66 80 74 99 63 84 35 26 83 67 | 43 92 52 67 63 84 16 21 88 23 31 22 24 49 59 99 75 47 66 80  1 83 91 95 70
  Card  51: 68 99 70 39 79 10 81 27 46 80 | 70 17 46 68 61 50 43 48 79 81 12 32 65  1 27 39 80 99 58  8 19 10 41  4 73
  Card  52: 37 86 40 43 66 14 63  2 19 50 | 96 50 27 43 64 83 13 92 63 86 37 19  2 40 58 66  3 31 59 14 62 61 67 54 53
  Card  53: 78 33 11 45 12 22 19 38 87 74 |  2 50 63 33 97  8 58 99 48 22  4 45 11 60 74 21 69 78 87 29 12 39 19 18 38
  Card  54: 11 51 64 21 19 87 70 80 55 95 | 11 69 53 94 24 96 87 59 95 76 23 19 68 47 51 74 70 55 32 77 80 64 21 36 78
  Card  55: 92 99 88 93  1 26 13  4 61 11 | 71 92 99 61 76 56 46 89  4 67  3 45 22 81 19 33 50 26 93 28 13 72  1 11 88
  Card  56: 11 65 76 35 97 63 16 57 92 53 | 96 30 65 82 76 59 63 97 35 40 16 98 86 79 41 11 78 95 10 88 29 28 64  5 74
  Card  57: 32  5  1  8 43 15 25 79 96 71 | 25 49 31 90 39 77 27 83 15 56 41  5  1 26 58 33 34 79 62  8 96 32 92 43 71
  Card  58: 65 20 54 93 18 31 97 99 94 86 | 89 46 12 27 23 42 43 88 75 73 35 49 95  9 37 66 50 62 51 48 11 17 26  1 41
  Card  59: 62 38 28  4 59 53 16 89 52 35 | 27 47 52 12 35 86 59  8 39 31 81 55 95 79 37 89 58 14 30 80 68 87 43 84 56
  Card  60:  8 89 16 22 75 94 34 67 78 62 | 84 81 29 51 10 70 91 95 32 34 46 12 67 66 68 99 74 87 92 78 90 13 76 18 27
  Card  61: 27 92 80 94 87  2 75 26 22 79 | 36 34 76 84 22 48 52 86 79 46 81 80 87 78 27 95 70 51 35 49  9 89 75  8 67
  Card  62: 89 10 56 52 80 76 46 31 69 24 | 73  6 53 98 17 65 44 16 83 45 92 41 94  3 81 99 26 61 43 67  2 93 36 28 29
  Card  63: 38 74 68 99 88  4 42 87 58 31 | 39 99 22 11 16 50 52 53 85 34 67 76 55 42 45  8 89 43  2 20 75  4 97 28 70
  Card  64: 22 38 75  7 35 62 49 30 10 32 |  1 54 59 40 12 74 46 51 37 21 72 57 97 82 31 25 87 47 29 43 67 88 19  9  8
  Card  65: 21 69 41 76 88 73  4 77 34 93 | 92 53 25 78 81 84  8 49 77 41 28 70 12 88 91 45 29 15 86 46 32 96 57 34 54
  Card  66: 42 60  7 35 31 50 13 61  9 19 | 53 18 80 69 78 88 24 56 29 62 49 95 64 81 11 42 17 40 34 28  6 98 70 54 91
  Card  67: 36 50 47 89 18 54  9 25 92 91 | 87 59 85 42 62 37 26 21 52  4 90 19 75 23 67 33 35 49 69 79 14 80 46 97 98
  Card  68: 92 43 44 34 29 75  6  1  8 31 | 88 85 55  9  1 95 14 97 67 42 22 72 89 19 90 35 74 96 58  5 57 51 47 37 69
  Card  69: 59 43 21 14  5 85 20 12  1  7 | 40 11 63 87 72 34 83 86 94 31 66  3 24 98 82 39 65 35 51 77 67 18  2 47 90
  Card  70: 24 83 87 85  3 48 99 11 21 33 | 76 92 16 81 61 86 83 14 57 44 74 41 98 63 96 38 89 65 32 11 48 51 53 23 19
  Card  71: 57 77 65 66 16 50 49 39 55 87 |  3 45 97 44 31 14 25 70 13 72 16 41  2 66 88 69 57 26 54 95 80 10 65 28 86
  Card  72:  3 80 44 10 43 90 71 20 17 85 | 86 53 46 72 74  3 91 99 19 55 94  2 65  4 36 26 29 16 95 48 11 24 90 76 78
  Card  73: 71 11 88  6 54 78 97 30 91 92 | 52 86 23 91 78 54 97 66 11 44 30  8 93 71 16 92 21 83 84 88 34  6 33 26  9
  Card  74: 87 88 97 95 33 72 21 39 60 66 | 65 68 95 84 97 32 72 21 43 74 23 55  1 96 92 87 25 66 60 16 33 59 39 98 88
  Card  75: 40 81 51 37 56 61 25 84 82  4 | 82 84 43  7 23 61 14 38 63  5 27 85 48 71 56 99 30 96 29 40 18 37 77 13 16
  Card  76: 40 46 25 27 39 47 33 37 36  7 | 13 39  9 80 34 38  8  7 60 48 92 71  5 40 10 41 37 21 67 29 25 43 69 28  2
  Card  77: 25 10  9 74 66 52  6 22 41  3 | 32 24 86  5 47 22  6 23  3 69 56 40 28 52 54 17 95 53 68 39 60 74 71 99  4
  Card  78: 59 18 58 51 88  8 92 27 82 79 | 97 86  8 11 79 28 88 70 48 80 42 37 87  2 92 95 55 59 82 40 50 27 51 68 63
  Card  79: 51 97 54 22 64 44 80 27 96 47 | 93 72 29 23 96  1 54 66 51 24 22 62 87 97 35 27 44 77 79 64  3 37 47 45 80
  Card  80: 64 67 54 24  8  4 35 89 15 23 | 67 12 13 77 45 15 54 92 89  9 96 95 25 24 99  4 81 52 46 35 69 64 23 79  8
  Card  81: 34 25 84  7 23 12 54 30 20  1 | 49 26 82  7 13 75 89 58 53 67 93 46  8 97 32 86 11 72 28 54 98 56  1 45 55
  Card  82: 87 24 17 63 67 65 43 97 38 95 |  8 40 49 43 15 36 88 11 83 29 46  7 62 31 51 23 69 67 66 39 54 72 35 80 65
  Card  83: 12 57 85 81 48 97 45  5 72 11 | 68 98 58 29  8 22  9 30 49 51 67 47 74 13 40 65 94 44 91 34 92 82 14 33 61
  Card  84: 95 33 18 64 24 92 27 29 57 53 | 56 19 14 79 60 36  6 12 75 71 26 87  4 58 54 16 52 31 98 17 85 40 61 41 77
  Card  85: 42 71 23 49 53 96 88 48 60 95 | 66 18 98 88 58  7 12 11 89 37 13  1  6 28 45 47 30 31 55 57 17 97 77 99  4
  Card  86: 44 31 35  2 49 88 26 98 43 42 | 19 46 70  1 92 12  3 11 30 74 33 38 95 17 24 75  9 28 83 32 40 65 62 10 29
  Card  87: 98 23 88 50  4 73 92  5 11 24 | 85 14 59 94 41 69  5 99 46 22 27 61 77  7 60 95 58  6 30 24 44 92 10 88 23
  Card  88: 39 61  4 84  2  6 33 53 85 42 |  3 77 16 69 11 76 48 80 95 15 12 10 83 78 19 57 30 56 52 46 58 88 55 35 13
  Card  89: 27 97 32 38 46  3 62 40 58 89 |  6 91 80 72 21 56 24 50 82 54 74 97 60 73 47 96 13 38 84 12  9 69 14  3 41
  Card  90: 80 50  8 55 93 29  3 87 84 27 | 38 83 96 69 76 28 18 87 32 45 89 48 82 91 70  6 25 24 73 42 19 49 34 51 93
  Card  91: 10 40  8 20 83 79 47  2 69 12 | 31 79 74 71 87 57 41 36  7 22 76 42 82 72 16 78  3 67 43 52 26 85 39 25 14
  Card  92: 72 76 71  8 20 13 48 25 81 47 | 33 94  7 85 64 93 53 31 10 21 92 50 70 23  1 99  2 12 18 97 66 45 57 51 55
  Card  93: 50 21 56 54 41 32 77 19 93 13 | 36 88 97 56 53 99 68 26 13 21  9 86 77 41 50  3 16 75 98 48 24 62  8 32 93
  Card  94: 52 39 66 88 19 43 80 53 33  3 | 66 34 43 41 65 92 80 50 72 86 94 69 52 53 39 67 83 16 25 19 99 93 11 33  6
  Card  95: 22 38 17 63 68 51 79 72 81 61 | 79 63 38 71 81  1 78 13 68 33 21 51 12 57 53 67 97 22 62 72 61  2  9 17 73
  Card  96: 83 96  2 47 21 68 50 78 19 29 | 77 66 37 59 36 96 74 16 80 84 65 87 90 58 89 48 42 47 68 85 35 49 56 40 19
  Card  97: 72  8 69 10  3 33 79  4 99 65 | 26 99 96 10 31 33  8 58 38  4 40 69  6 97 80 79 98 65 20 57 73  3 81  5 72
  Card  98: 43 67 24 40 95  3 27  1 89 39 | 24 87 37  1 26 72 19 95 43 89 32  3 27  5 55 40 25 71 69 67 39 74 56 93 35
  Card  99: 68 24 93 30 34 20 27 89 37 50 | 93 77 86 17  4 30 60 37 98 24 68 34 14 39  8 31 18 50 48 10 20 12 27 78 70
  Card 100: 68 45 61 38 58 50 27 87  9 96 |  3 23 52 54 76 49 34  8 81 78 11 38 33 15 26 40 37 67 94 51 24  5 30 97 31
  Card 101: 23 16 99 80 29 13 81 67 27 22 | 94 53 95 19 66 31 96  3 60 28 38 30 35 47 44 68 75 82 56 18  5 50 36 78 64
  Card 102: 17  2 85 30 78 23 93 46 88 92 | 18 44 84 92 13 62 48 46 53 31 52 17 93 78 29 51 99 39 30 23 91  5 81  2 33
  Card 103: 35 21 66 81 40 75 50 88 14  6 | 16 25 61 81 13  6 17 77 38 66 98 41 45 54 23 19 99 21 49 32 51 35  8 47 65
  Card 104: 29 37 46 77 92 53 81 20  9 96 | 94 81 75  8 24 78 68 48  4  5 98 16 30 57  3 10 14 70 36 33 91 64 47 18 87
  Card 105: 15  2 31 71 99 30 26 61 79 32 | 21 49 58 16 67 94  5 75  4 69 96 51 28 53 17 89 25 85  1 12 83 82 10 33  6
  Card 106: 51 24 14 80 10 38 53 55 41 32 | 69 66 91 73 65 12 36 75 45 90 46 58 80 57 74 28 39 37 95 22 30 62  7 32  1
  Card 107: 26 78 66 42 54 69 51 95 17 52 | 64 69 20 75 87 30 11 42 60 47 85 46 80 36 40  7 94 68 33 21 31 83 89 10 82
  Card 108: 82  2 99 56 80 38 54 47 20 29 | 23 56 40 97  5 81 37  4 69 48 91 64 58 73 32 61 54 78 77 43 67 14 17 68 15
  Card 109: 97 80 18 44 73 53 15 50 47 48 | 30 41 82 36 43 86 95 56 33  4 89 47 28 59 27 31 92 12 93 32 60 74 99 26 75
  Card 110:  4 58 43 91 66 59 69 73 37 94 | 35  3 65 27 77 52 44 38 86 79  2 32 56 84 10 60 18 24 49 64 61 78 93 99 22
  Card 111: 52 86 22  5 18 14  7 92 65 56 | 50 86 28 52 14 48 56 93  5 22 80 76 65 25 92  2 78  7 45 49 70 47 18 15 53
  Card 112: 10 36 28 87 20  7 93 15 65 53 | 27 93 36 83 87 46 24  1 86 43 28  7 89  4 32 20 38 14 15 67 57 29 69 40 10
  Card 113: 27 38 49 70 32 56 22 11 43 10 | 25 75 85 29 63 83 35 95 65 15 84 49 87 27 74 43 11 13 46 10 72 56 22 70 57
  Card 114: 91 82 29 32 44 84 51 67 94 11 | 51 69 55 28 89 74  8 96 93 35 42 33 73 44  3 31 36 68 38 11 94 46 29 12 82
  Card 115: 88 46 87 97 52 18 20 96  2  3 | 17 36 23 42 67 93 72 24 10 89 87  8 66 48 25 50 61 32 59 52 84  2 35 99 65
  Card 116: 50 23 72 60 40 77 97 90 98 70 |  3 76 97 92 72 11 28 60 30 29 35 45 70 62 84 55 57 87 22 14 38 69 51 25 86
  Card 117: 31  4 58 33 86  7 47 25 62 87 | 44 36  7  4 73 84 25 58 65 14 23 96 55 31 27 87 77 17  9 15 47 22 98 69 62
  Card 118: 71 33 83 75 28 82 56 94 21 42 |  1 21 43 28 13 86 19 82 58 48 89 94 71 91 41 95 27 79 73 93 75 31 66 30 83
  Card 119: 38 69 51 58 93 60 13 66 90 71 | 44 94 98 53 49 69  9 74 24 57 71 45 12 78 18 56 88 68 85 42 35  1 47 17  2
  Card 120: 44 82 72 71 73 16 39  5 93 81 | 57 21  8 33  3 69 54 47 26 70 53 10  5 44 77 31 29 87 24 19 93 37 80 65 84
  Card 121: 90 63 79 82 91 85 98 70 14 28 | 66 71 82 27  2 29 44 73 76 18 47  3 55 64 34 25  6 88 81  8 30 19 75  1 31
  Card 122: 80  4  6 16 18 20 23 35 50 90 | 50 25 27  1 70 12 60 19 96 37 57 82 69 89 45 87 23 26 75 90 48 42 30 78 54
  Card 123: 32  6  8 96 56 86 73 18 71 92 | 35 64 83 21 15 95 49 80 33 93 11 45 29 78 68  5 60 63 86 67 57 91 42 51 97
  Card 124: 72 84 64 25 99 28 40 98 96 59 | 31 50 67 35 94  3 10 95 85 38 46 45 80 42  6 62 97 52  7 92 83 44 55 65 21
  Card 125: 13 63  2 53 48 38 88 14  5 58 | 49 50 91 75 40 66 34 71 24 52 28 26 55 19 25 73 98 56 11 41 96 21 85 67 29
  Card 126: 55 36 33 58 17 53 39  6 21 52 | 88 30 68 84 61 14 17 97  7 19 99 54 45 56 52 35 92 50 85 36 24 70 27 29 75
  Card 127: 96 37 56 99 84 12 10 70 93 55 | 85 77 82 60 74 20 51 27 92 12 59 98 91 81 56 31  6 53  4 10 89 84 90 69 55
  Card 128: 63 44 56 61 88 65 33 85 81 55 | 58 28 88 75 33 89 20  8 61 37  6  9 19 92 46 17 35 94 29 62 76 41 55 57 80
  Card 129: 86 99 43 13 11 17 67  9 50 33 | 47 67  6 69 11  5 13 98 96 89 57 40 61 79 33 80 15 42 62 92 59 86 10 65 44
  Card 130:  4 71 54 22 81  7 25 19 29 50 | 91 16 36 54 51 19 50 80 83  7 81 64 61 30 85 72 79  9 13 12 67 59  4 31 20
  Card 131: 87 91 50 20  3 77 14 47 97 76 | 71 87  8 34 78 27 32 61 33 89 62 52 72 17 60 16 42 51 64 49 66 86 22 30 59
  Card 132: 68 17  4 26  8 14 41 57 21 31 | 98 31 75 47  9 48 30 65 36 40 70 57 77 72 76  3 21 42 68 24 96  7 23 17 10
  Card 133: 46 32 98 75 52 49 80 60  9 47 | 87  3 69 96 29 80 54 98 53 49 66 88 35 75 58 40 93 73 42  2 30 90  1 76 22
  Card 134: 23  8 93 17  5 21  9 19 13 82 | 71 37 95 91 65 43 27 44 36 24 98 99  2 74 20 88 49 17 76 80 46 57 79 94 81
  Card 135: 81 28 19  5 22 75 18 74 51 13 | 32 66 55 62 17 60 96 70 23 37 34 67 14 84 24 76 16 47 94 56 38 65 25 97 98
  Card 136: 72  8 16 42 50 75 57 39 82 41 | 86 82 57 11 62 92 79 78  1 41  3 64 15 12 46 31 89 45 63 91 81 47 96 27 10
  Card 137: 64 70 10 41 33 73 22 62  9 21 | 25 47 90 79 14 97 80 34 33 40  4  6 64 28 83 91 73 63 37 44 98 42  5 12 62
  Card 138: 87 14 61  6 27 82 35  8 54 56 | 95 36 51 60 98 78 30 83 19 58 72  4 88 10 77 69 96  8 87 74 27 92 65 75 35
  Card 139:  4 16 59 44 74 86 33  5 95 60 | 14  2 34 29 44 26 12 70 66 47 67 52 85 71 95  7 11  4 30 77 40 96 36 98  6
  Card 140: 12 86  6 69 88 43 13 55 81 10 | 19 71  6 51 72 46  2 97  3 67 56 74 90 42 86 28 32 52 98 17 38 76 77 49 10
  Card 141: 29 72 27 68 17  7 45 64 49 26 | 35 11 29 26 66 14 41 52  6 42 92  5 99 39 24 59 75 12 83 51 78 58 28 81 93
  Card 142: 41 63 11 16 15 59 97 34 40 23 | 39 85 37 84 30 20 77 60 36 19 42 61 11 67 10 21 99 87 32 66 48  1 28  5  9
  Card 143: 47 14 63 53 73 40  7 50 15 21 | 69 96 26 94 38  9 10 79 78 48 82 66 59 57 12 37 74  1 92 98 88 42 31 39 23
  Card 144: 36 88 96 60 86 29  1 57 37 46 | 99 47 22 57  3 60 29 87 86 36 58 30 40 37  1 33 88 49 46 11 96 80  9  8 82
  Card 145: 54 66 15 59 79 52 73 14 23  8 | 50  8 20 14 92 72 98 80 85 77 42 49 59 58 18 91 90 17 21 97  1 19 53 84  2
  Card 146: 36 80 57 90 97 28 76 52 77 45 | 41 14 46  8 84 91 20 57 52 99 37 67  3 55 10 87 25 18 43 77 97 80 78 85 74
  Card 147: 64 12 80 55 49 67 78 28 20 10 | 20 43  1 78 83 39 80 38 24 54 75 49 94 22 26 67 71 97 64 28 12 45 10 55 89
  Card 148: 57 96 75 17 53 63 60  8 95 27 |  8 60  2 82 19  5 24 98 27 93 80 86 63 97 17 53 99 59 70 14 78 96 95 57 75
  Card 149: 50 95 82 20 27 47 80 48 13 49 | 87 77 20 82 88 74 94 48 13 99 30 65 47 27 11 49 80 61 71 50 34 62 85 18 95
  Card 150: 52 14 22 54 43  3  1 99 73 39 | 42 97 89 92 58  8 60 80 82  5 28 17 35 79 40 50 61 56 53 75 95 25 83 31 15
  Card 151: 44  9  3 78 73 55 32 59 70 24 | 75 23 91 37 81 66 24 59 70 38 25 55 54  9  3 73 32 44 89 39 78 64 83 12  7
  Card 152: 37 29 16 15 24 41 40 99 21 87 | 37 78 68 17 95 60 69 44 55 21 66 96 82 65 87 29 23 36  4 20 15 52 94 75 74
  Card 153: 72 80 39 77 71 29 83 10  7 93 | 10 51 52 12  1 22 65 62 33 32 34 11 13 55 72 57 76 96 85 95 90  3 64 47 31
  Card 154: 89 66 34 86  8 75 50 98 56 71 | 74 39 16 68 56 27  5  2 58 97 75 34 90 91  8 71 95 66 50 98 60 92  6  9 35
  Card 155: 23 84 27 71 33 15 96 25 14 57 | 11 31 46 14 77 88 27 60 59 93  3 96 48 71 33 15  5  6 23 79 89 82 57 25 84
  Card 156: 10 25 83 53 73 33 56 29 95 24 | 22 29 11 32 41 74  4 43 46 38 78 16 91 12 73 54 62 10 25 47 52 65  7 28 63
  Card 157: 97 31 12 42 32 23 29 72 98 99 | 64 41  3 57 25 76 46 80 75 47 73 87 91 95 82 55 31 35 51 60 16  8 78 77 66
  Card 158: 90 46 61 13 33 59 12 25 30 49 | 29 57 31 46  1 64 93 43 94 21 87 83 23 67 91 52 92 85 71 78 36 79 62  5 58
  Card 159: 75 92 63 61 69 53  1 74 51 27 |  3 87 65 74 10 59 54 42 22 95 26 24 67 91 33 55 92 77 98 79 43 82 13 12 27
  Card 160: 50 38 97 82 73 27 91 79 74 41 | 69 71 34 94 55 40 23 84 10 25 14 67  7 46 48  6 37 91 12 66 16 17 26 22  9
  Card 161: 57 19 25 38 12 76 89 95 10 33 | 31 63 68 46 42 79 94 60  7 44 36 56 91 23 35 85 41 87 71 58 82 54 11  9 81
  Card 162: 17 54 37 84 85 46 99 51 86  7 | 32 38  4 66 49  7  9 23 76 35 51 85 52 30 45 19 89  6 82  5 58 91 87 72 50
  Card 163: 44  4 10 46 38 87 52 83 85 16 | 79 42 21 58 75  3 25 56  7 50 69 57 27 84 38 39 89 70 59 78 93 85  8 96 72
  Card 164: 76 26 66 23 89 37 87  9 34 81 | 84 43 14 21 13 20 95 97  3 33 18 88 81 78 16 86 58 48 90  6 61 11 68 62 64
  Card 165: 15 54 48 34 18 25 85 23 82 43 | 79 49 95 24  9 96 58 27  2  8 77  3 90 71 86 78 31 80 28 81 26 69 57 29 17
  Card 166: 23 94 29 56 27 33 51 55 79 98 | 85  7 89 74 69 15 19  2 97  5 27 88 43 80 86 62 78 76 67 63 30 20 65  1 37
  Card 167: 69 37 95  7 53 80 16 82 11 27 | 22 75  5 93 47 62 76 49  2 89  9 50 21 85 34 90 38 86 45 42 18 25 33 98 99
  Card 168: 95 12 30 74 21 24 80 64 17 67 | 86  8 98 19 37 48 75 56 16 31 20 40 29 83 79 73 71 27 59 43 65 61 57 78 81
  Card 169: 80  8  4 83 15 47 93  2 41 25 | 69 80 93 30 75 16 25 74 61 15 56 67 47  4 85 44  2 87 19 92 70 95 41 94 81
  Card 170: 91 25 44 98 29 80 63 26 72 88 |  7 57  3 38 17 44 70 75 88 92 54 14 80 26  8 40 98 55 39 32 72 29 61 63 86
  Card 171: 74 37 39 87 31  6  8 38 76 32 | 67 83 34 96 68 64 69 82 54 74 63 12 25 85  9 35 50 87 59 33 60 11 20 32 84
  Card 172: 45 96  3 16 97  2 98 27 51 34 | 63 82 10 95  6  5 14 24 57 69 98 23 51  3 43 91 79 35 20 36 48 44 90 84 70
  Card 173: 83 69 34  6  8 44 42 33 28  5 | 86 32 56 57  3 19 91 43 80 29 78  8 93 47 73 34 85 77 48 65 83 11  2 15 26
  Card 174: 22 30 18 86 72 57 26 29 38 69 | 37 21 80 26 61 68 52 33 15 74 69  9 66 81 17 40 99 78 23 65 43  1 95 79 24
  Card 175: 91 47 88  2 62 39 21  4 48 49 | 14 65 12  4 51 21 42  6 79 17 57 10  7 55 98 70 47 49  5 90 18 67 58 62 54
  Card 176: 76  7 72 24 57 19 70 41 67 87 | 37 59 36 95 90 28  8 58 93 97 40 57 18 80 69 66 13 54 87 27 86 62 76 84 19
  Card 177: 61 23 95 38  1 85 28 51 49 53 |  6 34 38 33 16 39 64 57 10 11 80 78 60 18 12 27  5 75 28 36 25 63 88 74  8
  Card 178: 22 69 42 55 54 52 58 11 89 70 | 54 75  5 88 74 97 64 59 94 82 16 76 58 20 23 90 28 47 67 38 66 51 42 83 52
  Card 179: 51 45 20 68 69 24 54 52 73 89 | 88  3 64  5 72  1 39 17 53 79 97  8 83 49 50 77 70 76 90 18 59 15 29 61 10
  Card 180: 68 10 39 93 62 32  1 20 90 99 | 40 31 38 23 63 27 94 85 87 36 53 67 56  5 72 13 22  6 89 25 35 64 41 57 65
  Card 181: 43 76 19 35 75 71 27 13 23  5 | 56 21 87 50 30 46  2 47 85 16 44 73  3 68 38 59 92 17 65 48 22 32 42 52 83
  Card 182: 77  3 61 97 96 84 27 48 52 40 |  9 54 65 43  7 20 29 86 73 67 87 82 42 14 55 33 39 71  1 81 69 31 92 74 75
  Card 183: 10 52 76 84 82 14 93 34 60 73 | 81 34 75 67 23 82 68 47 73  1 52 45 25 10  6 37 84 93 21 60 79 89 76 14 18
  Card 184: 39 91 94 34 71 86 36  2 65 74 | 46 37 91 79 74 59 65 66 34 30 40 73 36 16 64 57 92 71  2 78 94 89 77 86 39
  Card 185: 76 22 70 57 85 51 44 43 84 14 | 80 22 29 66 75  1 97 72 21 38 76 13 27 33 69 65 74  7 11 84 53 98 77 17 82
  Card 186: 59 49 71 34 66 23 52 79 32 28 | 59  2 32 93 70 96 86 71  1  3 10 28 49 51 66 79 61 24 23 19 46 52  7 34 42
  Card 187:  3 31 77 49 45 15 47  6 20 25 | 25 67 88 20 49  6 46 45  9 98 24  2 59 70 77 99 22 13 31 53 91 15  3 74 47
  Card 188: 84 19 66 65 53 61 38 25 83 91 | 24 64 43 66 11 72 53 94 86 39 28 97 18 70 68 52  5  7 30 55 38  9 85 34 31
  Card 189: 86 22 88 18 87 28 63 92  5 16 | 33 90 71 18 88 39 28 22 26 14 68  1 52 93 56 87 49 77 92 19 86 63  5 16 72
  Card 190: 67 83 94 44 66 25  9 98 21 51 | 55 97 76 81 85 68 40 94 66 41 51 45 69 44 50 37 63 83 87 39  2 96 98 95 13
  Card 191: 92 89 36 65  6 72 46 23 84 19 | 94 51 99  1  3 88 77 35 90 68 72 87 44 25 69 37  2 42 59 22 58 73 61 43 33
  Card 192: 52 49 74 40  2 89 54 87 21 79 | 50 58 54 24 79 27 74 72 62 67 46 89 52 38 83 40 49 29 26 77 87 12  5 21  2
  Card 193: 32 59 96 29 80  7 54  3 39 83 | 83 21 80 98 13 54 87 43 29 96 62 75 53 68 88 65 59 33  3 32 67 39 10 77  7
  Card 194: 40 12 79 91 84 54  1 74 56 38 | 31 78 38  9 25 46 10 99 54 11  2 97  5 84 37 77 27  1 50 91 43 72 12 96 56
  Card 195: 80 34 51 81 55 65 49 71  8 44 | 81 71 83 92  8 51 80 53 30 55 44  2 43 16 24 69 18 57 31 49 65 47 91 79  3
  Card 196: 12 22 77 95 49  1 48  8 84 47 | 61 64 63 42 55 13 96 70 73 41 92 10 58  6 86 30 14 23 91 66 87 72  9 27 51
  Card 197: 90 30 14 35 11 20 99 79 56  2 | 75 59 40 15 80 36 97 44 17 77 20 10 50 29 33 39 55 32 85 71 43 26 35 24 82
  Card 198: 92 98 86 34 64 32 74 17 26 53 | 32 75 97 22 66 89 74 17  8 31 69 52 41 53 34 77 45 46 68  2 96 86 95 93 21
  Card 199: 32 31 52 80  2 47  1 13 89  9 | 28 32 87  9 96  7 20 12 73 60 46 78 24 69 55 58 64 14 38 97 16 92 52 79 82
  Card 200:  1  8 31  4 53 15 45 22 73 13 | 22 10 73  9 81 74 83  2 11 53 15 45 46 21 62 43 69 50 32 67 41 48  5 25 24
  Card 201: 45 37 26 53 80  1 20 35 68 33 |  6 51 77 11 41 53 56 18 25 27 13 42 48 14 79 16 81 59 99 29 86 78  3 15 17
  Card 202: 86 56 57 83 11 19 52 69 36 17 | 65 72 11 95 73 49 25 75 15  5 84 35 18 71 44 99 26 52  9 60 45 22 14 19 94
  Card 203: 76 23 26 70 12 48 60 11 72 64 | 90 56 99 59 64 62 15 84 71 11 85 93 98 33 46 86 53 39  5 60 81 43  3 78 14
  Card 204: 23 75 70 14 95 84 61  9 66 77 | 79  8  1 64 50 41 32 93 58 15 33 10 28 72 82 16 77 65 25 43 39 49 13 23 83
  Card 205:  2 99 53 15 32  6 16 69 21 14 | 96 98 24 66  6 47  4 54 45 46 42 13 75 11 80 18 34 35 93 79 65 37 40 92 91
  Card 206: 74 30 29 66 68  2  3 34 79 87 | 63 45 88 78 98 27 97 32 38 75  9 11 71 93 55 69 56 20 12 82 81 41 80 23 94

Day 5: If You Give A Seed A Fertilizer

Get the puzzle solution as tangled .scm file.

Part One

Quest

You take the boat and find the gardener right where you were told he would be: managing a giant "garden" that looks more to you like a farm.

"A water source? Island Island is the water source!" You point out that Snow Island isn't receiving any water.

"Oh, we had to stop the water because we ran out of sand to filter it with! Can't make snow with dirty water. Don't worry, I'm sure we'll get more sand soon; we only turned off the water a few days… weeks… oh no." His face sinks into a look of horrified realization.

"I've been so busy making sure everyone here has food that I completely forgot to check why we stopped getting more sand! There's a ferry leaving soon that is headed over in that direction - it's much faster than your boat. Could you please go check it out?"

You barely have time to agree to this request when he brings up another. "While you wait for the ferry, maybe you can help us with our food production problem. The latest Island Island Almanac just arrived and we're having trouble making sense of it."

The almanac (your puzzle input) lists all of the seeds that need to be planted. It also lists what type of soil to use with each kind of seed, what type of fertilizer to use with each kind of soil, what type of water to use with each kind of fertilizer, and so on. Every type of seed, soil, fertilizer and so on is identified with a number, but numbers are reused by each category - that is, soil 123 and fertilizer 123 aren't necessarily related to each other.

For example:

  seeds: 79 14 55 13

  seed-to-soil map:
  50 98 2
  52 50 48

  soil-to-fertilizer map:
  0 15 37
  37 52 2
  39 0 15

  fertilizer-to-water map:
  49 53 8
  0 11 42
  42 0 7
  57 7 4

  water-to-light map:
  88 18 7
  18 25 70

  light-to-temperature map:
  45 77 23
  81 45 19
  68 64 13

  temperature-to-humidity map:
  0 69 1
  1 0 69

  humidity-to-location map:
  60 56 37
  56 93 4

The almanac starts by listing which seeds need to be planted: seeds 79, 14, 55, and 13.

The rest of the almanac contains a list of maps which describe how to convert numbers from a source category into numbers in a destination category. That is, the section that starts with seed-to-soil map: describes how to convert a seed number (the source) to a soil number (the destination). This lets the gardener and his team know which soil to use with which seeds, which water to use with which fertilizer, and so on.

Rather than list every source number and its corresponding destination number one by one, the maps describe entire ranges of numbers that can be converted. Each line within a map contains three numbers: the destination range start, the source range start, and the range length.

Consider again the example seed-to-soil map:

  50 98 2
  52 50 48

The first line has a destination range start of 50, a source range start of 98, and a range length of 2. This line means that the source range starts at 98 and contains two values: 98 and 99. The destination range is the same length, but it starts at 50, so its two values are 50 and 51. With this information, you know that seed number 98 corresponds to soil number 50 and that seed number 99 corresponds to soil number 51.

The second line means that the source range starts at 50 and contains 48 values: 50, 51, …, 96, 97. This corresponds to a destination range starting at 52 and also containing 48 values: 52, 53, …, 98, 99. So, seed number 53 corresponds to soil number 55.

Any source numbers that aren't mapped correspond to the same destination number. So, seed number 10 corresponds to soil number 10.

So, the entire list of seed numbers and their corresponding soil numbers looks like this:

  seed  soil
  0     0
  1     1
  ...   ...
  48    48
  49    49
  50    52
  51    53
  ...   ...
  96    98
  97    99
  98    50
  99    51

With this map, you can look up the soil number required for each initial seed number:

  • Seed number 79 corresponds to soil number 81.
  • Seed number 14 corresponds to soil number 14.
  • Seed number 55 corresponds to soil number 57.
  • Seed number 13 corresponds to soil number 13.

The gardener and his team want to get started as soon as possible, so they'd like to know the closest location that needs a seed. Using these maps, find the lowest location number that corresponds to any of the initial seeds. To do this, you'll need to convert each seed number through other categories until you can find its corresponding location number. In this example, the corresponding types are:

  • Seed 79, soil 81, fertilizer 81, water 81, light 74, temperature 78, humidity 78, location 82.
  • Seed 14, soil 14, fertilizer 53, water 49, light 42, temperature 42, humidity 43, location 43.
  • Seed 55, soil 57, fertilizer 57, water 53, light 46, temperature 82, humidity 82, location 86.
  • Seed 13, soil 13, fertilizer 52, water 41, light 34, temperature 34, humidity 35, location 35.

So, the lowest location number in this example is 35.

What is the lowest location number that corresponds to any of the initial seed numbers?

Puzzle Solution

Mapping Record
  (define-record entity type id)
  (define-record mapping-entry from-type to-type from-start from-end to-start to-end)
Data Extraction
Irregexes
  (define seed-irregex
    '(: (* whitespace)
        "seeds: "
        (submatch-named seed-numbers (+ (or numeric whitespace)))))
  (define mapping-irregex
    '(: (submatch-named mapping-from (+ alphabetic))
        "-to-"
        (submatch-named mapping-to (+ alphabetic))
        " map:"
        (submatch-named mapping-vals (+ (or numeric whitespace)))))
  (define mapping-nums-irregex
    '(: (* whitespace)
        (submatch-named to-range (+ numeric))
        (* whitespace)
        (submatch-named from-range (+ numeric))
        (* whitespace)
        (submatch-named range-size (+ numeric))))
Data Reading

A list of seed numbers:

  (define (input->seeds-list input)
    (let ((seeds-str (irregex-match-substring
                      (irregex-search seed-irregex input)
                      'seed-numbers)))
      (map string->number (string-split seeds-str))))

And a mapping from input type (e.g. #:soil) to the mappings to the next type:

  (define (input->mapping-alist input)
    (irregex-fold mapping-irregex
                  (lambda (from-index match seed)
                    (let ((map-from-key     (string->keyword (irregex-match-substring match 'mapping-from)))
                          (map-to-key       (string->keyword (irregex-match-substring match 'mapping-to)))
                          (mapping-vals-str (irregex-match-substring match 'mapping-vals)))
                      (cons
                       (cons
                        map-from-key
                        (irregex-fold mapping-nums-irregex
                                      (lambda (from-index match seed)
                                        (let ((from-start (string->number
                                                           (irregex-match-substring match 'from-range)))
                                              (to-start (string->number
                                                         (irregex-match-substring match 'to-range)))
                                              (range-size (string->number
                                                           (irregex-match-substring match 'range-size))))
                                          (cons
                                           (make-mapping-entry
                                            map-from-key map-to-key
                                            from-start (fx- (fx+ from-start range-size) 1)
                                            to-start (fx- (fx+ to-start range-size) 1))
                                           seed)))
                                      '() mapping-vals-str))
                       seed)))
                  '() input))
Processing The Data
  (define (map-entity-forward entity mapping-alist)
    (let ((maplist (alist-ref (entity-type entity) mapping-alist)))
      (if maplist
          (let ((default-target-type (mapping-entry-to-type (car maplist))))
            (or
             (foldl (lambda (new-entity mapping-entry)
                      (if (and (fx>= (entity-id entity)
                                     (mapping-entry-from-start mapping-entry))
                               (fx<= (entity-id entity)
                                     (mapping-entry-from-end mapping-entry)))
                          (make-entity (mapping-entry-to-type mapping-entry)
                                       (fx+ (mapping-entry-to-start mapping-entry)
                                            (fx- (entity-id entity)
                                                 (mapping-entry-from-start mapping-entry))))
                          new-entity))
                    #f maplist)
             (make-entity default-target-type (entity-id entity))))
          #f)))
  (define (map-entity-forward-fully entity mapping-alist)
    (let ((new-entity (map-entity-forward entity mapping-alist)))
      (if new-entity
          (map-entity-forward-fully new-entity mapping-alist)
          entity)))
Solution
  (let ((seeds (map (cut make-entity #:seed <>) (input->seeds-list input)))
        (mapping-alist (input->mapping-alist input)))
    (apply min (map (compose
                     entity-id
                     (cut map-entity-forward-fully <> mapping-alist))
                    seeds)))
1181555926

Part Two

Quest

Everyone will starve if you only plant such a small number of seeds. Re-reading the almanac, it looks like the seeds: line actually describes ranges of seed numbers.

The values on the initial seeds: line come in pairs. Within each pair, the first value is the start of the range and the second value is the length of the range. So, in the first line of the example above:

seeds: 79 14 55 13

This line describes two ranges of seed numbers to be planted in the garden. The first range starts with seed number 79 and contains 14 values: 79, 80, …, 91, 92. The second range starts with seed number 55 and contains 13 values: 55, 56, …, 66, 67.

Now, rather than considering four seed numbers, you need to consider a total of 27 seed numbers.

In the above example, the lowest location number can be obtained from seed number 82, which corresponds to soil 84, fertilizer 84, water 84, light 77, temperature 45, humidity 46, and location 46. So, the lowest location number is 46.

Consider all of the initial seed numbers listed in the ranges on the first line of the almanac. What is the lowest location number that corresponds to any of the initial seed numbers?

Puzzle Solution

All that is needed is to "expand" the seed numbers before continuing. Since we are dealing with such a huge number of seeds, I use delay-force to delay calculation of the later ones until they're actually needed.

  (define (expand-seed existing-seeds start size)
    (let ((max (- (+ start size) 1)))
      (do ((seedlist (cons start existing-seeds)
                     (cons (+ (car seedlist) 1)
                           seedlist)))
          ((< (- max 2) (car seedlist))
           seedlist))))

  (define (expand-seeds seed-nums #!optional (existing-seeds '()))
    (if (< 2 (length seed-nums))
        (expand-seeds (cddr seed-nums)
                      (delay-force (expand-seed existing-seeds
                                                (car seed-nums)
                                                (cadr seed-nums))))
        (expand-seed existing-seeds (car seed-nums) (cadr seed-nums))))

After that, it is almost identical to part 1, but we have to replace the foldl with a recursive function that handles the promises.

  (define (fold-seeds seeds mapping-alist #!optional (minimum most-positive-fixnum))
    (let* ((seeds (if (promise? seeds) (force seeds) seeds))
           (seeds-available? (not (eqv? '() seeds))))
      (if seeds-available?
          (let ((location-entity-id ((compose entity-id
                                              (cut map-entity-forward-fully <> mapping-alist)
                                              (cut make-entity #:seed <>))
                                     (car seeds))))
            (fold-seeds (cdr seeds)
                        mapping-alist
                        (min minimum location-entity-id)))
          minimum)))
  (let ((seeds (expand-seeds (input->seeds-list input)))
        (mapping-alist (input->mapping-alist input)))
    (fold-seeds seeds mapping-alist))
37806486

The Optimized Solution

For the optimized solution using ranges, a new record type is needed: ranged-entity.

  (define-record ranged-entity type from-id to-id)

To map the ranged-entity onto the next step, it has to be split up according to the mapping-entry ranges.

There are different types of splitting, and when they apply:

  • The beginning of ranged-entity lies lower than the mapping-entry: the part lower has to be extracted into a 1:1-mapping for the next step type.
  (define (extract-dangling-entity-part ranged-entity type mapping-entry)
    (let ((mapping-entry-lower-bound (mapping-entry-from-start mapping-entry)))
      (values (make-ranged-entity type
                                  (ranged-entity-from-id ranged-entity)
                                  (- mapping-entry-lower-bound 1))
              (make-ranged-entity (ranged-entity-type ranged-entity)
                                  mapping-entry-lower-bound
                                  (ranged-entity-to-id ranged-entity)))))
  • The beginning of ranged-entity is somewhere inside mapping-entry: the part inside the mapping-entity's range has to be extracted and the ids shifted accordingly.
  (define (extract-matching-entity-part ranged-entity type mapping-entry)
    (let* ((mapping-entry-lower-bound (mapping-entry-from-start mapping-entry))
           (mapping-entry-upper-bound (mapping-entry-from-end mapping-entry))
           (mapping-entry-target-start (mapping-entry-to-start mapping-entry))
           (ranged-entity-lower-bound  (ranged-entity-from-id ranged-entity))
           (ranged-entity-upper-bound  (ranged-entity-to-id ranged-entity))
           (start-offset               (- ranged-entity-lower-bound mapping-entry-lower-bound))
           (first-index                (max ranged-entity-lower-bound mapping-entry-lower-bound))
           (last-index                 (min ranged-entity-upper-bound mapping-entry-upper-bound))
           (range-size                 (- last-index first-index))
           (matches-mapping?           (= ranged-entity-upper-bound mapping-entry-upper-bound))
           (exceeds-mapping?           (> ranged-entity-upper-bound mapping-entry-upper-bound)))
      (values (make-ranged-entity type
                                  (+ mapping-entry-target-start start-offset)
                                  (+ mapping-entry-target-start start-offset range-size))
              (if exceeds-mapping?
                  (make-ranged-entity (ranged-entity-type ranged-entity)
                                     (+ mapping-entry-upper-bound 1)
                                     ranged-entity-upper-bound)
                  #f))))
  • There is just ranged-entity left, with nothing else: then it gets a new type, and is otherwise passed on 1:1.
  (define (map-dangling-entity ranged-entity type)
    (values (make-ranged-entity type
                                (ranged-entity-from-id ranged-entity)
                                (ranged-entity-to-id ranged-entity))
            #f))

This behemoth determines which of the functions above to call.

  (define (map-ranged-entity-forward ranged-entity type level-mappings)
    (let ((processed-ranged-entity #f)
          (remaining-ranged-entity #f)
          (retry? #f))
      (cond
       ((eqv? '() ranged-entity) '())
       ((eqv? '() level-mappings)
        (let-values (((processed-ranged-entity* remaining-ranged-entity*)
                      (map-dangling-entity ranged-entity type)))
          (set! processed-ranged-entity processed-ranged-entity*)
          (set! remaining-ranged-entity remaining-ranged-entity*)))
       ((and (>= (ranged-entity-from-id ranged-entity)
                 (mapping-entry-from-start (car level-mappings)))
             (<= (ranged-entity-from-id ranged-entity)
                 (mapping-entry-from-end (car level-mappings))))
        (let-values
            (((processed-ranged-entity* remaining-ranged-entity*)
              (extract-matching-entity-part ranged-entity type (car level-mappings))))
          (set! processed-ranged-entity processed-ranged-entity*)
          (set! remaining-ranged-entity remaining-ranged-entity*)))
       ((> (ranged-entity-from-id ranged-entity)
           (mapping-entry-from-end (car level-mappings)))
        (set! retry? #t))
       (else
        (let-values
            (((processed-ranged-entity* remaining-ranged-entity*)
              (extract-dangling-entity-part ranged-entity type (car level-mappings))))
          (set! processed-ranged-entity processed-ranged-entity*)
          (set! remaining-ranged-entity remaining-ranged-entity*))))
      (if retry?
          (map-ranged-entity-forward ranged-entity type (cdr level-mappings))
          (if remaining-ranged-entity
              (cons processed-ranged-entity
                    (map-ranged-entity-forward remaining-ranged-entity type (cdr level-mappings)))
              (list processed-ranged-entity)))))

Here, the mapping is being done.

  (define (map-ranged-entity-forward-fully ranged-entity mapping-alist)
    (let ((mappings (alist-ref (ranged-entity-type ranged-entity) mapping-alist)))
      (if (and (not (eqv? '() mappings))
               mappings)
          (let* ((mappings-alist (map (lambda (x)
                                        (cons (mapping-entry-from-start x) x))
                                      mappings))
                 (sorted-mapping-ids (sort (map car mappings-alist) <))
                 (sorted-mappings (map (cut alist-ref <> mappings-alist) sorted-mapping-ids))
                 (new-type (mapping-entry-to-type (car sorted-mappings)))
                 (new-entities (map-ranged-entity-forward ranged-entity new-type sorted-mappings)))
            (foldl append '() (map (cut map-ranged-entity-forward-fully <> mapping-alist)
                                   new-entities)))
          (list ranged-entity))))

  (define (seeds-list->ranged-entities seeds)
    (if (<= 2 (length seeds))
        (cons (make-ranged-entity #:seed (car seeds)
                                  (- (+ (car seeds) (cadr seeds)) 1))
              (seeds-list->ranged-entities (cddr seeds)))
        '()))

And here, it is all put together.

  (define (calc-part-2-optimized)
    (let ((seeds (seeds-list->ranged-entities (input->seeds-list input)))
          (mapping-alist (input->mapping-alist input)))
      (foldl min most-positive-fixnum
             (map ranged-entity-from-id
                  (foldl append '()
                         (map (cut map-ranged-entity-forward-fully <> mapping-alist)
                              seeds))))))

Puzzle Input

Jump to day 6.

  seeds: 364807853 408612163 302918330 20208251 1499552892 200291842 3284226943 16030044 2593569946 345762334 3692780593 17215731 1207118682 189983080 2231594291 72205975 3817565407 443061598 2313976854 203929368

  seed-to-soil map:
  2069473506 3732587455 1483883
  3235691256 2348990120 6550341
  3547561069 1392195671 747406227
  3264251584 3734071338 283309485
  391285622 257757572 195552540
  1645243555 3166958320 377191689
  335002083 512210869 56283539
  3242241597 897735089 22009987
  77244511 0 257757572
  989159646 4172023334 122943962
  605476380 3544150009 188437446
  0 568494408 18343754
  2700122696 4050276683 121746651
  2022435244 2139601898 47038262
  2227672101 919745076 95840269
  1112103608 2633818373 533139947
  826809686 2186640160 162349960
  3100147259 762191092 135543997
  18343754 453310112 58900757
  2323512370 1015585345 282396986
  2605909356 1297982331 94213340
  2821869347 2355540461 278277912
  793913826 4017380823 32895860
  2070957389 605476380 156714712

  soil-to-fertilizer map:
  2700214958 2743391193 363795571
  1484584575 1440072796 24660284
  927520818 435059068 191969051
  1588488926 1434420334 5652462
  1423277199 141187887 5443857
  1594141388 1350997453 83422881
  1986188257 3933008893 120750463
  1509244859 146631744 79093544
  3712482038 4220862006 74105290
  3948206286 1986188257 277570873
  291046304 281588807 153470261
  1119489869 918224946 303787330
  1677564269 1321192605 29804848
  2309878676 2336743687 390336282
  3079951473 3306332300 449116691
  444516565 1222012276 99180329
  543696894 1464733080 383823924
  3895169406 3771389935 53036880
  3529068164 4053759356 167102650
  0 627178642 291046304
  3696170814 2727079969 16311224
  3855550220 3824426815 39619186
  2106938720 3107186764 199145536
  1428721056 225725288 55863519
  1707369117 0 64378064
  1771747181 64378064 76809823
  3064010529 3755448991 15940944
  2306084256 2332949267 3794420
  4225777159 2263759130 69190137
  3786587328 3864046001 68962892
  1588338403 627028119 150523

  fertilizer-to-water map:
  2299879115 39069388 7889905
  514481680 504392888 101474410
  3448524168 0 25428313
  13641075 1832356728 472401611
  0 25428313 13641075
  1842445520 108629584 395763304
  486042686 3445513487 28438994
  2307769020 2304758339 1140755148
  2238208824 46959293 61670291
  615956090 605867298 1226489430

  water-to-light map:
  1318826171 2010420436 223477535
  2278894745 2233897971 671603259
  988189854 447584401 27746374
  2132052210 300741866 146842535
  0 1279660741 97125596
  3531244480 3147213622 507810286
  257581844 3816963790 101424269
  1298609589 3918388059 20216582
  3317726838 1072550929 21856732
  3065323607 1254863909 4121973
  97125596 1094407661 160456248
  359006113 1057194484 15356445
  374362558 1636971609 104335413
  4039054766 475330775 9209679
  1038424317 1376786337 260185272
  878530050 3938604641 109659804
  1784016098 3738041092 78922698
  3152462764 0 165264074
  1862938796 1741307022 269113414
  497536930 676201364 380993120
  3069445580 3655023908 83017184
  2950498004 165264074 114825603
  1015936228 1258985882 1835900
  478697971 1260821782 18838959
  1017772128 280089677 20652189
  1542303706 2905501230 241712392
  3339583570 484540454 191660910

  light-to-temperature map:
  2827696039 489007811 183207687
  1480301347 3744628626 306791400
  695239418 130668965 358338846
  1297125534 2232912413 183175813
  3979319170 1917264287 315648126
  3010903726 948848843 968415444
  130668965 2663473525 564570453
  1053578264 4051420026 243547270
  2303677395 672215498 276633345
  1787092747 3228043978 516584648
  2580310740 2416088226 247385299

  temperature-to-humidity map:
  4161466647 3871737509 133500649
  2423686895 2864370860 72123408
  1983529997 0 320533964
  3184295196 2695571092 41928210
  0 822932241 605870242
  3557076981 3267347843 604389666
  3226223406 2936494268 330853575
  2495810303 2737499302 126871558
  1108268519 1428802483 491674128
  605870242 320533964 502398277
  2622681861 2423686895 271884197
  2894566058 4005238158 289729138
  1599942647 1920476611 383587350

  humidity-to-location map:
  2945628300 1864953738 334378942
  3467273713 3579654586 715312710
  975015905 1356290883 508662855
  1483678760 2498980024 1080674562
  3443998409 2199332680 23275304
  3280007242 2222607984 163991167
  4182586423 2386599151 112380873
  2564353322 975015905 381274978

Day 6: Wait For It

Get the puzzle solution as tangled .scm file.

Part One

Quest

The ferry quickly brings you across Island Island. After asking around, you discover that there is indeed normally a large pile of sand somewhere near here, but you don't see anything besides lots of water and the small island where the ferry has docked.

As you try to figure out what to do next, you notice a poster on a wall near the ferry dock. "Boat races! Open to the public! Grand prize is an all-expenses-paid trip to Desert Island!" That must be where the sand comes from! Best of all, the boat races are starting in just a few minutes.

You manage to sign up as a competitor in the boat races just in time. The organizer explains that it's not really a traditional race - instead, you will get a fixed amount of time during which your boat has to travel as far as it can, and you win if your boat goes the farthest.

As part of signing up, you get a sheet of paper (your puzzle input) that lists the time allowed for each race and also the best distance ever recorded in that race. To guarantee you win the grand prize, you need to make sure you go farther in each race than the current record holder.

The organizer brings you over to the area where the boat races are held. The boats are much smaller than you expected - they're actually toy boats, each with a big button on top. Holding down the button charges the boat, and releasing the button allows the boat to move. Boats move faster if their button was held longer, but time spent holding the button counts against the total race time. You can only hold the button at the start of the race, and boats don't move until the button is released.

For example:

  Time:      7  15   30
  Distance:  9  40  200

This document describes three races:

  • The first race lasts 7 milliseconds. The record distance in this race is 9 millimeters.
  • The second race lasts 15 milliseconds. The record distance in this race is 40 millimeters.
  • The third race lasts 30 milliseconds. The record distance in this race is 200 millimeters.

Your toy boat has a starting speed of zero millimeters per millisecond. For each whole millisecond you spend at the beginning of the race holding down the button, the boat's speed increases by one millimeter per millisecond.

So, because the first race lasts 7 milliseconds, you only have a few options:

  • Don't hold the button at all (that is, hold it for 0 milliseconds) at the start of the race. The boat won't move; it will have traveled 0 millimeters by the end of the race.
  • Hold the button for 1 millisecond at the start of the race. Then, the boat will travel at a speed of 1 millimeter per millisecond for 6 milliseconds, reaching a total distance traveled of *=6 millimeters=.
  • Hold the button for 2 milliseconds, giving the boat a speed of 2 millimeters per millisecond. It will then get 5 milliseconds to move, reaching a total distance of 10 millimeters.
  • Hold the button for 3 milliseconds. After its remaining 4 milliseconds of travel time, the boat will have gone *=12= millimeters=.
  • Hold the button for 4 milliseconds. After its remaining 3 milliseconds of travel time, the boat will have gone 12 millimeters.
  • Hold the button for 5 milliseconds, causing the boat to travel a total of 10 millimeters.
  • Hold the button for 6 milliseconds, causing the boat to travel a total of 6 millimeters.
  • Hold the button for 7 milliseconds. That's the entire duration of the race. You never let go of the button. The boat can't move until you let go of the button. Please make sure you let go of the button so the boat gets to move. 0 millimeters.

Since the current record for this race is 9 millimeters, there are actually 4 different ways you could win: you could hold the button for 2, 3, 4, or 5 milliseconds at the start of the race.

In the second race, you could hold the button for at least 4 milliseconds and at most 11 milliseconds and beat the record, a total of 8 different ways to win.

In the third race, you could hold the button for at least 11 milliseconds and no more than 19 milliseconds and still beat the record, a total of 9 ways you could win.

To see how much margin of error you have, determine the number of ways you can beat the record in each race; in this example, if you multiply these values together, you get 288 (4 * 8 * 9).

Determine the number of ways you could beat the record in each race. What do you get if you multiply these numbers together?

Puzzle Solution

Data Extraction

First, we need to define the record for the race data.

  (define-record race time-limit record-distance winning-distances losing-distances)

The solution starts with the usual data extraction using irregex.

  (define input-extraction-irregex
    '(: "Time:"
        (submatch-named time-vals (+ (or numeric whitespace)))
        "Distance:"
        (submatch-named distance-vals (+ (or numeric whitespace)))))

Next, the data is converted into race records.

  (define (input->race-records input)
    (let ((match (irregex-search input-extraction-irregex
                                 input)))
      (map (lambda (time distance)
             (make-race time distance #f #f))
           (map string->number (string-split (irregex-match-substring match 'time-vals)))
           (map string->number (string-split (irregex-match-substring match 'distance-vals))))))
Race Calculations
  (define (get-distance race hold-time)
    (let ((time-remaining (- (race-time-limit race) hold-time)))
      (* time-remaining hold-time)))
  (define (calc-race-distances race
           #!optional (hold-time 1) (winning-distances '()) (losing-distances '()))
    (let* ((record-distance (race-record-distance race))
           (new-distance (get-distance race hold-time))
           (is-new-record? (> new-distance record-distance)))
      (cond
       ((= new-distance 0)
        (begin
          (race-winning-distances-set! race winning-distances)
          (race-losing-distances-set! race losing-distances)
          race))
       (else
        (calc-race-distances
         race (+ hold-time 1)
         (if is-new-record? (cons new-distance winning-distances) winning-distances)
         (if is-new-record? losing-distances (cons new-distance losing-distances)))))))
Getting The Result
  (import (chicken string)
          (chicken irregex))
  (define input "
    Time:        58     81     96     76
    Distance:   434   1041   2219   1218")
  (define-record race time-limit record-distance winning-distances losing-distances)
  (define input-extraction-irregex
    '(: "Time:"
        (submatch-named time-vals (+ (or numeric whitespace)))
        "Distance:"
        (submatch-named distance-vals (+ (or numeric whitespace)))))
  (define (input->race-records input)
    (let ((match (irregex-search input-extraction-irregex
                                 input)))
      (map (lambda (time distance)
             (make-race time distance #f #f))
           (map string->number (string-split (irregex-match-substring match 'time-vals)))
           (map string->number (string-split (irregex-match-substring match 'distance-vals))))))
  (define (get-distance race hold-time)
    (let ((time-remaining (- (race-time-limit race) hold-time)))
      (* time-remaining hold-time)))
  (define (calc-race-distances race
           #!optional (hold-time 1) (winning-distances '()) (losing-distances '()))
    (let* ((record-distance (race-record-distance race))
           (new-distance (get-distance race hold-time))
           (is-new-record? (> new-distance record-distance)))
      (cond
       ((= new-distance 0)
        (begin
          (race-winning-distances-set! race winning-distances)
          (race-losing-distances-set! race losing-distances)
          race))
       (else
        (calc-race-distances
         race (+ hold-time 1)
         (if is-new-record? (cons new-distance winning-distances) winning-distances)
         (if is-new-record? losing-distances (cons new-distance losing-distances)))))))
  (define (calc-part-1)
    (foldl *
           1 (map (compose length race-winning-distances)
                  (map calc-race-distances (input->race-records input)))))
1159152

Part Two

Quest

As the race is about to start, you realize the piece of paper with race times and record distances you got earlier actually just has very bad kerning. There's really only one race - ignore the spaces between the numbers on each line.

So, the example from before:

  Time:      7  15   30
  Distance:  9  40  200

…now instead means this:

  Time:      71530
  Distance:  940200

Now, you have to figure out how many ways there are to win this single race. In this example, the race lasts for 71530 milliseconds and the record distance you need to beat is 940200 millimeters. You could hold the button anywhere from 14 to 71516 milliseconds and beat the record, a total of 71503 ways!

How many ways can you beat the record in this one much longer race?

Puzzle Solution

Code Changes

The input->race-records function has to be rewritten:

  (define (input->race-record input)
    (let* ((match (irregex-search input-extraction-irregex input))
           (time-val ((compose string->number
                                (cut foldl string-append "" <>)
                                string-split
                                (cut irregex-match-substring <> 'time-vals))
                       match))
           (distance-val ((compose string->number
                                    (cut foldl string-append "" <>)
                                    string-split
                                    (cut irregex-match-substring <> 'distance-vals))
                           match)))
       (make-race time-val distance-val #f #f)))

And instead of keeping a list of all winning and losing distances, I use a counter.

  (define (calc-race-distances-with-counter race
           #!optional (hold-time 1) (winning-distances 0) (losing-distances 0))
    (let* ((record-distance (race-record-distance race))
           (new-distance (get-distance race hold-time))
           (is-new-record? (> new-distance record-distance)))
      (cond
       ((= new-distance 0)
        (begin
          (race-winning-distances-set! race winning-distances)
          (race-losing-distances-set! race losing-distances)
          race))
       (else
        (calc-race-distances-with-counter
         race (+ hold-time 1)
         (if is-new-record? (+ 1 winning-distances) winning-distances)
         (if is-new-record? losing-distances (+ 1 losing-distances)))))))
Race Variant Results
  (import (chicken string)
          (chicken irregex))
  (define input "
    Time:        58     81     96     76
    Distance:   434   1041   2219   1218")
  (define-record race time-limit record-distance winning-distances losing-distances)
  (define input-extraction-irregex
    '(: "Time:"
        (submatch-named time-vals (+ (or numeric whitespace)))
        "Distance:"
        (submatch-named distance-vals (+ (or numeric whitespace)))))
  (define (input->race-record input)
    (let* ((match (irregex-search input-extraction-irregex input))
           (time-val ((compose string->number
                                (cut foldl string-append "" <>)
                                string-split
                                (cut irregex-match-substring <> 'time-vals))
                       match))
           (distance-val ((compose string->number
                                    (cut foldl string-append "" <>)
                                    string-split
                                    (cut irregex-match-substring <> 'distance-vals))
                           match)))
       (make-race time-val distance-val #f #f)))
  (define (get-distance race hold-time)
    (let ((time-remaining (- (race-time-limit race) hold-time)))
      (* time-remaining hold-time)))
  (define (calc-race-distances-with-counter race
           #!optional (hold-time 1) (winning-distances 0) (losing-distances 0))
    (let* ((record-distance (race-record-distance race))
           (new-distance (get-distance race hold-time))
           (is-new-record? (> new-distance record-distance)))
      (cond
       ((= new-distance 0)
        (begin
          (race-winning-distances-set! race winning-distances)
          (race-losing-distances-set! race losing-distances)
          race))
       (else
        (calc-race-distances-with-counter
         race (+ hold-time 1)
         (if is-new-record? (+ 1 winning-distances) winning-distances)
         (if is-new-record? losing-distances (+ 1 losing-distances)))))))
  (define (calc-part-2)
    (race-winning-distances
     (calc-race-distances-with-counter (input->race-record input))))
41513103

Puzzle Input

Jump to day 7.

  Time:        58     81     96     76
  Distance:   434   1041   2219   1218

Day 7: Camel Cards

Get the puzzle solution as tangled .scm file.

Part One

Quest

Your all-expenses-paid trip turns out to be a one-way, five-minute ride in an airship. (At least it's a cool airship!) It drops you off at the edge of a vast desert and descends back to Island Island.

"Did you bring the parts?"

You turn around to see an Elf completely covered in white clothing, wearing goggles, and riding a large camel.

"Did you bring the parts?" she asks again, louder this time. You aren't sure what parts she's looking for; you're here to figure out why the sand stopped.

"The parts! For the sand, yes! Come with me; I will show you." She beckons you onto the camel.

After riding a bit across the sands of Desert Island, you can see what look like very large rocks covering half of the horizon. The Elf explains that the rocks are all along the part of Desert Island that is directly above Island Island, making it hard to even get there. Normally, they use big machines to move the rocks and filter the sand, but the machines have broken down because Desert Island recently stopped receiving the parts they need to fix the machines.

You've already assumed it'll be your job to figure out why the parts stopped when she asks if you can help. You agree automatically.

Because the journey will take a few days, she offers to teach you the game of Camel Cards. Camel Cards is sort of similar to poker except it's designed to be easier to play while riding a camel.

In Camel Cards, you get a list of hands, and your goal is to order them based on the strength of each hand. A hand consists of five cards labeled one of A, K, Q, J, T, 9, 8, 7, 6, 5, 4, 3, or 2. The relative strength of each card follows this order, where A is the highest and 2 is the lowest.

Every hand is exactly one type. From strongest to weakest, they are:

  • Five of a kind, where all five cards have the same label: AAAAA
  • Four of a kind, where four cards have the same label and one card has a different label: AA8AA
  • Full house, where three cards have the same label, and the remaining two cards share a different label: 23332
  • Three of a kind, where three cards have the same label, and the remaining two cards are each different from any other card in the hand: TTT98
  • Two pair, where two cards share one label, two other cards share a second label, and the remaining card has a third label: 23432
  • One pair, where two cards share one label, and the other three cards have a different label from the pair and each other: A23A4
  • High card, where all cards' labels are distinct: 23456

Hands are primarily ordered based on type; for example, every full house is stronger than any three of a kind.

If two hands have the same type, a second ordering rule takes effect. Start by comparing the first card in each hand. If these cards are different, the hand with the stronger first card is considered stronger. If the first card in each hand have the same label, however, then move on to considering the second card in each hand. If they differ, the hand with the higher second card wins; otherwise, continue with the third card in each hand, then the fourth, then the fifth.

So, 33332 and 2AAAA are both four of a kind hands, but 33332 is stronger because its first card is stronger. Similarly, 77888 and 77788 are both a full house, but 77888 is stronger because its third card is stronger (and both hands have the same first and second card).

To play Camel Cards, you are given a list of hands and their corresponding bid (your puzzle input). For example:

  32T3K 765
  T55J5 684
  KK677 28
  KTJJT 220
  QQQJA 483

This example shows five hands; each hand is followed by its bid amount. Each hand wins an amount equal to its bid multiplied by its rank, where the weakest hand gets rank 1, the second-weakest hand gets rank 2, and so on up to the strongest hand. Because there are five hands in this example, the strongest hand will have rank 5 and its bid will be multiplied by 5.

So, the first step is to put the hands in order of strength:

  • 32T3K is the only one pair and the other hands are all a stronger type, so it gets rank 1.
  • KK677 and KTJJT are both two pair. Their first cards both have the same label, but the second card of KK677 is stronger (K vs T), so KTJJT gets rank 2 and KK677 gets rank 3.
  • T55J5 and QQQJA are both three of a kind. QQQJA has a stronger first card, so it gets rank 5 and T55J5 gets rank 4.

Now, you can determine the total winnings of this set of hands by adding up the result of multiplying each hand's bid with its rank (765 * 1 + 220 * 2 + 28 * 3 + 684 * 4 + 483 * 5). So the total winnings in this example are 6440.

Find the rank of every hand in your set. What are the total winnings?

Puzzle Solution

Because the journey will take a few days, she offers to teach you the game of Camel Cards. Camel Cards is sort of similar to poker except it's designed to be easier to play while riding a camel.

In Camel Cards, you get a list of hands, and your goal is to order them based on the strength of each hand. A hand consists of five cards labeled one of A, K, Q, J, T, 9, 8, 7, 6, 5, 4, 3, or 2. The relative strength of each card follows this order, where A is the highest and 2 is the lowest.

  (define cards `((#:A . ,(make-card #:A 13))
                  (#:K . ,(make-card #:K 12))
                  (#:Q . ,(make-card #:Q 11))
                  (#:J . ,(make-card #:J 10))
                  (#:T . ,(make-card #:T  9))
                  (#:9 . ,(make-card #:9  8))
                  (#:8 . ,(make-card #:8  7))
                  (#:7 . ,(make-card #:7  6))
                  (#:6 . ,(make-card #:6  5))
                  (#:5 . ,(make-card #:5  4))
                  (#:4 . ,(make-card #:4  3))
                  (#:3 . ,(make-card #:3  2))
                  (#:2 . ,(make-card #:2  1))))
#<unspecified>

The hands are separated into types.

  (define (calc-card-frequencies cardlist #!optional (frequencies '()))
    (if (eqv? '() cardlist)
        (sort (map cdr frequencies) >)
        (let* ((card-label (card-label (car cardlist)))
               (card-old-frequency (alist-ref card-label frequencies eqv? 0)))
          (calc-card-frequencies (cdr cardlist)
                                 (alist-update card-label (+ 1 card-old-frequency) frequencies)))))

  (define (calc-hand-type hand)
    (let ((frequencies (calc-card-frequencies (hand-cards hand))))
      (cond ;; Insert the comparisons from below here
             ))
    hand)
#<unspecified>

For the sake of brevity, there is a shortcut function to get a type for a hand of cards, to be used in the following examples:

  (define (get-type-for-cards #!rest card-labels)
    (hand-type-label
     (hand-type-rec
      (calc-hand-type (make-hand (map (cut alist-ref <> cards) card-labels) #f #f #f)))))
#<unspecified>

Every hand is exactly one type. From strongest to weakest, they are:

  • Five of a kind, where all five cards have the same label: AAAAA;

    (get-type-for-cards #:A #:A #:A #:A #:A)
    #:five-of-a-kind

      ((= 5 (car frequencies))
       (hand-type-rec-set! hand (alist-ref #:five-of-a-kind hand-types)))
      Error: (#f) "unbound variable": (frequencies)
      Call history: 
      <eval>   (with-all-output-to-string (lambda () (call-with-values thunk (lambda v (set! result v)))))
      <eval>   (with-output-to-string (lambda () (with-error-output-to-port (current-output-port) thunk)))
      <eval>   (with-error-output-to-port (current-output-port) thunk)
      <eval>   (current-output-port)
      <eval>   (call-with-values thunk (lambda v (set! result v)))
      <eval>   (eval form)
      <syntax> (begin ((= 5 (car frequencies)) (hand-type-rec-set! hand (alist-ref #:five-of-a-kind hand-types))))
      <syntax> (##core#begin ((= 5 (car frequencies)) (hand-type-rec-set! hand (alist-ref #:five-of-a-kind hand-types))))
      <syntax> ((= 5 (car frequencies)) (hand-type-rec-set! hand (alist-ref #:five-of-a-kind hand-types)))
      <syntax> (= 5 (car frequencies))
      <syntax> (car frequencies)
      <syntax> (hand-type-rec-set! hand (alist-ref #:five-of-a-kind hand-types))
      <syntax> (alist-ref #:five-of-a-kind hand-types)
      <eval>   ((= 5 (car frequencies)) (hand-type-rec-set! hand (alist-ref #:five-of-a-kind hand-types)))
      <eval>   (= 5 (car frequencies))
      <eval>   (car frequencies)
    
  • Four of a kind, where four cards have the same label and one card has a different label: AA8AA;

    (get-type-for-cards #:A #:A #:8 #:A #:A)
    #:four-of-a-kind

      ((= 4 (car frequencies))
       (hand-type-rec-set! hand (alist-ref #:four-of-a-kind hand-types)))
      Error: (#f) "unbound variable": (frequencies)
      Call history: 
      <eval>   (with-all-output-to-string (lambda () (call-with-values thunk (lambda v (set! result v)))))
      <eval>   (with-output-to-string (lambda () (with-error-output-to-port (current-output-port) thunk)))
      <eval>   (with-error-output-to-port (current-output-port) thunk)
      <eval>   (current-output-port)
      <eval>   (call-with-values thunk (lambda v (set! result v)))
      <eval>   (eval form)
      <syntax> (begin ((= 4 (car frequencies)) (hand-type-rec-set! hand (alist-ref #:four-of-a-kind hand-types))))
      <syntax> (##core#begin ((= 4 (car frequencies)) (hand-type-rec-set! hand (alist-ref #:four-of-a-kind hand-types))))
      <syntax> ((= 4 (car frequencies)) (hand-type-rec-set! hand (alist-ref #:four-of-a-kind hand-types)))
      <syntax> (= 4 (car frequencies))
      <syntax> (car frequencies)
      <syntax> (hand-type-rec-set! hand (alist-ref #:four-of-a-kind hand-types))
      <syntax> (alist-ref #:four-of-a-kind hand-types)
      <eval>   ((= 4 (car frequencies)) (hand-type-rec-set! hand (alist-ref #:four-of-a-kind hand-types)))
      <eval>   (= 4 (car frequencies))
      <eval>   (car frequencies)
    
  • Full house, where three cards have the same label, and the remaining two cards share a different label: 23332;

    (get-type-for-cards #:2 #:3 #:3 #:3 #:2)
    #:full-house

      ((and (= 3 (car frequencies))
            (= 2 (cadr frequencies)))
       (hand-type-rec-set! hand (alist-ref #:full-house hand-types)))
  Error: (#f) "unbound variable": (frequencies)
  Call history: 
  <eval>   (eval form)
  <syntax> (begin ((and (= 3 (car frequencies)) (= 2 (cadr frequencies))) (hand-type-rec-set! hand (alist-ref #:full-house hand-types))))
  <syntax> (##core#begin ((and (= 3 (car frequencies)) (= 2 (cadr frequencies))) (hand-type-rec-set! hand (alist-ref #:full-house hand-types))))
  <syntax> ((and (= 3 (car frequencies)) (= 2 (cadr frequencies))) (hand-type-rec-set! hand (alist-ref #:full-house hand-types)))
  <syntax> (and (= 3 (car frequencies)) (= 2 (cadr frequencies)))
  <syntax> (##core#if (= 3 (car frequencies)) (and26474 (= 2 (cadr frequencies))) #f)
  <syntax> (= 3 (car frequencies))
  <syntax> (car frequencies)
  <syntax> (and26474 (= 2 (cadr frequencies)))
  <syntax> (= 2 (cadr frequencies))
  <syntax> (cadr frequencies)
  <syntax> (hand-type-rec-set! hand (alist-ref #:full-house hand-types))
  <syntax> (alist-ref #:full-house hand-types)
  <eval>   ((and (= 3 (car frequencies)) (= 2 (cadr frequencies))) (hand-type-rec-set! hand (alist-ref #:full-house hand-types)))
  <eval>   (= 3 (car frequencies))
  <eval>   (car frequencies)
  • Three of a kind, where three cards have the same label, and the remaining two cards are each different from any other card in the hand: TTT98;

    (get-type-for-cards #:T #:T #:T #:9 #:8)
    #:three-of-a-kind

      ((= 3 (car frequencies))
       (hand-type-rec-set! hand (alist-ref #:three-of-a-kind hand-types)))
      Error: (#f) "unbound variable": (frequencies)
      Call history: 
      <eval>   (with-all-output-to-string (lambda () (call-with-values thunk (lambda v (set! result v)))))
      <eval>   (with-output-to-string (lambda () (with-error-output-to-port (current-output-port) thunk)))
      <eval>   (with-error-output-to-port (current-output-port) thunk)
      <eval>   (current-output-port)
      <eval>   (call-with-values thunk (lambda v (set! result v)))
      <eval>   (eval form)
      <syntax> (begin ((= 3 (car frequencies)) (hand-type-rec-set! hand (alist-ref #:three-of-a-kind hand-types))))
      <syntax> (##core#begin ((= 3 (car frequencies)) (hand-type-rec-set! hand (alist-ref #:three-of-a-kind hand-types))))
      <syntax> ((= 3 (car frequencies)) (hand-type-rec-set! hand (alist-ref #:three-of-a-kind hand-types)))
      <syntax> (= 3 (car frequencies))
      <syntax> (car frequencies)
      <syntax> (hand-type-rec-set! hand (alist-ref #:three-of-a-kind hand-types))
      <syntax> (alist-ref #:three-of-a-kind hand-types)
      <eval>   ((= 3 (car frequencies)) (hand-type-rec-set! hand (alist-ref #:three-of-a-kind hand-types)))
      <eval>   (= 3 (car frequencies))
      <eval>   (car frequencies)
    
  • Two pair, where two cards share one label, two other cards share a second label, and the remaining card has a third label: 23432;

    (get-type-for-cards #:2 #:3 #:4 #:3 #:2)
    #:two-pair

      ((and (= 2 (car frequencies))
            (= 2 (cadr frequencies)))
       (hand-type-rec-set! hand (alist-ref #:two-pair hand-types)))
      Error: (#f) "unbound variable": (frequencies)
      Call history: 
      <eval>   (eval form)
      <syntax> (begin ((and (= 2 (car frequencies)) (= 2 (cadr frequencies))) (hand-type-rec-set! hand (alist-ref #:two-pair hand-types))))
      <syntax> (##core#begin ((and (= 2 (car frequencies)) (= 2 (cadr frequencies))) (hand-type-rec-set! hand (alist-ref #:two-pair hand-types))))
      <syntax> ((and (= 2 (car frequencies)) (= 2 (cadr frequencies))) (hand-type-rec-set! hand (alist-ref #:two-pair hand-types)))
      <syntax> (and (= 2 (car frequencies)) (= 2 (cadr frequencies)))
      <syntax> (##core#if (= 2 (car frequencies)) (and26693 (= 2 (cadr frequencies))) #f)
      <syntax> (= 2 (car frequencies))
      <syntax> (car frequencies)
      <syntax> (and26693 (= 2 (cadr frequencies)))
      <syntax> (= 2 (cadr frequencies))
      <syntax> (cadr frequencies)
      <syntax> (hand-type-rec-set! hand (alist-ref #:two-pair hand-types))
      <syntax> (alist-ref #:two-pair hand-types)
      <eval>   ((and (= 2 (car frequencies)) (= 2 (cadr frequencies))) (hand-type-rec-set! hand (alist-ref #:two-pair hand-types)))
      <eval>   (= 2 (car frequencies))
      <eval>   (car frequencies)
    
  • One pair, where two cards share one label, and the other three cards have a different label from the pair and each other: A23A4;

    (get-type-for-cards #:A #:2 #:3 #:A #:4)
    #:one-pair

      ((= 2 (car frequencies))
       (hand-type-rec-set! hand (alist-ref #:one-pair hand-types)))
      Error: (#f) "unbound variable": (frequencies)
      Call history: 
      <eval>   (with-all-output-to-string (lambda () (call-with-values thunk (lambda v (set! result v)))))
      <eval>   (with-output-to-string (lambda () (with-error-output-to-port (current-output-port) thunk)))
      <eval>   (with-error-output-to-port (current-output-port) thunk)
      <eval>   (current-output-port)
      <eval>   (call-with-values thunk (lambda v (set! result v)))
      <eval>   (eval form)
      <syntax> (begin ((= 2 (car frequencies)) (hand-type-rec-set! hand (alist-ref #:one-pair hand-types))))
      <syntax> (##core#begin ((= 2 (car frequencies)) (hand-type-rec-set! hand (alist-ref #:one-pair hand-types))))
      <syntax> ((= 2 (car frequencies)) (hand-type-rec-set! hand (alist-ref #:one-pair hand-types)))
      <syntax> (= 2 (car frequencies))
      <syntax> (car frequencies)
      <syntax> (hand-type-rec-set! hand (alist-ref #:one-pair hand-types))
      <syntax> (alist-ref #:one-pair hand-types)
      <eval>   ((= 2 (car frequencies)) (hand-type-rec-set! hand (alist-ref #:one-pair hand-types)))
      <eval>   (= 2 (car frequencies))
      <eval>   (car frequencies)
    
  • High card, where all cards' labels are distinct: 23456;

    (get-type-for-cards #:2 #:3 #:4 #:5 #:6)
    #:high-card

      ((= 1 (car frequencies))
       (hand-type-rec-set! hand (alist-ref #:high-card hand-types)))
      Error: (#f) "unbound variable": (frequencies)
      Call history: 
      <eval>   (with-all-output-to-string (lambda () (call-with-values thunk (lambda v (set! result v)))))
      <eval>   (with-output-to-string (lambda () (with-error-output-to-port (current-output-port) thunk)))
      <eval>   (with-error-output-to-port (current-output-port) thunk)
      <eval>   (current-output-port)
      <eval>   (call-with-values thunk (lambda v (set! result v)))
      <eval>   (eval form)
      <syntax> (begin ((= 1 (car frequencies)) (hand-type-rec-set! hand (alist-ref #:high-card hand-types))))
      <syntax> (##core#begin ((= 1 (car frequencies)) (hand-type-rec-set! hand (alist-ref #:high-card hand-types))))
      <syntax> ((= 1 (car frequencies)) (hand-type-rec-set! hand (alist-ref #:high-card hand-types)))
      <syntax> (= 1 (car frequencies))
      <syntax> (car frequencies)
      <syntax> (hand-type-rec-set! hand (alist-ref #:high-card hand-types))
      <syntax> (alist-ref #:high-card hand-types)
      <eval>   ((= 1 (car frequencies)) (hand-type-rec-set! hand (alist-ref #:high-card hand-types)))
      <eval>   (= 1 (car frequencies))
      <eval>   (car frequencies)
    

Hands are primarily ordered based on type; for example, every full house is stronger than any three of a kind.

  (define hand-types `((#:five-of-a-kind . ,(make-hand-type #:five-of-a-kind 7))
                       (#:four-of-a-kind . ,(make-hand-type #:four-of-a-kind 6))
                       (#:full-house . ,(make-hand-type #:full-house 5))
                       (#:three-of-a-kind . ,(make-hand-type #:three-of-a-kind 4))
                       (#:two-pair . ,(make-hand-type #:two-pair 3))
                       (#:one-pair . ,(make-hand-type #:one-pair 2))
                       (#:high-card . ,(make-hand-type #:high-card 1))))
#<unspecified>

If two hands have the same type, a second ordering rule takes effect. Start by comparing the first card in each hand. If these cards are different, the hand with the stronger first card is considered stronger. If the first card in each hand have the same label, however, then move on to considering the second card in each hand. If they differ, the hand with the higher second card wins; otherwise, continue with the third card in each hand, then the fourth, then the fifth.

  (define (card> card-a card-b)
    (> (card-weight card-a) (card-weight card-b)))

  (define (hand-cards> cards-a cards-b)
    (or (card> (car cards-a) (car cards-b))
        (and (< 1 (length cards-a))
             (= (card-weight (car cards-a)) (card-weight (car cards-b)))
             (hand-cards> (cdr cards-a) (cdr cards-b)))))

  (define (hands> hand-a hand-b)
    (let ((type-weight-a (hand-type-weight (hand-type-rec hand-a)))
          (type-weight-b (hand-type-weight (hand-type-rec hand-b)))
          (cards-a (hand-cards hand-a))
          (cards-b (hand-cards hand-b)))
      (or (> type-weight-a type-weight-b)
          (and (= type-weight-a type-weight-b)
               (hand-cards> cards-a cards-b)))))
#<unspecified>

So, 33332 and 2AAAA are both four of a kind hands, but 33332 is stronger because its first card is stronger. Similarly, 77888 and 77788 are both a full house, but 77888 is stronger because its third card is stronger (and both hands have the same first and second card).

  (hands> (make-hand (map (cut alist-ref <> cards) '(#:3 #:3 #:3 #:3 #:2))
                     0
                     (alist-ref #:four-of-a-kind hand-types) #f)
          (make-hand (map (cut alist-ref <> cards) '(#:2 #:A #:A #:A #:A))
                     0
                     (alist-ref #:four-of-a-kind hand-types) #f))
#t

To play Camel Cards, you are given a list of hands and their corresponding bid (your puzzle input). For example:

  32T3K 765
  T55J5 684
  KK677 28
  KTJJT 220
  QQQJA 483

Better sample input from u/LxsterGames on Reddit:

  2345A 1
  Q2KJJ 13
  Q2Q2Q 19
  T3T3J 17
  T3Q33 11
  2345J 3
  J345A 2
  32T3K 5
  T55J5 29
  KK677 7
  KTJJT 34
  QQQJA 31
  JJJJJ 37
  JAAAA 43
  AAAAJ 59
  AAAAA 61
  2AAAA 23
  2JJJJ 53
  JJJJ2 41
  (define camel-card-irregex
    '(: (submatch-named cards (+ (or (/ #\A #\Z) (/ #\0 #\9))))
        " "
        (submatch-named bid (+ (/ #\0 #\9)))))
#<unspecified>
  (define (cardstr->cards cardstr)
    (map (compose (cut alist-ref <> cards)
                  string->keyword
                  string)
         (string->list cardstr)))

  (define (input->hands input)
    (irregex-fold camel-card-irregex
                  (lambda (from-index match seed)
                    (let ((cardstr (irregex-match-substring match 'cards))
                          (bidstr  (irregex-match-substring match 'bid)))
                      (cons
                       (make-hand (cardstr->cards cardstr)
                                  (string->number bidstr) #f #f)
                       seed)))
                  '() input))
#<unspecified>

This example shows five hands; each hand is followed by its bid amount. Each hand wins an amount equal to its bid multiplied by its rank, where the weakest hand gets rank 1, the second-weakest hand gets rank 2, and so on up to the strongest hand. Because there are five hands in this example, the strongest hand will have rank 5 and its bid will be multiplied by 5.

  (define (rank-hands sorted-hands #!optional (index 1))
    (when (not (eqv? '() sorted-hands))
      (hand-rank-set! (car sorted-hands) index)
      (rank-hands (cdr sorted-hands) (+ index 1))))
#<unspecified>

So, the first step is to put the hands in order of strength:

  • 32T3K is the only one pair and the other hands are all a stronger type, so it gets rank 1.
  • KK677 and KTJJT are both two pair. Their first cards both have the same label, but the second card of KK677 is stronger (K vs T), so KTJJT gets rank 2 and KK677 gets rank 3.
  • T55J5 and QQQJA are both three of a kind. QQQJA has a stronger first card, so it gets rank 5 and T55J5 gets rank 4.
  (let ((hands (input->hands input)))
    (map calc-hand-type hands)
    (rank-hands (reverse (sort hands hands>)))
    (append '(("Cards" "Hand Type" "Rank" "Bid" "Bid*Rank"))
          (map (lambda (hand)
                 (let ((card-labels (map card-label (hand-cards hand)))
                       (hand-rank (hand-rank hand))
                       (hand-bid (hand-bid hand))
                       (hand-type (hand-type-label (hand-type-rec hand))))
                   (list (apply string-append (map keyword->string card-labels))
                         hand-type hand-rank hand-bid
                         (* hand-bid hand-rank))))
               (sort hands hands>))
          `(("Total" "" "" "" ,(total-winnings hands)))))
Cards Hand Type Rank Bid Bid*Rank
AAAAA five-of-a-kind 19 61 1159
JJJJJ five-of-a-kind 18 37 666
AAAAJ four-of-a-kind 17 59 1003
JAAAA four-of-a-kind 16 43 688
JJJJ2 four-of-a-kind 15 41 615
2AAAA four-of-a-kind 14 23 322
2JJJJ four-of-a-kind 13 53 689
Q2Q2Q full-house 12 19 228
QQQJA three-of-a-kind 11 31 341
T55J5 three-of-a-kind 10 29 290
T3Q33 three-of-a-kind 9 11 99
KK677 two-pair 8 7 56
KTJJT two-pair 7 34 238
T3T3J two-pair 6 17 102
Q2KJJ one-pair 5 13 65
32T3K one-pair 4 5 20
J345A high-card 3 2 6
2345A high-card 2 1 2
2345J high-card 1 3 3
Total 6592

Now, you can determine the total winnings of this set of hands by adding up the result of multiplying each hand's bid with its rank (765 * 1 + 220 * 2 + 28 * 3 + 684 * 4 + 483 * 5). So the total winnings in this example are 6440.

  (define (total-winnings hands)
    (foldl (lambda (total hand)
             (let ((bid (hand-bid hand))
                   (rank (hand-rank hand)))
               (+ total (* bid rank))))
           0 hands))
#<unspecified>

Find the rank of every hand in your set. What are the total winnings?

  (import (chicken string)
          (chicken keyword)
          (chicken sort)
          (chicken irregex))
  (define-record card label weight)
  (define-record hand cards bid type-rec rank)
  (define-record hand-type label weight)
  (define input "
    3Q373 470
    K53JT 351
    A9JK9 856
    2T333 515
    867T4 541
    58K22 253
    5JA6J 994
    K4A4K 865
    94377 519
    92J2Q 901
    J7676 389
    2KK36 938
    JQ2KK 987
    Q7A82 509
    TTTA5 243
    72J27 502
    AKKKA 387
    23222 674
    55335 161
    AA655 73
    QKKQA 686
    5J2T5 680
    666AT 385
    ATA3A 761
    TTT8J 364
    98A2T 282
    59A44 260
    6T9QJ 130
    T7TKQ 721
    9274T 656
    T9AJ4 182
    A2222 259
    TQKJ7 67
    4J844 560
    AAATA 636
    9J36J 546
    QJQQQ 119
    249TT 295
    877J7 221
    4KA23 116
    929Q2 929
    99JQQ 445
    Q9QJ8 432
    4Q7TJ 963
    4J2J8 783
    5J657 257
    88788 183
    KKK7K 909
    KK396 637
    J45AT 117
    84448 806
    A2698 820
    A9AA5 320
    A3934 19
    Q45Q5 392
    78686 254
    A55A5 701
    98A4K 655
    5AJ88 95
    AK3KK 55
    773KK 33
    J9J9J 356
    2KAKK 563
    655K5 287
    55T56 475
    54444 308
    5J5QA 811
    QKA76 792
    2K288 42
    JTKA2 694
    88668 889
    8TQ64 212
    23QQ2 261
    8K8K5 365
    JKKAA 234
    3J894 880
    667Q2 817
    888T4 599
    T5Q83 315
    3QK29 670
    JK4KK 322
    75T8T 144
    AAA7K 291
    7T333 495
    A49K4 448
    JJ3J3 251
    5999J 278
    38438 890
    6K3Q9 122
    TTT99 93
    94775 240
    K8QJ3 369
    59674 107
    267J4 355
    QTQTQ 187
    46J44 961
    Q7AK2 580
    69969 609
    876A5 474
    A3866 642
    Q3QQA 526
    JAA88 425
    35Q9K 986
    QQTQJ 550
    54535 357
    2J222 639
    QK5J7 743
    222Q2 191
    T4T44 855
    QTQQ2 338
    JA7A2 300
    AAAJ2 508
    4J455 23
    A77AA 339
    5KK25 899
    252J2 737
    7QJ76 888
    K46QK 795
    A4T3J 640
    8A8K8 176
    AA5AA 41
    J2Q24 958
    58855 632
    333J3 610
    74474 807
    K3AAA 78
    JJ222 765
    44224 688
    76733 361
    5845K 181
    TT4T2 974
    23J33 102
    QQJ6Q 34
    Q9AQQ 150
    22747 717
    KAA5A 121
    7AA7J 286
    J786T 780
    3K8TT 32
    A6KAA 25
    9A362 166
    A29Q2 499
    6688K 57
    KKQKA 947
    999JJ 975
    6A666 927
    TTT3K 658
    JQQ7T 467
    8A247 934
    7JK8J 712
    KK39K 612
    6666Q 17
    77Q37 868
    A66AJ 169
    KKKKJ 535
    7Q7JJ 591
    K9848 646
    46888 931
    A86A8 326
    743TA 527
    QKK67 977
    KKJ6K 471
    AAJ7A 571
    55292 330
    3A222 390
    6453J 109
    JKKKA 403
    4J9T5 21
    K7A5K 486
    6TT34 793
    3479Q 60
    44624 443
    6KK3K 164
    4447J 112
    QQ27Q 452
    JAK65 522
    Q5Q5Q 354
    J5Q6A 540
    68999 711
    3QJ4Q 155
    A6AAA 314
    222KK 767
    55T9A 373
    T5T57 913
    TTTTA 794
    8J258 190
    3Q87J 489
    AAQAQ 950
    Q4JJ4 588
    6T64T 9
    636K5 228
    AA222 248
    7KJ35 616
    26646 507
    44A4J 829
    23323 904
    TA265 135
    JJQT9 136
    KATJ8 644
    J2862 713
    4JQ28 152
    Q3K2T 56
    6Q232 812
    9A622 885
    KJKKJ 773
    3859T 374
    99333 101
    TKTTK 205
    3333A 35
    5A4AQ 548
    T4944 967
    43353 813
    423JK 869
    T99T7 219
    3AAAA 394
    T65Q6 740
    J9243 352
    6656J 496
    444K4 574
    Q8T6K 98
    AQ55K 917
    7QQJ7 605
    TJ5TT 615
    68JQ5 852
    7A3J2 745
    369AK 217
    57755 343
    A8844 61
    Q76QQ 698
    36333 774
    237Q7 12
    KT694 283
    88286 154
    4T552 990
    Q9J54 759
    K6697 350
    A3A33 937
    AA9AA 246
    QQ7KK 748
    TT4A6 380
    4J992 845
    A66AA 573
    5QQ2Q 28
    86J37 214
    2A443 362
    Q9QKK 654
    44434 964
    77773 74
    44355 235
    9QK75 863
    3AJ33 766
    T2TJT 53
    44494 860
    883A9 309
    QQ59Q 360
    A88A8 584
    A83A4 395
    7J9TA 299
    55955 833
    QJK35 188
    4656A 514
    8KTQ4 554
    56J47 985
    J272J 184
    9J999 671
    72295 31
    53555 264
    4A537 750
    7A4JJ 875
    QK834 463
    88KKA 570
    QQ9JK 906
    6Q646 858
    53336 359
    QJ8QJ 587
    424TJ 607
    KTKK6 285
    Q5AQQ 84
    899A8 542
    K8TKK 250
    4JA4A 705
    6J75J 896
    888K8 312
    5583J 660
    6T335 614
    Q757T 945
    3AKKA 629
    KK946 825
    3393Q 406
    7J288 367
    49999 907
    99729 837
    66265 384
    K47JQ 263
    2AJ4K 566
    TTKKA 186
    8J877 418
    56844 666
    JTTTT 531
    6TJ94 26
    JQ5J5 344
    7J772 85
    33747 510
    KJA2A 729
    333TQ 578
    JQAT4 955
    75766 834
    QQ6QQ 980
    32K33 306
    TTTJ6 231
    2QTTT 213
    999AQ 608
    33353 202
    Q8Q8Q 756
    KK555 490
    746K8 691
    98A75 853
    JQ858 816
    KK9KK 536
    9T999 933
    TA8A8 39
    8558J 919
    J8KQK 15
    73Q2K 503
    2K2KJ 585
    JK9K5 903
    TJ7T7 545
    J723T 453
    KT895 583
    TTTKT 123
    39535 393
    K4K88 893
    43KK6 821
    6AA8J 504
    972TA 597
    7J736 592
    536A8 63
    J23Q3 402
    83K9Q 405
    28337 396
    9T558 776
    7AA78 946
    QTT24 441
    26QT3 401
    AJQAQ 953
    6T6AJ 304
    JK5KK 162
    2JJ2J 484
    73773 6
    8J864 630
    78782 557
    6TJ52 424
    487JQ 830
    8J698 82
    AJAAA 866
    228J8 204
    622J4 823
    6J2QJ 79
    22K22 232
    A86A6 444
    83K8Q 965
    JK586 944
    JA848 465
    8888A 45
    2T28T 803
    73J73 450
    27272 857
    7A777 544
    A998J 679
    46466 458
    KJ233 192
    4453J 378
    TQQJT 451
    A3K5J 512
    888Q6 968
    6AA66 841
    QQ222 883
    3K5A3 233
    JA4AA 379
    62288 778
    44456 51
    4A644 862
    55647 981
    A77A7 327
    KQ3A3 687
    QQ7Q7 976
    T4A2T 293
    46226 628
    Q59Q5 348
    36AJ2 984
    54433 532
    JJQ24 831
    7455J 381
    78845 218
    72AQ5 276
    52T22 618
    99399 68
    36AA3 118
    69669 839
    33Q5J 785
    TJ766 626
    T28J4 556
    T883Q 142
    73928 932
    TJ884 494
    AJ36Q 485
    9Q999 324
    T725Q 267
    22622 88
    92364 685
    97792 789
    J673K 620
    99943 625
    77JJ7 921
    8828Q 572
    7777J 353
    TAAJT 926
    99T29 787
    AQ4J4 520
    9J559 5
    J3T94 706
    K9KK9 918
    KK252 439
    79925 97
    TT47T 497
    848T4 126
    6TTT6 426
    K8825 925
    888J8 62
    K5K85 972
    AAKKA 449
    J5555 663
    89J99 27
    4Q444 922
    A9A99 397
    5A555 163
    8J3K8 662
    29989 645
    95222 751
    Q4Q4Q 193
    555K5 982
    74AJ8 735
    KKQ6K 668
    7676Q 916
    A28T7 784
    K57KK 388
    A4J4J 115
    2K442 229
    33TT3 956
    TT6TA 741
    TT782 131
    TJ5JQ 238
    TQ7T7 415
    29KQQ 598
    A8AAT 676
    46A28 650
    6698K 696
    6J969 158
    6694A 271
    QTQ5T 498
    Q2QQQ 613
    2A7QJ 210
    6T466 683
    QJ575 799
    Q63Q3 822
    Q9J28 848
    TTTT7 7
    KA9AA 854
    K2JJT 859
    28228 179
    K29KJ 429
    JJ8JJ 222
    A99A5 457
    QQTTT 983
    43KK2 134
    984JJ 1
    97J97 892
    2AAA8 689
    9Q77J 819
    98TJK 517
    56KA5 71
    7J66J 294
    55855 335
    TTT8T 596
    33663 407
    7J774 911
    3JQ55 564
    QQQ7Q 329
    85668 120
    KK333 301
    Q3553 867
    7K557 988
    Q8488 400
    96J99 643
    29224 714
    T8ATA 346
    99J93 462
    K83J3 697
    3KQJ4 653
    5KJQ2 824
    4JJ3A 897
    56248 727
    JJ666 702
    355T5 245
    45KAK 553
    88AAA 236
    K55J5 581
    AJJ49 65
    A8Q3J 197
    AAAKQ 529
    55976 707
    77776 930
    A9995 227
    K7J7K 912
    29K99 244
    4Q464 80
    22972 195
    666JQ 189
    26278 241
    79288 601
    5454A 427
    JTAKQ 138
    88833 549
    84J54 215
    AATAK 114
    58959 145
    8ATTJ 431
    QJ26K 265
    A3JA3 81
    T8T4J 242
    4T3A3 37
    44777 871
    JQ542 561
    A97Q9 693
    A76T4 412
    28T4A 481
    T485A 861
    78286 303
    K6776 52
    T8TKQ 754
    KJ938 957
    Q444Q 840
    25A89 455
    58588 673
    K8858 634
    K8KJ8 170
    K6KKK 851
    53353 140
    2T2K6 593
    QQAQA 48
    TT6J6 305
    922J2 920
    AA22K 22
    J555Q 725
    TTAAT 781
    2244J 171
    A95K7 436
    2J299 651
    78AAA 321
    2KKK2 690
    2J565 649
    77J5K 77
    T999T 762
    J4445 879
    J888Q 873
    J884J 1000
    98898 413
    29299 442
    QKQ3Q 678
    A652A 993
    55272 898
    KA5K5 664
    8KJAQ 147
    Q56QJ 734
    K77J3 739
    J7677 661
    T5569 206
    2AA2J 757
    TJTJT 342
    T2TTT 682
    88J82 363
    9KK78 700
    AT4T4 730
    86968 736
    99995 207
    7A3J4 172
    8KK87 991
    TKKJJ 16
    J7532 165
    J9888 996
    9AJTA 92
    43T78 310
    93J77 317
    J4424 805
    43J86 703
    952TJ 127
    54363 146
    8T2J7 435
    88848 832
    TAAAQ 791
    8228T 256
    699QT 815
    KQQQK 30
    T82J3 49
    36222 4
    AK288 86
    6792A 194
    2Q22T 667
    J3545 270
    9QJK4 280
    QQ22Q 371
    K9247 446
    A422A 943
    765K3 469
    9J5A6 874
    4A4QA 775
    8Q8Q8 124
    T8Q62 850
    8Q8Q5 747
    6KT88 738
    82888 722
    3TQQQ 349
    2J3TT 539
    7TQ59 72
    8998T 733
    JQJT3 414
    82428 589
    92856 423
    89833 54
    79T4A 523
    95839 979
    TJJT5 936
    33839 29
    37433 511
    TKJ2T 681
    JT973 633
    Q8Q8J 971
    Q5555 440
    K8886 24
    Q75A4 43
    3AQ33 298
    T446T 719
    577J5 753
    KJTKT 167
    52528 8
    25222 641
    QJ2T8 621
    A8JQJ 316
    7T7A7 772
    KQQTQ 141
    83734 758
    6Q66Q 434
    QJ6Q2 638
    AAA7A 196
    57555 203
    4QJQ4 216
    82J5Q 763
    A73A3 940
    46AJQ 559
    T4936 103
    89Q29 262
    7872T 466
    A5J58 274
    AAAQA 290
    37399 844
    A759Q 328
    TJ9TT 273
    77887 268
    64A2J 978
    6T76Q 110
    QQ467 742
    9J7Q5 422
    4K6Q3 91
    336K3 826
    6K63Q 382
    23552 105
    243AA 505
    Q887J 764
    2J92A 749
    68A3Q 416
    7T8T8 199
    225J5 404
    24774 153
    T7T77 870
    3J393 347
    Q5Q8J 128
    7Q777 796
    QKKKK 617
    86686 108
    44KT4 75
    56858 622
    5AJK4 960
    3245Q 311
    36536 370
    6644Q 11
    JKAAA 104
    T2426 579
    J3399 83
    33933 602
    A299J 777
    26J22 224
    8666J 594
    J3J38 669
    3AJ84 239
    52Q8T 877
    QJQQK 779
    QJ6T8 797
    43339 399
    9AJ74 476
    T499Q 13
    2TAKA 928
    T3K78 809
    2923K 201
    J8858 798
    T8888 818
    98399 168
    8T266 555
    23A57 652
    3KKK3 113
    22T22 460
    AJJAA 106
    7QKA8 464
    QQ8TQ 368
    99A99 341
    62Q5A 223
    J9T47 568
    Q7388 894
    69662 744
    96J2T 323
    2A779 89
    Q2874 269
    77797 948
    5359A 864
    AJ9K4 482
    Q3Q44 567
    JT958 665
    A38J3 438
    J4666 296
    428J5 501
    38K8K 410
    6T979 709
    3533T 284
    2285A 910
    933T6 882
    K6666 786
    56Q32 992
    5J752 198
    AJJQJ 600
    KK5KK 3
    38T94 180
    67QTJ 69
    J6636 200
    229J8 493
    QJTQ3 247
    5KQ5K 149
    654AT 528
    T84T4 878
    Q23QQ 905
    QQQ74 325
    4JTQQ 408
    T4T78 340
    3T5T5 551
    3J3J3 391
    88844 631
    TTT9T 810
    57775 935
    A777J 604
    4555T 2
    A5J8T 942
    22AJJ 506
    22323 997
    A3323 624
    84442 516
    2T992 76
    J7T76 828
    J8552 995
    KTKK3 886
    33853 782
    53233 129
    44J4J 372
    KQQT2 480
    K5649 576
    3J63K 760
    2J666 827
    6JT68 318
    45Q64 849
    49884 801
    9KTTK 902
    66737 952
    5Q8J4 708
    57Q92 724
    627J7 331
    K22J6 473
    4T444 923
    J4444 552
    78J8J 491
    4K328 477
    4AA3A 808
    7A34Q 437
    AQ888 428
    8TA99 768
    AA9A9 143
    9K5AT 211
    77722 40
    TQTTT 941
    Q2A4K 492
    236T9 677
    J8686 746
    J585K 64
    TJKQT 582
    T3TTJ 157
    22266 38
    KT5TK 692
    QJQQJ 908
    4K623 279
    7JJJ7 173
    64A66 524
    J7AJ8 417
    K43Q3 769
    T662T 148
    54J2J 488
    K6485 44
    J6666 970
    J26J9 209
    8337Q 334
    A27A4 319
    A7T78 132
    K777A 842
    KKK4K 249
    99K9K 430
    8745K 151
    Q2QTJ 433
    QKQ76 525
    25Q2Q 533
    5QK6J 800
    77T77 558
    5K323 939
    33KK4 590
    K8A52 111
    ATQJ6 569
    ATK89 50
    4433A 836
    3KKKQ 891
    46TK4 538
    5249Q 447
    2462K 675
    8JT6T 336
    466J7 459
    7K7KK 838
    544Q4 959
    58773 483
    823J5 999
    2TKA5 752
    AKJ58 386
    7T833 99
    KQ88Q 659
    KJ3A4 790
    K9595 307
    3K3J4 534
    3838T 220
    32522 720
    366Q3 500
    J8868 989
    T7KTK 376
    JQQQA 14
    42555 409
    5T5T5 648
    4KK4Q 383
    K7777 884
    736A3 543
    343Q3 366
    TJ856 237
    JJ555 46
    K5QQQ 275
    QAQQ7 672
    8KTJQ 731
    QQQ3Q 47
    J257Q 575
    6Q3QQ 87
    QKK43 924
    TTATJ 998
    K44K5 771
    37895 881
    48823 521
    KKK74 456
    99J79 139
    J4542 635
    AJ96K 954
    K8937 411
    5J355 895
    96967 185
    333T3 562
    TAJ77 755
    J38A8 487
    AAT79 313
    A6Q73 398
    386JA 10
    J35Q8 623
    27758 969
    3K3KJ 966
    7928Q 627
    AAA4A 59
    2AA52 478
    848J8 133
    55225 843
    TTQT9 619
    3Q79K 255
    27AK8 58
    TKTKK 272
    KTTAT 333
    55666 802
    47748 454
    Q3T56 699
    63T3T 302
    8754Q 723
    4J86T 358
    8TTQ9 226
    5523J 125
    88588 606
    58AAA 208
    TK273 137
    4Q7KQ 160
    29292 577
    Q333Q 611
    22TT2 716
    A55AA 258
    64822 468
    22228 847
    2242T 788
    JA26Q 472
    8JAAA 174
    K5Q8A 175
    Q5AT4 732
    J4434 530
    76666 337
    9998Q 547
    9T2J9 100
    3Q982 90
    7727Q 281
    92944 973
    K2597 814
    K444K 36
    26KJ6 292
    34K38 962
    5A378 225
    636J9 375
    TTTT4 420
    A66TA 461
    69QK5 345
    76293 479
    66966 804
    A3383 297
    T82TT 657
    2QJJQ 156
    K2JK3 94
    K6K66 252
    K58QJ 876
    6J979 513
    92647 718
    QQ9Q9 586
    862Q5 20
    5465K 915
    KQ44Q 595
    T66T6 288
    TJT7T 710
    5JT8K 159
    KJTK3 603
    KKJTQ 949
    67776 914
    J4323 177
    22229 704
    96999 178
    8AJKA 70
    69T69 419
    65556 770
    87738 537
    547J4 835
    44766 421
    3355J 684
    2K266 647
    5TTT5 266
    3T3TT 332
    88JJ8 96
    QQ5K3 887
    K7JKK 377
    J8Q2Q 66
    2KKJ6 230
    TTKQT 277
    22Q92 18
    JTTTK 695
    J993Q 846
    88898 728
    88T87 715
    Q74J4 872
    4T999 951
    T997Q 289
    92QA9 726
    AJ394 900
    TT2T2 518
    JJJJJ 565")
  (define cards `((#:A . ,(make-card #:A 13))
                  (#:K . ,(make-card #:K 12))
                  (#:Q . ,(make-card #:Q 11))
                  (#:J . ,(make-card #:J 10))
                  (#:T . ,(make-card #:T  9))
                  (#:9 . ,(make-card #:9  8))
                  (#:8 . ,(make-card #:8  7))
                  (#:7 . ,(make-card #:7  6))
                  (#:6 . ,(make-card #:6  5))
                  (#:5 . ,(make-card #:5  4))
                  (#:4 . ,(make-card #:4  3))
                  (#:3 . ,(make-card #:3  2))
                  (#:2 . ,(make-card #:2  1))))
  (define (calc-card-frequencies cardlist #!optional (frequencies '()))
    (if (eqv? '() cardlist)
        (sort (map cdr frequencies) >)
        (let* ((card-label (card-label (car cardlist)))
               (card-old-frequency (alist-ref card-label frequencies eqv? 0)))
          (calc-card-frequencies (cdr cardlist)
                                 (alist-update card-label (+ 1 card-old-frequency) frequencies)))))

  (define (calc-hand-type hand)
    (let ((frequencies (calc-card-frequencies (hand-cards hand))))
      (cond ;; Insert the comparisons from below here
       ((= 5 (car frequencies))
        (hand-type-rec-set! hand (alist-ref #:five-of-a-kind hand-types))) ((= 4 (car frequencies))
    (hand-type-rec-set! hand (alist-ref #:four-of-a-kind hand-types))) ((and (= 3 (car frequencies))
         (= 2 (cadr frequencies)))
    (hand-type-rec-set! hand (alist-ref #:full-house hand-types))) ((= 3 (car frequencies))
    (hand-type-rec-set! hand (alist-ref #:three-of-a-kind hand-types))) ((and (= 2 (car frequencies))
         (= 2 (cadr frequencies)))
    (hand-type-rec-set! hand (alist-ref #:two-pair hand-types))) ((= 2 (car frequencies))
    (hand-type-rec-set! hand (alist-ref #:one-pair hand-types))) ((= 1 (car frequencies))
    (hand-type-rec-set! hand (alist-ref #:high-card hand-types)))))
    hand)
  (define hand-types `((#:five-of-a-kind . ,(make-hand-type #:five-of-a-kind 7))
                       (#:four-of-a-kind . ,(make-hand-type #:four-of-a-kind 6))
                       (#:full-house . ,(make-hand-type #:full-house 5))
                       (#:three-of-a-kind . ,(make-hand-type #:three-of-a-kind 4))
                       (#:two-pair . ,(make-hand-type #:two-pair 3))
                       (#:one-pair . ,(make-hand-type #:one-pair 2))
                       (#:high-card . ,(make-hand-type #:high-card 1))))

  (define (card> card-a card-b)
    (> (card-weight card-a) (card-weight card-b)))

  (define (hand-cards> cards-a cards-b)
    (or (card> (car cards-a) (car cards-b))
        (and (< 1 (length cards-a))
             (= (card-weight (car cards-a)) (card-weight (car cards-b)))
             (hand-cards> (cdr cards-a) (cdr cards-b)))))

  (define (hands> hand-a hand-b)
    (let ((type-weight-a (hand-type-weight (hand-type-rec hand-a)))
          (type-weight-b (hand-type-weight (hand-type-rec hand-b)))
          (cards-a (hand-cards hand-a))
          (cards-b (hand-cards hand-b)))
      (or (> type-weight-a type-weight-b)
          (and (= type-weight-a type-weight-b)
               (hand-cards> cards-a cards-b)))))
  (define camel-card-irregex
    '(: (submatch-named cards (+ (or (/ #\A #\Z) (/ #\0 #\9))))
        " "
        (submatch-named bid (+ (/ #\0 #\9)))))
  (define (cardstr->cards cardstr)
    (map (compose (cut alist-ref <> cards)
                  string->keyword
                  string)
         (string->list cardstr)))

  (define (input->hands input)
    (irregex-fold camel-card-irregex
                  (lambda (from-index match seed)
                    (let ((cardstr (irregex-match-substring match 'cards))
                          (bidstr  (irregex-match-substring match 'bid)))
                      (cons
                       (make-hand (cardstr->cards cardstr)
                                  (string->number bidstr) #f #f)
                       seed)))
                  '() input))
  (define (rank-hands sorted-hands #!optional (index 1))
    (when (not (eqv? '() sorted-hands))
      (hand-rank-set! (car sorted-hands) index)
      (rank-hands (cdr sorted-hands) (+ index 1))))
  (define (total-winnings hands)
    (foldl (lambda (total hand)
             (let ((bid (hand-bid hand))
                   (rank (hand-rank hand)))
               (+ total (* bid rank))))
           0 hands))
  (define (calc-part-1)
   (let ((hands (input->hands input)))
     (map calc-hand-type hands)
     (rank-hands (reverse (sort hands hands>)))
     (total-winnings hands)))
#<unspecified>
251216224

Part Two

Quest

To make things a little more interesting, the Elf introduces one additional rule. Now, J cards are jokers - wildcards that can act like whatever card would make the hand the strongest type possible.

To balance this, =J cards are now the weakest individual cards, weaker even than 2. The other cards stay in the same order: A, K, Q, T, 9, 8, 7, 6, 5, 4, 3, 2, J.

  (define p2-cards `((#:A . ,(make-card #:A 13))
                     (#:K . ,(make-card #:K 12))
                     (#:Q . ,(make-card #:Q 11))
                     (#:T . ,(make-card #:T 10))
                     (#:9 . ,(make-card #:9  9))
                     (#:8 . ,(make-card #:8  8))
                     (#:7 . ,(make-card #:7  7))
                     (#:6 . ,(make-card #:6  6))
                     (#:5 . ,(make-card #:5  5))
                     (#:4 . ,(make-card #:4  4))
                     (#:3 . ,(make-card #:3  3))
                     (#:2 . ,(make-card #:2  2))
                     (#:J . ,(make-card #:J  1))))
#<unspecified>

In addition, the cardstr->cards and, subsequently, input->hands functions have to be adjusted to use this new list.

  (define (p2-cardstr->cards cardstr)
    (map (compose (cut alist-ref <> p2-cards)
                  string->keyword
                  string)
         (string->list cardstr)))

  (define (p2-input->hands input)
    (irregex-fold camel-card-irregex
                  (lambda (from-index match seed)
                    (let ((cardstr (irregex-match-substring match 'cards))
                          (bidstr  (irregex-match-substring match 'bid)))
                      (cons
                       (make-hand (p2-cardstr->cards cardstr)
                                  (string->number bidstr) #f #f)
                       seed)))
                  '() input))
#<unspecified>

J cards can pretend to be whatever card is best for the purpose of determining hand type; for example, QJJQ2 is now considered four of a kind. However, for the purpose of breaking ties between two hands of the same type, J is always treated as J, not the card it's pretending to be: JKKK2 is weaker than QQQQ2 because J is weaker than Q.

  (define (add-joker frequencies joker-freq)
    (let* ((joker-account joker-freq)
           (new-freqs (map (lambda (freq)
                             (cond
                              ((eqv? #:J (car freq)) freq)
                              ((< 5 (+ joker-account (cdr freq)))
                               (set! joker-account (- 5 (cdr freq)))
                               (cons (car freq) 5))
                              (else
                               (let ((newval (+ joker-account (cdr freq))))
                                 (set! joker-account 0)
                                 (cons (car freq) newval)))))
                           frequencies)))
      (alist-update #:J joker-account new-freqs)))

  (define (p2-calc-card-frequencies cardlist #!optional (frequencies '()))
    (if (eqv? '() cardlist)
        (let* ((joker-freq (alist-ref #:J frequencies eqv? 0))
               (new-freqs (add-joker (sort frequencies (lambda (x y) (> (cdr x) (cdr y)))) joker-freq)))
          (sort (map cdr new-freqs) >))
        (let* ((card-label (card-label (car cardlist)))
               (card-old-frequency (alist-ref card-label frequencies eqv? 0)))
          (p2-calc-card-frequencies (cdr cardlist)
                                    (alist-update card-label (+ 1 card-old-frequency) frequencies)))))

  (define (p2-calc-hand-type hand)
    (let ((frequencies (p2-calc-card-frequencies (hand-cards hand))))
      (cond ;; Insert the comparisons from part 1 here
             ))
    hand)
#<unspecified>

Now, the above example goes very differently:

  32T3K 765
  T55J5 684
  KK677 28
  KTJJT 220
  QQQJA 483
  • 32T3K is still the only one pair; it doesn't contain any jokers, so its strength doesn't increase.
  • KK677 is now the only two pair, making it the second-weakest hand.
  • T55J5, KTJJT, and QQQJA are now all four of a kind! T55J5 gets rank 3, QQQJA gets rank 4, and KTJJT gets rank 5.

We again take the Reddit example from above, since it covers corner cases.

  (let ((hands (p2-input->hands input)))
    (map p2-calc-hand-type hands)
    (rank-hands (reverse (sort hands hands>)))
    (append '(("Cards" "Hand Type" "Rank" "Bid" "Bid*Rank"))
          (map (lambda (hand)
                 (let ((card-labels (map card-label (hand-cards hand)))
                       (hand-rank (hand-rank hand))
                       (hand-bid (hand-bid hand))
                       (hand-type (hand-type-label (hand-type-rec hand))))
                   (list (apply string-append (map keyword->string card-labels))
                         hand-type hand-rank hand-bid
                         (* hand-bid hand-rank))))
               (sort hands hands>))
          `(("Total" "" "" "" ,(total-winnings hands)))))
Cards Hand Type Rank Bid Bid*Rank
AAAAA five-of-a-kind 19 61 1159
AAAAJ five-of-a-kind 18 59 1062
2JJJJ five-of-a-kind 17 53 901
JAAAA five-of-a-kind 16 43 688
JJJJ2 five-of-a-kind 15 41 615
JJJJJ five-of-a-kind 14 37 518
KTJJT four-of-a-kind 13 34 442
QQQJA four-of-a-kind 12 31 372
T55J5 four-of-a-kind 11 29 319
2AAAA four-of-a-kind 10 23 230
Q2Q2Q full-house 9 19 171
T3T3J full-house 8 17 136
Q2KJJ three-of-a-kind 7 13 91
T3Q33 three-of-a-kind 6 11 66
KK677 two-pair 5 7 35
32T3K one-pair 4 5 20
2345J one-pair 3 3 9
J345A one-pair 2 2 4
2345A high-card 1 1 1
Total 6839

With the new joker rule, the total winnings in this example are 5905.

Using the new joker rule, find the rank of every hand in your set. What are the new total winnings?

  (import (chicken string)
          (chicken keyword)
          (chicken sort)
          (chicken irregex))
  (define-record card label weight)
  (define-record hand cards bid type-rec rank)
  (define-record hand-type label weight)
  (define input "
    3Q373 470
    K53JT 351
    A9JK9 856
    2T333 515
    867T4 541
    58K22 253
    5JA6J 994
    K4A4K 865
    94377 519
    92J2Q 901
    J7676 389
    2KK36 938
    JQ2KK 987
    Q7A82 509
    TTTA5 243
    72J27 502
    AKKKA 387
    23222 674
    55335 161
    AA655 73
    QKKQA 686
    5J2T5 680
    666AT 385
    ATA3A 761
    TTT8J 364
    98A2T 282
    59A44 260
    6T9QJ 130
    T7TKQ 721
    9274T 656
    T9AJ4 182
    A2222 259
    TQKJ7 67
    4J844 560
    AAATA 636
    9J36J 546
    QJQQQ 119
    249TT 295
    877J7 221
    4KA23 116
    929Q2 929
    99JQQ 445
    Q9QJ8 432
    4Q7TJ 963
    4J2J8 783
    5J657 257
    88788 183
    KKK7K 909
    KK396 637
    J45AT 117
    84448 806
    A2698 820
    A9AA5 320
    A3934 19
    Q45Q5 392
    78686 254
    A55A5 701
    98A4K 655
    5AJ88 95
    AK3KK 55
    773KK 33
    J9J9J 356
    2KAKK 563
    655K5 287
    55T56 475
    54444 308
    5J5QA 811
    QKA76 792
    2K288 42
    JTKA2 694
    88668 889
    8TQ64 212
    23QQ2 261
    8K8K5 365
    JKKAA 234
    3J894 880
    667Q2 817
    888T4 599
    T5Q83 315
    3QK29 670
    JK4KK 322
    75T8T 144
    AAA7K 291
    7T333 495
    A49K4 448
    JJ3J3 251
    5999J 278
    38438 890
    6K3Q9 122
    TTT99 93
    94775 240
    K8QJ3 369
    59674 107
    267J4 355
    QTQTQ 187
    46J44 961
    Q7AK2 580
    69969 609
    876A5 474
    A3866 642
    Q3QQA 526
    JAA88 425
    35Q9K 986
    QQTQJ 550
    54535 357
    2J222 639
    QK5J7 743
    222Q2 191
    T4T44 855
    QTQQ2 338
    JA7A2 300
    AAAJ2 508
    4J455 23
    A77AA 339
    5KK25 899
    252J2 737
    7QJ76 888
    K46QK 795
    A4T3J 640
    8A8K8 176
    AA5AA 41
    J2Q24 958
    58855 632
    333J3 610
    74474 807
    K3AAA 78
    JJ222 765
    44224 688
    76733 361
    5845K 181
    TT4T2 974
    23J33 102
    QQJ6Q 34
    Q9AQQ 150
    22747 717
    KAA5A 121
    7AA7J 286
    J786T 780
    3K8TT 32
    A6KAA 25
    9A362 166
    A29Q2 499
    6688K 57
    KKQKA 947
    999JJ 975
    6A666 927
    TTT3K 658
    JQQ7T 467
    8A247 934
    7JK8J 712
    KK39K 612
    6666Q 17
    77Q37 868
    A66AJ 169
    KKKKJ 535
    7Q7JJ 591
    K9848 646
    46888 931
    A86A8 326
    743TA 527
    QKK67 977
    KKJ6K 471
    AAJ7A 571
    55292 330
    3A222 390
    6453J 109
    JKKKA 403
    4J9T5 21
    K7A5K 486
    6TT34 793
    3479Q 60
    44624 443
    6KK3K 164
    4447J 112
    QQ27Q 452
    JAK65 522
    Q5Q5Q 354
    J5Q6A 540
    68999 711
    3QJ4Q 155
    A6AAA 314
    222KK 767
    55T9A 373
    T5T57 913
    TTTTA 794
    8J258 190
    3Q87J 489
    AAQAQ 950
    Q4JJ4 588
    6T64T 9
    636K5 228
    AA222 248
    7KJ35 616
    26646 507
    44A4J 829
    23323 904
    TA265 135
    JJQT9 136
    KATJ8 644
    J2862 713
    4JQ28 152
    Q3K2T 56
    6Q232 812
    9A622 885
    KJKKJ 773
    3859T 374
    99333 101
    TKTTK 205
    3333A 35
    5A4AQ 548
    T4944 967
    43353 813
    423JK 869
    T99T7 219
    3AAAA 394
    T65Q6 740
    J9243 352
    6656J 496
    444K4 574
    Q8T6K 98
    AQ55K 917
    7QQJ7 605
    TJ5TT 615
    68JQ5 852
    7A3J2 745
    369AK 217
    57755 343
    A8844 61
    Q76QQ 698
    36333 774
    237Q7 12
    KT694 283
    88286 154
    4T552 990
    Q9J54 759
    K6697 350
    A3A33 937
    AA9AA 246
    QQ7KK 748
    TT4A6 380
    4J992 845
    A66AA 573
    5QQ2Q 28
    86J37 214
    2A443 362
    Q9QKK 654
    44434 964
    77773 74
    44355 235
    9QK75 863
    3AJ33 766
    T2TJT 53
    44494 860
    883A9 309
    QQ59Q 360
    A88A8 584
    A83A4 395
    7J9TA 299
    55955 833
    QJK35 188
    4656A 514
    8KTQ4 554
    56J47 985
    J272J 184
    9J999 671
    72295 31
    53555 264
    4A537 750
    7A4JJ 875
    QK834 463
    88KKA 570
    QQ9JK 906
    6Q646 858
    53336 359
    QJ8QJ 587
    424TJ 607
    KTKK6 285
    Q5AQQ 84
    899A8 542
    K8TKK 250
    4JA4A 705
    6J75J 896
    888K8 312
    5583J 660
    6T335 614
    Q757T 945
    3AKKA 629
    KK946 825
    3393Q 406
    7J288 367
    49999 907
    99729 837
    66265 384
    K47JQ 263
    2AJ4K 566
    TTKKA 186
    8J877 418
    56844 666
    JTTTT 531
    6TJ94 26
    JQ5J5 344
    7J772 85
    33747 510
    KJA2A 729
    333TQ 578
    JQAT4 955
    75766 834
    QQ6QQ 980
    32K33 306
    TTTJ6 231
    2QTTT 213
    999AQ 608
    33353 202
    Q8Q8Q 756
    KK555 490
    746K8 691
    98A75 853
    JQ858 816
    KK9KK 536
    9T999 933
    TA8A8 39
    8558J 919
    J8KQK 15
    73Q2K 503
    2K2KJ 585
    JK9K5 903
    TJ7T7 545
    J723T 453
    KT895 583
    TTTKT 123
    39535 393
    K4K88 893
    43KK6 821
    6AA8J 504
    972TA 597
    7J736 592
    536A8 63
    J23Q3 402
    83K9Q 405
    28337 396
    9T558 776
    7AA78 946
    QTT24 441
    26QT3 401
    AJQAQ 953
    6T6AJ 304
    JK5KK 162
    2JJ2J 484
    73773 6
    8J864 630
    78782 557
    6TJ52 424
    487JQ 830
    8J698 82
    AJAAA 866
    228J8 204
    622J4 823
    6J2QJ 79
    22K22 232
    A86A6 444
    83K8Q 965
    JK586 944
    JA848 465
    8888A 45
    2T28T 803
    73J73 450
    27272 857
    7A777 544
    A998J 679
    46466 458
    KJ233 192
    4453J 378
    TQQJT 451
    A3K5J 512
    888Q6 968
    6AA66 841
    QQ222 883
    3K5A3 233
    JA4AA 379
    62288 778
    44456 51
    4A644 862
    55647 981
    A77A7 327
    KQ3A3 687
    QQ7Q7 976
    T4A2T 293
    46226 628
    Q59Q5 348
    36AJ2 984
    54433 532
    JJQ24 831
    7455J 381
    78845 218
    72AQ5 276
    52T22 618
    99399 68
    36AA3 118
    69669 839
    33Q5J 785
    TJ766 626
    T28J4 556
    T883Q 142
    73928 932
    TJ884 494
    AJ36Q 485
    9Q999 324
    T725Q 267
    22622 88
    92364 685
    97792 789
    J673K 620
    99943 625
    77JJ7 921
    8828Q 572
    7777J 353
    TAAJT 926
    99T29 787
    AQ4J4 520
    9J559 5
    J3T94 706
    K9KK9 918
    KK252 439
    79925 97
    TT47T 497
    848T4 126
    6TTT6 426
    K8825 925
    888J8 62
    K5K85 972
    AAKKA 449
    J5555 663
    89J99 27
    4Q444 922
    A9A99 397
    5A555 163
    8J3K8 662
    29989 645
    95222 751
    Q4Q4Q 193
    555K5 982
    74AJ8 735
    KKQ6K 668
    7676Q 916
    A28T7 784
    K57KK 388
    A4J4J 115
    2K442 229
    33TT3 956
    TT6TA 741
    TT782 131
    TJ5JQ 238
    TQ7T7 415
    29KQQ 598
    A8AAT 676
    46A28 650
    6698K 696
    6J969 158
    6694A 271
    QTQ5T 498
    Q2QQQ 613
    2A7QJ 210
    6T466 683
    QJ575 799
    Q63Q3 822
    Q9J28 848
    TTTT7 7
    KA9AA 854
    K2JJT 859
    28228 179
    K29KJ 429
    JJ8JJ 222
    A99A5 457
    QQTTT 983
    43KK2 134
    984JJ 1
    97J97 892
    2AAA8 689
    9Q77J 819
    98TJK 517
    56KA5 71
    7J66J 294
    55855 335
    TTT8T 596
    33663 407
    7J774 911
    3JQ55 564
    QQQ7Q 329
    85668 120
    KK333 301
    Q3553 867
    7K557 988
    Q8488 400
    96J99 643
    29224 714
    T8ATA 346
    99J93 462
    K83J3 697
    3KQJ4 653
    5KJQ2 824
    4JJ3A 897
    56248 727
    JJ666 702
    355T5 245
    45KAK 553
    88AAA 236
    K55J5 581
    AJJ49 65
    A8Q3J 197
    AAAKQ 529
    55976 707
    77776 930
    A9995 227
    K7J7K 912
    29K99 244
    4Q464 80
    22972 195
    666JQ 189
    26278 241
    79288 601
    5454A 427
    JTAKQ 138
    88833 549
    84J54 215
    AATAK 114
    58959 145
    8ATTJ 431
    QJ26K 265
    A3JA3 81
    T8T4J 242
    4T3A3 37
    44777 871
    JQ542 561
    A97Q9 693
    A76T4 412
    28T4A 481
    T485A 861
    78286 303
    K6776 52
    T8TKQ 754
    KJ938 957
    Q444Q 840
    25A89 455
    58588 673
    K8858 634
    K8KJ8 170
    K6KKK 851
    53353 140
    2T2K6 593
    QQAQA 48
    TT6J6 305
    922J2 920
    AA22K 22
    J555Q 725
    TTAAT 781
    2244J 171
    A95K7 436
    2J299 651
    78AAA 321
    2KKK2 690
    2J565 649
    77J5K 77
    T999T 762
    J4445 879
    J888Q 873
    J884J 1000
    98898 413
    29299 442
    QKQ3Q 678
    A652A 993
    55272 898
    KA5K5 664
    8KJAQ 147
    Q56QJ 734
    K77J3 739
    J7677 661
    T5569 206
    2AA2J 757
    TJTJT 342
    T2TTT 682
    88J82 363
    9KK78 700
    AT4T4 730
    86968 736
    99995 207
    7A3J4 172
    8KK87 991
    TKKJJ 16
    J7532 165
    J9888 996
    9AJTA 92
    43T78 310
    93J77 317
    J4424 805
    43J86 703
    952TJ 127
    54363 146
    8T2J7 435
    88848 832
    TAAAQ 791
    8228T 256
    699QT 815
    KQQQK 30
    T82J3 49
    36222 4
    AK288 86
    6792A 194
    2Q22T 667
    J3545 270
    9QJK4 280
    QQ22Q 371
    K9247 446
    A422A 943
    765K3 469
    9J5A6 874
    4A4QA 775
    8Q8Q8 124
    T8Q62 850
    8Q8Q5 747
    6KT88 738
    82888 722
    3TQQQ 349
    2J3TT 539
    7TQ59 72
    8998T 733
    JQJT3 414
    82428 589
    92856 423
    89833 54
    79T4A 523
    95839 979
    TJJT5 936
    33839 29
    37433 511
    TKJ2T 681
    JT973 633
    Q8Q8J 971
    Q5555 440
    K8886 24
    Q75A4 43
    3AQ33 298
    T446T 719
    577J5 753
    KJTKT 167
    52528 8
    25222 641
    QJ2T8 621
    A8JQJ 316
    7T7A7 772
    KQQTQ 141
    83734 758
    6Q66Q 434
    QJ6Q2 638
    AAA7A 196
    57555 203
    4QJQ4 216
    82J5Q 763
    A73A3 940
    46AJQ 559
    T4936 103
    89Q29 262
    7872T 466
    A5J58 274
    AAAQA 290
    37399 844
    A759Q 328
    TJ9TT 273
    77887 268
    64A2J 978
    6T76Q 110
    QQ467 742
    9J7Q5 422
    4K6Q3 91
    336K3 826
    6K63Q 382
    23552 105
    243AA 505
    Q887J 764
    2J92A 749
    68A3Q 416
    7T8T8 199
    225J5 404
    24774 153
    T7T77 870
    3J393 347
    Q5Q8J 128
    7Q777 796
    QKKKK 617
    86686 108
    44KT4 75
    56858 622
    5AJK4 960
    3245Q 311
    36536 370
    6644Q 11
    JKAAA 104
    T2426 579
    J3399 83
    33933 602
    A299J 777
    26J22 224
    8666J 594
    J3J38 669
    3AJ84 239
    52Q8T 877
    QJQQK 779
    QJ6T8 797
    43339 399
    9AJ74 476
    T499Q 13
    2TAKA 928
    T3K78 809
    2923K 201
    J8858 798
    T8888 818
    98399 168
    8T266 555
    23A57 652
    3KKK3 113
    22T22 460
    AJJAA 106
    7QKA8 464
    QQ8TQ 368
    99A99 341
    62Q5A 223
    J9T47 568
    Q7388 894
    69662 744
    96J2T 323
    2A779 89
    Q2874 269
    77797 948
    5359A 864
    AJ9K4 482
    Q3Q44 567
    JT958 665
    A38J3 438
    J4666 296
    428J5 501
    38K8K 410
    6T979 709
    3533T 284
    2285A 910
    933T6 882
    K6666 786
    56Q32 992
    5J752 198
    AJJQJ 600
    KK5KK 3
    38T94 180
    67QTJ 69
    J6636 200
    229J8 493
    QJTQ3 247
    5KQ5K 149
    654AT 528
    T84T4 878
    Q23QQ 905
    QQQ74 325
    4JTQQ 408
    T4T78 340
    3T5T5 551
    3J3J3 391
    88844 631
    TTT9T 810
    57775 935
    A777J 604
    4555T 2
    A5J8T 942
    22AJJ 506
    22323 997
    A3323 624
    84442 516
    2T992 76
    J7T76 828
    J8552 995
    KTKK3 886
    33853 782
    53233 129
    44J4J 372
    KQQT2 480
    K5649 576
    3J63K 760
    2J666 827
    6JT68 318
    45Q64 849
    49884 801
    9KTTK 902
    66737 952
    5Q8J4 708
    57Q92 724
    627J7 331
    K22J6 473
    4T444 923
    J4444 552
    78J8J 491
    4K328 477
    4AA3A 808
    7A34Q 437
    AQ888 428
    8TA99 768
    AA9A9 143
    9K5AT 211
    77722 40
    TQTTT 941
    Q2A4K 492
    236T9 677
    J8686 746
    J585K 64
    TJKQT 582
    T3TTJ 157
    22266 38
    KT5TK 692
    QJQQJ 908
    4K623 279
    7JJJ7 173
    64A66 524
    J7AJ8 417
    K43Q3 769
    T662T 148
    54J2J 488
    K6485 44
    J6666 970
    J26J9 209
    8337Q 334
    A27A4 319
    A7T78 132
    K777A 842
    KKK4K 249
    99K9K 430
    8745K 151
    Q2QTJ 433
    QKQ76 525
    25Q2Q 533
    5QK6J 800
    77T77 558
    5K323 939
    33KK4 590
    K8A52 111
    ATQJ6 569
    ATK89 50
    4433A 836
    3KKKQ 891
    46TK4 538
    5249Q 447
    2462K 675
    8JT6T 336
    466J7 459
    7K7KK 838
    544Q4 959
    58773 483
    823J5 999
    2TKA5 752
    AKJ58 386
    7T833 99
    KQ88Q 659
    KJ3A4 790
    K9595 307
    3K3J4 534
    3838T 220
    32522 720
    366Q3 500
    J8868 989
    T7KTK 376
    JQQQA 14
    42555 409
    5T5T5 648
    4KK4Q 383
    K7777 884
    736A3 543
    343Q3 366
    TJ856 237
    JJ555 46
    K5QQQ 275
    QAQQ7 672
    8KTJQ 731
    QQQ3Q 47
    J257Q 575
    6Q3QQ 87
    QKK43 924
    TTATJ 998
    K44K5 771
    37895 881
    48823 521
    KKK74 456
    99J79 139
    J4542 635
    AJ96K 954
    K8937 411
    5J355 895
    96967 185
    333T3 562
    TAJ77 755
    J38A8 487
    AAT79 313
    A6Q73 398
    386JA 10
    J35Q8 623
    27758 969
    3K3KJ 966
    7928Q 627
    AAA4A 59
    2AA52 478
    848J8 133
    55225 843
    TTQT9 619
    3Q79K 255
    27AK8 58
    TKTKK 272
    KTTAT 333
    55666 802
    47748 454
    Q3T56 699
    63T3T 302
    8754Q 723
    4J86T 358
    8TTQ9 226
    5523J 125
    88588 606
    58AAA 208
    TK273 137
    4Q7KQ 160
    29292 577
    Q333Q 611
    22TT2 716
    A55AA 258
    64822 468
    22228 847
    2242T 788
    JA26Q 472
    8JAAA 174
    K5Q8A 175
    Q5AT4 732
    J4434 530
    76666 337
    9998Q 547
    9T2J9 100
    3Q982 90
    7727Q 281
    92944 973
    K2597 814
    K444K 36
    26KJ6 292
    34K38 962
    5A378 225
    636J9 375
    TTTT4 420
    A66TA 461
    69QK5 345
    76293 479
    66966 804
    A3383 297
    T82TT 657
    2QJJQ 156
    K2JK3 94
    K6K66 252
    K58QJ 876
    6J979 513
    92647 718
    QQ9Q9 586
    862Q5 20
    5465K 915
    KQ44Q 595
    T66T6 288
    TJT7T 710
    5JT8K 159
    KJTK3 603
    KKJTQ 949
    67776 914
    J4323 177
    22229 704
    96999 178
    8AJKA 70
    69T69 419
    65556 770
    87738 537
    547J4 835
    44766 421
    3355J 684
    2K266 647
    5TTT5 266
    3T3TT 332
    88JJ8 96
    QQ5K3 887
    K7JKK 377
    J8Q2Q 66
    2KKJ6 230
    TTKQT 277
    22Q92 18
    JTTTK 695
    J993Q 846
    88898 728
    88T87 715
    Q74J4 872
    4T999 951
    T997Q 289
    92QA9 726
    AJ394 900
    TT2T2 518
    JJJJJ 565")
  (define p2-cards `((#:A . ,(make-card #:A 13))
                     (#:K . ,(make-card #:K 12))
                     (#:Q . ,(make-card #:Q 11))
                     (#:T . ,(make-card #:T 10))
                     (#:9 . ,(make-card #:9  9))
                     (#:8 . ,(make-card #:8  8))
                     (#:7 . ,(make-card #:7  7))
                     (#:6 . ,(make-card #:6  6))
                     (#:5 . ,(make-card #:5  5))
                     (#:4 . ,(make-card #:4  4))
                     (#:3 . ,(make-card #:3  3))
                     (#:2 . ,(make-card #:2  2))
                     (#:J . ,(make-card #:J  1))))
  (define (add-joker frequencies joker-freq)
    (let* ((joker-account joker-freq)
           (new-freqs (map (lambda (freq)
                             (cond
                              ((eqv? #:J (car freq)) freq)
                              ((< 5 (+ joker-account (cdr freq)))
                               (set! joker-account (- 5 (cdr freq)))
                               (cons (car freq) 5))
                              (else
                               (let ((newval (+ joker-account (cdr freq))))
                                 (set! joker-account 0)
                                 (cons (car freq) newval)))))
                           frequencies)))
      (alist-update #:J joker-account new-freqs)))

  (define (p2-calc-card-frequencies cardlist #!optional (frequencies '()))
    (if (eqv? '() cardlist)
        (let* ((joker-freq (alist-ref #:J frequencies eqv? 0))
               (new-freqs (add-joker (sort frequencies (lambda (x y) (> (cdr x) (cdr y)))) joker-freq)))
          (sort (map cdr new-freqs) >))
        (let* ((card-label (card-label (car cardlist)))
               (card-old-frequency (alist-ref card-label frequencies eqv? 0)))
          (p2-calc-card-frequencies (cdr cardlist)
                                    (alist-update card-label (+ 1 card-old-frequency) frequencies)))))

  (define (p2-calc-hand-type hand)
    (let ((frequencies (p2-calc-card-frequencies (hand-cards hand))))
      (cond ;; Insert the comparisons from part 1 here
       ((= 5 (car frequencies))
        (hand-type-rec-set! hand (alist-ref #:five-of-a-kind hand-types))) ((= 4 (car frequencies))
    (hand-type-rec-set! hand (alist-ref #:four-of-a-kind hand-types))) ((and (= 3 (car frequencies))
         (= 2 (cadr frequencies)))
    (hand-type-rec-set! hand (alist-ref #:full-house hand-types))) ((= 3 (car frequencies))
    (hand-type-rec-set! hand (alist-ref #:three-of-a-kind hand-types))) ((and (= 2 (car frequencies))
         (= 2 (cadr frequencies)))
    (hand-type-rec-set! hand (alist-ref #:two-pair hand-types))) ((= 2 (car frequencies))
    (hand-type-rec-set! hand (alist-ref #:one-pair hand-types))) ((= 1 (car frequencies))
    (hand-type-rec-set! hand (alist-ref #:high-card hand-types)))))
    hand)
  (define hand-types `((#:five-of-a-kind . ,(make-hand-type #:five-of-a-kind 7))
                       (#:four-of-a-kind . ,(make-hand-type #:four-of-a-kind 6))
                       (#:full-house . ,(make-hand-type #:full-house 5))
                       (#:three-of-a-kind . ,(make-hand-type #:three-of-a-kind 4))
                       (#:two-pair . ,(make-hand-type #:two-pair 3))
                       (#:one-pair . ,(make-hand-type #:one-pair 2))
                       (#:high-card . ,(make-hand-type #:high-card 1))))

  (define (card> card-a card-b)
    (> (card-weight card-a) (card-weight card-b)))

  (define (hand-cards> cards-a cards-b)
    (or (card> (car cards-a) (car cards-b))
        (and (< 1 (length cards-a))
             (= (card-weight (car cards-a)) (card-weight (car cards-b)))
             (hand-cards> (cdr cards-a) (cdr cards-b)))))

  (define (hands> hand-a hand-b)
    (let ((type-weight-a (hand-type-weight (hand-type-rec hand-a)))
          (type-weight-b (hand-type-weight (hand-type-rec hand-b)))
          (cards-a (hand-cards hand-a))
          (cards-b (hand-cards hand-b)))
      (or (> type-weight-a type-weight-b)
          (and (= type-weight-a type-weight-b)
               (hand-cards> cards-a cards-b)))))
  (define camel-card-irregex
    '(: (submatch-named cards (+ (or (/ #\A #\Z) (/ #\0 #\9))))
        " "
        (submatch-named bid (+ (/ #\0 #\9)))))
  (define (p2-cardstr->cards cardstr)
    (map (compose (cut alist-ref <> p2-cards)
                  string->keyword
                  string)
         (string->list cardstr)))

  (define (p2-input->hands input)
    (irregex-fold camel-card-irregex
                  (lambda (from-index match seed)
                    (let ((cardstr (irregex-match-substring match 'cards))
                          (bidstr  (irregex-match-substring match 'bid)))
                      (cons
                       (make-hand (p2-cardstr->cards cardstr)
                                  (string->number bidstr) #f #f)
                       seed)))
                  '() input))
  (define (rank-hands sorted-hands #!optional (index 1))
    (when (not (eqv? '() sorted-hands))
      (hand-rank-set! (car sorted-hands) index)
      (rank-hands (cdr sorted-hands) (+ index 1))))
  (define (total-winnings hands)
    (foldl (lambda (total hand)
             (let ((bid (hand-bid hand))
                   (rank (hand-rank hand)))
               (+ total (* bid rank))))
           0 hands))
  (define (calc-part-2)
   (let ((hands (p2-input->hands input)))
     (map p2-calc-hand-type hands)
     (rank-hands (reverse (sort hands hands>)))
     (total-winnings hands)))
#<unspecified>
250825971

Thoughts About Today's Puzzle

At first, when reading the description, I thought I'd miss not having extensions a lot for today's puzzle. But ultimately, I think it was fine witout. Sure, the code might have been a bit shorter here and there, but that's about it.

I also came across the conscious realization about what feels intuitively right, but maybe is not; Scheme is not evaluating code depth-first. Consider the following two examples:

  (let ((A '((#:X . 5) (#:Y . 10)))
        (X-buf 5))
    (alist-update #:X X-buf 
                  (map (lambda (a)
                         (cond ((eqv? #:X (car a)) a)
                               (else
                                (let ((new-Y X-buf))
                                  (set! X-buf 0)
                                  (cons (car a) new-Y)))))
                       A)))
((#:X . 5) (#:Y . 5))
  (let* ((A '((#:X . 5) (#:Y . 10)))
         (X-buf 5)
         (new-A (map (lambda (a)
                         (cond ((eqv? #:X (car a)) a)
                               (else
                                (let ((new-Y X-buf))
                                  (set! X-buf 0)
                                  (cons (car a) new-Y)))))
                       A)))
    (alist-update #:X X-buf new-A))
((#:X . 0) (#:Y . 5))

The first example evaluates as ((#:X . 5) (#:Y . 5)) , because Scheme evaluates left-to-right, and only nested-first as soon as it encounters a list. But would it really be unintuitive if it was depth-first? In that case, the first example would evaluate to the same result as the second: ((#:X . 0) (#:Y . 5))

Puzzle Input

Jump to day 8.

  3Q373 470
  K53JT 351
  A9JK9 856
  2T333 515
  867T4 541
  58K22 253
  5JA6J 994
  K4A4K 865
  94377 519
  92J2Q 901
  J7676 389
  2KK36 938
  JQ2KK 987
  Q7A82 509
  TTTA5 243
  72J27 502
  AKKKA 387
  23222 674
  55335 161
  AA655 73
  QKKQA 686
  5J2T5 680
  666AT 385
  ATA3A 761
  TTT8J 364
  98A2T 282
  59A44 260
  6T9QJ 130
  T7TKQ 721
  9274T 656
  T9AJ4 182
  A2222 259
  TQKJ7 67
  4J844 560
  AAATA 636
  9J36J 546
  QJQQQ 119
  249TT 295
  877J7 221
  4KA23 116
  929Q2 929
  99JQQ 445
  Q9QJ8 432
  4Q7TJ 963
  4J2J8 783
  5J657 257
  88788 183
  KKK7K 909
  KK396 637
  J45AT 117
  84448 806
  A2698 820
  A9AA5 320
  A3934 19
  Q45Q5 392
  78686 254
  A55A5 701
  98A4K 655
  5AJ88 95
  AK3KK 55
  773KK 33
  J9J9J 356
  2KAKK 563
  655K5 287
  55T56 475
  54444 308
  5J5QA 811
  QKA76 792
  2K288 42
  JTKA2 694
  88668 889
  8TQ64 212
  23QQ2 261
  8K8K5 365
  JKKAA 234
  3J894 880
  667Q2 817
  888T4 599
  T5Q83 315
  3QK29 670
  JK4KK 322
  75T8T 144
  AAA7K 291
  7T333 495
  A49K4 448
  JJ3J3 251
  5999J 278
  38438 890
  6K3Q9 122
  TTT99 93
  94775 240
  K8QJ3 369
  59674 107
  267J4 355
  QTQTQ 187
  46J44 961
  Q7AK2 580
  69969 609
  876A5 474
  A3866 642
  Q3QQA 526
  JAA88 425
  35Q9K 986
  QQTQJ 550
  54535 357
  2J222 639
  QK5J7 743
  222Q2 191
  T4T44 855
  QTQQ2 338
  JA7A2 300
  AAAJ2 508
  4J455 23
  A77AA 339
  5KK25 899
  252J2 737
  7QJ76 888
  K46QK 795
  A4T3J 640
  8A8K8 176
  AA5AA 41
  J2Q24 958
  58855 632
  333J3 610
  74474 807
  K3AAA 78
  JJ222 765
  44224 688
  76733 361
  5845K 181
  TT4T2 974
  23J33 102
  QQJ6Q 34
  Q9AQQ 150
  22747 717
  KAA5A 121
  7AA7J 286
  J786T 780
  3K8TT 32
  A6KAA 25
  9A362 166
  A29Q2 499
  6688K 57
  KKQKA 947
  999JJ 975
  6A666 927
  TTT3K 658
  JQQ7T 467
  8A247 934
  7JK8J 712
  KK39K 612
  6666Q 17
  77Q37 868
  A66AJ 169
  KKKKJ 535
  7Q7JJ 591
  K9848 646
  46888 931
  A86A8 326
  743TA 527
  QKK67 977
  KKJ6K 471
  AAJ7A 571
  55292 330
  3A222 390
  6453J 109
  JKKKA 403
  4J9T5 21
  K7A5K 486
  6TT34 793
  3479Q 60
  44624 443
  6KK3K 164
  4447J 112
  QQ27Q 452
  JAK65 522
  Q5Q5Q 354
  J5Q6A 540
  68999 711
  3QJ4Q 155
  A6AAA 314
  222KK 767
  55T9A 373
  T5T57 913
  TTTTA 794
  8J258 190
  3Q87J 489
  AAQAQ 950
  Q4JJ4 588
  6T64T 9
  636K5 228
  AA222 248
  7KJ35 616
  26646 507
  44A4J 829
  23323 904
  TA265 135
  JJQT9 136
  KATJ8 644
  J2862 713
  4JQ28 152
  Q3K2T 56
  6Q232 812
  9A622 885
  KJKKJ 773
  3859T 374
  99333 101
  TKTTK 205
  3333A 35
  5A4AQ 548
  T4944 967
  43353 813
  423JK 869
  T99T7 219
  3AAAA 394
  T65Q6 740
  J9243 352
  6656J 496
  444K4 574
  Q8T6K 98
  AQ55K 917
  7QQJ7 605
  TJ5TT 615
  68JQ5 852
  7A3J2 745
  369AK 217
  57755 343
  A8844 61
  Q76QQ 698
  36333 774
  237Q7 12
  KT694 283
  88286 154
  4T552 990
  Q9J54 759
  K6697 350
  A3A33 937
  AA9AA 246
  QQ7KK 748
  TT4A6 380
  4J992 845
  A66AA 573
  5QQ2Q 28
  86J37 214
  2A443 362
  Q9QKK 654
  44434 964
  77773 74
  44355 235
  9QK75 863
  3AJ33 766
  T2TJT 53
  44494 860
  883A9 309
  QQ59Q 360
  A88A8 584
  A83A4 395
  7J9TA 299
  55955 833
  QJK35 188
  4656A 514
  8KTQ4 554
  56J47 985
  J272J 184
  9J999 671
  72295 31
  53555 264
  4A537 750
  7A4JJ 875
  QK834 463
  88KKA 570
  QQ9JK 906
  6Q646 858
  53336 359
  QJ8QJ 587
  424TJ 607
  KTKK6 285
  Q5AQQ 84
  899A8 542
  K8TKK 250
  4JA4A 705
  6J75J 896
  888K8 312
  5583J 660
  6T335 614
  Q757T 945
  3AKKA 629
  KK946 825
  3393Q 406
  7J288 367
  49999 907
  99729 837
  66265 384
  K47JQ 263
  2AJ4K 566
  TTKKA 186
  8J877 418
  56844 666
  JTTTT 531
  6TJ94 26
  JQ5J5 344
  7J772 85
  33747 510
  KJA2A 729
  333TQ 578
  JQAT4 955
  75766 834
  QQ6QQ 980
  32K33 306
  TTTJ6 231
  2QTTT 213
  999AQ 608
  33353 202
  Q8Q8Q 756
  KK555 490
  746K8 691
  98A75 853
  JQ858 816
  KK9KK 536
  9T999 933
  TA8A8 39
  8558J 919
  J8KQK 15
  73Q2K 503
  2K2KJ 585
  JK9K5 903
  TJ7T7 545
  J723T 453
  KT895 583
  TTTKT 123
  39535 393
  K4K88 893
  43KK6 821
  6AA8J 504
  972TA 597
  7J736 592
  536A8 63
  J23Q3 402
  83K9Q 405
  28337 396
  9T558 776
  7AA78 946
  QTT24 441
  26QT3 401
  AJQAQ 953
  6T6AJ 304
  JK5KK 162
  2JJ2J 484
  73773 6
  8J864 630
  78782 557
  6TJ52 424
  487JQ 830
  8J698 82
  AJAAA 866
  228J8 204
  622J4 823
  6J2QJ 79
  22K22 232
  A86A6 444
  83K8Q 965
  JK586 944
  JA848 465
  8888A 45
  2T28T 803
  73J73 450
  27272 857
  7A777 544
  A998J 679
  46466 458
  KJ233 192
  4453J 378
  TQQJT 451
  A3K5J 512
  888Q6 968
  6AA66 841
  QQ222 883
  3K5A3 233
  JA4AA 379
  62288 778
  44456 51
  4A644 862
  55647 981
  A77A7 327
  KQ3A3 687
  QQ7Q7 976
  T4A2T 293
  46226 628
  Q59Q5 348
  36AJ2 984
  54433 532
  JJQ24 831
  7455J 381
  78845 218
  72AQ5 276
  52T22 618
  99399 68
  36AA3 118
  69669 839
  33Q5J 785
  TJ766 626
  T28J4 556
  T883Q 142
  73928 932
  TJ884 494
  AJ36Q 485
  9Q999 324
  T725Q 267
  22622 88
  92364 685
  97792 789
  J673K 620
  99943 625
  77JJ7 921
  8828Q 572
  7777J 353
  TAAJT 926
  99T29 787
  AQ4J4 520
  9J559 5
  J3T94 706
  K9KK9 918
  KK252 439
  79925 97
  TT47T 497
  848T4 126
  6TTT6 426
  K8825 925
  888J8 62
  K5K85 972
  AAKKA 449
  J5555 663
  89J99 27
  4Q444 922
  A9A99 397
  5A555 163
  8J3K8 662
  29989 645
  95222 751
  Q4Q4Q 193
  555K5 982
  74AJ8 735
  KKQ6K 668
  7676Q 916
  A28T7 784
  K57KK 388
  A4J4J 115
  2K442 229
  33TT3 956
  TT6TA 741
  TT782 131
  TJ5JQ 238
  TQ7T7 415
  29KQQ 598
  A8AAT 676
  46A28 650
  6698K 696
  6J969 158
  6694A 271
  QTQ5T 498
  Q2QQQ 613
  2A7QJ 210
  6T466 683
  QJ575 799
  Q63Q3 822
  Q9J28 848
  TTTT7 7
  KA9AA 854
  K2JJT 859
  28228 179
  K29KJ 429
  JJ8JJ 222
  A99A5 457
  QQTTT 983
  43KK2 134
  984JJ 1
  97J97 892
  2AAA8 689
  9Q77J 819
  98TJK 517
  56KA5 71
  7J66J 294
  55855 335
  TTT8T 596
  33663 407
  7J774 911
  3JQ55 564
  QQQ7Q 329
  85668 120
  KK333 301
  Q3553 867
  7K557 988
  Q8488 400
  96J99 643
  29224 714
  T8ATA 346
  99J93 462
  K83J3 697
  3KQJ4 653
  5KJQ2 824
  4JJ3A 897
  56248 727
  JJ666 702
  355T5 245
  45KAK 553
  88AAA 236
  K55J5 581
  AJJ49 65
  A8Q3J 197
  AAAKQ 529
  55976 707
  77776 930
  A9995 227
  K7J7K 912
  29K99 244
  4Q464 80
  22972 195
  666JQ 189
  26278 241
  79288 601
  5454A 427
  JTAKQ 138
  88833 549
  84J54 215
  AATAK 114
  58959 145
  8ATTJ 431
  QJ26K 265
  A3JA3 81
  T8T4J 242
  4T3A3 37
  44777 871
  JQ542 561
  A97Q9 693
  A76T4 412
  28T4A 481
  T485A 861
  78286 303
  K6776 52
  T8TKQ 754
  KJ938 957
  Q444Q 840
  25A89 455
  58588 673
  K8858 634
  K8KJ8 170
  K6KKK 851
  53353 140
  2T2K6 593
  QQAQA 48
  TT6J6 305
  922J2 920
  AA22K 22
  J555Q 725
  TTAAT 781
  2244J 171
  A95K7 436
  2J299 651
  78AAA 321
  2KKK2 690
  2J565 649
  77J5K 77
  T999T 762
  J4445 879
  J888Q 873
  J884J 1000
  98898 413
  29299 442
  QKQ3Q 678
  A652A 993
  55272 898
  KA5K5 664
  8KJAQ 147
  Q56QJ 734
  K77J3 739
  J7677 661
  T5569 206
  2AA2J 757
  TJTJT 342
  T2TTT 682
  88J82 363
  9KK78 700
  AT4T4 730
  86968 736
  99995 207
  7A3J4 172
  8KK87 991
  TKKJJ 16
  J7532 165
  J9888 996
  9AJTA 92
  43T78 310
  93J77 317
  J4424 805
  43J86 703
  952TJ 127
  54363 146
  8T2J7 435
  88848 832
  TAAAQ 791
  8228T 256
  699QT 815
  KQQQK 30
  T82J3 49
  36222 4
  AK288 86
  6792A 194
  2Q22T 667
  J3545 270
  9QJK4 280
  QQ22Q 371
  K9247 446
  A422A 943
  765K3 469
  9J5A6 874
  4A4QA 775
  8Q8Q8 124
  T8Q62 850
  8Q8Q5 747
  6KT88 738
  82888 722
  3TQQQ 349
  2J3TT 539
  7TQ59 72
  8998T 733
  JQJT3 414
  82428 589
  92856 423
  89833 54
  79T4A 523
  95839 979
  TJJT5 936
  33839 29
  37433 511
  TKJ2T 681
  JT973 633
  Q8Q8J 971
  Q5555 440
  K8886 24
  Q75A4 43
  3AQ33 298
  T446T 719
  577J5 753
  KJTKT 167
  52528 8
  25222 641
  QJ2T8 621
  A8JQJ 316
  7T7A7 772
  KQQTQ 141
  83734 758
  6Q66Q 434
  QJ6Q2 638
  AAA7A 196
  57555 203
  4QJQ4 216
  82J5Q 763
  A73A3 940
  46AJQ 559
  T4936 103
  89Q29 262
  7872T 466
  A5J58 274
  AAAQA 290
  37399 844
  A759Q 328
  TJ9TT 273
  77887 268
  64A2J 978
  6T76Q 110
  QQ467 742
  9J7Q5 422
  4K6Q3 91
  336K3 826
  6K63Q 382
  23552 105
  243AA 505
  Q887J 764
  2J92A 749
  68A3Q 416
  7T8T8 199
  225J5 404
  24774 153
  T7T77 870
  3J393 347
  Q5Q8J 128
  7Q777 796
  QKKKK 617
  86686 108
  44KT4 75
  56858 622
  5AJK4 960
  3245Q 311
  36536 370
  6644Q 11
  JKAAA 104
  T2426 579
  J3399 83
  33933 602
  A299J 777
  26J22 224
  8666J 594
  J3J38 669
  3AJ84 239
  52Q8T 877
  QJQQK 779
  QJ6T8 797
  43339 399
  9AJ74 476
  T499Q 13
  2TAKA 928
  T3K78 809
  2923K 201
  J8858 798
  T8888 818
  98399 168
  8T266 555
  23A57 652
  3KKK3 113
  22T22 460
  AJJAA 106
  7QKA8 464
  QQ8TQ 368
  99A99 341
  62Q5A 223
  J9T47 568
  Q7388 894
  69662 744
  96J2T 323
  2A779 89
  Q2874 269
  77797 948
  5359A 864
  AJ9K4 482
  Q3Q44 567
  JT958 665
  A38J3 438
  J4666 296
  428J5 501
  38K8K 410
  6T979 709
  3533T 284
  2285A 910
  933T6 882
  K6666 786
  56Q32 992
  5J752 198
  AJJQJ 600
  KK5KK 3
  38T94 180
  67QTJ 69
  J6636 200
  229J8 493
  QJTQ3 247
  5KQ5K 149
  654AT 528
  T84T4 878
  Q23QQ 905
  QQQ74 325
  4JTQQ 408
  T4T78 340
  3T5T5 551
  3J3J3 391
  88844 631
  TTT9T 810
  57775 935
  A777J 604
  4555T 2
  A5J8T 942
  22AJJ 506
  22323 997
  A3323 624
  84442 516
  2T992 76
  J7T76 828
  J8552 995
  KTKK3 886
  33853 782
  53233 129
  44J4J 372
  KQQT2 480
  K5649 576
  3J63K 760
  2J666 827
  6JT68 318
  45Q64 849
  49884 801
  9KTTK 902
  66737 952
  5Q8J4 708
  57Q92 724
  627J7 331
  K22J6 473
  4T444 923
  J4444 552
  78J8J 491
  4K328 477
  4AA3A 808
  7A34Q 437
  AQ888 428
  8TA99 768
  AA9A9 143
  9K5AT 211
  77722 40
  TQTTT 941
  Q2A4K 492
  236T9 677
  J8686 746
  J585K 64
  TJKQT 582
  T3TTJ 157
  22266 38
  KT5TK 692
  QJQQJ 908
  4K623 279
  7JJJ7 173
  64A66 524
  J7AJ8 417
  K43Q3 769
  T662T 148
  54J2J 488
  K6485 44
  J6666 970
  J26J9 209
  8337Q 334
  A27A4 319
  A7T78 132
  K777A 842
  KKK4K 249
  99K9K 430
  8745K 151
  Q2QTJ 433
  QKQ76 525
  25Q2Q 533
  5QK6J 800
  77T77 558
  5K323 939
  33KK4 590
  K8A52 111
  ATQJ6 569
  ATK89 50
  4433A 836
  3KKKQ 891
  46TK4 538
  5249Q 447
  2462K 675
  8JT6T 336
  466J7 459
  7K7KK 838
  544Q4 959
  58773 483
  823J5 999
  2TKA5 752
  AKJ58 386
  7T833 99
  KQ88Q 659
  KJ3A4 790
  K9595 307
  3K3J4 534
  3838T 220
  32522 720
  366Q3 500
  J8868 989
  T7KTK 376
  JQQQA 14
  42555 409
  5T5T5 648
  4KK4Q 383
  K7777 884
  736A3 543
  343Q3 366
  TJ856 237
  JJ555 46
  K5QQQ 275
  QAQQ7 672
  8KTJQ 731
  QQQ3Q 47
  J257Q 575
  6Q3QQ 87
  QKK43 924
  TTATJ 998
  K44K5 771
  37895 881
  48823 521
  KKK74 456
  99J79 139
  J4542 635
  AJ96K 954
  K8937 411
  5J355 895
  96967 185
  333T3 562
  TAJ77 755
  J38A8 487
  AAT79 313
  A6Q73 398
  386JA 10
  J35Q8 623
  27758 969
  3K3KJ 966
  7928Q 627
  AAA4A 59
  2AA52 478
  848J8 133
  55225 843
  TTQT9 619
  3Q79K 255
  27AK8 58
  TKTKK 272
  KTTAT 333
  55666 802
  47748 454
  Q3T56 699
  63T3T 302
  8754Q 723
  4J86T 358
  8TTQ9 226
  5523J 125
  88588 606
  58AAA 208
  TK273 137
  4Q7KQ 160
  29292 577
  Q333Q 611
  22TT2 716
  A55AA 258
  64822 468
  22228 847
  2242T 788
  JA26Q 472
  8JAAA 174
  K5Q8A 175
  Q5AT4 732
  J4434 530
  76666 337
  9998Q 547
  9T2J9 100
  3Q982 90
  7727Q 281
  92944 973
  K2597 814
  K444K 36
  26KJ6 292
  34K38 962
  5A378 225
  636J9 375
  TTTT4 420
  A66TA 461
  69QK5 345
  76293 479
  66966 804
  A3383 297
  T82TT 657
  2QJJQ 156
  K2JK3 94
  K6K66 252
  K58QJ 876
  6J979 513
  92647 718
  QQ9Q9 586
  862Q5 20
  5465K 915
  KQ44Q 595
  T66T6 288
  TJT7T 710
  5JT8K 159
  KJTK3 603
  KKJTQ 949
  67776 914
  J4323 177
  22229 704
  96999 178
  8AJKA 70
  69T69 419
  65556 770
  87738 537
  547J4 835
  44766 421
  3355J 684
  2K266 647
  5TTT5 266
  3T3TT 332
  88JJ8 96
  QQ5K3 887
  K7JKK 377
  J8Q2Q 66
  2KKJ6 230
  TTKQT 277
  22Q92 18
  JTTTK 695
  J993Q 846
  88898 728
  88T87 715
  Q74J4 872
  4T999 951
  T997Q 289
  92QA9 726
  AJ394 900
  TT2T2 518
  JJJJJ 565

Day 8: Haunted Wasteland

Part One

Part Two

Puzzle Input