Last active
December 30, 2015 10:49
-
-
Save lugu/7818183 to your computer and use it in GitHub Desktop.
Scalatron Bot #10
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import util.Random | |
class ControlFunction { | |
def respond(input: String) = { | |
val cmd = Command(input) | |
cmd.opcode match { | |
case "React" => { | |
if (cmd.generation == 0) { | |
val view = cmd.view | |
val stuffs = view.sorted.filter(cell => cell.isGood || cell.isBad) | |
if (stuffs.isEmpty) { | |
cmd.doMove(XY()) | |
} else { | |
val stuff: Cell = stuffs.head | |
if (stuff.isGood) { | |
cmd.doMove(stuff.pos) | |
} else { | |
cmd.doSpawn(stuff.pos, 100) | |
} | |
} | |
} else { | |
cmd.doMove(cmd.heading) | |
} | |
} | |
case s: String => { | |
cmd.doShowCommand | |
} | |
} | |
} | |
} | |
object XY { | |
val rnd = new Random() | |
def apply(): XY = new XY(rnd.nextInt(3)-1, rnd.nextInt(3)-1) | |
def apply(direction: String): XY = { | |
val directions = direction.split(':').map(_.toInt) | |
new XY(directions(0), directions(1)) | |
} | |
val Zero = XY(0,0) | |
val One = XY(1,1) | |
val Right = XY( 1, 0) | |
val RightUp = XY( 1, -1) | |
val Up = XY( 0, -1) | |
val UpLeft = XY(-1, -1) | |
val Left = XY(-1, 0) | |
val LeftDown = XY(-1, 1) | |
val Down = XY( 0, 1) | |
val DownRight = XY( 1, 1) | |
} | |
case class XY(val x: Int, val y: Int) { | |
override def toString = "%d:%d".format(x, y) | |
def add(that: XY) = new XY(x+that.x, y+that.y) | |
def isNonZero = x!=0 || y!=0 | |
def isZero = x==0 && y==0 | |
def isNonNegative = x>=0 && y>=0 | |
def updateX(newX: Int) = XY(newX, y) | |
def updateY(newY: Int) = XY(x, newY) | |
def addToX(dx: Int) = XY(x+dx, y) | |
def addToY(dy: Int) = XY(x, y+dy) | |
def +(pos: XY) = XY(x+pos.x, y+pos.y) | |
def -(pos: XY) = XY(x-pos.x, y-pos.y) | |
def *(factor: Double) = XY((x*factor).intValue, (y*factor).intValue) | |
def distanceTo(pos: XY) : Double = (this-pos).length | |
def length : Double = math.sqrt(x*x + y*y) | |
def signum = XY(x.signum, y.signum) | |
def negate = XY(-x, -y) | |
def negateX = XY(-x, y) | |
def negateY = XY(x, -y) | |
} | |
object View { | |
def apply(str: String): View = { | |
val size = math.sqrt(str.length).intValue | |
val center: XY = XY(size/2, size/2) | |
def posFromIndex(index: Int) = XY(index%size,index/size) - center | |
val cells = str.zipWithIndex.map{ | |
case (char, index) => new Cell(str.charAt(index), posFromIndex(index)) | |
} | |
new View(cells) | |
} | |
} | |
class View(val cells: Seq[Cell]) { | |
def sorted = cells.sortBy(_.pos.length) | |
def goods = sorted.filter(_.isGood) | |
def bads = sorted.filter(_.isGood) | |
} | |
case class Cell(value: Char, pos: XY) { | |
def isGood: Boolean = value match { | |
case 'P' => true | |
case _ => false | |
} | |
def isBad: Boolean = value match { | |
case '_' => false | |
case 'W' => false | |
case 'M' => false | |
case 'P' => false | |
case '?' => false | |
case _ => true | |
} | |
} | |
object Command { | |
// return the opcode and the params | |
def apply(input: String): Command = { | |
def splitArg(arg: String): Tuple2[String,String] = { | |
(arg.split('=')(0),arg.split('=')(1)) | |
} | |
def parseArgs(args: String): Map[String,String] = { | |
(args.split(',').map(splitArg)).toMap | |
} | |
if (input.isEmpty) throw new IllegalStateException("Empty command") | |
val tokens = input.dropRight(1).split('(') // split at '(', returns Array[String] | |
if (tokens.length < 2) throw new IllegalStateException("Missing arguments") | |
new Command(tokens(0), parseArgs(tokens(1))) | |
} | |
} | |
class Command(command: String, params: Map[String,String]) { | |
def apply(param: String): String = params(param) | |
def energy: Int = params("energy").toInt | |
def opcode: String = command | |
def generation: Int = params("generation").toInt | |
def heading: XY = XY(params("heading")) | |
def view: View = View(params("view")) | |
def doSpawn(direction: XY, energy: Int): String = { | |
val message = "Spawn(direction=%s,energy=%d,heading=%s)" | |
message.format(direction, energy, direction) | |
} | |
def doMove(direction: XY): String = { | |
val message = "Move(direction=%s)" | |
message.format(direction) | |
} | |
def doShowCommand: String = { | |
val message = "Status(text=Command:%s\n%s)" | |
message.format(opcode, params.mkString("\n")) | |
} | |
} | |
class ControlFunctionFactory { | |
def create = new ControlFunction().respond _ | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment