Strategy #31
File diff suppressed because one or more lines are too long
42
README.md
42
README.md
|
@ -1,2 +1,44 @@
|
|||
# team02-AngryNerds-projekt1-racetrack
|
||||
PM2 Team 02 Projekt 1 Racetrack
|
||||
Racetrack is a pen and paper game that dates back to the early 1960s in this version of the game, the game is digitalized and the math behind it is done automatically rather than calculated by hand and the winner gets informed automatically as well.
|
||||
|
||||
The aim of the game is to finish the race faster than your opponent or win by being the only survivor in case the other cars crash.
|
||||
|
||||
In order to not crash you have to keep in mind the acceleration and other players car to get to the finish line safely.
|
||||
|
||||
# Initialization:
|
||||
#### The game can be initialized by the terminal command:
|
||||
./gradlew run
|
||||
You will then be prompted to select a track file from the selection by entering the corresponding number.
|
||||
|
||||
#### For each car that is taking part in the race a strategy has to be chosen there are the following options:
|
||||
|
||||
+ Do not move Strategy
|
||||
> This Strategy sets the car stationary, and it won't make any moves during the game staying at the startpoint indefinitely.
|
||||
+ User Move Strategy
|
||||
> The player is prompted for each move to make a choice the different choices you are able to take are as following:
|
||||
> > 1=down-left <br> 2=down<br> 3=down-right<br> 4=left<br> 5=no acceleration<br> 6=right <br> 7=up-left<br> 8=up<br> 9=up-right<br> it is also possible to leave the game when it is your turn by entering 10
|
||||
+ Move List Strategy
|
||||
> For this strategy a predefined list of moves have to be given, the list may contain all allowed moves like mentioned in User Move Strategy
|
||||
> > To create your own Move List strategy it needs to be located in /racetrack/moves and be named as *track_name*-car-*character_of_car*.txt and be a txt file.
|
||||
+ Path Follow Move Strategy
|
||||
> A list of points given in a txt file where on each lime a coordinate is placed like (X:24, Y:22) gets used to calculate a path which makes the car cross each point.
|
||||
> > To create your own follow move strategy it needs to be located in /racetrack/moves and be named as *track_name*_points.txt and be a txt file.
|
||||
+ Path Finder Strategy
|
||||
> The pathfinder Strategy Calculates a route itself and follows it direction fully automatically.
|
||||
|
||||
The shown Track can be interpreted as following:<br>
|
||||
'spaces' are part of the raceable track.<br>
|
||||
'#' is a Wall<br>
|
||||
'>,<,^,v' are finish line components<br>
|
||||
'X' is shown if a car crashes at its crash location.<br>
|
||||
And every other character represents a car.
|
||||
> To create your own track it needs to be located inside /racetrack/tracks and be a txt file.
|
||||
### Determining a winner
|
||||
The winner gets determined automatically. <br> The car that first passes the finish line (doing a complete round) is given the win, if all car except one crash the surviving car will be crowned as the winner.<br>The game will inform you of this, and you will have the option to quit the game or play another match.
|
||||
|
||||
## Branching Model
|
||||
We choose a simple branching model where all starting features got a branch and where merged into the main branch, some branches who needed unfinished code to be completed where taken from the game branch but merged into the main at the end as well.<br> Since there was just one end product we abstained from using a development branch and merges where done straight into main branch.
|
||||
|
||||
## Class Diagramm
|
||||
![Classdiagramm of this program](/Klassendiagramm.drawio)
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
(X:40, Y:22)
|
||||
(X:43, Y:22)
|
||||
(X:46, Y:21)
|
||||
(X:48, Y:19)
|
||||
(X:48, Y:17)
|
||||
(X:46, Y:15)
|
||||
(X:41, Y:13)
|
||||
(X:41, Y:10)
|
||||
(X:46, Y:9)
|
||||
(X:49, Y:4)
|
||||
(X:40, Y:2)
|
||||
(X:30, Y:2)
|
||||
(X:21, Y:3)
|
||||
(X:16, Y:7)
|
||||
(X:13, Y:10)
|
||||
(X:14, Y:14)
|
||||
(X:11, Y:19)
|
||||
(X:13, Y:22)
|
||||
(X:24, Y:22)
|
|
@ -3,14 +3,12 @@ package ch.zhaw.pm2.racetrack;
|
|||
import ch.zhaw.pm2.racetrack.given.CarSpecification;
|
||||
import ch.zhaw.pm2.racetrack.strategy.MoveStrategy;
|
||||
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* Class representing a car on the racetrack.
|
||||
* Uses {@link PositionVector} to store current position on the track grid and current velocity vector.
|
||||
* Each car has an identifier character which represents the car on the race track board.
|
||||
* Each car has an identifier character which represents the car on the racetrack board.
|
||||
* Also keeps the state, if the car is crashed (not active anymore). The state can not be changed back to uncrashed.
|
||||
* The velocity is changed by providing an acelleration vector.
|
||||
* The velocity is changed by providing an acceleration vector.
|
||||
* The car is able to calculate the endpoint of its next position and on request moves to it.
|
||||
*/
|
||||
public class Car implements CarSpecification {
|
||||
|
@ -46,6 +44,7 @@ public class Car implements CarSpecification {
|
|||
|
||||
/**
|
||||
* Constructor for class Car
|
||||
*
|
||||
* @param id unique Car identification
|
||||
* @param position initial position of the Car
|
||||
*/
|
||||
|
@ -59,16 +58,16 @@ public class Car implements CarSpecification {
|
|||
*
|
||||
* @return id of the car.
|
||||
*/
|
||||
public char getID(){
|
||||
public char getID() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void increaseWinPoints() {
|
||||
winPoints ++;
|
||||
winPoints++;
|
||||
}
|
||||
|
||||
public void deductWinPoints() {
|
||||
winPoints --;
|
||||
winPoints--;
|
||||
}
|
||||
|
||||
public int getWinPoints() {
|
||||
|
@ -80,9 +79,10 @@ public class Car implements CarSpecification {
|
|||
*
|
||||
* @return velocity current velocity of the car.
|
||||
*/
|
||||
public PositionVector getVelocity(){
|
||||
public PositionVector getVelocity() {
|
||||
return velocity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this Car position directly, regardless of current position and velocity.
|
||||
* This should only be used by the game controller in rare cases to set the crash or winning position.
|
||||
|
@ -95,8 +95,7 @@ public class Car implements CarSpecification {
|
|||
public void setPosition(final PositionVector position) {
|
||||
if (position.getX() < 0 || position.getY() < 0) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
this.position = position;
|
||||
}
|
||||
}
|
||||
|
@ -109,7 +108,7 @@ public class Car implements CarSpecification {
|
|||
*/
|
||||
@Override
|
||||
public PositionVector nextPosition() {
|
||||
return new PositionVector(position.getX() + velocity.getX(),position.getY() + velocity.getY());
|
||||
return new PositionVector(position.getX() + velocity.getX(), position.getY() + velocity.getY());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -123,11 +122,10 @@ public class Car implements CarSpecification {
|
|||
*/
|
||||
@Override
|
||||
public void accelerate(PositionVector.Direction acceleration) {
|
||||
if(acceleration.vector.getX() < -1 || acceleration.vector.getX() > 1||
|
||||
if (acceleration.vector.getX() < -1 || acceleration.vector.getX() > 1 ||
|
||||
acceleration.vector.getY() < -1 || acceleration.vector.getY() > 1) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
velocity = new PositionVector(velocity.getX() + acceleration.vector.getX(),
|
||||
velocity.getY() + acceleration.vector.getY());
|
||||
}
|
||||
|
@ -161,6 +159,7 @@ public class Car implements CarSpecification {
|
|||
|
||||
/**
|
||||
* Set move strategy
|
||||
*
|
||||
* @param moveStrategy Strategy to be implemented
|
||||
*/
|
||||
public void setMoveStrategy(MoveStrategy moveStrategy) {
|
||||
|
@ -169,6 +168,7 @@ public class Car implements CarSpecification {
|
|||
|
||||
/**
|
||||
* Get current move strategy
|
||||
*
|
||||
* @return MoveStrategy
|
||||
*/
|
||||
public MoveStrategy getMoveStrategy() {
|
||||
|
|
|
@ -26,8 +26,11 @@ public class Game implements GameSpecification {
|
|||
this.userInterface = userInterface;
|
||||
}
|
||||
|
||||
|
||||
public boolean initPhase() throws InvalidTrackFormatException {
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public boolean initPhase() {
|
||||
File folder = new File("tracks");
|
||||
File[] listOfFiles = folder.listFiles();
|
||||
if (listOfFiles.length > 0) {
|
||||
|
@ -35,41 +38,59 @@ public class Game implements GameSpecification {
|
|||
for (File file : listOfFiles) {
|
||||
tracks.add(file.getName());
|
||||
}
|
||||
|
||||
File selectedTrack = listOfFiles[userInterface.selectOption("Select Track file", tracks)];
|
||||
try {
|
||||
selectTrack(selectedTrack);
|
||||
} catch (FileNotFoundException e) {
|
||||
userInterface.printInformation("There is an unexpected Error with the trackfile Path. Add trackfiles only to tracks path. Exit the Game and Fix the Problem");
|
||||
return false;
|
||||
} catch (InvalidTrackFormatException e) {
|
||||
userInterface.printInformation("There is an unexpected Error with the trackfile. Format does not match specifications! Exit the Game and Fix the Problem");
|
||||
return false;
|
||||
}
|
||||
List<String> moveStrategies = new ArrayList<>();
|
||||
moveStrategies.add("Do not move Strategy");
|
||||
moveStrategies.add("User Move Strategy");
|
||||
moveStrategies.add("Move List Strategy");
|
||||
moveStrategies.add("Path Follow Move Strategy");
|
||||
moveStrategies.add("Path Finder Move Strategy");
|
||||
for (int i = 0; i < track.getCarCount(); i++) {
|
||||
Car car = track.getCar(i);
|
||||
while (car.getMoveStrategy() == null) {
|
||||
MoveStrategy moveStrategy = null;
|
||||
while (moveStrategy == null) {
|
||||
String filePath;
|
||||
int moveStrategie = userInterface.selectOption(
|
||||
"Select Strategy for Car " + i + " (" + track.getCarId(i) + ")", moveStrategies);
|
||||
switch (moveStrategie + 1) {
|
||||
switch (moveStrategie) {
|
||||
case 0:
|
||||
moveStrategy = new DoNotMoveStrategy();
|
||||
break;
|
||||
case 1:
|
||||
selectMoveStrategy(car, new DoNotMoveStrategy());
|
||||
moveStrategy = new UserMoveStrategy(userInterface, i, track.getCarId(i));
|
||||
break;
|
||||
case 2:
|
||||
selectMoveStrategy(car, new UserMoveStrategy(userInterface, i, track.getCarId(i)));
|
||||
filePath = ".\\moves\\" + selectedTrack.getName().split("\\.")[0] + "-car-" + track.getCar(i).getID() + ".txt";
|
||||
try {
|
||||
moveStrategy = new MoveListStrategy(filePath);
|
||||
} catch (FileNotFoundException e) {
|
||||
userInterface.printInformation("There is no Move-List implemented. Choose another Strategy!");
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
String path = ".\\moves\\" + selectedTrack.getName().split("\\.")[0] + "-car-" + track.getCar(i).getID() + ".txt";
|
||||
filePath = ".\\follower\\" + selectedTrack.getName().split("\\.")[0] + "_points.txt";
|
||||
try {
|
||||
MoveStrategy moveStrategy = new MoveListStrategy(path);
|
||||
selectMoveStrategy(car, moveStrategy);
|
||||
moveStrategy = new PathFollowerMoveStrategy(filePath, track.getCarPos(i));
|
||||
} catch (FileNotFoundException e) {
|
||||
userInterface.printInformation("There is no MoveList implemented. Choose another Strategy!");
|
||||
userInterface.printInformation("There is no Point-List implemented. Choose another Strategy!");
|
||||
}
|
||||
//TODO: Backslash kompatibel für Linux
|
||||
break;
|
||||
case 4:
|
||||
//TODO: add Arguments
|
||||
selectMoveStrategy(car, new PathFollowerMoveStrategy());
|
||||
moveStrategy = new PathFinderMoveStrategy(track, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
selectMoveStrategy(car, moveStrategy);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
|
@ -80,17 +101,11 @@ public class Game implements GameSpecification {
|
|||
|
||||
/**
|
||||
* The functionality was taken out of init to automate testing
|
||||
*
|
||||
* @param selectedTrack
|
||||
*/
|
||||
Track selectTrack(File selectedTrack) {
|
||||
try {
|
||||
Track selectTrack(File selectedTrack) throws InvalidTrackFormatException,FileNotFoundException {
|
||||
track = new Track(selectedTrack);
|
||||
return track;
|
||||
} catch (FileNotFoundException | PositionVectorNotValid | InvalidTrackFormatException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -192,9 +207,8 @@ public class Game implements GameSpecification {
|
|||
* for this turn
|
||||
*/
|
||||
@Override
|
||||
public void doCarTurn(Direction acceleration) throws PositionVectorNotValid {
|
||||
public void doCarTurn(Direction acceleration) {
|
||||
track.getCar(currentCarIndex).accelerate(acceleration);
|
||||
|
||||
PositionVector crashPosition = null;
|
||||
List<PositionVector> positionList = calculatePath(track.getCarPos(currentCarIndex), track.getCar(currentCarIndex).nextPosition());
|
||||
for (int i = 0; i < positionList.size(); i++) {
|
||||
|
@ -210,22 +224,31 @@ public class Game implements GameSpecification {
|
|||
if (crashPosition != null) {
|
||||
track.carDoesCrash(currentCarIndex, crashPosition);
|
||||
} else {
|
||||
calculateWinner(track.getCarPos(currentCarIndex), track.getCar(currentCarIndex).nextPosition(), currentCarIndex);
|
||||
int newWinPoints = calculateNewWinPoints(track.getCarPos(currentCarIndex), track.getCar(currentCarIndex).nextPosition());
|
||||
if(newWinPoints == 1){
|
||||
track.getCar(currentCarIndex).increaseWinPoints();
|
||||
}else{
|
||||
track.getCar(currentCarIndex).deductWinPoints();
|
||||
}
|
||||
track.moveCar(currentCarIndex);
|
||||
}
|
||||
}
|
||||
|
||||
public String gamePhase() throws PositionVectorNotValid {
|
||||
/**
|
||||
* This method implements the gameflow in a while loop. If there is a winner. The method will return its carid.
|
||||
*
|
||||
* @return the ID of the winning car return null if there is no winner.
|
||||
*/
|
||||
public String gamePhase() {
|
||||
while (carsMoving() && getWinner() == NO_WINNER) {
|
||||
userInterface.printTrack(track);
|
||||
Direction direction;
|
||||
direction = track.getCar(currentCarIndex).getMoveStrategy().nextMove();
|
||||
if (direction == null) {
|
||||
track.getCar(currentCarIndex).setMoveStrategy(new DoNotMoveStrategy());
|
||||
direction = track.getCar(currentCarIndex).getMoveStrategy().nextMove(); //TODO: Entfernen?
|
||||
}else {
|
||||
doCarTurn(direction);
|
||||
direction = track.getCar(currentCarIndex).getMoveStrategy().nextMove();
|
||||
}
|
||||
doCarTurn(direction);
|
||||
switchToNextActiveCar();
|
||||
}
|
||||
userInterface.printTrack(track);
|
||||
|
@ -266,101 +289,58 @@ public class Game implements GameSpecification {
|
|||
*/
|
||||
@Override
|
||||
public List<PositionVector> calculatePath(PositionVector startPosition, PositionVector endPosition) {
|
||||
ArrayList<PositionVector> pathList = new ArrayList<>();
|
||||
// Use Bresenham's algorithm to determine positions.
|
||||
int x = startPosition.getX();
|
||||
int y = startPosition.getY();
|
||||
|
||||
// Relative Distance (x & y axis) between end- and starting position
|
||||
int diffX = endPosition.getX() - startPosition.getX();
|
||||
int diffY = endPosition.getY() - startPosition.getY();
|
||||
|
||||
// Absolute distance (x & y axis) between end- and starting position
|
||||
int distX = Math.abs(diffX);
|
||||
int distY = Math.abs(diffY);
|
||||
|
||||
// Direction of vector on x & y axis (-1: to left/down, 0: none, +1 : to right/up)
|
||||
int dirX = Integer.signum(diffX);
|
||||
int dirY = Integer.signum(diffY);
|
||||
|
||||
// Determine which axis is the fast direction and set parallel/diagonal step values
|
||||
int parallelStepX, parallelStepY;
|
||||
int diagonalStepX, diagonalStepY;
|
||||
int distanceSlowAxis, distanceFastAxis;
|
||||
if (distX > distY) {
|
||||
// x axis is the 'fast' direction
|
||||
parallelStepX = dirX;
|
||||
parallelStepY = 0; // parallel step only moves in x direction
|
||||
diagonalStepX = dirX;
|
||||
diagonalStepY = dirY; // diagonal step moves in both directions
|
||||
distanceSlowAxis = distY;
|
||||
distanceFastAxis = distX;
|
||||
} else {
|
||||
// y axis is the 'fast' direction
|
||||
parallelStepX = 0;
|
||||
parallelStepY = dirY; // parallel step only moves in y direction
|
||||
diagonalStepX = dirX;
|
||||
diagonalStepY = dirY; // diagonal step moves in both directions
|
||||
distanceSlowAxis = distX;
|
||||
distanceFastAxis = distY;
|
||||
return track.calculatePointsOnPath(startPosition, endPosition);
|
||||
}
|
||||
|
||||
int error = distanceFastAxis / 2;
|
||||
for (int step = 0; step < distanceFastAxis; step++) {
|
||||
error -= distanceSlowAxis;
|
||||
if (error < 0) {
|
||||
error += distanceFastAxis; // correct error value to be positive again
|
||||
// step into slow direction; diagonal step
|
||||
x += diagonalStepX;
|
||||
y += diagonalStepY;
|
||||
} else {
|
||||
// step into fast direction; parallel step
|
||||
x += parallelStepX;
|
||||
y += parallelStepY;
|
||||
}
|
||||
|
||||
pathList.add(new PositionVector(x, y));
|
||||
}
|
||||
return pathList;
|
||||
}
|
||||
|
||||
private void calculateWinner(PositionVector start, PositionVector finish, int carIndex) {
|
||||
/**
|
||||
* 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
|
||||
* @param carIndex of the current player.
|
||||
*/
|
||||
private int calculateNewWinPoints(PositionVector start, PositionVector finish) {
|
||||
List<PositionVector> path = calculatePath(start, finish);
|
||||
for (PositionVector point : path) {
|
||||
if (track.getSpaceType(point) != null) {
|
||||
switch (track.getSpaceType(point)) {
|
||||
case FINISH_UP:
|
||||
if (start.getY() < finish.getY()) {
|
||||
track.getCar(carIndex).increaseWinPoints();
|
||||
return 1;
|
||||
} else if (start.getY() > finish.getY()) {
|
||||
track.getCar(carIndex).deductWinPoints();
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case FINISH_DOWN:
|
||||
if (start.getY() > finish.getY()) {
|
||||
track.getCar(carIndex).increaseWinPoints();
|
||||
return 1;
|
||||
} else if (start.getY() < finish.getY()) {
|
||||
track.getCar(carIndex).deductWinPoints();
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case FINISH_RIGHT:
|
||||
if (start.getX() < finish.getX()) {
|
||||
track.getCar(carIndex).increaseWinPoints();
|
||||
return 1;
|
||||
} else if (start.getX() > finish.getX()) {
|
||||
track.getCar(carIndex).deductWinPoints();
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case FINISH_LEFT:
|
||||
if (start.getX() > finish.getX()) {
|
||||
track.getCar(carIndex).increaseWinPoints();
|
||||
return 1;
|
||||
} else if (start.getX() < finish.getX()) {
|
||||
track.getCar(carIndex).increaseWinPoints();
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -372,7 +352,7 @@ public class Game implements GameSpecification {
|
|||
* @return A boolean indicator if the car would crash with a WALL or another car.
|
||||
*/
|
||||
@Override
|
||||
public boolean willCarCrash(int carIndex, PositionVector position) throws PositionVectorNotValid {
|
||||
public boolean willCarCrash(int carIndex, PositionVector position) {
|
||||
return track.willCrashAtPosition(carIndex, position);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
package ch.zhaw.pm2.racetrack;
|
||||
|
||||
/**
|
||||
* Class for Exception when invalid Fileformat is used.
|
||||
*/
|
||||
public class InvalidFileFormatException extends Exception {
|
||||
// TODO: implementation
|
||||
public InvalidFileFormatException(){super();}
|
||||
public InvalidFileFormatException(String errorMessage) {
|
||||
super(errorMessage);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,13 @@
|
|||
package ch.zhaw.pm2.racetrack;
|
||||
|
||||
/**
|
||||
* Class for Exception when invalid track format is used.
|
||||
*/
|
||||
public class InvalidTrackFormatException extends Exception {
|
||||
// TODO: implementation
|
||||
public InvalidTrackFormatException(String errorMessage) {
|
||||
super(errorMessage);
|
||||
}
|
||||
public InvalidTrackFormatException() {
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
package ch.zhaw.pm2.racetrack;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Main {
|
||||
|
||||
public static void main(String[] args) throws InvalidTrackFormatException, PositionVectorNotValid {
|
||||
public static void main(String[] args) {
|
||||
UserInterface userInterface = new UserInterface("Hello and Welcome to Racetrack by Team02-\"AngryNerds\"");
|
||||
while (true) {
|
||||
Game game = new Game(userInterface);
|
||||
|
@ -17,19 +16,17 @@ public class Main {
|
|||
optionsNewGame.add("exit");
|
||||
optionsNewGame.add("new game");
|
||||
String winnerText;
|
||||
if(winner == null){
|
||||
if (winner == null) {
|
||||
winnerText = "There was no winner.";
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
winnerText = "The Winner was Car " + winner;
|
||||
}
|
||||
int selectedOption = userInterface.selectOption(winnerText + "\nStart new Game?", optionsNewGame);
|
||||
if(selectedOption == 0) {
|
||||
if (selectedOption == 0) {
|
||||
userInterface.quit("Thank you and goodbye\npress enter to close the application.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
userInterface.quit("The initialisation of the game failed. Press enter to close the application.");
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -7,8 +7,8 @@ package ch.zhaw.pm2.racetrack;
|
|||
* Created by mach 21.01.2020
|
||||
*/
|
||||
public final class PositionVector {
|
||||
private int x; // horizontal component (position / velocity)
|
||||
private int y; // vertical component (position / velocity)
|
||||
private final int x; // horizontal component (position / velocity)
|
||||
private final int y; // vertical component (position / velocity)
|
||||
|
||||
/**
|
||||
* Enum representing a direction on the track grid.
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
package ch.zhaw.pm2.racetrack;
|
||||
|
||||
public class PositionVectorNotValid extends Throwable {
|
||||
public PositionVectorNotValid(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public PositionVectorNotValid() {}
|
||||
}
|
|
@ -3,7 +3,10 @@ package ch.zhaw.pm2.racetrack;
|
|||
import ch.zhaw.pm2.racetrack.given.ConfigSpecification;
|
||||
import ch.zhaw.pm2.racetrack.given.TrackSpecification;
|
||||
|
||||
import java.io.*;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Scanner;
|
||||
|
@ -57,8 +60,8 @@ import java.util.Scanner;
|
|||
public class Track implements TrackSpecification {
|
||||
|
||||
public static final char CRASH_INDICATOR = 'X';
|
||||
private List<String> track;
|
||||
private List<Car> cars;
|
||||
private final List<String> track;
|
||||
private final List<Car> cars;
|
||||
private final List<PositionVector> finishLine;
|
||||
private ConfigSpecification.SpaceType finishTyp;
|
||||
|
||||
|
@ -69,7 +72,7 @@ public class Track implements TrackSpecification {
|
|||
* @throws FileNotFoundException if the given track file could not be found
|
||||
* @throws InvalidTrackFormatException if the track file contains invalid data (no tracklines, ...)
|
||||
*/
|
||||
public Track(File trackFile) throws FileNotFoundException, InvalidTrackFormatException, PositionVectorNotValid {
|
||||
public Track(File trackFile) throws FileNotFoundException, InvalidTrackFormatException {
|
||||
track = new ArrayList<>();
|
||||
cars = new ArrayList<>();
|
||||
finishLine = new ArrayList<>();
|
||||
|
@ -85,13 +88,17 @@ public class Track implements TrackSpecification {
|
|||
* @throws FileNotFoundException if the FilePath is invalid.
|
||||
*/
|
||||
private void readFile(File trackFile) throws FileNotFoundException {
|
||||
Scanner scanner = new Scanner(new FileInputStream(trackFile),"UTF-8");
|
||||
Scanner scanner = new Scanner(new FileInputStream(trackFile), StandardCharsets.UTF_8);
|
||||
while (scanner.hasNextLine()) {
|
||||
track.add(scanner.nextLine());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Goes through the track ArrayList and determines the locations of each cars and initializes them at the location.
|
||||
*
|
||||
* @throws InvalidTrackFormatException is thrown if a car is found more than once inside the track.
|
||||
*/
|
||||
private void addCars() throws InvalidTrackFormatException {
|
||||
ConfigSpecification.SpaceType[] spaceTypes = ConfigSpecification.SpaceType.values();
|
||||
List<Character> allSpaceTypesAsChar = new ArrayList<>();
|
||||
|
@ -101,23 +108,26 @@ public class Track implements TrackSpecification {
|
|||
allSpaceTypesAsChar.add(spaceType.getValue());
|
||||
}
|
||||
|
||||
|
||||
for (int j = 0; j < track.size(); j++) {
|
||||
String line = track.get(j);
|
||||
for (int i = 0; i < line.length(); i++) {
|
||||
char possibleCarChar = line.charAt(i);
|
||||
for (int yPosition = 0; yPosition < track.size(); yPosition++) {
|
||||
String line = track.get(yPosition);
|
||||
for (int xPosition = 0; xPosition < line.length(); xPosition++) {
|
||||
char possibleCarChar = line.charAt(xPosition);
|
||||
if (!allSpaceTypesAsChar.contains(possibleCarChar)) {
|
||||
if (usedSymbolForCar.contains(possibleCarChar)) {
|
||||
throw new InvalidTrackFormatException();
|
||||
}
|
||||
usedSymbolForCar.add(possibleCarChar);
|
||||
cars.add(new Car(possibleCarChar, new PositionVector(i, j)));
|
||||
cars.add(new Car(possibleCarChar, new PositionVector(xPosition, yPosition)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
//TODO: THIS
|
||||
|
||||
/**
|
||||
* @throws InvalidTrackFormatException
|
||||
*/
|
||||
private void findFinish() throws InvalidTrackFormatException {
|
||||
for (int i = 0; i < track.size(); i++) {
|
||||
String line = track.get(i);
|
||||
|
@ -141,6 +151,12 @@ public class Track implements TrackSpecification {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to find the PositionVector of a chosen character
|
||||
*
|
||||
* @param symbol char that we are looking for on the track
|
||||
* @return the PositionVector of the desired char
|
||||
*/
|
||||
private PositionVector findChar(char symbol) {
|
||||
PositionVector vector = null;
|
||||
for (int i = 0; i < track.size(); i++) {
|
||||
|
@ -154,6 +170,12 @@ public class Track implements TrackSpecification {
|
|||
return vector;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that places a character at a chosen position
|
||||
*
|
||||
* @param positionVector position where char will be placed
|
||||
* @param symbol char that should be placed at desired position
|
||||
*/
|
||||
private void drawCharOnTrackIndicator(PositionVector positionVector, char symbol) {
|
||||
String line = track.get(positionVector.getY());
|
||||
line = line.substring(0, positionVector.getX()) + symbol + line.substring(positionVector.getX() + 1);
|
||||
|
@ -161,30 +183,19 @@ public class Track implements TrackSpecification {
|
|||
track.add(positionVector.getY(), line);
|
||||
}
|
||||
|
||||
private void isPositionVectorOnTrack(PositionVector positionVector) throws PositionVectorNotValid {
|
||||
try{
|
||||
track.get(positionVector.getY()).charAt(positionVector.getX());
|
||||
}catch (IndexOutOfBoundsException e) {
|
||||
throw new PositionVectorNotValid();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return all Cars
|
||||
*/
|
||||
public List<Car> getCars() {
|
||||
return cars;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return finishLine
|
||||
* Method that returns the finishline as a List
|
||||
*
|
||||
* @return finishLine List
|
||||
*/
|
||||
public List<PositionVector> getFinishLine() {
|
||||
return finishLine;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the track
|
||||
* Returns the whole Track as List of Strings
|
||||
*
|
||||
* @return track as List of Strings
|
||||
*/
|
||||
public List<String> getTrack() {
|
||||
return track;
|
||||
|
@ -203,7 +214,7 @@ public class Track implements TrackSpecification {
|
|||
}
|
||||
|
||||
/**
|
||||
* This class does change the Position of the car only in the track.
|
||||
* This Method does change the Position of the car inside the track object.
|
||||
*
|
||||
* @param carIndex of the current car
|
||||
*/
|
||||
|
@ -213,8 +224,8 @@ public class Track implements TrackSpecification {
|
|||
drawCharOnTrackIndicator(carPositionVector, ConfigSpecification.SpaceType.TRACK.getValue());
|
||||
|
||||
//Redraw finishline if Car was on finish-line Position
|
||||
for(PositionVector finishLinePositionVector : finishLine){
|
||||
if(finishLinePositionVector.equals(carPositionVector)){
|
||||
for (PositionVector finishLinePositionVector : finishLine) {
|
||||
if (finishLinePositionVector.equals(carPositionVector)) {
|
||||
drawCharOnTrackIndicator(carPositionVector, finishTyp.getValue());
|
||||
}
|
||||
}
|
||||
|
@ -225,13 +236,12 @@ public class Track implements TrackSpecification {
|
|||
}
|
||||
|
||||
/**
|
||||
* This Method will check if the Car could crash at the specific position
|
||||
* This Method will check if the Car would crash at the specific position
|
||||
*
|
||||
* @param positionVector the position to check if the car could crash
|
||||
* @return true if car would crash. Else false.
|
||||
*/
|
||||
public boolean willCrashAtPosition(int carIndex, PositionVector positionVector) throws PositionVectorNotValid {
|
||||
isPositionVectorOnTrack(positionVector); //TODO: remove this line? Or Method?
|
||||
public boolean willCrashAtPosition(int carIndex, PositionVector positionVector) {
|
||||
char charAtPosition = track.get(positionVector.getY()).charAt(positionVector.getX());
|
||||
if (getCarId(carIndex) == charAtPosition) return false;
|
||||
return !(charAtPosition == ConfigSpecification.SpaceType.TRACK.value ||
|
||||
|
@ -247,8 +257,7 @@ public class Track implements TrackSpecification {
|
|||
* @param carIndex representing current Car
|
||||
* @param crashPositionVector where the Crash did happen
|
||||
*/
|
||||
public void carDoesCrash(int carIndex, PositionVector crashPositionVector) throws PositionVectorNotValid{
|
||||
isPositionVectorOnTrack(crashPositionVector); //TODO: remove this line? and Method?
|
||||
public void carDoesCrash(int carIndex, PositionVector crashPositionVector) {
|
||||
PositionVector currentCarPosition = getCarPos(carIndex);
|
||||
drawCharOnTrackIndicator(new PositionVector(currentCarPosition.getX(), currentCarPosition.getY()), ConfigSpecification.SpaceType.TRACK.getValue());
|
||||
Car car = cars.get(carIndex);
|
||||
|
@ -355,6 +364,107 @@ public class Track implements TrackSpecification {
|
|||
return currentSpace.getValue();
|
||||
}
|
||||
|
||||
public ArrayList<PositionVector> calculatePointsOnPath(PositionVector startPosition, PositionVector endPosition) {
|
||||
ArrayList<PositionVector> pathList = new ArrayList<>();
|
||||
// Use Bresenham's algorithm to determine positions.
|
||||
int x = startPosition.getX();
|
||||
int y = startPosition.getY();
|
||||
|
||||
// Relative Distance (x & y axis) between end- and starting position
|
||||
int diffX = endPosition.getX() - startPosition.getX();
|
||||
int diffY = endPosition.getY() - startPosition.getY();
|
||||
|
||||
// Absolute distance (x & y axis) between end- and starting position
|
||||
int distX = Math.abs(diffX);
|
||||
int distY = Math.abs(diffY);
|
||||
|
||||
// Direction of vector on x & y axis (-1: to left/down, 0: none, +1 : to right/up)
|
||||
int dirX = Integer.signum(diffX);
|
||||
int dirY = Integer.signum(diffY);
|
||||
|
||||
// Determine which axis is the fast direction and set parallel/diagonal step values
|
||||
int parallelStepX, parallelStepY;
|
||||
int diagonalStepX, diagonalStepY;
|
||||
int distanceSlowAxis, distanceFastAxis;
|
||||
if (distX > distY) {
|
||||
// x axis is the 'fast' direction
|
||||
parallelStepX = dirX;
|
||||
parallelStepY = 0; // parallel step only moves in x direction
|
||||
diagonalStepX = dirX;
|
||||
diagonalStepY = dirY; // diagonal step moves in both directions
|
||||
distanceSlowAxis = distY;
|
||||
distanceFastAxis = distX;
|
||||
} else {
|
||||
// y axis is the 'fast' direction
|
||||
parallelStepX = 0;
|
||||
parallelStepY = dirY; // parallel step only moves in y direction
|
||||
diagonalStepX = dirX;
|
||||
diagonalStepY = dirY; // diagonal step moves in both directions
|
||||
distanceSlowAxis = distX;
|
||||
distanceFastAxis = distY;
|
||||
}
|
||||
|
||||
int error = distanceFastAxis / 2;
|
||||
for (int step = 0; step < distanceFastAxis; step++) {
|
||||
error -= distanceSlowAxis;
|
||||
if (error < 0) {
|
||||
error += distanceFastAxis; // correct error value to be positive again
|
||||
// step into slow direction; diagonal step
|
||||
x += diagonalStepX;
|
||||
y += diagonalStepY;
|
||||
} else {
|
||||
// step into fast direction; parallel step
|
||||
x += parallelStepX;
|
||||
y += parallelStepY;
|
||||
}
|
||||
|
||||
pathList.add(new PositionVector(x, y));
|
||||
}
|
||||
return pathList;
|
||||
}
|
||||
|
||||
public int calculateNewWinPoints(PositionVector start, PositionVector finish) {
|
||||
List<PositionVector> path = calculatePointsOnPath(start, finish);
|
||||
for (PositionVector point : path) {
|
||||
if (getSpaceType(point) != null) {
|
||||
switch (getSpaceType(point)) {
|
||||
case FINISH_UP:
|
||||
if (start.getY() < finish.getY()) {
|
||||
return 1;
|
||||
} else if (start.getY() > finish.getY()) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case FINISH_DOWN:
|
||||
if (start.getY() > finish.getY()) {
|
||||
return 1;
|
||||
} else if (start.getY() < finish.getY()) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case FINISH_RIGHT:
|
||||
if (start.getX() < finish.getX()) {
|
||||
return 1;
|
||||
} else if (start.getX() > finish.getX()) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case FINISH_LEFT:
|
||||
if (start.getX() > finish.getX()) {
|
||||
return 1;
|
||||
} else if (start.getX() < finish.getX()) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a String representation of the track, including the car locations.
|
||||
*
|
||||
|
|
|
@ -6,13 +6,20 @@ import org.beryx.textio.TextTerminal;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Class representing the Userinterface.
|
||||
* Used to get inputs from users via textio.
|
||||
*
|
||||
* @author Roman Schenk
|
||||
*/
|
||||
public class UserInterface {
|
||||
|
||||
private final TextIO textIO;
|
||||
private final TextTerminal<?> textTerminal;
|
||||
|
||||
/**
|
||||
* Opens a new Terminal Window and prints the welcome Text
|
||||
* Opens a new Terminal Window and prints the welcome Text.
|
||||
*
|
||||
* @param welcomeText The Text which will be printed after the windows is opened.
|
||||
*/
|
||||
public UserInterface(String welcomeText) {
|
||||
|
@ -24,6 +31,7 @@ public class UserInterface {
|
|||
|
||||
/**
|
||||
* Prints the given Text in textTerminal
|
||||
*
|
||||
* @param text The Text which should be printed.
|
||||
*/
|
||||
public void printInformation(String text) {
|
||||
|
@ -31,21 +39,23 @@ public class UserInterface {
|
|||
}
|
||||
|
||||
/**
|
||||
* asks the user to choose one of the options given.
|
||||
* @param text Text which is printed befor the options are printed. Example: "Select Track file:"
|
||||
* Method which asks the user to choose one of the options given.
|
||||
*
|
||||
* @param text Text which is printed before the options are printed. Example: "Select Track file:"
|
||||
* @param options List with the options which can be selected.
|
||||
* @return the list index of the selected option
|
||||
*/
|
||||
public int selectOption(String text, List<String> options) {
|
||||
textTerminal.println(text + ":");
|
||||
for(int option = 0; option < options.size(); option ++) {
|
||||
for (int option = 0; option < options.size(); option++) {
|
||||
textTerminal.println(" " + (option + 1) + ": " + options.get(option));
|
||||
}
|
||||
return textIO.newIntInputReader().withMinVal(1).withMaxVal(options.size()).read("Enter your choice: ") - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* gives information which player's turn it is and asks for the direction to accelerate
|
||||
* Gives information which player is at turn and asks for the direction to accelerate or quit the game.
|
||||
*
|
||||
* @param playingCarIndex the index of the player
|
||||
* @param playingCarID the ID of the player
|
||||
* @return the direction which is selected by the player. If null -> quit game
|
||||
|
@ -70,7 +80,8 @@ public class UserInterface {
|
|||
}
|
||||
|
||||
/**
|
||||
* returns the the associated direction Object
|
||||
* Method which returns the associated direction Object.
|
||||
*
|
||||
* @param number the number which was typed by the user
|
||||
* @return the associated direction. If null -> unknown number
|
||||
*/
|
||||
|
@ -90,7 +101,8 @@ public class UserInterface {
|
|||
}
|
||||
|
||||
/**
|
||||
* prints the given Track in the terminal
|
||||
* Method to print the given Track in the terminal
|
||||
*
|
||||
* @param track the track which should be printed
|
||||
*/
|
||||
public void printTrack(Track track) {
|
||||
|
@ -98,14 +110,12 @@ public class UserInterface {
|
|||
}
|
||||
|
||||
/**
|
||||
* Method to dispose the Textterminal
|
||||
* @param text OUtput Text
|
||||
* Method to dispose of the Textterminal
|
||||
*
|
||||
* @param text Output Text
|
||||
*/
|
||||
public void quit(String text){
|
||||
public void quit(String text) {
|
||||
textIO.newStringInputReader().withMinLength(0).read(text);
|
||||
textTerminal.dispose();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package ch.zhaw.pm2.racetrack.given;
|
||||
|
||||
import ch.zhaw.pm2.racetrack.PositionVector;
|
||||
import ch.zhaw.pm2.racetrack.PositionVectorNotValid;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
@ -19,11 +18,11 @@ public interface GameSpecification {
|
|||
|
||||
int getWinner();
|
||||
|
||||
void doCarTurn(PositionVector.Direction acceleration) throws PositionVectorNotValid;
|
||||
void doCarTurn(PositionVector.Direction acceleration);
|
||||
|
||||
void switchToNextActiveCar();
|
||||
|
||||
List<PositionVector> calculatePath(PositionVector startPosition, PositionVector endPosition);
|
||||
|
||||
boolean willCarCrash(int carIndex, PositionVector position) throws PositionVectorNotValid;
|
||||
boolean willCarCrash(int carIndex, PositionVector position);
|
||||
}
|
||||
|
|
|
@ -5,13 +5,14 @@ import ch.zhaw.pm2.racetrack.PositionVector.Direction;
|
|||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Scanner;
|
||||
|
||||
public class MoveListStrategy implements MoveStrategy {
|
||||
|
||||
private List<Direction> moveList;
|
||||
private final List<Direction> moveList;
|
||||
private int pointer;
|
||||
|
||||
public MoveListStrategy(String path) throws FileNotFoundException{
|
||||
|
@ -21,13 +22,13 @@ public class MoveListStrategy implements MoveStrategy {
|
|||
}
|
||||
|
||||
private void readFile(File trackFile) throws FileNotFoundException {
|
||||
Scanner scanner = new Scanner(new FileInputStream(trackFile), "UTF-8");
|
||||
Scanner scanner = new Scanner(new FileInputStream(trackFile), StandardCharsets.UTF_8);
|
||||
Direction[] directions = Direction.values();
|
||||
while (scanner.hasNextLine()) {
|
||||
String line = scanner.nextLine();
|
||||
for (Direction dir : directions) {
|
||||
if (dir.toString().equals(line)) {
|
||||
moveList.add(dir);
|
||||
for (Direction direction : directions) {
|
||||
if (direction.toString().equals(line)) {
|
||||
moveList.add(direction);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,127 @@
|
|||
package ch.zhaw.pm2.racetrack.strategy;
|
||||
|
||||
import ch.zhaw.pm2.racetrack.PositionVector;
|
||||
import ch.zhaw.pm2.racetrack.Track;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class PathFinderMoveStrategy implements MoveStrategy{
|
||||
private Track track;
|
||||
private int carIndex;
|
||||
private List<PositionVector.Direction> moveList;
|
||||
private int pointer;
|
||||
private List<PositionVector.Direction> allDirections;
|
||||
|
||||
|
||||
public PathFinderMoveStrategy(Track track, int carIndex) {
|
||||
this.track = track;
|
||||
this.carIndex = carIndex;
|
||||
allDirections = Arrays.asList(PositionVector.Direction.values());
|
||||
createMoveList();
|
||||
}
|
||||
|
||||
|
||||
private void createMoveList(){
|
||||
PossibleMove finishedMove = null;
|
||||
List<PossibleMove> possibleMoves= new ArrayList<>();
|
||||
for(PositionVector.Direction direction : allDirections){
|
||||
possibleMoves.add(new PossibleMove(null, direction));
|
||||
}
|
||||
while(finishedMove == null){
|
||||
List<PossibleMove> newMoves = new ArrayList<>();
|
||||
for(PossibleMove previousMove : possibleMoves){
|
||||
for(PositionVector.Direction direction : allDirections){
|
||||
PossibleMove newMove = new PossibleMove(previousMove, direction);
|
||||
|
||||
if(! (newMove.crashed() || newMove.drivingLoop())){
|
||||
newMoves.add(newMove);
|
||||
}
|
||||
}
|
||||
}
|
||||
possibleMoves = newMoves;
|
||||
finishedMove = findFinishedMove(possibleMoves);
|
||||
}
|
||||
|
||||
moveList = finishedMove.directions;
|
||||
|
||||
pointer = moveList.size();
|
||||
|
||||
|
||||
}
|
||||
|
||||
private PossibleMove findFinishedMove(List<PossibleMove> moveList){
|
||||
for(PossibleMove move : moveList){
|
||||
if(move.finished()){
|
||||
return move;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public class PossibleMove {
|
||||
List<PositionVector.Direction> directions;
|
||||
List<PositionVector> positions;
|
||||
PositionVector endVelocity;
|
||||
|
||||
public PossibleMove(PossibleMove previousMove, PositionVector.Direction nextDirection){
|
||||
PositionVector startVelocity;
|
||||
PositionVector startPosition;
|
||||
positions = new ArrayList<>();
|
||||
directions = new ArrayList<>();
|
||||
if(previousMove != null){
|
||||
positions.addAll(previousMove.positions);
|
||||
directions.addAll(previousMove.directions);
|
||||
startPosition = positions.get(positions.size()-1);
|
||||
startVelocity = previousMove.endVelocity;
|
||||
}
|
||||
else {
|
||||
startPosition = track.getCarPos(carIndex);
|
||||
startVelocity = track.getCar(carIndex).getVelocity();
|
||||
}
|
||||
directions.add(nextDirection);
|
||||
endVelocity = new PositionVector(startVelocity.getX() + nextDirection.vector.getX(), startVelocity.getY() + nextDirection.vector.getY());
|
||||
positions.add(new PositionVector(startPosition.getX() + endVelocity.getX(), startPosition.getY() + endVelocity.getY()));
|
||||
}
|
||||
|
||||
public boolean finished(){
|
||||
if(track.calculateNewWinPoints(positions.get(positions.size()-2), positions.get(positions.size()-1)) == 1){
|
||||
return true;
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
|
||||
public boolean crashed() {
|
||||
for(PositionVector point : track.calculatePointsOnPath(positions.get(positions.size()-1), positions.get(positions.size()-2))) {
|
||||
if (track.willCrashAtPosition(carIndex, point)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean drivingLoop(){
|
||||
for(int i = 0; i < positions.size()-1; i++){
|
||||
if(positions.get(i).equals(positions.get(positions.size()-1))){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public PositionVector.Direction nextMove() {
|
||||
pointer -= 1;
|
||||
//TODO: Check if crash. if yes --> createMoveList();
|
||||
if (pointer >= 0) {
|
||||
return moveList.get(pointer);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,85 +0,0 @@
|
|||
package ch.zhaw.pm2.racetrack.strategy;
|
||||
|
||||
import ch.zhaw.pm2.racetrack.PositionVector;
|
||||
import ch.zhaw.pm2.racetrack.Track;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
public class PathFinderStrategy implements MoveStrategy{
|
||||
private ArrayList<tryOutPaths> possiblePaths;
|
||||
private Track track;
|
||||
List<PositionVector.Direction> directions = Arrays.asList(PositionVector.Direction.values());
|
||||
|
||||
public PathFinderStrategy(Track track, int carIndex) {
|
||||
this.track = track;
|
||||
possiblePaths = new ArrayList<>();
|
||||
}
|
||||
|
||||
private void test(){
|
||||
ArrayList<tryOutPaths> temporary = new ArrayList<>();
|
||||
Iterator<tryOutPaths> it = possiblePaths.iterator();
|
||||
|
||||
while(it.hasNext()) {
|
||||
tryOutPaths current = it.next();
|
||||
if (!current.isFeasible()) {
|
||||
it.remove();
|
||||
}
|
||||
else {
|
||||
for (PositionVector.Direction direction : directions) {
|
||||
temporary.add(current);
|
||||
if (temporary.get(temporary.size() - 1).takeDirection(direction)){
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//ab hier zu löschen
|
||||
for (tryOutPaths paths : possiblePaths){
|
||||
for (PositionVector.Direction direction : directions) {
|
||||
temporary.add(paths);
|
||||
temporary.get(temporary.size() - 1).takeDirection(direction);
|
||||
}
|
||||
}
|
||||
//bis hier löschen
|
||||
possiblePaths.clear();
|
||||
possiblePaths.addAll(temporary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PositionVector.Direction nextMove() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public class tryOutPaths {
|
||||
ArrayList<PositionVector.Direction> directionsTaken = new ArrayList<>();
|
||||
PositionVector currentPosition;
|
||||
Track track;
|
||||
private boolean feasible;
|
||||
private boolean finished;
|
||||
public tryOutPaths(Track track){
|
||||
this.track = track;
|
||||
}
|
||||
|
||||
public boolean isFeasible(){
|
||||
return feasible;
|
||||
}
|
||||
|
||||
public boolean takeDirection(PositionVector.Direction direction) {
|
||||
if(directionsTaken.size() >= 50){
|
||||
feasible = false;
|
||||
return false;
|
||||
}
|
||||
else if(finished){
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
//check if possible eventuell hier??
|
||||
directionsTaken.add(direction);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,15 +1,127 @@
|
|||
package ch.zhaw.pm2.racetrack.strategy;
|
||||
|
||||
import ch.zhaw.pm2.racetrack.PositionVector;
|
||||
import ch.zhaw.pm2.racetrack.PositionVector.Direction;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Scanner;
|
||||
|
||||
/**
|
||||
* The PathFollowerMoveStrategy class determines the next move based on a file containing points on a path.
|
||||
*/
|
||||
public class PathFollowerMoveStrategy implements MoveStrategy {
|
||||
|
||||
/**
|
||||
* The current Position of the car.
|
||||
*/
|
||||
private PositionVector currentPosition;
|
||||
/**
|
||||
* The current Velocity of the car.
|
||||
*/
|
||||
private PositionVector currentVelocity;
|
||||
/**
|
||||
* List of all points on the path.
|
||||
*/
|
||||
private final ArrayList<PositionVector> pointList;
|
||||
/**
|
||||
* The index of the next point on the path.
|
||||
*/
|
||||
private int pointer;
|
||||
|
||||
/**
|
||||
* Constructor to create a new PathFollowerMoveStrategy for a car.
|
||||
* @param path The location where the file is saved
|
||||
* @param startPosition The start position of the car
|
||||
* @throws FileNotFoundException If the file with the given path does not exist.
|
||||
*/
|
||||
public PathFollowerMoveStrategy(String path, PositionVector startPosition) throws FileNotFoundException {
|
||||
pointList = new ArrayList<>();
|
||||
pointer = 0;
|
||||
readFile(new File(path));
|
||||
currentPosition = startPosition;
|
||||
currentVelocity = new PositionVector(0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to read the given File and add the points to the pointList
|
||||
* @param trackFile the File Object which should be read
|
||||
* @throws FileNotFoundException If the file with the given path does not exist.
|
||||
*/
|
||||
public void readFile(File trackFile) throws FileNotFoundException {
|
||||
Scanner scanner = new Scanner(new FileInputStream(trackFile), StandardCharsets.UTF_8);
|
||||
while (scanner.hasNextLine()) {
|
||||
String line = scanner.nextLine();
|
||||
String[] coordinates = line.split("(\\(X:|, Y:|\\))");
|
||||
pointList.add(new PositionVector(Integer.parseInt(coordinates[1]), Integer.parseInt(coordinates[2])));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to select the direction for the next move.
|
||||
* @return The direction for the next move. null if there are no points left in the list.
|
||||
*/
|
||||
@Override
|
||||
public Direction nextMove() {
|
||||
// TODO: implementation
|
||||
throw new UnsupportedOperationException();
|
||||
// if no more points in the list --> return null
|
||||
if (pointer >= pointList.size()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// increase pointer variable if the next point is reached.
|
||||
if (pointList.get(pointer).equals(currentPosition)) {
|
||||
pointer ++;
|
||||
}
|
||||
|
||||
// calculate Vector from current Position to next Point
|
||||
PositionVector movementVector = new PositionVector(pointList.get(pointer).getX() - currentPosition.getX(), pointList.get(pointer).getY() - currentPosition.getY());
|
||||
|
||||
// select acceleration for X
|
||||
int accelerationX;
|
||||
if((movementVector.getX() == 0 && currentVelocity.getX() > 0) || //reduce velocity to 0 if the destination coordinate is reached
|
||||
(movementVector.getX() > 0 && movementVector.getX()/2.0 <= currentVelocity.getX()) || //increase velocity
|
||||
(movementVector.getX() < 0 && movementVector.getX()/2.0 < currentVelocity.getX())){ //reduce velocity
|
||||
accelerationX = -1;
|
||||
} else if((movementVector.getX() == 0 && currentVelocity.getX() < 0) || //reduce velocity to 0 if the destination coordinate is reached
|
||||
(movementVector.getX() > 0 && movementVector.getX()/2.0 > currentVelocity.getX()) || //increase velocity
|
||||
(movementVector.getX() < 0 && movementVector.getX()/2.0 >= currentVelocity.getX())) { //reduce velocity
|
||||
accelerationX = 1;
|
||||
}
|
||||
else { //no acceleration
|
||||
accelerationX = 0;
|
||||
}
|
||||
|
||||
// select acceleration for Y
|
||||
int accelerationY;
|
||||
if((movementVector.getY() == 0 && currentVelocity.getY() > 0) || //reduce velocity to 0 if the destination coordinate is reached
|
||||
(movementVector.getY() > 0 && movementVector.getY()/2.0 <= currentVelocity.getY()) || //increase velocity
|
||||
(movementVector.getY() < 0 && movementVector.getY()/2.0 < currentVelocity.getY())){ //reduce velocity
|
||||
accelerationY = -1;
|
||||
} else if((movementVector.getY() == 0 && currentVelocity.getY() < 0) || //reduce velocity to 0 if the destination coordinate is reached
|
||||
(movementVector.getY() > 0 && movementVector.getY()/2.0 > currentVelocity.getY()) || //increase velocity
|
||||
(movementVector.getY() < 0 && movementVector.getY()/2.0 >= currentVelocity.getY())) { //reduce velocity
|
||||
accelerationY = 1;
|
||||
}
|
||||
else { //no acceleration
|
||||
accelerationY = 0;
|
||||
}
|
||||
|
||||
//update current Velocity and current Position with the selected acceleration
|
||||
currentVelocity = new PositionVector(currentVelocity.getX() + accelerationX, currentVelocity.getY() + accelerationY);
|
||||
currentPosition = new PositionVector(currentPosition.getX() + currentVelocity.getX(), currentPosition.getY() + currentVelocity.getY());
|
||||
|
||||
//Find Direction for acceleration
|
||||
PositionVector acceleration = new PositionVector(accelerationX, accelerationY);
|
||||
Direction[] directions = Direction.values();
|
||||
for (Direction direction : directions) {
|
||||
if (direction.vector.equals(acceleration)) {
|
||||
return direction;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,9 +7,9 @@ import ch.zhaw.pm2.racetrack.UserInterface;
|
|||
* Let the user decide the next move.
|
||||
*/
|
||||
public class UserMoveStrategy implements MoveStrategy {
|
||||
private UserInterface userInterface;
|
||||
private int carIndex;
|
||||
private char carID;
|
||||
private final UserInterface userInterface;
|
||||
private final int carIndex;
|
||||
private final char carID;
|
||||
|
||||
public UserMoveStrategy(UserInterface userInterface, int carIndex, char carID) {
|
||||
this.userInterface = userInterface;
|
||||
|
|
|
@ -0,0 +1,228 @@
|
|||
|
||||
package ch.zhaw.pm2.racetrack;
|
||||
|
||||
import ch.zhaw.pm2.racetrack.strategy.*;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* Tests for Class Car
|
||||
*/
|
||||
class CarTest {
|
||||
|
||||
Car car;
|
||||
|
||||
// Default coordinates for tests
|
||||
int DEFAULT_X = 10;
|
||||
int DEFAULT_Y = 10;
|
||||
char DEFAULT_ID = 'f';
|
||||
|
||||
/**
|
||||
* Create a new Car Object and set Position to a defined Default Position
|
||||
*/
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
car = new Car(DEFAULT_ID, new PositionVector(DEFAULT_X, DEFAULT_Y));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getID() {
|
||||
assertEquals(DEFAULT_ID, car.getID());
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to check nextPosition with coordinates as int
|
||||
*
|
||||
* @param x the expected value for x coordinate
|
||||
* @param y the expected value for y coordinate
|
||||
*/
|
||||
void checkNextPosition(int x, int y) {
|
||||
assertEquals(new PositionVector(x, y), car.nextPosition());
|
||||
}
|
||||
|
||||
/**
|
||||
* - checks if the position of the car can be set and saved correctly with valid positions.
|
||||
* - checks if an exception is throwed and position keeps unchanged if invalid coordinates are entered.
|
||||
*/
|
||||
@Test
|
||||
void setPosition() {
|
||||
checkNextPosition(DEFAULT_X, DEFAULT_Y);
|
||||
|
||||
// List of valid Positions
|
||||
List<PositionVector> validPositions = new ArrayList<>();
|
||||
validPositions.add(new PositionVector(20, 20));
|
||||
validPositions.add(new PositionVector(0, 0));
|
||||
validPositions.add(new PositionVector(20, 0));
|
||||
validPositions.add(new PositionVector(0, 20));
|
||||
|
||||
for (PositionVector positionVector : validPositions) {
|
||||
car.setPosition(positionVector);
|
||||
assertEquals(positionVector, car.nextPosition());
|
||||
}
|
||||
|
||||
// List of invalid positions.
|
||||
List<PositionVector> invalidPositions = new ArrayList<>();
|
||||
invalidPositions.add(new PositionVector(0, -20));
|
||||
invalidPositions.add(new PositionVector(-20, 0));
|
||||
invalidPositions.add(new PositionVector(-20, -20));
|
||||
|
||||
for (PositionVector positionVector : invalidPositions) {
|
||||
boolean exception = false;
|
||||
setUp();
|
||||
try {
|
||||
car.setPosition(positionVector);
|
||||
} catch (IllegalArgumentException e) {
|
||||
exception = true;
|
||||
}
|
||||
assertTrue(exception);
|
||||
|
||||
// position should keep unchanged
|
||||
checkNextPosition(DEFAULT_X, DEFAULT_Y);
|
||||
}
|
||||
}
|
||||
|
||||
void checkVelocity(int x, int y) {
|
||||
assertEquals(new PositionVector(x, y), car.getVelocity());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks if the methods accelerate, move and getVelocity are working correctly with acceleration in all directions.
|
||||
* Checks also if velocity is calculated correctly if method accelerate is called a second time.
|
||||
*/
|
||||
@Test
|
||||
void movement() {
|
||||
// add all possible directions in a List
|
||||
PositionVector.Direction[] directions = PositionVector.Direction.values();
|
||||
|
||||
//position shouldn't be changed because velocity should be 0.
|
||||
car.move();
|
||||
checkNextPosition(DEFAULT_X, DEFAULT_Y);
|
||||
|
||||
|
||||
|
||||
for (PositionVector.Direction direction1 : directions) {
|
||||
for (PositionVector.Direction direction2 : directions) {
|
||||
|
||||
//create a new instance of Car with default coordinates and velocity 0.
|
||||
setUp();
|
||||
|
||||
//variables to save the actual expected result of method nextPosition
|
||||
int expectedNextPosX = DEFAULT_X;
|
||||
int expectedNextPosY = DEFAULT_Y;
|
||||
|
||||
//variables to save the acutal expected result of method getVelocity
|
||||
int expectedVelocityX = 0;
|
||||
int expectedVelocityY = 0;
|
||||
|
||||
car.accelerate(direction1);
|
||||
expectedVelocityX += direction1.vector.getX();
|
||||
expectedVelocityY += direction1.vector.getY();
|
||||
expectedNextPosX += direction1.vector.getX();
|
||||
expectedNextPosY += direction1.vector.getY();
|
||||
checkVelocity(expectedVelocityX, expectedVelocityY);
|
||||
checkNextPosition(expectedNextPosX, expectedNextPosY);
|
||||
|
||||
car.move();
|
||||
expectedNextPosX += direction1.vector.getX();
|
||||
expectedNextPosY += direction1.vector.getY();
|
||||
checkVelocity(expectedVelocityX, expectedVelocityY);
|
||||
checkNextPosition(expectedNextPosX, expectedNextPosY);
|
||||
|
||||
|
||||
car.accelerate(direction2);
|
||||
expectedVelocityX += direction2.vector.getX();
|
||||
expectedVelocityY += direction2.vector.getY();
|
||||
expectedNextPosX += direction2.vector.getX();
|
||||
expectedNextPosY += direction2.vector.getY();
|
||||
checkVelocity(expectedVelocityX, expectedVelocityY);
|
||||
checkNextPosition(expectedNextPosX, expectedNextPosY);
|
||||
|
||||
car.move();
|
||||
checkVelocity(expectedVelocityX, expectedVelocityY);
|
||||
expectedNextPosX += (direction1.vector.getX() + direction2.vector.getX());
|
||||
expectedNextPosY += (direction1.vector.getY() + direction2.vector.getY());
|
||||
checkNextPosition(expectedNextPosX, expectedNextPosY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* test for methods crash and isCrashed. checks if state crashed is set and returned correctly.
|
||||
*/
|
||||
@Test
|
||||
void crash() {
|
||||
assertFalse(car.isCrashed());
|
||||
car.crash();
|
||||
assertTrue(car.isCrashed());
|
||||
}
|
||||
|
||||
/**
|
||||
* test for methods setMoveStrategy. Checks if the MoveStrategy Object is saved and returned correctly
|
||||
* with all Types of MoveStrategy.
|
||||
*/
|
||||
@Test
|
||||
void MoveStrategy() {
|
||||
MoveStrategy moveStrategy;
|
||||
|
||||
moveStrategy = new DoNotMoveStrategy();
|
||||
car.setMoveStrategy(moveStrategy);
|
||||
assertEquals(moveStrategy, car.getMoveStrategy());
|
||||
|
||||
try {
|
||||
moveStrategy = new MoveListStrategy(".\\moves\\challenge-car-a.txt");
|
||||
} catch (FileNotFoundException e) {
|
||||
Assertions.fail();
|
||||
}
|
||||
car.setMoveStrategy(moveStrategy);
|
||||
assertEquals(moveStrategy, car.getMoveStrategy());
|
||||
|
||||
try {
|
||||
moveStrategy = new PathFollowerMoveStrategy(".\\follower\\challenge_points.txt", new PositionVector(0, 0));
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
car.setMoveStrategy(moveStrategy);
|
||||
assertEquals(moveStrategy, car.getMoveStrategy());
|
||||
|
||||
moveStrategy = new UserMoveStrategy(new UserInterface("Hello"),0,'a');
|
||||
car.setMoveStrategy(moveStrategy);
|
||||
assertEquals(moveStrategy, car.getMoveStrategy());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for get WinPoints
|
||||
*/
|
||||
@Test
|
||||
void getWinPoints() {
|
||||
assertEquals(0,car.getWinPoints());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for increase WinPoints
|
||||
*/
|
||||
@Test
|
||||
void increaseWinPoints() {
|
||||
car.increaseWinPoints();
|
||||
assertEquals(1,car.getWinPoints());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for deduct WinPoints
|
||||
*/
|
||||
@Test
|
||||
void deductWinPoints() {
|
||||
car.deductWinPoints();
|
||||
assertEquals(-1,car.getWinPoints());
|
||||
}
|
||||
|
||||
}
|
|
@ -1,59 +1,80 @@
|
|||
package ch.zhaw.pm2.racetrack;
|
||||
|
||||
import ch.zhaw.pm2.racetrack.strategy.UserMoveStrategy;
|
||||
import org.junit.jupiter.api.*;
|
||||
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import java.io.File;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.util.List;
|
||||
import static ch.zhaw.pm2.racetrack.Game.NO_WINNER;
|
||||
import static ch.zhaw.pm2.racetrack.PositionVector.Direction.*;
|
||||
|
||||
|
||||
/**
|
||||
* Test for Class Game
|
||||
*/
|
||||
class GameTest {
|
||||
private UserInterface userInterface;
|
||||
private Game game;
|
||||
private Track track;
|
||||
|
||||
private final String TRACK_FILE_PATH = ".\\tracks\\challenge.txt";
|
||||
private final int CAR_INDEX_ONE = 0;
|
||||
private final int CAR_INDEX_TWO = 1;
|
||||
|
||||
/**
|
||||
* This nested Class tests if the game gets initiatet correctly
|
||||
*/
|
||||
@Nested
|
||||
@DisplayName("Test correct Setup")
|
||||
class Setup {
|
||||
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
userInterface = new UserInterface("Test");
|
||||
game = new Game(userInterface);
|
||||
track = game.selectTrack(new File(".\\tracks\\challenge.txt"));
|
||||
game.selectMoveStrategy(track.getCar(0),new UserMoveStrategy(new UserInterface("Testing"),0, track.getCarId(0)));
|
||||
game.selectMoveStrategy(track.getCar(1),new UserMoveStrategy(new UserInterface("Testing"),1, track.getCarId(1)));
|
||||
try {
|
||||
track = game.selectTrack(new File(TRACK_FILE_PATH));
|
||||
} catch (InvalidTrackFormatException | FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
Assertions.fail();
|
||||
}
|
||||
game.selectMoveStrategy(track.getCar(CAR_INDEX_ONE), new UserMoveStrategy(new UserInterface("Testing"), CAR_INDEX_ONE, track.getCarId(CAR_INDEX_ONE)));
|
||||
game.selectMoveStrategy(track.getCar(CAR_INDEX_TWO), new UserMoveStrategy(new UserInterface("Testing"), CAR_INDEX_TWO, track.getCarId(CAR_INDEX_TWO)));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void getCurrentCarIndex() {
|
||||
Assertions.assertEquals(0,game.getCurrentCarIndex());
|
||||
Assertions.assertEquals(CAR_INDEX_ONE, game.getCurrentCarIndex());
|
||||
game.switchToNextActiveCar();
|
||||
Assertions.assertEquals(1,game.getCurrentCarIndex());
|
||||
Assertions.assertEquals(CAR_INDEX_TWO, game.getCurrentCarIndex());
|
||||
}
|
||||
|
||||
@Test
|
||||
void getCarId() {
|
||||
Assertions.assertEquals('a',game.getCarId(0));
|
||||
Assertions.assertEquals('b',game.getCarId(1));
|
||||
Assertions.assertEquals('a', game.getCarId(0));
|
||||
Assertions.assertEquals('b', game.getCarId(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getCarPosition() {
|
||||
Assertions.assertEquals(new PositionVector(24,22),game.getCarPosition(0));
|
||||
Assertions.assertEquals(new PositionVector(24,24),game.getCarPosition(1));
|
||||
Assertions.assertEquals(new PositionVector(24, 22), game.getCarPosition(0));
|
||||
Assertions.assertEquals(new PositionVector(24, 24), game.getCarPosition(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getCarVelocity() {
|
||||
Assertions.assertEquals(new PositionVector(0,0),game.getCarVelocity(0));
|
||||
Assertions.assertEquals(new PositionVector(0,0),game.getCarVelocity(1));
|
||||
Assertions.assertEquals(new PositionVector(0, 0), game.getCarVelocity(0));
|
||||
Assertions.assertEquals(new PositionVector(0, 0), game.getCarVelocity(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getWinner() {
|
||||
Assertions.assertEquals(NO_WINNER,game.getWinner());
|
||||
Assertions.assertEquals(NO_WINNER, game.getWinner());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -67,26 +88,35 @@ class GameTest {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This nested Class makes basic manipulation after Game init.
|
||||
*/
|
||||
@Nested
|
||||
@DisplayName("Basic manipulation")
|
||||
class manipulation {
|
||||
class Manipulation {
|
||||
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
userInterface = new UserInterface("Test");
|
||||
game = new Game(userInterface);
|
||||
track = game.selectTrack(new File(".\\tracks\\challenge.txt"));
|
||||
game.selectMoveStrategy(track.getCar(0),new UserMoveStrategy(new UserInterface("Testing"),0, track.getCarId(0)));
|
||||
game.selectMoveStrategy(track.getCar(1),new UserMoveStrategy(new UserInterface("Testing"),1, track.getCarId(1)));
|
||||
try {
|
||||
track = game.selectTrack(new File(TRACK_FILE_PATH));
|
||||
} catch (InvalidTrackFormatException | FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
Assertions.fail();
|
||||
}
|
||||
game.selectMoveStrategy(track.getCar(CAR_INDEX_ONE), new UserMoveStrategy(new UserInterface("Testing"), CAR_INDEX_ONE, track.getCarId(CAR_INDEX_ONE)));
|
||||
game.selectMoveStrategy(track.getCar(CAR_INDEX_TWO), new UserMoveStrategy(new UserInterface("Testing"), CAR_INDEX_TWO, track.getCarId(CAR_INDEX_TWO)));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void carTurnCorrect() {
|
||||
try {
|
||||
game.doCarTurn(PositionVector.Direction.RIGHT);
|
||||
Assertions.assertEquals(new PositionVector(1,0),game.getCarVelocity(0));
|
||||
} catch (PositionVectorNotValid positionVectorNotValid) {
|
||||
positionVectorNotValid.printStackTrace();
|
||||
game.doCarTurn(RIGHT);
|
||||
Assertions.assertEquals(new PositionVector(1, 0), game.getCarVelocity(0));
|
||||
} catch (PositionVectorNotValidException positionVectorNotValidException) {
|
||||
positionVectorNotValidException.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -95,10 +125,112 @@ class GameTest {
|
|||
try {
|
||||
game.doCarTurn(PositionVector.Direction.UP);
|
||||
Assertions.assertTrue(game.onlyOneCarLeft());
|
||||
} catch (PositionVectorNotValid positionVectorNotValid) {
|
||||
positionVectorNotValid.printStackTrace();
|
||||
} catch (PositionVectorNotValidException positionVectorNotValidException) {
|
||||
positionVectorNotValidException.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This nested Class tests a Playtrough. And implements a UserInterface interagtion to pretend a real player
|
||||
*/
|
||||
@Nested
|
||||
@DisplayName("Playtrough")
|
||||
class Play {
|
||||
private Game game;
|
||||
|
||||
@Test
|
||||
void winner() {
|
||||
game = new Game(new interFace("Test",new Integer[]{0,2,1},new PositionVector.Direction[]{RIGHT,
|
||||
RIGHT,
|
||||
RIGHT,
|
||||
NONE,
|
||||
NONE,
|
||||
NONE,
|
||||
NONE,
|
||||
UP,
|
||||
LEFT,
|
||||
LEFT,
|
||||
LEFT,
|
||||
LEFT,
|
||||
UP_LEFT,
|
||||
NONE,
|
||||
RIGHT,
|
||||
RIGHT,
|
||||
RIGHT,
|
||||
NONE,
|
||||
LEFT,
|
||||
DOWN_LEFT,
|
||||
DOWN_LEFT,
|
||||
LEFT,
|
||||
LEFT,
|
||||
NONE,
|
||||
RIGHT,
|
||||
NONE,
|
||||
DOWN,
|
||||
DOWN,
|
||||
RIGHT,
|
||||
NONE,
|
||||
RIGHT,
|
||||
DOWN,
|
||||
NONE,
|
||||
UP_RIGHT,
|
||||
RIGHT,
|
||||
UP_RIGHT,
|
||||
UP_RIGHT,
|
||||
RIGHT,
|
||||
RIGHT}));
|
||||
game.initPhase();
|
||||
Assertions.assertEquals("a",game.gamePhase());
|
||||
}
|
||||
|
||||
@Test
|
||||
void crashA() {
|
||||
game = new Game(new interFace("Test",new Integer[]{0,2,2},new PositionVector.Direction[]{UP}));
|
||||
game.initPhase();
|
||||
Assertions.assertEquals("b",game.gamePhase());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class interFace extends UserInterface {
|
||||
|
||||
private final PositionVector.Direction[] directions;
|
||||
private final Integer[] instructions;
|
||||
private int pointerDir,pointerInstruction;
|
||||
|
||||
|
||||
public interFace(String welcometxt, Integer[] instructions, PositionVector.Direction[] directions) {
|
||||
super(welcometxt);
|
||||
pointerDir = -1;
|
||||
pointerInstruction = -1;
|
||||
this.instructions = instructions;
|
||||
this.directions = directions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int selectOption(String text, List<String> options) {
|
||||
pointerInstruction++;
|
||||
return instructions[pointerInstruction];
|
||||
|
||||
}
|
||||
|
||||
public void printInformation(String text) {
|
||||
}
|
||||
|
||||
public void printTrack(Track track) {
|
||||
}
|
||||
|
||||
public void quit(String text) {
|
||||
}
|
||||
|
||||
public PositionVector.Direction selectDirection(int playingCarIndex, char playingCarID) {
|
||||
pointerDir += 1;
|
||||
if(pointerDir < directions.length) {
|
||||
return directions[pointerDir];
|
||||
}
|
||||
return NONE;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,10 +21,11 @@ public class TrackTest {
|
|||
File file = new File(".\\tracks\\challenge.txt");
|
||||
try {
|
||||
trackObj = new Track(file);
|
||||
|
||||
} catch (Exception | PositionVectorNotValid e) {
|
||||
System.err.println("Error in Test compareTrack" + e.getMessage());
|
||||
} catch (FileNotFoundException | InvalidTrackFormatException e) {
|
||||
e.printStackTrace();
|
||||
Assertions.fail();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -79,7 +80,7 @@ public class TrackTest {
|
|||
track.add("##################################################");
|
||||
track.add("##################################################");
|
||||
Assertions.assertLinesMatch(track, trackObj.getTrack());
|
||||
} catch (FileNotFoundException | InvalidTrackFormatException | PositionVectorNotValid e) {
|
||||
} catch (FileNotFoundException | InvalidTrackFormatException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
@ -108,28 +109,19 @@ public class TrackTest {
|
|||
@Test
|
||||
@DisplayName("Will Car Crash")
|
||||
void willCarCrash() {
|
||||
try {
|
||||
//Car will Crash
|
||||
Assertions.assertTrue(trackObj.willCrashAtPosition(0, new PositionVector(25, 21)));
|
||||
//Car will not Crash and is on track
|
||||
Assertions.assertFalse(trackObj.willCrashAtPosition(0, new PositionVector(7, 22)));
|
||||
//Car will not Crash and is on finishLine
|
||||
Assertions.assertFalse(trackObj.willCrashAtPosition(0, trackObj.getFinishLine().get(0)));
|
||||
} catch (PositionVectorNotValid positionVectorNotValid) {
|
||||
positionVectorNotValid.printStackTrace();
|
||||
Assertions.fail("Test should not throw error");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Make Car Crash")
|
||||
void makeCarCrash() {
|
||||
try {
|
||||
trackObj.carDoesCrash(0, new PositionVector(6, 22));
|
||||
} catch (PositionVectorNotValid positionVectorNotValid) {
|
||||
positionVectorNotValid.printStackTrace();
|
||||
Assertions.fail("Test should not throw exception");
|
||||
}
|
||||
Assertions.assertEquals(Track.CRASH_INDICATOR, trackObj.getTrack().get(22).charAt(6));
|
||||
Assertions.assertTrue(trackObj.getCar(0).isCrashed());
|
||||
}
|
||||
|
@ -139,14 +131,13 @@ public class TrackTest {
|
|||
@DisplayName("Negative TestCase")
|
||||
class negativeClass {
|
||||
File file;
|
||||
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
file = new File(".\\tracks\\challenge.txt");
|
||||
try {
|
||||
trackObj = new Track(file);
|
||||
|
||||
} catch (Exception | PositionVectorNotValid e) {
|
||||
} catch (InvalidTrackFormatException | FileNotFoundException e) {
|
||||
System.err.println("Error in Test compareTrack" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
@ -164,14 +155,5 @@ public class TrackTest {
|
|||
File testfile = new File(".\\src\\test\\InvalidTracks\\sameCar.txt");
|
||||
Assertions.assertThrows(InvalidTrackFormatException.class, () -> new Track(testfile));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Invalid Position Vector used")
|
||||
void invalidPositionVector() {
|
||||
Assertions.assertThrows(PositionVectorNotValid.class, () -> trackObj.willCrashAtPosition(0, new PositionVector(100, 200)));
|
||||
Assertions.assertThrows(PositionVectorNotValid.class, () -> trackObj.carDoesCrash(1,new PositionVector(200,100)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue