Merge remote-tracking branch 'origin/main'
This commit is contained in:
@@ -2,7 +2,6 @@ package ch.zhaw.pm2.racetrack;
|
||||
|
||||
import ch.zhaw.pm2.racetrack.given.GameSpecification;
|
||||
import ch.zhaw.pm2.racetrack.strategy.*;
|
||||
import org.hamcrest.core.IsInstanceOf;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
@@ -29,7 +28,7 @@ public class Game implements GameSpecification {
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will initialize the game. Therefore it interacts with the user via UserInterface
|
||||
* This method will initialize the game. Therefore, it interacts with the user via UserInterface
|
||||
*
|
||||
* @return true if the initialization is completed. Returns false if there is an error.
|
||||
*/
|
||||
@@ -85,7 +84,7 @@ public class Game implements GameSpecification {
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
userInterface.printInformation("No Trackfile found!");
|
||||
userInterface.printInformation("No track file found!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -137,7 +136,8 @@ public class Game implements GameSpecification {
|
||||
}
|
||||
|
||||
/**
|
||||
* The functionality was taken out of init to automate testing
|
||||
* Selects the desired track and returns it.
|
||||
* The functionality was taken out of init to automate testing.
|
||||
*
|
||||
* @param selectedTrack the Track which was selected by user
|
||||
*/
|
||||
@@ -147,6 +147,7 @@ public class Game implements GameSpecification {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a desired move strategy for a desired car.
|
||||
* The functionality was taken out of init to automate testing
|
||||
*
|
||||
* @param car to set the MoveStrategy
|
||||
@@ -168,7 +169,7 @@ public class Game implements GameSpecification {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the id of the specified car.
|
||||
* Gets the id of the specified car.
|
||||
*
|
||||
* @param carIndex The zero-based carIndex number
|
||||
* @return A char containing the id of the car
|
||||
@@ -241,7 +242,7 @@ public class Game implements GameSpecification {
|
||||
* <p>The calling method must check the winner state and decide how to go on. If the winner is different
|
||||
* than {@link Game#NO_WINNER}, or the current car is already marked as crashed the method returns immediately.</p>
|
||||
*
|
||||
* @param acceleration A Direction containing the current cars acceleration vector (-1,0,1) in x and y direction
|
||||
* @param acceleration A Direction containing the current car's acceleration vector (-1,0,1) in x and y direction
|
||||
* for this turn
|
||||
*/
|
||||
@Override
|
||||
@@ -273,7 +274,8 @@ public class Game implements GameSpecification {
|
||||
}
|
||||
|
||||
/**
|
||||
* This method implements the gameflow in a while loop. If there is a winner. The method will return its carid.
|
||||
* This method is in charge of changing the players and checking if a winner is found if there is no winner null will be returned.
|
||||
* If a winner is found the game will return the char of the winning player.
|
||||
*
|
||||
* @return the ID of the winning car return null if there is no winner.
|
||||
*/
|
||||
@@ -337,52 +339,6 @@ public class Game implements GameSpecification {
|
||||
return track.calculatePointsOnPath(startPosition, endPosition);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method will check if a car is passing the finishline.
|
||||
* If the car is passing the finishline in the wrong direction, the car will lose a winpoint.
|
||||
* If the car is passing the finishline in the correct direction, the car will gain a winpoint.
|
||||
*
|
||||
* @param start the startposition of the car
|
||||
* @param finish the expected finishpositon of the car after the move
|
||||
*/
|
||||
private void calculateWinner(PositionVector start, PositionVector finish, int carIndex) {
|
||||
List<PositionVector> path = calculatePath(start, finish);
|
||||
for (PositionVector point : path) {
|
||||
switch (track.getSpaceType(point)) {
|
||||
case FINISH_UP:
|
||||
if (start.getY() < finish.getY()) {
|
||||
track.getCar(carIndex).increaseWinPoints();
|
||||
} else if (start.getY() > finish.getY()) {
|
||||
track.getCar(carIndex).deductWinPoints();
|
||||
}
|
||||
break;
|
||||
case FINISH_DOWN:
|
||||
if (start.getY() > finish.getY()) {
|
||||
track.getCar(carIndex).increaseWinPoints();
|
||||
} else if (start.getY() < finish.getY()) {
|
||||
track.getCar(carIndex).deductWinPoints();
|
||||
}
|
||||
break;
|
||||
case FINISH_RIGHT:
|
||||
if (start.getX() < finish.getX()) {
|
||||
track.getCar(carIndex).increaseWinPoints();
|
||||
} else if (start.getX() > finish.getX()) {
|
||||
track.getCar(carIndex).deductWinPoints();
|
||||
}
|
||||
break;
|
||||
case FINISH_LEFT:
|
||||
if (start.getX() > finish.getX()) {
|
||||
track.getCar(carIndex).increaseWinPoints();
|
||||
} else if (start.getX() < finish.getX()) {
|
||||
track.getCar(carIndex).increaseWinPoints();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Does indicate if a car would have a crash with a WALL space or another car at the given position.
|
||||
*
|
||||
@@ -395,6 +351,11 @@ public class Game implements GameSpecification {
|
||||
return track.willCrashAtPosition(carIndex, position);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if there is just one player left in the game being able to make moves.
|
||||
*
|
||||
* @return true if there is just one car left false there are more than one car left in game
|
||||
*/
|
||||
public boolean onlyOneCarLeft() {
|
||||
int carsLeft = 0;
|
||||
for (int carIndex = 0; carIndex < track.getCarCount(); carIndex++) {
|
||||
@@ -405,6 +366,11 @@ public class Game implements GameSpecification {
|
||||
return !(carsLeft > 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if all cars have implemented the do not move strategy, so the game can determine it will end in a draw.
|
||||
*
|
||||
* @return true if all players have implemented do not move false otherwise
|
||||
*/
|
||||
public boolean carsMoving() {
|
||||
for (int carIndex = 0; carIndex < track.getCarCount(); carIndex++) {
|
||||
if (!(track.getCar(carIndex).isCrashed() || track.getCar(carIndex).getMoveStrategy().getClass() == DoNotMoveStrategy.class)) {
|
||||
|
||||
@@ -1,11 +1,19 @@
|
||||
package ch.zhaw.pm2.racetrack;
|
||||
|
||||
/**
|
||||
* Class for Exception when invalid Fileformat is used.
|
||||
* Class for Exception when invalid file format is used.
|
||||
*/
|
||||
public class InvalidFileFormatException extends Exception {
|
||||
public InvalidFileFormatException() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that is used when an error message is given with the exception.
|
||||
*
|
||||
* @param errorMessage is the message to be displayed
|
||||
*/
|
||||
public InvalidFileFormatException(String errorMessage) {
|
||||
super(errorMessage);
|
||||
}
|
||||
public InvalidFileFormatException(){super();}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ public class InvalidTrackFormatException extends Exception {
|
||||
public InvalidTrackFormatException(String errorMessage) {
|
||||
super(errorMessage);
|
||||
}
|
||||
|
||||
public InvalidTrackFormatException() {
|
||||
super();
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ public final class PositionVector {
|
||||
|
||||
/**
|
||||
* Adds two PositionVectors (e.g. car position and velocity vector or two velocity vectors).
|
||||
*
|
||||
* @param vectorA A position or velocity vector
|
||||
* @param vectorB A position or velocity vector
|
||||
* @return A new PositionVector holding the result of the addition. If both
|
||||
@@ -45,6 +46,7 @@ public final class PositionVector {
|
||||
|
||||
/**
|
||||
* Subtracts two PositionVectors (e.g. car position and velocity vector or two velocity vectors).
|
||||
*
|
||||
* @param vectorA A position or velocity vector
|
||||
* @param vectorB A position or velocity vector
|
||||
* @return A new PositionVector holding the result of the addition. If both
|
||||
@@ -58,6 +60,7 @@ public final class PositionVector {
|
||||
/**
|
||||
* Calculates the scalar product (Skalarprodukt) of two 2D vectors. The scalar product
|
||||
* multiplies the lengths of the parallel components of the vectors.
|
||||
*
|
||||
* @param vectorA A position or velocity vector
|
||||
* @param vectorB A position or velocity vector
|
||||
* @return The scalar product (vectorA * vectorB). Since vectorA and
|
||||
@@ -75,6 +78,7 @@ public final class PositionVector {
|
||||
|
||||
/**
|
||||
* Copy constructor
|
||||
*
|
||||
* @param other
|
||||
*/
|
||||
public PositionVector(final PositionVector other) {
|
||||
@@ -109,6 +113,6 @@ public final class PositionVector {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "(X:" + this.x + ", Y:" + this.y + ")";
|
||||
return "(X:" + this.x + ", Y:" + this.y + ")";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ public class DoNotMoveStrategy implements MoveStrategy {
|
||||
|
||||
/**
|
||||
* This method will be used to return the next Direction for the car.
|
||||
*
|
||||
* @return a NONE Direction
|
||||
*/
|
||||
@Override
|
||||
|
||||
@@ -9,7 +9,7 @@ import java.util.List;
|
||||
/**
|
||||
* Strategy which calculates the path automatically
|
||||
*/
|
||||
public class PathFinderMoveStrategy implements MoveStrategy{
|
||||
public class PathFinderMoveStrategy implements MoveStrategy {
|
||||
private final Track track;
|
||||
private final int carIndex;
|
||||
private List<PositionVector.Direction> moveList;
|
||||
@@ -23,6 +23,7 @@ public class PathFinderMoveStrategy implements MoveStrategy{
|
||||
|
||||
/**
|
||||
* Constructor which initialises the needed variables and creates the MoveList
|
||||
*
|
||||
* @param track track instance of the game
|
||||
* @param carIndex index of the car which owns this moveStrategy
|
||||
*/
|
||||
@@ -36,17 +37,17 @@ public class PathFinderMoveStrategy implements MoveStrategy{
|
||||
/**
|
||||
* Method to create a working moveList
|
||||
*/
|
||||
private void createMoveList(){
|
||||
private void createMoveList() {
|
||||
// if Movelist is recreated next move will be the first move in moveList
|
||||
pointer = 0;
|
||||
calculatedStates = new ArrayList<>();
|
||||
PossibleMove finishedMove = null;
|
||||
List<PossibleMove> possibleMoves= new ArrayList<>();
|
||||
List<PossibleMove> possibleMoves = new ArrayList<>();
|
||||
|
||||
// create a PossibleMove object for each direction which doesn't end with a crash.
|
||||
for(PositionVector.Direction direction : allDirections){
|
||||
for (PositionVector.Direction direction : allDirections) {
|
||||
PossibleMove newMove = new PossibleMove(null, direction);
|
||||
if(! newMove.crashed()){
|
||||
if (!newMove.crashed()) {
|
||||
possibleMoves.add(newMove);
|
||||
}
|
||||
|
||||
@@ -54,22 +55,22 @@ public class PathFinderMoveStrategy implements MoveStrategy{
|
||||
|
||||
// while no PossibleMove crosses the finishline
|
||||
// every PossibleMove will be accelerated in each direction to find a Move which finishes.
|
||||
while(finishedMove == null){
|
||||
while (finishedMove == null) {
|
||||
List<PossibleMove> newMoves = new ArrayList<>();
|
||||
for(PossibleMove previousMove : possibleMoves){
|
||||
for(PositionVector.Direction direction : allDirections){
|
||||
for (PossibleMove previousMove : possibleMoves) {
|
||||
for (PositionVector.Direction direction : allDirections) {
|
||||
PossibleMove newMove = new PossibleMove(previousMove, direction);
|
||||
State newState = new State(newMove.endPosition, newMove.endVelocity);
|
||||
//only use the new created Possible Move if it doesn't crash, end State isn't in List of calculatedStates
|
||||
// and if there is no move found yet which is finished.
|
||||
if(! (newMove.crashed() || alreadyCalculated(newState) || finishedMove != null)){
|
||||
if(newMove.finished()){
|
||||
finishedMove = newMove;
|
||||
} else {
|
||||
calculatedStates.add(newState);
|
||||
newMoves.add(newMove);
|
||||
}
|
||||
//only use the new created Possible Move if it doesn't crash, end State isn't in List of calculatedStates
|
||||
// and if there is no move found yet which is finished.
|
||||
if (!(newMove.crashed() || alreadyCalculated(newState) || finishedMove != null)) {
|
||||
if (newMove.finished()) {
|
||||
finishedMove = newMove;
|
||||
} else {
|
||||
calculatedStates.add(newState);
|
||||
newMoves.add(newMove);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
possibleMoves = newMoves;
|
||||
@@ -82,12 +83,13 @@ public class PathFinderMoveStrategy implements MoveStrategy{
|
||||
|
||||
/**
|
||||
* Method to check if a State is already in List calculatedStates
|
||||
*
|
||||
* @param state the State which should be checked
|
||||
* @return true if it is in List, false if it isn't in List
|
||||
*/
|
||||
private boolean alreadyCalculated(State state){
|
||||
for(State calculatedState: calculatedStates){
|
||||
if(state.equals(calculatedState)){
|
||||
private boolean alreadyCalculated(State state) {
|
||||
for (State calculatedState : calculatedStates) {
|
||||
if (state.equals(calculatedState)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -97,26 +99,28 @@ public class PathFinderMoveStrategy implements MoveStrategy{
|
||||
/**
|
||||
* Combination of position and velocity
|
||||
*/
|
||||
public static class State{
|
||||
public static class State {
|
||||
final PositionVector position;
|
||||
final PositionVector velocity;
|
||||
|
||||
/**
|
||||
* Constructor of State
|
||||
*
|
||||
* @param position the PositionVector object with coordinates of the Position
|
||||
* @param velocity the PositionVector object with coordinates of the Velocity
|
||||
*/
|
||||
public State(PositionVector position, PositionVector velocity){
|
||||
public State(PositionVector position, PositionVector velocity) {
|
||||
this.position = position;
|
||||
this.velocity = velocity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a state has the same Position and the same Velocity
|
||||
*
|
||||
* @param compareState the State object to compare
|
||||
* @return true if it is equal, false if it is not equal
|
||||
*/
|
||||
public boolean equals(State compareState){
|
||||
public boolean equals(State compareState) {
|
||||
return compareState.position.equals(position) && compareState.velocity.equals(velocity);
|
||||
}
|
||||
}
|
||||
@@ -136,21 +140,21 @@ public class PathFinderMoveStrategy implements MoveStrategy{
|
||||
|
||||
/**
|
||||
* Constructor of PossibleMove
|
||||
* @param previousMove The move which must be executed bevor this move can be executed
|
||||
*
|
||||
* @param previousMove The move which must be executed bevor this move can be executed
|
||||
* @param nextDirection The direction of the move
|
||||
*/
|
||||
public PossibleMove(PossibleMove previousMove, PositionVector.Direction nextDirection){
|
||||
public PossibleMove(PossibleMove previousMove, PositionVector.Direction nextDirection) {
|
||||
// Velocity of the car bevor the move is executed
|
||||
PositionVector startVelocity;
|
||||
|
||||
directions = new ArrayList<>();
|
||||
// check if there was a previousMove.
|
||||
if(previousMove != null){
|
||||
if (previousMove != null) {
|
||||
directions.addAll(previousMove.directions); //copy the LIst of Directions from the previousMove
|
||||
startPosition = previousMove.endPosition; //use the endPosition from previousMove as startPosition
|
||||
startVelocity = previousMove.endVelocity; //use the endVelocity from previousMove as startVelocity
|
||||
}
|
||||
else { //if there was no previousMove
|
||||
} else { //if there was no previousMove
|
||||
startPosition = track.getCarPos(carIndex); //use the current Position of the car from track as startPosition
|
||||
startVelocity = track.getCar(carIndex).getVelocity(); //use the current Velocity of the car from track as startVelocity
|
||||
}
|
||||
@@ -161,20 +165,22 @@ public class PathFinderMoveStrategy implements MoveStrategy{
|
||||
|
||||
/**
|
||||
* check if the finishline is crossed (in correct direction) if this move is executed
|
||||
*
|
||||
* @return true if finishline will be crossed
|
||||
*/
|
||||
public boolean finished(){
|
||||
public boolean finished() {
|
||||
return track.calculateNewWinPoints(startPosition, endPosition) == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* checks if the car will crash or finishline will be crossed in wrong direction if this move is executed
|
||||
*
|
||||
* @return true if car will crash
|
||||
*/
|
||||
public boolean crashed() {
|
||||
List<PositionVector> points = track.calculatePointsOnPath(startPosition, endPosition);
|
||||
for(PositionVector point : points) {
|
||||
if (track.willCrashAtPosition(carIndex, point)){
|
||||
for (PositionVector point : points) {
|
||||
if (track.willCrashAtPosition(carIndex, point)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -187,6 +193,7 @@ public class PathFinderMoveStrategy implements MoveStrategy{
|
||||
/**
|
||||
* Checks if the next Move in moveList will crash. If no crash next move in moveList will be executed.
|
||||
* If crash the moveList will be recreated.
|
||||
*
|
||||
* @return the direction of acceleration which should be executed.
|
||||
*/
|
||||
@Override
|
||||
@@ -197,11 +204,11 @@ public class PathFinderMoveStrategy implements MoveStrategy{
|
||||
PositionVector newVelocity = new PositionVector(currentVelocity.getX() + direction.vector.getX(), currentVelocity.getY() + direction.vector.getY());
|
||||
PositionVector currentPosition = track.getCarPos(carIndex);
|
||||
PositionVector newPosition = new PositionVector(currentPosition.getX() + newVelocity.getX(), currentPosition.getY() + newVelocity.getY());
|
||||
for(PositionVector point : track.calculatePointsOnPath(currentPosition, newPosition)){
|
||||
if(track.willCrashAtPosition(carIndex, point)){
|
||||
for (PositionVector point : track.calculatePointsOnPath(currentPosition, newPosition)) {
|
||||
if (track.willCrashAtPosition(carIndex, point)) {
|
||||
createMoveList();
|
||||
pointer = 0;
|
||||
direction = moveList.get(pointer);
|
||||
direction = moveList.get(pointer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user