Compare commits

...
38 Commits
Author SHA1 Message Date
romanschenk37 7f9b0bafe4 Merge branch 'main' into Strategy
# Conflicts:
#	src/main/java/ch/zhaw/pm2/racetrack/Game.java
#	src/main/java/ch/zhaw/pm2/racetrack/Track.java
#	src/test/java/ch/zhaw/pm2/racetrack/GameTest.java
2022-03-25 09:21:12 +01:00
Leonardo Brandenberger 2366f798ca added all javadocs to class Track 2022-03-25 08:58:34 +01:00
romanschenk37 d6a9b5f1aa fixed PathFinderMoveStrategy 2022-03-25 08:58:01 +01:00
Leonardo Brandenberger 13012c1d4b Merge remote-tracking branch 'origin/main'
# Conflicts:
#	src/main/java/ch/zhaw/pm2/racetrack/Track.java
2022-03-25 08:52:41 +01:00
romanschenk37 448e34e869 fixed PathFinderMoveStrategy 2022-03-25 00:10:07 +01:00
romanschenk37 b01bee0142 fixed PathFinderMoveStrategy 2022-03-25 00:02:04 +01:00
romanschenk37 7c8cf55ac2 fix calculateNewWinPoints 2022-03-24 19:14:36 +01:00
romanschenk37 0a57afc3c7 Merge remote-tracking branch 'origin/Strategy' into Strategy 2022-03-24 19:05:01 +01:00
romanschenk37 e84bce43af fix getWinner in Game.java
working on PathFinderMoveStrategy
2022-03-24 19:04:43 +01:00
Andrin Fassbind 1a3a96218c refactor Track 2022-03-24 18:49:07 +01:00
Andrin Fassbind 19eb41066c GameTest.java correct 2022-03-24 18:45:59 +01:00
Andrin Fassbind 95ef0b9d76 refactor gametest 2022-03-24 18:33:29 +01:00
romanschenk37 30162df956 Merge remote-tracking branch 'origin/Strategy' into Strategy 2022-03-24 18:18:20 +01:00
romanschenk37 d777b87549 fix in Method calculateNewWinPoints 2022-03-24 18:18:07 +01:00
Andrin Fassbind 7b6fc70e05 removed PositionVectorNotValidException.java 2022-03-24 17:53:35 +01:00
Andrin Fassbind a2dcc1b0d8 Merge remote-tracking branch 'origin/Strategy' into Strategy 2022-03-24 17:52:21 +01:00
Andrin Fassbind badec0d16f removed PositionVectorNotValidException.java 2022-03-24 17:50:03 +01:00
romanschenk37 82911fcfb6 merge Game.java 2022-03-24 17:45:15 +01:00
romanschenk37 f133f4305d Merge branch 'main' into Strategy
# Conflicts:
#	src/main/java/ch/zhaw/pm2/racetrack/Game.java
2022-03-24 17:43:40 +01:00
romanschenk37 0656b77662 worked on PathFinderMoveStrategy and Refactoring in Game.java 2022-03-24 17:38:40 +01:00
Leonardo Brandenberger c997730abf Merge remote-tracking branch 'origin/main'
# Conflicts:
#	src/main/java/ch/zhaw/pm2/racetrack/Track.java
2022-03-24 17:33:11 +01:00
Andrin Fassbind f6a16181cf removed PositionVectorNotValidException.java 2022-03-24 17:27:30 +01:00
Leonardo Brandenberger 2b2834f47a added all javadocs to class Track 2022-03-24 17:26:44 +01:00
romanschenk37 ad2e1c3104 worked on PathFinderMoveStrategy and Refactoring in Game.java 2022-03-24 17:09:05 +01:00
Andrin Fassbind eca2e2eb9b refactored merge conflict in Track 2022-03-24 17:02:42 +01:00
Andrin Fassbind 80b07111de Merge remote-tracking branch 'origin/main'
# Conflicts:
#	src/main/java/ch/zhaw/pm2/racetrack/Game.java
#	src/main/java/ch/zhaw/pm2/racetrack/Track.java
2022-03-24 16:57:00 +01:00
Andrin Fassbind a143a9c7d7 refactoring several classes 2022-03-24 16:50:18 +01:00
Leonardo Brandenberger 31ec1e9e64 refactoring done in several classes 2022-03-24 16:30:59 +01:00
Leonardo Brandenberger bc0dd52360 added elements to README.md 2022-03-24 14:38:08 +01:00
Leonardo Brandenberger 015dbac96c added elements to README.md 2022-03-24 14:36:48 +01:00
romanschenk37 4b5802a0d0 added PathFinderMoveStrategy in Game. 2022-03-24 13:59:46 +01:00
romanschenk37 a689df5fe1 Merge branch 'main' into Strategy 2022-03-24 13:41:42 +01:00
Leonardo Brandenberger 4ce26578b9 Merge pull request #30 from PM2-IT21bWIN-ruiz-mach-krea/Game
refactoring of Method calculatePath from Game.java to Track.java
2022-03-24 13:35:38 +01:00
Leonardo Brandenberger cf1a8d703e continued class PathFinderStrategy 2022-03-21 01:26:26 +01:00
Andrin Fassbind 6403ee958f Merge remote-tracking branch 'origin/Strategy' into Strategy 2022-03-20 16:59:50 +01:00
Leonardo Brandenberger 7c841abfc6 continued class PathFinderStrategy 2022-03-20 16:33:03 +01:00
Andrin Fassbind ae62f9e98c Merge branch 'Game' into Strategy 2022-03-20 13:45:44 +01:00
Leonardo Brandenberger 0b423b759e started method PathFinderStrategy, (much work needed still no real solution in mind) 2022-03-20 03:26:00 +01:00
18 changed files with 474 additions and 239 deletions
File diff suppressed because one or more lines are too long
+8 -3
View File
@@ -20,20 +20,25 @@ You will then be prompted to select a track file from the selection by entering
> > 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 > > 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 + 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 > 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 + Path Follow Move Strategy
> A list of point has to be given to the follow move strategy, the strategy will then calculate the route to cross each point in the given order. > 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 + Path Finder Strategy
> The pathfinder Strategy Calculates a route itself and follows it direction fully automatically. > The pathfinder Strategy Calculates a route itself and follows it direction fully automatically.
The shown Track can be interpreted as following:<br> The shown Track can be interpreted as following:<br>
'spaces' are part of the raceable track.<br>
'#' is a Wall<br> '#' is a Wall<br>
'>,<,^,v' are finish line components<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. 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 ### 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. 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 ## 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. 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 ## Class Diagramm
![Classdiagramm of this program](/Klassendiagramm.drawio)
+14 -14
View File
@@ -3,14 +3,12 @@ package ch.zhaw.pm2.racetrack;
import ch.zhaw.pm2.racetrack.given.CarSpecification; import ch.zhaw.pm2.racetrack.given.CarSpecification;
import ch.zhaw.pm2.racetrack.strategy.MoveStrategy; import ch.zhaw.pm2.racetrack.strategy.MoveStrategy;
import java.util.Vector;
/** /**
* Class representing a car on the racetrack. * Class representing a car on the racetrack.
* Uses {@link PositionVector} to store current position on the track grid and current velocity vector. * 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. * 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. * The car is able to calculate the endpoint of its next position and on request moves to it.
*/ */
public class Car implements CarSpecification { public class Car implements CarSpecification {
@@ -46,6 +44,7 @@ public class Car implements CarSpecification {
/** /**
* Constructor for class Car * Constructor for class Car
*
* @param id unique Car identification * @param id unique Car identification
* @param position initial position of the Car * @param position initial position of the Car
*/ */
@@ -59,16 +58,16 @@ public class Car implements CarSpecification {
* *
* @return id of the car. * @return id of the car.
*/ */
public char getID(){ public char getID() {
return id; return id;
} }
public void increaseWinPoints() { public void increaseWinPoints() {
winPoints ++; winPoints++;
} }
public void deductWinPoints() { public void deductWinPoints() {
winPoints --; winPoints--;
} }
public int getWinPoints() { public int getWinPoints() {
@@ -80,9 +79,10 @@ public class Car implements CarSpecification {
* *
* @return velocity current velocity of the car. * @return velocity current velocity of the car.
*/ */
public PositionVector getVelocity(){ public PositionVector getVelocity() {
return velocity; return velocity;
} }
/** /**
* Set this Car position directly, regardless of current position and 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. * 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) { public void setPosition(final PositionVector position) {
if (position.getX() < 0 || position.getY() < 0) { if (position.getX() < 0 || position.getY() < 0) {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} } else {
else {
this.position = position; this.position = position;
} }
} }
@@ -109,7 +108,7 @@ public class Car implements CarSpecification {
*/ */
@Override @Override
public PositionVector nextPosition() { 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 @Override
public void accelerate(PositionVector.Direction acceleration) { 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) { acceleration.vector.getY() < -1 || acceleration.vector.getY() > 1) {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} } else {
else {
velocity = new PositionVector(velocity.getX() + acceleration.vector.getX(), velocity = new PositionVector(velocity.getX() + acceleration.vector.getX(),
velocity.getY() + acceleration.vector.getY()); velocity.getY() + acceleration.vector.getY());
} }
@@ -161,6 +159,7 @@ public class Car implements CarSpecification {
/** /**
* Set move strategy * Set move strategy
*
* @param moveStrategy Strategy to be implemented * @param moveStrategy Strategy to be implemented
*/ */
public void setMoveStrategy(MoveStrategy moveStrategy) { public void setMoveStrategy(MoveStrategy moveStrategy) {
@@ -169,6 +168,7 @@ public class Car implements CarSpecification {
/** /**
* Get current move strategy * Get current move strategy
*
* @return MoveStrategy * @return MoveStrategy
*/ */
public MoveStrategy getMoveStrategy() { public MoveStrategy getMoveStrategy() {
+48 -27
View File
@@ -26,8 +26,11 @@ public class Game implements GameSpecification {
this.userInterface = userInterface; 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 folder = new File("tracks");
File[] listOfFiles = folder.listFiles(); File[] listOfFiles = folder.listFiles();
if (listOfFiles.length > 0) { if (listOfFiles.length > 0) {
@@ -35,13 +38,23 @@ public class Game implements GameSpecification {
for (File file : listOfFiles) { for (File file : listOfFiles) {
tracks.add(file.getName()); tracks.add(file.getName());
} }
File selectedTrack = listOfFiles[userInterface.selectOption("Select Track file", tracks)]; File selectedTrack = listOfFiles[userInterface.selectOption("Select Track file", tracks)];
try {
selectTrack(selectedTrack); 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<>(); List<String> moveStrategies = new ArrayList<>();
moveStrategies.add("Do not move Strategy"); moveStrategies.add("Do not move Strategy");
moveStrategies.add("User Move Strategy"); moveStrategies.add("User Move Strategy");
moveStrategies.add("Move List Strategy"); moveStrategies.add("Move List Strategy");
moveStrategies.add("Path Follow Move Strategy"); moveStrategies.add("Path Follow Move Strategy");
moveStrategies.add("Path Finder Move Strategy");
for (int i = 0; i < track.getCarCount(); i++) { for (int i = 0; i < track.getCarCount(); i++) {
Car car = track.getCar(i); Car car = track.getCar(i);
MoveStrategy moveStrategy = null; MoveStrategy moveStrategy = null;
@@ -49,23 +62,22 @@ public class Game implements GameSpecification {
String filePath; String filePath;
int moveStrategie = userInterface.selectOption( int moveStrategie = userInterface.selectOption(
"Select Strategy for Car " + i + " (" + track.getCarId(i) + ")", moveStrategies); "Select Strategy for Car " + i + " (" + track.getCarId(i) + ")", moveStrategies);
switch (moveStrategie + 1) { switch (moveStrategie) {
case 1: case 0:
moveStrategy = new DoNotMoveStrategy(); moveStrategy = new DoNotMoveStrategy();
break; break;
case 2: case 1:
moveStrategy = new UserMoveStrategy(userInterface, i, track.getCarId(i)); moveStrategy = new UserMoveStrategy(userInterface, i, track.getCarId(i));
break; break;
case 3: case 2:
filePath = ".\\moves\\" + selectedTrack.getName().split("\\.")[0] + "-car-" + track.getCar(i).getID() + ".txt"; filePath = ".\\moves\\" + selectedTrack.getName().split("\\.")[0] + "-car-" + track.getCar(i).getID() + ".txt";
try { try {
moveStrategy = new MoveListStrategy(filePath); moveStrategy = new MoveListStrategy(filePath);
} catch (FileNotFoundException e) { } catch (FileNotFoundException e) {
userInterface.printInformation("There is no Move-List implemented. Choose another Strategy!"); userInterface.printInformation("There is no Move-List implemented. Choose another Strategy!");
} }
//TODO: Backslash kompatibel für Linux
break; break;
case 4: case 3:
filePath = ".\\follower\\" + selectedTrack.getName().split("\\.")[0] + "_points.txt"; filePath = ".\\follower\\" + selectedTrack.getName().split("\\.")[0] + "_points.txt";
try { try {
moveStrategy = new PathFollowerMoveStrategy(filePath, track.getCarPos(i)); moveStrategy = new PathFollowerMoveStrategy(filePath, track.getCarPos(i));
@@ -73,6 +85,9 @@ public class Game implements GameSpecification {
userInterface.printInformation("There is no Point-List implemented. Choose another Strategy!"); userInterface.printInformation("There is no Point-List implemented. Choose another Strategy!");
} }
break; break;
case 4:
moveStrategy = new PathFinderMoveStrategy(track, i);
break;
} }
} }
selectMoveStrategy(car, moveStrategy); selectMoveStrategy(car, moveStrategy);
@@ -86,17 +101,11 @@ public class Game implements GameSpecification {
/** /**
* The functionality was taken out of init to automate testing * The functionality was taken out of init to automate testing
*
* @param selectedTrack * @param selectedTrack
*/ */
Track selectTrack(File selectedTrack) { Track selectTrack(File selectedTrack) throws InvalidTrackFormatException,FileNotFoundException {
try {
track = new Track(selectedTrack); track = new Track(selectedTrack);
return track; return track;
} catch (FileNotFoundException | PositionVectorNotValid | InvalidTrackFormatException e) {
e.printStackTrace();
}
return null;
} }
/** /**
@@ -160,14 +169,14 @@ public class Game implements GameSpecification {
*/ */
@Override @Override
public int getWinner() { public int getWinner() {
if (onlyOneCarLeft()) {
return currentCarIndex;
}
for (int i = 0; i < track.getCarCount(); i++) { for (int i = 0; i < track.getCarCount(); i++) {
if (track.getCar(i).getWinPoints() == 1) { if (track.getCar(i).getWinPoints() == 1) {
return i; return i;
} }
} }
if (onlyOneCarLeft()) {
return currentCarIndex;
}
return NO_WINNER; return NO_WINNER;
} }
@@ -198,9 +207,8 @@ public class Game implements GameSpecification {
* for this turn * for this turn
*/ */
@Override @Override
public void doCarTurn(Direction acceleration) throws PositionVectorNotValid { public void doCarTurn(Direction acceleration) {
track.getCar(currentCarIndex).accelerate(acceleration); track.getCar(currentCarIndex).accelerate(acceleration);
PositionVector crashPosition = null; PositionVector crashPosition = null;
List<PositionVector> positionList = calculatePath(track.getCarPos(currentCarIndex), track.getCar(currentCarIndex).nextPosition()); List<PositionVector> positionList = calculatePath(track.getCarPos(currentCarIndex), track.getCar(currentCarIndex).nextPosition());
for (int i = 0; i < positionList.size(); i++) { for (int i = 0; i < positionList.size(); i++) {
@@ -213,15 +221,25 @@ public class Game implements GameSpecification {
break; break;
} }
} }
int newWinPoints = track.calculateNewWinPoints(track.getCarPos(currentCarIndex), track.getCar(currentCarIndex).nextPosition());
if(newWinPoints == 1){
track.getCar(currentCarIndex).increaseWinPoints();
}else if(newWinPoints == -1){
track.getCar(currentCarIndex).deductWinPoints();
}
if (crashPosition != null) { if (crashPosition != null) {
track.carDoesCrash(currentCarIndex, crashPosition); track.carDoesCrash(currentCarIndex, crashPosition);
} else { } else {
calculateWinner(track.getCarPos(currentCarIndex), track.getCar(currentCarIndex).nextPosition(), currentCarIndex);
track.moveCar(currentCarIndex); 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) { while (carsMoving() && getWinner() == NO_WINNER) {
userInterface.printTrack(track); userInterface.printTrack(track);
Direction direction; Direction direction;
@@ -275,11 +293,16 @@ public class Game implements GameSpecification {
} }
/**
* 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) { private void calculateWinner(PositionVector start, PositionVector finish, int carIndex) {
List<PositionVector> path = calculatePath(start, finish); List<PositionVector> path = calculatePath(start, finish);
for (PositionVector point : path) { for (PositionVector point : path) {
if (track.getSpaceType(point) != null) {
switch (track.getSpaceType(point)) { switch (track.getSpaceType(point)) {
case FINISH_UP: case FINISH_UP:
if (start.getY() < finish.getY()) { if (start.getY() < finish.getY()) {
@@ -310,8 +333,6 @@ public class Game implements GameSpecification {
} }
break; break;
} }
}
} }
} }
@@ -324,7 +345,7 @@ public class Game implements GameSpecification {
* @return A boolean indicator if the car would crash with a WALL or another car. * @return A boolean indicator if the car would crash with a WALL or another car.
*/ */
@Override @Override
public boolean willCarCrash(int carIndex, PositionVector position) throws PositionVectorNotValid { public boolean willCarCrash(int carIndex, PositionVector position) {
return track.willCrashAtPosition(carIndex, position); return track.willCrashAtPosition(carIndex, position);
} }
@@ -4,6 +4,7 @@ package ch.zhaw.pm2.racetrack;
* Class for Exception when invalid Fileformat is used. * Class for Exception when invalid Fileformat is used.
*/ */
public class InvalidFileFormatException extends Exception { public class InvalidFileFormatException extends Exception {
public InvalidFileFormatException(){super();}
public InvalidFileFormatException(String errorMessage) { public InvalidFileFormatException(String errorMessage) {
super(errorMessage); super(errorMessage);
} }
@@ -1,12 +1,11 @@
package ch.zhaw.pm2.racetrack; package ch.zhaw.pm2.racetrack;
import java.io.FileNotFoundException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class Main { 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\""); UserInterface userInterface = new UserInterface("Hello and Welcome to Racetrack by Team02-\"AngryNerds\"");
while (true) { while (true) {
Game game = new Game(userInterface); Game game = new Game(userInterface);
@@ -17,19 +16,17 @@ public class Main {
optionsNewGame.add("exit"); optionsNewGame.add("exit");
optionsNewGame.add("new game"); optionsNewGame.add("new game");
String winnerText; String winnerText;
if(winner == null){ if (winner == null) {
winnerText = "There was no winner."; winnerText = "There was no winner.";
} } else {
else {
winnerText = "The Winner was Car " + winner; winnerText = "The Winner was Car " + winner;
} }
int selectedOption = userInterface.selectOption(winnerText + "\nStart new Game?", optionsNewGame); 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."); userInterface.quit("Thank you and goodbye\npress enter to close the application.");
break; break;
} }
} } else {
else {
userInterface.quit("The initialisation of the game failed. Press enter to close the application."); userInterface.quit("The initialisation of the game failed. Press enter to close the application.");
break; break;
} }
@@ -7,8 +7,8 @@ package ch.zhaw.pm2.racetrack;
* Created by mach 21.01.2020 * Created by mach 21.01.2020
*/ */
public final class PositionVector { public final class PositionVector {
private int x; // horizontal component (position / velocity) private final int x; // horizontal component (position / velocity)
private int y; // vertical component (position / velocity) private final int y; // vertical component (position / velocity)
/** /**
* Enum representing a direction on the track grid. * 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() {}
}
+113 -49
View File
@@ -3,7 +3,10 @@ package ch.zhaw.pm2.racetrack;
import ch.zhaw.pm2.racetrack.given.ConfigSpecification; import ch.zhaw.pm2.racetrack.given.ConfigSpecification;
import ch.zhaw.pm2.racetrack.given.TrackSpecification; 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.ArrayList;
import java.util.List; import java.util.List;
import java.util.Scanner; import java.util.Scanner;
@@ -57,19 +60,19 @@ import java.util.Scanner;
public class Track implements TrackSpecification { public class Track implements TrackSpecification {
public static final char CRASH_INDICATOR = 'X'; public static final char CRASH_INDICATOR = 'X';
private List<String> track; private final List<String> track;
private List<Car> cars; private final List<Car> cars;
private final List<PositionVector> finishLine; private final List<PositionVector> finishLine;
private ConfigSpecification.SpaceType finishTyp; private ConfigSpecification.SpaceType finishTyp;
/** /**
* Initialize a Track from the given track file. * Initializes the Track from the given track File including the cars.
* * Throws an corresponding error if one of the conditions are not met to build a track.
* @param trackFile Reference to a file containing the track data * @param trackFile Reference to a file containing the track data
* @throws FileNotFoundException if the given track file could not be found * @throws FileNotFoundException if the given track file could not be found
* @throws InvalidTrackFormatException if the track file contains invalid data (no tracklines, ...) * @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<>(); track = new ArrayList<>();
cars = new ArrayList<>(); cars = new ArrayList<>();
finishLine = new ArrayList<>(); finishLine = new ArrayList<>();
@@ -85,13 +88,17 @@ public class Track implements TrackSpecification {
* @throws FileNotFoundException if the FilePath is invalid. * @throws FileNotFoundException if the FilePath is invalid.
*/ */
private void readFile(File trackFile) throws FileNotFoundException { 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()) { while (scanner.hasNextLine()) {
track.add(scanner.nextLine()); 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 { private void addCars() throws InvalidTrackFormatException {
ConfigSpecification.SpaceType[] spaceTypes = ConfigSpecification.SpaceType.values(); ConfigSpecification.SpaceType[] spaceTypes = ConfigSpecification.SpaceType.values();
List<Character> allSpaceTypesAsChar = new ArrayList<>(); List<Character> allSpaceTypesAsChar = new ArrayList<>();
@@ -101,23 +108,28 @@ public class Track implements TrackSpecification {
allSpaceTypesAsChar.add(spaceType.getValue()); allSpaceTypesAsChar.add(spaceType.getValue());
} }
for (int yPosition = 0; yPosition < track.size(); yPosition++) {
for (int j = 0; j < track.size(); j++) { String line = track.get(yPosition);
String line = track.get(j); for (int xPosition = 0; xPosition < line.length(); xPosition++) {
for (int i = 0; i < line.length(); i++) { char possibleCarChar = line.charAt(xPosition);
char possibleCarChar = line.charAt(i);
if (!allSpaceTypesAsChar.contains(possibleCarChar)) { if (!allSpaceTypesAsChar.contains(possibleCarChar)) {
if (usedSymbolForCar.contains(possibleCarChar)) { if (usedSymbolForCar.contains(possibleCarChar)) {
throw new InvalidTrackFormatException(); throw new InvalidTrackFormatException();
} }
usedSymbolForCar.add(possibleCarChar); usedSymbolForCar.add(possibleCarChar);
cars.add(new Car(possibleCarChar, new PositionVector(i, j))); cars.add(new Car(possibleCarChar, new PositionVector(xPosition, yPosition)));
} }
} }
} }
} }
//TODO: THIS
/**
* Determines the finish line and saves it in a list, throws an Exception if none is found.
*
* @throws InvalidTrackFormatException thrown if no finish line is found
*/
private void findFinish() throws InvalidTrackFormatException { private void findFinish() throws InvalidTrackFormatException {
for (int i = 0; i < track.size(); i++) { for (int i = 0; i < track.size(); i++) {
String line = track.get(i); String line = track.get(i);
@@ -141,6 +153,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) { private PositionVector findChar(char symbol) {
PositionVector vector = null; PositionVector vector = null;
for (int i = 0; i < track.size(); i++) { for (int i = 0; i < track.size(); i++) {
@@ -154,6 +172,12 @@ public class Track implements TrackSpecification {
return vector; 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) { private void drawCharOnTrackIndicator(PositionVector positionVector, char symbol) {
String line = track.get(positionVector.getY()); String line = track.get(positionVector.getY());
line = line.substring(0, positionVector.getX()) + symbol + line.substring(positionVector.getX() + 1); line = line.substring(0, positionVector.getX()) + symbol + line.substring(positionVector.getX() + 1);
@@ -161,30 +185,19 @@ public class Track implements TrackSpecification {
track.add(positionVector.getY(), line); 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 * Method that returns the finishline as a List
*/ *
public List<Car> getCars() { * @return finishLine List
return cars;
}
/**
* @return finishLine
*/ */
public List<PositionVector> getFinishLine() { public List<PositionVector> getFinishLine() {
return finishLine; return finishLine;
} }
/** /**
* @return the track * Returns the whole Track as List of Strings
*
* @return track as List of Strings
*/ */
public List<String> getTrack() { public List<String> getTrack() {
return track; return track;
@@ -203,7 +216,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 * @param carIndex of the current car
*/ */
@@ -213,8 +226,8 @@ public class Track implements TrackSpecification {
drawCharOnTrackIndicator(carPositionVector, ConfigSpecification.SpaceType.TRACK.getValue()); drawCharOnTrackIndicator(carPositionVector, ConfigSpecification.SpaceType.TRACK.getValue());
//Redraw finishline if Car was on finish-line Position //Redraw finishline if Car was on finish-line Position
for(PositionVector finishLinePositionVector : finishLine){ for (PositionVector finishLinePositionVector : finishLine) {
if(finishLinePositionVector.equals(carPositionVector)){ if (finishLinePositionVector.equals(carPositionVector)) {
drawCharOnTrackIndicator(carPositionVector, finishTyp.getValue()); drawCharOnTrackIndicator(carPositionVector, finishTyp.getValue());
} }
} }
@@ -225,13 +238,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 * @param positionVector the position to check if the car would crash
* @return true if car would crash. Else false. * @return true if crash otherwise false
*/ */
public boolean willCrashAtPosition(int carIndex, PositionVector positionVector) throws PositionVectorNotValid { public boolean willCrashAtPosition(int carIndex, PositionVector positionVector) {
isPositionVectorOnTrack(positionVector); //TODO: remove this line? Or Method?
char charAtPosition = track.get(positionVector.getY()).charAt(positionVector.getX()); char charAtPosition = track.get(positionVector.getY()).charAt(positionVector.getX());
if (getCarId(carIndex) == charAtPosition) return false; if (getCarId(carIndex) == charAtPosition) return false;
return !(charAtPosition == ConfigSpecification.SpaceType.TRACK.value || return !(charAtPosition == ConfigSpecification.SpaceType.TRACK.value ||
@@ -242,13 +254,12 @@ public class Track implements TrackSpecification {
} }
/** /**
* This Method will make the Car Crash. In Track and in the Car Object * This Method will mark the Car as crashed inside the track and the car Object.
* *
* @param carIndex representing current Car * @param carIndex of car that will be marked as crashed
* @param crashPositionVector where the Crash did happen * @param crashPositionVector of the location of the crash
*/ */
public void carDoesCrash(int carIndex, PositionVector crashPositionVector) throws PositionVectorNotValid{ public void carDoesCrash(int carIndex, PositionVector crashPositionVector) {
isPositionVectorOnTrack(crashPositionVector); //TODO: remove this line? and Method?
PositionVector currentCarPosition = getCarPos(carIndex); PositionVector currentCarPosition = getCarPos(carIndex);
drawCharOnTrackIndicator(new PositionVector(currentCarPosition.getX(), currentCarPosition.getY()), ConfigSpecification.SpaceType.TRACK.getValue()); drawCharOnTrackIndicator(new PositionVector(currentCarPosition.getX(), currentCarPosition.getY()), ConfigSpecification.SpaceType.TRACK.getValue());
Car car = cars.get(carIndex); Car car = cars.get(carIndex);
@@ -262,11 +273,10 @@ public class Track implements TrackSpecification {
* If the location is outside the track bounds, it is considered a wall. * If the location is outside the track bounds, it is considered a wall.
* *
* @param position The coordinates of the position to examine * @param position The coordinates of the position to examine
* @return The type of track position at the given location * @return The type of space at the desired position
*/ */
@Override @Override
public Config.SpaceType getSpaceType(PositionVector position) { public Config.SpaceType getSpaceType(PositionVector position) {
//isPositionVectorOnTrack(position); Should be used but we are not allowed to change method head. We don't use function anyway
char charAtPosition = track.get(position.getY()).charAt(position.getX()); char charAtPosition = track.get(position.getY()).charAt(position.getX());
ConfigSpecification.SpaceType[] spaceTypes = ConfigSpecification.SpaceType.values(); ConfigSpecification.SpaceType[] spaceTypes = ConfigSpecification.SpaceType.values();
for (ConfigSpecification.SpaceType spaceType : spaceTypes) { for (ConfigSpecification.SpaceType spaceType : spaceTypes) {
@@ -275,13 +285,13 @@ public class Track implements TrackSpecification {
} }
} }
return null; return ConfigSpecification.SpaceType.WALL;
} }
/** /**
* Return the number of cars. * Return the number of cars that are located in a track
* *
* @return Number of cars * @return number of cars as int
*/ */
@Override @Override
public int getCarCount() { public int getCarCount() {
@@ -355,6 +365,13 @@ public class Track implements TrackSpecification {
return currentSpace.getValue(); return currentSpace.getValue();
} }
/**
* Determines all points that lie between the two position vectors including the endpoint VectorPosition using the Bresenham algorithm.
*
* @param startPosition PositionVector of the finish coordinate
* @param endPosition PositionVector of the start coordinate
* @return ArrayList containing PositionVectors of all position that are between the start and finish including the finish position.
*/
public ArrayList<PositionVector> calculatePointsOnPath(PositionVector startPosition, PositionVector endPosition) { public ArrayList<PositionVector> calculatePointsOnPath(PositionVector startPosition, PositionVector endPosition) {
ArrayList<PositionVector> pathList = new ArrayList<>(); ArrayList<PositionVector> pathList = new ArrayList<>();
// Use Bresenham's algorithm to determine positions. // Use Bresenham's algorithm to determine positions.
@@ -414,6 +431,53 @@ public class Track implements TrackSpecification {
return pathList; return pathList;
} }
/**
* 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
* @return Number of new Winpoints for the current player.
*/
public int calculateNewWinPoints(PositionVector start, PositionVector finish) {
List<PositionVector> path = calculatePointsOnPath(start, finish);
for (PositionVector point : path) {
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;
}
}
return 0;
}
/** /**
* Return a String representation of the track, including the car locations. * Return a String representation of the track, including the car locations.
* *
@@ -6,24 +6,31 @@ import org.beryx.textio.TextTerminal;
import java.util.List; import java.util.List;
/**
* Class representing the Userinterface.
* Used to get inputs from users via textio.
*
* @author Roman Schenk
*/
public class UserInterface { public class UserInterface {
private final TextIO textIO; private final TextIO textIO;
private final TextTerminal<?> textTerminal; 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. * @param welcomeText The Text which will be printed after the windows is opened.
*/ */
public UserInterface(String welcomeText) { public UserInterface(String welcomeText) {
textIO = TextIoFactory.getTextIO(); textIO = TextIoFactory.getTextIO();
textTerminal = textIO.getTextTerminal(); textTerminal = textIO.getTextTerminal();
textTerminal.println(welcomeText + "\n"); textTerminal.println(welcomeText + "\n");
} }
/** /**
* Prints the given Text in textTerminal * Prints the given Text in textTerminal
*
* @param text The Text which should be printed. * @param text The Text which should be printed.
*/ */
public void printInformation(String text) { public void printInformation(String text) {
@@ -31,21 +38,23 @@ public class UserInterface {
} }
/** /**
* asks the user to choose one of the options given. * Method which 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:" *
* @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. * @param options List with the options which can be selected.
* @return the list index of the selected option * @return the list index of the selected option
*/ */
public int selectOption(String text, List<String> options) { public int selectOption(String text, List<String> options) {
textTerminal.println(text + ":"); 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)); textTerminal.println(" " + (option + 1) + ": " + options.get(option));
} }
return textIO.newIntInputReader().withMinVal(1).withMaxVal(options.size()).read("Enter your choice: ") - 1; 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 playingCarIndex the index of the player
* @param playingCarID the ID of the player * @param playingCarID the ID of the player
* @return the direction which is selected by the player. If null -> quit game * @return the direction which is selected by the player. If null -> quit game
@@ -70,7 +79,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 * @param number the number which was typed by the user
* @return the associated direction. If null -> unknown number * @return the associated direction. If null -> unknown number
*/ */
@@ -90,7 +100,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 * @param track the track which should be printed
*/ */
public void printTrack(Track track) { public void printTrack(Track track) {
@@ -98,14 +109,12 @@ public class UserInterface {
} }
/** /**
* Method to dispose the Textterminal * Method to dispose of the Textterminal
* @param text OUtput Text *
* @param text Output Text
*/ */
public void quit(String text){ public void quit(String text) {
textIO.newStringInputReader().withMinLength(0).read(text); textIO.newStringInputReader().withMinLength(0).read(text);
textTerminal.dispose(); textTerminal.dispose();
} }
} }
@@ -1,7 +1,6 @@
package ch.zhaw.pm2.racetrack.given; package ch.zhaw.pm2.racetrack.given;
import ch.zhaw.pm2.racetrack.PositionVector; import ch.zhaw.pm2.racetrack.PositionVector;
import ch.zhaw.pm2.racetrack.PositionVectorNotValid;
import java.util.List; import java.util.List;
@@ -19,11 +18,11 @@ public interface GameSpecification {
int getWinner(); int getWinner();
void doCarTurn(PositionVector.Direction acceleration) throws PositionVectorNotValid; void doCarTurn(PositionVector.Direction acceleration);
void switchToNextActiveCar(); void switchToNextActiveCar();
List<PositionVector> calculatePath(PositionVector startPosition, PositionVector endPosition); 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.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Scanner; import java.util.Scanner;
public class MoveListStrategy implements MoveStrategy { public class MoveListStrategy implements MoveStrategy {
private List<Direction> moveList; private final List<Direction> moveList;
private int pointer; private int pointer;
public MoveListStrategy(String path) throws FileNotFoundException{ public MoveListStrategy(String path) throws FileNotFoundException{
@@ -21,7 +22,7 @@ public class MoveListStrategy implements MoveStrategy {
} }
private void readFile(File trackFile) throws FileNotFoundException { 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(); Direction[] directions = Direction.values();
while (scanner.hasNextLine()) { while (scanner.hasNextLine()) {
String line = scanner.nextLine(); String line = scanner.nextLine();
@@ -0,0 +1,169 @@
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.List;
public class PathFinderMoveStrategy implements MoveStrategy{
private Track track;
private int carIndex;
private List<PositionVector.Direction> moveList;
private int pointer;
private List<PositionVector.Direction> allDirections;
private List<State> calculatedStates;
public PathFinderMoveStrategy(Track track, int carIndex) {
this.track = track;
this.carIndex = carIndex;
allDirections = Arrays.asList(PositionVector.Direction.values());
createMoveList();
}
private void createMoveList(){
pointer = -1;
calculatedStates = new ArrayList<>();
PossibleMove finishedMove = null;
List<PossibleMove> possibleMoves= new ArrayList<>();
for(PositionVector.Direction direction : allDirections){
PossibleMove newMove = new PossibleMove(null, direction);
if(! newMove.crashed()){
possibleMoves.add(newMove);
}
}
while(finishedMove == null){
List<PossibleMove> newMoves = new ArrayList<>();
for(PossibleMove previousMove : possibleMoves){
for(PositionVector.Direction direction : allDirections){
PossibleMove newMove = new PossibleMove(previousMove, direction);
State newState = new State(newMove.endPosition, newMove.endVelocity);
if(! (newMove.crashed() || alreadyCalculated(newState) || finishedMove != null)){
if(newMove.finished()){
finishedMove = newMove;
} else {
calculatedStates.add(newState);
newMoves.add(newMove);
}
}
}
}
possibleMoves = newMoves;
}
moveList = finishedMove.directions;
}
private boolean alreadyCalculated(State state){
for(State calculatedState: calculatedStates){
if(state.equals(calculatedState)){
return true;
}
}
return false;
}
public class State{
PositionVector position;
PositionVector velocity;
public State(PositionVector position, PositionVector velocity){
this.position = position;
this.velocity = velocity;
}
public boolean equals(State compareState){
if(compareState.position.equals(position) && compareState.velocity.equals(velocity)){
return true;
} else{
return false;
}
}
}
public class PossibleMove {
List<PositionVector.Direction> directions;
PositionVector startPosition;
PositionVector endPosition;
PositionVector endVelocity;
public PossibleMove(PossibleMove previousMove, PositionVector.Direction nextDirection){
PositionVector startVelocity;
directions = new ArrayList<>();
if(previousMove != null){
directions.addAll(previousMove.directions);
startPosition = previousMove.endPosition;
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());
endPosition = new PositionVector(startPosition.getX() + endVelocity.getX(), startPosition.getY() + endVelocity.getY());
}
public boolean finished(){
if(track.calculateNewWinPoints(startPosition, endPosition) == 1){
return true;
}
else{
return false;
}
}
public boolean crashed() {
List<PositionVector> points = track.calculatePointsOnPath(startPosition, endPosition);
for(PositionVector point : points) {
if (track.willCrashAtPosition(carIndex, point)){
return true;
}
}
if(track.calculateNewWinPoints(startPosition, endPosition) == -1){
return true;
}
return false;
}
}
@Override
public PositionVector.Direction nextMove() { //TODO check for crash and recreate movelist if crash
pointer += 1;
if (pointer < moveList.size()) {
PositionVector.Direction direction = moveList.get(pointer);
PositionVector currentVelocity = track.getCarVelocity(carIndex);
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());
System.out.println("currentVelocity:" + currentVelocity.getX()+ ","+ currentVelocity.getY());
System.out.println("newVelocity:" + newVelocity.getX()+ ","+ newVelocity.getY());
for(PositionVector point : track.calculatePointsOnPath(currentPosition, newPosition)){
if(track.willCrashAtPosition(carIndex, point)){
createMoveList();
pointer = 0;
break;
}
}
return moveList.get(pointer);
}
return null;
}
}
@@ -6,6 +6,7 @@ import ch.zhaw.pm2.racetrack.PositionVector.Direction;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Scanner; import java.util.Scanner;
@@ -25,7 +26,7 @@ public class PathFollowerMoveStrategy implements MoveStrategy {
/** /**
* List of all points on the path. * List of all points on the path.
*/ */
private ArrayList<PositionVector> pointList; private final ArrayList<PositionVector> pointList;
/** /**
* The index of the next point on the path. * The index of the next point on the path.
*/ */
@@ -51,7 +52,7 @@ public class PathFollowerMoveStrategy implements MoveStrategy {
* @throws FileNotFoundException If the file with the given path does not exist. * @throws FileNotFoundException If the file with the given path does not exist.
*/ */
public void readFile(File trackFile) throws FileNotFoundException { public 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()) { while (scanner.hasNextLine()) {
String line = scanner.nextLine(); String line = scanner.nextLine();
String[] coordinates = line.split("(\\(X:|, Y:|\\))"); String[] coordinates = line.split("(\\(X:|, Y:|\\))");
@@ -7,9 +7,9 @@ import ch.zhaw.pm2.racetrack.UserInterface;
* Let the user decide the next move. * Let the user decide the next move.
*/ */
public class UserMoveStrategy implements MoveStrategy { public class UserMoveStrategy implements MoveStrategy {
private UserInterface userInterface; private final UserInterface userInterface;
private int carIndex; private final int carIndex;
private char carID; private final char carID;
public UserMoveStrategy(UserInterface userInterface, int carIndex, char carID) { public UserMoveStrategy(UserInterface userInterface, int carIndex, char carID) {
this.userInterface = userInterface; this.userInterface = userInterface;
@@ -101,7 +101,7 @@ class CarTest {
@Test @Test
void movement() { void movement() {
// add all possible directions in a List // add all possible directions in a List
List<PositionVector.Direction> directions = Arrays.asList(PositionVector.Direction.values()); PositionVector.Direction[] directions = PositionVector.Direction.values();
//position shouldn't be changed because velocity should be 0. //position shouldn't be changed because velocity should be 0.
car.move(); car.move();
@@ -7,6 +7,7 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException;
import java.util.List; import java.util.List;
import static ch.zhaw.pm2.racetrack.Game.NO_WINNER; import static ch.zhaw.pm2.racetrack.Game.NO_WINNER;
import static ch.zhaw.pm2.racetrack.PositionVector.Direction.*; import static ch.zhaw.pm2.racetrack.PositionVector.Direction.*;
@@ -20,9 +21,9 @@ class GameTest {
private Game game; private Game game;
private Track track; private Track track;
private String TRACK_FILE_PATH = ".\\tracks\\challenge.txt"; private final String TRACK_FILE_PATH = ".\\tracks\\challenge.txt";
private int CAR_INDEX_ONE = 0; private final int CAR_INDEX_ONE = 0;
private int CAR_INDEX_TWO = 1; private final int CAR_INDEX_TWO = 1;
/** /**
* This nested Class tests if the game gets initiatet correctly * This nested Class tests if the game gets initiatet correctly
@@ -35,7 +36,12 @@ class GameTest {
void setup() { void setup() {
userInterface = new UserInterface("Test"); userInterface = new UserInterface("Test");
game = new Game(userInterface); game = new Game(userInterface);
try {
track = game.selectTrack(new File(TRACK_FILE_PATH)); 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_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))); game.selectMoveStrategy(track.getCar(CAR_INDEX_TWO), new UserMoveStrategy(new UserInterface("Testing"), CAR_INDEX_TWO, track.getCarId(CAR_INDEX_TWO)));
@@ -93,7 +99,12 @@ class GameTest {
void setup() { void setup() {
userInterface = new UserInterface("Test"); userInterface = new UserInterface("Test");
game = new Game(userInterface); game = new Game(userInterface);
try {
track = game.selectTrack(new File(TRACK_FILE_PATH)); 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_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))); game.selectMoveStrategy(track.getCar(CAR_INDEX_TWO), new UserMoveStrategy(new UserInterface("Testing"), CAR_INDEX_TWO, track.getCarId(CAR_INDEX_TWO)));
@@ -101,22 +112,14 @@ class GameTest {
@Test @Test
void carTurnCorrect() { void carTurnCorrect() {
try {
game.doCarTurn(RIGHT); game.doCarTurn(RIGHT);
Assertions.assertEquals(new PositionVector(1, 0), game.getCarVelocity(0)); Assertions.assertEquals(new PositionVector(1, 0), game.getCarVelocity(0));
} catch (PositionVectorNotValid positionVectorNotValid) {
positionVectorNotValid.printStackTrace();
}
} }
@Test @Test
void carCrash() { void carCrash() {
try {
game.doCarTurn(PositionVector.Direction.UP); game.doCarTurn(PositionVector.Direction.UP);
Assertions.assertTrue(game.onlyOneCarLeft()); Assertions.assertTrue(game.onlyOneCarLeft());
} catch (PositionVectorNotValid positionVectorNotValid) {
positionVectorNotValid.printStackTrace();
}
} }
} }
@@ -130,7 +133,7 @@ class GameTest {
@Test @Test
void winner() { void winner() {
game = new Game(new interFace("Test",new Integer[]{0,2,1},new PositionVector.Direction[]{RIGHT, game = new Game(new interFace("Test",new Integer[]{0,2,0},new PositionVector.Direction[]{RIGHT,
RIGHT, RIGHT,
RIGHT, RIGHT,
NONE, NONE,
@@ -169,31 +172,23 @@ class GameTest {
UP_RIGHT, UP_RIGHT,
RIGHT, RIGHT,
RIGHT})); RIGHT}));
try {
game.initPhase(); game.initPhase();
Assertions.assertEquals("a",game.gamePhase()); Assertions.assertEquals("a",game.gamePhase());
} catch (InvalidTrackFormatException | PositionVectorNotValid e) {
e.printStackTrace();
}
} }
@Test @Test
void crashA() { void crashA() {
game = new Game(new interFace("Test",new Integer[]{0,2,2},new PositionVector.Direction[]{UP})); game = new Game(new interFace("Test",new Integer[]{0,1,0},new PositionVector.Direction[]{UP}));
try {
game.initPhase(); game.initPhase();
Assertions.assertEquals("b",game.gamePhase()); Assertions.assertEquals("b",game.gamePhase());
} catch (InvalidTrackFormatException | PositionVectorNotValid e) {
e.printStackTrace();
}
} }
} }
private class interFace extends UserInterface { private class interFace extends UserInterface {
private final PositionVector.Direction[] directions; private PositionVector.Direction[] directions;
private final Integer[] instructions; private Integer[] instructions;
private int pointerDir,pointerInstruction; private int pointerDir,pointerInstruction;
@@ -21,10 +21,11 @@ public class TrackTest {
File file = new File(".\\tracks\\challenge.txt"); File file = new File(".\\tracks\\challenge.txt");
try { try {
trackObj = new Track(file); trackObj = new Track(file);
} catch (FileNotFoundException | InvalidTrackFormatException e) {
} catch (Exception | PositionVectorNotValid e) { e.printStackTrace();
System.err.println("Error in Test compareTrack" + e.getMessage()); Assertions.fail();
} }
} }
@Test @Test
@@ -79,7 +80,7 @@ public class TrackTest {
track.add("##################################################"); track.add("##################################################");
track.add("##################################################"); track.add("##################################################");
Assertions.assertLinesMatch(track, trackObj.getTrack()); Assertions.assertLinesMatch(track, trackObj.getTrack());
} catch (FileNotFoundException | InvalidTrackFormatException | PositionVectorNotValid e) { } catch (FileNotFoundException | InvalidTrackFormatException e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
@@ -108,28 +109,19 @@ public class TrackTest {
@Test @Test
@DisplayName("Will Car Crash") @DisplayName("Will Car Crash")
void willCarCrash() { void willCarCrash() {
try {
//Car will Crash //Car will Crash
Assertions.assertTrue(trackObj.willCrashAtPosition(0, new PositionVector(25, 21))); Assertions.assertTrue(trackObj.willCrashAtPosition(0, new PositionVector(25, 21)));
//Car will not Crash and is on track //Car will not Crash and is on track
Assertions.assertFalse(trackObj.willCrashAtPosition(0, new PositionVector(7, 22))); Assertions.assertFalse(trackObj.willCrashAtPosition(0, new PositionVector(7, 22)));
//Car will not Crash and is on finishLine //Car will not Crash and is on finishLine
Assertions.assertFalse(trackObj.willCrashAtPosition(0, trackObj.getFinishLine().get(0))); Assertions.assertFalse(trackObj.willCrashAtPosition(0, trackObj.getFinishLine().get(0)));
} catch (PositionVectorNotValid positionVectorNotValid) {
positionVectorNotValid.printStackTrace();
Assertions.fail("Test should not throw error");
}
} }
@Test @Test
@DisplayName("Make Car Crash") @DisplayName("Make Car Crash")
void makeCarCrash() { void makeCarCrash() {
try {
trackObj.carDoesCrash(0, new PositionVector(6, 22)); 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.assertEquals(Track.CRASH_INDICATOR, trackObj.getTrack().get(22).charAt(6));
Assertions.assertTrue(trackObj.getCar(0).isCrashed()); Assertions.assertTrue(trackObj.getCar(0).isCrashed());
} }
@@ -139,14 +131,13 @@ public class TrackTest {
@DisplayName("Negative TestCase") @DisplayName("Negative TestCase")
class negativeClass { class negativeClass {
File file; File file;
@BeforeEach @BeforeEach
void setup() { void setup() {
file = new File(".\\tracks\\challenge.txt"); file = new File(".\\tracks\\challenge.txt");
try { try {
trackObj = new Track(file); trackObj = new Track(file);
} catch (Exception | PositionVectorNotValid e) { } catch (InvalidTrackFormatException | FileNotFoundException e) {
System.err.println("Error in Test compareTrack" + e.getMessage()); 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"); File testfile = new File(".\\src\\test\\InvalidTracks\\sameCar.txt");
Assertions.assertThrows(InvalidTrackFormatException.class, () -> new Track(testfile)); 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)));
} }
}
} }