package aoc

import org.assertj.core.api.KotlinAssertions.assertThat
import org.junit.Test

class Day3TobogganTrajectory {
    private fun rideToboggan(map: Map<Point, Char>, pathFunction: (Point) -> Point): Map<Point, Char> {
        val maxX = map.keys.map { it.x }.max() ?: 0
        val maxY = map.keys.map { it.y }.max() ?: 0

        fun getWithLoop(point: Point): Char? {
            return map[point] ?: map[point.copy(x = point.x.rem(maxX + 1))]
        }

        val path = generateSequence(Point(0, 0), pathFunction)
            .takeWhile { it.y <= maxY }
            .toList()

        return path.map { point ->
            point to when (getWithLoop(point)) {
                '#' -> 'X'
                else -> 'O'
            }
        }.toMap()
    }

    @Test
    fun silverTest() {
        val map = parseMap(testInput)
        val collisions = rideToboggan(map) { point ->
            point.right().right().right().down()
        }

        printMap(map + collisions)

        assertThat(collisions.count { (_, it) -> it == 'X' }).isEqualTo(7)
    }

    @Test
    fun silverTask() {
        val map = parseMap(input)
        val collisions = rideToboggan(map) { point ->
            point.right().right().right().down()
        }

        assertThat(collisions.count { (_, it) -> it == 'X' }).isEqualTo(274)
    }

    @Test
    fun goldTest() {
        val map = parseMap(testInput)
        val product = multiplyTreeHits(map)
        assertThat(product).isEqualTo(336)

        assertThat(rideToboggan(map) { point -> point.right().down() }.values.count { it == 'X' }).isEqualTo(2)
        assertThat(rideToboggan(map) { point ->
            point.right().right().right().down()
        }.values.count { it == 'X' }).isEqualTo(7)
        assertThat(rideToboggan(map) { point -> point.right(inc = 5).down() }.values.count { it == 'X' }).isEqualTo(3)
        assertThat(rideToboggan(map) { point -> point.right(inc = 7).down() }.values.count { it == 'X' }).isEqualTo(4)
        assertThat(rideToboggan(map) { point -> point.right().down(inc = 2) }.values.count { it == 'X' }).isEqualTo(2)
    }

    @Test
    fun goldTask() {
        val product = multiplyTreeHits(parseMap(input))
        assertThat(product).isEqualTo(6050183040)
    }

    /**
     * Right 1, down 1.
     * Right 3, down 1. (This is the slope you already checked.)
     * Right 5, down 1.
     * Right 7, down 1.
     * Right 1, down 2.
     */
    private fun multiplyTreeHits(map: Map<Point, Char>): Long {
        return listOf(
            rideToboggan(map) { point -> point.right().down() },
            rideToboggan(map) { point -> point.right(inc = 3).down() },
            rideToboggan(map) { point -> point.right(inc = 5).down() },
            rideToboggan(map) { point -> point.right(inc = 7).down() },
            rideToboggan(map) { point -> point.right().down(inc = 2) }
        )
            .map { it.count { (_, it) -> it == 'X' }.toLong() }
            .reduce { l, r -> l * r }
    }

    val testInput = """
..##.......
#...#...#..
.#....#..#.
..#.#...#.#
.#...##..#.
..#.##.....
.#.#.#....#
.#........#
#.##...#...
#...##....#
.#..#...#.#
""".trimIndent()

