This commit is contained in:
2018-05-20 04:23:22 +02:00
parent 4a1a48e1fe
commit 5236d4f0d6
13 changed files with 225 additions and 173 deletions

View File

@@ -76,7 +76,7 @@ public class Facade implements IFacade {
try { try {
worm.move(); worm.move();
} catch(IllegalArgumentException e) { } catch(IllegalArgumentException | IllegalStateException e) {
throw new ModelException(e); throw new ModelException(e);
} }
} }
@@ -192,7 +192,11 @@ public class Facade implements IFacade {
*/ */
@Override @Override
public void jump(Worm worm, double timeStep) throws ModelException { public void jump(Worm worm, double timeStep) throws ModelException {
try {
worm.jump(); worm.jump();
} catch (IllegalStateException e) {
throw new ModelException(e);
}
} }
/** /**
@@ -898,7 +902,7 @@ public class Facade implements IFacade {
try { try {
worm.setName(newName); worm.setName(newName);
} }
catch(IllegalNameException e) { catch(IllegalNameException | IllegalArgumentException e) {
throw new ModelException(e); throw new ModelException(e);
} }
} }
@@ -992,7 +996,7 @@ public class Facade implements IFacade {
public void addWormsToTeam(Team team, Worm... worms) throws ModelException, MustNotImplementException { public void addWormsToTeam(Team team, Worm... worms) throws ModelException, MustNotImplementException {
try { try {
team.addWorm(worms); team.addWorm(worms);
} catch(IllegalArgumentException e) { } catch(IllegalArgumentException | IllegalStateException e) {
throw new ModelException(e); throw new ModelException(e);
} }
} }
@@ -1090,6 +1094,10 @@ public class Facade implements IFacade {
*/ */
@Override @Override
public void castSpell(World world) throws ModelException { public void castSpell(World world) throws ModelException {
try {
world.castSpell(); world.castSpell();
} catch (IllegalStateException e) {
throw new ModelException(e);
}
} }
} }

View File

