forked from charlesfranciscodev/codingame
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsurface.kt
99 lines (84 loc) · 2.38 KB
/
surface.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
import java.util.Scanner
import java.util.ArrayDeque
const val LAND = '#'
const val WATER = 'O'
const val DEFAULT_INDEX = -1
fun main(args : Array<String>) {
val grid = Grid()
grid.readGameInput()
grid.test()
}
data class Square(val x: Int, val y: Int, val terrain: Char, var lakeIndex: Int = DEFAULT_INDEX)
class Grid {
val input = Scanner(System.`in`)
var width = 0
var height = 0
val nodes = ArrayList<List<Square>>()
val lakes = HashMap<Int, Int>() // lake_index -> surface area
fun readGameInput() {
width = input.nextInt()
height = input.nextInt()
if (input.hasNextLine()) {
input.nextLine()
}
for (y in 0 until height) {
val row = input.nextLine().withIndex().map { Square(it.index, y, it.value) }
nodes.add(row)
}
}
fun test() {
val n = input.nextInt()
for (i in 0 until n) {
val x = input.nextInt()
val y = input.nextInt()
println(area(x, y))
}
}
fun area(x: Int, y: Int): Int {
val node = nodes[y][x]
if (node.terrain == LAND) {
return 0
}
if (node.lakeIndex == DEFAULT_INDEX) {
floodFill(node)
}
return lakes.getOrDefault(node.lakeIndex, 0)
}
// Source https://en.wikipedia.org/wiki/Flood_fill
fun floodFill(start: Square) {
val queue = ArrayDeque<Square>()
var totalArea = 0
start.lakeIndex = start.y * width + start.x
queue.add(start)
while (!queue.isEmpty()) {
totalArea++
val current = queue.poll()
fillNeighbors(queue, current, start.lakeIndex)
}
lakes.put(start.lakeIndex, totalArea)
}
fun fillNeighbors(queue: ArrayDeque<Square>, square: Square, lakeIndex: Int) {
if (square.x + 1 < width) {
val rightNeighbor = nodes[square.y][square.x + 1]
fill(queue, rightNeighbor, lakeIndex)
}
if (square.x > 0) {
val leftNeighbor = nodes[square.y][square.x - 1]
fill(queue, leftNeighbor, lakeIndex)
}
if (square.y + 1 < height) {
val downNeighbor = nodes[square.y + 1][square.x]
fill(queue, downNeighbor, lakeIndex)
}
if (square.y > 0) {
val upNeighbor = nodes[square.y - 1][square.x]
fill(queue, upNeighbor, lakeIndex)
}
}
fun fill(queue: ArrayDeque<Square>, square: Square, lakeIndex: Int) {
if (square.terrain == WATER && square.lakeIndex == DEFAULT_INDEX) {
square.lakeIndex = lakeIndex
queue.add(square)
}
}
}