mshackman/bofa/src/main/scala/bot/Cortex.scala
2017-11-05 22:50:13 +01:00

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)
}
}