Day 20: Part 1 and 2
Signed-off-by: James Griffin <james@unsupervised.ca>
This commit is contained in:
10
main.go
10
main.go
@@ -3,7 +3,7 @@ package main
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/thatguygriff/aoc2020/nineteen"
|
||||
"github.com/thatguygriff/aoc2020/twenty"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -80,6 +80,10 @@ func main() {
|
||||
// fmt.Println(eighteen.PartTwo())
|
||||
|
||||
// Day 19
|
||||
fmt.Println(nineteen.PartOne())
|
||||
fmt.Println(nineteen.PartTwo())
|
||||
// fmt.Println(nineteen.PartOne())
|
||||
// fmt.Println(nineteen.PartTwo())
|
||||
|
||||
// Day 20
|
||||
fmt.Println(twenty.PartOne())
|
||||
fmt.Println(twenty.PartTwo())
|
||||
}
|
||||
|
599
twenty/day_twenty.go
Normal file
599
twenty/day_twenty.go
Normal file
@@ -0,0 +1,599 @@
|
||||
package twenty
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"math"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type tile struct {
|
||||
id int
|
||||
something [][]bool
|
||||
|
||||
edges []string
|
||||
matches map[int]bool
|
||||
}
|
||||
|
||||
type message struct {
|
||||
tiles []tile
|
||||
grid [][]*tile
|
||||
|
||||
image [][]bool
|
||||
}
|
||||
|
||||
func (t *tile) edge(side string) string {
|
||||
border := ""
|
||||
switch side {
|
||||
case "top":
|
||||
for _, c := range t.something[0] {
|
||||
if c {
|
||||
border += "#"
|
||||
} else {
|
||||
border += "."
|
||||
}
|
||||
}
|
||||
case "bottom":
|
||||
for _, c := range t.something[9] {
|
||||
if c {
|
||||
border += "#"
|
||||
} else {
|
||||
border += "."
|
||||
}
|
||||
}
|
||||
case "left":
|
||||
for _, row := range t.something {
|
||||
if row[0] {
|
||||
border += "#"
|
||||
} else {
|
||||
border += "."
|
||||
}
|
||||
}
|
||||
case "right":
|
||||
for _, row := range t.something {
|
||||
if row[9] {
|
||||
border += "#"
|
||||
} else {
|
||||
border += "."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return border
|
||||
}
|
||||
|
||||
func (t *tile) flip() {
|
||||
flipped := [][]bool{}
|
||||
flipped = make([][]bool, 10)
|
||||
for i := 0; i < 10; i++ {
|
||||
flipped[i] = make([]bool, 10)
|
||||
}
|
||||
|
||||
for y := 0; y < 10; y++ {
|
||||
for x := 0; x < 10; x++ {
|
||||
flipped[y][x] = t.something[9-y][9-x]
|
||||
}
|
||||
}
|
||||
|
||||
t.something = flipped
|
||||
}
|
||||
|
||||
func (t *tile) flipY() {
|
||||
flipped := [][]bool{}
|
||||
flipped = make([][]bool, 10)
|
||||
for i := 0; i < 10; i++ {
|
||||
flipped[i] = make([]bool, 10)
|
||||
}
|
||||
|
||||
for y := 0; y < 10; y++ {
|
||||
for x := 0; x < 10; x++ {
|
||||
flipped[y][x] = t.something[9-y][x]
|
||||
}
|
||||
}
|
||||
|
||||
t.something = flipped
|
||||
}
|
||||
|
||||
func (t *tile) rotate() {
|
||||
rotated := [][]bool{}
|
||||
rotated = make([][]bool, 10)
|
||||
for i := 0; i < 10; i++ {
|
||||
rotated[i] = make([]bool, 10)
|
||||
}
|
||||
|
||||
for y := 0; y < 10; y++ {
|
||||
for x := 0; x < 10; x++ {
|
||||
rotated[x][9-y] = t.something[y][x]
|
||||
}
|
||||
}
|
||||
|
||||
t.something = rotated
|
||||
}
|
||||
|
||||
func (m *message) load(filename string) error {
|
||||
file, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
m.tiles = []tile{}
|
||||
|
||||
scanner := bufio.NewScanner(file)
|
||||
var t *tile
|
||||
for scanner.Scan() {
|
||||
if strings.Contains(scanner.Text(), "Tile") {
|
||||
t = &tile{}
|
||||
count, err := fmt.Sscanf(scanner.Text(), "Tile %4d:", &t.id)
|
||||
|
||||
if count != 1 || err != nil {
|
||||
return fmt.Errorf("Unable to parse %s", scanner.Text())
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if scanner.Text() == "" {
|
||||
m.tiles = append(m.tiles, *t)
|
||||
t = nil
|
||||
continue
|
||||
}
|
||||
|
||||
if t != nil {
|
||||
row := []bool{}
|
||||
for _, c := range scanner.Text() {
|
||||
switch string(c) {
|
||||
case ".":
|
||||
row = append(row, false)
|
||||
case "#":
|
||||
row = append(row, true)
|
||||
}
|
||||
}
|
||||
|
||||
t.something = append(t.something, row)
|
||||
}
|
||||
}
|
||||
|
||||
if t != nil {
|
||||
m.tiles = append(m.tiles, *t)
|
||||
}
|
||||
|
||||
for i := 0; i < len(m.tiles); i++ {
|
||||
m.tiles[i].matches = map[int]bool{}
|
||||
m.tiles[i].edges = []string{}
|
||||
m.tiles[i].edges = append(m.tiles[i].edges, m.tiles[i].edge("top"))
|
||||
m.tiles[i].edges = append(m.tiles[i].edges, m.tiles[i].edge("bottom"))
|
||||
m.tiles[i].edges = append(m.tiles[i].edges, m.tiles[i].edge("left"))
|
||||
m.tiles[i].edges = append(m.tiles[i].edges, m.tiles[i].edge("right"))
|
||||
m.tiles[i].flip()
|
||||
m.tiles[i].edges = append(m.tiles[i].edges, m.tiles[i].edge("top"))
|
||||
m.tiles[i].edges = append(m.tiles[i].edges, m.tiles[i].edge("bottom"))
|
||||
m.tiles[i].edges = append(m.tiles[i].edges, m.tiles[i].edge("left"))
|
||||
m.tiles[i].edges = append(m.tiles[i].edges, m.tiles[i].edge("right"))
|
||||
m.tiles[i].flip()
|
||||
}
|
||||
|
||||
gridSize := int(math.Sqrt(float64(len(m.tiles))))
|
||||
m.grid = make([][]*tile, gridSize)
|
||||
for i := 0; i < gridSize; i++ {
|
||||
m.grid[i] = make([]*tile, gridSize)
|
||||
}
|
||||
|
||||
m.image = make([][]bool, gridSize*8)
|
||||
for i := 0; i < gridSize*8; i++ {
|
||||
m.image[i] = make([]bool, gridSize*8)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *message) findCorners() []tile {
|
||||
// Compute neighbours
|
||||
for i := 0; i < len(m.tiles); i++ {
|
||||
for j := 0; j < len(m.tiles); j++ {
|
||||
if i == j {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, iEdge := range m.tiles[i].edges {
|
||||
for _, jEdge := range m.tiles[j].edges {
|
||||
if iEdge == jEdge {
|
||||
m.tiles[i].matches[m.tiles[j].id] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
corners := []tile{}
|
||||
// Find neighbours with only 2 matches
|
||||
for i := 0; i < len(m.tiles); i++ {
|
||||
if len(m.tiles[i].matches) == 2 {
|
||||
corners = append(corners, m.tiles[i])
|
||||
}
|
||||
}
|
||||
|
||||
return corners
|
||||
}
|
||||
|
||||
func (m *message) getTile(id int) *tile {
|
||||
for _, t := range m.tiles {
|
||||
if t.id == id {
|
||||
return &t
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *message) inGrid(id int) bool {
|
||||
for y := 0; y < len(m.grid); y++ {
|
||||
for x := 0; x < len(m.grid); x++ {
|
||||
if m.grid[y][x] != nil {
|
||||
if id == m.grid[y][x].id {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (m *message) layout() bool {
|
||||
corners := m.findCorners()
|
||||
for i := range corners {
|
||||
m.grid[0][0] = &corners[i]
|
||||
if m.placeNeighbours(0, 0) {
|
||||
return true
|
||||
}
|
||||
|
||||
m.grid[0][0] = &corners[i]
|
||||
m.grid[0][0].rotate()
|
||||
if m.placeNeighbours(0, 0) {
|
||||
return true
|
||||
}
|
||||
|
||||
m.grid[0][0] = &corners[i]
|
||||
m.grid[0][0].rotate()
|
||||
if m.placeNeighbours(0, 0) {
|
||||
return true
|
||||
}
|
||||
|
||||
m.grid[0][0] = &corners[i]
|
||||
m.grid[0][0].rotate()
|
||||
if m.placeNeighbours(0, 0) {
|
||||
return true
|
||||
}
|
||||
|
||||
m.grid[0][0] = &corners[i]
|
||||
m.grid[0][0].rotate()
|
||||
m.grid[0][0].flip()
|
||||
if m.placeNeighbours(0, 0) {
|
||||
return true
|
||||
}
|
||||
|
||||
m.grid[0][0] = &corners[i]
|
||||
m.grid[0][0].rotate()
|
||||
if m.placeNeighbours(0, 0) {
|
||||
return true
|
||||
}
|
||||
|
||||
m.grid[0][0] = &corners[i]
|
||||
m.grid[0][0].rotate()
|
||||
if m.placeNeighbours(0, 0) {
|
||||
return true
|
||||
}
|
||||
|
||||
m.grid[0][0] = &corners[i]
|
||||
m.grid[0][0].rotate()
|
||||
if m.placeNeighbours(0, 0) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (m *message) placeNeighbours(x, y int) bool {
|
||||
allGood := true
|
||||
|
||||
if x+1 >= len(m.grid) && y+1 >= len(m.grid) {
|
||||
return true
|
||||
}
|
||||
|
||||
possibleTiles := []tile{}
|
||||
for id := range m.grid[y][x].matches {
|
||||
if !m.inGrid(id) {
|
||||
possibleTiles = append(possibleTiles, *m.getTile(id))
|
||||
}
|
||||
}
|
||||
|
||||
if x+1 < len(m.grid) {
|
||||
if m.grid[y][x+1] == nil {
|
||||
right := m.grid[y][x].edge("right")
|
||||
found := false
|
||||
for _, p := range possibleTiles {
|
||||
for _, match := range p.edges {
|
||||
if match == right {
|
||||
found = true
|
||||
rfound := false
|
||||
for i := 0; i < 4; i++ {
|
||||
if right == p.edge("left") {
|
||||
found = true
|
||||
rfound = true
|
||||
m.grid[y][x+1] = &p
|
||||
allGood = m.placeNeighbours(x+1, y)
|
||||
break
|
||||
}
|
||||
|
||||
p.rotate()
|
||||
}
|
||||
if rfound {
|
||||
break
|
||||
}
|
||||
|
||||
p.flipY()
|
||||
for i := 0; i < 4; i++ {
|
||||
if right == p.edge("left") {
|
||||
found = true
|
||||
m.grid[y][x+1] = &p
|
||||
allGood = m.placeNeighbours(x+1, y)
|
||||
break
|
||||
}
|
||||
|
||||
p.rotate()
|
||||
}
|
||||
}
|
||||
}
|
||||
if found {
|
||||
break
|
||||
}
|
||||
}
|
||||
allGood = found
|
||||
} else {
|
||||
allGood = m.grid[y][x].edge("right") == m.grid[y][x+1].edge("left")
|
||||
}
|
||||
}
|
||||
|
||||
if y+1 < len(m.grid) {
|
||||
bottom := m.grid[y][x].edge("bottom")
|
||||
found := false
|
||||
for _, p := range possibleTiles {
|
||||
for _, match := range p.edges {
|
||||
if match == bottom {
|
||||
found = true
|
||||
rfound := false
|
||||
for i := 0; i < 4; i++ {
|
||||
if bottom == p.edge("top") {
|
||||
found = true
|
||||
rfound = true
|
||||
m.grid[y+1][x] = &p
|
||||
allGood = m.placeNeighbours(x, y+1)
|
||||
break
|
||||
}
|
||||
|
||||
p.rotate()
|
||||
}
|
||||
if rfound {
|
||||
break
|
||||
}
|
||||
|
||||
p.flipY()
|
||||
for i := 0; i < 4; i++ {
|
||||
if bottom == p.edge("top") {
|
||||
found = true
|
||||
m.grid[y+1][x] = &p
|
||||
allGood = m.placeNeighbours(x, y+1)
|
||||
break
|
||||
}
|
||||
|
||||
p.rotate()
|
||||
}
|
||||
}
|
||||
}
|
||||
if found {
|
||||
break
|
||||
}
|
||||
|
||||
allGood = false
|
||||
}
|
||||
}
|
||||
|
||||
if !allGood {
|
||||
m.grid[y][x] = nil
|
||||
}
|
||||
|
||||
return allGood
|
||||
}
|
||||
|
||||
func (m *message) combineTiles() bool {
|
||||
for y := 0; y < len(m.grid); y++ {
|
||||
for x := 0; x < len(m.grid); x++ {
|
||||
if m.grid[y][x] == nil {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for y := 0; y < len(m.grid); y++ {
|
||||
for x := 0; x < len(m.grid); x++ {
|
||||
for tY := 1; tY < len(m.grid[y][x].something)-1; tY++ {
|
||||
for tX := 1; tX < len(m.grid[y][x].something[tY])-1; tX++ {
|
||||
imageY := (y * (len(m.grid[y][x].something) - 2)) + (tY - 1)
|
||||
imageX := (x * (len(m.grid[y][x].something[tY]) - 2)) + (tX - 1)
|
||||
m.image[imageY][imageX] = m.grid[y][x].something[tY][tX]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (m *message) rotateImage() {
|
||||
rotated := [][]bool{}
|
||||
rotated = make([][]bool, len(m.image))
|
||||
for i := 0; i < len(m.image); i++ {
|
||||
rotated[i] = make([]bool, len(m.image))
|
||||
}
|
||||
|
||||
for y := 0; y < 10; y++ {
|
||||
for x := 0; x < 10; x++ {
|
||||
rotated[x][9-y] = m.image[y][x]
|
||||
}
|
||||
}
|
||||
|
||||
m.image = rotated
|
||||
}
|
||||
|
||||
func (m *message) flipImage() {
|
||||
flipped := [][]bool{}
|
||||
flipped = make([][]bool, len(m.image))
|
||||
for i := 0; i < len(m.image); i++ {
|
||||
flipped[i] = make([]bool, len(m.image))
|
||||
}
|
||||
|
||||
for y := 0; y < 10; y++ {
|
||||
for x := 0; x < 10; x++ {
|
||||
flipped[y][x] = m.image[9-y][x]
|
||||
}
|
||||
}
|
||||
|
||||
m.image = flipped
|
||||
}
|
||||
|
||||
func (m *message) printGrid() {
|
||||
output := ""
|
||||
for y := 0; y < len(m.grid); y++ {
|
||||
for tY := 0; tY < 10; tY++ {
|
||||
for x := 0; x < len(m.grid[y]); x++ {
|
||||
for tX := 0; tX < 10; tX++ {
|
||||
if m.grid[y][x].something[tY][tX] {
|
||||
output += "#"
|
||||
} else {
|
||||
output += "."
|
||||
}
|
||||
}
|
||||
}
|
||||
output += "\n"
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf(output)
|
||||
}
|
||||
|
||||
func (m *message) printImage() {
|
||||
output := ""
|
||||
for _, row := range m.image {
|
||||
for _, val := range row {
|
||||
if val {
|
||||
output += "#"
|
||||
} else {
|
||||
output += "."
|
||||
}
|
||||
}
|
||||
output += "\n"
|
||||
}
|
||||
|
||||
fmt.Printf(output)
|
||||
}
|
||||
|
||||
func (m *message) alignMonsters() bool {
|
||||
for i := 0; i < 4; i++ {
|
||||
count := m.seaMonsters()
|
||||
if count > 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
m.rotateImage()
|
||||
}
|
||||
m.flipImage()
|
||||
for i := 0; i < 4; i++ {
|
||||
count := m.seaMonsters()
|
||||
if count > 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
m.rotateImage()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (m *message) cornerProduct() int {
|
||||
corners := m.findCorners()
|
||||
if len(corners) != 4 {
|
||||
return -1
|
||||
}
|
||||
|
||||
product := 1
|
||||
|
||||
for _, tile := range corners {
|
||||
product *= tile.id
|
||||
}
|
||||
|
||||
return product
|
||||
}
|
||||
|
||||
func (m *message) seaMonsters() int {
|
||||
monsters := 0
|
||||
for y := 0; y < len(m.image)-2; y++ {
|
||||
for x := 0; x < len(m.image[0])-19; x++ {
|
||||
// Check if this is a valid seamonster
|
||||
if m.image[y][x+18] &&
|
||||
m.image[y+1][x] &&
|
||||
m.image[y+1][x+5] &&
|
||||
m.image[y+1][x+6] &&
|
||||
m.image[y+1][x+11] &&
|
||||
m.image[y+1][x+12] &&
|
||||
m.image[y+1][x+17] &&
|
||||
m.image[y+1][x+18] &&
|
||||
m.image[y+1][x+19] &&
|
||||
m.image[y+2][x+1] &&
|
||||
m.image[y+2][x+4] &&
|
||||
m.image[y+2][x+7] &&
|
||||
m.image[y+2][x+10] &&
|
||||
m.image[y+2][x+13] &&
|
||||
m.image[y+2][x+16] {
|
||||
monsters++
|
||||
}
|
||||
}
|
||||
}
|
||||
return monsters
|
||||
}
|
||||
|
||||
func (m *message) countRoughness() int {
|
||||
monsters := m.seaMonsters() * 15
|
||||
total := 0
|
||||
for y := 0; y < len(m.image); y++ {
|
||||
for x := 0; x < len(m.image[0]); x++ {
|
||||
if m.image[y][x] {
|
||||
total++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return total - monsters
|
||||
}
|
||||
|
||||
// PartOne Find the product of the ids of the four corners
|
||||
func PartOne() string {
|
||||
m := message{}
|
||||
if err := m.load("twenty/input.txt"); err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
|
||||
return fmt.Sprintf("The product of the four corners is %d", m.cornerProduct())
|
||||
}
|
||||
|
||||
// PartTwo How many # are not seamonsters.
|
||||
func PartTwo() string {
|
||||
m := message{}
|
||||
if err := m.load("twenty/input.txt"); err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
|
||||
m.layout()
|
||||
m.combineTiles()
|
||||
m.alignMonsters()
|
||||
|
||||
return fmt.Sprintf("There are %d # that are not seamonsters", m.countRoughness())
|
||||
}
|
75
twenty/day_twenty_test.go
Normal file
75
twenty/day_twenty_test.go
Normal file
@@ -0,0 +1,75 @@
|
||||
package twenty
|
||||
|
||||
import "testing"
|
||||
|
||||
func Test_tile_load(t *testing.T) {
|
||||
m := message{}
|
||||
m.load("sample.txt")
|
||||
|
||||
if len(m.tiles) != 9 {
|
||||
t.Logf("Expected 9 tiles to be loaded, got %d", len(m.tiles))
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
if len(m.grid) != 3 && len(m.grid[0]) != 3 {
|
||||
t.Logf("Expected a 3x3 grid, got %dx%d", len(m.grid), len(m.grid[0]))
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
func Test_arrange_tile(t *testing.T) {
|
||||
m := message{}
|
||||
m.load("sample.txt")
|
||||
|
||||
result := m.cornerProduct()
|
||||
if result != 20899048083289 {
|
||||
t.Logf("Expected a result of 20899048083289, got %d", result)
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
func Test_arrange_input(t *testing.T) {
|
||||
m := message{}
|
||||
m.load("input.txt")
|
||||
|
||||
result := m.cornerProduct()
|
||||
if result == -1 {
|
||||
t.Logf("Expected a result other than -1, got %d", result)
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
func Test_count_monsters(t *testing.T) {
|
||||
m := message{}
|
||||
m.load("sample.txt")
|
||||
|
||||
grid := m.layout()
|
||||
if !grid {
|
||||
t.Log("Expected a grid")
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
m.combineTiles()
|
||||
m.alignMonsters()
|
||||
|
||||
result := m.seaMonsters()
|
||||
if result != 2 {
|
||||
t.Logf("Expected 2 monsters, found %d", result)
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
func Test_count_roughness(t *testing.T) {
|
||||
m := message{}
|
||||
m.load("sample.txt")
|
||||
|
||||
m.layout()
|
||||
m.combineTiles()
|
||||
m.alignMonsters()
|
||||
|
||||
result := m.countRoughness()
|
||||
if result != 273 {
|
||||
t.Logf("Expected 273 # not part of a monster, found %d", result)
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
1727
twenty/input.txt
Normal file
1727
twenty/input.txt
Normal file
File diff suppressed because it is too large
Load Diff
3
twenty/monster.txt
Normal file
3
twenty/monster.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
#
|
||||
# ## ## ###
|
||||
# # # # # #
|
107
twenty/sample.txt
Normal file
107
twenty/sample.txt
Normal file
@@ -0,0 +1,107 @@
|
||||
Tile 2311:
|
||||
..##.#..#.
|
||||
##..#.....
|
||||
#...##..#.
|
||||
####.#...#
|
||||
##.##.###.
|
||||
##...#.###
|
||||
.#.#.#..##
|
||||
..#....#..
|
||||
###...#.#.
|
||||
..###..###
|
||||
|
||||
Tile 1951:
|
||||
#.##...##.
|
||||
#.####...#
|
||||
.....#..##
|
||||
#...######
|
||||
.##.#....#
|
||||
.###.#####
|
||||
###.##.##.
|
||||
.###....#.
|
||||
..#.#..#.#
|
||||
#...##.#..
|
||||
|
||||
Tile 1171:
|
||||
####...##.
|
||||
#..##.#..#
|
||||
##.#..#.#.
|
||||
.###.####.
|
||||
..###.####
|
||||
.##....##.
|
||||
.#...####.
|
||||
#.##.####.
|
||||
####..#...
|
||||
.....##...
|
||||
|
||||
Tile 1427:
|
||||
###.##.#..
|
||||
.#..#.##..
|
||||
.#.##.#..#
|
||||
#.#.#.##.#
|
||||
....#...##
|
||||
...##..##.
|
||||
...#.#####
|
||||
.#.####.#.
|
||||
..#..###.#
|
||||
..##.#..#.
|
||||
|
||||
Tile 1489:
|
||||
##.#.#....
|
||||
..##...#..
|
||||
.##..##...
|
||||
..#...#...
|
||||
#####...#.
|
||||
#..#.#.#.#
|
||||
...#.#.#..
|
||||
##.#...##.
|
||||
..##.##.##
|
||||
###.##.#..
|
||||
|
||||
Tile 2473:
|
||||
#....####.
|
||||
#..#.##...
|
||||
#.##..#...
|
||||
######.#.#
|
||||
.#...#.#.#
|
||||
.#########
|
||||
.###.#..#.
|
||||
########.#
|
||||
##...##.#.
|
||||
..###.#.#.
|
||||
|
||||
Tile 2971:
|
||||
..#.#....#
|
||||
#...###...
|
||||
#.#.###...
|
||||
##.##..#..
|
||||
.#####..##
|
||||
.#..####.#
|
||||
#..#.#..#.
|
||||
..####.###
|
||||
..#.#.###.
|
||||
...#.#.#.#
|
||||
|
||||
Tile 2729:
|
||||
...#.#.#.#
|
||||
####.#....
|
||||
..#.#.....
|
||||
....#..#.#
|
||||
.##..##.#.
|
||||
.#.####...
|
||||
####.#.#..
|
||||
##.####...
|
||||
##..#.##..
|
||||
#.##...##.
|
||||
|
||||
Tile 3079:
|
||||
#.#.#####.
|
||||
.#..######
|
||||
..#.......
|
||||
######....
|
||||
####.#..#.
|
||||
.#...#.##.
|
||||
#.#####.##
|
||||
..#.###...
|
||||
..#.......
|
||||
..#.###...
|
Reference in New Issue
Block a user