From a0ced36a12527d2a0885fa1d4f37171c4ec21ec0 Mon Sep 17 00:00:00 2001 From: armin Date: Mon, 8 Jan 2018 23:11:28 +0100 Subject: [PATCH] GameTree based AI Implemented the first version of a GameTree based AI. Comparable to best Scala version, but a little weaker still. --- farbot/src/farbot/FarbotIO.java | 8 +- farbot/src/farbot/ai/AI.java | 68 ++++- farbot/src/farbot/ai/GameTree.java | 83 ++++++ farbot/src/farbot/ai/Parser.java | 2 +- farbot/src/farbot/game/GameState.java | 147 ++++++++--- farbot/src/farbot/game/MoveResult.java | 27 ++ farbot/src/farbot/game/Player.java | 15 +- farbot/src/farbot/game/map/GameMap.java | 244 +++++++++++++++--- farbot/src/farbot/game/map/Move.java | 12 + farbot/src/farbot/game/map/Point.java | 17 ++ farbot/src/farbot/game/token/Bug.java | 27 +- farbot/src/farbot/game/token/Code.java | 4 + farbot/src/farbot/game/token/Mine.java | 29 ++- farbot/src/farbot/game/token/Token.java | 23 +- .../riddles/hackman2/game/HackMan2Object.java | 2 +- .../hackman2/game/board/HackMan2Board.java | 2 +- .../riddles/hackman2/game/enemy/ChaseAI.java | 2 +- .../io/riddles/hackman2/game/item/Bomb.java | 2 +- .../riddles/hackman2/game/item/Snippet.java | 2 +- .../riddles/hackman2/game/move/MoveType.java | 2 +- .../game/processor/HackMan2Processor.java | 2 +- .../game/board/HackMan2BoardSpec.groovy | 16 +- javainterface | 1 + 23 files changed, 642 insertions(+), 95 deletions(-) create mode 100644 farbot/src/farbot/ai/GameTree.java create mode 100644 farbot/src/farbot/game/MoveResult.java create mode 100644 farbot/src/farbot/game/map/Move.java create mode 100644 farbot/src/farbot/game/map/Point.java create mode 160000 javainterface diff --git a/farbot/src/farbot/FarbotIO.java b/farbot/src/farbot/FarbotIO.java index 5694a8c..0a7a99d 100644 --- a/farbot/src/farbot/FarbotIO.java +++ b/farbot/src/farbot/FarbotIO.java @@ -45,13 +45,17 @@ public class FarbotIO { } private static void out(String out) { - log(out); + logln(out); System.out.println(out); } - public static void log(String log) { + public static void logln(String log) { GameState currentState = ai.getCurrentState(); String prefix = String.format("[%3d]: ", currentState.getRound()); System.err.println(prefix+log); } + + public static void log(String log) { + System.err.print(log); + } } diff --git a/farbot/src/farbot/ai/AI.java b/farbot/src/farbot/ai/AI.java index e96885f..09a40c8 100644 --- a/farbot/src/farbot/ai/AI.java +++ b/farbot/src/farbot/ai/AI.java @@ -1,25 +1,87 @@ package farbot.ai; -import farbot.FarbotIO; +import java.util.ArrayList; +import java.util.Set; + import farbot.game.GameState; +import farbot.game.MoveResult; +import farbot.game.map.Move; + +import static farbot.FarbotIO.logln; public class AI { private GameState currentState; + private int treeDepth = 20; + + private MoveValue lastMove; public AI() { this.currentState = new GameState(); } public String calcMove(Integer time) { - return "up"; + logln("Calculating move in "+time+"ms"); + Set validMoves = currentState.selfMoves(); + logln("Valid moves: "+validMoves.toString()); + + ArrayList 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) { Parser.parse(update, currentState); - FarbotIO.log(currentState.toString()); } public GameState getCurrentState() { return currentState; } + + private class MoveValue { + private Move move; + private Double value; + + private MoveValue(Move move, Double value) { + this.move = move; + this.value = value; + } + } } diff --git a/farbot/src/farbot/ai/GameTree.java b/farbot/src/farbot/ai/GameTree.java new file mode 100644 index 0000000..a2ad1d9 --- /dev/null +++ b/farbot/src/farbot/ai/GameTree.java @@ -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 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 children = makeChildren(node, this, level); + + while(level > 0) { + level--; + + Queue 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 makeChildren(GameState state, GameTree gtRoot, int level) { + Set selfMoves = state.selfMovePoints(); + selfMoves.removeAll(gtRoot.visited); + LinkedList 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; + } +} diff --git a/farbot/src/farbot/ai/Parser.java b/farbot/src/farbot/ai/Parser.java index ffe5f67..35a31e6 100644 --- a/farbot/src/farbot/ai/Parser.java +++ b/farbot/src/farbot/ai/Parser.java @@ -1,6 +1,6 @@ package farbot.ai; -import java.awt.Point; +import farbot.game.map.Point; import farbot.game.GameState; import farbot.game.Settings; diff --git a/farbot/src/farbot/game/GameState.java b/farbot/src/farbot/game/GameState.java index d92e8c6..21d70d0 100644 --- a/farbot/src/farbot/game/GameState.java +++ b/farbot/src/farbot/game/GameState.java @@ -1,76 +1,135 @@ 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.Move; import farbot.game.token.Bug; import farbot.game.token.Code; import farbot.game.token.Mine; +/** + * Manager for the GameState. + * + * Any data retrieved from GameState belongs to the caller. + */ public class GameState { + private Integer round; + private Player self; private Player opponent; - private Integer round; private GameMap map; - + + private boolean forked; + public GameState() { - Settings s = Settings.getInstance(); - this.self = new Player(new Point(0,0), s.getSelfId()); - this.opponent = new Player(new Point(0,0), s.getOpponentId()); - this.map = new GameMap(); + this(new Player(new Point(0,0), Settings.getInstance().getSelfId()), + new Player(new Point(0,0), Settings.getInstance().getOpponentId()), + new GameMap(), + 0); + } + + public GameState(Player self, Player opponent, GameMap map, Integer round) { + this(self, opponent, map, round, false); } - public GameState(Player self, Player opponent, Integer round) { - this.self = self; - 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.map = map; + this.forked = forked; + } + + public List fork(Integer times) { + ArrayList forks = new ArrayList<>(); + for (int i=0; i codes = map.removeCodesAt(position); + List 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() { return round; } @@ -78,6 +137,30 @@ public class GameState { this.round = round; } + public boolean isForked() { + return forked; + } + + public Set selfMovePoints(){ + return map.validMovePoints(self.getPosition()); + } + + public Set selfMoves(){ + return map.validMoves(self.getPosition()); + } + + public Set opponentMovePoints(){ + return map.validMovePoints(opponent.getPosition()); + } + + public Set opponentMoves(){ + return map.validMoves(opponent.getPosition()); + } + + public Point calcMovePoint(Point from, Move move) { + return map.calcMovePoint(from, move); + } + @Override public String toString() { return "GameState [self=" + self + ", opponent=" + opponent + ", round=" + round + ", map=" + map + "]"; diff --git a/farbot/src/farbot/game/MoveResult.java b/farbot/src/farbot/game/MoveResult.java new file mode 100644 index 0000000..59821df --- /dev/null +++ b/farbot/src/farbot/game/MoveResult.java @@ -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; + } + + +} diff --git a/farbot/src/farbot/game/Player.java b/farbot/src/farbot/game/Player.java index d66a792..42577f3 100644 --- a/farbot/src/farbot/game/Player.java +++ b/farbot/src/farbot/game/Player.java @@ -1,8 +1,8 @@ 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 snippets; private Point position; @@ -31,6 +31,12 @@ public class Player { protected void setSnippets(Integer snippets) { this.snippets = snippets; } + protected void addSnippets(Integer snippets) { + this.snippets += snippets; + } + protected void removeSnippets(Integer snippets) { + this.snippets -= snippets; + } public Point getPosition() { return position; } @@ -46,4 +52,9 @@ public class Player { protected void setId(Integer id) { this.id = id; } + + @Override + public Player clone() { + return new Player(this.bombs, this.snippets, new Point(this.position), this.id); + } } diff --git a/farbot/src/farbot/game/map/GameMap.java b/farbot/src/farbot/game/map/GameMap.java index 726b8ce..abdc150 100644 --- a/farbot/src/farbot/game/map/GameMap.java +++ b/farbot/src/farbot/game/map/GameMap.java @@ -1,93 +1,200 @@ package farbot.game.map; -import java.awt.Point; +import farbot.game.map.Point; import java.util.ArrayList; +import java.util.Collections; +import java.util.EnumSet; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; import farbot.game.Settings; import farbot.game.token.Bug; import farbot.game.token.Code; import farbot.game.token.Mine; +import farbot.game.token.Token; + +/** + * 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 { -public class GameMap { - private static Field[][] base; // contains invariant elements + + private boolean forked; private List bugs; private Map> bugMap; - + private boolean dirtyBugs; + private List codes; private Map> codeMap; - + private boolean dirtyCodes; + private List mines; private Map> mineMap; + private boolean dirtyMines; + private Settings s; + public GameMap() { - Settings s = Settings.getInstance(); + s = Settings.getInstance(); this.bugs = new ArrayList<>(); this.codes = new ArrayList<>(); this.mines = new ArrayList<>(); - + this.bugMap = new HashMap<>(); this.codeMap = new HashMap<>(); this.mineMap = new HashMap<>(); + this.setForked(false); + if(base == null) { base = new Field[s.getFieldWidth()][s.getFieldHeight()]; 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 validMoves(Point from) { + EnumSet 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 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) { + if(dirtyBugs) { + bugs = new ArrayList<>(bugs); + bugMap = new HashMap<>(bugMap); + dirtyBugs = false; + } + bugs.add(bug); bugMap.computeIfAbsent(bug.getPosition(), k -> new ArrayList<>()).add(bug); } - + public void putToken(Code code) { + if(dirtyCodes) { + codes = new ArrayList<>(codes); + codeMap = new HashMap<>(codeMap); + dirtyBugs = false; + } codes.add(code); codeMap.computeIfAbsent(code.getPosition(), k -> new ArrayList<>()).add(code); } - + public void putToken(Mine mine) { + if(dirtyMines) { + mines = new ArrayList<>(mines); + mineMap = new HashMap<>(mineMap); + dirtyBugs = false; + } mines.add(mine); mineMap.computeIfAbsent(mine.getPosition(), k -> new ArrayList<>()).add(mine); } - + public void clearTokens() { this.bugs = new ArrayList<>(); this.codes = new ArrayList<>(); this.mines = new ArrayList<>(); - + this.bugMap = new HashMap<>(); this.codeMap = 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() { - Settings s = Settings.getInstance(); assert(s.getFieldWidth() == 19); assert(s.getFieldHeight() == 15); - + 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," - + "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," + + "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,.,.,.,.,.,.,.,."; + String[] baseSplit = baseString.split(","); - + for (int i = 0; i < 19; i++) { for (int j = 0; j < 15; j++) { String b = baseSplit[i+(s.getFieldWidth()*j)]; @@ -116,4 +223,81 @@ public class GameMap { return "GameMap [bugs=" + bugs + ", bugMap=" + bugMap + ", codes=" + codes + ", codeMap=" + codeMap + ", mines=" + mines + ", mineMap=" + mineMap + "]"; } + + public List getBugs() { + return Collections.unmodifiableList(bugs); + } + + public List getBugsAt(Point position){ + return Collections.unmodifiableList(bugMap.get(position)); + } + + public List removeBugsAt(Point position) { + if(dirtyBugs && bugMap.containsKey(position)) { + bugs = new ArrayList<>(bugs); + bugMap = new HashMap<>(bugMap); + dirtyBugs = false; + } + + List rmBugs = bugMap.remove(position); + + if(rmBugs != null) rmBugs.forEach(bugs::remove); + else rmBugs = new ArrayList<>(); + + return rmBugs; + } + + public List getCodes() { + return Collections.unmodifiableList(codes); + } + + public List getCodesAt(Point position){ + return Collections.unmodifiableList(codeMap.get(position)); + } + + public List removeCodesAt(Point position){ + if(dirtyCodes && codeMap.containsKey(position)) { + codes = new ArrayList<>(codes); + codeMap = new HashMap<>(codeMap); + dirtyCodes = false; + } + + List rmCodes = codeMap.remove(position); + if(rmCodes != null) rmCodes.forEach(codes::remove); + else rmCodes = new ArrayList<>(); + + return rmCodes; + } + + public List getMines() { + return Collections.unmodifiableList(mines); + } + + public List getMinesAt(Point position){ + return Collections.unmodifiableList(mineMap.get(position)); + } + + public List removeMinesAt(Point position){ + if(dirtyMines && mineMap.containsKey(position)) { + mines = new ArrayList<>(mines); + mineMap = new HashMap<>(mineMap); + dirtyMines = false; + } + + List rmMines = mineMap.remove(position); + + if(rmMines != null) rmMines.forEach(mines::remove); + else rmMines = new ArrayList<>(); + + return rmMines; + } + + public List getTokensAt(Point position){ + ArrayList tokens = new ArrayList<>(); + tokens.addAll(getBugsAt(position)); + tokens.addAll(getCodesAt(position)); + tokens.addAll(getMinesAt(position)); + + return Collections.unmodifiableList(tokens); + } } diff --git a/farbot/src/farbot/game/map/Move.java b/farbot/src/farbot/game/map/Move.java new file mode 100644 index 0000000..0f2f065 --- /dev/null +++ b/farbot/src/farbot/game/map/Move.java @@ -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; } +} diff --git a/farbot/src/farbot/game/map/Point.java b/farbot/src/farbot/game/map/Point.java new file mode 100644 index 0000000..c55ebf6 --- /dev/null +++ b/farbot/src/farbot/game/map/Point.java @@ -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 + ")"; + } +} diff --git a/farbot/src/farbot/game/token/Bug.java b/farbot/src/farbot/game/token/Bug.java index 95445b4..8ace9c9 100644 --- a/farbot/src/farbot/game/token/Bug.java +++ b/farbot/src/farbot/game/token/Bug.java @@ -7,16 +7,37 @@ public class Bug extends Token { private BugAI aiType; + public Bug(Bug bug) { + this(bug.position.x, bug.position.y, bug.aiType); + } + public Bug(int x, int y, BugAI ai) { super(x,y); - this.setAiType(ai); + this.aiType = ai; } public BugAI getAiType() { return aiType; } - public void setAiType(BugAI aiType) { - this.aiType = aiType; + @Override + 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; + } + + } diff --git a/farbot/src/farbot/game/token/Code.java b/farbot/src/farbot/game/token/Code.java index d159ae7..4bd99c3 100644 --- a/farbot/src/farbot/game/token/Code.java +++ b/farbot/src/farbot/game/token/Code.java @@ -1,6 +1,10 @@ package farbot.game.token; public class Code extends Token { + public Code(Code code) { + this(code.position.x, code.position.y); + } + public Code(int x, int y) { super(x, y); } diff --git a/farbot/src/farbot/game/token/Mine.java b/farbot/src/farbot/game/token/Mine.java index a3b9110..10fa5c5 100644 --- a/farbot/src/farbot/game/token/Mine.java +++ b/farbot/src/farbot/game/token/Mine.java @@ -3,25 +3,44 @@ package farbot.game.token; public class Mine extends Token { private Integer timeToExplode; + public Mine(Mine mine) { + this(mine.position.x, mine.position.y, mine.timeToExplode); + } + public Mine(int x, int y) { this(x, y, -1); } public Mine(int x, int y, int timeToExplode) { super(x, y); - this.setTimeToExplode(timeToExplode); + this.timeToExplode = timeToExplode; } public Integer getTimeToExplode() { return timeToExplode; } - public void setTimeToExplode(Integer timeToExplode) { - this.timeToExplode = timeToExplode; - } - @Override public String toString() { 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); + } } diff --git a/farbot/src/farbot/game/token/Token.java b/farbot/src/farbot/game/token/Token.java index c6ea1b2..348e2d2 100644 --- a/farbot/src/farbot/game/token/Token.java +++ b/farbot/src/farbot/game/token/Token.java @@ -1,9 +1,9 @@ package farbot.game.token; -import java.awt.Point; +import farbot.game.map.Point; public abstract class Token { - private Point position; + Point position; public Token(int x, int y) { setPosition(x, y); @@ -20,4 +20,23 @@ public abstract class Token { public String toString() { 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); + } } diff --git a/hack-man-2-engine-development/src/java/io/riddles/hackman2/game/HackMan2Object.java b/hack-man-2-engine-development/src/java/io/riddles/hackman2/game/HackMan2Object.java index 07e9c04..5fb9661 100644 --- a/hack-man-2-engine-development/src/java/io/riddles/hackman2/game/HackMan2Object.java +++ b/hack-man-2-engine-development/src/java/io/riddles/hackman2/game/HackMan2Object.java @@ -19,7 +19,7 @@ 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 diff --git a/hack-man-2-engine-development/src/java/io/riddles/hackman2/game/board/HackMan2Board.java b/hack-man-2-engine-development/src/java/io/riddles/hackman2/game/board/HackMan2Board.java index 56cd177..1515af7 100644 --- a/hack-man-2-engine-development/src/java/io/riddles/hackman2/game/board/HackMan2Board.java +++ b/hack-man-2-engine-development/src/java/io/riddles/hackman2/game/board/HackMan2Board.java @@ -19,7 +19,7 @@ package io.riddles.hackman2.game.board; -import java.awt.Point; +import farbot.game.map.Point; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; diff --git a/hack-man-2-engine-development/src/java/io/riddles/hackman2/game/enemy/ChaseAI.java b/hack-man-2-engine-development/src/java/io/riddles/hackman2/game/enemy/ChaseAI.java index d57befd..21818a7 100644 --- a/hack-man-2-engine-development/src/java/io/riddles/hackman2/game/enemy/ChaseAI.java +++ b/hack-man-2-engine-development/src/java/io/riddles/hackman2/game/enemy/ChaseAI.java @@ -19,7 +19,7 @@ package io.riddles.hackman2.game.enemy; -import java.awt.Point; +import farbot.game.map.Point; import java.util.ArrayList; import io.riddles.hackman2.game.board.HackMan2Board; diff --git a/hack-man-2-engine-development/src/java/io/riddles/hackman2/game/item/Bomb.java b/hack-man-2-engine-development/src/java/io/riddles/hackman2/game/item/Bomb.java index 60d3f73..004bd5b 100644 --- a/hack-man-2-engine-development/src/java/io/riddles/hackman2/game/item/Bomb.java +++ b/hack-man-2-engine-development/src/java/io/riddles/hackman2/game/item/Bomb.java @@ -19,7 +19,7 @@ package io.riddles.hackman2.game.item; -import java.awt.Point; +import farbot.game.map.Point; import io.riddles.hackman2.game.HackMan2Object; diff --git a/hack-man-2-engine-development/src/java/io/riddles/hackman2/game/item/Snippet.java b/hack-man-2-engine-development/src/java/io/riddles/hackman2/game/item/Snippet.java index 750350b..ab10e27 100644 --- a/hack-man-2-engine-development/src/java/io/riddles/hackman2/game/item/Snippet.java +++ b/hack-man-2-engine-development/src/java/io/riddles/hackman2/game/item/Snippet.java @@ -19,7 +19,7 @@ package io.riddles.hackman2.game.item; -import java.awt.Point; +import farbot.game.map.Point; import io.riddles.hackman2.game.HackMan2Object; diff --git a/hack-man-2-engine-development/src/java/io/riddles/hackman2/game/move/MoveType.java b/hack-man-2-engine-development/src/java/io/riddles/hackman2/game/move/MoveType.java index 8848619..af9df27 100644 --- a/hack-man-2-engine-development/src/java/io/riddles/hackman2/game/move/MoveType.java +++ b/hack-man-2-engine-development/src/java/io/riddles/hackman2/game/move/MoveType.java @@ -19,7 +19,7 @@ package io.riddles.hackman2.game.move; -import java.awt.Point; +import farbot.game.map.Point; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; diff --git a/hack-man-2-engine-development/src/java/io/riddles/hackman2/game/processor/HackMan2Processor.java b/hack-man-2-engine-development/src/java/io/riddles/hackman2/game/processor/HackMan2Processor.java index cc75d07..a5ec822 100644 --- a/hack-man-2-engine-development/src/java/io/riddles/hackman2/game/processor/HackMan2Processor.java +++ b/hack-man-2-engine-development/src/java/io/riddles/hackman2/game/processor/HackMan2Processor.java @@ -19,7 +19,7 @@ package io.riddles.hackman2.game.processor; -import java.awt.Point; +import farbot.game.map.Point; import java.util.ArrayList; import java.util.Comparator; diff --git a/hack-man-2-engine-development/test/groovy/io/riddles/hackman2/game/board/HackMan2BoardSpec.groovy b/hack-man-2-engine-development/test/groovy/io/riddles/hackman2/game/board/HackMan2BoardSpec.groovy index c8ae323..829105a 100644 --- a/hack-man-2-engine-development/test/groovy/io/riddles/hackman2/game/board/HackMan2BoardSpec.groovy +++ b/hack-man-2-engine-development/test/groovy/io/riddles/hackman2/game/board/HackMan2BoardSpec.groovy @@ -22,7 +22,7 @@ package io.riddles.hackman2.game.board import io.riddles.hackman2.game.item.Bomb import spock.lang.Specification -import java.awt.Point +import farbot.game.map.Point /** * io.riddles.hackman2.game.board.HackMan2BoardSpec - Created on 13-6-17 @@ -65,13 +65,13 @@ class HackMan2BoardSpec extends Specification { ArrayList explosions = board.explodeBombs() then: - explosions.toString() == "[java.awt.Point[x=0,y=0], java.awt.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], " + - "java.awt.Point[x=3,y=2], java.awt.Point[x=4,y=2], java.awt.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], " + - "java.awt.Point[x=0,y=5], java.awt.Point[x=18,y=0], java.awt.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], " + - "java.awt.Point[x=18,y=5], java.awt.Point[x=17,y=0], java.awt.Point[x=16,y=0]]" + explosions.toString() == "[farbot.game.map.Point[x=0,y=0], farbot.game.map.Point[x=1,y=0], " + + "farbot.game.map.Point[x=2,y=0], farbot.game.map.Point[x=2,y=1], farbot.game.map.Point[x=2,y=2], " + + "farbot.game.map.Point[x=3,y=2], farbot.game.map.Point[x=4,y=2], farbot.game.map.Point[x=0,y=1], " + + "farbot.game.map.Point[x=0,y=2], farbot.game.map.Point[x=0,y=3], farbot.game.map.Point[x=0,y=4], " + + "farbot.game.map.Point[x=0,y=5], farbot.game.map.Point[x=18,y=0], farbot.game.map.Point[x=18,y=1], " + + "farbot.game.map.Point[x=18,y=2], farbot.game.map.Point[x=18,y=3], farbot.game.map.Point[x=18,y=4], " + + "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 } } diff --git a/javainterface b/javainterface new file mode 160000 index 0000000..1628e73 --- /dev/null +++ b/javainterface @@ -0,0 +1 @@ +Subproject commit 1628e73ebddad23d96ce07ea0d49cf1a955d3f93