    val input = """
        ......#..##..#...#...#.###.....
        #..#............#..........#...
        ..........#....#..........#....
        ....#..#.#..........#..#.....#.
        #.......#...#......#........###
        #####........#.#....##..##..#..
        ......#.#..#..#..##.#..#.##....
        .#..#.#..............##....##..
        ..##......#....#........#...###
        ...#....#.#....#.#..#......#..#
        ..................#.....#.....#
        #.#...#...#....#............#.#
        .#...#.....#...##........#.....
        ...#....#........#..#....#..###
        #...##.....##.#.#...........#.#
        .###........#.#.#.........#....
        ...#.............###.....#.#..#
        .####.#..#....#.....#.........#
        .#.#........#.#.....#.....#....
        .#.......#................##.##
        ...#.#..#...###.....#....#..##.
        ...#....##..#............##...#
        #...#............######...#.##.
        .........#........#.#...#..##..
        .....###..#.#.....##.#.#......#
        ..#.#...#.#..#.#.##..#.....#.#.
        ..#......#.#....#...#..........
        ..#...#.....#.#...##.....#.....
        .##...........####........##...
        ....#............#.#...........
        .....####.........#.##....###..
        #..#..#.#..............#.#.....
        ...#.#........#.........#......
        ......#.#.#...#.....#....#.....
        ........#.#...#####..#..#......
        .....#.#....#....#...........##
        .#...#.........#.......##......
        .#.##..##......#...............
        ...#.....#.......#.#.#.........
        .........#..#...#...#.#.##....#
        .#......##....#..#.........#...
        ....#.....#........#.........##
        ......#...........##...........
        .....#..............###.#....#.
        ........#..#...#..#..#..#..#.#.
        .#.....#.##.#..#..#.#.....#....
        ...#....#...#.#.....##.#...#..#
        #..#......#..#.###...........#.
        .##...##.#........#.#......#.#.
        ...#.#..#.#.......#..###...##..
        #.......#.#....#..........#....
        .#.....#..#.#.#..#..#........#.
        .#...#......#.#...#.##.....#.##
        ...######..#.#....#.........##.
        #.#.......................#....
        ..#..##...#...#.#..##.......#..
        .##..#.......##......##.#..#...
        #.#....##.......#..#...........
        ..#...#............#..#........
        ........#.#.........#...#..#..#
        .#...###...............##...#..
        ...........#.....#....#....###.
        #..#....##..#................##
        ...#.#..#..##......#....##....#
        ...#.##...#....#..#....#.......
        #...##..##.#.........#...#....#
        .##........###.#..........#....
        ..#..#..#...#.##..#.#......#...
        .......##..#....###.##.....#..#
        #....#...#.#.....#..###....##..
        .#.......#.........#....#.#..#.
        .........#.......#.#.......#...
        ..........#...##..#...#....#.##
        ..#........#.......#...........
        #....#.....##......#....#.#...#
        ......#.....#....#.....#..#....
        .#....##...#...##..............
        ..#....#......#...#....#...#...
        #....###...##..#.#....##......#
        ..#.......#.........#..#......#
        ...#...#.##.......#....##..#...
        ..#.#...#.##..#..#..#...#.#...#
        .#.........###....#....#.....#.
        .#.##.#..##..#...........#....#
        ....##..#..##.#.......#....#..#
        ....#..#.........##..#......#.#
        ..........#.#.#....##.#......##
        .##...#....###...#..........#..
        #..#.....#..#.#.#.#..#......#.#
        ......#....#......##.#......#.#
        ...#.....#.......#....#.......#
        .#.#................#..........
        ......#..#..#...............##.
        ##......#...#.####....#.#.#....
        ...#..##............#....#.....
        ..#..#.#...#..................#
        .##.#.#..##.###.....#..#.......
        ..#...#.#...#......#..#........
        .###..........##...###..##..#..
        #.#...#........#.......##......
        ..##...#........#....##...##...
        .......#.##.....#.#.##..#..##..
        ........#............#....##...
        ...#.#.#..#.........#.#.......#
        ..#..##.##...#.##...#....#...#.
        .....##.#...##............##...
        .#...#.###....#.......#...#...#
        .......#######.#....#.....#.#..
        ......#.......#............##..
        .....#...........#......#.....#
        ........#....#.##.#............
        .#........#.......##.#.#....#..
        #.....#..####.#................
        .....#.......................##
        .#.....#..##.#..##........#.#.#
        #...##....#..##................
        ......##.###..........#.....#..
        .#........#...#..............##
        ..#..........###.........#.....
        ....#.....##....#..#..#.#.#....
        ....#.......#.##...#.####.#....
        #........#............#.##.....
        ..#......##.....#..#...#.......
        ..#......###...#.##......#..#..
        #..#..#............#..#.###....
        ...##.........#..##...#..#.#...
        ..#.###..#.##.#........#..#....
        ......#..###.#........#........
        .#....#.#..#.....#..#..#.......
        #.....##.##...#...###.#.#..#.#.
        .#....#..#.........#..#....###.
        ......##.####...#....#........#
        ##..#........#..#..##...#......
        #.........#.........#...#..#.#.
        ..........#...................#
        ###....#....#....#......###...#
        #....##........#..###.#..#.....
        .#......#.....#.#.........#..#.
        ...#.......##.....#.........###
        ..............#........#.....##
        ....#.#..#.....###.#....##.....
        .........#..##.#....#.#........
        ...#....#.......#.#.#..#.#....#
        ...........#...#..........#.#..
        #.................##........###
        ####..#.#..#...#.....###.......
        ..#.#......##.#.......#........
        .......##........#..#.....#..#.
        ...#..#......#..#.#.......###..
        #....#...##..#.#.#.#.........#.
        ....#....#....#.#..#..........#
        ...###........#.#.###......##..
        ................#.....#.#...##.
        ..#..#.###...........#...###.#.
        .........................#..#.#
        #...#..#..##.###.....##.##.#...
        ...#..................#.#....#.
        ......#..##.#.......#.......#..
        .##....#.#................#....
        .#...#..#.#.#....##....#.......
        .##......#.....#..........#....
        ..#...........#..##.........#..
        ....#.#...........#..........##
        ....#.#.#...........#.#........
        ......#.....#..#....##....##...
        ............##...##......#.#.##
        #.#.....#..#....#..#...#.#...#.
        .#...###..#..#.......#.......#.
        .....#..#.##.....#....#...#....
        ##.....#..##.......##..#.#.#..#
        ....#.#......##....#.....#..###
        .#...#.#......#.##...#..##.....
        .#...#...#......##..#..#...#.#.
        .#.........#....##...###...##..
        ###.....#......####.....#.#....
        .....#..##.##................#.
        .#.................#...#..##.#.
        ....#....#..#.......#.....#....
        .##....#..#..#.....###.#..#..#.
        #.#.......#.....##...#.....#...
        #.#........#.#.###...#....#....
        .#.....#.....##.#...#..#.......
        ..###.#............#...##.###..
        .....#.....#..#..##............
        .#.#..#.#..##..#....#...##.....
        .#...........#..#.......#...#.#
        #.#.#.#.....##....#............
        ...#.................#.#......#
        .....##.............#...#.#....
        .##......#.#....#..........#.#.
        .#.##.......##...#...#.....#.#.
        #...#.#........#......##....#.#
        #....##....#....#...#..#..#.#.#
        ......#..........#...#.....#..#
        #..#....#....#..##.#..#.#...#..
        ......#..#.#....#.....#.#..#..#
        ...#.#...###........#.#......##
        ..#............................
        ...#.#..##...##...#...#......##
        ...#.####......#.........#....#
        .#...#.#...##....#......#.#....
        .#.....##..##.#................
        .#...............#.............
        ......#.....#...#..##..##......
        ...#..##.......#.......#..#.#.#
        ......##.....#..#.....#...#.#.#
        ........##........#.#........##
        .#....#.....###..#.......#...#.
        #...#....#.........#.......#...
        ...##..#........#####.#........
        ###..#....#.#..#...#.####......
        ..#..........#.#.............#.
        #......#.#....#.#.#....#.##....
        .#.#.#.............#....#...#..
        ......#.....#.#...#..###.#..#..
        .....#..#............#...#...##
        ..#......###..#........#.#.....
        #..##......#.#.#.#...........#.
        #..#...##.##.....#....#..#.....
        ...##.#..........#.#....#...#..
        .#.#.#.#..#.#...#......#.......
        ....#......###.#...............
        .........#...#....#...#.#....#.
        ##.#.........#...##............
        ........#..........#.#...#.....
        ..#........#....#.......#......
        #..#...............#..#...##.#.
        #........#.....##.#..#....#...#
        ..##....#....#.#...........##..
        ....#.#.........#..#.....#..#..
        .......##....#.#.#....###.#....
        ......#....#.#...#..#.........#
        .....##..#....#.#......#.#.#...
        #.##..##.#.......#..#...##.#.##
        ........#.#..#...##.#.#..#.....
        #..#......#......#...#.#..#....
        .....#......#.#....##....##....
        ....#.##...##..#..........##.#.
        .#....#.......#.........#......
        .#.......#.#...#...............
        ....#.##.......#.##..#.##..#...
        #..#.......#.....#..#..........
        ..#.##.......#....#.#..##..#...
        .#.....#...##.#.#..#...#.......
        .......#.........#......#.#....
        #.##.....##.......#....#.......
        ##.#.#.........##..#.....#....#
        ....#.#.#.#....#..#..##.......#
        #...#...........#.#............
        ...#...#.#..#..##..............
        ......#.......#.........#..#.#.
        #.....##.#....#...#..#.........
        #...#..###.##..###...##.....#..
        #....#.#.#...#.#..........#....
        ................#.#....#.....##
        #.##..............####.....#.##
        ................#.....#........
        #...#..#......#.....#......#...
        .........##...........#...#...#
        #.#....#...##.....#.....#..#..#
        .....#...##..##.............#..
        ....###.#.......#.........#...#
        ..#.......#......#..#...#.#....
        #.#....#......#.##....#.##.#...
        .#.#...#.......#.#...#.##..#...
        ..........#......#.....#.......
        ........#...#.....#...##...#.#.
        .....##....#.##..#........#.##.
        ..........##.....#..#........#.
        .#....#..#.......#.##..........
        .#..#..#...#...#........#.##...
        .#...#.##.......#...#........#.
        .....#....#.............#..#...
        ...#....##...#...#.....##......
        #.#####.........##...#.....#...
        ......#.......#....#.....#..#..
        ..#..............#.#..#..#.....
        ....#.................#...#....
        ###.#..##.#....#...#.#......#.#
        ..##......#.#........#.#...##..
        .....#...#...#..#.#..#..##..#..
        .##...#......#...#...##.#...#..
        .......###.#...........##.##...
        .#.##..#.#.###.......#..##...#.
        ..#....#.......#..##......#....
        .#....#.#..#..#.#.#....#...#...
        ..........##....#....#.#.......
        .....#.......#.#..###.#.###....
        .#.#....#.##..#.#..#.....#.#.#.
        ....#.....#.#.#............#...
        .###....#...##......##..###..#.
        ...#.#..#.....#...#....##..#...
        .#.#....#..........#...##.....#
        #.....##...#........#.#..##..#.
        .......#....#.#..........#...#.
        .........#..#.#.###.........##.
        ..................#.#....#....#
        ....#....#.#..#.......###.##.##
        ....#...#.................#....
        ...#..#####.......#.#..##.##...
        ##.#....#...............#..#...
        ....#..........#...........#.#.
        ..##.#.##.#..#.#....#..........
        .....#....#....##.#....#....#.#
        .......#..##.....###...#....#.#
        .#.......#..#.#.#...........#..
        .#...........##.#.##....#.#....
        ....#.#....#.#.#......##.......
        .........##......#.#.....###...
        ........#.#...#.##.....#.##.##.
        ##.#..##.#.........#....#......
        .#.#.#....#..........#.#....#..
        ....###.........#.#.#..........
        #..#....##.....#...............
        #.##....#.#...#.....#......#.#.
        ............#.##........#......
        .....#.#.....##..##............
        .##..........#.......#......#..
        ...##..##......#.....#..#....##
        .##.##...#.................##..
        #....#.#........#..#....#..##.#
        ....##..##......#....###.#.#..#
        .....#....#..#..#...##...#...#.
    """.trimIndent()
}
package aoc

