153 lines
No EOL
4.8 KiB
Scala
153 lines
No EOL
4.8 KiB
Scala
package bot
|
|
|
|
import scala.util.Random
|
|
import DebugUtil.{ log, dbg, time }
|
|
import scala.collection.mutable
|
|
|
|
sealed trait Direction {
|
|
val label: String
|
|
val deltaX: Int
|
|
val deltaY: Int
|
|
override def toString: String = label
|
|
}
|
|
final case object Left extends { val label = "left"; val deltaX = -1; val deltaY = 0 } with Direction
|
|
final case object Right extends { val label = "right"; val deltaX = 1; val deltaY = 0 } with Direction
|
|
final case object Up extends { val label = "up"; val deltaX = 0; val deltaY = -1 } with Direction
|
|
final case object Down extends { val label = "down"; val deltaX = 0; val deltaY = 1 } with Direction
|
|
|
|
class Cortex {
|
|
def move(state: State, time: Int): Direction = {
|
|
val directions: Seq[Direction] = possibleDirections(state.bofaField, state)
|
|
val weightBoard = weightCodes(1000, decr, state)
|
|
val dir = getMaxDir(state.bofaField, directions, weightBoard, state)
|
|
weightBoard(state.bofaField.x)(state.bofaField.y) = -999
|
|
printBoard(weightBoard)
|
|
|
|
dir
|
|
}
|
|
|
|
def decr(dist: Int, start: Int) = {
|
|
(start/math.pow(2, (dist+1))).intValue()
|
|
}
|
|
|
|
def getMaxField(weightBoard: Array[Array[Int]], state: State): Field = {
|
|
var maxField = (0,0)
|
|
for (x <- 0 until S.width; y <- 0 until S.height) {
|
|
if (weightBoard(x)(y) > weightBoard(maxField _1)(maxField _2)) maxField = (x,y)
|
|
}
|
|
|
|
state.board(maxField _1)(maxField _2)
|
|
}
|
|
|
|
def shortestPathTo(field: Field, state: State) = {
|
|
0
|
|
}
|
|
|
|
def mod(a: Int)(b: Int): Int = (a % b) + (if (a < 0) b else 0)
|
|
|
|
def getMaxDir(field: Field, directions: Seq[Direction], weightBoard: Array[Array[Int]], state: State): Direction = {
|
|
var maxDir: Direction = randomDirection(directions)
|
|
val board = state.board
|
|
|
|
for (d <- directions){
|
|
var (x,y) = (mod (field.x+d.deltaX) (S.width), mod (field.y+d.deltaY) (S.width))
|
|
var (maxX, maxY) = (mod (field.x+maxDir.deltaX) (S.width), mod (field.y+maxDir.deltaY) (S.width))
|
|
|
|
if (weightBoard(x)(y) > weightBoard(maxX)(maxY)) maxDir = d
|
|
}
|
|
|
|
maxDir
|
|
}
|
|
|
|
def possibleDirections(field: Field, state: State): Seq[Direction] = {
|
|
val pd = new mutable.ListBuffer[Direction]
|
|
val board = state.board
|
|
|
|
val toCheck = checkBorder(field, state)
|
|
|
|
for (d <- toCheck) {
|
|
if ( d == Left && board(field.x)(field.y).citizens.contains(Gate("l")) ) pd += d
|
|
else if ( d == Right && board(field.x)(field.y).citizens.contains(Gate("r")) ) pd += d
|
|
else {
|
|
val pfield = board(field.x + d.deltaX)(field.y + d.deltaY)
|
|
if (!(pfield.citizens contains Wall)) {
|
|
pd += d
|
|
}
|
|
}
|
|
}
|
|
|
|
pd
|
|
}
|
|
|
|
def weightCodes(start: Int, drop: (Int, Int) => Int, state: State): Array[Array[Int]] = {
|
|
val board = state.board
|
|
val codes = state.codes
|
|
val weightBoard = Array.ofDim[Int](S.width, S.height)
|
|
|
|
log(s"Codes: ${codes.length}")
|
|
|
|
|
|
for (code <- codes) {
|
|
val visited = Array.ofDim[Boolean](S.width, S.height)
|
|
for (x <- 0 until S.width; y <- 0 until S.height) visited(x)(y) = false
|
|
|
|
var coords: Seq[Field] = Seq.empty
|
|
val frontier = new mutable.ListBuffer[Field]
|
|
|
|
frontier += code
|
|
var weight = start
|
|
var dist = 0
|
|
|
|
while (weight >= drop(dist, start) && !frontier.isEmpty) {
|
|
coords = frontier.toList
|
|
frontier.clear()
|
|
|
|
for(field <- coords){
|
|
val dirs = possibleDirections(field, state)
|
|
for (d <- dirs) {
|
|
var (x,y) = (field.x+d.deltaX, field.y+d.deltaY)
|
|
if ( d == Left && board(field.x)(field.y).citizens.contains(Gate("l")) ) x = S.width-1
|
|
else if ( d == Right && board(field.x)(field.y).citizens.contains(Gate("r")) ) x = 0
|
|
|
|
if (!visited(x)(y)) frontier += board(x)(y)
|
|
}
|
|
|
|
if (!visited(field.x)(field.y)) weightBoard(field.x)(field.y) += weight
|
|
visited(field.x)(field.y) = true
|
|
}
|
|
|
|
weight -= drop(dist, start)
|
|
dist += 1
|
|
}
|
|
}
|
|
|
|
weightBoard
|
|
}
|
|
|
|
def checkBorder(field: Field, state: State): Seq[Direction] = {
|
|
val dirs = new mutable.ListBuffer[Direction]
|
|
|
|
if (field.y != 0) dirs += Up
|
|
if (field.y != (S.height-1)) dirs += Down
|
|
if (field.x != 0 || field.citizens.contains(Gate("l"))) dirs += Left
|
|
if (field.x != (S.width-1) || field.citizens.contains(Gate("r"))) dirs += Right
|
|
|
|
dirs
|
|
}
|
|
|
|
def randomDirection(directions: Seq[Direction]) = directions(Random.nextInt(directions.length))
|
|
|
|
def printBoard(board: Array[Array[Int]]) = {
|
|
val btp = board.transpose
|
|
val buf = new StringBuilder
|
|
buf append "\n+" + "-" * (S.width * 10) + "+" + "\n"
|
|
for (line <- btp) {
|
|
buf append s"""|${line.map(_.toString.padTo(4, ' ')).mkString("|")}|"""
|
|
buf append "\n+" + "-" * (S.width * 10) + "+" + "\n"
|
|
}
|
|
|
|
log(buf toString)
|
|
}
|
|
}
|
|
|
|
|