diff --git a/build.gradle b/build.gradle index 669126f..9b73dff 100644 --- a/build.gradle +++ b/build.gradle @@ -44,7 +44,7 @@ version = '2022.1' application { // Define the main class for the application. - mainClass = 'ch.zhaw.pm2.racetrack.ConsoleApp' + mainClass = 'ch.zhaw.pm2.racetrack.Main' } run { diff --git a/src/main/java/ch/zhaw/pm2/racetrack/Car.java b/src/main/java/ch/zhaw/pm2/racetrack/Car.java index c8739f1..8e9255e 100644 --- a/src/main/java/ch/zhaw/pm2/racetrack/Car.java +++ b/src/main/java/ch/zhaw/pm2/racetrack/Car.java @@ -24,6 +24,10 @@ public class Car implements CarSpecification { * Current position of the car on the track grid using a {@link PositionVector} */ private PositionVector position; + /** + * Points that car is holding for determining winner. + */ + private int winPoints; /** * Current velocity of the car using a {@link PositionVector} @@ -59,6 +63,18 @@ public class Car implements CarSpecification { return id; } + public void increaseWinPoints() { + winPoints ++; + } + + public void deductWinPoints() { + winPoints --; + } + + public int getWinPoints() { + return winPoints; + } + /** * Returns the current velocity of the car as a PositionVector. * diff --git a/src/main/java/ch/zhaw/pm2/racetrack/Game.java b/src/main/java/ch/zhaw/pm2/racetrack/Game.java index b0204e9..413fef3 100644 --- a/src/main/java/ch/zhaw/pm2/racetrack/Game.java +++ b/src/main/java/ch/zhaw/pm2/racetrack/Game.java @@ -1,7 +1,11 @@ package ch.zhaw.pm2.racetrack; import ch.zhaw.pm2.racetrack.given.GameSpecification; +import ch.zhaw.pm2.racetrack.strategy.*; +import java.io.File; +import java.io.FileNotFoundException; +import java.util.ArrayList; import java.util.List; import static ch.zhaw.pm2.racetrack.PositionVector.Direction; @@ -13,59 +17,152 @@ import static ch.zhaw.pm2.racetrack.PositionVector.Direction; */ public class Game implements GameSpecification { public static final int NO_WINNER = -1; + private Track track; + private int currentCarIndex; + + UserInterface userInterface; + + public Game(UserInterface userInterface) { + this.userInterface = userInterface; + } + + + public boolean initPhase() throws InvalidTrackFormatException { + File folder = new File("tracks"); + File[] listOfFiles = folder.listFiles(); + if (listOfFiles.length > 0) { + List tracks = new ArrayList<>(); + for (File file : listOfFiles) { + tracks.add(file.getName()); + } + File selectedTrack = listOfFiles[userInterface.selectOption("Select Track file", tracks)]; + selectTrack(selectedTrack); + List 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"); + for (int i = 0; i < track.getCarCount(); i++) { + Car car = track.getCar(i); + while (car.getMoveStrategy() == null) { + int moveStrategie = userInterface.selectOption( + "Select Strategy for Car " + i + " (" + track.getCarId(i) + ")", moveStrategies); + switch (moveStrategie + 1) { + case 1: + selectMoveStrategy(car, new DoNotMoveStrategy()); + break; + case 2: + selectMoveStrategy(car, new UserMoveStrategy(userInterface, i, track.getCarId(i))); + break; + case 3: + String path = ".\\moves\\" + selectedTrack.getName().split("\\.")[0] + "-car-" + track.getCar(i).getID() + ".txt"; + try { + MoveStrategy moveStrategy = new MoveListStrategy(path); + selectMoveStrategy(car, moveStrategy); + } catch (FileNotFoundException e) { + userInterface.printInformation("There is no MoveList implemented. Choose another Strategy!"); + } + //TODO: Backslash kompatibel für Linux + break; + case 4: + //TODO: add Arguments + selectMoveStrategy(car, new PathFollowerMoveStrategy()); + break; + } + } + } + return true; + } else { + userInterface.printInformation("No Trackfile found!"); + return false; + } + } + + /** + * The functionality was taken out of init to automate testing + * + * @param selectedTrack + */ + Track selectTrack(File selectedTrack) { + try { + track = new Track(selectedTrack); + return track; + } catch (FileNotFoundException | PositionVectorNotValid | InvalidTrackFormatException e) { + e.printStackTrace(); + } + return null; + } + + /** + * The functionality was taken out of init to automate testing + * + * @param car to set the MoveStrategy + * @param strategy The movestrategy to set + */ + void selectMoveStrategy(Car car, MoveStrategy strategy) { + car.setMoveStrategy(strategy); + } /** * Return the index of the current active car. * Car indexes are zero-based, so the first car is 0, and the last car is getCarCount() - 1. + * * @return The zero-based number of the current car */ @Override public int getCurrentCarIndex() { - // TODO: implementation - throw new UnsupportedOperationException(); + return currentCarIndex; } /** * Get the id of the specified car. + * * @param carIndex The zero-based carIndex number * @return A char containing the id of the car */ @Override public char getCarId(int carIndex) { - // TODO: implementation - throw new UnsupportedOperationException(); + return track.getCarId(carIndex); } /** * Get the position of the specified car. + * * @param carIndex The zero-based carIndex number * @return A PositionVector containing the car's current position */ @Override public PositionVector getCarPosition(int carIndex) { - // TODO: implementation - throw new UnsupportedOperationException(); + return track.getCarPos(carIndex); } /** * Get the velocity of the specified car. + * * @param carIndex The zero-based carIndex number * @return A PositionVector containing the car's current velocity */ @Override public PositionVector getCarVelocity(int carIndex) { - // TODO: implementation - throw new UnsupportedOperationException(); + return track.getCarVelocity(carIndex); } /** * Return the winner of the game. If the game is still in progress, returns NO_WINNER. + * * @return The winning car's index (zero-based, see getCurrentCar()), or NO_WINNER if the game is still in progress */ @Override public int getWinner() { - // TODO: implementation - throw new UnsupportedOperationException(); + if (onlyOneCarLeft()) { + return currentCarIndex; + } + for (int i = 0; i < track.getCarCount(); i++) { + if (track.getCar(i).getWinPoints() == 1) { + return i; + } + } + return NO_WINNER; } /** @@ -95,9 +192,48 @@ public class Game implements GameSpecification { * for this turn */ @Override - public void doCarTurn(Direction acceleration) { - // TODO: implementation - throw new UnsupportedOperationException(); + public void doCarTurn(Direction acceleration) throws PositionVectorNotValid { + track.getCar(currentCarIndex).accelerate(acceleration); + + PositionVector crashPosition = null; + List positionList = calculatePath(track.getCarPos(currentCarIndex), track.getCar(currentCarIndex).nextPosition()); + for (int i = 0; i < positionList.size(); i++) { + if (willCarCrash(currentCarIndex, positionList.get(i))) { + if (i == 0) { + crashPosition = track.getCarPos(currentCarIndex); + } else { + crashPosition = positionList.get(i - 1); + } + break; + } + } + if (crashPosition != null) { + track.carDoesCrash(currentCarIndex, crashPosition); + } else { + calculateWinner(track.getCarPos(currentCarIndex), track.getCar(currentCarIndex).nextPosition(), currentCarIndex); + track.moveCar(currentCarIndex); + } + } + + public String gamePhase() throws PositionVectorNotValid { + 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); + } + switchToNextActiveCar(); + } + userInterface.printTrack(track); + int indexWinner = getWinner(); + if (indexWinner == NO_WINNER) { + return null; + } + return String.valueOf(track.getCar(indexWinner).getID()); } /** @@ -105,8 +241,14 @@ public class Game implements GameSpecification { */ @Override public void switchToNextActiveCar() { - // TODO: implementation - throw new UnsupportedOperationException(); + do { + if ((currentCarIndex + 1) == track.getCarCount()) { + currentCarIndex = 0; + } else { + currentCarIndex++; + } + } while (track.getCar(currentCarIndex).isCrashed()); + // TODO: evtl andere Kapselung } /** @@ -117,28 +259,139 @@ public class Game implements GameSpecification { * - Detect which axis of the distance vector is longer (faster movement) * - for each pixel on the 'faster' axis calculate the position on the 'slower' axis. * Direction of the movement has to correctly considered + * * @param startPosition Starting position as a PositionVector - * @param endPosition Ending position as a PositionVector + * @param endPosition Ending position as a PositionVector * @return Intervening grid positions as a List of PositionVector's, including the starting and ending positions. */ @Override public List calculatePath(PositionVector startPosition, PositionVector endPosition) { - // TODO: implementation - throw new UnsupportedOperationException(); + ArrayList 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; } + private void calculateWinner(PositionVector start, PositionVector finish, int carIndex) { + List 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(); + } else if (start.getY() > finish.getY()) { + track.getCar(carIndex).deductWinPoints(); + } + break; + case FINISH_DOWN: + if (start.getY() > finish.getY()) { + track.getCar(carIndex).increaseWinPoints(); + } else if (start.getY() < finish.getY()) { + track.getCar(carIndex).deductWinPoints(); + } + break; + case FINISH_RIGHT: + if (start.getX() < finish.getX()) { + track.getCar(carIndex).increaseWinPoints(); + } else if (start.getX() > finish.getX()) { + track.getCar(carIndex).deductWinPoints(); + } + break; + case FINISH_LEFT: + if (start.getX() > finish.getX()) { + track.getCar(carIndex).increaseWinPoints(); + } else if (start.getX() < finish.getX()) { + track.getCar(carIndex).increaseWinPoints(); + } + break; + } + + } + } + } /** * Does indicate if a car would have a crash with a WALL space or another car at the given position. + * * @param carIndex The zero-based carIndex number * @param position A PositionVector of the possible crash position * @return A boolean indicator if the car would crash with a WALL or another car. */ @Override - public boolean willCarCrash(int carIndex, PositionVector position) { + public boolean willCarCrash(int carIndex, PositionVector position) throws PositionVectorNotValid { + return track.willCrashAtPosition(carIndex, position); + } + public boolean onlyOneCarLeft() { + int carsLeft = 0; + for (int carIndex = 0; carIndex < track.getCarCount(); carIndex++) { + if (!track.getCar(carIndex).isCrashed()) { + carsLeft++; + } + } + return !(carsLeft > 1); + } - return true; + public boolean carsMoving() { + for (int carIndex = 0; carIndex < track.getCarCount(); carIndex++) { + if (!(track.getCar(carIndex).isCrashed() || track.getCar(carIndex).getMoveStrategy().getClass() == DoNotMoveStrategy.class)) { + return true; + } + } + return false; } } diff --git a/src/main/java/ch/zhaw/pm2/racetrack/InvalidFileFormatException.java b/src/main/java/ch/zhaw/pm2/racetrack/InvalidFileFormatException.java index 6655e69..e7d0c07 100644 --- a/src/main/java/ch/zhaw/pm2/racetrack/InvalidFileFormatException.java +++ b/src/main/java/ch/zhaw/pm2/racetrack/InvalidFileFormatException.java @@ -1,10 +1,5 @@ package ch.zhaw.pm2.racetrack; -/** - * Class for Exception when invalid Fileformat is used. - */ public class InvalidFileFormatException extends Exception { - public InvalidFileFormatException(String errorMessage) { - super(errorMessage); - } + // TODO: implementation } diff --git a/src/main/java/ch/zhaw/pm2/racetrack/InvalidTrackFormatException.java b/src/main/java/ch/zhaw/pm2/racetrack/InvalidTrackFormatException.java index 3cdd04c..25de664 100644 --- a/src/main/java/ch/zhaw/pm2/racetrack/InvalidTrackFormatException.java +++ b/src/main/java/ch/zhaw/pm2/racetrack/InvalidTrackFormatException.java @@ -1,10 +1,5 @@ package ch.zhaw.pm2.racetrack; -/** - * Class for Exception when invalid track format is used. - */ public class InvalidTrackFormatException extends Exception { - public InvalidTrackFormatException(String errorMessage) { - super(errorMessage); - } + // TODO: implementation } diff --git a/src/main/java/ch/zhaw/pm2/racetrack/Main.java b/src/main/java/ch/zhaw/pm2/racetrack/Main.java new file mode 100644 index 0000000..aec65bd --- /dev/null +++ b/src/main/java/ch/zhaw/pm2/racetrack/Main.java @@ -0,0 +1,40 @@ +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 { + UserInterface userInterface = new UserInterface("Hello and Welcome to Racetrack by Team02-\"AngryNerds\""); + while (true) { + Game game = new Game(userInterface); + String winner; + if (game.initPhase()) { + winner = game.gamePhase(); + List optionsNewGame = new ArrayList<>(); + optionsNewGame.add("exit"); + optionsNewGame.add("new game"); + String winnerText; + if(winner == null){ + winnerText = "There was no winner."; + } + else { + winnerText = "The Winner was Car " + winner; + } + int selectedOption = userInterface.selectOption(winnerText + "\nStart new Game?", optionsNewGame); + if(selectedOption == 0) { + userInterface.quit("Thank you and goodbye\npress enter to close the application."); + break; + } + } + else { + userInterface.quit("The initialisation of the game failed. Press enter to close the application."); + break; + } + } + + } + +} diff --git a/src/main/java/ch/zhaw/pm2/racetrack/Track.java b/src/main/java/ch/zhaw/pm2/racetrack/Track.java index f3e51f0..c83839e 100644 --- a/src/main/java/ch/zhaw/pm2/racetrack/Track.java +++ b/src/main/java/ch/zhaw/pm2/racetrack/Track.java @@ -3,8 +3,7 @@ package ch.zhaw.pm2.racetrack; import ch.zhaw.pm2.racetrack.given.ConfigSpecification; import ch.zhaw.pm2.racetrack.given.TrackSpecification; -import java.io.File; -import java.io.FileNotFoundException; +import java.io.*; import java.util.ArrayList; import java.util.List; import java.util.Scanner; @@ -61,6 +60,7 @@ public class Track implements TrackSpecification { private List track; private List cars; private final List finishLine; + private ConfigSpecification.SpaceType finishTyp; /** * Initialize a Track from the given track file. @@ -85,7 +85,7 @@ public class Track implements TrackSpecification { * @throws FileNotFoundException if the FilePath is invalid. */ private void readFile(File trackFile) throws FileNotFoundException { - Scanner scanner = new Scanner(trackFile); + Scanner scanner = new Scanner(new FileInputStream(trackFile),"UTF-8"); while (scanner.hasNextLine()) { track.add(scanner.nextLine()); } @@ -133,7 +133,7 @@ public class Track implements TrackSpecification { if (finishLine.size() == 0) { throw new InvalidTrackFormatException(); } - ConfigSpecification.SpaceType finishTyp = getSpaceType(finishLine.get(0)); + finishTyp = getSpaceType(finishLine.get(0)); for (PositionVector positionVector : finishLine) { if (getSpaceType(positionVector) != finishTyp) { throw new InvalidTrackFormatException(); @@ -208,12 +208,20 @@ public class Track implements TrackSpecification { * @param carIndex of the current car */ private void makeCarMoveInTrack(int carIndex) { - PositionVector positionVector = findChar(getCarId(carIndex)); + PositionVector carPositionVector = findChar(getCarId(carIndex)); //Removes the Car at Current Pos - drawCharOnTrackIndicator(positionVector, ConfigSpecification.SpaceType.TRACK.getValue()); + drawCharOnTrackIndicator(carPositionVector, ConfigSpecification.SpaceType.TRACK.getValue()); + + //Redraw finishline if Car was on finish-line Position + for(PositionVector finishLinePositionVector : finishLine){ + if(finishLinePositionVector.equals(carPositionVector)){ + drawCharOnTrackIndicator(carPositionVector, finishTyp.getValue()); + } + } + //Adds Car at new Position - positionVector = cars.get(carIndex).nextPosition(); - drawCharOnTrackIndicator(positionVector, cars.get(carIndex).getID()); + carPositionVector = cars.get(carIndex).nextPosition(); + drawCharOnTrackIndicator(carPositionVector, cars.get(carIndex).getID()); } /** @@ -223,24 +231,30 @@ public class Track implements TrackSpecification { * @return true if car would crash. Else false. */ public boolean willCrashAtPosition(int carIndex, PositionVector positionVector) throws PositionVectorNotValid { - isPositionVectorOnTrack(positionVector); + isPositionVectorOnTrack(positionVector); //TODO: remove this line? Or Method? char charAtPosition = track.get(positionVector.getY()).charAt(positionVector.getX()); if (getCarId(carIndex) == charAtPosition) return false; - return (charAtPosition == ConfigSpecification.SpaceType.WALL.value); + return !(charAtPosition == ConfigSpecification.SpaceType.TRACK.value || + charAtPosition == ConfigSpecification.SpaceType.FINISH_RIGHT.value || + charAtPosition == ConfigSpecification.SpaceType.FINISH_LEFT.value || + charAtPosition == ConfigSpecification.SpaceType.FINISH_UP.value || + charAtPosition == ConfigSpecification.SpaceType.FINISH_DOWN.value); } /** * This Method will make the Car Crash. In Track and in the Car Object * * @param carIndex representing current Car - * @param positionVector where the Crash did happen + * @param crashPositionVector where the Crash did happen */ - public void carDoesCrash(int carIndex, PositionVector positionVector) throws PositionVectorNotValid{ - isPositionVectorOnTrack(positionVector); + public void carDoesCrash(int carIndex, PositionVector crashPositionVector) throws PositionVectorNotValid{ + isPositionVectorOnTrack(crashPositionVector); //TODO: remove this line? and Method? + PositionVector currentCarPosition = getCarPos(carIndex); + drawCharOnTrackIndicator(new PositionVector(currentCarPosition.getX(), currentCarPosition.getY()), ConfigSpecification.SpaceType.TRACK.getValue()); Car car = cars.get(carIndex); car.crash(); - car.setPosition(positionVector); - drawCharOnTrackIndicator(new PositionVector(positionVector.getX(), positionVector.getY()), CRASH_INDICATOR); + car.setPosition(crashPositionVector); + drawCharOnTrackIndicator(new PositionVector(crashPositionVector.getX(), crashPositionVector.getY()), CRASH_INDICATOR); } /** diff --git a/src/main/java/ch/zhaw/pm2/racetrack/UserInterface.java b/src/main/java/ch/zhaw/pm2/racetrack/UserInterface.java index d800a95..96a8c04 100644 --- a/src/main/java/ch/zhaw/pm2/racetrack/UserInterface.java +++ b/src/main/java/ch/zhaw/pm2/racetrack/UserInterface.java @@ -22,6 +22,14 @@ public class UserInterface { textTerminal.println(welcomeText + "\n"); } + /** + * Prints the given Text in textTerminal + * @param text The Text which should be printed. + */ + public void printInformation(String text) { + textTerminal.println(text); + } + /** * 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:" @@ -29,7 +37,7 @@ public class UserInterface { * @return the list index of the selected option */ public int selectOption(String text, List options) { - textTerminal.println(text + ":\n"); + textTerminal.println(text + ":"); for(int option = 0; option < options.size(); option ++) { textTerminal.println(" " + (option + 1) + ": " + options.get(option)); } @@ -44,7 +52,7 @@ public class UserInterface { */ public PositionVector.Direction selectDirection(int playingCarIndex, char playingCarID) { PositionVector.Direction direction = null; - textTerminal.println("Playing Car " + playingCarIndex + ": " + playingCarIndex); + textTerminal.println("Playing Car " + playingCarIndex + ": " + playingCarID); textTerminal.println("Directions are based on the number pad:"); textTerminal.println("7 8 9 7=up-left, 8=up, 9=up-right"); textTerminal.println("4 5 6 4=left, 5=no acceleration, 6=right"); @@ -89,6 +97,15 @@ public class UserInterface { textTerminal.println(track.toString()); } + /** + * Method to dispose the Textterminal + * @param text OUtput Text + */ + public void quit(String text){ + textIO.newStringInputReader().withMinLength(0).read(text); + textTerminal.dispose(); + } + } diff --git a/src/main/java/ch/zhaw/pm2/racetrack/given/GameSpecification.java b/src/main/java/ch/zhaw/pm2/racetrack/given/GameSpecification.java index 3596335..c9148e5 100644 --- a/src/main/java/ch/zhaw/pm2/racetrack/given/GameSpecification.java +++ b/src/main/java/ch/zhaw/pm2/racetrack/given/GameSpecification.java @@ -1,6 +1,7 @@ package ch.zhaw.pm2.racetrack.given; import ch.zhaw.pm2.racetrack.PositionVector; +import ch.zhaw.pm2.racetrack.PositionVectorNotValid; import java.util.List; @@ -18,11 +19,11 @@ public interface GameSpecification { int getWinner(); - void doCarTurn(PositionVector.Direction acceleration); + void doCarTurn(PositionVector.Direction acceleration) throws PositionVectorNotValid; void switchToNextActiveCar(); List calculatePath(PositionVector startPosition, PositionVector endPosition); - boolean willCarCrash(int carIndex, PositionVector position); + boolean willCarCrash(int carIndex, PositionVector position) throws PositionVectorNotValid; } diff --git a/src/main/java/ch/zhaw/pm2/racetrack/strategy/DoNotMoveStrategy.java b/src/main/java/ch/zhaw/pm2/racetrack/strategy/DoNotMoveStrategy.java index 24b09e0..62e15e3 100644 --- a/src/main/java/ch/zhaw/pm2/racetrack/strategy/DoNotMoveStrategy.java +++ b/src/main/java/ch/zhaw/pm2/racetrack/strategy/DoNotMoveStrategy.java @@ -1,5 +1,7 @@ package ch.zhaw.pm2.racetrack.strategy; +import ch.zhaw.pm2.racetrack.PositionVector; + import static ch.zhaw.pm2.racetrack.PositionVector.Direction; /** @@ -9,7 +11,6 @@ public class DoNotMoveStrategy implements MoveStrategy { @Override public Direction nextMove() { - // TODO: implementation - throw new UnsupportedOperationException(); + return PositionVector.Direction.NONE; } } diff --git a/src/main/java/ch/zhaw/pm2/racetrack/strategy/MoveListStrategy.java b/src/main/java/ch/zhaw/pm2/racetrack/strategy/MoveListStrategy.java index 4432c69..7d1e68e 100644 --- a/src/main/java/ch/zhaw/pm2/racetrack/strategy/MoveListStrategy.java +++ b/src/main/java/ch/zhaw/pm2/racetrack/strategy/MoveListStrategy.java @@ -2,11 +2,44 @@ package ch.zhaw.pm2.racetrack.strategy; import ch.zhaw.pm2.racetrack.PositionVector.Direction; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.util.ArrayList; +import java.util.List; +import java.util.Scanner; + public class MoveListStrategy implements MoveStrategy { + private List moveList; + private int pointer; + + public MoveListStrategy(String path) throws FileNotFoundException{ + moveList = new ArrayList<>(); + pointer = -1; + readFile(new File(path)); + } + + private void readFile(File trackFile) throws FileNotFoundException { + Scanner scanner = new Scanner(new FileInputStream(trackFile), "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); + break; + } + } + } + } + @Override public Direction nextMove() { - // TODO: implementation - throw new UnsupportedOperationException(); + pointer += 1; + if (pointer < moveList.size()) { + return moveList.get(pointer); + } + return null; } } diff --git a/src/main/java/ch/zhaw/pm2/racetrack/strategy/UserMoveStrategy.java b/src/main/java/ch/zhaw/pm2/racetrack/strategy/UserMoveStrategy.java index b7df019..06589ff 100644 --- a/src/main/java/ch/zhaw/pm2/racetrack/strategy/UserMoveStrategy.java +++ b/src/main/java/ch/zhaw/pm2/racetrack/strategy/UserMoveStrategy.java @@ -1,15 +1,24 @@ package ch.zhaw.pm2.racetrack.strategy; import ch.zhaw.pm2.racetrack.PositionVector.Direction; +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; + + public UserMoveStrategy(UserInterface userInterface, int carIndex, char carID) { + this.userInterface = userInterface; + this.carIndex = carIndex; + this.carID = carID; + } @Override public Direction nextMove() { - // TODO: implementation - throw new UnsupportedOperationException(); + return userInterface.selectDirection(carIndex, carID); } } diff --git a/src/test/java/ch/zhaw/pm2/racetrack/CarTest.java b/src/test/java/ch/zhaw/pm2/racetrack/CarTest.java deleted file mode 100644 index 89b1965..0000000 --- a/src/test/java/ch/zhaw/pm2/racetrack/CarTest.java +++ /dev/null @@ -1,191 +0,0 @@ - -package ch.zhaw.pm2.racetrack; - -import ch.zhaw.pm2.racetrack.strategy.*; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -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 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 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 - List directions = Arrays.asList(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()); - - moveStrategy = new MoveListStrategy(); - car.setMoveStrategy(moveStrategy); - assertEquals(moveStrategy, car.getMoveStrategy()); - - moveStrategy = new PathFollowerMoveStrategy(); - car.setMoveStrategy(moveStrategy); - assertEquals(moveStrategy, car.getMoveStrategy()); - - moveStrategy = new UserMoveStrategy(); - car.setMoveStrategy(moveStrategy); - assertEquals(moveStrategy, car.getMoveStrategy()); - } -} diff --git a/src/test/java/ch/zhaw/pm2/racetrack/GameTest.java b/src/test/java/ch/zhaw/pm2/racetrack/GameTest.java new file mode 100644 index 0000000..03cb0f3 --- /dev/null +++ b/src/test/java/ch/zhaw/pm2/racetrack/GameTest.java @@ -0,0 +1,104 @@ +package ch.zhaw.pm2.racetrack; + +import ch.zhaw.pm2.racetrack.strategy.UserMoveStrategy; +import org.junit.jupiter.api.*; + +import java.io.File; + +import static ch.zhaw.pm2.racetrack.Game.NO_WINNER; + +class GameTest { + private UserInterface userInterface; + private Game game; + private Track track; + + @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))); + + } + + + @Test + void getCurrentCarIndex() { + Assertions.assertEquals(0,game.getCurrentCarIndex()); + game.switchToNextActiveCar(); + Assertions.assertEquals(1,game.getCurrentCarIndex()); + } + + @Test + void getCarId() { + 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)); + } + + @Test + void getCarVelocity() { + 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()); + } + + @Test + void onlyOneCarLeft() { + Assertions.assertFalse(game.onlyOneCarLeft()); + } + + @Test + void carsMoving() { + Assertions.assertTrue(game.carsMoving()); + } + } + + @Nested + @DisplayName("Basic 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))); + + } + + @Test + void carTurnCorrect() { + try { + game.doCarTurn(PositionVector.Direction.RIGHT); + Assertions.assertEquals(new PositionVector(1,0),game.getCarVelocity(0)); + } catch (PositionVectorNotValid positionVectorNotValid) { + positionVectorNotValid.printStackTrace(); + } + } + + @Test + void carCrash() { + try { + game.doCarTurn(PositionVector.Direction.UP); + Assertions.assertTrue(game.onlyOneCarLeft()); + } catch (PositionVectorNotValid positionVectorNotValid) { + positionVectorNotValid.printStackTrace(); + } + } + + } +} diff --git a/src/test/java/ch/zhaw/pm2/racetrack/MoveStrategyTest.java b/src/test/java/ch/zhaw/pm2/racetrack/MoveStrategyTest.java new file mode 100644 index 0000000..f4e5afb --- /dev/null +++ b/src/test/java/ch/zhaw/pm2/racetrack/MoveStrategyTest.java @@ -0,0 +1,40 @@ +package ch.zhaw.pm2.racetrack; + +import ch.zhaw.pm2.racetrack.strategy.MoveListStrategy; +import ch.zhaw.pm2.racetrack.strategy.MoveStrategy; +import org.junit.jupiter.api.*; + +import java.io.FileNotFoundException; + +public class MoveStrategyTest { + + private MoveStrategy moveList; + + @Nested + @DisplayName("MoveListStrategy") + class MoveList { + + + @BeforeEach + void setup() { + try { + moveList = new MoveListStrategy(".\\moves\\challenge-car-a.txt"); + }catch (FileNotFoundException e) { + e.printStackTrace(); + } + } + + @Test + void checkMove() { + Assertions.assertEquals(PositionVector.Direction.RIGHT,moveList.nextMove()); + for (int i = 0; i < 3; i++) { + moveList.nextMove(); + } + Assertions.assertEquals(PositionVector.Direction.NONE,moveList.nextMove()); + for (int i = 0; i < 40; i++) { + moveList.nextMove(); + } + Assertions.assertNull(moveList.nextMove()); + } + } +} diff --git a/tracks/.gitignore b/tracks/.gitignore deleted file mode 100644 index e4af982..0000000 --- a/tracks/.gitignore +++ /dev/null @@ -1 +0,0 @@ -challenge_points.txt