Untitled

 avatar
unknown
kotlin
2 years ago
4.5 kB
4
Indexable
package org.aliance3

import kotlin.random.Random

fun main() {
    IslandKotlinTest().test()
}

class IslandKotlinTest {

//    @Test
    fun test() {
        val island = Island(28, 10)
        while (true) {
            val values = readln().split(" ").map { it.toInt() }
            island.from = Point(values[0], values[1])
            island.to = Point(values[2], values[3])
            println(island.ownToString())
        }
    }
}

class Island(private val cols: Int, private val rows: Int)  {

    private val random = Random.Default
    private val map = Table(cols, rows) { coin() }

    var from: Point = Point(1, 1)
    var to: Point = Point(cols, rows)

    private fun markPath() {
        findPath(from, to).forEach { map.set(it, 2) }
    }

    private fun findPath(from: Point, to: Point) =
        buildEdgesTree(from, to).let { if (it.isEmpty()) listOf() else traverseThroughMap(it, to) }

    private fun traverseThroughMap(edges: Map<Point, Point>, to: Point) =
        generateSequence(to) { edges[it] }.toList().reversed()

    private fun buildEdgesTree(from: Point, to: Point): Map<Point, Point> {
        val markUpMap = Table(cols, rows) { false }
        val edges = HashMap.newHashMap<Point, Point>(cols * rows)
        val queue = ArrayDeque<Point>()
        queue += from
        markVisited(markUpMap, from)
        while (queue.isNotEmpty() && queue.first() != to) {
            val cur = queue.removeFirst()
            neighbours(cur, markUpMap) { neighbour ->
                queue += neighbour
                markVisited(markUpMap, neighbour)
                edges[neighbour] = cur
            }
        }
        return if (queue.isEmpty()) mapOf() else edges
    }

    private fun countIslands(): Int {
        val markUpMap = Table(cols, rows) { false }
        var k = 0
        map.forEach {
            if (it.value == 1 && !markUpMap.get(it.point)) {
                ++k
                markIslandAsVisited(it.point, markUpMap)
            }
        }
        return k
    }

    private fun markIslandAsVisited(point: Point, markUpMap: Table<Boolean>) {
        markVisited(markUpMap, point)
        neighbours(point, markUpMap) { markIslandAsVisited(it, markUpMap) }
    }

    private fun neighbours(p: Point, markUpMap: Table<Boolean>, consumer: (Point) -> Unit) {
        return 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 { it.x in 1..cols && it.y in 1..rows }
            .filter { !markUpMap.get(it) }
            .filter { map.get(it) == 1 }
            .forEach { consumer.invoke(it) }
    }

    private fun markVisited(markUpMap: Table<Boolean>, point: Point) {
        markUpMap.set(point, true)
    }

    private fun coin() = random.nextInt(100).let { if (it > 30) 1 else 0 }

    fun ownToString(): String {
        markPath()
        val builder = StringBuilder(rows * cols)
        map.forEach { c ->
            builder.append(
                when (c.value) {
                    0 -> "@"
                    1 -> "·"
                    2 -> "+"
                    else -> IllegalStateException()
                }
            )
            builder.append(" ")
            if (c.point.x == cols) {
                builder.append("\n")
            }
        }
        builder.append("Islands: ").append(countIslands()).append("\n")
        return builder.toString()
    }
}

data class Point(val x: Int, val y: Int)
data class Cell<T> (var value: T, val point: Point)

class Table<T> (val cols: Int, val rows: Int, private val initFunction: () -> T) : Iterable<Cell<T>> {

    private val table = generateSequence {
        MutableList<T>(rows) { initFunction.invoke() }
    }.take(cols).toList()

    override fun iterator() = Iter()
    fun get(x: Int, y: Int) = table[x - 1][y - 1]
    fun get(point: Point) = get(point.x, point.y)
    fun set(point: Point, value: T) {
        table[point.x - 1][point.y - 1] = value
    }

    inner class Iter : Iterator<Cell<T>> {
        private var x: Int = -1
        private var y: Int = 0

        override fun hasNext() = x != cols - 1 || y != rows - 1
        override fun next(): Cell<T> {
            if (x != cols - 1) {
                x += 1
            } else {
                x = 0
                y += 1
            }
            return Point(x + 1, y + 1).let { Cell(get(it), it) }
        }
    }

}

Editor is loading...