@@ -42,10 +42,12 @@ public abstract class GameObject {
* |setRadius(radius) * |setRadius(radius)
*/ */
protected GameObject(World world, double[] location, double radius) { protected GameObject(World world, double[] location, double radius) {
if (!isValidLocation(Coordinate.create(location))) throw new IllegalArgumentException("Illegal location");
setLocation(location); setLocation(location);
setRadius(radius); setRadius(radius);
setWorld(world);
if (isValidWorld(world)) world.add(this); if (isValidWorld(world)) world.add(this);
setWorld(world);
} }
/** /**
@@ -62,8 +64,8 @@ public abstract class GameObject {
* |setRadius(radius) * |setRadius(radius)
*/ */
protected GameObject(World world, Coordinate location, double radius) { protected GameObject(World world, Coordinate location, double radius) {
setWorld(world);
world.add(this); world.add(this);
setWorld(world);
setLocation(location); setLocation(location);
setRadius(radius); setRadius(radius);
} }
@@ -139,7 +141,14 @@ public abstract class GameObject {
*/ */
protected void setLocation(Coordinate location) throws IllegalArgumentException { protected void setLocation(Coordinate location) throws IllegalArgumentException {
if (!isValidLocation(location)) throw new IllegalArgumentException(); if (!isValidLocation(location)) {
if (!(location.getX() - radius < 0) ||
!(location.getX() + radius > getWorld().getWidth()) ||
!(location.getY() + radius > getWorld().getHeight()) ||
!(location.getY() - radius < 0)) {
world.remove(this);
} else throw new IllegalArgumentException();
}
this.location = location; this.location = location;
} }
@@ -223,8 +232,7 @@ public abstract class GameObject {
!(location.getX() - radius < 0) && !(location.getX() - radius < 0) &&
!(location.getX() + radius > getWorld().getWidth()) && !(location.getX() + radius > getWorld().getWidth()) &&
!(location.getY() + radius > getWorld().getHeight()) && !(location.getY() + radius > getWorld().getHeight()) &&
!(location.getY() - radius < 0 && !(location.getY() - radius < 0) && getWorld().isPassable(location);
!getWorld().isPassable(location));
} }
/** /**
@@ -252,16 +260,18 @@ public abstract class GameObject {
Coordinate otherLocation = o.getLocation(); Coordinate otherLocation = o.getLocation();
return Math.sqrt(Math.pow((otherLocation.getX() - location.getX()), 2) + Math.pow((otherLocation.getY() - location.getY()), 2)); return Math.sqrt(Math.pow((otherLocation.getX() - location.getX()), 2) + Math.pow((otherLocation.getY() - location.getY()), 2)) - o.getRadius() - getRadius();
} }
public double getAngle(GameObject o) { public double getAngle(GameObject o) {
if (o.equals(this)) return Double.NaN;
double x1 = getLocation().getX(); double x1 = getLocation().getX();
double y1 = getLocation().getY(); double y1 = getLocation().getY();
double x2 = o.getLocation().getX(); double x2 = o.getLocation().getX();
double y2 = o.getLocation().getY(); double y2 = o.getLocation().getY();
return Math.atan(Math.abs(x1 - x2) / Math.abs(y1 - y2)); return Math.abs(Math.atan(Math.abs(x1 - x2) / Math.abs(y1 - y2)) - Math.PI / 2.0);
} }
} }

View File

@@ -1,7 +1,6 @@
package worms.model; package worms.model;
import worms.internal.gui.game.IActionHandler; import worms.internal.gui.game.IActionHandler;
import worms.programs.ArgumentExpression;
import worms.programs.Expression; import worms.programs.Expression;
import worms.programs.Procedure; import worms.programs.Procedure;
import worms.programs.Statement; import worms.programs.Statement;
@@ -14,9 +13,15 @@ import static java.lang.Math.toDegrees;
public class Program { public class Program {
private final Map<String, Statement> procMap; private final Map<String, Statement> procMap;
private final Map<String, Expression> varMap = new HashMap<>(); private final Map<String, Object> varMap = new HashMap<>();
private final List<Object> printList = new ArrayList<>(); private final List<Object> printList = new ArrayList<>();
private Stack<Statement.Type> currentType = new Stack<>();
private int inLoop = 0;
private int inProcedure = 0;
private boolean breakProcedure = false;
private boolean enoughAP = true; private boolean enoughAP = true;
private IActionHandler actionHandler; private IActionHandler actionHandler;
@@ -36,19 +41,35 @@ public class Program {
// reset everything // reset everything
enoughAP = true; enoughAP = true;
if (iteratorStack.empty()) { if (callStack.empty()) {
executeStatement(main); executeStatement(main);
} else { } else {
executeStatement(lastStatement); while (!callStack.empty()) {
while (!iteratorStack.empty()) { CallStackNode node = callStack.pop();
Iterator<Statement> it = iteratorStack.pop();
while(node.statementIterator == null && !callStack.empty()) {
executeStatement(node.lastStatement);
if (!enoughAP) break;
node = callStack.pop();
}
callStack.push(node);
if (node.statementIterator == null) {
executeStatement(node.lastStatement);
} else {
Iterator<Statement> it = node.statementIterator;
if (!enoughAP) break;
while (it.hasNext()) { while (it.hasNext()) {
executeStatement(it.next()); Statement current = it.next();
executeStatement(current);
if (!enoughAP) { if (!enoughAP) {
iteratorStack.push(it); node.lastStatement = current;
break; break;
} }
} }
if (!it.hasNext() && enoughAP) callStack.pop();
}
if (!enoughAP) break; if (!enoughAP) break;
} }
} }
@@ -59,13 +80,13 @@ public class Program {
execute(worm); execute(worm);
if (!enoughAP) return null; if (!enoughAP) return null;
iteratorStack.clear(); callStack.clear();
return printList; return printList;
} }
private boolean breakLoop = false; private boolean breakLoop = false;
@SuppressWarnings("unchecked") @SuppressWarnings({"unchecked", "SuspiciousMethodCalls"})
private void executeStatement(Statement s) { private void executeStatement(Statement s) {
if (!enoughAP) return; if (!enoughAP) return;
@@ -79,38 +100,39 @@ public class Program {
case ASSIGN: case ASSIGN:
Statement.Assign data = (Statement.Assign) s.getData(); Statement.Assign data = (Statement.Assign) s.getData();
if (procMap.containsKey(data.getVariableName())) throw new IllegalArgumentException("Already a procedure with same name."); if (procMap.containsKey(data.getVariableName())) throw new IllegalArgumentException("Already a procedure with same name.");
varMap.put(data.getVariableName(), data.getValue()); varMap.put(data.getVariableName(), data.getValue().execute(this));
break; break;
case PRINT: case PRINT:
printList.add(processExpression((Expression) s.getData()));
printList.add(((Expression) s.getData()).execute(this));
break; break;
case ACTION: case ACTION:
Statement.Action action = (Statement.Action) s.getData(); Statement.Action action = (Statement.Action) s.getData();
switch (action.getType()) { switch (action.getType()) {
case TURN: case TURN:
Double val = (Double) processExpression(action.getValue()); Double val = action.getValue().execute(this);
if (val == null) throw new IllegalArgumentException("Turn cannot be null"); if (val == null) throw new IllegalArgumentException("Turn cannot be null");
if (worm.getActionPoints() - (long) Math.abs(ceil(toDegrees(val) / 6)) < 0) { if (worm.getActionPoints() - (long) Math.abs(ceil(toDegrees(val) / 6)) < 0) {
enoughAP = false; enoughAP = false;
lastStatement = s; callStack.push(new CallStackNode(null, s));
return; return;
} }
else if (!worm.canTurn(val)) throw new IllegalArgumentException("Invalid turn value"); else if (!worm.canTurn(val)) throw new IllegalArgumentException("Invalid turn value");
actionHandler.turn(worm, (double) processExpression(action.getValue())); actionHandler.turn(worm, action.getValue().execute(this));
break; break;
case MOVE: case MOVE:
try { try {
actionHandler.move(worm); actionHandler.move(worm);
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
enoughAP = false; enoughAP = false;
lastStatement = s; callStack.push(new CallStackNode(null, s));
return; return;
} }
break; break;
case JUMP: case JUMP:
if (worm.getActionPoints() < 0) { if (worm.getActionPoints() <= 0) {
enoughAP = false; enoughAP = false;
lastStatement = s; callStack.push(new CallStackNode(null, s));
return; return;
} }
actionHandler.jump(worm); actionHandler.jump(worm);
@@ -118,7 +140,7 @@ public class Program {
case EAT: case EAT:
if (!worm.canEat()) { if (!worm.canEat()) {
enoughAP = false; enoughAP = false;
lastStatement = s; callStack.push(new CallStackNode(null, s));
return; return;
} }
actionHandler.eat(worm); actionHandler.eat(worm);
@@ -126,7 +148,7 @@ public class Program {
case FIRE: case FIRE:
if (!worm.canFire()) { if (!worm.canFire()) {
enoughAP = false; enoughAP = false;
lastStatement = s; callStack.push(new CallStackNode(null, s));
return; return;
} }
actionHandler.fire(worm); actionHandler.fire(worm);
@@ -134,20 +156,29 @@ public class Program {
} }
break; break;
case WHILE: case WHILE:
inLoop++;
Boolean condition = (Boolean) processExpression(((Statement.While) s.getData()).getCondition()); currentType.push(Statement.Type.WHILE);
CallStackNode whileNode = new CallStackNode(null, s);
callStack.push(whileNode);
Boolean condition = (Boolean) ((Statement.While) s.getData()).getCondition().execute(this);
if (condition == null) throw new IllegalArgumentException("Condition has to be a boolean"); if (condition == null) throw new IllegalArgumentException("Condition has to be a boolean");
while(condition) { while(condition) {
executeStatement(((Statement.While) s.getData()).getBody()); executeStatement(((Statement.While) s.getData()).getBody());
if (breakLoop) { if (breakLoop || !enoughAP) {
breakLoop = false; breakLoop = false;
break; break;
} }
condition = (Boolean) processExpression(((Statement.While) s.getData()).getCondition()); condition = (Boolean) ((Statement.While) s.getData()).getCondition().execute(this);
if (condition == null) throw new IllegalArgumentException("Condition has to be a boolean"); if (condition == null) throw new IllegalArgumentException("Condition has to be a boolean");
} }
if (enoughAP) {
callStack.remove(whileNode);
}
inLoop--;
currentType.pop();
break;
case IF: case IF:
if ((Boolean) processExpression(((Statement.If) s.getData()).getCondition())) { if ((Boolean) ((Statement.If) s.getData()).getCondition().execute(this)) {
executeStatement(((Statement.If) s.getData()).getIfBody()); executeStatement(((Statement.If) s.getData()).getIfBody());
} else { } else {
Statement elseBody = ((Statement.If) s.getData()).getElseBody(); Statement elseBody = ((Statement.If) s.getData()).getElseBody();
@@ -157,48 +188,47 @@ public class Program {
} }
break; break;
case INVOKE: case INVOKE:
executeStatement(procMap.get((String) s.getData())); currentType.push(Statement.Type.ASSIGN);
inProcedure++;
Statement proc = procMap.get(s.getData());
if (proc == null) throw new IllegalArgumentException("Procedure not defined");
executeStatement(proc);
inProcedure--;
currentType.pop();
break; break;
case BREAK: case BREAK:
if (inLoop == 0 && inProcedure == 0) {
throw new IllegalArgumentException("BREAK out of scope.");
}
if (currentType.peek() == Statement.Type.WHILE) {
breakLoop = true; breakLoop = true;
} else {
breakProcedure = true;
}
break; break;
} }
} }
private Stack<Iterator<Statement>> iteratorStack = new Stack<>(); private Stack<CallStackNode> callStack = new Stack<>();
private Statement lastStatement = null;
private void executeStatementBlock(List<Statement> list) { private void executeStatementBlock(List<Statement> list) {
Iterator<Statement> it = list.iterator(); Iterator<Statement> it = list.iterator();
iteratorStack.push(it); CallStackNode node = new CallStackNode(it, null);
callStack.push(node);
while(it.hasNext()) { while(it.hasNext()) {
executeStatement(it.next()); Statement current = it.next();
if (!enoughAP) { node.lastStatement = current;
executeStatement(current);
if (!enoughAP || breakLoop || breakProcedure) {
breakProcedure = false;
break; break;
} }
} }
} if (!it.hasNext() && enoughAP) callStack.pop();
@SuppressWarnings("unchecked")
private Object processExpression(Expression e) {
if (e instanceof ArgumentExpression) {
switch (((ArgumentExpression) e).getType()) {
case WORM:
return ((ArgumentExpression) e).execute(worm);
case VAR:
return ((ArgumentExpression) e).execute(varMap);
case GOBJECTS:
return ((ArgumentExpression) e).execute(worm.getWorld().getGameObjects());
}
} else {
return e.execute(this);
}
throw new UnsupportedOperationException();
} }
public void setActionHandler(IActionHandler actionHandler) { public void setActionHandler(IActionHandler actionHandler) {
@@ -213,7 +243,18 @@ public class Program {
this.worm = worm; this.worm = worm;
} }
public Map<String, Expression> getVariables() { public Map<String, Object> getVariables() {
return this.varMap; return this.varMap;
} }
private class CallStackNode {
public Iterator<Statement> statementIterator;
public Statement lastStatement;
public CallStackNode(Iterator<Statement> st, Statement ls) {
statementIterator = st;
lastStatement = ls;
} }
}
}

View File

@@ -1,6 +1,7 @@
package worms.model; package worms.model;
import java.util.*; import java.util.*;
import java.util.function.BiFunction;
import worms.util.IllegalNameException; import worms.util.IllegalNameException;
import worms.util.TeamComparator; import worms.util.TeamComparator;
@@ -82,7 +83,7 @@ public class Team {
Collection<Worm> worms = getAllWormsOfTeam(); Collection<Worm> worms = getAllWormsOfTeam();
for (Worm w : worm) { for (Worm w : worm) {
if (w == null) return false; if (w == null || w.getTeam() != null) return false;
if (!names.add(w.getName())) return false; if (!names.add(w.getName())) return false;
if (worms.contains(w)) return false; if (worms.contains(w)) return false;
if (worms.size() == 0 && !w.isTerminated()) continue; if (worms.size() == 0 && !w.isTerminated()) continue;
@@ -109,9 +110,9 @@ public class Team {
*/ */
public void removeWormsFromTeam(Worm... worm) throws IllegalArgumentException { public void removeWormsFromTeam(Worm... worm) throws IllegalArgumentException {
if (worm == null) throw new IllegalArgumentException();
if (worm == null || Arrays.stream(worm).anyMatch(w -> Objects.isNull(w) || !getAllWormsOfTeam().contains(w))) throw new IllegalArgumentException();
for (Worm w: worm) { for (Worm w: worm) {
if (w == null) throw new IllegalArgumentException();
getAllWormsOfTeam().remove(w); getAllWormsOfTeam().remove(w);
w.setTeam(null); w.setTeam(null);
} }
@@ -169,7 +170,8 @@ public class Team {
*/ */
public static void mergeTeams(Team receivingTeam, Team supplyingTeam) throws IllegalArgumentException { public static void mergeTeams(Team receivingTeam, Team supplyingTeam) throws IllegalArgumentException {
if (receivingTeam == null || supplyingTeam == null || receivingTeam.equals(supplyingTeam) ) { if (receivingTeam == null || supplyingTeam == null || receivingTeam.equals(supplyingTeam) ||
supplyingTeam.getAllWormsOfTeam().stream().anyMatch(s -> receivingTeam.getAllWormsOfTeam().contains(s))) {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }

View File

@@ -30,7 +30,7 @@ public class World {
*/ */
public World(double width, double height, boolean[][] map) { public World(double width, double height, boolean[][] map) {
if (!isValidDimension(width) || !isValidDimension(height) || map == null || map.length != height || map[0].length != height) throw new IllegalArgumentException(); if (!isValidDimension(width) || !isValidDimension(height) || map == null || map.length == 0) throw new IllegalArgumentException();
this.width = width; this.width = width;
this.height = height; this.height = height;
@@ -69,7 +69,7 @@ public class World {
public void activateNextWorm() throws IllegalStateException { public void activateNextWorm() throws IllegalStateException {
if (getWormList().size() == 0) { if (getWormList().size() == 0) {
throw new IllegalStateException("No worms"); return;
} }
this.activeWorm++; this.activeWorm++;
@@ -97,6 +97,9 @@ public class World {
Team lastTeam = getWormList().get(0).getTeam(); Team lastTeam = getWormList().get(0).getTeam();
for(Worm worm: getWormList()) { for(Worm worm: getWormList()) {
if (worm.getTeam() == null) {
return null;
}
if (!lastTeam.equals(worm.getTeam())) { if (!lastTeam.equals(worm.getTeam())) {
return null; return null;
} }
@@ -228,7 +231,7 @@ public class World {
if (Math.floor(location[0] / lengthX) >= getMap()[0].length || location[0] < 0.0 || if (Math.floor(location[0] / lengthX) >= getMap()[0].length || location[0] < 0.0 ||
location[1] / lengthY >= getMap().length || location[1] < 0.0) { location[1] / lengthY >= getMap().length || location[1] < 0.0) {
return false; return true;
} }
return this.map[map.length - 1 - (int) Math.floor(location[1] / lengthY)][(int) Math.floor(location[0] / lengthX)]; return this.map[map.length - 1 - (int) Math.floor(location[1] / lengthY)][(int) Math.floor(location[0] / lengthX)];
@@ -444,9 +447,16 @@ public class World {
*/ */
public void add(GameObject obj) throws IllegalStateException, IllegalArgumentException { public void add(GameObject obj) throws IllegalStateException, IllegalArgumentException {
if (hasActiveGame()) throw new IllegalStateException(); if (hasActiveGame()) throw new IllegalStateException();
if (obj == null || !getGameObjects().add(obj) || obj.isTerminated()) throw new IllegalArgumentException(); if (obj == null || !getGameObjects().add(obj) || obj.isTerminated() || obj.getWorld() != null) throw new IllegalArgumentException();
obj.setWorld(this);
if (obj.getClass().equals(Food.class) && !((Food) obj).isValidLocation(obj.getLocation(), this)) { if (obj.getClass().equals(Food.class) && !((Food) obj).isValidLocation(obj.getLocation(), this)) {
obj.setWorld(null);
throw new IllegalArgumentException();
}
else if(Worm.class.isInstance(obj) && (!obj.isValidLocation(obj.getLocation()) || !isAdjacent(obj.getLocation(), obj.getRadius()) )) {
obj.setWorld(null);
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
obj.setWorld(this); obj.setWorld(this);
@@ -503,28 +513,9 @@ public class World {
return getGameObjectsByClass(Food.class); return getGameObjectsByClass(Food.class);
} }
/**
*
* @param cl
*
* @return ...
* |list.add(gameObject) for each gameObject
* |result == list (ArrayList<>())
*/
public List<GameObject> getGameObjectList(Class cl) {
List<GameObject> list = new ArrayList<>();
for (GameObject x : getGameObjects()) {
if (x.getClass().equals(cl)) {
list.add(x);
}
}
return list;
}
@SuppressWarnings("unchecked")
public <T extends GameObject> List<T> getGameObjectsByClass(Class<T> cl) { public <T extends GameObject> List<T> getGameObjectsByClass(Class<T> cl) {
return getGameObjects().stream().filter(cl::isInstance).map(cl::cast).collect(Collectors.toList());
return (List<T>) getGameObjects().stream().filter(x -> x.getClass().equals(cl)).collect(Collectors.toList());
} }
/** /**
@@ -544,6 +535,7 @@ public class World {
Set<GameObject> gameObjects = getGameObjects(); Set<GameObject> gameObjects = getGameObjects();
int size = gameObjects.size(); int size = gameObjects.size();
if (size < 2) throw new IllegalStateException("Less than 2 objects");
int nb1 = new Random().nextInt(size); int nb1 = new Random().nextInt(size);
int nb2 = new Random().nextInt(size); int nb2 = new Random().nextInt(size);
while (nb2 == nb1) { while (nb2 == nb1) {

View File

@@ -109,7 +109,6 @@ public class Worm extends GameObject {
public Worm(World world, double[] location, double orientation, String name, double radius, double minRadius, Team team) public Worm(World world, double[] location, double orientation, String name, double radius, double minRadius, Team team)
throws IllegalArgumentException { throws IllegalArgumentException {
super(world, location, radius); super(world, location, radius);
setTeam(team);
setOrientation(orientation); setOrientation(orientation);
@@ -117,7 +116,7 @@ public class Worm extends GameObject {
throw new IllegalArgumentException("Invalid min radius"); throw new IllegalArgumentException("Invalid min radius");
this.minRadius = minRadius; this.minRadius = minRadius;
if (this.radius < this.minRadius) throw new IllegalArgumentException("Invalid radius"); if (!canHaveAsRadius(radius)) throw new IllegalArgumentException("Invalid radius");
setActionPoints(getMaxActionPoints()); setActionPoints(getMaxActionPoints());
@@ -132,6 +131,7 @@ public class Worm extends GameObject {
if (team != null) { if (team != null) {
team.addWorm(this); team.addWorm(this);
} }
setTeam(team);
} }
//=================================================================================== //===================================================================================
@@ -168,7 +168,7 @@ public class Worm extends GameObject {
*/ */
@Raw @Raw
private void setOrientation(double orientation) { private void setOrientation(double orientation) {
assert isValidOrientation(orientation); if (!isValidOrientation(orientation)) throw new IllegalArgumentException();
this.orientation = orientation; this.orientation = orientation;
} }
@@ -248,7 +248,7 @@ public class Worm extends GameObject {
*/ */
@Raw @Raw
private boolean canHaveAsRadius(double radius) { private boolean canHaveAsRadius(double radius) {
return !Double.isNaN(radius) && radius >= getMinRadius(); return !Double.isNaN(radius) && radius >= getMinRadius() && !Double.isInfinite(radius);
} }
/** /**
@@ -410,6 +410,8 @@ public class Worm extends GameObject {
*/ */
public static int isValidName(String name) { public static int isValidName(String name) {
if (name == null) throw new IllegalArgumentException("Name must not be null");
if (name.length() < 2 || !Character.isUpperCase(name.charAt(0))) { if (name.length() < 2 || !Character.isUpperCase(name.charAt(0))) {
return 0; return 0;
} }
@@ -473,15 +475,16 @@ public class Worm extends GameObject {
*/ */
public void move() throws IllegalArgumentException { public void move() throws IllegalArgumentException {
if (getWorld() == null) throw new IllegalStateException();
double newDirection = getFurthestLocationDirection(); double newDirection = getFurthestLocationDirection();
Coordinate newLocation = getFurthestLocationInDirection(newDirection, this.getRadius()); Coordinate newLocation = getFurthestLocationInDirection(newDirection, this.getRadius());
double distance = getDistance(this.getLocation(), newLocation); double distance = getDistance(this.getLocation(), newLocation);
long cost = (long) ceil(abs(distance * cos(newDirection)) + abs(4 * distance * sin(newDirection))); long cost = (long) round(abs(distance * cos(newDirection)) + abs(4 * distance * sin(newDirection)));
if (cost > getActionPoints()) if (cost > getActionPoints())
throw new IllegalArgumentException(); throw new IllegalArgumentException();
setLocation(newLocation); setLocation(newLocation);
subtractActionPoints(cost); subtractActionPoints(cost);
} }
@@ -501,6 +504,10 @@ public class Worm extends GameObject {
double radius = getRadius(); double radius = getRadius();
World world = getWorld(); World world = getWorld();
if (direction < 0 || direction > 2 * Math.PI || Double.isNaN(direction) || maxDistance < 0 ||
Double.isNaN(maxDistance) || Double.isInfinite(maxDistance))
throw new IllegalArgumentException("Invalid direction/distance");
if (getWorld() == null) { if (getWorld() == null) {
return Coordinate.create(currentLocation.getX() + maxDistance * cos(direction), currentLocation.getY() + maxDistance * sin(direction)); return Coordinate.create(currentLocation.getX() + maxDistance * cos(direction), currentLocation.getY() + maxDistance * sin(direction));
} }
@@ -550,6 +557,7 @@ public class Worm extends GameObject {
double maxLocDirection = minDirection; double maxLocDirection = minDirection;
Coordinate maxLoc = location; Coordinate maxLoc = location;
for (; minDirection <= maxDirection; minDirection += 0.0175) { for (; minDirection <= maxDirection; minDirection += 0.0175) {
if (minDirection < 0) minDirection = 0.0;
Coordinate tempLoc = getFurthestLocationInDirection(minDirection, this.getRadius()); Coordinate tempLoc = getFurthestLocationInDirection(minDirection, this.getRadius());
if (!getWorld().isAdjacent(tempLoc, getRadius())) tempLoc = location; if (!getWorld().isAdjacent(tempLoc, getRadius())) tempLoc = location;
if (getDistance(location, tempLoc) / Math.abs(direction - minDirection) > getDistance(location, maxLoc) / Math.abs(direction - maxLocDirection)) { if (getDistance(location, tempLoc) / Math.abs(direction - minDirection) > getDistance(location, maxLoc) / Math.abs(direction - maxLocDirection)) {
@@ -708,8 +716,6 @@ public class Worm extends GameObject {
} }
setLocation(newLocation); setLocation(newLocation);
setActionPoints(0); setActionPoints(0);
checkEat();
} }
/** /**
@@ -740,7 +746,7 @@ public class Worm extends GameObject {
* |if (Double.isNaN(deltaTime) || deltaTime > this.jumpTime() || deltaTime < 0) * |if (Double.isNaN(deltaTime) || deltaTime > this.jumpTime() || deltaTime < 0)
*/ */
public Coordinate jumpStep(double deltaTime) { public Coordinate jumpStep(double deltaTime) {
if (Double.isNaN(deltaTime) || deltaTime > this.jumpTime() || deltaTime < 0) if (Double.isNaN(deltaTime) || deltaTime > this.jumpTime() || deltaTime < 0 || getActionPoints() == 0)
throw new IllegalArgumentException(); throw new IllegalArgumentException();
double velocity = this.jumpVelocity(); double velocity = this.jumpVelocity();
@@ -766,12 +772,14 @@ public class Worm extends GameObject {
* |result == t * |result == t
*/ */
private double calcJumpTime() { private double calcJumpTime() {
double v = jumpVelocity();
World world = getWorld();
if (world == null) throw new IllegalStateException("World cannot be null");
double v = jumpVelocity();
double t = 0; double t = 0;
double a = getOrientation(); double a = getOrientation();
Coordinate loc = getLocation(); Coordinate loc = getLocation();
World world = getWorld();
double radius = getRadius(); double radius = getRadius();
Coordinate newLoc; Coordinate newLoc;
@@ -1113,19 +1121,18 @@ public class Worm extends GameObject {
if (terminate) food.terminate(); if (terminate) food.terminate();
System.out.println(getWorld().isAdjacent(getLocation(), getRadius()));
double radius = getRadius(); double radius = getRadius();
double changeRadius = radius * 0.1; double changeRadius = radius * 0.1;
if (food.isPoisonous()) { if (food.isPoisonous()) {
changeRadius *= -1; changeRadius *= -1;
radius *= 0.9; radius *= 0.9;
if (radius < getMinRadius()) radius = getMinRadius();
} else { } else {
radius *= 1.1; radius *= 1.1;
} }
decreaseActionPoints(8);
setRadius(radius); setRadius(radius);
World world = getWorld(); World world = getWorld();
@@ -1183,7 +1190,7 @@ public class Worm extends GameObject {
*/ */
public void checkEat() { public void checkEat() {
if (!canEat()) throw new IllegalStateException(); if (!canEat()) return;
World world = getWorld(); World world = getWorld();
if (world != null) { if (world != null) {
@@ -1191,6 +1198,7 @@ public class Worm extends GameObject {
for (Food food : foodList) { for (Food food : foodList) {
if (getDistance(food.getLocation(), this.getLocation()) < this.getRadius() + food.getRadius()) { if (getDistance(food.getLocation(), this.getLocation()) < this.getRadius() + food.getRadius()) {
eat(food); eat(food);
break;
} }
} }
} }
@@ -1272,4 +1280,13 @@ public class Worm extends GameObject {
// =================================================================================== // ===================================================================================
// endregion // endregion
@Override
public void terminate() {
super.terminate();
if (team != null) {
team.removeWormsFromTeam(this);
setTeam(null);
}
}
} }

View File

@@ -1,22 +0,0 @@
package worms.programs;
public abstract class ArgumentExpression<R, O> implements Expression<R> {
public final Type type;
protected ArgumentExpression(Type type) {
this.type = type;
}
public abstract R execute(O o);
public Type getType() {
return this.type;
}
public enum Type {
WORM,
VAR,
GOBJECTS
}
}

View File

@@ -19,10 +19,6 @@ public class BinaryExpression<T, R> implements Expression<R> {
@Override @Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public R execute(Program program) { public R execute(Program program) {
try {
return function.apply(left.execute(program), right.execute(program)); return function.apply(left.execute(program), right.execute(program));
} catch (ClassCastException e) {
throw new IllegalArgumentException();
}
} }
} }

View File

@@ -1,7 +1,7 @@
package worms.programs; package worms.programs;
import worms.model.Program; import worms.model.Program;
@FunctionalInterface
public interface Expression<R> { public interface Expression<R> {
R execute(Program program); R execute(Program program);

View File

@@ -8,6 +8,7 @@ import worms.util.MustNotImplementException;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.Objects;
public class ProgramFactory implements IProgramFactory<Expression, Statement, Procedure, Program> { public class ProgramFactory implements IProgramFactory<Expression, Statement, Procedure, Program> {
/** /**
@@ -58,7 +59,7 @@ public class ProgramFactory implements IProgramFactory<Expression, Statement, Pr
*/ */
@Override @Override
public Statement createAssignmentStatement(String variableName, Expression value, SourceLocation sourceLocation) throws ModelException { public Statement createAssignmentStatement(String variableName, Expression value, SourceLocation sourceLocation) throws ModelException {
return new Statement(Statement.Type.ASSIGN, new Statement.Assign(variableName, value)); return new Statement<>(Statement.Type.ASSIGN, new Statement.Assign<Object>(variableName, value));
} }
/** /**
@@ -70,7 +71,7 @@ public class ProgramFactory implements IProgramFactory<Expression, Statement, Pr
*/ */
@Override @Override
public Statement createPrintStatement(Expression value, SourceLocation sourceLocation) throws ModelException { public Statement createPrintStatement(Expression value, SourceLocation sourceLocation) throws ModelException {
return new Statement(Statement.Type.PRINT, value); return new Statement<Expression<Object>>(Statement.Type.PRINT, value);
} }
/** /**
@@ -82,7 +83,7 @@ public class ProgramFactory implements IProgramFactory<Expression, Statement, Pr
*/ */
@Override @Override
public Statement createTurnStatement(Expression angle, SourceLocation location) throws ModelException { public Statement createTurnStatement(Expression angle, SourceLocation location) throws ModelException {
return new Statement(Statement.Type.ACTION, new Statement.Action(Statement.Action.Type.TURN, angle)); return new Statement<>(Statement.Type.ACTION, new Statement.Action(Statement.Action.Type.TURN, angle));
} }
/** /**
@@ -93,7 +94,7 @@ public class ProgramFactory implements IProgramFactory<Expression, Statement, Pr
*/ */
@Override @Override
public Statement createMoveStatement(SourceLocation location) throws ModelException { public Statement createMoveStatement(SourceLocation location) throws ModelException {
return new Statement(Statement.Type.ACTION, new Statement.Action(Statement.Action.Type.MOVE, null)); return new Statement<>(Statement.Type.ACTION, new Statement.Action(Statement.Action.Type.MOVE, null));
} }
/** /**
@@ -103,7 +104,7 @@ public class ProgramFactory implements IProgramFactory<Expression, Statement, Pr
*/ */
@Override @Override
public Statement createJumpStatement(SourceLocation location) throws ModelException { public Statement createJumpStatement(SourceLocation location) throws ModelException {
return new Statement(Statement.Type.ACTION, new Statement.Action(Statement.Action.Type.JUMP, null)); return new Statement<>(Statement.Type.ACTION, new Statement.Action(Statement.Action.Type.JUMP, null));
} }
/** /**
@@ -113,7 +114,7 @@ public class ProgramFactory implements IProgramFactory<Expression, Statement, Pr
*/ */
@Override @Override
public Statement createEatStatement(SourceLocation location) { public Statement createEatStatement(SourceLocation location) {
return new Statement(Statement.Type.ACTION, new Statement.Action(Statement.Action.Type.EAT, null)); return new Statement<>(Statement.Type.ACTION, new Statement.Action(Statement.Action.Type.EAT, null));
} }
/** /**
@@ -124,7 +125,7 @@ public class ProgramFactory implements IProgramFactory<Expression, Statement, Pr
*/ */
@Override @Override
public Statement createFireStatement(SourceLocation location) throws ModelException { public Statement createFireStatement(SourceLocation location) throws ModelException {
return new Statement(Statement.Type.ACTION, new Statement.Action(Statement.Action.Type.FIRE, null)); return new Statement<>(Statement.Type.ACTION, new Statement.Action(Statement.Action.Type.FIRE, null));
} }
/** /**
@@ -135,7 +136,7 @@ public class ProgramFactory implements IProgramFactory<Expression, Statement, Pr
*/ */
@Override @Override
public Statement createSequenceStatement(List<Statement> statements, SourceLocation sourceLocation) throws ModelException { public Statement createSequenceStatement(List<Statement> statements, SourceLocation sourceLocation) throws ModelException {
return new Statement(Statement.Type.BLOCK, statements); return new Statement<>(Statement.Type.BLOCK, statements);
} }
/** /**
@@ -150,7 +151,7 @@ public class ProgramFactory implements IProgramFactory<Expression, Statement, Pr
*/ */
@Override @Override
public Statement createIfStatement(Expression condition, Statement ifBody, Statement elseBody, SourceLocation sourceLocation) throws ModelException { public Statement createIfStatement(Expression condition, Statement ifBody, Statement elseBody, SourceLocation sourceLocation) throws ModelException {
return new Statement(Statement.Type.IF, new Statement.If(condition, ifBody, elseBody)); return new Statement<>(Statement.Type.IF, new Statement.If<Boolean>(condition, ifBody, elseBody));
} }
/** /**
@@ -162,7 +163,7 @@ public class ProgramFactory implements IProgramFactory<Expression, Statement, Pr
*/ */
@Override @Override
public Statement createWhileStatement(Expression condition, Statement body, SourceLocation sourceLocation) throws ModelException { public Statement createWhileStatement(Expression condition, Statement body, SourceLocation sourceLocation) throws ModelException {
return new Statement(Statement.Type.WHILE, new Statement.While(condition, body)); return new Statement<>(Statement.Type.WHILE, new Statement.While<Boolean>(condition, body));
} }
/** /**
@@ -172,7 +173,7 @@ public class ProgramFactory implements IProgramFactory<Expression, Statement, Pr
*/ */
@Override @Override
public Statement createBreakStatement(SourceLocation sourceLocation) throws ModelException, MustNotImplementException { public Statement createBreakStatement(SourceLocation sourceLocation) throws ModelException, MustNotImplementException {
return new Statement(Statement.Type.BREAK, null); return new Statement<>(Statement.Type.BREAK, null);
} }
/** /**
@@ -183,7 +184,7 @@ public class ProgramFactory implements IProgramFactory<Expression, Statement, Pr
*/ */
@Override @Override
public Statement createInvokeStatement(String procedureName, SourceLocation sourceLocation) throws ModelException, MustNotImplementException { public Statement createInvokeStatement(String procedureName, SourceLocation sourceLocation) throws ModelException, MustNotImplementException {
return new Statement(Statement.Type.INVOKE, procedureName); return new Statement<String>(Statement.Type.INVOKE, procedureName);
} }
/** /**
@@ -195,7 +196,10 @@ public class ProgramFactory implements IProgramFactory<Expression, Statement, Pr
*/ */
@Override @Override
public Expression createReadVariableExpression(String variableName, SourceLocation sourceLocation) throws ModelException { public Expression createReadVariableExpression(String variableName, SourceLocation sourceLocation) throws ModelException {
return (Expression<Object>) program -> program.getVariables().get(variableName).execute(program); return (Expression<Object>) program -> {
if (!program.getVariables().containsKey(variableName)) throw new IllegalArgumentException("Variable not declared");
return program.getVariables().get(variableName);
};
} }
/** /**
@@ -239,7 +243,7 @@ public class ProgramFactory implements IProgramFactory<Expression, Statement, Pr
@Override @Override
public Expression createSelfExpression(SourceLocation location) throws ModelException { public Expression createSelfExpression(SourceLocation location) throws ModelException {
return new UnaryArgumentExpression<Worm>(w -> w.getWorm()); return new UnaryArgumentExpression<Worm>(Program::getWorm);
} }
/** /**
@@ -295,7 +299,7 @@ public class ProgramFactory implements IProgramFactory<Expression, Statement, Pr
@Override @Override
public Expression createEqualityExpression(Expression left, Expression right, SourceLocation location) throws ModelException { public Expression createEqualityExpression(Expression left, Expression right, SourceLocation location) throws ModelException {
return new BinaryExpression<Object, Boolean>(left, right, (l, r) -> l.equals(r)); return new BinaryExpression<Object, Boolean>(left, right, Objects::equals);
} }
/** /**
@@ -321,7 +325,7 @@ public class ProgramFactory implements IProgramFactory<Expression, Statement, Pr
.getWorld() .getWorld()
.getGameObjects() .getGameObjects()
.stream() .stream()
.filter(g -> g.getAngle(p.getWorm()) == p.getWorm().getOrientation()) .filter(g -> g.getAngle(p.getWorm()) == p.getWorm().getOrientation() + a)
.min(Comparator.comparingDouble(gameObject -> gameObject.getDistance(p.getWorm()))) .min(Comparator.comparingDouble(gameObject -> gameObject.getDistance(p.getWorm())))
.orElse(null)); .orElse(null));
} }
@@ -337,7 +341,7 @@ public class ProgramFactory implements IProgramFactory<Expression, Statement, Pr
@Override @Override
public Expression createSameTeamExpression(Expression entity, SourceLocation sourceLocation) throws ModelException, MustNotImplementException { public Expression createSameTeamExpression(Expression entity, SourceLocation sourceLocation) throws ModelException, MustNotImplementException {
return new BinaryArgumentExpression<Worm, Boolean>(entity, (w, p) -> w.getTeam().equals(p.getWorm().getTeam())); return new BinaryArgumentExpression<Worm, Boolean>(entity, (w, p) -> {if (w == null) return false; return Objects.equals(w.getTeam(), p.getWorm().getTeam());});
} }
/** /**
@@ -350,7 +354,10 @@ public class ProgramFactory implements IProgramFactory<Expression, Statement, Pr
@Override @Override
public Expression createDistanceExpression(Expression entity, SourceLocation sourceLocation) throws ModelException { public Expression createDistanceExpression(Expression entity, SourceLocation sourceLocation) throws ModelException {
return new BinaryArgumentExpression<GameObject, Double>(entity, (e, p) -> e.getDistance(p.getWorm())); return new BinaryArgumentExpression<GameObject, Double>(entity, (e, p) -> {
if (e == null) throw new IllegalArgumentException();
return e.getDistance(p.getWorm());
});
} }
/** /**
@@ -363,6 +370,6 @@ public class ProgramFactory implements IProgramFactory<Expression, Statement, Pr
@Override @Override
public Expression createIsWormExpression(Expression entity, SourceLocation sourceLocation) throws ModelException { public Expression createIsWormExpression(Expression entity, SourceLocation sourceLocation) throws ModelException {
return new UnaryExpression<GameObject, Boolean>(entity, w -> w instanceof Worm); return new UnaryExpression<Object, Boolean>(entity, e -> e instanceof Worm);
} }
} }

View File

@@ -1,11 +1,11 @@
package worms.programs; package worms.programs;
public class Statement { public class Statement<T> {
private final Type type; private final Type type;
private final Object data; private final T data;
public Statement(Type type, Object data) { public Statement(Type type, T data) {
this.type = type; this.type = type;
this.data = data; this.data = data;
} }
@@ -14,7 +14,7 @@ public class Statement {
return this.type; return this.type;
} }
public Object getData() { public T getData() {
return data; return data;
} }
@@ -29,13 +29,13 @@ public class Statement {
BREAK BREAK
} }
public static class If { public static class If<T> {
private final Statement ifBody; private final Statement ifBody;
private final Statement elseBody; private final Statement elseBody;
private final Expression condition; private final Expression<T> condition;
public If(Expression condition, Statement ifBody, Statement elseBody) { public If(Expression<T> condition, Statement ifBody, Statement elseBody) {
this.ifBody = ifBody; this.ifBody = ifBody;
this.elseBody = elseBody; this.elseBody = elseBody;
this.condition = condition; this.condition = condition;
@@ -49,17 +49,17 @@ public class Statement {
return elseBody; return elseBody;
} }
public Expression getCondition() { public Expression<T> getCondition() {
return condition; return condition;
} }
} }
public static class While { public static class While<T> {
private final Expression condition; private final Expression<T> condition;
private final Statement body; private final Statement body;
public While(Expression condition, Statement body) { public While(Expression<T> condition, Statement body) {
this.condition = condition; this.condition = condition;
this.body = body; this.body = body;
} }
@@ -68,7 +68,7 @@ public class Statement {
return body; return body;
} }
public Expression getCondition() { public Expression<T> getCondition() {
return condition; return condition;
} }
} }
@@ -106,17 +106,17 @@ public class Statement {
} }
} }
public static class Assign { public static class Assign<T> {
private final String variableName; private final String variableName;
private final Expression value; private final Expression<T> value;
public Assign(String variableName, Expression value) { public Assign(String variableName, Expression<T> value) {
this.variableName = variableName; this.variableName = variableName;
this.value = value; this.value = value;
} }
public Expression getValue() { public Expression<T> getValue() {
return value; return value;
} }

View File

@@ -7,6 +7,7 @@ import java.util.Comparator;
public class TeamComparator implements Comparator<Worm> { public class TeamComparator implements Comparator<Worm> {
@Override @Override
public int compare(Worm t1, Worm t2) { public int compare(Worm t1, Worm t2) {
if (t1.equals(t2)) return 0;
return t1.getName().compareTo(t2.getName()); return t1.getName().compareTo(t2.getName());
} }
} }

View File

@@ -976,7 +976,7 @@ public class Part3_FullFacadeTest {
@Test @Test
public void createWorm_IllegalWorld() { public void createWorm_IllegalWorld() {
max_score += 2; max_score += 2;
World someWorld = facade.createWorld(10.0, 20.0, map10x10); World someWorld = facade.createWorld(10.0, 10.0, map10x10);
facade.terminate(someWorld); facade.terminate(someWorld);
try { try {
facade.createWorm(someWorld, new double[] { 8.68, 8.68 }, 0.3, 0.3, "Worm", null); facade.createWorm(someWorld, new double[] { 8.68, 8.68 }, 0.3, 0.3, "Worm", null);