diff --git a/.classpath b/.classpath
new file mode 100644
index 0000000..062ee87
--- /dev/null
+++ b/.classpath
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.gitignore b/.gitignore
index 94eab12..107264a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,59 @@
-target/
-pom.xml.tag
-pom.xml.releaseBackup
-pom.xml.next
-release.properties
+#ignore thumbnails created by windows
+Thumbs.db
+
+#Ignore files build by Visual Studio
+*.obj
+*.user
+*.aps
+*.pch
+*.vspscc
+*_i.c
+*_p.c
+*.ncb
+*.suo
+*.tlb
+*.tlh
+*.bak
+*.cache
+*.ilk
+*.log
+[Bb]in
+[Dd]ebug*/
+*.lib
+*.sbr
+obj/
+[Rr]elease*/
+[Tt]est[Rr]esult*
+*.opensdf
+*.sdf
+ipch/
+.DS_Store
+
+# Resharper
+_ReSharper*/
+*.docstates
+
+# Maven
+target
+
+# Convention
+output
+download
+
+# vim
+*.swp
+
+# eclipse
+.settings
+.cache
+
+# emacs
+*~
+\#*#
+
+# project specific
+*.zip
+*.rep
+log/
+*.csv
+*.jar
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..8468fc4
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "JavaChallenge2012"]
+ path = JavaChallenge2012
+ url = git@github.com:JavaChallenge2012/JavaChallenge2012.git
diff --git a/.project b/.project
new file mode 100644
index 0000000..2c125b7
--- /dev/null
+++ b/.project
@@ -0,0 +1,24 @@
+
+
+ JavaChallenge2012
+
+
+
+
+
+ org.scala-ide.sdt.core.scalabuilder
+
+
+
+
+ org.eclipse.m2e.core.maven2Builder
+
+
+
+
+
+ org.scala-ide.sdt.core.scalanature
+ org.eclipse.jdt.core.javanature
+ org.eclipse.m2e.core.maven2Nature
+
+
diff --git a/README.md b/README.md
index d9eb8e2..3df8f63 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,30 @@
-JavaChallenge2012
-=================
+# Prepare Eclipse environment
+1. Install Eclipse
+ * For Juno (4.2)
+http://www.eclipse.org/downloads/
+2. Run Eclipse
+3. Menu > Help > Install new software
+4. Install Scala IDE (For Scala 2.9.x) on Eclipse
+http://download.scala-ide.org/sdk/e37/scala29/stable/site (for 3.7 Indigo) or
+http://download.scala-ide.org/sdk/e38/scala29/stable/site (for 3.8/4.2 Juno).
+5. Install m2e-scala connector on Eclipse
+http://alchim31.free.fr/m2e-scala/update-site/
+6. Edit eclipse.ini ("eclipse/eclipse.ini" on Windows, "Eclipse.app/Contents/MacOS/eclipse.ini" on Mac OS)
+-Xmx???m => -Xmx2048m
-A game platform of AI competition at ACM ICPC JavaChallenge 2012.
+# Import the maven project into your Eclipse workspace
+You can import maven projects with the following steps:
+
+1. Import > Existing Maven Projects
+2. Set Root Directory containing pom.xml
+3. Select Projects
+4. Push Finish
+5. Right click the imported project > Maven > Update Project Configuration > OK
+
+# Build with Maven 3
+1. run 'build.bat'
+
+# Dcouments
+* https://github.com/JavaChallenge2012/JavaChllaenge2012
+* http://www.slideshare.net/exKAZUu/javachallenge-2012-result
+* http://www.slideshare.net/exKAZUu/javachallenge-2012-special-league
diff --git a/build.bat b/build.bat
new file mode 100644
index 0000000..72a714e
--- /dev/null
+++ b/build.bat
@@ -0,0 +1 @@
+mvn package & cp target/JavaChallenge2012-*-dependencies.jar JavaChallenge2012ForDevelopingAI & cp target/JavaChallenge2012-*-dependencies.jar JavaChallenge2012ForRecording
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..678523c
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,219 @@
+
+ 4.0.0
+
+ net.javachallenge
+ JavaChallenge2012
+ 1.0.0
+ jar
+
+ ${project.artifactId}
+ A game platform for JavaChallenge2012.
+ 2012
+
+
+ 1.7
+ 1.7
+ UTF-8
+ UTF-8
+ UTF-8
+ UTF-8
+ 2.9.1
+
+
+
+
+ jp.ac.waseda.cs.washi
+ http://oss.sonatype.org/content/groups/public/
+
+ true
+
+
+ true
+
+
+
+
+
+
+ org.scala-lang
+ scala-library
+ ${scala.version}
+
+
+ commons-cli
+ commons-cli
+ 1.2
+
+
+ jp.ac.waseda.cs.washi
+ GameAIArena
+ 1.4.4
+
+
+ commons-lang
+ commons-lang
+ 2.6
+
+
+ com.google.guava
+ guava
+ 13.0.1
+
+
+
+
+ junit
+ junit
+ 4.10
+ test
+
+
+ org.hamcrest
+ hamcrest-all
+ 1.1
+ test
+
+
+ org.mockito
+ mockito-core
+ 1.9.0-rc1
+ test
+
+
+ org.scala-tools.testing
+ specs_${scala.version}
+ 1.6.9
+ test
+
+
+ org.scalatest
+ scalatest
+ 1.2
+ test
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-assembly-plugin
+ 2.2.2
+
+
+ jar-with-dependencies
+
+
+
+ net.javachallenge.Main
+
+
+
+
+
+ make-assembly
+ package
+
+ attached
+
+
+
+
+
+
+ org.scala-tools
+ maven-scala-plugin
+ 2.15.2
+
+
+ scala-compile-first
+ process-resources
+
+ add-source
+ compile
+
+
+
+ -make:transitive
+ -dependencyfile
+ ${project.build.directory}/.scala_dependencies
+
+
+
+
+ scala-test-compile
+ process-test-resources
+
+ testCompile
+
+
+
+ -make:transitive
+ -dependencyfile
+ ${project.build.directory}/.scala_dependencies
+
+
+
+
+
+
+
+ main
+ net.javachallenge.Main
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 2.6
+
+ false
+ true
+
+
+
+ **/*Test.*
+ **/*Suite.*
+
+
+
+
+
+
+
+
diff --git a/src/main/config/config.xml b/src/main/config/config.xml
new file mode 100644
index 0000000..574931a
--- /dev/null
+++ b/src/main/config/config.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/net/javachallenge/api/AlienTrade.java b/src/main/java/net/javachallenge/api/AlienTrade.java
new file mode 100644
index 0000000..da0a8be
--- /dev/null
+++ b/src/main/java/net/javachallenge/api/AlienTrade.java
@@ -0,0 +1,25 @@
+package net.javachallenge.api;
+
+/**
+ * An interface which represents the alien trade for providing market information.
+ *
+ * Note that this interface is immutable, thus, its object stores the information of just this turn
+ * and will not be updated.
+ */
+public interface AlienTrade {
+ /**
+ * Returns the price for buying the specified material from the alien.
+ *
+ * @param material a material to buy
+ * @return the price for buying the specified material from the alien
+ */
+ int getBuyPriceOf(Material material);
+
+ /**
+ * Returns the price for selling the specified material to the alien.
+ *
+ * @param material a material to sell
+ * @return the price for selling the specified material to the alien.
+ */
+ int getSellPriceOf(Material material);
+}
diff --git a/src/main/java/net/javachallenge/api/ComputerPlayer.java b/src/main/java/net/javachallenge/api/ComputerPlayer.java
new file mode 100644
index 0000000..75bd68e
--- /dev/null
+++ b/src/main/java/net/javachallenge/api/ComputerPlayer.java
@@ -0,0 +1,84 @@
+package net.javachallenge.api;
+
+import java.util.List;
+
+import net.javachallenge.api.command.Command;
+
+/**
+ * An abstract class which represents an AI player. Please extend this class for developing your AI
+ * player.
+ */
+public abstract class ComputerPlayer {
+ private List commands;
+ private TrianglePoint location;
+
+ /**
+ * Saves the temporal commands for controlling your player. Note that the temporal commands are
+ * accepted when your AI program does not decide the commands within the limiting time (1000 ms).
+ *
+ * @param commands the temporal commands to save
+ */
+ public final void saveTemporalCommands(List commands) {
+ this.commands = commands;
+ }
+
+ /**
+ * Returns the saved temporal commands.
+ *
+ * @return the saved temporal commands
+ */
+ public final Command[] getTemporalCommands() {
+ Command[] empty = new Command[0];
+ return commands != null ? commands.toArray(empty) : empty;
+ }
+
+ /**
+ * Saves the temporal vein location to occupy first for selecting your vein. Note that the
+ * temporal vein location is accepted when your AI program does not decide the vein location
+ * within the limiting time (10000[ms]).
+ *
+ * @param location the temporal vein location to save
+ */
+ public final void saveTemporalVeinLocation(TrianglePoint location) {
+ this.location = location;
+ }
+
+ /**
+ * Returns the saved temporal vein location to occupy first.
+ *
+ * @return the saved temporal vein location to occupy first
+ */
+ public final TrianglePoint getTemporalVeinLocation() {
+ return location != null ? location : new net.javachallenge.entity.TrianglePoint(
+ Integer.MAX_VALUE, Integer.MAX_VALUE);
+ }
+
+ /**
+ * Returns the selected vein location to occupy first. This method should terminate within
+ * 10000[ms]. The saved temporal vein location is used when this method exceed the limiting time.
+ * Note that the vein location are selected irresponsibly when an invalid vein location is
+ * selected.
+ *
+ * @param game the {@link Game} instance of the current turn
+ * @return the selected vein location to occupy first
+ */
+ public abstract TrianglePoint selectVein(Game game);
+
+ /**
+ * Returns the decided command list to control your player. This method should terminate within
+ * 10000[ms]. The saved temporal command list is used when this method exceed the limiting time.
+ * Note that the command to do nothing is accepted when an invalid or empty command is decided.
+ * Invalid commands are ignored, i.e. skipped to execute next commands in the command list.
+ *
+ * @param game the {@link Game} instance of the current turn
+ * @return the decided command list to control your player
+ */
+ public abstract List selectActions(Game game);
+
+ /**
+ * Return the team name.
+ *
+ * @return the team name
+ */
+ public abstract String getName();
+}
diff --git a/src/main/java/net/javachallenge/api/Field.java b/src/main/java/net/javachallenge/api/Field.java
new file mode 100644
index 0000000..dd389e4
--- /dev/null
+++ b/src/main/java/net/javachallenge/api/Field.java
@@ -0,0 +1,130 @@
+package net.javachallenge.api;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * A class which represents the field which contains the veins and the squads.
+ *
+ * Note that this interface is immutable, thus, its object stores the information of just this turn
+ * and will not be updated.
+ */
+public interface Field {
+ /**
+ * Returns all veins as a copied mutable list.
+ *
+ * @return all veins as a copied mutable list
+ */
+ ArrayList getVeins();
+
+ /**
+ * Returns all veins which the specified player owns as a copied mutable list.
+ *
+ * @param playerId the player to filter veins
+ * @return all veins which the specified player owns as a copied mutable list
+ */
+ ArrayList getVeins(int playerId);
+
+ /**
+ * Returns the veins of the same owner for the specified vein ordered by the distance in ascending
+ * order as a copied mutable list.
+ *
+ * @param origination the origination to calculate distances
+ * @return the veins of the same owner ordered by the distance in ascending order as a copied
+ * mutable list
+ */
+ ArrayList getVeinsOfSameOwnerOrderedByDistance(Vein origination);
+
+ /**
+ * Returns the veins of the other owners for the specified vein ordered by the distance in
+ * ascending order as a copied mutable list.
+ *
+ * @param origination the origination to calculate distances
+ * @return the veins of the other owners ordered by the distance in ascending order as a copied
+ * mutable list
+ */
+ ArrayList getVeinsOfOtherOwnersOrderedByDistance(Vein origination);
+
+ /**
+ * Returns the {@link Map} instance of the locations (key) and the veins (value) as a copied
+ * mutable map.
+ *
+ * @return the {@link Map} instance with the locations (key) and the veins (value) as a copied
+ * mutable map
+ */
+ TreeMap getVeinMap();
+
+ /**
+ * Returns the filtered {@link Map} instance of the locations (key) and the veins (value) by the
+ * specified id of the owner player as a copied mutable map.
+ *
+ * @return the filtered {@link Map} instance of the locations (key) and the veins (value) as a
+ * copied mutable map
+ */
+ TreeMap getVeinMap(int playerId);
+
+ /**
+ * Returns the vein with the specified location.
+ *
+ * @param location the location to locate the vein
+ * @return the vein with the specified location
+ */
+ Vein getVein(TrianglePoint location);
+
+ /**
+ * Returns the all squads as a copied mutable list.
+ *
+ * @return the all squads as a copied mutable list
+ */
+ ArrayList getSquads();
+
+ /**
+ * Returns the filtered squads by the specified id of the owner player as a copied mutable list.
+ *
+ * @return the filtered squads by the specified id of the owner player as a copied mutable list
+ */
+ ArrayList getSquads(int playerId);
+
+ /**
+ * Returns the valid {@link TrianglePoint} instances as a copied mutable set.
+ *
+ * @return the valid {@link TrianglePoint} instances as a copied mutable set
+ */
+ HashSet getValidCoords();
+
+ /**
+ * Returns the number of veins which the specified player owns.
+ *
+ * @param plyaerId the player id to filter veins
+ * @return the number of veins which the specified player owns
+ */
+ int countVeins(int plyaerId);
+
+ /**
+ * Sums and returns the number of the robots of the specified player on the vertexes and the
+ * sides.
+ *
+ * @param plyaerId the player to sum the number of the veins
+ * @return the number of robots including robots on the vertexes and the sides
+ */
+ int sumRobots(int plyaerId);
+
+ /**
+ * Sums and returns the productivity of the specified player and the specified material.
+ *
+ * @param plyaerId the player to sum the material productivity
+ * @param material the material to sum the material productivity
+ * @return the productivity of the specified player and the specified material
+ */
+ int sumCurrentMaterialProductivity(int plyaerId, Material material);
+
+ /**
+ * Sums and returns the robot productivity of the specified player.
+ *
+ * @param plyaerId the player to sum the robot productivity
+ * @return the robot productivity of the specified player
+ */
+ int sumCurrentRobotProductivity(int plyaerId);
+}
diff --git a/src/main/java/net/javachallenge/api/Game.java b/src/main/java/net/javachallenge/api/Game.java
new file mode 100644
index 0000000..d3763a6
--- /dev/null
+++ b/src/main/java/net/javachallenge/api/Game.java
@@ -0,0 +1,181 @@
+package net.javachallenge.api;
+
+import java.util.ArrayList;
+
+/**
+ * A class that represents the whole state of the game. The all information of the game can be
+ * retrieved from the instance of this class.
+ *
+ * Note that this interface is immutable, thus, its object stores the information of just this turn
+ * and will not be updated.
+ */
+public interface Game {
+ /**
+ * Returns the neutral player id, which is constant value.
+ *
+ * @return the neutral player id
+ */
+ int getNeutralPlayerId();
+
+ /**
+ * Returns your player id, which is the active player, because your program is executed when your
+ * player is active.
+ *
+ * @return your player id, which is the active player
+ */
+ int getMyPlayerId();
+
+ /**
+ * Returns the all players participating in the game without the neutral player as a copied
+ * mutable list.
+ *
+ * @return the all players participating in the game without the neutral player as a copied
+ * mutable list
+ */
+ ArrayList getPlayers();
+
+ /**
+ * Please use getSurvivingPlayers instead of this method.
+ */
+ @Deprecated
+ ArrayList getSurvivedPlayers();
+
+ /**
+ * Returns the surviving players participating in the game without the neutral player as a copied
+ * mutable list.
+ *
+ * @return the surviving players participating in the game without the neutral player as a copied
+ * mutable list
+ */
+ ArrayList getSurvivingPlayers();
+
+ /**
+ * Returns the {@link Player} instance with the specified player id.
+ *
+ * @param id the player id to retrieve the {@link Player} instance
+ * @return the player
+ */
+ Player getPlayer(int id);
+
+ /**
+ * Returns your player, which is the active player, because your program is executed when your
+ * player is active.
+ *
+ * @return your player, which is the active player
+ */
+ Player getMyPlayer();
+
+ /**
+ * Returns the boolean whether the specified player is surviving.
+ *
+ * @param playerId the player id to check surviving
+ * @return the boolean whether the specified player is surviving
+ */
+ boolean isSurvivingPlayer(int playerId);
+
+ /**
+ * Returns the alien trade for providing the market rate information.
+ *
+ * @return the alien trade for providing the market rate information
+ */
+ AlienTrade getAlienTrade();
+
+ /**
+ * Returns the field which contains the veins and the squads.
+ *
+ * @return the field which contains the veins and the squads
+ */
+ Field getField();
+
+ /**
+ * Returns the existing offer list with the specified material as a copied mutable list.
+ *
+ * @param material the material to get offers
+ * @return the existing offer list with the specified material as a copied mutable list
+ */
+ ArrayList getOffers(Material material);
+
+ /**
+ * Returns the existing demand list with the specified material as a copied mutable list.
+ *
+ * @param material the material to get demands
+ * @return the existing demand list with the specified material as a copied mutable list
+ */
+ ArrayList getDemands(Material material);
+
+ /**
+ * Returns the existing offer list with the specified player as a copied mutable list.
+ *
+ * @param playerId the player id to get offers
+ * @return the existing offer list with the specified player as a copied mutable list
+ */
+ ArrayList getOffers(int playerId);
+
+ /**
+ * Returns the existing demand list with the specified player as a copied mutable list.
+ *
+ * @param playerId the player id to get demands
+ * @return the existing demand list with the specified player as a copied mutable list
+ */
+ ArrayList getDemands(int playerId);
+
+ /**
+ * Returns the existing offer with the specified material from the specified player or, null if no
+ * offer.
+ *
+ * @param playerId the player id to get offer
+ * @param material the material to get offer
+ * @return the existing offer with the specified material from the specified player or, null if no
+ * offer
+ */
+ PlayerTrade getOffer(int playerId, Material material);
+
+ /**
+ * Returns the existing demand with the specified material from the specified player or, null if
+ * no offer.
+ *
+ * @param playerId the player id to get demand
+ * @param material the material to get demand
+ * @return the existing demand with the specified material from the specified player or, null if
+ * no offer
+ */
+ PlayerTrade getDemand(int playerId, Material material);
+
+ /**
+ * Returns the existing trades (offers and demands) as a copied mutable list.
+ *
+ * @return the existing trades (offers and demands) as a copied mutable list
+ */
+ ArrayList getPlayerTrades();
+
+ /**
+ * Returns the settings of this game.
+ *
+ * @return the settings of this game
+ */
+ GameSetting getSetting();
+
+ /**
+ * Returns the number of the players.
+ *
+ * @return the number of the players
+ */
+ int getPlayerCount();
+
+ /**
+ * Returns the number of the current round. Note that you can get the maximum round number from
+ * the {@link GameSetting} instance.
+ *
+ * @return the number of the current round
+ */
+ int getRound();
+
+ /**
+ * Returns the total money which is sum of the and all own materials of the bank with the
+ * specified player id.
+ *
+ * @param playerId player id to calculate total money
+ * @return the total money
+ */
+ int getTotalMoneyWhenSellingAllMaterials(int playerId);
+}
diff --git a/src/main/java/net/javachallenge/api/GameSetting.java b/src/main/java/net/javachallenge/api/GameSetting.java
new file mode 100644
index 0000000..59bbb6d
--- /dev/null
+++ b/src/main/java/net/javachallenge/api/GameSetting.java
@@ -0,0 +1,69 @@
+package net.javachallenge.api;
+
+
+/**
+ * A class which represents game setting.
+ *
+ * Note that this interface is immutable, thus, its object stores the information of just this turn
+ * and will not be updated.
+ */
+public interface GameSetting {
+ /**
+ * Returns the maximum round number. Note that the round number is more than or equal to 0 and
+ * less than or equal to the maximum number.
+ */
+ int getMaxRound();
+
+ /**
+ * Returns the initial money for the players.
+ */
+ int getInitialMoney();
+
+ /**
+ * Returns the initial amount of the specified material for the players.
+ */
+ int getInitialMaterial(Material material);
+
+ /**
+ * Returns the amount of the specified material required to upgrade material rank from 1 to 2.
+ *
+ * @return the amount of the specified material required to upgrade material rank from 1 to 2
+ */
+ int getMaterialsForUpgradingMaterialRankFrom1To2(Material material);
+
+ /**
+ * Returns the amount of the specified material required to upgrade material rank from 2 to 3.
+ *
+ * @return the amount of the specified material required to upgrade material rank from 2 to 3
+ */
+ int getMaterialsForUpgradingMaterialRankFrom2To3(Material material);
+
+ /**
+ * Returns the amount of the specified material required to upgrade robot rank from 1 to 2.
+ *
+ * @return the amount of the specified material required to upgrade robot rank from 1 to 2
+ */
+ int getMaterialsForUpgradingRobotRankFrom1To2(Material material);
+
+ /**
+ * Returns the amount of the specified material required to upgrade robot rank from 2 to 3.
+ *
+ * @return the amount of the specified material required to upgrade robot rank from 2 to 3
+ */
+ int getMaterialsForUpgradingRobotRankFrom2To3(Material material);
+
+ /**
+ * Returns the map size. Note that the size must be 10 in JavaChallenge2012.
+ */
+ int getMapSize();
+
+ /**
+ * Returns the number of the veins. Note that the number must be 40 in JavaChallenge2012.
+ */
+ int getVeinCount();
+
+ /**
+ * Return the margin of the alien trade. This margin is used to calculate only selling price.
+ */
+ int getAlienTradeMargin();
+}
diff --git a/src/main/java/net/javachallenge/api/GameSettingBuilder.java b/src/main/java/net/javachallenge/api/GameSettingBuilder.java
new file mode 100644
index 0000000..fda3aff
--- /dev/null
+++ b/src/main/java/net/javachallenge/api/GameSettingBuilder.java
@@ -0,0 +1,132 @@
+package net.javachallenge.api;
+
+/**
+ * The {@link GameSettingBuilder} class is used to initialize the settings of the game.
+ */
+public class GameSettingBuilder {
+ private int alienTradeMargin;
+ private int initialMoney;
+ private int mapSize;
+ private int maxRound;
+ private int veinCount;
+
+ /**
+ * Constructs a {@link GameSettingBuilder} with default settings.
+ */
+ public GameSettingBuilder() {
+ GameSetting gs = net.javachallenge.entity.GameSetting$.MODULE$.defaultInstance();
+ alienTradeMargin = gs.getAlienTradeMargin();
+ initialMoney = gs.getInitialMoney();
+ mapSize = gs.getMapSize();
+ maxRound = gs.getMaxRound();
+ veinCount = gs.getVeinCount();
+ }
+
+ /**
+ * Returns a {@link GameSetting} instance with the settings of this instance.
+ *
+ * @return settings for the game
+ */
+ public GameSetting build() {
+ return net.javachallenge.entity.GameSetting$.MODULE$.build(this);
+ }
+
+ /**
+ * Returns the alien trade margin.
+ *
+ * @return the alien trade margin
+ */
+ public int getAlienTradeMargin() {
+ return alienTradeMargin;
+ }
+
+ /**
+ * Set the alien trade margin to alienTradeMargin.
+ *
+ * @param alienTradeMargin the margin of the alien during trades
+ */
+ public GameSettingBuilder setAlienTradeMargin(int alienTradeMargin) {
+ this.alienTradeMargin = alienTradeMargin;
+ return this;
+ }
+
+ /**
+ * Return the initial amount of money.
+ *
+ * @return the initial amount of money
+ */
+ public int getInitialMoney() {
+ return initialMoney;
+ }
+
+ /**
+ * Set the initial amount of money.
+ *
+ * @param initialMoney the initial amount of money
+ * @return the updated instance of GameSettingBuilder
+ */
+ public GameSettingBuilder setInitialMoney(int initialMoney) {
+ this.initialMoney = initialMoney;
+ return this;
+ }
+
+ /**
+ * Returns the size of an edge of the map in tiles number.
+ *
+ * @return the size of an edge of the map in tiles number
+ */
+ public int getMapSize() {
+ return mapSize;
+ }
+
+ /**
+ * Set the size of the map with the size of an edge in tiles number.
+ *
+ * @param mapSize the number of the tiles in an edge
+ * @return the updated instance of GameSettingBuilder
+ */
+ public GameSettingBuilder setMapSize(int mapSize) {
+ this.mapSize = mapSize;
+ return this;
+ }
+
+ /**
+ * Returns the maximum number of rounds in a game.
+ *
+ * @return the maximum number of rounds in a game
+ */
+ public int getMaxRound() {
+ return maxRound;
+ }
+
+ /**
+ * Set the maxiumum numbers of round in a game.
+ *
+ * @param maxRound the maxiumum numbers of round in a game
+ * @return the updated instance of GameSettingBuilder
+ */
+ public GameSettingBuilder setMaxRound(int maxRound) {
+ this.maxRound = maxRound;
+ return this;
+ }
+
+ /**
+ * Returns the number of veins on the field.
+ *
+ * @return the number of veins on the field.
+ */
+ public int getVeinCount() {
+ return veinCount;
+ }
+
+ /**
+ * Set the number of veins on the field.
+ *
+ * @param veinCount the number of veins on the field.
+ * @return the updated instance of GameSettingBuilder
+ */
+ public GameSettingBuilder setVeinCount(int veinCount) {
+ this.veinCount = veinCount;
+ return this;
+ }
+}
diff --git a/src/main/java/net/javachallenge/api/Logger.java b/src/main/java/net/javachallenge/api/Logger.java
new file mode 100644
index 0000000..0ca0e06
--- /dev/null
+++ b/src/main/java/net/javachallenge/api/Logger.java
@@ -0,0 +1,16 @@
+package net.javachallenge.api;
+
+/**
+ * The Logger class is used to print logs of the operations occurring during the game.
+ */
+public class Logger {
+
+ /**
+ * Logs text using the current display function.
+ *
+ * @param text the text to log
+ */
+ public static void log(String text) {
+ net.javachallenge.Main$.MODULE$.log(text);
+ }
+}
diff --git a/src/main/java/net/javachallenge/api/Make.java b/src/main/java/net/javachallenge/api/Make.java
new file mode 100644
index 0000000..b8b9949
--- /dev/null
+++ b/src/main/java/net/javachallenge/api/Make.java
@@ -0,0 +1,36 @@
+package net.javachallenge.api;
+
+/**
+ * A utility class to construct some instances.
+ */
+public class Make {
+
+ private Make() {}
+
+ /**
+ * Constructs a builder for a game setting.
+ *
+ * @return a builder for a game setting
+ */
+ public static GameSettingBuilder gameSettingsBuilder() {
+ return new GameSettingBuilder();
+ }
+
+ /**
+ * Constructs a builder for a play mode.
+ *
+ * @return a builder for a play mode
+ * */
+ public static PlayModeBuilder playModeBuilder() {
+ return new PlayModeBuilder();
+ }
+
+ /**
+ * Constructs a location which represents a vertex of a tile.
+ *
+ * @return a location which represents a vertex of a tile
+ */
+ public static TrianglePoint point(int x, int y) {
+ return new net.javachallenge.entity.TrianglePoint(x, y);
+ }
+}
diff --git a/src/main/java/net/javachallenge/api/Material.java b/src/main/java/net/javachallenge/api/Material.java
new file mode 100644
index 0000000..62d8d78
--- /dev/null
+++ b/src/main/java/net/javachallenge/api/Material.java
@@ -0,0 +1,21 @@
+package net.javachallenge.api;
+
+/**
+ * The {@link Material} enum represents the three types of material available in the game.
+ */
+public enum Material {
+ /**
+ * A gas material.
+ */
+ Gas,
+
+ /**
+ * A stone material.
+ */
+ Stone,
+
+ /**
+ * A metal material.
+ */
+ Metal;
+}
diff --git a/src/main/java/net/javachallenge/api/MockPlayer.java b/src/main/java/net/javachallenge/api/MockPlayer.java
new file mode 100644
index 0000000..7ddda8f
--- /dev/null
+++ b/src/main/java/net/javachallenge/api/MockPlayer.java
@@ -0,0 +1,44 @@
+package net.javachallenge.api;
+
+import java.util.List;
+
+import net.javachallenge.api.command.Command;
+
+/**
+ * The {@link MockPlayer} class represents a dummy player controlled by the computer.
+ */
+public class MockPlayer extends ComputerPlayer {
+
+ private String name;
+
+ /**
+ * Constructs a MockPlayer with a dummy name.
+ */
+ public MockPlayer() {
+ this("MockPlayer");
+ }
+
+ /**
+ * Constructs a MockPlayer with the given name.
+ *
+ * @param name the name to give to the MockPlayer
+ */
+ public MockPlayer(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public TrianglePoint selectVein(Game game) {
+ return null;
+ }
+
+ @Override
+ public List selectActions(Game game) {
+ return null;
+ }
+}
diff --git a/src/main/java/net/javachallenge/api/PlayMode.java b/src/main/java/net/javachallenge/api/PlayMode.java
new file mode 100644
index 0000000..0d24d31
--- /dev/null
+++ b/src/main/java/net/javachallenge/api/PlayMode.java
@@ -0,0 +1,76 @@
+package net.javachallenge.api;
+
+/**
+ * The {@link PlayMode} class is used to control the different game external parameters.
+ */
+public class PlayMode {
+
+ private int fps;
+ private int availableVeinSelectMilliseconds;
+ private int availableTurnMilliseconds;
+ private UserInterfaceMode userInterfaceMode;
+ private boolean ignoringExceptions;
+
+ /**
+ * Returns the number of FPS of the game.
+ *
+ * @return the number of FPS of the game
+ */
+ public int getFps() {
+ return fps;
+ }
+
+ /**
+ * Returns the maximum milliseconds per a turn.
+ *
+ * @return the maximum milliseconds per a turn
+ */
+ public int getAvailableTurnMilliseconds() {
+ return availableTurnMilliseconds;
+ }
+
+ /**
+ * Returns the maximum milliseconds per a vein selection.
+ *
+ * @return the maximum milliseconds per a vein selection
+ */
+ public int getAvailableVeinSelectMilliseconds() {
+ return availableVeinSelectMilliseconds;
+ }
+
+ /**
+ * Returns the mode of the user interface.
+ *
+ * @return the mode of the user interface
+ */
+ public UserInterfaceMode getUserInterfaceMode() {
+ return userInterfaceMode;
+ }
+
+ /**
+ * Returns the ignoring exception status.
+ *
+ * @return the ignoring exception status
+ */
+ public boolean isIgnoringExceptions() {
+ return ignoringExceptions;
+ }
+
+ /**
+ * Constructs a PlayMode with the given parameters.
+ *
+ * @param fps the fps which is speed for advancing the game
+ * @param availableVeinSelectMilliseconds the maximum milliseconds per a vein selection
+ * @param availableTurnMilliseconds the maximum milliseconds per a turn.
+ * @param userInterfaceMode the user interface mode
+ * @param ignoringExceptions the ignoring exception status (true to ignore)
+ */
+ public PlayMode(int fps, int availableVeinSelectMilliseconds, int availableTurnMilliseconds,
+ UserInterfaceMode userInterfaceMode, boolean ignoringExceptions) {
+ this.fps = fps;
+ this.availableVeinSelectMilliseconds = availableVeinSelectMilliseconds;
+ this.availableTurnMilliseconds = availableTurnMilliseconds;
+ this.userInterfaceMode = userInterfaceMode;
+ this.ignoringExceptions = ignoringExceptions;
+ }
+}
diff --git a/src/main/java/net/javachallenge/api/PlayModeBuilder.java b/src/main/java/net/javachallenge/api/PlayModeBuilder.java
new file mode 100644
index 0000000..d49f026
--- /dev/null
+++ b/src/main/java/net/javachallenge/api/PlayModeBuilder.java
@@ -0,0 +1,131 @@
+package net.javachallenge.api;
+
+/**
+ * The {@link PlayModeBuilder} class is used to construct instances of the PlayMode class.
+ */
+public class PlayModeBuilder {
+ private int fps;
+ private int availableTurnMilliseconds;
+ private int availableVeinSelectMilliseconds;
+ private UserInterfaceMode userInterfaceMode;
+ private boolean ignoringExceptions;
+
+ /**
+ * Constructs a {@link PlayModeBuilder} with default parameters.
+ */
+ public PlayModeBuilder() {
+ PlayMode mode = net.javachallenge.PlayModeHelper.defaultInstance();
+ this.fps = mode.getFps();
+ this.availableTurnMilliseconds = mode.getAvailableTurnMilliseconds();
+ this.availableVeinSelectMilliseconds = mode.getAvailableVeinSelectMilliseconds();
+ this.userInterfaceMode = mode.getUserInterfaceMode();
+ this.ignoringExceptions = mode.isIgnoringExceptions();
+ }
+
+ /**
+ * Builds a {@link PlayMode} instance with this instance parameters.
+ */
+ public PlayMode build() {
+ return net.javachallenge.PlayModeHelper.build(this);
+ }
+
+ /**
+ * Returns the fps which is speed for advancing the game.
+ *
+ * @return the fps which is speed for advancing the game
+ */
+ public int getFps() {
+ return fps;
+ }
+
+ /**
+ * Set the fps which is speed for advancing the game.
+ *
+ * @param fps the fps to set
+ * @return the updated instance of PlayModeBuilder
+ */
+ public PlayModeBuilder setFps(int fps) {
+ this.fps = fps;
+ return this;
+ }
+
+ /**
+ * Returns the maximum milliseconds per a turn.
+ *
+ * @return the maximum milliseconds per a turn
+ */
+ public int getAvailableTurnMilliseconds() {
+ return availableTurnMilliseconds;
+ }
+
+ /**
+ * Set the maximum milliseconds per a turn.
+ *
+ * @param availableTurnMilliseconds the maximum milliseconds per a turn
+ * @return the updated instance of PlayModeBuilder
+ */
+ public PlayModeBuilder setAvailableTurnMilliseconds(int availableTurnMilliseconds) {
+ this.availableTurnMilliseconds = availableTurnMilliseconds;
+ return this;
+ }
+
+ /**
+ * Returns the maximum milliseconds per a vein selection.
+ *
+ * @return the maximum milliseconds per a vein selection
+ */
+ public int getAvailableVeinSelectMilliseconds() {
+ return availableVeinSelectMilliseconds;
+ }
+
+ /**
+ * Set the maximum milliseconds per a vein selection.
+ *
+ * @param availableVeinSelectMilliseconds the maximum milliseconds per a vein selection.
+ * @return the updated instance of PlayModeBuilder
+ */
+ public PlayModeBuilder setAvailableVeinSelectMilliseconds(int availableVeinSelectMilliseconds) {
+ this.availableVeinSelectMilliseconds = availableVeinSelectMilliseconds;
+ return this;
+ }
+
+ /**
+ * Returns the mode of the user interface.
+ *
+ * @return the mode of the user interface
+ */
+ public UserInterfaceMode getUserInterfaceMode() {
+ return userInterfaceMode;
+ }
+
+ /**
+ * Set the mode of the user interface.
+ *
+ * @param userInterfaceMode the mode of the user interface
+ * @return the updated instance of PlayModeBuilder
+ */
+ public PlayModeBuilder setUserInterfaceMode(UserInterfaceMode userInterfaceMode) {
+ this.userInterfaceMode = userInterfaceMode;
+ return this;
+ }
+
+ /**
+ * Returns the ignoring exception status.
+ *
+ * @return the ignoring exception status
+ */
+ public boolean isIgnoringExceptions() {
+ return ignoringExceptions;
+ }
+
+ /**
+ * Set the ignoring exception status.
+ *
+ * @param ignoringExceptions the ignoring exception status
+ * @return the updated instance of PlayModeBuilder
+ */
+ public PlayModeBuilder setIgnoringExceptions(boolean ignoringExceptions) {
+ this.ignoringExceptions = ignoringExceptions;
+ return this;
+ }
+}
diff --git a/src/main/java/net/javachallenge/api/Player.java b/src/main/java/net/javachallenge/api/Player.java
new file mode 100644
index 0000000..ed12cb2
--- /dev/null
+++ b/src/main/java/net/javachallenge/api/Player.java
@@ -0,0 +1,46 @@
+package net.javachallenge.api;
+
+/**
+ * The player interface is the abstract representation of a player in the game.
+ *
+ * Note that this interface is immutable, thus, its object stores the information of just this turn
+ * and will not be updated.
+ */
+public interface Player {
+
+ /**
+ * Returns the id of the player.
+ *
+ * @return the id of the player
+ */
+ int getId();
+
+ /**
+ * Returns the quantity of the given material owned by the player.
+ *
+ * @param material the material to get informations about
+ * @return the quantity of the given material owned by the player
+ */
+ int getMaterial(Material material);
+
+ /**
+ * Returns the amount of money owned by the player.
+ *
+ * @return the amount of money owned by the player
+ */
+ int getMoney();
+
+ /**
+ * Returns the time to live, i.e., the number of the last round where the player were active
+ * (considered as living).
+ *
+ * @return the time to live
+ */
+ int getTimeToLive();
+
+ /**
+ * Please use getTimeToLive instead of this method.
+ */
+ @Deprecated
+ int getLastActiveRound();
+}
diff --git a/src/main/java/net/javachallenge/api/PlayerTrade.java b/src/main/java/net/javachallenge/api/PlayerTrade.java
new file mode 100644
index 0000000..8db9816
--- /dev/null
+++ b/src/main/java/net/javachallenge/api/PlayerTrade.java
@@ -0,0 +1,46 @@
+package net.javachallenge.api;
+
+/**
+ * The {@link PlayerTrade} class represents a trade between players. It can be an offer or a demand.
+ *
+ * Note that this interface is immutable, thus, its object stores the information of just this turn
+ * and will not be updated.
+ *
+ */
+public interface PlayerTrade {
+
+ /**
+ * Returns the id of the player doing the trade.
+ *
+ * @return the id of the player doing the trade
+ */
+ int getPlayerId();
+
+ /**
+ * Returns the material of the trade.
+ *
+ * @return the material of the trade
+ */
+ Material getMaterial();
+
+ /**
+ * Returns the amount of material in the trade.
+ *
+ * @return the amount of material in the trade
+ */
+ int getAmount();
+
+ /**
+ * Returns the price per unit of material in this trade.
+ *
+ * @return the price per unit of material in this trade
+ */
+ int getPricePerOneMaterial();
+
+ /**
+ * Returns the type of the trade.
+ *
+ * @return the type of the trade
+ */
+ TradeType getTradeType();
+}
diff --git a/src/main/java/net/javachallenge/api/Squad.java b/src/main/java/net/javachallenge/api/Squad.java
new file mode 100644
index 0000000..68d9285
--- /dev/null
+++ b/src/main/java/net/javachallenge/api/Squad.java
@@ -0,0 +1,48 @@
+package net.javachallenge.api;
+
+import java.util.ArrayList;
+
+/**
+ * The {@link Squad} interface represents a squad of robots in the game.
+ *
+ * Note that this interface is immutable, thus, its object stores the information of just this turn
+ * and will not be updated.
+ */
+public interface Squad {
+ /**
+ * Returns the id of the owner of the squad.
+ *
+ * @return the id of the owner of the squad
+ */
+ int getOwnerId();
+
+ /**
+ * Returns the number of robots in the squad.
+ *
+ * @return the number of robots in the squad
+ */
+ int getRobot();
+
+ /**
+ * Returns the path of the squad from the current location to the destination as a copied mutable
+ * list.
+ *
+ * @return the path of the squad from the current location to the destination as a copied mutable
+ * list
+ */
+ ArrayList getPath();
+
+ /**
+ * Returns the current location of the squad.
+ *
+ * @return the current location of the squad
+ */
+ TrianglePoint getCurrentLocation();
+
+ /**
+ * Returns the destination of the squad.
+ *
+ * @return the destination of the squad
+ */
+ TrianglePoint getDestinationLocation();
+}
diff --git a/src/main/java/net/javachallenge/api/TradeType.java b/src/main/java/net/javachallenge/api/TradeType.java
new file mode 100644
index 0000000..13fe05f
--- /dev/null
+++ b/src/main/java/net/javachallenge/api/TradeType.java
@@ -0,0 +1,15 @@
+package net.javachallenge.api;
+
+/**
+ * The {@link TradeType} enum is used to express the type of the Trade.
+ */
+public enum TradeType {
+ /**
+ * The offer for selling items.
+ */
+ Offer,
+ /**
+ * The demand for buying items.
+ */
+ Demand,
+}
diff --git a/src/main/java/net/javachallenge/api/TriangleComparator.java b/src/main/java/net/javachallenge/api/TriangleComparator.java
new file mode 100644
index 0000000..9d2b52f
--- /dev/null
+++ b/src/main/java/net/javachallenge/api/TriangleComparator.java
@@ -0,0 +1,16 @@
+package net.javachallenge.api;
+
+import java.util.Comparator;
+
+/**
+ * A {@link Comparator} for {@link TrianglePoint}.
+ */
+public class TriangleComparator implements Comparator {
+ public int compare(TrianglePoint p1, TrianglePoint p2) {
+ if (p1.getY() == p2.getY()) {
+ return p1.getX() - p2.getX();
+ } else {
+ return p1.getY() - p2.getY();
+ }
+ }
+}
diff --git a/src/main/java/net/javachallenge/api/TrianglePoint.java b/src/main/java/net/javachallenge/api/TrianglePoint.java
new file mode 100644
index 0000000..0cfd72c
--- /dev/null
+++ b/src/main/java/net/javachallenge/api/TrianglePoint.java
@@ -0,0 +1,71 @@
+package net.javachallenge.api;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+
+/**
+ * The {@link TrianglePoint} class represents the coordinates of the game map.
+ *
+ * Note that this interface is immutable, thus, its object stores the information of just this turn
+ * and will not be updated.
+ *
+ */
+public interface TrianglePoint extends Serializable {
+ /**
+ * Returns the horizontal coordinate of the point.
+ *
+ * @return the horizontal coordinate of the point
+ */
+ int getX();
+
+ /**
+ * Returns the vertical coordinate of the point.
+ *
+ * @return the vertical coordinate of the point.
+ */
+ int getY();
+
+ /**
+ * Returns true if the triangle is upward, false otherwise
+ *
+ * @return true if the triangle is upward, false otherwise
+ */
+ boolean isUpwardTriangle();
+
+ /**
+ * Returns true if the triangle is downward, false otherwise
+ *
+ * @return true if the triangle is downward, false otherwise
+ */
+ boolean isDownwardTriangle();
+
+ /**
+ * Returns true if this and that are connected, else otherwise
+ *
+ * @return true if this and that are connected, else otherwise
+ */
+ boolean isConnected(TrianglePoint that);
+
+ /**
+ * Returns the distance to the point to
+ *
+ * @param to the target point
+ * @return the distance to the point to
+ */
+ int getDistance(TrianglePoint to);
+
+ /**
+ * Returns the shortest path from this position to the specified position as a copied mutable
+ * list.
+ *
+ * @param to the target point
+ * @return the shortest path from this position to the specified position as a copied mutable
+ * list.
+ */
+ ArrayList getShortestPath(TrianglePoint to);
+
+ /**
+ * Returns a string representation of the point to display in commands.
+ */
+ String toStringForCommand();
+}
diff --git a/src/main/java/net/javachallenge/api/UserInterfaceMode.java b/src/main/java/net/javachallenge/api/UserInterfaceMode.java
new file mode 100644
index 0000000..86b4f68
--- /dev/null
+++ b/src/main/java/net/javachallenge/api/UserInterfaceMode.java
@@ -0,0 +1,12 @@
+package net.javachallenge.api;
+
+/**
+ * The {@link UserInterfaceMode} enum represents the different user interface modes available for
+ * the game.
+ */
+public enum UserInterfaceMode {
+ /**
+ * The different user interface modes available.
+ */
+ CharacterBased, LargeGraphical, SmallGraphical,
+}
diff --git a/src/main/java/net/javachallenge/api/Vein.java b/src/main/java/net/javachallenge/api/Vein.java
new file mode 100644
index 0000000..b49e3d7
--- /dev/null
+++ b/src/main/java/net/javachallenge/api/Vein.java
@@ -0,0 +1,100 @@
+package net.javachallenge.api;
+
+import java.util.ArrayList;
+
+/**
+ * The {@link Vein} class represents a vein of the field in the game.
+ *
+ * Note that this interface is immutable, thus, its object stores the information of just this turn
+ * and will not be updated.
+ *
+ */
+public interface Vein {
+ /**
+ * Returns the id of the owner of the vein.
+ *
+ * Note that a neutral vein's owner is equal to Game.getNeutralPlayerId().
+ *
+ * @return the id of the owner of the vein
+ */
+ int getOwnerId();
+
+ /**
+ * Returns the location of the vein.
+ *
+ * @return the location of the vein
+ */
+ TrianglePoint getLocation();
+
+ /**
+ * Returns the material produced by the vein.
+ *
+ * @return the material produced by the vein
+ */
+ Material getMaterial();
+
+ /**
+ * Returns the number of robots in the vein.
+ *
+ * @return Returns the number of robots in the vein
+ */
+ int getNumberOfRobots();
+
+ /**
+ * Returns the current material productivity.
+ *
+ * @return the current material productivity
+ */
+ int getCurrentMaterialProductivity();
+
+ /**
+ * Returns the current robot productivity (reproduction rate).
+ *
+ * @return the current robot productivity (reproduction rate)
+ */
+ int getCurrentRobotProductivity();
+
+ /**
+ * Returns the initial material productivity.
+ *
+ * @return the initial material productivity
+ */
+ int getInitialMaterialProductivity();
+
+ /**
+ * Returns the initial robot productivity (reproduction rate).
+ *
+ * @return the initial robot productivity (reproduction rate)
+ */
+ int getInitialRobotProductivity();
+
+ /**
+ * Returns the material rank.
+ *
+ * @return the material rank
+ */
+ int getMaterialRank();
+
+ /**
+ * Returns the robot rank.
+ *
+ * @return the robot rank.
+ */
+ int getRobotRank();
+
+ /**
+ * Returns the distance to the vein to.
+ *
+ * @param to the target vein for the distance
+ * @return the distance between this and to
+ */
+ int getDistance(Vein to);
+
+ /**
+ * Returns the shortest path from this vein to the specified vein as a copied mutable list.
+ *
+ * @param to the target vein
+ * @return the shortest path from this vein to the specified vein as a copied mutable list.
+ */
+ ArrayList getShortestPath(Vein to);
+}
diff --git a/src/main/java/net/javachallenge/api/command/BuyFromAlienTradeCommand.java b/src/main/java/net/javachallenge/api/command/BuyFromAlienTradeCommand.java
new file mode 100644
index 0000000..beb6418
--- /dev/null
+++ b/src/main/java/net/javachallenge/api/command/BuyFromAlienTradeCommand.java
@@ -0,0 +1,31 @@
+package net.javachallenge.api.command;
+
+import net.javachallenge.api.Material;
+
+import com.google.common.base.Preconditions;
+
+/**
+ * The {@link BuyFromAlienTradeCommand} represents a command to buy the given material from aliens.
+ */
+class BuyFromAlienTradeCommand implements Command {
+ private Material material;
+ private int amount;
+
+ /**
+ * Constructs a {@link BuyFromAlienTradeCommand} with the given material and amount of it.
+ *
+ * @param material the material to buy
+ * @param amount the amount of material to buy
+ */
+ BuyFromAlienTradeCommand(Material material, int amount) {
+ // Check toString method works well with no exception.
+ Preconditions.checkNotNull(material);
+ this.material = material;
+ this.amount = amount;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("bank buy %s %d", material, amount);
+ }
+}
diff --git a/src/main/java/net/javachallenge/api/command/BuyFromOfferCommand.java b/src/main/java/net/javachallenge/api/command/BuyFromOfferCommand.java
new file mode 100644
index 0000000..e2c672a
--- /dev/null
+++ b/src/main/java/net/javachallenge/api/command/BuyFromOfferCommand.java
@@ -0,0 +1,34 @@
+package net.javachallenge.api.command;
+
+import net.javachallenge.api.PlayerTrade;
+
+import com.google.common.base.Preconditions;
+
+/**
+ * The {@link BuyFromOfferCommand} class represents a command to buy the given material from another
+ * player.
+ */
+class BuyFromOfferCommand implements Command {
+
+ private PlayerTrade trade;
+ private int amount;
+
+ /**
+ * Constructs a {@link BuyFromOfferCommand} with the given trade and the amount of material to buy
+ * from it.
+ *
+ * @param trade the offer to buy from
+ * @param amount the amount of material to buy
+ */
+ BuyFromOfferCommand(PlayerTrade trade, int amount) {
+ // Check toString method works well with no exception.
+ Preconditions.checkNotNull(trade);
+ this.trade = trade;
+ this.amount = amount;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("buy %d %s %d", trade.getPlayerId(), trade.getMaterial(), amount);
+ }
+}
diff --git a/src/main/java/net/javachallenge/api/command/Command.java b/src/main/java/net/javachallenge/api/command/Command.java
new file mode 100644
index 0000000..cb07add
--- /dev/null
+++ b/src/main/java/net/javachallenge/api/command/Command.java
@@ -0,0 +1,6 @@
+package net.javachallenge.api.command;
+
+/**
+ * The {@link Command} interface represents a command that can be executed by the player.
+ */
+public interface Command {}
diff --git a/src/main/java/net/javachallenge/api/command/Commands.java b/src/main/java/net/javachallenge/api/command/Commands.java
new file mode 100644
index 0000000..6ddab04
--- /dev/null
+++ b/src/main/java/net/javachallenge/api/command/Commands.java
@@ -0,0 +1,155 @@
+package net.javachallenge.api.command;
+
+import java.util.List;
+
+import net.javachallenge.api.Material;
+import net.javachallenge.api.PlayerTrade;
+import net.javachallenge.api.TrianglePoint;
+import net.javachallenge.api.Vein;
+
+/**
+ * A factory class to construct commands.
+ */
+public class Commands {
+ private Commands() {}
+
+ /**
+ * Constructs a command to buy the given material from aliens.
+ *
+ * @param material the material to buy
+ * @param amount the amount of material to buy
+ * @return the command to buy the material
+ */
+ public static Command buyFromAlienTrade(Material material, int amount) {
+ return new BuyFromAlienTradeCommand(material, amount);
+ }
+
+ /**
+ * Constructs a command to sell the given material to aliens.
+ *
+ * @param material the material to sell to the aliens
+ * @param amount the amount of material to sell
+ * @return the command to sell the material
+ */
+ public static Command sellToAlienTrade(Material material, int amount) {
+ return new SellToAlienTradeCommand(material, amount);
+ }
+
+ /**
+ * Constructs a command to buy the given material from another player.
+ *
+ * @param trade the offer to buy from
+ * @param amount the amount of material to buy
+ * @return the command to buy from the given offer
+ */
+ public static Command buyFromPlayerTrade(PlayerTrade trade, int amount) {
+ return new BuyFromOfferCommand(trade, amount);
+ }
+
+ /**
+ * Constructs a command to make an offer to other players.
+ *
+ * @param trade the demand to respond to
+ * @param amount the amount of material to sell. Should be less or equal to the amount of the
+ * demand.
+ * @return the command to sell in response to the given demand
+ */
+ public static Command sellToPlayerTrade(PlayerTrade trade, int amount) {
+ return new SellToDemandCommand(trade, amount);
+ }
+
+ /**
+ * Constructs a command to create an offer to sell material to other players.
+ *
+ * @param material the material to sell
+ * @param amount the amount of material to sell
+ * @param pricePerSingleItem the price of a unit of the material to sell
+ * @return the command to make the offer
+ */
+ public static Command offer(Material material, int amount, int pricePerSingleItem) {
+ return new OfferCommand(material, amount, pricePerSingleItem);
+ }
+
+ /**
+ * Constructs a command to create a demand to buy material from other players.
+ *
+ * @param material the material to buy
+ * @param amount the amount of material to buy
+ * @param pricePerSingleItem the price of a unit of the material to buy
+ * @return the command to make the demand
+ */
+ public static Command demand(Material material, int amount, int pricePerSingleItem) {
+ return new DemandCommand(material, amount, pricePerSingleItem);
+ }
+
+ /**
+ * Constructs a command to send robot to occupy a vein.
+ *
+ * @param robotsNumber the number of robots to send to the vein. There should be enough robots at
+ * the vein from where to send the robots.
+ * @param from the coordinates of the vein to send the robots from. The location shall point to an
+ * existing vein owned by the caller.
+ * @param to the coordinates of the vein to send the robots to. The location shall point to a vein
+ * owned by the caller.
+ * @return the command to send the robots
+ */
+ public static Command launch(int robotsNumber, TrianglePoint from, TrianglePoint to) {
+ return new LaunchCommand(robotsNumber, from, to);
+ }
+
+ /**
+ * Constructs a command with the number of robots to send, and the coordinates of the vein from
+ * and to where the robots should go to.
+ *
+ * @param robotsNumber the number of robots to send to the vein. There should be enough robots at
+ * the vein from where to send the robots. vein owned by the caller.
+ * @param path a list of points containing the path to take. The path should at least contain the
+ * departure point and the destination.
+ * @return the command to send the robots
+ */
+ public static Command launchWithPath(int robotsNumber, List path) {
+ return new LaunchWithPathCommand(robotsNumber, path);
+ }
+
+ /**
+ * Constructs a command to upgrade the productivity of the vein at the given location.
+ *
+ * @param location the location of the vein to upgrade. The location shall point to a vein owned
+ * by the caller.
+ * @return the command to upgrade material rank at the given location
+ */
+ public static Command upgradeMaterial(TrianglePoint location) {
+ return new UpgradeMaterialCommand(location);
+ }
+
+ /**
+ * Constructs a command to upgrade the reproduction rate of the robots at the given vein.
+ *
+ * @param location the location of the vein to upgrade. The location shall point to a vein owned
+ * by the caller.
+ * @return the command to upgrade material rank at the given location
+ */
+ public static Command upgradeRobot(TrianglePoint location) {
+ return new UpgradeRobotCommand(location);
+ }
+
+ /**
+ * Constructs a command to upgrade the productivity of the vein at the given location.
+ *
+ * @param vein the vein to upgrade. The vein shall point to a vein owned by the caller.
+ * @return the command to upgrade the vein at the given location
+ */
+ public static Command upgradeMaterial(Vein vein) {
+ return new UpgradeMaterialCommand(vein.getLocation());
+ }
+
+ /**
+ * Constructs a command to upgrade the reproduction rate of the robots at the given vein.
+ *
+ * @param vein the vein to upgrade. The vein shall point to a vein owned by the caller.
+ * @return the command to upgrade robot rank of the vein at the given location
+ */
+ public static Command upgradeRobot(Vein vein) {
+ return new UpgradeRobotCommand(vein.getLocation());
+ }
+}
diff --git a/src/main/java/net/javachallenge/api/command/DemandCommand.java b/src/main/java/net/javachallenge/api/command/DemandCommand.java
new file mode 100644
index 0000000..f0df7e8
--- /dev/null
+++ b/src/main/java/net/javachallenge/api/command/DemandCommand.java
@@ -0,0 +1,37 @@
+package net.javachallenge.api.command;
+
+import net.javachallenge.api.Material;
+
+import com.google.common.base.Preconditions;
+
+/**
+ * The {@link DemandCommand} class represents a command to create a demand to buy material from
+ * other players.
+ */
+class DemandCommand implements Command {
+
+ private Material material;
+ private int amount;
+ private int pricePerSingleItem;
+
+ /**
+ * Constructs a {@link DemandCommand} with the material and amount to buy and the price for a unit
+ * of this material.
+ *
+ * @param material the material to buy
+ * @param amount the amount of material to buy
+ * @param pricePerSingleitem the price of a unit of the material to buy
+ */
+ DemandCommand(Material material, int amount, int pricePerSingleItem) {
+ // Check toString method works well with no exception.
+ Preconditions.checkNotNull(material);
+ this.material = material;
+ this.amount = amount;
+ this.pricePerSingleItem = pricePerSingleItem;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("demand %s %d %d", material, amount, pricePerSingleItem);
+ }
+}
diff --git a/src/main/java/net/javachallenge/api/command/LaunchCommand.java b/src/main/java/net/javachallenge/api/command/LaunchCommand.java
new file mode 100644
index 0000000..411b9e0
--- /dev/null
+++ b/src/main/java/net/javachallenge/api/command/LaunchCommand.java
@@ -0,0 +1,41 @@
+package net.javachallenge.api.command;
+
+import net.javachallenge.api.TrianglePoint;
+
+import com.google.common.base.Preconditions;
+
+/**
+ * The {@link LaunchCommand} class represents a command to send robot to occupy a vein.
+ */
+class LaunchCommand implements Command {
+
+ private int robotsNumber;
+ private TrianglePoint from;
+ private TrianglePoint to;
+
+ /**
+ * Constructs a {@link LaunchCommand} with the number of robots to send, and the coordinates of
+ * the vein from and to where the robots should go to.
+ *
+ * @param robotsNumber the number of robots to send to the vein. There should be enough robots at
+ * the vein from where to send the robots.
+ * @param from the coordinates of the vein to send the robots from. The location shall point to a
+ * vein owned by the caller.
+ * @param to the coordinates of the vein to send the robots to. The location shall point to a vein
+ * owned by the caller.
+ */
+ LaunchCommand(int robotsNumber, TrianglePoint from, TrianglePoint to) {
+ // Check toString method works well with no exception.
+ Preconditions.checkNotNull(from);
+ Preconditions.checkNotNull(to);
+ this.robotsNumber = robotsNumber;
+ this.from = from;
+ this.to = to;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("launch %d %s %s", robotsNumber, from.toStringForCommand(),
+ to.toStringForCommand());
+ }
+}
diff --git a/src/main/java/net/javachallenge/api/command/LaunchWithPathCommand.java b/src/main/java/net/javachallenge/api/command/LaunchWithPathCommand.java
new file mode 100644
index 0000000..f33612d
--- /dev/null
+++ b/src/main/java/net/javachallenge/api/command/LaunchWithPathCommand.java
@@ -0,0 +1,45 @@
+package net.javachallenge.api.command;
+
+import java.util.List;
+
+import net.javachallenge.api.TrianglePoint;
+
+import com.google.common.base.Preconditions;
+
+/**
+ * The {@link LaunchWithPathCommand} class represents a command to send robot to occupy a vein.
+ */
+class LaunchWithPathCommand implements Command {
+
+ private int robotsNumber;
+ private List path;
+
+ /**
+ * Constructs a {@link LaunchWithPathCommand} with the number of robots to send, and the
+ * coordinates of the vein from and to where the robots should go to.
+ *
+ * @param robotsNumber the number of robots to send to the vein. There should be enough robots at
+ * the vein from where to send the robots. vein owned by the caller.
+ * @param path a list of points containing the path to take. The path should at least contain the
+ * departure point and the destination.
+ */
+
+ LaunchWithPathCommand(int robotsNumber, List path) {
+ // Check toString method works well with no exception.
+ Preconditions.checkNotNull(path);
+ for (TrianglePoint p : path) {
+ Preconditions.checkNotNull(p);
+ }
+ this.robotsNumber = robotsNumber;
+ this.path = path;
+ }
+
+ @Override
+ public String toString() {
+ String s = "launch " + String.valueOf(this.robotsNumber);
+ for (TrianglePoint p : this.path) {
+ s += " " + p.toStringForCommand();
+ }
+ return s;
+ }
+}
diff --git a/src/main/java/net/javachallenge/api/command/OfferCommand.java b/src/main/java/net/javachallenge/api/command/OfferCommand.java
new file mode 100644
index 0000000..79c8f08
--- /dev/null
+++ b/src/main/java/net/javachallenge/api/command/OfferCommand.java
@@ -0,0 +1,38 @@
+package net.javachallenge.api.command;
+
+import net.javachallenge.api.Material;
+
+import com.google.common.base.Preconditions;
+
+/**
+ * The {@link OfferCommand} class represents a command to create an offer to sell material to other
+ * players.
+ */
+class OfferCommand implements Command {
+
+ private Material material;
+ private int amount;
+ private int pricePerSingleItem;
+
+ /**
+ * Constructs an {@link OfferCommand} with the given material and amount to sell and the price for
+ * a unit of this material.
+ *
+ * @param material the material to sell
+ * @param amount the amount of material to sell
+ * @param pricePerSingleitem the price of a unit of the material to sell
+ *
+ */
+ OfferCommand(Material material, int amount, int pricePerSingleItem) {
+ // Check toString method works well with no exception.
+ Preconditions.checkNotNull(material);
+ this.material = material;
+ this.amount = amount;
+ this.pricePerSingleItem = pricePerSingleItem;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("offer %s %d %d", material, amount, pricePerSingleItem);
+ }
+}
diff --git a/src/main/java/net/javachallenge/api/command/SellToAlienTradeCommand.java b/src/main/java/net/javachallenge/api/command/SellToAlienTradeCommand.java
new file mode 100644
index 0000000..2955464
--- /dev/null
+++ b/src/main/java/net/javachallenge/api/command/SellToAlienTradeCommand.java
@@ -0,0 +1,33 @@
+package net.javachallenge.api.command;
+
+import net.javachallenge.api.Material;
+
+import com.google.common.base.Preconditions;
+
+/**
+ * The {@link SellToAlienTradeCommand} class represents a command to sell the given material to
+ * aliens.
+ */
+class SellToAlienTradeCommand implements Command {
+
+ private Material material;
+ private int amount;
+
+ /**
+ * Constructs a {@link SellToAlienTradeCommand} with the given material and amount of it.
+ *
+ * @param material the material to sell to the aliens
+ * @param amount the amount of material to sell
+ */
+ SellToAlienTradeCommand(Material material, int amount) {
+ // Check toString method works well with no exception.
+ Preconditions.checkNotNull(material);
+ this.material = material;
+ this.amount = amount;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("bank sell %s %d", material, amount);
+ }
+}
diff --git a/src/main/java/net/javachallenge/api/command/SellToDemandCommand.java b/src/main/java/net/javachallenge/api/command/SellToDemandCommand.java
new file mode 100644
index 0000000..fbbc368
--- /dev/null
+++ b/src/main/java/net/javachallenge/api/command/SellToDemandCommand.java
@@ -0,0 +1,33 @@
+package net.javachallenge.api.command;
+
+import net.javachallenge.api.PlayerTrade;
+
+import com.google.common.base.Preconditions;
+
+/**
+ * The {@link SellToDemandCommand} class represents a command to make an offer to other players.
+ */
+class SellToDemandCommand implements Command {
+
+ private PlayerTrade trade;
+ private int amount;
+
+ /**
+ * Constructs a {@link SellToDemandCommand} with the demand to respond to and the amount to sell.
+ *
+ * @param trade the demand to respond to
+ * @param amount the amount of material to sell. Should be less or equal to the amount of the
+ * demand.
+ */
+ SellToDemandCommand(PlayerTrade trade, int amount) {
+ // Check toString method works well with no exception.
+ Preconditions.checkNotNull(trade);
+ this.trade = trade;
+ this.amount = amount;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("sell %d %s %d", trade.getPlayerId(), trade.getMaterial(), amount);
+ }
+}
diff --git a/src/main/java/net/javachallenge/api/command/UpgradeMaterialCommand.java b/src/main/java/net/javachallenge/api/command/UpgradeMaterialCommand.java
new file mode 100644
index 0000000..7b81dc7
--- /dev/null
+++ b/src/main/java/net/javachallenge/api/command/UpgradeMaterialCommand.java
@@ -0,0 +1,31 @@
+package net.javachallenge.api.command;
+
+import net.javachallenge.api.TrianglePoint;
+
+import com.google.common.base.Preconditions;
+
+/**
+ * The {@link UpgradeMaterialCommand} class represents a command to upgrade the productivity of the
+ * vein at the given location.
+ */
+class UpgradeMaterialCommand implements Command {
+
+ private TrianglePoint location;
+
+ /**
+ * Constructs an {@link UpgradeMaterialCommand} for the vein at the given location.
+ *
+ * @param location the location of the vein to upgrade. The location shall point to a vein owned
+ * by the caller.
+ */
+ UpgradeMaterialCommand(TrianglePoint location) {
+ // Check toString method works well with no exception.
+ Preconditions.checkNotNull(location);
+ this.location = location;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("upgrade material %s", location.toStringForCommand());
+ }
+}
diff --git a/src/main/java/net/javachallenge/api/command/UpgradeRobotCommand.java b/src/main/java/net/javachallenge/api/command/UpgradeRobotCommand.java
new file mode 100644
index 0000000..aea70bf
--- /dev/null
+++ b/src/main/java/net/javachallenge/api/command/UpgradeRobotCommand.java
@@ -0,0 +1,32 @@
+package net.javachallenge.api.command;
+
+import net.javachallenge.api.TrianglePoint;
+
+import com.google.common.base.Preconditions;
+
+/**
+ * The {@link UpgradeRobotCommand} class represents a command to upgrade the reproduction rate of
+ * the robots at the given vein.
+ */
+class UpgradeRobotCommand implements Command {
+
+ private TrianglePoint location;
+
+ /**
+ * Constructs an {@link UpgradeRobotCommand} to upgrade the robots reproduction rate of the vein
+ * at the given location.
+ *
+ * @param location the location of the vein in which robots should be upgraded. The location shall
+ * point to a vein owned by the caller.
+ */
+ UpgradeRobotCommand(TrianglePoint location) {
+ // Check toString method works well with no exception.
+ Preconditions.checkNotNull(location);
+ this.location = location;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("upgrade robot %s", location.toStringForCommand());
+ }
+}
diff --git a/src/main/java/net/javachallenge/contest/FinalContestReplayer.java b/src/main/java/net/javachallenge/contest/FinalContestReplayer.java
new file mode 100644
index 0000000..9ca6384
--- /dev/null
+++ b/src/main/java/net/javachallenge/contest/FinalContestReplayer.java
@@ -0,0 +1,24 @@
+package net.javachallenge.contest;
+
+import java.util.List;
+
+import net.javachallenge.api.Make;
+import net.javachallenge.api.PlayMode;
+
+import com.google.common.collect.Lists;
+
+public class FinalContestReplayer {
+ public static void main(String[] args) {
+ PlayMode playMode = Make.playModeBuilder().setFps(20).build();
+ List fileNames =
+ Lists
+ .newArrayList(
+ "replay-final/2012_11_18_8_46_36__oshieteZukky_not_shiokawa_Mi_Sawa2012_wakaba_Gunma_s_Ambition___o______o__.rep",
+ "replay-final/2012_11_18_8_46_40__not_shiokawa_Gunma_s_Ambition_Mi_Sawa2012_oshieteZukky_wakaba___o______o__.rep",
+ "replay-final/2012_11_18_8_46_43__wakaba_not_shiokawa_oshieteZukky_Mi_Sawa2012___o______o___Gunma_s_Ambition.rep",
+ "replay-final/2012_11_18_11_25_35____o______o___oshieteZukky.rep");
+ for (String fileName : fileNames) {
+ net.javachallenge.Main.startReplayGame(fileName, playMode);
+ }
+ }
+}
diff --git a/src/main/java/net/javachallenge/contest/GuestFinalContestReplayer.java b/src/main/java/net/javachallenge/contest/GuestFinalContestReplayer.java
new file mode 100644
index 0000000..f591f59
--- /dev/null
+++ b/src/main/java/net/javachallenge/contest/GuestFinalContestReplayer.java
@@ -0,0 +1,24 @@
+package net.javachallenge.contest;
+
+import java.util.List;
+
+import net.javachallenge.api.Make;
+import net.javachallenge.api.PlayMode;
+
+import com.google.common.collect.Lists;
+
+public class GuestFinalContestReplayer {
+ public static void main(String[] args) {
+ PlayMode playMode = Make.playModeBuilder().setFps(20).build();
+ List fileNames =
+ Lists
+ .newArrayList(
+ "replay-guest-final/2012_11_18_9_8_46__methane1_not_shiokawa_wakaba_oshieteZukky___o______o___hasi.rep",
+ "replay-guest-final/2012_11_18_9_8_51__wakaba_methane1_oshieteZukky_hasi___o______o___not_shiokawa.rep",
+ "replay-guest-final/2012_11_18_9_8_53__wakaba___o______o___oshieteZukky_not_shiokawa_methane1_hasi.rep");
+
+ for (String fileName : fileNames) {
+ net.javachallenge.Main.startReplayGame(fileName, playMode);
+ }
+ }
+}
diff --git a/src/main/java/net/javachallenge/contest/GuestQualificationContestReplayer.java b/src/main/java/net/javachallenge/contest/GuestQualificationContestReplayer.java
new file mode 100644
index 0000000..e53eb80
--- /dev/null
+++ b/src/main/java/net/javachallenge/contest/GuestQualificationContestReplayer.java
@@ -0,0 +1,31 @@
+package net.javachallenge.contest;
+
+import java.util.List;
+
+import net.javachallenge.api.Make;
+import net.javachallenge.api.PlayMode;
+
+import com.google.common.collect.Lists;
+
+public class GuestQualificationContestReplayer {
+ public static void main(String[] args) {
+ PlayMode playMode = Make.playModeBuilder().setFps(20).build();
+ List fileNames =
+ Lists
+ .newArrayList(
+ "replay-guest-qual/2012_11_18_8_57_0__mecha_g3_Wand_Player_JoeJack_Oyososan_hasi_methane1.rep",
+ "replay-guest-qual/2012_11_18_8_57_4__JoeJack_methane1_hasi_Wand_Player_Oyososan_mecha_g3.rep",
+ "replay-guest-qual/2012_11_18_8_57_6__Oyososan_Wand_Player_mecha_g3_hasi_JoeJack_methane1.rep",
+ "replay-guest-qual/2012_11_18_8_57_9__methane1_Wand_Player_JoeJack_Oyososan_hasi_mecha_g3.rep",
+ "replay-guest-qual/2012_11_18_8_57_12__hasi_mecha_g3_Wand_Player_methane1_JoeJack_Oyososan.rep",
+ "replay-guest-qual/2012_11_18_8_57_15__methane1_hasi_Wand_Player_Oyososan_mecha_g3_JoeJack.rep",
+ "replay-guest-qual/2012_11_18_8_57_17__methane1_JoeJack_Wand_Player_hasi_Oyososan_mecha_g3.rep",
+ "replay-guest-qual/2012_11_18_8_57_19__JoeJack_Oyososan_methane1_hasi_mecha_g3_Wand_Player.rep",
+ "replay-guest-qual/2012_11_18_8_57_22__methane1_mecha_g3_Wand_Player_JoeJack_Oyososan_hasi.rep",
+ "replay-guest-qual/2012_11_18_8_56_56__methane1_JoeJack_Oyososan_hasi_Wand_Player_mecha_g3.rep");
+
+ for (String fileName : fileNames) {
+ net.javachallenge.Main.startReplayGame(fileName, playMode);
+ }
+ }
+}
diff --git a/src/main/java/net/javachallenge/contest/QualificationContestReplayer.java b/src/main/java/net/javachallenge/contest/QualificationContestReplayer.java
new file mode 100644
index 0000000..e8c802a
--- /dev/null
+++ b/src/main/java/net/javachallenge/contest/QualificationContestReplayer.java
@@ -0,0 +1,26 @@
+package net.javachallenge.contest;
+
+import java.util.List;
+
+import net.javachallenge.api.Make;
+import net.javachallenge.api.PlayMode;
+
+import com.google.common.collect.Lists;
+
+public class QualificationContestReplayer {
+ public static void main(String[] args) {
+ PlayMode playMode = Make.playModeBuilder().setFps(20).build();
+ List fileNames =
+ Lists
+ .newArrayList(
+ "replay-qual/2012_11_18_8_19_11__You_And_Java__Download_Freely____w___Gunma_s_Ambition_Sendy_Enumerable_C_hokudai.rep",
+ "replay-qual/2012_11_18_8_19_14__mofu_txt_not_shiokawa_GlasgowHaskellPlayer_Chrome_0xFF7_oshieteZukky.rep",
+ "replay-qual/2012_11_18_8_19_18_____3__________usagisan_Mi_Sawa2012_Amadeus___d__0w0__b_Hikikomori____Okubyoumono_wakaba.rep",
+ "replay-qual/2012_11_18_8_19_19__icp_py_Myu_TeamTakapt_muteki_shogun_ma_bo______w____________.rep",
+ "replay-qual/2012_11_18_8_19_21__There_s_more_than_one_WA_to_do_AC__JoeJack_Guan_Wun_CityU_EEngineer_UECoders_zerohachi.rep",
+ "replay-qual/2012_11_18_8_19_23__hiyokko_team_Otoshigami_tmt514___o______o___THE_2DM_STER_Mr__Tantan.rep");
+ for (String fileName : fileNames) {
+ net.javachallenge.Main.startReplayGame(fileName, playMode);
+ }
+ }
+}
diff --git a/src/main/java/net/javachallenge/players/Main.java b/src/main/java/net/javachallenge/players/Main.java
new file mode 100644
index 0000000..32fbcbf
--- /dev/null
+++ b/src/main/java/net/javachallenge/players/Main.java
@@ -0,0 +1,38 @@
+package net.javachallenge.players;
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+import net.javachallenge.api.ComputerPlayer;
+import net.javachallenge.api.GameSetting;
+import net.javachallenge.api.Make;
+import net.javachallenge.api.PlayMode;
+import net.javachallenge.players.guests.Hasi;
+import net.javachallenge.players.others.JoeJack;
+import net.javachallenge.players.others.Myu;
+import net.javachallenge.players.others.NearPlayer;
+import net.javachallenge.players.others.Sabateur;
+import net.javachallenge.players.others.Tokoharu;
+import net.javachallenge.players.others.Wand;
+
+import com.google.common.collect.Lists;
+
+public class Main {
+
+ public static void main(String[] args) {
+ ArrayList players =
+ Lists.newArrayList(new Hasi(), new JoeJack(), new Myu(), new Sabateur(), new Tokoharu(),
+ new NearPlayer());
+ Collections.shuffle(players);
+
+ // You can customize game setting.
+ GameSetting setting = Make.gameSettingsBuilder().build();
+ // You can customize play setting which is independent on game rule.
+ PlayMode playMode = Make.playModeBuilder().setFps(9999)
+ // .setIgnoringExceptions(false) for debugging
+ // .setUserInterfaceMode(UserInterfaceMode.CharacterBased)
+ .build();
+
+ net.javachallenge.Main.startAIGame(players.toArray(new ComputerPlayer[0]), setting, playMode);
+ }
+}
diff --git a/src/main/java/net/javachallenge/players/guests/Hasi.java b/src/main/java/net/javachallenge/players/guests/Hasi.java
new file mode 100644
index 0000000..63a7e92
--- /dev/null
+++ b/src/main/java/net/javachallenge/players/guests/Hasi.java
@@ -0,0 +1,397 @@
+package net.javachallenge.players.guests;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+
+import net.javachallenge.api.ComputerPlayer;
+import net.javachallenge.api.Game;
+import net.javachallenge.api.Make;
+import net.javachallenge.api.Material;
+import net.javachallenge.api.Squad;
+import net.javachallenge.api.TrianglePoint;
+import net.javachallenge.api.Vein;
+import net.javachallenge.api.command.Command;
+import net.javachallenge.api.command.Commands;
+
+public class Hasi extends ComputerPlayer {
+ Random rand = new Random("hasi".hashCode());
+ int median;
+ HashMap> G = null;
+
+ @Override
+ public String getName() {
+ return "hasi";
+ }
+
+ @Override
+ public TrianglePoint selectVein(Game game) {
+ this.saveTemporalVeinLocation(Make.point(0, 0));
+
+ if (G == null) {
+ G = new HashMap>();
+ ArrayList veinsAll = game.getField().getVeins();
+ int N = veinsAll.size();
+ int[][] distanceTable = new int[N][N];
+ for (int i = 1; i < N; ++i) {
+ for (int j = 0; j < i; ++j) {
+ distanceTable[i][j] = distanceTable[j][i] = veinsAll.get(i)
+ .getDistance(veinsAll.get(j));
+ }
+ }
+ boolean[][] notShortest = new boolean[N][N];
+ for (int i = 1; i < N; ++i) {
+ for (int j = 0; j < i; ++j) {
+ for (int k = 0; k < N; ++k)
+ if (k != i && k != j) {
+ if (distanceTable[i][j] >= distanceTable[i][k]
+ + distanceTable[k][j]) {
+ notShortest[i][j] = notShortest[j][i] = true;
+ break;
+ }
+ }
+ }
+ }
+ ArrayList cnt = new ArrayList();
+ for (int i = 0; i < N; ++i) {
+ ArrayList a = new ArrayList();
+ for (int j = 0; j < N; ++j) {
+ if (j != i && !notShortest[i][j]) {
+ a.add(veinsAll.get(j).getLocation());
+ }
+ }
+ G.put(veinsAll.get(i).getLocation(), a);
+ cnt.add(a.size());
+ }
+ Collections.sort(cnt);
+ median = cnt.get(cnt.size() / 2);
+ }
+
+ ArrayList veins = new ArrayList();
+ for (Vein vein : game.getField().getVeins(game.getNeutralPlayerId())) {
+ veins.add(vein);
+ }
+ if (!veins.isEmpty()) {
+ Collections.sort(veins, new SelectVeinComparator(game));
+ return veins.get(0).getLocation();
+ }
+ for (Vein vein : game.getField().getVeins()) {
+ if (vein.getOwnerId() == game.getNeutralPlayerId()) {
+ veins.add(vein);
+ }
+ }
+ return veins.get(rand.nextInt(veins.size())).getLocation();
+ }
+
+ @Override
+ public List selectActions(Game game) {
+ List commands = new ArrayList();
+ // Upgrade
+ ArrayList veins = new ArrayList();
+ for (Vein vein : game.getField().getVeins(game.getMyPlayerId())) {
+ veins.add(vein);
+ }
+ Collections.sort(veins, new UpgradeVeinComparator());
+ HashMap amount = new HashMap();
+ for (Material material : Material.values()) {
+ amount.put(material, game.getMyPlayer().getMaterial(material));
+ }
+ loop1: for (Vein vein : veins) {
+ if (vein.getRobotRank() == 1) {
+ for (Material material : Material.values()) {
+ if (amount.get(material) < game
+ .getSetting()
+ .getMaterialsForUpgradingRobotRankFrom1To2(material))
+ continue loop1;
+ }
+ for (Material material : Material.values()) {
+ amount.put(
+ material,
+ amount.get(material)
+ - game.getSetting()
+ .getMaterialsForUpgradingRobotRankFrom1To2(
+ material));
+ }
+ commands.add(Commands.upgradeRobot(vein));
+ } else if (vein.getRobotRank() == 2) {
+ for (Material material : Material.values()) {
+ if (amount.get(material) < game
+ .getSetting()
+ .getMaterialsForUpgradingRobotRankFrom2To3(material))
+ continue loop1;
+ }
+ for (Material material : Material.values()) {
+ amount.put(
+ material,
+ amount.get(material)
+ - game.getSetting()
+ .getMaterialsForUpgradingRobotRankFrom2To3(
+ material));
+ }
+ commands.add(Commands.upgradeRobot(vein));
+ }
+ }
+ // Trade
+ if (amount.get(Material.Metal) + amount.get(Material.Gas) < 1500
+ && amount.get(Material.Stone) > 0) {
+ commands.add(Commands.sellToAlienTrade(Material.Stone,
+ amount.get(Material.Stone)));
+ }
+ if (game.getMyPlayer().getMoney() > 0) {
+ Material minMaterial = amount.get(Material.Metal) < 1000 ? Material.Metal
+ : Material.Gas;
+ int x = game.getMyPlayer().getMoney()
+ / game.getAlienTrade().getBuyPriceOf(minMaterial);
+ if (x > 0)
+ commands.add(Commands.buyFromAlienTrade(minMaterial, x));
+ }
+ // Launch
+ HashMap posNeighbors = new HashMap<>();
+ HashMap hasNeighbors = new HashMap<>();
+ int numRobots = 0;
+ for (Vein vein : game.getField().getVeins(game.getMyPlayerId())) {
+ numRobots += vein.getNumberOfRobots();
+ for (TrianglePoint pos : G.get(vein.getLocation())) {
+ Vein toVein = game.getField().getVein(pos);
+ if (toVein.getOwnerId() != game.getMyPlayerId()) {
+ posNeighbors.put(pos, toVein.getNumberOfRobots());
+ hasNeighbors.put(vein.getLocation(), true);
+ }
+ }
+ }
+ ArrayList frontline = new ArrayList();
+ for (Vein vein : game.getField().getVeins(game.getMyPlayerId())) {
+ if (!hasNeighbors.containsKey(vein.getLocation())) {
+ int x = vein.getNumberOfRobots() - numRobots
+ / game.getSetting().getVeinCount();
+ if (x > 0) {
+ int minDist = Integer.MAX_VALUE;
+ ArrayList targetVein = new ArrayList();
+ for (Vein v : game.getField()
+ .getVeins(game.getMyPlayerId())) {
+ if (hasNeighbors.containsKey(v.getLocation())) {
+ if (vein.getDistance(v) < minDist) {
+ minDist = vein.getDistance(v);
+ targetVein = new ArrayList();
+ }
+ if (vein.getDistance(v) <= minDist) {
+ targetVein.add(v.getLocation());
+ }
+ }
+ }
+ HashSet toVein = new HashSet();
+ for (TrianglePoint p : targetVein) {
+ Vein v = game.getField().getVein(p);
+ int d = Integer.MAX_VALUE;
+ ArrayList a = new ArrayList();
+ for (Vein t : game.getField().getVeins(
+ game.getMyPlayerId())) {
+ if (t != vein
+ && vein.getDistance(t) <= d
+ && vein.getDistance(t) + t.getDistance(v) <= vein
+ .getDistance(v)) {
+ if (vein.getDistance(t) < d) {
+ d = vein.getDistance(t);
+ a = new ArrayList();
+ }
+ a.add(t);
+ }
+ }
+ if (a.isEmpty()) {
+ toVein.add(v.getLocation());
+ } else {
+ for (Vein t : a)
+ toVein.add(t.getLocation());
+ }
+ }
+ if (x >= toVein.size())
+ for (TrianglePoint p : toVein) {
+ Vein v = game.getField().getVein(p);
+ commands.add(Commands.launch(x / toVein.size(),
+ vein.getLocation(), v.getLocation()));
+ }
+ }
+ } else {
+ frontline.add(vein);
+ }
+ }
+ ArrayList targets = new ArrayList();
+ for (Map.Entry e : posNeighbors.entrySet()) {
+ targets.add(game.getField().getVein(e.getKey()));
+ }
+ HashMap squads = new HashMap();
+ for (Squad squad : game.getField().getSquads(game.getMyPlayerId())) {
+ TrianglePoint p = squad.getDestinationLocation();
+ if (!squads.containsKey(p)) {
+ squads.put(p, 0);
+ }
+ squads.put(p, squads.get(p) + squad.getRobot());
+ }
+ for (Vein vein : frontline) {
+ int num = 0;
+ int minDist = Integer.MAX_VALUE;
+ Vein toVein = null;
+ boolean existsNeutral = false;
+ Collections.sort(targets, new TargetVeinComparator(game, vein,
+ squads));
+ for (Vein v : targets) {
+ if (existsNeutral
+ && v.getOwnerId() == game.getNeutralPlayerId()) {
+ int distance = vein.getDistance(v);
+ if (distance < minDist) {
+ minDist = distance;
+ num = 1;
+ toVein = v;
+ } else if (distance == minDist) {
+ if (rand.nextInt(++num) == 0) {
+ toVein = v;
+ }
+ }
+ } else if (v.getOwnerId() == game.getNeutralPlayerId()) {
+ existsNeutral = true;
+ minDist = vein.getDistance(v);
+ num = 1;
+ toVein = v;
+ } else if (v.getOwnerId() != game.getMyPlayerId()) {
+ int distance = vein.getDistance(v);
+ if (distance < minDist) {
+ minDist = distance;
+ num = 1;
+ toVein = v;
+ } else if (distance == minDist) {
+ if (rand.nextInt(++num) == 0) {
+ toVein = v;
+ }
+ }
+ }
+ }
+ if (num > 0) {
+ int x = toVein.getNumberOfRobots();
+ if (toVein.getOwnerId() != game.getNeutralPlayerId()) {
+ x += toVein.getCurrentRobotProductivity()
+ * vein.getDistance(toVein);
+ }
+ if (x < vein.getNumberOfRobots() - 1) {
+ TrianglePoint p = toVein.getLocation();
+ x = Math.max(x + 1, vein.getNumberOfRobots() / 2);
+ commands.add(Commands.launch(x, vein.getLocation(), p));
+ if (!squads.containsKey(p)) {
+ squads.put(p, 0);
+ }
+ squads.put(p, squads.get(p) + x);
+ }
+ }
+ }
+
+ return commands;
+ }
+
+ class SelectVeinComparator implements Comparator {
+ HashMap weightMatrial = new HashMap();
+ Game game;
+
+ SelectVeinComparator(Game game) {
+ this.game = game;
+ for (Material material : Material.values()) {
+ weightMatrial.put(material, 0);
+ }
+ if (game.getField().getVeins(game.getMyPlayerId()).isEmpty()) {
+ weightMatrial.put(Material.Gas, 2);
+ weightMatrial.put(Material.Metal, 1);
+ } else {
+ weightMatrial.put(Material.Metal, 2);
+ weightMatrial.put(Material.Gas, 1);
+ }
+ }
+
+ public int score(Vein v) {
+ int score = 0;
+ for (Vein to : game.getField().getVeins()) {
+ if (to.getOwnerId() != v.getOwnerId()) {
+ if (to.getOwnerId() == game.getNeutralPlayerId()) {
+ score += (20 - v.getDistance(to)) * 100;
+ } else {
+ score -= (20 - v.getDistance(to)) * 500;
+ }
+ } else if (to != v) {
+ score -= (20 - v.getDistance(to)) * 100;
+ }
+ }
+ score += weightMatrial.get(v.getMaterial()) * 1000;
+ score += v.getInitialRobotProductivity() * 100;
+ score += v.getNumberOfRobots();
+ return score;
+ }
+
+ @Override
+ public int compare(Vein a, Vein b) {
+ return -new Integer(score(a)).compareTo(score(b));
+ }
+
+ };
+
+ class UpgradeVeinComparator implements Comparator {
+
+ @Override
+ public int compare(Vein a, Vein b) {
+ if (a.getCurrentRobotProductivity() != b
+ .getCurrentRobotProductivity()) {
+ return -new Integer(a.getCurrentRobotProductivity())
+ .compareTo(b.getCurrentRobotProductivity());
+ }
+ return 0;
+ }
+
+ };
+
+ class TargetVeinComparator implements Comparator {
+ Game game;
+ Vein from;
+ HashMap squads;
+
+ TargetVeinComparator(Game game, Vein from,
+ HashMap squads) {
+ this.game = game;
+ this.from = from;
+ this.squads = squads;
+ }
+
+ public int score(Vein v) {
+ int score = 0;
+ if (v.getOwnerId() == game.getNeutralPlayerId()) {
+ if (squads.containsKey(v.getLocation())) {
+ if (squads.get(v.getLocation()) <= v.getNumberOfRobots()) {
+ score += 10000;
+ } else {
+ score += 5000;
+ }
+ } else {
+ score += 10000;
+ }
+ } else {
+ if (squads.containsKey(v.getLocation())) {
+ if (squads.get(v.getLocation()) + 100 <= v
+ .getNumberOfRobots()) {
+ score += 500;
+ }
+ } else {
+ score += 500;
+ }
+ }
+ score -= from.getDistance(v);
+ return score;
+ }
+
+ @Override
+ public int compare(Vein a, Vein b) {
+ return -new Integer(score(a)).compareTo(score(b));
+ }
+
+ };
+
+}
diff --git a/src/main/java/net/javachallenge/players/guests/MechaPlayer.java b/src/main/java/net/javachallenge/players/guests/MechaPlayer.java
new file mode 100644
index 0000000..9255fef
--- /dev/null
+++ b/src/main/java/net/javachallenge/players/guests/MechaPlayer.java
@@ -0,0 +1,138 @@
+package net.javachallenge.players.guests;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import net.javachallenge.api.ComputerPlayer;
+import net.javachallenge.api.Field;
+import net.javachallenge.api.Game;
+import net.javachallenge.api.Make;
+import net.javachallenge.api.Material;
+import net.javachallenge.api.Player;
+import net.javachallenge.api.TrianglePoint;
+import net.javachallenge.api.Vein;
+import net.javachallenge.api.command.Command;
+import net.javachallenge.api.command.Commands;
+
+public class MechaPlayer extends ComputerPlayer {
+ Game game = null;
+ List enemyVeins = null;
+ List emptyVeins = null;
+
+ private void update(Game game){
+ this.game = game;
+ this.enemyVeins = new ArrayList();
+ this.emptyVeins = new ArrayList();
+ List allVeins = game.getField().getVeins();
+ for (Vein vein : allVeins) {
+ if(vein.getOwnerId() == game.getNeutralPlayerId())
+ emptyVeins.add(vein);
+ else if(vein.getOwnerId() != game.getMyPlayer().getId())
+ enemyVeins.add(vein);
+ }
+ }
+
+ private Integer getInitialScore(Vein vein){
+ Integer score = 0;
+ for (Vein evein : enemyVeins){
+ score += (vein.getDistance(evein))*(vein.getDistance(evein)) * 100;
+ }
+ for (Vein evein : emptyVeins){
+ score -= (vein.getDistance(evein))*(vein.getDistance(evein)) * 5;
+ }
+ score += vein.getLocation().getDistance(Make.point(0, 0)) * 100000;
+ return score;
+ }
+
+ @Override
+ public String getName() {
+ return "mecha_g3";
+ }
+
+ @Override
+ public TrianglePoint selectVein(Game game) {
+ update(game);
+ this.saveTemporalVeinLocation(Make.point(0, 0));
+ Vein selectVein = emptyVeins.get(0);
+ Integer maxScore = Integer.MIN_VALUE;
+ for (Vein vein : emptyVeins) {
+ Integer score = getInitialScore(vein);
+ if(maxScore < score){
+ maxScore = score;
+ selectVein = vein;
+ }
+ }
+ return selectVein.getLocation();
+ }
+
+ @Override
+ public List selectActions(Game game) {
+ update(game);
+ List commands = new ArrayList();
+
+ Field field = game.getField();
+ List myVeinList = field.getVeins(game.getMyPlayer().getId());
+
+ List copiedVeinList = new ArrayList();
+ for (Vein vein : enemyVeins) {
+ copiedVeinList.add(vein);
+ }
+ for (Vein vein : emptyVeins) {
+ copiedVeinList.add(vein);
+ }
+
+ // Launch
+ for (Vein myVein : myVeinList) {
+ Collections.sort(copiedVeinList, new VeinDistanceComparator(myVein));
+ Vein to = copiedVeinList.get(0);
+ int diff = myVein.getNumberOfRobots() - to.getNumberOfRobots();
+ if ( (to.getOwnerId() == game.getNeutralPlayerId() && (diff>1)) ||
+ (to.getOwnerId() != game.getNeutralPlayerId() && (diff>30)) ){
+ commands.add(Commands.launch(myVein.getNumberOfRobots()/2,
+ myVein.getLocation(),
+ to.getLocation()));
+ }
+ }
+
+ // Upgrade
+ for(Vein myVein : myVeinList){
+ commands.add(Commands.upgradeRobot(myVein));
+ commands.add(Commands.upgradeMaterial(myVein));
+ }
+
+ // Trade
+ for (Material material : Material.values()) {
+ int amount = game.getMyPlayer().getMaterial(material);
+ if (amount > 1000) {
+ commands.add(Commands.sellToAlienTrade(material, amount - 500));
+ }
+ if (amount < 500) {
+ commands.add(Commands.buyFromAlienTrade(material, 500));
+ }
+ }
+ return commands;
+ }
+
+ class VeinDistanceComparator implements Comparator {
+ Vein myVein;
+
+ VeinDistanceComparator(Vein myVein) {
+ this.myVein = myVein;
+ }
+
+ @Override
+ public int compare(Vein o1, Vein o2) {
+
+ if (o1.equals(myVein)) return 1;
+ if (o2.equals(myVein)) return -1;
+
+ if (o1.getOwnerId() == myVein.getOwnerId()) return 1;
+ if (o2.getOwnerId() == myVein.getOwnerId()) return -1;
+ return myVein.getDistance(o1) - myVein.getDistance(o2);
+ }
+ }
+}
diff --git a/src/main/java/net/javachallenge/players/guests/Methane1Player.java b/src/main/java/net/javachallenge/players/guests/Methane1Player.java
new file mode 100644
index 0000000..01f575b
--- /dev/null
+++ b/src/main/java/net/javachallenge/players/guests/Methane1Player.java
@@ -0,0 +1,587 @@
+package net.javachallenge.players.guests;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+import net.javachallenge.api.ComputerPlayer;
+import net.javachallenge.api.Field;
+import net.javachallenge.api.Game;
+import net.javachallenge.api.Make;
+import net.javachallenge.api.Material;
+import net.javachallenge.api.Player;
+import net.javachallenge.api.Squad;
+import net.javachallenge.api.TrianglePoint;
+import net.javachallenge.api.Vein;
+import net.javachallenge.api.command.Command;
+import net.javachallenge.api.command.Commands;
+
+public class Methane1Player extends ComputerPlayer {
+ private Player self;
+ private List commands;
+ private Game game;
+ int turn;
+
+ int stone, gas, metal;
+
+ class OwnVein {
+ Vein vein;
+ int robots;
+ TrianglePoint location;
+ int robotRank;
+ int materialRank;
+ int commingSquads;
+ boolean emerge = false;
+
+ OwnVein(Vein v) {
+ vein = v;
+ robots = v.getNumberOfRobots();
+ location = v.getLocation();
+ robotRank = v.getRobotRank();
+ materialRank = v.getMaterialRank();
+ commingSquads = 0;
+ for (Squad s : game.getField().getSquads()) {
+ if (s.getDestinationLocation().equals(location)) {
+ commingSquads += s.getRobot();
+ if (s.getCurrentLocation().getDistance(location) == 1) {
+ if (s.getRobot() > robots
+ + v.getCurrentRobotProductivity()) {
+ emerge = true;
+ }
+ }
+ }
+ }
+ }
+
+ boolean tryUpgradeRobot() {
+ if (robotRank == 1 && metal >= 200 && gas >= 200) {
+ commands.add(Commands.upgradeRobot(vein));
+ metal -= 200;
+ gas -= 200;
+ robotRank++;
+ return true;
+ } else if (robotRank == 2 && metal >= 500 && stone >= 300) {
+ commands.add(Commands.upgradeRobot(vein));
+ metal -= 500;
+ stone -= 300;
+ robotRank++;
+ return true;
+ }
+ return false;
+ }
+
+ boolean tryUpgradeMaterial() {
+ if (materialRank == 1 && gas >= 200 && stone >= 100) {
+ commands.add(Commands.upgradeMaterial(vein));
+ gas -= 200;
+ stone -= 100;
+ return true;
+ } else if (materialRank == 2 && gas >= 100 && stone >= 300) {
+ commands.add(Commands.upgradeMaterial(vein));
+ gas -= 100;
+ stone -= 300;
+ return true;
+ }
+ return false;
+ }
+
+ void attack(Vein target, int squadSize, boolean force) {
+ if (squadSize > robots) {
+ System.err.println("Warn: too big squad size.");
+ squadSize = robots;
+ }
+ List route = makeRoute(location,
+ target.getLocation());
+ // List route =
+ // location.getShortestPath(target.getLocation());
+ if (route == null) {
+ if (force) {
+ commands.add(Commands.launch(squadSize, location,
+ target.getLocation()));
+ saveTemporalCommands(commands);
+ return;
+ } else
+ return;
+ }
+
+ robots -= squadSize;
+ commands.add(Commands.launch(squadSize, location,
+ target.getLocation()));
+ // commands.add(Commands.launchWithPath(squadSize, route));
+ saveTemporalCommands(commands);
+ System.err.println("Move from " + location + " to "
+ + target.getLocation() + " with " + squadSize + " robots.");
+ // System.err.println("Route:" + route);
+ }
+
+ public boolean equals(Object other) {
+ OwnVein ov = (OwnVein) other;
+ return ov.location == this.location;
+ }
+
+ public int hashCode() {
+ return location.hashCode();
+ }
+
+ ArrayList nearFriends() {
+ ArrayList veins = new ArrayList<>();
+ for (Vein v : game.getField().getVeinsOfSameOwnerOrderedByDistance(
+ vein)) {
+ veins.add(myVeinsByLocation.get(v.getLocation()));
+ }
+ return veins;
+ }
+
+ List nearEnemies() {
+ return game.getField().getVeinsOfOtherOwnersOrderedByDistance(vein);
+ }
+ }
+
+ TreeMap myVeinsByLocation = new TreeMap<>();
+ ArrayList myVeins = new ArrayList<>();
+
+ @Override
+ public String getName() {
+ return "methane1";
+ }
+
+ Vein firstVein = null;
+
+ @Override
+ public TrianglePoint selectVein(Game game) {
+ int gas_ratio = 2;
+ int metal_ratio = 3;
+ TrianglePoint center = Make.point(1, 0);
+
+ if (firstVein != null) {
+ switch (firstVein.getMaterial()) {
+ case Metal:
+ metal_ratio = 1;
+ break;
+ case Gas:
+ gas_ratio = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ int bestScore = Integer.MIN_VALUE;
+ Vein bestVein = null;
+
+ for (Vein v : game.getField().getVeins()) {
+ if (v.getOwnerId() != -1) {
+ continue;
+ }
+ int score = 0;
+
+ score += center.getDistance(v.getLocation());
+ score += v.getNumberOfRobots() * 8;
+ score += v.getInitialRobotProductivity() * 40;
+ switch (v.getMaterial()) {
+ case Gas:
+ score += gas_ratio * v.getInitialMaterialProductivity();
+ break;
+ case Metal:
+ score += metal_ratio * v.getInitialMaterialProductivity();
+ break;
+ default:
+ break;
+ }
+ for (Vein ov : game.getField().getVeins()) {
+ if (ov.getOwnerId() == -1)
+ continue;
+ int d = ov.getDistance(v);
+ if (d < 16) {
+ score -= 16 - d;
+ if (d < 10) {
+ score -= 10 - d;
+ }
+ if (d < 6) {
+ score -= 6 - d;
+ }
+ }
+ score -= ov.getDistance(v);
+
+ }
+ if (score > bestScore) {
+ bestVein = v;
+ bestScore = score;
+ }
+ }
+ return bestVein.getLocation();
+ }
+
+ @Override
+ public List selectActions(Game game) {
+ this.game = game;
+ turn = game.getRound();
+ self = game.getMyPlayer();
+ gas = self.getMaterial(Material.Gas);
+ stone = self.getMaterial(Material.Stone);
+ metal = self.getMaterial(Material.Metal);
+
+ myVeins.clear();
+ myVeinsByLocation.clear();
+ for (Vein v : game.getField().getVeins(self.getId())) {
+ OwnVein ov = new OwnVein(v);
+ myVeins.add(ov);
+ myVeinsByLocation.put(v.getLocation(), ov);
+ }
+ commands = new ArrayList<>();
+
+ upgradeVeins();
+ saveTemporalCommands(commands);
+
+ doAttack();
+ return commands;
+ }
+
+ private static class LargerRobotProducer implements Comparator {
+ @Override
+ public int compare(OwnVein o1, OwnVein o2) {
+ return o2.vein.getInitialRobotProductivity()
+ - o1.vein.getInitialRobotProductivity();
+ }
+ }
+
+ private static class MoreMaterialProducer implements Comparator {
+ @Override
+ public int compare(OwnVein o1, OwnVein o2) {
+ int v1 = o1.vein.getInitialMaterialProductivity();
+ int v2 = o2.vein.getInitialMaterialProductivity();
+ // TODO: 資源の種類に対して重み付け
+ // TODO: vein の安全さに対して重み付け
+ return v2 - v1;
+ }
+ }
+
+ void doTrade() {
+ if (stone > 1200) {
+ commands.add(Commands
+ .sellToAlienTrade(Material.Stone, stone - 1200));
+ }
+ if (gas > 1200) {
+ commands.add(Commands.sellToAlienTrade(Material.Gas, gas - 1200));
+ }
+ if (metal > 1600) {
+ commands.add(Commands
+ .sellToAlienTrade(Material.Metal, metal - 1600));
+ }
+ if (metal < 400) {
+ commands.add(Commands.buyFromAlienTrade(Material.Metal, 400));
+ }
+ if (gas < 300) {
+ commands.add(Commands.buyFromAlienTrade(Material.Gas, 300));
+ }
+ if (metal < 400) {
+ commands.add(Commands.buyFromAlienTrade(Material.Metal, 400));
+ }
+ if (gas < 300) {
+ commands.add(Commands.buyFromAlienTrade(Material.Gas, 300));
+ }
+ if (stone < 300) {
+ commands.add(Commands.buyFromAlienTrade(Material.Stone, 300));
+ }
+ }
+
+ /** 所有している vein の rank up を行う. */
+ private void upgradeVeins() {
+ Collections.sort(myVeins, new LargerRobotProducer());
+ for (OwnVein vein : myVeins) {
+ vein.tryUpgradeRobot();
+ }
+ Collections.sort(myVeins, new MoreMaterialProducer());
+ for (OwnVein vein : myVeins) {
+ vein.tryUpgradeMaterial();
+ }
+ doTrade();
+ }
+
+ private static class MoreRobots implements Comparator {
+ @Override
+ public int compare(OwnVein v1, OwnVein v2) {
+ return v2.robots - v1.robots;
+ }
+ }
+
+ private static int getRemainTurn(Squad s) {
+ TrianglePoint loc = s.getCurrentLocation();
+ TrianglePoint dest = s.getDestinationLocation();
+ List path = s.getPath();
+
+ for (int i = 0; i < path.size(); ++i) {
+ if (path.get(i).equals(dest)) {
+ return path.size() - i;
+ }
+ }
+ System.err.println("Warn: can't calculate remain turn");
+ return loc.getDistance(s.getDestinationLocation());
+ }
+
+ private static class NearDestination implements Comparator {
+ @Override
+ public int compare(Squad s1, Squad s2) {
+ return getRemainTurn(s1) - getRemainTurn(s2);
+ }
+ }
+
+ private boolean _makeRouteSub(TrianglePoint from, TrianglePoint to,
+ List route, int t) {
+ int x = from.getX();
+ int y = from.getY();
+
+ if (from.equals(to))
+ return true;
+
+ if (t > 0) {
+ for (Squad s : game.getField().getSquads()) {
+ int now;
+ TrianglePoint cur = s.getCurrentLocation();
+ List sp = s.getPath();
+ for (now = 0; now < sp.size(); ++now) {
+ if (sp.get(now).equals(cur)) {
+ break;
+ }
+ }
+ // System.err.println("now="+now+" path="+sp.size() + " t="+t);
+ if (now + t - 1 < sp.size()) {
+ if (sp.get(now + t - 1).equals(from)) {
+ System.err.println("Boom: " + from);
+ return false;
+ }
+ }
+ if (now + t < sp.size()) {
+ if (sp.get(now + t).equals(from)) {
+ System.err.println("Boom: " + from);
+ return false;
+ }
+ }
+ }
+ }
+
+ int dist = from.getDistance(to);
+
+ TrianglePoint next = Make.point(x - 1, y);
+ if (next.getDistance(to) < dist) {
+ route.add(next);
+ if (_makeRouteSub(next, to, route, t + 1)) {
+ return true;
+ }
+ route.remove(t + 1);
+ }
+
+ next = Make.point(x + 1, y);
+ if (next.getDistance(to) < dist) {
+ route.add(next);
+ if (_makeRouteSub(next, to, route, t + 1)) {
+ return true;
+ }
+ route.remove(t + 1);
+ }
+
+ if ((x + y) % 2 == 0) {
+ // if (from.isUpwardTriangle()) {
+ next = Make.point(x, y + 1);
+ } else {
+ next = Make.point(x, y - 1);
+ }
+ if (next.getDistance(to) < dist) {
+ route.add(next);
+ if (_makeRouteSub(next, to, route, t + 1)) {
+ return true;
+ }
+ route.remove(t + 1);
+ }
+ return false;
+ }
+
+ /** 攻撃するときのルート計算 */
+ List makeRoute(TrianglePoint from, TrianglePoint to) {
+ List route = new ArrayList<>();
+ route.add(from);
+ if (_makeRouteSub(from, to, route, 0)) {
+ return route;
+ }
+ return null;
+ }
+
+ /** 攻撃を行う */
+ private void doAttack() {
+ Collections.sort(myVeins, new MoreRobots());
+ Field field = game.getField();
+ List squads = field.getSquads();
+
+ TreeSet targetted = new TreeSet<>();
+
+ int defence = 0;
+ int veins = 0;
+ for (Vein v : field.getVeinsOfOtherOwnersOrderedByDistance(myVeins
+ .get(0).vein)) {
+ if (v.getOwnerId() == game.getNeutralPlayerId())
+ continue;
+ veins++;
+ defence += v.getNumberOfRobots();
+ }
+ if (game.getRound() > 100) {
+ defence *= 200 - game.getRound();
+ } else {
+ defence *= game.getRound();
+ }
+ defence /= 100 * veins;
+ defence += 5;
+
+ // defence = (int)(defence * (1.0 + ((double) game.getRound() / 200.0 -
+ // 0.5)) / veins);
+
+ System.err.println("Round: " + game.getRound() + " / Defence: "
+ + defence);
+
+ for (OwnVein vein : myVeins) {
+ int mindist = Integer.MAX_VALUE;
+ int def2 = defence;
+ List nearEnemies = vein.nearEnemies();
+ for (Vein ev : nearEnemies) {
+ if (ev.getOwnerId() == game.getNeutralPlayerId())
+ continue;
+ int d = ev.getDistance(vein.vein);
+ if (d > 8)
+ break;
+ int x = ev.getNumberOfRobots() - d
+ * vein.vein.getCurrentRobotProductivity();
+ if (x > 0)
+ def2 += x;
+ def2 += vein.commingSquads;
+ }
+
+ targetloop: for (Vein enemyVein : nearEnemies) {
+ TrianglePoint loc = enemyVein.getLocation();
+ int enemyRobots = enemyVein.getNumberOfRobots();
+ if (targetted.contains(loc)) {
+ continue;
+ }
+
+ int dist = loc.getDistance(vein.location);
+ if (dist < mindist)
+ mindist = dist;
+ if (dist > 16) {
+ break;
+ }
+
+ ArrayList targetSquads = new ArrayList<>();
+ for (Squad s : squads) {
+ if (s.getDestinationLocation().equals(loc)) {
+ if (s.getCurrentLocation().getDistance(loc) >= dist) {
+ continue targetloop;
+ }
+ if (s.getOwnerId() == self.getId()) {
+ enemyRobots -= s.getRobot();
+ if (enemyRobots < 0)
+ enemyRobots = 0;
+ }
+ targetSquads.add(s);
+ }
+ }
+
+ Collections.sort(targetSquads, new NearDestination());
+ int enemyId = enemyVein.getOwnerId();
+ int t = 0;
+ for (Squad s : targetSquads) {
+ int r = getRemainTurn(s);
+ if (r >= dist) {
+ continue targetloop;
+ }
+ if (enemyId != game.getNeutralPlayerId()) {
+ enemyRobots += (r - t)
+ * enemyVein.getCurrentRobotProductivity();
+ }
+ t = r;
+ if (enemyRobots < s.getRobot()) {
+ enemyId = s.getOwnerId();
+ enemyRobots = s.getRobot() - enemyRobots;
+ } else {
+ enemyRobots -= s.getRobot();
+ }
+ }
+ if (enemyId != game.getNeutralPlayerId()) {
+ enemyRobots += (dist - t)
+ * enemyVein.getCurrentRobotProductivity();
+ }
+ enemyRobots += (dist / 2);
+
+ // ターゲットの周辺の敵基地の強さを勘案する. 取ってすぐ取り返されるなら最初から取らない.
+ if (turn > 4 || dist > 6
+ || enemyVein.getOwnerId() == game.getNeutralPlayerId()) {
+ for (Vein v : game.getField()
+ .getVeinsOfOtherOwnersOrderedByDistance(enemyVein)) {
+ int r = v.getDistance(enemyVein);
+ if (r > 6)
+ break;
+ if (v.getOwnerId() != self.getId()
+ && v.getOwnerId() != game.getNeutralPlayerId()) {
+ int x = v.getNumberOfRobots()
+ - enemyVein.getCurrentRobotProductivity()
+ * r;
+ if (x > 0)
+ enemyRobots += x / 2;
+ }
+ }
+ for (Vein v : game.getField()
+ .getVeinsOfSameOwnerOrderedByDistance(enemyVein)) {
+ int r = v.getDistance(enemyVein);
+ if (r > 6)
+ break;
+ int x = v.getNumberOfRobots()
+ - enemyVein.getCurrentRobotProductivity() * r;
+ if (x > 0)
+ enemyRobots += x / 2;
+ }
+ }
+
+ if (vein.emerge && enemyRobots < vein.robots) {
+ targetted.add(loc);
+ vein.attack(enemyVein, vein.robots, false);
+ break;
+ }
+ if (enemyRobots + def2 < vein.robots) {
+ targetted.add(loc);
+ int squadSize = vein.robots - def2;
+ vein.attack(enemyVein, squadSize, false);
+ break;
+ }
+ }
+
+ int distBonus = mindist * vein.vein.getCurrentRobotProductivity()
+ / 2;
+ if (distBonus >= defence)
+ distBonus = defence - 1;
+ if (mindist > 10
+ && (vein.robots - vein.commingSquads) > (defence - distBonus)) {
+ // move to mine.
+ for (OwnVein nearVein : vein.nearFriends()) {
+ if (nearVein.nearEnemies().get(0)
+ .getDistance(nearVein.vein) < mindist) {
+ int squadSize = vein.robots - vein.commingSquads
+ - defence + distBonus;
+ System.err.println("Move to friend: from="
+ + vein.location + " to=" + nearVein.location
+ + " robots=" + vein.robots + " mindist="
+ + mindist + " defence=" + defence
+ + " distBonus=" + distBonus + "squad="
+ + squadSize);
+ vein.attack(nearVein.vein, vein.robots - defence
+ + distBonus, true);
+ break;
+ }
+ }
+ }
+
+ // if (vein.emerge && vein.robots > 0) {
+ // System.err.println("WARNING! WARNING! WARNING!");
+ // vein.attack(vein.nearFriends().get(0).vein, vein.robots, false);
+ // }
+ }
+ }
+}
diff --git a/src/main/java/net/javachallenge/players/guests/Oyososan.java b/src/main/java/net/javachallenge/players/guests/Oyososan.java
new file mode 100644
index 0000000..0aeec94
--- /dev/null
+++ b/src/main/java/net/javachallenge/players/guests/Oyososan.java
@@ -0,0 +1,392 @@
+package net.javachallenge.players.guests;
+
+import static java.lang.Math.abs;
+import static java.lang.Math.exp;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import net.javachallenge.api.ComputerPlayer;
+import net.javachallenge.api.Field;
+import net.javachallenge.api.Game;
+import net.javachallenge.api.Material;
+import net.javachallenge.api.Player;
+import net.javachallenge.api.Squad;
+import net.javachallenge.api.TrianglePoint;
+import net.javachallenge.api.Vein;
+import net.javachallenge.api.command.Command;
+import net.javachallenge.api.command.Commands;
+
+public class Oyososan extends ComputerPlayer {
+
+ public static class Constant {
+ public static final int[] WEIGHTS = { 50, 10, 646, 20, 480, 200, 5, 4,
+ 5, 4, 8, 200, 5, 3, 4, 3, 50, 4, 1000, 1600, 12, 7, 1000, 5,
+ 14, 10, };
+ }
+
+ private static final int LAUNCH_ROBOT_BEHIND_NUMBER_RATIO = Constant.WEIGHTS[0];
+ private static final int LAUNCH_ROBOT_BEHIND_DISTANCE_THRESHOLD = Constant.WEIGHTS[1];
+ private static final int LAUNCH_ROBOT_BEHIND_NUMBER_THRESHOLD = Constant.WEIGHTS[2];
+ private static final int LAUNCH_ROBOT_BEHIND_BEGIN_ROUND = Constant.WEIGHTS[3];
+ private static final int LAUNCH_ROBOT_ENEMY_ROUND_WEIGHT = Constant.WEIGHTS[4];
+ private static final int LAUNCH_ROBOT_ENEMY_NUMBER_WEIGHT = Constant.WEIGHTS[5];
+ private static final int LAUNCH_ROBOT_ENEMY_Y_ROUND_WEIGHT = Constant.WEIGHTS[6];
+ private static final int LAUNCH_ROBOT_ENEMY_Y_OFFSET = Constant.WEIGHTS[7];
+ private static final int LAUNCH_ROBOT_ENEMY_X_ROUND_WEIGHT = Constant.WEIGHTS[8];
+ private static final int LAUNCH_ROBOT_ENEMY_X_OFFSET = Constant.WEIGHTS[9];
+ private static final int LAUNCH_ROBOT_ENEMY_BEGIN_ROUND = Constant.WEIGHTS[10];
+ private static final int LAUNCH_ROBOT_OTHER_ROUND_WEIGHT = Constant.WEIGHTS[11];
+ private static final int LAUNCH_ROBOT_OTHER_Y_ROUND_WEIGHT = Constant.WEIGHTS[12];
+ private static final int LAUNCH_ROBOT_OTHER_X_ROUND_WEIGHT = Constant.WEIGHTS[13];
+ private static final int LAUNCH_ROBOT_OTHER_Y_OFFSET = Constant.WEIGHTS[14];
+ private static final int LAUNCH_ROBOT_OTHER_X_OFFSET = Constant.WEIGHTS[15];
+ private static final int SELL_MATERIALS_AMOUNT_RATIO = Constant.WEIGHTS[16];
+ private static final int SELL_MATERIALS_MIN_MAX_RATIO = Constant.WEIGHTS[17];
+ private static final int SELL_MATERIALS_AMOUNT_THRESHOLD = Constant.WEIGHTS[18];
+ private static final int SELECT_VEIN_CENTER_SCORE = Constant.WEIGHTS[19];
+ private static final int SELECT_VEIN_MY_VEIN_FAVORITE_DISTANCE = Constant.WEIGHTS[20];
+ private static final int SELECT_VEIN_MY_VEIN_SCORE = Constant.WEIGHTS[21];
+ private static final int SELECT_VEIN_ENEMY_VEIN_SCORE = Constant.WEIGHTS[22];
+ private static final int SELECT_VEIN_OTHER_VEIN_SCORE = Constant.WEIGHTS[23];
+ private static final int CHOOSE_BY_ROBOT_PRODUCTIVITY = Constant.WEIGHTS[24];
+ private static final int CHOOSE_BY_MATERIAL_PRODUCTIVITY = Constant.WEIGHTS[25];
+
+ public static class PointComparator implements Comparator {
+ public final int compare(TrianglePoint left, TrianglePoint right) {
+ if (left.getX() == right.getX())
+ return left.getX() - right.getX();
+ return left.getY() - right.getY();
+ }
+ }
+
+ @Override
+ public String getName() {
+ return "Oyososan";
+ }
+
+ @Override
+ public TrianglePoint selectVein(Game game) {
+ Vein bestVein = null;
+ double bestScore = Double.NEGATIVE_INFINITY;
+
+ for (Vein vein : game.getField().getVeins()) {
+ if (vein.getOwnerId() != -1) {
+ continue;
+ }
+
+ double score = 0.0;
+ for (Vein otherVein : game.getField().getVeins()) {
+ if (vein.equals(otherVein)) {
+ continue;
+ }
+
+ if (otherVein.getOwnerId() == -1) {
+ // Other vein.
+ score += SELECT_VEIN_OTHER_VEIN_SCORE
+ * exp(-vein.getDistance(otherVein));
+ } else if (otherVein.getOwnerId() != game.getMyPlayer().getId()) {
+ // Enemy vein.
+ score -= SELECT_VEIN_ENEMY_VEIN_SCORE
+ * exp(-vein.getDistance(otherVein));
+ } else {
+ // My vein.
+ score += SELECT_VEIN_MY_VEIN_SCORE
+ * exp(-abs(SELECT_VEIN_MY_VEIN_FAVORITE_DISTANCE
+ - vein.getDistance(otherVein)));
+ }
+ }
+
+ // Distance from the center.
+ score -= SELECT_VEIN_CENTER_SCORE
+ * exp(-abs(vein.getLocation().getX())
+ - abs(vein.getLocation().getY()));
+
+ // Productivity
+ score += vein.getInitialRobotProductivity()
+ * CHOOSE_BY_ROBOT_PRODUCTIVITY / 100;
+ score += vein.getInitialMaterialProductivity()
+ * CHOOSE_BY_MATERIAL_PRODUCTIVITY / 100;
+
+ if (bestScore < score) {
+ bestScore = score;
+ bestVein = vein;
+ }
+ }
+
+ return bestVein.getLocation();
+ }
+
+ @Override
+ public List selectActions(final Game game) {
+ Player myPlayer = game.getMyPlayer();
+
+ List commands = new ArrayList();
+ this.saveTemporalCommands(commands);
+
+ List myVeins = new ArrayList();
+ List enemyVeins = new ArrayList();
+ List otherVeins = new ArrayList();
+
+ for (Vein vein : game.getField().getVeins()) {
+ if (vein.getOwnerId() == myPlayer.getId()) {
+ myVeins.add(vein);
+ } else if (vein.getOwnerId() != -1) {
+ enemyVeins.add(vein);
+ } else {
+ otherVeins.add(vein);
+ }
+ }
+ Collections.sort(myVeins, new Comparator() {
+ @Override
+ public int compare(Vein o1, Vein o2) {
+ Field field = game.getField();
+ return -(o1.getDistance(field
+ .getVeinsOfOtherOwnersOrderedByDistance(o1).get(0)) - o2
+ .getDistance(field
+ .getVeinsOfOtherOwnersOrderedByDistance(o2)
+ .get(0)));
+ }
+ });
+
+ Map materials = new HashMap();
+ int myMoney = myPlayer.getMoney();
+
+ Material minMaterial = Material.Gas;
+ Material maxMaterial = Material.Gas;
+ for (Material material : Material.values()) {
+ int amount = myPlayer.getMaterial(material);
+ materials.put(material, new AtomicInteger(amount));
+
+ if (myPlayer.getMaterial(minMaterial) > myPlayer
+ .getMaterial(material)) {
+ minMaterial = material;
+ }
+ if (myPlayer.getMaterial(maxMaterial) < myPlayer
+ .getMaterial(material)) {
+ maxMaterial = material;
+ }
+ }
+
+ // Sell materials.
+ if (materials.get(maxMaterial).get() > SELL_MATERIALS_AMOUNT_THRESHOLD
+ && materials.get(minMaterial).get()
+ * SELL_MATERIALS_MIN_MAX_RATIO < materials.get(
+ maxMaterial).get()) {
+ int price = game.getAlienTrade().getSellPriceOf(maxMaterial);
+ int sellAmount = materials.get(maxMaterial).get()
+ * SELL_MATERIALS_AMOUNT_RATIO / 100;
+ commands.add(Commands.sellToAlienTrade(maxMaterial, sellAmount));
+ materials.get(maxMaterial).addAndGet(-sellAmount);
+ myMoney += price * sellAmount;
+ }
+
+ // Buy materials.
+ int price = game.getAlienTrade().getBuyPriceOf(minMaterial);
+ int buyAmount = myMoney / price;
+ if (buyAmount > 0) {
+ commands.add(Commands.buyFromAlienTrade(minMaterial, buyAmount));
+ materials.get(minMaterial).addAndGet(buyAmount);
+ }
+
+ this.saveTemporalCommands(commands);
+
+ // Upgrade robots.
+ {
+ final int[] gasCost = { 0, 200, 0, Integer.MAX_VALUE };
+ final int[] stoneCost = { 0, 0, 300, Integer.MAX_VALUE };
+ final int[] metalCost = { 0, 200, 500, Integer.MAX_VALUE };
+
+ Vein toUpdate = null;
+ int distMin = Integer.MAX_VALUE;
+ for (Vein vein : myVeins) {
+ int rank = vein.getRobotRank();
+ if (materials.get(Material.Gas).get() < gasCost[rank]
+ || materials.get(Material.Metal).get() < metalCost[rank]
+ || materials.get(Material.Stone).get() < stoneCost[rank]) {
+ continue;
+ }
+ List enemies = game.getField()
+ .getVeinsOfOtherOwnersOrderedByDistance(vein);
+ int dist = enemies.get(0).getDistance(vein);
+
+ if (dist < distMin && dist > 3) {
+ toUpdate = vein;
+ distMin = dist;
+ }
+ }
+ if (toUpdate != null) {
+ int rank = toUpdate.getRobotRank();
+ commands.add(Commands.upgradeRobot(toUpdate));
+ materials.get(Material.Gas).addAndGet(-gasCost[rank]);
+ materials.get(Material.Metal).addAndGet(-metalCost[rank]);
+ materials.get(Material.Stone).addAndGet(-stoneCost[rank]);
+ }
+ }
+ this.saveTemporalCommands(commands);
+
+ // Upgrade materials.
+ {
+ final int[] gasCost = { 0, 200, 100, Integer.MAX_VALUE };
+ final int[] stoneCost = { 0, 100, 300, Integer.MAX_VALUE };
+ Vein toUpdate = null;
+ int distMin = Integer.MAX_VALUE;
+ for (Vein vein : myVeins) {
+ int rank = vein.getMaterialRank();
+ if (materials.get(Material.Gas).get() < gasCost[rank]
+ || materials.get(Material.Stone).get() < stoneCost[rank]) {
+ continue;
+ }
+ List enemies = game.getField()
+ .getVeinsOfOtherOwnersOrderedByDistance(vein);
+ int dist = enemies.get(0).getDistance(vein);
+ if (dist < distMin && dist > 3) {
+ toUpdate = vein;
+ distMin = dist;
+ }
+ }
+ if (toUpdate != null) {
+ int rank = toUpdate.getMaterialRank();
+ commands.add(Commands.upgradeMaterial(toUpdate));
+ materials.get(Material.Gas).addAndGet(-gasCost[rank]);
+ materials.get(Material.Stone).addAndGet(-stoneCost[rank]);
+ }
+ }
+ this.saveTemporalCommands(commands);
+
+ Map numberOfRobots = new HashMap();
+ for (Vein myVein : myVeins) {
+ numberOfRobots.put(myVein,
+ new AtomicInteger(myVein.getNumberOfRobots()));
+ }
+
+ // Launch robots to other veins.
+ Collections.shuffle(myVeins);
+ for (final Vein myVein : myVeins) {
+ Collections.sort(otherVeins, new Comparator() {
+ @Override
+ public int compare(Vein o1, Vein o2) {
+ return myVein.getDistance(o1) - myVein.getDistance(o2);
+ }
+ });
+
+ for (Vein otherVein : otherVeins) {
+ if (abs(myVein.getLocation().getX()
+ - otherVein.getLocation().getX()) < LAUNCH_ROBOT_OTHER_X_OFFSET
+ + game.getRound()
+ * LAUNCH_ROBOT_OTHER_X_ROUND_WEIGHT
+ / 100
+ && abs(myVein.getLocation().getY()
+ - otherVein.getLocation().getY()) < LAUNCH_ROBOT_OTHER_Y_OFFSET
+ + game.getRound()
+ * LAUNCH_ROBOT_OTHER_Y_ROUND_WEIGHT / 100) {
+ if (numberOfRobots.get(myVein).get() > otherVein
+ .getNumberOfRobots()
+ + game.getRound()
+ * LAUNCH_ROBOT_OTHER_ROUND_WEIGHT / 100) {
+ int robots = otherVein.getNumberOfRobots() + 1;
+ commands.add(Commands.launch(robots,
+ myVein.getLocation(), otherVein.getLocation()));
+ numberOfRobots.get(myVein).addAndGet(-robots);
+ }
+ }
+ }
+ }
+ this.saveTemporalCommands(commands);
+
+ // Launch robots to enemy veins.
+ Collections.shuffle(myVeins);
+ if (game.getRound() > LAUNCH_ROBOT_ENEMY_BEGIN_ROUND) {
+ for (Vein myVein : myVeins) {
+ for (Vein enemyVein : game.getField()
+ .getVeinsOfOtherOwnersOrderedByDistance(myVein)) {
+ if (abs(myVein.getLocation().getX()
+ - enemyVein.getLocation().getX()) < LAUNCH_ROBOT_ENEMY_X_OFFSET
+ + game.getRound()
+ * LAUNCH_ROBOT_ENEMY_X_ROUND_WEIGHT / 100
+ && abs(myVein.getLocation().getY()
+ - enemyVein.getLocation().getY()) < LAUNCH_ROBOT_ENEMY_Y_OFFSET
+ + game.getRound()
+ * LAUNCH_ROBOT_ENEMY_Y_ROUND_WEIGHT / 100) {
+ if (numberOfRobots.get(myVein).get() > enemyVein
+ .getNumberOfRobots()
+ * LAUNCH_ROBOT_ENEMY_NUMBER_WEIGHT
+ / 100
+ - game.getRound()
+ * LAUNCH_ROBOT_ENEMY_ROUND_WEIGHT / 100
+ && numberOfRobots.get(myVein).get() > enemyVein
+ .getNumberOfRobots()
+ + enemyVein
+ .getCurrentRobotProductivity()
+ * myVein.getDistance(enemyVein) + 1) {
+ int robots = enemyVein.getNumberOfRobots()
+ + enemyVein.getCurrentRobotProductivity()
+ * myVein.getDistance(enemyVein) + 1;
+ commands.add(Commands.launch(robots,
+ myVein.getLocation(),
+ enemyVein.getLocation()));
+ numberOfRobots.get(myVein).addAndGet(-robots);
+ }
+ }
+ }
+ }
+ }
+ this.saveTemporalCommands(commands);
+
+ // Launch robots from behind to front enemy veins.
+ Collections.shuffle(myVeins);
+ if (game.getRound() > LAUNCH_ROBOT_BEHIND_BEGIN_ROUND) {
+ for (Vein myVein : myVeins) {
+ if (numberOfRobots.get(myVein).get() < LAUNCH_ROBOT_BEHIND_NUMBER_THRESHOLD) {
+ continue;
+ }
+
+ for (Vein enemyVein : game.getField()
+ .getVeinsOfOtherOwnersOrderedByDistance(myVein)) {
+ if (myVein.getDistance(enemyVein) < LAUNCH_ROBOT_BEHIND_DISTANCE_THRESHOLD) {
+ continue;
+ }
+
+ int robots = numberOfRobots.get(myVein).get()
+ * LAUNCH_ROBOT_BEHIND_NUMBER_RATIO / 100;
+ commands.add(Commands.launch(robots, myVein.getLocation(),
+ enemyVein.getLocation()));
+ numberOfRobots.get(myVein).addAndGet(-robots);
+ break;
+ }
+ }
+ }
+ this.saveTemporalCommands(commands);
+
+ // TODO(tzik): Launch robot to veins under attacked to protect them.
+ // calcInvasionList(myPlayer.getId(), game.getField().getSquads());
+
+ return commands;
+ }
+
+ private static final class Invasion {
+ public TrianglePoint destination;
+ public int delay;
+ public int number;
+ }
+
+ List calcInvasionList(int myId, List squads) {
+ List invasions = new ArrayList();
+ for (Squad squad : squads) {
+ Invasion invasion = new Invasion();
+ invasion.destination = squad.getDestinationLocation();
+ invasion.delay = squad.getPath().size() - 1;
+ invasion.number = squad.getRobot();
+
+ if (squad.getOwnerId() == myId)
+ invasion.number *= -1;
+ invasions.add(invasion);
+ }
+ return invasions;
+ }
+}
diff --git a/src/main/java/net/javachallenge/players/others/JoeJack.java b/src/main/java/net/javachallenge/players/others/JoeJack.java
new file mode 100644
index 0000000..b31149a
--- /dev/null
+++ b/src/main/java/net/javachallenge/players/others/JoeJack.java
@@ -0,0 +1,335 @@
+package net.javachallenge.players.others;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import net.javachallenge.api.ComputerPlayer;
+import net.javachallenge.api.Game;
+import net.javachallenge.api.GameSetting;
+import net.javachallenge.api.Material;
+import net.javachallenge.api.PlayerTrade;
+import net.javachallenge.api.Squad;
+import net.javachallenge.api.TradeType;
+import net.javachallenge.api.TrianglePoint;
+import net.javachallenge.api.Vein;
+import net.javachallenge.api.command.Command;
+import net.javachallenge.api.command.Commands;
+
+public class JoeJack extends ComputerPlayer {
+ private Map allVeins;
+ private Map sentRobots;
+ private Map launchedRobots;
+ private Map usedMaterials;
+ private int usedMoney;
+ private Game game;
+ private final int MaxRank = 3;
+
+ private void initialize(Game game) {
+ this.game = game;
+ allVeins = game.getField().getVeinMap();
+ sentRobots = new HashMap();
+ launchedRobots = new HashMap();
+ usedMaterials = new HashMap();
+ usedMoney = 0;
+ for (Squad squad : game.getField().getSquads()) {
+ TrianglePoint destination = squad.getDestinationLocation();
+ increment(sentRobots, destination, squad.getRobot()
+ * (squad.getOwnerId() == game.getMyPlayer().getId() ? 1 : -1));
+ }
+ }
+
+ @Override
+ public String getName() {
+ return "JoeJack";
+ }
+
+ private Vein firstSelectedVein;
+
+ @Override
+ public TrianglePoint selectVein(Game game) {
+ initialize(game);
+ List all = new ArrayList();
+ all.addAll(allVeins.keySet());
+ Collections.sort(all, veinValueComparator);
+ TrianglePoint best = null;
+ for (TrianglePoint point : all) {
+ if (allVeins.get(point).getOwnerId() == game.getNeutralPlayerId()
+ && (firstSelectedVein == null || allVeins.get(point).getShortestPath(firstSelectedVein)
+ .size() < game.getSetting().getMapSize())) {
+ best = point;
+ break;
+ }
+ }
+ if (firstSelectedVein == null && best != null) {
+ firstSelectedVein = allVeins.get(best);
+ }
+ return best;
+ }
+
+ private void launch(List commands, int robotsToLaunch, TrianglePoint from,
+ TrianglePoint to) {
+ addCommand(commands, Commands.launch(robotsToLaunch, from, to));
+ increment(sentRobots, to, robotsToLaunch);
+ increment(launchedRobots, from, robotsToLaunch);
+ }
+
+ @Override
+ public List selectActions(Game game) {
+ // initialize
+ initialize(game);
+ List commands = new ArrayList();
+ ArrayList myVeinPoints = new ArrayList();
+ ArrayList otherVeinPoints = new ArrayList();
+ for (TrianglePoint point : allVeins.keySet()) {
+ if (allVeins.get(point).getOwnerId() == game.getMyPlayer().getId()) {
+ myVeinPoints.add(point);
+ } else {
+ otherVeinPoints.add(point);
+ }
+ }
+
+ // launch
+ Collections.sort(myVeinPoints, frontVeinComparator);
+ Collections.reverse(myVeinPoints);
+ for (TrianglePoint myPoint : myVeinPoints) {
+ TargetVeinComparator targetVeinComparator = new TargetVeinComparator();
+ targetVeinComparator.setSource(myPoint);
+ Collections.sort(otherVeinPoints, targetVeinComparator);
+ for (TrianglePoint otherPoint : otherVeinPoints.subList(0,
+ otherVeinPoints.size() / 4)) {
+ int robotsToLaunch =
+ getRequiredRobots(myPoint, otherPoint) + 1 - getValue(sentRobots, otherPoint);
+ if (robotsToLaunch > 0
+ && robotsToLaunch <= getRemainingRobots(myPoint) - getValue(launchedRobots, myPoint)) {
+ launch(commands, robotsToLaunch, myPoint, otherPoint);
+ }
+ }
+ final int NumberOfRobotsToHold = 100;
+ for (TrianglePoint otherPoint : otherVeinPoints) {
+ int robotsToLaunch = getRemainingRobots(myPoint) - NumberOfRobotsToHold;
+ if (robotsToLaunch <= 0) {
+ break;
+ } else {
+ launch(commands, robotsToLaunch, myPoint, otherPoint);
+ }
+ }
+ }
+
+ // upgrade
+ Collections.sort(myVeinPoints, veinValueComparator);
+ for (TrianglePoint point : myVeinPoints) {
+ GameSetting setting = game.getSetting();
+
+ int currentMaterialRank = allVeins.get(point).getMaterialRank();
+ Map requiredMaterialsForMaterial = new HashMap();
+ for (Material material : Material.values()) {
+ int requiredAmount;
+ if (currentMaterialRank == 1) {
+ requiredAmount = setting.getMaterialsForUpgradingMaterialRankFrom1To2(material);
+ } else {
+ requiredAmount = setting.getMaterialsForUpgradingMaterialRankFrom2To3(material);
+ }
+ requiredMaterialsForMaterial.put(material, requiredAmount);
+ }
+ upgrade(requiredMaterialsForMaterial, Commands.upgradeMaterial(point), point,
+ currentMaterialRank, commands);
+
+ int currentRobotRank = allVeins.get(point).getRobotRank();
+ Map requiredMaterialsForRobot = new HashMap();
+ for (Material material : Material.values()) {
+ int requiredAmount;
+ if (currentRobotRank == 1) {
+ requiredAmount = setting.getMaterialsForUpgradingRobotRankFrom1To2(material);
+ } else {
+ requiredAmount = setting.getMaterialsForUpgradingRobotRankFrom2To3(material);
+ }
+ requiredMaterialsForRobot.put(material, requiredAmount);
+ }
+ upgrade(requiredMaterialsForRobot, Commands.upgradeRobot(point), point, currentRobotRank,
+ commands);
+ }
+
+ // trade : prepare
+ final int MaxTradeAmount = 100;
+ final int MaterialAmountToHold = 300;
+ List materialsToBuy = new ArrayList();
+ List materialsToSell = new ArrayList();
+ for (Material material : Material.values()) {
+ if (getRemainingMaterials(material) < MaterialAmountToHold) {
+ materialsToBuy.add(material);
+ } else if (getRemainingMaterials(material) > MaterialAmountToHold) {
+ materialsToSell.add(material);
+ }
+ }
+
+ // trade : accept their trades
+ for (PlayerTrade trade : game.getPlayerTrades()) {
+ Material material = trade.getMaterial();
+ if (trade.getTradeType() == TradeType.Offer
+ && trade.getPricePerOneMaterial() < getDefaultPrice(material)
+ && materialsToBuy.contains(material)) {
+ addCommand(commands, Commands.buyFromPlayerTrade(trade, Math.min(trade.getAmount(),
+ Math.min(getMaximumAmountFromRemainingMoney(trade.getPricePerOneMaterial()),
+ MaxTradeAmount))));
+ } else if (trade.getTradeType() == TradeType.Demand
+ && trade.getPricePerOneMaterial() > getDefaultPrice(material)
+ && materialsToSell.contains(material)) {
+ addCommand(
+ commands,
+ Commands.sellToPlayerTrade(
+ trade,
+ Math.min(trade.getAmount(),
+ Math.min(getRemainingMaterials(material), MaxTradeAmount))));
+ }
+ }
+
+ // trade : send our trade requests
+ for (Material material : materialsToBuy) {
+ int amount = Math.min(getRemainingMoney() / getDefaultPrice(material), MaxTradeAmount);
+ if (amount > 0) {
+ addCommand(commands, Commands.demand(material, amount, getDefaultPrice(material)));
+ }
+ }
+ for (Material material : materialsToSell) {
+ int amount = Math.min(getRemainingMaterials(material), MaxTradeAmount);
+ if (amount > 0) {
+ addCommand(commands, Commands.offer(material, amount, getDefaultPrice(material)));
+ }
+ }
+
+ return commands;
+ }
+
+ private int getDefaultPrice(Material material) {
+ return game.getAlienTrade().getBuyPriceOf(material) / 2;
+ }
+
+ private int getMaximumAmountFromRemainingMoney(int price) {
+ return getRemainingMoney() / price;
+ }
+
+ private void upgrade(Map requiredMaterials, Command upgradeCommand,
+ TrianglePoint point, int currentRank, List commands) {
+ if (currentRank < MaxRank) {
+ boolean hasEnoughMaterials = true;
+ for (Material material : requiredMaterials.keySet()) {
+ if (getRemainingMaterials(material) < requiredMaterials.get(material)) {
+ hasEnoughMaterials = false;
+ break;
+ }
+ }
+ if (hasEnoughMaterials) {
+ addCommand(commands, upgradeCommand);
+ for (Material material : requiredMaterials.keySet()) {
+ increment(usedMaterials, material, requiredMaterials.get(material));
+ }
+ }
+ }
+ }
+
+ private void addCommand(List commands, Command command) {
+ commands.add(command);
+ this.saveTemporalCommands(commands);
+ }
+
+ private void increment(Map map, K key, Integer value) {
+ map.put(key, (map.containsKey(key) ? map.get(key) : 0) + value);
+ }
+
+ private Integer getValue(Map map, K key) {
+ if (map.containsKey(key)) {
+ return map.get(key);
+ } else {
+ return 0;
+ }
+ }
+
+ private int evaluateVein(TrianglePoint from, TrianglePoint to) {
+ if (getRequiredRobots(from, to) <= 0) {
+ return Integer.MIN_VALUE / 10;
+ }
+ int distance = from.getShortestPath(to).size();
+ if (distance > game.getSetting().getMapSize()) {
+ return Integer.MIN_VALUE / 10*2;
+ }
+ int evaluation = 0;
+ evaluation -= getRequiredRobots(from, to);
+ evaluation += allVeins.get(from).getNumberOfRobots();
+ evaluation -=
+ distance
+ * (allVeins.get(to).getOwnerId() == game.getNeutralPlayerId() ? 5 : allVeins.get(to)
+ .getCurrentRobotProductivity());
+ return evaluation;
+ }
+
+ private int getRequiredRobots(TrianglePoint from, TrianglePoint to) {
+ Vein targetVein = allVeins.get(to);
+ int productivity =
+ (targetVein.getOwnerId() == game.getNeutralPlayerId() ? 0 : targetVein
+ .getCurrentRobotProductivity());
+ int robots = targetVein.getNumberOfRobots() + from.getShortestPath(to).size() * productivity;
+ return robots;
+ }
+
+ private int getRemainingMaterials(Material material) {
+ return game.getMyPlayer().getMaterial(material) - getValue(usedMaterials, material);
+ }
+
+ private int getRemainingMoney() {
+ return game.getMyPlayer().getMoney() - usedMoney;
+ }
+
+ private int getRemainingRobots(TrianglePoint vein) {
+ return allVeins.get(vein).getNumberOfRobots() - getValue(launchedRobots, vein);
+ }
+
+ public Comparator veinValueComparator = new Comparator() {
+ private int getValue(Vein vein) {
+ return vein.getCurrentMaterialProductivity() + vein.getCurrentRobotProductivity();
+ }
+
+ public int compare(TrianglePoint left, TrianglePoint right) {
+ return getValue(allVeins.get(right)) - getValue(allVeins.get(left));
+ }
+ };
+
+ public class TargetVeinComparator implements Comparator {
+ private TrianglePoint source;
+
+ public void setSource(TrianglePoint source) {
+ this.source = source;
+ }
+
+ public int compare(TrianglePoint left, TrianglePoint right) {
+ return evaluateVein(source, right) - evaluateVein(source, left);
+ }
+ };
+
+ public Comparator frontVeinComparator = new Comparator() {
+ private int getValue(TrianglePoint from) {
+ int value = 0;
+ int nearFriendlies = 0;
+ for (TrianglePoint to : allVeins.keySet()) {
+ if (allVeins.get(to).getOwnerId() != game.getMyPlayer().getId()) {
+ value -= from.getShortestPath(to).size();
+ } else {
+ value -= game.getSetting().getMapSize() * 2;
+ nearFriendlies++;
+ }
+ }
+ if (nearFriendlies < 2) {
+ return Integer.MIN_VALUE / 10;
+ } else {
+ return value;
+ }
+ }
+
+ public int compare(TrianglePoint left, TrianglePoint right) {
+ return getValue(right) - getValue(left);
+ }
+ };
+}
diff --git a/src/main/java/net/javachallenge/players/others/Myu.java b/src/main/java/net/javachallenge/players/others/Myu.java
new file mode 100644
index 0000000..4663212
--- /dev/null
+++ b/src/main/java/net/javachallenge/players/others/Myu.java
@@ -0,0 +1,244 @@
+package net.javachallenge.players.others;
+
+import java.awt.Point;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import net.javachallenge.api.ComputerPlayer;
+import net.javachallenge.api.Field;
+import net.javachallenge.api.Game;
+import net.javachallenge.api.Material;
+import net.javachallenge.api.Player;
+import net.javachallenge.api.TrianglePoint;
+import net.javachallenge.api.Vein;
+import net.javachallenge.api.command.Command;
+import net.javachallenge.api.command.Commands;
+
+public class Myu extends ComputerPlayer {
+ private List veinPoints;
+ private List myVeinPoints = new ArrayList();
+ private static boolean isFirst = true;
+
+ @Override
+ public String getName() {
+ return "Myu";
+ }
+
+ @Override
+ public TrianglePoint selectVein(Game game) {
+ Field field = game.getField();
+ Map veins = field.getVeinMap();
+ Object[] tp = veins.keySet().toArray();
+ Point edge = getEdgeVeins(tp);
+
+ veinPoints = categolizeVeins(tp, edge);
+ return selectPoint(veins);
+ }
+
+ private Point getEdgeVeins(Object[] tp) {
+ int maxX = 0;
+ int minX = 100;
+ int maxY = 0;
+ int minY = 0;
+
+ for (int i = tp.length - 1; i >= 0; i--) {
+ TrianglePoint t = (TrianglePoint) tp[i];
+ int tmpX = t.getX();
+ int tmpY = t.getY();
+
+ if (maxX < tmpX) {
+ maxX = tmpX;
+ } else if (minX > tmpX) {
+ minX = tmpX;
+ }
+
+ if (maxY < tmpY) {
+ maxY = tmpY;
+ } else if (minY > tmpY) {
+ minY = tmpY;
+ }
+ }
+ return new Point(maxX + minX, maxY + minY);
+ }
+
+ private List categolizeVeins(Object[] tp, Point edge) {
+ int maxNum = 0;
+ int zone = 0;
+ List seVeins = new ArrayList();
+ List swVeins = new ArrayList();
+ List neVeins = new ArrayList();
+ List nwVeins = new ArrayList();
+
+ for (int i = tp.length - 1; i >= 0; i--) {
+ TrianglePoint t = (TrianglePoint) tp[i];
+ if (t.getX() >= edge.x / 2) {
+ if (t.getY() >= edge.y / 2) {
+ seVeins.add(t);
+ if (seVeins.size() > maxNum) {
+ maxNum = seVeins.size();
+ zone = 0;
+ }
+ } else {
+ neVeins.add(t);
+ if (neVeins.size() > maxNum) {
+ maxNum = neVeins.size();
+ zone = 3;
+ }
+ }
+ } else {
+ if (t.getY() >= edge.x / 2) {
+ swVeins.add(t);
+ if (swVeins.size() > maxNum) {
+ maxNum = swVeins.size();
+ zone = 2;
+ }
+ } else {
+ nwVeins.add(t);
+ if (nwVeins.size() > maxNum) {
+ maxNum = nwVeins.size();
+ zone = 1;
+ }
+ }
+ }
+ }
+
+ List points = new ArrayList();
+ switch (zone) {
+ case 0:
+ points.addAll(seVeins);
+ points.addAll(swVeins);
+ points.addAll(neVeins);
+ points.addAll(nwVeins);
+ return points;
+ case 1:
+ points.addAll(nwVeins);
+ points.addAll(neVeins);
+ points.addAll(swVeins);
+ points.addAll(seVeins);
+ return points;
+ case 2:
+ points.addAll(swVeins);
+ points.addAll(seVeins);
+ points.addAll(nwVeins);
+ points.addAll(neVeins);
+ return points;
+ case 3:
+ points.addAll(neVeins);
+ points.addAll(nwVeins);
+ points.addAll(seVeins);
+ points.addAll(swVeins);
+ return points;
+ }
+ return seVeins;
+ }
+
+ private TrianglePoint selectPoint(Map veins) {
+ int maxRP = 0;
+ Vein vein;
+ TrianglePoint point = veinPoints.get(0);
+ for (TrianglePoint t : veinPoints) {
+ vein = veins.get(t);
+ int rp = vein.getInitialRobotProductivity();
+ if (isFirst) {
+ if (maxRP <= rp && vein.getOwnerId() == -1 && vein.getMaterial() == Material.Gas) {
+ maxRP = rp;
+ point = t;
+ }
+ } else {
+ if (maxRP <= rp && vein.getOwnerId() == -1 && vein.getMaterial() == Material.Metal) {
+ maxRP = rp;
+ point = t;
+ }
+ }
+ }
+
+ isFirst = false;
+ myVeinPoints.add(point);
+ return point;
+ }
+
+ @Override
+ public List selectActions(Game game) {
+ Player myself = game.getMyPlayer();
+ Field field = game.getField();
+ Map veinlist = field.getVeinMap();
+ int robots =
+ (int) ((veinlist.get(myVeinPoints.get(0)).getNumberOfRobots() + veinlist.get(
+ myVeinPoints.get(1)).getNumberOfRobots()) * 0.8);
+
+ List commands = new ArrayList();
+ boolean ugrbt = true;
+ boolean ugmtl = true;
+ for (TrianglePoint tp : myVeinPoints) {
+ Vein v = veinlist.get(tp);
+ int rank = v.getRobotRank();
+
+ if (ugmtl
+ && myself.getMaterial(Material.Stone) > game.getSetting()
+ .getMaterialsForUpgradingMaterialRankFrom2To3(Material.Stone)
+ && myself.getMaterial(Material.Gas) > game.getSetting()
+ .getMaterialsForUpgradingRobotRankFrom2To3(Material.Gas)) {
+ if (rank < 3) {
+ commands.add(Commands.upgradeMaterial(v.getLocation()));
+ ugmtl = false;
+ }
+ }
+
+ if (ugmtl
+ && myself.getMaterial(Material.Stone) > game.getSetting()
+ .getMaterialsForUpgradingMaterialRankFrom1To2(Material.Stone)
+ && myself.getMaterial(Material.Gas) > game.getSetting()
+ .getMaterialsForUpgradingRobotRankFrom1To2(Material.Gas)) {
+ if (rank < 2) {
+ commands.add(Commands.upgradeMaterial(v.getLocation()));
+ ugmtl = false;
+ }
+ }
+
+ if (ugrbt
+ && myself.getMaterial(Material.Metal) > game.getSetting()
+ .getMaterialsForUpgradingRobotRankFrom2To3(Material.Metal)
+ && myself.getMaterial(Material.Gas) > game.getSetting()
+ .getMaterialsForUpgradingRobotRankFrom2To3(Material.Gas)) {
+ if (rank < 3) {
+ commands.add(Commands.upgradeRobot(v.getLocation()));
+ ugrbt = false;
+ }
+ }
+
+ if (ugrbt
+ && myself.getMaterial(Material.Metal) > game.getSetting()
+ .getMaterialsForUpgradingRobotRankFrom1To2(Material.Metal)
+ && myself.getMaterial(Material.Gas) > game.getSetting()
+ .getMaterialsForUpgradingRobotRankFrom1To2(Material.Gas)) {
+ if (rank < 2) {
+ commands.add(Commands.upgradeRobot(v.getLocation()));
+ ugrbt = false;
+ }
+ }
+
+ }
+
+ Iterator tp = veinPoints.iterator();
+ while (tp.hasNext()) {
+ TrianglePoint location = tp.next();
+ if (veinlist.get(location).getOwnerId() == game.getNeutralPlayerId()) {
+ if (veinlist.get(location).getNumberOfRobots() < robots * 0.8) {
+ for (TrianglePoint p : myVeinPoints) {
+ Vein v = veinlist.get(p);
+ commands.add(Commands.launch((int) (v.getNumberOfRobots() * 0.9), v.getLocation(),
+ location));
+ }
+ myVeinPoints.add(location);
+ tp.remove();
+ break;
+ }
+ }
+ }
+
+ this.saveTemporalCommands(commands);
+ return commands;
+ }
+}
diff --git a/src/main/java/net/javachallenge/players/others/NearPlayer.java b/src/main/java/net/javachallenge/players/others/NearPlayer.java
new file mode 100644
index 0000000..ed83434
--- /dev/null
+++ b/src/main/java/net/javachallenge/players/others/NearPlayer.java
@@ -0,0 +1,425 @@
+package net.javachallenge.players.others;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Random;
+import java.util.Set;
+
+import net.javachallenge.api.ComputerPlayer;
+import net.javachallenge.api.Game;
+import net.javachallenge.api.Material;
+import net.javachallenge.api.Squad;
+import net.javachallenge.api.TrianglePoint;
+import net.javachallenge.api.Vein;
+import net.javachallenge.api.command.Command;
+import net.javachallenge.api.command.Commands;
+
+public class NearPlayer extends ComputerPlayer {
+ static final double LAUNCH_RATE = 2.5;
+
+ static final int REQUIRED_MINIMUM_ROBOTS_TO_INVADE = 100;
+
+ static final int REQUIRED_MAXIMUM_SQUADS_TO_INVADE = 4;
+
+ static final int NEAR_THRESHOLD = 12;
+
+ class VeinWithPoint {
+ Vein vein;
+ TrianglePoint point;
+ int distance;
+
+ VeinWithPoint(Vein v, TrianglePoint p, TrianglePoint t) {
+ vein = v;
+ point = p;
+ distance = p.getShortestPath(t).size();
+ }
+ }
+
+ static Random random = new Random(1000000009);
+
+ @Override
+ public String getName() {
+ return "near-player";
+ }
+
+ @Override
+ public TrianglePoint selectVein(Game game) {
+ TrianglePoint bestPoint = null;
+ int bestRobot = -1;
+
+ Map map = filterVein(game, -1);
+ Material firstMaterial = null;
+ if (filterMyVein(game).size() == 0) {
+ firstMaterial = Material.Stone;
+ } else {
+ Vein selectedVein = filterMyVein(game).values().iterator().next();
+ firstMaterial = selectedVein.getMaterial();
+ }
+
+ for (Entry entry : map.entrySet()) {
+ TrianglePoint pt = entry.getKey();
+ Vein vein = entry.getValue();
+ boolean wantMaterial =
+ (vein.getMaterial() == Material.Gas || vein.getMaterial() == Material.Metal);
+ if (firstMaterial == vein.getMaterial()) {
+ wantMaterial = false;
+ }
+ if (wantMaterial) {
+ int score = evaluateInitialVeinScore(game, vein, pt);
+ if (bestRobot < score) {
+ bestRobot = score;
+ bestPoint = pt;
+ }
+ }
+ }
+ if (bestPoint != null) {
+ return bestPoint;
+ }
+ return map.entrySet().iterator().next().getKey();
+ }
+
+ /**
+ * Evaluate and return initial value of specified vein.
+ *
+ * @param game
+ * @param vein
+ * @param pt
+ * @return initial evaluation value of specified vein
+ */
+ private int evaluateInitialVeinScore(Game game, Vein vein, TrianglePoint pt) {
+ Map map = filterVein(game, -1);
+ Map enemyMap = filterEnemyVein(game);
+ int score = evaluateBaseProductivity(vein);
+ for (Entry entryTo : map.entrySet()) {
+ TrianglePoint topt = entryTo.getKey();
+ if (pt.equals(topt)) {
+ continue;
+ }
+ int d = topt.getShortestPath(pt).size();
+ score += (Math.max(0, NEAR_THRESHOLD - d));
+ }
+ for (Entry entryTo : enemyMap.entrySet()) {
+ TrianglePoint topt = entryTo.getKey();
+ if (pt.equals(topt)) {
+ continue;
+ }
+ int d = topt.getShortestPath(pt).size();
+ score -= (Math.max(0, NEAR_THRESHOLD - d)) * 100;
+ }
+ return score;
+ }
+
+
+ @Override
+ public List selectActions(Game game) {
+ List commands = new ArrayList();
+
+ commands.addAll(generateLaunchCommands(game));
+
+ commands.addAll(generateUpgradeCommands(game));
+
+ commands.addAll(generateTradeCommands(game));
+
+ return commands;
+ }
+
+ /**
+ * Generate and return trade commands.
+ *
+ * @param game
+ * @return trade commands
+ */
+ private List generateTradeCommands(Game game) {
+ List ret = new ArrayList();
+ return ret;
+ }
+
+ /**
+ * Return evaluation value of the vein based on initial productivity.
+ *
+ * @param vein
+ * @return evaluation value of the vein based on initial productivity
+ */
+ private int evaluateBaseProductivity(Vein vein) {
+ return vein.getInitialRobotProductivity() + vein.getInitialMaterialProductivity();
+ }
+
+ /**
+ * Generate and return upgrade commands.
+ *
+ * @param game
+ * @return upgrade commands
+ */
+ private List generateUpgradeCommands(Game game) {
+ List ret = new ArrayList();
+
+ Map myVeins = filterVein(game, game.getMyPlayer().getId());
+ for (Entry myEntry : myVeins.entrySet()) {
+ TrianglePoint myPoint = myEntry.getKey();
+ ret.add(Commands.upgradeRobot(myPoint));
+ }
+ for (Entry myEntry : myVeins.entrySet()) {
+ TrianglePoint myPoint = myEntry.getKey();
+ ret.add(Commands.upgradeMaterial(myPoint));
+ }
+ return ret;
+ }
+
+ /**
+ * Generate and return launch commands.
+ *
+ * @param game
+ * @return upgrade commands
+ */
+ private List generateLaunchCommands(Game game) {
+ List ret = new ArrayList();
+ Map myVeins = filterVein(game, game.getMyPlayer().getId());
+ Set sentSet = new HashSet();
+ Set sentToSet = new HashSet();
+
+ ret.addAll(launchSingleToSingle(game, myVeins, sentSet, sentToSet));
+
+ ret.addAll(launchMultipleToSingle(game, myVeins, sentSet, sentToSet));
+
+ return ret;
+ }
+
+ /**
+ * Return list of unused veins that owned by me
+ *
+ * @param myVeins
+ * @param sentSet
+ * @return list of unused veins that owned by me
+ */
+ private Map unusedMyVeins(Map myVeins,
+ Set sentSet) {
+ Map unusedMyVeins = new HashMap();
+ for (Entry myEntry : myVeins.entrySet()) {
+ TrianglePoint myPoint = myEntry.getKey();
+ if (sentSet.contains(myPoint)) {
+ continue;
+ }
+ if (myEntry.getValue().getNumberOfRobots() <= REQUIRED_MINIMUM_ROBOTS_TO_INVADE) {
+ continue;
+ }
+ unusedMyVeins.put(myPoint, myEntry.getValue());
+ }
+ return unusedMyVeins;
+ }
+
+ /**
+ * Return commands that launch robots multiple vein to enemy single vein.
+ *
+ * @param game
+ * @param myVeins
+ * @param sentSet
+ * @param sentToSet
+ * @return commands that launch robots multiple vein to enemy single vein.
+ */
+ private List launchMultipleToSingle(Game game, Map myVeins,
+ Set sentSet, Set sentToSet) {
+ List multipleLaunchCommands = new ArrayList();
+ for (Entry enemyEntry : filterEnemyVein(game).entrySet()) {
+ Vein enemyVein = enemyEntry.getValue();
+ TrianglePoint enemyPoint = enemyEntry.getKey();
+
+ Map unusedMyVeins = unusedMyVeins(myVeins, sentSet);
+
+ List nearPoints = nearVeins(game, enemyPoint, unusedMyVeins);
+ int cnt = 0;
+ int totalMyRobot = 0;
+ for (VeinWithPoint vwp : nearPoints) {
+ totalMyRobot += vwp.vein.getNumberOfRobots() / 2;
+ cnt++;
+ int expectedEnemyRobot =
+ enemyVein.getNumberOfRobots() + enemyVein.getCurrentRobotProductivity() * vwp.distance;
+ if (totalMyRobot >= expectedEnemyRobot * LAUNCH_RATE / 2) {
+ break;
+ }
+ }
+
+ if (cnt <= Math.min(nearPoints.size() - 1, REQUIRED_MAXIMUM_SQUADS_TO_INVADE)
+ && nearPoints.get(0).distance <= NEAR_THRESHOLD) {
+ for (int d = 0; d < cnt; d++) {
+ VeinWithPoint vwp = nearPoints.get(d);
+ multipleLaunchCommands.add(Commands.launch(vwp.vein.getNumberOfRobots() / 2, vwp.point,
+ enemyPoint));
+ sentSet.add(vwp.point);
+ }
+ }
+ }
+ return multipleLaunchCommands;
+ }
+
+ /**
+ * Return enemy squads going to specified points sorted by distance.
+ *
+ * @param game
+ * @param vwp
+ * @return enemy squads going to specified points sorted by distance
+ */
+ private List enemySquadsSortedByDistance(Game game, VeinWithPoint vwp) {
+ List squads = new ArrayList();
+ for (Squad squad : game.getField().getSquads()) {
+ if (squad.getOwnerId() == game.getMyPlayer().getId()) {
+ continue;
+ }
+ if (squad.getDestinationLocation().equals(vwp.point)) {
+ squads.add(squad);
+ }
+ }
+ Collections.sort(squads, new Comparator() {
+ @Override
+ public int compare(Squad o1, Squad o2) {
+ int z1 = o1.getCurrentLocation().getShortestPath(o1.getDestinationLocation()).size();
+ int z2 = o2.getCurrentLocation().getShortestPath(o2.getDestinationLocation()).size();
+ return z1 - z2;
+ }
+ });
+ return squads;
+ }
+
+ /**
+ * Return expected number of enemy robots.
+ *
+ * @param game
+ * @param squads
+ * @param length
+ * @return expected number of enemy robots
+ */
+ private int expectedEnemyRobot(Game game, List squads, int length) {
+ int squadIndex = squads.size() - 1;
+ int expectedEnemyRobot = 0;
+ while (squadIndex >= 0) {
+ Squad squad = squads.get(squadIndex);
+ if (squad.getOwnerId() != game.getMyPlayer().getId()) {
+ if (squad.getPath().size() > length) {
+ expectedEnemyRobot += squad.getRobot();
+ } else {
+ expectedEnemyRobot = Math.max(expectedEnemyRobot, squad.getRobot());
+ }
+ }
+ squadIndex--;
+ }
+ return expectedEnemyRobot;
+ }
+
+ /**
+ * Return commands that launch robots single vein to another single vein.
+ *
+ * @param game
+ * @param myVeins
+ * @param sentSet
+ * @param sentToSet
+ * @return commands that launch robots single vein to another single vein
+ */
+ private List launchSingleToSingle(Game game, Map myVeins,
+ Set sentSet, Set sentToSet) {
+ List singleLaunchCommands = new ArrayList();
+
+ for (Entry myEntry : myVeins.entrySet()) {
+ TrianglePoint fromPoint = myEntry.getKey();
+ Vein myVein = myEntry.getValue();
+
+ Map emptyVeins = filterVein(game, -1);
+ List nearVeins = nearVeins(game, fromPoint, emptyVeins);
+ for (VeinWithPoint vwp : nearVeins) {
+ if (sentToSet.contains(vwp.point)) {
+ continue;
+ }
+ int length = vwp.point.getShortestPath(fromPoint).size();
+ List squads = enemySquadsSortedByDistance(game, vwp);
+ int expectedEnemyRobot =
+ expectedEnemyRobot(game, squads, length) + vwp.vein.getNumberOfRobots();
+ if (length <= NEAR_THRESHOLD
+ && myVein.getNumberOfRobots() >= expectedEnemyRobot * LAUNCH_RATE) {
+ singleLaunchCommands.add(Commands.launch((int) (expectedEnemyRobot * LAUNCH_RATE / 2),
+ fromPoint, vwp.point));
+ sentSet.add(fromPoint);
+ sentToSet.add(vwp.point);
+ break;
+ }
+ }
+ }
+ return singleLaunchCommands;
+ }
+
+ /**
+ * Return veins owned by me.
+ *
+ * @param game
+ * @return my veins
+ */
+ private Map filterMyVein(Game game) {
+ return filterVein(game, game.getMyPlayer().getId());
+ }
+
+ /**
+ * Return veins owned by enemies.
+ *
+ * @param game
+ * @return enemy veins
+ */
+ private Map filterEnemyVein(Game game) {
+ return filterNotVein(game, game.getMyPlayer().getId(), -1);
+ }
+
+ private Map filterVein(Game game, int tid) {
+ return game.getField().getVeinMap(tid);
+ }
+
+ /**
+ * Returns the vein owned by tid nor tid2.
+ *
+ * @param game
+ * @param tid
+ * @param tid2
+ * @return
+ */
+ private Map filterNotVein(Game game, int tid, int tid2) {
+ Map map = game.getField().getVeinMap();
+ Map returnMap = new HashMap();
+ for (Entry entry : map.entrySet()) {
+ TrianglePoint pt = entry.getKey();
+ Vein vein = entry.getValue();
+ if (vein.getOwnerId() != tid && vein.getOwnerId() != tid2) {
+ returnMap.put(pt, vein);
+ }
+ }
+ return returnMap;
+ }
+
+ /**
+ * Return the map of vein and point that exist near the specified point.
+ *
+ * @param game
+ * @param p
+ * @param targetVeins
+ * @return the map of vein and point that exist near the specified point
+ */
+ private List nearVeins(Game game, TrianglePoint p,
+ Map targetVeins) {
+ List nearPoints = new ArrayList