better weighing function for Codes; simple bug avoidance heuristic

This commit is contained in:
Armin Friedl 2017-11-06 17:32:36 +01:00
parent dc6308e364
commit 005d2a3ab6
6 changed files with 410 additions and 73 deletions

File diff suppressed because one or more lines are too long

141
bofa/Calculations.ipynb Normal file

File diff suppressed because one or more lines are too long

View file

@ -1,3 +1,9 @@
bot.zip: src/main/scala/bot/*.scala release:
cd src/main/scala/bot && sed -i 's/Boolean = true/Boolean = false/' DebugUtil.scala cd src/main/scala/bot && sed -i 's/Dbg: Boolean = true/Dbg: Boolean = false/' DebugUtil.scala
cd src/main/scala/bot && sed -i 's/Dbg: Boolean = false/Dbg: Boolean = true/' DebugUtil.scala
cd src/main/scala && zip -r bot bot && mv bot.zip $(CURDIR)
dbg:
cd src/main/scala/bot && sed -i 's/Dbg: Boolean = false/Dbg: Boolean = true/' DebugUtil.scala
cd src/main/scala/bot && sed -i 's/Dbg: Boolean = true/Dbg: Boolean = false/' DebugUtil.scala
cd src/main/scala && zip -r bot bot && mv bot.zip $(CURDIR) cd src/main/scala && zip -r bot bot && mv bot.zip $(CURDIR)

View file

@ -5,7 +5,6 @@ import DebugUtil.{log,dbg,time}
object Main { object Main {
def main(args: Array[String]) = { def main(args: Array[String]) = {
var input: String = "" var input: String = ""
//Initialize general game settings //Initialize general game settings
@ -20,12 +19,14 @@ object Main {
log("init cortex") log("init cortex")
val cortex = new Cortex() val cortex = new Cortex()
log("init debug") var tmpRound = currentState.round
DebugUtil.state = Some(currentState)
// Main loop // Main loop
while (input != null ){ while (input != null ){
if (tmpRound != currentState.round){
tmpRound = currentState.round
log("\n");
log(s"********** ROUND ${tmpRound} **********")
}
def cmd: Seq[String] = input.split(" ") def cmd: Seq[String] = input.split(" ")
// dispatch // dispatch

View file

@ -23,71 +23,71 @@ object Scribble {
class Cortex { class Cortex {
def move(state: State, time: Int): Direction = { def move(state: State, time: Int): Direction = {
val directions: Seq[Direction] = possibleDirections(state.bofaField, state) val directions: Seq[Direction] = possibleDirections(state.bofaField, state)
val weightBoard = weightCodes(1000, decr, state) val weightBoard = weightCodes(1000, weigh, state)
preventFallBack(weightBoard, state) preventFallBack(weightBoard, state)
preventLethal(weightBoard, state)
val dir = getMaxDir(state.bofaField, directions, weightBoard, state) val dir = getMaxDir(state.bofaField, directions, weightBoard, state)
Scribble.lastBofaField = state.bofaField Scribble.lastBofaField = state.bofaField
weightBoard(state.bofaField.x)(state.bofaField.y) = -999 weightBoard(state.bofaField.x)(state.bofaField.y) = -999
printBoard(weightBoard) printBoard(weightBoard)
dir dir
} }
def decr(dist: Int, start: Int) = { def weigh(start: Int, dist: Int, cur: Int) = {
val d = (start/math.pow(2.5, (dist+1))).intValue() (start / math.pow(1.3, (dist + 1))).intValue()
if (d < 5) 5 else d
} }
def getMaxField(weightBoard: Array[Array[Int]], state: State): Field = { def getMaxField(weightBoard: Array[Array[Int]], state: State): Field = {
var maxField = (0,0) var maxField = (0, 0)
for (x <- 0 until S.width; y <- 0 until S.height) { for (x <- 0 until S.width; y <- 0 until S.height) {
// generally, the highest is best // generally, the highest is best
if (weightBoard(x)(y) > weightBoard(maxField _1)(maxField _2)) maxField = (x,y) if (weightBoard(x)(y) > weightBoard(maxField _1)(maxField _2)) maxField = (x, y)
// if equal prefer to go down, right b/c up/left is evil first but // if equal prefer to go down, right b/c up/left is evil first but
if (weightBoard(x)(y) == weightBoard(maxField _1)(maxField _2)){ if (weightBoard(x)(y) == weightBoard(maxField _1)(maxField _2)) {
if (x > (maxField _1) || y > (maxField _2)) maxField = (x, y) if (x > (maxField _1) || y > (maxField _2)) maxField = (x, y)
} }
} }
state.board(maxField _1)(maxField _2) state.board(maxField _1)(maxField _2)
} }
def shortestPathTo(field: Field, state: State) = { def shortestPathTo(field: Field, state: State) = {
0 0
} }
def mod(a: Int)(b: Int): Int = (a % b) + (if (a < 0) b else 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 = { def getMaxDir(field: Field, directions: Seq[Direction], weightBoard: Array[Array[Int]], state: State): Direction = {
var maxDir: Direction = randomDirection(directions) var maxDir: Direction = randomDirection(directions)
val board = state.board val board = state.board
for (d <- directions){ for (d <- directions) {
var (x,y) = (mod (field.x+d.deltaX) (S.width), mod (field.y+d.deltaY) (S.width)) 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)) 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 if (weightBoard(x)(y) > weightBoard(maxX)(maxY)) maxDir = d
} }
maxDir maxDir
} }
def manhattan(x: Int, y: Int)(a: Int, b: Int): Int = math.abs(x-a) + math.abs(y-b) def manhattan(x: Int, y: Int)(a: Int, b: Int): Int = math.abs(x - a) + math.abs(y - b)
def possibleDirections(field: Field, state: State): Seq[Direction] = { def possibleDirections(field: Field, state: State): Seq[Direction] = {
val pd = new mutable.ListBuffer[Direction] val pd = new mutable.ListBuffer[Direction]
val board = state.board val board = state.board
val toCheck = checkBorder(field, state) val toCheck = checkBorder(field, state)
for (d <- toCheck) { for (d <- toCheck) {
if ( d == Left && board(field.x)(field.y).citizens.contains(Gate("l")) ) pd += d 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 if (d == Right && board(field.x)(field.y).citizens.contains(Gate("r"))) pd += d
else { else {
val pfield = board(field.x + d.deltaX)(field.y + d.deltaY) val pfield = board(field.x + d.deltaX)(field.y + d.deltaY)
if (!(pfield.citizens contains Wall)) { if (!(pfield.citizens contains Wall)) {
@ -95,84 +95,101 @@ class Cortex {
} }
} }
} }
pd pd
} }
def preventFallBack(weightBoard: Array[Array[Int]], state: State): Unit = { def preventFallBack(weightBoard: Array[Array[Int]], state: State): Unit = {
val lastBofaField = Scribble.lastBofaField val lastBofaField = Scribble.lastBofaField
if (lastBofaField != Field.empty){ if (lastBofaField != Field.empty) {
// if something changed allow fallback // if something changed allow fallback
log(s"lastFieldWeight=${Scribble.lastFieldWeight}") log(s"lastFieldWeight=${Scribble.lastFieldWeight}")
if (Scribble.lastFieldWeight == weightBoard(lastBofaField.x)(lastBofaField.y)){ if (Scribble.lastFieldWeight == weightBoard(lastBofaField.x)(lastBofaField.y)) {
Scribble.lastFieldWeight = weightBoard(state.bofaField.x)(state.bofaField.y) Scribble.lastFieldWeight = weightBoard(state.bofaField.x)(state.bofaField.y)
val x: Int = weightBoard(lastBofaField.x)(lastBofaField.y) val x: Int = weightBoard(lastBofaField.x)(lastBofaField.y)
weightBoard(lastBofaField.x)(lastBofaField.y) = (x - (0.1 * x)).intValue() weightBoard(lastBofaField.x)(lastBofaField.y) = (0.5 * x).intValue()
} else{ } else {
Scribble.lastFieldWeight = weightBoard(state.bofaField.x)(state.bofaField.y) Scribble.lastFieldWeight = weightBoard(state.bofaField.x)(state.bofaField.y)
} }
} }
} }
def weightCodes(start: Int, drop: (Int, Int) => Int, state: State): Array[Array[Int]] = { def preventLethal(weightBoard: Array[Array[Int]], state: State): Unit = {
val board = state.board
for (bug <- state.bugs) {
val dirs = possibleDirections(bug, state)
for (d <- dirs) {
var (x, y) = (bug.x + d.deltaX, bug.y + d.deltaY)
if (d == Left && board(bug.x)(bug.y).citizens.contains(Gate("l"))) x = S.width - 1
else if (d == Right && board(bug.x)(bug.y).citizens.contains(Gate("r"))) x = 0
weightBoard(x)(y) = (weightBoard(x)(y) * 0.1).intValue()
}
weightBoard(bug.x)(bug.y) = 1
}
}
def weightCodes(start: Int, weigh: (Int, Int, Int) => Int, state: State): Array[Array[Int]] = {
val board = state.board val board = state.board
val codes = state.codes val codes = state.codes
val weightBoard = Array.ofDim[Int](S.width, S.height) val weightBoard = Array.ofDim[Int](S.width, S.height)
for (x <- 0 until S.width; y <- 0 until S.height) weightBoard(x)(y) = 10
log(s"Codes: ${codes.length}") log(s"Codes: ${codes.length}")
for (code <- codes) { for (code <- codes) {
val visited = Array.ofDim[Boolean](S.width, S.height) val visited = Array.ofDim[Boolean](S.width, S.height)
for (x <- 0 until S.width; y <- 0 until S.height) visited(x)(y) = false for (x <- 0 until S.width; y <- 0 until S.height) visited(x)(y) = false
var coords: Seq[Field] = Seq.empty var coords: Seq[Field] = Seq.empty
val frontier = new mutable.ListBuffer[Field] val frontier = new mutable.ListBuffer[Field]
frontier += code frontier += code
visited(code.x)(code.y) = true
var weight = start var weight = start
var dist = 0 var dist = 0
while (weight >= drop(dist, start) && !frontier.isEmpty) { while (!frontier.isEmpty) {
coords = frontier.toList coords = frontier.toList
frontier.clear() frontier.clear()
for(field <- coords){ for (field <- coords) {
val dirs = possibleDirections(field, state) val dirs = possibleDirections(field, state)
for (d <- dirs) { for (d <- dirs) {
var (x,y) = (field.x+d.deltaX, field.y+d.deltaY) 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 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 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(x)(y)) frontier += board(x)(y)
visited(x)(y) = true
} }
if (!visited(field.x)(field.y)) weightBoard(field.x)(field.y) += weight weightBoard(field.x)(field.y) += weight
visited(field.x)(field.y) = true
} }
weight -= drop(dist, start) weight = weigh(start, dist, weight)
dist += 1 dist += 1
} }
} }
weightBoard weightBoard
} }
def checkBorder(field: Field, state: State): Seq[Direction] = { def checkBorder(field: Field, state: State): Seq[Direction] = {
val dirs = new mutable.ListBuffer[Direction] val dirs = new mutable.ListBuffer[Direction]
if (field.y != 0) dirs += Up if (field.y != 0) dirs += Up
if (field.y != (S.height-1)) dirs += Down if (field.y != (S.height - 1)) dirs += Down
if (field.x != 0 || field.citizens.contains(Gate("l"))) dirs += Left if (field.x != 0 || field.citizens.contains(Gate("l"))) dirs += Left
if (field.x != (S.width-1) || field.citizens.contains(Gate("r"))) dirs += Right if (field.x != (S.width - 1) || field.citizens.contains(Gate("r"))) dirs += Right
dirs dirs
} }
def randomDirection(directions: Seq[Direction]) = directions(Random.nextInt(directions.length)) def randomDirection(directions: Seq[Direction]) = directions(Random.nextInt(directions.length))
def printBoard(board: Array[Array[Int]]) = { def printBoard(board: Array[Array[Int]]) = {
val btp = board.transpose val btp = board.transpose
val buf = new StringBuilder val buf = new StringBuilder

View file

@ -3,8 +3,8 @@ package bot
object DebugUtil { object DebugUtil {
var state: Option[State] = None // we need this to get access to the current game round var state: Option[State] = None // we need this to get access to the current game round
val Dbg: Boolean = false val Dbg: Boolean = false
val Log: Boolean = false val Log: Boolean = true
val Time: Boolean = false val Time: Boolean = true
def dbg(msg: String) = if(Dbg) Console.err.println(s"$round $msg") def dbg(msg: String) = if(Dbg) Console.err.println(s"$round $msg")
def log(msg: String) = if(Log) Console.err.println(s"$round $msg") def log(msg: String) = if(Log) Console.err.println(s"$round $msg")