From c16e4babdb9a32ef1f71378e00cef14d2c676292 Mon Sep 17 00:00:00 2001 From: Adam Wick Date: Mon, 21 Dec 2020 20:35:27 -0800 Subject: [PATCH] So not very proud of this one. Whew. --- inputs/day20.txt | 1728 +++++++++++++++++++++++++++++++++++++++++ inputs/day20_test.txt | 107 +++ src/bin/satellite.rs | 702 +++++++++++++++++ src/errors.rs | 16 + 4 files changed, 2553 insertions(+) create mode 100644 inputs/day20.txt create mode 100644 inputs/day20_test.txt create mode 100644 src/bin/satellite.rs diff --git a/inputs/day20.txt b/inputs/day20.txt new file mode 100644 index 0000000..849e809 --- /dev/null +++ b/inputs/day20.txt @@ -0,0 +1,1728 @@ +Tile 1237: +######..#. +...##.#..# +....#..#.. +.#.#...... +#..##..... +#.#..#..#. +......#..# +#.....#... +.......... +..#.#..... + +Tile 2113: +.##.####.# +.##.#.#.## +#....#...# +........#. +##.##.#.## +..#.#..... +#.##....#. +.##....... +.......#.# +##..##.#.. + +Tile 3089: +....###..# +##...#..#. +.....#.#.. +...#.....# +.......... +#........# +##.##..#.# +....###... +#.#....#.. +#####..#.. + +Tile 1217: +#..#...### +#.#....... +.......### +#......... +....#....# +#..#....## +#.......## +#........# +#.#..#..#. +##....##.# + +Tile 2129: +.###.##.## +##.......# +#....#.... +#......#.# +#..#.#..## +#.......#. +##....#### +..#.....## +#........# +...##.#### + +Tile 1861: +##.##..#.. +...#.#...# +#....#.... +......##.# +...#.....# +.........# +##....#... +##...#.... +.#...#.##. +#.#.###... + +Tile 3907: +.#.#.#...# +........## +##.......# +#......#.. +#......##. +..#......# +#.#..#.... +...#....#. +.......#.. +.#.####.## + +Tile 1549: +##.#...... +....#.#.## +...#.....# +.......... +..#......# +...##....# +.......... +#.......#. +##...#...# +.###.##..# + +Tile 2699: +..####...# +.##.#..### +..#..##.## +#.#.#...## +#.....#... +#.......## +###...#..# +.....#.... +#........# +.#.###.... + +Tile 2593: +.#....#... +....#.#... +....##.... +##...#...# +...#....## +#...#..#.# +..##.#..#. +..####.... +.#..#..#.. +...###.##. + +Tile 3209: +.#..#....# +.....#...# +#......... +.......... +#......... +.....#..#. +#......... +##........ +..#....... +#.#.....## + +Tile 1789: +###..#..#. +#.#..##.## +#...##...# +#......... +..#.#..... +..####..## +#.#..###.. +......#### +#....####. +..##.#..## + +Tile 2111: +#.##.#.### +.#..#....# +.#.#..#... +#.......#. +.......#.. +#......#.# +#......... +.....#...# +##.....#.. +..##.#..## + +Tile 3137: +.####..##. +##.##....# +#....#.... +#......... +..#...#.#. +#.#..##.#. +..#...#..# +..#..#.#.# +.......### +#.##...### + +Tile 1871: +#.####.... +#....#.... +......#..# +#.......## +##.#....## +..#..#.... +#..#...#.. +#.#...#.## +#.##.....# +.##.....## + +Tile 3119: +######.##. +..#..##..# +.......##. +#...#.#..# +..#...#... +#..#....#. +#....#.... +#......#.# +#......... +......#.## + +Tile 1579: +.#.#.#.... +#..#.....# +###.....#. +..#.#....# +####...... +#.#......# +.......#.. +...#.....# +.#####...# +#..#....## + +Tile 1249: +#...####.. +#......... +...#.....# +#......#.# +....##.... +#..#..##.# +#..#.....# +....#.#... +#.#....#.. +.##...#.#. + +Tile 1319: +....#.#### +#.#..#.#.# +#......#.. +..#.#.#..# +..#....#.# +##....#.#. +###...#... +###......# +..#..#..## +..#.#..##. + +Tile 1987: +.#...####. +...#...### +...##...## +..#..#..#. +##.....#.. +#..#....## +.#.....#.# +#......#.. +##......#. +..###...#. + +Tile 2963: +.##.#####. +#.##...##. +#..##..... +..#......# +..##.....# +.#..#..#.# +.......... +#...#..##. +...#...... +##..#####. + +Tile 1609: +..##..###. +.....#..#. +.....#.... +##....#... +###..#...# +##....#..# +......##.. +..#..###.. +#....#.#.. +...##....# + +Tile 2267: +...#.#..#. +..##....## +####..#.## +....#.##.# +##..#..... +..##.#.... +#.##...### +#..##.###. +.......... +..#..##... + +Tile 1531: +#.#..##..# +#........# +#.....#### +....#...## +#.....##.# +#......... +......##.# +.#.#..#..# +.........# +#..#.#.#.# + +Tile 2357: +.......#.. +...#..#... +.......#.. +.#...#.### +#.####...# +.#.#.....# +#.#.....#. +.###..##.# +#.#.#...#. +##.#.##### + +Tile 1373: +.#.....### +..#...##.. +..#......# +...#...#.# +.#..#.#..# +......#... +#...##..#. +#...#..##. +...#...... +##.#.#...# + +Tile 3373: +...##.#.## +#......... +....#....# +#..###...# +#...#...## +......#.## +........#. +.......##. +#..#...#.. +.##..#.#.. + +Tile 1831: +...#####.# +#........# +#.....#..# +#.#...###. +...#.##..# +..##.....# +..#....#.. +......##.# +##...#.... +##.###.#.# + +Tile 3607: +#...#.#... +.#...##.## +.#.......# +..####.... +####....#. +.#.#...#.# +###...##.. +#......#.. +###.#..#.# +##.##..### + +Tile 3251: +##.#..##.. +.#....##.# +#.......#. +..#..#..#. +#..##....# +#...##..## +.....#..## +...#...##. +....##.... +#####...## + +Tile 3917: +.##....... +.#..#...#. +....##...# +#.#..##.## +.#.#...#.. +..#....... +.....#..#. +.#..#.#..# +...##..#.# +##..#...## + +Tile 1489: +.##..##.#. +##...#.#.# +#.......#. +##.#.....# +.#...##..# +..#....... +.#..#....# +###..#..## +#..##..... +#######... + +Tile 3253: +#..#..#### +....#..#.. +#.##..#... +.##....### +........## +.......... +#...#..... +##...#...# +...##..... +.##..##.#. + +Tile 2081: +.......##. +#...#....# +#..#....## +##....##.. +#.#.###... +.....#.... +#...###.## +##..##.... +#........# +.#...#..#. + +Tile 1481: +######..#. +###.#....# +.....#...# +#......... +#..#....## +#........# +.......... +#...#....# +#..#.##... +#####..##. + +Tile 2953: +..##.##### +#.#..#..## +..#....#.# +#...#.#... +#..##....# +#.#....#.# +.......#.# +#..##..... +#.#.....## +...##..#.# + +Tile 1783: +.#..#.#.## +#...#....# +...#...... +#.#.#..#.# +.........# +......#... +.#...#..## +..#...#.#. +#..#..#..# +...#..#.## + +Tile 2269: +#.#.##..#. +#.....##.. +.#.......# +..#..#...# +....#..... +.......... +##.##....# +.....#.... +##.....### +.#.#####.# + +Tile 1277: +..##..#... +#...#..... +.......#.. +...#...... +....#....# +..#....... +#......#.. +.#........ +#......... +###.###... + +Tile 2633: +####.#.#.. +......#.#. +........#. +#......... +...#...### +...#.....# +.##.#..#.# +.#........ +#.#......# +.##.##.#.# + +Tile 3919: +###..###.. +...#...... +...##.#..# +#...#..#.# +.........# +...#.#.#.. +...#.#.... +#....#...# +.#.###..## +.#.#.##... + +Tile 1753: +#...##.... +#.....#... +.......... +.#..#..... +#.......## +..#....... +......#..# +#..####... +....#..#.# +..#.####.. + +Tile 3739: +.##.#.#..# +###.##.##. +##.###.#.. +.#....#..# +#...##.... +#..#...... +#....###.# +..#....... +###....#.# +...###..#. + +Tile 3701: +.####..#.# +#.....#... +.#........ +.........# +...#.#.... +#.#....... +#...#....# +.###.#.##. +#.#....... +##.##..##. + +Tile 3631: +#..#..###. +.........# +#...##.... +.......#.# +.....#.... +...#..#..# +........#. +..#....#.# +......#... +##.#..#.#. + +Tile 2389: +..#.##...# +###....... +#..##...## +#.######.. +..#..##... +.#...#...# +.....#...# +#..#....#. +..#...##.. +#...#..##. + +Tile 1123: +.##.#.###. +#........# +#......... +#.....##.# +....#..... +....##.#.# +....#....# +#.#.#..#.# +#..#.....# +#.#..#..#. + +Tile 2659: +#.##.#.##. +.#........ +#....#..## +###..##.## +#.#.###..# +#...##...# +...#...#.. +...#..#... +..#.#.#..# +####...#.. + +Tile 3709: +.##...#.## +..#..##..# +......#.## +......#..# +....#..... +.......... +#......#.# +#....##..# +.....##..# +####.##... + +Tile 2887: +######..## +#......... +.......#.# +...#.#.... +#....##... +#...#....# +...#.#...# +#....#...# +##....#..# +#########. + +Tile 1367: +#.####.### +#......#.# +.......... +#....#.... +.#......#. +#......... +...#.#.#.. +......#... +##....#... +.....##.## + +Tile 2221: +##..#..... +#.....#... +.........# +#..#...... +#.#...#... +###......# +...#.....# +#........# +#.....#... +..##.###.. + +Tile 2621: +##..#.###. +.......### +.........# +..#.#...#. +.......... +....#..... +#.##..##.. +......#..# +....#...#. +##.#.....# + +Tile 2503: +..#.##.##. +......#... +#.#..#.... +....#....# +#.....#... +..#......# +##...#..#. +#....#..#. +...#...... +#....####. + +Tile 3491: +#..#.###.. +#......... +#..#..#..# +###....### +#.#.##.... +#........# +......#... +##...#...# +##........ +.#.#.##.## + +Tile 2333: +..##.....# +.....#..#. +#.#.#..#.# +##.##...#. +..#.#..... +...#.....# +..###..#.. +###.....## +#........# +##.####.#. + +Tile 2399: +.....#.##. +##.....#.# +##.......# +.#.#..##.# +#...##...# +###.#....# +#......#.. +##......#. +#.#....#.. +.....#.#.. + +Tile 2683: +#.##..##.. +.#....#..# +.........# +.......#.# +.##.#..##. +.....##..# +#....##..# +....##.#.# +...###.### +.#.##.#.## + +Tile 1741: +.##..#.#.# +.##....#.. +##..#..... +##...###.. +......#..# +#.....#... +.......#.. +#.....#... +...##..#.# +#..###.##. + +Tile 3539: +.###....## +.......... +.##.#...#. +.....#...# +.........# +.........# +.......#.. +..#.....#. +.#.#.###.# +#.#.####.# + +Tile 3929: +##..###### +.#..##.### +#.##....#. +...##..#.# +#...#..... +........#. +.....#...# +#...#.#..# +.#.#.....# +..##.#..#. + +Tile 3221: +..####..#. +##......#. +..#..#.### +##........ +....#....# +.#...#...# +#.#...#..# +##....#..# +##......#. +.#..#..##. + +Tile 1117: +.##.##.#.# +##.....### +#.#.#.##.. +..#....#.. +##....#... +...#..##.# +..#.#.#..# +...#...#.# +....##...# +.###.#..## + +Tile 3163: +.####.#.#. +#......... +.......... +......#..# +....##.#.. +.#....#..# +.....####. +#....#.#.. +...#.#..## +##.#.#.... + +Tile 1129: +.....##... +##......## +#..#..#..# +..#....#.. +#.#...#... +....#.##.. +...#...#.. +#......... +#..#..#.#. +#.#..###.# + +Tile 3079: +###..#.##. +....###... +##..#....# +....##...# +......##.. +....#....# +#.#.#..... +#...#....# +.#........ +.##.#.###. + +Tile 2039: +.#.#.##..# +..##...... +.##....... +#......... +....#...## +#..#.#...# +.......... +#.....#..# +####..#..# +.#..#..##. + +Tile 1901: +####.#.##. +#.#...##.. +...#....## +.......... +#......... +#...##...# +.......... +##......## +.#.....#.. +.###.##... + +Tile 2029: +####..##.. +##...#.... +.#....##.# +..#....##. +#........# +.......... +.......... +#..#..#... +#..#....## +....####.. + +Tile 1879: +##..#.##.# +#...#...## +.##...#.## +.#.#.....# +.##.#..#.# +#..##..... +#..##...#. +......#.## +...#..#..# +#....#..#. + +Tile 3347: +###..#..## +.#..#....# +.#...#...# +....#....# +.#......## +......##.# +.....#..## +.........# +#......#.. +.####.#..# + +Tile 2417: +####.#..## +...#.#.... +.#....#..# +.#........ +#......... +.....#.... +#..##..... +#..#...#.# +#..#.##..# +..##..#### + +Tile 2897: +...#..#.## +#.#....... +.........# +#.#.#..#.. +..#....... +.........# +.##...#..# +....#..### +.###...##. +.#.#.#.#.. + +Tile 2837: +.#....###. +.......#.. +......#..# +#..#..#.## +#.#.##...# +#...#....# +...##.#.#. +#.....#..# +#.#.....#. +#####.#### + +Tile 3001: +##....#..# +#....#.#.. +.....##..# +.....##..# +...#...... +#.....#..# +#.#...##.# +.#...#...# +........#. +###.####.# + +Tile 2153: +.####.##.. +#..#.....# +..#....#.. +#......#.# +.........# +.###.....# +#.##.....# +#..#...... +#.#....... +.######..# + +Tile 2749: +..##.###.. +#..#...#.. +..##.....# +###....... +#..##..... +......#..# +..#..##... +.###.....# +#.#....... +...#..#..# + +Tile 2791: +..##.##.#. +.##.###.#. +.#..#....# +.##..#.#.# +#..#....#. +......##.. +#.##.#.#.# +##...#.##. +.#...#.#.. +...#.#...# + +Tile 2707: +..###...## +.#....#... +..#...##.. +#.#....... +....#....# +#.....#... +.........# +##.....### +#........# +#.##.##### + +Tile 2969: +..#####..# +.......... +#.....#..# +....#.#..# +...#...... +..##.#...# +...#.#.... +...#.....# +..#....... +####..##.# + +Tile 3329: +#.###..#.. +...#....#. +........#. +.........# +###.#..#.# +.#.......# +.........# +.......#.. +#....##..# +##.###.#.. + +Tile 3989: +.#####.### +#....#.#.. +.........# +.........# +##.#...#.# +......#..# +...#.....# +###......# +.#.......# +.###.##.#. + +Tile 3583: +..#..#.#.. +.#........ +###...##.. +##.....#.. +##.......# +#......... +#......... +#...#..#.# +##.#...... +#......... + +Tile 3931: +....#..#.. +#.#.#..... +..#..#..#. +.##...##.# +.......#.# +.........# +....#...## +......#..# +#.#....#.. +#.#.#.##.# + +Tile 1493: +####..##.# +.......... +....#..#.. +##...####. +#......... +#......... +.#.#.....# +....##...# +......##.. +.######### + +Tile 1013: +#.###....# +....####.# +...#.####. +.......##. +.#..#....# +#......... +#......#.. +...#...#.. +#.....#... +#.#.#####. + +Tile 2089: +.#...#.##. +..#...#..# +........#. +...#.#..#. +.....##..# +#...###... +#....#.#.. +#....#..#. +#...###..# +........## + +Tile 1613: +#.#...#### +#.....#... +#....##..# +#....#.... +.#....#... +#........# +......#.#. +#.....#... +##...#...# +....#..##. + +Tile 3331: +.#.#.##### +.....#...# +.......#.. +##..#...#. +#........# +......#..# +..#.#....# +.......#.. +..#....... +###.###..# + +Tile 3217: +..#.###... +#.##...... +..#...##.. +...#.##..# +###...###. +#...#.#.#. +##.#...#.. +.........# +.....##... +##.###.... + +Tile 3011: +#.##.#.... +....#...## +.......... +#........# +#....#...# +#..#...... +.......... +.........# +....##.... +##.####... + +Tile 1171: +###..###.# +..#.....## +##.#...#.. +.#.......# +.......... +##.....##. +.##.....## +..#...#### +##.##..#.# +#.#.#.#... + +Tile 1933: +#####..#.. +#.#.#.#... +#.#....... +#.#.#..... +.....#...# +#.#....... +.......... +...#..#... +.##....#.. +......#... + +Tile 2141: +#.###...#. +#.....#... +.........# +.....#..#. +#.###..... +#..###.#.. +.....#..#. +....#....# +.#.......# +...##..##. + +Tile 1031: +###...#..# +#.......#. +##.#..#..# +##..#..... +#...#..... +##....#... +#......##. +#......... +......#..# +....#..##. + +Tile 2857: +#.#..#...# +#........# +##.#..#.## +....#.##.. +....#...## +#...#..... +#..#...... +.......### +#...####.# +.#...####. + +Tile 3313: +.#......## +...##..... +.#.##..... +#.#.#..... +#.#..#.... +..#....... +#..#.#...# +#.#......# +##...#.... +..###.##.# + +Tile 1303: +#.##.#.... +#.......## +...#...##. +....##...# +.....#...# +.........# +#..#...#.# +##...##... +...#.#.#.. +....##..## + +Tile 3457: +#...#.#..# +.........# +#.#..#...# +.....#.#.. +........## +...#...... +..##.##... +.......... +....#....# +#...#..#.# + +Tile 3643: +##.##..### +..#.#....# +..##.....# +..#....... +#......... +#......... +#.......#. +......#..# +.#......#. +.###..##.# + +Tile 2803: +#...#..##. +##....#.## +.#.......# +#...###... +#...###..# +#..#...... +.......#.# +#.......#. +...##..... +..#..##.## + +Tile 2549: +.#....#### +.#........ +.....###.. +.....#..## +..#.###... +......#... +.........# +.......##. +#......#.# +..###.#### + +Tile 3571: +#..#.##... +...#....#. +..##..##.. +....#.##.# +.#.....#.. +.##...#... +.##......# +#.#......# +......#... +.#..#..#.. + +Tile 1327: +#..###...# +#....#...# +#.##...#.# +#.......#. +#.#...#..# +.........# +##........ +....#..#.. +.....#..#. +.#.###..## + +Tile 2833: +##...#..#. +##....#..# +##.#.....# +.......#.. +###...#..# +.........# +#.#....### +....##.#.. +..#...#... +..#.#.#.## + +Tile 1997: +##..#...## +#...#..... +#.....#... +.......#.. +.......#.# +#......... +#......#.. +.........# +..#.#.#..# +.###.##..# + +Tile 3673: +..#..###.. +.#..##.... +#.##.....# +.####..### +##..#..#.. +#.#.#...## +.#....#.#. +....#.##.. +#...#....# +..#.##.... + +Tile 3323: +.#...##### +#..#...#.# +.......... +#....#...# +.#........ +#........# +##......## +...##...#. +...#.#..## +#.##.###.# + +Tile 1619: +#..###.### +#...##...# +.#........ +#.#.....#. +#.##.....# +#......#.. +.......#.. +#####.#..# +.......... +####...#.. + +Tile 2477: +.##.##..#. +#.#.#..... +......#..# +......#.#. +##.##..... +.###.#..#. +.........# +...#.#.... +#.....#... +...##.#... + +Tile 3389: +#...#.#.## +##.#.....# +......#..# +#..#.#...# +#....#..#. +##......## +....#...## +#.##..##.. +#........# +...##.#.## + +Tile 1193: +.##...###. +#...##..#. +###....... +#.#..#.... +.#..#.#... +#..##....# +#.#..##... +####.....# +#...#..#.. +..##.....# + +Tile 3767: +#...#..... +...#.#..#. +#######... +...#.#.... +#......... +.#....##.. +#.#....... +.#.#.#..#. +..#.###..# +....##.#.. + +Tile 3191: +#.##...#.. +.......... +......#### +#..#..#... +....#.#.## +......#.#. +.....#.... +.#....##.# +..#..#.#.# +#...##.#.# + +Tile 3049: +#...#...#. +.#..#....# +##.#.....# +...#...##. +#.##.....# +.....#.#.. +..##..##.. +.......... +#....#.#.# +#.##.#..#. + +Tile 1747: +###....#.. +....#..#.# +.......#.. +........#. +#..#...... +.......### +...#.##... +.....#..## +.#....#... +.##..####. + +Tile 1429: +...#.#.#.. +.#...#.... +.......... +##........ +#......... +#..#.#.... +.##....... +.#........ +.##.#.#..# +#####.##.# + +Tile 2909: +#.##.###.. +#..#.....# +#...#..... +.#..#.##.. +#.#.....#. +#...#...## +...#...#.. +.##.....## +##..#..#.# +#.###..### + +Tile 1973: +#####.#.#. +...#.....# +#......... +#........# +.....###.. +.......... +.#.....#.# +.##..#.##. +##.#..#... +#.##...#.# + +Tile 3449: +.#.#.#..#. +#...#.#... +..#.##.... +#...###... +.....#...# +#.......#. +##....#.## +......#..# +#.......#. +..####.... + +Tile 3371: +##.#..#.#. +#...##...# +##...##... +.#....#... +#...##...# +..#......# +......#..# +##.###...# +#....#...# +.##....#.. + +Tile 1103: +####..#..# +.......#.. +#......#.# +.......... +.#....##.. +.#.##...## +##....##.# +..#..#.### +.......... +.#.#...#.# + +Tile 1723: +.#....###. +...#.#...# +..#.#..... +#####....# +.#.#...... +....#..#.. +..#....... +..##...#.# +....###... +...##.#.#. + +Tile 1093: +..##.#.### +.##....... +#....#.... +.#.....#.. +#.......## +.........# +.#......## +#......#.# +#..#.#...# +#.#####.#. + +Tile 1321: +#.#.###.#. +.#..##..#. +#.###..#.. +#..##....# +#.......#. +....#....# +#....#...# +.....#.... +#.###..... +.###...##. + +Tile 1979: +#####.###. +#.#..#..#. +#.####.... +###.....## +....#..... +#......... +###.#..#.# +..##...### +#.......## +..#....... + +Tile 2677: +##..#.##.# +#.##.....# +#..#...#.# +..#.#.#..# +##.#..#..# +.....#..#. +#...#...## +...#...### +##.#...#.. +.###..##.. + +Tile 1553: +.#...###.. +.........# +###....... +##..#...#. +..#...##.# +..##...... +.##....... +...#..#... +#....##... +#####.#... + +Tile 3187: +###..#..#. +#.....#... +.....#..## +#.....#..# +..#......# +##...#.... +......##.# +......#... +#.#..#.... +########.# + +Tile 2243: +##.####... +..#.#.#..# +#..#...... +.........# +....#...## +#......... +#......#.# +....#....# +......#.## +##.#....#. + +Tile 1423: +..#..##..# +..#....#.# +#.#.....## +##.......# +.#..#..#.. +......##.. +##...##... +.....##..# +...#.#.#.# +##...###.. + +Tile 3319: +##.##.#.#. +#.......#. +....#..... +###....### +........#. +###....... +.#.....##. +#...#....# +..#....... +.##...#### + +Tile 3343: +.#...##### +.......... +.###...#.# +.##....... +.......... +##....#### +#......#.# +#.#.###..# +..#....... +.#####..#. + +Tile 2789: +##....#### +.##....... +#......#.# +.#.##..... +#......#.# +#........# +##......#. +.#...##... +#.....##.# +...###.#.. + +Tile 3623: +##..#..#.# +#.....#.#. +##.....#.# +.#...##..# +.#.......# +..#...#..# +.#..#..##. +###..#.### +.#.##.#..# +.#.##.#.#. + +Tile 1439: +.#..#.#.#. +....#..... +.........# +#..#...... +##..#....# +#.#.#.##.. +##.#.#...# +#......... +#.......#. +####...#.# + +Tile 1361: +#.#...###. +#......... +....#..... +..#....... +......#..# +##....##.# +.##..#..## +..#......# +.....##..# +#..#....#. + +Tile 1823: +.##.#.#... +#......... +#..#.##.#. +#...##.... +##........ +#...#.#.## +#........# +.........# +........#. +#.###...#. + +Tile 2971: +.#.......# +#.#....#.. +#..#.#.... +...#..#... +##....#... +#..#...... +.........# +....##.... +#...###..# +#...#.#.#. + +Tile 3229: +..###.#### +#........# +.#.......# +.......... +##.......# +#..#...... +.#.#...... +#.....##.# +.#......#. +.#####.#.# + +Tile 1907: +####.#.#.. +....#....# +#....#.... +#......... +#...#..### +...#.#.#.# +....##.... +#.###..### +..#..##.## +..##.##... + +Tile 1699: +..#..##... +.#..#.#... +.....#...# +.#.#.#...# +........#. +##.....#.. +#.#......# +.##......# +....###.#. +...##..### + +Tile 2131: +#..#####.. +#....#...# +#..####..# +......#..# +#.#..#...# +#.#...#..# +..##...... +#.#####..# +......#..# +#...####.# + +Tile 1657: +..#..##.#. +#....##... +##..#....# +#........# +#......... +#.......## +#......### +#.#.#...## +........## +#.##.#.##. + diff --git a/inputs/day20_test.txt b/inputs/day20_test.txt new file mode 100644 index 0000000..b07aa4b --- /dev/null +++ b/inputs/day20_test.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/src/bin/satellite.rs b/src/bin/satellite.rs new file mode 100644 index 0000000..eea5672 --- /dev/null +++ b/src/bin/satellite.rs @@ -0,0 +1,702 @@ +use advent2020::errors::{TileParseError, TopLevelError}; +#[cfg(test)] +use std::collections::HashMap; +use std::env; +use std::fmt; +use std::fs; +use std::str::FromStr; + +#[derive(Clone)] +struct Tile { + identity: usize, + history: Vec, + top: u16, + bottom: u16, + left: u16, + right: u16, + edge_length: usize, + raw_data: Vec, +} + +impl PartialEq for Tile { + fn eq(&self, other: &Self) -> bool { + self.identity == other.identity && self.raw_data == other.raw_data + } +} + +impl fmt::Display for Tile { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.identity)?; + let mut prefix = ':'; + for mvmt in self.history.iter() { + write!(f, "{}{:?}", prefix, mvmt)?; + prefix = '+'; + } + Ok(()) + } +} + +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +enum Modification { + FlippedX, + FlippedY, + Rotated, +} + +impl Tile { + fn new(identity: usize, history: Vec, edge_length: usize, raw_data: Vec) -> Tile { + let mut res = Tile { + identity, + history, + top: 0, + bottom: 0, + left: 0, + right: 0, + edge_length, + raw_data, + }; + + for i in 0..edge_length { + res.top = (res.top << 1) | res.get_value(i, 0); + res.bottom = (res.bottom << 1) | res.get_value(i, edge_length-1); + res.left = (res.left << 1) | res.get_value(0, i); + res.right = (res.right << 1) | res.get_value(edge_length-1, i); + } + + res + } + + fn read<'a, I: Iterator>(lines: &mut I) -> Result, TileParseError> { + match lines.next() { + None => Ok(None), + Some("") => Tile::read(lines), + Some(x) if x.starts_with("Tile ") => { + let identity = usize::from_str(&x[5..x.len() - 1])?; + let mut edge_length = 0; + let mut raw_data = Vec::new(); + + for line in lines { + if line == "" { + break; + } + + for char in line.chars() { + match char { + '.' => raw_data.push(false), + '#' => raw_data.push(true), + _ => return Err(TileParseError::IllegalCharacter(char)), + } + } + + edge_length += 1; + } + + if raw_data.len() != (edge_length * edge_length) { + return Err(TileParseError::IllegalDimensions(identity)); + } + + Ok(Some(Tile::new(identity, vec![], edge_length, raw_data))) + } + Some(other) => Err(TileParseError::BadTileStart(other.to_string())), + } + } + + fn get(&self, x: usize, y: usize) -> bool { + self.raw_data[(y * self.edge_length) + x] + } + + fn get_value(&self, x: usize, y: usize) -> u16 { + if self.get(x, y) { + 1 + } else { + 0 + } + } + + fn set(&mut self, x: usize, y: usize, v: bool) { + self.raw_data[(y * self.edge_length) + x] = v; + } + + fn draw(&self) { + println!("Tile {} [{:?}]:", self.identity, self.history); + for y in 0..self.edge_length { + for x in 0..self.edge_length { + if self.get(x, y) { + print!("#"); + } else { + print!("."); + } + } + println!(); + } + } + + fn flip_over_x(&self) -> Tile { + let mut raw_data = Vec::with_capacity(self.edge_length * self.edge_length); + let reverser = self.edge_length - 1; + + for y in 0..self.edge_length { + for x in 0..self.edge_length { + raw_data.push(self.get(x, reverser - y)) + } + } + + let mut new_history = self.history.clone(); + new_history.push(Modification::FlippedX); + Tile::new(self.identity, new_history, self.edge_length, raw_data) + } + + fn flip_over_y(&self) -> Tile { + let mut raw_data = Vec::with_capacity(self.edge_length * self.edge_length); + let reverser = self.edge_length - 1; + + for y in 0..self.edge_length { + for x in 0..self.edge_length { + raw_data.push(self.get(reverser - x, y)) + } + } + + let mut new_history = self.history.clone(); + new_history.push(Modification::FlippedY); + Tile::new(self.identity, new_history, self.edge_length, raw_data) + } + + fn rotate(&self) -> Tile { + let mut res = self.clone(); + + res.history.push(Modification::Rotated); + for x in 0..self.edge_length { + for y in 0..self.edge_length { + res.set(self.edge_length - 1 - y, x, self.get(x, y)); + } + } + + Tile::new(res.identity, res.history, res.edge_length, res.raw_data) + } + + fn variants(self) -> Vec { + let mut res = vec![]; + let mut new_elements = vec![self]; + + while !new_elements.is_empty() { + res.append(&mut new_elements); + + for current in res.iter() { + let flip_x = current.flip_over_x(); + if !res.contains(&flip_x) && !new_elements.contains(&flip_x) { + new_elements.push(flip_x); + } + + let flip_y = current.flip_over_y(); + if !res.contains(&flip_y) && !new_elements.contains(&flip_y) { + new_elements.push(flip_y); + } + + let rotated = current.rotate(); + if !res.contains(&rotated) && !new_elements.contains(&rotated) { + new_elements.push(rotated); + } + } + } + + res + } + + fn can_be_left_of(&self, other: &Tile) -> bool { + self.identity != other.identity && self.right == other.left + } + + fn can_be_right_of(&self, other: &Tile) -> bool { + self.identity != other.identity && self.left == other.right + } + + fn can_be_above(&self, other: &Tile) -> bool { + self.identity != other.identity && self.bottom == other.top + } + + fn can_be_below(&self, other: &Tile) -> bool { + self.identity != other.identity && self.top == other.bottom + } +} + +#[test] +fn flip_x_test() { + let raw_data = vec![ + true, false, true, false, + true, true, true, true, + false, false, true, true, + false, false, false, false, + ]; + let edge_length = 4; + let identity = 1; + let original = Tile::new(identity, vec![], edge_length, raw_data); + let flipped = vec![ + false, false, false, false, + false, false, true, true, + true, true, true, true, + true, false, true, false, + ]; + + assert_eq!(flipped, original.flip_over_x().raw_data); +} + +#[test] +fn flip_y_test() { + let raw_data = vec![ + true, false, true, false, + true, true, true, true, + false, false, true, true, + false, false, false, false, + ]; + let edge_length = 4; + let identity = 1; + let original = Tile::new(identity, vec![], edge_length, raw_data); + let flipped = vec![ + false, true, false, true, + true, true, true, true, + true, true, false, false, + false, false, false, false, + ]; + + assert_eq!(flipped, original.flip_over_y().raw_data); +} + +#[test] +fn rotate_test() { + let original = Tile::new(0, vec![], 3, vec![true, true, true, false, false, false, true, true, true]); + let rotated = vec![true, false, true, true, false, true, true, false, true]; + assert_eq!(rotated, original.rotate().raw_data); +} + +#[test] +fn next_to_tests() { + let contents = fs::read_to_string("inputs/day20_test.txt").unwrap(); + let mut lines = contents.lines(); + let mut tiles = HashMap::new(); + + while let Some(new_tile) = Tile::read(&mut lines).unwrap() { + tiles.insert(new_tile.identity, new_tile); + } + + let tile1951 = tiles.get(&1951).unwrap().flip_over_x(); + let tile2729 = tiles.get(&2729).unwrap().flip_over_x(); + let tile2971 = tiles.get(&2971).unwrap().flip_over_x(); + let tile2311 = tiles.get(&2311).unwrap().flip_over_x(); + let tile1427 = tiles.get(&1427).unwrap().flip_over_x(); + let tile1489 = tiles.get(&1489).unwrap().flip_over_x(); + let tile3079 = tiles.get(&3079).unwrap().clone(); + let tile2473 = tiles.get(&2473).unwrap().flip_over_y().rotate(); + let tile1171 = tiles.get(&1171).unwrap().flip_over_y(); + + tile1951.draw(); println!(); + tile2729.draw(); println!(); + tile2971.draw(); println!(); + tile2311.draw(); println!(); + tile1427.draw(); println!(); + tile1489.draw(); println!(); + tile3079.draw(); println!(); + tile2473.draw(); println!(); + tile1171.draw(); println!(); + + // above tests + assert!(tile1951.can_be_above(&tile2729)); + assert!(tile2729.can_be_above(&tile2971)); + assert!(tile2311.can_be_above(&tile1427)); + assert!(tile1427.can_be_above(&tile1489)); + assert!(tile3079.can_be_above(&tile2473)); + assert!(tile2473.can_be_above(&tile1171)); + + // below tests + assert!(tile2729.can_be_below(&tile1951)); + assert!(tile2971.can_be_below(&tile2729)); + assert!(tile1427.can_be_below(&tile2311)); + assert!(tile1489.can_be_below(&tile1427)); + assert!(tile2473.can_be_below(&tile3079)); + assert!(tile1171.can_be_below(&tile2473)); + + // left tests + assert!(tile1951.can_be_left_of(&tile2311)); + assert!(tile2729.can_be_left_of(&tile1427)); + assert!(tile2971.can_be_left_of(&tile1489)); + assert!(tile2311.can_be_left_of(&tile3079)); + assert!(tile1427.can_be_left_of(&tile2473)); + assert!(tile1489.can_be_left_of(&tile1171)); + + // right tests + assert!(tile2311.can_be_right_of(&tile1951)); + assert!(tile1427.can_be_right_of(&tile2729)); + assert!(tile1489.can_be_right_of(&tile2971)); + assert!(tile3079.can_be_right_of(&tile2311)); + assert!(tile2473.can_be_right_of(&tile1427)); + assert!(tile1171.can_be_right_of(&tile1489)); +} + +#[derive(Clone)] +struct Board { + edge_length: usize, + raw_data: Vec>, +} + +impl Board { + fn new(original_tile_count: usize, all_variants: Vec) -> Board { + let mut edge_length = 1; + + while edge_length * edge_length < original_tile_count { + edge_length += 1; + } + + let mut raw_data = Vec::with_capacity(original_tile_count); + raw_data.resize(original_tile_count, all_variants); + + Board { + edge_length, + raw_data, + } + } + + fn get(&self, x: usize, y: usize) -> &[Tile] { + &self.raw_data[ (y * self.edge_length) + x ] + } + + fn set(&mut self, x: usize, y: usize, v: Vec) { + self.raw_data[ (y * self.edge_length) + x ] = v; + } + + fn print_status(&self) { + for y in 0..self.edge_length { + for x in 0..self.edge_length { + print!("{}\t", self.get(x, y).len()); + } + println!(); + } + } + + fn reduce(&mut self) -> bool { + let mut removed_something = false; + + for x in 0..self.edge_length { + for y in 0..self.edge_length { + let mut new_possibles = Vec::new(); + + for possible in self.get(x, y) { + let mut all_ok = true; + + if x > 0 { + all_ok &= self.get(x-1, y).iter().any(|other| possible.can_be_right_of(other)); + } + + if y > 0 { + all_ok &= self.get(x, y-1).iter().any(|other| possible.can_be_below(other)); + } + + if x + 1 != self.edge_length { + all_ok &= self.get(x+1, y).iter().any(|other| possible.can_be_left_of(other)); + } + + if y + 1 != self.edge_length { + all_ok &= self.get(x, y+1).iter().any(|other| possible.can_be_above(other)); + } + + if all_ok { + new_possibles.push(possible.clone()); + } else { + removed_something = true; + } + } + + self.set(x, y, new_possibles); + } + } + + removed_something + } + + fn solve(&mut self) -> Result { + // first, let's find the spot in the board with the fewest possibilities + let mut split_x = 0; + let mut split_y = 0; + let mut possibilities = 0xfffffffffffffff; + + for x in 0..self.edge_length { + for y in 0..self.edge_length { + if self.get(x,y).len() < possibilities { + split_x = x; + split_y = y; + possibilities = self.get(x,y).len(); + } + } + } + + for split_value in self.get(split_x, split_y).iter() { + let mut possible_board = self.clone(); + possible_board.set(split_x, split_y, vec![split_value.clone()]); + while possible_board.reduce() {} + if possible_board.raw_data.iter().all(|x| x.len() == 1) { + let mut idents: Vec = possible_board.raw_data.iter().map(|x| x[0].identity).collect(); + let orig_length = idents.len(); + idents.sort(); + idents.dedup(); + if idents.len() == orig_length { + return Ok(possible_board); + } + } + } + + Err(TopLevelError::NoSolutionFound) + } +} + +#[derive(Clone, PartialEq)] +struct Image { + width: usize, + height: usize, + raw_data: Vec, +} + +#[derive(Clone, Copy, Debug, PartialEq)] +enum Pixel { + Empty, + Block, + Monster, +} + +impl fmt::Display for Pixel { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Pixel::Empty => write!(f, "."), + Pixel::Block => write!(f, "#"), + Pixel::Monster => write!(f, "O"), + } + } +} + +impl From for Image { + fn from(b: Board) -> Image { + let board_edge_length = b.edge_length; + let tile_edge_length = b.raw_data[0][0].edge_length; + let chunk_edge_length = tile_edge_length - 2; + let edge_length = board_edge_length * chunk_edge_length; + let mut raw_data = Vec::with_capacity(edge_length * edge_length); + let width = edge_length; + let height = edge_length; + + raw_data.resize(edge_length * edge_length, Pixel::Empty); + let mut result = Image { width, height, raw_data }; + + for board_y in 0..board_edge_length { + for board_x in 0..board_edge_length { + let board = &b.get(board_x, board_y)[0]; + + for inner_y in 0..chunk_edge_length { + for inner_x in 0.. chunk_edge_length { + let pixel_value = if board.get(inner_x + 1, inner_y + 1) { + Pixel::Block + } else { + Pixel::Empty + }; + + result.set((board_x * chunk_edge_length) + inner_x, + (board_y * chunk_edge_length) + inner_y, + pixel_value); + } + } + } + } + + result + } +} + +impl Image { + fn sea_monster() -> Image { + let data = " # # ## ## ### # # # # # # "; + let raw_data = data.chars().map(|x| { + match x { + ' ' => Pixel::Empty, + '#' => Pixel::Monster, + _ => panic!("the world broke"), + } + }).collect(); + Image { + width: 20, + height: 3, + raw_data, + } + } + + fn get(&self, x: usize, y: usize) -> Pixel { + self.raw_data[(y * self.width) + x] + } + + fn set(&mut self, x: usize, y: usize, v: Pixel) { + self.raw_data[(y * self.width) + x] = v; + } + + fn draw(&self) { + for y in 0..self.height { + for x in 0..self.width { + print!("{}", self.get(x, y)); + } + println!(); + } + } + + fn overwrite(&mut self, x: usize, y: usize, image: &Image) { + for ix in 0..image.width { + for iy in 0..image.height { + if image.get(ix, iy) == Pixel::Monster { + self.set(x + ix, y + iy, Pixel::Monster); + } + } + } + } + + fn overlay(&mut self, image: &Image) -> usize { + let mut monsters_found = 0; + + for x in 0..=(self.width-image.width) { + for y in 0..=(self.height-image.height) { + let mut all_match = true; + + for ix in 0..image.width { + for iy in 0..image.height { + all_match &= image.get(ix,iy) != Pixel::Monster || self.get(x+ix,y+iy) != Pixel::Empty; + } + } + + if all_match { + self.overwrite(x, y, &image); + monsters_found += 1; + } + } + } + + monsters_found + } + + fn flip_over_x(&self) -> Image { + let mut raw_data = Vec::with_capacity(self.height * self.width); + let reverser = self.height - 1; + + for y in 0..self.height { + for x in 0..self.width { + raw_data.push(self.get(x, reverser - y)) + } + } + + Image { + height: self.height, + width: self.width, + raw_data + } + } + + fn flip_over_y(&self) -> Image { + let mut raw_data = Vec::with_capacity(self.height * self.width); + let reverser = self.width - 1; + + for y in 0..self.height { + for x in 0..self.width { + raw_data.push(self.get(reverser - x, y)) + } + } + + Image { + height: self.height, + width: self.width, + raw_data + } + } + + fn rotate(&self) -> Image { + let mut res = self.clone(); + + for x in 0..self.width { + for y in 0..self.height { + res.set(self.width - 1 - y, x, self.get(x, y)); + } + } + + res + } + + fn variants(self) -> Vec { + let mut res = vec![]; + let mut new_elements = vec![self]; + + while !new_elements.is_empty() { + res.append(&mut new_elements); + + for current in res.iter() { + let flip_x = current.flip_over_x(); + if !res.contains(&flip_x) && !new_elements.contains(&flip_x) { + new_elements.push(flip_x); + } + + let flip_y = current.flip_over_y(); + if !res.contains(&flip_y) && !new_elements.contains(&flip_y) { + new_elements.push(flip_y); + } + + let rotated = current.rotate(); + if !res.contains(&rotated) && !new_elements.contains(&rotated) { + new_elements.push(rotated); + } + } + } + + res + } + + fn blocks(&self) -> usize { + self.raw_data.iter().filter(|x| x == &&Pixel::Block).count() + } +} + +fn main() -> Result<(), TopLevelError> { + let filename = env::args().nth(1).expect("No file argument given."); + let contents = fs::read_to_string(filename)?; + let mut lines = contents.lines(); + let mut tiles = Vec::new(); + let mut num_originals = 0; + + while let Some(new_tile) = Tile::read(&mut lines)? { + let mut new_tiles = new_tile.variants(); + tiles.append(&mut new_tiles); + num_originals += 1; + } + + if num_originals == 0 { + return Err(TopLevelError::NoInputFound); + } + + let mut board = Board::new(num_originals, tiles); + board.print_status(); + while board.reduce() { + println!("---"); + board.print_status(); + } + let final_value = board.solve()?; + let tl = final_value.get(0,0)[0].identity; + let tr = final_value.get(final_value.edge_length-1,0)[0].identity; + let bl = final_value.get(0,final_value.edge_length-1)[0].identity; + let br = final_value.get(final_value.edge_length-1,final_value.edge_length-1)[0].identity; + + println!(); + println!("Part 1 result:{} * {} * {} * {} = {}", tl, tr, bl, br, tl * tr * bl * br); + println!(); + let mut base_image = Image::from(final_value); + base_image.draw(); + println!("---------------------"); + let sea_monster = Image::sea_monster(); + sea_monster.draw(); + println!("---------------------"); + for image in base_image.variants().iter_mut() { + if image.overlay(&sea_monster) > 0 { + image.draw(); + println!("Blocks left: {}", image.blocks()); + } + } + Ok(()) +} + diff --git a/src/errors.rs b/src/errors.rs index 97dc3a7..5b16ab7 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -56,6 +56,8 @@ pub enum TopLevelError { TicketParseError(#[from] TicketParseError), #[error("Bad rule parse: {0}")] GrammarParseError(#[from] GrammarParseError), + #[error("Bad tile parse: {0}")] + TileParseError(#[from] TileParseError), } #[derive(Error, Debug)] @@ -208,3 +210,17 @@ pub enum GrammarParseError { #[error("Duplicate rule definition for {0}")] DuplicateRule(usize), } + +#[derive(Error, Debug, PartialEq)] +pub enum TileParseError { + #[error("No tile identifier found")] + NoTileIdentifier, + #[error("Illegal character: '{0}'")] + IllegalCharacter(char), + #[error("Illegal tile identifier: {0}")] + IllegalTileIdentifier(#[from] ParseIntError), + #[error("Illegal tile dimensions for tile {0}")] + IllegalDimensions(usize), + #[error("Weird start to tile: {0}")] + BadTileStart(String), +}