/** * Changes the positions of the worm as a result of a jump from the current position. * * @post If the worm jumped out of the map it will have been removed. * |this.getWorld().getWorms().contains(this) == false * @post The worm jumped to the correct position | while (world.isPassable(tempXpos, tempYpos, * this.getRadius())) | tempXpos = this.jumpStep(t)[0] | tempYpos = this.jumpStep(t)[1] | t += * timeStep | if ((world.isAdjacent(tempXpos, tempYpos, this.getRadius())) && | * (Math.sqrt(Math.pow((origXpos-tempXpos), 2)+Math.pow((origYpos-tempYpos), * 2))>=this.getRadius() )) | new.getXpos() == tempXpos | new.getYpos() == tempYpos * @post The worm's actionpoints are reduced to zero. |new.getActionPoints() == 0; * @throws IllegalStateException When the worm has no action point left to jump the exception is * thrown. |! canJump() */ @Raw public void jump(Double timeStep) throws IllegalStateException { if (this.canJump()) { World world = this.getWorld(); double origXpos = this.getXpos(); double origYpos = this.getYpos(); double tempXpos = this.getXpos(); double tempYpos = this.getYpos(); double t = 0; while (world.isPassable(tempXpos, tempYpos, this.getRadius())) { tempXpos = this.jumpStep(t)[0]; tempYpos = this.jumpStep(t)[1]; t += timeStep; if (isOutOfTheMap(tempXpos, tempYpos)) { this.killWorm(); break; } if ((world.isAdjacent(tempXpos, tempYpos, this.getRadius())) && (Math.sqrt(Math.pow((origXpos - tempXpos), 2) + Math.pow((origYpos - tempYpos), 2)) >= this.getRadius())) { this.setXpos(tempXpos); this.setYpos(tempYpos); this.consumeFood(); this.setActionPoints(0); break; } } } else throw new IllegalStateException(); }
/** * Returns the time it would take for a potential jump from the current position in the direction * this Worm is facing. * * @effect * @return returns the time needed for a moving object to make a jump | - New method: * positionAtTime(T) = new Position(getX() + calculateVelocity() * cos(getDirection)*T, getY() * + calculateVelocity()*sin(getDirection())*T -g/2*T²) | if for each T in [0,time-stepSize]: * | (getWorld().isPassableForCircle(getRadius(),getRadius(), positionAtTime(T)) == true | && * getWorld().isPassableForCircle(getRadius(),getRadius(), positionAtTime(time)) == false) | * && | if for one t in [0,time-stepSize]: | (this.getOverlappingWorm() != null) | then result * == t * @return returns the time needed for a moving object to make a jump | - New method: * positionAtTime(T) = new Position(getX() + calculateVelocity() * cos(getDirection)*T, getY() * + calculateVelocity()*sin(getDirection())*T -g/2*T²) | if for each T in [0,time-stepSize]: * | (getWorld().isPassableForCircle(getRadius(),getRadius(), positionAtTime(T)) == true | && * getWorld().isPassableForCircle(getRadius(),getRadius(), positionAtTime(time)) == false) | * && | if for each t in [0,time-stepSize]: | (this.getOverlappingWorm() == null) | then * result == time | * @effect if this projectile overlaps with a worm then the worm is set as overlappingworm | * this.setOverlapsWorm(newPosition) */ @Override public double jumpTime(double stepSize) throws IllegalJumpTimeException, IllegalArgumentException { double t = 0; boolean found = false; while (!found) { double alpha = getDirection(); double v0 = calculateVelocity(); double v0x = v0 * Math.cos(alpha); double v0y = v0 * Math.sin(alpha); double x = getX() + v0x * t; double y = getY() + v0y * t - g / 2 * t * t; Position newPosition = new Position(x, y); t = t + stepSize; if (!this.getWorld().isPassableForCircle(this.getRadius(), this.getRadius(), newPosition)) found = true; this.setOverlapsWorm(newPosition); if (this.getOverlappingWorm() != null) found = true; t = t + stepSize; } return (t - stepSize); }
/** * Returns the time it takes to worm to jump (to his new position). * * @throws IllegalStateException If the worm can't jump the exception is thrown. | ! canJump() */ @Raw public double jumpTime(double timeStep) throws IllegalStateException { World world = this.getWorld(); double origXpos = this.getXpos(); double origYpos = this.getYpos(); double tempXpos = this.getXpos(); double tempYpos = this.getYpos(); double t = 0; if (this.canJump()) { while (world.isPassable(tempXpos, tempYpos, this.getRadius())) { tempXpos = this.jumpStep(t)[0]; tempYpos = this.jumpStep(t)[1]; t += timeStep; if ((world.isAdjacent(tempXpos, tempYpos, this.getRadius())) && (Math.sqrt(Math.pow((origXpos - tempXpos), 2) + Math.pow((origYpos - tempYpos), 2)) >= this.getRadius())) { return t; } if (isOutOfTheMap(tempXpos, tempYpos)) { return t; } } return t; } else throw new IllegalStateException(); }
/** * Calculates and returns the position of a jumping projectile at the given time. * * @param t The time at which we want to know the location of this projectile during the jump. * @param direction the direction in which the projectile is launched * @pre the direction given must be valid |isValidDirection(direction) * @return The position where this projectile lands after a potential jump. This projectile is not * facing down | if ( ! isFacingDown()) | result == this.jumpStep(this.jumpTime()) * <p>This projectile is facing down, so this projectile doesn't jump | if ( * isFacingDown(direction)) | result == this.jumpStep(0) * @effect if the projectile overlaps with a worm the worm will be set as the overlappingWorm | * this.setOverlapsWorm(newPosition); * @throws IllegalArgumentException the given value for t is not in the interval [0, jumpTime()]. * | ! isValidJumpTime(t) * @throws IllegalJumpTimeExcecption if for the given t the position is no longer passable for the * movingObject | -New variable: newPosition = new Position(getX() + * calculateVelocity()*cos(alpha)*t, getY() + calculateVelocity*sin(alpha)*t); | ! * this.getWorld().isPassableForCircle_BruteForce(this.getRadius(), newPosition) * @throws IllegalJumptTimeException if the projectile overlaps with a worm for the given t | -New * variable: newPosition = new Position(getX() + calculateVelocity()*cos(alpha)*t, getY() + * calculateVelocity*sin(alpha)*t); | overlapsWorm(newPosition); */ @Override public Position jumpStep(double t, double direction) throws IllegalJumpTimeException, IllegalArgumentException { assert isValidDirection(direction); if (!isValidJumpTime(t)) { throw new IllegalArgumentException("negative time"); } if (t == 0) return this.getPosition(); else { if (isFacingDown(direction)) { return this.getPosition(); } double alpha = getDirection(); double v0 = calculateVelocity(); double v0x = v0 * Math.cos(alpha); double v0y = v0 * Math.sin(alpha); double x = getX() + v0x * t; double y = getY() + v0y * t - g / 2 * t * t; Position newPosition = new Position(x, y); this.setOverlapsWorm(newPosition); return newPosition; } }
/** * Returns the worms position during a jump on a given time (after the jump started). * * @param timeAfterLaunch The time after the jump started * @throws IllegalStateException If the worm can't jump the exception is thrown. | ! canJump() */ @Basic @Raw public double[] jumpStep(double timeAfterLaunch) throws IllegalStateException { double[] step; step = new double[2]; if (!this.canJump()) throw new IllegalStateException(); step[0] = ((this.jumpVelocity() * Math.cos(this.getDirection()) * timeAfterLaunch) + this.getXpos()); step[1] = (this.jumpVelocity() * Math.sin(this.getDirection()) * timeAfterLaunch - 0.5 * G * Math.pow(timeAfterLaunch, 2)) + this.getYpos(); return step; }
/** * Changes the positions of the projectile as a result of a jump from the current position. * * @post If the projectile hits a worm this worm loses some hit points and the projectile is * removed from the world and set non active. | if ((Math.sqrt(Math.pow(w.getXpos()-tempXpos, * 2)+Math.pow(w.getYpos()-tempYpos, 2))< maxDistance)) | while (this.getActive == true) | * then (new.setHitPoints(worm.getHitPoints-this.getDamage()) | then (world.getProjectile() == * null) | then (new.getActive == false)) * @post If the projectile doesn't hit a worm, the projectile will be deleted when it leaves the * map or when it hits impassable terrain. | if !((Math.sqrt(Math.pow(w.getXpos()-tempXpos, * 2)+Math.pow(w.getYpos()-tempYpos, 2))< maxDistance)) | then ( if * ((isOutOfTheMap(tempXpos,tempYpos))) | then ((world.getProjectile() == null) | then * (new.getActive == false)) | (else if (world.isImpassable(tempXpos, tempYpos, * this.getRadius()))) | then ((world.getProjectile() == null) | then (new.getActive == * false))) * @throws IllegalStateException If the projectile can't jump the exception is thrown. |! * canJump() */ @Raw public void jump(Double timeStep) throws IllegalStateException { if (this.canJump()) { World world = this.getWorld(); double tempXpos = this.getXpos(); double tempYpos = this.getYpos(); double t = 0; while ((world.isPassable(tempXpos, tempYpos, this.getRadius()))) { tempXpos = this.jumpStep(t)[0]; tempYpos = this.jumpStep(t)[1]; Collection<Worm> collection = (world.getWorms()); for (Worm w : collection) { Worm overlappingWorm = null; double maxDistance = this.getRadius() + w.getRadius(); if (!(w == world.getCurrentWorm()) && (Math.sqrt( Math.pow(w.getXpos() - tempXpos, 2) + Math.pow(w.getYpos() - tempYpos, 2)) < maxDistance)) { overlappingWorm = w; while ((this.getActive() == true)) { overlappingWorm.setHitPoints(overlappingWorm.getHitPoints() - this.getDamage()); this.deleteProjectile(world); this.setActive(false); } } else { overlappingWorm = null; if ((isOutOfTheMap(tempXpos, tempYpos))) { this.deleteProjectile(world); this.setActive(false); } else if (((world.isImpassable(tempXpos, tempYpos, this.getRadius()))) && (this.getActive() == true)) { this.deleteProjectile(world); this.setActive(false); } } } t += timeStep; } } else { throw new IllegalStateException(); } }
/** * Makes the worm fall, if it can fall, until the worm falls on an obstacle or falls out of the * map. * * @post The worm has fallen to a new position that is adjacent. The x-position stays the same but * the y-position changes. |this.getWorld().isAdjacent(new.getXpos(),new.getYpos(), * new.getDirecetion) == true |new.getXpos()==old.getXpos() |while * (world.isPassable(this.getXpos(), this.getYpos(), this.getRadius())) | newYpos = * this.getYpos()-this.getRadius() | if (this.getYpos()<0) | then new.getYpos == * (this.getRadius()*1.1) | break; | else if ((this.getYpos()>=0)){ | while * (!world.isAdjacent(this.getXpos(), this.getYpos(), this.getRadius())) | newYpos = * (this.getYpos()+0.1*this.getRadius()) | new.getYpos() == newYpos * @post The worms hitpoints are correctly reduced. |new.getHitPoints() == old.getHitPoints() - * 3*distance * @post After the fall the worm could be on food this gets checked. | this.consumeFood() * @throws IllegalStateException If the worm can't fall because he is on adjacent terrain the * exception is thrown. | ! canFall() */ @Raw public void fall() throws IllegalStateException { World world = this.getWorld(); double distance = 0; boolean trigger = false; if (canFall()) { while (world.isPassable(this.getXpos(), this.getYpos(), this.getRadius())) { this.setYpos(this.getYpos() - this.getRadius()); distance += this.getRadius(); if (this.getYpos() < 0) { this.setYpos(0 + this.getRadius() * 1.1); trigger = true; break; } } if ((this.getYpos() >= 0) && !trigger) { while (!world.isAdjacent(this.getXpos(), this.getYpos(), this.getRadius())) { this.setYpos(this.getYpos() + 0.1 * this.getRadius()); distance -= 0.1 * this.getRadius(); } } this.setHitPoints(this.getHitPoints() - (3 * (int) Math.floor(distance))); this.consumeFood(); } else { throw new IllegalStateException(); } }
/** * The method sets the mass of the worm. A worms mass is equal to DENSITY*(4/3)*PI*radius^3, with * DENSITY = 1062. * * @param radius The radius to which the mass must be set accordingly. * @post The new mass of the worm is set correctly. |new.getMass() == DENSITY*(4/3)*PI*radius^3 * @post A new maximum for actionpoints is set. | new.getMaxActionPoints() == new.getMass(); * @post The number of actionpoints change accordingly. (AP can't be higher than MaxAP) | * new.getMaxActionPoints() >= new.getActionPoints() * @throws IllegalArgumentException When the given radius is not a valid radius the exception will * be thrown. | ! isValidRadius(radius)) */ @Raw private void setMass(double radius) throws IllegalArgumentException { if (!isValidRadius(radius)) throw new IllegalArgumentException(); this.mass = DENSITY * ((4.0 / 3.0) * Math.PI * Math.pow(radius, 3)); this.setMaxActionPoints(); this.setMaxHitPoints(); this.setActionPoints(this.getActionPoints()); }
/** This method return the food objects that overlap with the worms position. */ @Raw public Food overlappingFood() { World world = this.getWorld(); double maxDistance = this.getRadius() + 0.2; Food overlappingFood = null; Collection<Food> collection = (world.getFood()); for (Food f : collection) { if (Math.sqrt( Math.pow(f.getXpos() - this.getXpos(), 2) + Math.pow(f.getYpos() - this.getYpos(), 2)) < maxDistance) { overlappingFood = f; break; } else { overlappingFood = null; } } return overlappingFood; }
/** * Sets the team to a random team, if there are teams. * * @post If there where teams the worm is added to a team. If there where no teams the worm isn't * added to a team. | if ((this.getWorld().getTeams().size()!=0)) { | then this.hasTeam() == * true; */ @Raw public void setTeamRandom() { World world = this.getWorld(); ArrayList<Team> teams = (ArrayList<Team>) world.getTeams(); if (!(teams.size() == 0)) { int i = teams.size(); int randomIndex = (int) (Math.random() * i); this.setTeamTo(teams.get(randomIndex)); } }
/** * Returns the cost in actionpoints for a given number of steps in the current direction. * * @param steps the number of steps the worm is going to move. * @return The cost of steps (integer) in the current direction, rounded up to the next integer. * |(steps*(int) Math.round((Math.abs(Math.cos(this.getDirection())) * |+Math.abs((4*Math.sin(this.getDirection())))))) */ @Basic @Raw private int computeCostStep(int steps) { return Math.abs( (int) Math.round( (steps) * (Math.abs(Math.cos(this.getDirection())) + Math.abs((4.0 * Math.sin(this.getDirection())))))); }
/** @return ... | result == Math.sqrt(Math.pow(getXComponent(),2)+Math.pow(getYComponent(),2)) */ public double getTotalLength() { return Math.sqrt(Math.pow(xComp, 2) + Math.pow(yComp, 2)); }
/** * Sets the y-position of the projectile. * * @param ypos The (new) y-position of the projectile * @post the given y-position is the new y-position of the projectile. | new.getYpos() == ypos */ @Raw private void setYpos(double ypos) { this.ypos = ypos + ((this.getRadiusWorm() + this.getRadius()) * 1.1 * Math.sin(this.getDirection())); position.setYpos(this.ypos); }
/** * The method sets the radius of the projectile if it has a valid mass. * * @post The new radius of the projectile is set. |new.getRadius() == * Math.pow((3.0/4.0)*(this.getMass()/(density*Math.PI)) ,1.0/3.0) * @throws IllegalArgumentException When the mass appropriate to the projectile is not a valid * mass the exception will be thrown. | ! isValidMass(this.getMass())) */ @Raw private void setRadius() throws IllegalArgumentException { if (!isValidMass(this.getMass())) throw new IllegalArgumentException(); this.radius = Math.pow((3.0 / 4.0) * (this.getMass() / (density * Math.PI)), 1.0 / 3.0); }
/** * Returns the cost in actionpoints for a turn of a given angle. * * @param angle the angle over which the worm would like to turn in radians. * @return the cost in actionpoints for a turn of a given angle rounded up to the nearest integer. * |(int) Math.abs(Math.round(((60*angle)/(2*Math.PI)))) */ @Basic @Raw private int computeCostTurn(double angle) { return (int) Math.abs(Math.round(((60 * angle) / (2 * Math.PI)))); }
/** * Returns the cost in actionpoints to move in the current direction. * * @param prevXpos The x-position of the worm before he moved. * @param prevYpos The y-position of the worm before he moved. */ @Raw private int computeCost2(double prevXpos, double prevYpos) { return (int) (Math.round(Math.abs(this.getXpos() - prevXpos)) + Math.round(4 * Math.abs(this.getYpos() - prevYpos))); }
/** * The method makes the worm move to a next position that is adjacent to impassable terrain * following the slope of that terrain in the direction. The worm shall aim to maximize the * distance while minimizing the divergence. If no such location exists because all locations in * the direction +- 0,7875 are impassable the worm shall remain at its current position. If * locations in the direction are passable but not adjacent the worm shall move there and then * drop passively. * * @post If the worm can maximize the distance while minimizing the divergence, the worm has moved * to the optimal location. |for (double a = 0.1;a<=this.getRadius();a=a+(0.01*a)) { | x2 = * x+Math.cos(direction)*a; | y2 = y+Math.sin(direction)*a; | if (world.isAdjacent(x2, y2, * this.getRadius()) && | world.isPassable(x2, y2, this.getRadius())) { | double d = * Math.sqrt(Math.pow((x-x2),2)+Math.pow((y-y2),2)); | double s = Math.atan((x-x2)/(y-y2)); | * if ((d>=maxD) && (s<minS)) { | minS=s; | maxD=d; | x2Max = x2; | y2Max= y2; | direction = * direction +0.0175; |new.getXpos()==x2Max |new.getYpos() == y2Max * @post If the worm can't maximize the distance while minimizing the divergence and there is only * impassable terrain in the checked directions, the worm will not have moved. |new.getXpos() * == old.getXpos() |new.getYpos() == old.getYpos() * @post If the worm can't maximize the distance while minimizing the divergence and there is only * passable terrain in the checked directions that is not adjacent, the worm will move there. * |new.getXpos() == old.getXpos() + cos(direction)*radius |new.getYpos() == old.getYpos() + * sin(direction)*radius * @post The worms actionpoints are correctly reduced. |new.getActionPoints == * old.getActionPoints() - old.computeCost2(old.getXpos(),old.getYpos()) * @throws IllegalArgumentException If the worm can't move because he has insufficient * actionpoints the exception is thrown. | ! isValidStep() * @throws IllegalStateException If the worm can't move because the worm isn't positioned in * passable terrain and adjacent to impassable terrain the exception is thrown. | ! canMove() */ @Raw public void move() throws IllegalArgumentException, IllegalStateException { if (!isValidStep()) throw new IllegalArgumentException(); if (canMove()) { World world = this.getWorld(); double x = this.getXpos(); double y = this.getYpos(); double prevx = x; double prevy = y; double x2 = x; double y2 = y; double x2Max = x2; double y2Max = y2; double c = -0.7875; double direction = this.getDirection() + c; double maxD = 0; double minS = this.getDirection(); // geval 1: na gaan of in direction+-45° er een gischike volgende positie is // en zo ja, ernaar verplaatsen. for (double a = 0.1; a <= this.getRadius(); a = a + (0.01 * a)) { x2 = x + Math.cos(direction) * a; y2 = y + Math.sin(direction) * a; if (world.isAdjacent(x2, y2, this.getRadius()) && world.isPassable(x2, y2, this.getRadius())) { double d = Math.sqrt(Math.pow((x - x2), 2) + Math.pow((y - y2), 2)); double s = Math.atan((x - x2) / (y - y2)); if ((d >= maxD) && (s < minS)) { minS = s; maxD = d; x2Max = x2; y2Max = y2; } } direction = direction + 0.0175; } if (this.isOutOfTheMap(x2Max, y2Max)) { this.killWorm(); } else { this.setXpos(x2Max); this.setYpos(y2Max); this.setActionPoints(this.getActionPoints() - this.computeCost2(prevx, prevy)); } // geval2: Er werd in direction+-45° geen geschikte plaats gevonden // nagaan of er in direction naar een passable locatie kan verplaatst worden, // daarnaar verplaatsen en dan vallen (fall). if ((x2Max == x) && (y2Max == y)) { double pasXpos = x; double pasYpos = y; pasXpos = (x + (Math.cos(this.getDirection()) * this.getRadius())); pasYpos = (y + (Math.sin(this.getDirection()) * this.getRadius())); if (!world.isAdjacent(pasXpos, pasYpos, this.getRadius()) && world.isPassable(pasXpos, pasYpos, this.getRadius())) { if (this.isOutOfTheMap(pasXpos, pasYpos)) { this.killWorm(); } else { this.setXpos(pasXpos); this.setYpos(pasYpos); this.setActionPoints(this.getActionPoints() - this.computeCost2(prevx, prevy)); } } } this.consumeFood(); } else throw new IllegalStateException(); }
/** * Set the maximal amount of hit points of this worm. * * @param mass The hit points change along with the mass. * @post The amount of hit points must be equal to the mass of the worm rounded to the nearest * integer. | this.maxHitPoints = (int) Math.round(mass) * @post If the mass of a worm changes, the maximal must be adjusted accordingly. | new.getMass() * = mass | this.maxHitPoints == (int) Math.round(new.getMass()) == int Math.round(mass) * @effect The maximal amount of hit points has been set. */ @Raw private void setMaxHitPoints() { if (this.getMass() < Integer.MAX_VALUE) this.maxHitPoints = (int) Math.round(this.getMass()); else this.maxHitPoints = Integer.MAX_VALUE; }
/** * Sets the x-position of the projectile. * * @param xpos The (new) x-position of the projectile * @post the given x-position is the new x-position of the projectile. | new.getXpos() == xpos */ @Raw private void setXpos(double xpos) { this.xpos = xpos + ((this.getRadiusWorm() + this.getRadius()) * 1.1 * Math.cos(this.getDirection())); position.setXpos(this.xpos); }