~macaptain/advent-of-code

03b30ea08d4c342eb9693d8451020d1c8d9b1bfa — Michael Captain 2 months ago 356d2ac
Complete 2019 Day 20
M src/main/advent2019/Day18.kt => src/main/advent2019/Day18.kt +8 -8
@@ 12,7 12,7 @@ data class RobotsWithKeys(
    val currentRobot: Int
)

fun neighbours(map: Map<Point, Char>, p: PointWithKeys): Set<PointWithKeys> {
fun vaultNeighbours(map: Map<Point, Char>, p: PointWithKeys): Set<PointWithKeys> {
    val x = p.p.x
    val y = p.p.y
    val adjacent = setOf(


@@ 34,32 34,32 @@ fun neighbours(map: Map<Point, Char>, p: PointWithKeys): Set<PointWithKeys> {
    return adjacent
}

fun neighbours(map: Map<Point, Char>, p: RobotsWithKeys): Set<RobotsWithKeys> {
fun vaultNeighbours(map: Map<Point, Char>, p: RobotsWithKeys): Set<RobotsWithKeys> {
    // Only one robot moves at a time until a key is found. Then we queue as a neighbour all movements with any of the
    // robots moving.
    return when (p.currentRobot) {
        1 -> neighbours(map, PointWithKeys(p.p1, p.keys)).flatMap {
        1 -> vaultNeighbours(map, PointWithKeys(p.p1, p.keys)).flatMap {
            if (!p.keys.containsAll(it.keys))
                (1..4).map { n -> RobotsWithKeys(it.p, p.p2, p.p3, p.p4, it.keys, n) }
            else listOf(
                RobotsWithKeys(it.p, p.p2, p.p3, p.p4, it.keys, 1)
            )
        }
        2 -> neighbours(map, PointWithKeys(p.p2, p.keys)).flatMap {
        2 -> vaultNeighbours(map, PointWithKeys(p.p2, p.keys)).flatMap {
            if (!p.keys.containsAll(it.keys)) {
                (1..4).map { n -> RobotsWithKeys(p.p1, it.p, p.p3, p.p4, it.keys, n) }
            } else listOf(
                RobotsWithKeys(p.p1, it.p, p.p3, p.p4, it.keys, 2)
            )
        }
        3 -> neighbours(map, PointWithKeys(p.p3, p.keys)).flatMap {
        3 -> vaultNeighbours(map, PointWithKeys(p.p3, p.keys)).flatMap {
            if (!p.keys.containsAll(it.keys)) {
                (1..4).map { n -> RobotsWithKeys(p.p1, p.p2, it.p, p.p4, it.keys, n) }
            } else listOf(
                RobotsWithKeys(p.p1, p.p2, it.p, p.p4, it.keys, 3)
            )
        }
        4 -> neighbours(map, PointWithKeys(p.p4, p.keys)).flatMap {
        4 -> vaultNeighbours(map, PointWithKeys(p.p4, p.keys)).flatMap {
            if (!p.keys.containsAll(it.keys)) {
                (1..4).map { n -> RobotsWithKeys(p.p1, p.p2, p.p3, it.p, it.keys, n) }
            } else listOf(


@@ 88,7 88,7 @@ fun solve18a(lines: List<String>): Int {
        if (current.keys == allKeys) {
            return generateSequence(cameFrom[current]) { cameFrom[it] }.count()
        }
        neighbours(map, current).forEach { next ->
        vaultNeighbours(map, current).forEach { next ->
            if (next !in cameFrom.keys) {
                cameFrom[next] = current
                frontier.add(next)


@@ 148,7 148,7 @@ fun solve18b(updatedLines: List<String>): Int {
        if (current.keys == allKeys) {
            return generateSequence(cameFrom[current]) { cameFrom[it] }.count()
        }
        neighbours(map, current).forEach { next ->
        vaultNeighbours(map, current).forEach { next ->
            if (next !in cameFrom.keys) {
                cameFrom[next] = current
                frontier.add(next)

A src/main/advent2019/Day20.kt => src/main/advent2019/Day20.kt +110 -0
@@ 0,0 1,110 @@
package advent2019

import common.Point

data class PointWithLevel(val p: Point, val recursionLevel: Int)

fun isGateOuter(lines: List<String>, gatePoint: Point): Boolean {
    if (gatePoint.y == 2) return true
    if (gatePoint.y == lines.count { it.isNotBlank() } - 3) return true
    if (gatePoint.x == 2) return true
    if (gatePoint.x == lines[0].count() - 3) return true
    return false
}

fun gatePoints(lines: List<String>): Map<Point, String> {
    val gatePoints = mutableMapOf<Point, String>()
    lines.forEachIndexed j@{ j, row ->
        row.forEachIndexed i@{ i, c ->
            if (c != '.') return@i
            val left = listOf(lines[j][i - 2], lines[j][i - 1]).joinToString("")
            val right = listOf(lines[j][i + 1], lines[j][i + 2]).joinToString("")
            val up = listOf(lines[j - 2][i], lines[j - 1][i]).joinToString("")
            val down = listOf(lines[j + 1][i], lines[j + 2][i]).joinToString("")
            if (left.all { it.isUpperCase() }) gatePoints[Point(i, j)] = left
            if (right.all { it.isUpperCase() }) gatePoints[Point(i, j)] = right
            if (up.all { it.isUpperCase() }) gatePoints[Point(i, j)] = up
            if (down.all { it.isUpperCase() }) gatePoints[Point(i, j)] = down
        }
    }
    return gatePoints
}

fun pairedGatePoint(gatePoints: Map<Point, String>, p: Point): Point? {
    val gate = gatePoints[p] ?: return null
    return gatePoints.filterValues { it == gate }.filterKeys { it != p }.keys.firstOrNull()
}

fun donutNeighbours(lines: List<String>, gatePoints: Map<Point, String>, p: Point): Set<Point> {
    val adjacent = listOf(Point(p.x - 1, p.y), Point(p.x + 1, p.y), Point(p.x, p.y - 1), Point(p.x, p.y + 1)).filter {
        lines[it.y][it.x] == '.'
    }
    val pairedGatePoint = pairedGatePoint(gatePoints, p)
    return adjacent.plus(pairedGatePoint).filterNotNull().toSet()
}

fun donutNeighbours(lines: List<String>, gatePoints: Map<Point, String>, point: PointWithLevel): Set<PointWithLevel> {
    val p = point.p
    val level = point.recursionLevel
    val adjacent = listOf(Point(p.x - 1, p.y), Point(p.x + 1, p.y), Point(p.x, p.y - 1), Point(p.x, p.y + 1)).filter {
        lines[it.y][it.x] == '.'
    }.map { PointWithLevel(it, level) }
    val pairedGatePoint = pairedGatePoint(gatePoints, p)
    val pairedGatePointWithLevel = if (pairedGatePoint != null) {
        if (isGateOuter(lines, p)) {
            if (level > 0) PointWithLevel(pairedGatePoint, level - 1) else null
        } else
            PointWithLevel(pairedGatePoint, level + 1)
    } else null
    return adjacent.plus(pairedGatePointWithLevel).filterNotNull().toSet()
}

fun solve20a(lines: List<String>): Int {
    val gatePoints = gatePoints(lines)
    val startPoint = gatePoints.filterValues { it == "AA" }.keys.first()
    val frontier = ArrayDeque<Point>()
    frontier.add(startPoint)
    val cameFrom = mutableMapOf<Point, Point?>(startPoint to null)
    while (frontier.isNotEmpty()) {
        val current = frontier.removeFirst()
        if (gatePoints[current] == "ZZ") {
            return generateSequence(cameFrom[current]) { cameFrom[it] }.count()
        }
        donutNeighbours(lines, gatePoints, current).forEach { next ->
            if (next !in cameFrom.keys) {
                cameFrom[next] = current
                frontier.add(next)
            }
        }
    }
    throw IllegalArgumentException("couldn't find a path to the exit")
}

fun solve20b(lines: List<String>): Int {
    val gatePoints = gatePoints(lines)
    val startPoint = PointWithLevel(gatePoints.filterValues { it == "AA" }.keys.first(), 0)
    val frontier = ArrayDeque<PointWithLevel>()
    frontier.add(startPoint)
    val cameFrom = mutableMapOf<PointWithLevel, PointWithLevel?>(startPoint to null)
    while (frontier.isNotEmpty()) {
        val current = frontier.removeFirst()
        if (gatePoints[current.p] == "ZZ" && current.recursionLevel == 0) {
            val seq = generateSequence(cameFrom[current]) { cameFrom[it] }
            return seq.count()
        }
        val neighbours = donutNeighbours(lines, gatePoints, current)
        neighbours.forEach { next ->
            if (next !in cameFrom.keys) {
                cameFrom[next] = current
                frontier.add(next)
            }
        }
    }
    throw IllegalArgumentException("couldn't find a path to the exit")
}

fun main() {
    val lines = input("day20")
    println(solve20a(lines)) // 498
    println(solve20b(lines)) // 5564
}
\ No newline at end of file

A src/main/resources/advent2019/day20_input.txt => src/main/resources/advent2019/day20_input.txt +107 -0
@@ 0,0 1,107 @@
                               L       S     F Z     O     X     Q     W                                   
                               T       S     P Z     J     J     X     L                                   
  #############################.#######.#####.#.#####.#####.#####.#####.#################################  
  #.#.....#.....#.#.#.#.....#.....#.#.......#...#.....#.#...#.#.#.#.......#...#.#.#...#.#...#.#...#.#.#.#  
  #.###.#.###.###.#.#.###.#####.###.###.#.#####.###.###.#.###.#.#.#####.###.#.#.#.#.###.#.###.#.#.#.#.#.#  
  #.....#.#...#.#.....#.#...#.....#.#.#.#.#...#.#.....#.......#...#...#.....#.#.............#.#.#.....#.#  
  #######.###.#.#.#####.###.#.#####.#.###.#.#.#.#####.#.#.#.#.#.#.#.###.#####.#.#.#########.#.#.#######.#  
  #...#.....#.....#...#.........#.......#.#.#.....#...#.#.#.#.#.#.#...#.#.......#.........#.......#.....#  
  #.#######.#####.###.#########.###.###.#.#.#######.#.###.###.###.###.#.#.#####.#.#####.#.#.#.#######.###  
  #.#...#.....#.......#.#.#.#...#...#...#.#...#...#.#...#...#.#.....#...#.....#.#.....#.#.#.#.#.#.#.....#  
  #.#.#####.#.###.###.#.#.#.#.#####.###.#.#.###.#####.#.#.#######.#####.#####.###########.###.#.#.#.###.#  
  #...#...#.#.......#...........#.....#.#.#...#...#...#.#.....#...#.....#...#.#.....#...#.#.#.#.....#.#.#  
  ###.#.#######.#############.#######.#.#.###.#.#####.#.#.#.###.#.#######.#.#.#.###.###.###.#####.###.###  
  #.........#.#.#.....#...#.......#...#...#.......#...#.#.#.#.#.#.....#...#.......#.#.......#.....#...#.#  
  #.###.###.#.#.#####.###.###.#####.###.#.###.#.#######.#.###.###.#.#.#.#.#.###.###.###.#####.###.#.###.#  
  #.#...#.........#...............#.#...#.#...#...#.....#...#...#.#.#.#.#.#...#.#.......#.#.#...#...#...#  
  ###.#######.#.#####.###.###.#####.#######.###########.#.###.###.#####.#################.#.#.#####.###.#  
  #.#...#.....#.....#...#.#.....#.......#.#...#.........#.....#.#.....#...........#.#.#.#...#.#.#.#.#...#  
  #.#######.###.#.###########.#########.#.###.###.###.#######.#.###.###.#.###.#####.#.#.#.#.###.#.#.#.###  
  #.#...#.#.#...#...#.............#.......#.....#...#...#.......#...#...#.#...#.#...#.#...#...#.#.#...#.#  
  #.###.#.#####.#####.#######.###.###.#####.###########.###.#####.#####.#######.#.###.###.#####.#.#.###.#  
  #.#.........#.....#.#.....#.#.....#.....#...#.#.....#.#.......#...#.#...........#.#.#...#.#.#.#...#...#  
  #.#.#####.#.#.#.###.#####.###.#####.#.#####.#.###.#.#.###.#####.#.#.#.#####.#####.#.###.#.#.#.###.#.#.#  
  #.#.#.#...#.#.#.#.#.#.....#.......#.#.#.#.....#...#...#...#.....#.#.#.#.....#.#.#.#.#.....#...#...#.#.#  
  #.###.###.#######.#####.#.#####.#####.#.#.#####.###.#.#.#######.###.#.#####.#.#.#.#.###.#####.###.#.###  
  #.#.#...#.#.#.....#...#.#.......#.......#.....#...#.#.#.......#.....#.#...........#...#...#.#.#.......#  
  #.#.#.###.#.#####.###.#######.#########.#####.#.#############.#####.#####.#########.###.###.#.###.###.#  
  #.#.....#.#.#.#.#...#.#.#    U         D     P I             Q     L     M    #.#...#...#.......#.#...#  
  #.#####.#.#.#.#.#.###.#.#    E         R     V Q             X     T     X    #.###.###.###.#######.#.#  
  #.#.........#.#.....#.#.#                                                     #...#.#.#.#.......#.#.#.#  
  #.###.#######.###.###.#.#                                                     #.###.#.#.###.#####.###.#  
  #.#.#...#.....#.#.......#                                                   TI......#.........#.#.....#  
  #.#.#.#######.#.###.###.#                                                     #.#.#.#.###.#.###.###.#.#  
  #.....#.....#...#.#.#...#                                                     #.#.#...#...#.....#...#..IQ
  #.###.###.#####.#.#.###.#                                                     #.#.#.#.#.#####.#.#.#.###  
TI..#...#.....#...#.#...#..WL                                                   #.#.#.#.#.#.....#.#.#...#  
  #.#.###.#.#####.#.###.#.#                                                     #############.#####.#.###  
  #.#.....#.............#.#                                                     #...#...#.#.........#.#.#  
  #######.#.#.#.#.#######.#                                                     ###.###.#.#####.#.#####.#  
  #.....#.#.#.#.#.#.#.....#                                                     #.............#.#.#.#....UE
  #.###.###########.###.###                                                     ###.#.#######.#####.###.#  
  #...#...#.....#...#...#.#                                                     #...#.....#...........#.#  
  ###.###.#.#.#####.###.#.#                                                     #.#####.#.###.###.###.#.#  
OG..#...#...#...#.#.#.#.#..OB                                                   #.#.....#.#.#...#.#...#.#  
  #.###.#####.###.#.#.###.#                                                     ###.###.#.#.#########.#.#  
  #.......#...............#                                                   VU....#...#.#.#...#...#...#  
  #.###.#.#.#.#.###.#.#####                                                     #.#########.#.#####.#####  
  #...#.#.#.#.#...#.#.#....ZH                                                   #...#...#...#.....#.....#  
  #####.#.###.#.#######.###                                                     #######.#.#.#.###.#.###.#  
  #...#.#.#.#.#...#.......#                                                     #.....#...#.....#.....#.#  
  ###.#####.###.#########.#                                                     #.#.###.#####.###.#.###.#  
PV....#.#.....#.#.#.#.#...#                                                     #.#.......#.....#.#.#...#  
  #.#.#.#.#.#####.#.#.#.###                                                     ###.#.#############.#.#.#  
  #.#.....#.............#.#                                                   DS....#.#.#.....#.#.#.#.#..DR
  #######################.#                                                     #######.###.###.#.#######  
  #.................#.....#                                                     #.#.#.................#.#  
  #.###.###.#.#.#.#.#.###.#                                                     #.#.#.#####.###.#####.#.#  
  #.#...#.#.#.#.#.#.#.#...#                                                   SB....#...#.....#.#...#...#  
  #####.#.#########.#.#.###                                                     #.###.###.#.###.###.###.#  
  #...#.......#...#...#...#                                                     #.......#.#.#...#.#.#...#  
  #.#.#.###.###.#####.###.#                                                     #.#.#.#####.#####.#.#.###  
GU..#...#...#...#.#.....#..SS                                                   #.#.#.#.#.#.#.#.#.#......QN
  #############.#.#######.#                                                     #####.#.#.###.#.#.#######  
  #.#.#...............#.#.#                                                   OJ..#.#.#...#.......#.#....PO
  #.#.#.#######.#.###.#.###                                                     #.#.###.#.#.#####.#.###.#  
AA....#.....#.#.#.#.#.....#                                                     #...#...#.....#.#...#...#  
  #.###.#.#.#.#####.#####.#                                                     #.#.#.#.#.#####.#.#.#.#.#  
  #...#.#.#.....#.........#                                                     #.#...#.#.#...#...#.#.#.#  
  #.#.#.#####.#####.#.#####                                                     #.#.###.#.#.###.#.#.#.#.#  
MX..#.....#.#...#.#.#......OQ                                                 QN..#.#...#.#.#.#.#.#...#..MH
  ###.#####.#####.###.#####                                                     ###########.#.###########  
  #.#.#.#.#.....#...#.#....MH                                                 PO......#.#................YJ
  #.###.#.#.#######.#####.#                                                     #.#.###.#.#.#.###.###.#.#  
  #...#.........#.........#                                                     #.#.#.....#.#.#.....#.#.#  
  #.#.#.#.###############.#                                                     ###.#.#########.#.#.#.#.#  
OB..#.#.#...#.#.#.#.....#.#                                                     #...#.....#.#.#.#.#.#.#.#  
  #.#.#.#.###.#.#.#.#.#.#.#                                                     #.#######.#.#.###.#.#####  
  #.#...#...........#.#...#                                                     #...............#.#.....#  
  ###.###.#.#.#.#.#####.#.#        X D       H       O         G F         Y    #.#.#.###.###.#####.###.#  
  #.....#.#.#.#.#...#...#.#        J C       Y       G         U P         J    #.#.#.#.....#.....#.#.#.#  
  ###.###.###.#.#.###.#.###########.#.#######.#######.#########.#.#########.#########.###.#######.###.###  
  #.#...#...#.#.#...#.#.#.#.#.....#.#...#.........#...#.........#.....#.......#.....#.#.........#.#.#...#  
  #.#.###.#####.#.#.#####.#.#.###.#.###.#########.#.#####.#########.#####.#######.#####.###.#.#####.###.#  
  #...#.....#.#.#.#...#.#.......#...#.......#.....#.#...........#...#.#.#.............#.#...#...........#  
  ###.###.###.###.#####.#.#.###.#######.#.#####.###.#.#####.###.###.#.#.###.#.###.#.###.#.###.#.#######.#  
  #.#...#...#.........#...#...#.......#.#.#...#...#.#.#...#.#.....#.#.....#.#...#.#.#...#.#...#...#.....#  
  #.#.#.#.###.###.#.#######.#.#.###.#.###.#.#####.#.###.#####.#####.#.#.###.###########.#####.###.###.#.#  
  #...#.#.#.....#.#...#.#...#.#.#.#.#.#.......#...#...#.......#.....#.#...#.......#.#.#.#.......#.#.#.#.#  
  #.#.###.#.#.#.#####.#.#.#.#####.#.#.###.###.###.#.###.#.###.#####.#.#.###.#######.#.#.#####.###.#.###.#  
  #.#...#.#.#.#.#.#.#.#.#.#...#.....#.#.....#.#.#.#...#.#...#...#.....#.#.......#.#.#...#...#.#...#.....#  
  #######.#####.#.#.###.###.#####.#.#####.#####.#.#.#####.#######.#####.###.#####.#.#####.#.#####.#.###.#  
  #.#.#.#.....#.#.#.......#.#.#...#.....#.#.#.....#.....#.#.#.#...#.....#.................#...#...#...#.#  
  #.#.#.#.#.#####.#####.#####.#####.#####.#.###.###.#####.#.#.#######.###.#.#######.###.#.#######.#.###.#  
  #.......#.#.#.#...#.......#.........#.....#.#...#.#.#.....#.#.#.#.#...#.#.....#.#...#.#.......#.#.#...#  
  #.#.###.###.#.###.###.#########.###.###.###.###.#.#.#.###.#.#.#.#.###.#.###.#.#.#######.#########.###.#  
  #.#.#.#...#.......................#.#...#.#.....#...#.#.......#.......#...#.#.#.#...#.#.#.....#...#...#  
  #.###.#.###.###.###.#######.#########.#.#.#.###.###.###.#######.###.#####.#####.#.###.#####.#####.###.#  
  #...#...#.#.#.....#.#...#...#.....#...#.#.....#.#.#.#.#.#.#.#.....#...#.....#...........#.......#.#...#  
  #.###.###.#########.###.###.#.#.###.#.#####.#####.#.#.#.#.#.#######.#.#.#######.###.#####.###########.#  
  #.#.....#.#.#.......#.....#...#...#.#.#.....#.........#.#.#.#...#...#.#...........#...#.#...#.....#...#  
  ###.###.#.#.#######.###.#######.#####.###.#########.#.#.#.#.#.#######.###.#.###.###.###.#.###.#########  
  #...#.......#.......#.#...........#.....#.#.....#...#.#...#...#...#...#...#...#.#.....................#  
  #.###.#.###.#.#.#####.#####.###########.#.#.###.#.###.#.###.#.###.#.###.#.###########.###.###.#########  
  #.#...#.#...#.#.#...................#...#...#...#.#...#.....#.#.....#...#...........#...#...#.........#  
  #################################.###.#########.#####.#######.###.#####.###############################  
                                   H   V         Z     D       S   D     O                                 
                                   Y   U         H     C       B   S     Q                                 

A src/test/advent2019/Day20KtTest.kt => src/test/advent2019/Day20KtTest.kt +122 -0
@@ 0,0 1,122 @@
package advent2019

import org.junit.jupiter.api.Test

import org.junit.jupiter.api.Assertions.*

internal class Day20KtTest {

    private val example1 = listOf(
        "         A           ",
        "         A           ",
        "  #######.#########  ",
        "  #######.........#  ",
        "  #######.#######.#  ",
        "  #######.#######.#  ",
        "  #######.#######.#  ",
        "  #####  B    ###.#  ",
        "BC...##  C    ###.#  ",
        "  ##.##       ###.#  ",
        "  ##...DE  F  ###.#  ",
        "  #####    G  ###.#  ",
        "  #########.#####.#  ",
        "DE..#######...###.#  ",
        "  #.#########.###.#  ",
        "FG..#########.....#  ",
        "  ###########.#####  ",
        "             Z       ",
        "             Z       "
    )

    private val example2 = listOf(
        "                   A               ",
        "                   A               ",
        "  #################.#############  ",
        "  #.#...#...................#.#.#  ",
        "  #.#.#.###.###.###.#########.#.#  ",
        "  #.#.#.......#...#.....#.#.#...#  ",
        "  #.#########.###.#####.#.#.###.#  ",
        "  #.............#.#.....#.......#  ",
        "  ###.###########.###.#####.#.#.#  ",
        "  #.....#        A   C    #.#.#.#  ",
        "  #######        S   P    #####.#  ",
        "  #.#...#                 #......VT",
        "  #.#.#.#                 #.#####  ",
        "  #...#.#               YN....#.#  ",
        "  #.###.#                 #####.#  ",
        "DI....#.#                 #.....#  ",
        "  #####.#                 #.###.#  ",
        "ZZ......#               QG....#..AS",
        "  ###.###                 #######  ",
        "JO..#.#.#                 #.....#  ",
        "  #.#.#.#                 ###.#.#  ",
        "  #...#..DI             BU....#..LF",
        "  #####.#                 #.#####  ",
        "YN......#               VT..#....QG",
        "  #.###.#                 #.###.#  ",
        "  #.#...#                 #.....#  ",
        "  ###.###    J L     J    #.#.###  ",
        "  #.....#    O F     P    #.#...#  ",
        "  #.###.#####.#.#####.#####.###.#  ",
        "  #...#.#.#...#.....#.....#.#...#  ",
        "  #.#####.###.###.#.#.#########.#  ",
        "  #...#.#.....#...#.#.#.#.....#.#  ",
        "  #.###.#####.###.###.#.#.#######  ",
        "  #.#.........#...#.............#  ",
        "  #########.###.###.#############  ",
        "           B   J   C               ",
        "           U   P   P               "
    )

    private val example3 = listOf(
        "             Z L X W       C                 ",
        "             Z P Q B       K                 ",
        "  ###########.#.#.#.#######.###############  ",
        "  #...#.......#.#.......#.#.......#.#.#...#  ",
        "  ###.#.#.#.#.#.#.#.###.#.#.#######.#.#.###  ",
        "  #.#...#.#.#...#.#.#...#...#...#.#.......#  ",
        "  #.###.#######.###.###.#.###.###.#.#######  ",
        "  #...#.......#.#...#...#.............#...#  ",
        "  #.#########.#######.#.#######.#######.###  ",
        "  #...#.#    F       R I       Z    #.#.#.#  ",
        "  #.###.#    D       E C       H    #.#.#.#  ",
        "  #.#...#                           #...#.#  ",
        "  #.###.#                           #.###.#  ",
        "  #.#....OA                       WB..#.#..ZH",
        "  #.###.#                           #.#.#.#  ",
        "CJ......#                           #.....#  ",
        "  #######                           #######  ",
        "  #.#....CK                         #......IC",
        "  #.###.#                           #.###.#  ",
        "  #.....#                           #...#.#  ",
        "  ###.###                           #.#.#.#  ",
        "XF....#.#                         RF..#.#.#  ",
        "  #####.#                           #######  ",
        "  #......CJ                       NM..#...#  ",
        "  ###.#.#                           #.###.#  ",
        "RE....#.#                           #......RF",
        "  ###.###        X   X       L      #.#.#.#  ",
        "  #.....#        F   Q       P      #.#.#.#  ",
        "  ###.###########.###.#######.#########.###  ",
        "  #.....#...#.....#.......#...#.....#.#...#  ",
        "  #####.#.###.#######.#######.###.###.#.#.#  ",
        "  #.......#.......#.#.#.#.#...#...#...#.#.#  ",
        "  #####.###.#####.#.#.#.#.###.###.#.###.###  ",
        "  #.......#.....#.#...#...............#...#  ",
        "  #############.#.#.###.###################  ",
        "               A O F   N                     ",
        "               A A D   M                     "
    )

    @Test
    fun solve20a() {
        assertEquals(23, solve20a(example1))
        assertEquals(58, solve20a(example2))
    }

    @Test
    fun solve20b() {
        assertEquals(396, solve20b(example3))
    }

}
\ No newline at end of file