Compare commits

..
126 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
romanschenk37 fa4842e440 refactoring of Method calculatePath from Game.java to Track.java 2022-03-24 13:32:12 +01:00
Leonardo Brandenberger dc704cce4c continued readme 2022-03-23 21:32:15 +01:00
Leonardo Brandenberger 082d1414f5 started readme 2022-03-23 21:19:37 +01:00
Leonardo Brandenberger 7c87f4b2fd started readme 2022-03-23 21:11:36 +01:00
Leonardo Brandenberger 1c63c0cb21 started readme 2022-03-23 21:08:57 +01:00
Leonardo Brandenberger 787ddd7155 Merge remote-tracking branch 'origin/main' 2022-03-23 21:07:55 +01:00
Leonardo Brandenberger a14327a2a7 started readme 2022-03-23 21:07:44 +01:00
romanschenk37 ded9023ff1 adapted CarTest.java for PathFolowerMoveStrategy.java 2022-03-23 11:24:58 +01:00
romanschenk37 2de3993921 Merge pull request #28 from PM2-IT21bWIN-ruiz-mach-krea/PathFollowerMoveStrategy
implemented PathFollowerMoveStrategy.java
2022-03-23 10:09:35 +01:00
romanschenk37 de91717a48 Merge pull request #29 from PM2-IT21bWIN-ruiz-mach-krea/GameTest
Game test
2022-03-23 09:18:59 +01:00
Andrin Fassbind 826f67d125 gamePhase() prevent null direction 2022-03-23 09:10:51 +01:00
romanschenk37 6ac4f64456 Javadoc in PathFollowerMoveStrategy.java 2022-03-23 08:55:32 +01:00
Andrin Fassbind b1a4f3b3db -CarTest added winpoint test
-added Klassendiagramm
-create Constructor InvalidTrackFormatException
2022-03-23 08:53:40 +01:00
romanschenk37 45918124df refactoring and javadoc in PathFollowerMoveStrategy.javaa 2022-03-23 08:48:46 +01:00
Andrin Fassbind b8dda0b96a Merge branch 'main' into GameTest 2022-03-22 19:36:43 +01:00
Andrin Fassbind dc34d984f8 -CarTest added winpoint test
-added Klassendiagramm
-create Constructor InvalidTrackFormatException
2022-03-22 19:04:26 +01:00
Andrin Fassbind 8877f1476f GameTest 2022-03-22 18:47:14 +01:00
romanschenk37 c59e4a30d8 Update MoveListStrategy.java 2022-03-22 18:31:15 +01:00
romanschenk37 eddf9d3daa implemented PathFollowerMoveStrategy.java 2022-03-22 18:20:23 +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
romanschenk37 fe74d017b2 Merge pull request #23 from PM2-IT21bWIN-ruiz-mach-krea/Game
Game
2022-03-20 16:56:33 +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
Andrin Fassbind b467a79596 Changed mainClass in build.gradle to Main 2022-03-20 13:44:54 +01:00
fassband d7a593be30 Merge pull request #27 from PM2-IT21bWIN-ruiz-mach-krea/GameTest
GameTest startet
2022-03-20 13:40:48 +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
Andrin Fassbind 8826561963 GameTest startet
++ Game and Main clean up
2022-03-19 13:20:19 +01:00
romanschenk37 a80ea0fa1c fix doCarTurn in Game.java 2022-03-18 22:01:03 +01:00
romanschenk37 fc78b10365 optimized Main Class. added Method quit to UserInterface.java 2022-03-18 21:48:27 +01:00
romanschenk37 fec3aceaa6 Merge pull request #26 from PM2-IT21bWIN-ruiz-mach-krea/MoveListFeature
Move list feature
2022-03-18 20:54:27 +01:00
romanschenk37 833b122d2b Update Game.java
Removed System.out.println...
2022-03-18 20:54:04 +01:00
fassband 67c5a79174 Merge pull request #25 from PM2-IT21bWIN-ruiz-mach-krea/track-feature
Track feature
2022-03-18 19:57:18 +01:00
Andrin Fassbind 837297cd31 MoveListStrategy implemented 2022-03-18 19:44:47 +01:00
Andrin Fassbind c30d7a2988 merge 2022-03-18 18:20:28 +01:00
Andrin Fassbind 21da4feaf5 dev MoveListStrategy and test 2022-03-18 18:02:10 +01:00
romanschenk37 dad57ea8ac fix in CardoesCrash in Track.java (remove Car when crash) 2022-03-18 17:32:16 +01:00
romanschenk37 e6fc0fde39 fix in makeCarMoveInTrack in Track.java (redraw finish line if car was on finish line) 2022-03-18 17:23:50 +01:00
romanschenk37 9869e8e74d fix in getWinner in Game.java 2022-03-18 16:48:37 +01:00
romanschenk37 1c618ad09a change in gamephase in Game.java 2022-03-18 16:45:16 +01:00
romanschenk37 3684b5589e fixes in Game.java and Track.java 2022-03-18 16:13:37 +01:00
romanschenk37 fd4513e0d0 fixes in Game.java 2022-03-18 15:37:17 +01:00
Andrin Fassbind 504d5c62ef Fixed wrong encoding error 2022-03-18 14:18:07 +01:00
Andrin Fassbind 848d62a5f9 Test commit 2022-03-18 14:06:14 +01:00
romanschenk37 8dad26006c change in Main.java 2022-03-18 13:34:51 +01:00
Leonardo Brandenberger 268506a084 fixed errors in calculateWinner 2022-03-18 11:02:53 +01:00
romanschenk37 74a83e790a fixes in Game.java Method switchToNextActiveCar 2022-03-18 10:55:31 +01:00
romanschenk37 e1e03d4ad4 fixes in Game.java Method gamePhase 2022-03-18 10:43:51 +01:00
romanschenk37 63204a4b29 fixes in Game.java Method gamePhase 2022-03-18 10:43:22 +01:00
romanschenk37 e5f45b7bb1 fixes in Game.java and UserInterface.java 2022-03-18 10:37:53 +01:00
romanschenk37 a723ea16ec merge track into game and fix in initphase 2022-03-18 10:19:23 +01:00
romanschenk37 5ec7260b1e Merge remote-tracking branch 'origin/track-feature' into Game
# Conflicts:
#	src/main/java/ch/zhaw/pm2/racetrack/Track.java
2022-03-18 10:03:26 +01:00
romanschenk37 9b6908ef47 implemented Movestrategies in Game.java 2022-03-18 10:00:28 +01:00
Leonardo Brandenberger 06ad28fbe8 implemented getWinner method 2022-03-18 09:58:13 +01:00
Leonardo Brandenberger b606f20d9f implemented calculate winner and needed int in in car to hold winpoints. 2022-03-18 09:51:11 +01:00
romanschenk37 d02c04f91d Merge pull request #22 from PM2-IT21bWIN-ruiz-mach-krea/Exception
Exception
2022-03-18 09:21:53 +01:00
Leonardo Brandenberger e94053fee8 started method calculateWinner 2022-03-14 00:17:45 +01:00
romanschenk37 8929d295b9 Merge pull request #21 from PM2-IT21bWIN-ruiz-mach-krea/track-feature
Track feature
2022-03-11 18:41:11 +01:00
Andrin Fassbind 884b349077 - TrackTest done Track done 2022-03-11 16:01:49 +01:00
romanschenk37 af6914f795 changes in Methods in Game.java
created MainClass.java
2022-03-11 12:08:17 +01:00
romanschenk37 7e5d349f3f changes in Methods in Game.java 2022-03-11 12:01:55 +01:00
Leonardo Brandenberger e159274085 finished method currentCarIndex, switchToNextActiveCar, willCarCrash 2022-03-11 10:37:54 +01:00
Leonardo Brandenberger dd987a5a14 Merge remote-tracking branch 'origin/Game' into Game 2022-03-10 19:04:21 +01:00
Leonardo Brandenberger bf08749f28 implemented calculatePath method. 2022-03-10 19:04:09 +01:00
romanschenk37 dd625907c9 changes in Method initphase
added Method printInformation in UserInterface.java
2022-03-10 16:48:14 +01:00
romanschenk37 3fe1bb1426 completed Method initphase 2022-03-10 16:30:33 +01:00
Leonardo Brandenberger 6285cfe215 merged track into game 2022-03-10 15:39:58 +01:00
Leonardo Brandenberger 156f6d0cab Merge remote-tracking branch 'origin/track-feature' into Game 2022-03-10 15:36:00 +01:00
Leonardo Brandenberger ddbf666cc8 finished methods getCarPosition, getCarVelocity and get CarID 2022-03-10 15:33:20 +01:00
romanschenk37 57a5d199a6 changes in Method initphase 2022-03-10 15:29:04 +01:00
romanschenk37 4ebe8cb1ed created Method initphase in Game.java 2022-03-10 15:18:08 +01:00
Andrin Fassbind c4ea4d1920 - Crash Methoden hinzugefügt 2022-03-10 14:58:54 +01:00
Leonardo Brandenberger 16e4460a47 Merge pull request #20 from PM2-IT21bWIN-ruiz-mach-krea/car
Fixed Error in CarTest.java
2022-03-10 14:51:26 +01:00
romanschenk37 a67a96d19d fix in CarTest.java 2022-03-10 14:46:51 +01:00
Andrin Fassbind 46e6b838c2 - Methoden überarbeitet 2022-03-10 14:43:34 +01:00
Andrin Fassbind ee68bf9a1d Merge remote-tracking branch 'origin/main' into track-feature
# Conflicts:
#	src/main/java/ch/zhaw/pm2/racetrack/Car.java
2022-03-10 14:36:30 +01:00
Andrin Fassbind befc67f4f0 - Methoden überarbeitet 2022-03-10 14:35:33 +01:00
Leonardo Brandenberger 19b227c59f merged cartest branch into car branch 2022-03-10 14:18:33 +01:00
Leonardo Brandenberger cbc915bf50 Merge remote-tracking branch 'origin/CarTest' into car 2022-03-10 14:04:48 +01:00
romanschenk37 d6a46f3cae Merge pull request #19 from PM2-IT21bWIN-ruiz-mach-krea/car
created Branch car
2022-03-10 14:04:06 +01:00
Leonardo Brandenberger b6f69d3c1c created Branch car
finished all TODOS in car and created needed method getID and getVelocity.
2022-03-10 13:31:51 +01:00
romanschenk37 5afd0b0b61 Merge pull request #18 from PM2-IT21bWIN-ruiz-mach-krea/Class_UserInterface
created Class_UserInterface
2022-03-08 13:54:37 +01:00
Andrin Fassbind 15123b05bb - Methoden überarbeitet 2022-03-08 11:27:05 +01:00
romanschenk37 77b5f4cbfb created Class_UserInterface 2022-03-07 22:03:43 +01:00
romanschenk37 31a24120eb added checks for method getVelocity in Test Movement in CarTest.java 2022-03-07 20:44:05 +01:00
Andrin Fassbind 007d8ee393 - Methoden überarbeitet
Teils provisorisch da genaue Umsetzung noch unklar
Siehe TODO
2022-03-07 17:49:55 +01:00
romanschenk37 dea430e418 Added Test for Method getID in CarTest.java 2022-03-07 17:43:32 +01:00
romanschenk37 40cd4f7b72 Added Javadoc and comments in CarTest.java 2022-03-06 18:57:01 +01:00
romanschenk37 8086111772 Fix in CarTest.java
@Test setPosition
2022-03-06 18:13:27 +01:00
romanschenk37 972f011a08 changes in Tests car.CarTest
setPosition, movement, crash, moveStrategy
2022-03-06 17:06:42 +01:00
Andrin Fassbind 571728b6fd - Method toString done 2022-03-06 16:10:18 +01:00
Andrin Fassbind 8ff70ab3ac -Method readFile done and tested
-Method getSpaceType done and once tested
2022-03-06 15:15:39 +01:00
romanschenk37 381ea44a9a Created CarTest.java
added Tests setPosition, nextPosition
2022-03-05 16:39:08 +01:00
23 changed files with 1896 additions and 72 deletions
File diff suppressed because one or more lines are too long
+42
View File
@@ -1,2 +1,44 @@
# team02-AngryNerds-projekt1-racetrack
PM2 Team 02 Projekt 1 Racetrack
Racetrack is a pen and paper game that dates back to the early 1960s in this version of the game, the game is digitalized and the math behind it is done automatically rather than calculated by hand and the winner gets informed automatically as well.
The aim of the game is to finish the race faster than your opponent or win by being the only survivor in case the other cars crash.
In order to not crash you have to keep in mind the acceleration and other players car to get to the finish line safely.
# Initialization:
#### The game can be initialized by the terminal command:
./gradlew run
You will then be prompted to select a track file from the selection by entering the corresponding number.
#### For each car that is taking part in the race a strategy has to be chosen there are the following options:
+ Do not move Strategy
> This Strategy sets the car stationary, and it won't make any moves during the game staying at the startpoint indefinitely.
+ User Move Strategy
> The player is prompted for each move to make a choice the different choices you are able to take are as following:
> > 1=down-left <br> 2=down<br> 3=down-right<br> 4=left<br> 5=no acceleration<br> 6=right <br> 7=up-left<br> 8=up<br> 9=up-right<br> it is also possible to leave the game when it is your turn by entering 10
+ Move List Strategy
> For this strategy a predefined list of moves have to be given, the list may contain all allowed moves like mentioned in User Move Strategy
> > To create your own Move List strategy it needs to be located in /racetrack/moves and be named as *track_name*-car-*character_of_car*.txt and be a txt file.
+ Path Follow Move Strategy
> A list of points given in a txt file where on each lime a coordinate is placed like (X:24, Y:22) gets used to calculate a path which makes the car cross each point.
> > To create your own follow move strategy it needs to be located in /racetrack/moves and be named as *track_name*_points.txt and be a txt file.
+ Path Finder Strategy
> The pathfinder Strategy Calculates a route itself and follows it direction fully automatically.
The shown Track can be interpreted as following:<br>
'spaces' are part of the raceable track.<br>
'#' is a Wall<br>
'>,<,^,v' are finish line components<br>
'X' is shown if a car crashes at its crash location.<br>
And every other character represents a car.
> To create your own track it needs to be located inside /racetrack/tracks and be a txt file.
### Determining a winner
The winner gets determined automatically. <br> The car that first passes the finish line (doing a complete round) is given the win, if all car except one crash the surviving car will be crowned as the winner.<br>The game will inform you of this, and you will have the option to quit the game or play another match.
## Branching Model
We choose a simple branching model where all starting features got a branch and where merged into the main branch, some branches who needed unfinished code to be completed where taken from the game branch but merged into the main at the end as well.<br> Since there was just one end product we abstained from using a development branch and merges where done straight into main branch.
## Class Diagramm
![Classdiagramm of this program](/Klassendiagramm.drawio)
+2 -1
View File
@@ -29,6 +29,7 @@ dependencies {
// beryx uses SLF4J. To remove warning, we add the implementation "no operation"
implementation 'org.slf4j:slf4j-nop:2.+'
implementation 'junit:junit:4.13.1'
// Use JUnit Jupiter API for testing.
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2'
@@ -43,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 {
+19
View File
@@ -0,0 +1,19 @@
(X:40, Y:22)
(X:43, Y:22)
(X:46, Y:21)
(X:48, Y:19)
(X:48, Y:17)
(X:46, Y:15)
(X:41, Y:13)
(X:41, Y:10)
(X:46, Y:9)
(X:49, Y:4)
(X:40, Y:2)
(X:30, Y:2)
(X:21, Y:3)
(X:16, Y:7)
(X:13, Y:10)
(X:14, Y:14)
(X:11, Y:19)
(X:13, Y:22)
(X:24, Y:22)
+59 -16
View File
@@ -6,9 +6,9 @@ import ch.zhaw.pm2.racetrack.strategy.MoveStrategy;
/**
* Class representing a car on the racetrack.
* Uses {@link PositionVector} to store current position on the track grid and current velocity vector.
* Each car has an identifier character which represents the car on the race track board.
* Each car has an identifier character which represents the car on the racetrack board.
* Also keeps the state, if the car is crashed (not active anymore). The state can not be changed back to uncrashed.
* The velocity is changed by providing an acelleration vector.
* The velocity is changed by providing an acceleration vector.
* The car is able to calculate the endpoint of its next position and on request moves to it.
*/
public class Car implements CarSpecification {
@@ -22,6 +22,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}
@@ -40,7 +44,8 @@ public class Car implements CarSpecification {
/**
* Constructor for class Car
* @param id unique Car identification
*
* @param id unique Car identification
* @param position initial position of the Car
*/
public Car(char id, PositionVector position) {
@@ -48,17 +53,51 @@ public class Car implements CarSpecification {
setPosition(position);
}
/**
* Returns the id of the car.
*
* @return id of the car.
*/
public char getID() {
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.
*
* @return velocity current velocity of the car.
*/
public PositionVector getVelocity() {
return velocity;
}
/**
* Set this Car position directly, regardless of current position and velocity.
* This should only be used by the game controller in rare cases to set the crash or winning position.
* The next position is normaly automatically calculated and set in the {@link #move()} method.
*
* @param position The new position to set the car directly to.
* @throws IllegalArgumentException if invalid PositionVector is given.
*/
@Override
public void setPosition(final PositionVector position) {
// TODO: implementation
throw new UnsupportedOperationException();
if (position.getX() < 0 || position.getY() < 0) {
throw new IllegalArgumentException();
} else {
this.position = position;
}
}
/**
@@ -69,8 +108,7 @@ public class Car implements CarSpecification {
*/
@Override
public PositionVector nextPosition() {
// TODO: implementation
throw new UnsupportedOperationException();
return new PositionVector(position.getX() + velocity.getX(), position.getY() + velocity.getY());
}
/**
@@ -80,11 +118,17 @@ public class Car implements CarSpecification {
* Changes only velocity, not position.
*
* @param acceleration A Direction vector containing the amounts to add to the velocity in x and y dimension
* @throws IllegalArgumentException if PositionVector is not in allowed area.
*/
@Override
public void accelerate(PositionVector.Direction acceleration) {
// TODO: implementation
throw new UnsupportedOperationException();
if (acceleration.vector.getX() < -1 || acceleration.vector.getX() > 1 ||
acceleration.vector.getY() < -1 || acceleration.vector.getY() > 1) {
throw new IllegalArgumentException();
} else {
velocity = new PositionVector(velocity.getX() + acceleration.vector.getX(),
velocity.getY() + acceleration.vector.getY());
}
}
/**
@@ -92,8 +136,7 @@ public class Car implements CarSpecification {
*/
@Override
public void move() {
// TODO: implementation
throw new UnsupportedOperationException();
position = new PositionVector(position.getX() + velocity.getX(), position.getY() + velocity.getY());
}
/**
@@ -101,8 +144,7 @@ public class Car implements CarSpecification {
*/
@Override
public void crash() {
// TODO: implementation
throw new UnsupportedOperationException();
crashed = true;
}
/**
@@ -112,13 +154,13 @@ public class Car implements CarSpecification {
*/
@Override
public boolean isCrashed() {
// TODO: implementation
throw new UnsupportedOperationException();
return crashed;
}
/**
* Set move strategy
* @param moveStrategy
*
* @param moveStrategy Strategy to be implemented
*/
public void setMoveStrategy(MoveStrategy moveStrategy) {
this.moveStrategy = moveStrategy;
@@ -126,6 +168,7 @@ public class Car implements CarSpecification {
/**
* Get current move strategy
*
* @return MoveStrategy
*/
public MoveStrategy getMoveStrategy() {
+248 -19
View File
@@ -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,167 @@ 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;
}
/**
* This method will initialize the game. Therefore it interacts with the user via UserInterface
* @return true if the initialization is completed. Returns false if there is an error.
*/
public boolean initPhase() {
File folder = new File("tracks");
File[] listOfFiles = folder.listFiles();
if (listOfFiles.length > 0) {
List<String> tracks = new ArrayList<>();
for (File file : listOfFiles) {
tracks.add(file.getName());
}
File selectedTrack = listOfFiles[userInterface.selectOption("Select Track file", tracks)];
try {
selectTrack(selectedTrack);
} catch (FileNotFoundException e) {
userInterface.printInformation("There is an unexpected Error with the trackfile Path. Add trackfiles only to tracks path. Exit the Game and Fix the Problem");
return false;
} catch (InvalidTrackFormatException e) {
userInterface.printInformation("There is an unexpected Error with the trackfile. Format does not match specifications! Exit the Game and Fix the Problem");
return false;
}
List<String> moveStrategies = new ArrayList<>();
moveStrategies.add("Do not move Strategy");
moveStrategies.add("User Move Strategy");
moveStrategies.add("Move List Strategy");
moveStrategies.add("Path Follow Move Strategy");
moveStrategies.add("Path Finder Move Strategy");
for (int i = 0; i < track.getCarCount(); i++) {
Car car = track.getCar(i);
MoveStrategy moveStrategy = null;
while (moveStrategy == null) {
String filePath;
int moveStrategie = userInterface.selectOption(
"Select Strategy for Car " + i + " (" + track.getCarId(i) + ")", moveStrategies);
switch (moveStrategie) {
case 0:
moveStrategy = new DoNotMoveStrategy();
break;
case 1:
moveStrategy = new UserMoveStrategy(userInterface, i, track.getCarId(i));
break;
case 2:
filePath = ".\\moves\\" + selectedTrack.getName().split("\\.")[0] + "-car-" + track.getCar(i).getID() + ".txt";
try {
moveStrategy = new MoveListStrategy(filePath);
} catch (FileNotFoundException e) {
userInterface.printInformation("There is no Move-List implemented. Choose another Strategy!");
}
break;
case 3:
filePath = ".\\follower\\" + selectedTrack.getName().split("\\.")[0] + "_points.txt";
try {
moveStrategy = new PathFollowerMoveStrategy(filePath, track.getCarPos(i));
} catch (FileNotFoundException e) {
userInterface.printInformation("There is no Point-List implemented. Choose another Strategy!");
}
break;
case 4:
moveStrategy = new PathFinderMoveStrategy(track, i);
break;
}
}
selectMoveStrategy(car, moveStrategy);
}
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) throws InvalidTrackFormatException,FileNotFoundException {
track = new Track(selectedTrack);
return track;
}
/**
* 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();
for (int i = 0; i < track.getCarCount(); i++) {
if (track.getCar(i).getWinPoints() == 1) {
return i;
}
}
if (onlyOneCarLeft()) {
return currentCarIndex;
}
return NO_WINNER;
}
/**
@@ -96,8 +208,55 @@ public class Game implements GameSpecification {
*/
@Override
public void doCarTurn(Direction acceleration) {
// TODO: implementation
throw new UnsupportedOperationException();
track.getCar(currentCarIndex).accelerate(acceleration);
PositionVector crashPosition = null;
List<PositionVector> positionList = calculatePath(track.getCarPos(currentCarIndex), track.getCar(currentCarIndex).nextPosition());
for (int i = 0; i < positionList.size(); i++) {
if (willCarCrash(currentCarIndex, positionList.get(i))) {
if (i == 0) {
crashPosition = track.getCarPos(currentCarIndex);
} else {
crashPosition = positionList.get(i - 1);
}
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) {
track.carDoesCrash(currentCarIndex, crashPosition);
} else {
track.moveCar(currentCarIndex);
}
}
/**
* This method implements the gameflow in a while loop. If there is a winner. The method will return its carid.
*
* @return the ID of the winning car return null if there is no winner.
*/
public String gamePhase() {
while (carsMoving() && getWinner() == NO_WINNER) {
userInterface.printTrack(track);
Direction direction;
direction = track.getCar(currentCarIndex).getMoveStrategy().nextMove();
if (direction == null) {
track.getCar(currentCarIndex).setMoveStrategy(new DoNotMoveStrategy());
direction = track.getCar(currentCarIndex).getMoveStrategy().nextMove();
}
doCarTurn(direction);
switchToNextActiveCar();
}
userInterface.printTrack(track);
int indexWinner = getWinner();
if (indexWinner == NO_WINNER) {
return null;
}
return String.valueOf(track.getCar(indexWinner).getID());
}
/**
@@ -105,8 +264,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,25 +282,89 @@ 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<PositionVector> calculatePath(PositionVector startPosition, PositionVector endPosition) {
// TODO: implementation
throw new UnsupportedOperationException();
return track.calculatePointsOnPath(startPosition, endPosition);
}
/**
* This method will check if a car is passing the finishline.
* If the car is passing the finishline in the wrong direction, the car will lose a winpoint.
* If the car is passing the finishline in the correct direction, the car will gain a winpoint.
* @param start the startposition of the car
* @param finish the expected finishpositon of the car after the move
*/
private void calculateWinner(PositionVector start, PositionVector finish, int carIndex) {
List<PositionVector> path = calculatePath(start, finish);
for (PositionVector point : path) {
switch (track.getSpaceType(point)) {
case FINISH_UP:
if (start.getY() < finish.getY()) {
track.getCar(carIndex).increaseWinPoints();
} else if (start.getY() > finish.getY()) {
track.getCar(carIndex).deductWinPoints();
}
break;
case FINISH_DOWN:
if (start.getY() > finish.getY()) {
track.getCar(carIndex).increaseWinPoints();
} else if (start.getY() < finish.getY()) {
track.getCar(carIndex).deductWinPoints();
}
break;
case FINISH_RIGHT:
if (start.getX() < finish.getX()) {
track.getCar(carIndex).increaseWinPoints();
} else if (start.getX() > finish.getX()) {
track.getCar(carIndex).deductWinPoints();
}
break;
case FINISH_LEFT:
if (start.getX() > finish.getX()) {
track.getCar(carIndex).increaseWinPoints();
} else if (start.getX() < finish.getX()) {
track.getCar(carIndex).increaseWinPoints();
}
break;
}
}
}
/**
* Does indicate if a car would have a crash with a WALL space or another car at the given position.
*
* @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) {
// TODO: implementation
throw new UnsupportedOperationException();
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);
}
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;
}
}
@@ -4,6 +4,7 @@ package ch.zhaw.pm2.racetrack;
* Class for Exception when invalid Fileformat is used.
*/
public class InvalidFileFormatException extends Exception {
public InvalidFileFormatException(){super();}
public InvalidFileFormatException(String errorMessage) {
super(errorMessage);
}
@@ -7,4 +7,7 @@ public class InvalidTrackFormatException extends Exception {
public InvalidTrackFormatException(String errorMessage) {
super(errorMessage);
}
public InvalidTrackFormatException() {
super();
}
}
@@ -0,0 +1,37 @@
package ch.zhaw.pm2.racetrack;
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
UserInterface userInterface = new UserInterface("Hello and Welcome to Racetrack by Team02-\"AngryNerds\"");
while (true) {
Game game = new Game(userInterface);
String winner;
if (game.initPhase()) {
winner = game.gamePhase();
List<String> 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;
}
}
}
}
@@ -7,8 +7,8 @@ package ch.zhaw.pm2.racetrack;
* Created by mach 21.01.2020
*/
public final class PositionVector {
private int x; // horizontal component (position / velocity)
private int y; // vertical component (position / velocity)
private final int x; // horizontal component (position / velocity)
private final int y; // vertical component (position / velocity)
/**
* Enum representing a direction on the track grid.
+348 -25
View File
@@ -1,9 +1,15 @@
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.FileInputStream;
import java.io.FileNotFoundException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
/**
* This class represents the racetrack board.
@@ -54,19 +60,212 @@ import java.io.FileNotFoundException;
public class Track implements TrackSpecification {
public static final char CRASH_INDICATOR = 'X';
// TODO: Add necessary variables
private final List<String> track;
private final List<Car> cars;
private final List<PositionVector> finishLine;
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
* @throws FileNotFoundException if the given track file could not be found
* @throws InvalidTrackFormatException if the track file contains invalid data (no tracklines, ...)
*/
public Track(File trackFile) throws FileNotFoundException, InvalidTrackFormatException {
// TODO: implementation
throw new UnsupportedOperationException();
track = new ArrayList<>();
cars = new ArrayList<>();
finishLine = new ArrayList<>();
readFile(trackFile);
findFinish();
addCars();
}
/**
* This method reads the File and saves it to the track ArrayList Line by Line
*
* @param trackFile the File where the track has been documented
* @throws FileNotFoundException if the FilePath is invalid.
*/
private void readFile(File trackFile) throws FileNotFoundException {
Scanner scanner = new Scanner(new FileInputStream(trackFile), StandardCharsets.UTF_8);
while (scanner.hasNextLine()) {
track.add(scanner.nextLine());
}
}
/**
* Goes through the track ArrayList and determines the locations of each cars and initializes them at the location.
*
* @throws InvalidTrackFormatException is thrown if a car is found more than once inside the track.
*/
private void addCars() throws InvalidTrackFormatException {
ConfigSpecification.SpaceType[] spaceTypes = ConfigSpecification.SpaceType.values();
List<Character> allSpaceTypesAsChar = new ArrayList<>();
List<Character> usedSymbolForCar = new ArrayList<>();
for (ConfigSpecification.SpaceType spaceType : spaceTypes) {
allSpaceTypesAsChar.add(spaceType.getValue());
}
for (int yPosition = 0; yPosition < track.size(); yPosition++) {
String line = track.get(yPosition);
for (int xPosition = 0; xPosition < line.length(); xPosition++) {
char possibleCarChar = line.charAt(xPosition);
if (!allSpaceTypesAsChar.contains(possibleCarChar)) {
if (usedSymbolForCar.contains(possibleCarChar)) {
throw new InvalidTrackFormatException();
}
usedSymbolForCar.add(possibleCarChar);
cars.add(new Car(possibleCarChar, new PositionVector(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 {
for (int i = 0; i < track.size(); i++) {
String line = track.get(i);
for (int j = 0; j < line.length(); j++) {
if (line.charAt(j) == ConfigSpecification.SpaceType.FINISH_LEFT.getValue() ||
line.charAt(j) == ConfigSpecification.SpaceType.FINISH_RIGHT.getValue() ||
line.charAt(j) == ConfigSpecification.SpaceType.FINISH_DOWN.getValue() ||
line.charAt(j) == ConfigSpecification.SpaceType.FINISH_UP.getValue()) {
finishLine.add(new PositionVector(j, i));
}
}
}
if (finishLine.size() == 0) {
throw new InvalidTrackFormatException();
}
finishTyp = getSpaceType(finishLine.get(0));
for (PositionVector positionVector : finishLine) {
if (getSpaceType(positionVector) != finishTyp) {
throw new InvalidTrackFormatException();
}
}
}
/**
* Method to find the PositionVector of a chosen character
*
* @param symbol char that we are looking for on the track
* @return the PositionVector of the desired char
*/
private PositionVector findChar(char symbol) {
PositionVector vector = null;
for (int i = 0; i < track.size(); i++) {
String line = track.get(i);
for (int j = 0; j < line.length(); j++) {
if (line.charAt(j) == symbol) {
vector = new PositionVector(j, i);
}
}
}
return vector;
}
/**
* Method that places a character at a chosen position
*
* @param positionVector position where char will be placed
* @param symbol char that should be placed at desired position
*/
private void drawCharOnTrackIndicator(PositionVector positionVector, char symbol) {
String line = track.get(positionVector.getY());
line = line.substring(0, positionVector.getX()) + symbol + line.substring(positionVector.getX() + 1);
track.remove(positionVector.getY());
track.add(positionVector.getY(), line);
}
/**
* Method that returns the finishline as a List
*
* @return finishLine List
*/
public List<PositionVector> getFinishLine() {
return finishLine;
}
/**
* Returns the whole Track as List of Strings
*
* @return track as List of Strings
*/
public List<String> getTrack() {
return track;
}
/**
* This Method will update the Car on the track
* and will make the Car move to the next position
*
* @param carIndex representing the current Car
*/
public void moveCar(int carIndex) {
makeCarMoveInTrack(carIndex);
//Change position of car
getCar(carIndex).move();
}
/**
* This Method does change the Position of the car inside the track object.
*
* @param carIndex of the current car
*/
private void makeCarMoveInTrack(int carIndex) {
PositionVector carPositionVector = findChar(getCarId(carIndex));
//Removes the Car at Current Pos
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
carPositionVector = cars.get(carIndex).nextPosition();
drawCharOnTrackIndicator(carPositionVector, cars.get(carIndex).getID());
}
/**
* This Method will check if the Car would crash at the specific position
*
* @param positionVector the position to check if the car would crash
* @return true if crash otherwise false
*/
public boolean willCrashAtPosition(int carIndex, PositionVector positionVector) {
char charAtPosition = track.get(positionVector.getY()).charAt(positionVector.getX());
if (getCarId(carIndex) == charAtPosition) return false;
return !(charAtPosition == ConfigSpecification.SpaceType.TRACK.value ||
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 mark the Car as crashed inside the track and the car Object.
*
* @param carIndex of car that will be marked as crashed
* @param crashPositionVector of the location of the crash
*/
public void carDoesCrash(int carIndex, PositionVector crashPositionVector) {
PositionVector currentCarPosition = getCarPos(carIndex);
drawCharOnTrackIndicator(new PositionVector(currentCarPosition.getX(), currentCarPosition.getY()), ConfigSpecification.SpaceType.TRACK.getValue());
Car car = cars.get(carIndex);
car.crash();
car.setPosition(crashPositionVector);
drawCharOnTrackIndicator(new PositionVector(crashPositionVector.getX(), crashPositionVector.getY()), CRASH_INDICATOR);
}
/**
@@ -74,23 +273,29 @@ public class Track implements TrackSpecification {
* If the location is outside the track bounds, it is considered a wall.
*
* @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
public Config.SpaceType getSpaceType(PositionVector position) {
// TODO: implementation
throw new UnsupportedOperationException();
char charAtPosition = track.get(position.getY()).charAt(position.getX());
ConfigSpecification.SpaceType[] spaceTypes = ConfigSpecification.SpaceType.values();
for (ConfigSpecification.SpaceType spaceType : spaceTypes) {
if (spaceType.getValue() == charAtPosition) {
return spaceType;
}
}
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
public int getCarCount() {
// TODO: implementation
throw new UnsupportedOperationException();
return cars.size();
}
/**
@@ -101,8 +306,7 @@ public class Track implements TrackSpecification {
*/
@Override
public Car getCar(int carIndex) {
// TODO: implementation
throw new UnsupportedOperationException();
return cars.get(carIndex);
}
/**
@@ -113,20 +317,19 @@ public class Track implements TrackSpecification {
*/
@Override
public char getCarId(int carIndex) {
// TODO: implementation
throw new UnsupportedOperationException();
return cars.get(carIndex).getID();
}
/**
* Get the position of the specified car.
* Returns Null if carIndex not valid
*
* @param carIndex The zero-based carIndex number
* @return A PositionVector containing the car's current position
*/
@Override
public PositionVector getCarPos(int carIndex) {
// TODO: implementation
throw new UnsupportedOperationException();
return findChar(cars.get(carIndex).getID());
}
/**
@@ -137,8 +340,7 @@ public class Track implements TrackSpecification {
*/
@Override
public PositionVector getCarVelocity(int carIndex) {
// TODO: implementation
throw new UnsupportedOperationException();
return cars.get(carIndex).getVelocity();
}
/**
@@ -152,8 +354,128 @@ public class Track implements TrackSpecification {
*/
@Override
public char getCharAtPosition(int y, int x, Config.SpaceType currentSpace) {
// TODO: implementation
throw new UnsupportedOperationException();
char charAtPos = track.get(y).charAt(x);
PositionVector positionVector = new PositionVector(x, y);
for (Car car : cars) {
if (charAtPos == car.getID()) {
return charAtPos;
}
}
if (positionVector.equals(findChar(CRASH_INDICATOR))) return CRASH_INDICATOR;
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) {
ArrayList<PositionVector> pathList = new ArrayList<>();
// Use Bresenham's algorithm to determine positions.
int x = startPosition.getX();
int y = startPosition.getY();
// Relative Distance (x & y axis) between end- and starting position
int diffX = endPosition.getX() - startPosition.getX();
int diffY = endPosition.getY() - startPosition.getY();
// Absolute distance (x & y axis) between end- and starting position
int distX = Math.abs(diffX);
int distY = Math.abs(diffY);
// Direction of vector on x & y axis (-1: to left/down, 0: none, +1 : to right/up)
int dirX = Integer.signum(diffX);
int dirY = Integer.signum(diffY);
// Determine which axis is the fast direction and set parallel/diagonal step values
int parallelStepX, parallelStepY;
int diagonalStepX, diagonalStepY;
int distanceSlowAxis, distanceFastAxis;
if (distX > distY) {
// x axis is the 'fast' direction
parallelStepX = dirX;
parallelStepY = 0; // parallel step only moves in x direction
diagonalStepX = dirX;
diagonalStepY = dirY; // diagonal step moves in both directions
distanceSlowAxis = distY;
distanceFastAxis = distX;
} else {
// y axis is the 'fast' direction
parallelStepX = 0;
parallelStepY = dirY; // parallel step only moves in y direction
diagonalStepX = dirX;
diagonalStepY = dirY; // diagonal step moves in both directions
distanceSlowAxis = distX;
distanceFastAxis = distY;
}
int error = distanceFastAxis / 2;
for (int step = 0; step < distanceFastAxis; step++) {
error -= distanceSlowAxis;
if (error < 0) {
error += distanceFastAxis; // correct error value to be positive again
// step into slow direction; diagonal step
x += diagonalStepX;
y += diagonalStepY;
} else {
// step into fast direction; parallel step
x += parallelStepX;
y += parallelStepY;
}
pathList.add(new PositionVector(x, y));
}
return pathList;
}
/**
* 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;
}
/**
@@ -163,7 +485,8 @@ public class Track implements TrackSpecification {
*/
@Override
public String toString() {
// TODO: implementation
throw new UnsupportedOperationException();
StringBuilder str = new StringBuilder();
for (String line : track) str.append(line).append("\n");
return str.toString();
}
}
@@ -0,0 +1,120 @@
package ch.zhaw.pm2.racetrack;
import org.beryx.textio.TextIO;
import org.beryx.textio.TextIoFactory;
import org.beryx.textio.TextTerminal;
import java.util.List;
/**
* Class representing the Userinterface.
* Used to get inputs from users via textio.
*
* @author Roman Schenk
*/
public class UserInterface {
private final TextIO textIO;
private final TextTerminal<?> textTerminal;
/**
* Opens a new Terminal Window and prints the welcome Text.
*
* @param welcomeText The Text which will be printed after the windows is opened.
*/
public UserInterface(String welcomeText) {
textIO = TextIoFactory.getTextIO();
textTerminal = textIO.getTextTerminal();
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);
}
/**
* Method which asks the user to choose one of the options given.
*
* @param text Text which is printed before the options are printed. Example: "Select Track file:"
* @param options List with the options which can be selected.
* @return the list index of the selected option
*/
public int selectOption(String text, List<String> options) {
textTerminal.println(text + ":");
for (int option = 0; option < options.size(); option++) {
textTerminal.println(" " + (option + 1) + ": " + options.get(option));
}
return textIO.newIntInputReader().withMinVal(1).withMaxVal(options.size()).read("Enter your choice: ") - 1;
}
/**
* Gives information which player is at turn and asks for the direction to accelerate or quit the game.
*
* @param playingCarIndex the index of the player
* @param playingCarID the ID of the player
* @return the direction which is selected by the player. If null -> quit game
*/
public PositionVector.Direction selectDirection(int playingCarIndex, char playingCarID) {
PositionVector.Direction direction = null;
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");
textTerminal.println("1 2 3 1=down-left, 2=down, 3=down-right");
textTerminal.println("\n10 = quit \n");
while (direction == null) { //asks until a valid input in entered
int number = textIO.newIntInputReader().withMinVal(1).withMaxVal(10).read("choose your Acceleration direction: ");
if (number == 10) { //quit game
return null;
}
direction = getDirection(number);
}
return direction;
}
/**
* Method which returns the associated direction Object.
*
* @param number the number which was typed by the user
* @return the associated direction. If null -> unknown number
*/
private PositionVector.Direction getDirection(int number) {
return switch (number) {
case 1 -> PositionVector.Direction.DOWN_LEFT;
case 2 -> PositionVector.Direction.DOWN;
case 3 -> PositionVector.Direction.DOWN_RIGHT;
case 4 -> PositionVector.Direction.LEFT;
case 5 -> PositionVector.Direction.NONE;
case 6 -> PositionVector.Direction.RIGHT;
case 7 -> PositionVector.Direction.UP_LEFT;
case 8 -> PositionVector.Direction.UP;
case 9 -> PositionVector.Direction.UP_RIGHT;
default -> null;
};
}
/**
* Method to print the given Track in the terminal
*
* @param track the track which should be printed
*/
public void printTrack(Track track) {
textTerminal.println(track.toString());
}
/**
* Method to dispose of the Textterminal
*
* @param text Output Text
*/
public void quit(String text) {
textIO.newStringInputReader().withMinLength(0).read(text);
textTerminal.dispose();
}
}
@@ -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;
}
}
@@ -2,11 +2,45 @@ 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.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class MoveListStrategy implements MoveStrategy {
private final List<Direction> 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), StandardCharsets.UTF_8);
Direction[] directions = Direction.values();
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
for (Direction direction : directions) {
if (direction.toString().equals(line)) {
moveList.add(direction);
break;
}
}
}
}
@Override
public Direction nextMove() {
// TODO: implementation
throw new UnsupportedOperationException();
pointer += 1;
if (pointer < moveList.size()) {
return moveList.get(pointer);
}
return null;
}
}
@@ -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;
}
}
@@ -1,15 +1,127 @@
package ch.zhaw.pm2.racetrack.strategy;
import ch.zhaw.pm2.racetrack.PositionVector;
import ch.zhaw.pm2.racetrack.PositionVector.Direction;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Scanner;
/**
* The PathFollowerMoveStrategy class determines the next move based on a file containing points on a path.
*/
public class PathFollowerMoveStrategy implements MoveStrategy {
/**
* The current Position of the car.
*/
private PositionVector currentPosition;
/**
* The current Velocity of the car.
*/
private PositionVector currentVelocity;
/**
* List of all points on the path.
*/
private final ArrayList<PositionVector> pointList;
/**
* The index of the next point on the path.
*/
private int pointer;
/**
* Constructor to create a new PathFollowerMoveStrategy for a car.
* @param path The location where the file is saved
* @param startPosition The start position of the car
* @throws FileNotFoundException If the file with the given path does not exist.
*/
public PathFollowerMoveStrategy(String path, PositionVector startPosition) throws FileNotFoundException {
pointList = new ArrayList<>();
pointer = 0;
readFile(new File(path));
currentPosition = startPosition;
currentVelocity = new PositionVector(0, 0);
}
/**
* Method to read the given File and add the points to the pointList
* @param trackFile the File Object which should be read
* @throws FileNotFoundException If the file with the given path does not exist.
*/
public void readFile(File trackFile) throws FileNotFoundException {
Scanner scanner = new Scanner(new FileInputStream(trackFile), StandardCharsets.UTF_8);
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
String[] coordinates = line.split("(\\(X:|, Y:|\\))");
pointList.add(new PositionVector(Integer.parseInt(coordinates[1]), Integer.parseInt(coordinates[2])));
}
}
/**
* Method to select the direction for the next move.
* @return The direction for the next move. null if there are no points left in the list.
*/
@Override
public Direction nextMove() {
// TODO: implementation
throw new UnsupportedOperationException();
// if no more points in the list --> return null
if (pointer >= pointList.size()) {
return null;
}
// increase pointer variable if the next point is reached.
if (pointList.get(pointer).equals(currentPosition)) {
pointer ++;
}
// calculate Vector from current Position to next Point
PositionVector movementVector = new PositionVector(pointList.get(pointer).getX() - currentPosition.getX(), pointList.get(pointer).getY() - currentPosition.getY());
// select acceleration for X
int accelerationX;
if((movementVector.getX() == 0 && currentVelocity.getX() > 0) || //reduce velocity to 0 if the destination coordinate is reached
(movementVector.getX() > 0 && movementVector.getX()/2.0 <= currentVelocity.getX()) || //increase velocity
(movementVector.getX() < 0 && movementVector.getX()/2.0 < currentVelocity.getX())){ //reduce velocity
accelerationX = -1;
} else if((movementVector.getX() == 0 && currentVelocity.getX() < 0) || //reduce velocity to 0 if the destination coordinate is reached
(movementVector.getX() > 0 && movementVector.getX()/2.0 > currentVelocity.getX()) || //increase velocity
(movementVector.getX() < 0 && movementVector.getX()/2.0 >= currentVelocity.getX())) { //reduce velocity
accelerationX = 1;
}
else { //no acceleration
accelerationX = 0;
}
// select acceleration for Y
int accelerationY;
if((movementVector.getY() == 0 && currentVelocity.getY() > 0) || //reduce velocity to 0 if the destination coordinate is reached
(movementVector.getY() > 0 && movementVector.getY()/2.0 <= currentVelocity.getY()) || //increase velocity
(movementVector.getY() < 0 && movementVector.getY()/2.0 < currentVelocity.getY())){ //reduce velocity
accelerationY = -1;
} else if((movementVector.getY() == 0 && currentVelocity.getY() < 0) || //reduce velocity to 0 if the destination coordinate is reached
(movementVector.getY() > 0 && movementVector.getY()/2.0 > currentVelocity.getY()) || //increase velocity
(movementVector.getY() < 0 && movementVector.getY()/2.0 >= currentVelocity.getY())) { //reduce velocity
accelerationY = 1;
}
else { //no acceleration
accelerationY = 0;
}
//update current Velocity and current Position with the selected acceleration
currentVelocity = new PositionVector(currentVelocity.getX() + accelerationX, currentVelocity.getY() + accelerationY);
currentPosition = new PositionVector(currentPosition.getX() + currentVelocity.getX(), currentPosition.getY() + currentVelocity.getY());
//Find Direction for acceleration
PositionVector acceleration = new PositionVector(accelerationX, accelerationY);
Direction[] directions = Direction.values();
for (Direction direction : directions) {
if (direction.vector.equals(acceleration)) {
return direction;
}
}
return null;
}
}
@@ -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 final UserInterface userInterface;
private final int carIndex;
private final 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);
}
}
+26
View File
@@ -0,0 +1,26 @@
###############################################################
################# #############
############### ###########
############### #########
############### ################## #########
############### #################### #########
############## ##################### #########
############ ###################### ##########
######### ###################### ############
######### ###################### ##############
######### ##################### ################
######### ################# ##################
######### ################ ##################
########## ################## ###############
########### #################### #############
########### ####################### ##########
########## ########################## #########
######### ############################ ########
######## ############################# ########
####### ############################## ########
###### ############################# ########
###### ############################ #########
###### > a ###########
###### > a ##############
######## > b #################
###############################################################
@@ -0,0 +1,228 @@
package ch.zhaw.pm2.racetrack;
import ch.zhaw.pm2.racetrack.strategy.*;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
/**
* Tests for Class Car
*/
class CarTest {
Car car;
// Default coordinates for tests
int DEFAULT_X = 10;
int DEFAULT_Y = 10;
char DEFAULT_ID = 'f';
/**
* Create a new Car Object and set Position to a defined Default Position
*/
@BeforeEach
void setUp() {
car = new Car(DEFAULT_ID, new PositionVector(DEFAULT_X, DEFAULT_Y));
}
@Test
void getID() {
assertEquals(DEFAULT_ID, car.getID());
}
/**
* Method to check nextPosition with coordinates as int
*
* @param x the expected value for x coordinate
* @param y the expected value for y coordinate
*/
void checkNextPosition(int x, int y) {
assertEquals(new PositionVector(x, y), car.nextPosition());
}
/**
* - checks if the position of the car can be set and saved correctly with valid positions.
* - checks if an exception is throwed and position keeps unchanged if invalid coordinates are entered.
*/
@Test
void setPosition() {
checkNextPosition(DEFAULT_X, DEFAULT_Y);
// List of valid Positions
List<PositionVector> validPositions = new ArrayList<>();
validPositions.add(new PositionVector(20, 20));
validPositions.add(new PositionVector(0, 0));
validPositions.add(new PositionVector(20, 0));
validPositions.add(new PositionVector(0, 20));
for (PositionVector positionVector : validPositions) {
car.setPosition(positionVector);
assertEquals(positionVector, car.nextPosition());
}
// List of invalid positions.
List<PositionVector> invalidPositions = new ArrayList<>();
invalidPositions.add(new PositionVector(0, -20));
invalidPositions.add(new PositionVector(-20, 0));
invalidPositions.add(new PositionVector(-20, -20));
for (PositionVector positionVector : invalidPositions) {
boolean exception = false;
setUp();
try {
car.setPosition(positionVector);
} catch (IllegalArgumentException e) {
exception = true;
}
assertTrue(exception);
// position should keep unchanged
checkNextPosition(DEFAULT_X, DEFAULT_Y);
}
}
void checkVelocity(int x, int y) {
assertEquals(new PositionVector(x, y), car.getVelocity());
}
/**
* Checks if the methods accelerate, move and getVelocity are working correctly with acceleration in all directions.
* Checks also if velocity is calculated correctly if method accelerate is called a second time.
*/
@Test
void movement() {
// add all possible directions in a List
PositionVector.Direction[] directions = PositionVector.Direction.values();
//position shouldn't be changed because velocity should be 0.
car.move();
checkNextPosition(DEFAULT_X, DEFAULT_Y);
for (PositionVector.Direction direction1 : directions) {
for (PositionVector.Direction direction2 : directions) {
//create a new instance of Car with default coordinates and velocity 0.
setUp();
//variables to save the actual expected result of method nextPosition
int expectedNextPosX = DEFAULT_X;
int expectedNextPosY = DEFAULT_Y;
//variables to save the acutal expected result of method getVelocity
int expectedVelocityX = 0;
int expectedVelocityY = 0;
car.accelerate(direction1);
expectedVelocityX += direction1.vector.getX();
expectedVelocityY += direction1.vector.getY();
expectedNextPosX += direction1.vector.getX();
expectedNextPosY += direction1.vector.getY();
checkVelocity(expectedVelocityX, expectedVelocityY);
checkNextPosition(expectedNextPosX, expectedNextPosY);
car.move();
expectedNextPosX += direction1.vector.getX();
expectedNextPosY += direction1.vector.getY();
checkVelocity(expectedVelocityX, expectedVelocityY);
checkNextPosition(expectedNextPosX, expectedNextPosY);
car.accelerate(direction2);
expectedVelocityX += direction2.vector.getX();
expectedVelocityY += direction2.vector.getY();
expectedNextPosX += direction2.vector.getX();
expectedNextPosY += direction2.vector.getY();
checkVelocity(expectedVelocityX, expectedVelocityY);
checkNextPosition(expectedNextPosX, expectedNextPosY);
car.move();
checkVelocity(expectedVelocityX, expectedVelocityY);
expectedNextPosX += (direction1.vector.getX() + direction2.vector.getX());
expectedNextPosY += (direction1.vector.getY() + direction2.vector.getY());
checkNextPosition(expectedNextPosX, expectedNextPosY);
}
}
}
/**
* test for methods crash and isCrashed. checks if state crashed is set and returned correctly.
*/
@Test
void crash() {
assertFalse(car.isCrashed());
car.crash();
assertTrue(car.isCrashed());
}
/**
* test for methods setMoveStrategy. Checks if the MoveStrategy Object is saved and returned correctly
* with all Types of MoveStrategy.
*/
@Test
void MoveStrategy() {
MoveStrategy moveStrategy;
moveStrategy = new DoNotMoveStrategy();
car.setMoveStrategy(moveStrategy);
assertEquals(moveStrategy, car.getMoveStrategy());
try {
moveStrategy = new MoveListStrategy(".\\moves\\challenge-car-a.txt");
} catch (FileNotFoundException e) {
Assertions.fail();
}
car.setMoveStrategy(moveStrategy);
assertEquals(moveStrategy, car.getMoveStrategy());
try {
moveStrategy = new PathFollowerMoveStrategy(".\\follower\\challenge_points.txt", new PositionVector(0, 0));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
car.setMoveStrategy(moveStrategy);
assertEquals(moveStrategy, car.getMoveStrategy());
moveStrategy = new UserMoveStrategy(new UserInterface("Hello"),0,'a');
car.setMoveStrategy(moveStrategy);
assertEquals(moveStrategy, car.getMoveStrategy());
}
/**
* Test for get WinPoints
*/
@Test
void getWinPoints() {
assertEquals(0,car.getWinPoints());
}
/**
* Test for increase WinPoints
*/
@Test
void increaseWinPoints() {
car.increaseWinPoints();
assertEquals(1,car.getWinPoints());
}
/**
* Test for deduct WinPoints
*/
@Test
void deductWinPoints() {
car.deductWinPoints();
assertEquals(-1,car.getWinPoints());
}
}
@@ -0,0 +1,228 @@
package ch.zhaw.pm2.racetrack;
import ch.zhaw.pm2.racetrack.strategy.UserMoveStrategy;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Assertions;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.List;
import static ch.zhaw.pm2.racetrack.Game.NO_WINNER;
import static ch.zhaw.pm2.racetrack.PositionVector.Direction.*;
/**
* Test for Class Game
*/
class GameTest {
private UserInterface userInterface;
private Game game;
private Track track;
private final String TRACK_FILE_PATH = ".\\tracks\\challenge.txt";
private final int CAR_INDEX_ONE = 0;
private final int CAR_INDEX_TWO = 1;
/**
* This nested Class tests if the game gets initiatet correctly
*/
@Nested
@DisplayName("Test correct Setup")
class Setup {
@BeforeEach
void setup() {
userInterface = new UserInterface("Test");
game = new Game(userInterface);
try {
track = game.selectTrack(new File(TRACK_FILE_PATH));
} catch (InvalidTrackFormatException | FileNotFoundException e) {
e.printStackTrace();
Assertions.fail();
}
game.selectMoveStrategy(track.getCar(CAR_INDEX_ONE), new UserMoveStrategy(new UserInterface("Testing"), CAR_INDEX_ONE, track.getCarId(CAR_INDEX_ONE)));
game.selectMoveStrategy(track.getCar(CAR_INDEX_TWO), new UserMoveStrategy(new UserInterface("Testing"), CAR_INDEX_TWO, track.getCarId(CAR_INDEX_TWO)));
}
@Test
void getCurrentCarIndex() {
Assertions.assertEquals(CAR_INDEX_ONE, game.getCurrentCarIndex());
game.switchToNextActiveCar();
Assertions.assertEquals(CAR_INDEX_TWO, 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());
}
}
/**
* This nested Class makes basic manipulation after Game init.
*/
@Nested
@DisplayName("Basic manipulation")
class Manipulation {
@BeforeEach
void setup() {
userInterface = new UserInterface("Test");
game = new Game(userInterface);
try {
track = game.selectTrack(new File(TRACK_FILE_PATH));
} catch (InvalidTrackFormatException | FileNotFoundException e) {
e.printStackTrace();
Assertions.fail();
}
game.selectMoveStrategy(track.getCar(CAR_INDEX_ONE), new UserMoveStrategy(new UserInterface("Testing"), CAR_INDEX_ONE, track.getCarId(CAR_INDEX_ONE)));
game.selectMoveStrategy(track.getCar(CAR_INDEX_TWO), new UserMoveStrategy(new UserInterface("Testing"), CAR_INDEX_TWO, track.getCarId(CAR_INDEX_TWO)));
}
@Test
void carTurnCorrect() {
game.doCarTurn(RIGHT);
Assertions.assertEquals(new PositionVector(1, 0), game.getCarVelocity(0));
}
@Test
void carCrash() {
game.doCarTurn(PositionVector.Direction.UP);
Assertions.assertTrue(game.onlyOneCarLeft());
}
}
/**
* This nested Class tests a Playtrough. And implements a UserInterface interagtion to pretend a real player
*/
@Nested
@DisplayName("Playtrough")
class Play {
private Game game;
@Test
void winner() {
game = new Game(new interFace("Test",new Integer[]{0,2,0},new PositionVector.Direction[]{RIGHT,
RIGHT,
RIGHT,
NONE,
NONE,
NONE,
NONE,
UP,
LEFT,
LEFT,
LEFT,
LEFT,
UP_LEFT,
NONE,
RIGHT,
RIGHT,
RIGHT,
NONE,
LEFT,
DOWN_LEFT,
DOWN_LEFT,
LEFT,
LEFT,
NONE,
RIGHT,
NONE,
DOWN,
DOWN,
RIGHT,
NONE,
RIGHT,
DOWN,
NONE,
UP_RIGHT,
RIGHT,
UP_RIGHT,
UP_RIGHT,
RIGHT,
RIGHT}));
game.initPhase();
Assertions.assertEquals("a",game.gamePhase());
}
@Test
void crashA() {
game = new Game(new interFace("Test",new Integer[]{0,1,0},new PositionVector.Direction[]{UP}));
game.initPhase();
Assertions.assertEquals("b",game.gamePhase());
}
}
private class interFace extends UserInterface {
private PositionVector.Direction[] directions;
private Integer[] instructions;
private int pointerDir,pointerInstruction;
public interFace(String welcometxt, Integer[] instructions, PositionVector.Direction[] directions) {
super(welcometxt);
pointerDir = -1;
pointerInstruction = -1;
this.instructions = instructions;
this.directions = directions;
}
@Override
public int selectOption(String text, List<String> options) {
pointerInstruction++;
return instructions[pointerInstruction];
}
public void printInformation(String text) {
}
public void printTrack(Track track) {
}
public void quit(String text) {
}
public PositionVector.Direction selectDirection(int playingCarIndex, char playingCarID) {
pointerDir += 1;
if(pointerDir < directions.length) {
return directions[pointerDir];
}
return NONE;
}
}
}
@@ -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());
}
}
}
@@ -0,0 +1,159 @@
package ch.zhaw.pm2.racetrack;
import ch.zhaw.pm2.racetrack.given.ConfigSpecification;
import org.junit.jupiter.api.*;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.List;
public class TrackTest {
Track trackObj;
@Nested
@DisplayName("Positiv Test Cases")
class positivClass {
@BeforeEach
void setup() {
File file = new File(".\\tracks\\challenge.txt");
try {
trackObj = new Track(file);
} catch (FileNotFoundException | InvalidTrackFormatException e) {
e.printStackTrace();
Assertions.fail();
}
}
@Test
@DisplayName("Create correct amount of Car instance")
void checkCars() {
Assertions.assertEquals(2, trackObj.getCarCount());
}
@Test
@DisplayName("Create Car instance with correct Symbols / Id")
void checkCarId() {
Assertions.assertEquals('a', trackObj.getCarId(0));
Assertions.assertEquals('b', trackObj.getCarId(1));
}
@Test
@DisplayName("Check getSpaceTyp")
void getSpaceTyp() {
Assertions.assertEquals(ConfigSpecification.SpaceType.FINISH_RIGHT, trackObj.getSpaceType(new PositionVector(22, 24)));
}
@Test
@DisplayName("Find FinishLine")
void findFinish() {
List<PositionVector> expected = new ArrayList<>();
expected.add(new PositionVector(22, 22));
expected.add(new PositionVector(22, 23));
expected.add(new PositionVector(22, 24));
Assertions.assertEquals(expected, trackObj.getFinishLine());
}
@Test
@DisplayName("Converts Trackfile correctly to List<String>")
void checkTrack() {
Track trackObj;
try {
trackObj = new Track(new File(".\\tracks\\oval-anticlock-right.txt"));
List<String> track = new ArrayList<>();
track.add("##################################################");
track.add("##################################################");
track.add("############## #############");
track.add("########## ##########");
track.add("####### #######");
track.add("###### ################# ######");
track.add("##### ################### #####");
track.add("##### ################### #####");
track.add("###### ################# ######");
track.add("####### > a #######");
track.add("########## > ##########");
track.add("############## > b ##############");
track.add("##################################################");
track.add("##################################################");
Assertions.assertLinesMatch(track, trackObj.getTrack());
} catch (FileNotFoundException | InvalidTrackFormatException e) {
e.printStackTrace();
}
}
@Test
@DisplayName("Make Car move down on track")
void makeCarMoveDown() {
PositionVector beforeMove = trackObj.getCarPos(0);
trackObj.getCar(0).accelerate(PositionVector.Direction.DOWN);
trackObj.moveCar(0);
PositionVector afterMove = trackObj.getCarPos(0);
Assertions.assertEquals(beforeMove.getY() + 1, afterMove.getY());
Assertions.assertEquals(beforeMove.getX(), afterMove.getX());
}
@Test
@DisplayName("Make Car move with (0,0) acceleration on track")
void makeCarStay() {
PositionVector beforeMove = trackObj.getCarPos(0);
trackObj.moveCar(0);
PositionVector afterMove = trackObj.getCarPos(0);
Assertions.assertEquals(beforeMove.getY(), afterMove.getY());
Assertions.assertEquals(beforeMove.getX(), afterMove.getX());
}
@Test
@DisplayName("Will Car Crash")
void willCarCrash() {
//Car will Crash
Assertions.assertTrue(trackObj.willCrashAtPosition(0, new PositionVector(25, 21)));
//Car will not Crash and is on track
Assertions.assertFalse(trackObj.willCrashAtPosition(0, new PositionVector(7, 22)));
//Car will not Crash and is on finishLine
Assertions.assertFalse(trackObj.willCrashAtPosition(0, trackObj.getFinishLine().get(0)));
}
@Test
@DisplayName("Make Car Crash")
void makeCarCrash() {
trackObj.carDoesCrash(0, new PositionVector(6, 22));
Assertions.assertEquals(Track.CRASH_INDICATOR, trackObj.getTrack().get(22).charAt(6));
Assertions.assertTrue(trackObj.getCar(0).isCrashed());
}
}
@Nested
@DisplayName("Negative TestCase")
class negativeClass {
File file;
@BeforeEach
void setup() {
file = new File(".\\tracks\\challenge.txt");
try {
trackObj = new Track(file);
} catch (InvalidTrackFormatException | FileNotFoundException e) {
System.err.println("Error in Test compareTrack" + e.getMessage());
}
}
@Test
@DisplayName("Throw error if File not found")
void canReadFile() {
file = new File(".\\tracks\\NotExisting.txt");
Assertions.assertThrows(FileNotFoundException.class, () -> new Track(file));
}
@Test
@DisplayName("Throw error if File is invalid")
void invalidTrackFile() {
File testfile = new File(".\\src\\test\\InvalidTracks\\sameCar.txt");
Assertions.assertThrows(InvalidTrackFormatException.class, () -> new Track(testfile));
}
}
}
-1
View File
@@ -1 +0,0 @@
challenge_points.txt