├── .gitignore ├── README.md ├── java-solution ├── README.md ├── pom.xml └── src │ └── main │ └── java │ ├── Harvester.java │ ├── Main.java │ ├── Mothership.java │ └── Soldier.java ├── java-template ├── README.md ├── pom.xml └── src │ └── main │ └── java │ ├── Main.java │ └── Mothership.java ├── scala-solution ├── Harvester.scala ├── Main.scala ├── Mothership.scala ├── README.md ├── Soldier.scala └── build.sbt └── scala-template ├── Main.scala ├── Mothership.scala ├── README.md └── build.sbt /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | *.log 3 | 4 | # sbt specific 5 | .cache 6 | .history 7 | .lib/ 8 | dist/* 9 | target/ 10 | lib_managed/ 11 | src_managed/ 12 | project/boot/ 13 | project/plugins/project/ 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CodeCraft Tutorial [![Join the chat at https://gitter.im/cswinter/CodeCraftGame](https://badges.gitter.im/cswinter/CodeCraftGame.svg)](https://gitter.im/cswinter/CodeCraftGame?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.codecraftgame/codecraft_2.11/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.codecraftgame/codecraft_2.11) 2 | 3 | This is a tutorial which describes how to implement an AI for the programming game CodeCraft. 4 | You "play" CodeCraft by writing a program in Scala or Java and I am going to assume that you are already familiar with one of these languages. 5 | If you encounter a bug, have a question, or want to give feedback you can go on [Gitter](https://gitter.im/cswinter/CodeCraftGame) or send me an email at codecraftgame@gmail.com. 6 | 7 | ## Basics 8 | 9 | To get things set up, you need to create a new project and add the [CodeCraft library](http://search.maven.org/#artifactdetails%7Corg.codecraftgame%7Ccodecraft_2.11%7C0.6.0%7C) as a dependency (in sbt: `libraryDependencies += "org.codecraftgame" % "codecraft_2.11" % "0.6.0"`). 10 | An implementation of the setup described in this section can be found in the folders scala-template and java-template. 11 | 12 | The main entry point into the game is the `TheGameMaster` object. 13 | You can start the first level by calling `TheGameMaster.runLevel1` as such: 14 | 15 | ```scala 16 | import cwinter.codecraft.core.api._ 17 | 18 | object Main { 19 | def main(args: Array[String]): Unit = { 20 | TheGameMaster.runLevel1(new Mothership) 21 | } 22 | } 23 | ``` 24 | 25 | The same in Java: 26 | 27 | ```java 28 | import cwinter.codecraft.core.api.TheGameMaster; 29 | 30 | class Main { 31 | public static void main(String[] args) { 32 | TheGameMaster.runLevel1(new Mothership()); 33 | } 34 | } 35 | ``` 36 | 37 | 38 | The `runLevel1` method expects an object of type `DroneController` as argument. 39 | This object will implement the AI for your initial unit. 40 | So let's create a new file to implement this class: 41 | 42 | ```scala 43 | import cwinter.codecraft.core.api._ 44 | 45 | class Mothership extends DroneController { 46 | } 47 | ``` 48 | For Java, use the `JDroneController` variant instead. It is essentially identical to `DroneController`, but its getters return Java collections rather than their Scala counterparts: 49 | ```java 50 | import cwinter.codecraft.core.api.*; 51 | 52 | class Mothership extends JDroneController { 53 | } 54 | ``` 55 | 56 | As you can see, the Mothership class doesn't contain any code so your unit AI won't do anything yet. 57 | However, you should now be able to run the program. 58 | If everything works correctly, you will see a window that displays the game world. 59 | The camera is initially centered on your mothership, which looks like a septagon with various shapes inside (its modules, more on that later). 60 | The green pentagons are mineral crystals, which can be harvested to gain resources and construct additional drones. 61 | You can move your camera using the WASD keys and zoom in/out with Q and E. 62 | Somewhere to the left of your mothership you will find your orange opponent, who is already busy plotting your downfall. 63 | 64 | ## Building a scouting drone 65 | 66 | Ok, so let's actually tell our mothership to do something. 67 | The first thing we want is to build a new drone that will scout the map, harvest minerals and bring them back to the mothership. 68 | To do so, we override the `DroneController.onSpawn` method inside the `Mothership` class. 69 | This method is called automatically by the game engine when our drone first spawns. 70 | Inside `onSpawn`, we call `buildDrone(controller, droneSpec)`. This method take two arguments: 71 | 72 | * `controller` is another DroneController that will govern the behaviour of our new Drone. 73 | * `droneSpec` is a DroneSpec object which specifies what modules our new drone will have. (in this case, we want two storage modules which will allow us to harvest and transport resources) 74 | 75 | In Scala, you can use a simpler variant of buildDrone that allows you to directly specify with modules using named parameters instead of creating a DroneSpec object. 76 | Add the following code to your Mothership class: 77 | 78 | ```scala 79 | override def onSpawn(): Unit = buildDrone(new Harvester, storageModules = 2) 80 | ``` 81 | ```java 82 | @Override public void onSpawn() { 83 | DroneSpec harvesterSpec = new DroneSpec().withStorageModules(2); 84 | buildDrone(new Harvester(), harvesterSpec); 85 | } 86 | ``` 87 | 88 | Of course we still need to implement the `Harvester`, so create a new file with the following contents: 89 | 90 | ```scala 91 | import cwinter.codecraft.core.api._ 92 | import cwinter.codecraft.util.maths.Vector2 93 | import scala.util.Random 94 | 95 | class Harvester extends DroneController { 96 | override def onTick(): Unit = { 97 | if (!isMoving) { 98 | val randomDirection = Vector2(2 * math.Pi * Random.nextDouble()) 99 | val targetPosition = position + 500 * randomDirection 100 | moveTo(targetPosition) 101 | } 102 | } 103 | } 104 | ``` 105 | ```java 106 | import cwinter.codecraft.core.api.*; 107 | import cwinter.codecraft.util.maths.Vector2; 108 | import java.util.Random; 109 | 110 | class Harvester extends JDroneController { 111 | static Random rng = new Random(); 112 | 113 | @Override public void onTick() { 114 | if (!isMoving()) { 115 | Vector2 randomDirection = new Vector2(2 * Math.PI * rng.nextDouble()); 116 | Vector2 targetPosition = position.plus(randomDirection.times(500)); 117 | moveTo(targetPosition); 118 | } 119 | } 120 | } 121 | ``` 122 | 123 | This time, we override the `onTick` method which is called on every timestep. 124 | First, we test whether the drone is currently moving using the isMoving property. 125 | If this is not the case, we give the drone a command to move into a new random direction for 100 timesteps using the `moveInDirection` method. 126 | You should now run the program again and verify that your mothership constructs a new drone which moves randomly across the map. 127 | 128 | ## Harvesting resources 129 | 130 | We still want to harvest resources and return them to the mothership. 131 | For this, we override the `onMineralEntersVision` method which is called whenever a mineral crystal enters the sight radius of our drone. 132 | When this happens, we want to stop scouting and move towards the mineral crystal. 133 | Once we have arrived, the `onArrivesAtMineral` method is called, where we give orders to harvest the mineral. 134 | We also modify our code in the `onTick` method to send the drone back to the mothership when it's storage is full. 135 | Once the drone arrives there, the `onArrivesAtDrone` method will be called where we give orders to deposit the mineral crystals. 136 | The HarvesterController class should now look like this: 137 | 138 | ```scala 139 | class Harvester(mothership: DroneController) extends DroneController { 140 | override def onTick(): Unit = { 141 | if (!isMoving && !isHarvesting) { 142 | if (availableStorage == 0) moveTo(mothership) 143 | else { 144 | val randomDirection = Vector2(2 * math.Pi * Random.nextDouble()) 145 | val targetPosition = position + 500 * randomDirection 146 | moveTo(targetPosition) 147 | } 148 | } 149 | } 150 | 151 | override def onMineralEntersVision(mineral: MineralCrystal) = 152 | if (availableStorage > 0) moveTo(mineral) 153 | 154 | override def onArrivesAtMineral(mineral: MineralCrystal) = harvest(mineral) 155 | 156 | override def onArrivesAtDrone(drone: Drone) = giveResourcesTo(drone) 157 | } 158 | ``` 159 | ```java 160 | class Harvester extends JDroneController { 161 | static Random rng = new Random(); 162 | private JDroneController mothership; 163 | 164 | 165 | public Harvester(JDroneController mothership) { 166 | this.mothership = mothership; 167 | } 168 | 169 | 170 | @Override public void onTick() { 171 | if (!isMoving() && !isHarvesting()) { 172 | if (availableStorage() == 0) moveTo(mothership); 173 | else { 174 | Vector2 randomDirection = Vector2(2 * Math.PI * rng.nextDouble()); 175 | Vector2 targetPosition = position.plus(randomDirection.times(500)); 176 | moveTo(targetPosition); 177 | } 178 | } 179 | } 180 | 181 | @Override public void onMineralEntersVision(MineralCrystal mineral) { 182 | if (availableStorage() > 0) moveTo(mineral); 183 | } 184 | 185 | @Override public void onArrivesAtMineral(MineralCrystal mineral) { 186 | harvest(mineral); 187 | } 188 | 189 | @Override public void onArrivesAtDrone(Drone drone) { 190 | giveResourcesTo(drone); 191 | } 192 | } 193 | ``` 194 | 195 | We also need to make a small change to the `Mothership` controller. 196 | The `HarvesterController` now expects a reference to the mothership as argument, so it knows where to return the minerals. 197 | We are also going to move the construction code into the `onTick` method so that we keep building new drones. 198 | The `Mothership` class now looks like this: 199 | 200 | ```scala 201 | class Mothership extends DroneController { 202 | override def onTick(): Unit = 203 | if (!isConstructing) buildDrone(new Harvester(this), storageModules = 2) 204 | } 205 | ``` 206 | ```java 207 | import cwinter.codecraft.core.api.*; 208 | 209 | class Mothership extends JDroneController { 210 | static final DroneSpec HARVESTER_SPEC = new DroneSpec().withStorageModules(2); 211 | 212 | @Override public void onTick() { 213 | if (!isConstructing()) { 214 | buildDrone(new Harvester(this), HARVESTER_SPEC); 215 | } 216 | } 217 | } 218 | ``` 219 | 220 | If you run your program again now, you should see a growing armada of harvesters collecting all the mineral crystals. 221 | 222 | ## Combat 223 | 224 | Now that you have laid the economic foundations for your drone empire, it is time to start thinking about how to beat your opponent. 225 | By now you probably got the hang of how CodeCraft works, so I will just give you a high level overview of how to implement your army. 226 | After you have built some harvesters, you will want to start production on a different type of drone. 227 | Instead of `storageModules`, it should be equipped with one or more `missileBatteries` and maybe even `shieldGenerators`. 228 | Another controller will be required as well, and you will find the following methods useful: 229 | 230 | * The `DroneController` method `dronesInSight` returns a `Set` of all `Drone`s which can be seen by this drone controller 231 | * The `Drone` class has a method `isEnemy` which tells you whether that drone is an enemy 232 | * The `DroneController` method `isInMissileRange(target: Drone)` can be used to check whether some drone is within the range of your missiles 233 | * The `DroneController` method `fireMissilesAt(target: Drone)` will fire all your missiles at the drone `target` 234 | * If you are using Java method parentheses aren't optional, so you will need to write e.g. `dronesInSight()` and `isEnemy()` 235 | 236 | If you don't quite manage to get all of this to work, you can check out the scala-solution and java-solution directories in this repo, which contain a full implementation of everything described in this tutorial. 237 | If you want to go even further, check out the next section which gives an overview of all the other parts of the API which haven't been covered yet. 238 | If you write an AI that uses a different strategy than those in the current levels (or which beats all levels), please send me a link to your code at codecraft@gmail.com and I'll include in the next release. 239 | 240 | 241 | ## What to do next 242 | 243 | Hopefully this tutorial has succeded in giving you a good understanding of what CodeCraft is about and how to use it. 244 | If you want to continue building out your AI, you can get answers to any questions you have from the [comprehensive documentation](http://www.codecraftgame.org/docs/api/index.html) or [fellow CodeCraft users](http://www.codecraftgame.org/community). 245 | In addtiion to that, this section gives a quick overview of the most useful parts of the API. 246 | 247 | ### `TheGameMaster` 248 | To configure and start the game, you use `TheGameMaster` object. 249 | `TheGameMaster` has methods `runLevel1`, `runLevel2`, ..., `runLevel7` which take as an argument the `DroneController` for your mothership and start the corresponding level. 250 | There is also a `runGame` method which allows you to start a game with two custom `DroneController`s. 251 | The game automatically records replays of all games in the folder `~/.codecraft/replays`. 252 | You can run the last recorded replay using `runLastReplay` and run the replay with a specific filename using `runReplay`. 253 | 254 | ### Multiplayer 255 | You can start a multiplayer game using [`TheGameMaster.prepareMultiplayerGame`][API#Multiplayer]. This returns a `Future[DroneSimulator]` which completes as soon as another player connects to the same server: 256 | 257 | ```scala 258 | import cwinter.codecraft.core.api._ 259 | 260 | import scala.concurrent.Await 261 | import scala.concurrent.duration._ 262 | 263 | 264 | object Main { 265 | def main(args: Array[String]): Unit = { 266 | val game = Await.result( 267 | TheGameMaster.prepareMultiplayerGame("SERVER ADDRESS", new Mothership), 10.minutes) 268 | TheGameMaster.run(game) 269 | } 270 | } 271 | 272 | ``` 273 | 274 | You can run a server by calling `cwinter.codecraft.core.multiplayer.Server.start()`. 275 | 276 | ### `DroneController` 277 | Almost all interactions with the game world goes through this class. 278 | If you are using Java, you should use the `JDroneController` class instead, which is almost identical but returns Java collections rather than their Scala counterparts. 279 | `DroneController` has three different kinds of methods: 280 | 281 | * Event handlers such as `onSpawn` and `onDroneEntersVision`. These are automatically called by the game on specific events and you can override them to respond to these events. 282 | * Commands such as `moveTo` and `buildDrone`. You can call these methods to make your drones perform various actions. 283 | * Properties such as `position` and `hitpoints` which allow you to query the current state of the drone. 284 | 285 | You can find a complete description of all of them in the [API reference][API#DroneController]. 286 | In some methods (e.g. `onDroneEntersVision`) you are given a [`Drone`][API#Drone] object. 287 | Since this could reference an enemy drone, it only exposes a subset of the properties and none of the event and command methods. 288 | 289 | ### `Vector2` 290 | `Vector2` is an immutable 2D vector and used throughout CodeCraft. 291 | It defines various methods and operators to perform e.g. vector addition, scalar multiplication and compute it's length. 292 | Details can be found in the [API reference][API#Vector2]. 293 | 294 | ### `Debug` 295 | 296 | You can display a string at any position in the game world by using the `DroneController.showText(text: String, position: Vector2)` method. 297 | This is only valid for one timestep, so you if you will need to call this method on every timestep on which you want the text to be displayed. 298 | E.g. if you wanted your drones to display their position, you could use this code: 299 | 300 | override def onTick(): Unit = { 301 | showText(position.toString, position) 302 | } 303 | 304 | [API#DroneController]: http://codecraftgame.org/docs/api/index.html#cwinter.codecraft.core.api.DroneController 305 | [API#Drone]: http://codecraftgame.org/docs/api/index.html#cwinter.codecraft.core.api.Drone 306 | [API#Vector2]: http://codecraftgame.org/docs/api/index.html#cwinter.codecraft.core.api.Vector2 307 | [API#Multiplayer]: http://codecraftgame.org/docs/api/index.html#cwinter.codecraft.core.api.TheGameMaster$@prepareMultiplayerGame(serverAddress:String,controller:cwinter.codecraft.core.api.DroneControllerBase):scala.concurrent.Future[cwinter.codecraft.core.game.DroneWorldSimulator]$ 308 | -------------------------------------------------------------------------------- /java-solution/README.md: -------------------------------------------------------------------------------- 1 | Run with `mvn clean install exec:java -Dexec.mainClass="Main"`. 2 | -------------------------------------------------------------------------------- /java-solution/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | org.codecraft 6 | codecraft-java-template 7 | 1.0-SNAPSHOT 8 | 9 | 10 | 11 | org.codecraftgame 12 | codecraft_2.11 13 | 0.3.0.2 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /java-solution/src/main/java/Harvester.java: -------------------------------------------------------------------------------- 1 | import cwinter.codecraft.core.api.*; 2 | import cwinter.codecraft.util.maths.Vector2; 3 | import java.util.Random; 4 | 5 | class Harvester extends JDroneController { 6 | static Random rng = new Random(); 7 | private JDroneController mothership; 8 | 9 | 10 | public Harvester(JDroneController mothership) { 11 | this.mothership = mothership; 12 | } 13 | 14 | 15 | @Override public void onTick() { 16 | if (!isMoving() && !isHarvesting()) { 17 | if (availableStorage() == 0) moveTo(mothership); 18 | else { 19 | Vector2 randomDirection = new Vector2(2 * Math.PI * rng.nextDouble()); 20 | Vector2 targetPosition = position().plus(randomDirection.times(500)); 21 | moveTo(targetPosition); 22 | } 23 | } 24 | } 25 | 26 | @Override public void onMineralEntersVision(MineralCrystal mineral) { 27 | if (availableStorage() > 0) moveTo(mineral); 28 | } 29 | 30 | @Override public void onArrivesAtMineral(MineralCrystal mineral) { 31 | harvest(mineral); 32 | } 33 | 34 | @Override public void onArrivesAtDrone(Drone drone) { 35 | giveResourcesTo(drone); 36 | } 37 | } 38 | 39 | -------------------------------------------------------------------------------- /java-solution/src/main/java/Main.java: -------------------------------------------------------------------------------- 1 | import cwinter.codecraft.core.api.TheGameMaster; 2 | 3 | class Main { 4 | public static void main(String[] args) { 5 | TheGameMaster.runLevel1(new Mothership()); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /java-solution/src/main/java/Mothership.java: -------------------------------------------------------------------------------- 1 | import cwinter.codecraft.core.api.*; 2 | 3 | class Mothership extends JDroneController { 4 | static final DroneSpec HARVESTER_SPEC = new DroneSpec().withStorageModules(2); 5 | static final DroneSpec SOLDIER_SPEC = new DroneSpec().withMissileBatteries(3).withShieldGenerators(1); 6 | int nHarvesters = 0; 7 | 8 | 9 | @Override public void onTick() { 10 | if (!isConstructing()) { 11 | if (nHarvesters < 3) { 12 | buildDrone(new Harvester(this), HARVESTER_SPEC); 13 | nHarvesters++; 14 | } else buildDrone(new Soldier(), SOLDIER_SPEC); 15 | } 16 | } 17 | } 18 | 19 | -------------------------------------------------------------------------------- /java-solution/src/main/java/Soldier.java: -------------------------------------------------------------------------------- 1 | import cwinter.codecraft.core.api.*; 2 | import cwinter.codecraft.util.maths.Vector2; 3 | import java.util.Random; 4 | 5 | 6 | class Soldier extends JDroneController { 7 | static Random rng = new Random(); 8 | 9 | 10 | @Override public void onTick() { 11 | for (Drone drone : dronesInSight()) { 12 | if (drone.isEnemy()) { 13 | moveTo(drone.position()); 14 | if (missileCooldown() == 0 && isInMissileRange(drone)) { 15 | fireMissilesAt(drone); 16 | } 17 | return; 18 | } 19 | } 20 | 21 | if (!isMoving()) { 22 | Vector2 randomDirection = new Vector2(2 * Math.PI * rng.nextDouble()); 23 | Vector2 targetPosition = position().plus(randomDirection.times(500)); 24 | moveTo(targetPosition); 25 | } 26 | } 27 | } 28 | 29 | -------------------------------------------------------------------------------- /java-template/README.md: -------------------------------------------------------------------------------- 1 | Run with `mvn clean install exec:java -Dexec.mainClass="Main"`. 2 | -------------------------------------------------------------------------------- /java-template/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | org.codecraft 6 | codecraft-java-template 7 | 1.0-SNAPSHOT 8 | 9 | 10 | 11 | org.codecraftgame 12 | codecraft_2.11 13 | 0.3.0.2 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /java-template/src/main/java/Main.java: -------------------------------------------------------------------------------- 1 | import cwinter.codecraft.core.api.TheGameMaster; 2 | 3 | class Main { 4 | public static void main(String[] args) { 5 | TheGameMaster.runLevel1(new Mothership()); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /java-template/src/main/java/Mothership.java: -------------------------------------------------------------------------------- 1 | import cwinter.codecraft.core.api.*; 2 | 3 | class Mothership extends JDroneController { 4 | } 5 | -------------------------------------------------------------------------------- /scala-solution/Harvester.scala: -------------------------------------------------------------------------------- 1 | import cwinter.codecraft.core.api._ 2 | import cwinter.codecraft.util.maths.Vector2 3 | import scala.util.Random 4 | 5 | 6 | class Harvester(mothership: DroneController) extends DroneController { 7 | override def onTick(): Unit = { 8 | if (!isMoving && !isHarvesting) { 9 | if (availableStorage == 0) moveTo(mothership) 10 | else { 11 | val randomDirection = Vector2(2 * math.Pi * Random.nextDouble()) 12 | val targetPosition = position + 500 * randomDirection 13 | moveTo(targetPosition) 14 | } 15 | } 16 | } 17 | 18 | override def onMineralEntersVision(mineral: MineralCrystal) = 19 | if (availableStorage > 0) moveTo(mineral) 20 | 21 | override def onArrivesAtMineral(mineral: MineralCrystal) = harvest(mineral) 22 | 23 | override def onArrivesAtDrone(drone: Drone) = giveResourcesTo(drone) 24 | } 25 | 26 | -------------------------------------------------------------------------------- /scala-solution/Main.scala: -------------------------------------------------------------------------------- 1 | import cwinter.codecraft.core.api._ 2 | 3 | 4 | object Main { 5 | def main(args: Array[String]): Unit = { 6 | TheGameMaster.runLevel1(new Mothership) 7 | } 8 | } 9 | 10 | -------------------------------------------------------------------------------- /scala-solution/Mothership.scala: -------------------------------------------------------------------------------- 1 | import cwinter.codecraft.core.api._ 2 | 3 | 4 | class Mothership extends DroneController { 5 | var nHarvesters = 0 6 | 7 | override def onTick(): Unit = { 8 | if (!isConstructing) { 9 | if (nHarvesters < 3) { 10 | buildDrone(new Harvester(this), storageModules = 2) 11 | nHarvesters += 1 12 | } else buildDrone(new Soldier, missileBatteries = 3, shieldGenerators = 1) 13 | } 14 | } 15 | } 16 | 17 | -------------------------------------------------------------------------------- /scala-solution/README.md: -------------------------------------------------------------------------------- 1 | Run with `sbt run`. 2 | -------------------------------------------------------------------------------- /scala-solution/Soldier.scala: -------------------------------------------------------------------------------- 1 | import cwinter.codecraft.core.api._ 2 | import cwinter.codecraft.util.maths.Vector2 3 | import scala.util.Random 4 | 5 | 6 | class Soldier extends DroneController { 7 | override def onTick(): Unit = { 8 | val enemies = dronesInSight.filter(_.isEnemy) 9 | enemies.headOption match { 10 | case Some(enemy) => 11 | moveTo(enemy.position) 12 | if (missileCooldown <= 0 && isInMissileRange(enemy)) 13 | fireMissilesAt(enemy) 14 | case None => 15 | if (!isMoving) { 16 | val randomDirection = Vector2(2 * math.Pi * Random.nextDouble()) 17 | val targetPosition = position + 1000 * randomDirection 18 | moveTo(targetPosition) 19 | } 20 | } 21 | } 22 | } 23 | 24 | -------------------------------------------------------------------------------- /scala-solution/build.sbt: -------------------------------------------------------------------------------- 1 | lazy val root = (project in file(".")). 2 | settings( 3 | name := "scala-solution", 4 | version := "1.1", 5 | scalaVersion := "2.11.7", 6 | libraryDependencies += "org.codecraftgame" %% "codecraft" % "0.6.0" 7 | ) 8 | 9 | -------------------------------------------------------------------------------- /scala-template/Main.scala: -------------------------------------------------------------------------------- 1 | import cwinter.codecraft.core.api._ 2 | 3 | 4 | object Main { 5 | def main(args: Array[String]): Unit = { 6 | TheGameMaster.runLevel1(new Mothership) 7 | } 8 | } 9 | 10 | -------------------------------------------------------------------------------- /scala-template/Mothership.scala: -------------------------------------------------------------------------------- 1 | import cwinter.codecraft.core.api._ 2 | 3 | 4 | class Mothership extends DroneController { 5 | } 6 | -------------------------------------------------------------------------------- /scala-template/README.md: -------------------------------------------------------------------------------- 1 | Run with `sbt run`. 2 | -------------------------------------------------------------------------------- /scala-template/build.sbt: -------------------------------------------------------------------------------- 1 | lazy val root = (project in file(".")). 2 | settings( 3 | name := "scala-template", 4 | version := "1.1", 5 | scalaVersion := "2.11.7", 6 | libraryDependencies += "org.codecraftgame" %% "codecraft" % "0.6.0" 7 | ) 8 | 9 | --------------------------------------------------------------------------------