import org.assertj.core.api.KotlinAssertions.assertThat
import org.junit.Test

class Day3TobogganTrajectory {
    private fun rideToboggan(map: Map<Point, Char>, pathFunction: (Point) -> Point): Map<Point, Char> {
        val maxX = map.keys.map { it.x }.max() ?: 0
        val maxY = map.keys.map { it.y }.max() ?: 0

        fun getWithLoop(point: Point): Char? {
            return map[point] ?: map[point.copy(x = point.x.rem(maxX + 1))]
        }

        val path = generateSequence(Point(0, 0), pathFunction)
            .takeWhile { it.y <= maxY }
            .toList()

        return path.map { point ->
            point to when (getWithLoop(point)) {
                '#' -> 'X'
                else -> 'O'
            }
        }.toMap()
    }

    @Test
    fun silverTest() {
        val map = parseMap(testInput)
        val collisions = rideToboggan(map) { point ->
            point.right().right().right().down()
        }

        printMap(map + collisions)

        assertThat(collisions.count { (_, it) -> it == 'X' }).isEqualTo(7)
    }

    @Test
    fun silverTask() {
        val map = parseMap(input)
        val collisions = rideToboggan(map) { point ->
            point.right().right().right().down()
        }

        assertThat(collisions.count { (_, it) -> it == 'X' }).isEqualTo(274)
    }

