Skip to content

Instantly share code, notes, and snippets.

@lugu
Last active December 30, 2015 10:49
Show Gist options
  • Save lugu/7818183 to your computer and use it in GitHub Desktop.
Save lugu/7818183 to your computer and use it in GitHub Desktop.
Scalatron Bot #10
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