Java tutorial
// Copyright 2015 theaigames.com (developers@theaigames.com) // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. package com.theaigames.game.warlight2; import java.io.*; import java.util.ArrayList; import java.util.LinkedList; import java.util.Scanner; import java.lang.Thread; import java.util.zip.*; import java.util.Properties; import java.net.URL; import com.synisys.ai.WarlightApplication; import com.theaigames.engine.Engine; import com.theaigames.engine.Logic; import com.theaigames.engine.io.IOPlayer; import com.theaigames.game.warlight2.move.AttackTransferMove; import com.theaigames.game.warlight2.move.MoveResult; import com.theaigames.game.warlight2.move.PlaceArmiesMove; import com.theaigames.game.warlight2.map.Map; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; /** * Warlight2 class * * Main class for Warlight2 * * @author Jim van Eeden <jim@starapple.nl> */ public class Warlight2 implements Logic { private String playerName1, playerName2; private final String mapFile; private Processor processor; private Player player1, player2; private int maxRounds; private String secretKey, accessKey; private final int STARTING_ARMIES = 5; private final long TIMEBANK_MAX = 10000l; private final long TIME_PER_MOVE = 500l; private final int SIZE_WASTELANDS = 6; // size of wastelands, <= 0 for no wastelands public Warlight2(String mapFile) { this.mapFile = mapFile; this.playerName1 = "player1"; this.playerName2 = "player2"; } /** * sets up everything that's needed before a round can be played * @param players : list of bots that have already been initialized */ @Override public void setupGame(ArrayList<IOPlayer> players) throws IncorrectPlayerCountException, IOException { Map initMap, map; //System.out.println("setting up game"); // Determine array size is two players if (players.size() != 2) { throw new IncorrectPlayerCountException("Should be two players"); } this.player1 = new Player(playerName1, players.get(0), STARTING_ARMIES, TIMEBANK_MAX, TIME_PER_MOVE); this.player2 = new Player(playerName2, players.get(1), STARTING_ARMIES, TIMEBANK_MAX, TIME_PER_MOVE); // get map string from database and setup the map initMap = MapCreator.createMap(getMapString()); map = MapCreator.setupMap(initMap, SIZE_WASTELANDS); this.maxRounds = MapCreator.determineMaxRounds(map); // start the processor //System.out.println("Starting game..."); this.processor = new Processor(map, player1, player2); sendSettings(player1); sendSettings(player2); MapCreator.sendSetupMapInfo(player1, map); MapCreator.sendSetupMapInfo(player2, map); //System.out.println("initialmap " + map.getMapAsDictString()); player1.setTimeBank(TIMEBANK_MAX); player2.setTimeBank(TIMEBANK_MAX); this.processor.distributeStartingRegions(); //decide the player's starting regions this.processor.recalculateStartingArmies(); //calculate how much armies the players get at the start of the round (depending on owned SuperRegions) this.processor.sendAllInfo(); } /** * play one round of the game * @param roundNumber : round number */ @Override public void playRound(int roundNumber) { player1.getBot().addToDump(String.format("Round %d\n", roundNumber)); player2.getBot().addToDump(String.format("Round %d\n", roundNumber)); this.processor.playRound(roundNumber); } /** * @return : True when the game is over */ @Override public boolean isGameWon() { if (this.processor.getWinner() != null || this.processor.getRoundNr() > this.maxRounds) { return true; } return false; } /** * Sends all game settings to given player * @param player : player to send settings to */ private void sendSettings(Player player) { player.sendInfo("settings timebank " + TIMEBANK_MAX); player.sendInfo("settings time_per_move " + TIME_PER_MOVE); player.sendInfo("settings max_rounds " + this.maxRounds); player.sendInfo("settings your_bot " + player.getName()); if (player.getName().equals(player1.getName())) player.sendInfo("settings opponent_bot " + player2.getName()); else player.sendInfo("settings opponent_bot " + player1.getName()); } /** * Reads the string from the map file * @return : string representation of the map * @throws IOException */ private String getMapString() throws IOException { try (InputStream file = getClass().getResourceAsStream(this.mapFile); Scanner scanner = new Scanner(file)) { StringBuilder fileContents = new StringBuilder(); String lineSeparator = System.getProperty("line.separator"); while (scanner.hasNextLine()) { fileContents.append(scanner.nextLine() + lineSeparator); } return fileContents.toString(); } } /** * close the bot processes, save, exit program */ @Override public void finish() throws Exception { this.player1.getBot().finish(); this.player2.getBot().finish(); Thread.sleep(100); // write everything try { this.saveGame(); } catch (Exception e) { e.printStackTrace(); } // System.out.println("Done."); // System.exit(0); } /** * Turns the game that is stored in the processor to a nice string for the visualization * @param winner : winner * @param gameView : type of view * @return : string that the visualizer can read */ private String getPlayedGame(Player winner, String gameView) { StringBuilder out = new StringBuilder(); LinkedList<MoveResult> playedGame; if (gameView.equals("player1")) playedGame = this.processor.getPlayer1PlayedGame(); else if (gameView.equals("player2")) playedGame = this.processor.getPlayer2PlayedGame(); else playedGame = this.processor.getFullPlayedGame(); playedGame.removeLast(); int roundNr = 0; for (MoveResult moveResult : playedGame) { if (moveResult != null) { if (moveResult.getMove() != null) { try { PlaceArmiesMove plm = (PlaceArmiesMove) moveResult.getMove(); out.append(plm.getString() + "\n"); } catch (Exception e) { AttackTransferMove atm = (AttackTransferMove) moveResult.getMove(); out.append(atm.getString() + "\n"); } } out.append("map " + moveResult.getMap().getMapString() + "\n"); } else { out.append("round " + roundNr + "\n"); roundNr++; } } if (winner != null) out.append(winner.getName() + " won\n"); else out.append("Nobody won\n"); return out.toString(); } public String getPlayedGame() { Player winner = this.processor.getWinner(); int score = this.processor.getRoundNr() - 1; if (winner != null) { // System.out.println("winner: " + winner.getName()); } else { // System.out.println("winner: draw"); } // System.out.println("Saving the game..."); // do stuff here if you want to save results // save the full game: return getPlayedGame(winner, "full game"); } /** * Does everything that is needed to store the output of a game */ public void saveGame() { Player winner = this.processor.getWinner(); int score = this.processor.getRoundNr() - 1; if (winner != null) { // System.out.println("winner: " + winner.getName()); } else { // System.out.println("winner: draw"); } // System.out.println("Saving the game..."); // do stuff here if you want to save results // save the full game: // System.out.println(getPlayedGame(winner, "full game")); } /** * main * @param args : the map file should be given, along with the commands that start the bot processes * @throws Exception */ public static void main(String args[]) throws Exception { String mapFile = args[0]; String bot1Cmd = args[1]; String bot2Cmd = args[2]; // Construct engine Engine engine = new Engine(); // Set logic engine.setLogic(new Warlight2(mapFile)); // Add players engine.addPlayer(bot1Cmd); engine.addPlayer(bot2Cmd); engine.start(); } }