    @Test
    fun goldTest() {
        val map = parseMap(testInput)
        val product = multiplyTreeHits(map)
        assertThat(product).isEqualTo(336)

        assertThat(rideToboggan(map) { point -> point.right().down() }.values.count { it == 'X' }).isEqualTo(2)
        assertThat(rideToboggan(map) { point ->
            point.right().right().right().down()
        }.values.count { it == 'X' }).isEqualTo(7)
        assertThat(rideToboggan(map) { point -> point.right(inc = 5).down() }.values.count { it == 'X' }).isEqualTo(3)
        assertThat(rideToboggan(map) { point -> point.right(inc = 7).down() }.values.count { it == 'X' }).isEqualTo(4)
        assertThat(rideToboggan(map) { point -> point.right().down(inc = 2) }.values.count { it == 'X' }).isEqualTo(2)
    }

    @Test
    fun goldTask() {
        val product = multiplyTreeHits(parseMap(input))
        assertThat(product).isEqualTo(6050183040)
    }

    /**
     * Right 1, down 1.
     * Right 3, down 1. (This is the slope you already checked.)
     * Right 5, down 1.
     * Right 7, down 1.
     * Right 1, down 2.
     */
    private fun multiplyTreeHits(map: Map<Point, Char>): Long {
        return listOf(
            rideToboggan(map) { point -> point.right().down() },
            rideToboggan(map) { point -> point.right(inc = 3).down() },
            rideToboggan(map) { point -> point.right(inc = 5).down() },
            rideToboggan(map) { point -> point.right(inc = 7).down() },
            rideToboggan(map) { point -> point.right().down(inc = 2) }
        )
            .map { it.count { (_, it) -> it == 'X' }.toLong() }
            .reduce { l, r -> l * r }
    }

