diff --git a/chicken.org b/chicken.org new file mode 100644 index 0000000..5effd2e --- /dev/null +++ b/chicken.org @@ -0,0 +1,7581 @@ +# Created 2023-12-08 Fri 10:17 +#+title: Advent Of Code with Chicken Scheme +#+author: Daniel Ziltener +#+export_file_name: chicken.org +#+property: header-args:scheme :session *chicken* :comments both :exports both :prologue ";; -*- geiser-scheme-implementation: chicken -*-" +#+property: header-args:fundamental :eval no +* Prelude + +I don't know why I am spending my time this way, but I am trying to get through this year's +[[https://adventofcode.com/][Advent of Code]]. I decided to use [[https://call-cc.org][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 [[https://adventofcode.com/2015/day/1][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 [[https://en.wikipedia.org/wiki/Trebuchet][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: + +#+begin_example + 1abc2 + pqr3stu8vwx + a1b2c3d4e5f + treb7uchet +#+end_example + +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 +#+name: day1-solution-1 +#+begin_src scheme + (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))) +#+end_src +** 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: + +#+begin_example + two1nine + eightwothree + abcone2threexyz + xtwone3four + 4nineeightseven2 + zoneight234 + 7pqrstsixteen +#+end_example + +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 + +#+name: day1-solution-2 +#+begin_src scheme + (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))) +#+end_src +** Puzzle Input + +Jump to [[#headline-10][day 2]]. + +#+name: day1-input +#+begin_src fundamental + 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 +#+end_src +* 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: + +#+begin_example + 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 +#+end_example + +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. + +#+name: day2-part1-record-splitting +#+begin_src scheme + ;; 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)) +#+end_src +**** 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. + +#+name: day2-part1-draw-splitting +#+begin_src scheme + ;; 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)) +#+end_src +**** Draw Processing + +And as the last pre-processing step, I take apart the individual draws, and assign each amount to +its respective colour keyword. + +#+name: day2-part1-draw-processing +#+begin_src scheme + ;; 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)) +#+end_src +**** 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. + +#+name: day2-part1-success-check +#+begin_src scheme + ;; 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)) +#+end_src + +Then, I put everything together in a main function, preprocessing the input and summing up all game +ids for which ~game-possible?~ returns ~#t~. + +#+name: day2-part1-main-function +#+begin_src scheme + ;; 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))) +#+end_src + +And now, everything can be put together: + +#+name: day2-part1-solution +#+begin_src scheme + (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))) +#+end_src +** 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: + +#+begin_example + 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 +#+end_example + +- 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. + +#+name: day2-part2-powercalc +#+begin_src scheme + (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)))) +#+end_src + +And the main function gets modified to sum everything up. + +#+name: day2-part2-main-function +#+begin_src scheme + (define (game-set-power input) + (let ((games (record-fold input))) + (foldl + 0 + (map (lambda (game) + (powercalc (cdr game))) + games)))) +#+end_src + +The full thing put together: + +#+name: day2-part2-solution +#+begin_src scheme + (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)))) +#+end_src + +#+results: day2-part1-solution +: 78375 +** Puzzle Input + +Jump to [[#headline-22][day 3]]. + +#+name: day2-input +#+begin_example + 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 +#+end_example +* Day 3: Gear Ratios +Get the puzzle solution as [[file:./day3.scm][tangled .scm file]]. +** Part One + +*** Quest + +You and the Elf eventually reach a [[https://en.wikipedia.org/wiki/Gondola_lift][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: + +#+begin_example + 467..114.. + ...*...... + ..35..633. + ......#... + 617*...... + .....+.58. + ..592..... + ......755. + ...$.*.... + .664.598.. +#+end_example + +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 + +#+name: day3-part1-records +#+begin_src scheme + (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) +#+end_src +**** Indexing the Input + +#+name: day3-part1-indexing +#+begin_src scheme + (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)))))) +#+end_src +**** Tokenizing the Indexed Input + +#+name: day3-part1-number-char-p +#+begin_src scheme + (define (number-char? c) + (case (buffer-char-char c) + ((#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9) #t) + (else #f))) +#+end_src + +#+name: day3-part1-finalize-token +#+begin_src scheme + (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)))) +#+end_src + +#+name: day3-part1-compatible-with-buffer-p +#+begin_src scheme + (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)))))) +#+end_src + +#+name: day3-part1-tokenize-indexed-input +#+begin_src scheme + (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)))))))) +#+end_src +**** Checking for Part Neighbours + +#+name: day3-part1-neighbours-p +#+begin_src scheme + (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)))) +#+end_src +**** Folding Everything Together + +#+name: day3-part1-real-part-number-p +#+begin_src scheme + (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))))) +#+end_src + +#+name: day3-part1-fold +#+begin_src scheme + (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)) +#+end_src + +#+name: day3-part1-calc +#+begin_src scheme + (let-values (((part-nums part-syms) (tokenize-indexed-input (index-input (string->list input))))) + (fold-part-numbers part-nums part-syms)) +#+end_src + +#+results: day3-part1-calc-full +: 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: + +#+begin_example + 467..114.. + ...*...... + ..35..633. + ......#... + 617*...... + .....+.58. + ..592..... + ......755. + ...$.*.... + .664.598.. +#+end_example + +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 + +#+name: day3-part2-sym-neighbour-count +#+begin_src scheme + (define (gather-neighbours part-sym part-nums) + (foldl (lambda (output input) + (if (neighbours? input part-sym) + (cons input output) + output)) + (list) part-nums)) +#+end_src +**** Put Everything Together + +#+name: day3-part2-filter +#+begin_src scheme + (define (filter-gear-candidates part-syms) + (foldl (lambda (output input) + (if (eqv? '* (part-symbol-sym input)) + (cons input output) output)) + (list) part-syms)) +#+end_src + +#+name: day3-part2-fold +#+begin_src scheme + (define (calc-gear-ratio gears) + (foldl (lambda (output input) + (if (= 2 (length input)) + (+ output (apply * (map part-number-number input))) + output)) + 0 gears)) +#+end_src + +#+name: day3-part2-calc +#+begin_src scheme + (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))) +#+end_src + +#+results: day3-part2-calc-full +: 75220503 +** Puzzle Input + +Jump to [[#headline-37][day 4]]. + +#+name: day3-input +#+begin_src org + .....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.. +#+end_src +* Day 4: Scratchcards +Get the puzzle solution as [[file:./day4.scm][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 [[https://en.wikipedia.org/wiki/Scratchcard][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: + +#+begin_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 +#+end_example + +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./ + +#+name: day4-part1-scratchcard +#+begin_src scheme + (define-record scratchcard id winning-numbers card-numbers match-numbers copies) +#+end_src +**** 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. + +#+name: day4-part1-card-irregex +#+begin_src scheme + (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)) +#+end_src + +The pattern is then used to extract every scratch card which is then being parsed in a fold +statement. + +#+name: day4-part1-card-fold +#+begin_src scheme + (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)) +#+end_src +**** 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 ~!~. + +#+name: day4-part1-card-matching +#+begin_src scheme + (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))) +#+end_src + +As a next step, I calculate the points for each card. + +#+name: day4-part1-card-points +#+begin_src scheme + (define (card-points card) + (let ((match-nums (scratchcard-match-numbers card))) + (foldl (lambda (points num) + (if (= 0 points) + 1 + (* points 2))) + 0 match-nums))) +#+end_src + +And now, we can put everything together and sum up the points: + +#+name: day4-part1-calc +#+begin_src scheme + (foldl + (lambda (sum card) + (calc-card-matches card) + (+ sum + (card-points card))) + 0 (input->cards input)) +#+end_src + +#+results: day4-part1-calc-full +: 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: + +#+begin_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 +#+end_example + +- 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 + +#+name: day4-part2-card-alist +#+begin_src scheme + (define (card-alist cards) + (foldl (lambda (alist card) + (calc-card-matches card) + (alist-update (scratchcard-id card) + card + alist)) + '() (reverse cards))) +#+end_src + +#+name: day4-part2-gen-copies +#+begin_src scheme + (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))) +#+end_src + +#+name: day4-part2-count-scratchcards +#+begin_src scheme + (define (count-scratchcards cardlist) + (foldl + 0 (map (compose scratchcard-copies cdr) cardlist))) +#+end_src + +#+name: day4-part2-calc +#+begin_src scheme + (let ((cardlist (card-alist (input->cards input)))) + (generate-copies cardlist) + (count-scratchcards cardlist)) +#+end_src + +#+results: day4-part2-calc-full +: 5923918 +** Puzzle Input + +Jump to [[#headline-48][day 5]]. + +#+name: day4-input +#+begin_src org + 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 +#+end_src +* Day 5: If You Give A Seed A Fertilizer +Get the puzzle solution as [[file:./day5.scm][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 [[https://en.wikipedia.org/wiki/Sand_filter][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 [[https://en.wikipedia.org/wiki/Almanac][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: + +#+begin_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 +#+end_example + +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~: + +#+begin_example + 50 98 2 + 52 50 48 +#+end_example + +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: + +#+begin_example + seed soil + 0 0 + 1 1 + ... ... + 48 48 + 49 49 + 50 52 + 51 53 + ... ... + 96 98 + 97 99 + 98 50 + 99 51 +#+end_example + +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 + +#+name: day5-part1-mapping-record +#+begin_src scheme + (define-record entity type id) + (define-record mapping-entry from-type to-type from-start from-end to-start to-end) +#+end_src +**** Data Extraction + +***** Irregexes + +#+name: day5-part1-seed-irregex +#+begin_src scheme + (define seed-irregex + '(: (* whitespace) + "seeds: " + (submatch-named seed-numbers (+ (or numeric whitespace))))) +#+end_src + +#+name: day5-part1-mapping-irregex +#+begin_src scheme + (define mapping-irregex + '(: (submatch-named mapping-from (+ alphabetic)) + "-to-" + (submatch-named mapping-to (+ alphabetic)) + " map:" + (submatch-named mapping-vals (+ (or numeric whitespace))))) +#+end_src + +#+name: day5-part1-mapping-nums-irregex +#+begin_src scheme + (define mapping-nums-irregex + '(: (* whitespace) + (submatch-named to-range (+ numeric)) + (* whitespace) + (submatch-named from-range (+ numeric)) + (* whitespace) + (submatch-named range-size (+ numeric)))) +#+end_src +***** Data Reading + +A list of seed numbers: + +#+name: day5-part1-seeds-list +#+begin_src scheme + (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)))) +#+end_src + +And a mapping from input type (e.g. ~#:soil~) to the mappings to the next type: + +#+name: day5-part1-mapping-alist +#+begin_src scheme + (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)) +#+end_src +**** Processing The Data + +#+name: day5-part1-map-entity-forward +#+begin_src scheme + (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))) +#+end_src + +#+name: day5-part1-map-entity-forward-fully +#+begin_src scheme + (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))) +#+end_src +**** Solution + +#+name: day5-part1-calc +#+begin_src scheme + (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))) +#+end_src + +#+results: day5-part1-calc-full +: 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. + +#+name: day5-part2-expand-seeds +#+begin_src scheme + (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)))) +#+end_src + +After that, it is /almost/ identical to part 1, but we have to replace the ~foldl~ with a recursive +function that handles the promises. + +#+name: day5-part2-fold-seeds +#+begin_src scheme + (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))) +#+end_src + +#+name: day5-part2-calc +#+begin_src scheme + (let ((seeds (expand-seeds (input->seeds-list input))) + (mapping-alist (input->mapping-alist input))) + (fold-seeds seeds mapping-alist)) +#+end_src + +#+results: day5-part2-calc-full +: 37806486 +*** The Optimized Solution + +For the optimized solution using ranges, a new record type is needed: ~ranged-entity~. + +#+begin_src scheme + (define-record ranged-entity type from-id to-id) +#+end_src + +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. + +#+begin_src scheme + (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))))) +#+end_src + +- 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. + +#+begin_src scheme + (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)))) +#+end_src + +- There is just ~ranged-entity~ left, with nothing else: then it gets a new type, and is otherwise + passed on 1:1. + +#+begin_src scheme + (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)) +#+end_src + +This behemoth determines which of the functions above to call. + +#+begin_src scheme + (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))))) +#+end_src + +Here, the mapping is being done. + +#+begin_src scheme + (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))) + '())) +#+end_src + +And here, it is all put together. + +#+begin_src scheme + (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)))))) +#+end_src +** Puzzle Input + +Jump to [[#headline-63][day 6]]. + +#+name: day5-input +#+begin_src org + 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 +#+end_src +* Day 6: Wait For It +Get the puzzle solution as [[file:./day6.scm][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: + +#+begin_example + Time: 7 15 30 + Distance: 9 40 200 +#+end_example + +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. + +#+name: day6-part1-race-record +#+begin_src scheme + (define-record race time-limit record-distance winning-distances losing-distances) +#+end_src + +The solution starts with the usual data extraction using ~irregex~. + +#+name: day6-part1-input-extraction-irregex +#+begin_src scheme + (define input-extraction-irregex + '(: "Time:" + (submatch-named time-vals (+ (or numeric whitespace))) + "Distance:" + (submatch-named distance-vals (+ (or numeric whitespace))))) +#+end_src + +Next, the data is converted into ~race~ records. + +#+name: day6-part1-input--race-records +#+begin_src scheme + (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)))))) +#+end_src +**** Race Calculations + +#+name: day6-part1-get-distance +#+begin_src scheme + (define (get-distance race hold-time) + (let ((time-remaining (- (race-time-limit race) hold-time))) + (* time-remaining hold-time))) +#+end_src + +#+name: day6-part1-calc-race-distances +#+begin_src scheme + (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))))))) +#+end_src +**** Getting The Result + +#+name: day6-part1-calc-fn +#+begin_src scheme + (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))))) +#+end_src + +#+results: +: 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 [[https://en.wikipedia.org/wiki/Kerning][kerning]]. There's really *only one race* - ignore the +spaces between the numbers on each line. + +So, the example from before: + +#+begin_example + Time: 7 15 30 + Distance: 9 40 200 +#+end_example + +...now instead means this: + +#+begin_example + Time: 71530 + Distance: 940200 +#+end_example + +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: + +#+name: day6-part2-input--race-record +#+begin_src scheme + (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))) +#+end_src + +And instead of keeping a list of all winning and losing distances, I use a counter. + +#+name: day6-part2-calc-race-distances +#+begin_src scheme + (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))))))) +#+end_src +**** Race Variant Results + +#+name: day6-part2-calc-fn +#+begin_src scheme + (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)))) +#+end_src + +#+results: +: 41513103 +** Puzzle Input + +Jump to [[#headline-76][day 7]]. + +#+name: day6-input +#+begin_src org + Time: 58 81 96 76 + Distance: 434 1041 2219 1218 +#+end_src +* Day 7: Camel Cards +Get the puzzle solution as [[file:./day7.scm][tangled .scm file]]. +** Part One + +*** Quest + +Your all-expenses-paid trip turns out to be a one-way, five-minute ride in an [[https://en.wikipedia.org/wiki/Airship][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 [[https://en.wikipedia.org/wiki/Dromedary][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 [[https://en.wikipedia.org/wiki/List_of_poker_hands][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: + +#+begin_example + 32T3K 765 + T55J5 684 + KK677 28 + KTJJT 220 + QQQJA 483 +#+end_example + +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 [[https://en.wikipedia.org/wiki/List_of_poker_hands][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. + +#+name: day7-part1-cards +#+begin_src scheme + (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)))) +#+end_src + +#+results: day7-part1-cards +: # + + +The hands are separated into types. + +#+name: day7-part1-types +#+begin_src scheme + (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) +#+end_src + +#+results: day7-part1-types +: # + + +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: + +#+name: day7-part1-type-sample-noweb +#+begin_src scheme + + (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))))) +#+end_src + +#+results: day7-part1-type-sample-noweb +: # + + +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=; + src_scheme{(get-type-for-cards #:A #:A #:A #:A #:A)} =#:five-of-a-kind= + #+name: day7-part1-five-of-a-kind + #+begin_src scheme + ((= 5 (car frequencies)) + (hand-type-rec-set! hand (alist-ref #:five-of-a-kind hand-types))) + #+end_src + + #+results: day7-part1-five-of-a-kind + #+begin_example + Error: (#f) "unbound variable": (frequencies) + Call history: + (with-all-output-to-string (lambda () (call-with-values thunk (lambda v (set! result v))))) + (with-output-to-string (lambda () (with-error-output-to-port (current-output-port) thunk))) + (with-error-output-to-port (current-output-port) thunk) + (current-output-port) + (call-with-values thunk (lambda v (set! result v))) + (eval form) + (begin ((= 5 (car frequencies)) (hand-type-rec-set! hand (alist-ref #:five-of-a-kind hand-types)))) + (##core#begin ((= 5 (car frequencies)) (hand-type-rec-set! hand (alist-ref #:five-of-a-kind hand-types)))) + ((= 5 (car frequencies)) (hand-type-rec-set! hand (alist-ref #:five-of-a-kind hand-types))) + (= 5 (car frequencies)) + (car frequencies) + (hand-type-rec-set! hand (alist-ref #:five-of-a-kind hand-types)) + (alist-ref #:five-of-a-kind hand-types) + ((= 5 (car frequencies)) (hand-type-rec-set! hand (alist-ref #:five-of-a-kind hand-types))) + (= 5 (car frequencies)) + (car frequencies) + #+end_example + +- *Four of a kind*, where four cards have the same label and one card has a different label: =AA8AA=; + src_scheme{(get-type-for-cards #:A #:A #:8 #:A #:A)} =#:four-of-a-kind= + #+name: day7-part1-four-of-a-kind + #+begin_src scheme + ((= 4 (car frequencies)) + (hand-type-rec-set! hand (alist-ref #:four-of-a-kind hand-types))) + #+end_src + + #+results: day7-part1-four-of-a-kind + #+begin_example + Error: (#f) "unbound variable": (frequencies) + Call history: + (with-all-output-to-string (lambda () (call-with-values thunk (lambda v (set! result v))))) + (with-output-to-string (lambda () (with-error-output-to-port (current-output-port) thunk))) + (with-error-output-to-port (current-output-port) thunk) + (current-output-port) + (call-with-values thunk (lambda v (set! result v))) + (eval form) + (begin ((= 4 (car frequencies)) (hand-type-rec-set! hand (alist-ref #:four-of-a-kind hand-types)))) + (##core#begin ((= 4 (car frequencies)) (hand-type-rec-set! hand (alist-ref #:four-of-a-kind hand-types)))) + ((= 4 (car frequencies)) (hand-type-rec-set! hand (alist-ref #:four-of-a-kind hand-types))) + (= 4 (car frequencies)) + (car frequencies) + (hand-type-rec-set! hand (alist-ref #:four-of-a-kind hand-types)) + (alist-ref #:four-of-a-kind hand-types) + ((= 4 (car frequencies)) (hand-type-rec-set! hand (alist-ref #:four-of-a-kind hand-types))) + (= 4 (car frequencies)) + (car frequencies) + #+end_example + +- *Full house*, where three cards have the same label, and the remaining two cards share a different + label: =23332=; + src_scheme{(get-type-for-cards #:2 #:3 #:3 #:3 #:2)} =#:full-house= + #+name: day7-part1-full-house + #+begin_src scheme + ((and (= 3 (car frequencies)) + (= 2 (cadr frequencies))) + (hand-type-rec-set! hand (alist-ref #:full-house hand-types))) + #+end_src + +#+results: day7-part1-full-house +#+begin_example + Error: (#f) "unbound variable": (frequencies) + Call history: + (eval form) + (begin ((and (= 3 (car frequencies)) (= 2 (cadr frequencies))) (hand-type-rec-set! hand (alist-ref #:full-house hand-types)))) + (##core#begin ((and (= 3 (car frequencies)) (= 2 (cadr frequencies))) (hand-type-rec-set! hand (alist-ref #:full-house hand-types)))) + ((and (= 3 (car frequencies)) (= 2 (cadr frequencies))) (hand-type-rec-set! hand (alist-ref #:full-house hand-types))) + (and (= 3 (car frequencies)) (= 2 (cadr frequencies))) + (##core#if (= 3 (car frequencies)) (and26474 (= 2 (cadr frequencies))) #f) + (= 3 (car frequencies)) + (car frequencies) + (and26474 (= 2 (cadr frequencies))) + (= 2 (cadr frequencies)) + (cadr frequencies) + (hand-type-rec-set! hand (alist-ref #:full-house hand-types)) + (alist-ref #:full-house hand-types) + ((and (= 3 (car frequencies)) (= 2 (cadr frequencies))) (hand-type-rec-set! hand (alist-ref #:full-house hand-types))) + (= 3 (car frequencies)) + (car frequencies) +#+end_example + +- *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=; + src_scheme{(get-type-for-cards #:T #:T #:T #:9 #:8)} =#:three-of-a-kind= + #+name: day7-part1-three-of-a-kind + #+begin_src scheme + ((= 3 (car frequencies)) + (hand-type-rec-set! hand (alist-ref #:three-of-a-kind hand-types))) + #+end_src + + #+results: day7-part1-three-of-a-kind + #+begin_example + Error: (#f) "unbound variable": (frequencies) + Call history: + (with-all-output-to-string (lambda () (call-with-values thunk (lambda v (set! result v))))) + (with-output-to-string (lambda () (with-error-output-to-port (current-output-port) thunk))) + (with-error-output-to-port (current-output-port) thunk) + (current-output-port) + (call-with-values thunk (lambda v (set! result v))) + (eval form) + (begin ((= 3 (car frequencies)) (hand-type-rec-set! hand (alist-ref #:three-of-a-kind hand-types)))) + (##core#begin ((= 3 (car frequencies)) (hand-type-rec-set! hand (alist-ref #:three-of-a-kind hand-types)))) + ((= 3 (car frequencies)) (hand-type-rec-set! hand (alist-ref #:three-of-a-kind hand-types))) + (= 3 (car frequencies)) + (car frequencies) + (hand-type-rec-set! hand (alist-ref #:three-of-a-kind hand-types)) + (alist-ref #:three-of-a-kind hand-types) + ((= 3 (car frequencies)) (hand-type-rec-set! hand (alist-ref #:three-of-a-kind hand-types))) + (= 3 (car frequencies)) + (car frequencies) + #+end_example + +- *Two pair*, where two cards share one label, two other cards share a second label, and the + remaining card has a third label: =23432=; + src_scheme{(get-type-for-cards #:2 #:3 #:4 #:3 #:2)} =#:two-pair= + #+name: day7-part1-two-pair + #+begin_src scheme + ((and (= 2 (car frequencies)) + (= 2 (cadr frequencies))) + (hand-type-rec-set! hand (alist-ref #:two-pair hand-types))) + #+end_src + + #+results: day7-part1-two-pair + #+begin_example + Error: (#f) "unbound variable": (frequencies) + Call history: + (eval form) + (begin ((and (= 2 (car frequencies)) (= 2 (cadr frequencies))) (hand-type-rec-set! hand (alist-ref #:two-pair hand-types)))) + (##core#begin ((and (= 2 (car frequencies)) (= 2 (cadr frequencies))) (hand-type-rec-set! hand (alist-ref #:two-pair hand-types)))) + ((and (= 2 (car frequencies)) (= 2 (cadr frequencies))) (hand-type-rec-set! hand (alist-ref #:two-pair hand-types))) + (and (= 2 (car frequencies)) (= 2 (cadr frequencies))) + (##core#if (= 2 (car frequencies)) (and26693 (= 2 (cadr frequencies))) #f) + (= 2 (car frequencies)) + (car frequencies) + (and26693 (= 2 (cadr frequencies))) + (= 2 (cadr frequencies)) + (cadr frequencies) + (hand-type-rec-set! hand (alist-ref #:two-pair hand-types)) + (alist-ref #:two-pair hand-types) + ((and (= 2 (car frequencies)) (= 2 (cadr frequencies))) (hand-type-rec-set! hand (alist-ref #:two-pair hand-types))) + (= 2 (car frequencies)) + (car frequencies) + #+end_example + +- *One pair*, where two cards share one label, and the other three cards have a different label from + the pair and each other: =A23A4=; + src_scheme{(get-type-for-cards #:A #:2 #:3 #:A #:4)} =#:one-pair= + #+name: day7-part1-one-pair + #+begin_src scheme + ((= 2 (car frequencies)) + (hand-type-rec-set! hand (alist-ref #:one-pair hand-types))) + #+end_src + + #+results: day7-part1-one-pair + #+begin_example + Error: (#f) "unbound variable": (frequencies) + Call history: + (with-all-output-to-string (lambda () (call-with-values thunk (lambda v (set! result v))))) + (with-output-to-string (lambda () (with-error-output-to-port (current-output-port) thunk))) + (with-error-output-to-port (current-output-port) thunk) + (current-output-port) + (call-with-values thunk (lambda v (set! result v))) + (eval form) + (begin ((= 2 (car frequencies)) (hand-type-rec-set! hand (alist-ref #:one-pair hand-types)))) + (##core#begin ((= 2 (car frequencies)) (hand-type-rec-set! hand (alist-ref #:one-pair hand-types)))) + ((= 2 (car frequencies)) (hand-type-rec-set! hand (alist-ref #:one-pair hand-types))) + (= 2 (car frequencies)) + (car frequencies) + (hand-type-rec-set! hand (alist-ref #:one-pair hand-types)) + (alist-ref #:one-pair hand-types) + ((= 2 (car frequencies)) (hand-type-rec-set! hand (alist-ref #:one-pair hand-types))) + (= 2 (car frequencies)) + (car frequencies) + #+end_example + +- *High card*, where all cards' labels are distinct: =23456=; + src_scheme{(get-type-for-cards #:2 #:3 #:4 #:5 #:6)} =#:high-card= + #+name: day7-part1-high-card + #+begin_src scheme + ((= 1 (car frequencies)) + (hand-type-rec-set! hand (alist-ref #:high-card hand-types))) + #+end_src + + #+results: day7-part1-high-card + #+begin_example + Error: (#f) "unbound variable": (frequencies) + Call history: + (with-all-output-to-string (lambda () (call-with-values thunk (lambda v (set! result v))))) + (with-output-to-string (lambda () (with-error-output-to-port (current-output-port) thunk))) + (with-error-output-to-port (current-output-port) thunk) + (current-output-port) + (call-with-values thunk (lambda v (set! result v))) + (eval form) + (begin ((= 1 (car frequencies)) (hand-type-rec-set! hand (alist-ref #:high-card hand-types)))) + (##core#begin ((= 1 (car frequencies)) (hand-type-rec-set! hand (alist-ref #:high-card hand-types)))) + ((= 1 (car frequencies)) (hand-type-rec-set! hand (alist-ref #:high-card hand-types))) + (= 1 (car frequencies)) + (car frequencies) + (hand-type-rec-set! hand (alist-ref #:high-card hand-types)) + (alist-ref #:high-card hand-types) + ((= 1 (car frequencies)) (hand-type-rec-set! hand (alist-ref #:high-card hand-types))) + (= 1 (car frequencies)) + (car frequencies) + #+end_example + +Hands are primarily ordered based on type; for example, every *full house* is stronger than any +*three of a kind*. + +#+name: day7-part1-hand-types +#+begin_src scheme + (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)))) +#+end_src + +#+results: day7-part1-hand-types +: # + + +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. + +#+name: day7-part1-hand-comparison +#+begin_src scheme + (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))))) +#+end_src + +#+results: day7-part1-hand-comparison +: # + + +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). + +#+begin_src scheme + + (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)) +#+end_src + +#+results: +: #t + + +To play Camel Cards, you are given a list of hands and their corresponding *bid* (your puzzle +input). For example: + +#+begin_example + 32T3K 765 + T55J5 684 + KK677 28 + KTJJT 220 + QQQJA 483 +#+end_example + +Better sample input from [[https://old.reddit.com/r/adventofcode/comments/18cr4xr/2023_day_7_better_example_input_not_a_spoiler/][u/LxsterGames]] on Reddit: +#+name: day7-part1-hand-input-example +#+begin_example + 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 +#+end_example + +#+name: day7-part1-data-regex +#+begin_src scheme + (define camel-card-irregex + '(: (submatch-named cards (+ (or (/ #\A #\Z) (/ #\0 #\9)))) + " " + (submatch-named bid (+ (/ #\0 #\9))))) +#+end_src + +#+results: day7-part1-data-regex +: # + + +#+name: day7-part1-data-extraction +#+begin_src scheme + (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)) +#+end_src + +#+results: day7-part1-data-extraction +: # + + +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. + +#+name: day7-part1-hand-ranking +#+begin_src scheme + (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)))) +#+end_src + +#+results: day7-part1-hand-ranking +: # + + +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*. + +#+begin_src scheme + + (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))))) +#+end_src + +#+results: +| 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=*. + +#+name: day7-part1-total-winnings +#+begin_src scheme + (define (total-winnings hands) + (foldl (lambda (total hand) + (let ((bid (hand-bid hand)) + (rank (hand-rank hand))) + (+ total (* bid rank)))) + 0 hands)) +#+end_src + +#+results: day7-part1-total-winnings +: # + + +Find the rank of every hand in your set. *What are the total winnings?* + +#+name: day7-part1-calc-fn +#+begin_src scheme + (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))) +#+end_src + +#+results: day7-part1-calc-fn +: # + + +#+results: +: 251216224 +** Part Two + +*** Quest + +To make things a little more interesting, the Elf introduces one additional rule. Now, =J= cards are +[[https://en.wikipedia.org/wiki/Joker_(playing_card)][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=. + +#+name: day7-part2-cards +#+begin_src scheme + (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)))) +#+end_src + +#+results: day7-part2-cards +: # + + +/In addition, the ~cardstr->cards~ and, subsequently, ~input->hands~ functions have to be adjusted +to use this new list./ + +#+name: day7-part2-data-extraction +#+begin_src scheme + (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)) +#+end_src + +#+results: day7-part2-data-extraction +: # + + +=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=. + +#+name: day7-part2-types +#+begin_src scheme + (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) +#+end_src + +#+results: day7-part2-types +: # + + +Now, the above example goes very differently: + +#+begin_example + 32T3K 765 + T55J5 684 + KK677 28 + KTJJT 220 + QQQJA 483 +#+end_example + +- =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./ + +#+begin_src scheme + + (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))))) +#+end_src + +#+results: +| 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?* + +#+name: day7-part2-calc-fn +#+begin_src scheme + (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))) +#+end_src + +#+results: day7-part2-calc-fn +: # + + +#+results: +: 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: + +#+name: day7-thoughts-a +#+begin_src scheme + (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))) +#+end_src + +#+results: day7-thoughts-a +: ((#:X . 5) (#:Y . 5)) + + +#+name: day7-thoughts-b +#+begin_src scheme + (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)) +#+end_src + +#+results: day7-thoughts-b +: ((#: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 [[#headline-83][day 8]]. + +#+name: day7-input +#+begin_src fundamental + 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 +#+end_src +* Day 8: Haunted Wasteland +** Part One + +** Part Two + +** Puzzle Input diff --git a/day3.scm b/day3.scm new file mode 100644 index 0000000..f25837b --- /dev/null +++ b/day3.scm @@ -0,0 +1,375 @@ +;; Puzzle Solution + + +;; [[file:chicken-src.org::*Puzzle Solution][Puzzle Solution:1]] +;; -*- geiser-scheme-implementation: chicken -*- +(import (chicken string) + (chicken format)) +(define input " + .....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.. + ") +;; Puzzle Solution:1 ends here + +;; Records + +;; #+NAME: day3-part1-records + +;; [[file:chicken-src.org::day3-part1-records][day3-part1-records]] +;; -*- geiser-scheme-implementation: chicken -*- +(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) +;; day3-part1-records ends here + +;; Indexing the Input + +;; #+NAME: day3-part1-indexing + +;; [[file:chicken-src.org::day3-part1-indexing][day3-part1-indexing]] +;; -*- geiser-scheme-implementation: chicken -*- +(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)))))) +;; day3-part1-indexing ends here + +;; Tokenizing the Indexed Input + +;; #+NAME: day3-part1-number-char-p + +;; [[file:chicken-src.org::day3-part1-number-char-p][day3-part1-number-char-p]] +;; -*- geiser-scheme-implementation: chicken -*- +(define (number-char? c) + (case (buffer-char-char c) + ((#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9) #t) + (else #f))) +;; day3-part1-number-char-p ends here + + + +;; #+NAME: day3-part1-finalize-token + +;; [[file:chicken-src.org::day3-part1-finalize-token][day3-part1-finalize-token]] +;; -*- geiser-scheme-implementation: chicken -*- +(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)))) +;; day3-part1-finalize-token ends here + + + +;; #+NAME: day3-part1-compatible-with-buffer-p + +;; [[file:chicken-src.org::day3-part1-compatible-with-buffer-p][day3-part1-compatible-with-buffer-p]] +;; -*- geiser-scheme-implementation: chicken -*- +(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)))))) +;; day3-part1-compatible-with-buffer-p ends here + + + +;; #+NAME: day3-part1-tokenize-indexed-input + +;; [[file:chicken-src.org::day3-part1-tokenize-indexed-input][day3-part1-tokenize-indexed-input]] +;; -*- geiser-scheme-implementation: chicken -*- +(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)))))))) +;; day3-part1-tokenize-indexed-input ends here + +;; Checking for Part Neighbours + +;; #+NAME: day3-part1-neighbours-p + +;; [[file:chicken-src.org::day3-part1-neighbours-p][day3-part1-neighbours-p]] +;; -*- geiser-scheme-implementation: chicken -*- +(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)))) +;; day3-part1-neighbours-p ends here + +;; Folding Everything Together + +;; #+NAME: day3-part1-real-part-number-p + +;; [[file:chicken-src.org::day3-part1-real-part-number-p][day3-part1-real-part-number-p]] +;; -*- geiser-scheme-implementation: chicken -*- +(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))))) +;; day3-part1-real-part-number-p ends here + + + +;; #+NAME: day3-part1-fold + +;; [[file:chicken-src.org::day3-part1-fold][day3-part1-fold]] +;; -*- geiser-scheme-implementation: chicken -*- +(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)) +;; day3-part1-fold ends here + + + +;; #+RESULTS: day3-part1-calc-full +;; : 509115 + + +;; [[file:chicken-src.org::*Folding Everything Together][Folding Everything Together:5]] +;; -*- geiser-scheme-implementation: chicken -*- +(define (calc-part-1) + (let-values (((part-nums part-syms) (tokenize-indexed-input (index-input (string->list input))))) + (fold-part-numbers part-nums part-syms))) +;; Folding Everything Together:5 ends here + +;; Gather Symbol Neighbours + +;; #+NAME: day3-part2-sym-neighbour-count + +;; [[file:chicken-src.org::day3-part2-sym-neighbour-count][day3-part2-sym-neighbour-count]] +;; -*- geiser-scheme-implementation: chicken -*- +(define (gather-neighbours part-sym part-nums) + (foldl (lambda (output input) + (if (neighbours? input part-sym) + (cons input output) + output)) + (list) part-nums)) +;; day3-part2-sym-neighbour-count ends here + +;; Put Everything Together + +;; #+NAME: day3-part2-filter + +;; [[file:chicken-src.org::day3-part2-filter][day3-part2-filter]] +;; -*- geiser-scheme-implementation: chicken -*- +(define (filter-gear-candidates part-syms) + (foldl (lambda (output input) + (if (eqv? '* (part-symbol-sym input)) + (cons input output) output)) + (list) part-syms)) +;; day3-part2-filter ends here + + + +;; #+NAME: day3-part2-fold + +;; [[file:chicken-src.org::day3-part2-fold][day3-part2-fold]] +;; -*- geiser-scheme-implementation: chicken -*- +(define (calc-gear-ratio gears) + (foldl (lambda (output input) + (if (= 2 (length input)) + (+ output (apply * (map part-number-number input))) + output)) + 0 gears)) +;; day3-part2-fold ends here + + + +;; #+RESULTS: day3-part2-calc-full +;; : 75220503 + + +;; [[file:chicken-src.org::*Put Everything Together][Put Everything Together:5]] +;; -*- geiser-scheme-implementation: chicken -*- +(define (calc-part-2) + (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)))) +;; Put Everything Together:5 ends here diff --git a/day4.scm b/day4.scm new file mode 100644 index 0000000..fd92477 --- /dev/null +++ b/day4.scm @@ -0,0 +1,404 @@ +;; Puzzle Solution + + +;; [[file:chicken-src.org::*Puzzle Solution][Puzzle Solution:1]] +;; -*- geiser-scheme-implementation: chicken -*- +(import (chicken string) + (chicken irregex)) +(define input " + 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 + ") +;; Puzzle Solution:1 ends here + +;; 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./ + +;; #+NAME: day4-part1-scratchcard + +;; [[file:chicken-src.org::day4-part1-scratchcard][day4-part1-scratchcard]] +;; -*- geiser-scheme-implementation: chicken -*- +(define-record scratchcard id winning-numbers card-numbers match-numbers copies) +;; day4-part1-scratchcard ends here + +;; 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. + +;; #+NAME: day4-part1-card-irregex + +;; [[file:chicken-src.org::day4-part1-card-irregex][day4-part1-card-irregex]] +;; -*- geiser-scheme-implementation: chicken -*- +(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)) +;; day4-part1-card-irregex ends here + + + +;; The pattern is then used to extract every scratch card which is then being parsed in a fold +;; statement. + +;; #+NAME: day4-part1-card-fold + +;; [[file:chicken-src.org::day4-part1-card-fold][day4-part1-card-fold]] +;; -*- geiser-scheme-implementation: chicken -*- +(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)) +;; day4-part1-card-fold ends here + +;; 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 ~!~. + +;; #+NAME: day4-part1-card-matching + +;; [[file:chicken-src.org::day4-part1-card-matching][day4-part1-card-matching]] +;; -*- geiser-scheme-implementation: chicken -*- +(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))) +;; day4-part1-card-matching ends here + + + +;; As a next step, I calculate the points for each card. + +;; #+NAME: day4-part1-card-points + +;; [[file:chicken-src.org::day4-part1-card-points][day4-part1-card-points]] +;; -*- geiser-scheme-implementation: chicken -*- +(define (card-points card) + (let ((match-nums (scratchcard-match-numbers card))) + (foldl (lambda (points num) + (if (= 0 points) + 1 + (* points 2))) + 0 match-nums))) +;; day4-part1-card-points ends here + + + +;; #+RESULTS: day4-part1-calc-full +;; : 23441 + + +;; [[file:chicken-src.org::*Processing The Cards][Processing The Cards:5]] +;; -*- geiser-scheme-implementation: chicken -*- +(define (calc-part-1) + (foldl + (lambda (sum card) + (calc-card-matches card) + (+ sum + (card-points card))) + 0 (input->cards input))) +;; Processing The Cards:5 ends here + +;; Puzzle Solution + +;; #+NAME: day4-part2-card-alist + +;; [[file:chicken-src.org::day4-part2-card-alist][day4-part2-card-alist]] +;; -*- geiser-scheme-implementation: chicken -*- +(define (card-alist cards) + (foldl (lambda (alist card) + (calc-card-matches card) + (alist-update (scratchcard-id card) + card + alist)) + '() (reverse cards))) +;; day4-part2-card-alist ends here + + + +;; #+NAME: day4-part2-gen-copies + +;; [[file:chicken-src.org::day4-part2-gen-copies][day4-part2-gen-copies]] +;; -*- geiser-scheme-implementation: chicken -*- +(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))) +;; day4-part2-gen-copies ends here + + + +;; #+NAME: day4-part2-count-scratchcards + +;; [[file:chicken-src.org::day4-part2-count-scratchcards][day4-part2-count-scratchcards]] +;; -*- geiser-scheme-implementation: chicken -*- +(define (count-scratchcards cardlist) + (foldl + 0 (map (compose scratchcard-copies cdr) cardlist))) +;; day4-part2-count-scratchcards ends here + + + +;; #+RESULTS: day4-part2-calc-full +;; : 5923918 + + +;; [[file:chicken-src.org::*Puzzle Solution][Puzzle Solution:6]] +;; -*- geiser-scheme-implementation: chicken -*- +(define (calc-part-2) + (let ((cardlist (card-alist (input->cards input)))) + (generate-copies cardlist) + (count-scratchcards cardlist))) +;; Puzzle Solution:6 ends here diff --git a/day5.scm b/day5.scm new file mode 100644 index 0000000..df7725d --- /dev/null +++ b/day5.scm @@ -0,0 +1,543 @@ +;; Puzzle Solution + + +;; [[file:chicken-src.org::*Puzzle Solution][Puzzle Solution:1]] +;; -*- geiser-scheme-implementation: chicken -*- +(import (chicken fixnum) + (chicken sort) + (chicken string) + (chicken keyword) + (chicken irregex)) +(define input " + 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 + ") +;; Puzzle Solution:1 ends here + +;; Mapping Record + +;; #+NAME: day5-part1-mapping-record + +;; [[file:chicken-src.org::day5-part1-mapping-record][day5-part1-mapping-record]] +;; -*- geiser-scheme-implementation: chicken -*- +(define-record entity type id) +(define-record mapping-entry from-type to-type from-start from-end to-start to-end) +;; day5-part1-mapping-record ends here + +;; Irregexes + +;; #+NAME: day5-part1-seed-irregex + +;; [[file:chicken-src.org::day5-part1-seed-irregex][day5-part1-seed-irregex]] +;; -*- geiser-scheme-implementation: chicken -*- +(define seed-irregex + '(: (* whitespace) + "seeds: " + (submatch-named seed-numbers (+ (or numeric whitespace))))) +;; day5-part1-seed-irregex ends here + + + +;; #+NAME: day5-part1-mapping-irregex + +;; [[file:chicken-src.org::day5-part1-mapping-irregex][day5-part1-mapping-irregex]] +;; -*- geiser-scheme-implementation: chicken -*- +(define mapping-irregex + '(: (submatch-named mapping-from (+ alphabetic)) + "-to-" + (submatch-named mapping-to (+ alphabetic)) + " map:" + (submatch-named mapping-vals (+ (or numeric whitespace))))) +;; day5-part1-mapping-irregex ends here + + + +;; #+NAME: day5-part1-mapping-nums-irregex + +;; [[file:chicken-src.org::day5-part1-mapping-nums-irregex][day5-part1-mapping-nums-irregex]] +;; -*- geiser-scheme-implementation: chicken -*- +(define mapping-nums-irregex + '(: (* whitespace) + (submatch-named to-range (+ numeric)) + (* whitespace) + (submatch-named from-range (+ numeric)) + (* whitespace) + (submatch-named range-size (+ numeric)))) +;; day5-part1-mapping-nums-irregex ends here + +;; Data Reading + +;; A list of seed numbers: + +;; #+NAME: day5-part1-seeds-list + +;; [[file:chicken-src.org::day5-part1-seeds-list][day5-part1-seeds-list]] +;; -*- geiser-scheme-implementation: chicken -*- +(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)))) +;; day5-part1-seeds-list ends here + + + +;; And a mapping from input type (e.g. ~#:soil~) to the mappings to the next type: + +;; #+NAME: day5-part1-mapping-alist + +;; [[file:chicken-src.org::day5-part1-mapping-alist][day5-part1-mapping-alist]] +;; -*- geiser-scheme-implementation: chicken -*- +(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)) +;; day5-part1-mapping-alist ends here + +;; Processing The Data + +;; #+NAME: day5-part1-map-entity-forward + +;; [[file:chicken-src.org::day5-part1-map-entity-forward][day5-part1-map-entity-forward]] +;; -*- geiser-scheme-implementation: chicken -*- +(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))) +;; day5-part1-map-entity-forward ends here + + + +;; #+NAME: day5-part1-map-entity-forward-fully + +;; [[file:chicken-src.org::day5-part1-map-entity-forward-fully][day5-part1-map-entity-forward-fully]] +;; -*- geiser-scheme-implementation: chicken -*- +(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))) +;; day5-part1-map-entity-forward-fully ends here + + + +;; #+RESULTS: day5-part1-calc-full +;; : 1181555926 + + +;; [[file:chicken-src.org::*Solution][Solution:3]] +;; -*- geiser-scheme-implementation: chicken -*- +(define (calc-part-1) + (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)))) +;; Solution:3 ends here + +;; 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. + +;; #+NAME: day5-part2-expand-seeds + +;; [[file:chicken-src.org::day5-part2-expand-seeds][day5-part2-expand-seeds]] +;; -*- geiser-scheme-implementation: chicken -*- +(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)))) +;; day5-part2-expand-seeds ends here + + + +;; After that, it is /almost/ identical to part 1, but we have to replace the ~foldl~ with a recursive +;; function that handles the promises. + +;; #+NAME: day5-part2-fold-seeds + +;; [[file:chicken-src.org::day5-part2-fold-seeds][day5-part2-fold-seeds]] +;; -*- geiser-scheme-implementation: chicken -*- +(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))) +;; day5-part2-fold-seeds ends here + + + +;; #+RESULTS: day5-part2-calc-full +;; : 37806486 + + +;; [[file:chicken-src.org::*Puzzle Solution][Puzzle Solution:5]] +;; -*- geiser-scheme-implementation: chicken -*- +(define (calc-part-2) + (let ((seeds (expand-seeds (input->seeds-list input))) + (mapping-alist (input->mapping-alist input))) + (fold-seeds seeds mapping-alist))) +;; Puzzle Solution:5 ends here + +;; The Optimized Solution + +;; For the optimized solution using ranges, a new record type is needed: ~ranged-entity~. + + +;; [[file:chicken-src.org::*The Optimized Solution][The Optimized Solution:1]] +;; -*- geiser-scheme-implementation: chicken -*- +(define-record ranged-entity type from-id to-id) +;; The Optimized Solution:1 ends here + + + +;; 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. + + +;; [[file:chicken-src.org::*The Optimized Solution][The Optimized Solution:2]] +;; -*- geiser-scheme-implementation: chicken -*- +(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 Optimized Solution:2 ends here + + + +;; - 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. + + +;; [[file:chicken-src.org::*The Optimized Solution][The Optimized Solution:3]] +;; -*- geiser-scheme-implementation: chicken -*- +(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)))) +;; The Optimized Solution:3 ends here + + + +;; - There is just ~ranged-entity~ left, with nothing else: then it gets a new type, and is otherwise +;; passed on 1:1. + + +;; [[file:chicken-src.org::*The Optimized Solution][The Optimized Solution:4]] +;; -*- geiser-scheme-implementation: chicken -*- +(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)) +;; The Optimized Solution:4 ends here + + + +;; This behemoth determines which of the functions above to call. + + +;; [[file:chicken-src.org::*The Optimized Solution][The Optimized Solution:5]] +;; -*- geiser-scheme-implementation: chicken -*- +(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))))) +;; The Optimized Solution:5 ends here + + + +;; Here, the mapping is being done. + + +;; [[file:chicken-src.org::*The Optimized Solution][The Optimized Solution:6]] +;; -*- geiser-scheme-implementation: chicken -*- +(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))) + '())) +;; The Optimized Solution:6 ends here + + + +;; And here, it is all put together. + + +;; [[file:chicken-src.org::*The Optimized Solution][The Optimized Solution:7]] +;; -*- geiser-scheme-implementation: chicken -*- +(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)))))) +;; The Optimized Solution:7 ends here diff --git a/day6.scm b/day6.scm new file mode 100644 index 0000000..3e3a4c9 --- /dev/null +++ b/day6.scm @@ -0,0 +1,184 @@ +;; Puzzle Solution + +;; #+NAME: day6-part1-imports + +;; [[file:chicken-src.org::day6-part1-imports][day6-part1-imports]] +;; -*- geiser-scheme-implementation: chicken -*- +(import (chicken string) + (chicken irregex)) +;; day6-part1-imports ends here + + + +;; #+NAME: day6-input-scm + +;; [[file:chicken-src.org::day6-input-scm][day6-input-scm]] +;; -*- geiser-scheme-implementation: chicken -*- +(define input " + Time: 58 81 96 76 + Distance: 434 1041 2219 1218") +;; day6-input-scm ends here + +;; Data Extraction + +;; First, we need to define the record for the race data. + +;; #+NAME: day6-part1-race-record + +;; [[file:chicken-src.org::day6-part1-race-record][day6-part1-race-record]] +;; -*- geiser-scheme-implementation: chicken -*- +(define-record race time-limit record-distance winning-distances losing-distances) +;; day6-part1-race-record ends here + + + +;; The solution starts with the usual data extraction using ~irregex~. + +;; #+NAME: day6-part1-input-extraction-irregex + +;; [[file:chicken-src.org::day6-part1-input-extraction-irregex][day6-part1-input-extraction-irregex]] +;; -*- geiser-scheme-implementation: chicken -*- +(define input-extraction-irregex + '(: "Time:" + (submatch-named time-vals (+ (or numeric whitespace))) + "Distance:" + (submatch-named distance-vals (+ (or numeric whitespace))))) +;; day6-part1-input-extraction-irregex ends here + + + +;; Next, the data is converted into ~race~ records. + +;; #+NAME: day6-part1-input--race-records + +;; [[file:chicken-src.org::day6-part1-input--race-records][day6-part1-input--race-records]] +;; -*- geiser-scheme-implementation: chicken -*- +(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)))))) +;; day6-part1-input--race-records ends here + +;; Race Calculations + +;; #+NAME: day6-part1-get-distance + +;; [[file:chicken-src.org::day6-part1-get-distance][day6-part1-get-distance]] +;; -*- geiser-scheme-implementation: chicken -*- +(define (get-distance race hold-time) + (let ((time-remaining (- (race-time-limit race) hold-time))) + (* time-remaining hold-time))) +;; day6-part1-get-distance ends here + + + +;; #+NAME: day6-part1-calc-race-distances + +;; [[file:chicken-src.org::day6-part1-calc-race-distances][day6-part1-calc-race-distances]] +;; -*- geiser-scheme-implementation: chicken -*- +(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))))))) +;; day6-part1-calc-race-distances ends here + +;; Getting The Result + +;; #+NAME: day6-part1-calc-fn + +;; [[file:chicken-src.org::day6-part1-calc-fn][day6-part1-calc-fn]] +;; -*- geiser-scheme-implementation: chicken -*- + + + + + + + +(define (calc-part-1) + (foldl * + 1 (map (compose length race-winning-distances) + (map calc-race-distances (input->race-records input))))) +;; day6-part1-calc-fn ends here + +;; Code Changes + +;; The ~input->race-records~ function has to be rewritten: + +;; #+NAME: day6-part2-input--race-record + +;; [[file:chicken-src.org::day6-part2-input--race-record][day6-part2-input--race-record]] +;; -*- geiser-scheme-implementation: chicken -*- +(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))) +;; day6-part2-input--race-record ends here + + + +;; And instead of keeping a list of all winning and losing distances, I use a counter. + +;; #+NAME: day6-part2-calc-race-distances + +;; [[file:chicken-src.org::day6-part2-calc-race-distances][day6-part2-calc-race-distances]] +;; -*- geiser-scheme-implementation: chicken -*- +(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))))))) +;; day6-part2-calc-race-distances ends here + +;; Race Variant Results + +;; #+NAME: day6-part2-calc-fn + +;; [[file:chicken-src.org::day6-part2-calc-fn][day6-part2-calc-fn]] +;; -*- geiser-scheme-implementation: chicken -*- + + + + + + + +(define (calc-part-2) + (race-winning-distances + (calc-race-distances-with-counter (input->race-record input)))) +;; day6-part2-calc-fn ends here diff --git a/day7.scm b/day7.scm new file mode 100644 index 0000000..6c915f3 --- /dev/null +++ b/day7.scm @@ -0,0 +1,1447 @@ +;; 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 [[https://en.wikipedia.org/wiki/List_of_poker_hands][poker]] except it's designed to be easier to play while riding a camel. + +;; #+NAME: day7-imports + +;; [[file:chicken-src.org::day7-imports][day7-imports]] +;; -*- geiser-scheme-implementation: chicken -*- +(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) +;; day7-imports ends here + + + +;; #+NAME: day7-input-scm + +;; [[file:chicken-src.org::day7-input-scm][day7-input-scm]] +;; -*- geiser-scheme-implementation: chicken -*- +(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") +;; day7-input-scm ends here + + + +;; 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. + +;; #+NAME: day7-part1-cards + +;; [[file:chicken-src.org::day7-part1-cards][day7-part1-cards]] +;; -*- geiser-scheme-implementation: chicken -*- +(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)))) +;; day7-part1-cards ends here + + + +;; The hands are separated into types. + +;; #+NAME: day7-part1-types + +;; [[file:chicken-src.org::day7-part1-types][day7-part1-types]] +;; -*- geiser-scheme-implementation: chicken -*- +(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) +;; day7-part1-types ends here + + + +;; Hands are primarily ordered based on type; for example, every *full house* is stronger than any +;; *three of a kind*. + +;; #+NAME:day7-part1-hand-types + +;; [[file:chicken-src.org::day7-part1-hand-types][day7-part1-hand-types]] +;; -*- geiser-scheme-implementation: chicken -*- +(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)))) +;; day7-part1-hand-types ends here + + + +;; 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. + +;; #+NAME: day7-part1-hand-comparison + +;; [[file:chicken-src.org::day7-part1-hand-comparison][day7-part1-hand-comparison]] +;; -*- geiser-scheme-implementation: chicken -*- +(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))))) +;; day7-part1-hand-comparison ends here + + + +;; #+RESULTS: +;; : #t + +;; To play Camel Cards, you are given a list of hands and their corresponding *bid* (your puzzle +;; input). For example: + +;; #+begin_example +;; 32T3K 765 +;; T55J5 684 +;; KK677 28 +;; KTJJT 220 +;; QQQJA 483 +;; #+end_example + +;; Better sample input from [[https://old.reddit.com/r/adventofcode/comments/18cr4xr/2023_day_7_better_example_input_not_a_spoiler/][u/LxsterGames]] on Reddit: +;; #+NAME: day7-part1-hand-input-example +;; #+begin_example +;; 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 +;; #+end_example + +;; #+NAME: day7-part1-data-regex + +;; [[file:chicken-src.org::day7-part1-data-regex][day7-part1-data-regex]] +;; -*- geiser-scheme-implementation: chicken -*- +(define camel-card-irregex + '(: (submatch-named cards (+ (or (/ #\A #\Z) (/ #\0 #\9)))) + " " + (submatch-named bid (+ (/ #\0 #\9))))) +;; day7-part1-data-regex ends here + + + +;; #+NAME: day7-part1-data-extraction + +;; [[file:chicken-src.org::day7-part1-data-extraction][day7-part1-data-extraction]] +;; -*- geiser-scheme-implementation: chicken -*- +(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)) +;; day7-part1-data-extraction ends here + + + +;; 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. + +;; #+NAME: day7-part1-hand-ranking + +;; [[file:chicken-src.org::day7-part1-hand-ranking][day7-part1-hand-ranking]] +;; -*- geiser-scheme-implementation: chicken -*- +(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)))) +;; day7-part1-hand-ranking ends here + + + +;; #+RESULTS: +;; | 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=*. + +;; #+NAME: day7-part1-total-winnings + +;; [[file:chicken-src.org::day7-part1-total-winnings][day7-part1-total-winnings]] +;; -*- geiser-scheme-implementation: chicken -*- +(define (total-winnings hands) + (foldl (lambda (total hand) + (let ((bid (hand-bid hand)) + (rank (hand-rank hand))) + (+ total (* bid rank)))) + 0 hands)) +;; day7-part1-total-winnings ends here + + + +;; Find the rank of every hand in your set. *What are the total winnings?* + +;; #+NAME: day7-part1-calc-fn + +;; [[file:chicken-src.org::day7-part1-calc-fn][day7-part1-calc-fn]] +;; -*- geiser-scheme-implementation: chicken -*- + + + + + + + + + + +(define (calc-part-1) + (let ((hands (input->hands input))) + (map calc-hand-type hands) + (rank-hands (reverse (sort hands hands>))) + (total-winnings hands))) +;; day7-part1-calc-fn ends here + +;; Quest + +;; To make things a little more interesting, the Elf introduces one additional rule. Now, =J= cards are +;; [[https://en.wikipedia.org/wiki/Joker_(playing_card)][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=. + +;; #+NAME: day7-part2-cards + +;; [[file:chicken-src.org::day7-part2-cards][day7-part2-cards]] +;; -*- geiser-scheme-implementation: chicken -*- +(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)))) +;; day7-part2-cards ends here + + + +;; /In addition, the ~cardstr->cards~ and, subsequently, ~input->hands~ functions have to be adjusted +;; to use this new list./ + +;; #+NAME: day7-part2-data-extraction + +;; [[file:chicken-src.org::day7-part2-data-extraction][day7-part2-data-extraction]] +;; -*- geiser-scheme-implementation: chicken -*- +(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)) +;; day7-part2-data-extraction ends here + + + +;; =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=. + +;; #+NAME: day7-part2-types + +;; [[file:chicken-src.org::day7-part2-types][day7-part2-types]] +;; -*- geiser-scheme-implementation: chicken -*- +(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) +;; day7-part2-types ends here + + + +;; #+RESULTS: +;; | 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?* + +;; #+NAME: day7-part2-calc-fn + +;; [[file:chicken-src.org::day7-part2-calc-fn][day7-part2-calc-fn]] +;; -*- geiser-scheme-implementation: chicken -*- + + + + + + + + + + +(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))) +;; day7-part2-calc-fn ends here