GameTree based AI
Implemented the first version of a GameTree based AI. Comparable to best Scala version, but a little weaker still.
This commit is contained in:
parent
d007778f4a
commit
a0ced36a12
23 changed files with 642 additions and 95 deletions
|
@ -45,13 +45,17 @@ public class FarbotIO {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void out(String out) {
|
private static void out(String out) {
|
||||||
log(out);
|
logln(out);
|
||||||
System.out.println(out);
|
System.out.println(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void log(String log) {
|
public static void logln(String log) {
|
||||||
GameState currentState = ai.getCurrentState();
|
GameState currentState = ai.getCurrentState();
|
||||||
String prefix = String.format("[%3d]: ", currentState.getRound());
|
String prefix = String.format("[%3d]: ", currentState.getRound());
|
||||||
System.err.println(prefix+log);
|
System.err.println(prefix+log);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void log(String log) {
|
||||||
|
System.err.print(log);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,25 +1,87 @@
|
||||||
package farbot.ai;
|
package farbot.ai;
|
||||||
|
|
||||||
import farbot.FarbotIO;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import farbot.game.GameState;
|
import farbot.game.GameState;
|
||||||
|
import farbot.game.MoveResult;
|
||||||
|
import farbot.game.map.Move;
|
||||||
|
|
||||||
|
import static farbot.FarbotIO.logln;
|
||||||
|
|
||||||
public class AI {
|
public class AI {
|
||||||
private GameState currentState;
|
private GameState currentState;
|
||||||
|
private int treeDepth = 20;
|
||||||
|
|
||||||
|
private MoveValue lastMove;
|
||||||
|
|
||||||
public AI() {
|
public AI() {
|
||||||
this.currentState = new GameState();
|
this.currentState = new GameState();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String calcMove(Integer time) {
|
public String calcMove(Integer time) {
|
||||||
return "up";
|
logln("Calculating move in "+time+"ms");
|
||||||
|
Set<Move> validMoves = currentState.selfMoves();
|
||||||
|
logln("Valid moves: "+validMoves.toString());
|
||||||
|
|
||||||
|
ArrayList<MoveValue> valuedMoves = new ArrayList<>();
|
||||||
|
|
||||||
|
for(Move m: validMoves) {
|
||||||
|
logln("Checking move: "+m.name());
|
||||||
|
GameState fork = currentState.fork();
|
||||||
|
MoveResult mr = fork.moveSelf(m);
|
||||||
|
GameTree gt = new GameTree(fork);
|
||||||
|
gt.build(treeDepth);
|
||||||
|
Double value = gt.getValue();
|
||||||
|
value += mr.getCollectedCodes()*Math.pow((treeDepth+1), 1.6);
|
||||||
|
value -= mr.getKilledBugs()*8*Math.pow((treeDepth+1), 1.6);
|
||||||
|
|
||||||
|
logln("Move '"+m.name()+"': "+value);
|
||||||
|
valuedMoves.add(new MoveValue(m, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
valuedMoves.sort((mv1, mv2) -> -mv1.value.compareTo(mv2.value));
|
||||||
|
MoveValue maxMove = valuedMoves.get(0);
|
||||||
|
if(this.lastMove != null && this.lastMove.value <= maxMove.value) {
|
||||||
|
switch(this.lastMove.move) {
|
||||||
|
case LEFT:
|
||||||
|
if(maxMove.move == Move.RIGHT) maxMove = valuedMoves.get(1);
|
||||||
|
break;
|
||||||
|
case RIGHT:
|
||||||
|
if(maxMove.move == Move.LEFT) maxMove = valuedMoves.get(1);
|
||||||
|
break;
|
||||||
|
case UP:
|
||||||
|
if(maxMove.move == Move.DOWN) maxMove = valuedMoves.get(1);
|
||||||
|
break;
|
||||||
|
case DOWN:
|
||||||
|
if(maxMove.move == Move.UP) maxMove = valuedMoves.get(1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.lastMove = maxMove;
|
||||||
|
|
||||||
|
logln("Max.move '"+maxMove.move+"': "+maxMove.value);
|
||||||
|
return maxMove.move.name().toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void parseUpdate(String[] update) {
|
public void parseUpdate(String[] update) {
|
||||||
Parser.parse(update, currentState);
|
Parser.parse(update, currentState);
|
||||||
FarbotIO.log(currentState.toString());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public GameState getCurrentState() {
|
public GameState getCurrentState() {
|
||||||
return currentState;
|
return currentState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class MoveValue {
|
||||||
|
private Move move;
|
||||||
|
private Double value;
|
||||||
|
|
||||||
|
private MoveValue(Move move, Double value) {
|
||||||
|
this.move = move;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
83
farbot/src/farbot/ai/GameTree.java
Normal file
83
farbot/src/farbot/ai/GameTree.java
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
package farbot.ai;
|
||||||
|
|
||||||
|
import static farbot.FarbotIO.logln;
|
||||||
|
|
||||||
|
import farbot.game.map.Point;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.Queue;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import farbot.game.GameState;
|
||||||
|
import farbot.game.MoveResult;
|
||||||
|
|
||||||
|
public class GameTree {
|
||||||
|
private GameState node;
|
||||||
|
private Double value;
|
||||||
|
private HashSet<Point> visited;
|
||||||
|
private Integer totalLevel;
|
||||||
|
|
||||||
|
public GameTree(GameState root) {
|
||||||
|
this.node = root;
|
||||||
|
this.value = 0.0;
|
||||||
|
this.totalLevel = 1;
|
||||||
|
this.visited = new HashSet<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void build(int level) {
|
||||||
|
this.totalLevel = level;
|
||||||
|
|
||||||
|
Queue<GameState> children = makeChildren(node, this, level);
|
||||||
|
|
||||||
|
while(level > 0) {
|
||||||
|
level--;
|
||||||
|
|
||||||
|
Queue<GameState> nextChildren = new LinkedList<>();
|
||||||
|
while(!children.isEmpty()) {
|
||||||
|
GameState child = children.poll();
|
||||||
|
nextChildren.addAll(makeChildren(child, this, level));
|
||||||
|
}
|
||||||
|
|
||||||
|
children = nextChildren;
|
||||||
|
nextChildren = new LinkedList<>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value of a root node. Not 0.0 only for nodes
|
||||||
|
* from which a GameTree was built (i.e. nodes on which
|
||||||
|
* build() was called)
|
||||||
|
*
|
||||||
|
* @return Value of a root node. Always 0.0 if not the node
|
||||||
|
* upon which build() was called.
|
||||||
|
*/
|
||||||
|
public Double getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Queue<GameState> makeChildren(GameState state, GameTree gtRoot, int level) {
|
||||||
|
Set<Point> selfMoves = state.selfMovePoints();
|
||||||
|
selfMoves.removeAll(gtRoot.visited);
|
||||||
|
LinkedList<GameState> children = new LinkedList<>();
|
||||||
|
|
||||||
|
for(Point selfMove: selfMoves) {
|
||||||
|
GameState child = state.fork();
|
||||||
|
MoveResult mr = child.moveSelf(selfMove);
|
||||||
|
|
||||||
|
if(mr.getCollectedCodes() != 0){
|
||||||
|
logln("Got "+mr.getCollectedCodes()+" codes at "+selfMove.toString()+" in level "+level);
|
||||||
|
gtRoot.value += Math.pow(level*mr.getCollectedCodes(), 1.3);
|
||||||
|
}
|
||||||
|
if(mr.getKilledBugs() != 0) {
|
||||||
|
logln("Killed "+mr.getKilledBugs()+" bugs at "+selfMove.toString()+" in level "+level);
|
||||||
|
gtRoot.value -= Math.pow(level*4*mr.getKilledBugs(), level/totalLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
gtRoot.visited.add(selfMove);
|
||||||
|
|
||||||
|
children.add(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
return children;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
package farbot.ai;
|
package farbot.ai;
|
||||||
|
|
||||||
import java.awt.Point;
|
import farbot.game.map.Point;
|
||||||
|
|
||||||
import farbot.game.GameState;
|
import farbot.game.GameState;
|
||||||
import farbot.game.Settings;
|
import farbot.game.Settings;
|
||||||
|
|
|
@ -1,29 +1,59 @@
|
||||||
package farbot.game;
|
package farbot.game;
|
||||||
|
|
||||||
import java.awt.Point;
|
import farbot.game.map.Point;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import farbot.game.map.GameMap;
|
import farbot.game.map.GameMap;
|
||||||
|
import farbot.game.map.Move;
|
||||||
import farbot.game.token.Bug;
|
import farbot.game.token.Bug;
|
||||||
import farbot.game.token.Code;
|
import farbot.game.token.Code;
|
||||||
import farbot.game.token.Mine;
|
import farbot.game.token.Mine;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manager for the GameState.
|
||||||
|
*
|
||||||
|
* Any data retrieved from GameState belongs to the caller.
|
||||||
|
*/
|
||||||
public class GameState {
|
public class GameState {
|
||||||
|
private Integer round;
|
||||||
|
|
||||||
private Player self;
|
private Player self;
|
||||||
private Player opponent;
|
private Player opponent;
|
||||||
private Integer round;
|
|
||||||
private GameMap map;
|
private GameMap map;
|
||||||
|
|
||||||
|
private boolean forked;
|
||||||
|
|
||||||
public GameState() {
|
public GameState() {
|
||||||
Settings s = Settings.getInstance();
|
this(new Player(new Point(0,0), Settings.getInstance().getSelfId()),
|
||||||
this.self = new Player(new Point(0,0), s.getSelfId());
|
new Player(new Point(0,0), Settings.getInstance().getOpponentId()),
|
||||||
this.opponent = new Player(new Point(0,0), s.getOpponentId());
|
new GameMap(),
|
||||||
this.map = new GameMap();
|
0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public GameState(Player self, Player opponent, Integer round) {
|
public GameState(Player self, Player opponent, GameMap map, Integer round) {
|
||||||
this.self = self;
|
this(self, opponent, map, round, false);
|
||||||
this.opponent = opponent;
|
}
|
||||||
|
|
||||||
|
protected GameState(Player self, Player opponent, GameMap map, Integer round, Boolean forked) {
|
||||||
|
this.self = forked ? self.clone(): self;
|
||||||
|
this.opponent = forked ? opponent.clone(): opponent;
|
||||||
this.round = round;
|
this.round = round;
|
||||||
|
this.map = map;
|
||||||
|
this.forked = forked;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<GameState> fork(Integer times) {
|
||||||
|
ArrayList<GameState> forks = new ArrayList<>();
|
||||||
|
for (int i=0; i<times; i++) forks.add(fork());
|
||||||
|
return forks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GameState fork() {
|
||||||
|
GameState fork = new GameState(self.clone(), opponent.clone(), map.fork(), round, true);
|
||||||
|
fork.map.setForked(true);
|
||||||
|
return fork;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void putToken(Bug bug) {
|
public void putToken(Bug bug) {
|
||||||
|
@ -43,32 +73,61 @@ public class GameState {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSnippets(String playerName, Integer snippets) {
|
public void setSnippets(String playerName, Integer snippets) {
|
||||||
getPlayer(playerName).setSnippets(snippets);
|
Settings s = Settings.getInstance();
|
||||||
|
if (playerName == s.getSelfName()) self.setSnippets(snippets);
|
||||||
|
else opponent.setSnippets(snippets);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getSelfSnippets() {
|
||||||
|
return self.getSnippets();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getOpponentSnippets() {
|
||||||
|
return opponent.getSnippets();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setBombs(String playerName, Integer bombs) {
|
public void setBombs(String playerName, Integer bombs) {
|
||||||
getPlayer(playerName).setBombs(bombs);
|
Settings s = Settings.getInstance();
|
||||||
|
if (playerName == s.getSelfName()) self.setBombs(bombs);
|
||||||
|
else opponent.setBombs(bombs);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPlayerPosition(Integer playerId, Point position) {
|
public void setPlayerPosition(Integer playerId, Point position) {
|
||||||
getPlayer(playerId).setPosition(position);
|
Settings s = Settings.getInstance();
|
||||||
|
if (playerId == s.getSelfId()) self.setPosition(position);
|
||||||
|
else opponent.setPosition(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Player getPlayer(String name) {
|
public Point getSelfPosition() {
|
||||||
Settings s = Settings.getInstance();
|
return self.getPosition();
|
||||||
if (name.equals(s.getSelfName())) return getSelf();
|
|
||||||
else return getOpponent();
|
|
||||||
}
|
}
|
||||||
public Player getPlayer(Integer id) {
|
|
||||||
Settings s = Settings.getInstance();
|
public MoveResult moveSelf(Point position) {
|
||||||
if (id == s.getSelfId()) return getSelf();
|
return makeMove(self, position);
|
||||||
else return getOpponent();
|
|
||||||
}
|
}
|
||||||
public Player getSelf() {
|
|
||||||
return self;
|
public MoveResult moveSelf(Move move) {
|
||||||
|
return makeMove(self, calcMovePoint(self.getPosition(), move));
|
||||||
}
|
}
|
||||||
public Player getOpponent() {
|
|
||||||
return opponent;
|
public MoveResult moveOpponent(Point position) {
|
||||||
|
return makeMove(opponent, position);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MoveResult moveOpponent(Move move) {
|
||||||
|
return makeMove(self, calcMovePoint(opponent.getPosition(), move));
|
||||||
|
}
|
||||||
|
|
||||||
|
private MoveResult makeMove(Player player, Point position) {
|
||||||
|
player.setPosition(position);
|
||||||
|
|
||||||
|
List<Code> codes = map.removeCodesAt(position);
|
||||||
|
List<Bug> bugs = map.removeBugsAt(position);
|
||||||
|
|
||||||
|
player.addSnippets(codes.size());
|
||||||
|
player.removeSnippets(bugs.size()*4);
|
||||||
|
|
||||||
|
return new MoveResult(player.clone(), codes.size(), bugs.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
public Integer getRound() {
|
public Integer getRound() {
|
||||||
|
@ -78,6 +137,30 @@ public class GameState {
|
||||||
this.round = round;
|
this.round = round;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isForked() {
|
||||||
|
return forked;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<Point> selfMovePoints(){
|
||||||
|
return map.validMovePoints(self.getPosition());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<Move> selfMoves(){
|
||||||
|
return map.validMoves(self.getPosition());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<Point> opponentMovePoints(){
|
||||||
|
return map.validMovePoints(opponent.getPosition());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<Move> opponentMoves(){
|
||||||
|
return map.validMoves(opponent.getPosition());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Point calcMovePoint(Point from, Move move) {
|
||||||
|
return map.calcMovePoint(from, move);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "GameState [self=" + self + ", opponent=" + opponent + ", round=" + round + ", map=" + map + "]";
|
return "GameState [self=" + self + ", opponent=" + opponent + ", round=" + round + ", map=" + map + "]";
|
||||||
|
|
27
farbot/src/farbot/game/MoveResult.java
Normal file
27
farbot/src/farbot/game/MoveResult.java
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
package farbot.game;
|
||||||
|
|
||||||
|
public class MoveResult {
|
||||||
|
private Player player;
|
||||||
|
private int killedBugs;
|
||||||
|
private int collectedCodes;
|
||||||
|
|
||||||
|
public MoveResult(Player player, int collectedCodes, int killedBugs) {
|
||||||
|
this.player = player;
|
||||||
|
this.killedBugs = killedBugs;
|
||||||
|
this.collectedCodes = collectedCodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Player getPlayer() {
|
||||||
|
return player;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getKilledBugs() {
|
||||||
|
return killedBugs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCollectedCodes() {
|
||||||
|
return collectedCodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -1,8 +1,8 @@
|
||||||
package farbot.game;
|
package farbot.game;
|
||||||
|
|
||||||
import java.awt.Point;
|
import farbot.game.map.Point;
|
||||||
|
|
||||||
public class Player {
|
public class Player implements Cloneable {
|
||||||
private Integer bombs;
|
private Integer bombs;
|
||||||
private Integer snippets;
|
private Integer snippets;
|
||||||
private Point position;
|
private Point position;
|
||||||
|
@ -31,6 +31,12 @@ public class Player {
|
||||||
protected void setSnippets(Integer snippets) {
|
protected void setSnippets(Integer snippets) {
|
||||||
this.snippets = snippets;
|
this.snippets = snippets;
|
||||||
}
|
}
|
||||||
|
protected void addSnippets(Integer snippets) {
|
||||||
|
this.snippets += snippets;
|
||||||
|
}
|
||||||
|
protected void removeSnippets(Integer snippets) {
|
||||||
|
this.snippets -= snippets;
|
||||||
|
}
|
||||||
public Point getPosition() {
|
public Point getPosition() {
|
||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
|
@ -46,4 +52,9 @@ public class Player {
|
||||||
protected void setId(Integer id) {
|
protected void setId(Integer id) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Player clone() {
|
||||||
|
return new Player(this.bombs, this.snippets, new Point(this.position), this.id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,31 +1,51 @@
|
||||||
package farbot.game.map;
|
package farbot.game.map;
|
||||||
|
|
||||||
import java.awt.Point;
|
import farbot.game.map.Point;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.EnumSet;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import farbot.game.Settings;
|
import farbot.game.Settings;
|
||||||
import farbot.game.token.Bug;
|
import farbot.game.token.Bug;
|
||||||
import farbot.game.token.Code;
|
import farbot.game.token.Code;
|
||||||
import farbot.game.token.Mine;
|
import farbot.game.token.Mine;
|
||||||
|
import farbot.game.token.Token;
|
||||||
|
|
||||||
public class GameMap {
|
/**
|
||||||
|
* Represents the game map. Can be safely used in forks
|
||||||
|
* after setting setForked(true): Makes GameMap lazily
|
||||||
|
* immutable (creates deep copies of compound types on
|
||||||
|
* modification only).
|
||||||
|
*
|
||||||
|
* Any data retrieved from GameMap belongs to the caller.
|
||||||
|
*/
|
||||||
|
public final class GameMap {
|
||||||
|
|
||||||
private static Field[][] base; // contains invariant elements
|
private static Field[][] base; // contains invariant elements
|
||||||
|
|
||||||
|
private boolean forked;
|
||||||
|
|
||||||
private List<Bug> bugs;
|
private List<Bug> bugs;
|
||||||
private Map<Point, List<Bug>> bugMap;
|
private Map<Point, List<Bug>> bugMap;
|
||||||
|
private boolean dirtyBugs;
|
||||||
|
|
||||||
private List<Code> codes;
|
private List<Code> codes;
|
||||||
private Map<Point, List<Code>> codeMap;
|
private Map<Point, List<Code>> codeMap;
|
||||||
|
private boolean dirtyCodes;
|
||||||
|
|
||||||
private List<Mine> mines;
|
private List<Mine> mines;
|
||||||
private Map<Point, List<Mine>> mineMap;
|
private Map<Point, List<Mine>> mineMap;
|
||||||
|
private boolean dirtyMines;
|
||||||
|
|
||||||
|
private Settings s;
|
||||||
|
|
||||||
public GameMap() {
|
public GameMap() {
|
||||||
Settings s = Settings.getInstance();
|
s = Settings.getInstance();
|
||||||
this.bugs = new ArrayList<>();
|
this.bugs = new ArrayList<>();
|
||||||
this.codes = new ArrayList<>();
|
this.codes = new ArrayList<>();
|
||||||
this.mines = new ArrayList<>();
|
this.mines = new ArrayList<>();
|
||||||
|
@ -34,23 +54,96 @@ public class GameMap {
|
||||||
this.codeMap = new HashMap<>();
|
this.codeMap = new HashMap<>();
|
||||||
this.mineMap = new HashMap<>();
|
this.mineMap = new HashMap<>();
|
||||||
|
|
||||||
|
this.setForked(false);
|
||||||
|
|
||||||
if(base == null) {
|
if(base == null) {
|
||||||
base = new Field[s.getFieldWidth()][s.getFieldHeight()];
|
base = new Field[s.getFieldWidth()][s.getFieldHeight()];
|
||||||
parseBase();
|
parseBase();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private GameMap(GameMap father) {
|
||||||
|
s = Settings.getInstance();
|
||||||
|
this.bugs = father.bugs;
|
||||||
|
this.codes = father.codes;
|
||||||
|
this.mines = father.mines;
|
||||||
|
|
||||||
|
this.bugMap = father.bugMap;
|
||||||
|
this.codeMap = father.codeMap;
|
||||||
|
this.mineMap = father.mineMap;
|
||||||
|
|
||||||
|
this.setForked(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Forks the father map. Forks are fast and
|
||||||
|
* lazily deep copies (i.e. create deep field
|
||||||
|
* copies only if needed on write access).
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public GameMap fork() {
|
||||||
|
return new GameMap(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<Move> validMoves(Point from) {
|
||||||
|
EnumSet<Move> moves;
|
||||||
|
|
||||||
|
switch(base[from.x][from.y]) {
|
||||||
|
case GATE_L:
|
||||||
|
case GATE_R:
|
||||||
|
moves = EnumSet.of(Move.LEFT, Move.RIGHT);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
moves = EnumSet.allOf(Move.class);
|
||||||
|
moves.removeIf( move -> from.x+move.x < 0
|
||||||
|
|| from.y+move.y < 0
|
||||||
|
|| from.x+move.x >= s.getFieldWidth()
|
||||||
|
|| from.y+move.y >= s.getFieldHeight()
|
||||||
|
|| base[from.x+move.x][from.y+move.y] == Field.WALL );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return moves;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<Point> validMovePoints(Point from){
|
||||||
|
return validMoves(from).stream()
|
||||||
|
.map(move -> calcMovePoint(from, move))
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Point calcMovePoint(Point from, Move move) {
|
||||||
|
return new Point(Math.floorMod(from.x+move.x, s.getFieldWidth()),
|
||||||
|
Math.floorMod(from.y+move.y, s.getFieldHeight()));
|
||||||
|
}
|
||||||
|
|
||||||
public void putToken(Bug bug) {
|
public void putToken(Bug bug) {
|
||||||
|
if(dirtyBugs) {
|
||||||
|
bugs = new ArrayList<>(bugs);
|
||||||
|
bugMap = new HashMap<>(bugMap);
|
||||||
|
dirtyBugs = false;
|
||||||
|
}
|
||||||
|
|
||||||
bugs.add(bug);
|
bugs.add(bug);
|
||||||
bugMap.computeIfAbsent(bug.getPosition(), k -> new ArrayList<>()).add(bug);
|
bugMap.computeIfAbsent(bug.getPosition(), k -> new ArrayList<>()).add(bug);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void putToken(Code code) {
|
public void putToken(Code code) {
|
||||||
|
if(dirtyCodes) {
|
||||||
|
codes = new ArrayList<>(codes);
|
||||||
|
codeMap = new HashMap<>(codeMap);
|
||||||
|
dirtyBugs = false;
|
||||||
|
}
|
||||||
codes.add(code);
|
codes.add(code);
|
||||||
codeMap.computeIfAbsent(code.getPosition(), k -> new ArrayList<>()).add(code);
|
codeMap.computeIfAbsent(code.getPosition(), k -> new ArrayList<>()).add(code);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void putToken(Mine mine) {
|
public void putToken(Mine mine) {
|
||||||
|
if(dirtyMines) {
|
||||||
|
mines = new ArrayList<>(mines);
|
||||||
|
mineMap = new HashMap<>(mineMap);
|
||||||
|
dirtyBugs = false;
|
||||||
|
}
|
||||||
mines.add(mine);
|
mines.add(mine);
|
||||||
mineMap.computeIfAbsent(mine.getPosition(), k -> new ArrayList<>()).add(mine);
|
mineMap.computeIfAbsent(mine.getPosition(), k -> new ArrayList<>()).add(mine);
|
||||||
}
|
}
|
||||||
|
@ -63,28 +156,42 @@ public class GameMap {
|
||||||
this.bugMap = new HashMap<>();
|
this.bugMap = new HashMap<>();
|
||||||
this.codeMap = new HashMap<>();
|
this.codeMap = new HashMap<>();
|
||||||
this.mineMap = new HashMap<>();
|
this.mineMap = new HashMap<>();
|
||||||
|
|
||||||
|
this.dirtyBugs = false;
|
||||||
|
this.dirtyCodes = false;
|
||||||
|
this.dirtyMines = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isForked() {
|
||||||
|
return forked;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setForked(boolean forked) {
|
||||||
|
this.forked = forked;
|
||||||
|
this.dirtyBugs = forked;
|
||||||
|
this.dirtyCodes = forked;
|
||||||
|
this.dirtyMines = forked;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void parseBase() {
|
private void parseBase() {
|
||||||
Settings s = Settings.getInstance();
|
|
||||||
assert(s.getFieldWidth() == 19);
|
assert(s.getFieldWidth() == 19);
|
||||||
assert(s.getFieldHeight() == 15);
|
assert(s.getFieldHeight() == 15);
|
||||||
|
|
||||||
String baseString = ".,.,.,x,.,.,.,.,.,.,.,.,.,.,.,x,.,.,.,"
|
String baseString = ".,.,.,x,.,.,.,.,.,.,.,.,.,.,.,x,.,.,.,"
|
||||||
+ ".,x,.,x,.,x,x,x,x,.,x,x,x,x,.,x,.,x,.,"
|
+ ".,x,.,x,.,x,x,x,x,.,x,x,x,x,.,x,.,x,.,"
|
||||||
+ ".,x,.,.,.,x,.,.,.,.,.,.,.,x,.,.,.,x,.,"
|
+ ".,x,.,.,.,x,.,.,.,.,.,.,.,x,.,.,.,x,.,"
|
||||||
+ ".,x,x,x,.,x,.,x,x,x,x,x,.,x,.,x,x,x,.,"
|
+ ".,x,x,x,.,x,.,x,x,x,x,x,.,x,.,x,x,x,.,"
|
||||||
+ ".,x,.,.,.,x,.,.,.,.,.,.,.,x,.,.,.,x,.,"
|
+ ".,x,.,.,.,x,.,.,.,.,.,.,.,x,.,.,.,x,.,"
|
||||||
+ ".,.,.,x,.,x,.,x,x,.,x,x,.,x,.,x,.,.,.,"
|
+ ".,.,.,x,.,x,.,x,x,.,x,x,.,x,.,x,.,.,.,"
|
||||||
+ "x,.,x,x,.,.,.,x,x,.,x,x,.,.,.,x,x,.,x,"
|
+ "x,.,x,x,.,.,.,x,x,.,x,x,.,.,.,x,x,.,x,"
|
||||||
+ "Gl,.,x,x,.,x,x,x,x,.,x,x,x,x,.,x,x,.,Gr,"
|
+ "Gl,.,x,x,.,x,x,x,x,.,x,x,x,x,.,x,x,.,Gr,"
|
||||||
+ "x,.,x,x,.,.,.,.,.,.,.,.,.,.,.,x,x,.,x,"
|
+ "x,.,x,x,.,.,.,.,.,.,.,.,.,.,.,x,x,.,x,"
|
||||||
+ ".,.,.,x,.,x,x,x,x,x,x,x,x,x,.,x,.,.,.,"
|
+ ".,.,.,x,.,x,x,x,x,x,x,x,x,x,.,x,.,.,.,"
|
||||||
+ ".,x,.,.,.,.,.,.,x,x,x,.,.,.,.,.,.,x,.,"
|
+ ".,x,.,.,.,.,.,.,x,x,x,.,.,.,.,.,.,x,.,"
|
||||||
+ ".,x,.,x,x,.,x,.,.,.,.,.,x,.,x,x,.,x,.,"
|
+ ".,x,.,x,x,.,x,.,.,.,.,.,x,.,x,x,.,x,.,"
|
||||||
+ ".,x,.,x,x,.,x,x,x,x,x,x,x,.,x,x,.,x,.,"
|
+ ".,x,.,x,x,.,x,x,x,x,x,x,x,.,x,x,.,x,.,"
|
||||||
+ ".,x,.,x,x,.,x,.,.,.,.,.,x,.,x,x,.,x,.,"
|
+ ".,x,.,x,x,.,x,.,.,.,.,.,x,.,x,x,.,x,.,"
|
||||||
+ ".,.,.,.,.,.,.,.,x,x,x,.,.,.,.,.,.,.,.";
|
+ ".,.,.,.,.,.,.,.,x,x,x,.,.,.,.,.,.,.,.";
|
||||||
|
|
||||||
String[] baseSplit = baseString.split(",");
|
String[] baseSplit = baseString.split(",");
|
||||||
|
|
||||||
|
@ -116,4 +223,81 @@ public class GameMap {
|
||||||
return "GameMap [bugs=" + bugs + ", bugMap=" + bugMap + ", codes=" + codes + ", codeMap=" + codeMap + ", mines="
|
return "GameMap [bugs=" + bugs + ", bugMap=" + bugMap + ", codes=" + codes + ", codeMap=" + codeMap + ", mines="
|
||||||
+ mines + ", mineMap=" + mineMap + "]";
|
+ mines + ", mineMap=" + mineMap + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<Bug> getBugs() {
|
||||||
|
return Collections.unmodifiableList(bugs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Bug> getBugsAt(Point position){
|
||||||
|
return Collections.unmodifiableList(bugMap.get(position));
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Bug> removeBugsAt(Point position) {
|
||||||
|
if(dirtyBugs && bugMap.containsKey(position)) {
|
||||||
|
bugs = new ArrayList<>(bugs);
|
||||||
|
bugMap = new HashMap<>(bugMap);
|
||||||
|
dirtyBugs = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Bug> rmBugs = bugMap.remove(position);
|
||||||
|
|
||||||
|
if(rmBugs != null) rmBugs.forEach(bugs::remove);
|
||||||
|
else rmBugs = new ArrayList<>();
|
||||||
|
|
||||||
|
return rmBugs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Code> getCodes() {
|
||||||
|
return Collections.unmodifiableList(codes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Code> getCodesAt(Point position){
|
||||||
|
return Collections.unmodifiableList(codeMap.get(position));
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Code> removeCodesAt(Point position){
|
||||||
|
if(dirtyCodes && codeMap.containsKey(position)) {
|
||||||
|
codes = new ArrayList<>(codes);
|
||||||
|
codeMap = new HashMap<>(codeMap);
|
||||||
|
dirtyCodes = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Code> rmCodes = codeMap.remove(position);
|
||||||
|
if(rmCodes != null) rmCodes.forEach(codes::remove);
|
||||||
|
else rmCodes = new ArrayList<>();
|
||||||
|
|
||||||
|
return rmCodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Mine> getMines() {
|
||||||
|
return Collections.unmodifiableList(mines);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Mine> getMinesAt(Point position){
|
||||||
|
return Collections.unmodifiableList(mineMap.get(position));
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Mine> removeMinesAt(Point position){
|
||||||
|
if(dirtyMines && mineMap.containsKey(position)) {
|
||||||
|
mines = new ArrayList<>(mines);
|
||||||
|
mineMap = new HashMap<>(mineMap);
|
||||||
|
dirtyMines = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Mine> rmMines = mineMap.remove(position);
|
||||||
|
|
||||||
|
if(rmMines != null) rmMines.forEach(mines::remove);
|
||||||
|
else rmMines = new ArrayList<>();
|
||||||
|
|
||||||
|
return rmMines;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Token> getTokensAt(Point position){
|
||||||
|
ArrayList<Token> tokens = new ArrayList<>();
|
||||||
|
tokens.addAll(getBugsAt(position));
|
||||||
|
tokens.addAll(getCodesAt(position));
|
||||||
|
tokens.addAll(getMinesAt(position));
|
||||||
|
|
||||||
|
return Collections.unmodifiableList(tokens);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
12
farbot/src/farbot/game/map/Move.java
Normal file
12
farbot/src/farbot/game/map/Move.java
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
package farbot.game.map;
|
||||||
|
|
||||||
|
public enum Move {
|
||||||
|
UP (0,-1),
|
||||||
|
DOWN (0,1),
|
||||||
|
LEFT (-1,0),
|
||||||
|
RIGHT (1,0);
|
||||||
|
|
||||||
|
protected final int x;
|
||||||
|
protected final int y;
|
||||||
|
Move(int x, int y) { this.x = x; this.y = y; }
|
||||||
|
}
|
17
farbot/src/farbot/game/map/Point.java
Normal file
17
farbot/src/farbot/game/map/Point.java
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
package farbot.game.map;
|
||||||
|
|
||||||
|
public class Point extends java.awt.Point{
|
||||||
|
|
||||||
|
private static final long serialVersionUID = -4718250851453184212L;
|
||||||
|
|
||||||
|
public Point() { super(); }
|
||||||
|
|
||||||
|
public Point(Point p) { super(p); }
|
||||||
|
|
||||||
|
public Point(int x, int y) { super(x,y); }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "(x=" + x + ",y=" + y + ")";
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,16 +7,37 @@ public class Bug extends Token {
|
||||||
|
|
||||||
private BugAI aiType;
|
private BugAI aiType;
|
||||||
|
|
||||||
|
public Bug(Bug bug) {
|
||||||
|
this(bug.position.x, bug.position.y, bug.aiType);
|
||||||
|
}
|
||||||
|
|
||||||
public Bug(int x, int y, BugAI ai) {
|
public Bug(int x, int y, BugAI ai) {
|
||||||
super(x,y);
|
super(x,y);
|
||||||
this.setAiType(ai);
|
this.aiType = ai;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BugAI getAiType() {
|
public BugAI getAiType() {
|
||||||
return aiType;
|
return aiType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAiType(BugAI aiType) {
|
@Override
|
||||||
this.aiType = aiType;
|
public int hashCode() {
|
||||||
|
final int prime = 31;
|
||||||
|
int result = super.hashCode();
|
||||||
|
result = prime * result + ((aiType == null) ? 0 : aiType.hashCode());
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj) return true;
|
||||||
|
if (!super.equals(obj)) return false;
|
||||||
|
if (getClass() != obj.getClass()) return false;
|
||||||
|
|
||||||
|
Bug other = (Bug) obj;
|
||||||
|
|
||||||
|
return aiType == other.aiType;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
package farbot.game.token;
|
package farbot.game.token;
|
||||||
|
|
||||||
public class Code extends Token {
|
public class Code extends Token {
|
||||||
|
public Code(Code code) {
|
||||||
|
this(code.position.x, code.position.y);
|
||||||
|
}
|
||||||
|
|
||||||
public Code(int x, int y) {
|
public Code(int x, int y) {
|
||||||
super(x, y);
|
super(x, y);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,25 +3,44 @@ package farbot.game.token;
|
||||||
public class Mine extends Token {
|
public class Mine extends Token {
|
||||||
private Integer timeToExplode;
|
private Integer timeToExplode;
|
||||||
|
|
||||||
|
public Mine(Mine mine) {
|
||||||
|
this(mine.position.x, mine.position.y, mine.timeToExplode);
|
||||||
|
}
|
||||||
|
|
||||||
public Mine(int x, int y) {
|
public Mine(int x, int y) {
|
||||||
this(x, y, -1);
|
this(x, y, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Mine(int x, int y, int timeToExplode) {
|
public Mine(int x, int y, int timeToExplode) {
|
||||||
super(x, y);
|
super(x, y);
|
||||||
this.setTimeToExplode(timeToExplode);
|
this.timeToExplode = timeToExplode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Integer getTimeToExplode() {
|
public Integer getTimeToExplode() {
|
||||||
return timeToExplode;
|
return timeToExplode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTimeToExplode(Integer timeToExplode) {
|
|
||||||
this.timeToExplode = timeToExplode;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Mine [timeToExplode=" + timeToExplode + ", getPosition()=" + getPosition() + "]";
|
return "Mine [timeToExplode=" + timeToExplode + ", getPosition()=" + getPosition() + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
final int prime = 31;
|
||||||
|
int result = super.hashCode();
|
||||||
|
result = prime * result + ((timeToExplode == null) ? 0 : timeToExplode.hashCode());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj) return true;
|
||||||
|
if (!super.equals(obj)) return false;
|
||||||
|
if (getClass() != obj.getClass()) return false;
|
||||||
|
|
||||||
|
Mine other = (Mine) obj;
|
||||||
|
|
||||||
|
return timeToExplode.equals(other.timeToExplode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
package farbot.game.token;
|
package farbot.game.token;
|
||||||
|
|
||||||
import java.awt.Point;
|
import farbot.game.map.Point;
|
||||||
|
|
||||||
public abstract class Token {
|
public abstract class Token {
|
||||||
private Point position;
|
Point position;
|
||||||
|
|
||||||
public Token(int x, int y) {
|
public Token(int x, int y) {
|
||||||
setPosition(x, y);
|
setPosition(x, y);
|
||||||
|
@ -20,4 +20,23 @@ public abstract class Token {
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Token [position=" + position + "]";
|
return "Token [position=" + position + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
final int prime = 31;
|
||||||
|
int result = 1;
|
||||||
|
result = prime * result + ((position == null) ? 0 : position.hashCode());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj) return true;
|
||||||
|
if (obj == null) return false;
|
||||||
|
if (getClass() != obj.getClass()) return false;
|
||||||
|
|
||||||
|
Token other = (Token) obj;
|
||||||
|
|
||||||
|
return position.equals(other.position);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
package io.riddles.hackman2.game;
|
package io.riddles.hackman2.game;
|
||||||
|
|
||||||
import java.awt.Point;
|
import farbot.game.map.Point;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* io.riddles.hackman2.game.board.Item - Created on 12-6-17
|
* io.riddles.hackman2.game.board.Item - Created on 12-6-17
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
package io.riddles.hackman2.game.board;
|
package io.riddles.hackman2.game.board;
|
||||||
|
|
||||||
import java.awt.Point;
|
import farbot.game.map.Point;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
package io.riddles.hackman2.game.enemy;
|
package io.riddles.hackman2.game.enemy;
|
||||||
|
|
||||||
import java.awt.Point;
|
import farbot.game.map.Point;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
import io.riddles.hackman2.game.board.HackMan2Board;
|
import io.riddles.hackman2.game.board.HackMan2Board;
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
package io.riddles.hackman2.game.item;
|
package io.riddles.hackman2.game.item;
|
||||||
|
|
||||||
import java.awt.Point;
|
import farbot.game.map.Point;
|
||||||
|
|
||||||
import io.riddles.hackman2.game.HackMan2Object;
|
import io.riddles.hackman2.game.HackMan2Object;
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
package io.riddles.hackman2.game.item;
|
package io.riddles.hackman2.game.item;
|
||||||
|
|
||||||
import java.awt.Point;
|
import farbot.game.map.Point;
|
||||||
|
|
||||||
import io.riddles.hackman2.game.HackMan2Object;
|
import io.riddles.hackman2.game.HackMan2Object;
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
package io.riddles.hackman2.game.move;
|
package io.riddles.hackman2.game.move;
|
||||||
|
|
||||||
import java.awt.Point;
|
import farbot.game.map.Point;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
package io.riddles.hackman2.game.processor;
|
package io.riddles.hackman2.game.processor;
|
||||||
|
|
||||||
import java.awt.Point;
|
import farbot.game.map.Point;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ package io.riddles.hackman2.game.board
|
||||||
import io.riddles.hackman2.game.item.Bomb
|
import io.riddles.hackman2.game.item.Bomb
|
||||||
import spock.lang.Specification
|
import spock.lang.Specification
|
||||||
|
|
||||||
import java.awt.Point
|
import farbot.game.map.Point
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* io.riddles.hackman2.game.board.HackMan2BoardSpec - Created on 13-6-17
|
* io.riddles.hackman2.game.board.HackMan2BoardSpec - Created on 13-6-17
|
||||||
|
@ -65,13 +65,13 @@ class HackMan2BoardSpec extends Specification {
|
||||||
ArrayList<String> explosions = board.explodeBombs()
|
ArrayList<String> explosions = board.explodeBombs()
|
||||||
|
|
||||||
then:
|
then:
|
||||||
explosions.toString() == "[java.awt.Point[x=0,y=0], java.awt.Point[x=1,y=0], " +
|
explosions.toString() == "[farbot.game.map.Point[x=0,y=0], farbot.game.map.Point[x=1,y=0], " +
|
||||||
"java.awt.Point[x=2,y=0], java.awt.Point[x=2,y=1], java.awt.Point[x=2,y=2], " +
|
"farbot.game.map.Point[x=2,y=0], farbot.game.map.Point[x=2,y=1], farbot.game.map.Point[x=2,y=2], " +
|
||||||
"java.awt.Point[x=3,y=2], java.awt.Point[x=4,y=2], java.awt.Point[x=0,y=1], " +
|
"farbot.game.map.Point[x=3,y=2], farbot.game.map.Point[x=4,y=2], farbot.game.map.Point[x=0,y=1], " +
|
||||||
"java.awt.Point[x=0,y=2], java.awt.Point[x=0,y=3], java.awt.Point[x=0,y=4], " +
|
"farbot.game.map.Point[x=0,y=2], farbot.game.map.Point[x=0,y=3], farbot.game.map.Point[x=0,y=4], " +
|
||||||
"java.awt.Point[x=0,y=5], java.awt.Point[x=18,y=0], java.awt.Point[x=18,y=1], " +
|
"farbot.game.map.Point[x=0,y=5], farbot.game.map.Point[x=18,y=0], farbot.game.map.Point[x=18,y=1], " +
|
||||||
"java.awt.Point[x=18,y=2], java.awt.Point[x=18,y=3], java.awt.Point[x=18,y=4], " +
|
"farbot.game.map.Point[x=18,y=2], farbot.game.map.Point[x=18,y=3], farbot.game.map.Point[x=18,y=4], " +
|
||||||
"java.awt.Point[x=18,y=5], java.awt.Point[x=17,y=0], java.awt.Point[x=16,y=0]]"
|
"farbot.game.map.Point[x=18,y=5], farbot.game.map.Point[x=17,y=0], farbot.game.map.Point[x=16,y=0]]"
|
||||||
board.getBombs().size() == 1
|
board.getBombs().size() == 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
1
javainterface
Submodule
1
javainterface
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 1628e73ebddad23d96ce07ea0d49cf1a955d3f93
|
Loading…
Reference in a new issue