From 6190867d9f4c821babee1078e0758560b2e60dd0 Mon Sep 17 00:00:00 2001 From: Fabien Zucchet Date: Sun, 10 Dec 2023 14:24:08 +0000 Subject: [PATCH 1/6] feat(y2023): add solution for d01 --- y2023/d01/fabienz/solution.go | 150 ++++ y2023/d01/fabienz/solution_test.go | 58 ++ y2023/d01/fabienz/testdata/input.txt | 1000 ++++++++++++++++++++++++++ 3 files changed, 1208 insertions(+) create mode 100644 y2023/d01/fabienz/solution.go create mode 100644 y2023/d01/fabienz/solution_test.go create mode 100644 y2023/d01/fabienz/testdata/input.txt diff --git a/y2023/d01/fabienz/solution.go b/y2023/d01/fabienz/solution.go new file mode 100644 index 0000000..e7a95f8 --- /dev/null +++ b/y2023/d01/fabienz/solution.go @@ -0,0 +1,150 @@ +package fabienz + +import ( + "fmt" + "io" + "strings" + + "github.com/fabienzucchet/adventofcode/helpers" +) + +// PartOne solves the first problem of day 1 of Advent of Code 2023. +func PartOne(input io.Reader, answer io.Writer) error { + // Read the input. Feel free to change it depending on the input. + lines, err := helpers.LinesFromReader(input) + if err != nil { + return fmt.Errorf("could not read input: %w", err) + } + + sum := 0 + + for _, line := range lines { + first, last, err := findFirstAndLastDigit(line) + if err != nil { + return fmt.Errorf("could not find first and last digit: %w", err) + } + + sum += 10*first + last + } + + _, err = fmt.Fprintf(answer, "%d", sum) + if err != nil { + return fmt.Errorf("could not write answer: %w", err) + } + + return nil +} + +// PartTwo solves the second problem of day 1 of Advent of Code 2023. +func PartTwo(input io.Reader, answer io.Writer) error { + // Read the input. Feel free to change it depending on the input. + lines, err := helpers.LinesFromReader(input) + if err != nil { + return fmt.Errorf("could not read input: %w", err) + } + + sum := 0 + + for _, line := range lines { + first, last, err := findFirstAndLastDigitWithWords(line) + if err != nil { + return fmt.Errorf("could not find first and last digit: %w", err) + } + + sum += 10*first + last + } + + _, err = fmt.Fprintf(answer, "%d", sum) + if err != nil { + return fmt.Errorf("could not write answer: %w", err) + } + + return nil +} + +// Returns the first and last digit of a string. +func findFirstAndLastDigit(s string) (first int, last int, err error) { + first, last = -1, -1 + + for i := 0; i < len(s); i++ { + if isDigit(rune(s[i])) { + if first == -1 { + first, err = toDigit(rune(s[i])) + if err != nil { + return -1, -1, fmt.Errorf("could not convert first digit: %w", err) + } + } + + last, err = toDigit(rune(s[i])) + if err != nil { + return -1, -1, fmt.Errorf("could not convert last digit: %w", err) + } + } + } + + return first, last, nil +} + +// Checks if a rune is a digit. +func isDigit(r rune) bool { + return r >= '0' && r <= '9' +} + +// Converts a digit rune to an integer. +func toDigit(r rune) (int, error) { + d := int(r - '0') + + if d < 0 { + return 0, fmt.Errorf("rune %q is not a digit", r) + } + + return d, nil +} + +// Find the first and last digit also checking words. +func findFirstAndLastDigitWithWords(s string) (first int, last int, err error) { + first, last = -1, -1 + + for i, r := range s { + if isDigit(r) { + if first == -1 { + first, err = toDigit(r) + if err != nil { + return -1, -1, fmt.Errorf("could not convert first digit: %w", err) + } + } + + last, err = toDigit(r) + if err != nil { + return -1, -1, fmt.Errorf("could not convert last digit: %w", err) + } + + continue + } + + for word, digit := range wordsToDigits { + if strings.HasPrefix(s[i:], word) { + if first == -1 { + first = digit + } + + last = digit + } + } + + } + + return first, last, nil +} + +var wordsToDigits = map[string]int{ + "one": 1, + "two": 2, + "three": 3, + "four": 4, + "five": 5, + "six": 6, + "seven": 7, + "eight": 8, + "nine": 9, +} diff --git a/y2023/d01/fabienz/solution_test.go b/y2023/d01/fabienz/solution_test.go new file mode 100644 index 0000000..cfb06d5 --- /dev/null +++ b/y2023/d01/fabienz/solution_test.go @@ -0,0 +1,58 @@ +package fabienz + +import ( + "log" + "os" + "testing" + + "github.com/fabienzucchet/adventofcode/helpers" +) + +func ExamplePartOne() { + file, err := os.Open("testdata/input.txt") + if err != nil { + log.Fatalf("could not open input file: %v", err) + } + defer file.Close() + + if err := PartOne(file, os.Stdout); err != nil { + log.Fatalf("could not solve: %v", err) + } + // Output: 54239 +} + +func ExamplePartTwo() { + file, err := os.Open("testdata/input.txt") + if err != nil { + log.Fatalf("could open input file: %v", err) + } + defer file.Close() + + if err := PartTwo(file, os.Stdout); err != nil { + log.Fatalf("could not solve: %v", err) + } + // Output: 55343 +} + +func Benchmark(b *testing.B) { + testCases := map[string]struct { + solution helpers.Solution + inputFile string + }{ + "PartOne": { + solution: helpers.SolutionFunc(PartOne), + inputFile: "testdata/input.txt", + }, + + "PartTwo": { + solution: helpers.SolutionFunc(PartTwo), + inputFile: "testdata/input.txt", + }, + } + + for name, test := range testCases { + b.Run(name, func(b *testing.B) { + helpers.BenchmarkSolution(b, test.solution, test.inputFile) + }) + } +} diff --git a/y2023/d01/fabienz/testdata/input.txt b/y2023/d01/fabienz/testdata/input.txt new file mode 100644 index 0000000..90b1239 --- /dev/null +++ b/y2023/d01/fabienz/testdata/input.txt @@ -0,0 +1,1000 @@ +6798seven +six8b32csscsdgjsevenfivedlhzhc +fcvvkvjjnhfivesixfiveninesxlvnhfckc54 +feightwo4twofivefour +cgpzm2sevenone68636 +498879 +fivetwo2plltvdfourhhgrfn +onertxzlzdnxn2seven +ninethree4v1five +5pnnss16lzbsmcckeightdseven +jthree249four2cjzqmmbrqnnine +foursixfourfbgvqm1rchdlmzhtzqqfjzpmln +twojtwoscbrtgmnqzvbfbzvrtkxhmf76nine +2fourtwo +svxz8bjvt5zzvjzhkmtmnnft92 +threetffnjvkfh81nineqqshzdf2vtjfqjtbdv +seven1drfivethreedpqflxgdshlzmmnrb +7sggjxkcxfourthreefourtwos3nine +39t6rvkbdnfpssj6djnfbqklkgfsqbf +3four2zcfvtplkrbeight274 +one7sixninesix +kkxmtmdthree6jrj6 +81sevenmnine1llbqrsprc +5nine9qgjceight +three1sdmq9sevenfournine +khnlbmzhvlsix3 +nineone6onesixvlnlxeightfive +schplznseveneightnlcxgr7four +6one1djcdmpdrgq3two +fourzhpnphmq52r813four +scsxjthreefoureight2fivepfmpfj8 +69xvbxfffmr7one8gmch8 +one8tfpgrdhm +2gxmhtfrbrkpdvlvsmdqrktxtrpssbrv933 +4vfrtkdqlbtwordlbppsssp +2cjmtvnzpbkdcq5twofourtwo +2three5onetwogpfqtszbjh +hgvnine9four996 +37142745 +four73 +8552ztclnd +onevmpd76eighth +threethree8 +bgtwonedrmc35 +23one +9lpxzhkck2five3qone9zgxzrzd +hs1 +92xhflsixltpqprpfggbzrvmfqone4 +eight9sevenpcxvl6two1 +rceightwo6jc1nvllxsstqgnlhtl4 +tlnhlsixfn3lbdlqztmkthreedllfourone +74five +dcfpstvxnd52kdqhlht +7onenine +2twothreehdzssrt1 +eightseveneight54xflfspthreefsfbtbslx +4ffsfsvkxslvp +939flgbmvzpvfsmtcsix3 +742 +qcfive72plvnd7 +5hhd8onejbsfklmpzcgffivenine +twodsmjkhdxjdgktlrteightseven2cttnpjsv +31kptdmtwojrgp +dnnmrflcft92 +7gtglplfkrnine85xm7 +voneightznktfvmxlhnine1seven4z +24sevenncdmcpkrvnxlbeightsixlrvns +38prmrxcm5 +4vhncsevenjgvjllppvcfmvrlsdtkqcldpq +81phvtb +5l7twoeightlr +8xfqbnone5 +62737sixfourdfqvdcone +seven1two +79qncxqcj1one3 +69four3two7six2six +six499 +gknlkqvntvmsjzlfb7one +honeightmjlmvmbxsmjzg77 +6seven15 +five59two91 +gmhhtq9368gtsdg +nlmbvxckjtwofourfjnine47threefive +93eightnpkjf26one4 +qcslmgkkgbsnrr6ninennr +8381three2threeone +7hnqndhs8 +qd65 +twogtlrqrlvfourfour5qsixdjhvqvdlljnvbtkq +6seven8ldvkz +gf14sevenrv +2fourpkzdklbvm2 +four26jsrbsrxdlmzntsxgg +tghcz8fourthree +threethree8hzlvpjzxcdfvcpjbmc942 +jktsix2cprnhkkktjcvkvtkdggvrscf +dzhh82 +nine8tsix +9fivernlsl6jvfrljzjg +52d +threethree556nine +g2twoblhhptzdqbbnnrpseven5 +jfive8 +eighttwotwofiveqdfr9 +kqxncc74sjttqklx3lxpffbdlthreetwooneightnb +1xpvjzvplfjdsjqrtmzbknine +five4r6five +72eight +1kzvxckdbjjpprrqn4eight6onebsdmrcxqznjtbnh +htwocglz3jggvkcbzvtconeeight7 +twozspgcxf5bhx +ntglpd1six1bv1 +5zxgrdlhkmzsix47t43 +kfrnghxgfzpjxmstwofourkzvcsksixfive1 +grnd423 +8f +1xcqchtnsix4tvtffone +bxlbtwotwoeight9twoseveneight +7ldngmndg96pjnfour +five4threexp +mtwonexp7nine3z9 +8kg95ninesixtwonem +sixpmvfoursevenz8m +vrszvbtvtr28pzcjxkztzhvmtqvhnqf3 +1gsbtwopjkrrqc1one +tbmsix93 +n4 +kffgtgcl866364 +one4qgkzthpmeight8eightfourkdcnpxv6 +cfhlmng21five +8lhcseven9vksfgpvlnfq3bglktc +twocc2rpflzhqseventhree +six1fourfivefive5onesnpz +1ffqfxh75flgjqcx +fourthree1twortvlvcsvs2 +8rxrpvxthreestbbpcszhnbrsfour +6qdkshgrsjxxsvpmnjxnzmcone71fckgjbrsnq +8568three2eight +1khdqskj +onebdfour6 +dpcpqnineqjnfzffsb5tj1ccm4four +nsrvffqhd67sixtwoseventwohdgh3 +nvsscfour973fsngxbm6 +93zzrgmsqtlckzrnbbk4seven +3seventhreexpfrrfpfiverv7 +threeeightfourfoureightnine1one8 +7onethreefour33cghone +sevenfivesixseven2 +jgbgmcx76qc +zxbpvj7 +21xlcgpshvth96fourtwokcvmhcdtxnm +foursix2 +6three9nine4sevennine +dqnhdnine3 +seven58vzcxqmffive7 +xdmeightwomncvnkdkpxtwoonenineseven1tclckshvptwo +gsdff22fivethreebn +one7gd +jcz8xxfdlphz5threepzmjqzfb39qllhvcqj +fivesvjdbqlvgnvkcklszeightcjhdjxdvchfive9 +9sfgxbtcgbk +six4zvfivelxfghffvq9bfkshrkmbn +sdtxjnnjjp3fivejsll5 +tpeightwozhzqxjstneightsixgbjlmsjfls6tlc +668ninenine +three7two +gtskqnine1seven862mm +487jsqqfkzfcs2lthng7five +gjks7 +lfnqzjphssevenone2qvfiveninexhr +fvfgnddffhjjfour9six9 +ttkmtncjc9five5eight3 +3seven24426four +two9jnd5eight +threeonevmzqdxvjlqxgzqone1hcpqsd43 +tfzzzjjbx7oneeightbqthree +68onerrpvsixvkmnrndq +jbjljljmtwoqgt3kpvdkdsixone +kxvbxzzxrfour2slfjkkgq555gxfsix +three9tsthree +eighttbtdg2sevenxsqsq +seven213jbqmvmvvhsixrfqhlfive +nsvcdhkbdmxqbkthree28ztjtlsqprcplmx +4lntqfk4tkmmgkvrcninenineonelpjtq +221eightqfp7eightzshhl +vppzgrsix1fmvpcpkvsvppspqcsixone +5lhcrxclclcsix4 +qhone2mhhxqqdl73seven5 +5three9hdnfrgfjsfive7 +grcfbvfkj4 +487mzcgxvxqgx +four8nine3four3lpqnclxzzbmjztbhdfdjfive +3six6kbrvjjsndlxvsz5qcfmtzsqlmqbrn +klcx6eightsix2onesixthree +8ztdfdglxhjxmmvktwolsrr5six7 +9two66three +6threesixtgnznd +ggglpldvkkhgmrgt3 +9kktwo3srdtpskbbx446 +7xmrfkbsr5nzqfgseveneightcbshpfour +six5eightseven5gzsjfthree21 +2897cgv +dffvs7zrlrvlkjcfourjxsndkzq4 +eight22blzxvvshgtqlqpqhsixctp +three8bgjhkvnbdvbttblp1fivenxslnseven +3one21x73twongdnb +kfzzhhctgrlznqcdvzshlfive56pdqx +cfsthhgvgfddmsjn83sjrrkxzl +four99tfvbtxgfqrlhcdktmp +3rfhfgcf8six2 +onexsbxqmqkj3hrblqnfrseven +hfgnvtdzzb51gtljm9eight +zprhsph3 +sixsevennine2four715nine +fzxzkcvcxl4 +lcnkqqsrtwogcbvxrtfp2five5three2 +7ninesix9jxhrdqrpr94 +lxpqxseven2three +mnsjjgdlltwodrcfltwo8vninemqlfqsgccl3 +sevennfkfvxsqr7twotwonedb +7twonpkjfjmgqxsxpdtninetpsfjlqvv +seventhree328sixscxmpqjlxftwo +3qpxvglmpcgxzrseven9 +6onemqrvdmckhmdrzxzkxbjthreeeighttwoql +sevenfdpqqzpbflflgph698eight9 +fivedbntvzzdq36two3 +8six3fivefivefivesevenpxqpxrjqseven +sixtwoqt4 +tmcfive4zkxhvlrvfzhkczpkvbxk1 +rbrnxxbfxmbqscltvsixone79three +88sixzqntjsfhqj6three43 +pmcfsrpknvbfhrzlvlcffjmfive32323 +97rtggjhvvdfive +vtdljvqht1fivefivetwo +88rqtpdz5nine +rtwone725 +sghfour2eightgrgpsmfxpchmmpndccgzfzz +kpgrhmtkxzzmdpcdzeighteight2 +5bfhbmffeight6 +8fqtr17czztqgfour4lx +9xnbmgqgvrtwonevs +1zqsvmcqsxjtp +twollzsslxc37sixoneightp +6bbgl76 +58zntvhvgdnh2 +three54 +fftdddqnninesevenone76 +6ddqzjoneeighttwothree +56threetcp46 +21six3m +214onethreesp6six +652three6 +lvc1onefiveone +6ddrgglstz +twothreerjpb2four55 +eight8eightwoh +fivefqckddnine7one61zlkjgxjtqq +gzneightwovlsdvcmvj3qhbfmkdnvqone99 +92sixgxsix +64eightxb2six +51fivepbxrzkdzjhsixoneightmt +ninem3nlpdtonefivethree6six +lvxf3nine1eight +vvbvfvtninefive5onezgtsjplxc +qltld5p9tgpmkzrf4 +71six +2threergjrcqsixhgjtdkjpqnglzgdpqntnqtzcfcbb3 +7xfj5btrml3two +979nzpjkcthcl13tnfour +one1jseven6three7five +tppnljghmhxplmnjgfmpfourtkffqcghxx9four9 +396 +onettfdjdd5msplxhlqvv12 +7mrqgcxbbtwo6seven5oneonesix +hjnq8vbshrbxeight9sixlxznhqgcc +sixzq9nnq4lxzhzmzjmnbtfbkf +vfjhmf3ksgnlzzhsdtwotg9eight +ddztjmr453qghvzrtsgf +55lzcrzseven39 +onecggvnjfpone27qrzcrxvp6 +286hfzchgcgtcqhr +ngeighteightfive5mbdn +l1five +712onekndmfive6ntrmsk8eightwop +hqgfive512fourhgrm +vpdvhpkngnntqptmsevenoneseven619 +ninesevenckpjpxszfv1jzxtptvrdkfourfour +tjlcs5onetxfkq6hzfklslthreeeight +mxjrssqxt7one7hnffgqcgsthree +onefsxjsnzxncsix1rr +four725deight +sgssrlckfourprpsix5rktmjhxksgmvdqmnkndjls +75eightr6three +6threesixx1sixsixcbxxcxvnhsgl +4fiveeightkj9fivemqzvcc +ncgqljseveneight61nbcv +three83pnineskc +fivehninesevensix5 +five617twosr6nine +ncjjfvzzmghgq8 +2n48twodpnpgq +qpgnxtvhq1jcvtxlfkfour6eighttwoztzddkmpbk +fivevhfxpjtmdj2ninesevennine9two +fivejtxmg4hbctmpnntlpbzfmxqgthreejbjdb +4xgrzszmhx +28four78tmrkfndeighteightwonq +zvnxmbtjqzblnine3five +slmt6onetwo5sixfour +bthreenine3five +3fxjfivevcdmmphtrccptz +8fourksxxsixsevenseventwofour +fpxvbdgqxzdzxone7threeptgzhhqmkxmseven +9six654 +foursix6559 +9fvsdcbmmghfive8one8oneone +dlxcsjmcjpmmjr64onegtkkqkmhkl1 +pxkqbgdfour89 +nn88 +6sixthree +1zxszmgmfg9drnjzd +eight8onetvgzfzfjqlqtwo2dfhtwo +kcgzq8cxdqphsglsixfivefourdbsjjmdtnxrzt +4threenine3dpflrrtmt +one83five +8sixthreetwonez +3fxnhqrrseven +seven4onetwo +fourbvnvbnineqggx5twovbdzztqccjhqqqnine +qzcdgvninejbrfoursixseven24 +vknqxgpgxnl2mrmbxprseven +kfggmlcht8sevenfourkbtdzstpsnine +kxzhchjh77sixmvtceight4seven +five17 +eightdgkcrphqsndn7fivevkstrsprktqdrdxqslmjtz +2njqktntzjtwo7 +four66 +975eightnczdclht +twofour1mlbpb6d +ddleightwo64 +2239gksfnlvtg1 +jqrmqdkv1mhsjbqhhhjrvftwofour6 +fjglfourone74nlxzmxfkbn3three +6pseven1 +1nscmsconek3 +r182nine23 +rqvstbf5seven1 +mmtrqgddjone2 +n23fivelvprvxstrct5 +loneightgmlqfl7nineqrtmzdbbjmnfivepqhgtmb +sixfivefourtwoone3 +five39hjjcjktlcsixfive7eight +sixeightthree5three +5threeninebnbgxvnmfknp2dhbdb7nine +5cpljvtxtpbvzbdrdvsdgc23sixtwo +4fiverlflt549 +two1onefoursixmzm +4eightjksktjdvxsckgllpzdvblssix +xsxkj81vkstvjjtm5sevenfive +8943qxpcfqpnqtwo +58qnrthreethree1eight5 +6gqcfk +49lxnllkqrdgcxdrfv +94nine7six8nine +55six6dgshxnn +sixthreeeightfourbgnhsnjone1 +nine3qmpnnzldoneddthreethree +14ljmrtmhmeight8 +onetwo4eight31loneighttc +jnkg8lbjjvclcvmbseven3tdvnmrp +7qxklg +7dtwosixthree6 +sevenfivesixsgltjpcnthree2 +15rzct +tfn4ninevt74nine +1fiveseven68hztpthreexlbbgbqffvthree +svqjgxnmxlpfjc95 +nine9bn3njvhp9eight2 +92six1threeeightwot +sixfour2nine +nine1bstseven45snndcpmtbq +onesix4rkrglcvmvb +tjccltxqljfourcfbtcqtjd1 +fourgqjb7sixeightseven6 +6four99nine8dfjp2dhzsfgt +7kfgzrxgm7 +3nn3 +eightfzqvgrr1skhnqntgvv +8fmghkjzmrkpthcrk6eight9two1 +qgvgggrmnine3rl9rnf +seven6jvjfkr +ninetwofourlsbdlmlnsixb9 +khqtjbkpdvrdnine6three +pzninebmxq1onefourqtztvzlxf +seven1sixcjcbfv3ninenine +ngtsvjgmcg5mssqdgtsdrqff +1vshninetwolfbfhckb1vfkxv +1six3five +93hsvjggzqcgjbqjvpnine6 +dtwo4onefpthree18 +4fourfive +nnplsdmt962 +five83rzgdpc322threesix +3hcqbfiveppvzvtcbjnvqjz +khh4one2sg +pdtltjqgqzfive8sixone9vhnzbvfnxz +xtrxkfive83three +three75kjjxsixfivefive5scjbbflf +ljfcdxktbnmvbspglnjfive483 +eightonespmnrznpptmjvh68eight8 +qznqkgvkhlssszmdlvjdjjtbgz2 +6sixfourfbxrxfbv9hldlseven +3qzjrffxdthreeoneightbc +three4tfseven2sb +nine87rvkdgmpt +84threetwobjfzvncrkfour +eightsix9plxkppkgpzkfive +2eight4526 +hdmqlgnphg1two11 +ninekxlrjmmkm34sfvrdlb76lkbzprhnchrz +9one26txfggnctgfive +7pzrqmfivev +ddqknbqxnrxlcrhcmhmr5 +eightsix121twohbtkjqljkprzdsmnv +7eight2twoqblcpqqfckfour1 +cbnpcjljfninenine9 +73eight3eightzfzjs +szfsgstdmtwo2sixjkgxrxbtpdbkt +one722 +76eightrvs +five6two7rcss5eightone +9ckcnzponebnpjlznbrfxnkvfpsevenonebz3 +sixninedbtpcrz148tzvbhxjk +5zlpdbxk72twotlp6qbkpvjx +3three4sjgfjzzone8xmeight +56tkmpbmsix5seven7 +nineeighttqrntnvxrrbkpftwovclttztwo7two +bsxdzgxkcx5five6twoqlbqgjzbc +five22hhlpfiveeight8vrkjcstx6 +2psmkkxflgfoursixhjmdxfccbxqb +25kljltwoneggk +3fhtjzffgfph8twozr +eightsevenfbzlr7rqfivefour +one3fourninerl49rlvgnmtlcp +vrzcnn79txgxf5five2cftclqsg8 +kbbptjpbvvzcxrsix45prvjcq +one3ninefour2vcpdfkbnineeight +lx1 +1oneqphkrtwojczlpmcjseven38oneightgm +xsnzjbzfmb685ninezmgzfkzvpzj5six +547six +21five6z9 +5nqcsix1seven9 +nine4fbfprrfivevdvjphcqkfourthree +9243five +84zmtwothree +5c +17three +5gvfxttjch74eight +ninegs7hxmgmrzsx +dzxzfknlk5ddgsbsh +475cbbqscvfive +twovjtkcxpxlvqhvgsqfzmthreecg1rctndlmm +nine7eight +eightoneninethreebccrmone9six +twohbjxlfxdd4462 +2fivesixdrcmbksthree +24sevenk7 +3sixsix28 +four66vvjvqhhbhr4 +seven4fourfourprhplxheightxkgvgghlseven4 +ninegtsqsnk7fourzlmnv9 +gpr3q5twoninebqnr6 +rxhkdtwo8three2 +jljtwonesevenkckbv9four +4scdjjmkpf33 +vjfourzrlthreeseventbbzrm8n +two1fourxqlfqbhszveightrqcsprdonenine +mmppkfd745ninexfour +fxeightwo5tftddm8onexpeight +xdbmf415cq92dhmmc +nine3onedcvqdvhtqninepczfhhgbmzeight2 +ffsix6seven5ninelg +xtzsnzlvvztq64zhkklcgjrfourlztxlbtgxn9qcx +six1nbqxmq2nxhtvrnrbsflzlztghfzjgfnhmeightone +558 +xnhsbblmlp9sevensix +jz8eightonemrbchzmhrjcv +3twoktr +6fourtwosixthree +sixfivefour7 +ljbx2nine63four +889g7sixtwoone7 +four4one7cztqmheightwompd +ctqnhkqzxgtxrgfzvone45eightfbvjlgkc +8eight35two5 +6pvzljrvseven5eight +7zhgjds1 +mxv7dtbsbzfive +4sqhcsjb6 +954threeoners +63three9zltqkmpbqqpd +6sjknine6phmcxrv1three +threeoneprqcmzrbjjvlvsf2 +gbgfr2fivehsplpdnccxkfz +ninefnpxtgzhzvdnr7rftghqrhpv +seven2fourfive2 +8sixeight +gcfjqqgbcdp33five42q +fourfourbkrj3fourfivevlpvqbkgvxcfnlnbs +tcgzqgqq77two +nvzgmddmhseven1zbdfjrt17 +seven8fiveninethree48 +7five8 +nine3twoeightfgdkbtph +dzlblf4ninetwoqqj4onetvpbbfdcbvtwo +mcmbfvszjltlzdg7zxzzlrrvfbthreeninethreefdtsvclt +8mzcseventwoeight9kjchpd +sgpddvmkntwo9two +sevencgqkbcsh5 +13nine723twofour +twodpdvppxntseventwooneseven1 +9jjpxjpxdxxkqjseven +4seven1five +2nineckczklc5h +threekplnxmcjffhpfdhhhvsvsx62zrmbcpgj +35 +8gthree +nineffourninethree6two8 +1vsmthree67fourchzmone +bxnrzblqnv9xprtmvnfivevkdvqmvfhgxconezvzjlxgjhp +xtqsevenfive7fourmclszsmnqz5 +vrxnrvfivegjlqrbdtkksz9 +ninefszbsfnhbzzqhbkvxjfive7sixfive5q +eight38nklfskv3sb +5six4three +onezhpqfxgsz3stfsldzdhh +qdtwone72 +fttvpkjsf8 +8twodxeightbltlrvjjbs +sixninesixfourxzvf5 +85twokqdh2skxgnnnnsevenzg +lsjqvnfive4eightjbjceight3 +5eightnineglvjmdgjvt4 +cfhxfnvnsixfour8twosixsixtwo +hmp27seveneightsix +5two6 +d37sixeighteight +9fdbkdm86two +4threefbsjzzkthree723 +dgzvfszqpkfpxmvqf7onethree +eight2fkskmljrg12kschgbrbtgmkbdzseven +5sbdhqrsftwoqlfqblrvgghbps6ln +2pkmljtwospqdnflmj +nine1eighthgccrfourseven9 +eightjbptmtmmvsevenseven6fourfive +6threeseven6eightdsbpjzc9jsmtxdfour +4ninextnv +threeqjrdnfjlpnine55 +1psdrj3g2msfsjktgkv61 +sevenfive9xhdcthreenine9jctjthree +636 +2threeseven +nnxzzcgrhcgtz4ttnfive +seven9sixone2fbbdfqtdfg +4jgdxjqtbqzprpjdbjc2fivethreeonexlgkxtsdmcrrh +4threepvzzhkmlmbhzhmtb +m5xgplrjqlztvg9 +59s68ninerrhkrkxnzm +hknsnsf6 +trgpkmkbtlslmpqtdxfourxjspnnmhdtg1nvfxpllcrrbzjrhrstn +92twoj7two4six +tseven377 +p49five2 +kpffiveeightcsbjz39 +8sdmbrxbk +1vxknsvdqnsixkfsevenzqlr9 +fiveznrsqthpbddfcpbvhhhjctp9 +plbcxgkd4tmprsxn84hdrninetwo2 +twoqzqxbkm23brhsppdnvksixtwok +8one5 +six45tdxfmcr6 +onesix4 +fxrl57561ktxfsg +89nine54fiveeight +three62three5one +6mjqxh4scvddlls +nflfourzrrgpvftoneseven43 +7sixtf +sixxhxkvgnbz3rbdnvgf +ckq745ninepqk +1snlkqn +ninetqvcllfvcfs62qtt6seven +59khlmz +eightdndsvdcqneight9twonenf +zgcnqqmlgsmfzqbkllvsknsevensix5 +8qqxshjnnsp +xfvttdnxhz4sixsjkqhpfszn212three +fivelssnmckseven4ftqt +2qsqpjmcbtvxjgqhhk +tztwone749ninelncrmvthfourpgcbxzxvs +4threecgnjpthnsgxhxbffour8eightsvmjkg5 +458sixseven6one1smkjk +seven4fourrgqffqthree7 +jhpxqpspbsevenhpfnrpdvfoureight5nsbsfscjlzfive9 +sldxjjnjt5dlhdtrmsixxlmgxhvpscqqthree74 +8pvfhtpghtwo6 +nfknjlfive8 +eight7sevenseven9pdvhsevendzpxpghzr +9fgdrgsgdhtwo7238 +8nfjgxpcbbmjrhh9765dnlbsfddhf +tkqfc7sixsixsixggqsevenzrjrxtrnh3 +fivesix9zmxpjk +four1kvhvnhjcgz +one6sixthreenh4 +onesixfourtzkjjlnine1kq8 +1xkl +8six5zbonevbtbmvtjvlfive +zmggmrj9eight +5sixeight23 +19twobshhmblpkp68 +7fivethree22four9tghbrr2 +gc3 +6qdkjxgpseveneight1seven +7sevenfivegpllcnbvf3khjsqtwoner +3fivefive417 +seventhreefthree96hbrjfxlkrninetwo +vhnlzrv4gbdldncbgqrfd5 +gfjzvfchlzrnf8fivesixthreeninesevenrsfptjcrb +6nineninelllzx +sevenckthree1 +8one77four8sixnsmbhbp +ltcfm386 +bcncpxhhgbdtxh19kqkpffqx6 +pr95 +eightsix7gbtwofourvclrmgfvph4 +four6bgzbcthree1kjhkvlh +lbffslczqninesevenr6z +three6lpjrgbfivexzfkprdf +31kmnnffourtwo7dkmmlrdsm +six7fivenbljxg6onesevenzmknhdfive +32five5sggfive +two4four +xlf4rtftmttzk4fhrcbxmxlsjzfour +fivecxrsccjsgdfpfdgpfsix3sevenqgntlgvds +pbdmldone1s +threekpzzth3fivernp +glglvsnineckckdblscv2one9two3 +52cvnxlxqdoneone +kjdvcklltsttlncvgrfive9fkspxfhchml +sfxxlhkbhqnvskxd2five +three3ninevndkz2two +3two9six9sixfiveoneightf +36xq +twoeight76 +3kfsr1tworhvpqn7zmrp3nine +tvvtqdcx8eight6three6fqsmnd6 +3three7 +2five3eight +tmzhzsninetjjpmqdrkh6seven8threenine +dsvnxx6 +8xzllsdpvrjszlhlmrrsixfourninefzncn9pkgdtlb +four2eight4bdxhqxnjlfg3hkbkp +onehcnf9 +twosixktskmcppzx4 +xzeightwo1doneseven7sevensix1 +fourgbdz85nine +21xrsphxlr711mjeight +one654four +six4sevenxl +sixmqhtms6zp99 +497twofour3two +6twoxrjvzhldhfour69twofjjtskmzvls +px98skfppldqkpsix +7qxone8kzzdlqdmsixtzrhrzrhpeight +6eightmdsbrvhnine +onesixjxzx1jbfnjhm3 +threerbslfnzsbtjxfcmtxzjtvbdjnqj2 +4lbmlrptworkpdtfvnfour +2threelkvzmghvdm +6vrvcbbqv77 +gczqmslninepphpbvd896 +seven77nsnzeight5vzgvmfrxd +seven46fourfive1ninechrlthdhvnfn +sp2xngkbkqbpvqgd57onenine +7oneonenine38hpqntxsz1hxvc +nine3sixvrsrvfrseven4 +seventsvmxxn5sixgm1kdbrkcdfive +5eightnfblfbxrkrrmflg5 +fourxltzjthree2 +steightwojllrms39threesixvjxflgzkm +25ckxsgcgxjf +lpsztggf4nine73two5 +drktgkbkxlqlfvhvr8onesix1qbgjjtcf71 +4eights14five +jqjbzqvxcjqjjjhjjk8llseven1knphmcvnjcsfdzp +9qrthreeeightnqpnninexgprcrdsn1rgjt +59snmrlfxhsix +1286 +72five81gnc3 +sixtffnjthreevmhc64one +three96fournine4ninezr +lrzcgsgdll99 +qftkzxrlone8sixeightfour +eight7seveneight +kzkoneightfbptzkfive2sgbcnxg92 +v5hdone +onevzfour75cmzkfhklp +cxklnb9fivetbkgjdcvjhqgnmdgrjkmfjqqbjtrzqfdreight3 +six6twotwolmggvvxrtwo72 +2kcrxxbzkssixnddqsqsk +rpjglmp8onelvzbgvbjxdthreeonelvxdtqnz +sevennine6bvdtwo +16mseven3twojv +hhconeightxrnfvbqhseven3vs +sixnine17 +2lcssbzf1three3eightbvqrsmbh +5onezrsvkbpnsix7zjggs4 +3eightfive +cpgtwoneonerhgncphbfsrfplbfhxrmmpfive6 +4vbsrvggrzxxcxzeighttwo +52nine5 +7fourkczfpeightnine3eight +zzleightwo2onecfdsqthreejbcthreerbngllphhsixgp +3sixntzmjnrrone +3threeeight6bqcsdklzpfmbgxxtjs +rrbjsghzclnine833 +cfbrmlhqvtpxtpdbbcjj6eight +6twoqmhkgpktkdprrqxpbphjn +cmfv1eight41 +fsfdjhbeightfoursevenpmqlcf6mvfive +qmvq9sevenseven7 +1sevenjqrsevenfmrsncppbr1six +1eightvcpbnsqhcv56eightzthree +five8dnxkdbsxvd +3l76cbpbdvsix +vdvnbr1xzlssevenszdktcqfsqxtv4 +sixtwo9qngsslvmbv39eight +66fjjnc3threexqdctdtkseightbqpphzzm +hsqcqb1sjkdhhdltoneeight5one +1llpgqdfgseightfvssfive +znqqgtlmvxnlcgxr4fourscgzzhz +eight9onetx5vzvqln8gxblpkmtkhcl +eightczhdvmrlm5pmnlnlnine5hxzmlzntdmqldbnfive +one16shmhxdvzbh73dsvgvtpddls +5lph98flssjhz +2psmflmhcbsrvzfive176 +qzqz8sevenone +fmhgvseven7fivejdqcsznnone +415dsgfivethreexlfzccgn +qplzvmmhbh598ghnhrmzvxblxncdkrfntvzdtvqr +8fdkghntwophfnpzjllfr9 +6rfstqcmdvq9 +nmcdsbclthreeonekxnrvqgjxpsevenfour3seven +one72rqpfourdcqrlqpcthree +onefour6 +eightoneqqrc18 +nine3nrscbxlx4fchjdgnlvvfrnf7jfffbggjt +four8twofivesbpgjnt +8sixtwojhjvhfive +ninefg8xrvpbpgbklkbfrqgdloneeight +pbdggcfoureight5rdsssnj +gxqzltbzfbhfdcqeight3dggjvh9xg9jxq +fm6ninesix +1four8xkdjzkfthone77 +fourfourseven514 +2vfq9vfzxfmsfrxjxhfqrpc +zckzxj45onep +nine925 +nineone1eightsixkcd8ndvhj5 +fourfoureighthbhrnsix5seven +mpr9sevenzm5 +two415 +two2ddgkzt66sevenmdzhdzhdmzjmvrrnd +vntvkmtqm252 +bktbrctxtwoqbjls7 +seventwo26 +22threezlhpkpmzsnbshpgt +1pktkpfppxbjf8 +one1jzlvq +24fivek4 +84two +1sevensixeight13pvp2 +xvndrn85k5nr6nzgcdhlzvf8 +ninefour1 +rhztwosix7 +eight4five5sevenlzbhmsprsj +7seven1kmzsjl8jpdssncpvcjxczdvsk4six +zcmpfqzfxlfsxkmscs4lctqonepjkg4nine +8onesevenzlxflf9four +threefoursix3five +292mhsbgktzmlqk1fourone4 +pnnftwo5 +kpjmxmseven6 +fiveonetwoqbptwo4hmzhhfmvfqbgjk +one4bkzjstxgrv2dvzbdfztfive7three9 +monetwo6fbxbphkpdtwo2ninenvphvnxhxk +6mgmbthree9bnine3seven5 +eightvsfnsdkgh7fourninernvkrfcx +fourxglll561 +3eightsixeight72six7 +4fiveflsgrgznjfbsvgvbrgnm +763 +nine57qmhfgctmnp +eight579xgpsr +sbpbb215jnsfoursix +dfghm9mrcpfthree974 +bh7threeqvhttfqt +seven7kssmdclhfd +qdltfdhsvz5threekftjfdqbn +four8dxncfjhvpsxdseven3kcpmpfvnfb +nine1eightwox +vvcfdjlpcrfnnmbcx4eight9mtcfqqqfl5fourfive +qbcxpccssl9kvqtjncjdxsrpp8sixbnmq +sixonexjgqthdnrpfivetgnxqv1 +eightthree33ngpkqtqgtkmcfgqqgj313 +onezfnlseven1 +2threefhcs +3nineeightzmpvjqrvcb1tkmchzjtsrfllv +58cjnxhzfknnkj4ninezvskrvrc +hthree16zdtbfnlx +tzqcksevenfour3foursix5 +qbbzz1threesevenone +onegfzhlthree12 +gpjjzfiveone21qbrjdrz7 +xcpjznj54fivesevenfiveq +gsevenflcgfcmqtrzstrmnine9two +7nrsmkbqffnnvfpjgb +tfhnnmpbzq67six +52jhltfzqhfprmtgbmhg +vchpblqmsvffourzkndtsg7 +eightsevenvgfpttr62hmfzf4f +eight4four1tsvfq +4sevensix +vrkmjrrxnbgjbxfqxllp17four1bdm6 +2kqfd4threefour5 +44m +foursevenrxzjfftwo5twothree +eight4xbxqplmknhjhzm9fivetwozjrzjp +twojtjvdmgkjsstbdgl3bhhhzvllm6qxpzxjbgn +sixeight3sevenone +sixfour5m5 +fqlftfrtsj9 +rpjlhht2xxnnkqktkxteightsevensix +five3vbklfdmpsevenone2thxcmzktlz +fivefour7lxhg +49gcb8fqc3fnstcnmdneighttwo +2vd +6tfpxszrkdsgphdsblkqfk +43rjxkfgdm4gkxnvdfxs +6225eight3 +8one35four3 +prsevennineeightfour8 +twozqdxfg363zczthree +eight9vcncjcbxhnfeight +meightjdg2vp73 +seventhree9dzdhprp +btwoninegnfpfhxkvv3 +threegkxmmxzsmblsjfds8seven +crbbpggzbfsjb8kqqgk9fourflghlzbgseven +sixsix85eight5 +nmrvnmgdrtwo8three +gqntwoneseven95eight1vtthdng1cgvxlvstgm +oneqcftjqnxckthreegtsxfjbrmv2 +threekdfzqhqeight54four7twonep +525xtwomtcgmfhbjninepkpjjsf +1sevenxvgjdznvnjftwolvmjmg +ppbgncvclfive45 +three6386qxzsvxpbz4onejt +szxc93tfh +zdxgxlj9nine +9kkmgczf +4six3six97qcxxgmppgkll +6fivethreefourtwo +nine9qpngcdftwo1seven7kzsjxqbggxone +sevenninegfjkxkbptwo7nine3xjgsxh +6srqfplffour81threefive3 +869 +nnsjzlrjcsnpd7zcfive +fivenmndbmjngpsvkjsbqxvncm6qjzcktnsevennlxpbkchk +three4eightwol +2gnbninedt +1twoninefour8 +5lb +cdczlxgxpdqvkcqbfivet3 +nxxxreight158mvrhngveight +811dsqsscjgfive2 +nine8nine16gxqxcj6three +dqjdfksftwohrrhzlcxd12vblpmsqrrfourshg +345dstjsbllcnine +4three6vnzfssrqrg +mlcmlvlmcseven72mcqlzfnpm2 +ninegflbrbv6twosvfive +nineninerjmnhlthreenine3 +zvsqxdggl9dxppmcmc389fourvpeight +2fiveeighthtfvpndpn8mt3two +33tshvcbgtggone6 +1sevenfivextsfpsix +frmhtjxcnztfhtgtr5 +8jjsclsqgfourthree7lvct75 +62vqnhqct4 +2jlvv55 +lszrone3eight19ggpnine +8fivexxxrkzrppslbf8threexsskbkjcc +pvpxjrnnp11rmgfhbpbninesmbfpcpseven +seven8pfzgsbgjqtneight +rdksixnzmxgppj6qkftmcthgl9 +32three1 +bnxd75 +mzlcnxgdddfpqkp6hjjpnnine31 +135gnzr9brblpnk +vvninerkskndtjq8zst4sixnine +fivexdstdtfshcchblmknlneight5fncvl +7mhjsq7ninetwo3tbnkglngltwo +threeninesix5567 +2four14fzrsjr +9sixkl9 +rftbrjfour4 +onemtjqqdrtjgkbv1plcgtxtwoonefoureight +6fourqsgfkqdnspzstbrhzxbthreeqxrshrfdbk1jrxptfhjfld +sevensix9 +one75two9fourxdjmzjv +one8rbvxt +skzg13 +ninesevent3 +mcrgx49qbpzcqqbx +threebsevensix9nine54six +1bjgnlhtxgx +71crfour +3nkjflkqpjz61gzsffxlncmxg8 +rhppr943fourmmjm +rvmthreevbvxqhrhglvrh869 +6sixfivexgshnkmx26 +3srgvnbcsreighttfnjcs782 +87ninenjhxpnrhljkvnms3 +foursix1rfgvmxqfrninekthjjk +fourtqbjqcmsgnine1twoxgvqdhbnloneeight +hhzdrttjvbzdngnqv2 +kbm71 +qzmtwonexlzbv2eightfrjmhld6 +27mdxfj49kzkzdspbxvktm +three8cvfqmntngvmhddgqdgonetjgnnzggjz9xqlxffgsc +ckd3fourtwo5vzv +lhbvlseven41bdrkzmshkxone +6fourthreefourthreeskhdk +377dtljbhvfdr4ngqdqfbfournsnt +rvbkddqrfm8rpfive +1ninethree +zjhbkjrb5qvtjbcgpkvksbsszpqjfcrgrcqggdtc +73nine9pslhnpmxjjfourthree +91nine5xndjkx7 +four17crgvnqtwoxqxfcsbbbsjlsjhsfll +five9twobqlgcdpk4 +pblrzfive7ninetzfiverhlslrsone +7bltone +3eightthree16 +nineone54hspfngxzhzh +7sixzxqlsqqsvfouronethree6 +8kklgfmqvntwonine9 +dznsskrrfchdnm2fxcvqvf3eight +cmfkrlslhgzprgkfive6seven +4threethree +threesix2fkzsjkr6six +8bcqmshjlnfivecrjtcsznrfive +11nine3six +326one1zvdzc +1sjttzbstpx6sgfzpgdltxseven15bvrbmccbzkbgdnkkhpd +9bbpksbnpdm +3rtcztcr +bk1sevenjbmncfiveninejp +seven62hjvttpk +rsnqnlgfgrxk8sfxhrlgmc1jnjgctclr7 +3sbmxlshf5five4 +8nprjs +three89 +four399ljmdptjbgkthree +cthxllrzbseveneight7four +3gzvsfnxfive +pjbgbnine1rphbcrhgnine2 +56fourcsfpfnntpkfcsqkkp6oneightlsv +fourmn5kqgvk +96twoseven +2bk +8nineninesevenvxfnqlsrnxbr +fivetnxmljplldd3six +qtzcgtlh9 +gtnkglkd3twoqgqhj6dpfgqtpptg +7jvxsltntrksjzsix +three95fivebpvtzh +3kxxfvsseven +157xvtnfkqnsbvpxlrdmjszrpmpfive +7threeseventwo7twoseven5 +rcmzjxg1csdhdkvfhxppsixfivethree +nvgfnine38onezdbhhgtmshc +2ngoneninex +1eight57ggvqjmsixonefour +dhq7hzhmbzdhzjxhdtwo32 +ggdone3nbmsthreefourninefiveoneightpr +fourvzgnfnhkkp2 +j47three8sevenfivenfkd +twotwo4seven1fqklblqbdxcmtch From c86972d1643bd0c845a74cb7971f58d04809afc3 Mon Sep 17 00:00:00 2001 From: Fabien Zucchet Date: Sun, 10 Dec 2023 14:24:21 +0000 Subject: [PATCH 2/6] feat(y2023): add solution for d02 --- y2023/d02/fabienz/solution.go | 153 +++++++++++++++++++++++++++ y2023/d02/fabienz/solution_test.go | 58 ++++++++++ y2023/d02/fabienz/testdata/input.txt | 100 +++++++++++++++++ 3 files changed, 311 insertions(+) create mode 100644 y2023/d02/fabienz/solution.go create mode 100644 y2023/d02/fabienz/solution_test.go create mode 100644 y2023/d02/fabienz/testdata/input.txt diff --git a/y2023/d02/fabienz/solution.go b/y2023/d02/fabienz/solution.go new file mode 100644 index 0000000..dc5d276 --- /dev/null +++ b/y2023/d02/fabienz/solution.go @@ -0,0 +1,153 @@ +package fabienz + +import ( + "fmt" + "io" + "strconv" + "strings" + + "github.com/fabienzucchet/adventofcode/helpers" +) + +// PartOne solves the first problem of day 2 of Advent of Code 2023. +func PartOne(input io.Reader, answer io.Writer) error { + // Read the input. Feel free to change it depending on the input. + lines, err := helpers.LinesFromReader(input) + if err != nil { + return fmt.Errorf("could not read input: %w", err) + } + + maxCubesInGame := map[string]int{ + "red": 12, + "green": 13, + "blue": 14, + } + + sum := 0 + + for _, line := range lines { + gameId, maxCounts, err := parseGame(line) + if err != nil { + return fmt.Errorf("could not parse game: %w", err) + } + + if isGameValid(maxCounts, maxCubesInGame) { + sum += gameId + } + } + + _, err = fmt.Fprintf(answer, "%d", sum) + if err != nil { + return fmt.Errorf("could not write answer: %w", err) + } + + return nil +} + +// PartTwo solves the second problem of day 2 of Advent of Code 2023. +func PartTwo(input io.Reader, answer io.Writer) error { + // Read the input. Feel free to change it depending on the input. + lines, err := helpers.LinesFromReader(input) + if err != nil { + return fmt.Errorf("could not read input: %w", err) + } + + sum := 0 + + for _, line := range lines { + _, maxCounts, err := parseGame(line) + if err != nil { + return fmt.Errorf("could not parse game: %w", err) + } + + sum += powerOfACube(maxCounts) + } + + _, err = fmt.Fprintf(answer, "%d", sum) + if err != nil { + return fmt.Errorf("could not write answer: %w", err) + } + + return nil +} + +func parseGame(line string) (gameId int, maxCounts map[string]int, err error) { + splitLine := strings.Split(line, ": ") + if len(splitLine) != 2 { + return 0, maxCounts, fmt.Errorf("invalid line: %s", line) + } + + gameId, err = parseGameID(splitLine[0]) + if err != nil { + return 0, maxCounts, fmt.Errorf("failed to parse game id: %w", err) + } + + maxCounts, err = findMaxCubesByColor(strings.Split(splitLine[1], "; ")) + if err != nil { + return 0, maxCounts, fmt.Errorf("failed to find max cubes by color: %w", err) + } + + return gameId, maxCounts, nil +} + +// Parse the game id from the prefix of the line. +func parseGameID(line string) (int, error) { + id, err := strconv.Atoi((strings.Split(line, " "))[1]) + if err != nil { + return 0, fmt.Errorf("invalid game id: %s", line) + } + + return id, nil +} + +// return the max number of cubes shown by color +func findMaxCubesByColor(subsets []string) (maxCounts map[string]int, err error) { + maxCounts = make(map[string]int) + + for _, subset := range subsets { + for _, cubes := range strings.Split(subset, ", ") { + count, color, err := parseCubeCountAndColor(cubes) + if err != nil { + return maxCounts, fmt.Errorf("failed to parse cube count and color: %w", err) + } + + if _, ok := maxCounts[color]; !ok { + maxCounts[color] = count + } else { + if count > maxCounts[color] { + maxCounts[color] = count + } + } + } + } + + return maxCounts, nil +} + +func parseCubeCountAndColor(s string) (count int, color string, err error) { + split := strings.Split(s, " ") + if len(split) != 2 { + return 0, "", fmt.Errorf("invalid cube count and color: %s", s) + } + + count, err = strconv.Atoi(split[0]) + if err != nil { + return 0, "", fmt.Errorf("invalid cube count: %s", s) + } + + return count, split[1], nil +} + +func isGameValid(maxCounts map[string]int, maxCubesInGame map[string]int) bool { + for color, count := range maxCounts { + if count > maxCubesInGame[color] { + return false + } + } + + return true +} + +func powerOfACube(maxCounts map[string]int) int { + return maxCounts["red"] * maxCounts["green"] * maxCounts["blue"] +} diff --git a/y2023/d02/fabienz/solution_test.go b/y2023/d02/fabienz/solution_test.go new file mode 100644 index 0000000..2abbda7 --- /dev/null +++ b/y2023/d02/fabienz/solution_test.go @@ -0,0 +1,58 @@ +package fabienz + +import ( + "log" + "os" + "testing" + + "github.com/fabienzucchet/adventofcode/helpers" +) + +func ExamplePartOne() { + file, err := os.Open("testdata/input.txt") + if err != nil { + log.Fatalf("could not open input file: %v", err) + } + defer file.Close() + + if err := PartOne(file, os.Stdout); err != nil { + log.Fatalf("could not solve: %v", err) + } + // Output: 2237 +} + +func ExamplePartTwo() { + file, err := os.Open("testdata/input.txt") + if err != nil { + log.Fatalf("could open input file: %v", err) + } + defer file.Close() + + if err := PartTwo(file, os.Stdout); err != nil { + log.Fatalf("could not solve: %v", err) + } + // Output: 66681 +} + +func Benchmark(b *testing.B) { + testCases := map[string]struct { + solution helpers.Solution + inputFile string + }{ + "PartOne": { + solution: helpers.SolutionFunc(PartOne), + inputFile: "testdata/input.txt", + }, + + "PartTwo": { + solution: helpers.SolutionFunc(PartTwo), + inputFile: "testdata/input.txt", + }, + } + + for name, test := range testCases { + b.Run(name, func(b *testing.B) { + helpers.BenchmarkSolution(b, test.solution, test.inputFile) + }) + } +} diff --git a/y2023/d02/fabienz/testdata/input.txt b/y2023/d02/fabienz/testdata/input.txt new file mode 100644 index 0000000..e9e3f0f --- /dev/null +++ b/y2023/d02/fabienz/testdata/input.txt @@ -0,0 +1,100 @@ +Game 1: 4 red, 1 green, 15 blue; 6 green, 2 red, 10 blue; 7 blue, 6 green, 4 red; 12 blue, 10 green, 3 red +Game 2: 3 green, 18 blue; 14 green, 4 red, 2 blue; 3 red, 14 green, 15 blue +Game 3: 12 green, 2 blue; 9 green; 1 red, 11 blue, 4 green +Game 4: 4 blue, 8 green, 5 red; 6 red, 7 blue, 9 green; 2 green, 2 red, 2 blue; 2 green, 6 blue, 9 red; 10 red, 9 green +Game 5: 12 red, 1 green, 7 blue; 13 red, 16 blue; 16 blue, 10 red; 4 blue; 16 blue, 7 red; 1 blue, 7 red +Game 6: 17 blue, 2 red; 5 blue, 6 green, 2 red; 5 green, 5 blue; 5 green, 12 blue, 4 red +Game 7: 2 red, 1 blue, 10 green; 8 red, 14 green, 9 blue; 15 red, 1 blue, 6 green; 9 blue, 3 green, 10 red; 7 blue, 13 red, 4 green +Game 8: 1 green, 2 blue; 7 red, 2 blue, 1 green; 1 red, 2 green; 4 red, 1 blue; 11 red, 2 green, 2 blue; 1 blue, 2 green, 11 red +Game 9: 11 green, 11 blue, 6 red; 2 green, 3 blue, 2 red; 2 red, 11 blue, 14 green; 5 green, 7 red, 7 blue; 7 green, 1 red, 12 blue; 1 red, 8 green, 7 blue +Game 10: 2 red, 8 green, 7 blue; 10 red, 5 green, 2 blue; 4 red, 8 green, 16 blue; 10 blue, 3 green, 15 red +Game 11: 2 blue, 2 green, 5 red; 1 green, 3 red, 3 blue; 11 green, 1 red, 2 blue +Game 12: 8 blue, 11 green, 14 red; 10 green, 13 red, 2 blue; 1 red, 6 green, 4 blue; 13 red, 11 green, 6 blue +Game 13: 15 red, 17 green, 1 blue; 12 red, 1 blue, 1 green; 2 red, 1 blue, 14 green +Game 14: 6 green, 11 red, 3 blue; 6 green, 2 blue; 2 green, 10 red, 8 blue; 2 red; 1 green, 9 red; 3 blue, 1 green, 3 red +Game 15: 11 blue, 11 green, 4 red; 3 green, 10 blue; 2 red, 9 green, 9 blue +Game 16: 2 blue, 11 green; 1 red, 1 blue, 11 green; 12 green, 1 blue, 1 red; 3 blue, 14 green, 1 red; 14 green, 4 blue; 2 blue, 12 green +Game 17: 1 red, 2 blue, 4 green; 4 blue, 3 green; 1 green, 1 red, 6 blue; 1 red, 7 blue; 2 green +Game 18: 3 red, 3 blue, 7 green; 2 blue, 2 red, 2 green; 4 red, 12 green; 5 green, 2 blue, 4 red; 3 red +Game 19: 15 red, 7 blue, 10 green; 5 green, 8 red; 9 green, 8 red; 5 red, 10 green +Game 20: 15 blue, 6 green, 11 red; 13 red, 9 blue, 1 green; 15 blue, 10 red, 11 green +Game 21: 15 red, 4 green; 11 red, 2 blue, 4 green; 5 blue, 2 green, 4 red; 4 red, 5 blue; 6 red, 3 blue, 1 green +Game 22: 4 green, 4 red, 13 blue; 3 red, 7 blue, 9 green; 12 blue, 13 green, 5 red +Game 23: 20 green, 4 red; 6 blue, 9 red, 7 green; 6 green +Game 24: 1 green, 3 blue, 6 red; 1 green, 1 blue, 2 red; 3 blue, 5 red, 1 green +Game 25: 2 red, 9 blue, 2 green; 2 green, 1 red, 5 blue; 3 red, 1 green, 3 blue; 8 blue, 2 green, 3 red; 12 blue, 3 red; 1 blue, 2 green, 1 red +Game 26: 2 blue, 5 green, 20 red; 2 blue, 6 red, 9 green; 3 red, 2 blue, 5 green +Game 27: 17 blue, 2 red, 14 green; 15 green, 16 blue, 2 red; 13 blue, 13 green; 1 red, 7 green, 3 blue; 1 blue, 2 green +Game 28: 5 blue, 6 red, 3 green; 7 red, 19 green; 11 blue, 13 green +Game 29: 1 blue, 8 red, 7 green; 1 green, 1 red; 8 red, 7 green, 1 blue; 7 green, 2 red; 1 blue, 7 red; 1 blue, 2 red, 5 green +Game 30: 3 red, 17 blue; 11 red, 3 blue, 8 green; 7 green, 12 blue, 10 red; 5 blue, 2 green +Game 31: 14 blue, 7 green; 12 green, 14 blue, 2 red; 17 blue, 2 red, 8 green; 2 red, 3 blue, 11 green; 9 green, 4 blue; 1 red, 3 green, 1 blue +Game 32: 15 red, 1 blue, 10 green; 15 green, 10 red, 1 blue; 2 red, 6 green, 1 blue +Game 33: 10 green, 1 red, 16 blue; 11 blue, 14 green, 3 red; 14 green, 13 blue; 17 blue, 2 red, 3 green +Game 34: 8 red, 7 blue, 8 green; 3 green, 1 red; 1 red, 1 green, 5 blue; 6 red, 8 green, 2 blue; 7 red, 8 blue, 3 green +Game 35: 5 blue, 19 red; 2 blue, 11 red, 1 green; 16 red, 10 blue; 7 green, 3 blue, 6 red; 3 green, 18 red, 5 blue; 8 blue, 5 red +Game 36: 9 red, 6 green, 10 blue; 9 red, 15 green, 6 blue; 6 red, 1 blue, 14 green +Game 37: 7 green, 8 red, 2 blue; 3 blue, 5 red, 16 green; 1 green, 1 red, 3 blue +Game 38: 5 green, 5 red, 3 blue; 10 blue, 19 red, 9 green; 2 red, 3 blue, 11 green +Game 39: 15 red, 11 blue, 5 green; 11 green, 2 red, 6 blue; 2 blue, 3 green, 6 red; 15 red, 3 blue, 13 green +Game 40: 7 green, 4 red, 1 blue; 6 blue, 6 green, 2 red; 2 blue, 3 red, 1 green; 1 blue, 3 red, 3 green; 2 red, 5 green, 3 blue +Game 41: 10 blue, 8 green, 9 red; 7 blue, 9 red, 2 green; 10 blue, 4 red, 5 green +Game 42: 8 blue, 13 green, 14 red; 8 blue, 1 green, 11 red; 4 red, 6 green, 3 blue; 14 green, 4 red, 2 blue +Game 43: 2 red, 10 green, 19 blue; 5 blue, 4 green, 9 red; 9 green, 9 red, 2 blue +Game 44: 6 red, 2 green, 3 blue; 2 blue, 12 red, 6 green; 1 red, 10 blue; 12 red, 6 green, 2 blue; 14 red, 13 green, 3 blue; 10 green, 9 blue, 11 red +Game 45: 2 blue, 1 red, 1 green; 1 green, 1 blue; 2 green, 2 blue +Game 46: 7 green, 1 red; 1 green, 4 blue, 1 red; 3 blue, 4 green, 1 red; 1 red, 4 green; 1 blue, 12 green, 1 red; 16 green, 1 blue +Game 47: 4 blue, 8 green, 3 red; 6 red, 1 green, 3 blue; 16 green, 4 blue, 1 red; 4 blue, 8 red +Game 48: 1 blue, 9 red, 8 green; 8 green, 2 blue, 6 red; 2 green; 4 blue, 5 red; 1 blue, 9 red, 9 green; 1 red, 1 blue, 3 green +Game 49: 3 green, 2 blue; 7 blue, 4 red; 20 green, 5 red, 13 blue; 20 green, 1 red, 6 blue +Game 50: 3 red, 3 green; 3 green, 3 red; 2 blue, 10 red; 3 blue, 5 green; 14 red, 2 green, 2 blue; 7 red, 2 green +Game 51: 3 green, 3 blue, 2 red; 4 green, 16 red, 3 blue; 1 blue, 3 red; 9 red, 1 blue, 4 green +Game 52: 6 red, 18 green, 7 blue; 2 blue, 1 red, 5 green; 8 blue, 6 red, 1 green; 1 red, 1 blue; 6 red, 3 green, 10 blue +Game 53: 1 blue, 10 red, 3 green; 13 red, 2 green, 1 blue; 1 green, 2 red +Game 54: 4 blue, 6 green, 2 red; 5 blue, 6 red, 2 green; 6 blue, 4 green, 8 red; 13 red, 10 blue, 1 green; 5 red, 5 green, 9 blue +Game 55: 4 green, 18 red, 4 blue; 9 blue, 7 green, 16 red; 5 red, 6 blue, 14 green; 13 green, 11 red, 9 blue; 6 blue, 13 green, 1 red; 10 blue, 12 red, 14 green +Game 56: 8 green, 5 blue, 10 red; 10 green, 7 red, 12 blue; 11 red, 12 blue, 1 green; 4 blue, 6 red, 10 green; 17 blue, 8 green, 2 red +Game 57: 1 green, 2 red; 2 green, 5 red, 1 blue; 13 red, 3 green, 4 blue; 3 blue, 13 red, 9 green +Game 58: 1 red, 7 blue, 4 green; 2 green, 1 blue, 1 red; 1 green, 11 blue; 12 blue; 1 blue, 5 green, 1 red; 3 green, 11 blue, 1 red +Game 59: 5 green, 3 blue, 17 red; 2 red, 9 green; 1 blue, 4 green +Game 60: 5 red, 5 green, 1 blue; 2 red, 2 blue, 6 green; 2 red, 3 blue, 3 green +Game 61: 2 green, 3 blue, 4 red; 17 green, 1 blue; 1 green, 6 red, 4 blue; 3 blue, 9 green, 3 red; 18 green, 7 red, 2 blue +Game 62: 5 red; 3 blue, 9 green; 3 red, 13 blue, 10 green; 14 green, 1 red, 2 blue; 7 blue, 13 green +Game 63: 12 blue, 5 green; 5 green, 1 red, 1 blue; 4 red, 7 green, 9 blue; 8 blue, 2 green, 7 red +Game 64: 3 blue, 11 green; 5 blue, 2 red, 5 green; 17 green, 5 blue, 1 red; 4 red, 3 blue, 4 green +Game 65: 2 red, 1 blue, 2 green; 7 green, 2 red, 1 blue; 2 blue, 7 green, 1 red; 3 blue, 8 green, 3 red +Game 66: 4 red, 12 blue, 1 green; 20 blue, 3 green, 2 red; 11 blue, 1 green +Game 67: 12 blue, 10 red, 13 green; 19 green, 4 red, 7 blue; 12 red, 9 blue, 13 green +Game 68: 2 blue, 17 green; 12 green, 2 red; 5 red, 2 green, 4 blue; 4 blue +Game 69: 17 blue, 3 red, 1 green; 4 green, 8 blue, 8 red; 4 green, 7 red, 1 blue; 8 red, 1 green, 11 blue; 13 blue, 10 red, 9 green; 14 blue, 5 green, 6 red +Game 70: 1 red, 2 blue, 4 green; 13 blue, 3 red, 2 green; 6 green, 8 blue +Game 71: 5 red, 7 green, 1 blue; 11 green, 4 red, 1 blue; 1 red, 12 green, 10 blue; 1 red, 7 blue, 12 green +Game 72: 9 blue, 4 green, 1 red; 6 green, 4 blue; 8 green, 5 blue, 1 red +Game 73: 1 blue, 10 green, 14 red; 4 green; 2 blue, 9 red, 4 green; 2 blue, 13 green; 13 green, 13 red; 7 red, 5 green, 2 blue +Game 74: 3 red, 1 blue, 3 green; 4 green, 1 blue, 1 red; 2 blue, 10 green, 1 red; 1 blue, 3 red, 1 green +Game 75: 1 red, 1 blue, 1 green; 2 red, 1 green, 4 blue; 2 red, 4 blue; 1 blue, 1 red +Game 76: 4 green, 2 blue, 6 red; 7 green, 1 red; 8 green, 4 red +Game 77: 8 green, 7 blue, 5 red; 6 red, 14 green, 7 blue; 8 green, 7 blue; 1 red, 8 green, 8 blue +Game 78: 6 red, 3 blue, 3 green; 7 blue, 10 red; 5 green, 10 blue, 1 red; 3 green, 11 blue, 4 red; 14 red, 9 blue, 2 green; 16 red, 2 green, 12 blue +Game 79: 1 green; 5 green; 11 green, 3 blue, 2 red; 3 blue +Game 80: 2 green, 2 red; 1 blue, 1 green, 1 red; 1 blue, 1 green, 2 red; 2 red; 5 green +Game 81: 10 blue, 2 red, 9 green; 4 red, 12 blue, 5 green; 7 green, 4 blue, 6 red; 1 red, 13 green, 14 blue; 13 green, 11 blue +Game 82: 4 blue, 2 green; 7 blue, 3 green, 5 red; 1 red, 4 blue, 3 green; 5 blue, 1 red, 6 green; 6 green, 4 red; 11 blue, 3 red, 5 green +Game 83: 12 green; 5 red, 8 green; 11 red, 14 green, 1 blue; 9 green, 4 red +Game 84: 5 blue, 1 red; 16 blue, 5 green; 1 red, 9 blue, 3 green; 11 blue; 1 green, 2 blue; 1 red, 7 blue, 4 green +Game 85: 17 red, 5 blue; 18 blue, 2 red, 2 green; 18 blue, 2 green, 8 red +Game 86: 4 red, 1 blue, 11 green; 6 blue, 7 green, 1 red; 3 green, 4 blue; 2 red, 7 blue, 2 green +Game 87: 4 red, 5 blue; 1 green, 15 red, 1 blue; 11 blue, 12 red +Game 88: 11 green, 3 red, 1 blue; 6 green, 1 blue, 1 red; 1 blue, 3 green; 2 blue, 4 green, 2 red +Game 89: 2 green; 1 red, 2 green, 3 blue; 4 blue, 1 red, 10 green; 4 blue, 5 green; 6 blue, 1 red, 10 green +Game 90: 15 red, 7 green, 17 blue; 7 blue, 1 red; 7 green, 6 red, 3 blue +Game 91: 2 blue, 17 red, 6 green; 1 green, 1 blue, 6 red; 6 red, 4 blue; 10 green, 14 red, 1 blue; 7 blue, 10 green, 10 red; 16 red, 11 green, 9 blue +Game 92: 1 green, 8 blue, 4 red; 4 green, 4 red, 4 blue; 1 green, 7 red, 4 blue +Game 93: 11 blue, 12 red, 1 green; 9 blue, 2 green, 5 red; 7 red, 5 blue, 2 green +Game 94: 7 blue, 10 green; 9 green, 9 blue, 2 red; 1 red, 5 green, 4 blue +Game 95: 1 green, 1 blue, 2 red; 6 red; 1 blue; 1 green, 1 blue, 6 red +Game 96: 1 blue, 1 red, 2 green; 4 red, 13 green, 1 blue; 1 blue, 13 green, 5 red; 7 green, 4 red +Game 97: 10 blue, 5 red, 5 green; 4 red, 8 green, 2 blue; 5 red, 2 green, 15 blue; 2 red, 1 green, 4 blue; 2 red, 14 blue; 14 blue, 4 green +Game 98: 11 red, 8 green, 9 blue; 3 blue, 1 green, 14 red; 10 blue, 2 red, 4 green; 7 blue, 11 red, 3 green; 5 red, 12 blue, 4 green; 7 green, 7 blue, 8 red +Game 99: 3 green, 2 blue, 1 red; 15 red, 8 blue, 7 green; 18 red, 12 blue, 2 green +Game 100: 11 red, 1 blue, 2 green; 3 red, 3 green; 1 blue, 8 red, 4 green; 5 green, 5 blue, 1 red; 2 green, 1 red, 6 blue; 2 green, 8 red, 1 blue From 4903da9c129350e04d1e585271d8cf478fa54ca8 Mon Sep 17 00:00:00 2001 From: Fabien Zucchet Date: Sun, 10 Dec 2023 14:24:27 +0000 Subject: [PATCH 3/6] feat(y2023): add solution for d03 --- y2023/d03/fabienz/solution.go | 308 +++++++++++++++++++++++++++ y2023/d03/fabienz/solution_test.go | 58 +++++ y2023/d03/fabienz/testdata/input.txt | 140 ++++++++++++ 3 files changed, 506 insertions(+) create mode 100644 y2023/d03/fabienz/solution.go create mode 100644 y2023/d03/fabienz/solution_test.go create mode 100644 y2023/d03/fabienz/testdata/input.txt diff --git a/y2023/d03/fabienz/solution.go b/y2023/d03/fabienz/solution.go new file mode 100644 index 0000000..77a98b3 --- /dev/null +++ b/y2023/d03/fabienz/solution.go @@ -0,0 +1,308 @@ +package fabienz + +import ( + "fmt" + "io" + "strconv" + "strings" + + "github.com/fabienzucchet/adventofcode/helpers" +) + +// PartOne solves the first problem of day 3 of Advent of Code 2023. +func PartOne(input io.Reader, answer io.Writer) error { + // Read the input. Feel free to change it depending on the input. + lines, err := helpers.LinesFromReader(input) + if err != nil { + return fmt.Errorf("could not read input: %w", err) + } + + s, err := schematicFromInput(lines) + if err != nil { + return fmt.Errorf("could not create schematic: %w", err) + } + + s.UpdateParts() + + sum := 0 + for _, p := range s.parts { + sum += p.partNumber + } + + _, err = fmt.Fprintf(answer, "%d", sum) + if err != nil { + return fmt.Errorf("could not write answer: %w", err) + } + + return nil +} + +// PartTwo solves the second problem of day 3 of Advent of Code 2023. +func PartTwo(input io.Reader, answer io.Writer) error { + // Read the input. Feel free to change it depending on the input. + lines, err := helpers.LinesFromReader(input) + if err != nil { + return fmt.Errorf("could not read input: %w", err) + } + + s, err := schematicFromInput(lines) + if err != nil { + return fmt.Errorf("could not create schematic: %w", err) + } + + s.UpdateParts() + s.UpdateGears() + + sum := 0 + for _, g := range s.gears { + sum += g.gearRadius + } + + _, err = fmt.Fprintf(answer, "%d", sum) + if err != nil { + return fmt.Errorf("could not write answer: %w", err) + } + + return nil +} + +type Schematic struct { + elements []*SchematicElement + visualRepresentation [][]rune + parts []*SchematicElement + gears []*SchematicElement +} + +type SchematicElement struct { + coordinates [2]int + length int + value string + + isSymbol bool + partNumber int + gearRadius int +} + +func (s *Schematic) AddElement(e *SchematicElement) { + s.elements = append(s.elements, e) +} + +func (s *Schematic) String() string { + var sb strings.Builder + + for _, line := range s.visualRepresentation { + for _, c := range line { + sb.WriteRune(c) + } + sb.WriteRune('\n') + } + + return sb.String() +} + +func (e *SchematicElement) String() string { + return fmt.Sprintf("%s (length: %d) @ (%d,%d)", e.value, e.length, e.coordinates[0], e.coordinates[1]) +} + +func (s *Schematic) UpdateParts() { + parts := []*SchematicElement{} + for _, e := range s.elements { + if !e.isSymbol && s.isPart(e) { + e.partNumber = e.getPartNumber() + parts = append(parts, e) + } + } + + s.parts = parts +} + +func (e *SchematicElement) getPartNumber() int { + v, err := strconv.Atoi(e.value) + if err != nil { + panic(err) + } + return v +} + +func (s *Schematic) UpdateGears() { + gears := []*SchematicElement{} + for _, e := range s.elements { + if e.isSymbol && s.isGear(e) { + gears = append(gears, e) + } + } + + s.gears = gears +} + +func schematicFromInput(lines []string) (*Schematic, error) { + s := &Schematic{} + + // Initialize the visual representation of the schematic + s.visualRepresentation = make([][]rune, len(lines)) + for x, line := range lines { + s.visualRepresentation[x] = make([]rune, len(line)) + for y, c := range line { + s.visualRepresentation[x][y] = c + } + } + + // Extract the elements from the input + for x, line := range lines { + i := 0 + + for i < len(line) { + switch { + case line[i] >= '0' && line[i] <= '9': + // Extract the length + length := 1 + for i+length < len(line) && line[i+length] >= '0' && line[i+length] <= '9' { + length++ + } + + s.AddElement(&SchematicElement{ + coordinates: [2]int{x, i}, + length: length, + value: line[i : i+length], + }) + + i += length + case line[i] == '.': + i++ + default: + s.AddElement(&SchematicElement{ + coordinates: [2]int{x, i}, + length: 1, + value: line[i : i+1], + isSymbol: true, + }) + i++ + } + } + } + + return s, nil +} + +func (s *Schematic) isPart(e *SchematicElement) bool { + // Check if an element is adjacent to a symbol + neighbours := [][2]int{} + + // Check the element above + if e.coordinates[0] > 0 { + for i := 0; i < e.length; i++ { + neighbours = append(neighbours, [2]int{e.coordinates[0] - 1, e.coordinates[1] + i}) + } + } + + // Check the element below + if e.coordinates[0] < len(s.visualRepresentation)-1 { + for i := 0; i < e.length; i++ { + neighbours = append(neighbours, [2]int{e.coordinates[0] + 1, e.coordinates[1] + i}) + } + } + + // Check the element to the left + if e.coordinates[1] > 0 { + neighbours = append(neighbours, [2]int{e.coordinates[0], e.coordinates[1] - 1}) + } + + // Check the element to the right + if e.coordinates[1]+e.length < len(s.visualRepresentation[0])-1 { + neighbours = append(neighbours, [2]int{e.coordinates[0], e.coordinates[1] + e.length}) + } + + // Check the diagonal elements + if e.coordinates[0] > 0 && e.coordinates[1] > 0 { + neighbours = append(neighbours, [2]int{e.coordinates[0] - 1, e.coordinates[1] - 1}) + } + if e.coordinates[0] > 0 && e.coordinates[1]+e.length < len(s.visualRepresentation[0])-1 { + neighbours = append(neighbours, [2]int{e.coordinates[0] - 1, e.coordinates[1] + e.length}) + } + if e.coordinates[0] < len(s.visualRepresentation)-1 && e.coordinates[1] > 0 { + neighbours = append(neighbours, [2]int{e.coordinates[0] + 1, e.coordinates[1] - 1}) + } + if e.coordinates[0] < len(s.visualRepresentation)-1 && e.coordinates[1]+e.length < len(s.visualRepresentation[0])-1 { + neighbours = append(neighbours, [2]int{e.coordinates[0] + 1, e.coordinates[1] + e.length}) + } + + for _, n := range neighbours { + if s.visualRepresentation[n[0]][n[1]] != '.' && !isDigit(s.visualRepresentation[n[0]][n[1]]) { + return true + } + } + + return false +} + +func isDigit(c rune) bool { + return c >= '0' && c <= '9' +} + +func (s *Schematic) isGear(e *SchematicElement) bool { + adjacentParts := []*SchematicElement{} + for _, p := range s.parts { + if s.areAdjacent(p, e) { + adjacentParts = append(adjacentParts, p) + } + } + + if len(adjacentParts) == 2 { + e.gearRadius = adjacentParts[0].partNumber * adjacentParts[1].partNumber + + return true + } + + return false +} + +func (s *Schematic) areAdjacent(p *SchematicElement, e *SchematicElement) bool { + // Check if an element is adjacent to a symbol + neighbours := [][2]int{} + + // Check the element above + if p.coordinates[0] > 0 { + for i := 0; i < p.length; i++ { + neighbours = append(neighbours, [2]int{p.coordinates[0] - 1, p.coordinates[1] + i}) + } + } + + // Check the element below + if p.coordinates[0] < len(s.visualRepresentation)-1 { + for i := 0; i < p.length; i++ { + neighbours = append(neighbours, [2]int{p.coordinates[0] + 1, p.coordinates[1] + i}) + } + } + + // Check the element to the left + if p.coordinates[1] > 0 { + neighbours = append(neighbours, [2]int{p.coordinates[0], p.coordinates[1] - 1}) + } + + // Check the element to the right + if p.coordinates[1]+p.length < len(s.visualRepresentation[0])-1 { + neighbours = append(neighbours, [2]int{p.coordinates[0], p.coordinates[1] + p.length}) + } + + // Check the diagonal elements + if p.coordinates[0] > 0 && p.coordinates[1] > 0 { + neighbours = append(neighbours, [2]int{p.coordinates[0] - 1, p.coordinates[1] - 1}) + } + if p.coordinates[0] > 0 && p.coordinates[1]+p.length < len(s.visualRepresentation[0])-1 { + neighbours = append(neighbours, [2]int{p.coordinates[0] - 1, p.coordinates[1] + p.length}) + } + if p.coordinates[0] < len(s.visualRepresentation)-1 && p.coordinates[1] > 0 { + neighbours = append(neighbours, [2]int{p.coordinates[0] + 1, p.coordinates[1] - 1}) + } + if p.coordinates[0] < len(s.visualRepresentation)-1 && p.coordinates[1]+p.length < len(s.visualRepresentation[0])-1 { + neighbours = append(neighbours, [2]int{p.coordinates[0] + 1, p.coordinates[1] + p.length}) + } + + for _, n := range neighbours { + if n == e.coordinates { + return true + } + } + + return false +} diff --git a/y2023/d03/fabienz/solution_test.go b/y2023/d03/fabienz/solution_test.go new file mode 100644 index 0000000..34d1f69 --- /dev/null +++ b/y2023/d03/fabienz/solution_test.go @@ -0,0 +1,58 @@ +package fabienz + +import ( + "log" + "os" + "testing" + + "github.com/fabienzucchet/adventofcode/helpers" +) + +func ExamplePartOne() { + file, err := os.Open("testdata/input.txt") + if err != nil { + log.Fatalf("could not open input file: %v", err) + } + defer file.Close() + + if err := PartOne(file, os.Stdout); err != nil { + log.Fatalf("could not solve: %v", err) + } + // Output: 512794 +} + +func ExamplePartTwo() { + file, err := os.Open("testdata/input.txt") + if err != nil { + log.Fatalf("could open input file: %v", err) + } + defer file.Close() + + if err := PartTwo(file, os.Stdout); err != nil { + log.Fatalf("could not solve: %v", err) + } + // Output: 67779080 +} + +func Benchmark(b *testing.B) { + testCases := map[string]struct { + solution helpers.Solution + inputFile string + }{ + "PartOne": { + solution: helpers.SolutionFunc(PartOne), + inputFile: "testdata/input.txt", + }, + + "PartTwo": { + solution: helpers.SolutionFunc(PartTwo), + inputFile: "testdata/input.txt", + }, + } + + for name, test := range testCases { + b.Run(name, func(b *testing.B) { + helpers.BenchmarkSolution(b, test.solution, test.inputFile) + }) + } +} diff --git a/y2023/d03/fabienz/testdata/input.txt b/y2023/d03/fabienz/testdata/input.txt new file mode 100644 index 0000000..c109ae2 --- /dev/null +++ b/y2023/d03/fabienz/testdata/input.txt @@ -0,0 +1,140 @@ +...........441.................367................296........................................567..47.....45.................947............. +...606..........888.....................508..........*892................+..=138.381..967...............*....%......926...........218....... +....*......116..*..............747............-....................777..460..........*.......549......127...595.......*..290........*.968... +..902..........425................+..........730..........#...........*.....196.............-.......................512.*....@...994..%..... +..........................924.....................%...*...139..............*............/......458......................10..155............. +...318.......825.......+.....*201................793.143.......522.%...568.....&.........558....*.......583....792.......................... +....*................971............448....653..............79..@..792....*.105....115.........200.....+.........*.............*........380. +.850....269................775*........*......@.......%................921........#........................812....793....22.460.305......... +..........&..414@...824........129.....816......*..560...421......955/................141......336........*................................. +.........................59....................201......$...............@651.........*...........+..937...732...549-....284....544.......... +...........................*..178.125*808....................919..............246....400.53......................................$.+........ +.....=.....964.238..116.722.....*............624..............*...........209...............312....670.....953.....#....265.710.....414..... +...966.152*.........*........375....*........*.........663....639............................&....*.........*.....424......*....%........... +..................-..68.206......812.601......874..651...+..........857*686.........*.....33......825......497...............402............ +862*766......@...545.......*4............706.....................................887.395....=.731......47.........................942.949... +..........900..........390........5-........*345.....................724.......%..........................+........778..761........%........ +..............887..985...*.......................141...................$.......64......&...334.278..896...572.....*.....*.....804........... +......184....*..........596...$.....................*.-764....494....$....54............35....*................900...750..$.....*........... +.....#.....322......979.....447............542.61..52.................880..........................*718............-.......926..659......... +.......91.......793....*.@.............215*............@.........585......+....126..............102.......207..&....762.............&703.... +.....................751..87..$........................117.......*.......778...*.....363...=157......351.....*..577......................... +..483=...374*823.............512...835.551.....333..........978........#.......954.....*.............*.....140..........634.....357......473 +......................................*.........#...223.....*.........79...............275..........24..........310............+....390=.... +755.255.#....751....#...342....51..........507.....*.....764....220..........909../.............................../......................... +.....&...320..=..293.....*.....@......204.....*.956.............*......485....#...866..765..973..668......476.............772.....463.479... +..........................53.............*.............+410...667.-103..&..%...................*....*......*..995#.........-..75.......*.... +.......289.......995..............33...714.......366........................556.......518......95.....................836.....*......699.... +......./............/...31.........................&...............&....................*...........220.814............$....658............. +.....=...10...............*.....+852.....%98...........838......652..........11.125..488......799...*.....*................................. +...470......102......889.250..................209..118..#...........729........*..................159..799..417.140....762......588.629..... +........@...*...844....*........900...507....*......#...............=......*...........878.....................*......*.....539*............ +...756.769.426..*......94.........#......*....997...........#793........115.685..........*.....973.869.................12............596.... +.....=..........2......................698........416...$.........302...............530...315...@...@.......-.....605.........542.....*..... +.711....373........................358...............&..820..........*......#243...=........................148...../...$........*...581.... +...........$...727.......314...57..*.............*..................762......................524..346$...................581.....120........ +......=568..........@844.&.....*...257.485......593.....*................................30..*.........740.....709*......................... +................................75......*............194.675.420*282.....967..552.............850..................789..=.....-........223.. +..910.....$.............562..=..........56..............................-....*......194..................................425...789.....*.... +...-......618.716#...........233.............................828...........301......................190....#120....................360.232.. +.......................587..........766.812............178...-........929...................../.......*...........707.949....465..$......... +..........191...=....................-...................................*378............766..456......605...............*....*........593.. +.481...#.%......267.....729.................619......116*164....................505....+....*.....531...................498...47...789*..... +.....625............579*.......914.997=.....*...............................456*....632..133......*......751...%..631....................... +..........=415.481.........979.............318.......=.............942.855...................512...985..*....865./.......................... +.................*...........@..................436-..542.........*.....*..$631........108.....%........619........194..............825..329 +..333.............624......................=.................795-..818.431.......702...*..............................=........+....%....... +.../......................312.....666.......785.198......719....................&.......837........838..551.175..........368....557......... +.....581.........986......*........+................268.....*...445............................*..*.......-...*.......99*...............=... +.................@....793..............868......935....*..415.....*.430....253....@...........678..............420............%.46#..679.... +........................*....70*239......*............824.......499....*...*...965...696..532............405.........90....306.............. +.........................34...........152...216$.381.................373..22......../........*.............&...........-.........976........ +.................132.........448....................$.............*..........585.............321...............+...66....741.......*........ +.......194........&..669.......*................*..............460.465.54.......+........763.......738......444..........*....791..776...... +...978.....839......*........808...669.......864.30...................../...........439..*......*.....*...........441.....278...=........... +.......971*.....*.....................*......................................43....*....778..329.711.136.................................... +............792.182..21............81..545...398&...........................*.....763....................181............*506....736..141.933 +........282*..........*......=............................41*982......237..166.............678..718=.656..*...........87.........*.......... +...................684........5......220*697.......259............347....*.............*.....*.........*.832.............388.....192........ +..395........=............838......................+.....693....#.....784...469*334.....870.464......572........875.....*...............152. +......362.....693.........+...859......183..479...........*......969.......................................811..&....171.........284...=.... +.....*.............../...................*.........606..187..........644..........401.=984...98....760....*..............54................. +...505.............806....249..........327....821.....@.................*....211..*.........*........*.422.................*......*902.863.. +............................*...................*..........219..........571....*...284...272......477.........938.....312...981..7.......... +.688...=....................544...766...........346..........................923.............................*........+............923...... +......779..=281...419..............+.................308....51...................836.........537../....931....97.........................952 +..................*......312...834.....................*........../.............*....83.262....*...748...............873.....46.4........... +......355.......728.........*....%....................56..........752..296-....386.....*......53...........................-...*........@... +....-.................483/..192.........714*248.................-.........................621.........*............926.....244.........867.. +...878...........#641...........................832.72.........877.......=..793............@........676.696.........*....................... +.............853.............&614.......#699......*.......*29..........900.....*718..%369....#.$919........$....*....791.381......624....... +................*255..........................758.604...........985.......................811................955.745.......*................ +...........9............276.393.76............$.............952......................947............385...*.............620....875.......... +...........*..755...210...#..*..*................/............/.........774..=............315..........$.750...........................@.381 +........975..*...../........168..472.....662.....308..............996........685..................77.........424..188...............639..... +..............173.........#..............*...........740.............*372...........................*...............*....................... +........................991.........*769..651.36.+12...*......861&............897.....749..859....271...96..........248.667................. +.............%..............518..624...........*.......475.........183*.......%...............*...........-.....658.......*..+.............. +.29..........25...688..346.....*.........720.29....162.................502....................414...616........*........52..698..........453 +........286%.........-....*....359.........*......*........................881.........634..........+....=.....932..519...........765....... +.................&........280....................282..209...519...........................*............970...........*.....@.....&.....*.... +.....448...216..204.190........108*868...*408......../.......*..=............824.........344..................29.....254..139.......811.656. +.310..................*................................$..449....159...731.....*...154................107.......*279........................ +...*...194...........307.817.........................314....................208.....*................*.......+.......................871*... +254...@............$.......@..#17..............284.........757......................921..#479..933.414....308......@154............*.....222 +..................817.................555.389....*............@.151...........................&................143..............348.448..... +....20......321..........303............*.....873.....%..899...................226*.....*830.....................=........@................. +....@....*...*......698...*.............363........189......*...192.&................890...............@814...............830......300..48.. +.......907..207.......*...284.......24+....................346.+....867.....808..43......397....363................254.........178......*... +.................$................$............772...............+..........-...........*.......-...............#...%..................246.. +......332....855.250..........*....692.....968...............212..297...........223.....725.............419.....213...316.822............... +..290....&..*.........108.....577....................133.87...=..............$...+.............&.........................*..............917. +.......@.....701.......*..476....................806../..*.........216.5+.834......174..........597...............617......222.............. +...-...618.........992.47...*............497.............428.....@.*..............*.........276........521.../.......*......*........234.... +.465...............%........438.%627.727......................949...258.....927....365........*.....%..@...93.......186..535..........-..... +...........557..........................*66......456.....+........*........+............539..95..790............220..........$...........95. +117..........*.......869...........................@..943..133.249.364..............806*................=...342...*.......817....667........ +.............490.641*...........273.786..507.................@...............244......................71....*......717...........*.......871 +...236.70...............$.........*.*....%....................................*..386=...503..................778.=.........419...7.......... +.......*....$905..660...287....654..634........934.............344..........322............*............702......745..........*............. +........950.........*............................#..906..118..*.....553.694.....191.....682.........412*.........................801........ +.............186....175...607................330....@.......*..931.*....*......@...............618............14........851&.567*...../..... +............/...........+........156.449.334*....*....888..951.....559...144.........%.................................................16... +....835..................96..751..*...........409.365....*...........................736........................310$......583............... +......$........47...744........*.68.........*..........634..-..589........250..370...........644.....693...13*.............*...&............ +..470.....775...=..+.....&..234..........538.597...$.......391...........................179*.................524.......232..79............. +....*.....=.............72..........................493..............=...............$.............................828...........583.*...... +..207...........312..........867..806......224..123...............616......76.......777./200..232..149.48...716..@...=..........&.....7..... +......48.................277..........755=....*..........735.................*.................@....-...*..*....590..........+......-....... +........*787.....82........*.....208...........359......................766.11.............%..........31...60..............731...928........ +...................@.......265..........333.........................781.@...................991...#............93........................... +.........................................+...........................*..........................848....691.97...*..........539.............. +.507..238.........384......#.......&.....................987......@..395.844*......949*608.460......29...*.*.....955........*.........#734.. +........*./910..........607.........411.................*........102........................=...169...*....74........846..382.533/.......... +.....221........................742.......%...267.491.357...544......+...846.973....................66........440........................... +..............-................/....833.103...$....*..............369........*.......519.....4.........-........*................809.942.... +.833..48..523..281.................&...................................442.958......*....951..-.........856.=..............49...&...../..... +.......*.....*.......275.......259.....$.........-.175...662.697.307................169....*................33.....955.....*......+......68. +...388.......231.994....@.........*.934........889.*.........*.............................668....*878......................353.560.....*... +....@................%.........806..................708...221.......................498.....................79..385...................112... +451.....555&........463.........................%.........................80*494...$.........976..487.......*.....=....801........781....... +...*.99.......766@.........751.........174..760..169....479*368.382..281.............&........*.....*......179........=..........=.......51. +.670..&..565.......577.$......+...=583........-......=............*....=......173#....732....9...221............*979....*....=.............. +...............551..&..235..............204*....@...65.......735..664................................966.918$........247.945..237........... +.....920....42..*............844&.364@......823.801...........*.............&.995...344...688..178............560....................658*680 +.271...#........339.142.................921.................219..748......727.*.....*............@...........*.................131.......... +............./......#......260.....%851...*......................*.............910...535................657..996.%499..625........*......... +....@363......785...........*.............795........31.........213.443....................................*...........+........244.....=806 +.........390.........320...553...84@.................*..........................45....547.........376.......206............................. +54...................*................131..........*..32...............469........=..*.....665......&.........................427......349.. +..................193......894.....*.....*442...589.....................&............124...=.............405.........636......*...#......... +..............................-.950.457.......................................-...................39.875...*.....230*......191..349......... +.../.........863..........334...........90..199........184....................421.....979...666..+....*.....145.......#..................... +...288..............568..#....501........*.....................$.....677.+.............*......*....959..............302..=875..821@.....531. +...................*.........*....625..621.....689........405..247..#.....351..659..162....942............349.304........................... +.......851.........742...&...478.....*.........#....523.........................=................$.......*.........589....758......371...... +...$........745........593...........181...835......*......794....=...502..381@...................973...77..433.....=....&........#......... +.932........*................-.............%..........147........316..*..........%..........................*................323............ +.........283...+......100...486....4.............52..*...............977.......472.*....262................298......=894..........128.93.... +.............953.......*........................*....719....$......................473.....=...523......-.......723..................*...... +....................571.......................720..........269...........885.............................902...........80...738..........975 \ No newline at end of file From 2604e1f7d6201486ead20c1f6782d1283f4ea60a Mon Sep 17 00:00:00 2001 From: Fabien Zucchet Date: Sun, 10 Dec 2023 14:24:35 +0000 Subject: [PATCH 4/6] feat(y2023): add solution for d04 --- y2023/d04/fabienz/solution.go | 154 +++++++++++++++++++++ y2023/d04/fabienz/solution_test.go | 58 ++++++++ y2023/d04/fabienz/testdata/input.txt | 194 +++++++++++++++++++++++++++ 3 files changed, 406 insertions(+) create mode 100644 y2023/d04/fabienz/solution.go create mode 100644 y2023/d04/fabienz/solution_test.go create mode 100644 y2023/d04/fabienz/testdata/input.txt diff --git a/y2023/d04/fabienz/solution.go b/y2023/d04/fabienz/solution.go new file mode 100644 index 0000000..24bc058 --- /dev/null +++ b/y2023/d04/fabienz/solution.go @@ -0,0 +1,154 @@ +package fabienz + +import ( + "fmt" + "io" + "strconv" + "strings" + + "github.com/fabienzucchet/adventofcode/helpers" +) + +// PartOne solves the first problem of day 4 of Advent of Code 2023. +func PartOne(input io.Reader, answer io.Writer) error { + // Read the input. Feel free to change it depending on the input. + lines, err := helpers.LinesFromReader(input) + if err != nil { + return fmt.Errorf("could not read input: %w", err) + } + + totalScore := 0 + + for _, line := range lines { + splitLine := strings.Split(line, ": ") + if len(splitLine) != 2 { + return fmt.Errorf("invalid line: %s", line) + } + + winning, present, err := splitNumbers(splitLine[1]) + if err != nil { + return fmt.Errorf("could not split numbers: %w", err) + } + + totalScore += getScore(winning, present) + } + + _, err = fmt.Fprintf(answer, "%d", totalScore) + if err != nil { + return fmt.Errorf("could not write answer: %w", err) + } + + return nil +} + +// PartTwo solves the second problem of day 4 of Advent of Code 2023. +func PartTwo(input io.Reader, answer io.Writer) error { + // Read the input. Feel free to change it depending on the input. + lines, err := helpers.LinesFromReader(input) + if err != nil { + return fmt.Errorf("could not read input: %w", err) + } + + scratchcardsCount := make(map[int]int) + for i := 0; i < len(lines); i++ { + scratchcardsCount[i] = 1 + } + + for i, line := range lines { + + splitLine := strings.Split(line, ": ") + if len(splitLine) != 2 { + return fmt.Errorf("invalid line: %s", line) + } + + winning, present, err := splitNumbers(splitLine[1]) + if err != nil { + return fmt.Errorf("could not split numbers: %w", err) + } + + matchCount := countMatches(winning, present) + for j := 0; j < matchCount; j++ { + scratchcardsCount[i+j+1] += scratchcardsCount[i] + } + } + + totalCount := 0 + for _, count := range scratchcardsCount { + totalCount += count + } + + _, err = fmt.Fprintf(answer, "%d", totalCount) + if err != nil { + return fmt.Errorf("could not write answer: %w", err) + } + + return nil +} + +func splitNumbers(s string) (winning []int, present []int, err error) { + splitLine := strings.Split(s, " | ") + if len(splitLine) != 2 { + return nil, nil, fmt.Errorf("invalid line: %s", s) + } + + winning, err = parseNumbers(strings.Split(splitLine[0], " ")) + if err != nil { + return nil, nil, fmt.Errorf("could not parse numbers: %w", err) + } + + present, err = parseNumbers(strings.Split(splitLine[1], " ")) + if err != nil { + return nil, nil, fmt.Errorf("could not parse numbers: %w", err) + } + + return winning, present, nil +} + +func parseNumbers(numbersToParse []string) (numbers []int, err error) { + for _, number := range numbersToParse { + if len(number) == 0 { + continue + } + + n, err := strconv.Atoi(number) + if err != nil { + return nil, fmt.Errorf("%q is not an integer", number) + } + + numbers = append(numbers, n) + } + + return numbers, nil +} + +func getScore(winning []int, present []int) (score int) { + matchCount := 0 + + for _, p := range present { + if isInSlice(p, winning) { + matchCount++ + } + } + + return 1 << uint(matchCount-1) +} + +func isInSlice(n int, slice []int) bool { + for _, s := range slice { + if s == n { + return true + } + } + + return false +} + +func countMatches(winning []int, present []int) (matchCount int) { + for _, p := range present { + if isInSlice(p, winning) { + matchCount++ + } + } + + return matchCount +} diff --git a/y2023/d04/fabienz/solution_test.go b/y2023/d04/fabienz/solution_test.go new file mode 100644 index 0000000..079067d --- /dev/null +++ b/y2023/d04/fabienz/solution_test.go @@ -0,0 +1,58 @@ +package fabienz + +import ( + "log" + "os" + "testing" + + "github.com/fabienzucchet/adventofcode/helpers" +) + +func ExamplePartOne() { + file, err := os.Open("testdata/input.txt") + if err != nil { + log.Fatalf("could not open input file: %v", err) + } + defer file.Close() + + if err := PartOne(file, os.Stdout); err != nil { + log.Fatalf("could not solve: %v", err) + } + // Output: 17803 +} + +func ExamplePartTwo() { + file, err := os.Open("testdata/input.txt") + if err != nil { + log.Fatalf("could open input file: %v", err) + } + defer file.Close() + + if err := PartTwo(file, os.Stdout); err != nil { + log.Fatalf("could not solve: %v", err) + } + // Output: 5554894 +} + +func Benchmark(b *testing.B) { + testCases := map[string]struct { + solution helpers.Solution + inputFile string + }{ + "PartOne": { + solution: helpers.SolutionFunc(PartOne), + inputFile: "testdata/input.txt", + }, + + "PartTwo": { + solution: helpers.SolutionFunc(PartTwo), + inputFile: "testdata/input.txt", + }, + } + + for name, test := range testCases { + b.Run(name, func(b *testing.B) { + helpers.BenchmarkSolution(b, test.solution, test.inputFile) + }) + } +} diff --git a/y2023/d04/fabienz/testdata/input.txt b/y2023/d04/fabienz/testdata/input.txt new file mode 100644 index 0000000..1d2f88d --- /dev/null +++ b/y2023/d04/fabienz/testdata/input.txt @@ -0,0 +1,194 @@ +Card 1: 24 12 26 39 19 98 74 16 82 77 | 80 11 51 1 74 60 77 68 42 35 39 78 21 12 29 19 25 98 65 91 33 17 59 24 31 +Card 2: 33 21 96 64 9 38 65 74 16 91 | 14 51 85 1 64 29 74 18 15 38 13 96 16 88 84 21 95 49 9 27 33 63 65 91 90 +Card 3: 31 97 18 93 71 54 24 12 19 87 | 59 96 72 94 4 51 74 84 47 10 57 89 65 37 39 16 31 91 26 85 44 30 24 40 2 +Card 4: 77 20 66 48 23 32 76 9 75 89 | 31 57 89 51 8 34 9 59 39 73 4 32 18 77 94 76 29 23 41 27 66 20 40 48 75 +Card 5: 25 40 65 27 41 7 1 80 26 47 | 7 25 40 1 16 67 42 34 82 19 58 9 91 6 47 80 36 46 77 27 72 41 26 33 81 +Card 6: 92 39 18 64 7 71 48 29 3 38 | 55 29 73 31 15 75 13 71 94 48 78 23 54 7 10 86 34 82 91 85 67 14 57 64 3 +Card 7: 67 43 34 90 14 32 38 49 11 75 | 15 11 38 30 32 29 59 73 72 42 1 4 55 71 57 64 19 90 24 78 31 67 49 98 43 +Card 8: 70 64 82 4 16 6 19 13 9 29 | 21 93 37 69 24 62 60 3 90 83 8 66 20 34 55 22 6 84 99 50 33 26 65 98 86 +Card 9: 31 80 67 81 28 90 23 4 48 86 | 90 80 32 8 15 13 81 63 46 45 50 47 17 96 48 28 57 98 88 86 1 34 4 87 5 +Card 10: 40 46 22 70 59 97 32 20 4 65 | 22 25 59 88 30 82 39 91 4 72 9 42 86 65 96 93 5 84 67 40 57 20 36 8 80 +Card 11: 53 10 4 91 42 12 32 86 38 60 | 3 60 20 65 85 94 58 38 10 76 44 81 51 6 99 19 31 43 84 95 59 36 86 82 11 +Card 12: 73 87 16 92 67 13 28 82 97 86 | 60 45 83 4 90 43 54 55 93 62 7 94 65 72 32 25 23 38 88 61 87 76 35 20 18 +Card 13: 92 13 96 89 25 81 80 72 76 48 | 92 32 31 23 61 74 13 95 71 78 17 1 22 86 62 55 60 41 96 11 77 93 63 99 76 +Card 14: 8 59 91 73 10 61 65 34 29 81 | 9 32 87 78 26 16 90 49 74 61 56 11 57 93 77 62 75 46 36 59 85 3 19 34 28 +Card 15: 87 53 99 88 20 39 28 61 38 68 | 60 16 1 5 10 53 45 56 89 42 80 21 2 37 98 99 74 71 72 59 84 41 87 95 67 +Card 16: 2 19 58 83 91 76 9 63 71 77 | 37 3 59 79 72 53 70 9 43 36 97 98 6 85 90 16 55 11 56 1 8 49 52 15 22 +Card 17: 29 83 12 76 32 82 40 91 84 97 | 21 79 3 31 1 36 85 17 59 30 87 46 27 63 75 56 72 67 11 42 84 62 53 68 38 +Card 18: 39 63 75 71 70 41 49 15 82 78 | 44 74 3 24 35 41 12 47 34 54 91 45 67 57 62 60 95 8 99 19 9 79 80 4 92 +Card 19: 82 33 76 22 93 10 49 46 9 63 | 70 79 80 44 92 15 90 31 75 17 54 81 12 21 71 61 45 60 72 87 91 8 65 83 47 +Card 20: 60 22 86 1 94 25 72 51 73 57 | 28 66 60 25 16 1 54 36 94 7 73 29 57 55 61 22 51 44 39 69 86 23 72 9 71 +Card 21: 6 30 81 11 69 96 45 76 4 78 | 45 96 51 87 65 95 78 82 76 24 32 28 11 50 4 85 74 81 30 33 69 6 34 79 41 +Card 22: 91 88 99 7 98 1 34 81 36 44 | 69 98 15 50 22 7 27 56 52 97 66 88 89 5 31 34 99 11 91 36 1 33 44 81 55 +Card 23: 94 78 99 13 27 56 81 1 62 84 | 84 33 13 70 81 99 63 56 34 72 64 27 93 87 78 1 29 4 62 44 19 94 37 86 18 +Card 24: 8 81 12 30 78 84 33 39 74 20 | 39 51 4 93 62 74 67 75 8 12 28 33 30 99 84 97 95 5 14 1 20 78 81 61 60 +Card 25: 79 74 91 69 3 96 42 98 87 82 | 53 92 74 17 25 81 96 61 56 15 59 27 82 97 2 71 68 95 83 13 10 47 41 75 87 +Card 26: 20 87 17 34 69 97 36 77 96 66 | 66 10 11 96 83 17 13 57 6 73 88 72 2 39 89 48 79 33 22 19 56 14 9 85 26 +Card 27: 18 10 33 21 67 25 7 86 12 72 | 91 53 6 30 85 90 61 20 40 31 23 83 78 72 68 81 63 58 97 42 16 50 79 37 66 +Card 28: 96 36 98 66 37 8 78 41 55 7 | 77 70 42 37 74 8 96 76 63 64 93 98 78 30 66 1 9 55 7 41 90 29 4 36 22 +Card 29: 51 44 97 56 70 67 82 47 61 60 | 90 94 15 67 75 4 52 21 87 33 77 97 76 20 13 35 45 39 78 82 48 70 89 44 19 +Card 30: 57 24 50 79 36 12 45 68 41 14 | 66 90 12 44 29 79 91 73 57 69 68 24 36 56 33 14 1 83 41 45 9 40 60 20 50 +Card 31: 61 53 23 10 85 72 62 52 26 57 | 37 50 73 7 77 26 63 23 83 44 29 96 48 91 27 53 34 33 61 72 20 42 10 22 25 +Card 32: 76 41 35 73 45 66 54 3 69 12 | 8 2 42 85 28 93 58 89 76 73 84 17 3 56 12 52 68 62 66 54 69 45 41 82 35 +Card 33: 32 29 97 52 45 95 92 18 42 47 | 65 97 46 95 96 39 37 16 52 69 45 92 50 17 29 18 1 47 42 77 56 81 71 7 32 +Card 34: 26 96 10 87 15 16 84 99 75 4 | 29 53 75 48 91 8 89 30 5 22 21 87 13 36 49 16 25 94 2 41 18 69 70 68 67 +Card 35: 57 89 3 81 5 35 32 29 91 65 | 50 68 11 61 39 91 36 31 5 89 12 9 60 13 78 75 4 51 21 45 54 14 73 1 62 +Card 36: 80 46 17 70 42 1 63 87 92 98 | 37 18 64 47 46 94 35 2 10 86 91 19 1 80 4 71 5 78 81 52 31 17 92 40 68 +Card 37: 22 15 30 2 82 24 76 84 85 5 | 30 85 22 24 77 12 49 84 93 1 82 17 27 47 4 10 2 86 6 63 31 33 60 55 57 +Card 38: 63 51 26 56 99 22 32 59 7 3 | 73 11 13 5 37 18 84 35 98 42 4 55 15 58 60 78 22 41 3 89 33 74 93 56 46 +Card 39: 5 96 13 31 59 88 87 55 27 11 | 32 46 56 28 43 45 69 27 5 39 91 79 98 63 35 21 29 38 30 82 71 93 49 80 70 +Card 40: 62 47 56 14 20 91 86 5 12 33 | 88 65 66 10 17 30 51 63 15 83 3 55 27 28 64 35 7 99 76 68 39 23 48 74 41 +Card 41: 48 67 38 82 73 65 1 11 78 53 | 50 76 31 66 11 98 80 29 93 6 82 15 86 74 78 28 60 63 12 59 71 24 68 36 56 +Card 42: 91 27 55 36 14 71 45 10 42 5 | 87 44 80 24 43 84 95 99 53 76 33 23 96 20 62 51 72 49 79 78 39 94 74 61 89 +Card 43: 81 61 13 78 28 75 58 67 54 11 | 96 51 53 73 76 24 82 85 42 25 93 57 35 91 9 64 99 11 88 79 39 44 74 65 29 +Card 44: 82 69 37 22 80 81 55 35 27 19 | 12 63 85 74 39 33 95 75 93 73 44 40 2 76 14 94 42 8 17 9 6 84 34 23 4 +Card 45: 20 86 52 74 80 69 53 33 98 41 | 69 51 18 74 98 90 42 97 7 24 41 62 30 58 95 52 5 31 33 53 20 87 38 25 80 +Card 46: 67 72 36 1 54 24 86 61 85 52 | 19 22 86 64 41 88 31 72 17 1 21 85 67 29 82 54 36 61 75 56 70 53 95 52 24 +Card 47: 62 23 80 46 56 10 52 89 50 5 | 37 55 43 79 98 60 30 44 10 97 38 90 88 83 36 35 61 28 76 21 65 87 40 84 91 +Card 48: 11 26 39 71 9 51 86 65 47 13 | 54 23 60 47 26 9 71 13 85 92 39 19 79 14 73 74 45 22 36 15 65 11 63 10 33 +Card 49: 25 62 23 78 98 83 33 7 37 10 | 85 81 71 67 83 98 60 35 10 79 33 7 52 89 62 93 87 23 37 11 25 45 78 95 82 +Card 50: 98 18 87 92 43 45 67 12 46 69 | 38 74 44 31 89 9 62 53 34 43 41 96 11 4 47 8 5 42 3 95 71 28 73 97 33 +Card 51: 72 33 31 38 5 67 25 1 4 79 | 9 77 58 97 48 30 85 91 79 70 49 10 98 76 47 90 89 88 25 5 51 26 99 32 7 +Card 52: 92 18 67 66 45 23 10 83 78 57 | 70 17 97 6 9 95 37 4 69 40 93 2 11 12 61 5 30 42 74 7 87 85 20 52 75 +Card 53: 4 59 6 44 12 60 14 86 93 11 | 14 44 74 7 87 6 82 84 55 48 17 37 18 60 23 59 97 62 31 4 93 12 11 13 58 +Card 54: 2 64 63 60 87 72 33 46 88 92 | 96 5 46 94 92 7 63 93 17 13 25 60 73 55 9 98 20 49 29 57 61 64 48 52 19 +Card 55: 29 93 5 53 72 82 12 67 64 50 | 52 33 77 16 45 31 56 28 18 72 79 4 73 41 59 35 2 38 68 98 87 84 94 66 12 +Card 56: 26 18 58 78 53 22 94 23 76 93 | 4 36 64 38 26 72 21 53 68 91 17 18 24 78 33 16 5 9 79 2 98 52 99 40 76 +Card 57: 85 36 66 93 50 62 90 98 4 31 | 23 6 31 76 79 80 15 38 42 81 85 14 56 88 90 65 50 54 62 78 27 77 35 10 70 +Card 58: 80 61 53 48 94 11 87 89 72 43 | 3 55 54 77 57 95 31 7 12 52 92 59 25 23 80 14 45 85 81 94 30 24 67 53 16 +Card 59: 78 54 15 18 17 28 89 12 88 81 | 55 51 97 22 32 72 88 73 11 28 8 65 14 20 6 79 41 87 29 2 40 74 17 99 52 +Card 60: 64 74 67 76 78 43 6 14 79 96 | 82 23 87 37 51 64 89 15 1 56 86 66 10 9 8 53 2 11 24 88 76 35 54 69 68 +Card 61: 53 29 18 65 93 62 75 20 15 35 | 9 77 14 60 38 36 98 24 47 28 6 95 27 12 10 94 61 71 68 22 72 37 96 4 81 +Card 62: 43 85 70 78 16 8 3 18 26 67 | 63 86 95 90 15 13 4 31 82 74 34 76 96 14 49 94 55 80 39 84 79 68 54 81 1 +Card 63: 9 54 71 62 38 75 3 12 46 8 | 8 12 38 69 9 3 79 16 2 6 54 25 75 71 21 60 29 13 30 50 62 98 46 15 47 +Card 64: 98 90 48 49 86 78 45 60 92 81 | 84 67 21 27 37 76 99 1 74 20 23 73 58 10 60 17 57 26 29 86 11 64 31 54 66 +Card 65: 45 21 33 32 64 38 90 47 15 35 | 64 82 38 89 21 32 90 33 16 63 54 65 39 15 37 42 96 7 40 26 50 45 30 85 22 +Card 66: 95 88 40 57 32 31 89 23 68 17 | 64 94 68 4 55 58 8 6 1 17 88 89 32 95 13 78 93 45 23 40 76 31 96 15 57 +Card 67: 15 60 6 79 89 46 67 26 70 29 | 29 79 36 20 1 14 39 2 89 75 67 33 19 12 70 26 9 58 6 35 60 17 15 10 68 +Card 68: 76 32 99 77 16 6 17 46 91 42 | 81 42 82 80 91 52 70 90 26 15 45 35 22 27 84 67 16 24 32 76 54 77 75 51 31 +Card 69: 34 68 42 21 5 91 47 95 59 63 | 35 59 4 20 47 37 24 95 79 91 49 73 68 6 5 46 63 99 58 21 88 67 94 44 80 +Card 70: 69 11 94 64 21 65 31 89 55 28 | 5 64 99 53 34 4 51 88 10 68 74 81 1 23 29 58 93 94 43 32 70 76 7 77 21 +Card 71: 29 52 43 97 41 83 86 99 49 45 | 86 29 43 89 42 53 82 17 94 62 52 99 15 27 40 49 78 74 77 28 9 10 88 97 68 +Card 72: 48 11 62 26 1 89 61 3 23 6 | 11 54 93 60 43 3 24 77 48 61 32 5 79 91 21 73 62 96 87 6 89 59 26 1 15 +Card 73: 65 45 90 13 71 50 48 97 54 77 | 97 16 45 87 68 32 12 15 21 7 33 64 37 88 67 10 60 26 49 65 20 11 29 44 52 +Card 74: 83 54 74 80 4 60 8 68 35 18 | 71 81 31 11 5 60 77 90 76 58 64 32 82 21 97 2 53 9 10 85 75 18 55 86 25 +Card 75: 13 19 42 14 17 74 28 34 56 93 | 76 83 33 82 28 86 93 29 39 88 98 14 49 89 74 62 13 23 43 17 42 56 45 41 35 +Card 76: 51 79 58 45 42 65 29 96 36 13 | 82 99 23 66 29 69 92 95 64 13 40 45 76 86 74 44 81 73 10 4 30 79 68 1 12 +Card 77: 98 12 89 28 29 87 92 4 13 85 | 24 47 4 76 9 95 29 80 87 16 53 85 7 42 86 82 59 37 28 35 55 40 50 10 58 +Card 78: 98 59 89 56 30 15 51 64 4 95 | 74 92 70 91 45 94 95 58 79 88 87 63 40 54 50 77 31 30 41 17 43 82 4 44 13 +Card 79: 37 35 51 39 10 79 32 56 40 42 | 53 28 38 36 76 83 2 42 35 90 6 84 49 27 47 64 75 39 89 52 3 17 40 87 93 +Card 80: 80 42 36 87 9 50 40 96 27 16 | 6 65 3 69 85 63 30 18 8 77 11 94 53 55 5 20 66 33 32 13 49 89 19 83 70 +Card 81: 20 51 80 10 71 43 94 87 7 55 | 44 1 59 33 27 57 28 17 77 46 11 72 73 54 65 37 25 74 60 41 98 84 22 58 79 +Card 82: 13 87 41 55 28 79 7 2 22 37 | 8 20 91 72 53 65 96 54 44 42 90 79 97 31 75 67 21 93 62 81 82 3 11 58 73 +Card 83: 99 2 35 20 25 41 46 88 23 37 | 6 89 28 32 36 93 62 78 61 53 58 16 5 98 67 15 1 24 80 83 31 76 33 82 73 +Card 84: 13 5 98 70 63 92 79 10 53 84 | 32 10 41 63 92 40 85 53 88 57 13 5 70 93 96 54 29 30 44 22 98 84 79 21 78 +Card 85: 20 32 69 15 1 29 2 87 45 10 | 43 15 36 7 32 95 91 90 75 45 6 65 10 62 20 1 2 73 72 51 85 25 29 33 49 +Card 86: 74 56 19 8 4 35 78 43 75 26 | 74 30 77 56 42 14 19 1 28 18 16 99 63 72 8 90 43 15 20 4 78 23 35 75 26 +Card 87: 40 16 56 70 55 65 23 24 78 47 | 59 56 55 29 64 91 42 93 96 54 13 67 14 20 23 76 6 60 63 21 27 61 85 10 15 +Card 88: 50 48 45 15 51 65 97 22 12 39 | 59 93 75 12 30 39 5 85 32 56 29 50 80 82 21 38 96 65 14 53 62 51 15 23 54 +Card 89: 89 77 17 59 37 15 50 63 40 60 | 44 63 77 40 74 15 37 62 43 24 32 81 55 98 86 16 71 75 84 54 76 67 42 90 10 +Card 90: 63 97 57 10 38 19 42 69 73 56 | 3 89 60 13 33 24 70 97 27 56 15 21 19 83 63 42 36 68 57 38 10 73 77 17 5 +Card 91: 13 62 75 45 36 96 69 50 73 74 | 86 7 13 52 60 22 91 14 67 62 85 54 21 32 75 2 55 69 40 42 77 57 9 84 41 +Card 92: 54 97 73 17 67 58 69 27 21 7 | 38 66 59 27 69 7 71 68 83 2 58 44 11 89 10 75 70 63 61 73 94 5 41 45 17 +Card 93: 52 51 28 93 45 31 90 25 53 60 | 31 65 24 87 74 54 66 69 30 7 50 52 9 93 16 51 53 95 18 22 8 90 99 97 43 +Card 94: 73 17 53 21 91 3 85 89 36 92 | 53 57 5 44 55 90 74 20 51 77 41 81 75 31 63 23 76 18 48 82 45 40 9 37 54 +Card 95: 5 88 23 61 63 38 78 82 42 45 | 45 26 5 91 71 40 4 1 94 47 14 55 10 95 81 44 25 24 78 20 3 43 61 50 66 +Card 96: 70 85 30 35 56 69 83 47 18 33 | 6 93 99 79 52 5 69 48 57 85 4 11 9 22 43 53 87 21 33 56 39 31 83 32 67 +Card 97: 52 27 4 63 32 54 89 45 19 40 | 86 50 2 75 72 79 23 85 12 60 34 76 15 55 17 68 90 78 14 95 41 26 33 38 24 +Card 98: 89 50 13 23 47 26 27 90 92 24 | 45 74 96 24 40 46 23 17 76 15 53 25 29 27 92 58 20 12 37 35 72 10 32 47 26 +Card 99: 12 47 10 35 30 8 57 83 84 39 | 73 98 81 88 34 52 33 8 86 55 47 83 84 66 23 29 62 21 70 1 64 49 53 15 94 +Card 100: 45 99 97 10 17 5 44 54 96 88 | 95 91 34 50 61 15 81 20 99 14 69 33 48 75 16 9 29 98 41 80 53 77 89 56 72 +Card 101: 20 85 57 67 47 54 58 65 95 32 | 49 88 10 23 48 93 85 95 69 75 38 25 78 45 12 80 26 14 32 24 8 21 99 77 1 +Card 102: 52 32 10 58 7 99 74 1 59 50 | 29 97 91 78 53 11 96 25 79 43 77 72 60 66 81 55 69 93 50 48 98 54 39 87 10 +Card 103: 28 95 73 79 26 5 60 56 40 59 | 49 14 29 94 69 86 82 85 1 83 81 54 8 43 71 99 32 35 78 5 87 57 15 44 48 +Card 104: 68 70 17 29 85 16 48 21 2 34 | 14 45 36 72 99 94 62 37 74 84 97 75 31 35 83 19 1 15 91 57 61 40 79 77 5 +Card 105: 18 33 10 82 88 2 61 81 41 15 | 33 34 15 1 82 63 77 3 57 67 10 88 93 13 84 39 68 5 54 96 64 41 7 18 4 +Card 106: 67 56 16 10 80 60 62 61 64 51 | 51 10 21 64 71 80 9 98 67 4 60 45 16 85 92 27 56 91 61 43 62 68 1 77 35 +Card 107: 58 50 49 28 39 22 8 63 72 1 | 25 45 9 7 88 71 94 3 54 66 27 85 32 1 8 10 22 84 69 92 86 39 61 50 49 +Card 108: 41 38 72 4 70 66 61 87 42 83 | 69 99 89 43 50 15 5 29 68 28 86 37 66 38 27 19 95 41 62 82 2 87 33 20 42 +Card 109: 85 35 69 74 73 23 29 31 11 92 | 33 36 29 28 92 87 70 62 5 24 95 38 11 48 47 75 81 35 51 15 94 90 32 78 13 +Card 110: 86 6 55 64 15 23 66 51 77 67 | 51 44 89 73 22 29 58 17 77 48 18 53 75 91 57 60 30 63 96 93 33 79 68 86 12 +Card 111: 34 40 48 88 11 4 2 41 39 66 | 15 47 42 81 4 24 52 10 13 34 90 2 79 45 99 96 31 92 23 63 11 76 44 73 70 +Card 112: 34 74 86 79 37 30 31 51 41 13 | 75 21 14 78 1 93 60 96 56 77 65 29 34 58 22 90 79 59 8 19 42 46 33 2 4 +Card 113: 50 16 13 39 17 98 73 48 30 66 | 37 41 97 57 6 91 99 86 78 5 94 85 15 88 3 83 21 26 16 98 51 27 60 46 50 +Card 114: 36 74 72 70 13 27 42 21 8 65 | 39 27 16 94 75 5 87 66 51 68 72 67 85 19 21 91 65 10 56 86 84 40 83 36 43 +Card 115: 55 68 47 93 44 19 40 33 69 51 | 20 89 33 84 77 79 10 14 26 43 16 78 37 41 62 49 95 3 30 82 5 18 50 86 69 +Card 116: 40 7 60 18 17 94 24 12 79 59 | 91 22 74 80 35 10 20 97 25 78 24 95 18 70 26 33 8 41 71 32 77 15 72 86 61 +Card 117: 53 5 43 22 37 55 42 62 87 50 | 24 57 27 11 17 20 83 86 81 18 21 42 79 62 69 25 88 36 13 65 78 80 28 93 7 +Card 118: 49 76 39 26 97 89 9 2 79 40 | 77 99 93 86 89 3 24 47 52 13 19 6 44 25 73 71 70 34 46 28 97 61 92 35 20 +Card 119: 35 97 25 47 40 18 86 45 64 38 | 83 33 66 73 58 22 14 77 45 16 98 61 63 99 4 40 72 30 50 46 51 44 49 84 70 +Card 120: 86 99 32 14 39 90 15 6 89 76 | 56 18 35 31 5 83 68 42 47 36 33 81 69 43 46 20 97 53 94 60 23 71 26 24 52 +Card 121: 53 39 83 9 7 59 20 14 17 93 | 92 78 49 16 62 3 60 29 48 88 56 33 68 64 15 35 99 94 55 41 77 74 90 11 86 +Card 122: 39 62 24 68 36 29 38 15 96 76 | 79 99 71 75 70 43 20 21 41 82 7 17 9 57 85 8 33 30 80 26 93 63 12 5 54 +Card 123: 34 53 21 57 84 19 45 62 50 4 | 27 59 88 78 36 3 22 28 29 10 54 9 48 47 76 91 25 13 96 8 11 42 46 74 40 +Card 124: 51 30 87 45 39 11 33 94 22 65 | 11 30 18 39 2 33 90 87 37 72 51 81 67 45 78 48 14 94 56 27 65 22 20 10 76 +Card 125: 94 87 72 21 28 6 59 60 61 35 | 46 92 59 4 60 76 71 3 53 35 8 86 51 72 47 73 25 28 87 55 43 63 21 66 50 +Card 126: 77 83 56 19 75 12 58 54 64 90 | 18 53 50 77 44 57 74 64 61 65 62 5 91 85 26 1 66 71 41 68 92 69 27 9 93 +Card 127: 2 14 39 77 97 63 33 24 46 35 | 8 79 91 46 28 66 58 75 80 73 85 34 2 95 33 38 35 69 67 26 23 63 78 87 97 +Card 128: 23 78 35 17 80 32 90 34 30 63 | 42 80 4 32 37 27 8 23 40 65 17 41 43 90 34 81 35 63 83 46 30 78 72 55 82 +Card 129: 77 84 23 99 78 95 40 4 55 56 | 46 49 44 65 36 66 94 64 34 16 30 81 62 77 82 28 31 18 86 32 74 75 88 99 71 +Card 130: 50 93 25 12 24 66 38 29 46 76 | 99 27 29 84 66 7 47 34 93 4 60 24 25 46 12 9 33 86 38 69 76 48 81 85 21 +Card 131: 89 68 69 30 59 72 26 70 42 51 | 78 74 18 68 89 22 72 40 67 34 84 39 43 76 81 63 30 54 36 24 51 98 1 19 59 +Card 132: 70 73 4 37 15 86 65 7 77 85 | 79 21 5 55 81 99 25 27 94 33 40 34 20 29 68 93 98 16 90 54 71 13 78 60 74 +Card 133: 11 89 21 87 56 1 70 79 36 63 | 18 59 80 62 76 39 25 27 53 48 45 47 89 2 85 55 91 15 84 31 33 64 28 30 8 +Card 134: 69 96 77 54 67 24 46 22 81 42 | 79 73 45 14 97 39 61 74 95 58 82 43 89 2 4 36 21 78 37 51 65 47 53 99 20 +Card 135: 33 92 5 46 16 18 10 32 77 67 | 72 30 76 7 33 64 18 54 6 85 73 3 68 96 92 45 61 32 88 56 87 42 39 84 86 +Card 136: 27 53 79 82 18 4 75 63 11 39 | 66 55 93 24 58 83 33 92 61 68 26 72 80 49 8 36 22 43 63 20 84 69 21 97 88 +Card 137: 22 50 61 6 94 62 90 73 25 46 | 66 99 72 17 77 57 6 73 48 34 5 58 13 16 2 36 35 23 78 42 12 27 24 29 37 +Card 138: 18 19 59 57 23 68 61 78 91 65 | 2 4 83 10 20 85 51 73 30 1 31 9 80 27 24 92 3 42 71 67 84 54 82 45 76 +Card 139: 23 41 36 48 93 74 10 73 6 18 | 47 84 14 89 62 39 37 94 15 46 97 98 29 17 72 32 64 31 99 76 86 45 75 61 5 +Card 140: 99 71 15 31 61 53 4 62 69 77 | 58 8 86 44 59 47 91 38 30 25 42 82 11 19 49 75 9 83 20 90 1 94 12 22 52 +Card 141: 55 87 74 50 52 9 76 90 73 25 | 39 50 27 56 57 70 66 92 24 23 32 72 45 75 31 78 74 99 8 79 1 43 5 2 53 +Card 142: 28 66 34 64 49 48 91 73 81 41 | 54 78 66 59 32 43 41 85 15 64 68 56 4 46 90 67 63 45 24 16 53 74 52 75 81 +Card 143: 30 38 11 31 66 26 40 93 88 14 | 30 88 31 15 93 27 55 96 11 17 20 35 14 10 66 51 40 18 57 53 24 9 26 58 38 +Card 144: 70 6 21 59 69 99 30 43 60 58 | 60 1 11 69 70 59 66 79 58 73 54 30 33 55 21 89 14 43 99 4 52 82 6 2 96 +Card 145: 25 44 26 89 81 7 57 40 59 9 | 95 20 38 12 57 32 80 34 25 94 40 59 9 65 93 68 42 86 44 89 81 7 70 26 62 +Card 146: 90 61 87 20 26 51 33 19 64 10 | 1 84 80 86 22 50 73 69 78 70 12 34 65 54 5 83 44 98 82 57 31 3 37 59 79 +Card 147: 73 32 37 22 42 83 17 20 61 76 | 76 87 22 61 45 48 83 32 60 3 17 8 70 95 12 1 73 40 82 85 65 20 37 42 88 +Card 148: 16 40 86 29 68 67 22 42 96 9 | 34 83 95 91 40 11 74 99 25 16 15 76 52 12 75 43 92 59 17 98 88 36 4 5 28 +Card 149: 17 85 45 10 60 72 15 50 61 63 | 85 11 92 50 10 8 37 23 96 20 69 15 40 72 89 60 61 17 54 63 27 28 31 24 45 +Card 150: 64 87 43 20 97 83 69 61 95 56 | 29 76 26 52 65 84 62 11 49 92 90 77 47 46 42 50 33 37 98 2 5 9 71 22 85 +Card 151: 12 23 35 44 39 73 1 30 95 33 | 36 10 58 60 72 6 43 64 75 1 16 93 15 89 68 56 99 88 32 52 18 22 98 67 66 +Card 152: 69 85 51 1 46 21 31 19 44 49 | 45 92 8 10 80 94 32 33 88 28 16 86 23 93 6 96 25 81 3 52 64 90 76 95 59 +Card 153: 42 74 39 36 45 26 25 1 68 12 | 70 33 74 79 96 1 4 88 34 76 59 61 75 27 92 72 57 98 51 10 29 52 64 26 35 +Card 154: 85 95 68 79 28 93 46 65 38 14 | 52 18 50 9 79 2 88 43 85 31 83 74 21 38 87 73 56 63 71 15 59 72 13 64 46 +Card 155: 11 43 73 53 49 65 27 37 30 51 | 27 28 23 51 61 54 71 57 88 1 40 65 34 53 73 83 24 82 15 32 46 11 79 77 80 +Card 156: 64 26 5 45 59 81 23 43 27 44 | 11 16 77 37 62 98 10 21 71 35 28 13 74 65 89 78 45 61 96 7 12 53 51 52 44 +Card 157: 27 87 50 60 44 48 85 1 33 8 | 84 41 4 36 8 49 26 43 52 95 77 3 75 72 54 66 98 21 19 61 18 78 30 37 1 +Card 158: 31 88 37 91 12 56 65 79 95 17 | 64 32 43 1 45 8 99 94 39 16 77 18 84 70 24 51 27 93 59 25 41 73 78 34 44 +Card 159: 88 86 84 17 93 64 3 14 59 32 | 37 21 60 95 23 62 45 98 56 78 20 81 99 22 12 57 5 36 51 10 93 72 58 8 13 +Card 160: 49 37 23 63 73 64 16 70 19 32 | 75 74 21 77 37 56 30 76 66 1 51 9 97 95 38 40 29 69 67 6 47 50 45 71 87 +Card 161: 10 67 21 27 39 79 22 92 47 42 | 9 80 82 75 20 2 53 64 76 96 31 61 50 12 16 15 38 18 90 59 65 70 55 99 6 +Card 162: 89 99 28 87 4 43 30 48 46 82 | 46 51 59 81 14 40 82 5 85 48 97 28 11 7 87 64 58 38 92 30 89 99 27 36 34 +Card 163: 2 91 88 95 38 31 92 3 27 60 | 76 31 38 29 60 68 22 87 71 11 95 48 50 21 88 26 44 32 2 69 27 45 94 79 81 +Card 164: 87 91 47 40 2 71 95 99 49 74 | 34 8 65 49 45 43 51 81 9 13 80 38 33 88 82 74 28 60 91 48 1 55 42 95 56 +Card 165: 57 74 54 91 94 96 55 64 39 75 | 67 9 10 80 75 77 12 87 95 50 25 19 82 65 76 66 23 30 45 61 79 17 72 37 7 +Card 166: 16 4 73 97 28 19 17 10 57 43 | 73 97 24 57 43 58 72 10 2 34 9 63 70 64 68 28 44 16 99 61 4 78 46 83 19 +Card 167: 53 51 67 68 18 26 55 10 69 9 | 46 64 73 12 97 89 67 22 30 82 14 27 36 4 72 19 61 13 93 24 91 63 48 21 87 +Card 168: 69 32 33 90 72 88 55 80 15 27 | 10 80 14 55 64 39 97 82 24 96 74 46 73 68 65 87 43 59 16 53 84 38 79 11 47 +Card 169: 74 85 11 55 15 59 36 5 54 18 | 31 27 42 86 93 33 68 45 40 32 44 88 48 47 35 25 9 89 49 66 39 1 79 69 7 +Card 170: 9 49 3 88 4 31 13 64 38 41 | 71 38 32 13 91 61 3 48 88 63 17 19 59 75 98 36 6 49 50 44 20 2 45 67 53 +Card 171: 67 87 77 34 32 64 56 59 58 36 | 50 74 68 64 22 63 38 12 73 32 10 14 29 55 31 92 91 9 76 24 17 49 33 95 2 +Card 172: 4 80 72 36 37 99 64 16 22 31 | 8 78 95 47 18 36 55 59 23 86 70 54 60 98 13 25 80 75 74 48 16 7 81 5 11 +Card 173: 4 77 32 71 39 67 58 11 57 29 | 87 31 69 92 71 62 20 77 14 47 60 57 75 94 37 86 95 97 41 85 30 54 48 44 10 +Card 174: 21 12 8 71 74 77 31 82 1 16 | 4 89 75 19 91 51 10 71 88 78 30 80 47 96 28 65 99 35 13 48 73 29 53 49 42 +Card 175: 58 38 44 98 56 18 21 63 74 3 | 92 55 64 94 49 41 10 78 6 53 76 70 45 46 83 63 82 73 95 81 33 30 77 50 34 +Card 176: 94 39 50 86 44 81 88 55 54 9 | 16 60 84 75 52 81 4 10 37 6 56 14 22 8 90 41 45 70 12 23 89 31 28 80 87 +Card 177: 96 26 47 79 99 4 66 50 53 45 | 9 94 70 72 81 75 76 77 64 78 12 32 85 40 20 90 28 3 35 57 93 87 63 17 54 +Card 178: 33 65 93 44 97 37 12 41 83 24 | 2 1 46 10 55 82 58 57 52 64 81 76 74 99 5 89 9 14 42 27 6 19 66 3 15 +Card 179: 12 28 65 24 9 30 38 11 18 55 | 85 10 70 62 71 19 55 67 68 25 44 95 51 91 29 30 15 13 90 52 47 23 21 66 92 +Card 180: 65 7 39 97 64 3 50 27 46 4 | 12 59 88 91 43 61 36 18 58 85 26 5 23 1 62 56 8 49 66 72 9 67 90 52 95 +Card 181: 13 97 85 12 18 20 70 6 93 44 | 25 12 54 97 68 65 23 26 13 8 50 62 10 32 73 88 51 76 98 16 37 4 87 18 35 +Card 182: 65 35 63 2 34 77 15 89 16 54 | 36 2 6 62 81 58 34 99 54 48 57 15 52 16 30 65 83 53 38 10 41 77 63 35 21 +Card 183: 16 98 38 2 86 34 85 48 50 95 | 34 50 2 14 89 6 47 44 67 25 86 98 17 48 85 99 51 16 55 35 38 66 95 32 90 +Card 184: 4 1 48 73 89 69 47 81 94 59 | 20 18 50 30 87 17 99 76 74 61 9 84 40 46 51 97 65 98 56 53 3 77 11 8 34 +Card 185: 79 72 33 15 36 89 13 90 94 28 | 58 96 94 83 84 90 52 53 31 9 17 97 2 54 56 26 20 76 98 91 1 14 74 23 64 +Card 186: 36 34 86 79 32 64 15 94 72 35 | 12 94 19 11 35 78 59 91 86 47 55 36 53 21 9 45 77 18 17 72 10 79 49 34 74 +Card 187: 43 16 88 54 62 17 93 91 21 59 | 51 7 46 16 26 6 96 30 42 2 10 55 37 48 74 89 98 73 84 19 9 11 24 44 69 +Card 188: 50 59 97 84 11 57 7 94 29 92 | 19 79 94 25 18 55 24 89 65 11 53 93 83 92 27 85 48 4 68 97 46 64 40 1 74 +Card 189: 17 19 78 66 96 13 84 16 59 53 | 15 30 24 55 62 12 51 87 35 73 33 8 2 94 49 52 58 75 32 34 69 16 74 89 46 +Card 190: 61 96 6 49 37 3 26 12 99 11 | 87 95 57 43 23 53 36 25 84 69 38 67 46 92 74 16 18 27 80 19 13 54 12 39 61 +Card 191: 85 69 8 21 84 42 68 22 55 45 | 10 51 26 7 27 9 18 76 46 57 20 59 77 38 92 49 90 52 98 78 34 37 74 91 12 +Card 192: 58 46 36 50 72 87 96 63 83 5 | 69 11 88 81 52 97 43 42 26 41 47 54 78 67 51 95 18 62 13 99 30 3 34 89 53 +Card 193: 20 78 41 3 26 1 29 63 4 88 | 64 59 80 93 66 18 62 94 23 25 79 53 52 31 44 46 67 75 24 8 97 10 51 99 84 +Card 194: 40 5 28 23 65 78 63 94 60 83 | 45 54 2 74 75 11 55 8 68 41 30 51 47 33 88 58 37 36 64 1 21 72 77 25 99 From a438763a8cbb50c3cf2823f1abbaa76f7b218f0a Mon Sep 17 00:00:00 2001 From: Fabien Zucchet Date: Sun, 10 Dec 2023 14:24:48 +0000 Subject: [PATCH 5/6] feat(y2023): add solution for d05 --- helpers/maths.go | 12 ++ y2023/d05/fabienz/solution.go | 203 ++++++++++++++++++++++ y2023/d05/fabienz/solution_test.go | 58 +++++++ y2023/d05/fabienz/testdata/input.txt | 248 +++++++++++++++++++++++++++ 4 files changed, 521 insertions(+) create mode 100644 y2023/d05/fabienz/solution.go create mode 100644 y2023/d05/fabienz/solution_test.go create mode 100644 y2023/d05/fabienz/testdata/input.txt diff --git a/helpers/maths.go b/helpers/maths.go index 2108f1e..56cca70 100644 --- a/helpers/maths.go +++ b/helpers/maths.go @@ -13,6 +13,18 @@ func MaxInts(ints []int) int { return max } +func MinInts(ints []int) int { + min := ints[0] + + for _, i := range ints { + if i < min { + min = i + } + } + + return min +} + // Find the GCD of two integers. func GCD(a, b int) int { if a < 0 { diff --git a/y2023/d05/fabienz/solution.go b/y2023/d05/fabienz/solution.go new file mode 100644 index 0000000..9a846e7 --- /dev/null +++ b/y2023/d05/fabienz/solution.go @@ -0,0 +1,203 @@ +package fabienz + +import ( + "fmt" + "io" + "strconv" + "strings" + + "github.com/fabienzucchet/adventofcode/helpers" +) + +// PartOne solves the first problem of day 5 of Advent of Code 2023. +func PartOne(input io.Reader, answer io.Writer) error { + // Read the input. Feel free to change it depending on the input. + lines, err := helpers.LinesFromReader(input) + if err != nil { + return fmt.Errorf("could not read input: %w", err) + } + + a, err := parseInput(lines) + if err != nil { + return fmt.Errorf("could not parse input: %w", err) + } + + locations := []int{} + + for _, seed := range a.seeds { + locations = append(locations, a.getLocationForSeed(seed)) + } + + _, err = fmt.Fprintf(answer, "%d", helpers.MinInts(locations)) + if err != nil { + return fmt.Errorf("could not write answer: %w", err) + } + + return nil +} + +// PartTwo solves the second problem of day 5 of Advent of Code 2023. +func PartTwo(input io.Reader, answer io.Writer) error { + // Read the input. Feel free to change it depending on the input. + lines, err := helpers.LinesFromReader(input) + if err != nil { + return fmt.Errorf("could not read input: %w", err) + } + + // TODO: Write code to solve Part 2 here. + + // TODO: Write your solution to Part 2 below. + _, err = fmt.Fprintf(answer, "%d", len(lines)) + if err != nil { + return fmt.Errorf("could not write answer: %w", err) + } + + return nil +} + +var LINES = map[string][2]int{ + "SEED_TO_SOIL": {3, 50}, + "SOIL_TO_FERTILIZER": {53, 88}, + "FERTILIZER_TO_WATER": {91, 120}, + "WATER_TO_LIGHT": {123, 148}, + "LIGHT_TO_TEMPERATURE": {151, 194}, + "TEMPERATURE_TO_HUMIDITY": {197, 203}, + "HUMIDITY_TO_LOCATION": {206, 247}, +} + +// var LINES = map[string][2]int{ +// "SEED_TO_SOIL": {3, 4}, +// "SOIL_TO_FERTILIZER": {7, 9}, +// "FERTILIZER_TO_WATER": {12, 15}, +// "WATER_TO_LIGHT": {18, 19}, +// "LIGHT_TO_TEMPERATURE": {22, 24}, +// "TEMPERATURE_TO_HUMIDITY": {27, 28}, +// "HUMIDITY_TO_LOCATION": {31, 32}, +// } + +type Range struct { + sourceStart int + destinationStart int + length int +} + +type Almanac struct { + seeds []int + seedToSoil []Range + soilToFertilizer []Range + fertilizerToWater []Range + waterToLight []Range + lightToTemperature []Range + temperatureToHumidity []Range + humidityToLocation []Range +} + +func parseInput(lines []string) (a Almanac, err error) { + a = Almanac{} + + // Parse the seeds. + seeds := strings.Split(lines[0], " ")[1:] + for _, seed := range seeds { + seedInt, err := strconv.Atoi(seed) + if err != nil { + return a, fmt.Errorf("could not parse seed: %w", err) + } + a.seeds = append(a.seeds, seedInt) + } + + // Parse the seed to soil map. + for i := LINES["SEED_TO_SOIL"][0]; i <= LINES["SEED_TO_SOIL"][1]; i++ { + r, err := parseRange(lines[i]) + if err != nil { + return a, fmt.Errorf("could not parse seed to soil map: %w", err) + } + a.seedToSoil = append(a.seedToSoil, r) + } + + // Parse the soil to fertilizer map. + for i := LINES["SOIL_TO_FERTILIZER"][0]; i <= LINES["SOIL_TO_FERTILIZER"][1]; i++ { + r, err := parseRange(lines[i]) + if err != nil { + return a, fmt.Errorf("could not parse soil to fertilizer map: %w", err) + } + a.soilToFertilizer = append(a.soilToFertilizer, r) + } + + // Parse the fertilizer to water map. + for i := LINES["FERTILIZER_TO_WATER"][0]; i <= LINES["FERTILIZER_TO_WATER"][1]; i++ { + r, err := parseRange(lines[i]) + if err != nil { + return a, fmt.Errorf("could not parse fertilizer to water map: %w", err) + } + a.fertilizerToWater = append(a.fertilizerToWater, r) + } + + // Parse the water to light map. + for i := LINES["WATER_TO_LIGHT"][0]; i <= LINES["WATER_TO_LIGHT"][1]; i++ { + r, err := parseRange(lines[i]) + if err != nil { + return a, fmt.Errorf("could not parse water to light map: %w", err) + } + a.waterToLight = append(a.waterToLight, r) + } + + // Parse the light to temperature map. + for i := LINES["LIGHT_TO_TEMPERATURE"][0]; i <= LINES["LIGHT_TO_TEMPERATURE"][1]; i++ { + r, err := parseRange(lines[i]) + if err != nil { + return a, fmt.Errorf("could not parse light to temperature map: %w", err) + } + a.lightToTemperature = append(a.lightToTemperature, r) + } + + // Parse the temperature to humidity map. + for i := LINES["TEMPERATURE_TO_HUMIDITY"][0]; i <= LINES["TEMPERATURE_TO_HUMIDITY"][1]; i++ { + r, err := parseRange(lines[i]) + if err != nil { + return a, fmt.Errorf("could not parse temperature to humidity map: %w", err) + } + a.temperatureToHumidity = append(a.temperatureToHumidity, r) + } + + // Parse the humidity to location map. + for i := LINES["HUMIDITY_TO_LOCATION"][0]; i <= LINES["HUMIDITY_TO_LOCATION"][1]; i++ { + r, err := parseRange(lines[i]) + if err != nil { + return a, fmt.Errorf("could not parse humidity to location map: %w", err) + } + a.humidityToLocation = append(a.humidityToLocation, r) + } + + return a, nil +} + +func parseRange(s string) (r Range, err error) { + fmt.Sscanf(s, "%d %d %d", &r.destinationStart, &r.sourceStart, &r.length) + + return r, nil +} + +func (a *Almanac) getLocationForSeed(seed int) (location int) { + soil := findInMap(a.seedToSoil, seed) + fertilizer := findInMap(a.soilToFertilizer, soil) + water := findInMap(a.fertilizerToWater, fertilizer) + light := findInMap(a.waterToLight, water) + temperature := findInMap(a.lightToTemperature, light) + humidity := findInMap(a.temperatureToHumidity, temperature) + location = findInMap(a.humidityToLocation, humidity) + + return location +} + +func findInMap(m []Range, idx int) (newIdx int) { + newIdx = idx + + for _, r := range m { + if idx >= r.sourceStart && idx < r.sourceStart+r.length { + newIdx = r.destinationStart + (idx - r.sourceStart) + break + } + } + + return newIdx +} diff --git a/y2023/d05/fabienz/solution_test.go b/y2023/d05/fabienz/solution_test.go new file mode 100644 index 0000000..8edda5b --- /dev/null +++ b/y2023/d05/fabienz/solution_test.go @@ -0,0 +1,58 @@ +package fabienz + +import ( + "log" + "os" + "testing" + + "github.com/fabienzucchet/adventofcode/helpers" +) + +func ExamplePartOne() { + file, err := os.Open("testdata/input.txt") + if err != nil { + log.Fatalf("could not open input file: %v", err) + } + defer file.Close() + + if err := PartOne(file, os.Stdout); err != nil { + log.Fatalf("could not solve: %v", err) + } + // Output: 289863851 +} + +func ExamplePartTwo() { + file, err := os.Open("testdata/input.txt") + if err != nil { + log.Fatalf("could open input file: %v", err) + } + defer file.Close() + + if err := PartTwo(file, os.Stdout); err != nil { + log.Fatalf("could not solve: %v", err) + } + // Output: 👉 Write the answer here 👈 +} + +func Benchmark(b *testing.B) { + testCases := map[string]struct { + solution helpers.Solution + inputFile string + }{ + "PartOne": { + solution: helpers.SolutionFunc(PartOne), + inputFile: "testdata/input.txt", + }, + + "PartTwo": { + solution: helpers.SolutionFunc(PartTwo), + inputFile: "testdata/input.txt", + }, + } + + for name, test := range testCases { + b.Run(name, func(b *testing.B) { + helpers.BenchmarkSolution(b, test.solution, test.inputFile) + }) + } +} diff --git a/y2023/d05/fabienz/testdata/input.txt b/y2023/d05/fabienz/testdata/input.txt new file mode 100644 index 0000000..749b9c5 --- /dev/null +++ b/y2023/d05/fabienz/testdata/input.txt @@ -0,0 +1,248 @@ +seeds: 4043382508 113348245 3817519559 177922221 3613573568 7600537 773371046 400582097 2054637767 162982133 2246524522 153824596 1662955672 121419555 2473628355 846370595 1830497666 190544464 230006436 483872831 + +seed-to-soil map: +4064811 506246814 25615317 +1520011681 1661018909 106057083 +1007960598 8836276 47579700 +1055540298 679332386 82196064 +2377475243 3574057730 33434621 +2323567163 2090355001 53908080 +2724594670 4209189177 35645909 +3247614896 4244835086 50132210 +2793935335 3209861711 43002393 +2560156404 2081665194 8689807 +3490249256 2918928471 290933240 +1399066513 1515349965 120856915 +3383052312 1779636204 107196944 +1634905040 1464437422 50912543 +0 849557294 4064811 +2155322314 2548120606 2883579 +3362202103 2803876083 20850209 +465575436 853622105 310104399 +3781182496 3252864104 5074346 +3297747106 3844665588 64454997 +1779636204 2144263081 375686110 +2765805312 2519990583 28130023 +1325393680 605659553 73672833 +1211533784 841842038 7715256 +164952771 1163726504 300622665 +2197289480 3607492351 121111676 +54492157 395786200 110460614 +3835840979 3257938450 316119280 +1685817583 162560616 944821 +1626068764 0 8836276 +2760240579 3728604027 5564733 +1219249040 56415976 106144640 +2836937728 3734168760 105330821 +2994742998 2551004185 252871898 +4246162438 3909120585 48804858 +775679835 163505437 232280763 +2410909864 3957925443 149246540 +3786256842 4107171983 49584137 +2158205893 1886833148 39083587 +29680128 1636206880 24812029 +2994701606 2519949191 41392 +1137736362 531862131 73797422 +1686762404 761528450 80313588 +2942268549 4156756120 52433057 +1519923428 1464349169 88253 +4151960259 2824726292 94202179 +2568846211 1925916735 155748459 +2318401156 3839499581 5166007 + +soil-to-fertilizer map: +664927065 1834026871 25712908 +1735589252 664927065 98272608 +2065221534 1506193032 310617880 +2375839414 4115277554 6678312 +3253816560 1859739779 203737617 +1850812956 4108908733 6368821 +2919962848 2399006039 522616 +468677210 108672893 44408648 +1401161152 2664100077 99602261 +1500763413 2164180200 234825839 +3984134761 1144008481 310832535 +3804009398 3016674464 2139313 +963394967 763199673 148819056 +2382517726 2954526136 62148328 +2596720874 2399528655 264571422 +1112214023 3018813777 288947129 +1874397736 2763702338 190823798 +2920485464 4108473866 434867 +2496018070 2063477396 100702804 +3824353112 3447611199 78601908 +690639973 3526213107 99743564 +3806148711 928969825 18204401 +2861292296 3388940647 58670552 +0 356321399 298014179 +3902955020 3307760906 81179741 +360004317 0 108672893 +790383537 4121955866 173011430 +3457554177 3762018645 346455221 +1833861860 912018729 16951096 +3056982305 947174226 131597944 +2444666054 1454841016 51352016 +3188580249 1078772170 65236311 +513085858 153081541 141249720 +1857181777 1816810912 17215959 +298014179 294331261 61990138 +2920920331 3625956671 136061974 + +fertilizer-to-water map: +1314722794 2859771596 110470422 +925980570 2089240080 7623550 +2161966099 923823182 18764610 +4126382841 3495278690 168584455 +1914851626 1547043780 6792197 +3603209919 3780725227 292923781 +2451774221 919021074 4802108 +3495278690 4073649008 66625331 +3896133700 3663863145 116862082 +2180730709 506275893 271043512 +3141265861 2645889920 57381085 +3136392798 1603951687 4873063 +1538199090 942587792 376652536 +620357722 2970242018 228404928 +422454208 1814118646 197903514 +1921643823 265953617 240322276 +3561904021 4140274339 41305898 +2758272184 2474071507 63802901 +1065005613 777319405 141701669 +4012995782 4181580237 113387059 +2822075085 1553835977 50115710 +1425193216 2361065633 113005874 +933604120 1682717153 131401493 +1206707282 2537874408 108015512 +2872190795 2096863630 264202003 +2684379781 1608824750 73892403 +0 2703271005 156500591 +156500591 0 265953617 +2456576329 1319240328 227803452 +848762650 2012022160 77217920 + +water-to-light map: +3911747472 2911922447 51421887 +2536764367 3668005785 140896771 +1212477776 97723896 242971514 +3654733164 2831217728 80704719 +2181820500 1577059176 179170851 +1585336302 2992871942 130403154 +3625205556 2963344334 29527608 +637624684 802080725 399476166 +3348594580 2554606752 276610976 +2677661138 1756230027 290805772 +1715739456 3808902556 44864370 +1760603826 3853766926 127009556 +263054927 0 97723896 +3735437883 3980776482 176309589 +2052216401 4165363197 129604099 +3963169359 2047035799 96879299 +1037100850 340695410 175376926 +2968466910 3287878115 380127670 +4292066496 2319688114 2900800 +360778823 516072336 276845861 +1577059176 4157086071 8277126 +0 1201556891 263054927 +2360991351 2143915098 175773016 +1455449290 792918197 9162528 +1887613382 3123275096 164603019 +4060048658 2322588914 232017838 + +light-to-temperature map: +2208796188 2205653945 16706445 +3202718202 3702799517 119048394 +1789679483 2433538636 64618493 +3035078142 2303892266 86108184 +2549270997 3861079544 160369770 +1016521015 833146166 1531563 +2446163080 1924420264 78302216 +3321766596 2112712346 92941599 +8948937 233013740 2442944 +1900324808 3247280742 118974530 +215056009 134795275 63846376 +3929651545 3821847911 39231633 +3841595991 3463600348 88055554 +3968883178 1812769444 68270872 +2709640767 1707931127 104838317 +1494154584 2498157129 295524899 +0 1122900024 8948937 +4037154050 1450117881 257813246 +2814479084 2793682028 220599058 +3121186326 2222360390 81531876 +3568078009 4021449314 273517982 +393292224 0 134795275 +1251655629 2390000450 43538186 +2154776907 3193261461 54019281 +1854297976 1447593855 2524026 +1153492607 3551655902 98163022 +2019299338 3057783892 135477569 +93266807 850231816 121789202 +2225502633 3649818924 52980593 +377738137 834677729 15554087 +361270479 972021018 16467658 +1018052578 988488676 113796383 +72651842 1102285059 20614965 +3458088143 2002722480 109989866 +326898390 198641651 34372089 +1295193815 1248633086 198960769 +2278483226 3366255272 97345076 +2375828302 1153492607 70334778 +1856822002 3014281086 43502806 +278902385 235456684 47996005 +2524465296 1223827385 24805701 +11391881 283452689 61259961 +528087499 344712650 488433516 +3414708195 1881040316 43379948 + +temperature-to-humidity map: +1719782869 425080238 132898807 +1852681676 2807250453 270691921 +1309417343 2396884927 410365526 +963471708 0 345945635 +2998807771 345945635 79134603 +2123373597 557979045 875434174 +0 1433413219 963471708 + +humidity-to-location map: +3506221501 3772218811 141412231 +862456464 199991593 70194315 +3126163959 2720338622 159394827 +2437060415 0 153033469 +1749227774 1174286868 159521600 +349850270 652576354 37663076 +158202776 305209374 55106503 +663092217 153033469 46958124 +1358475419 819305682 231265535 +1589740954 2171223218 159486820 +1296848852 450545479 26971073 +213309279 2375483203 136540991 +501031877 1333808468 54731739 +2272970697 690239430 129066252 +427251734 1050571217 73780143 +1918845890 1626226842 116689237 +3494757929 2708875050 11463572 +2781047724 3224629140 67922856 +3442916224 4132386344 51841705 +932650779 1388540207 237686635 +387513346 1742916079 39738388 +3866389034 3340362984 418348873 +710050341 587492729 57697450 +3342406366 4184228049 100509858 +0 360315877 90229602 +812520956 1124351360 49935508 +2162994520 477516552 109976177 +2035535127 1901779730 127459393 +2719729782 3758711857 13506954 +2733236736 3292551996 47810988 +2652027470 3156926828 67702312 +767747791 2330710038 44773165 +2848970580 2879733449 277193379 +1170337414 645190179 7386175 +1177723589 1782654467 119125263 +3285558786 2652027470 56847580 +1323819925 2136567724 34655494 +1908749374 2512024194 10096516 +3647633732 3913631042 218755302 +555763616 2029239123 107328601 +2402036949 270185908 35023466 +90229602 2522120710 67973174 From 96aeb47e7185897312efd75fc7b9872067f8dbc9 Mon Sep 17 00:00:00 2001 From: Fabien Zucchet Date: Tue, 26 Nov 2024 17:09:04 +0000 Subject: [PATCH 6/6] --wip-- [skip ci] --- y2023/d05/fabienz/solution.go | 296 +++++++++++++++++---------- y2023/d05/fabienz/testdata/input.txt | 253 ++--------------------- 2 files changed, 204 insertions(+), 345 deletions(-) diff --git a/y2023/d05/fabienz/solution.go b/y2023/d05/fabienz/solution.go index 9a846e7..b8d24ea 100644 --- a/y2023/d05/fabienz/solution.go +++ b/y2023/d05/fabienz/solution.go @@ -3,6 +3,7 @@ package fabienz import ( "fmt" "io" + "regexp" "strconv" "strings" @@ -17,18 +18,19 @@ func PartOne(input io.Reader, answer io.Writer) error { return fmt.Errorf("could not read input: %w", err) } - a, err := parseInput(lines) + a, err := parseLines(lines) if err != nil { - return fmt.Errorf("could not parse input: %w", err) + return fmt.Errorf("could not parse lines: %w", err) } - locations := []int{} - - for _, seed := range a.seeds { - locations = append(locations, a.getLocationForSeed(seed)) + transformedSeeds, err := a.transformSeeds() + if err != nil { + return fmt.Errorf("could not transform seeds: %w", err) } - _, err = fmt.Fprintf(answer, "%d", helpers.MinInts(locations)) + lowestSeed := getLowestSeed(transformedSeeds) + + _, err = fmt.Fprintf(answer, "%d", lowestSeed) if err != nil { return fmt.Errorf("could not write answer: %w", err) } @@ -44,9 +46,6 @@ func PartTwo(input io.Reader, answer io.Writer) error { return fmt.Errorf("could not read input: %w", err) } - // TODO: Write code to solve Part 2 here. - - // TODO: Write your solution to Part 2 below. _, err = fmt.Fprintf(answer, "%d", len(lines)) if err != nil { return fmt.Errorf("could not write answer: %w", err) @@ -55,149 +54,224 @@ func PartTwo(input io.Reader, answer io.Writer) error { return nil } -var LINES = map[string][2]int{ - "SEED_TO_SOIL": {3, 50}, - "SOIL_TO_FERTILIZER": {53, 88}, - "FERTILIZER_TO_WATER": {91, 120}, - "WATER_TO_LIGHT": {123, 148}, - "LIGHT_TO_TEMPERATURE": {151, 194}, - "TEMPERATURE_TO_HUMIDITY": {197, 203}, - "HUMIDITY_TO_LOCATION": {206, 247}, +// 50 98 2 translates into MappedInterval{98, 2, 50-98} +type MappedInterval struct { + Start int + Length int + Offset int } -// var LINES = map[string][2]int{ -// "SEED_TO_SOIL": {3, 4}, -// "SOIL_TO_FERTILIZER": {7, 9}, -// "FERTILIZER_TO_WATER": {12, 15}, -// "WATER_TO_LIGHT": {18, 19}, -// "LIGHT_TO_TEMPERATURE": {22, 24}, -// "TEMPERATURE_TO_HUMIDITY": {27, 28}, -// "HUMIDITY_TO_LOCATION": {31, 32}, -// } +func (m *MappedInterval) String() string { + return fmt.Sprintf("[%d,%d] -> [%d, %d]", m.Start, m.Start+m.Length-1, m.Start+m.Offset, m.Start+m.Length-1+m.Offset) +} -type Range struct { - sourceStart int - destinationStart int - length int +func (m *MappedInterval) Copy() MappedInterval { + return MappedInterval{m.Start, m.Length, m.Offset} } -type Almanac struct { - seeds []int - seedToSoil []Range - soilToFertilizer []Range - fertilizerToWater []Range - waterToLight []Range - lightToTemperature []Range - temperatureToHumidity []Range - humidityToLocation []Range +func (m *MappedInterval) Contains(value int) bool { + return value >= m.Start && value < m.Start+m.Length } -func parseInput(lines []string) (a Almanac, err error) { - a = Almanac{} +func (m *MappedInterval) Map(value int) (int, error) { + if !m.Contains(value) { + return 0, fmt.Errorf("value %d is not in interval %v", value, m) + } + return value + m.Offset, nil +} - // Parse the seeds. - seeds := strings.Split(lines[0], " ")[1:] - for _, seed := range seeds { - seedInt, err := strconv.Atoi(seed) - if err != nil { - return a, fmt.Errorf("could not parse seed: %w", err) - } - a.seeds = append(a.seeds, seedInt) +func parseInterval(s string) (MappedInterval, error) { + var targetStart, sourceStart, length int + _, err := fmt.Sscanf(s, "%d %d %d", &targetStart, &sourceStart, &length) + if err != nil { + return MappedInterval{}, fmt.Errorf("could not parse interval %q: %w", s, err) } + return MappedInterval{sourceStart, length, targetStart - sourceStart}, nil +} - // Parse the seed to soil map. - for i := LINES["SEED_TO_SOIL"][0]; i <= LINES["SEED_TO_SOIL"][1]; i++ { - r, err := parseRange(lines[i]) - if err != nil { - return a, fmt.Errorf("could not parse seed to soil map: %w", err) - } - a.seedToSoil = append(a.seedToSoil, r) +type MappedIntervals []MappedInterval + +func (mm MappedIntervals) String() string { + var s string + for _, m := range mm { + s += m.String() + " " } + return s +} - // Parse the soil to fertilizer map. - for i := LINES["SOIL_TO_FERTILIZER"][0]; i <= LINES["SOIL_TO_FERTILIZER"][1]; i++ { - r, err := parseRange(lines[i]) - if err != nil { - return a, fmt.Errorf("could not parse soil to fertilizer map: %w", err) +// Given a list of intervals, sort them by their start value in ascending order +func (mm MappedIntervals) Sort() { + for i := 0; i < len(mm); i++ { + for j := i + 1; j < len(mm); j++ { + if mm[i].Start > mm[j].Start { + mm[i], mm[j] = mm[j], mm[i] + } } - a.soilToFertilizer = append(a.soilToFertilizer, r) } +} - // Parse the fertilizer to water map. - for i := LINES["FERTILIZER_TO_WATER"][0]; i <= LINES["FERTILIZER_TO_WATER"][1]; i++ { - r, err := parseRange(lines[i]) - if err != nil { - return a, fmt.Errorf("could not parse fertilizer to water map: %w", err) +func (mm MappedIntervals) Map(value int) (int, error) { + for _, m := range mm { + if m.Contains(value) { + mappedValue, err := m.Map(value) + if err != nil { + return 0, fmt.Errorf("could not map value %d: %w", value, err) + } + return mappedValue, nil } - a.fertilizerToWater = append(a.fertilizerToWater, r) } + return value, nil +} - // Parse the water to light map. - for i := LINES["WATER_TO_LIGHT"][0]; i <= LINES["WATER_TO_LIGHT"][1]; i++ { - r, err := parseRange(lines[i]) +func parseSeeds(s string) (seeds MappedIntervals, err error) { + + re := regexp.MustCompile(`\d+`) + rawSeeds := re.FindAllString(s, -1) + + seeds = make([]MappedInterval, len(rawSeeds)) + + for i, rawSeed := range rawSeeds { + seed, err := strconv.Atoi(rawSeed) if err != nil { - return a, fmt.Errorf("could not parse water to light map: %w", err) + return nil, fmt.Errorf("could not parse seed %q: %w", seed, err) } - a.waterToLight = append(a.waterToLight, r) + + seeds[i] = MappedInterval{seed, 1, 0} } - // Parse the light to temperature map. - for i := LINES["LIGHT_TO_TEMPERATURE"][0]; i <= LINES["LIGHT_TO_TEMPERATURE"][1]; i++ { - r, err := parseRange(lines[i]) + // Sort the seeds by their start value + seeds.Sort() + + return seeds, nil +} + +type Almanac struct { + Seeds MappedIntervals + AlmanacIntervals []MappedIntervals +} + +func (a *Almanac) transformSeed(seed int) (int, error) { + for _, interval := range a.AlmanacIntervals { + mappedSeed, err := interval.Map(seed) if err != nil { - return a, fmt.Errorf("could not parse light to temperature map: %w", err) + return 0, fmt.Errorf("could not map seed %d: %w", seed, err) } - a.lightToTemperature = append(a.lightToTemperature, r) + seed = mappedSeed } + return seed, nil +} - // Parse the temperature to humidity map. - for i := LINES["TEMPERATURE_TO_HUMIDITY"][0]; i <= LINES["TEMPERATURE_TO_HUMIDITY"][1]; i++ { - r, err := parseRange(lines[i]) +func (a *Almanac) transformSeeds() ([]int, error) { + transformedSeeds := make([]int, len(a.Seeds)) + for i, seed := range a.Seeds { + transformedSeed, err := a.transformSeed(seed.Start) if err != nil { - return a, fmt.Errorf("could not parse temperature to humidity map: %w", err) + return nil, fmt.Errorf("could not transform seed %d: %w", seed, err) } - a.temperatureToHumidity = append(a.temperatureToHumidity, r) + transformedSeeds[i] = transformedSeed } + return transformedSeeds, nil +} - // Parse the humidity to location map. - for i := LINES["HUMIDITY_TO_LOCATION"][0]; i <= LINES["HUMIDITY_TO_LOCATION"][1]; i++ { - r, err := parseRange(lines[i]) - if err != nil { - return a, fmt.Errorf("could not parse humidity to location map: %w", err) +// Merge two MappedIntervals using the following logic: +// - We assume that both MappedIntervals are sorted by their start value in ascending order +// - We follow a traditional merge algorithm but we need to keep the values of Offset distincts +// - Any interval that is not overlapping will be added to the result with an Offset of 0 +func mergeIntervals(a, b MappedIntervals) MappedIntervals { + merged := MappedIntervals{} + i, j := 0, 0 + for i < len(a) && j < len(b) { + // Case 1: a[i] is before b[j] - keep a[i] the same as we merge with an offset of 0 + if a[i].Start+a[i].Length < b[j].Start { + merged = append(merged, a[i]) + i++ + } else if a[i].Start > b[j].Start { + merged = append(merged, b[j]) + j++ + } else { + // We have an overlap + // We need to keep the Offset distinct + if a[i].Offset < b[j].Offset { + merged = append(merged, a[i]) + } else { + merged = append(merged, b[j]) + } + i++ + j++ } - a.humidityToLocation = append(a.humidityToLocation, r) } - return a, nil + // Add the remaining intervals + for i < len(a) { + merged = append(merged, a[i]) + i++ + } + for j < len(b) { + merged = append(merged, b[j]) + j++ + } + + return merged } -func parseRange(s string) (r Range, err error) { - fmt.Sscanf(s, "%d %d %d", &r.destinationStart, &r.sourceStart, &r.length) +// We use the fact that the lowest seed will always be at the start of an interval +func (a *Almanac) getLowestLocation() int { + lowestLocation := a.Seeds[0].Start + for _, interval := range a.AlmanacIntervals { + if interval[0].Start < lowestLocation { + lowestLocation = interval[0].Start + } + } + return lowestLocation +} - return r, nil +func getLowestSeed(seeds []int) int { + lowestSeed := seeds[0] + for _, seed := range seeds { + if seed < lowestSeed { + lowestSeed = seed + } + } + return lowestSeed } -func (a *Almanac) getLocationForSeed(seed int) (location int) { - soil := findInMap(a.seedToSoil, seed) - fertilizer := findInMap(a.soilToFertilizer, soil) - water := findInMap(a.fertilizerToWater, fertilizer) - light := findInMap(a.waterToLight, water) - temperature := findInMap(a.lightToTemperature, light) - humidity := findInMap(a.temperatureToHumidity, temperature) - location = findInMap(a.humidityToLocation, humidity) +func parseLines(lines []string) (Almanac, error) { - return location -} + a := Almanac{} + mapIdx := -1 + + for i, line := range lines { + if i == 0 { + seeds, err := parseSeeds(line) + if err != nil { + return Almanac{}, fmt.Errorf("could not parse seeds: %w", err) + } -func findInMap(m []Range, idx int) (newIdx int) { - newIdx = idx + a.Seeds = seeds + continue + } - for _, r := range m { - if idx >= r.sourceStart && idx < r.sourceStart+r.length { - newIdx = r.destinationStart + (idx - r.sourceStart) - break + if strings.Contains(line, "map:") { + mapIdx += 1 + a.AlmanacIntervals = append(a.AlmanacIntervals, MappedIntervals{}) + continue + } + + if line != "" { + interval, err := parseInterval(line) + if err != nil { + return Almanac{}, fmt.Errorf("could not parse interval: %w", err) + } + + a.AlmanacIntervals[mapIdx] = append(a.AlmanacIntervals[mapIdx], interval) + continue } } - return newIdx + // Sort the intervals by their start value + for i := range a.AlmanacIntervals { + a.AlmanacIntervals[i].Sort() + } + + return a, nil } diff --git a/y2023/d05/fabienz/testdata/input.txt b/y2023/d05/fabienz/testdata/input.txt index 749b9c5..bd902a4 100644 --- a/y2023/d05/fabienz/testdata/input.txt +++ b/y2023/d05/fabienz/testdata/input.txt @@ -1,248 +1,33 @@ -seeds: 4043382508 113348245 3817519559 177922221 3613573568 7600537 773371046 400582097 2054637767 162982133 2246524522 153824596 1662955672 121419555 2473628355 846370595 1830497666 190544464 230006436 483872831 +seeds: 79 14 55 13 seed-to-soil map: -4064811 506246814 25615317 -1520011681 1661018909 106057083 -1007960598 8836276 47579700 -1055540298 679332386 82196064 -2377475243 3574057730 33434621 -2323567163 2090355001 53908080 -2724594670 4209189177 35645909 -3247614896 4244835086 50132210 -2793935335 3209861711 43002393 -2560156404 2081665194 8689807 -3490249256 2918928471 290933240 -1399066513 1515349965 120856915 -3383052312 1779636204 107196944 -1634905040 1464437422 50912543 -0 849557294 4064811 -2155322314 2548120606 2883579 -3362202103 2803876083 20850209 -465575436 853622105 310104399 -3781182496 3252864104 5074346 -3297747106 3844665588 64454997 -1779636204 2144263081 375686110 -2765805312 2519990583 28130023 -1325393680 605659553 73672833 -1211533784 841842038 7715256 -164952771 1163726504 300622665 -2197289480 3607492351 121111676 -54492157 395786200 110460614 -3835840979 3257938450 316119280 -1685817583 162560616 944821 -1626068764 0 8836276 -2760240579 3728604027 5564733 -1219249040 56415976 106144640 -2836937728 3734168760 105330821 -2994742998 2551004185 252871898 -4246162438 3909120585 48804858 -775679835 163505437 232280763 -2410909864 3957925443 149246540 -3786256842 4107171983 49584137 -2158205893 1886833148 39083587 -29680128 1636206880 24812029 -2994701606 2519949191 41392 -1137736362 531862131 73797422 -1686762404 761528450 80313588 -2942268549 4156756120 52433057 -1519923428 1464349169 88253 -4151960259 2824726292 94202179 -2568846211 1925916735 155748459 -2318401156 3839499581 5166007 +50 98 2 +52 50 48 soil-to-fertilizer map: -664927065 1834026871 25712908 -1735589252 664927065 98272608 -2065221534 1506193032 310617880 -2375839414 4115277554 6678312 -3253816560 1859739779 203737617 -1850812956 4108908733 6368821 -2919962848 2399006039 522616 -468677210 108672893 44408648 -1401161152 2664100077 99602261 -1500763413 2164180200 234825839 -3984134761 1144008481 310832535 -3804009398 3016674464 2139313 -963394967 763199673 148819056 -2382517726 2954526136 62148328 -2596720874 2399528655 264571422 -1112214023 3018813777 288947129 -1874397736 2763702338 190823798 -2920485464 4108473866 434867 -2496018070 2063477396 100702804 -3824353112 3447611199 78601908 -690639973 3526213107 99743564 -3806148711 928969825 18204401 -2861292296 3388940647 58670552 -0 356321399 298014179 -3902955020 3307760906 81179741 -360004317 0 108672893 -790383537 4121955866 173011430 -3457554177 3762018645 346455221 -1833861860 912018729 16951096 -3056982305 947174226 131597944 -2444666054 1454841016 51352016 -3188580249 1078772170 65236311 -513085858 153081541 141249720 -1857181777 1816810912 17215959 -298014179 294331261 61990138 -2920920331 3625956671 136061974 +0 15 37 +37 52 2 +39 0 15 fertilizer-to-water map: -1314722794 2859771596 110470422 -925980570 2089240080 7623550 -2161966099 923823182 18764610 -4126382841 3495278690 168584455 -1914851626 1547043780 6792197 -3603209919 3780725227 292923781 -2451774221 919021074 4802108 -3495278690 4073649008 66625331 -3896133700 3663863145 116862082 -2180730709 506275893 271043512 -3141265861 2645889920 57381085 -3136392798 1603951687 4873063 -1538199090 942587792 376652536 -620357722 2970242018 228404928 -422454208 1814118646 197903514 -1921643823 265953617 240322276 -3561904021 4140274339 41305898 -2758272184 2474071507 63802901 -1065005613 777319405 141701669 -4012995782 4181580237 113387059 -2822075085 1553835977 50115710 -1425193216 2361065633 113005874 -933604120 1682717153 131401493 -1206707282 2537874408 108015512 -2872190795 2096863630 264202003 -2684379781 1608824750 73892403 -0 2703271005 156500591 -156500591 0 265953617 -2456576329 1319240328 227803452 -848762650 2012022160 77217920 +49 53 8 +0 11 42 +42 0 7 +57 7 4 water-to-light map: -3911747472 2911922447 51421887 -2536764367 3668005785 140896771 -1212477776 97723896 242971514 -3654733164 2831217728 80704719 -2181820500 1577059176 179170851 -1585336302 2992871942 130403154 -3625205556 2963344334 29527608 -637624684 802080725 399476166 -3348594580 2554606752 276610976 -2677661138 1756230027 290805772 -1715739456 3808902556 44864370 -1760603826 3853766926 127009556 -263054927 0 97723896 -3735437883 3980776482 176309589 -2052216401 4165363197 129604099 -3963169359 2047035799 96879299 -1037100850 340695410 175376926 -2968466910 3287878115 380127670 -4292066496 2319688114 2900800 -360778823 516072336 276845861 -1577059176 4157086071 8277126 -0 1201556891 263054927 -2360991351 2143915098 175773016 -1455449290 792918197 9162528 -1887613382 3123275096 164603019 -4060048658 2322588914 232017838 +88 18 7 +18 25 70 light-to-temperature map: -2208796188 2205653945 16706445 -3202718202 3702799517 119048394 -1789679483 2433538636 64618493 -3035078142 2303892266 86108184 -2549270997 3861079544 160369770 -1016521015 833146166 1531563 -2446163080 1924420264 78302216 -3321766596 2112712346 92941599 -8948937 233013740 2442944 -1900324808 3247280742 118974530 -215056009 134795275 63846376 -3929651545 3821847911 39231633 -3841595991 3463600348 88055554 -3968883178 1812769444 68270872 -2709640767 1707931127 104838317 -1494154584 2498157129 295524899 -0 1122900024 8948937 -4037154050 1450117881 257813246 -2814479084 2793682028 220599058 -3121186326 2222360390 81531876 -3568078009 4021449314 273517982 -393292224 0 134795275 -1251655629 2390000450 43538186 -2154776907 3193261461 54019281 -1854297976 1447593855 2524026 -1153492607 3551655902 98163022 -2019299338 3057783892 135477569 -93266807 850231816 121789202 -2225502633 3649818924 52980593 -377738137 834677729 15554087 -361270479 972021018 16467658 -1018052578 988488676 113796383 -72651842 1102285059 20614965 -3458088143 2002722480 109989866 -326898390 198641651 34372089 -1295193815 1248633086 198960769 -2278483226 3366255272 97345076 -2375828302 1153492607 70334778 -1856822002 3014281086 43502806 -278902385 235456684 47996005 -2524465296 1223827385 24805701 -11391881 283452689 61259961 -528087499 344712650 488433516 -3414708195 1881040316 43379948 +45 77 23 +81 45 19 +68 64 13 temperature-to-humidity map: -1719782869 425080238 132898807 -1852681676 2807250453 270691921 -1309417343 2396884927 410365526 -963471708 0 345945635 -2998807771 345945635 79134603 -2123373597 557979045 875434174 -0 1433413219 963471708 +0 69 1 +1 0 69 humidity-to-location map: -3506221501 3772218811 141412231 -862456464 199991593 70194315 -3126163959 2720338622 159394827 -2437060415 0 153033469 -1749227774 1174286868 159521600 -349850270 652576354 37663076 -158202776 305209374 55106503 -663092217 153033469 46958124 -1358475419 819305682 231265535 -1589740954 2171223218 159486820 -1296848852 450545479 26971073 -213309279 2375483203 136540991 -501031877 1333808468 54731739 -2272970697 690239430 129066252 -427251734 1050571217 73780143 -1918845890 1626226842 116689237 -3494757929 2708875050 11463572 -2781047724 3224629140 67922856 -3442916224 4132386344 51841705 -932650779 1388540207 237686635 -387513346 1742916079 39738388 -3866389034 3340362984 418348873 -710050341 587492729 57697450 -3342406366 4184228049 100509858 -0 360315877 90229602 -812520956 1124351360 49935508 -2162994520 477516552 109976177 -2035535127 1901779730 127459393 -2719729782 3758711857 13506954 -2733236736 3292551996 47810988 -2652027470 3156926828 67702312 -767747791 2330710038 44773165 -2848970580 2879733449 277193379 -1170337414 645190179 7386175 -1177723589 1782654467 119125263 -3285558786 2652027470 56847580 -1323819925 2136567724 34655494 -1908749374 2512024194 10096516 -3647633732 3913631042 218755302 -555763616 2029239123 107328601 -2402036949 270185908 35023466 -90229602 2522120710 67973174 +60 56 37 +56 93 4 \ No newline at end of file