diff --git a/2020.csproj b/2020.csproj
index a5e3b15..f2f965e 100644
--- a/2020.csproj
+++ b/2020.csproj
@@ -62,6 +62,9 @@
PreserveNewest
+
+ PreserveNewest
+
PreserveNewest
diff --git a/20input.txt b/20input.txt
new file mode 100644
index 0000000..8ee1319
--- /dev/null
+++ b/20input.txt
@@ -0,0 +1,1727 @@
+Tile 2729:
+.....#####
+##..##.#.#
+......#.##
+#....#.#.#
+#......##.
+#...#..#.#
+#.........
+.......##.
+#.#..#....
+#.#.###..#
+
+Tile 3673:
+##.....###
+.....##...
+#.......#.
+..#..##.##
+...##.#...
+...#......
+..#...#..#
+..........
+##..#.#..#
+####.#.#.#
+
+Tile 2797:
+#######..#
+###..#.#.#
+#...#.....
+....#...#.
+....#...#.
+#...##....
+....#....#
+#..#......
+.#........
+#.#.....##
+
+Tile 3779:
+....###..#
+#..#......
+...##.....
+#.#..#...#
+..##.#....
+##.##....#
+#.........
+.....#...#
+#.###...#.
+.#####.#.#
+
+Tile 3217:
+...###.###
+#....#..##
+#.......#.
+......#..#
+#...##..##
+##..#....#
+#...####.#
+..#..##...
+..#.##...#
+#..#.###..
+
+Tile 3137:
+.#..#.#.#.
+#.......#.
+###...#..#
+#.#...#...
+.....#.#.#
+..#..#....
+#...#.#.##
+..#......#
+..#...#...
+###.##.##.
+
+Tile 2857:
+...##..##.
+.........#
+#........#
+.#.....#..
+#..#..#...
+#...#.#.#.
+##....####
+#.....##.#
+...#..#...
+..####....
+
+Tile 1831:
+#.##..####
+.#.#.#...#
+#..##.....
+#..#....#.
+#.##......
+...#....#.
+......#..#
+..........
+####..#...
+####.###..
+
+Tile 2423:
+...#.##..#
+#...##...#
+##......##
+...#.#....
+#.....#...
+#.....#..#
+.#..####..
+.##...#.##
+..##.#..#.
+#..#..####
+
+Tile 3221:
+..#.##.###
+#.#.......
+#...#....#
+...#...#..
+#..#.#...#
+....###..#
+.........#
+.........#
+#...#.##.#
+##..##.###
+
+Tile 2707:
+.##.#.#...
+.#.##..#.#
+#...#.....
+#.#.......
+#...#.....
+..#......#
+.......###
+..#.#...#.
+#.#.......
+..#...#.##
+
+Tile 3041:
+#.####...#
+##.....#..
+..#.#..###
+#.###..###
+.#.#.....#
+#....#....
+..##......
+.###....#.
+###.##.#..
+#####.##.#
+
+Tile 1627:
+.###..#..#
+.#..#.##..
+##...#...#
+#....###.#
+..#......#
+#....#..#.
+#.##.....#
+.##..#...#
+..#...#..#
+...#.###.#
+
+Tile 1237:
+...##..###
+#.#......#
+#.##..#..#
+#.#.....#.
+#....#...#
+...#....#.
+#.#....#..
+.##.......
+..#..#..##
+.###.#.#.#
+
+Tile 1187:
+#...###...
+#.###.#...
+..##...#..
+##.....#..
+.....#...#
+#.....#...
+....#..#.#
+.........#
+.#...#....
+.####.#.##
+
+Tile 1361:
+.#.##..###
+......#..#
+....#.#..#
+.#.......#
+#.#.....##
+.#.#..##..
+##.##....#
+#.##..#.##
+#.#......#
+.##..##...
+
+Tile 2087:
+###.#.....
+.#...#....
+.#..#.....
+####.....#
+...#.....#
+...##.....
+##..###..#
+....##..#.
+.#.####...
+...#..####
+
+Tile 1129:
+###.#.#...
+#.##..###.
+.....#....
+#...#..#..
+#.#.###.#.
+.##..###..
+#...##..##
+.....#...#
+#........#
+...#..####
+
+Tile 1093:
+.....##.##
+#.......##
+.##.#.##.#
+#.#..####.
+#....#....
+###......#
+#.#.......
+#..#.....#
+#..#.#.#..
+#..#....#.
+
+Tile 3049:
+##...#..##
+#........#
+#......#..
+.....#.###
+#........#
+#..#.#....
+#........#
+....#.....
+..##.....#
+##.#..##.#
+
+Tile 2399:
+##...#.##.
+...#......
+#.#.##...#
+##.......#
+#.........
+#.........
+.....##..#
+#....#....
+.........#
+.....##.##
+
+Tile 3371:
+##....##..
+.....##...
+##.##.#.##
+......###.
+##..####.#
+..#..##..#
+.....#...#
+#..#..#..#
+.##.#...##
+.####..###
+
+Tile 3343:
+#......##.
+.##.#.#..#
+#...#.##.#
+.##..##...
+.#.#....##
+##.#..#...
+#....#.#.#
+.....##..#
+#.....##.#
+.##.#....#
+
+Tile 2393:
+.####.#.#.
+.#..##....
+.##..#.#..
+#....#....
+#...##.##.
+.#...#...#
+#..#......
+....#.##.#
+#....##..#
+.#..###.#.
+
+Tile 1621:
+##..###..#
+##.....#..
+#.#....###
+.##..#.#.#
+#.........
+#......#.#
+#.#.......
+.#........
+#.#......#
+....####.#
+
+Tile 3181:
+#...#.####
+...#.#...#
+..........
+....#..#..
+##........
+......####
+#.#..#..##
+..........
+..#....##.
+...###...#
+
+Tile 2441:
+.#..#..#..
+#....##...
+.#...#.#..
+#...##..#.
+...#..###.
+.....#.#.#
+#...#...#.
+#...##...#
+#......#.#
+#...##..##
+
+Tile 2389:
+.#...#.#..
+.........#
+..........
+###.......
+....#.#...
+....#.##..
+#.....##.#
+..#.......
+#.##.....#
+#...###.##
+
+Tile 1847:
+#.###.#..#
+#.#...#.#.
+#.......##
+#...#..#.#
+..###.#..#
+...##....#
+#....#...#
+##...#...#
+.###...#..
+.#.#.####.
+
+Tile 1871:
+.###.##...
+#.......#.
+#.......#.
+#.....#..#
+..##...#.#
+##.....###
+.....###..
+#....###.#
+##.##..#..
+###...####
+
+Tile 3877:
+#.....#.#.
+..##....##
+###......#
+#...###...
+.##...##..
+.#...#....
+..#....#.#
+#.........
+...#..#...
+#..###.#..
+
+Tile 3517:
+###..##.#.
+...###...#
+..#......#
+.#.#...#.#
+....#.##.#
+#...#..#..
+...##....#
+#.....###.
+.#..##...#
+........##
+
+Tile 2609:
+#...#..###
+.........#
+...#.#.#..
+#####..#.#
+#.#....#.#
+.......#..
+###..#...#
+..........
+.#...#....
+#.#.....#.
+
+Tile 3001:
+..#...#...
+#........#
+#..#.....#
+.#.#.#...#
+#..##.....
+#.....##..
+#......#.#
+..##...#..
+.#..#.##.#
+#.##.#####
+
+Tile 3067:
+#.#.#.###.
+##....#...
+.#..#.....
+....#.....
+.###..#.##
+.....#....
+.#...##...
+.#.#.##..#
+.....#...#
+#.#.#....#
+
+Tile 1583:
+####....#.
+##.#....##
+##..#....#
+#...#.##..
+....##....
+###.##...#
+#..#..##.#
+.###.....#
+.#.##....#
+..#.####.#
+
+Tile 1741:
+#.#.#####.
+....#.....
+#.#......#
+..##...###
+......#...
+#........#
+..##...###
+#.#...####
+####.#....
+.#..#.#.#.
+
+Tile 1933:
+#####..###
+#...#..#..
+.##...#..#
+.......###
+##........
+..#...##..
+.....#..##
+#....#....
+#.....#.#.
+....##..#.
+
+Tile 3697:
+#..#.#####
+...#..##..
+#.....#...
+.#..#.##..
+......#...
+#......#..
+##....#..#
+.##.....#.
+#.#..#....
+#..##...##
+
+Tile 1429:
+##.....#..
+###.#...##
+#.....#..#
+#...###..#
+....#.....
+##.#...#..
+#....##...
+.##.#..#..
+..#.#.#..#
+#.#.###...
+
+Tile 1721:
+##..#.#..#
+...#.#....
+##...#.#.#
+##..#....#
+.##.#....#
+#..#.#....
+#.##.#....
+##.....#..
+..#..###..
+..###.#..#
+
+Tile 1867:
+.##.####.#
+#.##....#.
+#....#....
+##..#..#..
+##.#..#..#
+.......#..
+##........
+..#...##.#
+....#..#.#
+..###.#.##
+
+Tile 2143:
+##..##.#..
+#.........
+..#.#..###
+.#.#..#...
+.#######..
+....#....#
+##.##.#..#
+......##..
+..#.#.##.#
+..#...#..#
+
+Tile 1657:
+......#..#
+#.##..###.
+.#.....#.#
+.#......##
+#.####...#
+...#.#....
+#.#....###
+#.....##.#
+....#....#
+#..#..#...
+
+Tile 2719:
+#####..#..
+#.....###.
+.##....###
+..#.##....
+#..##.....
+.......###
+#.....#...
+..#...##..
+.#..##.#.#
+..####....
+
+Tile 2803:
+###..###..
+.#..#...##
+#.....#...
+#.#.###...
+##..#....#
+#...#..#.#
+...##...##
+......####
+.......##.
+.###.#..##
+
+Tile 3929:
+.#.#####.#
+##...#....
+...#.#.#.#
+.#......#.
+.......#..
+##....##.#
+...#...#..
+.......###
+.........#
+..##..##.#
+
+Tile 1321:
+.#.#...#.#
+.......#..
+...#.####.
+#.........
+..#.#.#.##
+##....#...
+..........
+#.##...#..
+#....#...#
+#######.##
+
+Tile 1153:
+.#...#.###
+#........#
+#...#...#.
+#.....#..#
+#........#
+#.#.....##
+.....##...
+#..#...#..
+#.....#..#
+##.#..##.#
+
+Tile 3803:
+#.####...#
+#.##..#...
+##..#.....
+.##.....#.
+..#...#...
+#.##.#.#..
+##.....#.#
+##.#..#..#
+##..#..#..
+....##..##
+
+Tile 2791:
+.#....####
+#.....#...
+#.#.##...#
+..#.#.#..#
+##..#....#
+#....#..##
+...#.##..#
+......#..#
+#....#.#..
+#.###.#.#.
+
+Tile 3529:
+.#...#...#
+.....#..#.
+#........#
+.........#
+.##.##.#..
+##.......#
+#...#...##
+.......#..
+...#.##..#
+#.#####...
+
+Tile 3257:
+####.#.###
+.##...##..
+..#....#..
+..###..#.#
+#.#..#...#
+.......##.
+##.##.####
+.....##..#
+#....##...
+###..###.#
+
+Tile 1531:
+#.#...#...
+.........#
+##...#...#
+##......##
+...#.....#
+#.#.###..#
+#....#...#
+.#....#.#.
+#...#....#
+#########.
+
+Tile 3413:
+#...#.....
+...###..##
+##..##....
+.#..##....
+#..#.#.#..
+...#.....#
+....#..#.#
+...#....##
+...#.#...#
+#.###..#.#
+
+Tile 1117:
+#.#.##...#
+.........#
+.........#
+#....#..##
+#.#.##..#.
+#......#..
+#.#.#.#...
+#..#.....#
+......#.#.
+..##.#..#.
+
+Tile 1499:
+.#####..##
+...#...###
+.........#
+#..#.....#
+##......##
+#.......#.
+#......##.
+#####.....
+.#.....#..
+.###..####
+
+Tile 1787:
+.######..#
+#....#.#.#
+........#.
+#.....#...
+..........
+..#..#.###
+#.#..#...#
+.#.#.#####
+.....#.#.#
+##.#.##.##
+
+Tile 1949:
+##..####.#
+##.#......
+.........#
+....#..#.#
+.#...##..#
+....#..#..
+#.....#...
+##....#..#
+.....#..#.
+.#.#.#.#.#
+
+Tile 2161:
+####.#..#.
+#.......#.
+.##....#.#
+.###..#..#
+#.#..#....
+#..#..#...
+#...#.#.##
+#...#.##.#
+###....#..
+#...#.##.#
+
+Tile 2953:
+#.#...#.##
+#.#.#...##
+#.......##
+.........#
+#..#.....#
+..#.##.#..
+..#.###..#
+##.....#..
+......#...
+###.#.#.#.
+
+Tile 1039:
+##..###..#
+#.....#...
+#....#.#.#
+#...#...##
+##.......#
+#.....#..#
+...#.....#
+.#.###...#
+.........#
+#.#..#####
+
+Tile 2027:
+##.####..#
+..#.....#.
+#.#.##...#
+.#.......#
+.....#.###
+#........#
+.#.#.....#
+#.#...#.#.
+#.###...#.
+..##.##...
+
+Tile 1889:
+..####.##.
+#....#.#.#
+##.#..##.#
+#..#...###
+##...#..##
+#..##...#.
+#..#.###.#
+#.###.#...
+##...##...
+##.##..###
+
+Tile 3557:
+##.##.#...
+.....#.#.#
+#.#..#....
+##..###..#
+....##...#
+....#....#
+.#..#...#.
+.#.#.##..#
+###..#...#
+#.#.#..#..
+
+Tile 2549:
+....#..#..
+#..#..#.##
+.....#...#
+#..##.#.#.
+.#.##....#
+.#..#....#
+.#.#...#..
+##.....#..
+..........
+#....#...#
+
+Tile 1543:
+.##.###.##
+....#.#..#
+#.........
+...#.#...#
+#.......#.
+.....##...
+....#.....
+..###.#..#
+###..#....
+###.#.###.
+
+Tile 2417:
+.#....#.#.
+#.#..###.#
+....##....
+##.....#.#
+..........
+#....#..##
+.....#...#
+#.#......#
+#........#
+###..##..#
+
+Tile 3541:
+.##..###..
+##...##.##
+##..#....#
+.........#
+...#.#....
+...#.....#
+#..#...#..
+..........
+.#..##.#.#
+..##.#..##
+
+Tile 1931:
+.##...##.#
+...#.....#
+#...###...
+#.......#.
+#.......##
+.#.#.#....
+##..#....#
+##...#..##
+..........
+....#.#.#.
+
+Tile 2833:
+.#...#....
+#..####...
+.#...##.##
+.#.......#
+#.#...#..#
+..#.....##
+#......#..
+##....#..#
+......#..#
+##..##...#
+
+Tile 3301:
+###.#.####
+..###.##..
+..........
+.#....##..
+#.#..##...
+..#....#.#
+.#.#..#...
+#.#..#...#
+....#.##.#
+......##.#
+
+Tile 3671:
+##.#..#...
+.##....###
+##.....#..
+###.#.#.#.
+....#...##
+#.....#..#
+#.#......#
+.......###
+#..#.....#
+...#.###.#
+
+Tile 1609:
+..##..#.##
+###..##...
+.#..#..#..
+#....#.#..
+#..#.##.#.
+#.......#.
+.....#...#
+#.....#..#
+......##..
+###..##...
+
+Tile 2957:
+###..#####
+###.......
+#..#.....#
+#.#......#
+#.....#..#
+#.#.......
+###.#..#.#
+.#.#.##.#.
+###.#.#...
+...##.####
+
+Tile 2467:
+##.#.#.#..
+........#.
+....#...#.
+#.......#.
+..#...#..#
+...#.#...#
+#...###.##
+#.##.#.#..
+.#...##...
+..#.####..
+
+Tile 1907:
+###..###.#
+#...#....#
+...#..#..#
+.......#.#
+........##
+##...#..##
+#..#.##...
+#....#.#.#
+#......###
+###.....#.
+
+Tile 2251:
+##...#..##
+#..#.##..#
+..#.#..###
+##........
+.......#..
+.#..#.#...
+#..#.#..#.
+#..#......
+###.#...##
+#.###.##..
+
+Tile 2657:
+.#..##..##
+##.#....##
+#.#...#...
+#..#......
+#........#
+#.........
+..#....#..
+#.........
+#.........
+##.###.###
+
+Tile 2671:
+#.#.#.##.#
+.#..#..#.#
+.#.......#
+#...#..#..
+.....###.#
+#.....#..#
+#.#......#
+#........#
+#....#....
+####.#..#.
+
+Tile 3121:
+..#..#...#
+#....#...#
+....###.#.
+#........#
+..####....
+.......###
+#..#.####.
+##.#.###.#
+.####..#..
+#.#...#..#
+
+Tile 1021:
+#####.####
+#....#...#
+####....#.
+#......#..
+##..#...##
+##.#.#..##
+#.....#.#.
+#.#...##.#
+.#......##
+.#.##...#.
+
+Tile 1019:
+...#.##..#
+#........#
+.........#
+##....#...
+#..#..##.#
+........#.
+.....##...
+#..##....#
+#.....#.#.
+.##.####..
+
+Tile 2099:
+#.##..###.
+#..#......
+#.##...#.#
+...##..##.
+#...#.....
+.#.....#.#
+.....#..#.
+.....##...
+#...##..##
+##.#####.#
+
+Tile 1297:
+.###..####
+##...###.#
+..#..##..#
+#...#.....
+...#....##
+#....#...#
+###.##.#..
+#.........
+......#.##
+..#.##..#.
+
+Tile 1993:
+####..#.#.
+.#.#.#....
+#...#.##.#
+#.....#..#
+..#..#.#..
+#.#.#...#.
+.#..#...#.
+##...##..#
+..#...##.#
+#..#.##.#.
+
+Tile 2617:
+..#.#.#.##
+.##.####..
+#.#..####.
+....#.#..#
+#.#.#.#.##
+...#......
+##......##
+.#...#.#..
+#..#...#.#
+.###.#..#.
+
+Tile 1009:
+##.#....#.
+#.#.#...#.
+#.#....#..
+......#..#
+####......
+....#...##
+......#..#
+.......#..
+##.....#..
+..#...#.#.
+
+Tile 2203:
+#.#.###.##
+#.#...##.#
+....#.##.#
+#..#......
+.#....#..#
+......#...
+##.##....#
+#...#...#.
+##.##....#
+#..#..#.##
+
+Tile 3467:
+....##.##.
+#...#..#..
+##....#...
+#.......##
+#.........
+...#....##
+#...#.....
+##.#.#.#.#
+...##.#..#
+#...#.....
+
+Tile 3617:
+##..####.#
+#...#.#..#
+.......#.#
+..........
+.......#..
+...#...###
+#.#.......
+#.........
+.....##...
+##.#.###..
+
+Tile 1601:
+.#..####.#
+.....##...
+#.....##.#
+#...###..#
+##....#...
+##......#.
+#.#.....#.
+##.......#
+#.......##
+..##.#.#..
+
+Tile 2699:
+.#...#...#
+#.##...##.
+..........
+#.##..#.#.
+...#..#..#
+...#.##..#
+#.#..#..##
+.#...###..
+.#.......#
+##..###.##
+
+Tile 1231:
+#.....##..
+#..#.....#
+###..#.#.#
+..######..
+...##....#
+#..#...#.#
+.....#...#
+#.##..####
+..#.#.....
+.###.##..#
+
+Tile 3373:
+###...#...
+.##..#...#
+.#.#.....#
+........#.
+....#.....
+#....#....
+##.....#.#
+###.......
+#......#.#
+#.#..#####
+
+Tile 1901:
+##.##..##.
+##...#..##
+......#..#
+.#.#......
+#.###.#..#
+##.#.#.#..
+........##
+#....#..#.
+.....#...#
+.#..##....
+
+Tile 1213:
+...#.#.#.#
+#.##...#..
+.#.##.####
+.....####.
+##.##....#
+#..#...#..
+....#.....
+##........
+##..##....
+###...#...
+
+Tile 3163:
+#.....#.#.
+###.#..#..
+......#...
+#..#.#....
+##....#.#.
+##.#..##..
+#.##.#..##
+.#........
+.#...#....
+.....#.##.
+
+Tile 2053:
+.###.#...#
+#.....#...
+#..#.#..##
+##.......#
+#..#....##
+....###..#
+#.#..#...#
+#.##.#.#..
+.#..#..#.#
+#.......##
+
+Tile 3229:
+......#...
+#...#....#
+##....#..#
+.#..#.##.#
+..####.#.#
+###.......
+##....#...
+#..#...#.#
+........#.
+.#.###.###
+
+Tile 3271:
+#....#.###
+#.......#.
+#......#..
+.###..##.#
+....#..#..
+.....#..##
+.#...#....
+........##
+.......##.
+#..####.##
+
+Tile 2003:
+..#.#....#
+.##..#...#
+#.........
+#.........
+#.........
+#.##...#..
+#..#..##.#
+.......#..
+##.......#
+..#####..#
+
+Tile 3637:
+##.##.####
+....#.#..#
+##.#...#.#
+....###.##
+..........
+.##.###.#.
+#.###.....
+......#...
+..##.....#
+##.#######
+
+Tile 3967:
+#..#.####.
+###..#....
+#.........
+#..#..#..#
+#..#.....#
+..#...#...
+..###.#.#.
+#..#.....#
+.#......#.
+...##.#..#
+
+Tile 2621:
+...##.###.
+...#.....#
+#.#.##....
+#.#.......
+##.#.#.#..
+...#....##
+.......###
+..##....##
+#.#..#....
+#####...#.
+
+Tile 3347:
+####..##..
+#.#.##....
+...#.##...
+....##.#.#
+####...###
+..##..#..#
+......#..#
+#....#.#..
+#....##..#
+.#.#.#...#
+
+Tile 1319:
+#..###...#
+#..##.#..#
+#........#
+##...#.#.#
+#.##....#.
+.....#.#.#
+#...#....#
+.....#...#
+#.........
+.#.##.....
+
+Tile 1279:
+##.....###
+##...#....
+#....#..##
+#...##...#
+...#.###.#
+.#........
+#.....##.#
+...#.....#
+..###.....
+#.#.#..##.
+
+Tile 1861:
+.##...#.#.
+#....####.
+..........
+#.#...#..#
+###.####..
+#......#.#
+.......#.#
+#.#.#.#..#
+##.....#.#
+....##..##
+
+Tile 2861:
+.#.######.
+..#.#..##.
+#.##......
+....#.#...
+........##
+#....##...
+......#...
+#.#.......
+#.#....#..
+#######..#
+
+Tile 1879:
+#..#.....#
+#........#
+#..#####..
+#.#..#..#.
+#........#
+.#....##.#
+.##.....##
+...#.....#
+.##......#
+..###.##.#
+
+Tile 1291:
+......##..
+.#.....###
+...#.#....
+#....#.#.#
+###.......
+....#.....
+.#.#.#.#..
+.#.##....#
+#..#.#....
+##..##..#.
+
+Tile 1109:
+#....##.##
+#.##....##
+..#......#
+.........#
+..#.##.#..
+#........#
+##.#.....#
+##....#...
+.......###
+##...#.#.#
+
+Tile 2333:
+......#..#
+##..####..
+..#.......
+#.........
+#.#.##...#
+#.........
+#.......#.
+#.##.#..##
+.#..#..#..
+###..##..#
+
+Tile 2081:
+####...#.#
+.....#....
+.....##..#
+.#..#..#.#
+#.........
+..##.#...#
+.......###
+.#..#.....
+#......##.
+#.#.#.#.##
+
+Tile 1489:
+#..##.#..#
+..#.#.#.#.
+...#......
+#........#
+#.#.#.....
+.#.#.#.#.#
+#.##......
+#.#.##.#.#
+#.#......#
+.#..#..#.#
+
+Tile 3931:
+##.###.#.#
+#........#
+#.....#..#
+.###......
+......##.#
+#..#...###
+..#......#
+#..#......
+#....##...
+###.###.##
+
+Tile 1249:
+.###.###.#
+#.##...###
+...#.#....
+#...#..#..
+......#..#
+#......###
+##..#...#.
+..##.....#
+#..#.#....
+##....####
+
+Tile 2381:
+#...#....#
+.#...##..#
+##...##..#
+...#.#...#
+#..##.#...
+.##..#.##.
+.....####.
+#..#..##.#
+##...##...
+.##.######
+
+Tile 1747:
+.####..#.#
+#........#
+....#....#
+#.....####
+##..#.#..#
+###.##..##
+.##...#...
+..##......
+#....###..
+.#####..##
+
+Tile 2687:
+#.#.....#.
+.........#
+#..#...#.#
+..........
+#......##.
+..#...##..
+##.##...##
+##.#...##.
+......#..#
+.#.#....#.
+
+Tile 1327:
+.###.#####
+.......#.#
+#..#..#.#.
+#...#..#..
+.......#..
+..#.#.....
+#........#
+.##....#..
+..###.#..#
+#..#.##.##
+
+Tile 3727:
+#.#..#...#
+..#.#....#
+.##.###.#.
+#.........
+##.#...#.#
+##.#....##
+.##...#...
+......#..#
+........#.
+#....##.##
+
+Tile 2341:
+.##.#.####
+...#....#.
+.#.....#.#
+.....#....
+#.#.###.#.
+##.##.....
+#...#.....
+..#.#..#..
+........#.
+#.##......
+
+Tile 1439:
+#..#.#..##
+.......#..
+....#..##.
+..#..#.#..
+.....#...#
+.#..#.##..
+#...#..#.#
+#.#......#
+.#..#.....
+##.#...#.#
+
+Tile 2351:
+..###...##
+#....###..
+.#....#..#
+.#...#....
+.#.......#
+..#....##.
+#..#.....#
+#.......#.
+##..#..#.#
+...#..##..
+
+Tile 2269:
+.#####...#
+#........#
+#.......##
+#.#....#..
+..##.....#
+.#..#..#.#
+##...##...
+#......###
+...#......
+#.#.###.#.
+
+Tile 2887:
+.#.##.#.##
+.#....#...
+#.....#..#
+#.##...#.#
+#...#.#.##
+##.##.#...
+##.#.##..#
+.#.##..#..
+......#..#
+.#.#.##...
+
+Tile 3391:
+.####....#
+.#..#..###
+....#...#.
+...#..#.##
+#....#..##
+#...#..##.
+#..####.#.
+..####..##
+..##.....#
+...#.#..##
+
+Tile 3533:
+.#....#..#
+#.........
+..#..#..##
+.#.##.#..#
+#...#.....
+......##..
+...#.#.#.#
+#.....##..
+..........
+##.##..#..
+
+Tile 1637:
+.#.#.#.##.
+#.#.....##
+.#....#...
+##.......#
+.##.###.##
+##.#......
+..#.....#.
+.###...#.#
+........#.
+#.##...#.#
+
+Tile 3323:
+..#.#.#.#.
+#.#.....#.
+#.##..#.##
+##.......#
+#.#....#.#
+.##......#
+.#..#..#..
+..#..##..#
+...##.....
+##.##.##.#
+
+Tile 1559:
+##.##.#..#
+.....#.#..
+#.#.####..
+...#.#...#
+##....#..#
+#.##...#..
+.#..##.###
+....#..#..
+.#.#.#.#.#
+#....#..#.
+
+Tile 2039:
+..#.######
+.#...#...#
+###.#.....
+##..###..#
+.#...##...
+..#..#...#
+#.....#.#.
+....#.....
+.###.....#
+..##.#.###
+
+Tile 3677:
+####......
+.......#..
+#.........
+........#.
+.....###.#
+#...#.###.
+##........
+....##..##
+.#....#...
+.##..##.#.
+
+Tile 1973:
+#.###..##.
+#.........
+#......###
+#.#...####
+#.#..#.#.#
+..#..#..#.
+#..#.#.#.#
+##.##..#..
+#.###...##
+##.#.##.#.
+
+Tile 2309:
+####..##.#
+#..#..#..#
+...#.#...#
+#....###.#
+##....#.#.
+....##....
+......#...
+##..#.....
+#....#..#.
+.##.#....#
+
+Tile 2237:
+.##......#
+#.#....##.
+...###..#.
+#.#....###
+.....#...#
+#.##.....#
+#..#...#..
+.#...#..##
+#.#....##.
+....#.#.#.
+
+Tile 2663:
+##..##.###
+#..#..##..
+#...##...#
+#.#.#..#.#
+#..#......
+....#..#.#
+...#...###
+##........
+##....#.#.
+.#...##.#.
+
+Tile 1571:
+##.#.#...#
+.##.##.###
+........##
+#.........
+#.#...##..
+#.......#.
+##..#####.
+#..#...##.
+##......#.
+..#..##..#
+
+Tile 3011:
+#.#.#...##
+....##.#.#
+#...##...#
+#........#
+.#....#...
+......#...
+#.#.#..#..
+..#####...
+#.###.....
+.......#.#
+
+Tile 3457:
+##.##..#.#
+###.##....
+.#.#...#..
+##.......#
+.....#.##.
+#.#.##.#.#
+.###.#####
+..#.......
+.##.....##
+....#.###.
+
+Tile 1619:
+#..#...#..
+#.....#.#.
+#..#..##..
+.....#....
+#.#...#...
+.#..#....#
+#....##.##
+.....##.#.
+......####
+#.#.#.##..
+
+Tile 1663:
+..#..###.#
+#...#.#..#
+#...#.....
+###..##...
+..#.#.....
+..........
+#.#....##.
+..#....###
+#..#..#.#.
+###.#.##..
diff --git a/Program.cs b/Program.cs
index 2df1647..0165408 100644
--- a/Program.cs
+++ b/Program.cs
@@ -22,6 +22,7 @@
Q15.Go();
Q18.Go();
Q19.Go();
+ Q20.Go();
Q21.Go();
Q22.Go();
Util.Log($"Total time={(System.DateTime.Now - start).TotalMilliseconds}ms");
diff --git a/Q20.cs b/Q20.cs
new file mode 100644
index 0000000..cd7657e
--- /dev/null
+++ b/Q20.cs
@@ -0,0 +1,345 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+
+namespace _2020
+{
+ class Q20
+ {
+ static readonly List list = new List();
+ const int TileSize = 10;
+
+ [DebuggerDisplay("{ID}")]
+ private class Tile
+ {
+ public enum SideName { Top, TopReverse, Left, LeftReverse, Bottom, BottomReverse, Right, RightReverse }
+ public int ID { get; private set; }
+ public char[,] Data = new char[TileSize, TileSize];
+ public bool IsPlaced { get; set; }
+ public IEnumerable Sides => Enum.GetValues(typeof(SideName)).Cast().Select(n => GetSide(n));
+
+ public Tile(int id, string[] lines)
+ {
+ ID = id;
+ for (int i = 0; i < lines.Length; i++)
+ {
+ for (int j = 0; j < lines[i].Length; j++)
+ {
+ Data[i, j] = lines[i][j];
+ }
+ }
+ }
+
+ public int GetSide(SideName name)
+ {
+ return name switch
+ {
+ SideName.Top => ParseNumber(new string(Enumerable.Range(0, TileSize).Select(r => Data[0, r]).ToArray())),
+ SideName.TopReverse => ParseNumber(new string(Enumerable.Range(0, TileSize).Select(r => Data[0, r]).Reverse().ToArray())),
+ SideName.Left => ParseNumber(new string(Enumerable.Range(0, TileSize).Select(r => Data[r, 0]).ToArray())),
+ SideName.LeftReverse => ParseNumber(new string(Enumerable.Range(0, TileSize).Select(r => Data[r, 0]).Reverse().ToArray())),
+ SideName.Bottom => ParseNumber(new string(Enumerable.Range(0, TileSize).Select(r => Data[TileSize - 1, r]).ToArray())),
+ SideName.BottomReverse => ParseNumber(new string(Enumerable.Range(0, TileSize).Select(r => Data[TileSize - 1, r]).Reverse().ToArray())),
+ SideName.Right => ParseNumber(new string(Enumerable.Range(0, TileSize).Select(r => Data[r, TileSize - 1]).ToArray())),
+ SideName.RightReverse => ParseNumber(new string(Enumerable.Range(0, TileSize).Select(r => Data[r, TileSize - 1]).Reverse().ToArray())),
+ _ => -1,
+ };
+ }
+
+ public void Rotate()
+ {
+ RotateSquareCW(ref Data);
+ }
+
+ public void FlipHorizontally()
+ {
+ Data = FlipH(Data);
+ }
+
+ public void FlipVertically()
+ {
+ Data = FlipV(Data);
+ }
+
+ public int Matches(IEnumerable tiles)
+ {
+ return tiles.Count(t => t.ID != ID && t.Sides.Any(s => Sides.Contains(s)));
+ }
+
+ private static int ParseNumber(string text)
+ {
+ return Convert.ToInt32(text.Replace('#', '1').Replace('.', '0'), 2);
+ }
+ }
+
+ static void RotateSquareCW(ref char[,] source)
+ {
+ var n = source.GetLength(0);
+ for (int i = 0; i < n / 2; i++)
+ {
+ for (int j = i; j < n - i - 1; j++)
+ {
+ var temp = source[i, j];
+ source[i, j] = source[n - 1 - j, i];
+ source[n - 1 - j, i] = source[n - 1 - i, n - 1 - j];
+ source[n - 1 - i, n - 1 - j] = source[j, n - 1 - i];
+ source[j, n - 1 - i] = temp;
+ }
+ }
+ }
+
+ static char[,] FlipH(char[,] source)
+ {
+ var numRows = source.GetLength(0);
+ var numCols = source.GetLength(1);
+ char[,] temp = new char[numRows, numCols];
+ for (int row = 0; row < numRows; row++)
+ {
+ for (int col = 0; col < numCols; col++)
+ {
+ temp[row, numCols - col - 1] = source[row, col];
+ }
+ }
+
+ return temp;
+ }
+
+ static char[,] FlipV(char[,] source)
+ {
+ var numRows = source.GetLength(0);
+ var numCols = source.GetLength(1);
+ char[,] temp = new char[numRows, numCols];
+ for (int row = 0; row < numRows; row++)
+ {
+ for (int col = 0; col < numCols; col++)
+ {
+ temp[numRows - row - 1, col] = source[row, col];
+ }
+ }
+
+ return temp;
+ }
+
+ public static void Go()
+ {
+ var start = DateTime.Now;
+ MakeList();
+ Util.Log($"Q20 MakeList took {(DateTime.Now - start).TotalMilliseconds}ms");
+ var p1start = DateTime.Now;
+ Part1();
+ Util.Log($"Q20 part1 took {(DateTime.Now - p1start).TotalMilliseconds}ms");
+ var p2start = DateTime.Now;
+ Part2();
+ Util.Log($"Q20 part2 took {(DateTime.Now - p2start).TotalMilliseconds}ms");
+
+ Util.Log($"Q20 took {(DateTime.Now - start).TotalMilliseconds}ms");
+ }
+
+ static void MakeList()
+ {
+ string[] currTile = new string[TileSize];
+ int tileNum = 0;
+ int rowNum = 0;
+ foreach (var line in File.ReadAllLines("20input.txt"))
+ {
+ if (string.IsNullOrWhiteSpace(line))
+ {
+ list.Add(new Tile(tileNum, currTile));
+ currTile = new string[TileSize];
+ rowNum = 0;
+ }
+ else if (line.StartsWith("Tile"))
+ {
+ tileNum = Convert.ToInt32(line["Tile ".Length..^1]);
+ }
+ else
+ {
+ currTile[rowNum] = line;
+ rowNum++;
+ }
+ }
+
+ list.Add(new Tile(tileNum, currTile));
+ }
+
+ static int CountMonsters(char[,] input)
+ {
+ var count = 0;
+ for (int col = 0; col < input.GetLength(1) - monster.GetLength(1); col++)
+ {
+ for (int row = 0; row < input.GetLength(0) - monster.GetLength(0); row++)
+ {
+ if (HasMonster(input, row, col))
+ {
+ count++;
+ }
+ }
+ }
+
+ return count;
+ }
+
+ static readonly char[,] monster = new char[3, 20]
+ {
+ { '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '#', '.' },
+ { '#', '.', '.', '.', '.', '#', '#', '.', '.', '.', '.', '#', '#', '.', '.', '.', '.', '#', '#', '#' },
+ { '.', '#', '.', '.', '#', '.', '.', '#', '.', '.', '#', '.', '.', '#', '.', '.', '#', '.', '.', '.' },
+ };
+
+ static int MonsterSize
+ {
+ get
+ {
+ int size = 0;
+ for (int i = 0; i < monster.GetLength(0); i++)
+ {
+ for (int j = 0; j < monster.GetLength(1); j++)
+ {
+ if (monster[i, j] == '#')
+ {
+ size++;
+ }
+ }
+ }
+
+ return size;
+ }
+ }
+
+ static bool HasMonster(char[,] grid, int row, int col)
+ {
+ for (int c2 = 0; c2 < 20; c2++)
+ {
+ for (int r2 = 0; r2 < 3; r2++)
+ {
+ if (monster[r2, c2] == '#' && grid[col + c2, row + r2] != '#')
+ {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ static List _corners;
+ static List Corners
+ {
+ get
+ {
+ if (_corners == null)
+ {
+ _corners = list.Where(t => t.Matches(list) == 2).ToList();
+ }
+
+ return _corners;
+ }
+ }
+
+ static void Part1()
+ {
+ Util.Log($"Q20Part1: {Corners.Aggregate(1L, (i, v) => i * v.ID)}");
+ }
+
+ static void Part2()
+ {
+ var sides = new Dictionary>(
+ list.SelectMany(t => t.Sides.Select(s => new { s, t }))
+ .GroupBy(s => s.s)
+ .Where(s => s.Count() > 1)
+ .Select(s => new KeyValuePair>(s.Key, s.Select(i => i.t).ToList()))
+ );
+
+ var gridSize = (int)Math.Sqrt(list.Count);
+ var assembled = new Tile[gridSize, gridSize];
+ for (int col = 0; col < gridSize; col++)
+ {
+ for (int row = 0; row < gridSize; row++)
+ {
+ Tile nextTile;
+ if (col == 0 && row == 0) // Find the corner and orient
+ {
+ nextTile = Corners.First();
+ while (!sides.ContainsKey(nextTile.GetSide(Tile.SideName.Right)) || !sides.ContainsKey(nextTile.GetSide(Tile.SideName.Bottom)))
+ {
+ nextTile.Rotate();
+ }
+ }
+ else if (row == 0) // top row: find the tile that fits to the right of the last one
+ {
+ var lastRight = assembled[row, col - 1].GetSide(Tile.SideName.Right);
+ nextTile = sides[lastRight].Single(e => !e.IsPlaced);
+ // Rotate until the right side is on the left
+ while (nextTile.GetSide(Tile.SideName.Left) != lastRight && nextTile.GetSide(Tile.SideName.LeftReverse) != lastRight)
+ {
+ nextTile.Rotate();
+ }
+ // Flip if necessary
+ if (nextTile.GetSide(Tile.SideName.Left) != lastRight)
+ {
+ nextTile.FlipVertically();
+ }
+ }
+ else // find the tile that fits the one above
+ {
+ var lastBottom = assembled[row - 1, col].GetSide(Tile.SideName.Bottom);
+ nextTile = sides[lastBottom].Single(e => !e.IsPlaced);
+ while (nextTile.GetSide(Tile.SideName.Top) != lastBottom && nextTile.GetSide(Tile.SideName.TopReverse) != lastBottom)
+ {
+ nextTile.Rotate();
+ }
+ if (nextTile.GetSide(Tile.SideName.Top) != lastBottom)
+ {
+ nextTile.FlipHorizontally();
+ }
+ }
+ assembled[row, col] = nextTile;
+ nextTile.IsPlaced = true;
+ }
+ }
+
+ // Extract the final image
+ var imgDimensions = (TileSize - 2) * gridSize;
+ var grid = new char[imgDimensions, imgDimensions];
+ var innerWidth = TileSize - 2;
+ for (int col = 0; col < gridSize; col++)
+ {
+ for (int tileColIdx = 1; tileColIdx < innerWidth + 1; tileColIdx++)
+ {
+ for (int row = 0; row < gridSize; row++)
+ {
+ for (int tileRowIdx = 1; tileRowIdx < innerWidth + 1; tileRowIdx++)
+ {
+ grid[(col * innerWidth) + tileColIdx - 1, (row * innerWidth) + tileRowIdx - 1] = assembled[row, col].Data[tileRowIdx, tileColIdx];
+ }
+ }
+ }
+ }
+
+ var waterCount = grid.Cast().Count(c => c == '#');
+ var roughness = waterCount;
+ var numSides = 4;
+ for (int i = 0; i < numSides * 2; i++)
+ {
+ var count = CountMonsters(grid);
+ if (count > 0)
+ {
+ roughness = waterCount - count * MonsterSize;
+ }
+
+ if (i == numSides)
+ {
+ grid = FlipH(grid);
+ }
+ else
+ {
+ RotateSquareCW(ref grid);
+ }
+ }
+
+ Util.Log($"Q20Part2: roughness={roughness}");
+ }
+ }
+}