In CodinGame, code is executed on server side. This makes debugging a luxury. In this post, I’ll share how to debug your Bot with Scala’s case class.

Feed Game State to Bot

In CodinGame Scala Kit, we model Bot as a function which maps game state to actions. Therefore, to debug the Bot locally, we only need to feed it with the game state. The following example shows how I debug my Caribbean Bot:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
object CaribbeanPlayerDebug {

def main(args: Array[String]): Unit = {
val state = CaribbeanState(
CaribbeanContext(Map(), Map(2 -> 50, 0 -> 39)),
Map(0 -> Ship(0, Offset(8, 12), 1, 2, 64, 1)
, 2 -> Ship(2, Offset(10, 11), 2, 1, 50, 1)
, 1 -> Ship(1, Offset(20, 10), 4, 2, 67, 0)
, 3 -> Ship(3, Offset(17, 16), 5, 2, 59, 0)),
Map(),
Map(59 -> Ball(59, Offset(12, 14), 3, 1)
, 60 -> Ball(60, Offset(14, 17), 2, 2)),
Map(5 -> Mine(5, Offset(14, 12))
, 29 -> Mine(29, Offset(7, 8))
, 61 -> Mine(61, Offset(15, 12))
, 38 -> Mine(38, Offset(4, 10))
, 7 -> Mine(7, Offset(12, 16))
, 51 -> Mine(51, Offset(14, 10))
, 4 -> Mine(4, Offset(14, 8))), 51)

val player = CaribbeanPlayer(1, 0, new CountStopper(100))
println(player.reactTo(state))
}
}

Data as Code

In scala, when you print a case class, you get a magic string because it can re-instantiate the case class itself. To feed your bot, just print the game state.
As shown in the GameLoop, we print the game state at line13.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class GameLoop[C, S, A](
controller: GameController[C, S, A],
myPlayer: GamePlayer[S, A]
) {
def run(): Unit = {
val time = System.nanoTime()
val initContext = controller.readContext
controller.warmup(myPlayer)
System.err.println("GameInit elt: " + (System.nanoTime() - time) / 1000000 + "ms")
(1 to 200).foldLeft(initContext) {
case (c, turn) =>
val state = controller.readState(turn, c)
System.err.println(state)
val time = System.nanoTime()
val actions = myPlayer.reactTo(state)
System.err.println("GameReact elt: " + (System.nanoTime() - time) / 1000000 + "ms")
actions.foreach(a => println(a))
val context = controller.nextContext(c, state, actions)
context
}
}

}

Another real-world example in Ghost-in-the-Cell contest: