├── .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 [](https://gitter.im/cswinter/CodeCraftGame?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [](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 |
--------------------------------------------------------------------------------