    val testInput = """
..##.......
#...#...#..
.#....#..#.
..#.#...#.#
.#...##..#.
..#.##.....
.#.#.#....#
.#........#
#.##...#...
#...##....#
.#..#...#.#
""".trimIndent()

    val input = """
        ......#..##..#...#...#.###.....
        #..#............#..........#...
        ..........#....#..........#....
        ....#..#.#..........#..#.....#.
        #.......#...#......#........###
        #####........#.#....##..##..#..
        ......#.#..#..#..##.#..#.##....
        .#..#.#..............##....##..
        ..##......#....#........#...###
        ...#....#.#....#.#..#......#..#
        ..................#.....#.....#
        #.#...#...#....#............#.#
        .#...#.....#...##........#.....
        ...#....#........#..#....#..###
        #...##.....##.#.#...........#.#
        .###........#.#.#.........#....
        ...#.............###.....#.#..#
        .####.#..#....#.....#.........#
        .#.#........#.#.....#.....#....
        .#.......#................##.##
        ...#.#..#...###.....#....#..##.
        ...#....##..#............##...#
        #...#............######...#.##.
        .........#........#.#...#..##..
        .....###..#.#.....##.#.#......#
        ..#.#...#.#..#.#.##..#.....#.#.
        ..#......#.#....#...#..........
        ..#...#.....#.#...##.....#.....
        .##...........####........##...
        ....#............#.#...........
        .....####.........#.##....###..
        #..#..#.#..............#.#.....
        ...#.#........#.........#......
        ......#.#.#...#.....#....#.....
        ........#.#...#####..#..#......
        .....#.#....#....#...........##
        .#...#.........#.......##......
        .#.##..##......#...............
        ...#.....#.......#.#.#.........
        .........#..#...#...#.#.##....#
        .#......##....#..#.........#...
        ....#.....#........#.........##
        ......#...........##...........
        .....#..............###.#....#.
        ........#..#...#..#..#..#..#.#.
        .#.....#.##.#..#..#.#.....#....
        ...#....#...#.#.....##.#...#..#
        #..#......#..#.###...........#.
        .##...##.#........#.#......#.#.
        ...#.#..#.#.......#..###...##..
        #.......#.#....#..........#....
        .#.....#..#.#.#..#..#........#.
        .#...#......#.#...#.##.....#.##
        ...######..#.#....#.........##.
        #.#.......................#....
        ..#..##...#...#.#..##.......#..
        .##..#.......##......##.#..#...
        #.#....##.......#..#...........
        ..#...#............#..#........
        ........#.#.........#...#..#..#
        .#...###...............##...#..
        ...........#.....#....#....###.
        #..#....##..#................##
        ...#.#..#..##......#....##....#
        ...#.##...#....#..#....#.......
        #...##..##.#.........#...#....#
        .##........###.#..........#....
        ..#..#..#...#.##..#.#......#...
        .......##..#....###.##.....#..#
        #....#...#.#.....#..###....##..
        .#.......#.........#....#.#..#.
        .........#.......#.#.......#...
        ..........#...##..#...#....#.##
        ..#........#.......#...........
        #....#.....##......#....#.#...#
        ......#.....#....#.....#..#....
        .#....##...#...##..............
        ..#....#......#...#....#...#...
        #....###...##..#.#....##......#
        ..#.......#.........#..#......#
        ...#...#.##.......#....##..#...
        ..#.#...#.##..#..#..#...#.#...#
        .#.........###....#....#.....#.
        .#.##.#..##..#...........#....#
        ....##..#..##.#.......#....#..#
        ....#..#.........##..#......#.#
        ..........#.#.#....##.#......##
        .##...#....###...#..........#..
        #..#.....#..#.#.#.#..#......#.#
        ......#....#......##.#......#.#
        ...#.....#.......#....#.......#
        .#.#................#..........
        ......#..#..#...............##.
        ##......#...#.####....#.#.#....
        ...#..##............#....#.....
        ..#..#.#...#..................#
        .##.#.#..##.###.....#..#.......
        ..#...#.#...#......#..#........
        .###..........##...###..##..#..
        #.#...#........#.......##......
        ..##...#........#....##...##...
        .......#.##.....#.#.##..#..##..
        ........#............#....##...
        ...#.#.#..#.........#.#.......#
        ..#..##.##...#.##...#....#...#.
        .....##.#...##............##...
        .#...#.###....#.......#...#...#
        .......#######.#....#.....#.#..
        ......#.......#............##..
        .....#...........#......#.....#
        ........#....#.##.#............
        .#........#.......##.#.#....#..
        #.....#..####.#................
        .....#.......................##
        .#.....#..##.#..##........#.#.#
        #...##....#..##................
        ......##.###..........#.....#..
        .#........#...#..............##
        ..#..........###.........#.....
        ....#.....##....#..#..#.#.#....
        ....#.......#.##...#.####.#....
        #........#............#.##.....
        ..#......##.....#..#...#.......
        ..#......###...#.##......#..#..
        #..#..#............#..#.###....
        ...##.........#..##...#..#.#...
        ..#.###..#.##.#........#..#....
        ......#..###.#........#........
        .#....#.#..#.....#..#..#.......
        #.....##.##...#...###.#.#..#.#.
        .#....#..#.........#..#....###.
        ......##.####...#....#........#
        ##..#........#..#..##...#......
        #.........#.........#...#..#.#.
        ..........#...................#
        ###....#....#....#......###...#
        #....##........#..###.#..#.....
        .#......#.....#.#.........#..#.
        ...#.......##.....#.........###
        ..............#........#.....##
        ....#.#..#.....###.#....##.....
        .........#..##.#....#.#........
        ...#....#.......#.#.#..#.#....#
        ...........#...#..........#.#..
        #.................##........###
        ####..#.#..#...#.....###.......
        ..#.#......##.#.......#........
        .......##........#..#.....#..#.
        ...#..#......#..#.#.......###..
        #....#...##..#.#.#.#.........#.
        ....#....#....#.#..#..........#
        ...###........#.#.###......##..
        ................#.....#.#...##.
        ..#..#.###...........#...###.#.
        .........................#..#.#
        #...#..#..##.###.....##.##.#...
        ...#..................#.#....#.
        ......#..##.#.......#.......#..
        .##....#.#................#....
        .#...#..#.#.#....##....#.......
        .##......#.....#..........#....
        ..#...........#..##.........#..
        ....#.#...........#..........##
        ....#.#.#...........#.#........
        ......#.....#..#....##....##...
        ............##...##......#.#.##
        #.#.....#..#....#..#...#.#...#.
        .#...###..#..#.......#.......#.
        .....#..#.##.....#....#...#....
        ##.....#..##.......##..#.#.#..#
        ....#.#......##....#.....#..###
        .#...#.#......#.##...#..##.....
        .#...#...#......##..#..#...#.#.
        .#.........#....##...###...##..
        ###.....#......####.....#.#....
        .....#..##.##................#.
        .#.................#...#..##.#.
        ....#....#..#.......#.....#....
        .##....#..#..#.....###.#..#..#.
        #.#.......#.....##...#.....#...
        #.#........#.#.###...#....#....
        .#.....#.....##.#...#..#.......
        ..###.#............#...##.###..
        .....#.....#..#..##............
        .#.#..#.#..##..#....#...##.....
        .#...........#..#.......#...#.#
        #.#.#.#.....##....#............
        ...#.................#.#......#
        .....##.............#...#.#....
        .##......#.#....#..........#.#.
        .#.##.......##...#...#.....#.#.
        #...#.#........#......##....#.#
        #....##....#....#...#..#..#.#.#
        ......#..........#...#.....#..#
        #..#....#....#..##.#..#.#...#..
        ......#..#.#....#.....#.#..#..#
        ...#.#...###........#.#......##
        ..#............................
        ...#.#..##...##...#...#......##
        ...#.####......#.........#....#
        .#...#.#...##....#......#.#....
        .#.....##..##.#................
        .#...............#.............
        ......#.....#...#..##..##......
        ...#..##.......#.......#..#.#.#
        ......##.....#..#.....#...#.#.#
        ........##........#.#........##
        .#....#.....###..#.......#...#.
        #...#....#.........#.......#...
        ...##..#........#####.#........
        ###..#....#.#..#...#.####......
        ..#..........#.#.............#.
        #......#.#....#.#.#....#.##....
        .#.#.#.............#....#...#..
        ......#.....#.#...#..###.#..#..
        .....#..#............#...#...##
        ..#......###..#........#.#.....
        #..##......#.#.#.#...........#.
        #..#...##.##.....#....#..#.....
        ...##.#..........#.#....#...#..
        .#.#.#.#..#.#...#......#.......
        ....#......###.#...............
        .........#...#....#...#.#....#.
        ##.#.........#...##............
        ........#..........#.#...#.....
        ..#........#....#.......#......
        #..#...............#..#...##.#.
        #........#.....##.#..#....#...#
        ..##....#....#.#...........##..
        ....#.#.........#..#.....#..#..
        .......##....#.#.#....###.#....
        ......#....#.#...#..#.........#
        .....##..#....#.#......#.#.#...
        #.##..##.#.......#..#...##.#.##
        ........#.#..#...##.#.#..#.....
        #..#......#......#...#.#..#....
        .....#......#.#....##....##....
        ....#.##...##..#..........##.#.
        .#....#.......#.........#......
        .#.......#.#...#...............
        ....#.##.......#.##..#.##..#...
        #..#.......#.....#..#..........
        ..#.##.......#....#.#..##..#...
        .#.....#...##.#.#..#...#.......
        .......#.........#......#.#....
        #.##.....##.......#....#.......
        ##.#.#.........##..#.....#....#
        ....#.#.#.#....#..#..##.......#
        #...#...........#.#............
        ...#...#.#..#..##..............
        ......#.......#.........#..#.#.
        #.....##.#....#...#..#.........
        #...#..###.##..###...##.....#..
        #....#.#.#...#.#..........#....
        ................#.#....#.....##
        #.##..............####.....#.##
        ................#.....#........
        #...#..#......#.....#......#...
        .........##...........#...#...#
        #.#....#...##.....#.....#..#..#
        .....#...##..##.............#..
        ....###.#.......#.........#...#
        ..#.......#......#..#...#.#....
        #.#....#......#.##....#.##.#...
        .#.#...#.......#.#...#.##..#...
        ..........#......#.....#.......
        ........#...#.....#...##...#.#.
        .....##....#.##..#........#.##.
        ..........##.....#..#........#.
        .#....#..#.......#.##..........
        .#..#..#...#...#........#.##...
        .#...#.##.......#...#........#.
        .....#....#.............#..#...
        ...#....##...#...#.....##......
        #.#####.........##...#.....#...
        ......#.......#....#.....#..#..
        ..#..............#.#..#..#.....
        ....#.................#...#....
        ###.#..##.#....#...#.#......#.#
        ..##......#.#........#.#...##..
        .....#...#...#..#.#..#..##..#..
        .##...#......#...#...##.#...#..
        .......###.#...........##.##...
        .#.##..#.#.###.......#..##...#.
        ..#....#.......#..##......#....
        .#....#.#..#..#.#.#....#...#...
        ..........##....#....#.#.......
        .....#.......#.#..###.#.###....
        .#.#....#.##..#.#..#.....#.#.#.
        ....#.....#.#.#............#...
        .###....#...##......##..###..#.
        ...#.#..#.....#...#....##..#...
        .#.#....#..........#...##.....#
        #.....##...#........#.#..##..#.
        .......#....#.#..........#...#.
        .........#..#.#.###.........##.
        ..................#.#....#....#
        ....#....#.#..#.......###.##.##
        ....#...#.................#....
        ...#..#####.......#.#..##.##...
        ##.#....#...............#..#...
        ....#..........#...........#.#.
        ..##.#.##.#..#.#....#..........
        .....#....#....##.#....#....#.#
        .......#..##.....###...#....#.#
        .#.......#..#.#.#...........#..
        .#...........##.#.##....#.#....
        ....#.#....#.#.#......##.......
        .........##......#.#.....###...
        ........#.#...#.##.....#.##.##.
        ##.#..##.#.........#....#......
        .#.#.#....#..........#.#....#..
        ....###.........#.#.#..........
        #..#....##.....#...............
        #.##....#.#...#.....#......#.#.
        ............#.##........#......
        .....#.#.....##..##............
        .##..........#.......#......#..
        ...##..##......#.....#..#....##
        .##.##...#.................##..
        #....#.#........#..#....#..##.#
        ....##..##......#....###.#.#..#
        .....#....#..#..#...##...#...#.
    """.trimIndent()
}