A simple SBT build for your Scalatron bot
Recently, the Scala world got richer again – we now have our own educational robot wars hacking environment: Scalatron.
Unfortunately, it’s not yet well documented or obvious how to set that environment up, except for a huuuge instructions document for IntelliJ IDEA. I mean, 13 pages?! – That just has to be doable in an easier way!
As I’m an Eclipse user and somewhat fluent with SBT, I thought I’d try to setup Scalatron with an SBT build. With the sbteclipse (and sbt-idea) plugins, I’ll then get the IDE setup for free.
So, let’s create a basic SBT build file. As I already suspect that I’ll need a build that’s a bit more complicated than a few lines of configuring standard settings, let’s start with a Build.scala file:
import sbt._
import Keys._
object Build extends Build {
val bot = Project(
id = "mybot",
base = file("."),
settings = Project.defaultSettings ++ botSettings)
val botSettings = Seq[Setting[_]](
organization := "de.johoop",
name := "my-scalatron-bot",
version := "1.0.0-SNAPSHOT",
scalaVersion := "2.9.1",
scalacOptions ++= Seq("-deprecation", "-unchecked"))
}
This simply initializes my bot project and adds a few standard Scala options I usually like to use.
Next, I want to add the dependency to the Scalatron jar file to the project. As Scalatron isn’t published anywhere, I’ll just create a lib directory and put the jar file from the Scalatron distribution in there.
Another basic thing that’s still missing from the build is the configuration of some kind of tests. I absolutely want to write tests against my bot’s functionality, as it’s very difficult to debug a bot during a running bot war. I’ll use Specs2 for that, of course, because it’s all kinds of genius. We’ll add the following lines to our botSettings:
libraryDependencies ++= Seq(
"org.specs2" %% "specs2" % "1.8.2" % "test",
"org.pegdown" % "pegdown" % "1.0.2" % "test",
"junit" % "junit" % "4.7" % "test"),
testOptions := Seq(
Tests.Filter(_ == "de.johoop.scalatron.BotSpec"),
Tests.Argument("html", "console")),
testOptions <+= crossTarget map { ct =>
Tests.Setup { () =>
System.setProperty("specs2.outDir",
new File(ct, "specs2").getAbsolutePath)
}
},
The first few lines add all required dependencies: pegdown for the nice HTML reports, junit for running the tests from within Eclipse using JUnit.
Then I tell SBT to just execute my main test specification called BotSpec and ignore any sub specifications. And I tell it to create HTML reports, too, and where to put them.
I can now already hack and test my bot to my heart’s content. However, I can’t yet try it out in the Scalatron environment. Let’s do something about this. I need a way to start the Scalatron simulation, and I probably want to configure the directory where all the bots are kept (the enemy bots as well as my own).
For this, I first create two simple SBT keys and add them to the Build class:
val botDirectory = SettingKey[File]("bot-directory")
val play = TaskKey[Unit]("play")
The botDirectory setting will simply be initialized to where I want to keep the bots (in the botSettings sequence):
botDirectory := file("bots"),
The play task will have the job to take my bot jar and deploy it into the bot directory, and then to start a (forked) Scalatron simulation. In order to be able to do this, it will require quite a few dependencies as inputs:
- botDirectory: where the bots go,
- name: in order to name my bot in the bot directory,
- javaOptions: so that I can configure memory settings and the like for the simulation,
- unmanagedClasspath in Compile: to retrieve the Scalatron.jar from and finally
- Keys.`package` in Compile: to retrieve my bot’s jar from.
So, here we go (again, at this to the botSettings):
play <<= (botDirectory, name, javaOptions,
unmanagedClasspath in Compile,
Keys.`package` in Compile) map {
(bots, name, javaOptions, ucp, botJar) =>
IO createDirectory (bots / name)
IO copyFile (botJar, bots / name / "ScalatronBot.jar")
val cmd = "java %s -cp %s scalatron.main.Main -plugins %s" format (
javaOptions mkString " ",
Seq(ucp.files.head, botJar).absString,
bots.absolutePath)
cmd run
}
And that’s it!
I can now deploy my bot to the bot directory and run the simulation from within SBT just by typing play into the SBT console.
Except… except that I noticed that the simulation seems to use a lot of memory, so I added a java option for this:
javaOptions += "-Xmx1g"
And also, the Eclipse project I generate via the sbteclipse plugin unfortunately warns me about two Scala runtimes (one generated by the plugin, one inside the Scalatron jar). I won’t do anything against this, hoping that we’ll soon get a clean published Scalatron jar that doesn’t automatically include the Scala runtime…
Here’s my complete build file as a gist.
Now go and create your own Scalatron bot!
Thanks for sharing
Very nice, thanks for sharing! We are going to test this pretty soon
Hi, this is really helpful to quickly test and run bots.
Thank you.
I still have a little problem setting up the project correctly. When I add the demo bot JARs in my bots directory, I end up with as many clones of my own bot.
As a workaround, I put my bot in the default package.