From 071c20222ac810cf5cf5472f8755373800812e63 Mon Sep 17 00:00:00 2001 From: Ian Fijolek Date: Mon, 4 Jan 2021 11:55:10 -0500 Subject: [PATCH] Initial commit d01-24 --- .gitignore | 5 + .golangci.yml | 5 + README.md | 5 + d01/aoc-d1-input.txt | 200 ++++ d01/main.go | 81 ++ d01/main.py | 36 + d02/input.txt | 1000 +++++++++++++++++++ d02/main.go | 110 +++ d02/main.py | 44 + d03/input.txt | 323 +++++++ d03/main.go | 120 +++ d03/main.py | 107 ++ d04/input.txt | 1100 +++++++++++++++++++++ d04/invalid.txt | 13 + d04/main.go | 149 +++ d04/main.py | 121 +++ d04/valid.txt | 12 + d05/input.txt | 874 +++++++++++++++++ d05/main.go | 128 +++ d05/main.py | 65 ++ d06/input.txt | 2199 ++++++++++++++++++++++++++++++++++++++++++ d06/main.go | 141 +++ d06/main.py | 43 + d07/input.txt | 594 ++++++++++++ d07/main.py | 82 ++ d08/input.txt | 596 ++++++++++++ d08/main.py | 94 ++ d09/input.txt | 1000 +++++++++++++++++++ d09/main.go | 273 ++++++ d09/testinput.txt | 20 + d10/input.txt | 94 ++ d10/main.go | 217 +++++ d11/input-small.txt | 10 + d11/input.txt | 98 ++ d11/main.go | 463 +++++++++ d12/input.txt | 779 +++++++++++++++ d12/main.go | 180 ++++ d13/input.txt | 2 + d13/main.py | 132 +++ d14/input.txt | 572 +++++++++++ d14/main.go | 200 ++++ d15/main.go | 94 ++ d16/input-small.txt | 12 + d16/input-small2.txt | 11 + d16/input.txt | 261 +++++ d16/main.go | 399 ++++++++ d17/input.txt | 8 + d17/main.go | 113 +++ d17/main.py | 703 ++++++++++++++ d17/util.go | 300 ++++++ d18/input-small.txt | 4 + d18/input.txt | 373 +++++++ d18/main.py | 88 ++ d18/main2.py | 96 ++ d19/input.txt | 538 +++++++++++ d19/main.py | 381 ++++++++ d20/input.txt | 1727 +++++++++++++++++++++++++++++++++ d20/main.py | 400 ++++++++ d20/output.txt | 142 +++ d20/test-input.txt | 107 ++ d21/input.txt | 46 + d21/main.py | 105 ++ d21/sample-input.txt | 4 + d22/input.txt | 54 ++ d22/loop-input.txt | 8 + d22/main.py | 174 ++++ d22/sample-input.txt | 13 + d23/main.py | 171 ++++ d23/main2.py | 157 +++ d24/__init__.py | 0 d24/expanding.py | 662 +++++++++++++ d24/input.txt | 547 +++++++++++ d24/main.py | 231 +++++ d24/main2.py | 136 +++ main.go | 14 + util.go | 300 ++++++ 76 files changed, 20666 insertions(+) create mode 100644 .gitignore create mode 100644 .golangci.yml create mode 100644 README.md create mode 100644 d01/aoc-d1-input.txt create mode 100644 d01/main.go create mode 100755 d01/main.py create mode 100644 d02/input.txt create mode 100644 d02/main.go create mode 100755 d02/main.py create mode 100644 d03/input.txt create mode 100644 d03/main.go create mode 100755 d03/main.py create mode 100644 d04/input.txt create mode 100644 d04/invalid.txt create mode 100644 d04/main.go create mode 100755 d04/main.py create mode 100644 d04/valid.txt create mode 100644 d05/input.txt create mode 100644 d05/main.go create mode 100755 d05/main.py create mode 100644 d06/input.txt create mode 100644 d06/main.go create mode 100755 d06/main.py create mode 100644 d07/input.txt create mode 100755 d07/main.py create mode 100644 d08/input.txt create mode 100755 d08/main.py create mode 100644 d09/input.txt create mode 100644 d09/main.go create mode 100644 d09/testinput.txt create mode 100644 d10/input.txt create mode 100644 d10/main.go create mode 100644 d11/input-small.txt create mode 100644 d11/input.txt create mode 100644 d11/main.go create mode 100644 d12/input.txt create mode 100644 d12/main.go create mode 100644 d13/input.txt create mode 100755 d13/main.py create mode 100644 d14/input.txt create mode 100644 d14/main.go create mode 100644 d15/main.go create mode 100644 d16/input-small.txt create mode 100644 d16/input-small2.txt create mode 100644 d16/input.txt create mode 100644 d16/main.go create mode 100644 d17/input.txt create mode 100644 d17/main.go create mode 100755 d17/main.py create mode 100644 d17/util.go create mode 100644 d18/input-small.txt create mode 100644 d18/input.txt create mode 100755 d18/main.py create mode 100755 d18/main2.py create mode 100644 d19/input.txt create mode 100755 d19/main.py create mode 100644 d20/input.txt create mode 100755 d20/main.py create mode 100644 d20/output.txt create mode 100644 d20/test-input.txt create mode 100644 d21/input.txt create mode 100755 d21/main.py create mode 100644 d21/sample-input.txt create mode 100644 d22/input.txt create mode 100644 d22/loop-input.txt create mode 100755 d22/main.py create mode 100644 d22/sample-input.txt create mode 100755 d23/main.py create mode 100755 d23/main2.py create mode 100644 d24/__init__.py create mode 100644 d24/expanding.py create mode 100644 d24/input.txt create mode 100755 d24/main.py create mode 100755 d24/main2.py create mode 100644 main.go create mode 100644 util.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3791316 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +*.pyc +__pycache__ +tags +tags.lock +tags.temp diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000..771f0bf --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,5 @@ +--- +linters: + disable: + - gochecknoglobals + - goerr113 diff --git a/README.md b/README.md new file mode 100644 index 0000000..402f14f --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +https://adventofcode.com/ + +Each day is organized in a subfolder. There is no consistency at all. + +Good luck! diff --git a/d01/aoc-d1-input.txt b/d01/aoc-d1-input.txt new file mode 100644 index 0000000..c9d1743 --- /dev/null +++ b/d01/aoc-d1-input.txt @@ -0,0 +1,200 @@ +1934 +1702 +1571 +1737 +1977 +1531 +1428 +1695 +1794 +1101 +13 +1164 +1235 +1289 +1736 +1814 +1363 +1147 +1111 +1431 +1765 +1515 +1184 +1036 +1803 +1791 +1638 +1809 +1283 +1980 +1854 +1878 +1574 +1352 +1151 +730 +1581 +1990 +1919 +2003 +1538 +1663 +1735 +1772 +1830 +1152 +1022 +1774 +1544 +1551 +1835 +1383 +1614 +1396 +1715 +1530 +295 +1208 +1978 +1104 +1691 +1176 +1183 +1909 +1192 +1535 +1924 +1268 +1969 +1954 +1760 +1077 +1734 +1371 +1676 +1933 +1400 +1928 +1982 +1541 +1106 +1248 +1346 +1782 +1142 +1849 +1798 +1362 +1379 +1886 +1265 +1226 +1751 +1575 +1027 +1710 +1601 +1205 +1922 +1452 +1206 +1263 +2000 +1957 +1951 +1834 +1533 +1149 +1245 +1564 +1182 +1237 +1013 +1254 +1895 +1504 +1480 +1556 +1821 +1589 +1864 +1573 +1698 +1927 +1434 +516 +1722 +1360 +1940 +1212 +1329 +1675 +1812 +1917 +1302 +1604 +1336 +1233 +1405 +1179 +1169 +1081 +1941 +1553 +1236 +1824 +1923 +1938 +1475 +1446 +1545 +1853 +1664 +317 +1489 +1884 +1743 +1621 +1128 +1474 +1505 +394 +1387 +1509 +1627 +1914 +1913 +1949 +1843 +1847 +1882 +1486 +1082 +1802 +1645 +1690 +1629 +1377 +2004 +1044 +1191 +1014 +1857 +1813 +1572 +1055 +1002 +1721 +1273 +1417 +1968 +1888 +1863 +1278 +1141 +1964 +1259 +1823 +1181 +1779 diff --git a/d01/main.go b/d01/main.go new file mode 100644 index 0000000..61851b0 --- /dev/null +++ b/d01/main.go @@ -0,0 +1,81 @@ +package main + +import ( + "bufio" + "fmt" + "log" + "os" + "strconv" +) + +func proccessLines(path string, f func(string) (stop bool, err error)) error { + file, err := os.Open(path) + if err != nil { + return err + } + defer file.Close() + scanner := bufio.NewScanner(file) + for scanner.Scan() { + stop, err := f(scanner.Text()) + if stop || err != nil { + return err + } + } + if err := scanner.Err(); err != nil { + return err + } + return nil +} + +func part1() { + seen := map[int]bool{} + err := proccessLines("./aoc-d1-input.txt", func(line string) (bool, error) { + num, err := strconv.Atoi(line) + if err != nil { + return true, err + } + pair := 2020 - num + if _, ok := seen[pair]; ok { + fmt.Printf("Found pair! %d + %d = 2020 Product = %d\n", num, pair, num*pair) + return true, nil + } + seen[num] = true + return false, nil + }) + if err != nil { + log.Fatal(err) + } +} + +type numberPair struct { + A, B int +} + +func part2() { + singles := map[int]bool{} + doubles := map[int]numberPair{} + err := proccessLines("./aoc-d1-input.txt", func(line string) (bool, error) { + num, err := strconv.Atoi(line) + if err != nil { + return true, err + } + remain := 2020 - num + if pair, ok := doubles[remain]; ok { + fmt.Printf("Found set! %d + %d + %d = 2020 Prouct = %d\n", num, pair.A, pair.B, num*pair.A*pair.B) + return true, nil + } + for single := range singles { + doubles[num+single] = numberPair{num, single} + } + singles[num] = true + return false, nil + }) + if err != nil { + log.Fatal(err) + } +} + +func main() { + part1() + part2() +} diff --git a/d01/main.py b/d01/main.py new file mode 100755 index 0000000..439c1ac --- /dev/null +++ b/d01/main.py @@ -0,0 +1,36 @@ +#! /usr/bin/env python3 + + +def part1(): + print("Part1:") + seen = set() + with open("./aoc-d1-input.txt", "r") as f: + for line in f: + v = int(line) + remain = 2020 - v + if remain in seen: + print(f"{v} * {remain} = {v*remain}") + break + seen.add(v) + + +def part2(): + print("Part2:") + singles = set() + doubles = {} + with open("./aoc-d1-input.txt", "r") as f: + for line in f: + v = int(line) + remain = 2020 - v + if remain in doubles: + n2, n3 = doubles[remain] + print(f"{v} * {n2} * {n3} = {v*n2*n3}") + break + for n1 in singles: + doubles[v+n1] = (v, n1) + singles.add(v) + + +if __name__ == "__main__": + part1() + part2() diff --git a/d02/input.txt b/d02/input.txt new file mode 100644 index 0000000..2da5b54 --- /dev/null +++ b/d02/input.txt @@ -0,0 +1,1000 @@ +2-6 c: fcpwjqhcgtffzlbj +6-9 x: xxxtwlxxx +5-6 w: wwwwlwwwh +7-10 q: nfbrgwqlvljgq +2-3 g: gjggg +9-11 q: qqqqqqnqgqq +14-20 b: bbbbbbbbbbbbzwbbbbbb +2-6 s: sjsssss +4-13 b: mdbctbzgcpdjbhsdctrd +5-6 t: tttttt +7-9 h: zbhhfmwhhpxh +3-4 t: ttmt +4-6 j: jjjjjj +12-13 w: wwwwwwwwwwwwkw +3-4 f: sgbmjfftf +11-12 p: pdppppppppcppp +5-9 q: qqqqqvsqdjq +5-8 j: qsljqmxwk +1-7 w: gwvktwwwkwwww +2-3 w: gvwcvrggjbk +1-4 d: kddd +13-14 k: zkkpkkkkkksskp +2-5 w: wwwwfw +4-5 n: bnrnlnnkdvhbnnj +7-17 s: kswscfssbssztsgwmdr +9-14 h: hhhhhhhvhhhhhbhhhhh +1-2 s: sgvmzrpssss +1-4 x: xxvgbxwxqx +5-9 b: bbbbbbqbdbbzbxb +6-10 d: ndddkqdddd +8-9 z: zzqvkhpzzhx +10-11 k: jrktpgkvkqk +2-4 l: lklf +14-16 c: cxqccccccccccctccc +1-2 g: bsmmpkmd +4-16 q: vmqdqktlqqnhzqqx +6-12 k: kqkwkktfbklkjnkqrtmb +15-16 v: vvvvvvvvvvvvvvxt +12-13 r: rrrrrrsrrrrrx +5-7 p: ppbqlppppp +5-8 s: dxmsqssk +3-4 m: mxmlmm +6-7 c: kcfcbhcc +4-6 z: zzzxzxz +12-14 r: rrrrmrrrrrrrrkkltr +4-6 j: zhbtgg +5-7 r: rrdrrrzrr +1-3 x: rxcxxxxxxxxxxxxx +5-7 g: ggggggvgmcg +12-15 n: nnnnnnnnnnnnnnhn +4-6 p: qppppppp +9-12 j: pjjsmbjjjjjj +3-16 b: bhgbtjhqvkpgcbgbpbz +2-7 q: mqfhknwswqjxjncxjt +6-16 c: wclpphqjcmbzdwccp +13-15 k: dkkdkkkkkkkknkkcn +7-9 b: blfbbbhvz +14-18 w: wwwwwwwvwvwwwwwwwc +11-18 w: xstwwbwwwwwwtrbwww +3-14 z: zdgxzpvzjztfzzrpjz +7-10 j: mjrxjstdnj +10-13 f: ffrfqflffftjkf +1-4 j: jnjtjfj +8-9 g: wtbqjjggjfcvgs +2-7 z: qpwvvjcpzf +3-4 k: kfgk +6-12 l: lllllllllllw +14-15 n: nnnnnnnnnnnnnpr +10-11 p: prcpwdzmcqp +12-14 v: vvvrvvvqvvvschvvzvv +1-11 q: jqqqkfqqqqqqqqwqq +11-12 j: jjjjjjjjjjtj +2-6 x: nqxxxx +7-17 s: blbvqsssssssnslgswz +9-10 s: ssssssssbsss +1-2 t: ttvqtt +3-8 w: bsddhgwb +1-2 r: jrxdfg +8-9 j: ljjjjjjljfmj +1-3 j: jjjjjjjjjdkjj +4-13 f: jfffmsffmfxrmhnf +1-4 s: sswvjx +4-8 b: btfgtwkvdfqkwv +2-3 p: tptddqdkgdfcbxxrpv +1-4 p: dspz +14-16 d: ddddhdvdddddtddh +6-9 l: hnvrpllsl +4-5 h: hjhzhnh +3-10 b: zsvjzttjnbbgdt +12-15 c: ccjscwcccdcccccl +1-9 j: xjjjkjjlj +1-9 m: gngmvxqmmmmhmmml +9-10 k: kkkkkkkkpc +13-14 q: qrsxtpgpnhcrkq +3-6 k: pkjcks +1-3 t: ttjtt +10-15 f: sjwnfftrffptbqltg +3-4 b: nwbtnz +5-7 k: kkkkkkdk +14-18 l: lglllllllllllllllrpl +1-14 q: fqqqqqqdqqqqvd +16-18 p: pppppppppppppppppn +3-7 l: lllllgvx +2-5 b: pbbkcbbbbbg +7-9 c: bcnjkzxccl +4-5 x: cwxxfxtmqtxxp +10-11 d: dddddwcxdvddbdddd +3-5 v: vvvvlvv +4-7 m: mmmmmltldmmmbk +13-14 s: sssssssssssssks +4-6 s: ssslszs +15-16 z: dzbzfxmpzhrrszzf +5-12 x: xrzxxxgxtcxxxxxx +17-19 g: ggggggggggggggxwjgq +12-13 n: nnnnnnhnnnnjn +8-10 l: llllllltllldlll +9-14 t: fttftqttmtkstdf +4-11 l: nnlljlhllllx +5-7 q: qhpzqjl +2-6 v: fglnsvvwlpx +2-3 b: mbvbb +4-9 w: wwqwwwjwmz +1-4 j: jjxpmsk +6-8 c: pckczdcccncr +3-6 x: xbslxxzhqn +11-17 j: jdkjkjjjjbjxjjjjsj +4-8 h: hphbzhjh +12-14 x: xxxxxrxxxxxxxrx +2-4 q: kqgm +1-14 r: lrtrzrrrsrrzrr +5-15 w: tpwwwbdlbxczwcgwnvbw +1-4 p: qppsppp +1-9 z: zzzzzzzzzzzzzz +8-12 t: tttttttbttst +2-3 n: bkfn +5-8 w: xwwwwwwdw +9-10 c: csdccccqcgcbxcn +3-5 v: mvfvvqvvm +2-5 r: rrstrnzfrdwrvbpfqz +1-4 m: mmmmmmmmmmmmmmmmm +8-9 m: mmmmmmmmg +3-6 l: llllll +3-5 j: jjgjft +10-11 b: xtlppqfbnkq +15-17 p: pppxpppfppppppppb +7-8 f: ffbmfffd +6-11 t: htgvbttnjzpkt +5-6 t: tvttwt +8-10 b: bbqbrtbrbb +6-10 x: xxspxkxmpxxxvrcxx +3-6 f: lgrxkfrfkfj +1-7 f: fffffftf +5-6 t: rcjtqtwvgsttc +12-13 k: kkmgwdjmgpkkgrkk +1-13 w: dwdwzlwxrtvhwwhmwj +3-13 n: nnwnnnnnnnfnnnnn +9-10 j: kbjjcsjtjn +17-18 v: vvvvvvvvvvvvvvvvvh +11-17 z: zzqkzzzzdzhzgzzzvzz +7-11 f: nrdftjqffff +3-8 t: tttttttctt +4-5 r: rrcrwrf +5-7 c: ccqccccccc +13-14 r: rrdrrrfrrrrrhrr +9-12 s: xjddslskrjpd +8-9 n: nnnpgnnbnnnn +6-10 j: wjjdjjjjjpjjjj +1-7 z: hzzzzzzzz +4-7 b: bbbzbbbxlb +4-13 t: tttqnttttkxtt +6-9 h: vhphhzhhshh +2-10 p: bpfwnncsmtppppsq +3-19 n: dnklnrnnnnfnnnngndn +5-15 n: nnnnknnnnnnnnnsnnnn +6-8 t: trttttwv +8-12 m: mtmmbkmxmjdjmmmtm +2-8 k: kjkkkkkkkk +6-8 n: xrnmndqn +13-16 n: nnnnnnnnnnnndnnnnnn +14-15 c: cswjctfcccrccxc +2-9 k: knkkkkkkj +5-12 r: rxrfwrdrcmdr +6-11 v: vxwsnvnxvgs +12-13 n: nnnnnnnnprnnmn +1-3 l: blbz +4-7 h: hhhbhhh +8-12 m: mqhrnmzmmmmmm +6-15 n: nnnnnpnnnbnnnnzn +3-6 q: lzjcxqpmjqsbqgxjql +6-7 q: qqqnqrq +5-7 q: qtlhqct +3-5 q: qlxmq +2-3 n: knnn +4-5 z: zzzzh +4-9 r: rrrwlprfrlrnpzrrmwt +14-15 j: fchdfjzmdrjxrxj +1-4 m: dmmm +2-4 x: wxkmpxn +5-11 r: rvblrrjkvrsbr +1-2 c: ntcmkz +14-16 h: hhhhhhhhhhfhhhhhhh +1-3 h: cnsvhm +4-5 w: wwwww +7-10 j: jjjjjjjjjsjjj +9-14 j: zjjjjjjjkjjjjwj +12-13 k: nqwkrcpkkkkkkk +3-5 k: vxkkj +6-7 j: pjjjtjpjjjw +2-3 j: jjsg +4-5 g: ggggcg +3-5 b: wbbnvxw +2-4 h: gwjhqj +3-4 l: ltlm +8-10 j: bjpdpvtjdj +1-7 v: vbfvvsvcvv +11-16 j: jbjhjjjjjjjjjjjc +6-13 b: bmswrnbdhbrfbmbb +1-4 x: xxxh +4-10 c: wjgcwbrkxk +11-13 v: sfbcphvzttvmzv +6-16 q: pqqqqqqqqqqqqqqq +10-12 w: wwwwwwwwwswww +2-9 b: fbwwwbrdp +3-4 v: vvnvvvvv +8-14 x: drwxxvqdgmpxmxfcxr +8-10 k: kkkkklkkkc +4-7 j: jcwrjjjfc +3-4 c: cczcgc +3-12 l: smllklclprdvlsl +1-2 j: fjqd +10-19 g: gggggggggqggggggggxg +3-5 m: fpmmmvb +2-3 c: ccmc +3-7 v: pvqktqh +1-3 c: ccfv +4-5 x: khxxj +3-4 g: ggbgf +1-9 x: xxhxxxxxx +5-6 f: zfffmfff +5-8 l: gmlqlkrl +7-10 c: ccccckcscsb +1-3 p: spppp +1-3 v: qmvvv +15-16 z: czhzzzzzpzzzzzzkzz +2-4 r: rrrr +3-13 k: kktkkgkkkkkkgkk +10-13 p: bpqpxpqqtprjn +6-7 j: jwnjjjxj +2-8 w: wmgwdwww +12-14 g: gggggggcgggggg +4-8 f: mdffklwtcj +2-7 j: jmjxjdxjrbrjjdjjrjwj +3-4 m: mmml +5-7 l: wllkqll +6-10 s: ssqcpssddslxncsbs +6-11 n: nnnvnznnnnwn +9-10 w: cbbqgrqglwgqskw +1-8 v: nvvzlhcvvvslv +1-3 t: tttttt +3-6 f: mftpff +1-11 t: pmjtttttttl +8-11 h: hhkmfhvhnwwhhhhhhh +4-6 k: kkkrkkkb +2-17 x: zzxxzvrsbmjxnxxxx +5-6 d: zdhxdldm +1-4 c: nmcc +2-4 j: njjjj +7-13 s: jjsbqrsddsclpvs +10-15 f: mbffrlpjtptgfff +10-13 d: dddddvddddddv +8-9 g: gxhgkggrgc +2-4 b: tbbcnkvp +9-11 g: ggggghgldgpggvg +4-5 m: mmmvm +2-5 d: ddfdp +8-11 r: rrrsrlcmltgrrbr +9-11 r: rrgrrrrxwrrr +3-11 g: zgggvgdggdsj +13-15 x: xxxxxxxvkxxxrxlbxx +13-16 b: bbbrbbpbbfcbqbbxbbb +7-10 x: jxlhxxxxxbx +1-12 p: plkprppjpppb +9-10 t: ttttttttft +1-5 q: qqqsqqjsqp +6-9 m: mzmmmlqmmgm +6-7 j: pbjjkjcj +8-9 b: bbbbbbbbxb +1-2 c: cflj +12-15 c: xskhcckcttmtmfc +5-6 p: pppppb +10-18 v: vjrplvzjxmjvvrvvfvd +3-5 x: hvfqxxqzqz +1-10 t: sttttttbttftttttttt +4-7 f: nrxknwf +3-9 l: fllltcllltlsjlc +10-16 x: cxxxxhxjrxxqjxxkxcx +10-14 m: mdmmmcmmmmmmmmmm +2-17 n: nmnnnnnnnnnnnnnnnn +7-11 s: dtpqdssfbbsrl +1-4 h: hhqh +2-7 j: jjrbbmjps +3-4 d: dhsddvflkqdvgd +6-7 m: gmmmpmr +2-9 j: jjjjjjjtpjjjjjjjjj +12-13 g: gggggggtggggz +16-17 p: ppppppppppppppppspp +6-8 w: wntlwwwhnwtgwhwjj +2-4 s: tntsjn +4-6 t: tgtgtt +6-7 f: qpffwwfv +3-5 k: zltkkgsvjhrbxwvkg +8-10 l: ljlwlgpllkklllflrb +3-5 q: qqbqqqs +4-5 f: zfffb +2-5 b: bbzhbbbb +4-5 q: sfhqpqtqbrbgdqgqw +13-14 k: kkkkdkkkkkgtkzpqkkk +4-9 p: bnpwptvkps +10-11 n: nnnnnnnnnnsnnn +12-14 d: ntpzdcqdpsrmddkcwgc +4-10 g: wgxxgsgggkchgggkg +2-7 q: qwbqccqlqmqqqsqcw +3-5 d: ddddddd +2-4 v: vwsvv +4-13 p: pppppppprppql +6-8 s: zcxssstnfr +8-9 f: zfffcqfff +10-11 m: qmbmmmmmpmx +1-3 j: qvjjkn +14-16 d: zfdmddxdrddvdcdc +5-10 w: rwwwwwwwwww +1-4 p: cmpp +2-3 f: dffff +4-8 n: nnnznznnn +1-4 t: bvrntkt +5-6 v: xjgvnvmgfwxvvv +2-4 w: tvwgtc +1-7 f: ffffffdfc +15-18 w: wwwwwwwwwwwwvwwwwww +1-2 t: jtct +2-3 k: cskdkkkl +3-19 q: qpfqqmqqqqqqqqqqqtqq +2-9 n: wnnjcngnkdnbnlrcbvns +1-14 d: vddfpndddfddddjhddd +1-2 m: bmmbwtwml +3-4 p: ppgrprpgrqb +2-3 m: mrmmm +5-6 l: zllllz +8-13 k: xkzptdzzkggkv +5-6 j: jjjjcj +4-5 b: bbcdfb +1-2 b: vbmbrbsf +8-9 q: lqhmjvdqgnxmb +2-4 n: snmrcnntn +11-15 r: rrsjrfrmqrlrqrz +2-3 l: dlblr +2-3 h: cthlxj +8-15 l: lllwlllllclfllbl +6-7 q: hqqqqqjq +13-14 f: ffffffffffffhf +2-4 v: dtxvztgnvffxlxfcdwf +5-11 h: hxhkhpfnhlchh +3-5 n: nnwcj +12-15 s: sssssssssmssssrcl +1-6 d: rdddddddd +14-15 b: bzbfnbbbbbbbbpxbb +4-8 w: jkxpzcnwhzsgmbkw +7-13 t: ttmlfbttdttgtpvktt +8-11 z: jdqfmwgltdztpzc +13-17 s: sssshsssssskslsxnss +9-10 t: tttttttttf +3-4 l: sllzl +1-2 s: ksxsxbwjn +12-17 l: dlvflhjmlgtldlllr +1-5 f: hfffffhf +5-12 f: gmklffbffztjfwswdg +18-19 z: zzzzzzzzzzzzzzzzzqz +1-5 c: cwccgcc +3-4 p: pspp +5-9 n: tknnnnsjwnsntng +6-7 x: xxxxxxm +6-10 g: szrpggtlwr +9-11 s: xgwsbcssxcs +8-9 t: dtttdtzrt +5-11 d: snddldcdhdd +11-13 m: fbkmsdvklzmtmkmmbjq +10-13 s: nqnsssmsvwrrs +3-4 w: hwnwk +5-11 h: ztkpgzhpfhh +6-7 w: wwwwwwww +3-4 z: zvzzczzlglv +13-14 l: llllllllllllll +12-13 x: xxxwxxxxxxxgx +3-4 p: mxkppr +2-3 d: ddbdt +3-5 l: zlplllphl +3-7 p: spmrbvp +4-5 b: bbbvn +16-17 l: zzxvmvxsgrprbclvl +4-7 h: hphwfshhrpgdmktsphhl +1-5 l: nllllll +4-5 r: rrrnr +5-9 k: bbkwgkklqkqhkk +4-5 t: sttnt +15-16 f: fffjffffffsdffwfsff +5-8 z: bzzzzjzzzv +5-7 f: qqzzffmfvb +3-10 m: zmmpmfcwdmfmvc +3-4 z: zlzzz +2-3 c: cjcsl +5-15 r: mrdznrsrctlrrqrflzm +8-11 g: ggggggggggdg +5-10 s: bnshsbvrthssmq +7-10 m: mmhmmmmmmmm +14-17 h: hhhhhhhhhhhnmkhhhhh +1-5 n: nnsnx +4-17 j: jmxjdkgbhjxflrmqjjdj +6-8 m: mmmmmmmb +3-5 p: ppppxrpp +3-8 t: jtjtttqttt +17-18 k: xklkkkkkgkfmrkkhkbhh +1-3 k: kkhk +13-14 j: jjjjjjjjbjjjgj +9-12 q: cmwwkzrkqsqqqmqhqb +3-8 s: sssfclpwhssfss +3-6 s: mshsfss +10-16 p: plftpppkpqppppppp +4-5 d: dddgdq +4-5 s: slsss +1-7 z: zzgxkzf +6-7 w: wwwwlwz +11-12 w: mqwwwwwwwwbzw +13-14 t: ttttttttttttlt +9-10 c: ccccccccvc +9-13 q: qmqqqqqqhqqqqq +1-7 z: rzzzzzmzzzzz +7-16 w: wwwwwwwwwwwwwwwcw +4-5 m: nkmrmxz +8-9 q: qqmqqcmqlqqqqw +10-15 x: ltnxqwwxxztmzhxxmnt +3-6 r: pkvpfprgwm +10-11 k: kkkkkkkkkkkk +3-4 c: ccfjs +1-6 n: nqvkzjn +9-12 k: qkhxrknkkzpk +8-10 x: xxxxxxxxddx +4-14 t: tttttttttttttbttq +12-13 h: hhhnhhhhhhhhd +2-6 x: bdwljxqxhkxjwpvdxk +3-4 w: kwfw +5-13 w: skrwgwwdwmcwv +1-3 m: mtmvsmc +5-7 v: gvbvvdt +7-8 s: ssshssspss +4-14 m: mmbmdbtmvhvmlc +4-9 g: ggsgnhhmgg +1-6 g: gsmfgjgzmkglzbgfjw +1-12 z: zzzzzzzzzzzdz +4-6 q: dbqjwnd +9-15 c: ccccccchccjcccc +1-7 l: fkllkmp +2-17 g: dggmgzhvphggcjgmtx +9-10 f: fffffffpfs +1-4 n: nnnw +11-12 l: llllllllllrl +9-10 p: ppppppppppp +5-6 p: pskgtx +7-8 q: qqqqqqjr +7-8 d: ddrdddkgddd +2-5 l: llllhl +4-6 h: hhbhlbhh +9-12 m: mmmmmmqmtmqgcx +10-13 f: fbfffjffffffjff +5-14 c: cvvrcmkhztsctfpf +1-2 k: fkkk +8-11 j: kjzchnjlrxjjljjljj +5-6 x: xxxxxq +6-11 r: zrkrrrznrfm +2-5 r: rdrrrr +12-16 c: cccccccccccccccvcccc +14-16 w: pwwfwwntkwwrjwcww +1-16 z: zzzpzmzmdzjzzzzvzzgs +6-8 j: mttjfgswgjwjjdjx +1-8 w: hwswwlwwxtgxbgkwp +7-8 h: hhhhbhnhb +3-4 n: cnzn +8-9 r: ltnkhrdsr +4-5 t: tttmtltptttttttltt +7-8 s: sssslsscszws +16-18 j: jjjljjxjjnvjjjjjjnj +3-4 s: psjpswct +5-7 b: kslrgbhcxmhbv +7-9 x: gxxxdxxxbxxx +1-5 d: lddddd +12-16 x: gsbzzgxnwsrmqxvx +10-12 m: mmrmmmmmmmmbmmmmmr +4-7 f: lfsfcnczbfh +9-11 r: rrrrrrrrrfzr +3-6 c: jfhnvcc +8-19 f: ffffffgfffffffffffj +2-6 x: lpfxdqws +1-4 q: xcvqnqvh +2-11 r: rrrrrrrrrrrcr +1-5 z: pvdczgkznqpxpnzrz +2-3 j: rzcjvmjb +5-6 w: wcwwwlblgplfwft +3-13 j: djjrjmwzrkzzn +10-11 p: hlsbzcpdqppww +9-10 f: fffffffffb +2-7 m: tvmjknlkdqlqmh +6-19 x: cqkrszrxppxxzrclxkx +1-11 m: zfmmjmmmlmmmmmdmm +3-4 t: fstwjtqqsdzbwrt +8-9 x: xxxxxxxxg +4-5 n: xnnnfnnnl +1-4 n: xxnngpfxl +5-6 m: tgsmmqm +10-11 l: lpvhlllrhcn +11-12 k: kkkkkkkkkfdkk +14-16 c: cccccccccccccbcc +13-14 f: ffffffffffffjff +10-11 w: hwhwqngbwmw +16-18 m: mmmmmmmmmmmmmmmrmm +8-12 d: bddddddrddddd +14-16 z: zzzzzzzzvzkvzzznzz +9-10 z: fzzzzzzzzbf +14-15 j: jjjjjjjjjjjjjqjj +8-11 b: qtfjvqgbpwb +6-9 d: ddddddddzddddd +5-7 c: rlqqctcr +5-6 m: mmkmmfmdwjd +6-7 n: nnnnnnz +11-12 s: sssssssssswpsss +12-15 r: rrrrrrrrvrgrrrk +2-3 b: bqbbb +7-9 c: ccccccdcc +15-17 s: sssssssspsdsssqsssss +2-7 g: bgggwrbggfc +4-5 n: ncdnb +11-12 x: xxxxvxxsxxrxxvx +4-17 c: crscfpdcrngngctxc +1-3 s: xsrsss +14-18 w: wzwwwwpxwwfwwlkwbl +2-8 w: tbjctwlwml +1-10 h: xhhfhhgjhhhhhwhz +13-15 c: cccccccccccclccq +1-14 j: hjfjjjzsjpjjjjjj +6-10 c: jccxcccbcc +5-6 n: nznnnxcnn +4-10 w: wwwbwwvfwwmwwws +9-10 s: krsgskgtvl +2-11 p: pppppcppppspp +12-14 c: ccccccccccccvcc +3-13 c: blcvjwrwzzwlmttsncg +3-9 w: wqwlqwqpdwc +12-15 v: gtwlqvxjkvvgvft +14-19 k: kkkkkkkkkkkkkkkkkknk +4-5 g: gggnx +3-4 r: rxxrr +13-14 h: hhhhhhphhhhhch +11-15 w: wwwwwwwwwwdwwwdw +16-17 l: jmphnlvdgmltcflxlm +1-4 q: qmqw +5-10 f: ffmbxfqffffbfff +2-14 b: bbbqjbxvdbbvbdx +18-19 p: ppppppppppppptpppnn +5-6 m: mmbmmkmm +3-8 d: ldkddkddmbcdwdrbx +11-12 s: shjssssssspgssssssss +2-4 d: fddqdd +6-11 f: ffffffffcszsrff +5-10 r: mrrrhrrrrr +2-17 n: nhtnxnnnnfnnnnnnnn +3-4 s: ssvs +5-6 t: ktgbft +7-10 m: mwmmmlmmmhp +10-11 c: cccccccccbc +1-3 t: rnttg +13-14 f: kjqrkfstrfngqf +12-15 g: gdgknggggqghgpd +1-13 t: ttttttgttttttjrttt +1-5 r: brrgrrrrr +4-7 c: cccnccccccp +11-12 n: nnnnnnnnnndl +9-11 j: jwjjjkjjjjfj +3-10 w: wdwgswwwwx +10-12 r: zzrrctnvrxfrrqrrjrrr +4-5 x: xxxhx +5-9 j: fqgwpjtjnt +7-9 l: lxllllllqllwllll +11-17 p: ptbzpvppswpppplpr +7-13 g: ggggggzgggggfgg +2-8 j: pbftjswjqzcp +5-6 z: zzzzzczzzzzzzzzzzzz +2-6 n: ntvnnnnnn +12-13 n: nndntnhknsnnnnnnqfnn +1-6 x: wtnxdw +2-4 f: fxxf +5-12 k: xcxrwkpfkkfkdk +3-4 z: lzzz +12-15 n: knnnnnnncnnnnnpnnnn +3-11 h: jdhfhhfmthh +9-10 k: kkkkkkhkskk +2-6 g: hhngvjgbkg +3-4 k: zkkz +12-19 r: rrrrrrrrrrpmrrrprrvr +2-9 d: dkddddddjdddd +1-4 c: zccc +7-12 d: dqbxtdxdgztddc +4-5 x: kxxxd +1-3 x: xjfkxvhvbq +5-9 w: dpqcpwcrwpwcqhlj +1-7 q: dkbtgkqxjhjzsqccn +4-10 c: cncccccccccc +7-13 b: bbmbqwbbbbbbbpnbb +9-10 b: bbbbbwbbbgx +7-14 b: bbbqjbcpbbjbvbbbqrxb +5-13 s: fspsqsshvhssssmrqss +11-15 v: vvvvvvvvvvvvvsjvhvdp +5-9 d: brwdshwddzvg +2-7 w: wwkfgkwtbvwx +6-9 l: llllwnlllll +4-7 h: hchhhtpr +1-4 n: npgnn +3-4 k: kvkkkkjkkxkgkk +1-13 m: xmkkhmwddbtkm +6-7 x: xxxxxxr +15-19 m: mmmmnmmmmmmmkmbmmmd +14-15 z: zzzzzzzzznzzzhzz +11-13 h: sfhxhlhtnnkvdkhm +9-10 z: dzzzvzzzztmhczbzx +5-7 v: vvvvwvv +5-7 z: zrgzxzzfdz +1-3 n: nvlm +4-7 x: xkvxxjt +4-10 m: mfwzzmnqfsdkxzmmmm +1-15 x: xxxxxxxxxxxxxxt +5-7 n: nnnnnnm +11-12 z: xknzzzwddzxxzzzzzzhc +3-4 f: fzflfjf +4-6 g: ggkgrxg +1-2 n: sncpt +4-18 z: xvrsrxzzzzlzzznzzz +5-7 j: jbhfjcrpkgjhp +6-7 g: gggggsh +8-9 n: nnnzntnqpfnnpc +8-9 k: kkkkkkkxsk +6-11 n: nnhntnmhnnms +3-5 q: qzqqqqhlcbfdqq +6-9 r: rrrrrrrrvdjrrrr +3-7 r: rrrrqhm +6-9 t: xmdtvstttjtt +3-5 l: gnsnlp +2-6 x: hxjxjd +2-6 t: tttttp +7-8 l: vdtrllllrmlwllcplgb +10-11 t: ttttttztmwtt +3-4 d: ddgd +9-11 j: jjjjtnjjqjcjj +6-7 n: nnnnlcwbn +4-6 g: ngdsggg +7-9 q: hnxrvqjqqr +3-5 l: fltllw +3-11 g: gghggggggggg +7-17 w: wwwwwwwvwpwwwmwtgw +2-19 n: nhnnnnnnnnnnnnnnnnn +1-2 n: xnmr +4-6 x: xtxxxpxxxx +10-13 z: zbzzzpjrwzdzxszzzz +9-19 b: bbbbbbbbbbbbbbbbbvbb +9-10 w: wwlwzwwwvr +5-9 p: pnkpdppppppkpwzpp +15-17 j: jjvjjvjjjjjjjjljwcj +3-4 t: tttkt +1-5 j: jvjtq +2-11 r: rrrrrrrrrrwr +1-4 x: xqpzxwcslbj +3-4 b: bpbp +11-13 w: wwwwhwwwwwnwl +2-4 f: nfnjtfkbsxvm +6-7 v: vvvvvvs +1-4 t: xwtxxmgfwpkqd +5-6 h: hgjhrhhhh +2-4 p: psppp +10-14 j: pqjjjsjjjbcbjjjjj +3-7 d: ddbjddgzdd +6-7 l: llsllbl +1-13 p: pppppmpppppppppppcpp +1-3 r: rbdzrjsrd +11-14 x: xxxxxcxxqxxxxs +11-12 c: ccccwccczccccc +2-12 g: spwsxfgdrqngkqgdb +1-3 h: dhrhh +1-7 f: tfffffff +15-16 s: sssssssssssssvssz +12-13 q: qqzqqqqqqqqvq +4-5 g: cgxgk +3-8 n: nnnnnnnnnnnnn +1-3 r: rrkr +14-15 g: sgtgggggggggggxgr +2-5 s: vhcts +2-4 x: xdbvvrnxxhnzsl +8-11 p: ppwpppclpvlp +7-11 b: bblbbkbbbbmxfqgxgk +5-6 d: dddldffx +5-6 z: zzzzzwz +11-15 q: hqrqbzbhnhdqjfqdvg +3-16 b: btgbbbbhzbbbbbjb +4-5 f: ffvkf +6-10 q: qqqqxqqdvlqq +12-15 g: gggxsgsnwqxldmg +8-12 d: ddddddjpdddh +1-2 p: pphgjjm +9-11 d: ddddddmdfddd +18-19 z: zzzzzzzzzzzzzzzzzmz +8-14 r: rrrrrrrtrkrrrq +4-5 t: jhtrt +3-6 h: bjhwkpdjqbnng +4-5 m: mmmmbm +2-4 t: dqttgszbrwpcdr +5-7 q: dfxmqxxqtdfqxqq +3-5 k: kkkcmk +7-10 t: tttttttttn +7-14 m: mmhmbmkmmvrtmxgxwmm +10-11 v: vvvvvzvvcxvvv +5-6 s: lssssbrssl +8-15 h: hhbhhhhhwhrhhhqh +18-19 q: qqqqkqqqqqqqqqqqqtq +10-12 p: xpprjzzlpqspsnpb +5-6 t: ttttgt +4-12 s: csvwsslsshgkbsrds +12-17 z: zzzzzjfzzzzzzzzzzzz +4-5 f: fnktwj +3-6 h: hphdhvh +16-19 m: mmmmmmmmmmmmmmmnmmmm +5-8 m: msmjtplmmtqbm +6-9 q: gqqcqqqrq +1-10 g: gvgfsqggph +10-11 l: nlllpllljql +1-4 q: qqqx +2-4 q: qbwqwpqq +3-5 s: scsmjtszkscsds +2-5 t: txttfttt +1-2 s: swsqspmz +2-4 f: vffw +11-16 r: rrrrrrrrrrjrrrrq +2-13 r: rlxpzrftnrkhrvlzrp +4-7 g: lggfgsggggggggggg +4-5 w: wwblw +2-5 t: tbgtg +6-7 n: jvzmhnmnphhx +1-8 m: cmmhmlmmm +10-14 x: wtxtkxxjpxxxxr +3-5 h: hmchhfhk +5-8 h: qgfkhktmhhhmbw +10-11 k: kkkkkkkkkkh +5-6 g: ghzggxgsgpksg +3-4 w: mwwv +3-7 p: zppsxpnbj +1-2 d: qtdd +9-10 h: rhdhlhhhwhhtdhzxhp +1-6 v: lvtpvvnb +2-6 q: qqqlqm +4-8 j: jjfjjvjjxjj +13-14 x: xhvqxxxxxxhxxq +10-13 k: kclwxblmncnbkkdhrhr +1-3 j: jjpj +3-4 b: sbmxhbbt +2-3 d: mjscddjrh +2-6 x: xxxgxqxxxxzxrxx +19-20 h: hhshhhhhmshhhhhhhhhq +12-15 s: scbssrsslnsskfbs +3-4 p: jpmp +11-19 p: pppptpppcthpppppppp +1-5 w: lwwvw +3-4 d: xzfddddpdddzdjxcdd +3-8 f: fspmqqkfjtfrz +9-12 c: cccccccccccr +15-16 w: wwwwwwwwwwwwpwlg +2-3 v: vzvb +10-18 t: txttttmtmtrtntttfktt +3-12 h: mwbdpslghxxhhh +2-9 l: lcllllllxllllllll +9-10 r: rrrrrrjrtrrr +2-9 m: mmmbmmmmmmmm +7-13 t: ttttttttttwtz +7-13 b: bzbbbbqdxbqbb +5-7 d: ddhdddmd +4-5 b: bqbdkbbb +1-3 k: wkkkk +4-6 d: dddddf +2-7 j: tmnjptjtrvx +5-7 z: qzlzzzvzm +4-5 h: hhhhhf +3-14 s: zsrkrsssmsssshsssss +7-8 k: bkkkgkkxk +8-9 x: xxxxxxxtxm +7-9 j: jmjjjjljjjjb +10-11 n: xnnkrqnfnjnnnpncnn +3-6 c: cxcdlhv +1-2 q: qdlmfhgtgrnqhmvqmkhm +6-7 t: tttttttt +2-4 j: xjvzcjcftgvfqg +5-7 n: srnxnjjgdnnnnqrwt +2-3 z: vhzzvk +6-13 d: nlbwzrpsrfvwddcz +1-3 s: ssfs +10-13 n: nnnnnnnnnmnnnnnnn +6-8 g: lggggnggx +7-10 j: jjjjjjqjjjj +2-10 c: fccbgjccvzwqczcvcc +3-4 p: wqws +1-6 w: wqbjbnrp +5-9 v: vvvvvvvvhvvv +13-16 n: nnnnnnnnnnnntnnn +5-7 h: qzjhhhp +14-15 c: ccccccccccccclcc +11-13 g: tkthwlwggncggxmjfk +2-11 v: vndvvvvvvvvv +10-11 p: ppppppppppt +1-11 c: ccccccccccdc +9-10 b: bbbfbpbbtbb +5-10 r: rrsrrrckhp +2-16 v: vvbktgjvhvvkmfbvccwc +6-10 v: nrvxrvcvvvktrvvvl +10-17 d: ddddddqdhdddddddvd +5-7 f: fqkxhfffghfc +1-13 z: zkzwcggpsppzzxwcbbp +2-4 d: hkvdzhlpbqdnvrjsc +9-11 x: zxxxxxxxsxx +14-17 q: qqqqqqlqqqvqqgtqq +5-12 q: qqqqqqqqqqqrqqqqq +10-13 w: wxwbnbkwgwxwhwwwln +5-16 c: xzvscccccjcccchhc +2-3 v: vgmvvvvvvvvv +7-9 j: mjjjjpjjdjjjb +6-9 q: gqqqqqqqq +10-12 p: pcpxppppprpppp +1-6 s: zsssss +1-3 g: mhggg +2-7 g: gsggsgnvggggqggvlgrc +1-6 d: rddddddd +1-3 n: nntnknnr +8-9 t: tttltttttt +5-6 f: jfzqfljhkwdn +12-14 j: jljjjjvjjjjjjcj +9-10 q: qqqqqqqqqwqq +2-11 h: hhhhhhmhhhqhphhh +4-9 z: cldzzfxzblb +3-4 l: lvlm +3-4 m: mmrmm +15-18 m: mmmmmmvdmmmmmdmmmsmm +4-5 f: wffzff +10-16 b: bbbtmbblpbbbbbmmbv +13-14 d: dpdmjrgdqrdwwd +6-7 m: mmmmmjm +12-19 g: gggggzxggggrgggglgvv +10-15 p: ppppspbpvpkpcpqppp +4-10 m: mmmmzmnmpct +11-12 c: chcccpcccccdcccpd +3-5 f: ffnzqjzh +1-6 p: cpjpppp +7-14 p: ppppnpqpwnrtmbjjppm +7-8 w: wwwwwwtw +3-4 d: ddds +3-4 r: vrxdtlt +2-7 w: wcwvwwqw +5-12 b: bbbbbbbbbbbhb +1-5 t: tlvktt +6-7 p: mprngps +8-12 x: xxrbnxxjhxxxxlx +1-3 x: xvqx +5-7 v: vvvvqjvvvvsg +2-6 w: fwwjwz +16-20 q: qrqqbqnqqfqjhqfqqqqh +3-6 j: jhjjjfjsjk +4-9 k: rkgpgskkz +2-4 z: gzdz +6-8 t: tttttsttdtttt +11-12 p: ppppppppppppp +4-6 x: mzqcfxct +16-19 d: qjdlfdccdbxngddnkgn +2-3 f: rrcvqfs +13-16 z: zzqzzjzzfnttznxzzzz +16-17 w: rbngvbwpgwgzkwswp +1-9 k: klkkkkpkp +3-4 f: fffxffffff +1-2 l: lhpl +1-4 w: vznmj +2-3 j: jdjmpjd +17-20 v: vvvvvvvvvvfvvvvvvrvx +3-7 w: wnzwwswwwwj +3-8 m: mmnmmmmmmm +3-4 l: llmll +9-11 r: rrrfrrrdqrwrr +9-10 w: wwwwwzwwhw +6-10 t: pttwtbxqgttttntktjt +1-3 j: jpngpm +1-9 g: gggggggggg +4-5 b: gbbtb +2-6 q: qqblqdrnmcnhqvvpvkq +6-7 w: zwwwwjw +2-8 w: rpbbwwwlqzhl +11-13 b: bbqbbbbbbbbbb +7-10 v: vvvvfvvvvv +6-17 t: ttttttttttttttttwt +2-3 f: fbff +8-13 l: qlllzllmllgllmlcl +3-4 n: nnnfnqd +9-12 z: lzzzlzzzzffb +3-11 p: bhlpnccgcfp +1-3 s: stccsf +10-18 p: pdgpphscppdlpppvsh +3-6 j: jjjjjq +2-3 s: dslwlsvljc +3-7 g: sgggtdgwkdhspgnxkglv +12-13 h: vrgnfshfssvhh +12-13 m: mmmmmmmmmmmbgm +12-16 d: djddvdqpdddddjlt +3-4 k: kfkmkpk +6-13 s: ksphskxpdswsssbbnwwt +6-18 x: xxsvxndxxxxfvkxxbxs +7-8 d: dxbdddddddd +6-7 q: qqkqdcqjfdqqbbqp +4-5 k: vkkbkzqpk +4-9 l: llbhllllldl +14-17 d: ddddhdhddddddxdddd +3-5 r: htlfbsgmvz +2-4 h: hthhh +4-7 l: xlzllbqkdwqsllfsw +17-18 n: wnnrnnnnngnnnnnnqnfn +1-3 j: vlwkv +1-2 g: bggz +10-11 x: ddsxjxxtnxjpcxxxxxv +4-5 g: hggkg +5-7 t: khtnzct +10-15 g: ggkggsggcgggggqggwgg +9-11 s: ssssbwjhssj +1-8 b: gxvbllbjqk +2-3 w: jgwqhrw +7-8 j: wxtqdvjpbcfzxsjlpmsj +9-16 b: bcpbcbbbbbjmbpwbbj +2-5 t: tpttttt +2-3 z: pzzz +3-10 j: jjpjjrjjjjjjw +5-8 t: tttttttxt +5-15 r: rrnrrrrrrrrrrrkr +8-9 j: hdjwgbjmj +3-14 c: jcccwcccccrckccch +11-12 n: jvzktxgpcmnjglwljrn +9-13 k: vqsgdcksxtxhks +3-5 c: zdccczpwlxt +3-5 r: wxgkrqrsgl +7-8 s: kspsssksswssj +3-7 j: djjjhbrkhtncxjvf +11-12 x: xxxxxxxxxxxz +11-12 t: ttttttttttht +8-11 v: ptvvvsvtvrvvwvxvtfg +9-13 d: nhjddddvlbkdcdntdf +3-6 w: gnwwjqwzqwm +3-5 s: tsssc +3-7 k: kkkzkpmmll +13-15 k: kgkkkkkkhkkktkf +5-8 t: ktttrttnt +1-4 z: nzzzzzz +2-4 k: lkkc +2-3 z: szjh +19-20 d: dddpcddkddckdddbmdld +3-9 q: xqqqpqqqwlqqqqq +14-17 s: ssspkssssssssssslss +17-19 c: ccccccccjcczccccxccc +4-13 h: qtrhflbfmkfchjmfzph +10-18 m: nmmmmmmmmmmmmmmmxd +5-11 n: dnnnfsnnkznbgnjn +6-11 c: cccccvccccc +7-9 d: dddddrxdzldv +2-4 z: zbzz +1-6 j: njjjjjjpjj +3-5 p: prpww +3-16 c: tqjdhbgxvxcxwbvcn +4-5 c: vclfc +3-18 x: xxrxxxtxxxxxxxxxxtxx +2-4 g: gvgggg +6-12 j: cjjpjjjjlhpt +3-4 w: pfwq +5-14 v: vsqqvlrmqbbrlp +2-12 l: rlblqwmphxzpsp +2-8 h: hhqqvhhphhhqddhh +7-9 f: dnfvhwwffk +4-5 p: ppppcd +8-14 t: ttttdtqhttttftttt +13-14 f: fffffffffffffff +1-6 s: jrtwjslzwgkt +4-6 c: jcwzhcscc +10-14 x: llxxxxxxvnxsmx +1-2 h: hhhhv +2-4 d: mvdclzddj +16-17 t: tttttttttttttttmt +2-3 l: jklzlmzrppdpzt +5-6 g: rvfgnggjgk diff --git a/d02/main.go b/d02/main.go new file mode 100644 index 0000000..6c0ae01 --- /dev/null +++ b/d02/main.go @@ -0,0 +1,110 @@ +package main + +import ( + "bufio" + "fmt" + "log" + "os" + "regexp" + "strconv" + "strings" +) + +func proccessLines(path string, f func(string) (stop bool, err error)) error { + file, err := os.Open(path) + if err != nil { + return err + } + defer file.Close() + scanner := bufio.NewScanner(file) + for scanner.Scan() { + stop, err := f(scanner.Text()) + if stop || err != nil { + return err + } + } + if err := scanner.Err(); err != nil { + return err + } + return nil +} + +var matcher = regexp.MustCompile(`([0-9]+)-([0-9]+) ([a-zA-Z]): ([a-zA-Z]+)`) + +func part1() { + totalValid := 0 + err := proccessLines("input.txt", func(line string) (stop bool, err error) { + results := matcher.FindStringSubmatch(line) + if results == nil { + err = fmt.Errorf("invalid line %s", line) + return + } + minCount, err := strconv.Atoi(results[1]) + if err != nil { + return + } + maxCount, err := strconv.Atoi(results[2]) + if err != nil { + return + } + letter := results[3] + password := results[4] + // fmt.Printf("Make sure %s is in %s between %d and %d times\n", letter, password, minCount, maxCount) + // Validate + count := strings.Count(password, letter) + if minCount <= count && count <= maxCount { + totalValid++ + } + return + }) + if err != nil { + log.Fatal(err) + } + + fmt.Printf("Total valid %d\n", totalValid) +} + +func part2() { + totalValid := 0 + err := proccessLines("input.txt", func(line string) (stop bool, err error) { + results := matcher.FindStringSubmatch(line) + if results == nil { + err = fmt.Errorf("invalid line %s", line) + return + } + pos1, err := strconv.Atoi(results[1]) + if err != nil { + return + } + pos2, err := strconv.Atoi(results[2]) + if err != nil { + return + } + // 1 vs 0 indexed + pos1-- + pos2-- + letter := results[3] + password := results[4] + // fmt.Printf("Make sure %s is in %s between %d and %d times\n", letter, password, minCount, maxCount) + // Validate + if pos1 >= len(password) || pos2 >= len(password) { + return + } + letter1 := string(password[pos1]) + letter2 := string(password[pos2]) + if (letter == letter1 || letter == letter2) && letter1 != letter2 { + totalValid++ + } + return + }) + if err != nil { + log.Fatal(err) + } + + fmt.Printf("Total valid %d\n", totalValid) +} + +func main() { + part1() + part2() +} diff --git a/d02/main.py b/d02/main.py new file mode 100755 index 0000000..b528971 --- /dev/null +++ b/d02/main.py @@ -0,0 +1,44 @@ +#! /usr/bin/env python3 +import re + + +def part1(): + print("Part1:") + total_valid = 0 + with open("./input.txt", "r") as f: + for line in f: + g = re.search("([0-9]+)-([0-9]+) ([a-zA-Z]): ([a-zA-Z]+)", line) + min_count = int(g.group(1)) + max_count = int(g.group(2)) + letter = g.group(3) + password = g.group(4) + # print(f"min: {min_count} max: {max_count} letter: {letter} password: {password}") + count = password.count(letter) + if min_count <= count <= max_count: + total_valid += 1 + + print(f"Total valid {total_valid}") + + +def part2(): + print("Part2:") + total_valid = 0 + with open("./input.txt", "r") as f: + for line in f: + g = re.search("([0-9]+)-([0-9]+) ([a-zA-Z]): ([a-zA-Z]+)", line) + password = g.group(4) + try: + pos1 = password[int(g.group(1))-1] + pos2 = password[int(g.group(2))-1] + except IndexError: + continue + letter = g.group(3) + if (pos1 == letter or pos2 == letter) and pos1 != pos2: + total_valid += 1 + + print(f"Total valid {total_valid}") + + +if __name__ == "__main__": + part1() + part2() diff --git a/d03/input.txt b/d03/input.txt new file mode 100644 index 0000000..8a00870 --- /dev/null +++ b/d03/input.txt @@ -0,0 +1,323 @@ +.........#..##..#..#........#.. +#...#..#..#...##.....##.##.#... +....#..............#....#....#. +#.#..#.....#...#.##..#.#.#..... +........#..#.#..#.......#...... +.#........#.#..###.#....#.#.#.. +........#........#.......#..... +...##..#.#.#........##......... +#.#.##..###............#...#... +............#....#.......###.## +....##....##..#........#......# +............#.#..........#..... +#.#....#....##...#.....#.....#. +......#.#.#...#.....###....#..# +...........##..#.........#..#.# +..#..#.................#..#..#. +.#....###...#.......#.........# +#.#.#.#...#......#.......#...#. +.......#.#.#...#..............# +...##.......#..##.#.......##... +#.#.##....#..##..##..###...###. +.#......##.##.#....#.##........ +..###.............##..##..#.... +.....#.#...........#..##..##... +.###.#.#......#.....#........## +...#.......#...##..#..#..#..... +..............#.#..##.##..##..# +#..#.#......#............#..... +........#..#....#.............. +...#...#..............#.#####.. +...##......#........#.#...#.... +..##......#............#..#..#. +....#.........#.#.#.....###.#.. +#....#........#........#....#.# +.....#...#..##.....##...#.....# +#...#.#.#...##..##.###.#.#..... +......#.#..........#...#.##.... +..............##...#..#.......# +........##.....#.....#.#....#.. +..............#..#..#...#.....# +##......##.......##...#.#....#. +.....#.............#.#......... +#.........##..#..#.........##.. +..#..#.....#####.........##.#.. +.......##.#......#........#.... +#.................#.#...#....#. +...#........#.###.##.##.....#.. +#.....##..#...##.#.#......#.... +.....#..#.#..........##..#.##.. +..###.............#..#..#...#.. +...###..#...#.....##..........# +#.......#.#...#....#..##..#..#. +.#..#.........#..............#. +..######.....#....##......#.... +#..##...#......#..#.#....#..... +.#...................#.#.....#. +..#...#.#..#.#......#..#...#..# +..##..##.#.##.........#.#.#.... +...#...#...........#..##.##...# +#...#....#....#....#..#.##..#.. +..#.##....#....###..#.......... +#.#..##.#.#...##.#..#.##..#.#.. +#......##...#.#..........#..#.. +#.#...#..#...#.#.#..#........#. +#.#.##.#..#...#..#.#.##........ +.....#......#........#..#...... +...#....#.#....#............... +....#..###..#....#..#....#....# +.#........###..........##.##.#. +#.#......##....##...##.#......# +#..##.##...#...........##.#.#.. +.#.....#.#...#................. +##..........#..#....#.....#...# +....#.#..........##..#.....#.## +#.#..#..#..##..........#....... +..#.#.###...................... +......##..##.....#..##.##....#. +...#.......#.##....#......#.... +...#...#........#...#.#...#..## +##...#....#.#...#.#.##..##...#. +...#.....#...#...#....###.#..#. +..#.#..#........#......#..##..# +...#......#...#.#.##...##.#.#.# +....#.#....#....#.....#.....##. +.....#.#..##.#....##....##..... +.#...###..#.....#............#. +#..#.#.#..#..#...#....#...#.... +#.....#..#...#................# +..........#..#.......#......#.# +...#..#......#...#......#...... +.#.#.....#.#.#.#......#..#..#.. +.....#.........#.#.#.....##.#.. +.....#.#.....#..#..#..#.....### +##....#......##....##.#....#.#. +#####........#..........##..... +.#...##...#...#.......#....#... +#.#.##...##...##..##........#.. +#.#..............#.#...#...###. +...#.....##..#.........#....#.# +#.#....#....#..##.#..#...#..... +..#....#.#..#...#...##.....#... +....#...#...................... +..#...#.......#..#...##....#... +.#........#...#.....##.##...#.. +#......#..............#..#..#.. +...........#.#..#.#.#....#....# +.##..##.......#...#..#.....#..# +...#.........#.........###..#.. +...#.##....#....#.....#.....#.. +.#.#.#.........#.#.#....#....#. +...#..........##..#....#.#..... +...#....##................#.... +#....##..#..#........##...#.... +#...#...##.#............#....#. +##..#....#...#...............#. +..........#.#...#..##..#.#..... +..##...##..#....#.#......#..... +.......#......#.#.....#.....##. +#...###.....##..##....#.#....#. +.###......#.....#.#............ +#.....#.....####.##....#..#.... +......###.............#......## +.........##.......##..#..#..#.. +.#.......#....#...#...#.#...... +#...#..#...#........#...##..#.. +.#....#........#.........##..#. +..............##.#...##..#.##.# +.#....#...#....#......#..#..... +#....##.#...#.#.....###..#....# +#.......##.#..###.............. +#..#..#..#......#.#..#...#..#.# +.......#.#.#..#..#...#..#...... +.#..#......#.....#......##..##. +....#....#.......#.......#.#.## +.......#.#................#...# +#.#.....#.......#.#........#... +.....#....##...#......#.....##. +.#......#.#...#..#....#....#.## +##...#.###.#....#..#....#.#...# +....#.##..##.#.............#... +#..#.............##.......#.#.. +##.#..#..#.#...........###...## +.#.#.....#......###........#... +#.#...#.#....##......#.#....#.. +#.........#..........#......... +.......#....#...#..#.....#...## +.......................#...#..# +.###...........##...#........## +#.#....######.#........#..##.#. +..#.##.#...#.#.......#.##.##..# +#.............###..#.##.#...... +...#..##......#...#..###.....#. +..........#.....#..#...##..#... +..##..........#.#..#.....#...#. +...#.......#.....##.........#.. +#..#.#...#..#...###...#...#.#.. +#.##....#..#.#.......#..#..#... +..#.##.#......#.#......#....#.. +..........#...##.....###....... +...#...##..#......#...##....... +....#........#.#.......#..###.. +.....#.#..........##.#..#..#.#. +.............##.....#.#..##.... +...#...............##...#...... +....#......#..#....#...##..#... +.##.#....#.#.....#.#.........#. +.....#.###....#..###..#.#.....# +.#.........##.........##...#... +..#.....###....##..........#..# +........#..#.#.#..#.......#..## +..#.#..#.#............#.##.#..# +.#....#.....#..#...#.......##.. +.#...........#.#..#..###.###... +..#.....#..#........#.#........ +.#........##........#..#.##.... +......#.....##........##..#.... +.#..................##....#.#.. +.#..#.#..#.#...#........#...... +...#..##.#......#..#..........# +....#.##...#....##............. +#....#.##....##.###..#..#..#... +..........#..#...##.##....#..#. +.###.#.....#...#...#...#....... +............#...............#.# +#....#...#......#....#.#.#.#.## +...#..........#.#.#.....###.... +#.#...##...#..#.....###...#.... +......#...#..#..#..#.##...##... +...#..#.#....#...#.#.........## +##....#..###.#.##.....##....... +..#.#...#..##.......#.#.......# +##......#...........#......#... +.......#..###....###..##.#...## +.........#.....#..#.......##..# +.......#.##..#....#...#.#...#.. +#..#.#..................##.#..# +...#..#..#.....#..#........#... +...#.#..###..#.....##...#....#. +..#..#......#...........#...#.. +#...##.##..###.......##........ +.#.....#..#....#.....#.##....#. +#..#........#.#....#..#...#.### +..#...#.#.#.....#.....#..#..... +.##.............#.#......##...# +.#....#####............#.....## +#.###.......#.#...##.....#..... +......#.##..#...#..#..##.#..##. +......#.#...##.....#...#....##. +....#............#...#...#....# +.........##.#.#....#....#....## +.#...##.#...#.......#.##....#.# +#....#.#...#.#...#.#.#...#..... +.#.#.........##..#..#.......... +.#.........#.#.....#..#.#..###. +....##.#.#..........#..####.... +....#..#.#.#...#...#..#....#... +..#.#...#...##.......#.#.#..#.. +...##...#......#.....#.#...#..# +......#.###.#.......##...#...#. +.....#.#.#......##..........### +##.#.#.#..#....#............... +.#.#.##.......#....#.#.....#..# +.........#...#.#..#.......#.... +....#.####.#......#...#...##... +#..#..#..#..#....#...##.....##. +......####.#..##..#.....##..... +##.#.........#........#..#.#... +.#.#....#....#.......#.#....##. +....#....#.......##..#.....#... +.#......#..#....#.#............ +#..#.#.##.....#..#.#.#.#.#.##.. +.#.....#.....#...#..#.#...#.#.. +.#.#.##............#.#.#.#.#.#. +.##..........#.....#...###..... +#.#...#...#................#.#. +##...#.##.....#.....#.#.##..... +####.....##..........#......#.. +#.............#..............#. +.###....#.#...#..#..#..#....... +..#.#.....#...#..#..####....... +...#.#..#........#..##..#..#.## +.#........#..........#.#...##.. +.#.......#.#.#..#...#..#.#...## +.#.....##......##.............. +......#..#.#.##...##.#.....#... +.........#.#...##.....##....#.# +.....##...#........#..#.#..#.#. +.#.##..#.....##...#...###.#.#.. +...##...#...#..#.#..#.......... +##..............#...#...#.#..#. +......#..#......#..#.....#...#. +.......#...#..#....#.....#..... +..##.....##..#.#........#...... +.###.#...#..................... +..#...#.................#...#.. +#..#.##...####.............#... +.##....#..####.......#......... +#..#...###...#...#..#..##...... +....#.##.#.#.........#.....#..# +.....#...#.....#.#.#.##.#...##. +.............#........#.....#.. +...##.###.#....##.......#..#... +#..#....#....#.#............#.. +.........#.##........##.....#.. +.........#.#.#..#..#.......#... +.......#.#..#.......#.....#.#.. +##.#.....##...##.....#.#....... +.#.#.#......##.##.#.........#.. +..#.##..###.....###.........##. +.#......#..#..##...#.#...##.#.# +......#.#............#.....#... +###.#..#..#..#..#.##...#....... +.#.#.##..###....#......##..###. +#...#.#.#..#..#..##.#.##....#.. +..#...#...####...#......####.## +..##.#.####........#..#......#. +.#..#.......#...#.#.........#.. +........#.#....#..#####..#..... +.#...........#..#..#..#...#.... +....#....#...#................. +....##..#....##....#..#....#.## +....#.##.....###...#...##.##... +......##.#..##.#.#.#....#.#.#.. +##.#...###....#.#..#.#.###....# +......###..#..#..........##...# +..........#.##...##..#....##.#. +.#...#.#..#.#.#..#.....#....... +.#....#..#.#..#.#...##.#.#..... +.##.....#...#..##.#........#... +....#......#.........#....#..## +.#..#.#.#.#..#..#.#.........#.. +.........#.....#...#....#...... +#..#..#........#...#.#......... +...#.#.#...##.#.#...#..#......# +#.#.#.#........#...#..#.....#.. +.###..#..#..###..#..#.......... +.....#......#.#..#...#.......#. +##.##.........#.......##....... +#...##.......#..#.#.......#.... +#..#..#.....#...#......#....... +.#..#..#.##....#.#..#...#...#.. +.#...#.....#..#.........#..#... +...#.#.#.......#....#..##.....# +.........#..##.#..#..#.#....... +#.##.....##..###..#..#..#.##... +........#......#...##...###..## +.##....##..#..#..###......#.... +............##......#...#..##.. +...##.......#......#...##.##..# +...#..#..#.#...####.#.......#.. +..#.##..#....#......#.#.....#.. +..#.##..............#..##.....# +.....##....#......#....#......# +......#..#......#.........#..#. +...#.##.###...###..#.##........ +..........####.#.##.....#..#.## +#...##...........#...........## +#.#..#.#....#.#..#....##......# +.......#...#.....#......#.#.##. +....#.##..##..........#..#..... +#.#.#...#......#...#.....#.##.# +........#.......#..##.....##... +.....####.#....#.#............. diff --git a/d03/main.go b/d03/main.go new file mode 100644 index 0000000..37950d3 --- /dev/null +++ b/d03/main.go @@ -0,0 +1,120 @@ +package main + +import ( + "bufio" + "fmt" + "log" + "os" +) + +var ( + tree = "#" + snow = "." +) + +func proccessLines(path string, f func(string) (stop bool, err error)) error { + file, err := os.Open(path) + if err != nil { + return err + } + defer file.Close() + scanner := bufio.NewScanner(file) + for scanner.Scan() { + stop, err := f(scanner.Text()) + if stop || err != nil { + return err + } + } + if err := scanner.Err(); err != nil { + return err + } + return nil +} + +type world struct { + x, y int + dx, dy int + worldMap []string +} + +func (w *world) move(dx, dy int) string { + result := w.peek(dx, dy) + w.x += dx + w.y += dy + return result +} + +func (w world) peek(dx, dy int) string { + row := w.worldMap[w.y+dy] + return string(row[(w.x+dx)%len(row)]) +} + +func (w world) atEnd() bool { + return w.y >= len(w.worldMap)-1 +} + +func (w *world) setSlope(dx, dy int) { + w.dx = dx + w.dy = dy +} + +func (w *world) ski() int { + trees := 0 + for !w.atEnd() { + space := w.move(w.dx, w.dy) + if space == tree { + trees++ + } + } + return trees +} + +func (w *world) takeLift() { + w.x, w.y = 0, 0 +} + +func readMap() world { + worldMap := []string{} + err := proccessLines("input.txt", func(line string) (stop bool, err error) { + worldMap = append(worldMap, line) + return + }) + if err != nil { + log.Fatal(err) + } + return world{worldMap: worldMap} +} + +func part1() { + theWorld := readMap() + theWorld.setSlope(3, 1) + trees := theWorld.ski() + fmt.Printf("Total trees: %d\n", trees) +} + +func part2() { + trees := []int{} + theWorld := readMap() + + product := 1 + for _, slope := range [][]int{ + []int{1, 1}, + []int{3, 1}, + []int{5, 1}, + []int{7, 1}, + []int{1, 2}, + } { + theWorld.setSlope(slope[0], slope[1]) + count := theWorld.ski() + product *= count + trees = append(trees, count) + theWorld.takeLift() + } + + fmt.Printf("Total trees: %v, product: %d\n", trees, product) +} + +func main() { + part1() + part2() +} diff --git a/d03/main.py b/d03/main.py new file mode 100755 index 0000000..c9979ca --- /dev/null +++ b/d03/main.py @@ -0,0 +1,107 @@ +#! /usr/bin/env python3 +import functools + + +TREE = "#" +SNOW = "." + + +class LoopingList(list): + + def __getitem__(self, key): + if isinstance(key, int): + return super().__getitem__(key % len(self)) + if isinstance(key, slice): + return [ + self[x] + for x in range(key.start, key.stop, key.step or 1) + ] + + +def read_map(): + world_map = [] + with open("input.txt") as f: + for line in f: + world_map.append(LoopingList(line.strip())) + return world_map + + +class World(object): + + def __init__(self, world_map, x=0, y=0): + self._world_map = world_map + self._x = x + self._y = y + # Default slopes + self._dx = 1 + self._dy = 1 + + def move(self, dx, dy, should_print=False, print_buffer=0): + self._x += dx + self._y += dy + if should_print: + print("".join(self._world_map[self._y][0:self._x+print_buffer])) + return self._world_map[self._y][self._x] + + def print_row(self): + print("".join(self._world_map[self._y])) + + def peek(self, dx, dy): + return self._world_map[dy + self._y][dx + self._x] + + def at_end(self): + return self._y >= len(self._world_map) - 1 + + def set_slope(self, dx, dy): + self._dx = dx + self._dy = dy + + def ski(self, count_trees=True): + trees = 0 + while not self.at_end(): + try: + space = self.move(self._dx, self._dy) + if count_trees and space == TREE: + trees += 1 + except IndexError: + print("At end of the world") + return trees + + def take_lift(self): + self._x = 0 + self._y = 0 + + +def part1(): + world_map = read_map() + world = World(world_map) + world.set_slope(3, 1) + trees = world.ski() + + print("Total trees", trees) + + +def part2(): + slopes = { + (1, 1): None, + (3, 1): None, + (5, 1): None, + (7, 1): None, + (1, 2): None, + } + + world_map = read_map() + world = World(world_map) + + for slope in slopes: + world.take_lift() + world.set_slope(*slope) + slopes[slope] = world.ski() + + print(slopes) + print("Answer:", functools.reduce(lambda x, y: x*y, slopes.values())) + + +if __name__ == "__main__": + part1() + part2() diff --git a/d04/input.txt b/d04/input.txt new file mode 100644 index 0000000..46fe04a --- /dev/null +++ b/d04/input.txt @@ -0,0 +1,1100 @@ +ecl:grn +cid:315 iyr:2012 hgt:192cm eyr:2023 pid:873355140 byr:1925 hcl:#cb2c03 + +byr:2027 hcl:ec0cfd ecl:blu cid:120 +eyr:1937 pid:106018766 iyr:2010 hgt:154cm + +byr:1965 eyr:2028 hgt:157cm +cid:236 iyr:2018 ecl:brn +hcl:#cfa07d pid:584111467 + +eyr:2029 ecl:hzl +iyr:1972 byr:1966 +pid:2898897192 +hgt:59cm hcl:z + +pid:231652013 hcl:#602927 hgt:166 +ecl:grn eyr:2025 +byr:2008 iyr:1986 + +byr:1928 hgt:167cm +hcl:#18171d iyr:2012 +ecl:oth pid:237657808 eyr:1944 + +hgt:73in ecl:grn byr:1931 pid:358388825 iyr:2020 +hcl:#602927 eyr:2020 + +hcl:#efcc98 eyr:2024 ecl:hzl +byr:2030 hgt:192cm +iyr:2013 pid:7479289410 + +pid:053467220 iyr:2012 hgt:169cm +cid:149 hcl:#866857 +eyr:2030 +byr:1995 ecl:oth + +hgt:162cm hcl:#efcc98 ecl:grn byr:1985 pid:419840766 +eyr:2022 +iyr:2020 + +pid:22086957 hcl:c69235 ecl:#c458c5 eyr:1986 byr:2014 hgt:72cm iyr:1934 + +hcl:#866857 +ecl:brn eyr:2024 +iyr:2017 +pid:505225484 cid:144 +byr:1980 +hgt:170cm + +hcl:#866857 ecl:gry +byr:1972 iyr:2019 eyr:2023 +cid:234 pid:721290041 hgt:191cm + +pid:346301363 +eyr:2020 +hcl:#733820 iyr:2019 hgt:177cm +byr:1998 + +hgt:157cm byr:1963 +pid:898055805 +hcl:#fffffd ecl:blu iyr:2017 cid:87 +eyr:2030 + +pid:605900764 iyr:2011 +hgt:73in ecl:hzl eyr:2024 +hcl:#888785 +cid:281 + +iyr:2010 eyr:2026 hcl:#4f7e76 pid:883386029 byr:1946 ecl:brn + +hcl:z +iyr:2020 pid:9121928466 byr:2014 ecl:zzz eyr:2025 +hgt:172in + +hgt:151cm cid:163 pid:670884417 iyr:2012 +ecl:oth hcl:#ceb3a1 +eyr:2028 + +hcl:z cid:92 hgt:69cm +byr:2008 pid:492284612 +eyr:2020 iyr:2023 +ecl:hzl + +byr:1933 +hcl:#7d3b0c eyr:2020 hgt:170cm +pid:949064511 iyr:2010 +ecl:oth + +eyr:2025 byr:1989 ecl:oth cid:100 hgt:182cm +pid:629190040 iyr:2017 hcl:#b6652a + +ecl:hzl cid:76 hcl:#e71392 eyr:2021 iyr:2013 byr:1995 +pid:762177473 +hgt:179cm + +pid:198500564 eyr:2029 hcl:#733820 cid:51 iyr:2012 +hgt:70in byr:1938 ecl:oth + +hgt:190cm ecl:brn byr:1952 iyr:2015 hcl:#623a2f +eyr:2023 + +hgt:169cm hcl:#602927 byr:2001 pid:823979592 iyr:2016 eyr:2029 + +iyr:2010 ecl:gry +eyr:2022 hgt:156cm byr:1953 pid:434063393 +hcl:#733820 + +pid:091724580 hcl:a7069e eyr:1984 ecl:#95d01e byr:2012 iyr:2005 + +eyr:2022 byr:1972 hcl:#866857 ecl:hzl pid:227453248 +hgt:153cm cid:324 iyr:2018 + +cid:195 pid:049871343 +eyr:2024 hgt:169cm +byr:1952 iyr:2010 ecl:grn + +eyr:2035 pid:189cm +hgt:77 iyr:1973 ecl:#dc83d5 +hcl:z byr:2004 + +byr:2027 +pid:89338932 hcl:1de39e ecl:grn hgt:159in eyr:2034 iyr:1937 + +pid:076534920 +hgt:152cm +byr:1969 +ecl:blu +hcl:#866857 iyr:2011 eyr:2024 + +iyr:2019 eyr:2028 +ecl:blu hgt:169cm +hcl:#888785 pid:332202163 byr:1923 + +hgt:65in byr:1964 iyr:2019 +pid:287612987 ecl:hzl cid:213 eyr:2023 hcl:#ceb3a1 + +hcl:#623a2f pid:182484027 +iyr:2016 ecl:brn byr:1943 +hgt:71in eyr:2021 cid:344 + +hcl:#cdee64 iyr:2011 ecl:brn eyr:2026 hgt:176cm +byr:1985 pid:978641227 + +eyr:2029 ecl:brn hgt:173cm byr:1920 cid:211 +hcl:#866857 +iyr:2016 pid:289769625 + +hcl:#7d3b0c pid:770938833 iyr:2010 byr:1941 ecl:oth eyr:2029 hgt:161cm + +hgt:172cm iyr:2015 ecl:gry byr:1948 +eyr:2029 +pid:466359109 hcl:#341e13 + +cid:74 pid:405199325 ecl:blu +hcl:#6b5442 +eyr:1980 byr:2024 hgt:174cm iyr:2011 + +hgt:183cm pid:075760048 cid:78 byr:1960 ecl:hzl eyr:2030 hcl:#6b5442 iyr:2014 + +cid:264 hcl:#7d3b0c +ecl:blu iyr:2011 eyr:2020 hgt:182cm +byr:1929 + +pid:435338286 byr:1931 +hcl:z ecl:amb iyr:2013 hgt:73in +cid:165 eyr:2027 + +pid:511898552 eyr:2025 hgt:184cm hcl:#602927 +iyr:2018 byr:1989 ecl:hzl + +iyr:2016 +hgt:168in +hcl:#623a2f +eyr:2025 pid:310738569 ecl:#0c3039 +byr:2027 + +pid:158cm byr:1946 ecl:grt +iyr:1920 cid:189 +hcl:389bce hgt:165cm + +pid:973732906 hcl:#cfa07d iyr:2010 eyr:2020 hgt:180cm +byr:1930 +ecl:brn + +pid:930994364 byr:1967 hgt:151cm +iyr:2011 eyr:2022 + +eyr:1968 hgt:75cm cid:241 +iyr:2011 pid:5493866745 +ecl:grt +byr:1976 hcl:#a97842 + +eyr:2026 ecl:oth +iyr:2016 hcl:#c0946f +byr:1929 +hgt:175cm +pid:9421898537 + +eyr:2028 iyr:2016 byr:1962 +ecl:grn hgt:186cm hcl:#cfa07d pid:432962396 + +iyr:2010 byr:1934 eyr:2023 hgt:180cm hcl:#cfa07d ecl:gry + +cid:168 +byr:1978 +eyr:2027 hgt:189cm pid:802710287 +hcl:#2f980b iyr:2014 +ecl:grn + +eyr:1970 +pid:576329104 +ecl:xry iyr:1954 hcl:#341e13 byr:2026 +hgt:74in + +eyr:2027 hgt:153cm +ecl:oth +hcl:#866857 +pid:290407832 byr:1956 iyr:2017 + +iyr:2011 +cid:128 +ecl:amb hcl:#7d3b0c hgt:68in pid:743606119 eyr:2020 + +ecl:oth hcl:#cfa07d +byr:2016 pid:#de98ae iyr:1984 cid:194 +hgt:170cm +eyr:2034 + +pid:526098672 hgt:168cm +hcl:#7d3b0c cid:167 byr:1923 ecl:blu iyr:2016 +eyr:2030 + +pid:495569197 hcl:#866857 hgt:193cm +iyr:2013 eyr:2021 byr:1921 ecl:amb + +ecl:amb +hcl:#a97842 pid:862249915 iyr:2012 byr:1964 +cid:325 +eyr:2021 + +iyr:1958 +byr:2003 +hgt:160 hcl:#18171d +ecl:hzl eyr:2020 + +iyr:2019 byr:1997 ecl:brn +pid:342735713 hcl:#efcc98 +hgt:181cm cid:307 +eyr:2027 + +pid:817121616 eyr:2020 +iyr:2012 +hgt:185cm +hcl:#18171d byr:1969 ecl:hzl + +pid:381399203 +ecl:oth byr:1930 +iyr:2014 hcl:#6b5442 hgt:71in cid:156 eyr:2025 + +byr:2002 hcl:#18171d iyr:2017 +pid:398245854 hgt:64in ecl:gry eyr:2025 cid:127 + +eyr:2028 hcl:#341e13 +ecl:amb iyr:2012 +pid:079796480 hgt:69cm +byr:1995 + +cid:315 iyr:2028 +pid:775929239 +hgt:162cm ecl:dne byr:1940 eyr:1952 hcl:#c0946f + +iyr:2015 +hgt:154cm byr:1997 +ecl:grn +cid:125 eyr:2024 pid:834780229 +hcl:#18171d + +ecl:hzl hcl:#a97842 pid:553710574 eyr:2028 +hgt:183cm cid:196 +iyr:2014 + +pid:377912488 hgt:159cm ecl:amb eyr:2024 byr:1974 +iyr:2014 +hcl:#ceb3a1 + +eyr:2024 +byr:1947 hgt:63in ecl:brn +cid:69 +pid:185228911 hcl:#b6652a iyr:2016 + +eyr:2024 +hgt:168cm hcl:#602927 +iyr:2013 +byr:1993 +pid:681091728 ecl:gry cid:203 + +pid:037922164 iyr:2020 +byr:1990 hgt:156cm eyr:2023 hcl:#866857 +cid:97 ecl:grn + +hgt:170cm pid:980455250 +iyr:2011 ecl:hzl byr:1957 +eyr:2030 hcl:#cfa07d + +hgt:158cm +hcl:#602927 +byr:2002 ecl:hzl iyr:2013 +cid:99 +eyr:2020 pid:48646993 + +byr:1955 pid:814033843 eyr:2030 hcl:#a97842 +hgt:191cm iyr:2019 + +pid:111196491 hgt:191cm iyr:2012 ecl:blu hcl:#a97842 +eyr:2026 cid:131 byr:1979 + +hcl:#fffffd hgt:68in +cid:121 ecl:oth eyr:2024 pid:343836937 +byr:1955 +iyr:2020 + +eyr:2025 byr:1954 +pid:737517118 +cid:343 hcl:#b6652a +iyr:2017 ecl:hzl +hgt:175cm + +ecl:brn +iyr:2011 hgt:171cm cid:102 pid:066348279 byr:1981 + +ecl:oth iyr:2018 byr:1975 +eyr:2029 +hgt:185cm cid:226 +pid:978243407 hcl:#341e13 + +iyr:2015 pid:918017915 hcl:#3e52b7 +byr:1999 ecl:brn cid:314 +eyr:2025 hgt:192cm + +hcl:#19d1fa byr:1984 ecl:dne hgt:76in +iyr:2015 cid:118 pid:417075672 +eyr:2020 + +iyr:2019 +cid:120 hgt:186cm +hcl:#733820 eyr:2024 pid:423238982 ecl:brn byr:1968 + +hgt:70cm cid:173 pid:767014975 +hcl:#866857 eyr:2039 ecl:brn byr:1985 + +pid:340424924 +eyr:2027 hcl:#7d3b0c +hgt:168cm ecl:hzl iyr:2016 +byr:1994 + +ecl:hzl byr:1933 pid:580425691 +iyr:2010 hcl:#c0946f eyr:2024 +hgt:64in + +hcl:#9fe6b0 pid:913184461 ecl:grn eyr:2030 +cid:262 iyr:2014 + +ecl:amb pid:640007768 eyr:2030 byr:2017 iyr:1988 hcl:z + +byr:1977 cid:54 +eyr:1939 pid:882762394 iyr:2030 hcl:#ceb3a1 ecl:blu + +iyr:2011 hcl:#7d3b0c byr:1928 +pid:340969354 cid:199 hgt:168cm eyr:2029 ecl:hzl + +pid:729464282 +iyr:2012 hcl:baae60 +eyr:2026 ecl:hzl hgt:166cm byr:2019 + +pid:930997801 iyr:2019 eyr:2030 +hcl:#866857 ecl:oth byr:1960 cid:235 hgt:73in + +ecl:brn +byr:1988 hgt:179cm iyr:2017 +pid:864768439 cid:305 hcl:#c0946f +eyr:2029 + +hcl:#7d3b0c ecl:grn +hgt:182cm eyr:2021 pid:719891314 +byr:1920 iyr:2017 + +hgt:62cm +cid:71 ecl:brn hcl:#fffffd iyr:2025 eyr:1997 +pid:175cm byr:2022 + +hcl:#cfa07d cid:239 eyr:2025 ecl:hzl hgt:189in byr:1980 iyr:2020 +pid:703047050 + +byr:1951 +eyr:2030 +ecl:hzl +pid:130992467 hgt:157cm hcl:#341e13 + +hgt:175cm +hcl:#623a2f +cid:68 eyr:2025 +byr:2001 ecl:oth pid:253618704 iyr:2016 + +hcl:#fffffd pid:379344553 ecl:grn +eyr:2026 +hgt:72in byr:1974 iyr:2013 + +ecl:#b4e952 byr:1970 hcl:z +eyr:2039 pid:6056894636 iyr:2021 hgt:165cm +cid:328 + +hcl:#602927 iyr:2014 pid:890429537 byr:1957 hgt:68in eyr:2020 ecl:hzl + +cid:265 byr:1961 hcl:#ceb3a1 eyr:2022 iyr:2016 hgt:184cm pid:921615309 + +byr:1951 eyr:2024 +hcl:#341e13 +ecl:amb pid:414644982 +iyr:2010 hgt:159cm + +iyr:2015 cid:319 +eyr:2029 ecl:brn pid:380237898 +hcl:#efcc98 hgt:157cm byr:1972 + +pid:237156579 ecl:#312a91 +hgt:167cm iyr:2011 hcl:#c0946f eyr:2021 byr:1953 + +ecl:hzl iyr:2015 pid:10160221 eyr:2025 hgt:175cm hcl:z byr:1939 + +hgt:59in hcl:#18171d byr:1962 ecl:hzl +iyr:2019 eyr:2025 +cid:337 pid:491938615 + +ecl:utc hgt:82 pid:51674655 byr:2020 +eyr:1954 iyr:2029 hcl:z + +pid:119530189 +cid:103 +iyr:2010 byr:1979 +hgt:168cm hcl:#a97842 ecl:brn eyr:2029 + +hgt:177cm ecl:brn +byr:1990 +pid:015089628 eyr:2028 hcl:#733820 iyr:2020 + +ecl:blu iyr:2020 hgt:189cm +hcl:#efcc98 byr:1982 pid:346500376 eyr:2021 cid:160 + +ecl:brn hgt:173cm iyr:2011 cid:259 hcl:#6b5442 eyr:2026 +byr:1995 +pid:654875035 + +ecl:grn eyr:2025 pid:147155222 byr:1942 +cid:341 hcl:#602927 +hgt:165cm +iyr:2016 + +pid:543171646 +hgt:153cm +iyr:2019 hcl:#fffffd byr:1985 cid:266 +eyr:2027 +ecl:hzl + +ecl:blu +eyr:2022 +pid:667939101 byr:1974 +cid:259 hcl:#888785 + +eyr:2030 byr:2016 iyr:2022 +pid:86902982 +ecl:zzz hgt:72 hcl:ceb867 + +hcl:#fffffd +ecl:grn pid:046978329 +byr:1924 +eyr:2025 hgt:158cm iyr:2011 + +hgt:150cm eyr:2028 byr:1985 ecl:gry hcl:#866857 pid:340615189 +iyr:2017 +cid:50 + +cid:171 hcl:#18171d pid:009562218 byr:1981 hgt:175cm eyr:2024 ecl:oth iyr:2017 + +iyr:2019 +eyr:2022 +ecl:brn hcl:#cfa07d pid:050270380 cid:159 +hgt:151cm +byr:1951 + +hcl:#7d3b0c hgt:176cm iyr:2015 byr:1923 pid:348188421 ecl:blu eyr:2029 + +byr:1997 hgt:162cm eyr:2023 pid:445685977 +iyr:2012 ecl:amb hcl:#efcc98 + +iyr:2017 ecl:oth eyr:2028 pid:791977055 hgt:170cm byr:1991 +hcl:#623a2f + +byr:1998 hcl:#fffffd +eyr:2020 +ecl:gry pid:039483695 hgt:163cm iyr:2020 +cid:165 + +ecl:hzl hgt:74in iyr:2016 pid:026214321 +cid:152 hcl:#a1f179 +eyr:2036 byr:2001 + +pid:257900949 cid:80 byr:1956 iyr:2012 hgt:165cm eyr:2030 + +pid:918371363 +ecl:xry +iyr:2012 +byr:2012 hgt:65cm +eyr:2029 + +pid:041789006 iyr:2018 byr:1945 eyr:2024 ecl:blu +hcl:#5ab31e hgt:171cm + +ecl:gry +byr:1956 cid:318 iyr:2020 hcl:#623a2f +eyr:2030 pid:020576506 hgt:184cm + +hgt:173cm iyr:2025 +eyr:2023 +ecl:amb pid:958983168 hcl:#866857 byr:1935 + +byr:1974 +eyr:2040 pid:57104308 iyr:1980 hcl:z +hgt:192in cid:295 ecl:amb + +pid:180cm hcl:1109f7 eyr:2039 byr:2020 +ecl:dne hgt:189in iyr:1921 + +iyr:2013 byr:1961 +hcl:#866857 +eyr:2025 hgt:158cm ecl:gry + +ecl:brn iyr:2013 eyr:2021 pid:978650418 byr:1980 +hcl:#ceb3a1 cid:110 +hgt:166cm + +pid:864880558 ecl:hzl hcl:#c0946f byr:1955 eyr:2027 hgt:169cm iyr:2011 + +eyr:2023 hgt:191cm hcl:#866857 +pid:454509887 +ecl:grn byr:1938 iyr:2015 + +pid:793008846 eyr:2025 ecl:grn hcl:#341e13 +hgt:187cm +byr:1973 cid:224 +iyr:2013 + +hcl:#866857 eyr:2022 pid:802335395 hgt:171cm ecl:amb +iyr:2015 byr:1991 + +hcl:#888785 pid:768625886 +hgt:180cm +eyr:2026 ecl:oth cid:178 byr:1958 + +pid:921387245 cid:82 hgt:190cm hcl:#c0946f ecl:grn +iyr:2015 eyr:2023 + +pid:0704550258 hcl:1ba8f6 iyr:2010 byr:1978 cid:130 +eyr:2030 ecl:dne hgt:66cm + +pid:626293279 hcl:#7d3b0c hgt:185cm ecl:oth +eyr:2020 byr:1937 iyr:2012 + +hgt:175 +eyr:1933 ecl:gry +hcl:#7d3b0c byr:2003 pid:#5d8fcc +iyr:2012 + +eyr:2027 +byr:1927 cid:154 +ecl:gry pid:683668809 hgt:164cm +hcl:#a97842 iyr:2011 + +byr:1940 iyr:2014 hgt:172cm eyr:2024 pid:033678324 hcl:#10fded +cid:292 ecl:oth + +iyr:1970 ecl:#201515 pid:#4cd485 eyr:2034 hgt:162 +byr:2005 cid:67 +hcl:#c0946f + +cid:306 +byr:1948 +hcl:#efcc98 +eyr:2024 hgt:171cm pid:440657854 iyr:2015 ecl:brn + +hgt:172cm ecl:brn byr:1958 pid:054926969 hcl:#4b8065 iyr:2019 + +pid:45977569 ecl:amb byr:2002 hgt:71cm hcl:z iyr:1983 + +pid:811407848 hcl:#866857 cid:112 hgt:180cm byr:1986 +ecl:brn eyr:2026 + +ecl:amb +byr:1992 +cid:288 pid:417117245 hcl:#623a2f +iyr:2011 hgt:181cm +eyr:2021 + +byr:1974 hgt:192cm cid:172 +eyr:2022 +ecl:blu +hcl:#cfa07d iyr:2014 + +eyr:2024 ecl:gry +pid:874569675 byr:1960 iyr:2017 hgt:186cm +hcl:#6b5442 + +byr:1988 eyr:2024 iyr:2020 ecl:oth hcl:#866857 pid:227304269 hgt:170cm + +ecl:grn iyr:2019 byr:2002 cid:150 hcl:#efcc98 +pid:600740993 +hgt:167cm eyr:2027 + +pid:553824537 iyr:2019 ecl:blu eyr:2025 hcl:#e21269 hgt:193cm +byr:1923 + +byr:2030 iyr:2019 ecl:#cb0911 +hcl:#cfa07d hgt:74in eyr:2012 +pid:7647207386 + +cid:289 hgt:128 pid:178cm iyr:2025 ecl:#4ad977 byr:2020 eyr:2036 hcl:#efcc98 + +cid:119 hgt:150in +hcl:z +iyr:2012 +ecl:brn eyr:1975 +byr:2007 pid:#0dcd32 + +hcl:8a1ce7 pid:0434291854 +eyr:2034 iyr:2005 +hgt:62cm byr:2029 ecl:utc + +ecl:gry hcl:#ceb3a1 byr:1976 eyr:2024 iyr:2010 hgt:188cm +pid:636312902 + +hcl:#888785 byr:2027 hgt:178in iyr:2017 pid:973095872 eyr:1952 + +hgt:179cm iyr:2015 hcl:#ceb3a1 +byr:1944 pid:182079308 cid:317 +eyr:2025 ecl:hzl + +hcl:#6b5442 ecl:grn eyr:2023 hgt:71in pid:829794667 byr:2000 +iyr:2014 cid:192 + +iyr:2014 pid:096659610 hcl:#c0946f ecl:oth byr:1991 cid:180 +hgt:177cm +eyr:2023 + +byr:2017 +eyr:2036 iyr:1933 +cid:225 ecl:gmt hgt:179in +hcl:b5c44d pid:99932231 + +hcl:#18171d +hgt:187cm eyr:2023 byr:1934 cid:286 pid:878541119 iyr:2020 ecl:amb + +hgt:185cm +pid:754207134 ecl:oth eyr:2023 +hcl:#a97842 cid:313 byr:1966 +iyr:2015 + +hcl:#ceb3a1 byr:1921 eyr:2022 pid:799265846 cid:285 +hgt:67in iyr:2015 + +iyr:2011 byr:1941 +hcl:#341e13 cid:65 pid:413556937 +hgt:169cm +ecl:amb eyr:2020 + +iyr:2016 +hgt:158cm ecl:grn byr:1931 hcl:#7d3b0c + +pid:574299170 iyr:2013 byr:1961 ecl:hzl hcl:#866857 hgt:168cm eyr:2022 + +eyr:2022 pid:245416405 +iyr:2019 hgt:173cm hcl:#c0946f +ecl:brn +byr:1965 + +byr:1980 hgt:162cm ecl:brn pid:239318191 +hcl:#fffffd +cid:58 eyr:2025 iyr:2020 + +pid:892646915 +iyr:2012 hcl:#733820 byr:1991 eyr:2021 +hgt:157cm ecl:oth + +pid:310597466 eyr:2025 +hcl:#cfa07d byr:1944 iyr:2018 ecl:oth +hgt:183cm + +iyr:2010 hgt:187cm ecl:oth +pid:975763328 +hcl:#866857 eyr:2023 cid:283 byr:1997 + +iyr:2020 cid:225 hcl:#efcc98 pid:424680047 ecl:blu +hgt:154cm +byr:1968 eyr:2027 + +ecl:oth eyr:2020 hgt:183cm hcl:#623a2f +pid:771851807 +byr:1990 +iyr:2017 + +hcl:#efcc98 ecl:blu byr:1991 hgt:191cm pid:266021118 +cid:124 +eyr:2025 + +byr:1993 +ecl:hzl eyr:2020 +hgt:163cm +iyr:2015 pid:831538073 hcl:#18171d + +hgt:74in hcl:#420afb eyr:2028 +ecl:grn pid:264469103 +byr:1993 + +eyr:2020 +cid:79 +byr:1972 +pid:084953331 hcl:#a97842 ecl:brn iyr:2010 +hgt:170cm + +iyr:2014 ecl:gry pid:094812116 eyr:2026 hgt:190cm byr:1965 hcl:#944667 + +hcl:#fffffd byr:1953 iyr:2014 ecl:hzl hgt:164cm +cid:123 eyr:2023 pid:546394433 + +iyr:2012 hgt:155cm byr:1998 pid:#2c9be6 eyr:2023 hcl:#ceb3a1 ecl:gry + +eyr:2029 ecl:gry pid:752489331 iyr:2015 hgt:167cm hcl:#18171d cid:70 byr:2002 + +byr:1938 +ecl:gry +pid:764937909 iyr:2014 +hcl:#7d3b0c +eyr:2022 cid:145 hgt:184cm + +cid:340 +byr:1924 hgt:169cm eyr:2026 +iyr:2013 ecl:amb +pid:499844992 hcl:#18171d + +pid:838417672 hgt:175cm +ecl:grt iyr:2017 eyr:2025 hcl:17aa1a + +eyr:2020 +byr:1925 hcl:#341e13 +ecl:brn cid:342 pid:047426814 hgt:156cm iyr:2012 + +iyr:2011 hcl:#341e13 byr:1959 +ecl:amb pid:969679865 + +byr:1978 cid:320 hgt:180cm hcl:#435ceb pid:363518544 eyr:2023 iyr:2016 ecl:blu + +iyr:2010 eyr:2028 +pid:183cm byr:1948 +ecl:oth cid:133 +hcl:#8d3298 hgt:190cm + +hcl:#6b5442 byr:1929 iyr:2019 pid:207713865 eyr:2029 +hgt:166cm ecl:gry + +ecl:blu iyr:2019 +byr:1985 eyr:2030 hcl:#866857 hgt:155cm pid:659180287 + +ecl:hzl +eyr:2020 iyr:2016 pid:440624039 +cid:147 +hgt:61in byr:1976 hcl:#733820 + +hcl:#341e13 pid:178082907 eyr:2023 +iyr:2015 byr:1956 +ecl:amb hgt:163cm + +eyr:2023 +iyr:2011 hcl:#cfa07d hgt:164cm +pid:291621559 byr:1960 ecl:gry + +hcl:#efcc98 byr:1976 +iyr:2017 pid:394566091 cid:248 +hgt:176cm ecl:hzl eyr:2026 + +iyr:2013 eyr:2029 hgt:152cm ecl:gry byr:1984 hcl:#623a2f pid:511780941 + +pid:953716819 iyr:2010 hgt:156cm ecl:amb +byr:1947 +hcl:#18171d eyr:2025 + +eyr:2025 ecl:amb +iyr:2016 +hcl:#cfa07d byr:1925 pid:322787273 hgt:168cm + +hgt:59in iyr:2012 +pid:916978929 byr:1959 +hcl:#c0946f eyr:2021 +ecl:brn + +byr:2018 eyr:1929 hgt:187in +hcl:z +iyr:2003 pid:0377361331 ecl:utc + +byr:1949 hcl:#fffffd pid:071791776 eyr:2030 iyr:2015 hgt:71in ecl:hzl + +hcl:#341e13 +hgt:154cm byr:1927 eyr:2023 ecl:blu iyr:2017 +pid:639867283 + +hcl:z pid:315276249 byr:2026 +hgt:151cm +iyr:2028 eyr:2020 +ecl:hzl + +hcl:#341e13 eyr:2027 byr:1981 cid:342 pid:999898177 hgt:187cm +ecl:blu iyr:2011 + +byr:2009 +hgt:73cm iyr:1921 hcl:z +pid:181cm +ecl:xry + +ecl:hzl +byr:1925 +pid:034183103 hcl:#341e13 hgt:158cm eyr:2029 iyr:2010 + +byr:1976 +iyr:2011 hgt:177cm pid:833479839 hcl:#dcab9d ecl:blu eyr:2020 + +cid:230 hcl:#7d3b0c byr:1954 +iyr:2014 eyr:2026 pid:122150889 +ecl:brn hgt:182cm + +hcl:#a97842 +ecl:brn hgt:187cm +eyr:2028 +pid:427631634 iyr:2002 byr:2004 + +pid:912516995 ecl:hzl iyr:2017 hcl:#ceb3a1 byr:1929 eyr:2028 +hgt:155cm + +pid:019809181 +cid:128 iyr:2013 hcl:#f5b9f7 byr:1931 +hgt:161cm +ecl:amb + +hgt:64in byr:1924 +iyr:2016 eyr:2029 ecl:hzl pid:474940085 hcl:#c0946f + +pid:172419213 +ecl:grn +hgt:193cm iyr:2010 byr:1973 hcl:#6b5442 +eyr:2027 + +ecl:#7b5cfd iyr:2019 +byr:2016 +eyr:2040 hgt:191in +cid:187 hcl:z pid:#c61084 + +eyr:2032 iyr:2014 pid:430247344 byr:1967 +hcl:#ceb3a1 +cid:241 +ecl:brn hgt:178in + +hcl:#623a2f iyr:2017 cid:235 +eyr:2020 byr:1978 ecl:blu hgt:175cm + +iyr:2013 ecl:amb hgt:174cm hcl:#866857 pid:285533942 byr:1954 + +hgt:152cm ecl:blu pid:952587262 eyr:2024 +iyr:2019 cid:268 hcl:#602927 byr:1947 + +hgt:176in cid:245 byr:2011 iyr:2018 +eyr:1987 +hcl:z +pid:346518170 +ecl:utc + +hgt:180cm +iyr:2015 ecl:brn eyr:2027 pid:807494368 cid:324 byr:1980 + +byr:1936 hcl:#866857 ecl:blu +eyr:2021 hgt:187cm +iyr:2016 pid:244556968 + +byr:1950 cid:125 +iyr:2020 hgt:168cm hcl:#c0946f eyr:2030 pid:758313758 ecl:blu + +eyr:2021 +pid:618915663 hcl:#cfa07d iyr:2018 byr:2002 +hgt:157cm ecl:blu + +byr:1967 +ecl:brn hcl:#c0946f pid:200495802 eyr:2021 iyr:2020 +cid:335 +hgt:181cm + +byr:1996 +ecl:brn iyr:2015 +eyr:2030 +hcl:#fffffd cid:207 +pid:022460311 hgt:158cm + +eyr:2022 hgt:59cm iyr:2023 +byr:1974 pid:354098699 hcl:b244f7 +ecl:#219505 + +hcl:#866857 eyr:2025 +pid:370874666 +byr:1947 +cid:162 ecl:oth hgt:186cm iyr:2011 + +ecl:hzl eyr:2029 +byr:1981 +iyr:2012 pid:433430792 cid:252 +hgt:171cm + +pid:512473844 hgt:186cm iyr:2012 eyr:2028 byr:1949 ecl:hzl hcl:#18171d + +hgt:60cm iyr:1934 +ecl:#4a4017 pid:3067366202 hcl:1161df +eyr:1938 byr:2008 + +pid:119509757 hcl:#cfa07d eyr:2022 hgt:174cm byr:1983 +iyr:2015 +ecl:blu + +byr:1955 eyr:2023 +cid:114 +hcl:f1aa8a pid:609049659 ecl:grn hgt:177cm +iyr:2015 + +eyr:2027 cid:284 +pid:654627982 byr:1964 iyr:2018 hgt:168cm +hcl:#fffffd ecl:oth + +iyr:1988 +hgt:191cm hcl:b87a62 byr:1990 ecl:xry +pid:996624367 eyr:1960 + +pid:641466821 eyr:2028 hcl:#7d3b0c +iyr:2010 hgt:175cm ecl:gry + +hcl:#b6652a +ecl:oth +byr:1926 eyr:2030 iyr:2019 hgt:183cm +pid:057196056 + +iyr:2017 +eyr:2022 pid:936841429 +ecl:blu hcl:#6b5442 cid:179 byr:1927 hgt:161cm + +eyr:2021 +cid:289 hgt:174cm iyr:2013 +ecl:grn pid:329574701 byr:1970 + +eyr:2021 byr:1939 ecl:gry pid:933505139 iyr:2014 hgt:173cm hcl:#7d3b0c + +cid:116 hcl:045bff eyr:2030 iyr:1920 +ecl:brn +byr:2030 +pid:#38f7f3 +hgt:155in + +eyr:2028 +pid:225829241 byr:1928 hcl:#cfa07d iyr:2019 +ecl:oth +hgt:166cm + +cid:80 byr:1936 +iyr:2017 +hgt:94 hcl:#2e7503 ecl:oth eyr:2030 +pid:597284996 + +ecl:oth +iyr:2019 hgt:76in +byr:1956 pid:821874039 + +eyr:2026 hgt:168cm +pid:019015588 +iyr:2010 +ecl:amb byr:2009 hcl:#623a2f cid:159 + +iyr:1980 hgt:167in +pid:380644909 eyr:1966 ecl:blu byr:2004 hcl:z + +eyr:2020 iyr:2013 +hcl:#08ad66 pid:540886868 +ecl:oth byr:1980 hgt:158cm + +eyr:2026 hgt:186cm byr:1995 +cid:275 +hcl:z iyr:1958 ecl:blu + +eyr:2026 iyr:2012 +hgt:61in byr:1936 pid:390833536 cid:298 ecl:grn hcl:#623a2f + +pid:393878498 eyr:2023 ecl:gry byr:1943 iyr:2010 hcl:#888785 hgt:158cm + +hgt:191cm cid:197 iyr:2014 byr:1945 +hcl:#fffffd +eyr:2020 +pid:183948344 ecl:amb + +ecl:gmt hgt:88 +cid:260 iyr:2024 byr:2022 eyr:2031 hcl:z pid:#532c6e + +hcl:#a97842 +hgt:160cm eyr:2024 ecl:blu iyr:2015 byr:1970 + +byr:1964 hgt:178cm +eyr:2025 +pid:813643223 ecl:brn iyr:2014 +hcl:#ceb3a1 + +byr:1965 eyr:2024 iyr:2018 +hgt:165cm hcl:#18171d ecl:grn pid:475669993 + +hgt:116 +iyr:2024 eyr:1974 hcl:504345 byr:2010 cid:206 pid:166cm ecl:zzz + +iyr:2014 eyr:2020 pid:096460673 byr:1948 +hgt:153cm +ecl:blu hcl:#341e13 + +hcl:#ceb3a1 +iyr:2017 hgt:67cm +pid:178cm byr:2028 ecl:brn +cid:293 + +hgt:157cm +hcl:#602927 byr:1941 +iyr:2012 pid:611003211 eyr:2029 + +iyr:2019 byr:2000 pid:083917767 eyr:2024 hgt:172cm +cid:248 hcl:#7e4d15 + +byr:1946 +hgt:160cm iyr:2020 hcl:#559278 pid:989139577 +ecl:amb eyr:2020 + +pid:165cm byr:1927 cid:178 hcl:#733820 iyr:2017 hgt:156in +eyr:2029 ecl:brn + +hcl:#18171d hgt:163cm eyr:2022 byr:1962 pid:639124940 cid:258 ecl:hzl +iyr:2015 + +cid:123 pid:4542006033 +eyr:1987 byr:2010 iyr:2029 ecl:amb +hgt:191cm hcl:#18171d + +hcl:z +byr:1928 iyr:1965 +eyr:2022 hgt:75 ecl:oth pid:400765046 + +hcl:#c0946f hgt:62in +ecl:blu byr:1978 iyr:1923 +cid:260 eyr:2021 pid:404628742 + +pid:#bf1611 ecl:grn +iyr:2018 cid:146 byr:1948 +eyr:2025 hcl:#fffffd hgt:87 + +pid:767547618 +iyr:2018 hcl:#b6652a eyr:2029 hgt:165cm ecl:hzl byr:1937 + +ecl:blu iyr:2019 pid:960083875 eyr:2027 hgt:71in hcl:#c0946f +byr:1921 + +iyr:2011 +pid:9562042482 +hcl:z hgt:59cm +eyr:1994 cid:258 ecl:#6c1bcc byr:2025 + +eyr:2028 pid:494999718 byr:1928 hgt:176cm +iyr:2015 ecl:oth hcl:#733820 + +cid:78 eyr:2020 hgt:160cm byr:1947 ecl:blu +hcl:#b6652a iyr:2016 pid:069457741 + +hcl:#6b5442 iyr:2010 +byr:1971 +eyr:2028 hgt:169cm ecl:brn pid:528961949 + +eyr:2028 +hcl:#7d3b0c +byr:1952 +ecl:hzl +cid:317 iyr:2016 +pid:832169844 + +hcl:#c0946f +ecl:brn +iyr:2017 eyr:2028 +pid:161390075 byr:1993 cid:50 +hgt:171cm + +ecl:#ae12d3 hgt:74cm cid:239 hcl:z pid:345439730 iyr:1924 byr:2029 eyr:2031 diff --git a/d04/invalid.txt b/d04/invalid.txt new file mode 100644 index 0000000..a7fa5bb --- /dev/null +++ b/d04/invalid.txt @@ -0,0 +1,13 @@ +eyr:1972 cid:100 +hcl:#18171d ecl:amb hgt:170 pid:186cm iyr:2018 byr:1926 + +iyr:2019 +hcl:#602927 eyr:1967 hgt:170cm +ecl:grn pid:012533040 byr:1946 + +hcl:dab227 iyr:2012 +ecl:brn hgt:182cm pid:021572410 eyr:2020 byr:1992 cid:277 + +hgt:59cm ecl:zzz +eyr:2038 hcl:74454a iyr:2023 +pid:3556412378 byr:2007 diff --git a/d04/main.go b/d04/main.go new file mode 100644 index 0000000..eb3d4b0 --- /dev/null +++ b/d04/main.go @@ -0,0 +1,149 @@ +package main + +import ( + "bufio" + "fmt" + "log" + "os" + "regexp" + "strconv" + "strings" +) + +func proccessLines(path string, f func(string) (stop bool, err error)) error { + file, err := os.Open(path) + if err != nil { + return err + } + defer file.Close() + scanner := bufio.NewScanner(file) + for scanner.Scan() { + stop, err := f(scanner.Text()) + if stop || err != nil { + return err + } + } + if err := scanner.Err(); err != nil { + return err + } + return nil +} + +func between(low, mid, high int) bool { + return low <= mid && mid <= high +} + +type validator = func(v string) bool + +var heightMatcher = regexp.MustCompile(`^([0-9]+)(cm|in)$`) + +func heightValidator(v string) bool { + result := heightMatcher.FindStringSubmatch(v) + if result == nil { + return false + } + value, err := strconv.Atoi(result[1]) + if err != nil { + return false + } + switch result[2] { + case "cm": + return between(150, value, 193) + case "in": + return between(59, value, 76) + } + return false +} + +func betweenValidator(low, high int) validator { + return func(v string) bool { + val, err := strconv.Atoi(v) + if err != nil { + return false + } + return between(low, val, high) + } +} + +func valueInValidator(valid ...string) validator { + validValues := map[string]bool{} + for _, value := range valid { + validValues[value] = true + } + return func(v string) bool { + _, ok := validValues[v] + return ok + } +} + +var requiredKeys = map[string]validator{ + "byr": betweenValidator(1920, 2002), + "iyr": betweenValidator(2010, 2020), + "eyr": betweenValidator(2020, 2030), + "hgt": heightValidator, + "hcl": regexp.MustCompile(`^#[0-9a-f]{6}$`).MatchString, + "ecl": valueInValidator("amb", "blu", "brn", "gry", "grn", "hzl", "oth"), + "pid": regexp.MustCompile(`^[0-9]{9}$`).MatchString, +} + +func parseKeys(text string) map[string]string { + d := map[string]string{} + for _, kvp := range strings.Split(text, " ") { + parts := strings.Split(kvp, ":") + d[parts[0]] = parts[1] + } + return d +} + +func validateKeys(d map[string]string) bool { + for key := range requiredKeys { + if _, ok := d[key]; !ok { + return false + } + } + return true +} + +func validateValues(d map[string]string) bool { + for key, f := range requiredKeys { + var v string + var ok bool + if v, ok = d[key]; !ok { + return false + } + if !f(v) { + return false + } + } + return true +} + +func main() { + validKeys, validValues, total := 0, 0, 0 + buffer := []string{} + processBuffer := func(buffer []string) { + d := parseKeys(strings.Join(buffer, " ")) + if validateKeys(d) { + validKeys++ + } + if validateValues(d) { + validValues++ + } + total++ + } + err := proccessLines("input.txt", func(line string) (stop bool, err error) { + if line == "" { + processBuffer(buffer) + buffer = []string{} + } else { + buffer = append(buffer, line) + } + return + }) + if err != nil { + log.Fatal(err) + } + processBuffer(buffer) + + fmt.Printf("Total: %d, Valid keys: %d, Valid values: %d\n", total, validKeys, validValues) +} diff --git a/d04/main.py b/d04/main.py new file mode 100755 index 0000000..f39c141 --- /dev/null +++ b/d04/main.py @@ -0,0 +1,121 @@ +#! /usr/bin/env python3 + +import re + + +def height_validator(x): + match = re.match(r"^([0-9]+)(cm|in)$", x.strip()) + if not match: + return False + if match.group(2) == "cm": + return 150 <= int(match.group(1)) <= 193 + elif match.group(2) == "in": + return 59 <= int(match.group(1)) <= 76 + return False + + +required_keys = { + "byr": lambda x: 1920 <= int(x) <= 2002, + "iyr": lambda x: 2010 <= int(x) <= 2020, + "eyr": lambda x: 2020 <= int(x) <= 2030, + "hgt": height_validator, + "hcl": lambda x: re.match(r"^#[0-9a-f]{6}$", x.strip()), + "ecl": lambda x: x in ("amb", "blu", "brn", "gry", "grn", "hzl", "oth"), + "pid": lambda x: re.match(r"^[0-9]{9}$", x.strip()), +} + +optional_keys = { + "cid": lambda x: True, +} + + +class Passport(object): + + def __init__(self, s): + self.d = {} + for kvp in s.split(): + parts = kvp.partition(":") + self.d[parts[0]] = parts[2] + + def key_set(self): + return set(self.d.keys()) + + def is_valid(self, deep=False): + valid = set(required_keys.keys()) <= self.key_set() + if not valid or not deep: + # print(f"Valid: {valid}. Missing: {set(required_keys.keys()) - self.key_set()}") + return valid + + for key, validator in required_keys.items(): + valid = validator(self.d[key]) + if not valid: + # print(f"Invalid value for {key}: {self.d[key]}") + return False + # print("Valid!", self.d) + return valid + + +def parse_passport(buffer): + s = " ".join(buffer) + return Passport(s) + + +def part1(): + num_valid = 0 + total_passports = 0 + with open("input.txt") as f: + buffer = [] + for line in f: + line = line.strip() + if line == "": + p = parse_passport(buffer) + total_passports += 1 + if p.is_valid(): + num_valid += 1 + buffer = [] + else: + buffer.append(line) + # if total_passports == 4: + # break + if buffer: + p = parse_passport(buffer) + total_passports += 1 + if p.is_valid(): + num_valid += 1 + + print("Total passports:", total_passports) + print("Total valid passports:", num_valid) + + +def part2(): + num_valid = 0 + total_passports = 0 + # with open("valid.txt") as f: + # with open("invalid.txt") as f: + with open("input.txt") as f: + buffer = [] + for line in f: + line = line.strip() + if line == "": + p = parse_passport(buffer) + total_passports += 1 + if p.is_valid(deep=True): + num_valid += 1 + buffer = [] + else: + buffer.append(line) + # if total_passports == 4: + # break + if buffer: + p = parse_passport(buffer) + total_passports += 1 + if p.is_valid(deep=True): + num_valid += 1 + + print("Total passports:", total_passports) + print("Total valid passports:", num_valid) + + +if __name__ == "__main__": + part1() + part2() diff --git a/d04/valid.txt b/d04/valid.txt new file mode 100644 index 0000000..ca41800 --- /dev/null +++ b/d04/valid.txt @@ -0,0 +1,12 @@ +pid:087499704 hgt:74in ecl:grn iyr:2012 eyr:2030 byr:1980 +hcl:#623a2f + +eyr:2029 ecl:blu cid:129 byr:1989 +iyr:2014 pid:896056539 hcl:#a97842 hgt:165cm + +hcl:#888785 +hgt:164cm byr:2001 iyr:2015 cid:88 +pid:545766238 ecl:hzl +eyr:2022 + +iyr:2010 hgt:158cm hcl:#b6652a ecl:blu byr:1944 eyr:2021 pid:093154719 diff --git a/d05/input.txt b/d05/input.txt new file mode 100644 index 0000000..acff32c --- /dev/null +++ b/d05/input.txt @@ -0,0 +1,874 @@ +FBFBFFFLLL +FFBBBBFLRR +BFBFBBBLLL +FFBBBBBLLL +BFFBBBBRLL +BBBFFBFRLL +FFBBFFFRRR +FFBFFBBLRL +FBFFBFBRRR +FBFFBFBRLL +BFFBFFFRLR +FFFBBFFRRR +BFBFBBFLLL +FBFBBFFRRL +BFFBFBFLRL +FBFFFBFRRL +FBFBFFBRRR +FBFBFFBRLL +BFBFFFBLLL +BFBFFBBLRL +FBFFFFBRRL +BFFFBFFRRL +FBFBFFFRLR +BFFFFBBLLR +FFBFFFFRLR +BBFBBFFLLL +FFBFFBFRRR +FBFBFBBRRR +BBBFFFFLRR +FFFBFFBRRR +BFFBFBFLRR +BFFFBBBRLL +FFBFBBBRLR +FBFFFFBLLR +FBBFBFFLRL +FBFFFFFRLL +FBBBBFBRLL +BFBBBBFLLL +FBBBFBBRRR +BFFFBFBLLL +FBBBBBFLRL +BFBBBFFLRR +BFBBFBBLRR +FFBBBFFLRR +FFBBBBFRLR +BFFFBFFLLR +FBBFFFBRRL +FBBBFBBLRR +FFBBFBFRRL +FFFBFBBLRR +FBFBBBBRLR +FBFFBFBLLL +FBBFFFFRLL +BBBFFFBLRL +FBBFBBBLLL +FFBBFBBLLR +FBFFFBBRLR +BBFBBFFRRL +FFFBBFFRLL +FBFFBBBLRL +BFFBFFFLRL +FFFFBBFRRR +FBBFBBFLLR +BFBFBFBRRL +BBFBFBBRRR +BBBFFFBLLL +BFBFFBFRLL +FFBBFFBRRR +BFBBFFFRRL +BFBBBFBRRL +BFBBBBBRRR +BBFBFBFRLL +BBFFBFFLRL +BFFBBFFLLL +BFBFBFFLLL +FBBBFFFRLR +BFFFBBBLRL +FBFBFFFLRR +FBBBFBBLRL +FFBBFBBRLR +FBBFFFFLRL +FFFBFBBLLL +FBFBFFBRRL +BBFFBBFRRR +BFFFFBFRLR +FBFBFFBLRL +FFBFFBBLLL +FBFBBFBRLR +BFFBBFBRLR +FFBFBFBLLL +FFBBFFBRLR +FBBBBBBLLL +FFFBBBBRRL +BFBBFBBRLL +BBFFFBFLLR +FFBBBBFRRR +BFBFFFBRLL +BFBFFBFLRR +FFFFBBBLLR +FBFFBBFRLL +FFFFBBBRRL +FFBFFBBLLR +FBFFFBBLLL +FFBBBBFRLL +BBFFBFFLLL +BFBBBBBRRL +BFFBFBFLLL +FFBFBBFLLR +FFBFBBBLRL +BFFBFFBLRL +FBBBFFFRRR +FBBFFBBRRL +FBBFFBBLLR +BBFBBBFLRR +BBFFFBFRRL +FBFBFBFRRL +FFBFBBFRRR +FBFFBBBLLR +BBFBFFBRLL +BFBBBFBLRL +FFBBFFFLRR +BFFFBFFLRL +BFFBBBFLLL +FBBFFFBLRL +BBBFFBFLLL +BFBBFBBRLR +FBBBBBFRLL +FBBBBFBLRR +FFBFBBFRLR +BBFFFFBLLL +FBFBBBFRLR +FBBFBBBLRL +BBFFBBBRLL +FFBFBFFLLR +FFFBBFBRLL +FFBBBFFRLL +BFBBFFFLRR +FBBBFBFRLL +BBFBFBFLRR +BFBBBFFRLL +FFBFFFFRRR +BFBBBBBLLR +FBBBBBBRRR +BBFBBFFLRR +BFBFFBBLRR +BFFBFBBLRR +BFFBBFFRLR +FBBBFFBRRR +FFFFBBBRLR +FBFFFFFLLL +BBFFFBFLRR +BFFFFBFLRL +BFFBFFBLLL +BFFBBFBRRL +FFFBBFFLLR +FBFFFFBLRL +FBFFFBFLLR +FFBBFBBRLL +FFBFFBBRLR +FFBFFFBRRL +FFFBFBFLRR +BBFFBFFRRR +BBFFFFFLLL +FBBFBFBRLR +BBFBBFBLLR +BBFBBBFRRL +BFBFFBBLLR +FBBFFFFLLR +FFBFBFFRRL +FFFBFFBRRL +FBFBFFBRLR +BFBBFBFRLL +BBFBBBBLLR +BFBBBFFLLL +BBFBBBBRRL +BFBFBFBRLR +BFFFBFBRRL +BFFBBBFRRL +BFFFBFBRLL +FBFBFBFLRR +FFBFFBFLRR +BBFBBBBRLL +BFBBBFFLRL +FBBBBFBLLL +BBFBBBFLRL +BFBBFBFLLL +FBBBBBBLRL +FFBFFFBLLL +FFBBBBBRRL +FBBFFFBLLL +FBBBFFBLRR +BBBFFBFLLR +FFFFBBBLLL +FBBBBBBRLR +FFBFFBBRRR +BFFFBFFRLL +BBBFFFBRRR +FBBFBFFLLL +FBFBFBBRLR +FBFFFFFLRL +FFBBBBBRLR +FBBBFFBRRL +BFBBBBFRRL +FBFBBFBLLR +BBFFBBBLLL +BBBFFBFRLR +FFBBFFFLLL +FFBFFBBRRL +FBBBBFFLLL +FBBBBBFRRR +FBFFBBFLLR +FFFBFFFLRL +FFFBFBBRRL +BFFFBFFLLL +FBBBFBBLLL +FFBFBBBLLL +BFFFFFBLRL +FBBBFBFLRR +BBFFBBFLLR +FBFFBBBRLR +BFBFFFFLLR +BFBBBFBLLL +BBFBFBBRLR +FFFBBFBLLR +BFFBFBBRRL +BBFFBBFLRR +BFFBBBFLRR +FBFBBBBRRL +BFBFBFFRRL +BBFBBFFRLR +BBFBBBBRLR +FFBBFFFLLR +BBFBFBBLRR +FBFBFBFLLL +BFFFFBBRRR +BFBBBBFRRR +BFFFFFFLRL +BBBFFBFLRR +FFFBBBBRLR +FBBFFFBRLL +BBFFBBFLRL +FFBBBBBRRR +BBFFBFFRLL +BFFFFFBRRR +FBBFBFBRRR +BFFFFBFRRR +FBBFBBBRLL +FFFBFBBRLR +FBBBBFFRLR +FBBFFFBLLR +FFBBFFBLLR +BFBFFFBLRR +FFBFBBBRRR +BFBFBFBLRR +BFFBBFBLRR +FBFFBFFRLL +BFFBBBFRLR +FBFFFBFRLR +FFFBFBFRLL +FBBFBBFLLL +BFBBFFFLRL +FBBFBFFLRR +BBFFFBFRRR +FBBFBFBLRL +FBBBFBFLLR +FBFBBBBLLR +BBBFFFFLLR +BFBBFBFRRR +FFBFBFFRLR +FFBBFBBLLL +BFFFFFBLLR +FBBBFBFLLL +FBBFBBFRLR +BBFFFFFRLL +BFBFBFFLRR +FBFBBFFLRR +BBFBBFBRLR +BFFFBBFRLR +FBFFBBFRRR +FBFFFBFLLL +FBBFBBBRRR +BBFFFBBLRL +FFBFFBFLLR +BBFFBFFLLR +BBBFFBFRRL +FBFBBFBRRR +FBBBBBBRLL +FBFFFBBLRR +FFFBFFFLLL +BBFBBFFRLL +BBFFFBFRLL +BBFFFBFLLL +FFBBFBBRRL +FFFFBBFLRL +BFBBBBFLRL +BBFBBFFLLR +BBFFBFBRRR +FBFBBFFRLL +FBFBBFBLLL +BFBBBFFRRR +FFBBBFBRLL +FFBFBBBRRL +BFBBFBFRLR +BBFBFBFRLR +FBFBBBFLLR +FBFBBBFLRL +BBFFBBFRLR +FFBBFFFLRL +FFFFBBFLRR +FFFBBFFLRL +FFFBFBFRRR +FBBFFBBLRR +BBFBBFBLRR +BFFBBBFLRL +FBFFBFFRLR +FBFFFBFRRR +BFFBBFFRRL +BFFFBBFRLL +BFBFBBBLRR +FFBFFFBLRL +FBFBBFBRLL +FBBBBFBLLR +FFBFBFBLRL +FBFBBBFLRR +FFBBBBBLRR +FFBFFFBLLR +BBFFFBBRLL +BBFFBBFLLL +FFFBBFBLRL +FBBBFBFRRR +BBFBBBBRRR +FBBBFFBLLR +FBBBBFBLRL +FBFBFFFRRL +FBBFFFFLRR +BFFFBFBLRL +BFFBFFBRLL +BFBFFFBLRL +FBFBFBFRLL +BBFBFBFLLL +FBBBBBFRRL +BFFBFFFRLL +FBBBFBBRRL +BFBBFFBRLR +FFBFBFFLLL +FFBBBBBLLR +FFBFBFBRRL +FFFBFFBLRL +BBFFFBFLRL +FBFBFBBRRL +BFFBFFBRRL +BBFBFBBLRL +BBFBFBFRRR +FBFFBBFRLR +FBFBBFBLRR +FBBFFFFLLL +FFFBFFFLRR +FFFBBBBRRR +BBFFFBBRLR +FFBFFFFRLL +FBFFBFBRLR +FBFBFBBRLL +FBBBBFFLRR +FBBFBFBRLL +FBBBFBFLRL +BBFBBBFLLR +FFBFBBBLLR +BFFBBBFRRR +FFBBFBFLLL +BFBBBFBRLR +FFBFBBBRLL +FFBFBFFLRR +FBFBFBBLLL +BFBBBBFLLR +FFBBFBFRRR +FBFBFBBLRR +BFFFBFBLLR +BFFBFBFRRL +FFFBBBFRLR +FFFBBFFRRL +FFFBBBFLRL +FFFFBBFLLL +BBBFFFBLRR +FBFFFFBRRR +FFFFBBFRRL +FBFBBFFRLR +BFFBBBBLRL +FBFFFFBLRR +FFFBBFBLRR +FFFFBBFRLL +FFFBBFBRRR +FBFFBBBRRL +BBFFFFFLRL +BBFFBBFRRL +BFFFBBBLLL +FBBBBBBLRR +FBBBFFFRLL +FBFFBFFLRR +FFBFBBFLLL +FFBBBFBRRR +BFFFBFBRRR +BBFFBFBRRL +BFFFBBBRLR +FBFFFBBRRR +BBFBBFBRLL +BBFFBBBRRR +FBFFBFBLLR +FFBFFBBLRR +FBBFBBFLRL +FFBFFBFLLL +FFFBFFFRRL +BBBFFFBRLL +BFBFBBBRRL +FFBFBFBLLR +FFFBBBFRLL +BFFFBBFRRR +BFBBFFFRLR +FBBFFBBRLL +BFBBBBBLRL +BBFBFBFLRL +BFBBBFBLLR +FBBFFBBRRR +BFFFFBBLRR +FBBFBBBLLR +BFBFBFBRLL +BFBFBFBRRR +BFFFFBFRRL +FBFBBFFLLR +FBBFBBFRRL +BBFBFBBLLL +BFFBFFBRRR +FBBFBFBLRR +BFFBBFBLLR +BFBFBBBRLL +FBFFBBBLRR +BBFFBFBLRR +BBFFFFFRLR +BBBFFBBLLR +BBFBBFFRRR +BBFFFBBLLR +BFFBFFBRLR +FBFFBFFLLL +BFBBFFFRLL +FFFBFBBRLL +FBFBFBBLRL +FFFBBBFRRL +BFBFBBFRLR +BBFFFFFRRL +FBBFBFFLLR +BFFFBBFLRR +BBFBBFBRRR +BBFFBBBLRR +FBFBBFFRRR +BFFFBFFRLR +FFBBFBFLLR +FBFBFFBLRR +FBFFBFBLRL +FFBFBFBRLR +FBBFBBBRRL +FFBBFFFRLR +FFFBFBBRRR +FBBFBFFRLL +FFBFBFFRLL +FFBFBBBLRR +FFBBBFFLLR +BFBFFFFLRR +FFBBBFBLRL +BBFFFBBRRL +FFBFFBFRRL +FFBBBFBRLR +BFBFFBFLLL +BBFBBBFRLR +BFBFFBFRLR +FFBBBBBLRL +FFFBBFFLLL +BBFFBFFRRL +BFBBFBBLRL +BFFBFFFLRR +BBBFFFFLRL +BFBFFBBRLL +FBBBFFBLLL +FBBFFBBLLL +BBFFFFFLLR +FFBBFFBLRR +BFBBFBFLRR +BBFFFFFLRR +BFFBFBFLLR +FBFBBBBLLL +FBBBFFBRLR +FBBBFBBLLR +BFBFBBBLRL +BFFFBFBRLR +FBBFFBFRRR +BFFFBBFLLL +FFBFFFBRLR +FFBFFFBRRR +FFFBFFBRLR +BBFBFFFRLL +BFBFFBFRRL +BFBFBBFRRL +FBBBBBFLRR +BFFBBBBLRR +FFBFFBFLRL +BFBFBBFLRL +BFFFFFFLLR +FBFFBBBRRR +BFBFFBBRLR +FBBFBFFRLR +BFFBBBFLLR +BFBFFFBLLR +FFBFFFFRRL +FFFBBBBLRR +FFFBBFBLLL +BFFBFBBLLR +FBFFBFBLRR +FFFBBBBRLL +BBBFFFBRLR +BFBBFFFLLL +BFBBBFFLLR +BFBFBFFRRR +BFFFFBFLLR +FBBBBFBRLR +BFFBBBBRRL +FBFBFBFRLR +FFBFBBFRRL +BFFFBBFLLR +FFBBBFBLLL +FFBFBBFLRR +BFFFFBFLLL +FBBBBBFRLR +BBFBBBFLLL +FBFBBFBRRL +FFBBFBFRLL +BFBFFFFRRR +FBFFFFFRLR +FFBBFFBLRL +BBFBBBBLRL +FBBFFBFLRL +BFFFBFBLRR +FBFFFBBRRL +BBFBFFBRLR +FFBBFBBLRL +FBBBBFFLRL +BFFFFBBRLR +FBFFBBFLRR +FFBFBFFRRR +FFBBFBFLRR +BFFBFFFRRL +FBBFFBFRLR +FBBFBFBLLR +BFBFFBBRRL +FBFFFBFLRR +FBFBBFBLRL +BFFFFBFRLL +BFBFBBBRRR +FFFBFFFLLR +FBBBFFFLRR +FFBFBBFLRL +BFFFFBBLRL +BBFFBFFLRR +FBBFFFFRRR +FFFBFBBLRL +BFFFBFFLRR +BFBBFBFLRL +FBFFBFBRRL +BFBFFFFLRL +FBBFFFBRRR +FFBBFFBRLL +FFBFFBFRLL +BBFBFBBLLR +BFBFBFFLLR +BFFFBBBRRL +BBFBFFFLLR +FBFBFFFLRL +BFFBBFFRRR +BFFBFBBRLR +BBBFFBFLRL +BBFBFFBLRR +BBFBFFFLLL +FFBBBBFLLL +BFBBFBBRRR +BBFFFFBRRL +FFBFFBBRLL +FBBFFFBLRR +FFFFBBBLRL +FFBFBFFLRL +FBBBBFBRRR +BFFBBFBRRR +BFFFBBBLLR +BFFBFBFRLR +BFFBBBFRLL +FFFFBBBLRR +BFBFBBBRLR +BFBFBFFRLL +FFBBFFFRRL +FBBFFBFRRL +BBFFBBFRLL +FBBFFBBRLR +BFBBFFFRRR +BFBBFFBRRL +FBFFFBBRLL +FBBBBBBRRL +FBFFFFBRLR +BFBBFFBLLR +BBFBFFBRRL +BFFBBFFLLR +BFFFFBBRLL +BBFFBFBLLL +FBBFFFFRLR +FBBFFBFLRR +BFFBBFFRLL +BFBBFBBLLL +FBFBFBFLLR +BFFFBBBLRR +BFBFBFBLRL +BBBFFFFRRR +FFBFBFBRLL +FBFFBFFRRR +FFBFFFBRLL +FBBFBBFRRR +FFFBBBFRRR +FBFFBFFRRL +FFBBFFBRRL +FBBBFFFLLR +BBFBBFBRRL +BBFBFFFRRL +FFFBBBBLRL +FBBBFFFRRL +BFBBFFBLRL +FBFFFFFLRR +FBFFBBFLRL +BBFFBBBRRL +BBBFFBBLLL +FBFFBBBRLL +BBBFFFFRLL +FFBBBFFRLR +BBFFFFBRLL +FBFFFBBLLR +BFFBFBFRRR +FBFFBBBLLL +FBFBBBFRLL +BFFFFFBLRR +BFFBBFFLRL +FFBBFBBRRR +FBFFBFFLLR +BFFBBBBLLR +BFFFFFFRRR +BBFBBBFRRR +BBFFFFBLRR +BFFBBFBLLL +FFBBFFBLLL +BBBFFFFRRL +FBBFBBFLRR +FBBFFFBRLR +FBFBBFFLRL +FBFBFFFRLL +FBBFFBBLRL +BFFBBBBRRR +FFFFBBFLLR +BBFFBBBRLR +BFFFFFFRLL +FBBBBBBLLR +BBFFFBBLRR +BFFFFFBLLL +FBBBBFFLLR +BBFBFFFRRR +FBFBFFBLLL +FBFFFFBLLL +FFBFFBFRLR +BFBFFBBLLL +BFFBBFFLRR +FBBBBBFLLL +FFBBBFBLRR +BFFFFFBRLR +BBFBFBBRRL +BBFFFFBRRR +FFFBFBFLRL +FBFBBBBLRR +BFBFFBBRRR +FFBFFFFLLL +BFBFFBFLLR +FBBFBBBRLR +FFFBFFFRLL +FFFBFBFRLR +FFBBBFFLRL +BFFBBBBRLR +FBFFBBFLLL +FFFBBFFLRR +BBFBFBFLLR +FFBBFBFLRL +BBFFBBBLRL +BBFFFFBLLR +FFBFFFBLRR +BFBBFBFLLR +BFBBBBBLLL +BBFBBFBLRL +BBFBFFFRLR +BFFBFFFLLL +BBFBFFBRRR +FBFBBBFRRR +FBBBBFFRLL +BFFBBFBLRL +BBFBFFBLRL +BFBBFFBRRR +BBBFFFFLLL +BFBFFFFRRL +FBFFFFFRRR +BFFFFBBLLL +BFBBFFBRLL +FFBBBBBRLL +BFFBFBBRRR +BFBBFFFLLR +BFBBFBBLLR +FBBBBFBRRL +FBFBFBFLRL +BFBBBBFRLL +FFFBFFBLLL +BFFBFFFLLR +BFBBBFBRLL +FFFBBFBRRL +FFBFBFBRRR +FFFBFBBLLR +BFBBBFBRRR +FBBFBBFRLL +BFBBFBBRRL +BFBBBBFRLR +FFFBBBBLLL +BBFFFBBLLL +FFBBBBFLRL +BFBBBBBRLL +FBBFFBFRLL +FBFFFBBLRL +FBBFBFFRRR +FFFBFBFLLR +FFBBBFFRRL +FBBBFBBRLR +BBFBFFFLRR +FBFBBFFLLL +BBFFBFFRLR +BBFBFFFLRL +FBBBBFFRRR +FFBBBFBLLR +BBBFFFBRRL +FBFBFFFLLR +BBFBFFBLLL +FFFBBFBRLR +FBFFFBFLRL +BFFBFBBLLL +BBFBFBBRLL +FBFFBBFRRL +BFBFFFFRLL +BBBFFBBLRL +FFFBFFBLLR +BFFBFBBRLL +FFBFBFBLRR +BBFBFBFRRL +FBBBFBFRRL +FFFBBBBLLR +FBBBFBBRLL +BFBFBBFLRR +BFFFFFFLLL +FFFBFFFRLR +BFBBBFFRLR +BFFFFFBRLL +FBFFFFFLLR +FBBBFFBRLL +FBBFFBFLLR +BFFBFFBLRR +FBFBBBFLLL +FBFFFFFRRL +BBFFFFBLRL +BFBFFFFRLR +FBBFFFFRRL +BFFBBBBLLL +FFFFBBBRRR +FFBBFBBLRR +FBBFFBFLLL +BFFFFBBRRL +FFBBBBFRRL +BFFFFBFLRR +BFFFBBFRRL +BFBBBFFRRL +BFFFBFFRRR +FBFBBBBRRR +FBFFBFFLRL +FBBBBBFLLR +BFBFBBFLLR +BBBFFBFRRR +BFBBFFBLRR +FBBFBFFRRL +BBFBBFBLLL +BFBBFFBLLL +FFBBBFBRRL +BFBFBFBLLL +BFFBFBFRLL +BBFFBBBLLR +FFFBFBFLLL +FFBBBBFLLR +FFFBFBFRRL +BFBFFFBRRR +FFBFBBFRLL +FFFBBBFLLR +FBBFBFBLLL +BBFFFFFRRR +FFFBFFFRRR +BFFFBBBRRR +FFBFFFFLRL +FFFBFFBLRR +FFBBFBFRLR +FBBFBBBLRR +BFFBBFBRLL +BBFFFBBRRR +FFFFBBFRLR +FBBFBFBRRL +FBFBFFBLLR +FBFBFBBLLR +BFBFBBFRRR +BBFFBFBLLR +FFBBBFFLLL +BBFFBFBRLL +BFFFBBFLRL +BFBFBFFRLR +BFBFFFFLLL +FFBBBFFRRR +BBFBFFBLLR +BFBBBBFLRR +BFFBFBBLRL +FFBBFFFRLL +FFBFFFFLLR +BFBFFFBRRL +BFBFBFFLRL +BFFFFFFLRR +BBFBBFFLRL +FBFFFFBRLL +BBFFBFBRLR +FBBBFFFLLL +FFFBBBFLLL +BFFBFFFRRR +BBFBBBBLLL +BBFFFBFRLR +FBFBFFFRRR +FFFBBFFRLR +BFFBFFBLLR +BBFFBFBLRL +BFBFBFBLLR +FBFFFBFRLL +BBFBBBFRLL +BFBBBBBRLR +BFBFFFBRLR +FFFBBBFLRR +BFBFFBFLRL +BBFBBBBLRR +BFBFBBFRLL +FFFFBBBRLL +BFBBBBBLRR +FBFBBBBRLL +BFBBFBFRRL +BBFFFFBRLR +FBBBFBFRLR +BFBFFBFRRR +FBFBBBBLRL +BFBFBBBLLR +FFBFFFFLRR +FBFBBBFRRL +FBFBFBFRRR +BFFFFFFRLR +FBBBBFFRRL +BFFFFFBRRL +BBBFFFFRLR +FBBBFFBLRL +FBBBFFFLRL +FFFBFFBRLL +BFFFFFFRRL +BBBFFFBLLR diff --git a/d05/main.go b/d05/main.go new file mode 100644 index 0000000..bd55d19 --- /dev/null +++ b/d05/main.go @@ -0,0 +1,128 @@ +package main + +import ( + "bufio" + "fmt" + "log" + "os" + "sort" +) + +func proccessLines(path string, f func(string) (stop bool, err error)) error { + file, err := os.Open(path) + if err != nil { + return err + } + defer file.Close() + scanner := bufio.NewScanner(file) + for scanner.Scan() { + stop, err := f(scanner.Text()) + if stop || err != nil { + return err + } + } + if err := scanner.Err(); err != nil { + return err + } + return nil +} + +type seat struct { + row, column, id int +} + +func paritionSearch(partitions string, start, end float64, lower, upper string) (int, error) { + if start == end { + return int(start), nil + } + if partitions == "" { + return 0, fmt.Errorf("empty partitions are invalid") + } + if start > end { + return 0, fmt.Errorf("start cannot be greater than end") + } + if lower == "" || upper == "" { + return 0, fmt.Errorf("invalid upper and lower bounds") + } + + mid := (end - start) / 2.0 + direction := string(partitions[0]) + switch direction { + case lower: + return paritionSearch(partitions[1:], start, mid+start-.5, lower, upper) + case upper: + return paritionSearch(partitions[1:], mid+start+.5, end, lower, upper) + } + + return 0, fmt.Errorf("unknown direction %s", direction) +} + +func parseSeat(code string) (seat, error) { + totalRows, totalCols := 128, 8 + if len(code) != 10 { + return seat{}, fmt.Errorf("invalid code length %s", code) + } + row, err := paritionSearch(code[:7], 0.0, float64(totalRows-1), "F", "B") + if err != nil { + return seat{}, err + } + col, err := paritionSearch(code[7:], 0.0, float64(totalCols-1), "L", "R") + if err != nil { + return seat{}, err + } + + return seat{ + row: row, + column: col, + id: row*8 + col, + }, nil +} + +func part1() { + max := -1 + err := proccessLines("input.txt", func(line string) (stop bool, err error) { + s, err := parseSeat(line) + if err != nil { + return + } + if s.id > max { + max = s.id + } + return + }) + if err != nil { + log.Fatal(err) + } + + fmt.Printf("Max id is %d\n", max) +} + +func part2() { + seatIds := []int{} + err := proccessLines("input.txt", func(line string) (stop bool, err error) { + s, err := parseSeat(line) + if err != nil { + return + } + seatIds = append(seatIds, s.id) + return + }) + if err != nil { + log.Fatal(err) + } + + sort.Ints(seatIds) + lastID := -3 + for _, id := range seatIds { + if id == lastID+2 { + fmt.Printf("Found my seat! %d", lastID+1) + break + } + lastID = id + } +} + +func main() { + part1() + part2() +} diff --git a/d05/main.py b/d05/main.py new file mode 100755 index 0000000..03d7b52 --- /dev/null +++ b/d05/main.py @@ -0,0 +1,65 @@ +#! /usr/bin/env python3 +from collections import namedtuple + + +Seat = namedtuple("Seat", ["row", "column", "id"]) + + +def partition_search(partitions, start, end, lower, upper): + if start == end: + return start + assert partitions + assert start < end + assert all((lower, upper)) + # print(f"Searching: range {start}:{end} {partitions[0]}") + + mid = (end - start) / 2 + direction = partitions.pop(0) + if direction == lower: + return partition_search(partitions, start, start + mid - .5, lower, upper) + elif direction == upper: + return partition_search(partitions, start + mid + .5, end, lower, upper) + + raise ValueError(f"Unknown direction {direction}") + + +def parse_seat(code, total_rows=128, total_cols=8): + if len(code) != 10: + raise ValueError(f"Invalid code length: {code}") + row_partitions = list(code[:7]) + row = partition_search(row_partitions, 0, total_rows-1, "F", "B") + col_partitions = list(code[7:]) + col = partition_search(col_partitions, 0, total_cols-1, "L", "R") + return Seat(int(row), int(col), int(row*8+col)) + + +def part1(): + with open("input.txt") as f: + max_seat = max((parse_seat(line.strip()).id + for line in f)) + print(f"Max seat id: {max_seat}") + + +def part2(): + seats = [] + with open("input.txt") as f: + seats = list(sorted((parse_seat(line.strip()).id + for line in f))) + last_id = None + for id in seats: + # print("Seat:", id) + if last_id is None: + last_id = id + continue + if id == last_id + 2: + print(f"My seat: {last_id+1}") + return + last_id = id + else: + print("Didn't find seat") + + +if __name__ == "__main__": + # print(parse_seat("FBFBBFFRLR")) + part1() + part2() diff --git a/d06/input.txt b/d06/input.txt new file mode 100644 index 0000000..ae67ede --- /dev/null +++ b/d06/input.txt @@ -0,0 +1,2199 @@ +nvlyak +nyvha +yaen +qynia + +kend +endk + +atxcykpvmb +pcvmthyxbak +ayvpcbtkxm +cvpkyabtmx +typbmvckxa + +s +s +s +s + +on +aoqc +owq +coa + +pw +wpi +pwxlhqor +pw + +nx +xn + +dlevrzpucfmsq +pceimlrfsquvd +dpceruqsfmlv +hgxudfpqyvbcslrjname + +kczmswvorg +uryvlqaogmdixs +rmostvg +gsrmovb + +ref +fer + +vmwdhgnlfiyoepsujbk +epudykjwhignmfbovsl +fjvuimnwbkogsldhpey +ibmhuscpgeolfkynvdwj +psjgubfvlhaknodeiywm + +fmnpljusix +vqrefngyjdahclk +lfjons + +y +uiwl + +lsuqkmjinrzhgevfpwto +gkmodihnsjtful +ciguflhkojmtsn +thkjnoufsimgl +oskgmdfljntuhi + +gaktdwxhmqvfrpsuc +hmtwkgipdvaurxqf +akrmpxtughdqwfbv +gumqniswhrdkvftaxp +hagouqxpzrjlmedftywkv + +zkbyecw +kczeybw +wbeyakuzc + +iwdkjlarzfynvechgbxsq +jetfxrzdbcksnavilmwgyh +wvexlryjbizfgkhanqdcs + +vk +kv +kv +vk + +yrguw +rguyw +pwuryg +gnuwry + +dyhkusanvjwc +ukaywncj +uyqjknwac +aknyjcuw +jnukwaytxc + +toczmkldrevywiajgn +jyldmgewcvrozinkat +iynkmatdjerlogzwvc + +pthyrfjgqelxa +qfejxtrynlh +xwdfkuziyhejtqovrmlc + +osjrgc +vohfpa +goc +gjo + +j +jon +j +xdj + +bpqhmgwzakfrtjvuno +eafupgombqnwrkzth +frwqtdngpbhuaklzmo +wgtnuchpkqibfzmravso +mfbtvkghauzopnrwq + +xiocgdwpastbmyj +rdzgcbtfaomsy +dstgbcymozkqal + +xvc +cvx +xvc +xvc + +dhvtlqkeniymjzoa +eoazjnhvtkyqdlm +koltmeyqjhzdva +doumkhrlyzjqeagtcv + +mn +mfhw + +kx +x +jm + +x +xv + +tdhyubvwqfxejslpringc +xqhvtbfwrygsdapjiulnec +vnwbsurdiexghpjtlycqf + +pqtdgsmkolzryca +qjguxdratfeclpmoy + +twnviyzmlk +gknjmyqvziwl + +deoabzihqvycxn +iqcxadpehvry + +dbflcxvnapwgei +pchmodnafl +hadcflpn +dlcfanp + +tk +kt + +peuroxtzyg +iwdcnlqfskmbavjh + +mjfh +ynkbrsdpwoqtagci +lvx +ujxez +xl + +gyuszwb +sioduawzrglb +tsbumxwzg +zwgeuxbs + +tujvkwpy +tyvrpmjfk +vwpkuyjt + +wdkqailvjmfcshugy +qugwvlxdsikhfmyjac +dkiscawvyfqhmjlug + +noblsu +snloub +sulobn +lonubsm + +osecqjbfg +fljbmiose +ojesfbt + +zmctviabre +ajzmicetrvb +ctmivabzre +yrztbmieavc +mivcbtazer + +tyql +osmjgxzrcakn +iwftdbl + +nmqflphkvyjcatgbzd +jxzemtvdknwqr + +ilxrytkdpmsevfjchozqw +tpdrjxwihvlycozemsfkq +hitwfmzvjpylcodbqxsrke + +flhp +pflh + +ao +a +o +o +gljzn + +ajmkvwqu +ogvjzwta +whalvuj + +mhktpynfrjgblaqueox +anmjxplvibukhztqersy +tabljcpemkyrxhunwq + +lnkvfawqo +nofpsqwavylz +vofwalqen +hcnowiaqlfv + +dofxbaqrtnyvkpljmhsu +uklstfynmbxhapojqi +tufmnpaqyojsklxhb +oanlusqmxftkpjbhy + +tpjle +the +vtpez +ytern +ouecxwfkt + +jbna +xepqbmufn +ybjni + +jklhaxoqysbt +tzwpcf +tenfcvdmpzu + +kyqumgfrdiapzwojtvch +fvczqjrgadiwhnpluomk +dpwkmrjzauiqvfgcho +nkpwrmzidfahcvjuogq +azrkxioghpvcudmwqfj + +udjshwgpeaozimcl +fylwnoevcza +evlakborcfwz + +xhued +iubgewo + +lywovcemagd +ahveyomxsl +oqzyfljavbe + +pkyn +befycqpi +pysk +yp + +mgi +mgi +digm +gmi + +cgdqeoyfjranxuv +lwnkzeptsdqihvcujmg + +wzqrhgibdxuyl +ludbwqxgiyr +yruxibwdgql +bgtwqxruylid +buyrwlidgxq + +gqwvxspbl +xvbwpsgql +bspgxwvql +cwlxsvqgpb +sgpxqblwv + +camqk +onaslperix +jauw +yatm + +z +z +z +z +z + +fx +fxe + +goemcr +roegm +sgmxiero +ogmert +germo + +czgdxtiprhnwqeujkfl +dyhmkanzwbv + +n +e + +dkcjqbw +o +gp +h + +zbwcu +ubf +mveurnab + +tqwbxuc +qcwutxb +ucbxwqt +xqwutbc +xqtuwcba + +uwhqrt +wrtq +trwq +crtqw +wrtqc + +rqfntm +nrqm +rqmn + +limsht +alstikh +ilhst +uhitls +lsahti + +oaex +vsgyo +lziu + +cwqdlxbst +cdxtlwbsq + +hgqc +hgdq +qhg + +eh +he +eh + +zfutalwkxms +ukxltsfzmwa + +zpklocsqgwyhb +zobyqhlcksgpw +zhspqwovjylkgbc + +ymkudfqethwgji +emtuyfwghjdqki +zwyeumktfhjdirgq +wymqgifkudjteh + +edhqnrxtpz +tqdxznrhep +qzepndrthx +exzrhnqptds +zetyhrpdqunx + +vmleax +valxum +vpmlax +axlpvumz +clvamxbn + +ebt +xr +rl +u + +vzny +nz +nz + +ywebzj +ywefjzb +bxwnjcyzkep +zjeywfpb +yldrbhsizajewvu + +hfd +dmf +fadh +dvmf +fcousnld + +egar +hwnrgzcp +bgofedjr +jkruvsylg +rdvgue + +jsge +hesqg +esug + +xaoz +ocuqev +fwgrlp +otxv + +fzemjdhwb +xhdmjzbe + +ytsfpumedxqvzhl +fdteschymvxqlpz +phyrfwtqlaxgvznesd +hvlextsbqpzyfd +jydlhetzoqfpsvix + +jxkrobp +rsplxbgk +yxmbpkorhj + +injbuyktrcs +bcsriktuny +skyrhbtnucxe + +duck +cykuv +osfcurnlwax +uvmc + +vpt +tpv +pvt +vpt +vtp + +dacxvsi +icaxsd +xdihcneas + +nf +nkf +fn + +yrewaxckd +wtydesfcr +erdftwqyc + +hmfezapkqjyri +ekqajhyzfpmri +raikjeqmhfypz +qjmyrekfzphai +frtjeqkimhazpys + +ryxmsbqovuidphfwecajnz +hdjmiqbxnpvouyfcewsazr +vubyrcmqeswafxjzhinpdo +cbjmnaoqurlhsifvwzdexyp + +iu +ui +isutlr +iu +iu + +lftaziorb +rvamfeyjgqnx +frtak +aifr +aftzr + +us +schk + +bjafywgieth +tifbhyjgwade +imhwefbgatjy +wgtyifejbah + +a +yj +b +iab + +qkgazumerlhb +syritxopfvd + +gdiakrne +ygdpcwqfbmikzanver +dolarkigen +gtkanierdh + +axv +axdvl + +erpjfh +prgjfeh +hrejpf +pejfhr +ejrhfp + +zijsrtcqdxmy +mtxdfyji +timydgxj +jtmhvakxidyn +iyjmwdvxnt + +rh +har + +tdoyugpljirwenzx +nurlzgjtyopide +jnrlitgpzdoyue +zlptnudjryogie +pzgyeoliturnjd + +ivcyexsotkzqmr +sgfjhqnpy + +omw +joq +mop + +welbhpzftgjinqyk +gwpdjqacitshlbykfzmrx + +sygqwn +fwyqsdg +scgwqy + +gdjzwbhltxs +dlkojzbq +jfavyipcembun + +cydkuqlhan +uavstnychbqxk +azqntcuyhk + +k +bf +z +w + +gyh +e + +rhmpg +pmhgr +rpmhg + +pas +vhtsaqfgnu +kpjsa +sab +jcopska + +tsjabirpehudncx +custniapedhxrb +cepnuastxhdirb +shbpetcdaxuinr +dbtiepaucrshnx + +tuswfrqpgxk +kprjsdtqxunf +pxwfrtuqske +xwskmfprqut +pfrtxqskhu + +szirxjtu +zuxjtsi +jutsxiz +usjitxz +ijstxuz + +zqesxfbmrivokl +mevkzirbfol +fbkomeyvilrz + +rlwoeckxnh +xebkornwcl +xcoknwler +wnlkrcoex +kecronwxl + +fmdbraihnpxytkcgezu +kbeyxmadczhritnpuf +pnhfmubicxteadrzyk +updrybtmhzefcnxkia +kbezfjwmhytnixacudpr + +w +w +w +w + +fgwdoctvpzymhbrkjxn +yaqjctxvsrozmwk +xkwozitrvmeqjcyl +cwkazxtrmlijyov + +vnym +bvmy +yvm +byvm +vym + +mxjblongrfahycqvpu +ncywhdpxefajbrgloqu + +sgukdmfqvbwcei +zigahlxojdnpc + +fudobaklngyjqpstmiz +psflydzmbtkiqaojgnu +itgzqsfdyabnolpjkum +sitlkyuqnjodzmpbagf +ytdijopqublaksmngzf + +vhaobfn +ohbnfav +vahofbn +naovhfb + +tfhsqwcbrv +iqrbzspnwyhtfc + +pfbwotesuyhkvgx +vnrlcxayzdmih + +nbyhpfklvtqo +qbtjopfyk +qpoeybfkt + +uvmgzs +pvsmizrug +ghvmszu +mugszcv +kusmvzg + +mua +amu +uma +mua + +d +m + +s +s +yuk +s + +gtjqp +pfotsh +pshgbt +wpeztyr +bqjtplo + +zwbvestiaoljy +gmnzshupfqre + +anvsdkbltiugc +tqsdcanuibgvkl +stkrvabegidclxun +takcsgnuvmdibl +cvqsklngiubadt + +txvfnuwcljpqkeryoamigd +jgarvmodftpniekquxszcyhb + +htu +hegb +whf + +jn +nj +jn + +vcjlxekmqzoduphynw +hkyeojlvndumcwzx +ozhdnvjeckwlmuxy +ujxdyznvlcmokhew +vdywzekucjnhoxlm + +blxuhyvjrzow +uzlwokmsripy + +rum +mrl +rbwfmz +durmq + +obcpqvkitduelwf +ahcrwiltpuedfobxkv +cvijgzoukptwdfble +kpqjduetilovfcbw + +irfqsp +wifas + +xvgyrpq +yrpqvhgzx +fspxmrivkwgycnequ +axhyqrpvgz +xdygqvrpa + +xrlmcsibvea +bdcveasxzip +esvbclaxi +vaxsbcei +xaeibsvc + +songrtmwhpydqizlf +halvzroefxcsubt + +uqozritygam +kmtryqvz +qfmjstkyrz + +rqtepcofhuylnxaj +xoptqwruhijsmnzcylfe +hxqcpyfjntleuro +brjyuoetfxpndlvcqh + +prltixwohdmfjukgqzsv +orluxtzpvjafdqwkhsgbe + +iyhuarewvbfjmlz +vramijyfzhbew +zyehbmwvifjra +vjmweybazihrf + +duixtbqyhomsla +suinmaxtlqdoyhb +htiquxmaybosld + +pselyhov +zhwpovekt +snheopv +ivxophe +nhpoeuv + +amqcriebkojlwyuxnhfdptgzvs +uovdszkygbjhanefqxplimtwcr + +ozngukih +nvksbd + +grkotivmcxnyubwleqspjzhfad +ekmqxnfabwiduopjsgclzvyhtr + +jzv +wzxfivmjb +zjvp +zjv +jzvs + +js +evqis +qxs +swyct +s + +n +n +zn + +udjtxws +usdwixj + +lf +l + +cdsaxzlv +jcsxlnydtrzvk +lvdqamzsxhc +udlxwczvgs + +gutwbrhjxyeam +jrleawgbsnxthimyu +rbjexdythumwag +hrwjmoexytqaubg +uwymabxrhjqgdect + +vipjrlbsmcogxznty +vetpngyzsbmoxcrijl +hoxvbsnjlfygmrczpti +pmlgzyasvxticjbrknod + +xzakbvtehnlciswmyufjdrgo +kocmslwbgvuxijernzydfhat +vcdxgkslnzoarmjwutyiefbh +tzhugvbcnokyxsfliwardmej + +up +u +pu +fu + +cbzjelmqivw +ickezvjlqm + +srwnt +nwrtj +rswnt + +hfjxoskd +dlpzeyjai + +mt +tm +mt +mt +tm + +rpxenfzmhwdvacbygiujkqot +lhbvkwmpfyazrtojcquxind +qtcjdairznhuwxmpsvyfkob + +apvk +qvapk + +ujscpqtgbyezdfhnwoil +bftognyujilpwhsqzdce +zbhslwipdjeqntcfouyg +tyuqdlfepgzshcoiwnbj +dzqxjblenucpwshtoiyfg + +cdxtsaunbwkezlrp +vbdpsuktlxczerwan +pnxudwaclrtebksz + +tq +t +zt +t +jtqg + +fvmhiloanbgjzptryucdkxw +jzhwtkbdpoxfacirngluyvm +pwnybcjmgxurfzivoklhdta +brtavopdklnhxwgzmifyjcu +ncifvypdtgwxbzakhjrmulo + +kwhiguft +uxyo +ux + +ruyoe +ezqhbi +clndewsfta +e +qrke + +doa +doa +doa + +xt +tx +xt +xt +xt + +roxwktbmgiyc +qtbejyxzlpcaighfod +oscgtuyiwvrbkxn + +agcdevxkmbnzqjl +jrdzmnclbgkvexqwa + +pqjtyenfmxdaorw +qayjpxmfdterwon +frdtlawxmjnoeqpy + +aze +zea +veaz +yzxdequoa + +eq +uetqs + +jsmezrk +zskmer +zmkers +krezsm + +mfzqsukgcw +cmskguzfqw +gksucwfmqz +uwqsgfzmck +wfzucmgsqk + +wftx +fwtd +twf + +bizwg +gzwosd +afzqrwun +cjpzwb + +qjntchmdbgpe +nqtephjgmdbc +qjeltdcphgbmn +nqtbcjhepmdg + +g +g +gr +g +g + +yulnpwc +uplcwn +nplemufywc +calkisogupw + +sigh +igsh +ghski + +naqpd +xydrsjwlibzm +qdevh +cd + +mraejinsdp +mierdjansp +qpsmrianjde +npirjedams +ridpaejmns + +o +o +o +o + +lhfqsxm +xlmsqfh +slfqmxh + +jhivsoabqlfpeuw +fvxrelbhuncowqjtsz + +yajhetclfk +jnqbylmpwgxcf +azchyrsivjeltdf + +n +n +n +n +n + +hkuaq +hkqua +uakqh +khqtalu +ahxkuqy + +tguprf +pfu +ufp +uofp + +lnmtjo +njolmt + +qymzdw +vjckmtl +oipreghfausnxb + +niswjectqkldzyg +wunjdetklisczyqg +gldcysiqznjtekw +iqwdczjsytkleng +lgyiezdncjqktws + +dntm +atm +tma +tm +txm + +ntpcwask +skcna +nksac + +prai +pria +arpi +irpa + +mzldgbrtovj +tbjgldozmvr +ogzvdlrjtbm + +ft +fq + +jgstdlzarcemiopynukfw +ywlhakgzeoxdnjmsirc +moicgebadzlwkysrnxj + +jpeiqxbz +xipjebzt + +rnpf +fqhu +agprm +wedyzci +bxur + +aynswjoklfeqzcitxudbrvh +ihrbxwvdqsyoejpnfkzc + +hrqliwxtfbk +qiwfrxbtkhl +kihqxrftlwb +wrhlxbtqkif +tfbqriwlkhx + +bwdhnqk +wbhkqtd +qwbkhdx + +fpcboialrdgqkejntyzm +lmieayocqpkznbrtdfgj +mbtdrpozfljkeyangiqc +pmdjlerfkybgnaoqzitc +pganmcfbtedkrzloyqij + +zfrvn +zfnr +znrf + +nuq +ltiuacgjs +aug + +xj +lyzixn +eaxwuf + +aeywqjkl +eanklwju +kjelzaw +ealjwtk +azklwej + +ncqxulrmfvedao +eodqxlvmrncu +elrmnuqpcdoxv +qloxudmvnecahr +lcdxqwmurvznjeo + +aijnhvxemsqztfk +xnvkehsiqmzft +tehvxnfskiwqzm +epsmzhixqvtnkfr +htkinzvqefxmrs + +wgfzomlbhujxs +ezvrxmkycafwob + +lhyrq +ylfherq +hlreyq +wqlyerh +hgsqlyru + +acnkurdevm +duernacvm +nteaducorvs + +hxvqtsjzgn +iakeoyr + +id +i +di +hkxi + +fqunm +funxikw +xfiuknz + +wvgpqlzxnui +livzmwyqgpnu + +eanbkcjlxpsm +ofmdwrqe + +w +ws +wr +w +w + +aylsbi +lyaiqsgb +vyeblmasuhi +yblsia +ylbsiaq + +fpbhozqdljytwcnxsvr +zarwdgqhtvyxcnpbsofji +dbzhsfwrvqnyjxtpoc +qwxpbnycrfjsozvhtd +tsoypwnmzfjhbvdxcqr + +bezfskqut +egbpkdflqtmouzs +kxzenfustqb +tsebufkzq + +hoekryzuqt +oreuqhyktz +teorhukzqy +kyqehortuz + +d +uqwgitdaj +dz +vod +fvd + +smjqnlt +jsqmlnt +ntsqlmj +jqntslm + +saxdlkjwvyctqenrio +wqnvsoyaextcilkrjd +krdqwevyliojxcntas +ywlnkcafdoirsvjxetq + +ryae +yaq +ya +ya +ya + +epvy +nvyqu +vnxy +oyvh + +kschegfmla +lgfmscaehk +gshfalcemk +lcgemshkfa +mkgaselhctf + +bfxqtegnoismrk +mnuivtxasgbjqyfkp +mkxgrnltfiqbhsw + +s +s +s + +zoe +eoz +oze +eoz + +q +kuprd +gvmbn +vctx +oi + +nbrjveycdlw +jyhfcwnglerv + +vkoxqwfhubrcsnme +bqkexhovswmntfrc + +aidoznexygkjlqs +neysaiudmoqklgxzc + +ypsn +eyp +yp +iyp + +gol +olg + +rypjohwvxkisnldatuzfb +btpxvolknwdhuryiafjsz +vkahgbsitwdoyjplfruznx + +mipqtk +nikqpvu + +kztifpne +yzit +rigtz +zait + +jxgvt +gfjoky +kvygh +dmwgqsrcp +ounalgyze + +nypvuiseqtjwxchlbfogdamzr +apqnbzhwmjldotfsvexruicyg +bpyjzomwahcrgsutlefxkqdivn + +qumcbsvlpthfwyda +hagwiucnvfdypqlzs + +tog +otg +gfto +gto + +ctp +uda + +vlbi +swmiujf + +xbi +upsdbi +bizr + +ltw +we +wzavnymh +iw +wfe + +caqjdphelmtvyfbxo +acxmtljedhoqbsfyp + +fyqthpe +bmrceljqy +eyqt + +frjdhuyqsgon +krouhsfgydnj + +ltopekjnacgbms +elngjotmpsca +splcgnatmoej +egjctspmlaon +jtealcmpongs + +fvsmiotkb +fbnupmcsxd +fmkvjysb +qbksmywrtf + +mklqnp +mqnlk +mwqnlke + +jykqrlaocvunfpix +rcymsnwuafdtvgbqoieh + +c +c +ct +c + +mlv +lyfpq +vsli +vrdwl + +srtaq +nuptlr + +hcfjdaqwo +qmoefalzdh + +zxyksijbeahgvc +xgvjhsczeyikba +yxickjesbhgavz +sjvgibeczxhkay +hvgizjmaxsybcke + +wjmypxi +jipmx +pjmix +bjivamxp + +dytnalmqkbpruef +qplfuynbdaertm +rbnetqdupamlwyf + +e +e +m +p +e + +b +eb +b +b +b + +yieovwqukxcnbfjpdg +qjvunkgywpfoidbxec +jupowqfbiknvdgeycx +dqeicgjfpxonbukwvy +gociquxvjbfdwnpkye + +lwrch +huosc + +somiywgdbf +fbmvdwgzsy +ufrltkydsnwm + +epvfduyh +vfpeyuhd +epdchvyuf +udeohyvpf +evhpyufd + +b +b + +szfgmlxwd +eapoqydvi + +puedtjkqbwfznhvycxrolamsgi +cvqeyszrwdfnkutjihxmlapbgo +nfdpoukvizgctxwmeaqjrhlbys + +nuf +je +uieq +ctodh +sbx + +psrwqlgd +lrwdqgpzs + +qheijmngzsrdawbvucolxpy +vhqnlcouibjdarzxpmeygs +edlixjhrquamovnpbsgycz + +jkphyr +urycxn + +snbcyoe +nuewpy + +gbnsoirkwyhp +iogsqbkymwp +fzbwkeyutdxp + +w +w +w + +jsbp +bjsp +jspb + +jfbdpv +pfjvb + +wfhvsjloznb +gmupxcnrakelfsvzqd + +dbsuoriacgnwxtzveyhqfkmp +adwcifzvsgnkphyburtexomq +wzbkmsdpfrhiaqxyecuonvgt +athzyrgbwckvomqudsnexfip +vidbhyqesancrzugkxfopwmt + +nl +ln +nl +osnl + +iewcxgqtf +gtwmfieqc +icfvqwyhadgkn +qcgwerfli + +wyj +jy +atycnje +qyjg +yzjsg + +ivjwfeuz +jvcw +mbhvwj +rswvhjd + +zmjlpeia +eimrlpzaj +jmealyqpi + +zgkf +gkz + +zuosdlvkxm +tlxskcvpumo +kuyomrxlvs +uvosxmldyk + +yuilcqhgmazts +swhvdcigltmakzuy +stojxiflyghnazcpum +gkhqtyciuwszmal + +nzhlyu +hngc +ngcah +anch +nvkhj + +xhfvwbkn +nahwxfo +fhgnwx +dmfuxnht + +vbhpedluncftoxys +cydfsolpejhbntux + +vkilx +pvxskd + +hvwuecgs +guvwcsh +sgrwculmvhb +wcpznuqsvghi +vhwcsulg + +ndfapjlztc +npoacfjtld + +jzd +xaulvyksp +zeh + +ck +ck +ck +kc + +kiroh +rh + +euxdrkvtfbqon +ytfvurxwheokqn + +sirznatbxkghm +skaiqzrmhnx +ztgmhrsikanx +hksxmairnez +ywdiracnfsuzhjxmpk + +bacgwvmxrdfne +pdcofwbza +cfqdwuptzabo + +dqmp +dqpm +qvmpd + +kczxnlerm +vqrzjmf + +qmuorwspx +dywcxarilegkh + +gqzph +qhapozk +zhqp + +fastkjnl +jsnafkt +jfnacskt + +fxgpiadjrvhs +smfwbejadh +hjmfyaods +fzdqsjham +hlcbyfjkaunsdt + +dqlevpahscoyi +iypldavhsqoce +clhvyaisoepdq +eayqiosdlpvch +epodliqvhcsay + +nhxbmlqv +qylkhmnxvbj +xbnlvqmh +vxmbhqln +lbvhxsqmn + +exrtdq +tderq +djretq + +lwqj +jmwlr +zbswtx + +pxi +ipx +ixp +xip + +vgfscwrqzdojxhe +xfvqhzsjecgownd +qdopyzjwegfsxchv +gosqeckhvzdjfxw +gszxpfveocjhqmdw + +gvlyuiscaewfpx +gfwjtapuoynvqzi + +ycsdnbzjoki +wfpvogmqhautlx + +tbjliqdfzgny +zjwilpghqdyekc + +yftcnao +ncfytaio +conyfta + +yslactbwhjfvnomiue +mbyiavojlwtunces +eontumvircsalbjwy +jguvcxylitsbmwenazo +bayolijwqcevpmsktdun + +ynmki +ykinm +inymk +iykmn +yimnk + +vzjnpybg +vjqfyno +rnvity + +ilxkjhcfpdmeb +hwdjleirc +aiulechdj +dljiwehc + +rptom +ife +nuli +yized + +loe +eg + +fprtvcgkwnasljebhm +nvbltrckumfhpgjew +grpuefzknmblovjw +bjwgykpinqlemrd +mrlegnjwbkp + +xtquyrjnszl +ysrqzj +zsqyjpr + +ft +fjt +ft +tf + +ejli +l +l +rl + +lwgrihbdvno +ydbrvhgolniw +rivdongwhlb +ndhbrgwilov +dwvrnlhbgio + +fc +fc +cqfo +fc +fc + +nhaoi +nioha +osijah + +hgrec +gchre +cehrg + +higmvfbtjre +ikhxjbrefvq +brjiefhvl +ivfeqblhrj +hrkifjvbe + +vsgqmibordtznkl +dehupjlcxtsrnfawy + +t +crfi + +nrai +hjcmpzla +dveria + +krp +achvofx +kbp + +vfdzhuskanm +lhucb +uh + +qu +uqj +quh +qu + +tokmzyuxjsbvic +zegday + +wqfxlhyapcdtv +vctalwmjdpqyfh + +nqge +vneiqt +hqvfenwj +nksqcrlmde +vqgbone + +f +w +w +f +oq + +qziwcdjyepvhn +wvypijednqzc + +uwjflbhoq +dwxublig + +c +lc +ec +c +txcjrkd + +cglvpyadf +rqfvgaplc +kgpatsxuelvh +oapgvliwc + +ln +st +bs + +sfra +dskrnf +mzhjrfpx + +phu +uph +uph +hpu +phu + +pcxhvbf +hxbtyk + +jdzsaiwbphmftqxrlngcyoe +mqbrsplojgyheznxcdtfwia +pitajxzhsonwygrfblecmqd +nyliauzgfbcprewhdtjmsxoq +taxnylhvgjqewcksfpmzdbior + +h +c +om + +ruplsfnhyjqigwkzexbtoc +newjivhyckdagob +ywocjmnkbghie + +jdrtpbvohaxy +dnjxyrfsv + +lq +nsulxvmhj +l +lk + +fdsxhvqaiblt +fihykrdlsoaqx +laqgpznecjiuxfsdhmw + +capkzueqjmdv +ckdvymqazu +fklcmdbuxqarzv +zkcsvmqhiadgeu +jotqkuzndvciwam + +lzqbrgkp +grvpntoz +ozwvpg +suefagcp +pkjygd + +zbangyoqjlkdevrxti +gzniebarjloykqtdxv + +xviqehycstgjladuoznfwp +odwplyiqnxghutezcvsj +ersxgqtcjouvdiznlyhwp +cpshuoijtxvelqynwmdgz + +tnzkdmgqci +mqkzgydtijn +mtikzqdng + +d +ad +d + +k +iof + +otkvualrqdsixf +nkhwid +dbkiwpj +ikd +ekziydgm + +wjvgqsxinfburh +wxgqsurjvflnhbi + +hebmgftkpcq +owektbpfhqcmg +egtfbpckhmdq +qmcetgpfkhb + +exukswmlgznjoqhvabid +dkgmeoahtxpzflnwru + +lf +fl +lf +fle + +zblhfjqpr +rzp +uprzo + +wmktipjq +twmikp +jmtwikyp +azcempwtkiv +itkmpw + +qwodjmelanykpxuh +weqnajoxmupklyihd +pjodermlyuknwxhqa +mqbaoxylgdshtnjpwuvkfe +lnaxijmwqhukodpye + +azxw +xazw +zwax +wafqztx +zaxw + +ydzmvpskfjiqneluabgtrw +vyfdpqrkbistwlaxzjum +ukortizjvdwhlpafycmqsb + +cno +y +no +y +bqe + +zlcotxyhfeij +xtlvhifkszoj + +kczqegopj +qupzjod + +hpclqaktjmbnyxw +iqphxcamk + +rebc +qcbra +brc +crb + +flkoiavp +aduhjeqtyrmzkn +cslwgfaokp + +qmnzcjb +bmeqzjsc +jxochgfbmwzvq +zqcbmja + +deyifvsxw +evdyw +edbhzyuqv + +xmhknbcwdaztvl +mruslxozyangpj +xgszalnm +aoqmleunizxs + +eh +he +eh +nxeh +eh + +cjbx +jxsub + +yusezdlpgxtm +dyrkmstuegpx +pdxmyeutvkjsrhgaw + +ruz +rzu +zur +zru + +wgbdctzlsmh +peglstyhcd +adtqlhcgvs +tylndgrcujhsbx +odltpshecg + +ylntchparijwfo +wtrjpiaohylcf +wlfyvrehcutapgko + +tkbpfhjzravmquxewgl +goxphazbfvrqkijlwtm +mkrbzqphvawtyjfxilg +plhcnwgqmrxfvdzabjkt + +pfhtlqawckegij +wjpaksdctfghlo + +jqctpgrvu +qkvgjuprtc +vutcqpgrj +gpruvjtcq +gvqprujct + +dkevisf +kfei +mlukicwfje + +nsoyjcwzife +spnocteji + +cfuzsbtvdkq +rcasmqzkpdxuo +drxzwqckus +zqsrndeukxic + +vkgpbz +zkpvg +zkvpg + +eqhpyasvnumzgclitofjw +ofsgpaijzqmtvcuwhlbe +ujiewctamfxqdghslpvzo +qivnwtlfcmpgaeouhjzs + +lfahbowz +ryxcwtvs +mytucdivw + +lqetdskgyznojharxvufpwimbc +kpcoqugdvxibftjmywzslnreh +mxjgcinhobeldrwfukyvptqsz + +jxhc +fjsqglzwhu +mhcj +hecj + +ihdsbckn + +siponk +sikonp +psinkfo + +qbvdrutoan +qbcftunvoi +qvkoxzbtushny +qtwojubnv + +eu +u +xtujdms +ehu + +jkqdoner +eyxnkuaoqfg +kqenxmyo + +wk +wk +ykw +kw +kw + +gvrebwq +erkflnbjhagv +givrybues +itpvegsrbz + +hlykfbqnexots +tqhgfonkzeyxsbl +qkcybxtsnloefh +fxalqkntsuobyech +hvyjefkbitrqoplwxns + +paxu +parnkxu +pxua +xupa +uxpa + +ytzjokcqlmviha +sykbmizchvq +aocvizymhkq +ivhkcqlzym +iayelkzqmtchv + +aekxzstuc +czetkxsau +zqpakexsuct +zuxtacske +kuszetcax + +czlkiprvydnmsoxqwajgb +byszdijkplawcvnm +ikmwandcjzlvybsp +nbvwlikjscdmpzay + +fpuxqtigly +hpuqkfxigyt +tifpygqkux +uygqftwpxi + +gvdwnrefpj +nwgapvedr +egdvwnrp +xshwezgipdvr + +joefgnu +tknuhvfy + +rjo +rpjyos +rjo +roj +jro + +zxvatmfbujgryinokwehsc +xjzdusehibgtvncmkflyao + +fpnkyo +nopfky +kpnyof +ponkfy +tnpfoyk + +mevhflgowbkqdjutrzys +qrgmkeohvstnbwfdjluy + +pejhrgwtmcny +hjangqtbprsmwe +umiegvdprwtznhj +nhgptresjwlm + +ohgmls +othljm +jmhtlso +mhxlcnp + +dtufxjrbq +rdfjxtqbu +qjtdufbrx + +iexvaok +kexu +xkje +xkfe + +dpursykgo +ugkrsqpody +sokpgyrdnu +kwsuoyrpdg +sovjiydkagmuptbrhcf + +mwxcqs +mcwxqs +mwxqsc +tcswmxq + +cqatfowbvmirly +woibncaylqgvsf + +bico +izdt +tiz + +af +fkq +f +fyb +f + +wxftpjclsrhm +sdzuvanek + +jr +rjp +rj + +zhpknlosiadcfbjweuqvy +ulbkhapqzisefdyonjc + +oivjy +djvwbofy +kvlqyxrj +bsivdyjf + +kifcamqwgy +amfkgicyq +miygkcafq + +egslifrtvcnhk +vymgiprjzcxasbqn + +gji +g +oar +jgk + +gxtkohsqcvmrjzie +jfghvuxokznqwsdmarcl + +xvlnpjdar +vldnopxaj +dtnpsayjvlc +dgjvalnmp +mfnvjdpal + +mnaxd +xmda +kdaxm + +szpeac +ezpsac +aesxpcz + +vgpldyruqmfbsehzkxjwa +wrxmvtqgyjsdazlkbofeuhc +ablmzyevqgswfnxkdrphuj + +aoedxnzjqsbyihtpkcfuwl +dsbeyathwxjupozlqncikf + +mwzkrnhp +okqj + +s +s + +erjyvcwhuitdaogsnfb +dculesyjotbwhavfirn +swfbohtjdciaurenyv +ubsvfamrjoynwchitdke + +yb +yb +by + +pbrhzvjcsgeylfxt +sjcyezvxfgbhtplr + +rphvaxw +zhjapvrxw +xahvwspr +lpdqrvwahmx + +rpmild +vlrpswnb +ylrezfpi +pbraslm +utxgqhpjkorl + +pizbmcxreftywhdq +pqyezcxtidgmhfrw +ixrctphwqydzfme +fxdhpyctwrinmazqe +pctzyrhdiqwmxef + +wasjdyzgfu +zfdyujgwsa +wbyzjgadufs +afzswydguj + +zqanmksjruhx +qljaunzmkrshx +jrxqsmzknhua +rjazknumxqhs +kuzqxhjmasrn + +virdpbztchkgo +hdiopebvzaw + +ziwscmotk +jwmas + +h +h +h +h +h + +qhywbkuvnst +zmynwxvufqarkbeht + +onfvrqxa +xrvqnofa +fiuarnvoxq +qvzafonrx +fqvxebnaolr + +kmfulryg +bkswufgylmr +myulgjrfk +gouyxrlkmf + +skerjmgbvtcphdzafniyxo +ljybizemsvhokxrdcagptnf + +oyt +hytx +mdtyjrslkczu +bvyto + +mpwv +acvbp + +m +ftz + +kvtmidlngo +edznioyvkx +kofvirdn diff --git a/d06/main.go b/d06/main.go new file mode 100644 index 0000000..9da3fb4 --- /dev/null +++ b/d06/main.go @@ -0,0 +1,141 @@ +package main + +import ( + "bufio" + "fmt" + "log" + "os" +) + +func processLines(path string, f func(string) (stop bool, err error)) error { + file, err := os.Open(path) + if err != nil { + return err + } + defer file.Close() + scanner := bufio.NewScanner(file) + for scanner.Scan() { + stop, err := f(scanner.Text()) + if stop || err != nil { + return err + } + } + if err := scanner.Err(); err != nil { + return err + } + return nil +} + +func processGroups(path string, f func([]string) (stop bool, err error)) error { + group := []string{} + if err := processLines(path, func(line string) (stop bool, err error) { + if strings.HasPrefix(line, "mask") { + stop, err = f(group) + if stop || err != nil { + return + } + group = []string{} + } else { + group = append(group, line) + } + + return + }); err != nil { + return err + } + + _, err := f(group) + + return err +} + +// StringSet is a set of strings +type StringSet struct { + d map[string]bool +} + +// Add an item to a StringSet +func (s *StringSet) Add(v string) { + s.d[v] = true +} + +// Len gives the length of a StringSet +func (s StringSet) Len() int { + return len(s.d) +} + +// NewStringSet creates an empty string set +func NewStringSet() StringSet { + return StringSet{map[string]bool{}} +} + +// Union returns the union of two SringSets +func Union(s1, s2 StringSet) StringSet { + union := NewStringSet() + for v := range s1.d { + union.Add(v) + } + for v := range s2.d { + union.Add(v) + } + return union +} + +// Intersection returns the union of two SringSets +func Intersection(s1, s2 StringSet) StringSet { + intersect := NewStringSet() + for v := range s1.d { + if _, ok := s2.d[v]; ok { + intersect.Add(v) + } + } + return intersect +} + +func part1() { + total := 0 + err := processGroups("input.txt", func(group []string) (stop bool, err error) { + questions := NewStringSet() + for _, person := range group { + for _, q := range person { + questions.Add(string(q)) + } + } + total += questions.Len() + return + }) + if err != nil { + log.Fatal(err) + } + + fmt.Printf("Part 1 answer %d\n", total) +} + +func part2() { + total := 0 + err := processGroups("input.txt", func(group []string) (stop bool, err error) { + result := NewStringSet() + for _, q := range group[0] { + result.Add(string(q)) + } + for _, person := range group[1:] { + questions := NewStringSet() + for _, q := range person { + questions.Add(string(q)) + } + result = Intersection(result, questions) + } + total += result.Len() + return + }) + if err != nil { + log.Fatal(err) + } + + fmt.Printf("Part 2 answer %d\n", total) +} + +func main() { + part1() + part2() +} diff --git a/d06/main.py b/d06/main.py new file mode 100755 index 0000000..a1cec72 --- /dev/null +++ b/d06/main.py @@ -0,0 +1,43 @@ +#! /usr/bin/env python3 + + +def iter_groups(): + group_responses = [] + with open("input.txt") as f: + for line in f: + line = line.strip() + if line == "": + # Group divider + yield group_responses + group_responses = [] + else: + group_responses.append(line) + else: + if group_responses: + yield group_responses + + +def part1(): + total = 0 + for group in iter_groups(): + questions = set() + for person in group: + for question in person: + questions.add(question) + total += len(questions) + print("Total", total) + + +def part2(): + total = 0 + for group in iter_groups(): + result = set(group[0]) + for person in group[1:]: + result = result & set(person) + total += len(result) + print("Total", total) + + +if __name__ == "__main__": + part1() + part2() diff --git a/d07/input.txt b/d07/input.txt new file mode 100644 index 0000000..e92708e --- /dev/null +++ b/d07/input.txt @@ -0,0 +1,594 @@ +striped green bags contain 5 posh indigo bags. +light yellow bags contain 3 wavy turquoise bags. +bright lime bags contain 2 striped crimson bags, 3 dull red bags. +dull blue bags contain 4 posh coral bags, 3 mirrored coral bags, 2 striped fuchsia bags. +vibrant coral bags contain 2 shiny blue bags, 2 muted gray bags. +mirrored gold bags contain 2 dotted maroon bags. +drab lavender bags contain 4 pale turquoise bags, 5 faded lime bags, 2 bright aqua bags. +mirrored red bags contain 4 shiny tan bags, 4 muted aqua bags, 4 pale salmon bags, 5 bright violet bags. +clear gray bags contain 4 bright lavender bags, 2 dotted plum bags, 1 drab coral bag, 3 faded aqua bags. +dull aqua bags contain 2 wavy coral bags. +muted yellow bags contain 3 drab olive bags, 4 pale lime bags, 2 striped crimson bags, 3 wavy blue bags. +shiny chartreuse bags contain 5 bright yellow bags. +posh turquoise bags contain 3 dotted blue bags, 4 pale lime bags, 1 mirrored fuchsia bag. +faded maroon bags contain 5 striped indigo bags, 2 light aqua bags, 3 dim chartreuse bags, 4 vibrant tomato bags. +dotted lavender bags contain 3 pale crimson bags, 3 wavy gray bags, 2 plaid plum bags, 5 mirrored bronze bags. +striped olive bags contain 5 dull lime bags. +vibrant aqua bags contain 3 drab tan bags, 5 bright coral bags, 3 pale brown bags. +wavy aqua bags contain 4 dim lime bags, 4 dotted bronze bags, 1 bright gray bag. +pale green bags contain 1 shiny purple bag, 4 dim plum bags. +vibrant purple bags contain 2 pale gray bags, 2 dull crimson bags. +faded green bags contain 4 dotted plum bags, 1 light white bag. +posh orange bags contain 4 light blue bags. +drab tomato bags contain 1 dull salmon bag, 3 plaid orange bags, 3 posh gray bags. +vibrant beige bags contain 2 dull fuchsia bags. +wavy orange bags contain 2 bright tan bags, 5 light beige bags, 2 vibrant turquoise bags. +light salmon bags contain 1 dark blue bag, 2 bright orange bags. +light blue bags contain 3 clear chartreuse bags, 5 dull olive bags. +dull crimson bags contain 4 dim gold bags, 5 dark tan bags, 5 dark lavender bags. +dim teal bags contain 3 striped gray bags, 4 shiny fuchsia bags, 2 vibrant chartreuse bags, 2 drab plum bags. +striped crimson bags contain no other bags. +dark brown bags contain 1 dim plum bag. +dotted tan bags contain 1 striped fuchsia bag. +bright turquoise bags contain 3 light orange bags, 2 wavy bronze bags, 2 light beige bags. +drab salmon bags contain 4 wavy silver bags. +light brown bags contain 1 clear gold bag. +plaid aqua bags contain 4 shiny maroon bags, 2 mirrored gray bags. +posh chartreuse bags contain 3 clear maroon bags, 4 wavy black bags, 3 vibrant white bags. +wavy gray bags contain 3 shiny violet bags, 2 striped silver bags, 5 pale lime bags. +dim crimson bags contain 1 wavy blue bag, 1 dull red bag, 1 dotted plum bag. +wavy black bags contain 5 dim crimson bags, 5 dotted chartreuse bags. +faded gray bags contain 4 plaid white bags, 2 mirrored yellow bags. +muted violet bags contain 5 vibrant blue bags, 5 shiny beige bags. +dull white bags contain 1 dull olive bag, 5 clear chartreuse bags, 1 dull red bag, 1 wavy red bag. +light bronze bags contain 4 bright gray bags, 3 light tomato bags, 2 shiny white bags, 2 clear silver bags. +plaid violet bags contain 2 vibrant indigo bags, 2 dim turquoise bags. +posh purple bags contain 5 wavy purple bags. +bright olive bags contain 4 muted bronze bags, 4 mirrored green bags, 2 dim plum bags, 5 bright silver bags. +vibrant olive bags contain 1 vibrant beige bag, 4 striped gold bags, 4 shiny beige bags, 1 faded blue bag. +muted fuchsia bags contain 3 vibrant red bags. +plaid indigo bags contain 4 dull lime bags, 3 faded violet bags. +wavy chartreuse bags contain 3 dotted yellow bags. +posh magenta bags contain 4 bright gray bags, 4 dotted turquoise bags. +drab teal bags contain 5 dotted plum bags, 2 light white bags, 2 dark plum bags, 4 dim crimson bags. +dark coral bags contain 3 wavy chartreuse bags, 3 plaid bronze bags, 1 muted magenta bag. +posh white bags contain 4 dotted turquoise bags, 1 mirrored lime bag. +mirrored brown bags contain 2 shiny chartreuse bags, 1 light bronze bag, 4 bright bronze bags, 5 dotted crimson bags. +faded cyan bags contain 2 dull crimson bags, 4 light chartreuse bags, 4 light salmon bags. +bright maroon bags contain 3 dotted yellow bags, 1 bright gray bag, 2 dim yellow bags, 5 light fuchsia bags. +clear silver bags contain 4 faded green bags, 4 posh white bags, 4 dark plum bags. +shiny crimson bags contain 4 dark lavender bags, 3 dotted gold bags, 3 dark tan bags. +wavy olive bags contain 4 dotted cyan bags. +wavy coral bags contain 3 dim gold bags, 4 dim silver bags, 4 faded green bags, 2 muted purple bags. +striped chartreuse bags contain 4 mirrored plum bags, 4 dull tan bags, 5 muted gold bags. +bright blue bags contain 5 mirrored beige bags, 4 muted bronze bags, 1 dark tan bag, 5 dark cyan bags. +vibrant red bags contain 3 light chartreuse bags, 2 faded indigo bags, 3 drab teal bags, 1 striped indigo bag. +dim cyan bags contain 5 faded silver bags, 3 wavy coral bags. +muted gold bags contain 4 pale coral bags. +wavy violet bags contain 2 dotted gray bags, 1 clear tan bag, 5 plaid brown bags. +light maroon bags contain 5 faded silver bags. +light cyan bags contain 5 pale brown bags, 3 pale black bags, 3 light tomato bags, 2 faded violet bags. +pale turquoise bags contain 1 dull white bag, 1 muted tomato bag, 2 clear gold bags. +clear plum bags contain 2 dotted orange bags, 1 bright olive bag, 3 striped violet bags. +plaid silver bags contain 5 muted olive bags, 1 vibrant bronze bag, 5 dull lavender bags, 3 dark purple bags. +clear gold bags contain 1 dotted turquoise bag, 3 dark indigo bags. +muted indigo bags contain 1 mirrored orange bag, 3 dull beige bags. +light plum bags contain 3 drab brown bags, 4 wavy cyan bags, 3 vibrant lavender bags. +dim maroon bags contain 4 dull tan bags. +pale lime bags contain 4 dotted maroon bags, 2 faded silver bags, 5 shiny tomato bags. +shiny black bags contain 2 dull crimson bags. +wavy indigo bags contain 1 light fuchsia bag. +dull lime bags contain no other bags. +shiny fuchsia bags contain 2 drab fuchsia bags, 1 shiny cyan bag, 1 muted black bag, 2 dull aqua bags. +muted lavender bags contain 4 dull fuchsia bags, 1 dim chartreuse bag, 1 vibrant gold bag, 2 shiny beige bags. +bright cyan bags contain 5 dark gold bags, 2 vibrant cyan bags, 1 pale coral bag. +posh black bags contain 3 dull violet bags, 5 drab coral bags. +posh olive bags contain 3 muted magenta bags, 3 dark plum bags, 1 shiny violet bag. +dull coral bags contain 1 dark gold bag, 2 striped silver bags, 5 vibrant lavender bags, 2 light red bags. +clear bronze bags contain 4 striped cyan bags, 4 dotted chartreuse bags, 4 shiny maroon bags. +bright red bags contain 2 dark violet bags, 4 pale brown bags. +muted silver bags contain 3 bright blue bags, 1 shiny blue bag, 5 muted bronze bags, 1 bright tan bag. +dotted maroon bags contain 5 muted white bags, 4 dull lime bags, 2 dim gold bags, 2 faded fuchsia bags. +clear lime bags contain 4 striped gold bags, 2 vibrant purple bags, 5 dotted green bags, 2 light tomato bags. +shiny tan bags contain 5 dark lavender bags, 1 dull red bag, 4 vibrant turquoise bags, 5 faded fuchsia bags. +dark teal bags contain 2 dotted brown bags, 5 clear salmon bags, 5 wavy coral bags, 3 light fuchsia bags. +shiny cyan bags contain 1 mirrored gold bag, 1 mirrored aqua bag, 1 posh magenta bag. +pale red bags contain 1 vibrant turquoise bag. +drab coral bags contain 2 faded tomato bags, 3 plaid aqua bags. +clear white bags contain 1 dull white bag, 5 shiny tan bags, 1 mirrored yellow bag, 1 wavy chartreuse bag. +clear crimson bags contain 5 muted white bags, 1 vibrant yellow bag. +posh lavender bags contain 2 mirrored aqua bags, 4 faded aqua bags, 2 light red bags. +dim violet bags contain 4 dull orange bags, 5 dull turquoise bags, 5 dark purple bags. +pale beige bags contain 3 wavy indigo bags, 5 dark plum bags, 2 dark purple bags, 2 dim turquoise bags. +striped brown bags contain 4 bright lime bags, 5 wavy coral bags. +shiny blue bags contain 2 wavy coral bags, 2 dotted plum bags. +pale black bags contain 5 clear maroon bags, 4 striped crimson bags, 4 dark gold bags. +drab plum bags contain 3 clear gold bags. +posh beige bags contain 3 faded silver bags, 3 dim gold bags, 5 shiny gold bags. +clear lavender bags contain 1 clear white bag. +light lavender bags contain 4 dotted violet bags, 3 dull violet bags, 4 dark maroon bags, 2 striped violet bags. +plaid brown bags contain 4 dotted yellow bags. +dotted green bags contain 3 dull red bags, 2 faded green bags, 3 muted white bags, 1 dim turquoise bag. +muted olive bags contain 4 vibrant tan bags, 3 dotted black bags. +light turquoise bags contain 3 wavy blue bags, 4 dim plum bags, 4 dim chartreuse bags. +dim salmon bags contain 2 mirrored yellow bags. +shiny white bags contain 1 mirrored violet bag. +drab olive bags contain 3 striped crimson bags, 3 dotted maroon bags. +drab silver bags contain 5 shiny cyan bags, 1 dull teal bag, 4 dark lime bags. +vibrant turquoise bags contain 4 striped crimson bags, 5 dark plum bags, 3 dark lavender bags, 5 dark purple bags. +shiny purple bags contain 1 posh beige bag, 1 dark indigo bag, 4 plaid fuchsia bags, 5 dotted green bags. +bright brown bags contain 1 striped lavender bag, 5 light gold bags, 1 dim maroon bag. +dotted violet bags contain 3 striped blue bags. +bright crimson bags contain 2 muted gold bags, 3 vibrant turquoise bags, 3 wavy green bags, 5 dull white bags. +striped tan bags contain 2 wavy gray bags, 4 bright gray bags, 1 plaid cyan bag, 1 vibrant magenta bag. +dull green bags contain 1 bright brown bag, 5 posh beige bags, 5 mirrored crimson bags, 1 dark silver bag. +mirrored lime bags contain 4 muted tomato bags, 5 wavy chartreuse bags, 5 dotted plum bags. +striped beige bags contain 2 striped bronze bags, 2 shiny yellow bags, 4 pale gray bags, 2 vibrant tomato bags. +vibrant lime bags contain 4 striped crimson bags, 2 pale silver bags, 4 clear purple bags. +pale blue bags contain 1 bright cyan bag, 1 shiny fuchsia bag, 5 wavy turquoise bags, 5 dotted silver bags. +striped maroon bags contain 1 muted lime bag. +faded chartreuse bags contain 2 mirrored white bags. +mirrored crimson bags contain 2 dotted gold bags, 5 shiny red bags, 5 wavy red bags. +dull beige bags contain 2 posh red bags, 1 vibrant turquoise bag, 5 dark plum bags, 5 clear aqua bags. +wavy green bags contain 3 shiny crimson bags. +striped salmon bags contain 2 dim plum bags, 2 mirrored indigo bags. +faded coral bags contain 3 muted tomato bags, 1 light chartreuse bag. +dark blue bags contain 2 shiny violet bags. +shiny gold bags contain 1 dull lime bag, 2 pale coral bags, 1 wavy silver bag, 5 muted black bags. +clear turquoise bags contain 1 posh magenta bag. +dotted salmon bags contain 2 mirrored lime bags, 1 mirrored salmon bag. +pale gray bags contain 3 bright blue bags, 5 muted tan bags. +shiny teal bags contain 5 pale indigo bags. +drab beige bags contain 5 faded indigo bags, 5 vibrant bronze bags, 4 pale lime bags, 3 dark black bags. +vibrant white bags contain 5 striped violet bags, 3 bright blue bags, 2 dim gold bags. +posh aqua bags contain 5 plaid violet bags, 3 drab chartreuse bags. +plaid gray bags contain 5 dotted cyan bags, 2 mirrored silver bags. +clear indigo bags contain 1 bright tan bag, 2 dull yellow bags, 5 mirrored lavender bags, 2 mirrored fuchsia bags. +mirrored turquoise bags contain 3 faded chartreuse bags, 2 drab turquoise bags. +dark chartreuse bags contain 2 mirrored silver bags, 3 vibrant crimson bags, 4 shiny green bags, 1 pale brown bag. +pale tomato bags contain 2 light gold bags. +mirrored purple bags contain 1 light magenta bag, 3 shiny yellow bags, 4 striped lavender bags. +mirrored blue bags contain 3 posh magenta bags, 4 dark lavender bags, 5 striped crimson bags. +dull purple bags contain 4 mirrored indigo bags, 2 wavy bronze bags, 4 muted white bags, 4 shiny crimson bags. +mirrored teal bags contain 5 dim teal bags, 4 dark lime bags, 4 mirrored yellow bags, 3 mirrored turquoise bags. +drab gold bags contain 3 dark maroon bags, 2 plaid beige bags. +dotted gold bags contain 2 striped crimson bags, 3 clear red bags. +posh fuchsia bags contain 4 dim cyan bags, 4 vibrant turquoise bags, 4 dotted plum bags. +dim lime bags contain 4 posh indigo bags. +dim tan bags contain 3 pale indigo bags, 1 striped turquoise bag, 4 plaid coral bags. +plaid red bags contain 5 wavy gold bags, 1 muted plum bag, 2 vibrant plum bags, 1 dim brown bag. +light orange bags contain 4 dotted teal bags, 4 dotted yellow bags. +dark green bags contain 1 dull cyan bag. +posh coral bags contain 3 shiny green bags, 3 dotted red bags, 1 drab silver bag. +striped orange bags contain 3 plaid plum bags. +pale purple bags contain 1 vibrant coral bag, 2 shiny olive bags, 1 clear orange bag. +bright fuchsia bags contain 3 bright yellow bags. +striped red bags contain 2 bright orange bags, 3 mirrored yellow bags, 1 dotted coral bag, 3 clear aqua bags. +faded plum bags contain 2 shiny tan bags, 4 dull tan bags. +striped gold bags contain 1 shiny crimson bag. +faded olive bags contain 2 shiny lavender bags, 5 posh fuchsia bags, 3 pale gray bags. +pale aqua bags contain 3 posh beige bags. +dotted plum bags contain 4 clear red bags. +dotted chartreuse bags contain 1 light white bag, 5 drab turquoise bags. +striped tomato bags contain 4 dim plum bags, 1 striped black bag, 4 drab black bags. +shiny lime bags contain 3 drab coral bags, 1 drab green bag, 4 muted salmon bags. +dim orange bags contain 2 striped chartreuse bags. +plaid tan bags contain 5 light chartreuse bags, 1 dotted maroon bag, 2 clear silver bags. +dull olive bags contain 3 muted gold bags, 5 dotted gold bags, 4 muted white bags, 1 shiny violet bag. +dotted beige bags contain 1 clear tan bag. +dotted silver bags contain 2 faded crimson bags. +muted black bags contain 3 clear red bags, 3 dotted maroon bags. +clear purple bags contain 5 dotted plum bags. +striped indigo bags contain 5 mirrored blue bags, 2 striped violet bags, 3 striped yellow bags. +faded teal bags contain 2 light black bags, 1 vibrant maroon bag. +drab red bags contain 3 dark tan bags, 4 pale red bags, 5 faded salmon bags, 3 dotted tomato bags. +muted aqua bags contain 2 striped purple bags, 3 vibrant orange bags, 3 bright cyan bags. +mirrored black bags contain 4 muted yellow bags, 5 light fuchsia bags. +dark gold bags contain 2 dark indigo bags, 3 muted magenta bags, 3 dull white bags. +dotted lime bags contain 4 shiny blue bags, 3 striped fuchsia bags. +posh brown bags contain 2 muted beige bags. +muted green bags contain 5 bright white bags, 5 dim gold bags. +vibrant salmon bags contain 1 pale green bag, 5 light maroon bags, 4 striped violet bags. +drab white bags contain 2 drab fuchsia bags, 4 dull beige bags, 2 pale coral bags, 1 shiny tan bag. +light lime bags contain 4 dotted salmon bags, 5 dark fuchsia bags, 2 vibrant indigo bags. +shiny tomato bags contain 5 wavy green bags, 2 striped blue bags, 3 faded green bags, 3 muted tomato bags. +mirrored aqua bags contain 2 dark gold bags, 2 shiny green bags. +plaid cyan bags contain 5 shiny brown bags, 2 pale aqua bags, 3 striped turquoise bags, 5 plaid yellow bags. +light crimson bags contain 3 bright silver bags, 2 dark lime bags. +dull cyan bags contain 3 pale gray bags, 5 light beige bags, 3 striped blue bags. +muted plum bags contain 2 muted turquoise bags, 5 wavy lavender bags, 3 striped blue bags, 3 striped gray bags. +posh tan bags contain 4 dark brown bags, 1 drab crimson bag. +clear yellow bags contain 3 striped purple bags, 4 faded blue bags. +wavy fuchsia bags contain 2 light beige bags, 3 faded fuchsia bags. +pale gold bags contain 4 faded green bags, 5 clear bronze bags, 5 vibrant aqua bags, 3 muted cyan bags. +shiny gray bags contain 3 plaid chartreuse bags. +bright indigo bags contain 3 drab fuchsia bags. +drab black bags contain 3 shiny brown bags, 3 posh blue bags. +dark crimson bags contain 5 faded olive bags, 1 mirrored green bag. +vibrant silver bags contain 1 dark black bag, 2 drab tan bags. +shiny green bags contain 4 dark plum bags, 4 drab fuchsia bags, 3 dim plum bags, 3 mirrored gold bags. +plaid crimson bags contain 1 dim olive bag, 5 bright brown bags, 5 dull lavender bags. +dark salmon bags contain 2 light gold bags, 4 shiny blue bags. +faded blue bags contain 4 striped crimson bags, 1 muted tomato bag. +wavy magenta bags contain 5 wavy purple bags, 3 bright yellow bags, 3 shiny maroon bags, 1 wavy orange bag. +striped cyan bags contain 1 dotted plum bag, 1 bright coral bag. +faded crimson bags contain 5 pale aqua bags, 3 light blue bags. +muted gray bags contain 3 shiny tomato bags. +striped aqua bags contain 3 dim crimson bags. +wavy salmon bags contain 5 drab bronze bags, 4 light maroon bags. +drab fuchsia bags contain 3 faded black bags, 4 shiny crimson bags, 5 shiny tan bags. +clear black bags contain 4 dark crimson bags, 5 pale lavender bags. +dotted orange bags contain 1 dotted coral bag, 1 shiny gold bag, 3 wavy coral bags. +plaid tomato bags contain 4 wavy orange bags. +dark white bags contain 3 posh cyan bags. +wavy lime bags contain 4 faded silver bags, 3 vibrant gold bags, 3 vibrant coral bags. +faded tomato bags contain 1 striped bronze bag, 4 dotted green bags. +mirrored salmon bags contain 1 faded crimson bag, 3 muted gold bags, 4 clear aqua bags. +drab maroon bags contain 5 clear silver bags, 4 vibrant cyan bags, 5 faded gold bags. +dull violet bags contain 4 shiny tomato bags. +bright orange bags contain 4 bright tan bags. +plaid magenta bags contain 3 light fuchsia bags. +shiny turquoise bags contain 5 muted bronze bags, 4 bright lavender bags, 4 dark tan bags. +pale fuchsia bags contain 4 dull crimson bags, 3 wavy red bags, 5 dark gold bags. +plaid fuchsia bags contain 2 dim cyan bags, 5 bright coral bags. +dark indigo bags contain 3 dotted teal bags, 3 striped blue bags. +vibrant bronze bags contain 4 mirrored plum bags, 5 faded silver bags. +light tomato bags contain 3 posh fuchsia bags, 4 mirrored magenta bags, 1 muted gold bag, 3 dim green bags. +shiny silver bags contain 2 dim yellow bags, 1 wavy coral bag. +bright bronze bags contain 3 plaid coral bags, 2 wavy coral bags, 2 bright gray bags. +plaid turquoise bags contain 3 dim lime bags. +plaid teal bags contain 1 vibrant teal bag, 3 dark indigo bags, 4 plaid fuchsia bags. +striped purple bags contain 2 striped chartreuse bags, 2 clear chartreuse bags, 4 dark cyan bags, 5 striped salmon bags. +pale orange bags contain 5 muted green bags. +light green bags contain 2 plaid plum bags. +plaid purple bags contain 4 muted lime bags. +dark cyan bags contain no other bags. +wavy teal bags contain 5 dull black bags, 3 striped teal bags, 4 dotted cyan bags, 5 vibrant olive bags. +shiny indigo bags contain 3 dull lavender bags. +bright beige bags contain 1 bright bronze bag. +light white bags contain no other bags. +muted red bags contain 3 light tan bags, 4 clear cyan bags. +light coral bags contain 2 dull aqua bags, 1 bright beige bag, 4 wavy maroon bags, 3 posh tan bags. +bright violet bags contain 2 drab beige bags, 3 shiny fuchsia bags, 2 shiny cyan bags, 5 light gray bags. +striped fuchsia bags contain 1 striped black bag, 4 shiny white bags, 3 dim plum bags. +vibrant teal bags contain 1 faded tomato bag, 3 dim gray bags. +striped turquoise bags contain 3 wavy silver bags, 3 bright orange bags, 5 plaid coral bags, 1 clear red bag. +mirrored fuchsia bags contain 1 dotted green bag, 1 plaid cyan bag. +dim green bags contain 1 posh olive bag, 1 dim silver bag. +faded orange bags contain 4 drab beige bags, 1 vibrant salmon bag, 2 plaid orange bags. +bright tomato bags contain 4 dim aqua bags, 2 posh beige bags, 4 striped purple bags. +faded lime bags contain 1 bright tan bag. +mirrored indigo bags contain 4 shiny tan bags, 3 faded blue bags. +vibrant orange bags contain 3 vibrant olive bags, 2 bright olive bags, 3 wavy violet bags. +plaid beige bags contain 2 shiny violet bags, 3 faded violet bags. +muted purple bags contain 3 light beige bags, 3 bright tan bags. +mirrored orange bags contain 5 plaid lime bags, 4 dotted olive bags. +wavy purple bags contain 3 dim chartreuse bags. +wavy blue bags contain 5 striped blue bags, 5 posh olive bags. +dull black bags contain 3 dotted plum bags. +drab bronze bags contain 5 dim olive bags, 3 vibrant gray bags, 3 pale green bags, 1 dull cyan bag. +pale coral bags contain 5 dim gold bags, 1 vibrant bronze bag. +dull orange bags contain 1 shiny turquoise bag. +mirrored gray bags contain 1 mirrored plum bag, 5 dim silver bags. +drab cyan bags contain 1 dark fuchsia bag, 1 striped salmon bag, 4 plaid beige bags, 5 dim olive bags. +dark bronze bags contain 2 pale salmon bags, 5 dull magenta bags, 5 clear indigo bags, 3 wavy plum bags. +dim tomato bags contain 5 striped lavender bags. +faded white bags contain 3 striped lime bags, 4 dotted orange bags. +dull teal bags contain 4 vibrant yellow bags. +clear teal bags contain 4 wavy gold bags. +muted tan bags contain 3 faded green bags. +dim gold bags contain no other bags. +dim turquoise bags contain 3 mirrored plum bags, 3 bright orange bags, 1 muted tan bag. +striped silver bags contain 4 dull lime bags, 5 striped blue bags. +striped yellow bags contain 2 vibrant crimson bags. +striped violet bags contain 1 clear beige bag, 2 dim indigo bags, 3 muted lime bags. +posh cyan bags contain 4 faded blue bags, 2 vibrant magenta bags, 3 dull lime bags, 3 shiny blue bags. +vibrant brown bags contain 5 shiny violet bags. +pale chartreuse bags contain 1 wavy teal bag, 1 muted maroon bag, 5 clear turquoise bags. +vibrant indigo bags contain 5 drab teal bags, 1 bright aqua bag. +bright green bags contain 4 drab silver bags, 5 shiny gold bags. +dim black bags contain 1 faded violet bag. +muted orange bags contain 3 dull yellow bags, 1 vibrant blue bag, 3 plaid tan bags, 2 dotted teal bags. +muted crimson bags contain 4 muted silver bags, 5 shiny lavender bags, 3 posh beige bags, 2 shiny purple bags. +clear tomato bags contain 4 dotted teal bags, 2 vibrant olive bags, 5 plaid magenta bags, 4 bright chartreuse bags. +vibrant fuchsia bags contain 5 dim cyan bags, 4 light white bags, 1 dull orange bag, 5 dark gold bags. +muted magenta bags contain no other bags. +dim brown bags contain 1 striped red bag, 4 posh fuchsia bags, 3 mirrored gold bags. +dim plum bags contain 1 vibrant turquoise bag, 1 clear chartreuse bag, 3 faded brown bags. +plaid gold bags contain 5 drab tomato bags. +wavy tomato bags contain 3 dark gold bags, 1 light orange bag, 4 muted salmon bags, 2 muted olive bags. +pale olive bags contain 2 plaid cyan bags. +wavy plum bags contain 4 faded aqua bags, 5 dull olive bags, 3 bright lavender bags, 2 drab chartreuse bags. +posh tomato bags contain 5 drab blue bags. +dull gray bags contain 5 dull olive bags, 3 mirrored coral bags, 4 striped lavender bags. +posh plum bags contain 5 dull cyan bags, 2 dotted orange bags, 3 plaid indigo bags, 5 light beige bags. +striped plum bags contain 2 drab white bags, 2 mirrored yellow bags, 3 dim crimson bags, 2 pale salmon bags. +light beige bags contain 3 dark cyan bags, 3 striped crimson bags. +dark maroon bags contain 5 light tan bags, 5 faded green bags, 3 striped gold bags, 4 bright aqua bags. +faded brown bags contain 5 dotted gold bags, 3 striped turquoise bags, 4 bright tan bags, 3 clear chartreuse bags. +striped lime bags contain 4 dim gold bags, 5 pale coral bags, 4 mirrored plum bags. +light olive bags contain 1 shiny white bag, 3 dotted plum bags, 3 clear orange bags, 3 posh turquoise bags. +light magenta bags contain 2 shiny turquoise bags. +dotted turquoise bags contain 5 posh olive bags. +dark violet bags contain 1 faded blue bag, 1 shiny green bag. +shiny plum bags contain 2 dotted blue bags, 1 clear gold bag. +striped bronze bags contain 5 dim chartreuse bags, 1 shiny violet bag. +vibrant lavender bags contain 1 faded fuchsia bag, 2 shiny blue bags, 2 dotted plum bags. +dotted crimson bags contain 2 dark cyan bags, 1 dim chartreuse bag, 4 light red bags. +posh blue bags contain 2 bright silver bags, 4 drab beige bags, 2 dim salmon bags. +plaid orange bags contain 3 dark lime bags. +wavy gold bags contain 1 drab olive bag, 1 shiny cyan bag, 3 drab brown bags. +muted lime bags contain 2 dull teal bags. +vibrant magenta bags contain 3 muted gray bags. +posh silver bags contain 4 bright lavender bags, 5 light gold bags, 2 posh beige bags, 2 dull crimson bags. +shiny bronze bags contain 5 pale lavender bags, 3 plaid bronze bags, 3 mirrored blue bags, 4 bright olive bags. +dotted tomato bags contain 2 drab yellow bags. +posh violet bags contain 4 muted fuchsia bags, 1 dark blue bag, 1 shiny indigo bag. +wavy turquoise bags contain 5 shiny yellow bags. +plaid lavender bags contain 3 dim lavender bags, 3 dotted salmon bags. +striped teal bags contain 5 mirrored crimson bags, 1 mirrored violet bag, 1 dark violet bag, 5 dotted yellow bags. +faded black bags contain 5 posh red bags. +faded tan bags contain 1 mirrored violet bag, 4 dark lime bags, 4 dim green bags, 4 muted green bags. +clear brown bags contain 3 pale coral bags, 1 plaid coral bag, 4 pale gray bags. +light violet bags contain 5 dim plum bags, 4 muted violet bags, 3 drab teal bags. +dotted gray bags contain 4 mirrored white bags, 3 vibrant lavender bags, 4 dark lime bags, 5 vibrant coral bags. +faded yellow bags contain 2 plaid bronze bags, 1 dark purple bag, 5 shiny crimson bags, 3 shiny tan bags. +shiny violet bags contain 4 dull lime bags, 4 muted white bags, 2 dark cyan bags. +faded gold bags contain 5 plaid aqua bags. +bright salmon bags contain 2 shiny lavender bags, 5 plaid red bags. +clear violet bags contain 4 posh turquoise bags. +light silver bags contain 1 light salmon bag, 2 clear aqua bags, 4 mirrored plum bags, 2 striped silver bags. +pale cyan bags contain 4 vibrant orange bags, 3 light salmon bags, 4 striped cyan bags, 4 wavy gray bags. +wavy cyan bags contain 3 light orange bags, 1 bright yellow bag, 2 pale fuchsia bags. +clear maroon bags contain 1 dotted coral bag, 4 plaid yellow bags. +striped blue bags contain 5 light white bags, 2 dull lime bags, 1 shiny maroon bag. +clear red bags contain no other bags. +pale tan bags contain 5 light gold bags, 5 dark brown bags, 1 wavy black bag, 5 drab blue bags. +mirrored magenta bags contain 4 dotted plum bags, 3 posh beige bags. +dull maroon bags contain 1 mirrored fuchsia bag. +dim silver bags contain 5 striped crimson bags, 1 light beige bag. +plaid olive bags contain 3 shiny white bags, 2 bright lavender bags. +shiny magenta bags contain 3 dotted gray bags, 1 shiny blue bag, 3 faded silver bags, 2 dark tomato bags. +mirrored green bags contain 4 dim cyan bags, 2 bright tan bags. +faded silver bags contain 1 dark plum bag, 5 dotted plum bags, 1 dark cyan bag, 5 dull red bags. +vibrant cyan bags contain 5 vibrant lavender bags. +shiny brown bags contain 4 striped blue bags, 1 light beige bag, 1 muted tan bag, 5 bright orange bags. +wavy maroon bags contain 3 vibrant white bags, 1 pale red bag, 5 striped yellow bags, 4 plaid bronze bags. +shiny aqua bags contain 5 dotted salmon bags, 5 bright maroon bags, 1 wavy red bag. +clear cyan bags contain 2 striped red bags, 5 plaid coral bags, 2 dark fuchsia bags. +dotted red bags contain 5 dim orange bags, 4 striped tan bags. +vibrant green bags contain 1 dark plum bag. +striped black bags contain 5 dull white bags. +dotted indigo bags contain 2 vibrant orange bags, 5 vibrant lavender bags, 4 shiny bronze bags. +dark tan bags contain 1 muted tan bag. +dotted yellow bags contain 3 dark cyan bags, 2 shiny maroon bags. +dull chartreuse bags contain 4 vibrant red bags, 4 dim salmon bags, 5 drab salmon bags. +shiny beige bags contain 3 dotted yellow bags, 2 muted tomato bags, 4 wavy red bags. +faded indigo bags contain 4 faded green bags. +light chartreuse bags contain 1 mirrored violet bag, 5 striped lavender bags. +dark red bags contain 5 dark green bags, 3 clear beige bags, 5 wavy tan bags, 4 striped cyan bags. +muted blue bags contain 3 dark beige bags, 2 bright lavender bags, 5 dull teal bags. +mirrored olive bags contain 5 dark lavender bags, 1 clear blue bag. +pale yellow bags contain 2 dark chartreuse bags, 4 posh silver bags, 2 dim crimson bags, 3 wavy gold bags. +dull brown bags contain 1 light aqua bag, 2 pale aqua bags, 1 faded red bag, 1 wavy white bag. +clear chartreuse bags contain 2 wavy coral bags. +bright white bags contain 4 light fuchsia bags, 5 drab turquoise bags, 5 striped lime bags. +light gray bags contain 4 mirrored violet bags, 5 dotted maroon bags, 3 pale lime bags. +mirrored cyan bags contain 4 mirrored salmon bags, 2 drab olive bags. +dark orange bags contain 3 vibrant lavender bags. +drab chartreuse bags contain 2 wavy orange bags. +muted white bags contain no other bags. +dull red bags contain 1 faded fuchsia bag, 2 dark purple bags, 4 clear red bags. +shiny red bags contain 2 bright gray bags, 4 drab blue bags, 2 bright aqua bags. +vibrant gold bags contain 3 shiny tan bags, 5 mirrored gold bags. +wavy red bags contain 1 dark plum bag, 3 striped blue bags, 4 light white bags, 1 wavy silver bag. +mirrored coral bags contain 4 dark indigo bags. +mirrored beige bags contain 1 muted white bag. +faded bronze bags contain 5 bright aqua bags, 2 dotted chartreuse bags, 2 faded tomato bags. +bright plum bags contain 3 drab chartreuse bags. +shiny coral bags contain 2 dark yellow bags, 5 dark blue bags, 4 dotted green bags. +mirrored yellow bags contain 1 dotted plum bag. +faded fuchsia bags contain no other bags. +bright magenta bags contain 4 muted orange bags, 3 striped red bags, 5 light bronze bags. +drab aqua bags contain 5 dotted indigo bags, 3 dim gray bags. +faded violet bags contain 2 shiny gold bags. +dull lavender bags contain 1 drab chartreuse bag, 2 shiny plum bags, 4 vibrant tan bags, 5 dark tomato bags. +shiny lavender bags contain 2 light fuchsia bags. +dotted brown bags contain 5 shiny brown bags, 4 light fuchsia bags, 3 plaid cyan bags. +dark olive bags contain 2 wavy red bags, 5 striped lavender bags, 4 vibrant lavender bags, 2 shiny gold bags. +dotted black bags contain 1 dark lime bag. +faded aqua bags contain 2 dim turquoise bags, 3 muted green bags, 5 clear aqua bags. +plaid yellow bags contain 1 striped turquoise bag, 4 striped lime bags. +pale bronze bags contain 4 muted tan bags, 5 dotted fuchsia bags. +muted coral bags contain 2 striped bronze bags, 1 dark violet bag. +dim indigo bags contain 1 shiny red bag. +drab gray bags contain 3 posh white bags, 2 plaid indigo bags. +pale silver bags contain 1 faded coral bag, 5 shiny lavender bags, 5 wavy lime bags. +wavy silver bags contain 1 vibrant bronze bag. +wavy crimson bags contain 1 mirrored orange bag. +dotted aqua bags contain 4 drab plum bags, 5 faded indigo bags, 3 dark violet bags, 3 pale gray bags. +mirrored violet bags contain 5 mirrored white bags. +dotted white bags contain 3 muted plum bags, 3 bright bronze bags, 2 dark salmon bags. +bright coral bags contain 5 mirrored gray bags. +dim aqua bags contain 3 mirrored plum bags, 3 plaid olive bags, 1 light gold bag. +drab crimson bags contain 5 faded purple bags. +pale crimson bags contain 4 dotted orange bags, 2 faded silver bags. +mirrored tan bags contain 3 posh gray bags, 2 dark silver bags, 3 dim tan bags. +clear olive bags contain 1 dim yellow bag, 1 bright blue bag, 3 bright tomato bags. +dim blue bags contain 3 drab black bags, 1 light blue bag, 5 light orange bags, 5 bright white bags. +mirrored chartreuse bags contain 4 drab beige bags, 1 pale indigo bag. +dark turquoise bags contain 1 vibrant black bag, 1 light turquoise bag, 5 pale aqua bags. +posh yellow bags contain 4 dim teal bags, 2 dark black bags. +clear aqua bags contain 2 drab teal bags, 5 light gold bags, 4 dim crimson bags. +dotted purple bags contain 4 striped salmon bags. +light indigo bags contain 3 faded red bags, 2 shiny crimson bags, 3 wavy green bags, 2 striped coral bags. +vibrant yellow bags contain 1 dotted cyan bag, 3 posh silver bags. +faded lavender bags contain 5 dull cyan bags. +dull magenta bags contain 2 dotted green bags. +posh indigo bags contain 1 dull lime bag, 4 striped lavender bags, 1 faded silver bag. +light aqua bags contain 3 posh maroon bags, 3 dotted black bags, 4 muted tomato bags, 4 mirrored magenta bags. +mirrored maroon bags contain 3 light aqua bags. +dim red bags contain 2 muted green bags, 1 vibrant tan bag. +wavy yellow bags contain 3 dotted cyan bags. +bright aqua bags contain 1 dotted maroon bag, 1 muted white bag, 3 striped turquoise bags. +clear fuchsia bags contain 2 mirrored fuchsia bags, 4 bright white bags, 3 mirrored white bags, 1 bright coral bag. +dotted olive bags contain 3 pale aqua bags, 4 light gold bags, 5 dim yellow bags. +light black bags contain 4 clear tan bags, 5 wavy lime bags, 3 dim fuchsia bags, 3 pale indigo bags. +dark purple bags contain 5 dark cyan bags. +dim purple bags contain 2 wavy crimson bags, 2 dim chartreuse bags, 3 shiny yellow bags, 1 light black bag. +plaid salmon bags contain 1 faded lime bag. +dotted cyan bags contain 2 shiny tomato bags, 1 mirrored plum bag. +posh maroon bags contain 1 light bronze bag, 4 muted tan bags, 5 vibrant plum bags. +dim fuchsia bags contain 3 dim plum bags, 5 dark gray bags. +bright tan bags contain 1 shiny maroon bag, 1 light beige bag, 2 faded fuchsia bags. +plaid green bags contain 3 wavy cyan bags, 5 dark chartreuse bags, 5 dark blue bags. +plaid black bags contain 4 dull olive bags, 4 mirrored white bags, 4 plaid white bags. +clear beige bags contain 1 dull tan bag. +mirrored tomato bags contain 5 drab tomato bags, 1 plaid bronze bag. +dim yellow bags contain 4 dark indigo bags, 4 bright silver bags, 3 muted purple bags. +clear tan bags contain 4 light gold bags, 3 bright lavender bags, 2 mirrored fuchsia bags. +dim lavender bags contain 3 vibrant aqua bags. +striped white bags contain 3 posh tomato bags, 3 dark gold bags, 2 clear olive bags, 1 dotted bronze bag. +wavy bronze bags contain 1 plaid lime bag, 4 plaid yellow bags, 1 bright white bag. +shiny orange bags contain 3 drab chartreuse bags, 1 shiny gold bag. +dim coral bags contain 2 faded silver bags. +bright gold bags contain 5 dim aqua bags, 2 drab bronze bags. +vibrant black bags contain 4 dotted green bags, 2 light brown bags. +bright teal bags contain 1 light gold bag, 2 bright aqua bags. +drab brown bags contain 2 wavy blue bags, 5 wavy orange bags. +dull yellow bags contain 4 striped green bags, 4 bright lime bags, 2 faded tan bags, 5 dotted green bags. +vibrant maroon bags contain 4 mirrored fuchsia bags. +vibrant gray bags contain 3 faded turquoise bags, 5 pale black bags, 3 drab aqua bags. +pale white bags contain 3 shiny beige bags. +dim beige bags contain 1 pale fuchsia bag, 1 muted lime bag, 3 dotted plum bags. +drab blue bags contain 4 dim crimson bags, 4 shiny beige bags, 2 bright silver bags. +dark black bags contain 5 light beige bags, 5 muted gold bags. +plaid bronze bags contain 3 wavy indigo bags. +posh salmon bags contain 3 dark salmon bags, 2 posh purple bags, 5 dim yellow bags. +mirrored lavender bags contain 4 wavy chartreuse bags, 4 plaid bronze bags. +muted brown bags contain 1 drab magenta bag, 2 vibrant plum bags, 4 clear purple bags, 4 dark blue bags. +wavy white bags contain 2 striped red bags. +dark gray bags contain 5 bright blue bags, 2 light brown bags. +mirrored silver bags contain 2 dotted chartreuse bags, 1 dotted fuchsia bag, 4 mirrored lavender bags, 2 mirrored white bags. +wavy brown bags contain 5 posh teal bags, 4 drab white bags, 5 shiny chartreuse bags, 4 light maroon bags. +posh gray bags contain 1 striped turquoise bag, 4 muted crimson bags, 3 clear yellow bags, 3 striped crimson bags. +dull tomato bags contain 5 drab purple bags, 4 faded yellow bags. +dotted blue bags contain 2 dull cyan bags, 3 dim plum bags. +vibrant tomato bags contain 5 plaid coral bags, 5 pale fuchsia bags. +wavy beige bags contain 3 dull magenta bags, 3 dotted beige bags, 3 bright white bags, 2 striped fuchsia bags. +plaid lime bags contain 3 light blue bags, 3 drab brown bags, 1 drab teal bag. +dim white bags contain 5 wavy coral bags, 5 vibrant bronze bags, 2 dark cyan bags, 2 dark plum bags. +bright yellow bags contain 4 pale aqua bags, 2 dim turquoise bags, 4 faded brown bags. +plaid maroon bags contain 1 dark teal bag, 4 vibrant white bags, 5 striped coral bags, 4 shiny white bags. +pale lavender bags contain 2 shiny violet bags. +drab magenta bags contain 5 bright gray bags. +clear salmon bags contain 4 wavy purple bags, 1 bright olive bag, 1 clear yellow bag. +dark yellow bags contain 1 bright bronze bag, 3 striped plum bags. +posh bronze bags contain 1 shiny maroon bag, 4 drab olive bags, 2 mirrored green bags, 5 light silver bags. +drab green bags contain 3 dim orange bags, 5 vibrant chartreuse bags. +light fuchsia bags contain 2 wavy silver bags, 4 muted white bags, 5 muted black bags, 1 faded green bag. +dark plum bags contain 4 bright tan bags, 4 dull lime bags, 2 faded fuchsia bags, 4 shiny maroon bags. +light teal bags contain 4 light lavender bags. +vibrant tan bags contain 1 vibrant bronze bag. +muted teal bags contain 5 wavy green bags, 5 plaid turquoise bags. +bright chartreuse bags contain 2 muted gold bags, 5 posh olive bags, 1 vibrant tan bag, 2 faded salmon bags. +dotted fuchsia bags contain 3 pale lime bags. +pale teal bags contain 5 plaid silver bags, 4 shiny turquoise bags, 3 dim coral bags, 2 vibrant bronze bags. +drab orange bags contain 2 shiny silver bags, 2 vibrant indigo bags, 5 mirrored lavender bags, 5 dark yellow bags. +clear green bags contain 4 vibrant beige bags, 1 bright crimson bag, 5 muted gray bags. +shiny yellow bags contain 4 light fuchsia bags, 2 mirrored plum bags. +plaid blue bags contain 4 mirrored blue bags, 1 plaid olive bag. +mirrored plum bags contain 2 dull red bags, 3 muted magenta bags. +dim bronze bags contain 3 vibrant olive bags. +posh green bags contain 3 mirrored blue bags, 4 vibrant yellow bags, 5 bright yellow bags, 2 wavy fuchsia bags. +clear blue bags contain 5 mirrored yellow bags. +dotted teal bags contain 5 shiny brown bags, 2 faded silver bags, 3 plaid coral bags. +muted cyan bags contain 4 clear aqua bags. +dark fuchsia bags contain 1 shiny blue bag, 1 dull fuchsia bag, 2 dull lime bags, 5 drab salmon bags. +dark silver bags contain 2 dim salmon bags. +muted beige bags contain 1 shiny lavender bag, 1 striped chartreuse bag. +dull indigo bags contain 1 bright beige bag, 2 dark gold bags, 1 mirrored magenta bag. +bright silver bags contain 3 faded violet bags, 4 dim cyan bags, 5 faded indigo bags, 1 clear chartreuse bag. +dim olive bags contain 1 mirrored plum bag, 1 clear indigo bag, 2 striped crimson bags. +pale magenta bags contain 5 vibrant black bags, 3 muted salmon bags, 1 dotted fuchsia bag. +faded turquoise bags contain 2 light lavender bags, 3 clear lavender bags, 3 dull coral bags. +posh gold bags contain 5 clear blue bags. +muted maroon bags contain 5 dark fuchsia bags, 2 muted red bags, 5 dim salmon bags. +muted tomato bags contain 4 striped blue bags, 3 dark plum bags, 5 faded green bags, 4 bright tan bags. +dark lime bags contain 2 posh white bags, 4 dull crimson bags, 2 dark cyan bags, 4 mirrored plum bags. +posh lime bags contain 1 wavy violet bag, 3 dotted teal bags, 5 shiny cyan bags. +light tan bags contain 4 striped turquoise bags, 4 dim white bags, 4 shiny violet bags. +dull bronze bags contain 2 drab teal bags, 5 light red bags, 4 muted indigo bags. +plaid coral bags contain 5 dark purple bags, 5 striped crimson bags, 4 light beige bags. +wavy lavender bags contain 5 muted white bags. +drab indigo bags contain 4 dotted green bags, 1 striped silver bag. +dull silver bags contain 1 dark yellow bag, 2 light beige bags, 3 striped indigo bags, 4 wavy violet bags. +dark aqua bags contain 1 drab violet bag. +muted bronze bags contain 4 clear chartreuse bags, 4 drab turquoise bags, 3 pale coral bags. +striped coral bags contain 1 shiny red bag, 1 dark purple bag. +faded beige bags contain 2 bright fuchsia bags, 2 mirrored turquoise bags. +dull plum bags contain 5 dull aqua bags. +drab lime bags contain 3 clear aqua bags, 4 shiny cyan bags. +pale plum bags contain 5 shiny silver bags, 5 dull coral bags. +pale violet bags contain 1 wavy purple bag, 1 light plum bag, 3 striped silver bags, 3 drab teal bags. +clear magenta bags contain 2 dark plum bags, 2 striped tan bags, 4 posh plum bags, 4 dark turquoise bags. +vibrant plum bags contain 3 dotted teal bags, 5 vibrant gold bags. +bright gray bags contain 3 muted white bags, 2 striped crimson bags, 3 mirrored gray bags, 4 wavy silver bags. +clear coral bags contain 2 vibrant magenta bags, 2 dim orange bags, 3 dark black bags. +vibrant chartreuse bags contain 3 dark lime bags, 1 mirrored turquoise bag, 2 vibrant indigo bags, 1 dull gray bag. +faded purple bags contain 2 mirrored indigo bags, 3 dark indigo bags, 2 pale fuchsia bags, 5 muted olive bags. +drab violet bags contain 4 muted black bags, 1 clear maroon bag, 1 clear gold bag. +dim magenta bags contain 5 wavy tan bags. +clear orange bags contain 5 shiny tomato bags, 1 faded fuchsia bag. +mirrored white bags contain 5 dim plum bags, 3 mirrored magenta bags. +plaid white bags contain 1 pale tomato bag, 2 posh magenta bags, 5 vibrant maroon bags, 5 shiny fuchsia bags. +shiny olive bags contain 4 striped salmon bags, 2 mirrored gray bags, 5 plaid beige bags. +plaid plum bags contain 3 bright bronze bags. +dull salmon bags contain 3 bright white bags, 2 muted cyan bags. +pale maroon bags contain 3 muted tan bags, 1 bright gray bag. +faded salmon bags contain 1 bright silver bag. +striped magenta bags contain 5 dark plum bags, 5 faded bronze bags, 4 striped brown bags. +vibrant crimson bags contain 2 muted lime bags, 5 plaid indigo bags. +wavy tan bags contain 2 shiny yellow bags, 3 clear beige bags, 2 dotted gold bags. +posh teal bags contain 4 striped gold bags, 3 drab salmon bags, 3 shiny plum bags, 2 pale gray bags. +dotted coral bags contain 2 wavy chartreuse bags, 3 wavy blue bags. +light purple bags contain 1 mirrored lime bag. +bright lavender bags contain 5 faded brown bags. +muted turquoise bags contain 2 shiny maroon bags, 3 light purple bags, 2 striped tan bags, 4 plaid cyan bags. +posh red bags contain 2 striped lavender bags, 1 dark black bag, 5 dark purple bags, 3 drab olive bags. +bright black bags contain 3 dark brown bags, 4 clear olive bags, 4 plaid olive bags. +mirrored bronze bags contain 1 wavy turquoise bag. +vibrant violet bags contain 2 plaid indigo bags, 4 faded orange bags. +drab tan bags contain 3 clear crimson bags, 4 mirrored turquoise bags, 2 muted magenta bags. +dim gray bags contain 5 striped black bags, 5 muted silver bags, 1 dotted blue bag, 3 posh gray bags. +dull tan bags contain 1 clear maroon bag, 4 posh beige bags, 2 striped crimson bags, 5 dim gold bags. +vibrant blue bags contain 4 bright beige bags, 5 bright bronze bags, 2 plaid salmon bags. +posh crimson bags contain 2 mirrored purple bags, 1 striped silver bag, 2 bright magenta bags, 5 bright blue bags. +dotted bronze bags contain 2 wavy crimson bags, 5 muted purple bags, 5 light gold bags. +pale brown bags contain 1 drab coral bag, 2 mirrored lavender bags, 4 dark tomato bags, 3 plaid indigo bags. +shiny maroon bags contain 5 light beige bags, 3 light white bags. +dark tomato bags contain 5 shiny gold bags, 5 clear aqua bags, 2 dotted gold bags. +dark beige bags contain 2 bright gray bags, 3 light beige bags, 1 dull lime bag. +light red bags contain 5 mirrored magenta bags, 1 mirrored lime bag, 4 dotted teal bags. +faded magenta bags contain 1 dim maroon bag, 3 mirrored gray bags, 1 dotted beige bag. +drab turquoise bags contain no other bags. +shiny salmon bags contain 5 shiny tan bags, 2 posh magenta bags, 4 clear turquoise bags. +dark magenta bags contain 1 light fuchsia bag, 3 muted yellow bags, 5 dotted olive bags, 4 dark crimson bags. +light gold bags contain 5 clear red bags. +faded red bags contain 4 clear beige bags, 3 dim silver bags, 4 posh gray bags. +pale salmon bags contain 5 mirrored white bags. +striped lavender bags contain 2 striped blue bags. +dull fuchsia bags contain 1 bright orange bag. +dull turquoise bags contain 1 vibrant tomato bag, 3 clear tan bags, 3 bright teal bags, 1 drab maroon bag. +dotted magenta bags contain 5 drab gold bags, 2 muted beige bags. +pale indigo bags contain 4 plaid brown bags, 1 plaid cyan bag, 1 mirrored black bag, 5 drab magenta bags. +drab yellow bags contain 5 dark turquoise bags, 2 dotted beige bags, 5 clear red bags, 2 muted lavender bags. +striped gray bags contain 5 bright orange bags, 5 muted white bags, 2 clear chartreuse bags. +dark lavender bags contain 5 dim gold bags, 2 pale coral bags. +dull gold bags contain 1 dull beige bag. +muted chartreuse bags contain 3 muted bronze bags, 1 faded black bag, 4 bright tan bags. +plaid chartreuse bags contain 4 dim indigo bags, 4 mirrored gold bags, 4 dim lime bags. +muted salmon bags contain 4 faded brown bags, 1 dotted black bag, 5 muted black bags. +bright purple bags contain 5 shiny red bags, 5 vibrant cyan bags, 4 plaid cyan bags, 5 bright silver bags. +dim chartreuse bags contain 1 faded indigo bag. +drab purple bags contain 4 muted cyan bags, 3 wavy lavender bags, 2 dotted blue bags. diff --git a/d07/main.py b/d07/main.py new file mode 100755 index 0000000..470e3b8 --- /dev/null +++ b/d07/main.py @@ -0,0 +1,82 @@ +#! /usr/bin/env python3 +import itertools +import re +from collections import namedtuple + +line_matcher = re.compile(r"(\w+ \w+) bags contain ([\w+ ,]+)+.") +child_matcher = re.compile(r"([0-9]+) (\w+ \w+) bag[s]{0,1}") + + +BagRule = namedtuple("BagRule", ["parent_bag", "bag_counts"]) + + +def parse_line(line): + result = line_matcher.match(line) + if result is None: + # print(f"{line}: No match") + return None + else: + parent_bag = result.group(1) + bag_counts = {} + # print(result.groups()) + for bags in result.group(2).split(","): + if bags == "no other bags": + break + child_result = child_matcher.search(bags.strip()) + # print(bags.strip(), child_result.groups()) + if child_result is None: + print(f"Invalid child bags: {bags}") + bag_counts[child_result.group(2)] = int(child_result.group(1)) + + return BagRule(parent_bag, bag_counts) + + +def get_direct_carriers(contained_in, bags): + return set(itertools.chain.from_iterable(( + contained_in.get(bag, []) + for bag in bags + ))) + + +def part1(): + contained_in = {} + with open("input.txt") as f: + for line in f: + rule = parse_line(line) + for bag in rule.bag_counts.keys(): + contained_in.setdefault(bag, []).append(rule.parent_bag) + + my_bag = "shiny gold" + holding_bags = set() + last_level = set((my_bag,)) + while last_level: + last_level = get_direct_carriers(contained_in, last_level) + holding_bags |= last_level + + print(f"Holding bags: {len(holding_bags)}") + + +def count_children(contents, bag): + rule = contents.get(bag) + if rule is None: + return 0 + return sum( + count * (1 + count_children(contents, child_bag)) + for child_bag, count in rule.bag_counts.items() + ) + + +def part2(): + contents = {} + with open("input.txt") as f: + for line in f: + rule = parse_line(line) + contents[rule.parent_bag] = rule + + children = count_children(contents, "shiny gold") + print(f"Holds {children} bags") + + +if __name__ == "__main__": + part1() + part2() diff --git a/d08/input.txt b/d08/input.txt new file mode 100644 index 0000000..c4578c8 --- /dev/null +++ b/d08/input.txt @@ -0,0 +1,596 @@ +acc +40 +jmp +187 +acc +47 +acc +20 +acc -12 +jmp +225 +nop +488 +acc +13 +nop +462 +jmp +374 +acc +15 +acc +42 +jmp +116 +acc +23 +nop +216 +acc -15 +jmp +398 +jmp +103 +acc +17 +acc +7 +jmp +571 +jmp +1 +jmp +217 +acc +7 +jmp +1 +acc +35 +jmp +257 +acc +24 +nop +20 +jmp +309 +acc +2 +acc -15 +acc -13 +nop +457 +jmp +19 +acc +46 +acc +45 +acc +35 +jmp +295 +acc -15 +acc +49 +acc +22 +jmp +400 +jmp +202 +nop -38 +jmp +381 +acc +0 +jmp +137 +acc +27 +jmp +196 +acc +46 +acc -15 +jmp +348 +jmp +457 +acc +50 +acc +8 +jmp +452 +acc -14 +nop +321 +acc +39 +jmp +273 +acc -9 +jmp +413 +acc +32 +jmp +64 +acc +18 +jmp +152 +acc -4 +acc +9 +acc +10 +acc -1 +jmp +433 +acc +40 +jmp -55 +acc +28 +nop +279 +jmp +145 +acc +24 +nop +416 +acc +45 +jmp +45 +acc +0 +acc +49 +acc -14 +jmp +44 +acc +17 +acc +18 +nop +224 +acc +3 +jmp +261 +jmp -84 +acc -11 +acc +29 +acc +42 +jmp -13 +acc -5 +jmp +210 +acc +26 +acc -19 +acc -19 +jmp -82 +acc +29 +acc +31 +acc -4 +jmp +53 +acc +46 +jmp +139 +acc +45 +acc +30 +jmp +1 +jmp +418 +jmp +248 +acc +24 +acc +15 +acc +34 +acc +17 +jmp +52 +acc +23 +acc +18 +jmp +65 +jmp +1 +acc +37 +acc +25 +jmp +385 +jmp +281 +nop +345 +jmp -25 +jmp +149 +acc +21 +acc +28 +acc +15 +jmp -74 +jmp +179 +jmp +287 +acc +14 +acc -3 +acc -7 +jmp -9 +acc +17 +acc -8 +jmp +344 +jmp +1 +acc +36 +acc -16 +acc -17 +jmp -82 +jmp +1 +acc +41 +acc -8 +acc +27 +jmp +381 +acc -10 +nop -71 +acc +23 +nop +377 +jmp -125 +jmp +319 +nop +119 +nop +309 +nop +195 +jmp +307 +acc +8 +acc +31 +jmp +1 +acc -15 +jmp +398 +jmp +265 +jmp -55 +nop +143 +jmp -36 +acc +38 +nop -38 +jmp +298 +acc -17 +acc +39 +acc -13 +jmp -38 +acc +23 +jmp +133 +acc +23 +jmp -90 +acc +14 +jmp +1 +jmp +100 +nop +230 +jmp +346 +acc +36 +jmp +14 +jmp +126 +jmp -32 +jmp -142 +acc +25 +jmp +146 +nop +118 +acc -3 +jmp +1 +acc -8 +jmp +101 +nop +277 +acc +27 +jmp +328 +acc -11 +acc +17 +nop +135 +jmp +196 +acc -9 +jmp +39 +nop +110 +acc +14 +nop +3 +jmp +17 +jmp +220 +acc +17 +jmp +5 +acc +18 +acc +39 +acc -12 +jmp -204 +jmp +317 +acc +37 +jmp +222 +nop +146 +nop +248 +jmp +182 +acc +48 +acc -13 +jmp +174 +jmp +342 +nop -189 +jmp +324 +acc +35 +acc +25 +acc +21 +jmp -152 +nop -92 +acc -3 +acc -15 +acc +30 +jmp -157 +acc -17 +acc +37 +acc +7 +acc +5 +jmp -225 +jmp -177 +acc +21 +jmp +244 +acc +42 +acc -4 +jmp -116 +nop +225 +nop -63 +acc +20 +jmp +195 +acc +20 +acc +21 +jmp +228 +acc +16 +acc -8 +acc +12 +nop +188 +jmp +9 +acc +6 +acc -13 +acc +36 +jmp -86 +jmp -253 +nop -60 +acc +25 +jmp -174 +acc +10 +nop -114 +jmp -65 +jmp +1 +acc +24 +jmp -150 +acc +27 +jmp -47 +acc +50 +nop -58 +acc -17 +acc -16 +jmp -170 +jmp -104 +jmp -177 +acc +46 +jmp +106 +jmp -206 +acc +2 +acc +10 +acc +17 +nop -107 +jmp -126 +jmp +1 +acc +50 +acc -14 +acc +29 +jmp -234 +nop +144 +acc +43 +acc +34 +jmp +221 +jmp +1 +nop +97 +acc +39 +jmp -60 +acc +44 +jmp -240 +acc +11 +acc +36 +jmp -71 +acc -5 +jmp +149 +jmp +54 +acc +38 +jmp +44 +jmp -165 +acc +14 +jmp -134 +acc +3 +acc +22 +nop +46 +acc -12 +jmp -57 +acc +49 +acc +24 +acc +16 +jmp +27 +acc +6 +nop -5 +acc +45 +acc +34 +jmp -175 +jmp -76 +acc +3 +acc +15 +acc -19 +jmp +1 +nop -226 +acc -2 +jmp -55 +jmp -284 +acc +2 +jmp +1 +jmp +15 +acc +11 +acc +12 +acc -1 +acc +2 +jmp +179 +acc +19 +acc +17 +jmp -329 +jmp -272 +jmp -104 +acc +41 +nop +189 +acc +47 +jmp -88 +acc +4 +acc +16 +acc +43 +acc +25 +jmp +71 +acc -2 +acc +45 +jmp -173 +jmp +1 +acc +44 +acc +33 +jmp -53 +acc +45 +acc +9 +acc +0 +acc +12 +jmp +178 +jmp -100 +acc +14 +jmp -67 +acc +42 +jmp +201 +acc +30 +jmp -319 +nop -4 +nop -211 +acc -3 +nop -165 +jmp -175 +acc +12 +acc -10 +acc -14 +jmp -53 +acc -13 +nop -143 +jmp +159 +acc -5 +nop +18 +nop -5 +acc +13 +jmp -248 +jmp +114 +acc +10 +nop -396 +nop -246 +jmp +16 +acc -3 +acc +33 +nop +174 +acc +48 +jmp -289 +nop +98 +acc +18 +acc -17 +jmp -137 +jmp +1 +acc +34 +acc +36 +jmp -216 +acc +11 +jmp -102 +acc +10 +jmp +10 +acc +26 +acc +35 +acc -9 +jmp -83 +acc +15 +nop -397 +jmp -140 +nop +111 +jmp +139 +jmp -165 +acc +16 +jmp -343 +acc +8 +acc +35 +acc -17 +acc -8 +jmp +29 +acc +50 +nop -256 +jmp -268 +jmp +132 +acc +13 +acc +38 +acc -6 +acc -7 +jmp -327 +acc -8 +jmp -256 +nop -139 +acc +30 +jmp -60 +acc -1 +acc +11 +jmp -216 +acc -12 +nop -390 +acc +17 +acc +39 +jmp +101 +acc +28 +jmp +1 +acc -7 +acc -18 +jmp -277 +jmp -90 +acc -10 +jmp -326 +jmp -368 +nop -396 +jmp -320 +acc +42 +acc +3 +jmp -430 +acc +47 +acc +11 +acc +19 +acc +41 +jmp -354 +acc +30 +acc +7 +nop -106 +jmp -420 +acc +22 +acc -15 +jmp -296 +acc -7 +acc +48 +jmp -19 +jmp -148 +acc +10 +jmp +1 +jmp +17 +nop -273 +acc +42 +acc -4 +nop -130 +jmp +47 +nop -436 +acc -7 +jmp +1 +acc +42 +jmp -330 +acc +35 +jmp +56 +acc -19 +jmp -440 +jmp -335 +jmp -279 +nop -390 +jmp +74 +acc -5 +jmp -456 +acc +38 +acc +3 +jmp +47 +acc +50 +acc +26 +acc +46 +acc -7 +jmp -491 +acc -4 +acc -7 +acc +14 +nop -105 +jmp -487 +jmp -326 +nop -360 +jmp -378 +jmp -285 +acc +46 +jmp -190 +acc +10 +jmp -346 +acc +49 +jmp -492 +acc -9 +acc -17 +jmp -147 +acc +20 +jmp -217 +nop -183 +acc +35 +jmp -268 +nop -51 +jmp +1 +jmp -440 +acc +22 +acc +24 +jmp +1 +acc +26 +jmp -451 +acc -14 +acc +48 +acc +3 +jmp -363 +acc +21 +acc +24 +acc +36 +jmp -418 +jmp -108 +jmp -323 +jmp +20 +acc +1 +acc +21 +nop -212 +acc -3 +jmp -338 +acc +36 +acc -19 +jmp -192 +acc +49 +jmp -380 +acc -12 +acc +14 +acc +38 +acc +4 +jmp -228 +acc +2 +jmp -197 +jmp -41 +jmp -265 +jmp -113 +jmp -459 +jmp +1 +acc +38 +jmp -79 +acc +16 +nop -456 +jmp -129 +acc +12 +acc +29 +nop -575 +acc -7 +jmp +1 diff --git a/d08/main.py b/d08/main.py new file mode 100755 index 0000000..02c8cbb --- /dev/null +++ b/d08/main.py @@ -0,0 +1,94 @@ +#! /usr/bin/env python3 +from copy import copy + +sample = [ + "nop +0", + "acc +1", + "jmp +4", + "acc +3", + "jmp -3", + "acc -99", + "acc +1", + "jmp -4", + "acc +6", +] + + +def parse_lines(lines): + def parse_line(line): + inst, _, num = line.partition(" ") + return (inst, int(num)) + + return [ + parse_line(line) + for line in lines + ] + + +def run_line(instructions, index): + inst, num = instructions[index] + if inst == "nop": + return index+1, 0 + elif inst == "acc": + return index+1, num + elif inst == "jmp": + return index+num, 0 + + +def part1(): + with open("input.txt") as f: + instructions = parse_lines(f) + _, acc = run_until_loop(instructions, 0) + print("Total accumulated:", acc) + + +def run_until_loop(instructions, line, seen_lines=None): + if seen_lines is None: + seen_lines = set() + acc = 0 + while line < len(instructions): + seen_lines.add(line) + # print(f"Inner: {line}:{instructions[line]}") + line, num = run_line(instructions, line) + acc += num + if line in seen_lines: + # print(f"Inner loop, break out") + return True, acc + return False, acc + + +def part2(): + with open("input.txt") as f: + instructions = parse_lines(f) + + accum = 0 + line = 0 + seen_lines = set() + + while line < len(instructions): + if line in seen_lines: + print(f"Ugh, looping") + return + + # print(f"{line}:{instructions[line]}") + inst, num = instructions[line] + if inst != "acc": + # print(f"Found an alternate, check for loop") + # Possible change + new_inst = copy(instructions) + new_seen = copy(seen_lines) + new_inst[line] = ("nop" if inst == "jmp" else "jmp", num) + has_loop, acc_d = run_until_loop(new_inst, line, new_seen) + if not has_loop: + accum += acc_d + print(f"Found solution! Changing {line}: Total {accum}") + return + + seen_lines.add(line) + line, num = run_line(instructions, line) + accum += num + + +if __name__ == "__main__": + part1() + part2() diff --git a/d09/input.txt b/d09/input.txt new file mode 100644 index 0000000..c9c6b80 --- /dev/null +++ b/d09/input.txt @@ -0,0 +1,1000 @@ +4 +15 +11 +10 +33 +20 +42 +34 +49 +45 +29 +43 +26 +12 +19 +17 +28 +47 +46 +2 +18 +39 +50 +3 +23 +5 +14 +7 +52 +9 +60 +16 +20 +61 +97 +79 +8 +10 +11 +22 +13 +12 +15 +65 +17 +19 +28 +21 +18 +24 +23 +33 +25 +41 +34 +26 +35 +29 +36 +20 +27 +38 +40 +39 +43 +32 +80 +37 +45 +58 +42 +49 +53 +44 +73 +46 +52 +47 +55 +100 +56 +57 +59 +60 +64 +66 +69 +88 +130 +77 +127 +79 +169 +86 +89 +90 +103 +106 +99 +98 +93 +187 +102 +184 +113 +163 +116 +148 +181 +141 +152 +146 +193 +176 +156 +199 +279 +200 +175 +182 +209 +191 +192 +195 +206 +297 +215 +218 +229 +265 +257 +262 +287 +368 +293 +302 +321 +331 +371 +338 +392 +367 +439 +542 +863 +397 +457 +387 +401 +421 +433 +472 +698 +486 +519 +583 +788 +685 +614 +595 +940 +652 +669 +705 +725 +754 +764 +784 +1307 +798 +1035 +844 +1185 +887 +854 +905 +958 +1005 +1100 +1102 +1833 +1209 +1489 +1449 +1247 +1430 +2101 +1459 +1469 +2432 +1518 +1949 +2267 +1642 +2313 +1698 +1731 +1741 +1759 +1954 +2791 +1963 +2105 +2202 +3373 +3383 +4842 +2677 +5805 +2977 +3128 +3101 +2928 +2987 +3160 +3216 +3690 +3340 +3401 +8933 +12623 +5160 +10647 +3713 +7030 +5033 +5478 +5092 +5130 +5605 +5654 +6137 +5905 +5915 +6056 +6029 +6376 +9457 +6147 +6500 +6556 +6741 +7053 +7114 +11820 +8746 +8805 +10570 +8843 +10125 +11132 +10222 +10697 +11569 +15399 +11559 +11934 +11944 +12085 +12176 +12405 +12523 +12647 +12703 +13056 +13297 +17873 +14167 +17239 +20364 +26082 +19937 +18968 +19065 +23308 +25579 +20919 +22266 +23735 +24019 +25108 +24120 +24029 +24261 +24581 +24928 +25350 +25703 +37637 +37810 +37603 +31406 +35086 +36304 +38033 +40856 +38905 +39887 +39984 +49608 +47764 +55141 +46001 +47754 +48139 +48290 +86659 +48610 +48842 +49509 +50278 +66559 +60789 +66492 +67710 +69009 +69439 +114246 +74337 +85797 +84906 +78792 +188583 +87748 +93755 +93765 +94140 +94291 +95893 +124615 +134407 +97452 +98119 +98351 +135306 +229446 +145695 +135126 +134202 +185200 +138448 +168092 +153129 +218906 +163698 +166540 +189648 +181503 +181513 +281001 +187905 +338329 +301846 +395986 +195571 +195803 +196470 +232321 +233657 +319669 +269328 +273574 +304988 +272650 +291577 +302146 +316827 +486491 +330238 +363016 +348053 +369408 +391374 +413834 +383476 +560905 +427892 +392041 +392273 +428124 +562559 +428791 +465978 +502985 +541978 +542902 +546224 +849454 +593723 +1065544 +904994 +988797 +678291 +739427 +1167319 +717461 +1277346 +783647 +806107 +775517 +819933 +820165 +970102 +1022514 +1012202 +894769 +1644421 +1044963 +1049209 +1084880 +1311184 +1263685 +2275887 +1272014 +1395752 +1456888 +1784390 +1453808 +2466010 +1501108 +2131349 +2356147 +1753749 +1626040 +1745619 +2083850 +2426990 +1864871 +2648554 +1906971 +3861762 +2094172 +4510840 +3017633 +2720573 +2896860 +4221018 +3238198 +5665188 +2849560 +3652590 +3079848 +2954916 +4814745 +7117878 +3618620 +3379789 +3610490 +4513425 +4803831 +3771842 +3959043 +5675489 +4001143 +6095315 +6789475 +4943732 +5570133 +5617433 +8572349 +6515480 +6502150 +5929408 +8575673 +5804476 +6034764 +6334705 +6565406 +10848130 +6990279 +6998409 +7151631 +7382332 +7730885 +7772985 +9867157 +7960186 +8944875 +9571276 +10513865 +12794755 +10561165 +11187566 +11546841 +11733884 +11839240 +11964172 +16348658 +12139181 +13025043 +13947738 +12900111 +14763264 +21099369 +14721164 +14924616 +14533963 +15113217 +15503870 +20758842 +16905061 +20754941 +18516151 +20085141 +21075030 +23803412 +21748731 +22734407 +24758927 +23873065 +23978421 +35759450 +25039292 +25164224 +25925154 +29297227 +27663375 +30037833 +31626225 +29647180 +29458579 +31439024 +55572334 +46363640 +35421212 +36990202 +47773699 +41160171 +59335060 +42823761 +48631992 +44483138 +46607472 +59289600 +47851486 +70342061 +54622803 +89431233 +85030913 +53588529 +56960602 +57121954 +96325262 +60897603 +59105759 +64879791 +66860236 +87767643 +72411414 +78244973 +89011657 +112923589 +91455753 +87306899 +90675247 +94458958 +91090610 +105713231 +137282719 +108211332 +110549131 +110710483 +112694288 +114082556 +114486132 +116066361 +116227713 +149781006 +120003362 +123985550 +131740027 +139271650 +150656387 +159718313 +165551872 +176318556 +177982146 +178397509 +181765857 +202670290 +185549568 +224631687 +269022746 +269784368 +218760463 +287029039 +445341302 +226776844 +228568688 +243988912 +232294074 +236231075 +251743389 +255725577 +426300689 +304823522 +315590206 +531017951 +367315425 +341870428 +403029196 +388219858 +506015443 +400526320 +404310031 +474486040 +547884280 +464799763 +875012360 +454991538 +614996702 +455345532 +459070918 +460862762 +507468966 +701030838 +487974464 +556566911 +709185853 +646693950 +876194322 +1042901266 +730090286 +742396748 +863891958 +804836351 +859301569 +859597238 +859655563 +911778997 +1734609598 +1320460000 +910337070 +914062456 +914416450 +916208294 +919933680 +947045382 +1265752764 +995443430 +1044541375 +1134668414 +1203260861 +1355879803 +1376784236 +1618591070 +1962834946 +1472487034 +1547233099 +1664137920 +1664433589 +1718898807 +2332084272 +1769992633 +1822116067 +1861107838 +1824399526 +2337929275 +1828478906 +1830624744 +1836141974 +2922159668 +2081713796 +2179209789 +1721308972 +2247802236 +2490548217 +2924569833 +2974470873 +2849271270 +3019720133 +3136624954 +3492912495 +3211371019 +3328571509 +3383332396 +4857933926 +3491301605 +3543425039 +3551933716 +3545708498 +4015351763 +4329516032 +3549787878 +5412707885 +5003873464 +5896630541 +6686412832 +3900518761 +4741029105 +5097073506 +5339819487 +5899040706 +5985896224 +5868991403 +9531604722 +6347995973 +6594703415 +6539942528 +6711903905 +6874634001 +7034726644 +7037010103 +9450974422 +7095496376 +11052361866 +16325608423 +7450306639 +8290816983 +8641547866 +14162210544 +10495222176 +10248514734 +8997592267 +14094665773 +13576952631 +11208810890 +15327827086 +11854887627 +12216987376 +13443492349 +12887938501 +14130223020 +13251846433 +13586537906 +13909360645 +16447898906 +16546470798 +16932364849 +19667294015 +25793940007 +15741123622 +16091854505 +17288409250 +17639140133 +19246107001 +19492814443 +20206403157 +25106734060 +23063698517 +25339033910 +30676693818 +24071875003 +24742826128 +36599658864 +26139784934 +26474476407 +27716760926 +32189022528 +55419519946 +29650484267 +36115192921 +32673488471 +40352107767 +55444424274 +31832978127 +36534516251 +51681836971 +37494812407 +36885247134 +38738921444 +49178609063 +46346188091 +47135573520 +47806524645 +58663498935 +88313983202 +63481747572 +50882611062 +52614261341 +62589669328 +54191237333 +86864725804 +111288272217 +70571899571 +62323972738 +64506466598 +84691771779 +86063856197 +98028025062 +84020820654 +85085109535 +110852654689 +146344793392 +101391713732 +85874494964 +93481761611 +125805720310 +94942098165 +98689135707 +103496872403 +105073848395 +106805498674 +201747596839 +165898180330 +200287260285 +126830439336 +132895872309 +135078366169 +149198238377 +147015744517 +231036565171 +170959604499 +169105930189 +182048845716 +178566871146 +183774245242 +180816593129 +179356256575 +276028677713 +184563630671 +188423859776 +193631233872 +198438970568 +211879347069 +210302371077 +231904287731 +282094110686 +354322040106 +292728619666 +304184296358 +261908805505 +319641996840 +315894959298 +445683050747 +326372001092 +340065534688 +347672801335 +348462186764 +360615716862 +357923127721 +360172849704 +507188594221 +727777161433 +612370616506 +372987490447 +382055093648 +392070204440 +673818087019 +422181718146 +442206658808 +674110946539 +586278407044 +902173366342 +601974340193 +707965163738 +707591856252 +635536956138 +642266960390 +749993332161 +666437535780 +687738336023 +696134988099 +706385314485 +1034552334652 +800129786529 +733160340151 +1276085286732 +755042584095 +774125298088 +1188252747237 +804236811794 +814251922586 +1118316706245 +1221815363182 +1028485065852 +1228545367434 +1237511296331 +1301974491918 +1244241300583 +1614381709115 +1277803916528 +1308704496170 +1330005296413 +1394123650508 +1354175871803 +1383873324122 +1402520302584 +1439545654636 +1488202924246 +2337189562022 +2198360462302 +2063747080265 +1529167882183 +2472492578048 +1618488734380 +1832721877646 +2574246596996 +2146801772097 +2692577820292 +2257030433286 +2466056663765 +2552945796753 +3727528344485 +2724128946921 +2756696174387 +2927193230550 +3141426373816 +4257198526963 +2748299522311 +4031082339948 +2872076248368 +2842065957220 +2927748578882 +3017370806429 +3147656616563 +3361889759829 +3451210612026 +3675969654280 +7398624900779 +7274569333392 +4298778541411 +4403832205383 +4612858435862 +5398456807102 +4723087097051 +5190185610686 +5277074743674 +9335945532913 +5590365479531 +5889725896127 +5714142205588 +5620375770679 +5676048101193 +5765670328740 +6379260566258 +5769814536102 +5859436763649 +9974826642604 +6165027422992 +6823626270843 +10849835512805 +8866155264966 +8079801859663 +10293558101510 +8702610746794 +10382672971964 +15969606202703 +10437229302639 +14143230008640 +11334517976267 +10866233711879 +10867440223205 +18373359961173 +11210741250210 +11296423871872 +16057605073318 +11386046099419 +11441718429933 +11535484864842 +19733595488171 +11934841959094 +15031182687958 +16798452913447 +14867638169786 +14903428130506 +21303463014518 +17568766011760 +18947242082868 +22827764529352 +19085283718758 +20819902274603 +21733653174511 +22507165122082 +21733673935084 +22078181473415 +22252279811298 +23376560389027 +22596787349629 +22652459680143 +22682469971291 +33626371085078 +22921530964261 +31175313918104 +32472194142266 +28733294872541 +31701881043953 +29771066300292 +31666091083233 +32436404181546 +33850670213374 +40165553361389 +45279257320920 +50649123126821 +39905185993361 +40818936893269 +42553555449114 +44240818296593 +43811855408499 +43985953746382 +44330461284713 +44934749782589 +62877194962057 +73301582806964 +56503129893517 +55154664113557 +51654825836802 +73755856206735 +58504361172833 +62243260442558 diff --git a/d09/main.go b/d09/main.go new file mode 100644 index 0000000..d7340df --- /dev/null +++ b/d09/main.go @@ -0,0 +1,273 @@ +package main + +import ( + "bufio" + "container/list" + "fmt" + "log" + "os" + "strconv" +) + +func processLines(path string, f func(string) (stop bool, err error)) error { + file, err := os.Open(path) + if err != nil { + return err + } + defer file.Close() + scanner := bufio.NewScanner(file) + for scanner.Scan() { + stop, err := f(scanner.Text()) + if stop || err != nil { + return err + } + } + if err := scanner.Err(); err != nil { + return err + } + return nil +} + +// LimitedList acts as a list with a fixed size +type LimitedList struct { + elements *list.List + maxLength int +} + +// Len returns the current length of the fixed list +func (ll *LimitedList) Len() int { + return ll.elements.Len() +} + +// Full checks if the fixed list is full +func (ll *LimitedList) Full() bool { + return ll.Len() == ll.maxLength +} + +// Front moves the pointer to the front of the list +func (ll *LimitedList) Front() *list.Element { + return ll.elements.Front() +} + +// Push adds an item to the back of the fixed list +func (ll *LimitedList) Push(v interface{}) *list.Element { + if ll.Full() { + _ = ll.elements.Remove(ll.Front()) + } + return ll.elements.PushBack(v) +} + +// NewLimitedList initializes a new list limited to the given length +func NewLimitedList(size int) *LimitedList { + return &LimitedList{ + list.New(), + size, + } +} + +// Pair of numbers +type Pair struct { + A, B int +} + +func searchPairs(l LimitedList, target int) (Pair, error) { + var x, y int + for ex := l.Front(); ex != nil; ex = ex.Next() { + x = ex.Value.(int) + for ey := ex.Next(); ey != nil; ey = ey.Next() { + y = ey.Value.(int) + if x+y == target { + return Pair{x, y}, nil + } + } + } + + return Pair{}, fmt.Errorf("could not find pair matching %d in %v", target, l) +} + +func searchPairsSlice(numbers []int, target int) (Pair, error) { + for i, x := range numbers { + for _, y := range numbers[i:] { + if x+y == target { + return Pair{x, y}, nil + } + } + } + + return Pair{}, fmt.Errorf("could not find pair matching %d in %v", target, numbers) +} + +func part1Old() int { + bufferSize := 25 + buffer := []int{} + result := -1 + err := processLines("input.txt", func(line string) (stop bool, err error) { + v, err := strconv.Atoi(line) + if err != nil { + return + } + if len(buffer) < bufferSize { + buffer = append(buffer, v) + } else { + // Check number + _, err = searchPairsSlice(buffer[len(buffer)-bufferSize:], v) + if err != nil { + stop = true + err = nil + result = v + return + } + buffer = append(buffer, v) + } + return + }) + + if err != nil { + log.Fatal(err) + } + + if result < 0 { + fmt.Println("All valid") + } else { + fmt.Printf("First non matching is %d\n", result) + } + + return result +} + +func part1() int { + ll := NewLimitedList(25) + result := -1 + err := processLines("input.txt", func(line string) (stop bool, err error) { + v, err := strconv.Atoi(line) + if err != nil { + return + } + if !ll.Full() { + ll.Push(v) + } else { + // Check number + _, err = searchPairs(*ll, v) + if err != nil { + stop = true + err = nil + result = v + return + } + ll.Push(v) + } + return + }) + + if err != nil { + log.Fatal(err) + } + + if result < 0 { + fmt.Println("All valid") + } else { + fmt.Printf("First non matching is %d\n", result) + } + + return result +} + +// SumQueue acts as a list with a fixed size +type SumQueue struct { + elements *list.List + sum int +} + +// Len returns the current length of the queue +func (sq *SumQueue) Len() int { + return sq.elements.Len() +} + +// Sum returns the sum of the items in the queue +func (sq *SumQueue) Sum() int { + return sq.sum +} + +// Front moves the pointer to the front of the list +func (sq *SumQueue) Front() *list.Element { + return sq.elements.Front() +} + +// Push adds an item to the back of the queue +func (sq *SumQueue) Push(v int) *list.Element { + sq.sum = sq.sum + v + return sq.elements.PushBack(v) +} + +// Pop removes an item from the queue +func (sq *SumQueue) Pop() int { + v := sq.elements.Remove(sq.Front()).(int) + sq.sum = sq.sum - v + return v +} + +// NewSumQueue creates a new SumQueue +func NewSumQueue() *SumQueue { + return &SumQueue{ + list.New(), + 0, + } +} + +func part2(target int) { + sq := NewSumQueue() + found := false + err := processLines("input.txt", func(line string) (stop bool, err error) { + v, err := strconv.Atoi(line) + // fmt.Println(v, sq.Len()) + if err != nil { + return + } + if v == target { + return + } + sq.Push(v) + if sq.Sum() == target { + // Found it! + stop = true + found = true + return + } + for sq.Sum() > target && sq.Sum() > 0 { + // While too big, pop from the front + _ = sq.Pop() + } + if sq.Sum() == target { + // Found it! + stop = true + found = true + return + } + return + }) + + if err != nil { + log.Fatal(err) + } + + if found { + min := -1 + max := -1 + for e := sq.Front(); e != nil; e = e.Next() { + if min < 0 || e.Value.(int) < min { + min = e.Value.(int) + } + if e.Value.(int) > max { + max = e.Value.(int) + } + } + fmt.Printf("Found %d numbers matching min %d max %d sum %d", sq.Len(), min, max, min+max) + } else { + fmt.Println("Didn't find anything") + } +} + +func main() { + result := part1() + part2(result) +} diff --git a/d09/testinput.txt b/d09/testinput.txt new file mode 100644 index 0000000..28d66e4 --- /dev/null +++ b/d09/testinput.txt @@ -0,0 +1,20 @@ +35 +20 +15 +25 +47 +40 +62 +55 +65 +95 +102 +117 +150 +182 +127 +219 +299 +277 +309 +576 diff --git a/d10/input.txt b/d10/input.txt new file mode 100644 index 0000000..f8eeb97 --- /dev/null +++ b/d10/input.txt @@ -0,0 +1,94 @@ +38 +23 +31 +16 +141 +2 +124 +25 +37 +147 +86 +150 +99 +75 +81 +121 +93 +120 +96 +55 +48 +58 +108 +22 +132 +62 +107 +54 +69 +51 +7 +134 +143 +122 +28 +60 +123 +82 +95 +14 +6 +106 +41 +131 +109 +90 +112 +1 +103 +44 +127 +9 +83 +59 +117 +8 +140 +151 +89 +35 +148 +76 +100 +114 +130 +19 +72 +36 +133 +12 +34 +46 +15 +45 +87 +144 +80 +13 +142 +149 +88 +94 +61 +154 +24 +66 +113 +5 +73 +79 +74 +65 +137 +47 diff --git a/d10/main.go b/d10/main.go new file mode 100644 index 0000000..9fe8c8a --- /dev/null +++ b/d10/main.go @@ -0,0 +1,217 @@ +package main + +import ( + "bufio" + "fmt" + "log" + "math" + "os" + "sort" + "strconv" +) + +func processLines(path string, f func(string) (stop bool, err error)) error { + file, err := os.Open(path) + if err != nil { + return err + } + defer file.Close() + scanner := bufio.NewScanner(file) + for scanner.Scan() { + stop, err := f(scanner.Text()) + if stop || err != nil { + return err + } + } + if err := scanner.Err(); err != nil { + return err + } + return nil +} + +func part1() { + values := []int{} + if err := processLines("input.txt", func(line string) (bool, error) { + v, err := strconv.Atoi(line) + values = append(values, v) + return false, err + }); err != nil { + log.Fatal(err) + } + + sort.Ints(values) + + lastVal := 0 + ones := 0 + threes := 0 + for _, v := range values { + diff := v - lastVal + switch diff { + case 1: + ones++ + case 2: + case 3: + threes++ + default: + log.Fatalf("unsupported distance: %d-%d=%d", v, lastVal, diff) + return + } + lastVal = v + } + // Final devices is a 3 jolt diff + threes++ + + fmt.Printf("Total ones %d total threes %d. Product %d\n", ones, threes, ones*threes) +} + +var memoized = map[int][][]int{} + +func searchSlice(s []int, start int) [][]int { + // Check for memoized results + if memResults, ok := memoized[start]; ok { + fmt.Printf("Cached value for index %d", start) + return memResults + } + // Check for a memoized result + // If at the end, return an empty array + lastVal := s[start] + if start == len(s)-1 { + // fmt.Println("At end! Yay!") + return [][]int{[]int{lastVal}} + } + fmt.Printf("Checking index %d value %d\n", start, lastVal) + results := [][]int{} + for i := 1; i <= 3 && start+i < len(s); i++ { + v := s[start+i] + if v-lastVal > 3 { + // Not valid, skip this + continue + } + subResults := searchSlice(s, start+i) + for _, subResult := range subResults { + subResult = append([]int{lastVal}, subResult...) + results = append(results, subResult) + } + } + // memoize the results + memoized[start] = results + return results +} + +var memoizedC = map[int]int{} + +func searchSliceC(s *[]int, start int) int { + // Check for memoized results + if memResultsC, ok := memoizedC[start]; ok { + // fmt.Printf("Cached value for index %d", start) + return memResultsC + } + // Check for a memoized result + // If at the end, return an empty array + lastVal := (*s)[start] + if start == len(*s)-1 { + // fmt.Println("At end! Yay!") + return 1 + } + fmt.Printf("Checking index %d value %d\n", start, lastVal) + results := 0 + for i := 1; i <= 3 && start+i < len(*s); i++ { + v := (*s)[start+i] + if v-lastVal > 3 { + // Not valid, skip this + continue + } + results += searchSliceC(s, start+i) + + } + // memoize the results + memoizedC[start] = results + return results +} + +func part2() { + values := []int{} + if err := processLines("input.txt", func(line string) (bool, error) { + v, err := strconv.Atoi(line) + values = append(values, v) + return false, err + }); err != nil { + log.Fatal(err) + } + + values = append([]int{0}, values...) + sort.Ints(values) + deviceJolts := values[len(values)-1] + 3 + values = append(values, deviceJolts) + fmt.Println("Total values", len(values)) + + /* + * paths := []int{} + * i := 0 + * for i < len(values) { + * // look ahead + * for l := 3; l > 1; l-- { + * if i+l < len(values) && values[i+l]-values[i] <= 3 { + * // Look ahead is valid + * paths = append([]int{l}, paths...) + * // We only want max, so break out if we found it + * i = i + l + * break + * } + * } + * i++ + * } + * fmt.Println("Paths", paths) + * powTotal := 1.0 + * for _, num := range paths { + * if powTotal == 1.0 { + * powTotal = float64(num) + * } else { + * powTotal = math.Pow(float64(powTotal), float64(num)) + * } + * } + * fmt.Println("Total pow paths", powTotal) + * productTotal := 1 + * for _, num := range paths { + * productTotal = productTotal * num + * } + * fmt.Println("Total product paths", productTotal) + * + * totalOptions := 0 + * i = 0 + * options := []int{} + * for i < len(values) { + * // look ahead + * for l := 3; l >= 1; l-- { + * if i+l < len(values) && values[i+l]-values[i] <= 3 { + * // Look ahead is valid + * totalOptions++ + * options = append(options, l) + * break + * } + * } + * i++ + * } + * fmt.Println("Options", options) + * fmt.Println("Total sum options *2=", totalOptions*2) + * totalProdOptions := 1 + * for _, num := range options { + * totalProdOptions = totalProdOptions * num + * } + * fmt.Println("Total prod options", totalProdOptions) + */ + + fmt.Printf("Looking for device jolts %d\n", deviceJolts) + countResults := searchSliceC(&values, 0) + fmt.Printf("Search found %d results\n", countResults) + + /* + * results := searchSlice(values, 0) + * fmt.Printf("Search found %d results\n", len(results)) + */ +} + +func main() { + part1() + part2() +} diff --git a/d11/input-small.txt b/d11/input-small.txt new file mode 100644 index 0000000..1beaede --- /dev/null +++ b/d11/input-small.txt @@ -0,0 +1,10 @@ +L.LL.LL.LL +LLLLLLL.LL +L.L.L..L.. +LLLL.LL.LL +L.LL.LL.LL +L.LLLLL.LL +..L.L..... +LLLLLLLLLL +L.LLLLLL.L +L.LLLLL.LL diff --git a/d11/input.txt b/d11/input.txt new file mode 100644 index 0000000..d5e50bd --- /dev/null +++ b/d11/input.txt @@ -0,0 +1,98 @@ +LLLLLL.LLLLLLLLLLLL.LLLLLL.LLLLLLLLLLLL.LLLLLLLLLLLLL.LLLLLLLLLLLLLLLLLLLLLLLLL.LLLLLLLL.LLLLLLLLL +LLLLLL.LLLLLLLLLLLL.LLLLLLL.LLLLL.LLLLL.LLLLLLLLLLLLLLLLLLLLL.LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL.LL +LLLLLLLLLLLLL.LLLLLLLLLLLLL.LLLLL.LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL.LLLLLLLL.L.LLLLLL.LL.LLLLLL +LLLLLLLLLLLLL.LLLLL.LLLLLLLLLLLLLLLLL.LLLLLLLLLL.LLLL.LLLLLLL.LLLLLLLLLLLLLLLLL.LLLLLLLL.LLLLLLLLL +LLLLL..LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL.LLLLLLLL.LLLL.LLLLLLL.LLLLL.LL.LLLLLLLLLLLLLL.LL.LLLLLLLLL +LLLLLL.LLLLL..LLLLL.LLLLLLL.LLLLL.LLLLLLLL.LLLLLLLLLLLLLLLLLLLLLLLLLLL.LLLLLLL.LLLLLLLLL.L.LLLLL.L +LLLLLL.LLLLLL.LLL.L.LLLLLLL.LLLLL.LLLLL.LLLLLLLL.LLLL.LLLLLL..LLLLLLLL.LLLLLLLL.LLLLLLLLLLLLLL.LLL +.LLLLLLLLLLLL.LLL.L.LLLLLLLLLLLLLLLLLLL.LLLLLLLL.LLLLLLLLLLLL.LLLLLL.L.L.LLLLLLLLLLLLL.L.LLLLLLLLL +LLLLLL.LLLLLL.LLLLL.LLLLLLL..LLLLLLLLLL..LLLLLLL.LLLLLLLLLLLL.LLLLLLLL.LLLLLLLL.LLL.LLLL..LLLLLLLL +..........LL....L..LL..L.....L...L....L............L.LL...L.......L.L.LL...L.L...L....L.L....LLL.. +LLLLLL.LLLLLL.LLLLL.LLLLLLL.LLL.L.LLLLL.LLLLLLLLLLLLLLLLLLLLL.LLLLLLLLLLLLL.LL..LLLLLLL.LLLLLLLLLL +LLLLLLLLLLLLL.LLLLL.LLLLLLL.LLL.L.LLLLLLLLLLLLLL.LLLL.LLLLLLL.LLLLLLLL.LLLLLLLL.LLLLLLLLLLLLLL.LLL +.LLLLL..LL.LL..LLL.LLLLLLLL.LLLLL.LLLLL.LLLLLLLLLLLLL.LLLLLLL.LLLLLLLLLLLLLLLLL.LLLLLLLLLLLLLLLLLL +L.LLLL.LLL.LLLLLLLL.LLLLLLL.LLLLL.LLLLLLLLLLLLLLLLLLL.LLL.LLL.LLLLLLLL.LLLLLLLL.LLLLLLLLLLLLL.LLLL +LLLLLL.LLLLLLLLLLLLLLLLLLLL.L.LLLLLLLLL.LLLLLLLLLLLLLLLLLLLLL.LLLLLL.L.LLLLLLLL.LLLLLLLL.LLLLLLLLL +LLLLLL.LLLLLLLLLLLL.LLLLLLLLLLLLL.LLLLL.LLLLLLLL.LLLL.LLLLLLL.LLLLLL.L.LLLLLLLL.LLLLLLLL.LLLLLLLLL +...LLLLL.......L.LL..L..LL...LL..L.....L...L...LLL.L.L.....L.L....L.L......LL..L.L.L..LL.L.....LL. +LLLLLLLLLLL.L.LLL.LLLLLLLLL.LLLLLLLLLLL.LLLLLLLL.LLLL.LLLLLLLLLLLLLLLL.LLLLLL.L.LL.LLLLLLLLLLLLLLL +LLLLLL.LLLLLL.LLLLL.LLLLLLL.LLLLL.LLLLL.LLLLLLLLLLLLL.LLL.LLL.LLLLLLLL.LLLLLLLL..LLLLLLLLLLLLLL.LL +LLLLLL.LLLLLLLLLLLL.LLLLLLL.LLLLL.LLLLLLLLLLLLLLLLLLL.LLLLL.L.LLLLLLLLLLLLLLLLL.LLLLLLLL.LLLLLLLLL +LLLLL..LL.L.LLLLLLL.LLLLLLL.LLLLL.LLLLLLL.LLLLLLLLLLL.LLLLLLLLLLLLLLLLLLLLLLL.L.LLLLLLLL.LLLLLLLLL +LLLLLL.LLLLLL.LLLLL.LLLLLLL.LLLLLL.LLLL.LLLLLLLL.LLLL.LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL.L.LLLLLLLLL +L.LLLL.LLLLLL.LLLLL.LLLLLLL.LLLLL.LLLLL.LLLLLLLL.LLLL.LLLL.LL.LLLLLLLLLLLLLLLLL.LLLLLLLL.LLLLLLLLL +.LLLLL.LLLLLL.LLLLL.LLLLLLL.LLLLL.L.LLL.LLLLLLLL.LLL..LLLLLLL.LL.LLLLL.LLLLLLLLLLLLLLLLL.LLLLLLLLL +LLLLLL.LLLLLL.LLLLL.LLLLLLLLLLLLLLLLLLLLLLLLLLLL.LLLL.LLLLLLLLLLLLLLLL.L.LLLLLL.LLLLLLLLLLLLLLLLL. +L.LL..LLL.L.........L.L....L...LL.L......L..LL.......L.....L.LL.....L..L.L.....L.....L.L...L.L.... +LLLLLL.LLLLLLLLLLLL.LLLLLLL.LLLLL..LLLL..LLLLLLLLLLLL.LLLLLLL.LLLLLLLLLLLLLLLLLLLLLLLLLLLLLL.LLLLL +LLL.L..LLLL.L.LLLLLLLLLLLLL.LLLLL.LLLLL.L.LLLLLLL.LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL..LLLLLLLL +LLLLLL.LLLLLL.LLLL.LLLLLLLL.LLLLLLLLLLLLLLLLLLLL.LLLL.LLLLLLL..LLLLLLL.LLLLLLLLLLLLLLLLL.LLLLLLLLL +LL.LLLLLLLLLLLLLLL..LLLLLLLLLLLL..LLLLLLLLL.LLLLLLLLL.LLLL.LLLLLLLLLLLLLLLLLLLLLLLLLLL.L.LLLLLLLLL +LLLLLL..LLLLLLLLLLLLLLLLL.L.LLLLLLLLLLL.LLLLLLLL.LLLL.LLLLLLLLLLLLLLLL.LLLLLLLL.LLLLLLLL.LLLLLLLLL +..L...L...L..L..LL...L..........L.....L......L....L.L..L.L.L..L.LL....L..L...L...L......L.....L..L +LLLLLLLLLLLL..LLLLL.LLLLLLL.LLLLL.LLLLLLLLLLLLLLLLLLL.LL.LLLLLLLLLLLLL.L.LLLLLL.LLLLLLLL.LLLLLLLLL +LLLLLLLLLLLLL.LLLLL.LLLLLLL.LLLLL.LLLLL.LLLLLLLL.LLLL.L.LLLLL.LLLLLLLLLLLLLLLLL..LLLLLLL.LLLLLLLLL +LLLLLLLLLLLLL.LLLLLLLL.LLLL.LLLLL.LLLLLLLLLLLLLL.LLLL.LLLLLLLLL.LLLLLL.LLLLLL.LLLLLLLLLL.LLLLLLLLL +LLLLLLLLLLLLL.LLLLL.LLLLLLLLLLLLL.LLLLLLLLLLLLLLLLLLLLLLLLLLL.LLL.LLLL.LLLLLLLL.LLLLL.LLLLLLLLLL.L +LLLLLLLLLLLLL.L.LLL.LLLLLLL.LLLLL.LLLLL.LLLL.LLLLLLLL.LLLLLLLLLLLLLLLLLLLLL.LLL.LLLLLLLL.LLLLLLLLL +LLLLLL.LLLLLLLLLLLL.LLLLLLL.LLLLL.LLLLL.LLLLLLLLLLLLL.LLLLLLL.LLLLLLLL.LLLLLLLL.LLLLLLL..LLLLLLLLL +LLL..L..LLLL.LLL.L......L...LL.L..L.L...L...LL....L.L.L.L................L....L..L...L......LLL.L. +LLLLLLLLLLLLL.LLLLLLLLLLLLL.LLLL..LLLLL.LLLLLLLL.LLLL.LLLLLLL.LLLLLLLL..LLLLLLL.LLLLLLLLLLLLLLLLLL +LLLLLL.LLLLLL.LLLLLLLLLLLLLLLL.LLLLLLLL.LLLLLLLLLLLLLLLLLL.LL.LLLLLLLL.LLLLLL.LLLLLLLLLL.LLLLLLLLL +.LLLLL.LLLLLL.LLLLL.LLLLLLLLLLLLL.LLLLLLLLLLLLLL.LLLL.LLLLLLL.LLLLLLLL.LLLLLLLL.LLLLLLLL.LLLL.LLLL +LLLLLLLLLLLLL.LLLLLLLLLLLLL.LLLLLLLLLLL.LLLLLLLL.LLLLLLLLLLL..LLLLLLLL.LLLLLLLL.LLLLLLLL.L.LLLLLLL +LLLLLLLLLLLLL.LLLLL.LLLLLLL.LLLLLLLLLLLLLLLLLLLL.LLLL.LLLLLLLLLLLLLLLL.LLLLL.LL.LLLLLLLLLLLLLLLLLL +LLLLLL.LLLLLL.LLLLL.LLLL.LL.LLLLL.LLLLL.LLLLLLLL..LLL.LLLLL.L.LLLLLLLLLLLLLLLLL.LLL.LLLL.LLLLLLLLL +LL.LLL.LLLLLL.LLLLL.LLLLLLLLLLLLL.LL.LLLLLLLLLLL.LLLLLLLLLLLL.LLLLLLLL.LLL.L.LL.LLLLLLLLLLL.LLLLLL +LLLLLLLLLLLLL.LLLLL..LLLLLLLLLLLLLLLLLL.L.LLLLLL.LLLL.LLLLLLL.LLLLLLLLL.LLLLLLLLLLLLLLLL.LLLLLLLLL +.LLLLL..L.L.L...L...L..LL.L.L.LL.L...L.L.L...................LL..L...L......L..L.........L.....LL. +LLLL.LLLLLLLL.LLLLL.LLLLLLL.LLLLLL.LLLLLLLLLLLLL.LLLL.L.LLLLL.LLLLLLLLLLLLLLLLL.LLLLLLLL.LLLLLLLLL +LLLLLL.LLLLLL.LLLLLL.L.LLLL.LLLLL.LLLLLLLLLLLLLL.LLLL.LLLLLLLLLLLLLLLL.LLLLLLLL.LLLL.LLL.LL..LLLL. +.LLLLL.LLLLLLLLLLLL.LLLL.LLLLLLLL.LLLLLLLLLLLLLL.L.LLLL.LLLLLLLLLLLLLL.LLLLLLL..LLLLLLLL.LLLLLLLLL +LLLLLL.LLLLLL.LLLLL.LLLLLLL.LLLL...LLLLL.LLLLLLL.LLLL.LLLLLL..LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL +LLLLLLLLLLLLLLLLLLL.LLLLLLLLLLLLLLLLLLL.LLL.LLLLLLLLL.LLLLLLL.LLLLLLLL..L.LLLLL.LLLLLLLL.LLLLLLLLL +LLLLLLLLLLLLL.LLLLLLLLLLLLL.LLLLLLLLLLL.LLLLLLLLLLLLL.LLLLLLL.LLLLLLLL.LLLLLLLL.LL.LLLLLLLLLLLLLL. +LLL.LL.LLLLLL.LLLLL.LLLLLLL.LLLLLLLLLLL.LLLLLLLL.LLLLLLLLLLLLLLLLLLLLL.LLLLLLLLLLLLLLLLLLLLLLLLLLL +LLLLLL.LLLLLL.LLLLLLLLLLLLL.LLLLLLLL.LLLLLLLL.LL.LLLL.LLLLLLL.LLLLLLLL.LLLLLLLLLLLLLLLLLLLLLLLLLLL +LLLLLL.LLL..L.LLLLL.LLLLLLLLLLLLLLLLL.L.LLLLLLLLLLLLL.LLLLLLL.LLLLLLLL.LLLLLLLL.LLLLLLLL.LLLLLLLLL +L.LL.L.L...L.LL.L.LLL...L.......LLL.L.LL..LLLL.L.L...L..LL.L..LL..L.L..LLLL.L.L..L.L....L....L...L +LLLLLL.LLLLLLLLLLLL.LLLLLLL.LLLLL.LLLLL.LLLLLLLL.LLLL.LLLLLLL.LLLLLLLLLLLLLLLLL.LLL.LLLL.L.LLLLLLL +LLLLLL.LLLLLLLLLLLLLLLLLLLL.LLLLL.LLLLLLLLLLLLLLLL.LL.LLLLLLLLLLLLLLLL.LLLLLLLLLLLLLLLLL.LLLLLLLLL +LLLLLL.L.LLLL.LLLLL.LLL.LLL.LLLLLLLLLLLLL.LLLLLLLLLLL.LLLLLL..LLLLLLLL.LLLLLLLL.LLLLLLLL.LLLLLLLLL +LLLL.LLLLLLLL.LLLLL..LLLLLLLLLLLL.LL.LL.LLLLLLLLLLLLL.LLLLLLL.LLLLLLLL.L.LLLLLL.LLLLLLLLLLLLLLLLLL +LLLLLL.LLLLLLLLLLLLLLLLLLLL.LLLLLLLLLLL.LLLLLLLLLLLLL.LLLLLLL.LLLLLLLL.LLLLLLLL..LLLLLLL.LL.LLLLLL +LLLLLL.LLLLLLLLLLLL.LLLLLLLLLLLLL.LLLL..LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL.LLLLLLLL.LLL.LLLLL +L.L..L................L..LL.....LL...L............L....LL..LL.LLL.L.............L..L...L.....LLL.. +LLLLLLLLLLLLLLLL.LL.LLLLLLL.LLLLL.LLLLLLLLLLLLLLLLLLL.LLLLLLL.LLLLLLLLLLLLLLLLL.LLLLLLLL.LLLLLLLLL +LLLLLL.LLLLL.LLLLLL.LLLLLLL.LLLLL.LLL.LLLLLLLLLL.LLLL.LLLLLLL.LLLLLLLL.LLLLLLLL.LLLLLLLL.LLLLLLLL. +LLLLLL.LLLLLLLLLLLLLL.LLLLL.LLLLL.LL.LL.LLLLLLLL.LLLL.LLLLLLL.LL.LLLLL.LLLLLLLLLLLLLLLLL.LLLLLLLLL +LLLL.LL.LLLLL.LLLLL.LLLLLLL.LLLLL.LLLLL.LLLLLLLL.LLLL.LLLLLLL.LLLLLLLLLLLLLLLLL.LLLLLLLL.LLLLLLLLL +LLLLLL.LLLLL..LLLLL.LLLLLLL.LLLLLLLLLLLLLLLLLLLL.LLLL.LLLLLLL.LLL.LLLL.LLLLLL.L.LLLLLLLL.LLLLLLLLL +L.L..L...LL.L.....LL..LL.L.....L.L..L....L..L.L...L.LLLL....L...LL......L..L....LL..L..L........LL +LLLLLLLLLLLLLLLLLLL.LLLL.LL.LLLLLLLLLLL.LLLLLLLLLLLLL.LLLLLLLLLLLLLLLL.LLL.LLLL.LLLLLLLL.LLLLL.LLL +LLLLLLLLLLLLL.LLLLL.LLLLLLL.LLLLLLLL.LL.LLLLLL.LLLLLL.LLLLLLL.LLLLLLLL.LLLLLLLLLLLLLLLLLLLLLLLLLLL +LLLLLL.LLLLL.LLLLLL.LLLLLLL.LLLLLLLLLLL..LLLLLLL.L.LL.LLLLLLL.LLLLLLLL.LLLLLLLLLLLLLLLL..LLLLLLLLL +LLLLLL.LLLLLLLLLLLL.LLLLLLL.LLLLL.LLLLL.LLLLLLLLLLLLLLLLLLLLL.LLLLLLLL.LLL.LLLL.LLLLLLLL.LLLLLLLLL +LLLLLL.LLLLLLLLLLLLLLLLL.LL.LLLLL.LLLLLLLLLLLLLLLL.LLLLLLLLLL.LLLLLLLL.LLLLLLLL.LLLLLLLL.LLLLLLLLL +LLLLLL.LLLL.L.LLLLLLLLLLLLL.LLLLLLLLL.L.LLLLLLLL.LLLL.LLLLLLL.LLLLLLLL.LLLLLLL..LLLLLLLL.LLLLLLLLL +LLLLL..LLLL.L.LLLLL.LLLLLLLLLLLLL.LLLLL.LLLLLLLL.LLLLLLLLLLLL.LLLLLLLLLLLLLLLL..LLLLLLLL.LLLLLLLLL +L.LLLLLLLLLLLLLLLLL.LLLLLLL.LL.LL.LLLLL.LLLLLLLLLLLLL.LL.LLLLLLLLLLLLLLLLLLLLLL.LLLLLLLL.LLLLLLLLL +LL.L......L......L...L..LLL.....L.L..L.L...L......L..L..L.....L...LL.L.LL.L.LLL....L.LLL....L..L.. +LLLLLLLLLL.LLLLLLLLLL.LL.LL.LLLLLLLLLLL.L..LLLLL.LLLL.LLLLLLL.LLLLLLLL.LLLLLLLL.LLLLLLLL.LLLLLLLLL +LLLLLL.LLLLLL.LLLLL.LLLLLLL.LLLLL.LLLLL.LLLLL.LL..LLL.LLLLLLL.LLLLLLLLL.LLLLLLL.LLLLLLLL.LLLLLLLLL +LLLLLL..LL.LL.LLLLL.LLLLLLL.L.LLLLLLLLL.LLLLLLLL.LLLLLLLL.LLL.LLL.LLLL.LLLLLLLLLLLLLLLL..LLLLLLLLL +LLLLLLLLLLL.LLLLLLL.LLL.LLLLLLLLL.LLLLL.LLLLLLLL.LLLLLL.LLLLLLLLLLLLLL.LLLLLLLL.LLLLLLLL.LLLLLLLLL +LLLLLLLLLLL.L.LLLLL.LLLLLLL.LLLLL.LLLLL.LLLLLLLL.L.LLLLLLLLLLL.LLLLLLL.LLLLLLLL.LLLLLLLL.LLLLLLLLL +LLLLLL.LLLLLL..LLLL.LLLLLLLLLLLLLLLL.LL.LLLL.LLL.LLLL.LLLLLLL.LLLLLLLL.LLLLLLLL.LLLLLLLL.LLLLLLLLL +LLLLLLLLLLLLLLLLLLL.LLLLLLL.LLLLLLLLL.L.L.LLLLLL.LLLLLLLLLLLL.LLLLLLLLLLLLLLLLL.LLLLLLLL.LLLLLLLLL +LLLLLL.LLLLLLLLLLLL.LLLLLLL.LLLLLLLLLLL.LLLLLLLLLL.LLLLLLLLLLLLLLLLLLL.LL.LLLLLLLLL.LLLLLLL.LLLLLL +L..L.LL......LLL....LLLL.......L.L..L..L....LLLLL..LLLLL..L..L.L.L........LLL...LL.L......LLL..... +LLLLLL.LLLLLLLLLLLLLLLLLLLL.LLLL..LLLLLLLLLLLLLLLLLLL.LLLLLLLLL.LL.LLL.LLLLLLLL.LLLLLLLL.LLLLLLLLL +LLLLLL.LLLLLL.LLLLL.LLLLLLL.LLLLLLLLLLL.LLLLLLLL.LLLLLLLLLLLL.LLLLLLLL.LLLLLLLL.LLLLLLLL.LLLLLLLLL +LLLLL.LLLL.LLLLLLLL..LLLLLL.LLLLL.LLLL...LLLLL.L.LLLL.LLLLLLL..LLLLLLLL.LLLLLLLLLLLLLLLL.LLLLLLLLL +LLLLLLLLLLLLL.LLLLL.LLLLLLL.LLLLL.LLLLLL.LLLLLLLLLLLL.LLLLLLLLLLLLLLLLLL.LLLLLL.LLLLLLLL.LLLLL.LLL +LLLLLLLLLLLLL.LLLLL.L.LLLLL.LLLLLLLLLLL.LLLLLLLLLL.LL.LLLLLLLLLL.LLLLL.LLLLLLLL.LLLLLLLLLLLLL.LLLL +LLLLL.LLLLLLLLLLLLL.LLLLLLL.LLLLL.LLLLL.LLLLLLLL.LLLL.LLLLLLL.LLLLLLLLLLLLLLLLLLLLLLLLLL.LLLLLLLLL +LLLLLL.LLLLLL.LLLLL.LLLLLLL.LLLLL.LLLLL.LLLLLLLL.LLLL.LLLLLLL.LLLLLLLL.LLLLLLLL.LLLLLLLL.LLLLLLLLL +LLLLLL.LLLLLL.LLLLL.LLLLLLL.LLLLL.LLLLLLLLLLLLLLLLLLL.LLLLLLL.LLLLLLLL.L.LLLLLL.LLLLLLLLLLLLLLLLL. +LLLLLLLLLLLLLLLLLLLLLLLLLLL.LLLLLLLLLLL.LLLLLLLL.LLLL.LLLLL.LLLLLLLLLLLLLLLLLLLLLLLLLLLL.LLLLLLLLL diff --git a/d11/main.go b/d11/main.go new file mode 100644 index 0000000..838ed6c --- /dev/null +++ b/d11/main.go @@ -0,0 +1,463 @@ +package main + +import ( + "bufio" + "fmt" + "log" + "os" +) + +func processLines(path string, f func(string) (stop bool, err error)) error { + file, err := os.Open(path) + if err != nil { + return err + } + defer file.Close() + + scanner := bufio.NewScanner(file) + for scanner.Scan() { + stop, err := f(scanner.Text()) + if stop || err != nil { + return err + } + } + + if err := scanner.Err(); err != nil { + return err + } + + return nil +} + +var ( + emptySeatCode = 'L' + occupiedSeatCode = '#' + floorCode = '.' + printMaps = false + + // Variables for controlling part 1 and part 2. + maxOccupied = 4 + lookVisible = false +) + +type point struct { + x, y int +} + +type square struct { + seat bool + occupied bool + loc point + left *square + right *square + up *square + down *square + + tock func() error +} + +func (s square) isAvailable() bool { + return s.seat && !s.occupied +} + +func (s square) hasPerson() bool { + return s.seat && s.occupied +} + +func (s *square) sit() error { + if !s.seat { + return fmt.Errorf("cannot sit on the floor") + } + + if s.occupied { + return fmt.Errorf("someone is already sitting here") + } + + s.occupied = true + + return nil +} + +func (s *square) leave() error { + if !s.seat { + return fmt.Errorf("cannot leave from the floor") + } + + if !s.occupied { + return fmt.Errorf("nobody is here to leave") + } + + s.occupied = false + + return nil +} + +func (s *square) setLeft(l *square) { + if l.right != nil { + log.Fatalf( + "cannot set square above %v to %v because %v already has %v below it", + s.loc, l.loc, l.loc, l.right.loc, + ) + } + + s.left = l + l.right = s +} + +func (s *square) setUp(u *square) { + if u.down != nil { + log.Fatalf( + "cannot set square above %v to %v because %v already has %v below it", + s.loc, u.loc, u.loc, u.down.loc, + ) + } + + s.up = u + u.down = s +} + +func (s *square) leftUp() *square { + if s.left != nil { + if s.left.up != nil { + return s.left.up + } + } + + return nil +} + +func (s *square) upRight() *square { + if s.up != nil { + if s.up.right != nil { + return s.up.right + } + } + + return nil +} + +func (s *square) rightDown() *square { + if s.right != nil { + if s.right.down != nil { + return s.right.down + } + } + + return nil +} + +func (s *square) downLeft() *square { + if s.down != nil { + if s.down.left != nil { + return s.down.left + } + } + + return nil +} + +func (s *square) lookLeft() *square { + n := s.left + if n != nil && !n.seat { + return n.lookLeft() + } + + return n +} + +func (s *square) lookRight() *square { + n := s.right + if n != nil && !n.seat { + return n.lookRight() + } + + return n +} + +func (s *square) lookUp() *square { + n := s.up + if n != nil && !n.seat { + return n.lookUp() + } + + return n +} + +func (s *square) lookDown() *square { + n := s.down + if n != nil && !n.seat { + return n.lookDown() + } + + return n +} + +func (s *square) lookLeftUp() *square { + n := s.leftUp() + if n != nil && !n.seat { + return n.lookLeftUp() + } + + return n +} + +func (s *square) lookUpRight() *square { + n := s.upRight() + if n != nil && !n.seat { + return n.lookUpRight() + } + + return n +} + +func (s *square) lookRightDown() *square { + n := s.rightDown() + if n != nil && !n.seat { + return n.lookRightDown() + } + + return n +} + +func (s *square) lookDownLeft() *square { + n := s.downLeft() + if n != nil && !n.seat { + return n.lookDownLeft() + } + + return n +} + +func appendNonNil(s []*square, e *square) []*square { + if e != nil { + return append(s, e) + } + + return s +} + +func (s *square) visibleSeats() []*square { + result := []*square{} + result = appendNonNil(result, s.lookLeft()) + result = appendNonNil(result, s.lookRight()) + result = appendNonNil(result, s.lookUp()) + result = appendNonNil(result, s.lookDown()) + result = appendNonNil(result, s.lookLeftUp()) + result = appendNonNil(result, s.lookUpRight()) + result = appendNonNil(result, s.lookRightDown()) + result = appendNonNil(result, s.lookDownLeft()) + + return result +} + +func (s *square) adjacentSeats() []*square { + result := []*square{} + result = appendNonNil(result, s.left) + result = appendNonNil(result, s.right) + result = appendNonNil(result, s.up) + result = appendNonNil(result, s.down) + result = appendNonNil(result, s.leftUp()) + result = appendNonNil(result, s.upRight()) + result = appendNonNil(result, s.rightDown()) + result = appendNonNil(result, s.downLeft()) + + return result +} + +func (s *square) tick() bool { + // Noop tock function + s.tock = func() error { return nil } + + if !s.seat { + return false + } + + var seats []*square + + if lookVisible { + seats = s.visibleSeats() + } else { + seats = s.adjacentSeats() + } + + if s.isAvailable() { + // Check adjacent seats + for _, adj := range seats { + if adj.hasPerson() { + // If any adjacent seat is occupied, do nothing + return false + } + } + // Nothing is occupied? Sit! + s.tock = s.sit + + return true + } + + if s.hasPerson() { + numOccupied := 0 + + for _, adj := range seats { + if adj.hasPerson() { + numOccupied++ + } + } + + if numOccupied >= maxOccupied { + s.tock = s.leave + + return true + } + } + + return false +} + +func (s square) String() string { + // return fmt.Sprintf("%v", s.loc) + if !s.seat { + return "." + } + + if s.occupied { + return "#" + } + + return "L" +} + +func readMap() *[][]*square { + worldMap := [][]*square{} + rowIndex := 0 + + if err := processLines("input.txt", func(line string) (bool, error) { + // fmt.Printf("New line! %d\n", rowIndex) + row := []*square{} + var leftSeat *square + for i, c := range line { + var s square + switch c { + case emptySeatCode: + s = square{loc: point{i, rowIndex}, seat: true} + case occupiedSeatCode: + s = square{loc: point{i, rowIndex}, seat: true, occupied: true} + case floorCode: + s = square{loc: point{i, rowIndex}, seat: false} + default: + return false, fmt.Errorf("unknown square value %x", c) + } + // fmt.Printf("%v", s.loc) + if leftSeat != nil { + s.setLeft(leftSeat) + } + if rowIndex > 0 { + up := worldMap[rowIndex-1][i] + // fmt.Printf("\nTry set above %d,%d to %d,%d ", i, rowIndex, up.loc.x, up.loc.y) + s.setUp(up) + } + + leftSeat = &s + row = append(row, &s) + } + // fmt.Println(row) + worldMap = append(worldMap, row) + // fmt.Printf("\n") + rowIndex++ + + return false, nil + }); err != nil { + log.Fatal("could not parse map", err) + } + + return &worldMap +} + +func printMap(worldMap *[][]*square) { + for _, row := range *worldMap { + for _, s := range row { + fmt.Print(s.String()) + } + + fmt.Print("\n") + } +} + +func tickMap(worldMap *[][]*square) bool { + worldChanged := false + + for _, row := range *worldMap { + for _, s := range row { + worldChanged = s.tick() || worldChanged + } + } + + return worldChanged +} + +func tockMap(worldMap *[][]*square) error { + for _, row := range *worldMap { + for _, s := range row { + err := s.tock() + if err != nil { + return err + } + } + } + + return nil +} + +func countOccupied(worldMap *[][]*square) int { + occupied := 0 + + for _, row := range *worldMap { + for _, s := range row { + if s.hasPerson() { + occupied++ + } + } + } + + return occupied +} + +func run() { + worldMap := readMap() + + if printMaps { + fmt.Println("Time 0") + printMap(worldMap) + } + + var err error + + t := 1 + changed := true + + for changed { + changed = tickMap(worldMap) + + err = tockMap(worldMap) + if err != nil { + log.Fatal(err) + } + + if printMaps { + fmt.Printf("\nTime %d (%t)\n", t, changed) + printMap(worldMap) + } + t++ + } + fmt.Printf("\nTotal %d occupied seats after %d iterations\n", countOccupied(worldMap), t) +} + +func main() { + // Part 1 + run() + + // Part 2 + maxOccupied = 5 + lookVisible = true + + run() +} diff --git a/d12/input.txt b/d12/input.txt new file mode 100644 index 0000000..8c0435e --- /dev/null +++ b/d12/input.txt @@ -0,0 +1,779 @@ +S3 +W3 +F47 +L90 +W1 +F42 +N1 +R90 +F7 +R90 +E2 +S1 +W2 +F11 +E4 +N1 +F77 +W1 +S3 +W4 +F64 +W3 +R180 +N5 +E1 +F8 +N1 +F54 +N2 +L180 +N1 +F44 +E2 +N2 +L90 +W3 +F5 +W2 +L180 +F100 +N3 +E1 +W4 +N5 +F40 +R180 +W5 +R90 +N1 +W3 +R270 +N1 +R90 +S5 +F10 +E4 +N4 +F56 +E3 +N4 +W4 +R90 +N3 +F24 +F58 +R90 +N2 +R90 +W5 +S2 +R90 +W3 +R90 +W1 +N3 +R90 +N4 +E2 +F25 +N5 +N4 +L90 +E5 +N4 +R90 +N1 +R90 +F73 +W1 +S3 +W4 +W1 +F28 +W3 +E2 +S3 +F28 +S3 +R270 +E1 +S2 +W3 +S3 +L90 +F56 +E5 +L180 +R90 +F48 +N2 +F75 +S2 +E5 +F21 +F57 +N5 +L90 +E4 +N4 +F14 +S3 +F75 +W5 +L90 +E3 +R90 +N1 +W4 +F4 +W5 +S3 +E3 +F68 +N3 +R90 +W4 +N5 +S3 +F4 +R90 +F48 +R90 +F93 +R90 +S3 +F90 +R90 +F41 +N2 +S1 +E5 +F19 +E3 +F71 +R180 +F16 +W3 +N4 +W3 +F12 +L180 +L90 +R180 +W4 +R90 +F26 +W1 +E4 +F65 +L90 +F90 +W5 +S4 +W1 +E3 +L90 +W3 +N2 +F77 +W2 +L90 +E4 +S2 +W5 +F60 +R90 +F45 +R90 +S3 +F56 +W2 +S3 +W5 +F58 +L90 +N1 +F94 +S4 +F17 +W5 +R180 +S2 +R90 +N4 +W1 +S3 +R180 +F93 +R90 +F45 +E4 +R90 +S1 +F81 +E2 +L90 +S1 +F63 +E2 +R90 +E2 +N1 +W1 +L90 +F91 +S5 +L270 +E3 +S1 +F29 +N4 +R180 +F44 +L90 +E3 +L90 +F90 +R90 +F93 +N2 +S2 +F28 +E1 +F58 +N1 +F9 +L90 +S1 +F74 +N2 +F19 +L180 +S3 +E1 +R90 +F55 +S3 +L90 +F58 +S1 +R90 +E4 +F42 +S5 +R90 +S4 +L90 +S1 +E3 +F75 +L90 +F44 +E2 +F50 +S2 +N4 +W2 +F14 +W2 +N2 +F14 +S1 +W4 +F74 +L90 +F52 +W3 +S5 +L90 +W5 +N3 +L90 +F54 +S1 +R90 +E3 +R90 +F23 +S4 +F75 +N5 +R90 +F79 +R90 +F70 +N2 +F89 +W1 +S5 +E2 +F44 +L180 +W5 +R90 +F72 +R90 +N3 +W4 +N4 +F90 +R270 +E4 +F43 +W4 +F44 +N5 +F55 +S4 +F68 +S1 +E1 +F39 +W2 +N4 +F46 +W5 +F62 +E1 +R270 +F97 +W4 +L180 +F41 +R90 +W3 +R270 +S1 +E1 +R90 +E2 +F18 +E2 +F12 +R90 +W5 +L90 +E2 +F82 +N3 +E5 +F45 +N5 +F69 +N5 +W1 +R90 +F15 +W1 +S2 +R90 +F50 +S4 +S5 +W2 +S4 +F21 +E5 +L90 +F47 +E1 +F73 +L90 +F4 +R90 +F65 +E2 +S4 +F52 +E1 +N1 +L90 +S1 +F41 +R180 +S2 +F5 +E1 +R90 +N3 +F29 +L90 +F69 +E4 +F92 +R90 +N4 +L180 +W5 +N3 +R180 +W1 +N5 +E5 +F1 +N3 +F19 +W4 +F33 +N2 +R90 +E2 +N3 +F68 +E3 +S1 +R90 +N3 +R180 +E5 +R90 +W1 +R90 +S2 +L90 +F67 +W2 +S4 +R270 +W1 +R90 +F11 +L180 +F83 +R90 +N3 +L90 +W1 +N1 +L90 +F41 +N4 +F45 +S2 +W4 +S4 +F92 +E3 +F21 +R180 +W4 +S1 +N3 +R90 +N2 +L90 +F97 +N4 +F99 +F78 +E2 +S3 +W1 +N4 +N1 +E1 +L180 +F32 +S1 +F84 +L90 +S3 +L90 +E3 +R90 +F62 +N4 +L90 +E2 +R90 +F68 +S4 +F29 +E5 +S5 +R180 +S1 +F15 +W1 +S3 +F65 +L180 +F54 +L90 +W2 +S3 +W2 +F22 +L180 +W5 +R90 +E4 +L90 +F65 +W5 +F82 +S3 +W5 +L90 +F83 +W4 +L90 +E1 +F92 +W4 +N2 +F99 +L90 +E5 +R180 +N5 +W5 +R90 +N3 +F74 +R90 +N1 +F26 +S3 +W2 +N2 +E3 +L90 +F75 +R90 +F12 +W3 +S5 +L90 +N2 +E4 +F13 +E1 +F44 +N3 +R90 +E5 +R90 +W4 +F4 +W5 +N3 +W3 +F40 +L180 +W3 +N2 +E3 +F57 +W1 +F16 +S2 +W3 +R90 +W3 +F24 +R90 +F84 +R90 +W2 +R270 +S1 +L180 +F62 +W1 +R180 +F71 +E2 +S2 +R90 +F84 +E2 +F64 +R90 +S5 +F42 +S4 +F37 +E5 +R90 +S2 +R90 +S4 +W1 +R180 +F71 +W3 +F19 +W5 +R180 +F98 +S5 +R90 +N2 +W5 +N5 +F14 +L270 +F29 +L90 +F94 +W4 +F92 +W5 +N4 +F78 +N1 +S3 +F10 +L90 +F72 +R90 +S2 +L180 +N3 +R180 +W3 +F83 +N4 +E5 +N2 +E3 +L90 +E2 +F84 +S4 +R90 +E3 +S4 +F59 +R90 +W1 +R90 +F29 +S4 +W1 +S5 +L90 +F77 +R90 +N4 +F69 +L90 +W5 +F15 +N3 +N1 +L180 +N2 +N4 +W4 +N1 +L180 +W4 +F5 +R180 +E2 +R90 +S2 +R90 +N2 +F49 +L180 +F32 +N5 +R90 +W5 +L90 +E1 +F46 +E1 +L90 +W3 +F69 +N5 +E1 +S3 +L90 +F98 +W2 +L90 +F17 +W3 +N2 +F78 +E5 +W1 +S1 +F73 +S2 +F36 +N5 +E3 +F61 +R90 +E4 +F88 +L90 +E4 +R180 +W4 +S2 +R180 +N2 +F17 +E5 +S5 +E1 +R90 +S3 +L90 +R90 +S4 +F1 +W2 +N1 +W5 +F35 +S2 +F78 +S2 +L90 +W1 +L180 +N4 +F99 +F34 +L90 +N5 +R90 +S4 +L90 +N2 +F72 +E5 +S4 +R180 +S4 +F18 +W1 +L90 +E1 +S4 +E2 +R90 +F62 +L90 +F71 +S1 +F18 +F6 +N1 +F28 +L90 +N1 +F24 +E1 +R90 +S2 +F51 diff --git a/d12/main.go b/d12/main.go new file mode 100644 index 0000000..0a9bc1b --- /dev/null +++ b/d12/main.go @@ -0,0 +1,180 @@ +package main + +import ( + "bufio" + "fmt" + "log" + "math" + "os" + "strconv" +) + +func processLines(path string, f func(string) (stop bool, err error)) error { + file, err := os.Open(path) + if err != nil { + return err + } + defer file.Close() + + scanner := bufio.NewScanner(file) + for scanner.Scan() { + stop, err := f(scanner.Text()) + if stop || err != nil { + return err + } + } + + if err := scanner.Err(); err != nil { + return err + } + + return nil +} + +type ship struct { + // Ship position and heading + e, n, heading int + // Waypoint positions + pe, pn int +} + +func (s *ship) part2(inst string) error { + fmt.Println("Read inst", inst) + c := inst[0] + + amt, err := strconv.Atoi(inst[1:]) + if err != nil { + return err + } + + switch c { + case 'N': + s.pn += amt + case 'S': + s.pn -= amt + case 'W': + s.pe -= amt + case 'E': + s.pe += amt + case 'R': + err = s.rotateWaypoint(amt) + case 'L': + err = s.rotateWaypoint(-amt) + case 'F': + err = s.moveToWaypoint(amt) + default: + err = fmt.Errorf("unknown instruction %s", inst) + } + + fmt.Printf("After move %+v\n", s) + + return err +} + +func (s *ship) moveToWaypoint(amt int) error { + s.n += amt * s.pn + s.e += amt * s.pe + + return nil +} + +func (s *ship) rotateWaypoint(amt int) error { + if amt < 0 { + amt = 360 + amt + } + + for i := 0; i < amt/90; i++ { + s.pe, s.pn = s.pn, -s.pe + } + + return nil +} + +func (s *ship) forward(amt int) error { + switch s.heading { + case 0: + s.n += amt + case 90: + s.e += amt + case 180: + s.n -= amt + case 270: + s.e -= amt + default: + return fmt.Errorf("unable to move in heading %d", s.heading) + } + + return nil +} + +func (s *ship) changeHeading(amt int) error { + // Add to heading + for amt < 0 { + amt = 360 + amt + } + + s.heading = (s.heading + amt) % 360 + + return nil +} + +func (s *ship) move(inst string) error { + c := inst[0] + + amt, err := strconv.Atoi(inst[1:]) + if err != nil { + return err + } + + switch c { + case 'N': + s.n += amt + case 'S': + s.n -= amt + case 'W': + s.e -= amt + case 'E': + s.e += amt + case 'R': + return s.changeHeading(amt) + case 'L': + return s.changeHeading(-amt) + case 'F': + return s.forward(amt) + default: + return fmt.Errorf("unknown instruction %s", inst) + } + + return nil +} + +func part1() { + s := ship{0, 0, 90, 0, 0} + + if err := processLines("input.txt", func(line string) (bool, error) { + return false, s.move(line) + }); err != nil { + log.Fatal(err) + } + + dist := int(math.Abs(float64(s.e)) + math.Abs(float64(s.n))) + fmt.Printf("Resulting position %d,%d Distance: %d\n", s.e, s.n, dist) +} + +func part2() { + s := ship{0, 0, 90, 10, 1} + + if err := processLines("input.txt", func(line string) (bool, error) { + return false, s.part2(line) + }); err != nil { + log.Fatal(err) + } + + dist := int(math.Abs(float64(s.e)) + math.Abs(float64(s.n))) + fmt.Printf("Resulting position %d,%d Distance: %d\n", s.e, s.n, dist) +} + +func main() { + part1() + part2() +} diff --git a/d13/input.txt b/d13/input.txt new file mode 100644 index 0000000..f9fa7a4 --- /dev/null +++ b/d13/input.txt @@ -0,0 +1,2 @@ +1000066 +13,x,x,41,x,x,x,37,x,x,x,x,x,659,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,19,x,x,x,23,x,x,x,x,x,29,x,409,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,17 diff --git a/d13/main.py b/d13/main.py new file mode 100755 index 0000000..d0ee3b1 --- /dev/null +++ b/d13/main.py @@ -0,0 +1,132 @@ +#! /usr/bin/env python3 +import sys +import math +from typing import List +from typing import Tuple + + +def read_file(filename: str) -> Tuple[int, List[int]]: + with open(filename) as f: + ts = int(next(f).strip()) + busses = [ + int(bus) if bus != "x" else -1 + for bus in next(f).strip().split(",") + ] + + return ts, busses + + +def read_cli(arg: str) -> List[int]: + busses = [ + int(bus) if bus != "x" else -1 + for bus in arg.strip().split(",") + ] + + return busses + + +def wait_time(ts: int, bus_id: int) -> int: + return (bus_id - (ts % bus_id) % bus_id) + + +def part1(): + ts, busses = read_file("input.txt") + + min_wait = -1 + min_bus_id = 0 + for bus_id in busses: + if bus_id < 0: + continue + w = wait_time(ts, bus_id) + if min_wait < 0 or w < min_wait: + min_wait = w + min_bus_id = bus_id + + print(f"Wait {min_wait} for bus {min_bus_id}. Answer {min_wait * min_bus_id}") + + +def part2(busses=None, start=0): + if busses is None: + _, busses = read_file("input.txt") + # busses = [7, 13, -1, -1, 59, -1, 31, 19] + + t = start + # t = 100000000000000 + # t = t - (t%7) + # if t%7 != 0: + # print("Not starting with multiple of 7") + # return + while True: + # print(f"Checking time {t}") + for i, bus_id in enumerate(busses): + if bus_id < 0: + continue + if i == 0: + w = t % bus_id + else: + w = wait_time(t, bus_id) + # print(f"Wait for bus {bus_id} is {w} expect {i}") + if w != i: + if i > 0: + t += busses[0] + else: + t += 1 + break + else: + print(f"All busses match for time {t}") + break + + +def part2_calc(busses=None, start=0): + if busses is None: + _, busses = read_file("input.txt") + # busses = [7, 13, -1, -1, 59, -1, 31, 19] + + t = start + last_index = 0 + product = -1 + while True: + print(f"Checking time {t}") + for i, bus_id in enumerate(busses[last_index:], last_index): + if bus_id < 0: + continue + if i == 0: + w = t % bus_id + else: + w = wait_time(t, bus_id) + print(f"Wait for bus {bus_id} is {w} expect {i}") + if w == i % bus_id: + last_index = i+1 + if product < 0: + product = bus_id + else: + product = product * bus_id + print(f"New index {last_index}, new product {product}") + else: + if i > 0: + t += product + else: + t += 1 + break + else: + print(f"All busses match for time {t}") + break + + +if __name__ == "__main__": + if len(sys.argv) == 1: + part1() + part2_calc() + else: + busses = read_cli(sys.argv[1]) + b1, b2 = busses[0], busses[1] + t = b1 * math.floor(b2/b1) + print(f"Maybe t = {t}") + start = 0 + if len(sys.argv) > 2: + start = int(sys.argv[2]) + print("brute") + part2(busses, start) + print("") + print("calc") + part2_calc(busses, start) diff --git a/d14/input.txt b/d14/input.txt new file mode 100644 index 0000000..eadc753 --- /dev/null +++ b/d14/input.txt @@ -0,0 +1,572 @@ +mask = 01X11X10X10110110X111X11010X1X101010 +mem[19409] = 3025 +mem[40104] = 798480382 +mem[25359] = 905 +mask = 01011X111100XX1100X1X10X110000000000 +mem[55479] = 930785 +mem[25548] = 130263864 +mem[60518] = 202648 +mem[11955] = 1138 +mem[45248] = 753 +mask = 00XX10001XXX00101X1XX1101000010X0010 +mem[2050] = 27965 +mem[5662] = 110507779 +mem[60807] = 1608 +mask = 000110101100XX10X01000X010X000010100 +mem[28713] = 1039 +mem[22733] = 182274602 +mem[21460] = 12248397 +mem[60257] = 103 +mem[13722] = 137279 +mem[2117] = 208446548 +mask = 100110111X011X1X10110X11010001X11XX0 +mem[29709] = 6606 +mem[27812] = 143567051 +mem[3595] = 478522065 +mem[13123] = 7445318 +mem[37070] = 32452 +mem[60140] = 47608 +mem[21316] = 69201021 +mask = X10X0010110000111111X0X11X10X1000111 +mem[29528] = 3980 +mem[41054] = 274606 +mem[34884] = 265241899 +mem[7496] = 228368 +mem[35014] = 109110 +mem[40696] = 172101503 +mask = 010X011010X0001X11101011X1X100010100 +mem[23210] = 3864280 +mem[53761] = 5046 +mem[6853] = 1214 +mem[45297] = 219 +mem[33797] = 1843462 +mask = 01011011110011110X0X01110110010XX000 +mem[15509] = 16472647 +mem[19332] = 526724681 +mask = 0101X0101100X01X111X1X11X000X1X1X110 +mem[16393] = 122368236 +mem[18852] = 4351408 +mem[56526] = 780 +mem[46701] = 31085562 +mem[53459] = 47134 +mem[19409] = 7629114 +mem[47891] = 76573711 +mask = 000110X0010010X0X010XX110000X0X1000X +mem[35342] = 1095 +mem[56466] = 3462270 +mem[31124] = 204698678 +mem[104] = 2115 +mem[22733] = 154721 +mask = 00X100X01XX000101X1001110000010XX110 +mem[44047] = 6823624 +mem[11955] = 242152 +mem[41039] = 515174779 +mask = 0101101X110X10110X11101011X00110XXXX +mem[46716] = 52535895 +mem[20578] = 851818 +mem[7307] = 1658 +mem[59777] = 7566837 +mem[38136] = 6 +mem[18835] = 95379 +mem[37574] = 28195477 +mask = 010XXX101X0X0011X1100X1001110X01X100 +mem[17831] = 4467 +mem[45439] = 61064 +mem[43070] = 291981105 +mem[9562] = 725 +mem[18574] = 82455219 +mem[53761] = 2223 +mask = 0001X010X1001010XX10011110000011000X +mem[24954] = 229575 +mem[49643] = 118597 +mem[40891] = 218656479 +mem[6549] = 655 +mem[16413] = 105021 +mask = 01X0X01010010X111X1001X0X1X1X0000110 +mem[24722] = 3306225 +mem[18574] = 2046331 +mem[51991] = 2879 +mask = 010X10001X00XX10000000101100000X0000 +mem[64694] = 69415191 +mem[42979] = 1589 +mem[49282] = 199 +mem[3987] = 2386 +mem[64631] = 17661 +mask = 011XXX1010010111101X0000100100X10XX0 +mem[21201] = 341993 +mem[61134] = 328 +mem[19716] = 463044 +mem[53800] = 23668576 +mem[46317] = 368717 +mem[3978] = 2699 +mask = X10X01X011001011X111101010X0XX111111 +mem[5567] = 9644235 +mem[50029] = 4717 +mem[34043] = 119207 +mem[35949] = 665131137 +mem[58233] = 98752 +mask = 0X00001011X0001111X000100X0000XX0110 +mem[28818] = 809 +mem[20113] = 604 +mem[58178] = 11229 +mem[9389] = 38294680 +mem[34657] = 8016112 +mem[10161] = 1585984 +mem[8020] = 1403857 +mask = 01011011110XX0110111111101100X000X01 +mem[47451] = 201798 +mem[62498] = 61888 +mem[49564] = 16728 +mem[60513] = 23392513 +mem[36774] = 56575 +mem[22431] = 70709 +mask = 011X100011000X1X10X0101100X10X011111 +mem[41938] = 34906 +mem[62853] = 221817 +mem[50173] = 471027372 +mem[55286] = 4561108 +mask = 1X010X0011010000X1100X000101X101X000 +mem[22998] = 62382 +mem[18574] = 57889052 +mem[57700] = 1018 +mask = X1XX0X1011001011111X101X111001111111 +mem[34453] = 6483 +mem[49122] = 391290 +mask = 01010000000100110XX000011X00X01XX10X +mem[23870] = 19517 +mem[24291] = 616878 +mem[12134] = 1990123 +mem[26637] = 55962054 +mem[47968] = 712481177 +mem[20878] = 242502 +mem[30722] = 1568 +mask = 11X11111X100XX1000100111100000000010 +mem[35335] = 59630 +mem[63185] = 11256526 +mem[30722] = 266092278 +mem[9776] = 63532545 +mask = 10010010010X1010111X11001000X110101X +mem[12312] = 4029860 +mem[27593] = 42705942 +mem[46156] = 27895 +mem[64088] = 1408576 +mem[50342] = 15980145 +mem[46315] = 29427 +mem[47451] = 18865 +mask = 011111001X0XX01010100110X11000X01100 +mem[1293] = 837 +mem[29000] = 10697 +mask = XX0X0010X1001010XX11X01110X101101100 +mem[42918] = 1028 +mem[2608] = 3093 +mem[21904] = 6098595 +mem[41278] = 1039294 +mem[53102] = 858102784 +mask = 0X0110X01100X010X0X0001X10X00XX00000 +mem[20578] = 860568571 +mem[52466] = 143792 +mem[10261] = 182 +mask = 0X0110101100X011XX111X111110111X11XX +mem[5752] = 37841428 +mem[31368] = 1094581 +mask = 000X11101X01001110100001000X0100100X +mem[56372] = 1046359 +mem[19541] = 315663570 +mem[37436] = 437380 +mem[54334] = 241690746 +mem[16559] = 3127549 +mem[59609] = 176914004 +mask = 110101X01XX1000X0XX0100000X0000XX101 +mem[1033] = 8174 +mem[49587] = 107787 +mem[1572] = 430 +mem[49873] = 115828687 +mem[24389] = 2707208 +mem[30170] = 91827506 +mask = 01XX01001XX10010X0101001000000011101 +mem[26015] = 198698 +mem[50136] = 19382 +mem[16413] = 103882 +mem[8340] = 2066093 +mask = XX01101X1101101XX01111X01X1100X00100 +mem[42378] = 518494 +mem[13927] = 94055 +mem[48225] = 15652034 +mask = 000100X0110X101X0X1XXX1X10110011101X +mem[65006] = 6769 +mem[46625] = 5473325 +mem[22440] = 617624684 +mem[24954] = 719974 +mem[53626] = 62067 +mask = 00011XX01101X01X1010X11X10000X00X0X0 +mem[43072] = 106139234 +mem[53459] = 26813614 +mem[31162] = 184146764 +mask = 0X01X0101X00001XXX10X11X000001000010 +mem[5467] = 121320 +mem[63724] = 11067492 +mem[57246] = 315 +mem[16413] = 2008242 +mem[10240] = 11073 +mem[24282] = 618660016 +mask = 1101111011000010101X1101X0X0001X1011 +mem[61598] = 627237127 +mem[16057] = 235475116 +mem[5662] = 6226 +mem[61721] = 26023344 +mem[58178] = 209547 +mem[59687] = 141941 +mem[9548] = 1392254 +mask = 00011X1000X01010011X01111X0110X10100 +mem[13185] = 300556 +mem[51203] = 17097 +mem[59687] = 8787507 +mem[12337] = 124607 +mem[46043] = 4378256 +mask = 1100X100110100100110X10X000X01111101 +mem[17458] = 420459 +mem[46315] = 142385 +mem[7273] = 58415 +mem[49604] = 57549 +mem[33375] = 12460422 +mem[61540] = 7752 +mask = X1X11XXX1100X010X0100100000000X00010 +mem[28889] = 13691764 +mem[27546] = 355436 +mem[45337] = 10614 +mem[64088] = 960 +mem[39291] = 3019 +mem[30722] = 1976602 +mem[18725] = 299 +mask = 0X111X1011000X101010X0X001X100XX1010 +mem[5532] = 413573 +mem[7707] = 78463710 +mem[46156] = 25164851 +mem[17354] = 15295191 +mask = 000110100X0X10100X100011XX0010010000 +mem[18725] = 7003 +mem[49536] = 49752 +mem[33519] = 116272721 +mem[46701] = 253380665 +mask = 000X001001001XXX101XX00X0101X1010000 +mem[57459] = 792510 +mem[10350] = 217210394 +mem[43612] = 178868 +mem[2374] = 42534899 +mem[40891] = 621 +mem[7270] = 1014999 +mem[49038] = 1657373 +mask = 00XX10100001100X01000110001001010X10 +mem[7270] = 1904 +mem[33267] = 171621958 +mem[42531] = 623 +mask = 011111001100001X00X0010X10010010001X +mem[59756] = 19646 +mem[45248] = 182118 +mem[49395] = 186 +mem[46043] = 1875998 +mem[42378] = 2150393 +mem[16423] = 449813446 +mask = 00X10X1001001010111X0X11100XX0101X01 +mem[42378] = 11316 +mem[6217] = 448726 +mem[56349] = 105698 +mem[18523] = 6560236 +mask = 0X01101011000X101111X1110010X1110111 +mem[57685] = 1052364113 +mem[42200] = 1624 +mem[64281] = 162750 +mem[53459] = 900417618 +mem[44010] = 311326 +mem[38385] = 168338 +mem[64234] = 715 +mask = 0110001010X1001X111000XX01X110X1000X +mem[46270] = 413222 +mem[20358] = 301418973 +mask = 0101X01010000X1X111001000X010000X100 +mem[25549] = 9478586 +mem[27938] = 186993583 +mem[10014] = 630139 +mem[50316] = 22183454 +mask = 00X10XX0110010100X10XX11X01000100010 +mem[51762] = 575 +mem[39895] = 33305 +mem[19768] = 31036515 +mem[30918] = 522221 +mem[26371] = 790132 +mem[43705] = 13814 +mask = 00XXX010X1100010100101110101X0001110 +mem[12495] = 2801000 +mem[43811] = 35764 +mem[59173] = 235362 +mem[50677] = 13747007 +mem[47458] = 49520 +mask = 00X1101X1100X010X010001010000000010X +mem[19737] = 309 +mem[10289] = 1391 +mem[44222] = 202053013 +mem[32818] = 57015 +mask = XX111010X10XX0101010XX00000X00100X01 +mem[25062] = 92115406 +mem[40507] = 8539848 +mem[6853] = 1555113 +mem[59566] = 55734 +mem[29440] = 3860 +mem[2339] = 1687 +mask = X0X100100100X000X0011000100100110001 +mem[62983] = 496942 +mem[55239] = 31959819 +mem[23037] = 185 +mem[14426] = 11052660 +mem[59756] = 11483028 +mask = 0X1X101011X0101X0X100110100110X101XX +mem[9761] = 26687118 +mem[152] = 1818 +mask = 01X110X01010001X1110XXX0000100X100X0 +mem[46327] = 780262 +mem[11424] = 1003003 +mask = 010011XX100X0011X1XX000X01X10X011110 +mem[40928] = 10697 +mem[989] = 22449916 +mem[9034] = 107225 +mask = 010100X0X001001101100XX110X0000X10X0 +mem[50403] = 60110 +mem[1465] = 9126 +mem[4598] = 348452 +mem[26661] = 17672110 +mask = 00X110101XX00010100X0010010011X10010 +mem[38295] = 20183 +mem[61069] = 22691 +mem[51394] = 7278100 +mem[18711] = 34474 +mem[52888] = 1962576 +mask = 1001001X0X001010101X0110XXX001XX100X +mem[33226] = 3641501 +mem[2376] = 72068973 +mem[57257] = 11382653 +mem[22489] = 47282 +mem[45359] = 38362 +mask = 010X1X10010X101X01111010111110111011 +mem[26980] = 755824 +mem[47763] = 385 +mem[23332] = 30083831 +mem[32975] = 61896119 +mask = XX0110111101X011X011X0XXX10000011100 +mem[29709] = 711754376 +mem[36513] = 71516 +mem[7293] = 5061813 +mem[60256] = 419151 +mask = 0101101011000XX1111111X001100100XX00 +mem[19475] = 35852 +mem[57183] = 6494332 +mem[1327] = 872346 +mem[2543] = 943 +mem[2188] = 868813 +mem[29387] = 209125695 +mask = 00X1X0101X1000X01X010X1X01100X0X1101 +mem[51955] = 196066365 +mem[38207] = 15671526 +mem[26980] = 75520251 +mem[11077] = 161630247 +mem[26456] = 30666501 +mem[19737] = 9386 +mask = 1101011010110X0X01101XX001X0X001X001 +mem[49292] = 858273 +mem[11497] = 884831 +mem[49282] = 93065 +mem[54031] = 862594 +mask = 0X01011010X1X01111X0X0X00X11X1010100 +mem[58536] = 4031842 +mem[11621] = 155458283 +mem[8786] = 12859 +mask = 00010010XXX000X010010X1XX001X0X01100 +mem[45429] = 122467 +mem[57256] = 759 +mem[3687] = 384128816 +mem[56464] = 10758724 +mem[11869] = 652805159 +mem[50173] = 75914445 +mask = 0001001001001010111XX10X1X0XX0111101 +mem[5809] = 743780 +mem[52067] = 806 +mem[12750] = 22132 +mem[13019] = 654 +mask = 00X110X01100101X00100X1X00XX00100001 +mem[2117] = 4067660 +mem[2068] = 9851885 +mem[48662] = 52185630 +mem[24246] = 72048 +mem[25978] = 5182633 +mask = 010X1010X0X0001111100X001101X01X0XX0 +mem[10242] = 1118 +mem[57601] = 525 +mem[38099] = 930509 +mask = 10111101110X0X10001001X00001001000X1 +mem[50741] = 59787235 +mem[1588] = 218533 +mem[33080] = 182579 +mem[3978] = 1591079 +mem[62070] = 15472 +mask = 0101100X1100X0X10110X010000X000X00X1 +mem[3814] = 788124 +mem[63265] = 215577374 +mem[57364] = 1311024 +mem[36364] = 3985 +mem[18564] = 4526 +mem[23647] = 376609 +mask = 001XX00011010010111000101X100X0011X0 +mem[61429] = 6896 +mem[22094] = 1966698 +mask = X00110111101XX111011101X011010100X01 +mem[36214] = 310642 +mem[59733] = 1160 +mem[10909] = 1820 +mem[25225] = 51102962 +mem[35074] = 514484736 +mem[21460] = 3630 +mask = 1001001X01001010XX10111001XX1X1X1000 +mem[53608] = 6145 +mem[44618] = 302105 +mem[50955] = 12609449 +mem[48282] = 22035626 +mask = 01X1XX001XXX001XX0100111000000001100 +mem[47458] = 4534 +mem[26444] = 4150059 +mem[10366] = 1061 +mem[51657] = 2817023 +mem[35995] = 1064419 +mem[38295] = 148703436 +mask = 01X0001010010X1110X0000010111X001000 +mem[26046] = 2672378 +mem[1080] = 682 +mem[2151] = 737 +mask = 110X0100110100X001X0X1XXX100011101X0 +mem[56044] = 527135884 +mem[39296] = 107094645 +mem[61785] = 1261 +mask = 01001X00100X0011010000000101000XX101 +mem[54752] = 16579540 +mem[36330] = 1696582 +mem[1435] = 240113842 +mem[49758] = 7811 +mem[51729] = 2543212 +mem[10909] = 13139 +mask = 0X0XXX100001101X011010101000011001XX +mem[58487] = 9986 +mem[7175] = 3371969 +mem[14294] = 10275 +mem[36225] = 13168 +mem[7934] = 48879 +mem[47891] = 1571293 +mem[18711] = 399 +mask = X1010XX01X01001X01101010X1X00001X010 +mem[62247] = 18380710 +mem[20715] = 15548870 +mem[61924] = 28821546 +mem[40119] = 181518508 +mem[50251] = 59934 +mask = XXX1011X11X100X1X110001011X001100001 +mem[13627] = 4734 +mem[36208] = 48295 +mem[37672] = 184327969 +mem[60518] = 9137 +mem[46168] = 105126453 +mask = 1X111101110X0010001000XX000100XXX011 +mem[4455] = 17333982 +mem[58592] = 931411 +mem[61752] = 198443 +mem[183] = 808 +mask = XX010010010XX0101011111111010011X100 +mem[6221] = 256009562 +mem[3528] = 422478 +mem[16002] = 6328770 +mask = 0X01X00011001010XX000010100000100010 +mem[31570] = 32237 +mem[14971] = 846258186 +mem[18978] = 1202 +mem[15368] = 120674 +mem[13185] = 22420 +mask = 010110111101101XX011X11XX11X00X00X00 +mem[59330] = 628 +mem[9283] = 58883 +mem[44010] = 387833048 +mask = 010010101001X1111010111X000X00X0X110 +mem[50633] = 751888 +mem[11056] = 31979 +mem[50741] = 4724 +mem[40028] = 7336181 +mem[42263] = 6863 +mask = 0001X010110000X00010010X10000XX10100 +mem[20546] = 8708 +mem[36908] = 234294 +mem[63185] = 1408 +mem[57531] = 1054 +mem[13722] = 1045167819 +mem[4617] = 3519205 +mask = 00111000X10010X10010X01010X00010010X +mem[46693] = 4740 +mem[17824] = 884 +mem[54997] = 339096 +mem[2117] = 26803 +mem[20] = 84635057 +mask = 0101XXX01100X011011X010000000X00X100 +mem[40142] = 140297 +mem[53459] = 5575659 +mem[57435] = 69641959 +mem[28563] = 433881 +mem[59188] = 230341 +mem[26483] = 151116806 +mask = 110101X01XX100X10110001XX1X0X01000X1 +mem[37526] = 454911 +mem[35793] = 3340 +mem[54537] = 630806 +mem[58456] = 115228 +mem[59172] = 13363 +mask = 010110X0110000101010X001111X0X010010 +mem[45969] = 1736711 +mem[2487] = 610736260 +mem[54173] = 453 +mem[55144] = 2748104 +mem[52466] = 6109568 +mem[31890] = 3977366 +mask = 01011001110000X101100X00X00X10010000 +mem[64336] = 3971537 +mem[60265] = 85267 +mem[24597] = 7455656 +mem[34924] = 703390248 +mem[40391] = 328312 +mem[49255] = 1117186 +mask = 110X0100101100X1011010101X0X11X11010 +mem[31313] = 789405 +mem[7934] = 1803 +mem[36190] = 1836611 +mask = X0010010010010101X1X1X1010X111X010XX +mem[4017] = 64210 +mem[40696] = 58930789 +mem[18166] = 195479433 +mem[41257] = 40207 +mem[40948] = 1058796 +mem[30803] = 486 +mem[29709] = 72337 +mask = 000X101000X110X001X00110X1X0011X0XX1 +mem[11077] = 1653 +mem[2376] = 77389 +mem[19561] = 4876923 +mem[32851] = 538156 +mem[38532] = 1110 +mask = X101101011X010111110X0111001X101010X +mem[44618] = 13980 +mem[10366] = 711247 +mem[4942] = 74171 +mem[25306] = 350133 +mem[21409] = 27748 +mask = 00011010X1001010XXX0001110000001011X +mem[5809] = 1082 +mem[36908] = 180 +mem[59172] = 196430412 +mem[60137] = 1388 +mem[49643] = 1887 +mask = 01011010X10000X1111111111XX00101111X +mem[56344] = 1237 +mem[23638] = 37922654 +mem[20307] = 593227321 diff --git a/d14/main.go b/d14/main.go new file mode 100644 index 0000000..6042632 --- /dev/null +++ b/d14/main.go @@ -0,0 +1,200 @@ +package main + +import ( + "bufio" + "fmt" + "log" + "math" + "os" + "regexp" + "strconv" + "strings" +) + +func processLines(path string, f func(string) (stop bool, err error)) error { + file, err := os.Open(path) + if err != nil { + return err + } + defer file.Close() + + scanner := bufio.NewScanner(file) + for scanner.Scan() { + stop, err := f(scanner.Text()) + if stop || err != nil { + return err + } + } + + if err := scanner.Err(); err != nil { + return err + } + + return nil +} + +var memExtractor = regexp.MustCompile(`^mem\[([0-9]+)] = ([0-9]+)`) + +func powInt(x, y int) int { + return int(math.Pow(float64(x), float64(y))) +} + +func applyMask(mask string, v int) (int, error) { + for i := 0; i < len(mask); i++ { + m := mask[len(mask)-i-1] + switch m { + case 'X': + case '1': + v |= powInt(2, i) + case '0': + v &^= powInt(2, i) + default: + return 0, fmt.Errorf("could not apply mask %v in position %d", m, i) + } + } + + return v, nil +} + +func sprintBinArray(a []int, z int) string { + r := " " + + for _, v := range a { + f := fmt.Sprintf("%%%db(%%d)", z) + r += fmt.Sprintf(f, v, v) + } + + return fmt.Sprintf("[%s]", r) +} + +func applyFloatingMask(mask string, v int) ([]int, error) { + base2 := 2 + results := []int{v} + + // fmt.Printf("Applying %s to %8b\n", mask, v) + + for i := 0; i < len(mask); i++ { + m := mask[len(mask)-i-1] + // fmt.Printf("Apply %s at %d ", string(m), i) + + resultLen := len(results) + for j := 0; j < resultLen; j++ { + switch m { + case 'X': + // Add a 0 mask to end of results + results = append(results, results[j]|powInt(base2, i)) + // Apply a 1 mask in place + results[j] &^= powInt(base2, i) + case '1': + results[j] |= powInt(base2, i) + case '0': + // results[j] &^= powInt(base2, i) + default: + return results, fmt.Errorf("could not apply mask %v in position %d", m, i) + } + } + + // fmt.Printf("Result %s\n", sprintBinArray(results, 8)) + } + + return results, nil +} + +func parseMemValues(line string) (loc int, val int, err error) { + match := memExtractor.FindStringSubmatch(line) + if match == nil { + err = fmt.Errorf("could not extract mem val in %s", line) + + return + } + + loc, err = strconv.Atoi(match[1]) + if err != nil { + err = fmt.Errorf("error parsing int from %s: %w", line, err) + + return + } + + val, err = strconv.Atoi(match[2]) + if err != nil { + err = fmt.Errorf("error parsing int from %s: %w", line, err) + + return + } + + return +} + +func part1() { + var mask string + + mem := map[int]int{} + + if err := processLines("input.txt", func(line string) (bool, error) { + if strings.HasPrefix(line, "mask") { + mask = strings.TrimPrefix(line, "mask = ") + } else { + loc, val, err := parseMemValues(line) + if err != nil { + return false, err + } + val, err = applyMask(mask, val) + if err != nil { + return false, fmt.Errorf("error applying mask to value on line %s: %w", line, err) + } + // fmt.Printf("mem[%d] = %d\n", loc, val) + mem[loc] = val + } + + return false, nil + }); err != nil { + log.Fatal(err) + } + + sum := 0 + for _, v := range mem { + sum += v + } + + fmt.Printf("Total value in memory %d\n", sum) +} + +func part2() { + var mask string + + mem := map[int]int{} + + if err := processLines("input.txt", func(line string) (bool, error) { + if strings.HasPrefix(line, "mask") { + mask = strings.TrimPrefix(line, "mask = ") + } else { + loc, val, err := parseMemValues(line) + if err != nil { + return false, err + } + locs, err := applyFloatingMask(mask, loc) + if err != nil { + return false, fmt.Errorf("error applying mask to value on line %s: %w", line, err) + } + for _, l := range locs { + mem[l] = val + } + } + + return false, nil + }); err != nil { + log.Fatal(err) + } + + sum := 0 + for _, v := range mem { + sum += v + } + + fmt.Printf("Total value in memory %d\n", sum) +} + +func main() { + part1() + part2() +} diff --git a/d15/main.go b/d15/main.go new file mode 100644 index 0000000..20b45a5 --- /dev/null +++ b/d15/main.go @@ -0,0 +1,94 @@ +package main + +import "fmt" + +type game struct { + turn, lastNumber int + history map[int]int +} + +func newGame(startingNumbers []int) *game { + g := game{0, 0, map[int]int{}} + for _, n := range startingNumbers { + g.history[g.lastNumber] = g.turn + g.turn++ + g.lastNumber = n + } + + return &g +} + +func (g *game) takeTurn() (int, int) { + // fmt.Printf("> Starting turn %d. last: %d\n", g.turn+1, g.lastNumber) + // fmt.Printf(">> state %+v\n", g) + + var number int + + // Get the new number + if t, ok := g.history[g.lastNumber]; ok { + // fmt.Printf(">> We've seen %d before!\n", g.lastNumber) + // Last number was seen + number = g.turn - t + } else { + // Otherwise the number is zero + number = 0 + } + + // Store the last turn in history + g.history[g.lastNumber] = g.turn + + // Go to the next turn + g.turn++ + g.lastNumber = number + + // fmt.Printf(">> Incrementing turn and updating state %+v\n", g) + // fmt.Printf("Turn %d spoke \"%d\"\n", g.turn, g.lastNumber) + + return g.turn, g.lastNumber +} + +func (g *game) turnTo(targetTurn int) int { + var n int + + for g.turn < targetTurn { + _, n = g.takeTurn() + } + + return n +} + +func part1() { + numbers := []int{16, 12, 1, 0, 15, 7, 11} + // numbers := []int{0, 3, 6} + g := newGame(numbers) + fmt.Println(g) + + t, n := g.takeTurn() + for t < 2020 { + t, n = g.takeTurn() + } + + fmt.Printf("Part 1: Number on turn %d is %d\n", t, n) +} + +func part2() { + numbers := []int{16, 12, 1, 0, 15, 7, 11} + // numbers := []int{0, 3, 6} + g := newGame(numbers) + fmt.Println(g) + + t, n := g.takeTurn() + for t < 30000000 { + t, n = g.takeTurn() + } + + fmt.Printf("Part 2: Number on turn %d is %d\n", t, n) +} + +func main() { + fmt.Println(newGame([]int{16, 12, 1, 0, 15, 7, 11}).turnTo(2020)) + fmt.Println(newGame([]int{16, 12, 1, 0, 15, 7, 11}).turnTo(30000000)) + part1() + part2() + +} diff --git a/d16/input-small.txt b/d16/input-small.txt new file mode 100644 index 0000000..fe34e40 --- /dev/null +++ b/d16/input-small.txt @@ -0,0 +1,12 @@ +class: 1-3 or 5-7 +row: 6-11 or 33-44 +seat: 13-40 or 45-50 + +your ticket: +7,1,14 + +nearby tickets: +7,3,47 +40,4,50 +55,2,20 +38,6,12 diff --git a/d16/input-small2.txt b/d16/input-small2.txt new file mode 100644 index 0000000..b48bf37 --- /dev/null +++ b/d16/input-small2.txt @@ -0,0 +1,11 @@ +class: 0-1 or 4-19 +row: 0-5 or 8-19 +seat: 0-13 or 16-19 + +your ticket: +11,12,13 + +nearby tickets: +3,9,18 +15,1,5 +5,14,9 diff --git a/d16/input.txt b/d16/input.txt new file mode 100644 index 0000000..53bb849 --- /dev/null +++ b/d16/input.txt @@ -0,0 +1,261 @@ +departure location: 29-766 or 786-950 +departure station: 40-480 or 491-949 +departure platform: 46-373 or 397-957 +departure track: 33-657 or 673-970 +departure date: 31-433 or 445-961 +departure time: 33-231 or 250-966 +arrival location: 48-533 or 556-974 +arrival station: 42-597 or 620-957 +arrival platform: 32-119 or 140-967 +arrival track: 28-750 or 762-973 +class: 26-88 or 101-950 +duration: 30-271 or 293-974 +price: 33-712 or 718-966 +route: 49-153 or 159-953 +row: 36-842 or 851-972 +seat: 43-181 or 194-955 +train: 29-500 or 513-964 +type: 32-59 or 73-974 +wagon: 47-809 or 816-957 +zone: 44-451 or 464-955 + +your ticket: +151,103,173,199,211,107,167,59,113,179,53,197,83,163,101,149,109,79,181,73 + +nearby tickets: +339,870,872,222,255,276,706,890,583,718,924,118,201,141,59,581,931,143,221,919 +400,418,807,726,84,142,820,112,228,687,335,855,761,740,627,532,369,313,147,620 +474,926,741,424,632,982,876,926,738,936,300,726,400,321,348,160,421,464,78,258 +337,683,885,368,214,215,620,650,321,311,200,696,838,880,526,812,821,891,829,204 +678,69,480,939,219,736,628,948,178,296,204,890,199,526,736,210,170,923,228,726 +574,55,871,945,347,207,840,707,442,791,159,216,427,312,947,326,738,801,264,54 +811,259,417,932,870,634,945,408,706,766,303,402,942,50,415,150,839,674,904,836 +670,358,701,172,231,914,875,205,586,517,576,206,796,400,363,303,295,932,73,308 +319,949,312,803,217,6,719,870,202,883,111,532,467,801,83,202,331,637,930,412 +580,262,196,529,401,806,446,104,326,657,589,789,876,817,470,653,167,191,634,678 +720,217,118,422,190,115,684,827,317,228,524,569,531,471,322,408,896,566,875,302 +678,683,218,820,896,303,296,316,229,758,114,261,825,750,901,428,479,556,373,404 +502,259,577,77,260,588,340,199,626,575,171,422,372,83,111,902,300,863,800,886 +577,216,195,804,298,948,83,807,878,656,740,743,854,740,219,331,714,176,683,199 +492,187,259,528,853,80,808,887,149,723,324,922,170,323,884,825,710,562,416,471 +702,55,141,261,743,256,632,693,787,581,363,851,578,74,164,146,413,224,829,282 +370,161,470,207,876,57,564,103,195,216,468,632,161,734,487,150,570,251,311,196 +242,430,115,575,806,258,109,85,433,794,85,258,647,596,84,339,215,879,203,74 +912,449,174,371,857,556,743,537,521,643,903,745,764,207,295,896,431,901,592,332 +687,361,855,683,298,828,421,894,163,214,308,110,643,495,106,198,613,205,322,582 +318,578,83,318,150,182,298,740,424,306,411,895,50,265,887,465,912,262,294,428 +320,948,74,114,643,801,928,280,868,930,822,140,620,696,627,520,692,820,526,764 +622,477,314,253,419,73,333,924,750,432,705,894,114,827,364,946,577,269,789,463 +639,742,840,541,656,787,222,637,728,734,558,744,173,801,80,629,634,572,151,326 +830,468,597,75,259,762,331,315,151,369,308,419,447,207,523,268,118,719,501,839 +496,312,525,343,559,77,114,404,362,595,656,301,622,337,741,818,816,352,1,449 +432,512,627,739,729,627,218,829,595,471,641,447,639,350,220,718,573,319,859,363 +646,368,258,320,916,520,328,327,180,357,646,620,530,208,269,84,264,53,184,163 +904,657,329,897,327,339,674,803,110,327,308,78,883,353,150,446,296,645,539,932 +472,726,685,676,406,419,594,419,699,364,416,868,106,53,662,856,859,571,674,571 +301,741,900,869,259,727,557,975,334,913,496,948,929,79,165,680,838,465,591,902 +939,201,586,897,948,725,625,224,923,801,910,723,361,338,55,217,721,300,674,777 +362,211,592,573,711,831,170,949,171,408,647,578,228,349,629,780,582,567,84,349 +317,874,623,704,934,526,898,797,447,485,400,589,679,109,827,107,353,807,859,513 +519,108,304,162,888,88,742,637,789,923,749,404,171,175,708,432,559,200,557,444 +787,589,518,397,762,200,734,222,468,252,306,560,558,701,905,656,155,689,51,258 +354,159,938,734,932,636,478,162,562,718,315,712,933,862,530,877,118,535,366,797 +189,338,517,302,414,401,167,905,947,500,895,940,405,222,864,706,835,352,269,825 +757,404,212,426,628,113,945,480,398,271,353,364,225,804,643,84,416,728,936,223 +337,529,631,589,909,314,174,820,257,199,822,359,344,445,929,20,513,450,212,928 +254,927,865,202,851,733,897,329,433,224,319,674,857,722,837,207,419,84,728,375 +416,464,822,368,920,175,0,213,799,200,648,529,398,889,678,407,180,870,496,786 +712,335,80,824,826,416,261,400,904,630,255,691,259,723,344,354,786,857,774,195 +945,257,57,260,642,817,934,909,574,358,269,683,764,176,365,427,549,878,500,791 +807,140,308,885,866,623,80,111,648,848,572,643,853,854,560,934,699,52,580,164 +895,590,647,730,540,874,255,115,304,117,224,399,168,819,420,525,306,160,580,595 +594,265,401,920,855,62,352,706,908,835,925,908,829,620,476,51,251,73,875,696 +261,748,411,706,409,53,470,202,227,918,653,398,516,518,416,187,917,836,649,222 +288,690,877,468,620,451,147,919,251,408,836,584,319,729,640,445,673,87,650,856 +308,806,477,875,329,928,948,800,417,574,220,991,355,51,693,838,747,794,498,913 +706,582,499,834,887,109,677,857,280,407,651,517,468,407,403,303,515,881,656,523 +256,597,344,577,636,702,561,738,683,884,268,858,73,201,421,721,646,739,424,992 +903,211,920,623,160,152,567,786,852,423,179,258,690,493,110,505,823,303,721,373 +397,893,747,819,729,88,651,893,699,229,744,948,712,104,741,643,511,854,876,706 +929,880,820,532,259,621,307,480,900,59,915,188,863,624,119,252,928,935,451,885 +335,893,475,733,787,850,629,839,530,231,451,942,260,718,654,473,255,495,406,464 +451,822,629,745,226,595,295,862,408,592,498,474,77,110,845,354,906,424,913,936 +75,891,446,347,468,521,312,320,346,579,900,205,528,307,370,890,8,269,826,566 +566,353,58,360,629,793,649,567,259,736,261,531,118,880,244,145,581,172,885,471 +107,371,947,936,250,468,624,888,334,622,947,327,837,941,360,521,754,199,688,905 +313,163,370,367,8,174,341,792,153,736,725,581,313,203,872,225,590,720,841,475 +210,823,329,556,763,691,371,202,807,902,741,413,303,832,651,802,473,358,990,897 +718,652,891,367,702,640,645,883,817,231,590,842,350,820,291,681,422,859,691,338 +349,408,890,915,116,719,872,589,586,620,116,206,683,353,317,81,319,86,849,797 +84,520,856,641,254,206,209,356,178,476,728,114,559,802,579,377,298,112,941,853 +518,741,500,466,796,676,833,235,330,854,494,762,58,923,908,228,335,433,85,565 +418,697,943,513,854,907,824,872,479,81,372,324,688,216,299,407,621,492,63,685 +559,652,645,107,685,577,870,370,509,58,371,85,445,800,174,255,412,475,640,837 +85,366,789,597,625,701,275,166,632,82,854,422,628,863,855,213,448,213,517,263 +447,373,853,469,912,545,712,695,749,673,299,647,744,826,893,367,865,448,116,943 +570,520,859,919,742,221,577,316,946,358,82,910,892,595,584,559,644,593,665,879 +645,345,399,430,697,86,641,642,239,764,325,253,728,82,891,372,402,270,400,153 +144,533,735,296,806,648,521,747,115,194,405,764,188,861,838,584,872,373,738,744 +446,180,652,85,429,330,172,517,629,566,167,922,177,884,751,868,919,102,494,930 +306,946,257,637,886,231,836,566,108,210,357,720,791,819,826,489,346,159,420,883 +360,622,764,398,398,82,323,165,403,185,557,447,635,171,493,211,736,570,766,79 +840,174,102,911,424,821,878,311,498,785,798,572,211,268,59,177,732,853,475,165 +109,228,693,210,300,882,184,419,872,939,706,693,596,635,625,905,566,351,202,727 +686,414,806,638,869,737,407,506,912,465,448,738,913,118,514,321,363,180,905,345 +928,348,305,110,916,827,222,681,197,313,827,903,148,761,498,523,643,297,430,897 +317,816,623,799,152,518,491,801,934,762,694,708,583,257,818,400,931,358,899,755 +418,943,493,888,559,252,826,222,680,726,426,639,104,579,886,732,844,111,856,817 +478,728,865,930,591,340,734,401,900,399,116,839,78,106,315,111,667,631,302,478 +744,691,703,984,901,301,75,432,687,336,630,421,527,116,944,111,930,641,497,729 +529,930,589,712,588,59,817,76,566,704,319,253,935,423,692,753,626,217,299,142 +911,403,257,196,179,178,55,627,468,546,684,327,255,923,912,252,646,266,206,207 +889,638,475,473,866,227,789,148,72,57,50,366,269,743,878,901,627,227,586,199 +833,976,570,51,335,212,173,110,652,424,446,858,677,73,787,107,877,159,587,165 +333,831,361,52,165,59,145,528,935,57,262,366,884,198,354,223,985,808,170,521 +928,301,762,573,572,832,728,708,933,150,689,308,680,579,603,313,354,582,368,477 +437,686,400,937,162,594,878,414,170,209,259,886,432,208,348,228,399,519,708,574 +85,633,54,353,886,917,161,499,496,78,804,119,652,496,511,919,476,306,728,51 +451,718,399,578,639,651,293,940,364,75,450,364,799,341,851,295,465,335,754,266 +371,268,852,750,706,735,113,752,863,795,467,572,794,497,838,310,160,367,251,471 +883,269,624,268,268,557,68,197,590,330,678,316,429,266,877,414,896,733,899,746 +991,521,595,300,422,471,686,620,159,341,448,730,694,513,342,575,743,213,790,684 +178,252,643,595,697,59,703,328,424,76,567,173,254,880,805,728,519,798,332,157 +297,373,312,687,566,491,571,109,448,581,720,873,552,695,806,446,351,854,594,150 +260,216,58,789,676,180,708,785,115,252,331,344,498,334,570,935,200,105,208,687 +207,484,171,323,466,722,794,833,323,50,763,347,729,252,710,176,910,328,74,649 +938,293,838,840,341,429,702,483,259,852,900,112,143,180,881,526,519,58,466,750 +700,172,253,365,871,563,643,520,945,587,253,852,492,731,493,281,310,112,573,220 +425,941,103,586,871,801,807,918,843,898,522,251,799,177,763,144,195,228,408,84 +149,256,792,82,711,419,533,946,835,271,76,681,172,141,120,451,178,633,358,297 +595,79,203,762,856,988,556,562,791,528,635,678,865,205,449,870,823,341,260,817 +407,24,904,411,818,365,859,654,491,817,297,86,674,218,360,840,620,54,806,708 +466,210,258,641,199,766,76,256,651,267,824,343,940,405,198,701,431,259,205,536 +561,164,326,563,765,897,177,805,207,571,425,572,349,734,907,233,255,310,54,88 +934,866,361,699,709,861,140,680,217,699,172,647,572,923,56,319,164,475,136,255 +689,587,52,885,751,517,624,915,790,347,172,366,162,941,893,916,358,419,421,226 +562,516,58,626,940,802,840,212,473,230,887,875,180,893,332,942,274,896,718,170 +863,557,196,692,263,53,145,340,211,61,117,816,417,108,171,111,683,312,559,75 +250,808,732,474,174,261,312,587,349,167,573,934,790,334,819,643,784,212,564,500 +480,103,319,230,477,428,119,563,896,421,568,712,923,519,737,672,882,398,496,625 +424,787,54,256,917,880,415,466,309,410,59,836,230,189,594,927,620,730,561,168 +584,104,415,451,747,808,349,742,54,410,315,711,531,277,705,521,368,259,144,708 +365,467,337,75,993,147,223,519,150,206,864,946,763,51,596,105,736,310,695,146 +79,365,85,309,649,676,324,597,938,310,733,942,223,693,316,904,413,229,833,484 +946,921,52,450,229,180,700,268,16,701,919,885,730,682,494,836,786,852,171,220 +295,750,718,149,626,497,335,819,518,624,199,705,631,825,418,897,468,19,698,866 +556,584,807,269,721,213,420,721,870,812,88,359,180,829,738,789,295,877,151,360 +940,333,838,622,637,173,325,923,547,866,304,398,943,789,822,916,639,679,261,340 +480,266,711,197,322,112,362,169,705,828,84,862,719,17,593,864,142,561,916,356 +337,675,859,872,586,689,329,949,771,573,267,932,200,526,333,161,350,115,300,697 +562,362,942,150,924,215,330,162,753,565,498,321,307,709,641,697,863,578,205,868 +655,464,886,153,318,402,818,733,490,73,354,853,936,858,637,473,203,301,177,312 +705,429,402,348,882,471,644,193,427,687,804,841,414,270,332,720,228,633,787,880 +265,927,325,889,345,403,88,168,219,696,230,570,733,521,833,217,482,711,522,742 +335,702,271,178,592,569,845,913,176,649,299,916,788,253,205,860,146,113,710,168 +264,219,87,368,798,852,470,224,646,367,355,710,655,17,649,219,942,169,314,118 +54,710,880,343,270,468,269,850,167,50,675,303,688,750,419,870,324,674,728,914 +528,423,153,101,939,471,418,21,414,926,656,446,211,826,681,863,897,530,839,347 +909,298,338,890,335,216,693,171,584,480,228,987,198,252,582,657,641,218,824,791 +254,578,837,816,936,271,368,268,167,101,685,516,743,399,465,542,495,626,888,319 +268,140,857,844,79,763,115,322,735,159,409,519,857,699,317,917,520,910,75,728 +628,2,410,568,299,252,168,683,587,303,743,141,702,723,498,911,766,165,465,800 +431,583,212,933,253,358,981,114,766,764,942,361,524,586,203,730,562,627,449,926 +631,337,858,720,866,567,723,828,731,926,145,204,640,653,231,724,688,371,482,144 +83,571,836,361,797,349,834,809,704,293,839,301,271,219,797,743,803,637,719,811 +844,59,356,851,692,180,786,476,703,801,323,797,943,86,432,329,943,596,868,745 +230,922,302,180,118,241,231,867,469,639,161,207,807,325,825,74,338,526,722,855 +628,0,416,116,143,467,262,937,269,590,80,926,176,523,519,674,523,911,651,366 +873,934,81,406,163,945,905,216,359,795,819,554,314,583,722,568,597,317,204,880 +433,683,181,426,583,631,826,873,894,938,588,854,308,267,885,222,861,843,719,144 +905,825,294,143,203,465,794,674,346,364,180,88,865,168,905,947,897,943,252,717 +492,416,629,719,827,108,921,163,745,930,500,343,426,740,777,326,574,149,250,589 +940,340,584,722,251,520,880,532,151,398,795,886,869,253,185,304,468,311,852,877 +833,371,112,810,56,516,829,352,641,466,295,528,476,718,413,725,559,917,818,533 +677,355,203,373,356,398,573,831,750,410,697,809,53,597,435,946,173,890,905,152 +588,465,475,201,523,521,340,897,427,834,875,718,635,407,733,323,908,341,440,595 +478,496,748,82,890,210,623,809,315,273,58,681,655,101,640,325,621,337,494,299 +216,761,834,342,766,808,466,325,51,480,221,721,433,411,403,342,267,620,218,255 +301,58,310,355,891,149,474,681,76,677,518,734,532,745,908,333,519,418,278,446 +842,527,339,354,940,828,198,478,413,181,695,84,637,988,712,938,165,147,696,211 +795,712,522,698,402,310,813,465,910,630,263,331,731,706,936,686,226,829,199,828 +575,786,691,828,447,512,730,270,56,722,794,108,175,346,639,174,217,347,652,822 +530,732,51,688,74,696,416,309,264,521,209,727,710,259,361,401,559,909,260,510 +368,590,119,906,200,725,329,696,942,140,118,933,474,847,657,557,652,823,162,332 +107,940,194,558,335,798,926,366,528,918,880,867,695,491,268,226,70,765,150,732 +161,684,179,184,732,749,265,529,349,87,934,467,723,111,216,201,861,795,449,801 +649,141,914,636,468,196,656,703,813,897,852,472,347,56,337,809,736,901,707,747 +594,141,425,316,174,573,885,357,873,595,726,334,59,745,717,887,207,200,310,357 +732,368,862,346,795,657,531,464,721,356,732,422,114,735,328,421,741,332,394,164 +264,261,806,898,471,170,763,819,642,690,500,267,847,592,73,906,171,175,909,532 +77,852,267,578,219,913,795,839,85,920,645,560,303,871,404,804,595,206,727,138 +264,323,50,338,301,417,702,817,791,666,172,674,597,721,876,705,576,449,786,945 +880,633,356,366,197,692,209,426,261,940,643,634,926,160,269,590,191,293,928,529 +295,700,113,627,643,557,141,820,379,140,430,677,791,450,686,118,322,479,495,423 +467,749,178,367,520,566,938,114,176,226,894,470,908,824,806,373,436,596,497,575 +816,233,748,518,829,424,901,643,56,565,333,570,561,948,114,430,632,901,301,708 +208,268,409,297,571,838,722,62,889,885,256,725,166,869,168,150,647,406,498,762 +646,695,359,76,710,363,748,887,416,515,696,227,166,86,742,308,140,721,311,663 +635,479,734,830,338,224,563,359,88,587,676,370,582,871,840,476,247,790,856,584 +226,101,270,301,423,103,264,674,724,361,349,620,646,337,801,830,445,688,746,64 +821,112,882,887,295,764,760,789,623,198,655,922,109,809,922,88,399,419,925,305 +891,308,685,214,106,147,228,903,114,497,309,743,175,399,416,416,354,935,747,990 +642,449,852,913,621,752,318,255,331,478,229,680,630,871,865,922,253,422,151,201 +115,732,583,361,316,500,210,77,319,737,448,625,371,651,202,949,403,228,263,999 +711,280,169,354,364,255,176,633,560,225,194,214,252,229,168,117,329,348,344,681 +168,471,181,476,368,691,918,19,910,325,629,793,298,340,880,570,201,686,795,398 +763,206,648,686,679,163,250,167,178,917,301,205,69,372,175,201,802,629,258,513 +340,304,195,422,220,450,942,500,620,505,88,924,266,566,832,50,647,480,222,840 +643,560,923,526,880,942,411,945,184,527,630,725,258,118,908,868,205,422,416,523 +376,639,418,938,425,905,650,891,317,269,495,940,113,582,728,178,176,589,802,78 +775,312,631,797,931,103,109,588,109,464,680,293,655,149,167,821,415,816,260,881 +478,655,496,170,419,806,582,115,908,639,110,153,644,571,543,164,103,210,175,228 +206,211,889,225,703,901,857,530,648,144,81,934,110,923,305,846,433,745,529,646 +493,763,224,310,921,644,355,479,81,115,269,265,886,9,110,625,694,675,350,636 +836,518,345,917,78,445,478,892,945,476,417,107,862,744,380,327,872,935,884,691 +928,475,349,927,404,801,203,924,667,915,143,932,119,197,864,513,646,802,359,592 +194,369,582,115,422,531,675,373,166,640,311,268,703,710,826,699,722,114,795,847 +179,257,525,695,324,197,745,719,171,450,707,576,814,478,888,426,828,749,268,916 +654,520,898,640,929,586,425,828,862,861,861,266,743,297,0,689,884,116,414,366 +318,365,189,651,586,294,326,429,735,569,934,109,447,914,675,701,701,803,106,634 +145,229,170,364,581,722,918,875,866,410,566,982,635,321,750,164,741,335,403,918 +890,497,731,81,432,417,919,338,355,297,153,640,675,799,620,684,518,4,209,301 +197,733,109,834,889,207,898,400,140,525,424,583,416,448,902,201,902,688,472,14 +0,809,569,206,625,431,56,448,913,800,476,344,882,269,166,314,908,202,373,570 +206,201,414,688,166,718,677,696,978,431,594,263,628,449,868,360,807,305,346,499 +217,513,429,924,143,167,526,348,268,101,260,654,917,866,812,748,59,816,589,655 +788,52,203,270,361,796,895,466,596,149,864,929,895,325,351,702,883,316,892,239 +831,500,911,524,820,498,547,315,737,103,494,406,220,358,467,414,725,415,466,472 +577,821,171,9,863,807,398,354,266,268,339,724,932,691,334,679,450,264,228,654 +116,497,360,294,166,469,919,870,321,592,566,206,883,214,736,309,806,762,810,748 +839,525,166,295,269,203,892,578,740,645,305,583,874,634,681,499,998,912,365,638 +419,692,496,597,297,945,929,410,911,699,733,868,831,709,932,680,890,199,728,615 +944,820,324,693,736,874,637,872,528,249,681,149,339,151,464,591,225,314,315,313 +270,639,345,944,690,150,201,822,851,468,876,830,511,303,57,923,762,869,472,316 +641,793,104,944,23,870,307,788,877,591,860,328,492,899,472,328,419,361,903,820 +799,992,500,116,516,142,903,451,177,477,931,560,744,77,570,52,344,695,816,50 +691,227,707,202,302,813,149,623,261,116,575,564,704,824,653,890,937,101,174,256 +257,112,339,420,261,834,492,907,912,649,874,838,729,826,271,345,361,470,637,193 +339,812,319,906,401,575,867,586,207,351,697,497,855,740,407,347,945,736,152,896 +925,845,88,477,58,216,885,565,623,259,142,307,621,304,115,476,939,700,202,469 +808,786,83,651,174,623,579,224,224,789,208,161,7,722,116,350,698,733,883,199 +682,421,887,432,847,336,524,654,361,371,161,480,59,880,797,348,407,308,681,403 +686,571,408,941,788,705,480,365,678,728,631,591,152,555,119,725,595,936,143,142 +825,331,993,830,876,399,142,880,741,140,694,947,293,532,445,855,78,912,357,412 +898,315,491,897,927,807,165,596,695,563,877,700,56,307,480,253,139,77,117,762 +299,690,341,493,500,152,351,810,631,339,828,87,205,565,725,696,207,828,270,404 +484,260,809,639,52,620,910,223,499,706,465,348,85,698,116,622,579,707,826,571 +621,655,13,445,733,686,411,449,467,898,491,75,344,805,148,356,195,79,449,653 +988,891,824,632,229,909,571,176,928,586,708,117,471,560,864,805,725,161,114,934 +741,165,570,908,632,728,938,570,516,220,86,301,655,882,581,637,877,475,234,320 +67,801,766,731,254,827,916,572,449,621,628,596,478,175,166,696,323,533,416,701 +720,58,837,307,695,306,629,215,522,706,856,591,281,110,175,872,532,524,181,167 +525,841,651,174,940,530,165,869,423,250,920,705,724,742,112,144,378,259,467,360 +740,648,791,679,674,404,165,265,151,256,348,162,880,150,66,353,80,636,258,115 +886,575,150,754,365,562,362,522,498,571,639,364,834,169,55,562,470,446,466,366 +552,361,412,118,318,724,652,828,450,627,469,594,424,620,519,108,884,884,53,349 +519,587,585,341,892,56,175,316,312,472,874,496,267,358,946,874,812,218,943,228 +927,307,867,229,597,448,929,557,688,886,269,331,718,345,471,651,369,838,619,469 +203,796,199,515,424,212,572,529,220,786,170,889,198,359,596,65,626,569,933,687 +208,105,266,278,269,653,531,627,881,253,81,632,836,445,574,788,348,209,166,586 +425,543,702,474,424,673,918,747,628,762,175,931,832,863,79,213,109,557,881,494 +606,789,514,465,893,339,315,494,314,921,944,477,724,920,856,150,733,932,897,415 diff --git a/d16/main.go b/d16/main.go new file mode 100644 index 0000000..7383786 --- /dev/null +++ b/d16/main.go @@ -0,0 +1,399 @@ +package main + +import ( + "bufio" + "fmt" + "log" + "os" + "regexp" + "sort" + "strconv" + "strings" +) + +func processLines(path string, f func(string) (stop bool, err error)) error { + file, err := os.Open(path) + if err != nil { + return err + } + defer file.Close() + + scanner := bufio.NewScanner(file) + for scanner.Scan() { + stop, err := f(scanner.Text()) + if stop || err != nil { + return err + } + } + + if err := scanner.Err(); err != nil { + return err + } + + return nil +} + +func processGroups(path string, f func([]string) (stop bool, err error)) error { + group := []string{} + + if err := processLines(path, func(line string) (stop bool, err error) { + if line == "" { + stop, err = f(group) + if stop || err != nil { + return + } + group = []string{} + } else { + group = append(group, line) + } + + return + }); err != nil { + return err + } + + _, err := f(group) + + return err +} + +// StringSet is a set of strings. +type StringSet map[string]bool + +// Add an item to a StringSet. +func (s *StringSet) Add(v string) { + (*s)[v] = true +} + +// AddAll adds all items in a list to the set. +func (s *StringSet) AddAll(l []string) { + for _, v := range l { + s.Add(v) + } +} + +// Values returns all values in the set as a list. +func (s StringSet) Values() []string { + values := []string{} + for k := range s { + values = append(values, k) + } + + return values +} + +// NewStringSet creates an empty string set. +func NewStringSet() StringSet { + return StringSet{} +} + +// Union returns the union of two SringSets. +func Union(s1, s2 StringSet) StringSet { + union := NewStringSet() + + for v := range s1 { + union.Add(v) + } + + for v := range s2 { + union.Add(v) + } + + return union +} + +// Intersection returns the union of two SringSets. +func Intersection(s1, s2 StringSet) StringSet { + intersect := NewStringSet() + + for v := range s1 { + if _, ok := s2[v]; ok { + intersect.Add(v) + } + } + + return intersect +} + +// Difference returns the value of s1 with values of s2 removed. +func Difference(s1, s2 StringSet) StringSet { + difference := NewStringSet() + + for v := range s1 { + if _, ok := s2[v]; !ok { + difference.Add(v) + } + } + + return difference +} + +type numRange struct { + lower, upper int +} + +func (r numRange) validate(n int) bool { + return r.lower <= n && n <= r.upper +} + +type fieldRule struct { + name string + ranges []numRange +} + +func (f fieldRule) validate(n int) bool { + for _, r := range f.ranges { + if r.validate(n) { + return true + } + } + + return false +} + +var ruleMatcher = regexp.MustCompile(`([a-z ]+): ([0-9]+)-([0-9]+) or ([0-9]+)-([0-9]+)`) + +func parseFieldRule(line string) (fieldRule, error) { + res := ruleMatcher.FindStringSubmatch(line) + if res == nil { + return fieldRule{}, fmt.Errorf("failed parsing rule line: %s", line) + } + + name := res[1] + + l1, err := strconv.Atoi(res[2]) + if err != nil { + return fieldRule{}, fmt.Errorf("failed parsing int in rule %w", err) + } + + u1, err := strconv.Atoi(res[3]) + if err != nil { + return fieldRule{}, fmt.Errorf("failed parsing int in rule %w", err) + } + + l2, err := strconv.Atoi(res[4]) + if err != nil { + return fieldRule{}, fmt.Errorf("failed parsing int in rule %w", err) + } + + u2, err := strconv.Atoi(res[5]) + if err != nil { + return fieldRule{}, fmt.Errorf("failed parsing int in rule %w", err) + } + + return fieldRule{ + name: name, + ranges: []numRange{ + numRange{ + lower: l1, + upper: u1, + }, + numRange{ + lower: l2, + upper: u2, + }, + }, + }, nil +} + +type fieldRules []fieldRule + +func (f fieldRules) validFields(n int) []string { + validFields := []string{} + for _, r := range f { + if r.validate(n) { + validFields = append(validFields, r.name) + } + } + + return validFields +} + +type ticket []int + +func parseTicket(line string) (ticket, error) { + t := ticket{} + + for _, n := range strings.Split(line, ",") { + i, err := strconv.Atoi(n) + if err != nil { + return nil, err + } + + t = append(t, i) + } + + return t, nil +} + +func parseInput() (fieldRules, ticket, []ticket) { + rules := fieldRules{} + nearby := []ticket{} + + var t ticket + + if err := processGroups("input.txt", func(group []string) (bool, error) { + if len(rules) == 0 { + for _, line := range group { + rule, err := parseFieldRule(line) + if err != nil { + log.Fatal(err) + } + rules = append(rules, rule) + } + } else if group[0] == "your ticket:" { + var err error + t, err = parseTicket(group[1]) + if err != nil { + log.Fatal(err) + } + } else if group[0] == "nearby tickets:" { + for _, line := range group[1:] { + nt, err := parseTicket(line) + if err != nil { + log.Fatal(err) + } + nearby = append(nearby, nt) + } + } else { + log.Fatal(fmt.Errorf("unknown section %v", group)) + } + + return false, nil + }); err != nil { + log.Fatal(err) + } + + return rules, t, nearby +} + +func part1() { + rules, _, nearby := parseInput() + + invalid := 0 + + for _, t := range nearby { + for _, v := range t { + if len(rules.validFields(v)) == 0 { + invalid += v + } + } + } + + fmt.Printf("Total scanning error rate is %d\n", invalid) +} + +func reduceFields(fieldOptions []StringSet) ([]string, error) { + type fieldOption struct { + options StringSet + position int + } + + workingFields := []fieldOption{} + for i, o := range fieldOptions { + workingFields = append( + workingFields, + fieldOption{o, i}, + ) + } + + // Sort slice by number of options + sort.Slice(workingFields, func(i, j int) bool { + return len(workingFields[i].options) < len(workingFields[j].options) + }) + + for i, o1 := range workingFields { + if len(o1.options) == 1 { + // Remove this option from everywhere else + for j, o2 := range workingFields { + if i == j { + // Skip current outer index + continue + } + + workingFields[j].options = Difference(o2.options, o1.options) + } + } + } + + // fmt.Printf("All options? %+v", workingFields) + + // Sort slice by number of options + sort.Slice(workingFields, func(i, j int) bool { + return workingFields[i].position < workingFields[j].position + }) + + results := []string{} + for _, o := range workingFields { + if len(o.options) != 1 { + return []string{}, fmt.Errorf("some options have multiple values") + } + + results = append(results, o.options.Values()[0]) + } + + return results, nil +} + +func part2() { + rules, myTicket, nearby := parseInput() + fieldOptions := []StringSet{} + + // Get all possible field names + allFields := []string{} + for _, rule := range rules { + allFields = append(allFields, rule.name) + } + + // Add them to every field in ticket + for range myTicket { + s := StringSet{} + s.AddAll(allFields) + fieldOptions = append(fieldOptions, s) + } + + var ticketOptions []StringSet + + for _, nearbyTicket := range nearby { + ticketOptions = []StringSet{} + for _, ticketValue := range nearbyTicket { + validFields := StringSet{} + validFields.AddAll(rules.validFields(ticketValue)) + if len(validFields) == 0 { + // This ticket is invalid + ticketOptions = nil + break + } + ticketOptions = append(ticketOptions, validFields) + } + // Done checking ticket + if ticketOptions != nil { + // Ticket is valid + for i := range fieldOptions { + fieldOptions[i] = Intersection(fieldOptions[i], ticketOptions[i]) + } + } + } + + // fmt.Printf("Final fieldOptions %+v\n", fieldOptions) + + fieldLabels, err := reduceFields(fieldOptions) + if err != nil { + log.Fatal(err) + } + + // fmt.Println("Values: ", fieldLabels) + product := 1 + for i, label := range fieldLabels { + if strings.HasPrefix(label, "departure") { + product *= myTicket[i] + } + } + + fmt.Printf("Product of all departures %d\n", product) +} + +func main() { + part1() + part2() +} diff --git a/d17/input.txt b/d17/input.txt new file mode 100644 index 0000000..c96dc9e --- /dev/null +++ b/d17/input.txt @@ -0,0 +1,8 @@ +#...#.#. +..#.#.## +..#..#.. +.....### +...#.#.# +#.#.##.. +#####... +.#.#.##. diff --git a/d17/main.go b/d17/main.go new file mode 100644 index 0000000..a151be9 --- /dev/null +++ b/d17/main.go @@ -0,0 +1,113 @@ +package main + +import "fmt" + +var ( + activeRune = '#' + inactiveRune = '.' +) + +type point3 [3]int + +func addPoint(p1, p2 point3) point3 { + p := point3{} + for i := range p { + p[i] = p1[i] + p2[i] + } + + return p +} + +type cube struct { + loc point3 + active bool + + tock func() error + world *grid +} + +func (c cube) neighbors() []cube { + directions := []point3{ + // 1 pt + point3{0, 0, 1}, + point3{0, 0, -1}, + point3{0, 1, 0}, + point3{0, -1, 0}, + point3{1, 0, 0}, + point3{-1, 0, 0}, + // 2pt + point3{0, 1, 1}, + point3{0, 1, -1}, + point3{0, -1, 1}, + point3{0, -1, -1}, + point3{1, 1, 0}, + point3{1, -1, 0}, + point3{-1, 1, 0}, + point3{-1, -1, 0}, + point3{1, 0, 1}, + point3{-1, 0, 1}, + point3{1, 0, -1}, + point3{-1, 0, -1}, + // 3pt + point3{1, 1, 1}, + point3{-1, 1, 1}, + point3{1, -1, 1}, + point3{1, 1, -1}, + point3{-1, -1, 1}, + point3{1, -1, -1}, + point3{-1, 1, -1}, + point3{-1, -1, -1}, + } +} + +func (c *cube) tick() error { + +} + +type world [][][]*cube + +func (w world) getCube(p point) *cube { + x := point[0] + y := point[1] + z := point[2] + + if z >= len(w) { + return nil + } + + slice := world[z] + + if y >= len(slice) { + return nil + } + + row := slice[y] + + if x >= len(row) { + return nil + } + + return row[x] +} + +func (w *world) tick() error { + for z, slice := range w { + for y, row := range slice { + for x, cube := range row { + err := cube.tick() + if err != nil { + return err + } + } + } + } + + return nil +} + +func main() { + p := point3{} + p[0] = 1 + fmt.Println(p) + +} diff --git a/d17/main.py b/d17/main.py new file mode 100755 index 0000000..a5da792 --- /dev/null +++ b/d17/main.py @@ -0,0 +1,703 @@ +#! /usr/bin/env python3 +from collections import namedtuple +from itertools import product +from typing import Any +from typing import Callable +from typing import Iterable +from typing import List +from typing import Optional +from typing import Tuple +from typing import Set + + +Point = namedtuple("Point", "x y z w", defaults=(0,)) + + +back_refs = { + "left": "right", + "right": "left", + "up": "down", + "down": "up", + "front": "back", + "back": "front", +} + +ACTIVE = "#" +INACTIVE = "." + + +def add_points(p1, p2) -> Point: + return Point( + p1.x + p2.x, + p1.y + p2.y, + p1.z + p2.z, + p1.w + p2.w, + ) + + +class Cube(object): + + def __init__(self, loc: Point, world: "World", active=False): + self._loc = loc + self._world = world + self.active = active + + self._ticked = False + + def _tock(): + # print("Default tock") + pass + + self.tock = _tock + + # def __init__(self, left=None, up=None, right=None, + # down=None, front=None, back=None): + # # self.set_neighbor("left", left) + # # self.set_neighbor("up", up) + # # self.set_neighbor("right", right) + # # self.set_neighbor("down", down) + # # self.set_neighbor("front", front) + # # self.set_neighbor("back", back) + # + # # tock func + # self.tock = None + + # def set_neighbor(self, direction: str, value: "Cube"): + # backref = back_refs[direction] + # setattr(self, direction, value) + # if value is not None: + # setattr(value, backref, self) + + def neighbors(self, expand=False) -> Iterable["Cube"]: + seen_points: Set[Point] = set() + for diff in product((0, 1, -1), repeat=4): + # from pdb import set_trace; set_trace() + neighbor_point = add_points( + self._loc, + Point( + diff[0], + diff[1], + diff[2], + diff[3], + ), + ) + if self._loc == neighbor_point: + # skip self + continue + + if neighbor_point in seen_points: + # skip points we've already visited + # print("Already seen, skipping") + continue + + seen_points.add(neighbor_point) + + # print(f"Getting point {neighbor_point}") + neighbor = self._world.get_point(neighbor_point, expand=expand) + if neighbor is not None: + # print("FOUND!") + yield neighbor + + def tick(self): + active_neighbors = 0 + for neighbor in self.neighbors(): + # print(f"Neighbor is active: {neighbor.active}") + if neighbor.active: + # print(f"Neighbor is active {neighbor}") + active_neighbors += 1 + + # if self._loc == Point(1, 3, 0): + # import pdb; pdb.set_trace() + + if self.active and active_neighbors not in (2, 3): + # print("Should go inactive") + def _tock(): + # print("go inactive") + self.active = False + + self.tock = _tock + elif not self.active and active_neighbors == 3: + # print("Should go active") + def _tock(): + # print("go active") + self.active = True + + self.tock = _tock + + else: + # print("Should do nothing") + def _tock(): + # print("Empty tock") + pass + + self.tock = _tock + + def __repr__(self) -> str: + return f"({self._loc.x}, {self._loc.y}, {self._loc.z})" + + def to_str(self) -> str: + return ACTIVE if self.active else INACTIVE + + +class AutoExpanding(object): + _l: List[Any] + _zero: int + _item_factory: Callable[[int], Any] + + def __init__(self): + self._l = [self._item_factory(0)] + self._zero = 0 + + def get(self, i, expand=True): + if not expand: + if self._zero+i < 0: + raise IndexError(f"index {i} is out of bounds") + return self._l[self._zero+i] + + if self._zero is None: + self._l = [self._item_factory(0)] + self._zero = 0 + + if i > 0 and i >= len(self._l) - self._zero - 1: + # print(f"resize pos to {i} with {self._l} zero={self._zero}") + self._l = self._l + [ + self._item_factory(j) + for j in range(len(self._l)-self._zero, i+1) + ] + # print(f"> done {self._l} zero={self._zero}") + elif i < 0 and abs(i) > self._zero: + # print(f"resize neg to {i} with {self._l} zero={self._zero}") + self._l = [ + self._item_factory(j) + for j in range(i, -1 * self._zero) + ] + self._l + self._zero = abs(i) + # print(f"> done {self._l} zero={self._zero}") + + # print(f"Now getting item at index {i} from {self._l}") + return self._l[self._zero+i] + + def __getitem__(self, i): + if isinstance(i, slice): + return [ + self[j] + for j in range( + i.start if i.start is not None else self.min_index(), + (i.stop if i.stop is not None else self.max_index()) + 1, + i.step or 1, + ) + ] + + return self.get(i, expand=False) + + def __setitem__(self, i, value): + self.get(i, expand=True) + self._l[self._zero+i] = value + + def __len__(self) -> int: + return len(self._l) + + def __iter__(self): + return iter(self._l) + + def min_index(self) -> int: + return -1 * self._zero + + def max_index(self) -> int: + return len(self._l) - self._zero - 1 + + def get_bounds(self) -> Tuple[int, int]: + return self.min_index(), self.max_index() + + def resize(self, min_index: int, max_index: int): + if min_index < self.min_index(): + self.get(min_index, expand=True) + else: + if min_index > 0: + raise IndexError("Cannot resize to exclude zero") + self._l = self[min_index:] + self._zero = abs(min_index) + + if max_index > self.max_index(): + self.get(max_index, expand=True) + else: + if max_index < 0: + raise IndexError("Cannot resize to exclude zero") + self._l = self[:max_index] + + def __repr__(self) -> str: + return f"" + + +class World(AutoExpanding): + + def iter_cubes(self) -> Iterable[Cube]: + raise NotImplementedError() + + def tick(self): + for c in self.iter_cubes(): + c.tick() + + def tock(self): + for c in self.iter_cubes(): + c.tock() + + def get_point(self, p: Point, expand=True) -> Optional[Cube]: + raise NotImplementedError() + + def trim(self): + raise NotImplementedError() + + def get_all_bounds(self) -> Tuple[Point, Point]: + raise NotImplementedError() + + def true_up(self): + raise NotImplementedError() + + def expand_all(self, i: int): + raise NotImplementedError() + + def count_active(self) -> int: + total = 0 + + for c in self.iter_cubes(): + if c.active: + total += 1 + + return total + + +class GridRow(AutoExpanding): + def __init__(self, y: int, z: int, world: World, w: Optional[int] = 0): + self._y = y + self._z = z + self._w = w + self._world = world + super().__init__() + + def _item_factory(self, x: int) -> Cube: + return Cube(Point(x, self._y, self._z, self._w), self._world) + + def __repr__(self) -> str: + return "[" + " ".join((str(c) for c in self._l)) + "]" + + def to_str(self) -> str: + return "".join((c.to_str() for c in self._l)) + + +class GridSlice(AutoExpanding): + def __init__(self, z: int, world: World, w: Optional[int] = 0): + self._z = z + self._w = w + self._world = world + super().__init__() + + def _item_factory(self, y: int) -> GridRow: + return GridRow(y, self._z, self._world, w=self._w) + + def __repr__(self) -> str: + return f"z={self._z}\n" + "\n".join(( + str(r) for r in self._l + )) + + def to_str(self) -> str: + return f"z={self._z}\n" + "\n".join([r.to_str() for r in self._l]) + + +class Grid(World): + def __init__(self, world: Optional[World] = None, w: Optional[int] = 0): + if world is not None: + self._world = world + else: + self._world = self + + self._w = w + + super().__init__() + + def _item_factory(self, z: int) -> GridSlice: + return GridSlice(z, self._world, w=self._w) + + def __repr__(self) -> str: + return "\n\n".join(( + str(s) for s in self._l + )) + + def to_str(self) -> str: + return "\n\n".join(( + s.to_str() for s in self._l + )) + + def iter_cubes(self) -> Iterable[Cube]: + for s in self: + for r in s: + for c in r: + yield c + + def get_point(self, p: Point, expand=True) -> Optional[Cube]: + try: + # print(f"expand world z to {p.z}") + c = self.get( + p.z, + expand=expand, + ).get( + p.y, + expand=expand, + ).get( + p.x, + expand=expand, + ) + # from pdb import set_trace; set_trace() + return c + except IndexError: + return None + + def trim(self): + for s in self: + for r in s: + first, last = None, None + min_index, max_index = r.get_bounds() + for i in range(min_index, max_index+1): + if r[i].active: + if first is None: + first = i + last = i + if first is None or first > 0: + first = 0 + if last is None or last < 0: + last = 0 + r.resize(first, last) + + first, last = None, None + min_index, max_index = s.get_bounds() + for i in range(min_index, max_index+1): + if len(s[i]) > 1 or (len(s[i]) == 1 and s[i][0].active): + if first is None: + first = i + last = i + if first is None or first > 0: + first = 0 + if last is None or last < 0: + last = 0 + s.resize(first, last) + + def get_all_bounds(self) -> Tuple[Point, Point]: + min_z, max_z = self.get_bounds() + min_y, max_y = 0, 0 + min_x, max_x = 0, 0 + + for s in self: + if s.min_index() < min_y: + min_y = s.min_index() + + if s.max_index() > max_y: + max_y = s.max_index() + + for r in s: + if r.min_index() < min_x: + min_x = r.min_index() + + if r.max_index() > max_x: + max_x = r.max_index() + + return Point(min_x, min_y, min_z), Point(max_x, max_y, max_z) + + def true_up(self): + min_point, max_point = self.get_all_bounds() + + for s in self: + s.resize(min_point.y, max_point.y) + for r in s: + r.resize(min_point.x, max_point.x) + + def expand_all(self, i: int): + min_point, max_point = self.get_all_bounds() + # print(f"expand {i} cell") + # print("expsting min, max:", min_point, max_point) + min_point = add_points(min_point, Point(-i, -i, -i)) + max_point = add_points(max_point, Point(i, i, i)) + # print("new min, max:", min_point, max_point) + self.get_point(min_point, expand=True) + self.get_point(max_point, expand=True) + + +class HyperGrid(World): + def __init__(self): + super().__init__() + + def _item_factory(self, w: int) -> Grid: + return Grid(world=self, w=w) + + def __repr__(self) -> str: + return "\n\n".join(( + str(s) for s in self._l + )) + + def to_str(self) -> str: + return "\n\n".join(( + f"w = {s._w}, " + s.to_str() for s in self._l + )) + + def iter_cubes(self) -> Iterable[Cube]: + for g in self: + for s in g: + for r in s: + for c in r: + yield c + + def get_point(self, p: Point, expand=True) -> Optional[Cube]: + try: + # print(f"expand world z to {p.z}") + c = self.get( + p.w, + expand=expand, + ).get( + p.z, + expand=expand, + ).get( + p.y, + expand=expand, + ).get( + p.x, + expand=expand, + ) + # from pdb import set_trace; set_trace() + return c + except IndexError: + return None + + def get_all_bounds(self) -> Tuple[Point, Point]: + min_w, max_w = self.get_bounds() + min_z, max_z = 0, 0 + min_y, max_y = 0, 0 + min_x, max_x = 0, 0 + + for g in self: + if g.min_index() < min_z: + min_z = g.min_index() + + if g.max_index() > max_z: + max_z = g.max_index() + + for s in g: + if s.min_index() < min_y: + min_y = s.min_index() + + if s.max_index() > max_y: + max_y = s.max_index() + + for r in s: + if r.min_index() < min_x: + min_x = r.min_index() + + if r.max_index() > max_x: + max_x = r.max_index() + + return ( + Point(min_x, min_y, min_z, min_w), + Point(max_x, max_y, max_z, max_w), + ) + + def true_up(self): + min_point, max_point = self.get_all_bounds() + for g in self: + g.resize(min_point.z, max_point.z), + for s in g: + s.resize(min_point.y, max_point.y) + for r in s: + r.resize(min_point.x, max_point.x) + + def expand_all(self, i: int): + min_point, max_point = self.get_all_bounds() + # print(f"expand {i} cell") + # print("existing min, max:", min_point, max_point) + min_point = add_points(min_point, Point(-i, -i, -i, -i)) + max_point = add_points(max_point, Point(i, i, i, i)) + # print("new min, max:", min_point, max_point) + self.get_point(min_point, expand=True) + self.get_point(max_point, expand=True) + + +def part1(): + # Load world + g = Grid() + with open("input.txt") as f: + for y, row in enumerate(f): + row.strip() + for x, c in enumerate(row): + g.get(0).get(y).get(x).active = c == ACTIVE + + g.true_up() + + print("time = 0\n_____________") + print(g.to_str()) + + for t in range(6): + g.expand_all(1) + g.true_up() + + g.tick() + g.tock() + # g.trim() + g.true_up() + + print(f"time = {t+1}\n_____________") + print(g.to_str()) + # print(g) + + total = g.count_active() + print(f"Total active: {total}") + + +def part2(): + # Load world + g = HyperGrid() + with open("input.txt") as f: + for y, row in enumerate(f): + row.strip() + for x, c in enumerate(row): + g.get(0).get(0).get(y).get(x).active = c == ACTIVE + + g.true_up() + + print("time = 0\n_____________") + print(g.to_str()) + + # g.expand_all(1) + # g.true_up() + # print("EXPANDED\ntime = 0\n_____________") + # print(g.to_str()) + # return + + for t in range(6): + g.expand_all(1) + g.true_up() + + g.tick() + g.tock() + # g.trim() + g.true_up() + + # print(f"time = {t+1}\n_____________") + # print(g.to_str()) + # print(g) + + total = g.count_active() + print(f"Total active: {total}") + + +def test(): + g = Grid() + + # print("test") + # s = [ + # "...", + # "###", + # "...", + # ] + # for y, row in enumerate(s): + # row.strip() + # for x, c in enumerate(row): + # g.get(0).get(y).get(x).active = c == ACTIVE + # + # g.true_up() + # + # print("time = 0") + # print(g.to_str()) + # print(g) + # + # p = g.get(0).get(0).get(1) + # from pdb import set_trace; set_trace() + # p.tick() + # p.tock() + # print(g.to_str()) + # + # p = g.get(0).get(2).get(1) + # from pdb import set_trace; set_trace() + # p.tick() + # p.tock() + # print(g.to_str()) + + # print(list(g[0][0][0].neighbors())) + # + # print(g.to_str()) + # + # + # return + + # g.get(1).get(1).get(1) + # g.get_point(Point(1, 1, 1)) + # g.expand_all(1) + # g.true_up() + # print(g) + + # r = GridRow(0, 0, None) + # print(r) + # r.get(1) + # print(r) + # print(r[:3]) + # r.get(-3) + # # print(r[0:3]) + # print(r[-2:]) + # + # print("Resize") + # print(r) + # r.resize(0, 3) + # print(r) + + # return + + # c = g.get(0).get(0).get(0) + # print(g) + # from pdb import set_trace; set_trace() + # neigh = list(c.neighbors()) + # print(neigh) + # + # return + + print("test") + s = [ + ".#.", + "..#", + "###", + ] + for y, row in enumerate(s): + row.strip() + for x, c in enumerate(row): + g.get(0).get(y).get(x).active = c == ACTIVE + + g.true_up() + + print("time = 0\n_____________") + print(g.to_str()) + # print(g) + + # g.expand_all(1) + # g.true_up() + # print(g.to_str()) + # print(g) + # return + + for t in range(6): + g.expand_all(1) + g.true_up() + # print(g.to_str()) + # p = g.get(0).get(3).get(1) + # from pdb import set_trace; set_trace() + + g.tick() + g.tock() + # g.trim() + g.true_up() + + print(f"time = {t+1}\n_____________") + print(g.to_str()) + # print(g) + + total = g.count_active() + print(f"Total active: {total}") + + +if __name__ == "__main__": + # part1() + part2() diff --git a/d17/util.go b/d17/util.go new file mode 100644 index 0000000..7589424 --- /dev/null +++ b/d17/util.go @@ -0,0 +1,300 @@ +package main + +import ( + "bufio" + "errors" + "fmt" + "math" + "os" +) + +var ( + errItemAlreadySet = errors.New("cannot set item in direction as one is already set") +) + +// ProcessLines maps a function on lines parsed from a file. +func ProcessLines(path string, f func(string) (stop bool, err error)) error { + file, err := os.Open(path) + if err != nil { + return err + } + defer file.Close() + + scanner := bufio.NewScanner(file) + for scanner.Scan() { + stop, err := f(scanner.Text()) + if stop || err != nil { + return err + } + } + + if err := scanner.Err(); err != nil { + return err + } + + return nil +} + +// ProcessGroups maps a function on groups of lines parsed from a file separated by some string. +func ProcessGroups(path, separator string, f func([]string) (stop bool, err error)) error { + group := []string{} + + if err := ProcessLines(path, func(line string) (stop bool, err error) { + if line == separator { + stop, err = f(group) + if stop || err != nil { + return + } + group = []string{} + } else { + group = append(group, line) + } + + return + }); err != nil { + return err + } + + _, err := f(group) + + return err +} + +// StringSet is a set of strings.. +type StringSet map[string]bool + +// Add an item to a StringSet. +func (s *StringSet) Add(v string) { + (*s)[v] = true +} + +// AddAll adds all items in a list to the set. +func (s *StringSet) AddAll(l []string) { + for _, v := range l { + s.Add(v) + } +} + +// Items returns all values in the set as a list. +func (s StringSet) Items() []string { + values := []string{} + for k := range s { + values = append(values, k) + } + + return values +} + +// NewStringSet creates an empty string set. +func NewStringSet(values []string) StringSet { + v := StringSet{} + v.AddAll(values) + + return v +} + +// Union returns the union of two SringSets. +func Union(s1, s2 StringSet) StringSet { + union := NewStringSet(s1.Items()) + union.AddAll(s2.Items()) + + return union +} + +// Intersection returns the union of two SringSets. +func Intersection(s1, s2 StringSet) StringSet { + intersect := StringSet{} + + for v := range s1 { + if _, ok := s2[v]; ok { + intersect.Add(v) + } + } + + return intersect +} + +// Difference returns the value of s1 with values of s2 removed. +func Difference(s1, s2 StringSet) StringSet { + difference := StringSet{} + + for v := range s1 { + if _, ok := s2[v]; !ok { + difference.Add(v) + } + } + + return difference +} + +// Point represents a point on a coordinate system. +type Point struct { + x, y int +} + +// AddPoints adds two points together. +func AddPoints(p1, p2 Point) Point { + return Point{ + p1.x + p2.x, + p1.y + p2.y, + } +} + +// PowInt is equivalent to math.Pow but for integers. +func PowInt(x, y int) int { + return int(math.Pow(float64(x), float64(y))) +} + +// LinkedGridItem is a single item in a linked grid. +type LinkedGridItem struct { + location Point + left, right, up, down *LinkedGridItem + grid *LinkedGrid +} + +func (item LinkedGridItem) String() string { + return fmt.Sprintf("%v", item.location) +} + +// Location of the item. +func (item LinkedGridItem) Location() Point { + return item.location +} + +// Left gives a pointer to the item on the left. +func (item LinkedGridItem) Left() *LinkedGridItem { + return item.left +} + +// Up gives a pointer to the item above. +func (item LinkedGridItem) Up() *LinkedGridItem { + return item.up +} + +// Right gives a pointer to the item on the right. +func (item LinkedGridItem) Right() *LinkedGridItem { + return item.right +} + +// Down gives a pointer to the item below. +func (item LinkedGridItem) Down() *LinkedGridItem { + return item.down +} + +// SetLeft gives a pointer to the item on the left. +func (item *LinkedGridItem) SetLeft(other *LinkedGridItem) error { + if item.left != nil || other.right != nil { + return errItemAlreadySet + } + + item.left = other + other.right = item + + return nil +} + +// SetUp gives a pointer to the item on the up. +func (item *LinkedGridItem) SetUp(other *LinkedGridItem) error { + if item.up != nil || other.down != nil { + return errItemAlreadySet + } + + item.up = other + other.down = item + + return nil +} + +// SetRight gives a pointer to the item on the right. +func (item *LinkedGridItem) SetRight(other *LinkedGridItem) error { + if item.right != nil || other.left != nil { + return errItemAlreadySet + } + + item.right = other + other.left = item + + return nil +} + +// SetDown gives a pointer to the item on the down. +func (item *LinkedGridItem) SetDown(other *LinkedGridItem) error { + if item.down != nil || other.up != nil { + return errItemAlreadySet + } + + item.down = other + other.up = item + + return nil +} + +// LinkedGrid is a 2d array of grid square. +type LinkedGrid [][]*LinkedGridItem + +// Print a linked grid. +func (grid LinkedGrid) Print() { + for _, row := range grid { + for _, item := range row { + fmt.Print(item.String()) + } + + fmt.Print("\n") + } +} + +// NewLinkedGrid initializes a new linked grid of a given size. +func NewLinkedGrid(width, height int) *LinkedGrid { + + var w = make(LinkedGrid, height) + + for y := 0; y < height; y++ { + w[y] = make([]*LinkedGridItem, width) + + for x := 0; x < height; x++ { + item := LinkedGridItem{location: Point{x, y}} + + if x != 0 { + _ = item.SetLeft(w[y][x-1]) + } + + if y != 0 { + _ = item.SetUp(w[y-1][x]) + } + + w[y][x] = &item + } + } + + return &w +} + +// MapInt maps a function onto a list of ints. +func MapInt(a []int, f func(int) (int, error)) error { + var err error + + for i, v := range a { + a[i], err = f(v) + if err != nil { + return err + } + } + + return nil +} + +// ReduceInt maps a function onto a list of ints. +func ReduceInt(a []int, start int, f func(int, int) (int, error)) (int, error) { + var err error + + result := start + + for _, v := range a { + result, err = f(result, v) + if err != nil { + return 0, err + } + } + + return result, nil +} diff --git a/d18/input-small.txt b/d18/input-small.txt new file mode 100644 index 0000000..9e1ad36 --- /dev/null +++ b/d18/input-small.txt @@ -0,0 +1,4 @@ +2 * 3 + (4 * 5) +5 + (8 * 3 + 9 + 3 * 4 * 3) +5 * 9 * (7 * 3 * 3 + 9 * 3 + (8 + 6 * 4)) +((2 + 4 * 9) * (6 + 9 * 8 + 6) + 6) + 2 + 4 * 2 diff --git a/d18/input.txt b/d18/input.txt new file mode 100644 index 0000000..a2341bf --- /dev/null +++ b/d18/input.txt @@ -0,0 +1,373 @@ +(4 + (2 * 7) * 4) + (6 * 9 + 8 * 4 + 7 * 3) * 3 * 5 +5 * 9 + (5 * 9) * (6 + 2) + 3 + 7 +8 + 5 * 9 * 9 + 9 + 5 +(7 + 9 * 8 + 4 * 6) + 6 * ((9 + 9 + 5 * 7 + 4) * 8 * 2 + 5 * 6 + 2) + 2 * 6 +(6 * (5 + 8 * 7 * 8 + 4) * (7 + 7 * 3 * 5)) + 5 * (8 + (8 + 3 + 5 + 5) + (3 + 2 + 7 * 2 * 9) + 6 * 5 + (2 * 6)) * ((4 * 3) + 3) + 9 * (3 + 6 * 2 + 3 * 8) +2 * 9 + (6 * 2 + 6 + (9 + 6 + 8 + 5 + 5) + (8 + 7 * 4 + 3) + 8) * (4 + 4 * 2 + 6) +5 + 4 + 5 + (7 + (9 + 7 + 4 + 4 + 4 + 5) + 2 * 4) + 4 * 9 +9 + (7 * 8 + (6 + 3 + 4)) + (5 * 9) +2 * 4 + 8 + (5 + 8) * 9 * (9 + (5 + 3) + 3) +8 * 6 * 5 + 8 + (8 * (2 + 8 * 7 * 5 + 3 + 5)) * 2 +6 * ((3 + 4 * 3 * 7 * 8) * 8 + (9 + 5 + 2 * 3) * 3 * 2) + 7 + 8 * 8 + 4 +9 + 3 + 7 * 8 +(9 + (4 + 9 + 3 + 5 * 5 + 5) * 5 + 9 * 6) * 3 * 2 * 6 * 5 +7 * 9 * 6 +(5 + 2 * 8) * 8 + 3 + 8 +9 * 5 * (5 + (5 * 4 + 8 + 6 * 5) * (9 * 7 + 5)) * 3 * 9 +(6 * (8 * 3 * 7 + 2) * (3 + 9 + 5 + 5) + 3) + 7 * 3 +7 + 9 + (4 + 9 * (4 * 6 + 3 * 8 * 5) + 8 + 9 + 3) + 6 * (6 + 8 + 7 * 9 * 6 + 6) + 7 +2 * (5 * 5 + 6 + (5 + 5 * 5 + 6)) * 4 + 5 + 2 +8 + 2 * (8 * 7 * 4 + 8) * 9 +9 + 5 * (4 * 8 + 9 * 6 + (3 * 3) + 2) + 5 + (4 * 5 + 2 * 2) +(5 * 7 + 2) + 3 + 9 +7 * 9 + 8 +3 * 7 * (7 + 5 + 8 * 5 * 8) +(7 + (3 * 6 + 6 * 9 + 2) * 8 * 6 + 6 + 2) * 6 +4 * (7 * 5 * (6 + 8) * 7 * (5 * 3 * 2 * 9 + 2 * 4) * 6) * 2 + 2 * 5 +((3 * 3 * 9 + 8) + 2 + 5 + 8) + 6 * (6 + 9 * 2) + 7 * 9 * ((9 + 4 + 4) * 4 + 4 + 9) +7 * (4 * 2 + 3 + 7 + 5) * (8 + 2 + (5 * 9) * 2 + 3 * 5) +7 + (8 + 3 + 8 * 4 * 2 * 2) + 7 * 2 + ((3 + 5 * 3 + 5) * 8 + 3) + 8 +7 + 2 + 9 * 9 + 5 +((6 + 4 + 2) * 2 + 9) + 3 * 6 * (6 + 4 + 9 + 2 + 6) * 9 +6 + 6 * (9 * 9 + 6 + 6) + 2 * 6 +2 + 5 * ((4 * 4) * 6) + (3 * 3 + 2) * 9 + 5 +9 * 4 + 8 * 5 * ((6 * 5 * 4) + (3 + 8 * 7 + 6 * 7) * (6 * 6 + 7) * 8 + 4 + 7) +3 * 8 + (4 + (7 * 7 + 9 * 8 * 6 + 7) * (8 * 4 + 4 * 6 * 4 + 4) + 2 * 9) +3 + 6 * 2 * 3 * (4 + 7 + (3 * 6 + 7 * 8) * 7 + 9 * 8) +2 + 8 + (5 * 4 * 2 * 5 + 5) * 4 + 3 * 4 +6 + 4 + (5 + 5) +6 * 3 + 8 + (8 + 2 + 9 * 3) * ((6 * 8 + 6) + 6 + (7 * 4 * 3) * 4 + 9 + 3) +((9 + 7 + 9 + 2 * 7 * 7) + 8 * 6) + 2 + 7 +6 * (6 + 9 * 2 + 4 * 7 + 8) + 5 * 9 +((2 + 5 + 6 * 3) + 7 + (7 * 6 * 8 * 3 + 8 * 3)) + (8 * 6 * 8 * 9 * 5) +6 * 7 * 5 + 5 * (2 * 9) * 4 +(8 * 7) * (2 * (7 + 3) + 3) + 8 +(7 * 9 + 7 + 7 + 7 + 7) + (7 * 5 * 8 + 4 * 5) + 6 +5 * (6 * 7 * 8 * 5) * 6 +5 * (2 + (6 * 7) * 8 * 3 + 6 * 2) + 2 * 4 + 8 + 3 +3 * 5 + 6 + 6 +((9 * 9) * 6) + (4 + 9 * 6 + 4 * 9 + 7) +(3 + 9 + 2) * (3 * 7 * 7 * 7 * (8 * 8 * 4 + 3 + 8)) + 2 +6 * 6 + 8 +((9 + 5 + 8) + 9) + 7 + ((9 * 5) * 3 * (3 * 4 * 4 + 3) * 7) + ((5 + 6 + 2) * (7 * 2 * 9 * 8) * 5) +6 + (8 * 7 * 6 + 5) + 9 * 7 * 7 * 7 +2 + (4 * 9 * 3 * 9 + 8) + 2 * 7 * 3 + 4 +7 + 3 + (5 + 7 * (4 + 4 * 8) + 2 + 8 * 6) * 2 +(2 * 5 * (4 * 7) * 9 * (3 + 7)) + 3 * 4 * (2 * 3 * 8 * 4) * ((6 + 2 * 2) + (6 * 5 * 7 * 6) + 9 * (8 + 4)) +((9 + 3 + 5) + 8) * 2 +2 + 4 + 7 + 5 * (6 * 7 + 8 * (4 * 3 + 6 * 4 + 7) * (7 + 3 + 7 + 3 * 2) + 8) +5 + (9 * 8 + 5) +(2 + (9 + 7 * 8) + (6 + 7) + 6) * 5 + 3 * 2 +7 + (9 + (8 * 7 * 9)) * 8 + 3 +9 * (9 + 4 * 2 * 3 + (6 + 7 * 8 + 9)) + 6 * ((7 * 4 + 7 * 4) + 2 * 6 * 5 + 6 * 6) +((3 * 3 + 4 * 9) + 7 + 7 + 3) * 8 +9 + 8 * (2 + 6 + 8 * 6 + 3 + (8 * 6 * 6 * 4 * 6)) +3 * (9 + 2 * (9 + 2 * 8) + 3 + 8 * 5) + (9 + 8 + (6 * 9 + 2 + 8 * 5 + 7) * 7) * 2 +((2 + 9) + 3) * 6 * 2 * 2 * 4 + 7 +2 * 3 + 4 + (7 + (7 * 5 * 5 + 5) * 9 + (3 + 3 * 5) + 3 * 8) +4 * (8 + 2 + (3 * 7 + 4 + 2 * 6 + 2) * 8 + 7) +4 + (5 * 9 * (8 + 3 * 9 + 9 + 5) * (3 * 8 + 9 * 8)) * 8 + 9 +4 * 5 * (2 + 2 + 7 + (3 * 7 * 4 * 2) + 3) * 6 +((8 * 8 * 4 + 4 + 5) + 6) + 9 * (3 * 3) * 4 +9 * (8 + (6 + 2 * 7 + 3 + 8 * 8) * 3 * (9 + 3) * (3 + 7 * 3) + 5) +9 * 3 +6 * (7 + 8 * 8 * 4) * 6 * 9 + (4 * 7) * 4 +4 * (3 * (4 * 9 * 6) + 5 + 5) * 4 * 6 * 6 * ((9 + 3 * 6 + 5 + 8) + 4) +5 * 2 * (4 * 3 + (8 * 4 + 2 + 2) * 6 * (8 * 8 * 2 + 7 + 9) + 3) * 5 + (4 + 6) +3 + (5 + 6 * 5 * 9) * 9 + 7 +((3 + 6 + 8) * 7 * 3 + 4 + 4 * 8) * 2 * 2 +2 + ((9 + 9 * 4 + 2 + 3) * 4 + 9 + 5 + (7 + 3 * 9)) + 8 + 7 * 3 +5 * 5 * (5 * 6 * 6 + (3 + 4 * 8 + 7) * 2) * 6 + 4 + 3 +4 + 3 * (5 + (6 * 5 + 6 * 2) * 4) + 9 + 7 * (5 * 5 + 9 * 5) +2 + (6 * 7) + 7 + 3 * 7 +5 * 7 * (6 + (9 * 5)) * 4 + 2 +((7 * 7 * 3) + 2 + 2 + (9 + 8 + 3)) * (3 * 8 + 6) + ((6 + 2 * 6) * (2 * 4 + 3 + 8 + 2)) * 8 +((8 + 3 + 8 + 5 + 8 * 3) * 2 + 4 * (6 + 4)) * 8 * 2 * 5 + 9 +7 + 6 * 3 + 3 + (5 * 7 + 3 + 3 + 8) * 6 +8 + 7 + ((5 * 9 * 3 + 3 + 4 + 6) + (6 * 6 + 2 + 6) + 8) +5 + 5 +6 + (6 * 5 * 7 + 8) +(8 + (9 + 2 + 8 + 2 + 2) * 4 + 7 * 6) * 9 * 6 * (6 * 6 * 5 + 5 * 4) + 7 + 9 +3 + 8 + (3 + (6 * 9 + 9 * 2 * 3 * 4) * 3 + 9 * (4 * 2) + (3 * 2 * 9 + 2)) +(5 * 8 + 7 * 8 + (2 + 3 * 8) * (8 + 4 * 7)) * 3 +8 + 2 * (2 + (6 * 6 + 9 * 3 + 6) + (9 * 2 * 4) + 6 * 4 * (6 * 3 + 2 + 6 + 3 + 5)) + 8 + 4 * 9 +8 + 8 + (4 * 9 + 9) +5 + 5 * (5 + 8 + (3 * 9 * 9 + 8 + 8 * 2) * 5) * (8 + 7 + 7 + 8 + (2 + 7 * 4 * 8)) +6 * 3 + 6 + ((9 * 5 * 4 + 6 + 5 + 5) * 6) * 2 + (6 * 5 + 5 * 7 * 8 * (3 + 7 * 7 * 9)) +4 + (3 + 4 + 5 * (4 * 2 + 7 * 9 + 6 + 6)) + (7 + 7) +2 * (6 + 2 + 6 * 3 + 4) + (6 + 5 * 4 * 8 + 3 + 7) + 8 + 3 * 5 +((5 + 3 + 7 * 2 + 9 * 5) + 7 * 7 * (4 + 7 + 9) + 8 + 6) + 3 +((9 * 9 + 2 * 7 * 5 * 6) + 8 * 7 * 4 * 2 + 6) * 5 * 9 +((3 * 3 * 2 + 5 + 6) * 7 + (3 * 6 * 2) * 3 + 3) + 9 * 7 + 5 +(7 + (4 + 7 + 6 * 8 + 9 * 9) + 7 * 2 * 2) * 7 +(9 * 3 * 9) + ((2 * 6 * 6 + 9 * 7) * 3) + 3 + 8 + 8 +2 + (3 * 5) * (2 + 8 + 8 * 3 * 6 + 6) * 6 * 9 +(4 * 7 * 7 + 3 + 4) * 3 * 9 + 6 * (2 + 5 * 4) +(8 * 4 + 3 * 8) * 4 * 5 +(7 + 5 + (4 + 2) + 4) + (2 * 5 * 9 * 2 * 6) +9 * 4 + 3 + 8 * (2 * 4 + 7 * 2 * 2) * (2 + 6 + 5 + 9 + 5) +8 + 3 * (6 * 8) + (2 * 4 + 7 * 8) +(9 + 6 + 3) * 5 + (9 * 8) * 5 + 6 * 5 +((6 * 2 + 6 * 2) + 3 + 7 + 5 * 8) * 2 + 2 +2 + (9 * 3 * 9) * (4 + (6 + 4 + 7) + 5) + 9 +(3 + 4) + 5 + 7 + 7 +9 + 8 + 8 + 7 + 5 + ((2 + 7 * 9 * 7 * 6 * 9) * 8 * 8 + 7 * 3 + 9) +(8 * 7 * (8 * 7)) * 9 + (4 * (4 + 9) * (7 * 9 + 9 + 6 * 5 + 5) + 7) +(6 + 7 * 9 + 5 + 5) * 5 * (2 + 6 + (3 * 6) + (7 + 3 + 5 * 5) + 9) +2 + ((7 + 8 * 2 + 8) * 4 + 2) * 9 * 9 + 8 +8 * 8 * 7 * 2 + 2 +7 * 2 + 9 + ((5 * 2 + 6 * 9 + 8 + 7) + 6 * 2 + 8 + 4 * (3 * 2 * 3 * 2)) +5 * (7 * 5 + (7 * 9) * 4 * 6 * (8 + 7 + 3 + 9 + 9)) * 4 +8 * ((3 + 7 + 5) + 7) + 5 + (6 + 4 + 6 + 4 * 4) + ((2 * 6) * 3) + 9 +3 * 3 +4 * (5 + 5 + 6 + 2 + 7) + 7 * 6 +(7 + 4 + 5 * 9 + 5 + 8) * 8 * (7 * 9 * 9) + 4 +3 + (9 * (7 * 7 + 3 * 4 + 8 + 5) * 7 * (2 * 4) + 9 + 5) * (4 + 7) +6 * (5 * (6 * 2) + 6 + (4 * 8 + 9) + 3 * (2 * 4 + 4)) * 6 * 5 + 6 + 3 +(9 * 3 * 9) * 8 * 5 * (8 + 3 + 2 + 9) +(8 + 8 * (8 * 9) + 2 + 7) + 8 * (5 * 7 + 6 + 2 * 4 * 2) + 6 * (3 * 8 + 6) * 2 +2 * (8 * 5 + 7) * 8 + 7 * 9 +4 * 4 * (5 + (5 * 4 + 2 * 9 + 5 + 7)) * 8 * ((4 * 9 + 4) + 6 * (7 + 2 + 4 * 8 * 9)) +4 * 6 + (4 * 8 * 3 * (9 + 8) * 7 * 9) +(6 + 9 + 3 * 2 + 8 * 8) * 6 +(8 + (3 + 3 + 2 * 3) + (6 + 7 * 6) + 7 * 4 + (9 * 5 * 4 * 6 + 2)) * 2 + 5 +4 * 6 + 2 * 5 * 2 + (5 + 3 + 2 + (5 * 3 * 3 + 7 * 6 + 2) + 8) +9 + 2 + (7 * 7 + 7 + 9) +5 + 8 + (8 + (5 + 9 + 6 * 2 * 4 * 4)) * 9 +(2 + 4 + 8 + 7 * 8 * 5) + 3 + 3 + (9 + 9 + (9 * 2 + 6 + 4 + 4) + 6 * 2) + 2 +7 + (6 + 5 * 2 * 9 + 7 + (9 + 7)) * (3 + 6 + 2 * 5 * 3) +8 + (9 + (4 * 3 * 7 * 7) * 7) + 9 * 6 +6 * 9 * ((8 + 5) + 9) * 7 * 8 +(2 * 9 + 2) + (6 * 3 * 3 + 6 * 7 + 9) +7 * 5 * (4 * 4 + 7 * 4 + 8 + 3) +3 * (6 + (5 + 3) + 5) * 3 +(7 * (9 * 5 * 9 + 2 + 4) + 3 * 8 + (9 + 7) + (2 * 9 + 5)) * (6 + 3 * 9 + 3 + (7 + 4 * 9 + 5) + 9) * (8 * 2 + (2 * 9 + 7 + 5 * 4) * 4) +4 + 7 + 5 + 6 * 8 +5 + 4 + 3 +9 * (6 * 2 + 7 + 5) * 3 * 2 * 2 +7 * 4 + ((6 * 7 * 6 * 8 + 6 * 9) * 7 * 3) + 8 +9 * 5 + 4 + 8 + 8 * 8 +(3 + 6) * 2 * 7 * (2 * 7 + 2 + 6 + 3) +5 * 2 + 8 * 7 + (4 + 8 + (3 * 6 + 7 * 2 + 4 + 7)) +6 + (8 + 6 * (9 * 7 + 2 + 2 + 3 + 4) * (4 * 7 + 2 + 4 * 3) * 3) +(8 + 5 * 2) * (9 * 4) + 5 +3 * (4 * 5 * (4 + 3 + 4) + 5 * (3 + 6 + 3 * 7 * 7)) * 3 +2 + 7 + (8 + 3) + 8 +8 * (9 * 8 * 3) + 4 +(2 * 6) * 3 +((9 * 6 + 3 + 3 * 9 + 7) + 2 * (2 + 9 * 8 + 2 * 4) + 9 * 8 + 6) + (5 * 9 * (2 + 7) + 7 * 9) + 7 +4 + 7 * ((3 * 7 + 2) * 9 * 7 * 2 + 4 + 3) * 4 * (3 + 8 * 9) + 6 +9 * (9 + (9 * 6 + 2 * 7 + 6) + 7 * 2 + 2) +(9 * 2 + 4 + 8 + 6 * 8) * (4 + 8 + 7) * 5 + (4 * 2 + 2) * ((4 * 5) * 8) * 2 +(5 * 9 + 9 + 2) * 3 + ((7 * 5 + 9 * 3) + 2 + 3 + 6 + 7) + 4 * 6 * 6 +9 * 8 + 3 * 4 * (9 + 5 + 7 + 5) * (6 * (7 + 4 * 6 * 7) + 6 * (6 * 5 * 3 + 9 + 4) + (2 * 3 + 3 + 6)) +7 * 6 * 2 + (8 * 9 + (6 * 7 * 8 + 6 + 9 * 8) * 3 + 6) +5 + 7 * 8 + 2 + ((2 + 4) * 7) +2 * 5 + 6 * 6 * (3 * 6) +6 * 6 * 6 * (6 * (4 * 4 + 5) * 4 + 3 + 9) + 4 +((3 * 4 * 7) * 5 * 9 + 7 * 6 + 5) + 2 * 2 * 6 + 4 * 8 +7 * 2 * (3 + (6 * 9 * 9) * 4) * (5 * 8 * 7 * 6 + 2 * 9) * 7 +9 + (6 + 6 + (8 + 8 * 3 + 6 + 6)) +5 * 2 + 7 + 3 * (9 + 9 * 9 * 9 * (4 * 4)) * 2 +4 + 6 + 3 + (2 + 2 * 7 * 2) + 5 + 7 +7 * 9 * 9 * 2 * 4 + 7 +6 + (6 + 5 + 5) + 7 + 4 +9 + (9 * (7 * 3 + 9 + 7 + 8 * 8) * 6 * 5) + 2 * 5 +8 + 6 * 8 +8 * (9 * 6 + 4 + 8 + 8) +((8 + 3) + 8 * 2) + (3 * 6 * 7 + 7 + 4 + 2) * 9 * 5 +6 * (4 * 5 + 6 * 7 * 4) + (2 * 8 + 4 + 7 + 7 + 6) + 9 + 5 +9 * 8 * (2 + 7 + 9 + 4 + 5) + (8 * (3 * 8 + 3 * 6)) + ((7 * 2) * 7) + 2 +9 + 4 + 9 * 2 * (5 * 2 + 6 + (9 * 5 + 8 + 2 * 5) + 6 + 6) + 7 +9 + 9 * ((3 * 6) + (5 + 5 + 7 * 9 * 4 + 9) + 2 * 6 * 6) * 5 +(9 * (3 * 2) + 8 * 2) * (6 * (8 + 3 * 8 + 5 * 5 * 9) + 4 + 9 * 6) * 5 + 9 * 6 +7 * 9 * (2 * 9 + 4 * (3 * 2 * 6 * 9 + 5 + 6) + 2) + 7 * 6 + 3 +9 + (5 * (3 * 9) + 4 * 6 + 6) + 9 + 8 * 5 +8 + 8 * 8 + (9 + 4 * (5 + 3 * 8 * 3 * 4 * 4) + 2 * 8 * (9 * 6 * 4 * 6 + 9)) +(6 + 6 * 3 + (5 + 8 * 4 + 4) + 3) * (3 + 7) * (6 + 5 * 4 * 6 + 6 + (5 * 7)) +(9 + 7 + 6 + (8 * 8) * 4 * 6) + 3 * 5 +5 * 2 * 3 + (3 + (6 + 9 * 2) * 3 * 3) +2 + (8 * 7 * (4 * 8 * 2 + 6 * 7)) * 5 + 5 + (8 * 5) +9 * 6 * 4 * 2 * ((6 * 3 + 9 * 8) * 5) * 3 +((8 + 6) + 6 * (8 * 5 * 5 * 7) + (2 + 9 + 6 * 7) * 7 * (2 + 9 * 7 * 3)) * ((7 * 5 + 2 * 5) + (8 * 7)) +(7 + 8) * 6 * 9 + 6 + 6 * 8 +7 * 8 + (8 * 2) * 7 * 8 * 9 +9 * ((8 + 6 * 9 + 2 + 3 * 2) * 2 + 4 + 3 + 7) * 2 * 6 +2 + (8 + (2 + 9) * 7 * 4 + (8 * 6 + 8 * 6 * 4 + 5) + 6) + 4 * (9 + (3 + 4) * (3 * 9 * 7 * 6 + 9 + 7) + 9 * 6 * 3) +2 + (8 + (8 * 2 + 3 * 8 * 4 + 2)) + 3 * 6 +(5 * 5 + (3 + 5 * 6 * 9 + 4 * 4)) * 8 * (7 * 7 + 3 * 7) +9 + 6 * (9 * 2 + 2 * (9 + 6 * 8 + 5 + 3)) +5 * 5 + 5 * (7 * 3 * 3 * 5) + 6 +7 * 5 * 7 * ((6 * 3 + 5 * 8 * 6) * 7 + 4 * 5) + 7 +(5 * 4 + 8) * 3 + 6 + 9 + 6 +(7 + 7 + 4 + 8) * (2 * 7 + 9) * 2 * 4 +2 + ((7 + 2 + 9 * 4 + 2) * 6 + 9) +9 + 2 + (7 + 6 + 4) * 3 * 8 +5 + 7 * 2 + 2 * (3 * 4 + 4 * 6) + 2 +2 + (7 + 2 + (9 * 3 * 5 + 7 + 7) + 5 * (7 + 7 * 2 * 4 * 7 * 4) + 5) * (6 + 2 * 5 + (4 * 6 + 4 * 8 * 4) + 7) * 2 * 5 +((5 * 9) * 9) * 2 + 4 + ((3 + 6) + (9 + 3 + 6 + 3) * 3 * 5 + (9 + 9 + 6 * 7) + 7) * 2 + 9 +4 + (4 + 4 + 6) + 6 + 5 * 9 + 8 +(3 * 8 * (7 * 5 * 7 * 5 * 7 + 2)) * 7 * 4 + 3 + 2 + 4 +(4 * 8 + 7 + 8 * 5 * 9) + 2 * (5 * 2 * 3 * 9) + 7 + 7 * 2 +6 * 3 * (4 + 6) + 7 + 2 +(5 + 4 + 4 * 8 + (4 * 6 * 5 + 7 * 4 * 2)) * 9 * 6 * 6 * (3 + 5 + 9 * 7) +4 * (5 * 2 + 8 * 9 * 3) + 3 +7 * 3 + 7 + 5 + ((6 * 8 * 8 + 8 + 2 * 4) * 8 * 2 * 9) +4 * 2 + 6 + 2 +(2 * 2 + 2 * 9 * 6) + (5 + 9) * 3 * 9 * 5 +(5 + 5 * (3 + 3 + 7) * (3 * 7 * 7)) + 4 +9 + 7 + 9 + 5 * 6 +(6 + 9 + (4 + 7 * 7 * 4) + (9 * 2 + 9 + 5 + 6)) + 7 * 8 +5 + (5 * (6 * 5 + 8 + 2) + (4 * 7 * 4 * 7 * 7 * 8) * 8) +4 + (6 + 6 * 2 + 9) + 7 * ((3 + 8) * (3 * 5 + 5 * 3 * 3 * 6) + (4 + 9 * 3 + 3 * 2 + 9)) +(7 * (7 + 7 + 5) * 8 * 2 * 8 + 3) + (2 * 4 + 8 * 7 + 3 + 2) + 7 * (7 + 2 + 2) +(3 * 7 * 4) * 5 + 4 * 7 * 8 * 4 +7 * 3 * (2 * 7 * 9 * 7 * (8 + 4 + 2) * 3) + 7 +7 * (9 + 2 + 5 + 5 + 7 * 5) +5 + 2 * 9 * (8 * 6 * 8 + 2 * 7) +4 + (2 + (2 * 5 * 7 * 5) + 3 + 6) + 8 * ((3 + 4 * 4 + 5 * 3 + 6) + 2 + (5 * 8)) + 8 + 3 +2 * (9 * 7 * 3) + (8 + 7 + 8 + 2 * 3 + 9) + 8 + 9 +8 * (7 + 5 * 3 + (2 * 6 * 6 * 4) + 9) + 3 * 4 +3 + 4 * 8 * 9 + (6 + (5 + 7 * 7 * 4)) + 7 +(5 + 6 + 8 + 5 * 7) * 2 + 5 * (9 * (9 * 9 + 8 + 5) + 7 * 4) +8 + (8 * 2 * 4 * 2 + 3 * 2) * (3 * 3) * 6 + 8 +(6 * 2 * (6 + 5 * 9 * 3) * 6 * 2 + 7) + 7 * 8 + 2 * 4 +5 + (2 + 4 + 5 * 4 + 6) + 9 * (5 * (5 + 9) * 9 * 9 * 2 + 8) * 5 +7 * 4 + 9 * (9 + (5 * 7 + 8 * 7 * 5) + 9 + 2 + 2 + (2 * 4 * 7 + 5)) +7 + 2 + (4 + (8 + 8 + 5 * 9)) + 9 +(8 * 3 * 9 + 6) * 8 + 8 + 7 +(2 + 3 * 9 * 4) * 7 + (8 * 6 * 9) * (8 + 6 + 9 + 4) +((7 * 6 + 4) + 6 + 6) + 5 * 4 + 3 * 4 +5 * (2 + (3 * 9 + 9 * 6) + (7 + 3 + 2 * 4 + 9)) + 7 + 8 * 5 * 5 +7 * 9 * (5 + 6 + (7 * 6) + 4 + 4 + 3) * 2 + 9 +(3 * 2 + 5) * 8 * (2 + 4 + 2 + 8 + 7 * (8 * 9)) +((2 + 7 * 8 * 9) * 4 * 3 + 6 * 7) + 9 * 8 + 5 + 9 +5 + 4 + 9 + 8 +7 + 7 + 9 + 2 + 5 + ((6 * 3 + 3 + 6) * 4 * (4 + 4)) +(9 * 4) + 8 * 4 +3 * 9 * (9 + 5 * 4) + 8 + 9 * 3 +3 + (9 * 8 * (6 + 4 + 6 + 5 * 2) + 9 + (4 * 7 * 7) + (3 + 4 + 6 * 8 + 9)) * (2 + 8) + 7 * 5 * 6 +9 + 6 +6 * 8 * 8 + 6 * 6 * ((9 + 3) + (4 + 2 * 8 + 8 * 2 + 5) * 2) +4 + (4 * (2 + 2)) + 7 + 4 + (4 * (8 + 8 + 4 + 4 + 2) + (3 + 2) * 9 + 8) + (4 + 9 * 9) +(2 * (3 * 7 + 6 + 2)) + (4 * 6) + 6 + (6 + 9 + (2 * 2 * 2 + 6 + 4) * 4) * 5 + (4 + 2 * 5 * 8 + 6 * 2) +4 * ((5 + 5 + 9 + 3 * 5) * 7 * (7 + 9 * 5 * 7 + 2) + 5 * (4 + 7)) + 7 * 9 * 6 * 4 +4 * 7 + 4 + ((4 + 8 * 6 * 3 + 2) + 3 + 8 * (6 * 7 * 2 * 8) * 7) * 9 + 6 +4 * 6 * ((3 * 6) + 4 + (2 * 2 * 2 * 7) + 9 + 8) * (3 + 8 * 2 * 4 * 2 * 3) + (4 + 3 * (7 + 5) + 6 + 9) + 5 +(7 + 2 + (8 + 6 * 4)) + 8 + (7 + 5 + (2 * 5 + 9) * 5) +(7 * 8 + 5 + 8 + 8 * 2) * 6 + (5 + (8 + 3 + 4 * 5) * 9) +8 * (4 + 5 * 9 + 6 + 8 * 7) * 3 * 6 + 4 * 5 +6 + ((6 * 3 * 4) + (8 * 8 * 2 * 5 * 8 + 2)) + 3 +9 * 3 + 6 + 5 + ((5 * 2 + 9 * 5 + 6) + (4 * 9)) + (4 * 2 * 3 + 7) +6 + 8 + (6 + 2 + 8 + 2) * (5 + 8 + 5 * 5 + (4 + 9 + 3)) +(2 * 7) + (6 + 4 + (8 + 6 + 5 + 9 * 4 + 7)) +8 * 3 + 3 * (3 * 5) * 6 + 2 +9 + 4 + ((5 * 4 + 2 + 6) + 5) * 5 + 6 + 4 +(9 * 9 * 3 + 5 * 3 * 4) * 3 + (2 + 3 * 5 + (3 + 6 * 6 + 2) * 8 + 3) +(6 + 9 * 9 + 7 * 6) + 7 +4 + 6 * (3 * 3 * 7 * 7 * 5 + 2) * (7 + 7 * 2 * 5 + 4 + 9) + (8 * 2 + (8 + 8 * 4 + 7 + 3 + 5) * 7) + 9 +4 + 8 + 6 * 7 * 7 + (2 * 8 + 3 + 5) +4 * 8 * 4 * (9 * 9 * 5) + 9 +8 * 5 + (2 + 3 + 2 + 8 * (3 + 5 + 8 + 7 * 9)) +3 * ((8 * 6 + 9 * 8 * 5) + 9 * 6 + 6) * 6 +5 * 8 + 6 * (5 * 2 * 8) +8 + (6 + 7 + 7 * (6 + 7 + 3) * (5 + 2 * 7) + 7) + (2 * 8) +6 + 5 + 4 + 2 + ((3 + 8) * (5 + 4 * 9) * (4 + 9 + 3 + 9 + 9 * 7) + (5 + 2 + 9 + 3) + (6 + 6) + 3) +3 * (2 + 5 * (5 * 6 * 5 + 9) + 9 * 5) * 8 * 5 + 4 +2 * 4 + 6 + (9 * 4 * 3 * 4) +(4 * 6 * (3 + 9) + (3 * 5 + 8 * 5 * 9) + 6) + 9 + 8 +(3 * 5 + 8) + 8 * 8 * 7 + 8 * (9 + 6) +(5 * 4 * 6 + 3 + 3) * (3 * 8 * (7 + 2 * 9 * 6)) + ((9 * 9 * 4 + 8 * 7 * 7) + 4 * 4) + 8 * 6 +3 + 5 * 5 * 6 * ((3 + 3) * 8 + (6 + 9 + 2 + 6 * 7)) * 4 +9 + ((4 * 7 + 2 + 2 * 6) + 8 * (4 * 6 + 7 * 5) * 7 + 4) + 6 + 6 +(9 + 9 * (8 * 2 + 9 + 5) * 3 * 4 * 4) + 5 * ((3 + 6 * 3 * 7) + 6 * 4) * (3 + 8 * 9 + 6 + (4 + 3 * 4 + 2) + 6) +5 * 5 * (9 + 8 * 3 * 3 + 3) * 4 + 8 +3 + (6 * 9 * 8) + 9 + (3 + 3 + 2 + 5 + 2) +3 + 4 * (4 * 8 + 2 * (3 + 3 + 4 + 9 * 7) + 4 + (6 + 9 + 4 * 6 + 9)) +6 * 5 * 9 * ((6 + 9 * 6 + 7) + (6 * 4 + 2 * 4 * 6 * 6) + 9 + 6 + 8) +7 + 7 * 2 * 4 + 7 * 2 +2 + 8 * (7 + 3 * 3 + 2) + 6 + 3 * 7 +2 * 2 * 9 + 8 + 8 +9 + 5 + 4 * (6 * 7 * 5 * 7 * 4 * 3) * 3 +7 * 5 * 7 * 6 + 4 * 9 +((9 + 7 + 9 + 7 * 7 * 4) * 6 * 5) + 5 + (8 + (2 + 6 * 9 * 7 * 9 + 9) * (9 * 3 * 8 + 9 * 6 * 2) + 6 * 7) * (2 + 6 + (3 * 4 + 4) * 6 * 5) * 9 * 5 +(7 * 5 * (3 + 2 + 6 * 5 + 9) + 5 + (2 + 9) + 2) + 2 * 6 + (5 * (7 * 2 + 3 + 8 * 9) * 7 + 6 + 6 * (5 + 3 + 9)) * (4 * 6 + (9 + 7 + 4)) +((3 + 5) + 7 + 3) + 6 +3 * 4 + 4 * 6 + (5 + 8 * 2) +7 + (7 * (4 + 4)) * 3 + 7 * 4 +(5 + 4 * 6 + 3 * 9 + 7) * (7 * 3 * 5) + 6 +3 + 4 * (8 + 2) + ((6 * 7) + 8 + 8 * (9 * 3 + 2) * 9) +7 + (7 + 9 * 2 * 9 * 2 * (2 + 5 + 9 * 6)) * 4 +(7 + 6 + 3 + 5 * 2) + 2 * 3 + 4 * (3 + 4 * 5 * (3 + 7) + (7 + 2 * 7 * 6) + 8) * 8 +4 + (9 * 2 * 6 * (6 + 6 * 7 * 7 + 5) * 9) * 9 + (4 + 8 * 7) * 4 + 4 +6 * 6 * 2 + (4 * 2 + 7 + 4 + (2 + 2 * 5)) + 2 +8 + 2 + 3 + 3 + 8 + (6 + 4) +8 + 9 + 2 + ((3 * 9 * 3 * 5) * 3 + (2 + 2 + 8 + 6 + 9 + 7)) + 9 +6 * (3 * (5 * 4 + 4 * 4 * 4 + 4)) * 8 * (5 + (5 + 2 * 7 + 8) * 3) +3 + ((3 + 7) + 2 + (5 * 3 + 4 * 9)) +4 + 5 * 6 * (7 * 5 + 6 * 5 * 5 + (4 * 6 * 9 * 6)) + 7 + 3 +7 * 4 * 7 * 5 * (3 + (5 + 6 + 9 * 9 * 3 * 7) * 2 * 8 + 2 + 6) +5 * 4 + (4 * 7 * (3 + 8 + 9)) + 4 +(7 + (3 * 5 * 7 + 5 * 8) * (6 + 9 * 6 * 7) * (3 + 9 * 8 + 4) + 8 + 7) * 2 + 4 +8 + 7 + (9 + 6 + 7 + 9 + 6 + 4) + (7 * 8 * 6 * 5 * 3) + (3 * 4 * 3 * 8) +7 * ((4 + 4 + 9 + 3 * 3) + (9 * 6 * 8 * 7 * 3 + 6) * 7 + (7 + 2 * 3 + 6 * 2)) + 3 + (5 * 8) + (4 + 9 * 6 * (2 * 5 + 7 * 3 * 5) * 3 * 8) +8 + (3 + (8 + 3 * 4 + 4)) * 2 * 4 * (3 + 4) +(4 + 9 + 4 + (4 + 7 * 3 * 2 * 5 + 7)) * 2 +2 * 8 +6 * (7 * 5 + (4 * 5 * 2)) +(3 + 3 * 4 * 3 + 7 + 4) + 8 + 2 + 4 * 4 * 5 +7 * 2 * 5 + (2 * (9 + 6) * (3 * 8 + 4) + 3) * 9 +(6 * 9 * (6 + 6 + 7 + 7) * (5 * 7 + 8 * 5 + 2 * 8) + 5 + 8) * 9 * 9 + 3 * 2 + 7 +(2 * 3 + 8 + (4 * 2 + 7 * 2 + 7 + 7) + 3 + 6) * 3 * (6 + (9 + 7 * 2 + 2) + 6) + (4 + 3) * 3 +4 * (6 * (8 * 8 + 7) + 7) * 6 * 9 * (4 * (6 * 4 * 3 * 2 + 6) + (8 * 9) + (9 + 3) * 4) +5 * 7 * 2 * (2 * 2 * 5 * (8 + 6)) +(8 * (7 + 7 + 8)) + 2 + 9 * 9 + 9 * 4 +6 + 6 + 5 + (2 * (8 * 7 + 3 * 6) + 9) * 7 + 6 +8 + 6 + (8 * 4 * 8 * 2 + (6 * 6 + 9 * 3 + 6)) + 3 +9 * 5 * 4 * (5 + (3 + 7) + (4 + 4 * 5 + 5 * 8 * 9) * 5) +5 + 4 * 9 * ((2 * 4 + 8 * 2 * 7 + 2) + 4) * 9 * 3 +3 + 6 * (6 + 2 + 3 * 2) + (3 + 5) + ((3 * 6 + 5 + 7 + 8 * 8) * 9 + (5 + 8 * 7 + 6 * 8 + 7) + 7 + 8 + 5) +7 * ((7 + 5 * 3 * 5 + 4) + 7 + (6 * 3 * 6 * 6 * 7 * 7)) +((5 + 7 * 9 * 2 + 3) * 2 + 9 * 3) * (4 + 6) * (4 * 7 * (9 + 6 * 8 + 5) * (3 + 8 + 9) + 9 * (8 + 6 * 9 + 6)) * 6 + 4 +2 * (6 * 3 + 4 + 4 * 2) + 6 + 7 + 5 +2 + 7 + 5 + 5 * ((7 * 6 + 2) * 8 * 8) + (2 * 5 * 4 * 5) +3 + (7 * 8 * 5) + 5 + (5 + (4 * 4 + 7 + 2) + 6 + (8 + 3) * 9 + 4) +6 * (9 + 5 + 6) * 5 + 5 * (7 * (3 * 5 + 6 + 2 * 5) * 2) +(9 + 6 + (9 + 7 * 5 + 6 * 7) * 7 * 3) + 3 + 4 + 6 +7 * ((5 + 4 + 6) + 7) + 2 * 3 + (6 + 9 * (6 * 4 * 8 * 3 + 4 * 2) + 7) + 3 +7 * (8 + 9 + 5 * (9 * 7 * 9) + 2) + (7 + 7 + (7 + 3 + 2 * 2) + 4 * 2) +3 * (2 * (4 + 6) * 8) +8 + ((6 * 4 * 8 + 4) + 7) * 7 +(7 + (2 + 8 * 8 * 6 * 2)) + 7 * 2 +(4 * 2 + 4 * 8 + 4) + (3 * 9 + (2 * 4 + 2 * 7) * 9 + 7) * (5 + 9) * (7 + (3 * 4 * 4 * 6) + 8 * 7) + 8 + 8 +8 + (2 + 2 * 8 * 7 + 7) + 2 + 4 * 3 + (8 + 9 * 9) +3 + 2 + 8 + (9 + 3 * (3 + 2 + 9 + 7) + 4 * 4 * 7) * 3 +5 * 4 * 7 * 3 + (9 * (6 * 6 + 2 * 4) * 8 + 2 * 9) +4 * 7 * (3 + 6 * 6 + 4 + 8) + 5 +(8 + (8 + 2 * 9 + 3 * 3) * 8 * 8 * (9 * 6 + 2 * 6)) * 9 + 5 * 2 + 5 +5 + 6 + 3 + 4 * 9 + (4 + (4 + 3 + 9 * 2) + 4) +3 * (5 + 3) * 7 + 6 +((3 * 2 + 2 * 6 + 5 + 3) + 4) + (4 * (8 + 2 + 9 * 2) * 8 + (8 * 3 + 6 + 2 + 6) * 2) + 7 + 2 * 9 +6 * 8 * ((8 * 8 + 3 * 7 + 8 * 4) * 4 + 9) + (8 * 7 * (6 * 8 * 3 * 2) * 3) * 2 * 8 +(2 * 7 + 4) * 2 * (5 * 4 + 2 + 5 + (7 + 5) * (4 * 3 + 6 * 8 * 5 + 9)) * 5 +(6 * 8) * (7 * 7 + 8 * 3 * 3) * (5 * 8 + 2) +(6 + 6 * 2) * 5 + ((7 * 6 * 8) * 8 * 9 * 4) +(8 * 4 * 9) + ((5 * 3 + 6 * 3) + (9 + 9 + 9 * 2 * 2) * (4 + 9 * 7 + 2 * 2 + 3) + 6) * 7 * 6 * 6 +((4 + 3) * (2 * 5 + 8 * 2 * 4) * 9) + 6 + (6 + (5 * 4 * 5 * 3 + 3) * 6 * (5 * 3 + 7 * 2 + 4 + 8)) + 4 + 7 +(6 * 9 + 9 + 7) * (6 * 2 * (4 * 7 * 4 + 4 * 5 + 7) + (7 + 5 * 8 * 4 + 9 + 6)) * 7 + 8 * 5 + (9 * 5 * 2 + 7) +6 * 6 + ((2 + 9) * 5 + 2 * 3 + 3 * 3) + 9 * ((4 * 7) + 5 + 8 + 4) +5 + (4 * 5 + 5 * 3 + 7) * 6 * 5 + (2 + (9 + 7 + 8 + 4)) +(2 * 4 + 5 + 8 + 6 * 9) + 3 + 6 +9 + (9 + 8 * 3) * (3 + 8 + 6 + 5) * 5 +(3 + 9 * 5 + 7) + 2 +((9 + 5 * 2) * 5 + (4 + 2 * 7) + 9) * 8 +(4 + 4) * 9 + 3 + 2 * 8 +(3 + 4 * 8 + 9 * 6 + 6) * 5 + 8 + 9 +3 * 8 + 9 * (3 * 4) +6 + 7 * 6 * 7 +3 * 3 + (8 * 8 * 9 + 3 * 8 + 2) * 3 + 8 * 2 +5 + ((6 + 2 * 6) * 8 + 6 * 5) + ((7 + 3) + 2 * 5 + 7 + 6 + 5) + (8 + 2 * 7 + 4 + 2 * 3) * 2 * 5 +(6 * (6 * 7) * 7 + 3) * 9 + 6 * 3 +(5 * 9 + 7) + 8 +(3 + 9 * 3 * 9 * 2) * 9 * 5 +5 + (6 * 3) diff --git a/d18/main.py b/d18/main.py new file mode 100755 index 0000000..792e5d3 --- /dev/null +++ b/d18/main.py @@ -0,0 +1,88 @@ +#! /usr/bin/env python3 + +operators = { + "+": lambda x, y: x + y, + "-": lambda x, y: x - y, + "*": lambda x, y: x * y, + "/": lambda x, y: x / y, +} + + +def evaluate(s): + num_s = "" + num = None + left_num = None + op = None + s = s+" " + inner = None + level = 0 + for c in s: + # print(f"reading {c} level {level} left: {left_num} inner: {inner}") + if c == ")": + # print("close paren") + level -= 1 + if level == 0: + # print("eval inner", inner) + num = evaluate(inner) + # print(f"finished evaluating {inner}, Result was: {num}") + inner = None + else: + inner += c + elif c == "(": + # Start to read innner + # print("start reading inner paren") + if inner is None: + inner = "" + else: + inner += c + level += 1 + pass + elif inner is not None: + inner += c + # print("append to inner paren", inner) + elif c.isnumeric(): + num_s += c + elif c == " " and num_s: + # print("got number") + num = int(num_s) + num_s = "" + elif c in operators: + op = operators[c] + + if num is not None and left_num is None: + # print(f"putting {num} on left") + left_num = num + num = None + + # Evaluate + if left_num is not None and num is not None: + # print(f"evaluating {left_num} {op} {num}") + left_num = op(left_num, num) + # print(f"new left is {left_num}") + num = None + op = None + + return left_num or 0 + + +def part1(): + # r = evaluate("1 + (2 * 3)") + # r = evaluate("1 + (2 * 3) + (4 * (5 + 6))") + # r = evaluate("1 + 2 * 3 + 4 * 5 + 6") + # r = evaluate("((2 + 4 * 9) * (6 + 9 * 8 + 6) + 6) + 2 + 4 * 2") + # print(r) + # return + + total = 0 + with open("input.txt") as f: + for line in f: + line.strip() + v = evaluate(line) + print(v) + total += v + + print("sum: ", total) + + +if __name__ == "__main__": + part1() diff --git a/d18/main2.py b/d18/main2.py new file mode 100755 index 0000000..4ba7ee4 --- /dev/null +++ b/d18/main2.py @@ -0,0 +1,96 @@ +#! /usr/bin/env python3 +from typing import List + + +operators = { + "+": lambda x, y: x + y, + "-": lambda x, y: x - y, + "*": lambda x, y: x * y, + "/": lambda x, y: x / y, +} + + +class SynNode(object): + def __init__(self, nodes, ops): + self.nodes = nodes + self.ops = ops + + def evaluate(self) -> int: + assert len(self.nodes) == len(self.ops) + 1 + # Eval sub nodes + node_values = [node.evaluate() for node in self.nodes] + total_value = node_values[0] + + for i, op in enumerate(self.ops, 1): + total_value = operators[op](total_value, node_values[i]) + + return total_value + + +class ValueNode(SynNode): + def __init__(self, val: int): + self.value = val + + def evaluate(self) -> int: + return self.value + + +def find_high_level_ops(s: str): + balance = 0 + indicies = [] + for i, ch in enumerate(s): + if ch == ')': + balance += 1 + elif ch == '(': + balance -= 1 + elif ch in operators and balance == 0: + indicies.append(i) + + return indicies + + +def parse(s: str) -> SynNode: + s = s.strip() + if s.isnumeric(): + return ValueNode(int(s)) + + hl_op_indicies = find_high_level_ops(s) + if not hl_op_indicies: + # Must be like "(1 + 2)", remove parent and try parse sub operation + return parse(s[1:-1]) + + ops = [s[i] for i in hl_op_indicies] + nodes: List[SynNode] = [] + + start = 0 + for i in hl_op_indicies: + nodes.append(parse(s[start:i])) + start = i + 1 + + # Parse remaining + nodes.append(parse(s[start:])) + + while '+' in ops: + add_index = ops.index('+') + # Remove op and neighbor nodes and replace with a syn node instead + op = ops.pop(add_index) + right = nodes.pop(add_index+1) + left = nodes.pop(add_index) + nodes.insert(add_index, SynNode([left, right], [op])) + + return SynNode(nodes, ops) + + +def part2(): + # print(parse("1 + (2 * 3) + (4 * (5 + 6))").evaluate()) + # print(parse("5 + (8 * 3 + 9 + 3 * 4 * 3)").evaluate()) + total = 0 + with open("input.txt") as f: + for line in f: + r = parse(line).evaluate() + total += r + + print(f"Total: {total}") + +if __name__ == "__main__": + part2() diff --git a/d19/input.txt b/d19/input.txt new file mode 100644 index 0000000..53a0b67 --- /dev/null +++ b/d19/input.txt @@ -0,0 +1,538 @@ +2: 12 16 | 41 26 +55: 92 16 | 84 26 +107: 48 26 | 29 16 +91: 16 86 | 26 120 +56: 19 16 | 30 26 +33: 69 16 | 127 26 +65: 112 16 | 76 26 +23: 16 16 | 44 26 +102: 16 116 | 26 132 +39: 16 26 | 26 26 +40: 23 26 | 76 16 +108: 16 53 | 26 51 +22: 110 26 | 55 16 +42: 1 16 | 47 26 +14: 112 26 | 46 16 +117: 115 26 | 76 16 +120: 26 6 | 16 59 +72: 26 130 | 16 66 +131: 102 26 | 20 16 +93: 16 16 | 26 16 +58: 97 26 | 104 16 +69: 26 88 | 16 46 +54: 76 16 | 116 26 +1: 26 64 | 16 28 +48: 13 26 | 61 16 +92: 85 26 | 117 16 +49: 124 26 | 98 16 +6: 44 44 +24: 112 26 +17: 112 16 | 116 26 +115: 44 16 | 16 26 +113: 16 128 | 26 89 +106: 26 132 | 16 6 +16: "b" +67: 44 16 | 26 26 +104: 44 88 +41: 26 132 | 16 76 +38: 16 59 | 26 46 +89: 16 24 | 26 62 +80: 18 26 | 35 16 +98: 46 26 +101: 16 132 | 26 46 +85: 16 59 +126: 16 67 | 26 59 +9: 26 49 | 16 80 +10: 26 67 | 16 59 +34: 26 93 | 16 23 +4: 70 26 | 107 16 +100: 123 26 | 63 16 +109: 118 16 | 54 26 +77: 16 50 | 26 99 +88: 26 26 | 16 16 +81: 67 26 +18: 16 115 | 26 88 +123: 57 16 | 103 26 +60: 26 18 | 16 43 +94: 26 23 | 16 59 +0: 8 11 +57: 46 16 | 125 26 +110: 26 58 | 16 60 +20: 44 76 +15: 56 26 | 33 16 +114: 26 132 | 16 23 +7: 16 6 | 26 115 +28: 16 3 | 26 25 +51: 112 16 | 23 26 +43: 88 16 | 116 26 +111: 26 6 | 16 93 +62: 26 132 | 16 112 +76: 16 26 | 26 16 +27: 96 26 | 45 16 +50: 26 93 | 16 76 +132: 16 26 +35: 16 115 | 26 132 +53: 16 46 | 26 116 +75: 104 26 | 81 16 +82: 26 9 | 16 100 +78: 26 116 | 16 125 +19: 16 39 | 26 132 +37: 26 41 | 16 127 +45: 91 16 | 108 26 +59: 26 26 | 26 16 +116: 26 16 +84: 7 16 | 94 26 +86: 16 6 | 26 88 +63: 94 26 | 17 16 +103: 115 26 | 59 16 +130: 16 34 | 26 20 +99: 39 26 | 6 16 +26: "a" +64: 16 15 | 26 21 +97: 67 16 | 23 26 +83: 105 26 | 27 16 +21: 75 16 | 52 26 +30: 26 125 | 16 112 +3: 16 121 | 26 74 +105: 26 73 | 16 113 +125: 16 16 +13: 16 88 | 26 39 +32: 72 26 | 122 16 +122: 16 77 | 26 2 +90: 4 26 | 32 16 +12: 26 6 | 16 39 +29: 68 26 | 101 16 +79: 106 26 | 111 16 +61: 132 16 | 46 26 +31: 83 26 | 90 16 +96: 16 87 | 26 5 +118: 26 93 | 16 116 +44: 26 | 16 +25: 37 16 | 71 26 +52: 10 26 | 7 16 +124: 125 16 | 6 26 +66: 26 36 | 16 14 +127: 16 116 | 26 39 +68: 26 46 | 16 6 +70: 79 26 | 109 16 +128: 126 16 | 40 26 +8: 42 +71: 26 114 | 16 78 +73: 129 16 | 131 26 +5: 16 65 | 26 118 +11: 42 31 +119: 16 112 | 26 6 +95: 16 88 | 26 59 +87: 119 16 | 14 26 +121: 35 26 | 95 16 +47: 22 26 | 82 16 +46: 16 16 | 16 26 +129: 12 16 | 17 26 +112: 26 26 +36: 67 26 | 125 16 +74: 16 10 | 26 38 + +aaaaaababbaaababaaaabbbb +aabbabbabbbbbaaaababbbbbaaabbaabababbaaabababbab +baabaabaaabbaaaaaaabaabb +aabaaababababbbaabababaaaaaaabba +babbaabaaaabbabbabbaabba +aabbabbbaaaaaaabaabaabaa +aaabaabbaaabaabbaaaaababaabaabbabbabaaababaabaabbaabaabbaabaaaabbabababa +abbabaabbbaabbbbaabaababaabbaabbbabbbabbaabbabbaabaabbbbbaaabaababbabbba +abaaabaababaaabbbaaabbbb +baabbabbaaababbbabaabaab +abababbabbabbbaabaaaaaab +bbabbaababbbbbbbbaababba +abaaaaaaabbaaaaabbaabbba +abbbbaabbabbbaabbabbbbbbaaababbaabaaaababaaabbbabaaaaabbbababaabbbaababb +aabaaabbaaabbbaababbbaaaaabbaaababbbababbbabaabbabbaabbbbbabbbbbaaaababbabbabaaa +aaabbbababbbabababbaabba +babbbbabbbaabaabbbbaabba +ababbbbbbbbaaabababbaaaabbaabaaabbbabbab +bbabaaaaabababaababaabaaabababbb +bbabbabbabbaaaabbbaababbbaaaabaabbaaaaaa +baaaabaabbabbabbabbbbbbaabbbbbbbbbaababbbbabbaabaabababb +babbaaaabaababaabaababab +bbbababaababaabbbabaabbb +baaababbbbbbbababbabbabaaaaabbaa +baababaababbabbbabbababaabbaaabababbaaab +bbbaaabbbabbbaaaaaabaabaabbbbaabbaaabbba +aabbabaaaaaabaabababaabbbbbaabbaaababbbb +aaababbbaabaabbababaababbbaaabbabaaaabab +bbbbbbbbabbbaaaabbbbaaaa +abbbbaaaaabaababbbbaabba +abbbbaaaaabbbabbbbbaabbbaaabbabbabbababaababbaaa +bababbabaaabbaaaaabaabaababababa +aabaabbabbabaabaaaabbaaabbbbbbbabbbbbabbabbbbabb +abbaaabaaaaaaaaabaaabbbaabbbaaabbaaaaabaaaabbbbaaaabbaab +aabaaababbaaabbbaabbbaaabaabbbbabbbaaabaabbaababababaaba +aaaaaabaabbaaaababbaabba +aaaaaaaabaaabbaabaabaaabbbababaaabbabbab +bbabbabaaabbababaabababb +aabbbbabbaaabbbabaababaaaaabbbba +baaaaaaabbbababbabbaaabaaabababbaababaaaababaaabaababaaa +bbbaabbbabaaaabaaaabbbaa +baaaabaabbababaabaabaaaa +bbbbbaabbaaaaaaabbaaabaa +aabbbbabbbbaaabbabbbbaab +babaababbabbabbabbababbbaaabbbbb +babbbbabbbaabaaabbbaabaa +abbbbaaaabbaaaaabbabbbaaabbbaababaababbbaaaababbaaabbbbbaabaaaaa +baabbbbabbbbbaabbbaabbba +aabbabbbaaabaaaabbaabbbb +babaabaabaaaabbaabababbb +aabbabbbbabbaababbaaaaaa +bbaababbababbbbbbbbbaaab +bbbbbbabaaabbabbabaababbbbbbbbaa +baabbaaabbabaabbbbbababb +abbbbbbaaabaaabbaababbbb +bababbbabbabaabbbabbaabaaabbbabaababbababbababab +aababbababbbbbaabaababab +babbbaaaaaaaaaabbbabaaba +abbbaaabbaaaabaaababaabbaabaaaaaabbaabbaabaabababbabaaaa +aababaabaabbaaaabababaab +babababbaaaaaabaabababababbbabbbbbababaabaababba +bbbbbabbbbaababaabaabbbbbababababaabbaba +baabbbbabbabaabbbaababbb +abbbbbabbababbbbbbaaabbabababbabaabbaabbabaaabbaaaaabababaabbaababbbabbaaaabaaaa +aababababaaaabbbaaaabbbaaaaabbbb +ababbaabbbaaaabaaaabaaab +abbbbbbaaababaabbabbabbababbbaaabbaababa +bbaabaabbbbaabbbbbaaabbbabbababbbbbbaabb +abbababbabababbbaabaaaaa +abbbaaaaaaaaabaabababbab +bbaababbabababbaababaabbabbbbbabbbabbbbb +babbabbabaabbaabaababbbb +bbbbbaaaaabbabbabbaaaaab +aaababababbbabaababbabab +baababbbaaabbaababaaaabbabbaabbb +aababaabaabaaaabbbbabaabbbbbbbabaabbbbaa +aaaaaaaabbbbaabbbbbababaabbaabbbaaababba +bbbababbbbaabbabbbababbaabababababbaaabaababaaab +baababaaaabbbabbabbbabbababbababbabbaaab +baabbbbaaabbbababbaaaabb +bbababbbabbbbaaaabbabbab +babbabbbabbbabaabaabbbbb +aabaabbabbababaabbbbaaaa +aabbbabbbbababaabaaaaaab +aaabaaaabbbabaabaabbabaabbbabbbb +aababaabbbbbabaaaaaaabba +babaabbabbababbbbaabbbaabbbbbaababbbbabbbbabbbab +abaaabbbbbababbbbabbbbba +abbbbaaaaabbbabaaababbaa +ababbbaaabbbabbbbabbaabb +aaaaaaabaaaaabaababbbbabbabbbbababaabbaa +aaaabbabbaaababbbbbabababbabaabaaabbbabbbbbbbabbaaabbbbbbabbabab +bbbaaabbbbbbaabbaaabbbba +bbbaaababbabbabbbaabaabb +abbbbbbbaababbbbbbbbabbaabaabbaababbbaba +aaaaaabbbbbbbababbaababbbaabbbba +baaaabaaabbababaabaabaaaababbbbbbababaaabbbbbabb +bbabbbaabbbaabbbbabaaabbbabaaabaabbbbbbbaaaaabba +aaaaaabaabababbabbbbabba +ababbaababababbaaaaabbba +aabaababbabbbbabbbbaabbbabaaaaaaaabaaababaabbbbb +baabbabbbbaaabbabababbaaaaaababb +aaabbaabababbabaababaaab +abbaaaabaaaaaabbaaabbbaa +ababbababbabbabababbaaaababbabbabbbabaabbababaabbbabbbbaabbbbabbabbabbbb +baaaaaaabbababbababaabbabaaaabbaaabababaabaaaaabaabbbbaa +aabbaaaabbaaababbbaaabbaabbbababababaaaa +aaaaabbbaaabababbaabbaabbaaaaaba +bbababaabaaabaabbbbbabbb +aababaabaaaaabbbabaaabaaabababbb +bbbabababbaaaabbabaaabbabbabaaba +bababbaaabaaaaaababbaabb +aaaaaabbaaabaaaabaababab +baaabaabbabaababaabbbbabaabaabbbbbbabbbabbaabbaa +aaaaabaaaaabbabbbbbbbabb +babbabaaaaabaaaaabbbbabb +bbbbbaababbbbbbabbbaaabbabbbabbbbabbaabbbababbbb +aaabababbbabbabbaaaabaababbaabbbaabababb +bbaaababaaaaabaabaabbbbabbabbabbbabbbbbabaaabbba +aabaaabbababbbbbbbbbaaaa +aababbabbbaabaaabbabbaabaabbababbabbbbbb +bababaaabbbbbaabbbbabaabbaabaaba +aaaabaaaaaaaaababbaaaaabbbbababbbabbbaab +aabaaaabbaaabaabaababbaa +aabaababbbbabaabbaaabbba +bbbbababbbabaaabbabbaabbababaaabbbbbabba +aabbaaaaabbaaaababbbaabb +aaabaaaaaaaaaaaabaaababaabbbabbbaababaabbaabaabbbbaabbabbbbabbaa +abaaaaaaabbbabbbababbbaabaabaabb +abbaaaaaaabbaaaababbbaab +bbabaabbaaaaaabbabaabbba +bbabaabbabbbabaababbbbba +baabbbbaaaabaabaaabaabaa +bbabbbbbbbaabbbaaabbaabbbbaabbabbabbbabbbbabbbab +aaabababbbabbaababababababbbbabaabababaaaaaaabba +aabbbaaaaababbabbbaaabbabbaaaabaabbbbaaaabbaabba +ababaabbaabbbabaabaaaabbbbabbbbbbaaabbbb +baababbbabbbabbbaababaaa +bbbbbaaaabababababbabaab +bbbbbaabbbabbaabbaaaaaba +abaaabbbbabaababbabaaababbaababa +aabbbbabbabaaabbbbababaaabaaaabbbabaabaa +babbabbbababbbbbbaabbbbaabbabbab +abababababbaaaaaaaabbbba +aabbbabbbbabaaabbabbbbabaabaaaabbbbabaaaaaabbbba +aabbbabbbbaababbbbbbbaab +bbaaaababbbababaaaabbbbaabbbaaabbababbbb +abbabbaabaaaabababaabababaaabbaaababbbbaababbabbaaabbabaababbaab +aaabababaaaabaabaaaaaaabbbababbababbabbababbaaab +babaabbabaabbabbbbbaabaa +babbabbbbbaabaaabbbbbabaabbbabbabbaaaabbabbbabaabbbaaaaa +bbbababaaabaaabbabababaabaaababbbabaaaaaabbaabba +baabbabbababbbaaaaaabbaa +aabaabababbbbbaabaababba +ababbbaaababbbaaaaabbbaa +abbabbbabbaababbaababbbb +aababaababaabaaabbabaaababaabababbabbbab +aaaabaaaaabbbbabaabbbabbbbaababbbbbbaaab +bbbbababbbbbababaaaabbaa +abbbaaaabbbaaabaabbbaaab +bbabaaabbbbbabaababbaaaabbbaaabbbaaaaabaabbbabbbbbabbbbbbaaaaabbaaabbbabbbbaabababaaabaa +aaabbaabaabbababaaaaabba +bbabaaaaabbbaabaaabbabaaaabbabbbaaabaabbbbaabbab +bbaabaaaaabbbaaababaabaaabbabaab +bbbbababababaabbbaaababa +baabaaaaabbababaaababaabaabbbabaabbabababbababbaabaaaabaabbbbaaaabaabbbbbaabbbbb +bbababaaababababbababaaabbbabbbaaaaababa +bbaabaaaabbbbbbbaaaabbbb +aabaabbaababbbbbbaaababb +abbbaaaaaabbabbababaaabaabbabaabababaaaabababbbb +abbbbbaaaaaabbabbbabaaabbaaaaaaabbbabbab +bbabbabbbbabbabbaabbaabb +aabbabbababbaababbbabbba +abababbabaababaababbbbaababbabab +bbababbabbaabbbbbbbaaaaabababaabaaaaabba +abaaaabbbaabbaabbaabaabb +ababbaababbabbbaabaababa +abaaaabaaabbbabbbaabbaaaababaaaabbbabbbabbaaaaaa +aabbababbbabbbaaabaabbba +abbabbbaaaaaabbbaabbabaabbaaabbbababbabbabaaabba +aabbbabaaaabbbabbabbbbbabbabaabbabaababa +babaabbaabaabaaababbabbaababababaabababa +abbaaaaaaaabbbabbbaaabbbbaaaaaba +bbaaabbbbbaaabbabababbab +aabbababbbbaabbbaababbba +abaaabbaaabaabbbbaaaabab +babbaabaaabbbbabbaaabbaabbaaaabb +bbabbabbababbbaabbaababa +babbbababbabbbbabbbaabbbbbaaaabaabbbababaabbabbabbabbaaababbbbaaaabaaaabbbaabaabaaabbabb +bbabbabbbbbbbbabbabbbbbb +bbbaaabbabaaabaaabbababbbabababbbbabaaabaaaababb +babaaababbaababbababbababbbabaabbbbbbabbabbaaababbabaabaaababbaa +aabbbbabbaaaabbaaabaabbabaabbabbabbbaaabaaaababa +abbaaaaaabbababbbbbbbabb +baabbbaaabbaababbbbabbaa +ababbabababbbaabbbaabbbb +abababbabaabbbabbaababaaababaabbbbbabbaabbaabbababbabbababbbbabbaabbbaaaaabbaababaabbaba +aabaababababbbaabbaabbab +babaabbabbbbaabbaababbaa +baabbaabbbbbbababaabbaaaabababaabaabbbabbbbbabaa +abbabababbaabaabbbaababa +baababbbaabaaabaabaaabbbaabababa +bbabaabbbbbbbaabbabaabbb +babaabbaabaabbbaaabaabbbbabbabaababbabbb +babaababbbaababbbbaabaaaabbbbabaabbabbbbaaaabbba +ababaabaababbbbaaaaabbba +aabbbabbaabbbbabaabbabbbabbbaababaaaaaaaabbabbbb +aaabaaaaaabaabbaaabaaaaa +abbababbabbbaababbbaabba +abababbababbbbabbaaaaaab +aaaabaabaaabbbabbbaabbab +abbbbbbbbaababbbbabbabab +ababaabbbbbbbbababbbbaab +aaaaaaabaabbabababaaaaaaaaabababbabbbbaa +bbaabaaaaabbbabbbaaabbba +baabbaaababbabaabbbbaaba +bbbaabbbabbabbbabaaaaaab +aaaaababbbbabbaababbabababaabbab +aaabbbababbbabbaabaabbbb +abababaaabababababbaabba +ababbbaaabbaabaaabbabbbb +bbabaabbbaabbbbabaaabaaa +ababbaabaaaabaabbbbbbbab +baabaaabbbaabaaaaabaaaabbaabbbabbbbabbbbaabababb +abbaabbbabaababaabaabaaaabbbaaaababbaabbbabaabaa +aababbabbababaaaababbbba +bbabbabaabaaaaaaabaaaaaabbaababbaaaabbaababbbbaabbabbbbaaabbabaa +aaaaaaabbbaababbababbbaabbabbabaaababbaabbabbbbbaabababa +aaabaaaabaaabaababaabbab +baaaaaaabaabaaababaaaabaaabbaabb +bbaabaabaabaaaabbbbbaaab +abaabbbaaaabaaaaabbbababaaabaaaaaaaabaaaababbbabbbababbaaabbabbb +abaaabbbabbbbbabbabaaaaa +ababbababbbabaababbbbabb +babaababaaaaaaaaaaabbbabaaaababa +aabaaabbaaaaabbbaaabbaba +baaabbaaaabaaababaababaaaabaaabaaaabaaaaabbbaaba +aaaaabbbbabbaabaaaabbaabbbbbbabb +aabbbbababbbaaaabbaaaaab +bbbabaabaabaaaabbabaaaaa +abbbbaaaabbbaabaabaabbbb +abbaaaaababbaaaaabbbabbabaaaaaba +abbbaabaabbbaababbababab +bbbaaabbbaabaababaaabbab +aabaabababbbaaaabbbbaaba +baababbbbaababbbbabbbbabbbbababbabbbbaab +bbbbababaababaabbbbbbaaabbaaaabaabbbbaaabbbabbba +baaabbaabaabbbabaaaaabaaaabbaabb +aabaaababbbabababbbabbbb +aabbaababaabbbbabaaaaaba +aaaabbababbaababbabbbabb +ababababaaaabbababaaabab +aaabaabababbbbababbabbbbaabbaaabaabaaabbbbbababbabbabbabaaabbbba +aabaaabbaabaaabbbbbaaabbbbbabaaa +bbbaabbbbabaaababbbbbbabababbbbbaaabbabbabbabbaa +abbaaaabbaabaababbbaaaab +baaaabaaabaaaabbbbabbbab +bbabbababbbbbbbbbabaabbb +babaaabaaabbabbabbababab +bbabbabaabbbababbbbabbba +abaaaabababbbaaabbabbabaaabaaabb +aaaabbabaaaaaaabbabbbaba +abaaaaaabaabbaaababbbbabaabbabbabbbaaaaaaaabbbba +ababbabaabbbbbaaaabaabaa +abbbaababaaababbaabaaaaa +bbbabaabbbaabbbbbaaabaaa +bbabbabbbaaabbaabaaabbba +babbabaabbabbaababaabbba +abbababaababababaabbbbaa +baabbbabaaaaabbbbabbbbbb +aabbabaaaabbabbaabbbaaab +abbbbbaaaabaaaabbbbabbbb +bbbaabbbbbbbabaaababaaaa +ababbaabbbaababbbbaaababbaaabaabbbaababbbbbbbbaa +bbbabbababbbbbaaaabbbabbbbbaabbabbaaaaabbaabbaaaabbbbabaaababaaa +aababaaababbbaababaabbbaaababbbabbbbbbaa +babbabbbaaaabbabaaabaaab +aabbbaaaaaabaabaababaaab +babaaabaaabbbaaaabaabbba +aabaaaababbbabbaabaababa +bbbbbbaaabbabbaaabaabaabaaabbabaaaababbbabbbabbb +aababaababbaaaabbabbaabb +abbbaaaabaaabbaabbabababbaabaabb +aaaaaabbabbaaaaababababa +bbbbabaabbbaaabaaababbbb +babaabababbbabbabbbabaaa +bbbaaabbbaabbbbaaaabbbaa +abbabbbababbbaaabaabbabbababbabbababbbbaaaabbabababbbbabaabbaaba +abababbabbbaaababaabbaba +aabbababaaabbbbbbbaaaabbbbbbbbababbbabaabbabbbbb +abaabaaabbababbbbaaaabababaabbaaaaaabbbbbbbbaaaabbbbbbaabbaababa +aabbabbaababbbbbbbbbaaaa +aaaaaabbaabbababbbaaaaaa +bbbaaababbbbbbabaaabbaabbbbaabba +bbabbabbabbbabbabbabbbab +bbaabaaabbaabbbbabbbaabb +babbbaaaaababaabbbbbbabb +abaaabaaabaaaabaaabbbbbb +bbababaaabbbabbaabbbabbbbabbbbbaababaaba +abababaabbabaabbbbaaabbabaabbbababbaabbb +babbaabaabbbabbaabaabbbb +baabbbbabbababbabaababba +bbaaabbbaabbaaaabaaababbbabbabaabaabbbbb +aaaabbabbbbbbbbbaaaabbabbaaaabbb +bbbbabaaabbaababbbaabbab +baaaabbaabaaaaaababbabaabaaababa +aabaabbabbaaaababababbaababbabab +abaaaaaabaaababbabbaaabb +abbbabbabbbbabaabbbbaaba +babababbbbabbbaaaabbbabbaaaaaabbbabbabbbaabaaaabababaaaa +aaaabaababbbbbbaabaabbaa +ababbbaaababababababbaaa +ababbbaabababaaabbbbbabb +abbababbaabaaabbbbbaabab +babaababbababbbabbbbabbb +abbbbabbabbbaabbabaaaaabbaaabbbbbabbaaababaababa +baabbbbaaaabbabbbbbababb +aaaaabaaabbabbbababbbbaabaaabbaabbbabbba +baabaaabaabbbaaaabaaabba +aabaabbabbbbbababaababbb +aabbbabaabaaaaaaabaabbaa +abaabababaabaababbbbbbaabbabaabbaabaabbb +aabaaabbbbabbabaabaaaababbaababaaabbbaab +abaaaaaabababbbaabbbaabb +bbabaabbaaabaaaababbbabaabbaabba +bbbbabababbbabababaababb +babbaaabababbabaabbabababaaababbbbabbbbbbbabbabbbaaaabaaabbbbbba +abbbbbbbbbbbabababbabbaaabbaaaababbbbabaaabbaaaaaababbbbbbaababbbbaabaabababaabbababaabbbbbbbbba +bbbaaababaaaabbabaaababbababbaabbbbbbbba +babbabbaaaabbbabababbabb +ababaabbabbabbbabbabbbba +aaabbaabababbbaaababaaab +ababbbabaababbaaababbaaa +baaaabaaaabbaaaaabaababa +baaababbababababbbabbaaa +ababbabababaabababaabaabaaaabbbbbbaaaaababaabbaabbaaaabb +abbbbbaaaaaaabbbabbabaab +aaaaaaabbbaaababbbbaaababaababaaababbaaa +aaabbbabbabaabaaaabbbaab +abbbabbabbababaaaaabbbbb +abbbbabaaaaabbbaabbabaab +bbabaabbaabbbaaabaabbbbb +ababbaababbabbbabbabbaabbbaaaaabbbbbbbba +aabaaabababbbbaabaabaabb +aabbbaaabaabaaabbbbabbaa +babbbaaababbaabaabbbabbbababbaabababaaba +aababaabbabbabbababbbbabaabbbbabbbbbaaaaaabaabaa +aabaaaabbbaabbbabaabaaababaaabababbbabbbabbaaababbaabaababbabbbbabbabaaa +abbbabbbbabbbbaaaabbbabbaabaaabaabaababbbbbabaaa +babababbaababbababbabaaa +aaaaabbbabbbabbabbbaabba +bbaabaaaabaabbabababaaab +babbabaaaaaaaababaaababbbaabbbaaabaabaab +abbbbbbbabbaabaabbbbbbaa +aabaaaaabaaaaaabaaaaabbaaabababa +abababbabbabbabbaabaabbb +aabbbaaaabababbaabbaaaabbbababab +baababaababbabaaaabaaabaaabbbababbbbabbabbabbaaababbbbba +bbababaabaaaabbaababbababbabaaaaabbabbab +abbbbbbbabbbbbaaaaaabbba +bababbbabbbaaabaaabbbabbabaaabaaaabbabbbababbbbbababbbab +abababaaaaaaaababbbaabaa +babbabbbaabbabbbaababaaa +abbaabaababaaaabbbbbabbaaaabbabbbbbababaabbbbbabbaaaaabbbbaaaabaaabbaaab +aaababababbaaaabbaaaabbb +aaaaaabaaaaabaabaaaabbaa +bbaaabbbabbbbbbaaabbaaaaababbabbbaaabbba +bbbaabbbbbabbbaaabbbbbab +aabbaabaabbbababbaaabbbb +bbabbbabbbaabbaaabbbbbbababaaabaabbababbaabbaabbbaabaaaabaababbb +aaaabaaaabbbabaababbbbaabaaaaaba +abbbabbaabaaabbbabbababaaaaabbabbaabbaaaababbbab +baaabaabaabbaaaabbababbbabbaaaababbbbbab +bbbbbbababaaabaabbaaaaaa +baaabbaaaabaaabaaaabaaab +bbbaaabaaabbabbaabbabaab +babaabababbbbbbaaaaabbba +aaabbbabaaaaaaaabababbab +bbbbababaabbabbababbbbbb +aaaaabaaaaaaaababaaaaabb +aaaaaaaababbbbababbbabbaabababbb +abbbbbbaaababaababbbbaab +aaaaaabababaababaaaaabba +aabbaaaabababbabaabaababbbaabbbbabbbaaaaaabbabaaabaabbbb +ababbbbaabbabbbabbbbbaaababababbaababaaabaaaaaab +bbabbabbbabaaabaaabbbbaa +baaaabbaaabbbabaabaabaaabbabbababbbbbbbbaaabaaaababbbbbabaaabbabbabbbbbaaaababaa +abbababaaaabababbbabbaaa +babaabbabbbaabbbaaaabbaa +abbbbbaaaabaabbaaabbabbaabbabaaaabbabaaa +abababbababaaabaabbababaaaaabbababaaaaaaabababbaabaabbbabbaaaabb +bbbaabbbababaabbabaaaaab +aabaabaaabbabaabbbaaabaa +abababaabaabbaababbabbbb +babaabbaaaaaaaabaaaaabba +bbaabbbaababaaaaaaaababa +bbabaaaaabaaaaaaaaabaaaabbbabababaabbbababaaabba +abaaabaaabaaaabbbaaaabab +aabbabaaaaaaabbbababbbba +abababaabbbbaabbaabbaaabbbbbaaaabababababababaaaabbbbaaaaaaaabbbbabbbaaa +abbbabbabababbaaabaabbaa +aaabaaaaaabbaaaabbaabbba +aabaabbababbabbaaabbabbbababbaab +bbbbbaabaaabaaabaabbaabbbbaababa diff --git a/d19/main.py b/d19/main.py new file mode 100755 index 0000000..03566be --- /dev/null +++ b/d19/main.py @@ -0,0 +1,381 @@ +#! /usr/bin/env python3 +from itertools import product +from typing import Dict +from typing import List +from typing import Optional +from typing import Tuple + +MAX_DEPTH = 10 + + +class Rule(object): + _rule_body: str + key: int + _values: List[str] + _depth: int + + def __init__(self, key: int, rule_body: str): + self.key = key + self._rule_body = rule_body + self._values = [] + self._depth = 0 + + def validate(self, s: str) -> bool: + return s in self.values() + + def values(self) -> List[str]: + if not self._values: + if self._depth >= MAX_DEPTH: + # Break out of recursion + return [] + + self._depth += 1 + + values: List[str] = [] + for sub_rule in self._rule_body.split(" | "): + rule_combo: "Rule" = ValueRule(-1, [""]) + for rule_key in sub_rule.split(" "): + rule_combo += RULE_INDEX[int(rule_key)] + + values += rule_combo.values() + + self._values = values + + return self._values + + def __add__(self, other) -> "Rule": + values = [ + "".join(v) + for v in product(self.values(), other.values()) + ] + return ValueRule( + -1, + values, + ) + + def __mul__(self, other) -> List[str]: + raise NotImplementedError() + + def __repr__(self) -> str: + return f"" + + +class ValueRule(Rule): + key: int + + def __init__(self, key: int, values: List[str]): + self.key = key + self._values = values + + def values(self) -> List[str]: + return self._values + + def __repr__(self) -> str: + return f"" + + +def parse_rule(line) -> Tuple[int, Rule]: + rule_index = line.find(":") + if rule_index <= 0: + raise ValueError(f"Could not find rule number in {line}") + rule_key = int(line[:rule_index]) + rule_body = line[rule_index+2:] + rule: Optional[Rule] = None + if rule_body[0] == '"': + rule = ValueRule(rule_key, [rule_body[1:-1]]) + else: + rule = Rule(rule_key, rule_body) + + return rule_key, rule + + +RULE_INDEX: Dict[int, Rule] = {} + + +def test(): + test_input = ( + "0: 4 1 5", + "1: 2 3 | 3 2", + "2: 4 4 | 5 5", + "3: 4 5 | 5 4", + '4: "a"', + '5: "b"', + ) + RULE_INDEX.update({ + parse_rule(line) + for line in test_input + }) + + print(RULE_INDEX) + + for rule in RULE_INDEX.values(): + print(rule.key, rule.values()) + + test_eval = ( + "ababbb", + "bababa", + "abbbab", + "aaabbb", + "aaaabbb", + ) + + rule_0 = RULE_INDEX[0] + matched = 0 + + for t in test_eval: + if rule_0.validate(t): + matched += 1 + + print(f"Total matched is {matched}") + + +def part1(): + rules_parsed = False + matched = 0 + + with open("input.txt") as f: + for line in f: + line = line.strip() + print(line, end="") + if line == "": + rules_parsed = True + print("DONE PARSING RULES") + elif not rules_parsed: + key, rule = parse_rule(line) + RULE_INDEX[key] = rule + print(" Parsed") + elif RULE_INDEX[0].validate(line): + matched += 1 + print(" OK") + else: + print(" Not OK") + + print(f"Total matched is {matched}") + + +def chunk(a, n): + return (a[i:i+n] for i in range(0, len(a), n)) + + +def count_prefix(value: str, prefix: str) -> int: + count = 0 + for c in chunk(value, len(prefix)): + if c == prefix: + count += 1 + else: + break + + return count + + +class Rule0(Rule): + def __init__(self): + super().__init__(0, "") + + def validate(self, value: str) -> bool: + r42 = RULE_INDEX[42] + r31 = RULE_INDEX[31] + + # print(42, "\n".join(r42.values())) + # print(31, "\n".join(r31.values())) + + size = None + for v in r42.values(): + if size is None: + size = len(v) + assert len(v) == size + for v in r31.values(): + assert len(v) == size + + match42, match31 = 0, 0 + for c in chunk(value, size): + if match31 == 0 and r42.validate(c): + match42 += 1 + elif match42 != 0 and r31.validate(c): + match31 += 1 + else: + return False + + # if value == "abbbbbabbbaaaababbaabbbbabababbbabbbbbbabaaaa": + # from pdb import set_trace; set_trace() + + if match42 > match31 and match31 > 0: + return True + + return False + + # if RULE_INDEX[0].validate(value): + # from pdb import set_trace; set_trace() + + # Check beginning starts with "8" + for prefix1 in r42.values(): + prefix_count = count_prefix(value, prefix1) + + if prefix_count == 0: + # Not even one chunk was matched, this is a bust + continue + + # Trim first prefix out + back_half = value[len(prefix1) * prefix_count:] + + # Check following "11" match + for prefix2, suffix in product(r42.values(), r31.values()): + remain = back_half + + if RULE_INDEX[0].validate(value) and prefix1 == "bbabb" and prefix2 == "bbaab" and suffix == "aabba": + from pdb import set_trace; set_trace() + + # If prefixes aren't the same, look for the new one + if prefix1 != prefix2: + prefix_count = count_prefix(remain, prefix2) + # Trim the new prefix + remain = remain[len(prefix2) * prefix_count:] + + if prefix_count == 0: + # No valid prefix + continue + + suffix_count = count_prefix(remain, suffix) + + if suffix_count == 0: + # No valid suffix + continue + + # Trim the suffix + remain = remain[len(suffix) * suffix_count:] + if len(remain) > 0: + # There is something after the suffix + continue + + # Make sure we've seen at least the same number of prefixes + if prefix_count >= suffix_count: + return True + + return False + + +def part2(): + # Update two changed rules + # 0: 8 11 + + # Test short circuits + # RULE_INDEX[42] = parse_rule('42: "a"')[1] + # RULE_INDEX[31] = parse_rule('31: "b"')[1] + + # rule8 = parse_rule("8: 42 | 42 8")[1] + # rule11 = parse_rule("11: 42 31 | 42 11 31")[1] + + # print(RULE_INDEX[8].values()) + # print(RULE_INDEX[11].values()) + + rules_parsed = False + matched = 0 + + # Empty rules + RULE_INDEX.clear() + + with open("input.txt") as f: + for line in f: + line = line.strip() + print(line, end="") + if line == "": + rules_parsed = True + # All rules parsed, replace values + # RULE_INDEX[8] = rule8 + # RULE_INDEX[11] = rule11 + print("DONE PARSING RULES") + r42 = RULE_INDEX[42] + print("prefixes", r42.values()) + r31 = RULE_INDEX[31] + print("suffixes", r31.values()) + elif not rules_parsed: + key, rule = parse_rule(line) + RULE_INDEX[key] = rule + print(" Parsed") + elif Rule0().validate(line): + matched += 1 + print(" OK") + else: + print(" Not OK") + + print(f"Total matched is {matched}") + + +def test2(): + r0 = Rule0() + # RULE_INDEX[42] = ValueRule(42, ["prefixa", "prefixb"]) + # RULE_INDEX[31] = ValueRule(31, ["sa", "sb"]) + + test_input = ( + "42: 9 14 | 10 1", + "9: 14 27 | 1 26", + "10: 23 14 | 28 1", + '1: "a"', + "11: 42 31", + "5: 1 14 | 15 1", + "19: 14 1 | 14 14", + "12: 24 14 | 19 1", + "16: 15 1 | 14 14", + "31: 14 17 | 1 13", + "6: 14 14 | 1 14", + "2: 1 24 | 14 4", + "0: 8 11", + "13: 14 3 | 1 12", + "15: 1 | 14", + "17: 14 2 | 1 7", + "23: 25 1 | 22 14", + "28: 16 1", + "4: 1 1", + "20: 14 14 | 1 15", + "3: 5 14 | 16 1", + "27: 1 6 | 14 18", + '14: "b"', + "21: 14 1 | 1 14", + "25: 1 1 | 1 14", + "22: 14 14", + "8: 42", + "26: 14 22 | 1 20", + "18: 15 15", + "7: 14 5 | 1 21", + "24: 14 1", + ) + RULE_INDEX.update({ + parse_rule(line) + for line in test_input + }) + + og_valid = 0 + new_valid = 0 + + for v in ( + "abbbbbabbbaaaababbaabbbbabababbbabbbbbbabaaaa", + "bbabbbbaabaabba", + "babbbbaabbbbbabbbbbbaabaaabaaa", + "aaabbbbbbaaaabaababaabababbabaaabbababababaaa", + "bbbbbbbaaaabbbbaaabbabaaa", + "bbbababbbbaaaaaaaabbababaaababaabab", + "ababaaaaaabaaab", + "ababaaaaabbbaba", + "baabbaaaabbaaaababbaababb", + "abbbbabbbbaaaababbbbbbaaaababb", + "aaaaabbaabaaaaababaa", + "aaaabbaaaabbaaa", + "aaaabbaabbaaaaaaabbbabbbaaabbaabaaa", + "babaaabbbaaabaababbaabababaaab", + "aabbbbbaabbbaaaaaabbbbbababaaaaabbaaabba", + ): + og = RULE_INDEX[0].validate(v) + n = r0.validate(v) + print(v, "og", og, "new", n) + if og: + og_valid += 1 + if n: + new_valid += 1 + + print("og valid:", og_valid, "new valid:", new_valid) + + +if __name__ == "__main__": + # part1() + part2() + # test2() diff --git a/d20/input.txt b/d20/input.txt new file mode 100644 index 0000000..47603c6 --- /dev/null +++ b/d20/input.txt @@ -0,0 +1,1727 @@ +Tile 1759: +.##.#..#.. +.......... +..#..#...# +##....#### +###.##.##. +.#.#.#..#. +......#..# +##.....#.. +.......... +.##....#.. + +Tile 3803: +#.#.#.#.#. +#......... +#.....#... +#...#..#.# +#....#.... +#..#.#...# +.##.#.##.# +#........# +#..#...#.. +..#####.#. + +Tile 2351: +......###. +##...##.## +.........# +..#.#..... +....#.##.. +#.#.#.#.## +.##.#.##.# +....#...## +#..#...### +#.##...##. + +Tile 2467: +#####.#.## +#........# +#.#....### +.......##. +....#....# +#......... +.......#.# +##.#..#..# +.#....#.## +..#....### + +Tile 1933: +##.....### +#.#......# +....#...## +#.###..... +#.##.#..#. +....#....# +....##.... +##........ +#..##....# +.#.#.#...# + +Tile 2971: +#.#.#.#..# +.........# +......#..# +##...#.... +...###.... +#....##... +.....#.#.. +#....#.#.# +#.......#. +.###...#.# + +Tile 2731: +.....##### +..##...... +.......##. +.#........ +#..#.#.... +.......... +#..##.#... +.#..###... +#.#..#.... +..#.#..... + +Tile 2423: +.####.#... +#.##.#...# +.....##... +##........ +..#..#..## +#...###### +....#...## +.....##... +...#...### +##.#..###. + +Tile 1877: +.#...##..# +#..##....# +#.##...... +...#...... +.#........ +#........# +#.....##.# +#.....##.. +.........# +..####.#.. + +Tile 3461: +....##.##. +....##.... +###......# +#.#...#... +#........# +.##..#.#.# +#.....#.#. +#.......#. +#........# +#.#.##.### + +Tile 2137: +##.#.#...# +#..#.##..# +.##......# +#..#.#...# +###.#....# +#........# +#....#..#. +#...##.##. +...#.###.. +##...#...# + +Tile 2647: +##.##..#.. +......#..# +.....#.... +##......## +#.#.#..### +##.......# +#...###... +##...##..# +.....#.... +###....##. + +Tile 3253: +......#.#. +#.......#. +##..##.... +#.#.##...# +.....#...# +...#..#..# +#.....#... +.#...#.... +.#..#.##.. +.###...##. + +Tile 1409: +.###.###.# +#..#.##.## +........## +.###...... +#####.#### +..#..#.#.# +..#...##.# +..##..#.## +....#....# +####.....# + +Tile 2503: +###.....## +.....#..#. +#...##.... +.##..##..# +...#...#.# +.#..#.#... +#...#...## +#......... +##...#...# +...#....#. + +Tile 1879: +.######.## +......#..# +..#.#..##. +.......... +#..#.....# +.##....... +#.......## +.......... +.........# +#.#.#.##.. + +Tile 3739: +#..#.#.... +#.....#... +#......... +##....#..# +###..##..# +..#...#..# +#.####.... +.##....... +.##......# +###..#.### + +Tile 2713: +..#..#..#. +#......... +.#.....### +.#.##.#.## +.#.#.##... +.##..#.#.# +..####..#. +#..##..... +#....#.... +.#..####.. + +Tile 2243: +#.##...##. +...#...... +..#..#..## +....#....# +#....####. +.##.#...## +#..#..#... +#..###...# +#.##.##### +.#..#.###. + +Tile 3307: +...####..# +....#..... +.###...... +..#....... +.....#...# +#...#....# +#...#..... +.........# +#..###.... +#####..#.# + +Tile 2161: +###.#.#..# +#.#...###. +.##......# +##.#..#.#. +#.#.#..#.# +#..#.#.... +...#....## +#.##...#.# +#......#.. +..#.#.#### + +Tile 3257: +....##..## +#......... +..#..##.## +.#......#. +#...#....# +#.#...#.#. +....##...# +###....##. +.##...#..# +.#...#..## + +Tile 1997: +..#.##.### +....#..... +..#......# +.#.#..#.#. +###...#.## +.#......## +.......... +#........# +..#..#..## +##.#.##### + +Tile 2741: +#####..### +#..#.....# +#...#...#. +....##...# +...#...... +#..##.#... +###....### +........#. +##.###.... +...#...### + +Tile 2671: +##....#..# +........#. +.##.#..### +......##.# +#..#....## +....#...#. +#.#......# +###......# +...#...... +..###.##.# + +Tile 3943: +####...#.# +#..##..... +.#......#. +......##.. +..#.....## +#...#....# +....##.#.# +.......... +..#....#.# +..#.....## + +Tile 1283: +..##...### +#..#....#. +#...#..... +.#.....##. +#.##....## +.#..#...#. +#....#...# +##....#... +.##...#### +##..##.### + +Tile 3067: +#.#.#.#.#. +#..#...... +..##...... +#..#...#.# +.##.#....# +......#... +#...#.#.## +.#..##..#. +...#...### +...##..#.. + +Tile 2957: +.#..###... +#........# +......#.## +...#..##.# +###....#.# +.....#..## +#.......#. +#....##.#. +......#.## +.##..#..## + +Tile 1571: +..#...##.# +#..####..# +#......... +.#.###..## +#.....##.# +......#... +..#....... +.#........ +........#. +####.#..## + +Tile 1481: +#.#..##... +#...#....# +#.....#..# +..#......# +.#...#.#.# +....#..### +.#.###.... +.....###.. +.#....#..# +####..#..# + +Tile 1637: +#.##...#.. +.........# +#........# +.###.....# +##..#..#.. +.#....#... +.......#.# +.....#.... +#..##..#.# +#..###.#.# + +Tile 1567: +####.#.#.# +...##..... +......#... +.#...##... +#.#....#.# +#.#......# +.###.....# +##..#..#.. +...#...... +########.. + +Tile 1117: +#..#.#.#.# +....#....# +.#.#..##.. +....#.##.. +##..#..... +...#...... +#....#...# +...##..#.# +...#....#. +.#..#.##.. + +Tile 1663: +####..#... +#.#......# +......#... +....#..##. +#......#.# +...##....# +#........# +#.#..#...# +####.#.... +..####.##. + +Tile 3079: +.#....#### +.#......#. +.......... +......#..# +###..#.#.# +...#....## +..##.##### +..#.###..# +....##.... +.#.######. + +Tile 2011: +##.###.... +..##.#.##. +##.##..#.. +##.....##. +#...#...#. +.#.##.##.# +###..#.### +..#....#.. +#.##..#### +.......##. + +Tile 1801: +.#..##..## +..#.###..# +....##.... +#...#.#... +..##...... +#.....#... +#......... +..##....## +#.#.#..#.# +..#.#..##. + +Tile 1499: +...#..#### +#.......#. +.......... +#.....#..# +#..###.... +#..#..##.# +...##.#..# +..#......# +..#....... +#.######.. + +Tile 1061: +###.#...## +#..###.##. +##.#...... +#.#...#... +.....#..## +.#....#.#. +...#...#.# +...###.... +.##..##.#. +#.#...#.## + +Tile 1783: +#...####.# +#.....#### +.#........ +......##.# +..##....## +..#......# +#...#.#... +#........# +.#...#...# +.#######.. + +Tile 1301: +#.....#.## +#....#...# +#.##.#...# +.#..#.#..# +.#....#.#. +....##.##. +##..#...#. +.#...#.#.. +...#.#.... +..##...... + +Tile 1259: +#..###..## +....###..# +.#...#..#. +.....#...# +.#.##..... +#..#...... +#.#.....#. +#...#....# +.....#.##. +#####...## + +Tile 3823: +#..##..#.. +#...#..... +.#.......# +#..#.##.#. +.......... +#....#.... +#.#.....## +..#.#.#... +..#......# +#..####.## + +Tile 3181: +#......... +#......### +##....##.. +......##.# +...#.##... +#.#..#...# +#.......#. +##...#.... +#.....##.# +.####.#### + +Tile 3251: +...###.##. +...#.....# +##...#...# +#.####..## +...#.#..## +..#...#.## +##....#..# +.##....... +...#.#...# +..##..#### + +Tile 3121: +#..#....#. +#..##.#... +....#....# +#....#..#. +...#.....# +....#..... +.....#...# +...###...# +#..##...#. +.####.#... + +Tile 3209: +##....#... +##.......# +.......#.. +###.#...#. +.......... +..#...#..# +..#.##..#. +##..#..... +#..####... +###..##..# + +Tile 1049: +..#..#.... +....##.... +...#...... +#...#..... +#..#.....# +...#.....# +.#.....##. +..#.#.##.# +..##.#.#.# +.##.###.#. + +Tile 3671: +.###...... +..###..#.# +....#..... +####...... +#.#.#..... +#.......#. +..##...#.. +.....#.... +.##..#.... +.##.#..##. + +Tile 1171: +...###.##. +#......... +#......... +#........# +....##.#.# +#.....#..# +##..#..... +.......#.. +...#.....# +.#####.### + +Tile 3259: +###..##.#. +#..###..## +......##.. +..#...#.#. +...#.#.... +##....#..# +..#...##.# +.#....##.. +........#. +.######... + +Tile 1601: +#..#.#.### +......#### +.#...##... +#......### +#...#....# +#....#.#.# +#...#..##. +..###.#... +#....##..# +.#.#..###. + +Tile 2371: +.#.....#.. +#.#..##... +.....##### +###..#.##. +#.####.#.. +........#. +###......# +.........# +.......### +.##.###.#. + +Tile 2153: +.#....#..# +#....#..## +#......... +.....##... +##.....##. +#.#......# +.#..##...# +##.#.#.#.. +...#.....# +.#.##.##.. + +Tile 2269: +.#.#.#.... +...#.....# +..#....#.. +#.#....... +.#.#...... +........## +.......... +...#.....# +#.##...#.# +#.#....#.. + +Tile 1291: +##.##..#.# +##.#...... +##..#..... +###...##.. +.#..#.#..# +##...#...# +..#####... +###..####. +#.#......# +.#.#.##... + +Tile 1487: +.##..##... +..#.#.##.. +#...#...## +..#.#...#. +.###...#.# +..##.....# +...#.#...# +#.....#..# +#..#...... +.##.#.#### + +Tile 3023: +########.. +.#..#..#.# +###.###... +#.#......# +##.#.#..#. +.....#.... +##..#..... +.##....... +.##......# +###..#...# + +Tile 2887: +..#.#..#.. +...#...... +.......#.# +.......#.. +#......#.# +#...#....# +..#....### +........#. +.#...#.##. +#.#..#.#.. + +Tile 2333: +#....##.#. +.#.......# +#....##..# +........## +#......... +.......... +...##.#..# +#.#.#..... +.........# +###..#.##. + +Tile 2311: +...####.#. +##.#...... +#.#....... +#.##....## +...#.#..## +..#....#.. +###....... +..#.##.... +.#.###...# +#...###.## + +Tile 1039: +.#..#.#.#. +....###... +##.......# +.##....... +..#......# +.......... +#......#.. +#....##..# +#.....#..# +..#.##..## + +Tile 3571: +....#....# +#...#...## +##......## +.......... +..#....... +.........# +...##.##.# +.#####.... +.....#.... +.#..#..... + +Tile 2221: +##.#.###.. +.###..#... +.#...#...# +#....#.... +#..#.#.... +#.#......# +#......### +..##.#.... +#...###..# +#.##...... + +Tile 1361: +.#.#.#.#.. +.##..##... +...##..... +#...##..## +##.##..#.# +...#..#... +#...#..#.. +#........# +...#...... +#..#...### + +Tile 3637: +.#####...# +#........# +#..##.#.#. +#......... +#..##..... +.#....#... +...#....## +...###..#. +#....#.#.. +##.#.#..## + +Tile 3083: +.#....#.## +#....#.... +#...#...#. +....#....# +.#.#..##.# +######..#. +#.###..... +.#........ +#........# +###..###.. + +Tile 1619: +.###...##. +#....#...# +..#..#.... +#...#.#### +#.....#.#. +#..#...... +..#..##..# +#..###.... +#..#.#.#.. +#..##..#.# + +Tile 2063: +.#..#..... +#....#.... +#..#.###.. +#.#...#... +#....##.## +#...##..#. +#........# +..#...#... +...#..#... +#......#.. + +Tile 3911: +##..##.... +##.......# +###....### +##.#.###.# +..#....... +#..#.#.### +.#.#.#.### +####..#### +..##.##.#. +......#..# + +Tile 2447: +#.......#. +##...##.#. +#.#..#...# +......###. +.#....#.## +..#...#..# +....#.#..# +#...#....# +..#....... +...##.#... + +Tile 3191: +.#....#.#. +#..#...#.# +........## +....#..#.. +#......#.# +#...##.... +#......#.# +.##...#... +##....#... +#.####...# + +Tile 1733: +..###..### +.......... +#.##....#. +#..#...#.# +#..#.....# +.......... +.........# +.......#.. +#........# +.#.##..... + +Tile 3533: +###.#...## +.........# +...##.#.#. +#........# +#..#...#.. +.#.......# +#.#...#... +##.#..##.. +#...##.### +...#.#.#.# + +Tile 3767: +.######..# +##.#####.. +....#.#... +#....##..# +.....#.#.# +#...#..#.. +#...#...## +#.###.#..# +.......... +#.#.#..#.# + +Tile 2531: +.#.#...#.. +....#....# +......#..# +#...#....# +##.......# +.#..####.. +..##..#.## +#........# +#.....#### +..##..#### + +Tile 3329: +##..#.##.# +....#...#. +##..#..#.# +##..#.#.## +...#...#.. +.#####...# +...#....## +###...#... +.......... +#######.## + +Tile 2473: +##.#.####. +#.#....... +.......#.# +#.#.#.#... +....#..#.. +#####....# +#..#..##.. +#...#..... +.....#.#.# +##.#...##. + +Tile 2851: +#......#.. +#.#....##. +.......... +#..##...## +#.#.#....# +#...#..... +#.#...##.# +##.#.#..## +#.#....... +##.##..... + +Tile 2111: +#..###..#. +#...#.#.## +#.....#... +#.....#### +#..##.#... +....##..#. +....#..... +...###.### +..#.#..... +#..#..#.## + +Tile 3001: +..#.###... +......##.. +..#...#### +#..#.#.... +##..#..... +..#.....## +.....##..# +.#.#..#..# +#.....#.## +..##...... + +Tile 2549: +.#..#..### +#..#.#.##. +.....#.... +####..#..# +......#.#. +#.....#.#. +.......... +##..#...## +...##....# +...###..#. + +Tile 3989: +.......#.# +..##.#.### +#..##..#.# +.......... +.#.##..#.. +.....#...# +..#.#..### +.....###.. +##...##... +.####..... + +Tile 3049: +##...##### +###.#...## +#....#...# +#........# +#....#.... +##..##..#. +..###.#..# +#.###..... +#...#..... +#.####.#.# + +Tile 1721: +..###.#.## +#........# +.#.#...#.# +#.##.#.### +#..###..## +.....##..# +##.#.##..# +#......#.# +....##.#.. +.#.......# + +Tile 2791: +###.#.#... +#....#.... +....##...# +...#.##.## +...#...#.. +...###.##. +.#.#..#..# +##.##...## +.##..#.##. +#..##..### + +Tile 2083: +#.#..#..## +.#....##.# +..#......# +#......... +....##...# +.......#.# +..###....# +###.....#. +###....##. +...#.#...# + +Tile 3613: +.###.#..#. +#.#..##..# +#.###.#... +.#.....#.# +......#..# +......#... +.#.#...#.# +#.......## +......#..# +#..#.#.#.. + +Tile 1201: +..#.#...#. +#.....#... +#..##..#.. +.#...#...# +#..##....# +#..#..#..# +.##.#..#.# +#..#...... +...#..#... +#...##..## + +Tile 3119: +#..#.##..# +#.#...#... +##....#.#. +#..#..#.## +#......... +...##..##. +#...#..#.# +#......... +#..#....#. +#.##.#.##. + +Tile 2459: +.#....###. +....#.#... +#..#.#.... +#...#..#.. +#........# +.#.#...... +....#...#. +#...#....# +..#.#..... +##.##..### + +Tile 2341: +#..#..###. +#.#......# +#.#....#.# +##........ +.#.##..#.# +.###...... +.......#.# +##...#.#.. +####...#.# +.#...###.# + +Tile 3011: +###..#..## +...#.###.. +#........# +.##.#...#. +.....##### +........## +.........# +#......#.. +###....... +#..###.### + +Tile 3727: +#.###..##. +#...#....# +...#....## +##..#....# +.........# +##..#..... +#......... +.##....... +#.##.###.# +#..#.#...# + +Tile 2659: +#.##.###.. +.........# +#...#..#.. +.#..#.#... +....##...# +#..#.##... +#.##.....# +.......... +...##..#.. +#.##..#.#. + +Tile 2657: +#...###### +..#...#... +..#......# +...#...#.. +......###. +#......##. +#..#..#..# +#.#.#..#.. +.###..#... +#......### + +Tile 2789: +#.....#..# +...#..###. +#.#....... +#........# +.#.#....#. +...#.....# +.#.....### +##.##....# +.##...#... +#####..#.# + +Tile 1627: +#.##..#.## +#...##.#.# +....#....# +##..#...## +.....#...# +.#..#....# +........#. +#.#.###.## +.#.##.#..# +.#.###.#.. + +Tile 3167: +..###.#... +.....#..## +#..##..... +#.#..##.#. +#.....#.## +####.....# +#.###..#.. +.##....#.. +.#..#..... +#....#.#.# + +Tile 3229: +###...#.## +##....##.. +#.......## +...##....# +#.#.....#. +........## +##...#...# +#........# +..#......# +..#.....## + +Tile 2383: +#.####.### +.#.#...#.. +####..#.#. +.#..#.#..# +..#.#..#.. +##.....#.. +.....#.#.# +...##..#.# +##...####. +##...#.#.# + +Tile 1381: +#.#.#.#### +........## +.#..#..#.. +#.....##.. +.#...#.#.# +#.....#..# +...##..#.. +..####.... +##........ +..######.# + +Tile 3089: +..#..####. +.....#...# +.#........ +.###..#.## +#..#.....# +#..##..#.# +##.....#.# +#...#.#... +.....#...# +...##.##.# + +Tile 1229: +##..#....# +##.#.#...# +#...#..### +#......... +.......#.. +...#.....# +#.#....... +.......... +#...#.##.. +.#...##### + +Tile 3691: +.####.#.#. +#..#.##..# +.....#.### +#....#..## +##........ +#...##.#.# +#.....#..# +..#.#..... +.##...##.# +#.##..#... + +Tile 1019: +...##.#..# +#..#.....# +.........# +##..#..#.. +#.....#... +#....#.#.. +#.#..#.... +#.#...#..# +##....#..# +.#.#####.. + +Tile 3217: +#.##..##.. +#.#...###. +#.#....#.# +.#.#...... +##.......# +...#.#..#. +##.#...... +#.#.....## +.#........ +.######... + +Tile 2833: +....###.## +##........ +....###... +....##.... +.#.#...... +..#...##.# +#.##....## +.###.#.... +...##..#.# +.#.#....#. + +Tile 1493: +...#.#.#.# +#.#..#.... +#...#....# +.##......# +..#.##...# +#......... +.........# +##....#..# +#.#....... +.#.#..#..# + +Tile 2963: +.##..#..## +#.#.....#. +#........# +#..#.#.... +#........# +##....#..# +#.....##.# +###......# +.#....#... +......#..# + +Tile 1873: +.###.#.#.. +...##..... +#...#..... +.......#.# +.#.....#.# +...#....#. +..#..#.... +##..#.#... +..#....### +#.##.##### + +Tile 2539: +#..#...#.# +##.......# +#..#..#..# +......#.#. +.......... +.###.#.##. +##.#.##..# +.......### +..#.###... +##.####... + +Tile 2339: +#.###.#.## +#.....#..# +.......... +#......... +......##.# +#..#.###.# +#......... +.......#.. +.........# +...##..... + +Tile 1303: +....##.### +#.#..#...# +.........# +#.....#.## +.#..#....# +.......#.# +...#....#. +#.####...# +.#.#....#. +##...#..#. + +Tile 3539: +.#........ +.#..#.##.# +###..##.## +....#....# +#......#.. +#.###.#.## +.........# +..#...#.#. +##......#. +.#..#....# + +Tile 1153: +#..##.#.## +#.#...#.## +#..##..#.. +#..#..#..# +####.#.### +#...#...#. +#.....#... +#..##..#.# +.##.###.## +####.#.### + +Tile 2273: +#.#....##. +###..####. +##....#### +##.....#.. +..#.....#. +....#...## +##........ +.#.......# +#........# +.#..#.##.# + +Tile 2543: +..###...#. +#..#..#... +####....#. +...###..#. +...#.#..## +###.#..... +#......... +##.....#.. +..#...#... +..####...# + +Tile 1451: +.#.####.## +.....#.#.# +.##....... +..#......# +...#.#..## +..#......# +#...##..## +#.#....... +#......... +#..#..#... + +Tile 3203: +..###..... +#...#....# +###..##... +.......... +###....#.. +........## +...#...... +#......##. +....#.#..# +.###.##... + +Tile 1009: +..#.#..##. +##..#....# +#..##...## +##...#...# +##...#..#. +...#...### +....##.#.. +....#.##.# +...##.#### +....#.#... + +Tile 1531: +.....#.##. +.#.####... +....##.#.# +#...#...## +#....##.#. +###......# +..#..##... +#..#.....# +..#....#.# +###.#..#.. + +Tile 3617: +.##.##.#.# +#....#..#. +.#....#.#. +#......... +.#...##..# +.##.#.##.# +#.#.#.##.# +.....###.. +.#..#.##.# +.#.....##. + +Tile 2617: +#..##.#..# +#..#....#. +.#.......# +#..#...... +.###.####. +..#.....## +..#..#.... +..#....... +....#..... +#....##### + +Tile 1847: +..#.#...#. +.##....#.. +###.#.##.# +..#.##..## +#####...#. +.###.#...# +#.......## +..#.#..#.. +...##.#... +.###.#.##. + +Tile 3299: +..#.##.##. +...##..... +#........# +...#.##.#. +.#####.... +#..#.#..## +#..#..#.## +..#..#...# +#.#.#..... +.#...#..#. + +Tile 2591: +......#.#. +#....#...# +##......## +...#...#.. +..#....... +.....#.#.# +#.......## +..###...## +#..#..##.# +.....#.##. + +Tile 3169: +###...##.# +..#..##..# +#..###...# +.#..#....# +..#......# +....#.#... +.##.#..### +..##...##. +###....... +##..#.#### + +Tile 3697: +..#.#.#..# +.###.#...# +#.##...##. +.#.##.#... +#..##....# +.......... +#....#.... +.##....... +#..#.#.##. +#.....#..# + +Tile 2551: +#.##..#..# +#..#...... +.#..#..... +#....#..#. +#.......## +.#..#....# +.#........ +....#..... +.#.##..... +###.#.#... + +Tile 2909: +.....#.#.. +.#.#.....# +#....##... +#......##. +...#...... +##.......# +......###. +#..#.##... +...#...##. +#.##...### + +Tile 2027: +.#.#.####. +..##.....# +#...##.### +.##.#..... +##.##....# +....#.#... +#.##....#. +..###..#.# +#...#.#.## +##..#.##.# + +Tile 3947: +#.#.#.##.# +.#........ +#....##..# +#......... +.....#...# +......#... +#.#.##...# +.##.#..... +.........# +.###.#...# + +Tile 3797: +#...####.. +.#....##.. +#.....#... +.....#.#.# +...#..##.. +.....#...# +......##.# +.##...#... +.....##... +.#..#.#.#. + +Tile 3187: +##...#..#. +#..#..#..# +#........# +......#.#. +......##.. +#.#....... +#.#......# +##...#..## +##..#...## +####...#.# + +Tile 1151: +..#..#..## +...#.#.... +#.#.#....# +..#......# +...##....# +..#....... +#......#.. +#.##..#... +#.#....### +######.#.. + +Tile 1511: +#...#..... +#.######.# +#.....#... +....#...#. +#..###.#.# +.....#.#.# +....#....# +#..#...##. +#........# +#....#.##. + +Tile 2293: +##...#...# +#......#.. +.#..#..... +#...###..# +##....#..# +#...##.#.# +....#..... +....#..... +#.....#.## +##.#.##.## + +Tile 2131: +#.#..#.#.. +#..#...#.. +#.##..#... +....##..#. +#........# +#..#.....# +##.......# +####.#...# +.##..#.#.. +###..#..#. + +Tile 2711: +..###..... +..#....... +..##...##. +##..#..##. +.#...#.... +.....#.... +#...#....# +.##.#.#..# +#.##.#.... +##.#..##.# + +Tile 1543: +##.....##. +#...###... +...#.#..#. +#.#...#.## +.#.#.###.. +####...### +#..##..#.. +####..#.## +#.##...#.. +...#..#.#. + +Tile 1723: +.#####.### +....##.... +##........ +#.......#. +#..####..# +.####..##. +.#........ +#..#..#... +.......... +..#.#.##.. + +Tile 2819: +..#..##.## +.....#.... +#.#.....## +..#....... +..##..#.#. +#....#...# +#...#...#. +..#....... +.........# +#.#..###.. diff --git a/d20/main.py b/d20/main.py new file mode 100755 index 0000000..d21337a --- /dev/null +++ b/d20/main.py @@ -0,0 +1,400 @@ +#! /usr/bin/env python3 +from itertools import chain +from functools import reduce +from typing import List +from typing import Optional +from typing import Set +from typing import Tuple + + +class Tile(object): + def __init__(self, tile_num: int, content: List[List[str]]): + self.num = tile_num + self.content = content + + # Neighboring tiles + self.top: Optional["Tile"] = None + self.bottom: Optional["Tile"] = None + self.left: Optional["Tile"] = None + self.right: Optional["Tile"] = None + + # All edges for quick match + self.edges: Set[str] = set() + self.edges.add(self.top_edge) + self.edges.add(self.top_edge[::-1]) + self.edges.add(self.bottom_edge) + self.edges.add(self.bottom_edge[::-1]) + self.edges.add(self.left_edge) + self.edges.add(self.left_edge[::-1]) + self.edges.add(self.right_edge) + self.edges.add(self.right_edge[::-1]) + + @property + def left_edge(self) -> str: + return "".join( + [self.content[y][0] for y in range(0, len(self.content))] + ) + + @property + def right_edge(self) -> str: + return "".join( + [self.content[y][-1] for y in range(0, len(self.content))] + ) + + @property + def top_edge(self) -> str: + return "".join(self.content[0]) + + @property + def bottom_edge(self) -> str: + return "".join(self.content[-1]) + + def flip_lr(self): + for i, row in enumerate(self.content): + self.content[i] = row[::-1] + + def flip_tb(self): + self.content = self.content[::-1] + + def rotate_cw(self): + self.content = [ + [self.content[j][i] for j in range(len(self.content)-1, -1, -1)] + for i in range(len(self.content[0])) + ] + + def rotate_ccw(self): + self.content = [ + [self.content[j][i] for j in range(len(self.content))] + for i in range(len(self.content[0])-1, -1, -1) + ] + + def align_edge(self, edge: str, direction: str): + assert edge in self.edges + + if direction in ("top", "bottom"): + while getattr(self, direction+"_edge") != edge: + if getattr(self, direction+"_edge")[::-1] == edge: + self.flip_lr() + return + + self.rotate_cw() + elif direction in ("left", "right"): + while getattr(self, direction+"_edge") != edge: + if getattr(self, direction+"_edge")[::-1] == edge: + self.flip_tb() + return + self.rotate_cw() + else: + raise ValueError(f"Unknown direction {direction}") + + def count_neighbors(self, other_tiles: List["Tile"]) -> int: + num_neighbors = 0 + for tile in other_tiles: + if self.num == tile.num: + continue + if self.edges & tile.edges: + num_neighbors += 1 + + return num_neighbors + + def find_bottom( + self, + other_tiles: List["Tile"], + assign: Optional[bool] = True, + ) -> Optional["Tile"]: + bottom_tile: Optional[Tile] = None + for tile in other_tiles: + if self.num == tile.num: + continue + if self.bottom_edge in tile.edges: + tile.align_edge(self.bottom_edge, "top") + if bottom_tile is None: + bottom_tile = tile + else: + raise ValueError("Multiple match error") + if assign: + self.bottom = tile + tile.top = self + + return bottom_tile + + def find_right( + self, + other_tiles: List["Tile"], + assign: Optional[bool] = True, + ) -> Optional["Tile"]: + right_tile: Optional[Tile] = None + for tile in other_tiles: + if self.num == tile.num: + continue + if self.right_edge in tile.edges: + tile.align_edge(self.right_edge, "left") + if right_tile is None: + right_tile = tile + else: + raise ValueError("Multiple match error") + if assign: + self.right = tile + tile.left = self + + return right_tile + + def remove_edges(self): + self.content = [ + row[1:-1] + for row in self.content[1:-1] + ] + + def __add__(self, other) -> "Tile": + new_content = [ + s + o + for s, o in zip(self.content, other.content) + ] + + return Tile(self.num * other.num, new_content) + + def __truediv__(self, other) -> "Tile": + new_content = [ + row for row in chain(self.content, other.content) + ] + + return Tile(self.num * other.num, new_content) + + def __eq__(self, other) -> bool: + return self.num == other.num + + def __hash__(self) -> int: + return self.num + + def __repr__(self) -> str: + return f"" + + def to_str(self) -> str: + return "\n".join( + "".join(row) + for row in self.content + ) + + def total_turbulance(self) -> int: + total = 0 + for row in self.content: + for c in row: + if c == "#": + total += 1 + + return total + + +SEAMONSTER = [ + " # ", + "# ## ## ###", + " # # # # # # ", +] + +IN_THE_SEA: Set[Tuple[int, int]] = set() + + +def search_seamonster( + content: List[List[str]], + x: int, + y: int, +) -> Tuple[bool, int]: + found = True + turbulance = 0 + + in_the_sea: Set[Tuple[int, int]] = set() + for yi in range(len(SEAMONSTER)): + if y+yi >= len(content): + return False, 0 + row = content[y+yi] + for xi in range(len(SEAMONSTER[yi])): + p = (x+xi, y+yi) + if p in IN_THE_SEA: + return False, 0 + + if x+xi >= len(row): + return False, 0 + + c = row[x+xi] + sea = SEAMONSTER[yi][xi] + + if sea == "#" and c == "#": + in_the_sea.add(p) + # Not a seamonster match + elif sea == "#" and c != "#": + return False, 0 + elif sea == " " and c == "#": + turbulance += 1 + elif sea == " " and c == ".": + continue + else: + raise ValueError(f"Uncharted waters: {sea}, {c}") + + if found: + for p in in_the_sea: + IN_THE_SEA.add(p) + + return found, turbulance + + +def read_tiles(filename: str) -> List[Tile]: + results: List[Tile] = [] + with open(filename) as f: + tile_num = -1 + content: List[List[str]] = [] + for line in f: + line = line.strip() + if line.startswith("Tile "): + tile_num = int(line[5:line.index(":")]) + elif line == "": + results.append(Tile(tile_num, content)) + tile_num = -1 + content = [] + else: + content.append([c for c in line]) + + results.append(Tile(tile_num, content)) + + return results + + +def test(): + tiles = read_tiles("test-input.txt") + corners: List[Tile] = [] + for tile in tiles: + num_neighbors = tile.count_neighbors(tiles) + print(f"Tile: {tile.num}: {num_neighbors}") + if num_neighbors == 2: + corners.append(tile) + + product = 1 + for t in corners: + product *= t.num + + print("Corner product:", product) + + +def part1(): + tiles = read_tiles("input.txt") + corners: List[Tile] = [] + for tile in tiles: + num_neighbors = tile.count_neighbors(tiles) + print(f"Tile: {tile.num}: {num_neighbors}") + if num_neighbors == 2: + corners.append(tile) + + product = 1 + for t in corners: + product *= t.num + + print("Corner product:", product) + + +def part2(): + tiles = set(read_tiles("input.txt")) + corners: List[Tile] = [] + for tile in tiles: + num_neighbors = tile.count_neighbors(tiles) + print(f"Tile: {tile.num}: {num_neighbors}") + if num_neighbors == 2: + corners.append(tile) + + product = 1 + for t in corners: + product *= t.num + + top_left: Optional[Tile] = None + + print("Corner product:", product) + for corner in corners: + right = corner.find_right(tiles, False) + if not right: + continue + bottom = corner.find_bottom(tiles, False) + if not bottom: + continue + + top_left = corner + # print(corner.to_str(), corner.right.to_str()) + # print(corner.bottom.to_str()) + break + else: + print("no perfect corner") + + # Init grid + g = [[top_left]] + print("removing", top_left) + tiles.remove(top_left) + + tile = top_left + tile.find_bottom(tiles) + + # Build rows + while tile.bottom: + tile = tile.bottom + g.append([tile]) + print("removing bottom", tile) + tiles.remove(tile) + tile.find_bottom(tiles) + + for row in g: + tile = row[0] + tile.find_right(tiles) + while tile.right: + print(f"removing right {tile}->{tile.right}") + tile = tile.right + row.append(tile) + tiles.remove(tile) + tile.find_right(tiles) + + v_split = Tile(0, [[" "] for _ in range(len(top_left.content))]) + h_split = Tile(0, [[" " for _ in range(len(top_left.content[0]))]]) + m = reduce(lambda x, y: x/h_split/y, ( + reduce(lambda x, y: x+v_split+y, (tile for tile in row)) + for row in g + )) + + m.flip_tb() + print(m.to_str()) + + # Trim all edges + for row in g: + for t in row: + t.remove_edges() + + m = reduce(lambda x, y: x/y, ( + reduce(lambda x, y: x+y, (tile for tile in row)) + for row in g + )) + + turbulance = m.total_turbulance() + seamonsters = 0 + + while seamonsters == 0: + m.rotate_cw() + content = m.content + for y in range(len(content)): + for x in range(len(content[y])): + found, _ = search_seamonster(content, x, y) + if found: + print("found a seamonster at", x, y) + seamonsters += 1 + + sea_turb = 0 + for row in SEAMONSTER: + for c in row: + if c == "#": + sea_turb += 1 + + turbulance -= sea_turb * seamonsters + + for p in IN_THE_SEA: + m.content[p[1]][p[0]] = "O" + + print(m.to_str()) + print(f"Found {seamonsters} seamonsters with {turbulance} turbulance") + + +if __name__ == "__main__": + # part1() + part2() diff --git a/d20/output.txt b/d20/output.txt new file mode 100644 index 0000000..aef869b --- /dev/null +++ b/d20/output.txt @@ -0,0 +1,142 @@ +...###...##...#...#..### +.#.###..##..##..####.##. +#.##..#..#...#..####...# +#####..#####...###....## +#..####...#.#.#.###.###. +..#.#..#..#.#.#.####.### +.####.###.#...###.#..#.# +.#.#.###.##.##.#..#.##.. +###.#...#..#.##.######.. +.#.#....#.##.#...###.##. +...#..#..#.#.##..###.### +##..##.#...#...#.#.#.#.. +#.####....##..########.# +###.#.#...#.######.#..## +#.####..#.####.#.#.###.. +#..#.##..#..###.#.##.... +.####...#..#....#..##### +....#..#...##..#.#...... +...########.#...#####... +##.#....#.##.######.#..# +###.#####...#.###...#.## +##.##.###.#.#..#.#####.# +###....#.#....#..#.###.. +.#.#..#.##...#.#.#...... + +.####...#####..#...###.. +#####..#..#.#.####..#.#. +.#.#...#.###...#.##.O#.. +#.O.##.OO#.#.OO.##.OOO## +..#O.#O#.O##O..O.#O##.## +...#.#..##.##...#..#..## +#.##.#..#.#..#..##.#.#.. +.###.##.....#...###.#... +#.####.#.#....##.#..#.#. +##...#..#....#..#...#### +..#.##...###..#.#####..# +....#.##.#.#####....#... +..##.##.###.....#.##..#. +#...#...###..####....##. +.#.##...#.##.#.#.###...# +#.###.#..####...##..#... +...###.##.##...#.######. +###.###..#######..#####. +..#.##..#..#.#######.### +.##..#.#########..#..##. +.#####.#.#.#...##..#.... +.##....#.#.#########..## +...#...#..#..##...###.## +..###..#..##.#...##.##.# + +.####...#####..#...###.. +#####..#..#.#.####..#.#. +.#.#...#.###...#.##.O#.. +#.O.##.OO#.#.OO.##.OOO## +..#O.#O#.O##O..O.#O##.## +...#.#..##.##...#..#..## +#.##.#..#.#..#..##.#.#.. +.###.##.....#...###.#... +#.####.#.#....##.#..#.#. +##...#..#....#..#...#### +..#.##...###..#.#####..# +....#.##.#.#####....#... +..##.##.###.....#.##..#. +#...#...###..####....##. +.#.##...#.##.#.#.###...# +#.###.#..####...##..#... +#.###...#.##...#.##O###. +.O##.#OO.###OO##..OOO##. +..O#.O..O..O.#O##O##.### +#.#..##.########..#..##. +#.#####..#.#...##..#.... +#....##..#.#########..## +#...#.....#..##...###.## +#..###....##.#...##.##.# + + +..#.#....# ##.#.#.... ...##..... +#...###... ..##...#.. ...#..#### +#.#.###... .##..##... .####.##.# +##.##..#.. ..#...#... .####...#. +.#####..## #####...#. .##....##. +.#..####.# #..#.#.#.# ####.###.. +#..#.#..#. ...#.#.#.. .####.###. +..####.### ##.#...##. .#.#..#.## +..#.#.###. ..##.##.## #..#.##..# +...#.#.#.# ###.##.#.. .##...#### + +...#.#.#.# ###.##.#.. .##...#### +####.#.... .#..#.##.. .######... +..#.#..... .#.##.#..# #.###.##.. +....#..#.# #.#.#.##.# #.###.###. +.##..##.#. ....#...## #.#.#.#... +.#.####... ...##..##. .######.## +####.#.#.. ...#.##### ###.#..### +##.####... .#.####.#. ..#.###..# +##..#.##.. ..#..###.# ##.##....# +#.##...##. ..##.#..#. ..#.###... + +#.##...##. ..##.#..#. #.#.#####. +#.####...# ##..#..... .#..###### +.....#..## #...##..#. ..#....... +#...###### ####.#...# ######.... +.##.#....# ##.##.###. ####.#..#. +.###.##### ##...#.### .#...#.##. +###.##.##. .#.#.#..## #.#####.## +.###....#. ..#....#.. ..#.###... +..#.#..#.# ###...#.#. ..#....... +#...##.#.. ..###..### ..#.###... + + +#...##.#.. ..###..### #.#.#####. +..#.#..#.# ###...#.#. .#..###### +.###....#. ..#....#.. ..#....... +###.##.##. .#.#.#..## ######.... +.###.##### ##...#.### ####.#..#. +.##.#....# ##.##.###. .#...#.##. +#...###### ####.#...# #.#####.## +.....#..## #...##..#. ..#.###... +#.####...# ##..#..... ..#....... +#.##...##. ..##.#..#. ..#.###... + +#.##...##. ..##.#..#. ..#.###... +##..#.##.. ..#..###.# ##.##....# +##.####... .#.####.#. ..#.###..# +####.#.#.. ...#.##### ###.#..### +.#.####... ...##..##. .######.## +.##..##.#. ....#...## #.#.#.#... +....#..#.# #.#.#.##.# #.###.###. +..#.#..... .#.##.#..# #.###.##.. +####.#.... .#..#.##.. .######... +...#.#.#.# ###.##.#.. .##...#### + +...#.#.#.# ###.##.#.. .##...#### +..#.#.###. ..##.##.## #..#.##..# +..####.### ##.#...##. .#.#..#.## +#..#.#..#. ...#.#.#.. .####.###. +.#..####.# #..#.#.#.# ####.###.. +.#####..## #####...#. .##....##. +##.##..#.. ..#...#... .####...#. +#.#.###... .##..##... .####.##.# +#...###... ..##...#.. ...#..#### +..#.#....# ##.#.#.... ...##..... diff --git a/d20/test-input.txt b/d20/test-input.txt new file mode 100644 index 0000000..b07aa4b --- /dev/null +++ b/d20/test-input.txt @@ -0,0 +1,107 @@ +Tile 2311: +..##.#..#. +##..#..... +#...##..#. +####.#...# +##.##.###. +##...#.### +.#.#.#..## +..#....#.. +###...#.#. +..###..### + +Tile 1951: +#.##...##. +#.####...# +.....#..## +#...###### +.##.#....# +.###.##### +###.##.##. +.###....#. +..#.#..#.# +#...##.#.. + +Tile 1171: +####...##. +#..##.#..# +##.#..#.#. +.###.####. +..###.#### +.##....##. +.#...####. +#.##.####. +####..#... +.....##... + +Tile 1427: +###.##.#.. +.#..#.##.. +.#.##.#..# +#.#.#.##.# +....#...## +...##..##. +...#.##### +.#.####.#. +..#..###.# +..##.#..#. + +Tile 1489: +##.#.#.... +..##...#.. +.##..##... +..#...#... +#####...#. +#..#.#.#.# +...#.#.#.. +##.#...##. +..##.##.## +###.##.#.. + +Tile 2473: +#....####. +#..#.##... +#.##..#... +######.#.# +.#...#.#.# +.######### +.###.#..#. +########.# +##...##.#. +..###.#.#. + +Tile 2971: +..#.#....# +#...###... +#.#.###... +##.##..#.. +.#####..## +.#..####.# +#..#.#..#. +..####.### +..#.#.###. +...#.#.#.# + +Tile 2729: +...#.#.#.# +####.#.... +..#.#..... +....#..#.# +.##..##.#. +.#.####... +####.#.#.. +##.####... +##..#.##.. +#.##...##. + +Tile 3079: +#.#.#####. +.#..###### +..#....... +######.... +####.#..#. +.#...#.##. +#.#####.## +..#.###... +..#....... +..#.###... diff --git a/d21/input.txt b/d21/input.txt new file mode 100644 index 0000000..957f835 --- /dev/null +++ b/d21/input.txt @@ -0,0 +1,46 @@ +pnglkx nfnzx tjsdp jkbqk rpmqq gzgvdh rgdx szsbj xjdhk zfml ddbmq thvm mvnqdh gsgmdn dtlhh rqqfnlc bxv nthhxn hnmjfl ckqq qrsczjv fkh hkxcb rpcdfph flhfddq qspfqb zmb rpmmv zrgzf jfqqgtl xxfgvz kltcm xjrpr vnfmc xhmmt zkzdrn jmdg xgbvk ngqh hlmvqh djpsmd bnzq rbvdt tfmgl pjln (contains sesame, nuts) +qchnn dnpgcd zfml thvm gsgmdn frld nfnzx nqfc xbpb kltcm ljmvpp mrfxh zntrfp gzgvdh rrbndl pptgt rknm qsgb mstc ckqq zzldmh nggcjr bkd zfsks hlmvqh cxzkmr zmb tzjnvp npbnj lh pfqxsxd clqk rpmmv szsbj mnvq cnghsg jdtzr kfsfn jxjqp knqzf lvjpp qdpbx qrsczjv xxfgvz ngqh zrgzf jvvmcq zmcj dsmc xhmmt (contains sesame) +hlmvqh klmjmz clqk qrsczjv pjln lvjpp tbm thvm rqqfnlc gzgvdh klx sfk bnzq mhrm vht pjqdmpm tfmgl cxzkmr ghr rxrgtvs rfh rhrc vnfmc ljhn fbcds rkzhxmh htllnq zrgzf xhmmt rcr dgrrm xlzqfb xlnn ckqq vpgvm zntrfp jmdg pgqxp xjrpr vnmfg vqrjn thcs mnvq rczbvg bkd zqsc ngqh rpmqq zmcj cbbkfx rpcdfph mrfxh jfqqgtl mszc tzjnvp sdccxkt rcvd pcf xzcdnr jgtrnm zfcvnj dsmc gjqfj gtgrcf nthhxn jngghk hnmjfl qspfqb bxv (contains eggs) +nthhxn htllnq pbn qsgb mrfxh zrgzf dvcfx mstc jngghk xddkbd dpfphd zhghprj rfh ljmvpp vtljml pmtfmv zmb xxfgvz crnfzr xbpb jmdg tshn nqfc kmsh rknm hkqp pjqdmpm pjln ddbmq bjvcg zntrfp vnfmc qszmzsh fhtsl tjsdp kfsfn jkbqk thvm mnvq dnpgcd xzcdnr xjrpr rbvdt vht jxjqp zzldmh cnghsg pzxj jfqqgtl ckqq kqzcj lxr glrc dgrrm cxzkmr clqk xjdhk hlmvqh vpvj lbfgp klmjmz (contains dairy, peanuts, eggs) +rqqfnlc vgp tbm tjsdp tshn zzldmh zrgzf vgjbgj pptgt xnfhq pbn rpmmv dnpgcd qszmzsh rbvdt nzlks xddkbd thvm npbnj lxr szsbj dtlhh mrfxh ljmvpp xjzc zmb pjqdmpm rknm rrbndl xhmmt hlmvqh jmdg pjln pfqxsxd jdtzr jnr jkbqk vht vhcnpg ckqq ddgdhg pzxj ljhn xgbvk qfkjsq zhghprj gzgvdh xzcdnr ddbmq rcvd lbfgp mvnqdh rfh nggcjr gjqfj hrfmdk (contains dairy) +cmnb cnghsg cxzkmr vfkpj pgb xddkbd qfvfzg gzgvdh bxv zfml clqk pbn nthhxn jmdg ckqq rvchbn xbpb sfk dtlhh rqqfnlc rhrc djpsmd qrftr gjqfj bjvcg zntrfp qrsczjv thvm zlgztsbd lbfgp vnmfg jkbqk lvjpp pfqxsxd ljmvpp mrfxh mnvq ljhn fkh ddrd hlmvqh qmmt rcr vht xgbvk ddbmq tbm vhcnpg srgnx zrgzf ngqh mhrm pptgt glrc rpmmv kx htllnq (contains soy, shellfish) +fdf tshn zhghprj xjzc xxfgvz nggcjr hkqp vgjbgj ckqq hnmjfl mstc dmxhhd rpmmv jdtzr klx ngqh gtgrcf bjvcg vgp jgtrnm ttxx bcvmz pgqxp nfnzx sjgx zfcvnj tzjnvp qmmt jmdg qdpbx zmb rhrc gmc zfsks ljmvpp gjqfj fjgxv zttx lbskg vnfmc vfkpj lxr hkxcb dln xbpb sfk vpgvm thvm ljhn rknm rfh mgxzl thcs jfqqgtl bkd sdccxkt zzldmh mrfxh rcvd qchnn xhmmt rkzhxmh xgbvk csfmx zrgzf qrsczjv gzgvdh ncqdr rxr vtljml lbfgp pzxj djpsmd dpfphd rczbvg knnmm xmjlsn (contains nuts, dairy, sesame) +klx hkqp lqmfgp mstc mgxzl cxfzhj xxfgvz qrsczjv jxjqp ljhn pcf mrxg jmdg bjvcg vht lbskg tphtz nldzpc tjsdp mszc hlmvqh sfk dln ghr mppf lbfgp zkzdrn qdpbx bnzq qsgb rrbndl nggcjr zttx qjsbk llgsg srgnx dbx stcsp rcr zfml jvvmcq pptgt gmc fkh xjdhk pzxj zntrfp flhfddq knqzf ddrd jmgt fdf thcs lh mrfxh xmjlsn kglr pjqdmpm kx dpfphd vqrjn vhcnpg rxrgtvs pfqxsxd nqfc ckqq cbbkfx dtlhh thvm zmb qmmt xlzqfb rpmmv jfqqgtl gsgmdn bcvmz mnvq fbcds xjzc gtgrcf (contains nuts, sesame) +gzgvdh vbqbkt fjgxv nggcjr jvvmcq pptgt fmvvb zqsc hlmvqh rbvdt llgsg xddkbd rfh pjln tzjnvp glrc zmb rqqfnlc zttx qrsczjv rrbndl qfkjsq mppf rxrgtvs lvjpp dtlhh zfml stcsp zkzdrn vtljml qdpbx zrgzf fstgc xlnn sdccxkt hkxcb kltcm xlzqfb jfqqgtl npbnj bcvmz rknm ngqh xbpb rcr thvm kglr dbx xxfgvz bjvcg rpmmv srgnx ckqq gjqfj tshn gmc vgp dgrrm ljhn knnmm qkgqv mstc pnglkx flhfddq tjsdp jmdg zntrfp vgjbgj bkd (contains soy) +qjsbk fkh xddkbd fjgxv lbfgp rxr ckqq tphtz vhcnpg klmjmz pmtfmv jmdg hrfmdk dbx fbcds jnr xxfgvz pfqxsxd qfvfzg bxv flhfddq rknm rpmqq pjln sdccxkt pgb klx jdtzr zmb thvm hlmvqh lxr zrgzf nthhxn vnmfg jgtrnm nfnzx zzldmh ddbmq nldzpc tvqbhv dznd dnpgcd cmnb vpvj sjgx xjzc hkxcb szsbj dcbk pmvl pjqdmpm mhrm rgdx jfqqgtl zttx vtljml mrfxh cbbkfx knqzf mszc jkbqk xbpb vgjbgj pptgt vfkpj vqrjn zhghprj xnfhq tshn rcvd xjdhk djpsmd rfh glrc rkzhxmh (contains wheat, dairy) +mvnqdh nqfc bjvcg ckqq zfcvnj jmdg ljhn hkqp srgnx zfsks bxv xbpb rkzhxmh cxfzhj rpmqq zdntns dnpgcd thcs lvjpp klx jngghk flhfddq gmc pjln dcbk cbbkfx vbqbkt qchnn tshn fhtsl qmthj jvvmcq ncqdr jmgt csfmx qrsczjv tzjnvp rczbvg rcr hlmvqh rbvdt gtgrcf thvm cnghsg zrgzf rxrgtvs zmb (contains peanuts, soy) +ckqq frld mvnqdh tphtz bjvcg xzcdnr djpsmd ttxx dcbk qdpbx tshn rczbvg vpvj qmmt ddrd dln bxv zrgzf jxjqp lh mgxzl qrsczjv ltvr pbn nggcjr dsmc llgsg knnmm pzxj cnghsg thvm vnmfg mhrm xlnn gjqfj pptgt jkbqk htllnq jmdg xnfhq klx jmgt mrfxh rxr hnmjfl lqmfgp qrftr mppf sjgx rvchbn lvjpp mstc zqsc gmc kmsh rpmmv crnfzr hrfmdk kglr hlmvqh cxzkmr dvcfx (contains shellfish, eggs, dairy) +xjrpr mjpt cbbkfx rpmqq ljhn jmdg vht sdccxkt ngqh bnzq jgtrnm fmvvb mrfxh xxfgvz jfqqgtl tfmgl bcvmz pgqxp thvm crnfzr xddkbd zfsks qrsczjv pzxj tshn fbcds lbfgp thcs hkqp gsgmdn dvcfx zmb cnghsg csfmx vhqfz rxr bxv xjdhk zhghprj dtlhh ckqq qmthj jxjqp rczbvg gmc sfk ttxx ltvr pnglkx dnpgcd qsgb clqk klmjmz lh rvchbn pjln knqzf vnfmc qspfqb nthhxn zqsc mhrm gzgvdh ncqdr zrgzf ddrd vqrjn (contains nuts, shellfish) +rvchbn vhcnpg mstc zrgzf hkqp bnzq xbpb qrsczjv fhtsl fjgxv ddgdhg jfqqgtl rpmqq dpfphd pcf qrftr ngqh vht dvcfx dfrg tphtz mnvq qjsbk mvnqdh zntrfp xjzc jmgt xzcdnr vnfmc xddkbd fkh kmsh xmjlsn ckqq zfsks bcvmz ljhn gmc rrbndl fmvvb cxzkmr lh zdntns pgb thvm xxfgvz hrfmdk dln mrfxh tvqbhv cnghsg vpgvm hlmvqh mjpt jdtzr dgrrm kglr pgqxp kqzcj hkxcb xgbvk djpsmd tshn klmjmz rfh xlnn bjvcg qfkjsq rkzhxmh glrc clqk gjqfj jmdg knqzf ljmvpp csfmx rbvdt zfcvnj dsmc fstgc (contains dairy) +nthhxn vnfmc dsmc vpvj rhrc zfcvnj zdntns qmthj knnmm rpmmv dtlhh qdpbx zhghprj xddkbd mrfxh rqqfnlc dpfphd xhmmt dgrrm pgqxp zmb gmc flhfddq zkzdrn hlmvqh qrsczjv vhcnpg mjpt fbcds thvm ncqdr pjln zttx hrfmdk xlnn dvcfx fkh mszc klx cmnb zfml zrgzf mnvq rcr bjvcg csfmx xlzqfb ckqq (contains sesame, shellfish) +xnfhq hlmvqh lh qdpbx rpcdfph qsgb rpmqq tjsdp ljhn gsgmdn vfkpj jmdg xlzqfb ckqq qmmt jmgt dvcfx zrgzf bkd pmvl ngqh sjgx dpfphd kfsfn mrfxh bjvcg jkbqk qrftr mjpt vnmfg nldzpc ncqdr jvvmcq pptgt pjqdmpm thvm pjln ddrd csfmx kglr xgbvk tzjnvp bxv htllnq fstgc zfcvnj jxjqp pbn dsmc kbtx vqrjn rqqfnlc rxrgtvs hnmjfl qrsczjv (contains eggs) +mvnqdh klx rbvdt kx qmthj hrfmdk bcvmz fhtsl zrgzf xxfgvz pmvl csfmx hkxcb rpmqq vpvj jmgt vbqbkt lxr hlmvqh zhghprj kglr dpfphd xzcdnr mszc vgp dvcfx gzgvdh ncqdr mppf nldzpc djpsmd pnglkx mrfxh lqmfgp sjgx jfqqgtl dln vhcnpg npbnj cmnb hnmjfl kfsfn vtljml qspfqb xlzqfb dcbk jngghk lh jxjqp rxr jdtzr qrftr fbcds thvm mrxg zzldmh qfvfzg dtlhh hkqp dsmc qdpbx cxzkmr tfmgl xjrpr pjqdmpm rczbvg rcvd lbfgp jmdg qszmzsh glrc qkgqv tvqbhv qrsczjv fkh rknm ckqq zntrfp cbbkfx (contains shellfish, dairy) +zqsc zmb sfk thvm lvjpp ddgdhg qrsczjv qspfqb dmxhhd zzldmh xzcdnr xjdhk dznd qfvfzg ljhn ghr zrgzf bcvmz frld pnglkx fhtsl srgnx jfqqgtl fdf vhqfz qsgb jkbqk ckqq xxfgvz pjqdmpm rpmqq jmdg fkh crnfzr mjpt cnghsg qrftr xddkbd rkzhxmh pfqxsxd mhrm gtgrcf hlmvqh fmvvb tvqbhv dgrrm xbpb qmthj gjqfj kqzcj tshn qkgqv vfkpj kmsh pgqxp ddrd glrc xgbvk hrfmdk rgdx bnzq knnmm qchnn vnmfg ncqdr qfkjsq pmtfmv xnfhq sjgx cbbkfx stcsp rbvdt mstc gzgvdh kglr dsmc rrbndl xjzc rpcdfph (contains nuts) +rbvdt jmdg zkzdrn zmb hnmjfl gmc pgqxp lqmfgp knqzf xbpb fmvvb bkd dgrrm vgjbgj dcbk ttxx dtlhh vpgvm xlnn hlmvqh jgtrnm dpfphd qrsczjv xzcdnr jngghk qmmt thvm flhfddq gzgvdh crnfzr qszmzsh xlzqfb dfrg qspfqb qmthj rpcdfph frld zqsc xjdhk dmxhhd ljhn qchnn bnzq kltcm gtgrcf mszc zhghprj rhrc csfmx mrxg klmjmz lbskg ckqq pzxj nggcjr nthhxn nldzpc rpmqq dbx mhrm zrgzf xjzc (contains dairy, wheat, eggs) +lh sfk jvvmcq szsbj fmvvb xxfgvz sjgx jnr vqrjn gmc cnghsg qsgb jmdg mppf jfqqgtl fjgxv vbqbkt zqsc xgbvk pgqxp nqfc jmgt rfh xlnn rhrc nfnzx rpcdfph qszmzsh kglr zmb xnfhq thvm tbm zzldmh rcvd pmvl kqzcj hnmjfl nggcjr qrsczjv qchnn zmcj rvchbn fdf xmjlsn mnvq mgxzl rkzhxmh bxv ngqh xlzqfb gjqfj sdccxkt clqk cmnb rbvdt jkbqk dpfphd mrfxh hlmvqh kltcm ckqq jngghk mszc (contains sesame) +zfcvnj mvnqdh gjqfj htllnq nggcjr vtljml qrftr fstgc xjrpr dvcfx klmjmz thvm qjsbk rcvd hrfmdk rczbvg mjpt ncqdr kbtx nqfc xxfgvz xlzqfb mrfxh zmb jkbqk jmgt rxrgtvs qspfqb rhrc qmthj mszc ghr fmvvb cxfzhj lqmfgp ckqq zrgzf vfkpj tzjnvp mhrm vpvj pgqxp ngqh xlnn hlmvqh xnfhq tbm zqsc jvvmcq rvchbn lxr qrsczjv vgp cmnb pjqdmpm (contains dairy) +qfvfzg ngqh rhrc nthhxn mvnqdh rcr knnmm zmcj nfnzx stcsp nzlks qdpbx kfsfn nldzpc mrfxh cxzkmr fkh vpvj llgsg pgb cmnb ncqdr qchnn zrgzf rknm xjzc zntrfp mstc clqk gsgmdn jnr ljhn mppf hkqp jmdg xlnn xgbvk csfmx rpmmv fmvvb mjpt thvm zlgztsbd dtlhh dln bnzq klmjmz tfmgl vgp qmmt kglr dbx gzgvdh rcvd kmsh rgdx kqzcj ttxx tzjnvp qmthj hlmvqh zfsks qrsczjv lh vhcnpg pgqxp zmb zhghprj vht rxr vbqbkt pcf gtgrcf zzldmh dvcfx (contains wheat) +vfkpj kbtx qkgqv bkd srgnx rcr zdntns tjsdp kfsfn rhrc mstc vtljml zlgztsbd rbvdt zrgzf glrc qfvfzg rkzhxmh ddbmq pbn flhfddq dfrg kglr clqk rxrgtvs cxzkmr mrfxh ddgdhg cmnb hlmvqh rpmmv dln zttx pjln zmb pjqdmpm jmgt ckqq qdpbx rcvd thvm rrbndl vbqbkt xmjlsn lh xhmmt qmthj nzlks pgb xzcdnr mrxg xgbvk fkh vgp rqqfnlc gjqfj gsgmdn tbm szsbj bxv lxr cnghsg jfqqgtl dbx pmtfmv lvjpp xjzc xlnn dtlhh dsmc vnfmc qrsczjv zkzdrn ghr fhtsl (contains dairy, wheat, peanuts) +nldzpc pbn rxr vgp zmb pgqxp zfsks vfkpj tvqbhv qmmt pjln jmdg qfkjsq hnmjfl mrxg hlmvqh dln nqfc lbfgp rcr kfsfn vtljml rxrgtvs tbm dsmc hkqp lh jngghk vbqbkt thvm fbcds clqk pjqdmpm ckqq mppf tzjnvp xhmmt csfmx rpcdfph sdccxkt kbtx knqzf rkzhxmh qrsczjv mszc ttxx klx mrfxh mnvq (contains dairy, sesame) +rgdx tfmgl gmc fstgc ltvr ckqq pnglkx kglr hkqp ddgdhg qfkjsq xzcdnr jnr xxfgvz hlmvqh zhghprj ghr pfqxsxd ljmvpp zmb cmnb nldzpc dznd xlnn zrgzf lh zfcvnj dcbk kmsh xjrpr qjsbk nzlks gtgrcf kfsfn dpfphd rqqfnlc mppf zzldmh thcs cbbkfx jmgt rcr pjln mrfxh jxjqp fmvvb pmvl mgxzl knqzf rbvdt gzgvdh jmdg qrsczjv nqfc vnmfg qszmzsh tjsdp ljhn qrftr ddbmq bkd fbcds (contains wheat, peanuts) +clqk rpmmv rkzhxmh pbn mrfxh pmvl hkxcb mvnqdh kbtx tzjnvp ncqdr kmsh dcbk zrgzf qchnn bkd kqzcj hlmvqh thvm cmnb mjpt knnmm pzxj frld gsgmdn pfqxsxd ltvr lqmfgp fkh rbvdt vgjbgj nldzpc jgtrnm dbx qrftr zdntns lbskg rpcdfph djpsmd vbqbkt dsmc jdtzr qmthj zmb hnmjfl sfk mppf fmvvb rcr xmjlsn qrsczjv csfmx dln vqrjn xbpb stcsp fdf rxrgtvs mstc jmdg ljhn npbnj thcs ddbmq knqzf dgrrm rqqfnlc mszc jnr lbfgp qsgb dtlhh pgb bcvmz qszmzsh rfh gjqfj xlzqfb rxr (contains peanuts) +clqk csfmx lvjpp kqzcj thvm zntrfp dcbk ghr vtljml pfqxsxd pjqdmpm jgtrnm flhfddq zzldmh llgsg nthhxn mjpt zrgzf pjln dznd mnvq bjvcg nfnzx tzjnvp vgp dtlhh qmmt rpmmv jmdg zfcvnj xzcdnr zmb tbm dbx bxv cxzkmr tfmgl mszc ttxx qkgqv qjsbk ckqq pgqxp zfml mhrm vpvj jdtzr mgxzl tvqbhv qfvfzg vhcnpg lbskg lqmfgp cnghsg rcvd hnmjfl zhghprj hlmvqh xjrpr xxfgvz dln gtgrcf sdccxkt kx qspfqb jfqqgtl pptgt dmxhhd rpcdfph fstgc rcr fmvvb ljmvpp mrxg gmc pgb mrfxh kmsh cmnb (contains soy, wheat, eggs) +klx nggcjr xjrpr zdntns kltcm vhcnpg xlnn kqzcj hlmvqh dnpgcd vht rpmmv bnzq hnmjfl lbskg fdf bkd dgrrm rvchbn mgxzl pgb jdtzr dcbk qszmzsh rpmqq hrfmdk qrftr dpfphd lxr ngqh xddkbd qrsczjv tbm vqrjn qchnn vpvj mstc ckqq pbn zrgzf jxjqp jgtrnm tfmgl zmb rqqfnlc xmjlsn rxr pmtfmv zmcj zfsks zqsc crnfzr jmdg fbcds mrfxh xgbvk hkxcb gmc nldzpc nfnzx xnfhq (contains peanuts, eggs, nuts) +csfmx zzldmh dcbk fdf rhrc fjgxv qchnn cxzkmr qmthj crnfzr nqfc zmcj mhrm ltvr sdccxkt flhfddq cbbkfx cmnb qdpbx thvm xmjlsn fhtsl knqzf bxv nggcjr vnmfg zmb cxfzhj jdtzr pnglkx jmdg lxr kmsh vgjbgj mrfxh dln mppf gzgvdh rpmmv zntrfp zrgzf pgqxp ckqq zfml vnfmc vht pmvl xlzqfb rxrgtvs kltcm pzxj dsmc dtlhh hrfmdk qmmt dnpgcd bjvcg gsgmdn cnghsg xhmmt gmc ttxx qjsbk hlmvqh fkh vhqfz xxfgvz (contains dairy, sesame, eggs) +jmgt mppf ttxx dsmc xnfhq bxv kglr bcvmz ckqq jmdg dfrg jnr mnvq ngqh sfk fdf xhmmt fjgxv zfcvnj rczbvg cmnb xjrpr szsbj dvcfx gtgrcf knqzf pjln mrfxh lbfgp vnmfg jdtzr mhrm fstgc tbm djpsmd pnglkx qkgqv zmb vfkpj hkxcb qfkjsq pgqxp xzcdnr nfnzx npbnj rbvdt jfqqgtl hlmvqh qfvfzg jvvmcq hnmjfl thvm rgdx gjqfj zhghprj kqzcj rcr zrgzf tvqbhv tshn (contains peanuts) +rknm lvjpp cnghsg qrsczjv sdccxkt zrgzf rcvd rxrgtvs stcsp thvm fstgc ttxx pmvl rpcdfph dznd ckqq pptgt mstc rpmmv fdf knnmm jnr bjvcg mnvq qdpbx zfml rqqfnlc zqsc zhghprj mgxzl qmmt fkh rxr dsmc lbskg sfk xhmmt kqzcj vfkpj mhrm hlmvqh mrfxh pcf zmb jmgt ljmvpp jfqqgtl szsbj xjrpr vnfmc qszmzsh dbx mszc xlnn qrftr qchnn mjpt zttx ddgdhg gmc djpsmd zfcvnj dln qkgqv rcr dnpgcd tzjnvp hkxcb zmcj lxr bcvmz fhtsl vnmfg vpgvm (contains dairy, sesame) +rgdx jmdg cmnb thvm fstgc pfqxsxd ncqdr dmxhhd glrc xjrpr rkzhxmh fhtsl mrfxh hkxcb pmtfmv zfsks knnmm pgb vnmfg thcs dfrg ddbmq clqk zntrfp nthhxn xjzc dgrrm lvjpp rpmmv vht lh jfqqgtl vgp mszc rczbvg jnr jngghk xhmmt vhqfz bcvmz zmb ckqq tjsdp bkd xlzqfb xddkbd pmvl qrsczjv ddgdhg djpsmd ttxx zfcvnj mjpt nldzpc qrftr kx xnfhq fjgxv jmgt ljhn mrxg pbn sdccxkt rxrgtvs dln dpfphd zrgzf tbm rfh tvqbhv (contains sesame, dairy, shellfish) +rczbvg cxfzhj lxr mgxzl hkxcb kbtx zmb jvvmcq pmtfmv jfqqgtl jxjqp mszc thvm rknm jmdg vfkpj qmmt hlmvqh ltvr cnghsg pjln mrfxh gzgvdh szsbj pgb dcbk lvjpp qchnn bcvmz sdccxkt llgsg xgbvk mrxg ghr zhghprj hkqp thcs zrgzf zzldmh ckqq frld gtgrcf pnglkx clqk kglr xhmmt hnmjfl qjsbk qfvfzg dnpgcd dbx djpsmd qrftr rgdx tvqbhv ncqdr (contains eggs) +pmvl zmb zrgzf rxrgtvs mvnqdh dznd srgnx qmmt pgb jmdg hlmvqh dgrrm xjdhk klx rcvd qrsczjv cnghsg ttxx hrfmdk qspfqb pfqxsxd fmvvb pzxj sfk rbvdt nggcjr zqsc npbnj kglr xddkbd lbskg lqmfgp mrxg mrfxh zfml rkzhxmh jfqqgtl vgjbgj rpmmv tphtz mszc dln zfcvnj vpgvm tzjnvp rhrc nldzpc rknm tshn jgtrnm mppf fjgxv ckqq ddgdhg vpvj fbcds (contains shellfish) +xlzqfb nthhxn dln rczbvg jmdg vgp cbbkfx gsgmdn jvvmcq glrc klmjmz stcsp bcvmz dbx vpvj cmnb sjgx rfh rrbndl mgxzl jnr rhrc thvm xlnn mhrm mrfxh bxv qrftr lvjpp fjgxv kglr cxfzhj zmb pptgt ghr kbtx pnglkx qjsbk ckqq jfqqgtl fstgc dznd qszmzsh jgtrnm zrgzf tjsdp klx pjln vgjbgj vbqbkt zkzdrn sfk qrsczjv vhqfz hrfmdk kltcm vnfmc zqsc xhmmt knnmm qfvfzg xjrpr nqfc jkbqk (contains nuts, sesame) +jgtrnm bxv fbcds dznd bkd ttxx rpmqq ckqq pmvl dtlhh xjdhk zdntns knnmm vqrjn dsmc lqmfgp ltvr jfqqgtl mszc xhmmt szsbj crnfzr fkh rbvdt pjqdmpm nggcjr qrftr bcvmz qmmt srgnx xddkbd rvchbn zmb cmnb pptgt xjzc llgsg rxr bnzq gsgmdn thvm zzldmh rcvd mrfxh dgrrm zfsks qsgb tvqbhv zkzdrn nzlks lh klmjmz rxrgtvs kqzcj mnvq ngqh rczbvg tshn tjsdp hlmvqh pcf fdf rfh pnglkx hkqp zrgzf jkbqk sdccxkt fstgc vpvj ddbmq zttx xlzqfb qfvfzg frld qrsczjv zlgztsbd xnfhq pfqxsxd cxfzhj cxzkmr tphtz clqk (contains shellfish, peanuts) +hrfmdk nthhxn lh zrgzf thvm rbvdt qdpbx mhrm vhqfz lqmfgp qjsbk vgp qfvfzg szsbj nldzpc vpgvm sdccxkt dgrrm tfmgl zdntns ddgdhg zfsks hlmvqh zmcj pnglkx ncqdr qrsczjv sfk mrfxh rqqfnlc vht mstc pmvl cmnb gmc ckqq jmdg thcs bjvcg nzlks klx jfqqgtl fkh ghr ddbmq htllnq xlnn kglr (contains nuts) +fkh knqzf tvqbhv mrfxh hkqp nqfc mvnqdh xxfgvz gzgvdh vnfmc qrftr qrsczjv ngqh cxzkmr mjpt dvcfx zmcj xddkbd clqk rvchbn dsmc xjzc pfqxsxd dfrg qmmt mhrm flhfddq rrbndl xnfhq hlmvqh jmdg dznd frld jnr djpsmd thvm qjsbk ddbmq qchnn pnglkx dtlhh zhghprj fhtsl vtljml nzlks qszmzsh lqmfgp pbn cmnb rpcdfph kx qkgqv zrgzf tshn zmb zlgztsbd xlnn (contains eggs, nuts, dairy) +gsgmdn zqsc cxzkmr xlnn htllnq vbqbkt pgb pnglkx tphtz jmgt mrfxh qkgqv pjqdmpm glrc sdccxkt rbvdt vht pzxj fstgc bcvmz mjpt dvcfx vpvj ljmvpp pfqxsxd tshn zmcj zrgzf qmmt pcf dpfphd xxfgvz jxjqp rczbvg mgxzl thvm fjgxv hnmjfl rkzhxmh qrsczjv jmdg cnghsg zfml gjqfj tbm lh mppf dcbk zntrfp dbx jvvmcq szsbj pjln xhmmt rcr nthhxn kx fmvvb xzcdnr klx rpcdfph zmb djpsmd jdtzr mnvq hlmvqh bjvcg mrxg (contains eggs) +vqrjn rhrc pzxj pjqdmpm tshn pjln nggcjr ljhn fkh qchnn kfsfn vgjbgj jmgt qkgqv stcsp knnmm dznd pgb csfmx fmvvb ltvr rknm rpcdfph thvm mrfxh qfvfzg zfcvnj zmb clqk kx ghr rpmmv vbqbkt tfmgl dfrg lxr hrfmdk vpgvm zlgztsbd rczbvg tvqbhv jnr qjsbk qfkjsq xxfgvz hlmvqh klx dnpgcd kbtx flhfddq jfqqgtl jmdg ddrd xgbvk rqqfnlc ckqq bnzq mnvq ncqdr dln qdpbx kltcm mppf zttx dbx pmtfmv klmjmz vnmfg pgqxp nthhxn crnfzr dmxhhd xhmmt rgdx mvnqdh gsgmdn nzlks xzcdnr fbcds djpsmd zfsks dpfphd lh ddbmq vfkpj vgp qrsczjv (contains peanuts, eggs, soy) +dsmc hlmvqh rqqfnlc dgrrm lbskg xxfgvz klmjmz jmgt jnr dznd npbnj rrbndl fkh vfkpj dvcfx hnmjfl qrftr pmtfmv kltcm xzcdnr gtgrcf lbfgp bcvmz xddkbd vgjbgj gjqfj kglr qchnn zlgztsbd rcvd xmjlsn bnzq kbtx vnfmc zmb srgnx pptgt llgsg thvm ckqq qrsczjv cbbkfx cnghsg xjzc rbvdt mnvq mrfxh mppf rknm jmdg tzjnvp rfh vgp vpvj nfnzx hkxcb zqsc lqmfgp kmsh dnpgcd sjgx sfk gmc jfqqgtl ltvr vpgvm pmvl qmthj klx tbm rvchbn pfqxsxd xjdhk glrc rczbvg knqzf (contains shellfish, dairy, nuts) +ngqh lxr qrftr nldzpc cbbkfx zdntns xxfgvz srgnx qspfqb zfsks tzjnvp tphtz qrsczjv lbfgp gjqfj xjrpr qfkjsq rfh xgbvk dtlhh mrfxh xjdhk qkgqv hkqp dsmc rczbvg klmjmz ckqq xlzqfb ddgdhg kltcm vhqfz kglr jxjqp xddkbd htllnq gtgrcf zrgzf lbskg gmc szsbj thvm zmb zfcvnj hlmvqh pjqdmpm (contains peanuts, shellfish) +xlzqfb vpgvm flhfddq kbtx zmcj jmdg vhqfz tphtz vqrjn stcsp ckqq rgdx nfnzx nggcjr qrsczjv xmjlsn pgb ngqh pjqdmpm qsgb nldzpc hkxcb klmjmz rpmmv xjrpr zlgztsbd ncqdr zmb rpcdfph qjsbk gzgvdh xnfhq hlmvqh cbbkfx knnmm qfkjsq xddkbd vgp pmtfmv qdpbx cnghsg hrfmdk fjgxv xlnn xjzc mszc ljmvpp zntrfp fdf pcf mnvq thvm bkd fbcds dbx fstgc dln pfqxsxd zrgzf mhrm pbn zttx zhghprj (contains peanuts, eggs, dairy) +nldzpc gmc mjpt knqzf rbvdt zntrfp nthhxn jmdg rxr xzcdnr kx ljmvpp kltcm jmgt gjqfj pgqxp xjrpr zmb qrsczjv hlmvqh dbx dmxhhd pnglkx gsgmdn vhcnpg zrgzf xjzc pjqdmpm rpcdfph lbfgp xgbvk jvvmcq qdpbx nqfc dvcfx thvm rknm kbtx npbnj mrxg klmjmz rrbndl xbpb ncqdr fdf vpvj kglr pptgt mrfxh (contains sesame) +tshn dmxhhd qmthj kqzcj rqqfnlc pcf dgrrm hkqp ckqq flhfddq qmmt thcs vqrjn vht tbm lqmfgp bcvmz fbcds jmdg rbvdt xzcdnr xlzqfb vfkpj mrfxh sdccxkt fstgc fhtsl qfvfzg kmsh dznd zrgzf bxv glrc thvm pmtfmv rkzhxmh zqsc xjzc fmvvb ddbmq qspfqb tjsdp rcvd xgbvk gzgvdh cmnb pptgt ngqh xlnn sjgx mrxg qdpbx rknm hnmjfl szsbj zntrfp gtgrcf fdf kltcm vhcnpg zmb pjln mppf dnpgcd ttxx qrsczjv srgnx qszmzsh (contains shellfish, nuts) + diff --git a/d21/main.py b/d21/main.py new file mode 100755 index 0000000..051526b --- /dev/null +++ b/d21/main.py @@ -0,0 +1,105 @@ +#! /usr/bin/env python3 +import re +from functools import reduce +from dataclasses import dataclass +from typing import Any +from typing import Dict +from typing import Iterable +from typing import Set + + +food_parser = re.compile(r"([a-z ]+) \(contains ([a-z, ]+)\)") + + +@dataclass +class Food: + items: Set[str] + alergens: Set[str] + + +def read_input(filename: str) -> Iterable[Food]: + with open(filename) as f: + for line in f: + line = line.strip() + if line == "": + continue + match = food_parser.match(line) + if not match: + raise ValueError(f"cannot parse line {line}") + items = match.group(1).split(" ") + alergens = match.group(2).split(", ") + yield Food(set(items), set(alergens)) + + +def extract_alergen_info(foods: Iterable[Food]) -> Dict[str, Set[str]]: + alergen_defs: Dict[str, Set[str]] = {} + + for food in foods: + for alergen in food.alergens: + if alergen not in alergen_defs: + alergen_defs[alergen] = food.items.copy() + else: + alergen_defs[alergen] &= food.items + + return alergen_defs + + +def reduce_union(items: Iterable[Set[Any]]) -> Set[Any]: + return reduce(lambda x, y: x | y, items) + + +def reduce_intersecion(items: Iterable[Set[Any]]) -> Set[Any]: + return reduce(lambda x, y: x & y, items) + + +def narrow_results(alergen_defs: Dict[str, Set[str]]): + sorted_alergens = sorted(alergen_defs.items(), key=lambda x: len(x[1])) + for i, alergen_info in enumerate(sorted_alergens): + if len(alergen_info[1]) == 1: + # Remove from others + if i+1 < len(sorted_alergens): + for other_info in sorted_alergens[i+1:]: + other_info[1].difference_update(alergen_info[1]) + + +def part1(): + all_foods = list(read_input("input.txt")) + alergen_defs = extract_alergen_info(all_foods) + + print("Alergen defs", alergen_defs) + + safe_items = reduce_union((food.items for food in all_foods)) + all_possible_alergens = reduce_union(alergen_defs.values()) + + print("All possible alergens", all_possible_alergens) + + safe_items -= all_possible_alergens + + print("All safe items", safe_items) + + count_safe = sum( + map( + lambda food: len(food.items & safe_items), + (food for food in all_foods), + ), + ) + + print("Count of safe items appeared is", count_safe) + + print("Part 2") + + narrow_results(alergen_defs) + narrow_results(alergen_defs) + narrow_results(alergen_defs) + + print("Narrowed alergen list", alergen_defs) + + canon_list = ",".join(( + a[1].pop() for a in sorted(alergen_defs.items(), key=lambda x: x[0]) + )) + + print("Canon list of ingredients", canon_list) + + +if __name__ == "__main__": + part1() diff --git a/d21/sample-input.txt b/d21/sample-input.txt new file mode 100644 index 0000000..1c0ea2f --- /dev/null +++ b/d21/sample-input.txt @@ -0,0 +1,4 @@ +mxmxvkd kfcds sqjhc nhms (contains dairy, fish) +trh fvjkl sbzzf mxmxvkd (contains dairy) +sqjhc fvjkl (contains soy) +sqjhc mxmxvkd sbzzf (contains fish) diff --git a/d22/input.txt b/d22/input.txt new file mode 100644 index 0000000..27623b0 --- /dev/null +++ b/d22/input.txt @@ -0,0 +1,54 @@ +Player 1: +14 +6 +21 +10 +1 +33 +7 +13 +25 +8 +17 +11 +28 +27 +50 +2 +35 +49 +19 +46 +3 +38 +23 +5 +43 + +Player 2: +18 +9 +12 +39 +48 +24 +32 +45 +47 +41 +40 +15 +22 +36 +30 +26 +42 +34 +20 +16 +4 +31 +37 +44 +29 + diff --git a/d22/loop-input.txt b/d22/loop-input.txt new file mode 100644 index 0000000..a29e13a --- /dev/null +++ b/d22/loop-input.txt @@ -0,0 +1,8 @@ +Player 1: +43 +19 + +Player 2: +2 +29 +14 diff --git a/d22/main.py b/d22/main.py new file mode 100755 index 0000000..1b874f2 --- /dev/null +++ b/d22/main.py @@ -0,0 +1,174 @@ +#! /usr/bin/env python3 +from copy import copy +from enum import Enum +from typing import Set, Tuple, List, Optional + + +class Player(Enum): + UNKNOWN = 0 + ONE = 1 + TWO = 2 + + +def read_decks(filename: str): + deck1, deck2 = None, None + cur_deck: List[int] = [] + with open(filename) as f: + for line in f: + line = line.strip() + if line.startswith("Player 1"): + continue + if line == "": + continue + if line.startswith("Player 2"): + deck1 = cur_deck + cur_deck = [] + continue + cur_deck.append(int(line)) + + deck2 = cur_deck + + return deck1, deck2 + + +def play_round(deck1, deck2): + c1 = deck1.pop(0) + c2 = deck2.pop(0) + + print(f"{c1} vs {c2} ", end="", flush=True) + + if c1 > c2: + print("Player 1 wins!") + deck1 += [c1, c2] + elif c2 > c1: + print("Player 2 wins!") + deck2 += [c2, c1] + else: + print("Nobody wins?") + # raise ValueError("Nobody wins") + + +RoundHistory = Set[Tuple[Tuple[int, ...], Tuple[int, ...]]] + + +def recursive_combat( + deck1: List[int], + deck2: List[int], + game: int = 1, + past_games: Optional[RoundHistory] = None +) -> Player: + if past_games is None: + past_games = set() + + print(f"{game}: Starting p2 {deck1} p2 {deck2}") + + # Play until there is an empty deck + game_round = 0 + winner = Player.UNKNOWN + while deck1 and deck2: + game_round += 1 + + # Check for looping... + this_round = (tuple(deck1), tuple(deck2)) + if this_round in past_games: + print( + f"{game}:{game_round} Loop detected. Player 1 wins the game!", + ) + return Player.ONE + + past_games.add(this_round) + + print(f"{game}:{game_round} p1 {deck1} p2 {deck2} ") + + # Draw + c1 = deck1.pop(0) + c2 = deck2.pop(0) + + print(f"{game}:{game_round} {c1} vs {c2} ", end="", flush=True) + + winner = Player.UNKNOWN + if c1 <= len(deck1) and c2 <= len(deck2): + print("RECURSIVE COMBAT!!!!") + winner = recursive_combat( + copy(deck1[:c1]), + copy(deck2[:c2]), + game=game+1, + past_games=past_games.copy(), + ) + else: + if c1 > c2: + winner = Player.ONE + elif c2 > c1: + winner = Player.TWO + else: + raise ValueError("cards are equal? No way!") + + if winner == Player.ONE: + print("Player 1 wins!") + deck1 += [c1, c2] + elif winner == Player.TWO: + print("Player 2 wins!") + deck2 += [c2, c1] + else: + print("Nobody wins?") + raise ValueError("Nobody wins") + + print(f"{game}: Game finished p1 {deck1} p2 {deck2}") + + # Deck is empty! + if deck1: + winner = Player.ONE + elif deck2: + winner = Player.TWO + else: + raise ValueError("unknown winner") + + return winner + + +def part1(): + deck1, deck2 = read_decks("input.txt") + + print("Initial decks") + print("Player 1", deck1) + print("Player 2", deck2) + + while deck1 and deck2: + play_round(deck1, deck2) + + winning_deck: List[int] = None + if deck1: + winning_deck = deck1 + print("Winner! Player 1!") + elif deck2: + winning_deck = deck2 + print("Winner! Player 2!") + + score = sum((i*v for i, v in enumerate(reversed(winning_deck), 1))) + print("Score:", score) + + +def part2(): + deck1, deck2 = read_decks("input.txt") + + print("Initial decks") + print("Player 1", deck1) + print("Player 2", deck2) + + _ = recursive_combat(deck1, deck2) + + winning_deck: List[int] = None + if deck1: + winning_deck = deck1 + print("Winner! Player 1!") + elif deck2: + winning_deck = deck2 + print("Winner! Player 2!") + + score = sum((i*v for i, v in enumerate(reversed(winning_deck), 1))) + print("Score:", score) + + +if __name__ == "__main__": + part1() + part2() diff --git a/d22/sample-input.txt b/d22/sample-input.txt new file mode 100644 index 0000000..391cd24 --- /dev/null +++ b/d22/sample-input.txt @@ -0,0 +1,13 @@ +Player 1: +9 +2 +6 +3 +1 + +Player 2: +5 +8 +4 +7 +10 diff --git a/d23/main.py b/d23/main.py new file mode 100755 index 0000000..30ba108 --- /dev/null +++ b/d23/main.py @@ -0,0 +1,171 @@ +#! /usr/bin/env python3 +from typing import List +from typing import Tuple + + +def cups_str(cups: List[int], current: int) -> str: + return " ".join( + ("(" if c == current else "") + str(c) + (")" if c == current else "") + for c in cups + ) + + +def get_result(cups: List[int], part2: bool = False) -> str: + # Rotate 1 to the front + index_1 = cups.index(1) + + if not part2: + result = cups[index_1:] + cups[:index_1] + # Remove 1 from the front + result = result[1:] + return "".join((str(c) for c in result)) + else: + cup1 = cups[index_1+1 % len(cups)] + cup2 = cups[index_1+2 % len(cups)] + print(f"cup1: {cup1} cup2: {cup2}") + return str(cup1 * cup2) + + +def str_to_cups(opening: str, part2: bool = False) -> List[int]: + cups = [int(c) for c in opening] + + if part2: + max_cup = max(cups) + cup_limit = 1000000 + cups += [c for c in range(max_cup+1, cup_limit+1)] + + return cups + + +def play_round( + cups: List[int], + current: int, + debug: bool = True, +) -> Tuple[List[int], int]: + if debug: + print(f"cups: {cups_str(cups, current)}") + + cur_i = cups.index(current) + + # Pick up cups + picked_up: List[int] = [] + + while len(picked_up) < 3: + if cur_i+1 < len(cups): + picked_up.append(cups.pop(cur_i+1)) + else: + picked_up.append(cups.pop(0)) + cur_i -= 1 + + if debug: + print(f"pick up: {', '.join((str(c) for c in picked_up))}") + + # Find destination + dest = 0 + max_cup = 0 + for c in cups: + if c < current and c > dest: + dest = c + if dest == current-1: + break + if c > max_cup: + max_cup = c + + if dest <= 0: + dest = max_cup + + dest_i = cups.index(dest) + # Other guy + # dest = max((c for c in cups if c < current), default=max(cups)) + # dest_i = cups.index(dest) + # My attempt 1 + # dest = current - 1 + # dest_i = None + # while dest_i is None: + # if dest <= 0: + # # Wrap around to the highest value instead + # dest = max(cups) + # try: + # dest_i = cups.index(dest) + # except ValueError: + # # Try the next cup down + # dest -= 1 + + if debug: + print(f"destination: {dest}") + + # Add cups back + # cups[dest_i+1:dest_i+1] = picked_up + if dest_i+1 >= len(cups): + cups += picked_up + else: + for cup in reversed(picked_up): + cups.insert(dest_i+1, cup) + + # If inserted before the current, move that index up + if dest_i < cur_i: + cur_i += 3 + + # Get the new current to the right of old + cur_i += 1 + cur_i = cur_i % len(cups) + current = cups[cur_i] + + return cups, current + + +def play_game(cups: List[int], rounds: int, debug: bool = True) -> List[int]: + current = cups[0] + if debug: + print(f"game: {cups_str(cups, current)} {rounds} rounds") + + ten_percent = int(rounds / 10) + + for move in range(rounds): + if move % ten_percent == 0: + print(f"{move/ten_percent*10}%") + if debug: + print(f"-- move {move+1} --") + cups, current = play_round(cups, current, debug=debug) + if debug: + print("") + + if debug: + print("-- final --") + print(f"cups: {cups_str(cups, current)}") + + print(f"result {get_result(cups)}") + + return cups + + +def sample(): + # cups = str_to_cups("389125467") + # cups = play_game(cups, 10, debug=False) + # print(f"result {get_result(cups)}") + # + cups = str_to_cups("389125467") + cups = play_game(cups, 100, debug=False) + print(f"result {get_result(cups)}") + + # cups = str_to_cups("389125467", part2=True) + # cups = play_game(cups, 10000000, debug=False) + # print(f"result {get_result(cups, part2=True)}") + + +def part1(): + cups = str_to_cups("853192647") + cups = play_game(cups, 100, debug=False) + print(f"result {get_result(cups)}") + + +def part2(): + cups = str_to_cups("853192647", part2=True) + cups = play_game(cups, 10000000, debug=False) + print(f"result {get_result(cups, part2=True)}") + + +if __name__ == "__main__": + # sample() + # part1() + part2() diff --git a/d23/main2.py b/d23/main2.py new file mode 100755 index 0000000..00be31c --- /dev/null +++ b/d23/main2.py @@ -0,0 +1,157 @@ +#! /usr/bin/env python3 +from typing import List +from typing import Iterable +from typing import Dict +from typing import Tuple + + +def listify(cups: Dict[int, int]) -> Iterable[int]: + yield 1 + next_cup = cups[1] + while next_cup != 1: + yield next_cup + next_cup = cups[next_cup] + + +def cups_str(cups: Dict[int, int], current: int) -> str: + return " ".join( + ("(" if c == current else "") + str(c) + (")" if c == current else "") + for c in listify(cups) + ) + + +def get_result(cups: Dict[int, int]) -> str: + # Rotate 1 to the front + cup1 = cups[1] + cup2 = cups[cup1] + print(f"cup1: {cup1} cup2: {cup2}") + return str(cup1 * cup2) + + +def str_to_cups(opening: str, max_cups: int = 0) -> Dict[int, int]: + cups_list = [int(c) for c in opening] + max_cup = max(cups_list) + + if max_cups: + cup_limit = max_cups + cups_list += [c for c in range(max_cup+1, cup_limit+1)] + + cups = dict(zip(cups_list, cups_list[1:]+cups_list[0:1])) + + return cups + + +def play_round( + cups: Dict[int, int], + current: int, + max_cup: int, + debug: bool = False, +) -> Tuple[Dict[int, int], int]: + if debug: + print(f"cups: {cups_str(cups, current)}") + + # Pick up cups + first_cup = cups[current] + second_cup = cups[first_cup] + third_cup = cups[second_cup] + following_cup = cups[third_cup] + + # Seal + cups[current] = following_cup + + if debug: + print(f"pick up: {first_cup}, {second_cup}, {third_cup}") + + # Find destination + dest = current - 1 + if dest < 1: + dest = max_cup + + while dest in (first_cup, second_cup, third_cup): + dest -= 1 + if dest < 1: + dest = max_cup + + if debug: + print(f"destination: {dest}") + + # Add cups back + following_cup = cups[dest] + cups[dest] = first_cup + cups[third_cup] = following_cup + + # Get the new current to the right of old + current = cups[current] + + return cups, current + + +def play_game( + cups: Dict[int, int], + start: int, + max_cup: int, + rounds: int, + debug: bool = False, +) -> Dict[int, int]: + current = start + if debug: + print(f"game: {cups_str(cups, current)} {rounds} rounds") + + ten_percent = int(rounds / 10) + + for move in range(rounds): + if move % ten_percent == 0: + print(f"{move/ten_percent*10}%") + if debug: + print(f"-- move {move+1} --") + cups, current = play_round(cups, current, max_cup, debug) + if debug: + print("") + + if debug: + print("-- final --") + print(f"cups: {cups_str(cups, current)}") + + # print(f"result {get_result(cups)}") + + return cups + + +def sample(): + # cups = str_to_cups("389125467") + # cups = play_game(cups, 10, debug=False) + # print(f"result {get_result(cups)}") + + # cups = str_to_cups("389125467") + # start = 3 + # max_cups = 9 + # cups = play_game(cups, start, max_cups, 100, debug=True) + # print(f"result {get_result(cups)}") + + start = 3 + rounds = 10000000 + max_cups = 1000000 + cups = str_to_cups("389125467", max_cups=max_cups) + cups = play_game(cups, start, max_cups, rounds, debug=False) + print(f"result {get_result(cups)}") + + +def part1(): + cups = str_to_cups("853192647") + cups = play_game(cups, 100, debug=False) + print(f"result {get_result(cups)}") + + +def part2(): + start = 8 + rounds = 10000000 + max_cups = 1000000 + cups = str_to_cups("853192647", max_cups=max_cups) + cups = play_game(cups, start, max_cups, rounds, debug=False) + print(f"result {get_result(cups)}") + + +if __name__ == "__main__": + # sample() + # part1() + part2() diff --git a/d24/__init__.py b/d24/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/d24/expanding.py b/d24/expanding.py new file mode 100644 index 0000000..dee2e4b --- /dev/null +++ b/d24/expanding.py @@ -0,0 +1,662 @@ +#! /usr/bin/env python3 +from collections import namedtuple +from itertools import product +from typing import Any +from typing import Callable +from typing import Iterable +from typing import List +from typing import Optional +from typing import Tuple +from typing import Set + + +Point = namedtuple("Point", "x y z w", defaults=(0, 0)) + + +def add_points(p1, p2) -> Point: + return Point( + p1.x + p2.x, + p1.y + p2.y, + p1.z + p2.z, + p1.w + p2.w, + ) + + +class GridItem(object): + + def __init__(self, loc: Point, world: "World"): + self._loc = loc + self._world = world + + self._ticked = False + + def _tock(): + # print("Default tock") + pass + + self.tock = _tock + + def neighbors(self, expand=False) -> Iterable["GridItem"]: + seen_points: Set[Point] = set() + for diff in product((0, 1, -1), repeat=4): + # from pdb import set_trace; set_trace() + neighbor_point = add_points( + self._loc, + Point( + diff[0], + diff[1], + diff[2], + diff[3], + ), + ) + if self._loc == neighbor_point: + # skip self + continue + + if neighbor_point in seen_points: + # skip points we've already visited + # print("Already seen, skipping") + continue + + seen_points.add(neighbor_point) + + # print(f"Getting point {neighbor_point}") + neighbor = self._world.get_point(neighbor_point, expand=expand) + if neighbor is not None: + # print("FOUND!") + yield neighbor + + def tick(self): + active_neighbors = 0 + for neighbor in self.neighbors(): + # print(f"Neighbor is active: {neighbor.active}") + if neighbor.active: + # print(f"Neighbor is active {neighbor}") + active_neighbors += 1 + + if self.active and active_neighbors not in (2, 3): + # print("Should go inactive") + def _tock(): + # print("go inactive") + self.active = False + + self.tock = _tock + elif not self.active and active_neighbors == 3: + # print("Should go active") + def _tock(): + # print("go active") + self.active = True + + self.tock = _tock + + else: + # print("Should do nothing") + def _tock(): + # print("Empty tock") + pass + + self.tock = _tock + + def __repr__(self) -> str: + return f"({self._loc.x}, {self._loc.y}, {self._loc.z})" + + def to_str(self) -> str: + raise NotImplementedError() + + +class AutoExpanding(object): + _l: List[Any] + _zero: int + _item_factory: Callable[[int], Any] + + def __init__(self): + self._l = [self._item_factory(0)] + self._zero = 0 + + def get(self, i, expand=True): + if not expand: + if self._zero+i < 0: + raise IndexError(f"index {i} is out of bounds") + return self._l[self._zero+i] + + if self._zero is None: + self._l = [self._item_factory(0)] + self._zero = 0 + + if i > 0 and i >= len(self._l) - self._zero - 1: + # print(f"resize pos to {i} with {self._l} zero={self._zero}") + self._l = self._l + [ + self._item_factory(j) + for j in range(len(self._l)-self._zero, i+1) + ] + # print(f"> done {self._l} zero={self._zero}") + elif i < 0 and abs(i) > self._zero: + # print(f"resize neg to {i} with {self._l} zero={self._zero}") + self._l = [ + self._item_factory(j) + for j in range(i, -1 * self._zero) + ] + self._l + self._zero = abs(i) + # print(f"> done {self._l} zero={self._zero}") + + # print(f"Now getting item at index {i} from {self._l}") + return self._l[self._zero+i] + + def __getitem__(self, i): + if isinstance(i, slice): + return [ + self[j] + for j in range( + i.start if i.start is not None else self.min_index(), + (i.stop if i.stop is not None else self.max_index()) + 1, + i.step or 1, + ) + ] + + return self.get(i, expand=False) + + def __setitem__(self, i, value): + self.get(i, expand=True) + self._l[self._zero+i] = value + + def __len__(self) -> int: + return len(self._l) + + def __iter__(self): + return iter(self._l) + + def min_index(self) -> int: + return -1 * self._zero + + def max_index(self) -> int: + return len(self._l) - self._zero - 1 + + def get_bounds(self) -> Tuple[int, int]: + return self.min_index(), self.max_index() + + def resize(self, min_index: int, max_index: int): + if min_index < self.min_index(): + self.get(min_index, expand=True) + else: + if min_index > 0: + raise IndexError("Cannot resize to exclude zero") + self._l = self[min_index:] + self._zero = abs(min_index) + + if max_index > self.max_index(): + self.get(max_index, expand=True) + else: + if max_index < 0: + raise IndexError("Cannot resize to exclude zero") + self._l = self[:max_index] + + def __repr__(self) -> str: + return f"" + + +class World(AutoExpanding): + + def iter_items(self) -> Iterable[GridItem]: + raise NotImplementedError() + + def tick(self): + for c in self.iter_items(): + c.tick() + + def tock(self): + for c in self.iter_items(): + c.tock() + + def get_point(self, p: Point, expand=True) -> Optional[GridItem]: + raise NotImplementedError() + + def trim(self): + raise NotImplementedError() + + def get_all_bounds(self) -> Tuple[Point, Point]: + raise NotImplementedError() + + def true_up(self): + raise NotImplementedError() + + def expand_all(self, i: int): + raise NotImplementedError() + + +class GridRow(AutoExpanding): + def __init__(self, y: int, z: int, world: World, w: Optional[int] = 0): + self._y = y + self._z = z + self._w = w + self._world = world + super().__init__() + + def _item_factory(self, x: int) -> GridItem: + return GridItem(Point(x, self._y, self._z, self._w), self._world) + + def __repr__(self) -> str: + return "[" + " ".join((str(c) for c in self._l)) + "]" + + def to_str(self) -> str: + return "".join((c.to_str() for c in self._l)) + + +class GridSlice(AutoExpanding): + def __init__(self, z: int, world: World, w: Optional[int] = 0): + self._z = z + self._w = w + self._world = world + super().__init__() + + def _item_factory(self, y: int) -> GridRow: + return GridRow(y, self._z, self._world, w=self._w) + + def __repr__(self) -> str: + return f"z={self._z}\n" + "\n".join(( + str(r) for r in self._l + )) + + def to_str(self) -> str: + return f"z={self._z}\n" + "\n".join([r.to_str() for r in self._l]) + + +class Grid(World): + def __init__(self, world: Optional[World] = None, w: Optional[int] = 0): + if world is not None: + self._world = world + else: + self._world = self + + self._w = w + + super().__init__() + + def _item_factory(self, z: int) -> GridSlice: + return GridSlice(z, self._world, w=self._w) + + def __repr__(self) -> str: + return "\n\n".join(( + str(s) for s in self._l + )) + + def to_str(self) -> str: + return "\n\n".join(( + s.to_str() for s in self._l + )) + + def iter_cubes(self) -> Iterable[GridItem]: + for s in self: + for r in s: + for c in r: + yield c + + def get_point(self, p: Point, expand=True) -> Optional[GridItem]: + try: + # print(f"expand world z to {p.z}") + c = self.get( + p.z, + expand=expand, + ).get( + p.y, + expand=expand, + ).get( + p.x, + expand=expand, + ) + # from pdb import set_trace; set_trace() + return c + except IndexError: + return None + + def trim(self): + for s in self: + for r in s: + first, last = None, None + min_index, max_index = r.get_bounds() + for i in range(min_index, max_index+1): + if r[i].active: + if first is None: + first = i + last = i + if first is None or first > 0: + first = 0 + if last is None or last < 0: + last = 0 + r.resize(first, last) + + first, last = None, None + min_index, max_index = s.get_bounds() + for i in range(min_index, max_index+1): + if len(s[i]) > 1 or (len(s[i]) == 1 and s[i][0].active): + if first is None: + first = i + last = i + if first is None or first > 0: + first = 0 + if last is None or last < 0: + last = 0 + s.resize(first, last) + + def get_all_bounds(self) -> Tuple[Point, Point]: + min_z, max_z = self.get_bounds() + min_y, max_y = 0, 0 + min_x, max_x = 0, 0 + + for s in self: + if s.min_index() < min_y: + min_y = s.min_index() + + if s.max_index() > max_y: + max_y = s.max_index() + + for r in s: + if r.min_index() < min_x: + min_x = r.min_index() + + if r.max_index() > max_x: + max_x = r.max_index() + + return Point(min_x, min_y, min_z), Point(max_x, max_y, max_z) + + def true_up(self): + min_point, max_point = self.get_all_bounds() + + for s in self: + s.resize(min_point.y, max_point.y) + for r in s: + r.resize(min_point.x, max_point.x) + + def expand_all(self, i: int): + min_point, max_point = self.get_all_bounds() + # print(f"expand {i} cell") + # print("expsting min, max:", min_point, max_point) + min_point = add_points(min_point, Point(-i, -i, -i)) + max_point = add_points(max_point, Point(i, i, i)) + # print("new min, max:", min_point, max_point) + self.get_point(min_point, expand=True) + self.get_point(max_point, expand=True) + + +class HyperGrid(World): + def __init__(self): + super().__init__() + + def _item_factory(self, w: int) -> Grid: + return Grid(world=self, w=w) + + def __repr__(self) -> str: + return "\n\n".join(( + str(s) for s in self._l + )) + + def to_str(self) -> str: + return "\n\n".join(( + f"w = {s._w}, " + s.to_str() for s in self._l + )) + + def iter_cubes(self) -> Iterable[GridItem]: + for g in self: + for s in g: + for r in s: + for c in r: + yield c + + def get_point(self, p: Point, expand=True) -> Optional[GridItem]: + try: + # print(f"expand world z to {p.z}") + c = self.get( + p.w, + expand=expand, + ).get( + p.z, + expand=expand, + ).get( + p.y, + expand=expand, + ).get( + p.x, + expand=expand, + ) + # from pdb import set_trace; set_trace() + return c + except IndexError: + return None + + def get_all_bounds(self) -> Tuple[Point, Point]: + min_w, max_w = self.get_bounds() + min_z, max_z = 0, 0 + min_y, max_y = 0, 0 + min_x, max_x = 0, 0 + + for g in self: + if g.min_index() < min_z: + min_z = g.min_index() + + if g.max_index() > max_z: + max_z = g.max_index() + + for s in g: + if s.min_index() < min_y: + min_y = s.min_index() + + if s.max_index() > max_y: + max_y = s.max_index() + + for r in s: + if r.min_index() < min_x: + min_x = r.min_index() + + if r.max_index() > max_x: + max_x = r.max_index() + + return ( + Point(min_x, min_y, min_z, min_w), + Point(max_x, max_y, max_z, max_w), + ) + + def true_up(self): + min_point, max_point = self.get_all_bounds() + for g in self: + g.resize(min_point.z, max_point.z), + for s in g: + s.resize(min_point.y, max_point.y) + for r in s: + r.resize(min_point.x, max_point.x) + + def expand_all(self, i: int): + min_point, max_point = self.get_all_bounds() + # print(f"expand {i} cell") + # print("existing min, max:", min_point, max_point) + min_point = add_points(min_point, Point(-i, -i, -i, -i)) + max_point = add_points(max_point, Point(i, i, i, i)) + # print("new min, max:", min_point, max_point) + self.get_point(min_point, expand=True) + self.get_point(max_point, expand=True) + + +def part1(): + # Load world + g = Grid() + with open("input.txt") as f: + for y, row in enumerate(f): + row.strip() + for x, c in enumerate(row): + # g.get(0).get(y).get(x).active = c == ACTIVE + pass + + g.true_up() + + print("time = 0\n_____________") + print(g.to_str()) + + for t in range(6): + g.expand_all(1) + g.true_up() + + g.tick() + g.tock() + # g.trim() + g.true_up() + + print(f"time = {t+1}\n_____________") + print(g.to_str()) + # print(g) + + total = g.count_active() + print(f"Total active: {total}") + + +def part2(): + # Load world + g = HyperGrid() + with open("input.txt") as f: + for y, row in enumerate(f): + row.strip() + for x, c in enumerate(row): + # g.get(0).get(0).get(y).get(x).active = c == ACTIVE + pass + + g.true_up() + + print("time = 0\n_____________") + print(g.to_str()) + + # g.expand_all(1) + # g.true_up() + # print("EXPANDED\ntime = 0\n_____________") + # print(g.to_str()) + # return + + for t in range(6): + g.expand_all(1) + g.true_up() + + g.tick() + g.tock() + # g.trim() + g.true_up() + + # print(f"time = {t+1}\n_____________") + # print(g.to_str()) + # print(g) + + total = g.count_active() + print(f"Total active: {total}") + + +def test(): + g = Grid() + + # print("test") + # s = [ + # "...", + # "###", + # "...", + # ] + # for y, row in enumerate(s): + # row.strip() + # for x, c in enumerate(row): + # g.get(0).get(y).get(x).active = c == ACTIVE + # + # g.true_up() + # + # print("time = 0") + # print(g.to_str()) + # print(g) + # + # p = g.get(0).get(0).get(1) + # from pdb import set_trace; set_trace() + # p.tick() + # p.tock() + # print(g.to_str()) + # + # p = g.get(0).get(2).get(1) + # from pdb import set_trace; set_trace() + # p.tick() + # p.tock() + # print(g.to_str()) + + # print(list(g[0][0][0].neighbors())) + # + # print(g.to_str()) + # + # + # return + + # g.get(1).get(1).get(1) + # g.get_point(Point(1, 1, 1)) + # g.expand_all(1) + # g.true_up() + # print(g) + + # r = GridRow(0, 0, None) + # print(r) + # r.get(1) + # print(r) + # print(r[:3]) + # r.get(-3) + # # print(r[0:3]) + # print(r[-2:]) + # + # print("Resize") + # print(r) + # r.resize(0, 3) + # print(r) + + # return + + # c = g.get(0).get(0).get(0) + # print(g) + # from pdb import set_trace; set_trace() + # neigh = list(c.neighbors()) + # print(neigh) + # + # return + + print("test") + s = [ + ".#.", + "..#", + "###", + ] + for y, row in enumerate(s): + row.strip() + for x, c in enumerate(row): + # g.get(0).get(y).get(x).active = c == ACTIVE + pass + + g.true_up() + + print("time = 0\n_____________") + print(g.to_str()) + # print(g) + + # g.expand_all(1) + # g.true_up() + # print(g.to_str()) + # print(g) + # return + + for t in range(6): + g.expand_all(1) + g.true_up() + # print(g.to_str()) + # p = g.get(0).get(3).get(1) + # from pdb import set_trace; set_trace() + + g.tick() + g.tock() + # g.trim() + g.true_up() + + print(f"time = {t+1}\n_____________") + print(g.to_str()) + # print(g) + + total = g.count_active() + print(f"Total active: {total}") + + +if __name__ == "__main__": + # part1() + part2() diff --git a/d24/input.txt b/d24/input.txt new file mode 100644 index 0000000..35e6f00 --- /dev/null +++ b/d24/input.txt @@ -0,0 +1,547 @@ +neeneneneswneneee +eeeswneseseeseeeseeeeesesee +swswsweswwswswswnw +neseewwswwneswnewnewwswswwswwse +wswsweenweesenweeeeeenweeee +neswwwswwwnewwwwwwwwsewwswsww +neseeeswesweenweeeeeeeeee +neeeneneeneeswneeneneneene +ewwsenwwenwnwswnwswwnewwwsewne +sesesesesesewseseweeeeneweseeww +neeeswnwneswneneneweeneeneswnwnesw +neseswnwnenenewneneesenenenenenenenenenene +eneeeeseseeseesewseseseeeseee +enenewseeenewnweseewnwneseweesw +sesesesesenwseseseseseseseswseseee +nenenenenwneeesweseneeeeeenenenwe +neeenenwseswsenewseswenwewsww +neeenesweswwneeneeeeeeeeenwe +swseneswewwsewsweeeseeswwsesww +nenwwnwnwswwnwwnwnwnwnwnweswswnenww +swswseseswnwswswswseswseeswswswswnwswsesenw +nwnewwswnwesewnwwwsenwwnewewe +newwsewwsenwswwswswswswseswwnwwwsw +swswsweswseswswwswswnwseswswswswswswswsw +nenwnwnwnenwnwnwnenenwnenwneswnesenwenw +nwswnwwnwnwwnwnenwwse +neesweeeesewewneese +nwneweswwwswswwswwswswsewsw +wwwwsenwwnwneswsewsewnenewnwwseswne +eeeeeneneneneweneeeeeweswnene +enenwneneeneswnewnweewseswneswnew +swsesesesesenweswseseseswswseswswsesese +nweeeneweewsw +nwswswneswswswneswsewswswswswsesw +swenwwnenwnwnwswnwsesenenw +swswswnwneswswswseswswswswswswswseswse +sweseseseeseseweenese +wnwnwnwnwnenwnwswnwnwenwsenwenwnwnene +eeenweeeeeeeeeeesweeee +nesenwswnwseswneewnenwenwsenwenwewnw +eeeeeewesenweeseeeeswe +swwwswneswsewwswsw +nwnenwnenwnenwnenesenenwnwnwnwnwnwwnw +newnesewnwnenwneneenwnenenwnenenenenesw +eeeeeeeeeeenweeeseeeesw +swnwnwwnwwwnwwewnwwsewwwwnwnew +nwnwnwenenwswnwnwnwnwwnwnenwswewnwnw +swseenwnwswnwnenesenenwnwneeswneenwwnw +enwwseeswwenwswswesw +enwseseeeeeeenweeeseeseswseee +eseswseseswseneenwwneeswwwse +swswswwesenwswswswswswswswswswsenesesw +neswenwswswswnwnwsweswnweswswsweswsw +newsenenwswesewenesewwseeesenwesew +seswswswswswswneseseswweswseswsewseswnw +wnwwwwnwnwnwwnenwwewnwnwswnwnww +newwwwwwsenwwwewwwnwwwww +seseseeeswseseswseswswwsewseseswswse +eenenwswnenwneswnesenwnenenenwnwnenenewsw +swnwewswwewnwnwswwwnwnwewwwse +nwenewneneneewnene +wwwwwswwswenwwsewwwwwwswsww +enenewswnwneneneneseneneneeneneeneene +wnwswswnewwwswnewwwsewwseswnew +nenenwwsenweswnwswswnwswnwnenwnwne +seeenwesesesewseseeseseeesesesese +eeneeeeeeeneenwenweswsweeene +wneneneswseneneneneneneeneenenwsenwnene +seseseswsenewesesesenwneseseeseseesese +wsesenesenwsesweseswnwsesweseseesenwsese +wwwwnwwnewewwswsenwseseewnwnenwnw +wnenenenenenenenenwnenenwnenenesenenene +neeewnwwneneesweneeweseswnwneswsw +neesewwneenwnwwwwseswwnwwwwswww +esweeeeeeneneenwe +eseeseeeeenwswseeseneeseseseswee +neneenewnweneseswnenenwneneenwwseswne +senwwnesenwswnwneeewswnenwnwwnwnwsene +eeeeseeeeeneewwneeweneeenene +nwnenesenwwwseswseswnwwesesenwwnene +swseneswswswswswsewswnwneseswseneeswsesw +nwnwwnwswnwnwwnwnwenenwswwnwnwnwnwenw +seswswseeesesenwnweeseeeneeenewese +nwsenenesenwwnenenwnwneswnenenenenenene +swsewnwwwseswwwsewneneswneenene +nwenenwnwnenwsenwnenwnwswnwnenenenwnenwnw +swwneneneneneenweeeneenesweenesenesw +swnwnwswnwwwswsenewsewswsewswswseswsww +enenenenesenenenenenenenenenenwswnenewne +newewesesewseseseseeeseseeesesese +nenwwwnwsewswwwwewsewwwwwsew +enwewnwwwwnwwnwnwnwnwnwnwwwnwnwswnw +neweeswesweeswewneseewnw +swswswswsewesewswswswswneseswswswseswse +swneeewseneeeeeswneewwneseenwe +wwwwwwwwwneewwsewwwwweww +eeeesweneenweeeneneeweeenee +wnenwneseeenwseeneneewneseswwnene +wwwnwewnwnwnwnwnwewneenwnwnwswswswnw +enenenenwesesewnwneeeswneneeneenenene +nwnewseneseenwwwseswneswseneeeswnew +swsewwsweseswneseseeseswneseneswswse +swswswwswswnewsesesweswswswswseneswnesww +enwwnwwnwwnewnwswswseeswnenwwnwwnwse +sesenwnenwnwnenwnwnwswnwnenwnwnenenwnwnwsw +seeneswswwswwswswwwwswwwswnenesw +swwwwswneseswwwwswwnwswswswswwswsew +swseeenenwnwswenwneneenwnwnenwnwsewsw +wswswswwwswwwswswswneswswswseswswsw +neswnewnenenwnenewenenwneneeenenenw +eswneneneneneenenwneneeeneenenewe +enenenenenenwneneeneeeeeeenese +seeseewswwseseneesenwneseseswsewswsw +ewwewswwswwswswwewwnwswwsww +swwswswswswswswswswswne +nwnenwnenenenwnwnwswnwne +nwnenwnwswnwwewnwnwswnwsenwwnwnwnwnw +nwnwnenwnwnwnwwnwnwnwswnwswnwnwewnwnw +eseneseeswenwneeneneneneewnenwnenene +swwnwwswwswswwswwswswswsewwwwswne +swsewsenenweseesweee +nwnwnwnwsenwnwnwnenenwnewnwnwnenwnwnwnw +nwsweeeseseeeeseeeeseneeswene +neenwneneswnwnesewewswneswnwnwneneswe +esenenwnwnewseneswnwsewswwnwsenwsewswse +nwwwweneeewwwesesenwneneswswswnw +nwnwsenwnewseswnwesenewnenenwnenenenwe +wnwwnwnenwnwsenwnewwnwwsewwnwwwwe +wwwewwswwswwwswwwwswsw +swswwswswseswswswswseswswswswnesw +wwwwwwwwwwswwewwnwwwww +nwnenwnwnwnwnwsenenwnwnwnwnwnw +swnwswswswswwseeeswswswswswswsewnwnwsw +nenwnenwnenewnwnenwnwnenwnwseenenwnenwne +seewseeseeeeseseeeweneseseseese +seenesesesesesesesewseseseseesesesese +nenenenenwneneneenweneneneesenenenesene +swswneneeseswwswnwseswswwswswseswsesw +nwswsenwneenwnwnwnwsenwnwwsenwenewnwsw +nweseseseswswswswswswswswswsw +seseswseseseswsenwseseseseesesesesesese +wwwwwwsenwwnewewnwwsewswnesww +nwseswswnwseswswsewseseeseswswesesesesw +seswseseenwswseseseenwswseswseesewswse +nwwnwnwswnwwnwnwnwnwesenwnwnwwwwnww +neneswseneneneswwnenweneeneneenesenww +swswswswneseswswseswswswwswswsesweswswse +swneswseswswswswswswswswswseswswseseswsene +swswneneswswwneswwwswswswwswnweswsene +nenwnwnwwnwnwnwnwnwnwnwnwnwenwnwnwswnwnw +wwneswwwwwwwwewwwnwwwsewww +neneeswnwneneeneeee +swesweswswnesweswsesewwnenwnwnewnwnee +nwwwwewwwwwwwnwwseswwwswwe +sweenwseeseneweseseeewnwseeseenenw +eeeeeenweseeneeeeeeeenesw +nwnwnwswnwnwnwswnwnwnwnweeenwnwswnenw +eneeneeeeweeeeeneeeeneewsee +swnenwnweneneenwnwnwnwswnwnenenenwnwnwnw +nenwnenwnwnenwnenesenenwnwnwnenw +neeswnweswswseewwnwwweswwwwwne +nwseeeeeeweseeeeseeeeeeee +sweseneneseeseeseeneeeeeewsweew +wnwwnewswwwswwwwewwwwnwww +wswnwsweswwneseswnwswswwseswsweswnwwsw +nweswneeweeeeswsenwew +neeswneneenenweeneneneeneseenesenwe +nwnwnwnwnwnwnwnwnwnwnenenwnwnwnwsenwnwse +seswseseswseseswseseseseswsesenw +nwnenwewnesenwnwnwnwnewnenwnenwne +swswswswesweswswswwswswswswswswwswsw +nwnweeeeeeeeeseeeeeeeese +wswnwnwswswswwwwswswswswswwwseswswse +seneswwseswsesewsenwsenenesenwseseese +neneneswneswenenweeneenenenenwnwswnene +newwwnwwwwnwsewwwwseswwwwse +swsenwenwnwnwnwnewnwswenwwesw +newwnwnwnewsewwswwwwnwnwnwswww +eseswsenenesesenwwseswseseseeseesese +nwwenwenwsenwnewnenenwnwwnweneswnwne +neswneneseswseeseseswswsenesenwswswsww +neneeeswseneswnwnwwenenenwseswwwe +nwswseseseeeseseseseesesesesese +wswwnwswswnenwneswnweswseenwewwwse +swseseswseneswswseswswseseswswnwswseswswsw +sesesenwseswseseseseseeesesesesesesese +nenenenenenenewwneeeneneseneeneneene +wnwswwewswnwnwsenenwesesweeswsene +enenenwneneneeneeeneeseswneenenenene +seenwseseeneeswwneseeeseswwesenww +seseswnwwsewnewswnwseswneswswswesweenw +nenenenenwnwnenenwwnwenwnenw +nwwwwnwneeeeneneneseswsenewesenw +swswswneneseswwwwswswswswswnwswswswsw +nesesenwswswseswnenwsewswseseseseswnese +neeeenenweswenweneneeneeneeeeese +seeweneseeneseseseswseewsenenwe +seseseseseseseseseseseseseseswsenwsw +wswswswswsweswwwwseweswwwswswne +nwseeswneswneswwnenwseswenewseswwsw +neeweenweeeeneeeeeesweeeee +swwswwswwneweswwswswwwswsewwsw +sesweswwswenwweswswesenwnwnwnweswse +nwneenenwnewenesw +wnwseewwenwwwwesewwwnwewwnw +eeeneesenenenweswene +seenwseseseeseseewsweesesesewsese +wswsweswswseseseseseseseseswswsesesenwse +wweeeeeneeseeeeeeeeesese +swseswseseseeswsenenwseswseseseseseswsw +wwwewwwwwnwswwwnwnwnwwwewnw +wwnwnenwseneeswswswewewswswswwenw +neswswswswswseseswseseseseswseesenwswsw +neeswnewnwwswsenwnwnenwnwsenesewene +nenwseeswwswseswsesesweseswswswswseswsw +nwwwwseneneswseseneeseswswnwnwseene +seesesesesenwseweseeseseeseseswseese +ewwwswswwsewnwwwwswnewneeswsw +eeneneneneneneeneenenewnenenenesewne +enweeswnwsweseneeneenwsenewnwswswne +sesenwseewsesenweseeeseseeeseeenee +nwnwnwnenwnwnwswnwnwnwnenwnwenwnenwswnwnwnw +seswnwsenwnenwnwnenwnenwnwnenw +nenwnwnwsenwnwnwnwnwnwnwnesenwswnwnwnwnwne +swnwnenwnenenwnwnwnwnenwweenwwenwnwnwnw +senwnwnwwnwwwwnwwnwnwnwswnenwnwnwnewnw +neswnenwswsesewnwnewsewwnewnesenewnwnw +wwwsenwnewwwwewwnwwwwwsww +enwneeneneswswnesw +enweesesewsenesesw +eeswewneesenenweneneneneneeseee +nwnwseneswnwnwwewwwwsenwwwnwww +swwneswneswwwswsweeswswswwswswseswnw +ewwwwwsewswwwwwwenwwwneww +swneswseeswswswwswnwsewwswswswswwswwsw +sweswwswseneseeewswwnenwnwneewwsw +swwswswseswswswwswswswswswswswwswswne +nwwwswwwwwwswwweweswneswwew +neneneswsenenenwnenenwneswnweweenwsww +senwswnewwseseeseenewseseneeeswene +nenwsewwsenewswseenesewsenenewnwe +swswswswwwwwewswwnewwswwwwww +swsweswsenwnweenenwe +wnwsesesesewseswnesenesenwswsesesesesesese +eeewseeeseeweeeseeewwenee +eeeeeneeeeeeeweseeewwe +neneneneenenwneneneneneneneneneneneswne +seeseeseesesesenweseeeswneenwnwee +seeeseenwswneeeewswewneseeew +nwseenwnwnwnwnwswnwnewwseenwnwnwsenw +esweeeweweneeseeneseee +ewswnwswswwnewswwsweseswweswswww +sweseeneswwwwnwnenwsenwwsweseswe +eweeseseeswnwneneeeneew +swnweseeeeeneweeeeeeweene +wwnwwweswwnenwwnwnwswwwewwsw +neneeeweenewneneeeeneeeneswe +swwwesewnwsenenwnewnwneseenwwswnew +senwnwnenwnwnewnwneneswwneeneneenewse +nwwwnwwwwwnwwwwnwsewnwwwsew +wwwswwswwwswwwwseneneeswwwww +neswswseswswnwseswseseswswwseswsesesesese +nwsewnwnwwnewnwnwnenwneenwnwseneenw +seseseseseseseesenewsesesesenesewsese +newwnwnwnwwnwwwnwsenwnwnwwwsenww +swswenwnewswswswneweweswswswswnwsesese +seeseswseseseseesesesesesewseseswnwse +nenewneneneswnenwsenenenenewneenenenee +sewseneseswneseneseeewswnwswsewswwsw +eeswwswswswswswswswswswsenwswswnwwswsw +seneenwswseseeeneeeeeswswsenewe +nenenwnwnenwenenenwnewnwwsenenenwnwne +nenwenwswenwnenwnwsenwwnwenwnwswnwnw +wwwsenwwswnwwwewenewwwwwnwnw +nwnwnwnesenwnwnwsenwnwnwswnwnwnwnwnwnwnw +swswswswseswsweswswnwswwswseswneswswswwsw +eswnenwneenwewnwnwnww +seseseseeseneseseseseseseweeseseseswnw +enwwnwnwswnwnwnwnwwwnwnwnwwnw +swsewseneswneewwwwnwnwnwnwwseswsesww +nenesenwnenenenenenenenenenewneneswnee +nwweswwsweswswswneswswnwswswswswww +neeneeneneneeneenenenenenenewsenene +nwswswswsweswwswswswwswewwwswswsw +swwswwwwwswwseswswswnwweneswswsw +wswnwneeneswnwwswwnwwsenenewwnwww +nenenenenwwenwnwnenwenenww +seseneseseswwneseeseewseseesesenwse +nwenwsenwnewneswnwnenwnwnwneenwnwnwnenw +nwnwnenwnwnwnwnweswnenwsenenwnwnwnenwnwwne +nwnenwenwswnwenwwswnenwnenwnwnwnwewnee +wwnwenwnwwnwwwnenwnwwnwnwnwesww +neseeneeeneeeeewneneneneeenee +swseseswnwneeseseneswswwswswnwswse +swnwswseswswwswswswneswsw +swwweeeeswnwneneeewnweeeeee +enenwnenwsenwswnwnwnenenwnewnesenwnwsenwnw +swewswwneneseeeenwneenenwnenwseee +seseseseseenwseneseseeseswseeseswnwse +seneeeseseeeseswnwswsesesenwwwseenw +wwnewwwwwwwsenewwwwwwswwnww +nwswwwswswwnwsweswswsweswswsesweswsw +swswnwnwnwnwwenwnwnwenenwnenw +seeseseseseweseseeeseseesee +wnwnwnwsewnwnwnwnw +nwnenenwnwneswnwnwnwnwnwnwnwneenwnwwnw +sweeseneweseneswenwsesenweswsenwnee +wswnwnweseseewenenenwenenesweene +nwnesenwnwseesewneswwnesweswnwnwsenww +sewneswwwnwewnenwnwnwwwswnwwnwswe +eeesweseneeweenweeswenweneewe +neneneeneeeeneneeesweeenwenene +eeneneeeneeeenwneeswweneenenee +sesweeneeseeeweeeenweeeese +swnwswneewwwnwwsewwnwnwwnwnwwenwnw +eeeeesweseeeseswenwnwenwnwee +sewwnewwswwwwswnesewswsw +nesewseewseswsesewwswweseseneswswe +newneenwsewnenenenenenwne +sewsenwseeseesewneswwwnwsenweswnene +swswswwwwwswwwswneww +wnewwwwwwwwwwwwwwwswsw +swwwnewwwwswsenwnwwwnenwseenww +neeenenwweneeneeneneneneneeneneswse +nwsenwnwnwnwnwswwnenenwsewnwswnwenwse +nwesenwnewwnwwwnwwwwnwwswnwnww +neswwsenwswnwwwswswseswswwsw +neneeneswneneneenewnewseenenenenene +seswseswsesesenesesesesesese +wwwnwwwwweswewswnw +seneseswsesewseseneesewwseswwswsenese +enenwnwnwwnwswnwnwnwswnwenwnwswenwnw +neswwsenwswsweneswswnwswseswnesenwnesw +senwwnweswseswneswneewneseesesesesene +nwenwwnesenwnwwswenwnenwswnenwnenwse +weneeseeneeswweswnweswenwewswnw +eswnwewwnwnwswwswwswene +swwnwneseseseneneseswewswwsenewseee +seswwnwwwswseeswwswnwwsewwenene +neeneneneneneenenenenewsenenenwswnene +eesesweeeeeeeneenweeweseww +seswswswnwswswsweswswnwswswswseswswswsesw +nenwnwnwnenenwnwnwnwwnwsenesenwnenwnew +neneswneneneenesenwnenenwnenwwnewnesene +wnwnwewnwwswsenewenenwnwswwwwwwnw +weneswnenwnenwnenenenenwnenesewnwnene +eneneewswneenenwswnenweeeeneesee +neswseseswseswwseseseseswnwnwnwswnwsesw +nenenenenenwenenewnwnwwsenwnenenenene +weseswnewnenwwenwnwnwewnenenwsenw +swenwnewewwwnwneswewwsewnwsewnw +seseseseneswseseswseswseseseseswnesewsesese +nwnwnwnenwnwnwnwnenwnwenwnwnwnwnwnwnwsww +nwesweeeneeeeseeeeeneeeeee +esweseswnenwsenwnw +swneswwswswswewswwnwnewswsenenenwsw +enenwnwswnwnwnwsenenwnwnenenwnwnenwnwsenw +neswneswswswsenwseseneswseseneswseswswse +ewneneenwnenwneneswnwnw +swsenwsenesweswwnwsenesewswswwseswswsesw +swwswwswwwswwswswwswnwswswswe +nwwnewwewwwwswneswwswswseswswsw +seeseswwnesesenwsenwswweseswenwnese +nwnenwneneswswwnenesenenwnenenwnwnenenene +nenwnenwnwswnwnenwnewneneneneneneneenwne +eeeenenenenwneneeeeeeneewsese +neseswsesesesewsenewsesenwseneswnesesw +eswnwswsweeswnwnwnwwswwwswwesesesw +wnwwsenwwwenwswswswsewwenewnwwnw +seweeeeeeeneeeeseenwswnenwee +nwsenwwwwwwwwwwwwnwwwneww +swneswswswswwswsweswwwswnenwwswseswsw +swneeeeeeesweenwneneeeeeee +neewsewswseswswsenwswswneswwswenesw +wnwnwsewwswnwwwwnwnwnwnenw +neseseeseswsesesewswsenwswseseswseswswnw +nwenenwnwnwnwnwnwnwwswnwnwnwnwnwsenwe +neneeewnewnweseenenwswwnesewsee +sesewseswneswswseseswnwswswneswneswswe +seseseswseswsesesesesesesesenesesewsesenwse +enwwwswswwwnwsesewwewwwnwew +nwsenwnweseswnwnenwnwnwnwnwnwwwswnwnw +nwseseeneseesweseseseseseseseeswnwsese +seswswseswneseswswneswswswseswswswswswswnw +swswsenwseswswseswswswseseneseseseswneswsw +seseeseswswswswswseswnwswswnwsweswsesw +wneseswseseneseesenenwwnesewseswswese +neneswnenwnenenenenwneesenwnenenenwnwnene +sweneseweseeeeeseeeeeenweeee +enwnwnwnwnwnewenwsenenenwnenenwnwswne +weeeeneeeseseeeeseseesewewee +wsenwnwsewwwwwwwnwwnwnewnwww +nwnwewnwnewnwsewnwwnwnwnwnwwwwwse +swswswwwwswwswswsewnewwwswwneww +nenwswewwswneswwswswwweswswwww +neneneswenenenwneneweewnwnenenenene +swswseneseseseseswseswsese +nwnesenwnenenewneseswwwnwenenwseene +wsesewseseseseseseesesesesesenesesese +seseweswsesesesesesesese +nwnwnwnenwsenwnwnwneswnenwnenwenwnenwnw +seseswewseneseseseseseseswswsesewnese +seswseswsesenesesesesesenwswseseseswsese +sweenwseeeeeeeeenweeeeeeswe +eenwwnewswsesewewswswseneswnewww +wwwwwwwwwnwwsewww +wnwnenwswenwnwnwnwse +swneseneneswneneesewwnenene +wwswewwwwwwwwnwwnwwwswwswwse +sesesewseeseswsewseswnesesesesesesene +swwwwwwwwwswwwwnewwwsenesw +swswseswswnwswswswseseeswsw +newwswsenwnewwsewseseswenwneeswwnw +nwsweswswswswswswnwswswswseswswswswsesw +nwswneseswseswsenewenewwneseewsenw +sewseneseneseseseseesewseseneswsesesese +wnwnwenwnwnwnwnwnwnwnwsenwnwneswnwnwne +sewneewwsesenwnwnewwswwwwneswwsw +wwwnwsewwwwswwwwwnwwwwwe +ewneenwseneneewswneswneenenwenee +swwswswswswswswneswswseswswweswswswswswsw +nwswnwswnenenwswneneneneeneene +esenenenwneneneswenenewneneneenenenenene +swswsweseewweswwsesw +enwewwnwnwsenwneseswwesewnewenew +eeeseseseeneesweeeeeee +ewenwwwswwseswnwswnwwswsweswwww +wnwweeneenewnenenwnewswneeesew +nenwnenwnenenwswnenwnewnwnenwenwnwnene +neneneseneeeneneesewneneeew +neneneneneneneenenwneneneneswneenesenene +nenwnenenwnwnwenenwnwneneneenewswnenenw +swwwswwwwewswswswwwswnwseneswswww +neenenewneneseneneesenewenenenenwnwnese +wnwwweswswswwswweswswwswwswwwwnw +wswwwewwswwswwwwwwnwwwsw +senwesewenwseseswesesesenwswnwsesee +nwnwnwnwnwneneswnwsenenwnenwsenenwnwnw +seewwwwwnwnwwwwnwneswwwnwswnww +seeweseeeseeeeseneeswseeseene +enesweeweeeneesweneseeeeneee +senwseweswneeesweeneseweeesenesew +swswseswseswswsweneswswswwenwwneswsw +swswswwewnwswswswswewwswswswswswswsw +swswswseswsesewseswseenwseswseswnwnesese +ewswswswswswneswswnwwenwsesenwswwsee +swnenwweesenwswnewneneneswnwnwnwswnenw +nwnwnwnwnenwswnenwnenwenwnwwnwnenenwnwne +neneseenewnenenenewnenenenesenenenenenee +nwnwnwswnenwnwenwsenenwnwnenwnwnenenwnwnene +nenenenenewnenewsenenenenesenenenenene +swswswswseseesesesenwswswsesenwseseseese +neneneweeeenesesewneweneeeneene +wwnwewswsewwnewwnewwwww +seseeeeseeeeeesewseee +senesesesweseswenwnesesweseneeseswe +wweeswswnwswwsesesewesenwseewee +nwwnwwnwnwnwnwwwnwnwswenwwnwnw +wwswnewwwwwwwwwwsewwwww +neneeneneneneneneeneenenesenenenewne +neweseeeeseeeeeeeswseeseesee +nweneneswnwnwnwnenesenesewnwnwneenwnwnw +neneseswnenenwnwswwnwnenwnewseneseneneenw +nenenewesewseweeeswswneswneseee +swswseseeseseeeseesesesenwsesesesenwsese +seneeneenweeneneenesweeewneee +wwwewsenewwswneeneeswseswswenw +nwnwwnewsenewswnesenwwwnwenwwsenwnw +seeenwneewnweswnweewseewseese +sewnwswwwwnewwnewnwwwsewwww +swsenwnwewnwnwnwnwnwnwwnwnw +enwesweeseeneswneeseewsewwnee +wnwweneswswwsenwwwnwwwwnwnwww +wwwswwwwwwnewswwwweswwww +swswnewswswsweswswwwswseswswwwsw +wwwnwwewnwwwwnwwwwnwwwnwsew +nwnwnwnwnwsenwwnwsewnwnwnwnwnwnenwnwnw +nesenweswnenenesenenenwneneeeneenwne +sweeeseeeeesenweseeseseeese +eseswwswseswseswneseseseseseswswseswwswsw +nwenwnwsenwnwnenwnwnwnwnwnwsenwnwnwwne +wewwwwwnewwwwewwnwwswww +wnwwwswswneeswswswswswseseseesenwesw +seweeeenweeeeesweeeeee +nenenenenwsewnenenwneneswnenenenenenenene +neesewneswneeeneneneneeenwwwneene +swseswneswseswwesesweswswswnwseswnwswswe +newnwwwseswswwswwswnwswwwsewswwne +swswswwswswswswswsenwseswnenewswwswsw +neeneenenewneeweeeswneseeeeee +newsewnenwnewsenesewnwee +nwnwswswseseneswswnweseswsenwneseweswsw +seswswwwwwswwneswswwenewswne +eneeenwwnwwwwwswnwnwswnwnwwww +nwnwnwnwnwnwnwwewnwsww +seeswneseseseeseesesesewenwseenwwse +nwnwwswnwwwwewnwnwwwnwnwwewnwew +eeseseseeeseneseeeseseeneseseswwsese +swwswswweswwwnwswneswwswswswwww +wnwswwwwwnwnwwwsenenwewswwwnenw +sewswseseswnwnwsweenweswwseswswswnenwne +wwnwwwnwnwwwwwnenwwnewswnwwnwwse +seweswwneeswsenwswnwwswswswnwseswwsw +nwnenenwnwnwneswnenenenenwenwnenwnenwneswne +sewsenwnenwnwwwnenwnewwsenwwnwwnwse +seseeseseenweneseweseswswswnesesenw +swwneswwwwswwnewwswwseswswwsww +seesweswnwseseseswnwnwswswnwse +eesesweseeeseeeeeeenwsweene +swseswswswseswswswswswswswwswswenwswsesw +swwswswsweswwwnwswswswnwswwsewswsw +nwnwwwnwwnwnwwnwwneenwwwwnwsesee +weeenwseseseseeseenesesee +nwnwwseenwwwwnwwnwwnwnenwsenwnww +eeeeseseeeeswseeseseswneseeseeenw +eeeeeneesweeeesweeenenweeee +eweeseneeseesesenesweeseewsewne +neneneswswenenwwnenewsweneswenwswsenw +wwswnwsewneseswswneesenewswwwsenwsw +seswswsweswnweswesweswswwnwnwsesese +weneeeneeeeewseeeeeeeneee +nwwnewwswwswswswwwswswwewswwwe +seseesewseneeseesesweswsenwwsenwsese +wenwseeswwnwewwneswnwenwwnwnwse +wwwewswwwwwwwewnwwwwwnww +seseswsesweweeesenweeseeeeseesenw +swseneswneseswwswswswswseneseswswswswsesww +esenwseseeeseseseesesesesenwwnwseene +neeneneneeneeenenenwwswe +wnewwswswswwwswswswswsewswwswwsw +eswnwesenesweeeneesweeneseeesw +nenwneneneeswneneneswnwnenene +swswswswswswswneseswswenwwnweswswswsw +eeeeneeeneeewneneeeeeeenwesw +neneeesweseneneenwseenwnee +nwnenenenwswewnwnwnwnwnwnweswseswnenw +wneseseseseseseswseneswseseswsesesesese +wswsweseseswswneswwswneswneswswnwswsw +swnwnweneneswsewnenwnw +nwnwnwnwnewnwnenwnenwnwnwnwnwnesenenesene +nenenenenenwnenenwneenwswnenwsenenenenw +swnwswnweesenwswswswsenwswseseeswswsesw +ewswnwseswsenweenwsenesesewsee +nwnewseewsewnwnwnesewwnwsesenwwswnw +nwnwnenwnenwneneneenwwnenenenwswnwenenw +nwwwswwwwwwnwwwswwenwnwwwe +wnwsenesenwswsewswneswswnwsewswwwwsw diff --git a/d24/main.py b/d24/main.py new file mode 100755 index 0000000..ee7a1b7 --- /dev/null +++ b/d24/main.py @@ -0,0 +1,231 @@ +#! /usr/bin/env python3 +from typing import Iterable +from typing import Tuple +from typing import Optional + +from expanding import AutoExpanding +from expanding import GridItem +from expanding import Point +from expanding import World +from expanding import add_points + + +D2P = { + "se": Point(1, -1), + "sw": Point(-1, -1), + "ne": Point(1, 1), + "nw": Point(-1, 1), + "w": Point(-2, 0), + "e": Point(2, 0), +} + + +def directions_to_point(s: str) -> Point: + point = Point(0, 0) + direction = "" + for c in s: + direction += c + if direction in D2P: + point = add_points(point, D2P[direction]) + direction = "" + + if direction != "": + raise ValueError("Something left over unexpectedly") + + return point + + +class Tile(GridItem): + + def __init__(self, loc: Point, world: World, is_black: bool = False): + # Give this tile a unique id for tracking later + self.is_black = is_black + + def _tock(): + # print("Default tock") + pass + + self.tock = _tock + + super().__init__(loc, world) + + def flip(self): + self.is_black = not self.is_black + + def neighbors(self, expand=False) -> Iterable["Tile"]: + for diff in D2P.values(): + neighbor_point = add_points(self._loc, diff) + neighbor = self._world.get_point(neighbor_point, expand=expand) + if neighbor: + yield neighbor + + def tick(self): + num_black = count_black(self.neighbors(expand=True)) + if self.is_black and (num_black == 0 or num_black > 2): + self.tock = self.flip + if not self.is_black and num_black == 2: + self.tock = self.flip + + +def count_black(tiles: Iterable[Tile]) -> int: + return sum(map(lambda x: 1 if x.is_black else 0, tiles)) + + +class TileRow(AutoExpanding): + def __init__(self, y: int, world: World): + self._y = y + self._world = world + super().__init__() + + def _item_factory(self, x: int) -> GridItem: + return Tile(Point(x, self._y), self._world) + + def __repr__(self) -> str: + return "[" + " ".join((str(c) for c in self._l)) + "]" + + def to_str(self) -> str: + return "".join((c.to_str() for c in self._l)) + + +class Floor(World): + def __init__(self): + super().__init__() + + def _item_factory(self, y: int) -> TileRow: + return TileRow(y, self) + + def iter_items(self) -> Iterable[GridItem]: + for r in self: + for t in r: + yield t + + def get_point(self, p: Point, expand=True) -> Optional[GridItem]: + try: + return self.get( + p.y, + expand=expand, + ).get( + p.x, + expand=expand, + ) + except IndexError: + return None + + def get_all_bounds(self) -> Tuple[Point, Point]: + min_y, max_y = self.get_bounds() + min_x, max_x = 0, 0 + + for r in self: + if r.min_index() < min_x: + min_x = r.min_index() + + if r.max_index() > max_x: + max_x = r.max_index() + + return Point(min_x, min_y, 0), Point(max_x, max_y, 0) + + def true_up(self): + min_point, max_point = self.get_all_bounds() + + for r in self: + r.resize(min_point.x, max_point.x) + + def expand_all(self, i: int): + min_point, max_point = self.get_all_bounds() + min_point = add_points(min_point, Point(-i, -i)) + max_point = add_points(max_point, Point(i, i)) + self.get_point(min_point, expand=True) + self.get_point(max_point, expand=True) + + def tick(self): + for t in self.iter_items(): + t.tick() + + def tock(self): + for t in self.iter_items(): + t.tock() + + +def sample(): + print(directions_to_point("nwwswee")) + + seen = {Point(0, 0)} + floor = Floor() + for line in ( + "sesenwnenenewseeswwswswwnenewsewsw", + "neeenesenwnwwswnenewnwwsewnenwseswesw", + "seswneswswsenwwnwse", + "nwnwneseeswswnenewneswwnewseswneseene", + "swweswneswnenwsewnwneneseenw", + "eesenwseswswnenwswnwnwsewwnwsene", + "sewnenenenesenwsewnenwwwse", + "wenwwweseeeweswwwnwwe", + "wsweesenenewnwwnwsenewsenwwsesesenwne", + "neeswseenwwswnwswswnw", + "nenwswwsewswnenenewsenwsenwnesesenew", + "enewnwewneswsewnwswenweswnenwsenwsw", + "sweneswneswneneenwnewenewwneswswnese", + "swwesenesewenwneswnwwneseswwne", + "enesenwswwswneneswsenwnewswseenwsese", + "wnwnesenesenenwwnenwsewesewsesesew", + "nenewswnwewswnenesenwnesewesw", + "eneswnwswnwsenenwnwnwwseeswneewsenese", + "neswnwewnwnwseenwseesewsenwsweewe", + "wseweeenwnesenwwwswnew", + ): + p = directions_to_point(line) + print(f"Parsed point {p}") + if p in seen: + print("seen!") + seen.add(p) + floor.get_point(p, expand=True).flip() + + black = count_black(floor.iter_items()) + print("Day 0") + print(f"Number black is {black}") + + for day in range(100): + floor.expand_all(1) + floor.true_up() + floor.tick() + floor.tock() + black = count_black(floor.iter_items()) + total = sum(map(lambda x: 1, floor.iter_items())) + print(f"Day {day+1}: {black} / {total}") + + +def part1(): + floor = Floor() + with open("input.txt") as f: + for line in f: + line = line.strip() + p = directions_to_point(line) + floor.get_point(p, expand=True).flip() + + black = count_black(floor.iter_items()) + print(f"Number black is {black}") + + +def part2(): + floor = Floor() + with open("input.txt") as f: + for line in f: + line = line.strip() + p = directions_to_point(line) + floor.get_point(p, expand=True).flip() + + black = count_black(floor.iter_items()) + print("Day 0") + print(f"Number black is {black}") + + for day in range(1, 11): + floor.tick() + floor.tock() + black = count_black(floor.iter_items()) + print(f"Day {day}: {black}") + + +if __name__ == "__main__": + sample() + # part1() + # part2() diff --git a/d24/main2.py b/d24/main2.py new file mode 100755 index 0000000..bb510f5 --- /dev/null +++ b/d24/main2.py @@ -0,0 +1,136 @@ +#! /usr/bin/env python3 +from typing import Iterable +# from typing import Tuple +from typing import Set +from typing import Dict +# from typing import Optional + +import itertools +from collections import Counter +from collections import namedtuple + + +Point = namedtuple("Point", "x y") + +D2P = { + "se": Point(1, -1), + "sw": Point(-1, -1), + "ne": Point(1, 1), + "nw": Point(-1, 1), + "w": Point(-2, 0), + "e": Point(2, 0), +} + + +def directions_to_point(s: str) -> Point: + point = Point(0, 0) + direction = "" + for c in s: + direction += c + if direction in D2P: + point = add_points(point, D2P[direction]) + direction = "" + + if direction != "": + raise ValueError("Something left over unexpectedly") + + return point + + +def add_points(p1, p2) -> Point: + return Point( + p1.x + p2.x, + p1.y + p2.y, + ) + + +def neighbors(point: Point) -> Iterable[Point]: + for diff in D2P.values(): + yield add_points(point, diff) + + +def neighbor_counts(points: Set[Point]) -> Dict[Point, int]: + # return { + # p: sum(map(lambda x: 1 if x in points else 0, neighbors(p))) + # for p in points + # } + return Counter(itertools.chain.from_iterable(map(neighbors, points))) + + +def next_generation(points: Set[Point]): + counts = neighbor_counts(points) + return ( + {p for p in points if counts[p] in (1, 2)} | + {p for p in counts if p not in points and counts[p] == 2} + ) + + +def point_deltas() -> Iterable[Point]: + return D2P.values() + + +def life(points: Set[Point], n: int) -> Set[Point]: + for r in range(n): + points = next_generation(points) + + return points + + +def sample(): + black: Set[Point] = set() + for line in ( + "sesenwnenenewseeswwswswwnenewsewsw", + "neeenesenwnwwswnenewnwwsewnenwseswesw", + "seswneswswsenwwnwse", + "nwnwneseeswswnenewneswwnewseswneseene", + "swweswneswnenwsewnwneneseenw", + "eesenwseswswnenwswnwnwsewwnwsene", + "sewnenenenesenwsewnenwwwse", + "wenwwweseeeweswwwnwwe", + "wsweesenenewnwwnwsenewsenwwsesesenwne", + "neeswseenwwswnwswswnw", + "nenwswwsewswnenenewsenwsenwnesesenew", + "enewnwewneswsewnwswenweswnenwsenwsw", + "sweneswneswneneenwnewenewwneswswnese", + "swwesenesewenwneswnwwneseswwne", + "enesenwswwswneneswsenwnewswseenwsese", + "wnwnesenesenenwwnenwsewesewsesesew", + "nenewswnwewswnenesenwnesewesw", + "eneswnwswnwsenenwnwnwwseeswneewsenese", + "neswnwewnwnwseenwseesewsenwsweewe", + "wseweeenwnesenwwwswnew", + ): + p = directions_to_point(line) + if p in black: + black.remove(p) + else: + black.add(p) + + print(f"Num black is {len(black)}") + + rounds = 100 + black = life(black, rounds) + print(f"Num black after {rounds} is {len(black)}") + + +def part2(): + black: Set[Point] = set() + with open("input.txt") as f: + for line in f: + line = line.strip() + p = directions_to_point(line) + if p in black: + black.remove(p) + else: + black.add(p) + + print(f"Num black is {len(black)}") + + rounds = 100 + black = life(black, rounds) + print(f"Num black after {rounds} is {len(black)}") + + +if __name__ == "__main__": + # sample() + part2() diff --git a/main.go b/main.go new file mode 100644 index 0000000..9f70997 --- /dev/null +++ b/main.go @@ -0,0 +1,14 @@ +package main + +import "fmt" + +func main() { + wm := NewLinkedGrid(5, 5) + wm.Print() + + a := []int{1, 2, 3, 4} + _ = MapInt(a, func(v int) (int, error) { return v * 2, nil }) + fmt.Println(a) + r, _ := ReduceInt(a, 0, func(t, v int) (int, error) { return t + v, nil }) + fmt.Println(r) +} diff --git a/util.go b/util.go new file mode 100644 index 0000000..7589424 --- /dev/null +++ b/util.go @@ -0,0 +1,300 @@ +package main + +import ( + "bufio" + "errors" + "fmt" + "math" + "os" +) + +var ( + errItemAlreadySet = errors.New("cannot set item in direction as one is already set") +) + +// ProcessLines maps a function on lines parsed from a file. +func ProcessLines(path string, f func(string) (stop bool, err error)) error { + file, err := os.Open(path) + if err != nil { + return err + } + defer file.Close() + + scanner := bufio.NewScanner(file) + for scanner.Scan() { + stop, err := f(scanner.Text()) + if stop || err != nil { + return err + } + } + + if err := scanner.Err(); err != nil { + return err + } + + return nil +} + +// ProcessGroups maps a function on groups of lines parsed from a file separated by some string. +func ProcessGroups(path, separator string, f func([]string) (stop bool, err error)) error { + group := []string{} + + if err := ProcessLines(path, func(line string) (stop bool, err error) { + if line == separator { + stop, err = f(group) + if stop || err != nil { + return + } + group = []string{} + } else { + group = append(group, line) + } + + return + }); err != nil { + return err + } + + _, err := f(group) + + return err +} + +// StringSet is a set of strings.. +type StringSet map[string]bool + +// Add an item to a StringSet. +func (s *StringSet) Add(v string) { + (*s)[v] = true +} + +// AddAll adds all items in a list to the set. +func (s *StringSet) AddAll(l []string) { + for _, v := range l { + s.Add(v) + } +} + +// Items returns all values in the set as a list. +func (s StringSet) Items() []string { + values := []string{} + for k := range s { + values = append(values, k) + } + + return values +} + +// NewStringSet creates an empty string set. +func NewStringSet(values []string) StringSet { + v := StringSet{} + v.AddAll(values) + + return v +} + +// Union returns the union of two SringSets. +func Union(s1, s2 StringSet) StringSet { + union := NewStringSet(s1.Items()) + union.AddAll(s2.Items()) + + return union +} + +// Intersection returns the union of two SringSets. +func Intersection(s1, s2 StringSet) StringSet { + intersect := StringSet{} + + for v := range s1 { + if _, ok := s2[v]; ok { + intersect.Add(v) + } + } + + return intersect +} + +// Difference returns the value of s1 with values of s2 removed. +func Difference(s1, s2 StringSet) StringSet { + difference := StringSet{} + + for v := range s1 { + if _, ok := s2[v]; !ok { + difference.Add(v) + } + } + + return difference +} + +// Point represents a point on a coordinate system. +type Point struct { + x, y int +} + +// AddPoints adds two points together. +func AddPoints(p1, p2 Point) Point { + return Point{ + p1.x + p2.x, + p1.y + p2.y, + } +} + +// PowInt is equivalent to math.Pow but for integers. +func PowInt(x, y int) int { + return int(math.Pow(float64(x), float64(y))) +} + +// LinkedGridItem is a single item in a linked grid. +type LinkedGridItem struct { + location Point + left, right, up, down *LinkedGridItem + grid *LinkedGrid +} + +func (item LinkedGridItem) String() string { + return fmt.Sprintf("%v", item.location) +} + +// Location of the item. +func (item LinkedGridItem) Location() Point { + return item.location +} + +// Left gives a pointer to the item on the left. +func (item LinkedGridItem) Left() *LinkedGridItem { + return item.left +} + +// Up gives a pointer to the item above. +func (item LinkedGridItem) Up() *LinkedGridItem { + return item.up +} + +// Right gives a pointer to the item on the right. +func (item LinkedGridItem) Right() *LinkedGridItem { + return item.right +} + +// Down gives a pointer to the item below. +func (item LinkedGridItem) Down() *LinkedGridItem { + return item.down +} + +// SetLeft gives a pointer to the item on the left. +func (item *LinkedGridItem) SetLeft(other *LinkedGridItem) error { + if item.left != nil || other.right != nil { + return errItemAlreadySet + } + + item.left = other + other.right = item + + return nil +} + +// SetUp gives a pointer to the item on the up. +func (item *LinkedGridItem) SetUp(other *LinkedGridItem) error { + if item.up != nil || other.down != nil { + return errItemAlreadySet + } + + item.up = other + other.down = item + + return nil +} + +// SetRight gives a pointer to the item on the right. +func (item *LinkedGridItem) SetRight(other *LinkedGridItem) error { + if item.right != nil || other.left != nil { + return errItemAlreadySet + } + + item.right = other + other.left = item + + return nil +} + +// SetDown gives a pointer to the item on the down. +func (item *LinkedGridItem) SetDown(other *LinkedGridItem) error { + if item.down != nil || other.up != nil { + return errItemAlreadySet + } + + item.down = other + other.up = item + + return nil +} + +// LinkedGrid is a 2d array of grid square. +type LinkedGrid [][]*LinkedGridItem + +// Print a linked grid. +func (grid LinkedGrid) Print() { + for _, row := range grid { + for _, item := range row { + fmt.Print(item.String()) + } + + fmt.Print("\n") + } +} + +// NewLinkedGrid initializes a new linked grid of a given size. +func NewLinkedGrid(width, height int) *LinkedGrid { + + var w = make(LinkedGrid, height) + + for y := 0; y < height; y++ { + w[y] = make([]*LinkedGridItem, width) + + for x := 0; x < height; x++ { + item := LinkedGridItem{location: Point{x, y}} + + if x != 0 { + _ = item.SetLeft(w[y][x-1]) + } + + if y != 0 { + _ = item.SetUp(w[y-1][x]) + } + + w[y][x] = &item + } + } + + return &w +} + +// MapInt maps a function onto a list of ints. +func MapInt(a []int, f func(int) (int, error)) error { + var err error + + for i, v := range a { + a[i], err = f(v) + if err != nil { + return err + } + } + + return nil +} + +// ReduceInt maps a function onto a list of ints. +func ReduceInt(a []int, start int, f func(int, int) (int, error)) (int, error) { + var err error + + result := start + + for _, v := range a { + result, err = f(result, v) + if err != nil { + return 0, err + } + } + + return result, nil +}