Merge remote-tracking branch 'origin/main'
# Conflicts: # src/main/java/ch/zhaw/pm2/racetrack/strategy/PathFinderMoveStrategy.java
This commit is contained in:
commit
c43a08cef9
|
@ -38,7 +38,7 @@ And every other character represents a car.
|
||||||
The winner gets determined automatically. <br> The car that first passes the finish line (doing a complete round) is given the win, if all car except one crash the surviving car will be crowned as the winner.<br>The game will inform you of this, and you will have the option to quit the game or play another match.
|
The winner gets determined automatically. <br> The car that first passes the finish line (doing a complete round) is given the win, if all car except one crash the surviving car will be crowned as the winner.<br>The game will inform you of this, and you will have the option to quit the game or play another match.
|
||||||
|
|
||||||
## Branching Model
|
## Branching Model
|
||||||
We choose a simple branching model where all starting features got a branch and where merged into the main branch, some branches who needed unfinished code to be completed where taken from the game branch but merged into the main at the end as well.<br> Since there was just one end product we abstained from using a development branch and merges where done straight into main branch.
|
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.<br>Commits which contain only documentation and doesn't change any functionality are committed directly into the Main branch.
|
||||||
|
|
||||||
## Class Diagramm
|
## Class Diagramm
|
||||||
![Classdiagramm of this program](/Klassendiagramm.drawio)
|
![Classdiagramm of this program](/Klassendiagramm.drawio)
|
||||||
|
|
|
@ -4,30 +4,46 @@ import ch.zhaw.pm2.racetrack.PositionVector;
|
||||||
import ch.zhaw.pm2.racetrack.Track;
|
import ch.zhaw.pm2.racetrack.Track;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Strategy which calculates the path automatically
|
||||||
|
*/
|
||||||
public class PathFinderMoveStrategy implements MoveStrategy{
|
public class PathFinderMoveStrategy implements MoveStrategy{
|
||||||
private Track track;
|
private Track track;
|
||||||
private int carIndex;
|
private int carIndex;
|
||||||
private List<PositionVector.Direction> moveList;
|
private List<PositionVector.Direction> moveList;
|
||||||
|
// the index of the next move in moveList
|
||||||
private int pointer;
|
private int pointer;
|
||||||
private List<PositionVector.Direction> allDirections;
|
// all Directions which can be used for acceleration
|
||||||
|
private PositionVector.Direction[] allDirections;
|
||||||
|
// List of all States (combination of Position and Velocity) which are already reached with a calculated move.
|
||||||
private List<State> calculatedStates;
|
private List<State> calculatedStates;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor which initialises the needed variables and creates the MoveList
|
||||||
|
* @param track track instance of the game
|
||||||
|
* @param carIndex index of the car which owns this moveStrategy
|
||||||
|
*/
|
||||||
public PathFinderMoveStrategy(Track track, int carIndex) {
|
public PathFinderMoveStrategy(Track track, int carIndex) {
|
||||||
this.track = track;
|
this.track = track;
|
||||||
this.carIndex = carIndex;
|
this.carIndex = carIndex;
|
||||||
allDirections = Arrays.asList(PositionVector.Direction.values());
|
allDirections = PositionVector.Direction.values();
|
||||||
createMoveList();
|
createMoveList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to create a working moveList
|
||||||
|
*/
|
||||||
private void createMoveList(){
|
private void createMoveList(){
|
||||||
pointer = -1;
|
// if Movelist is recreated next move will be the first move in moveList
|
||||||
|
pointer = 0;
|
||||||
calculatedStates = new ArrayList<>();
|
calculatedStates = new ArrayList<>();
|
||||||
PossibleMove finishedMove = null;
|
PossibleMove finishedMove = null;
|
||||||
List<PossibleMove> possibleMoves= new ArrayList<>();
|
List<PossibleMove> possibleMoves= new ArrayList<>();
|
||||||
|
|
||||||
|
// create a PossibleMove object for each direction which doesn't end with a crash.
|
||||||
for(PositionVector.Direction direction : allDirections){
|
for(PositionVector.Direction direction : allDirections){
|
||||||
PossibleMove newMove = new PossibleMove(null, direction);
|
PossibleMove newMove = new PossibleMove(null, direction);
|
||||||
if(! newMove.crashed()){
|
if(! newMove.crashed()){
|
||||||
|
@ -35,12 +51,17 @@ public class PathFinderMoveStrategy implements MoveStrategy{
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// while no PossibleMove crosses the finishline
|
||||||
|
// every PossibleMove will be accelerated in each direction to find a Move which finishes.
|
||||||
while(finishedMove == null){
|
while(finishedMove == null){
|
||||||
List<PossibleMove> newMoves = new ArrayList<>();
|
List<PossibleMove> newMoves = new ArrayList<>();
|
||||||
for(PossibleMove previousMove : possibleMoves){
|
for(PossibleMove previousMove : possibleMoves){
|
||||||
for(PositionVector.Direction direction : allDirections){
|
for(PositionVector.Direction direction : allDirections){
|
||||||
PossibleMove newMove = new PossibleMove(previousMove, direction);
|
PossibleMove newMove = new PossibleMove(previousMove, direction);
|
||||||
State newState = new State(newMove.endPosition, newMove.endVelocity);
|
State newState = new State(newMove.endPosition, newMove.endVelocity);
|
||||||
|
//only use the new created Possible Move if it doen't crash, end State isn't in List of calculatedStates
|
||||||
|
// and if there is no move found yet which is finished.
|
||||||
if(! (newMove.crashed() || alreadyCalculated(newState) || finishedMove != null)){
|
if(! (newMove.crashed() || alreadyCalculated(newState) || finishedMove != null)){
|
||||||
if(newMove.finished()){
|
if(newMove.finished()){
|
||||||
finishedMove = newMove;
|
finishedMove = newMove;
|
||||||
|
@ -55,12 +76,15 @@ public class PathFinderMoveStrategy implements MoveStrategy{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if a finished Move is found save it's directions as moveList
|
||||||
moveList = finishedMove.directions;
|
moveList = finishedMove.directions;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to check if a State is already in List calculatedStates
|
||||||
|
* @param state the State which should be checked
|
||||||
|
* @return true if it is in List, false if it isn't in List
|
||||||
|
*/
|
||||||
private boolean alreadyCalculated(State state){
|
private boolean alreadyCalculated(State state){
|
||||||
for(State calculatedState: calculatedStates){
|
for(State calculatedState: calculatedStates){
|
||||||
if(state.equals(calculatedState)){
|
if(state.equals(calculatedState)){
|
||||||
|
@ -70,15 +94,28 @@ public class PathFinderMoveStrategy implements MoveStrategy{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Combination of position and velocity
|
||||||
|
*/
|
||||||
public class State{
|
public class State{
|
||||||
PositionVector position;
|
PositionVector position;
|
||||||
PositionVector velocity;
|
PositionVector velocity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor of State
|
||||||
|
* @param position the PositionVector object with coordinates of the Position
|
||||||
|
* @param velocity the PositionVector object with coordinates of the Velocity
|
||||||
|
*/
|
||||||
public State(PositionVector position, PositionVector velocity){
|
public State(PositionVector position, PositionVector velocity){
|
||||||
this.position = position;
|
this.position = position;
|
||||||
this.velocity = velocity;
|
this.velocity = velocity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a state has the same Position and the same Velocity
|
||||||
|
* @param compareState the State object to compare
|
||||||
|
* @return true if it is equal, false if it is not equal
|
||||||
|
*/
|
||||||
public boolean equals(State compareState){
|
public boolean equals(State compareState){
|
||||||
if(compareState.position.equals(position) && compareState.velocity.equals(velocity)){
|
if(compareState.position.equals(position) && compareState.velocity.equals(velocity)){
|
||||||
return true;
|
return true;
|
||||||
|
@ -88,32 +125,48 @@ public class PathFinderMoveStrategy implements MoveStrategy{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PossibleMove represents a move which can be done by the player.
|
||||||
|
*/
|
||||||
public class PossibleMove {
|
public class PossibleMove {
|
||||||
|
// List of all directions used for the previous moves and the direction of the current move (the highest Index).
|
||||||
List<PositionVector.Direction> directions;
|
List<PositionVector.Direction> directions;
|
||||||
|
// Position of the car bevor the move is executed
|
||||||
PositionVector startPosition;
|
PositionVector startPosition;
|
||||||
|
// Position of the car after the move is executed
|
||||||
PositionVector endPosition;
|
PositionVector endPosition;
|
||||||
|
// Velocity of the car after the move is executed
|
||||||
PositionVector endVelocity;
|
PositionVector endVelocity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor of PossibleMove
|
||||||
|
* @param previousMove The move which must be executed bevor this move can be executed
|
||||||
|
* @param nextDirection The direction of the move
|
||||||
|
*/
|
||||||
public PossibleMove(PossibleMove previousMove, PositionVector.Direction nextDirection){
|
public PossibleMove(PossibleMove previousMove, PositionVector.Direction nextDirection){
|
||||||
|
// Velocity of the car bevor the move is executed
|
||||||
PositionVector startVelocity;
|
PositionVector startVelocity;
|
||||||
|
|
||||||
directions = new ArrayList<>();
|
directions = new ArrayList<>();
|
||||||
|
// check if there was a previousMove.
|
||||||
if(previousMove != null){
|
if(previousMove != null){
|
||||||
directions.addAll(previousMove.directions);
|
directions.addAll(previousMove.directions); //copy the LIst of Directions from the previousMove
|
||||||
startPosition = previousMove.endPosition;
|
startPosition = previousMove.endPosition; //use the endPosition from previousMove as startPosition
|
||||||
startVelocity = previousMove.endVelocity;
|
startVelocity = previousMove.endVelocity; //use the endVelocity from previousMove as startVelocity
|
||||||
}
|
}
|
||||||
else {
|
else { //if there was no previousMove
|
||||||
startPosition = track.getCarPos(carIndex);
|
startPosition = track.getCarPos(carIndex); //use the current Position of the car from track as startPosition
|
||||||
startVelocity = track.getCar(carIndex).getVelocity();
|
startVelocity = track.getCar(carIndex).getVelocity(); //use the current Velocity of the car from track as startVelocity
|
||||||
}
|
}
|
||||||
directions.add(nextDirection);
|
directions.add(nextDirection);
|
||||||
endVelocity = new PositionVector(startVelocity.getX() + nextDirection.vector.getX(), startVelocity.getY() + nextDirection.vector.getY());
|
endVelocity = new PositionVector(startVelocity.getX() + nextDirection.vector.getX(), startVelocity.getY() + nextDirection.vector.getY());
|
||||||
endPosition = new PositionVector(startPosition.getX() + endVelocity.getX(), startPosition.getY() + endVelocity.getY());
|
endPosition = new PositionVector(startPosition.getX() + endVelocity.getX(), startPosition.getY() + endVelocity.getY());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* check if the finishline is crossed (in correct direction) if this move is executed
|
||||||
|
* @return true if finishline will be crossed
|
||||||
|
*/
|
||||||
public boolean finished(){
|
public boolean finished(){
|
||||||
if(track.calculateNewWinPoints(startPosition, endPosition) == 1){
|
if(track.calculateNewWinPoints(startPosition, endPosition) == 1){
|
||||||
return true;
|
return true;
|
||||||
|
@ -123,6 +176,10 @@ public class PathFinderMoveStrategy implements MoveStrategy{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* checks if the car will crash or finishline will be crossed in wrong direction if this move is executed
|
||||||
|
* @return true if car will crash
|
||||||
|
*/
|
||||||
public boolean crashed() {
|
public boolean crashed() {
|
||||||
List<PositionVector> points = track.calculatePointsOnPath(startPosition, endPosition);
|
List<PositionVector> points = track.calculatePointsOnPath(startPosition, endPosition);
|
||||||
for(PositionVector point : points) {
|
for(PositionVector point : points) {
|
||||||
|
@ -139,10 +196,13 @@ public class PathFinderMoveStrategy implements MoveStrategy{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the next Move in moveList will crash. If no crash next move in moveList will be executed.
|
||||||
|
* If crash the moveList will be recreated.
|
||||||
|
* @return the direction of acceleration which should be executed.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public PositionVector.Direction nextMove() {
|
public PositionVector.Direction nextMove() {
|
||||||
pointer += 1;
|
|
||||||
if (pointer < moveList.size()) {
|
if (pointer < moveList.size()) {
|
||||||
PositionVector.Direction direction = moveList.get(pointer);
|
PositionVector.Direction direction = moveList.get(pointer);
|
||||||
PositionVector currentVelocity = track.getCarVelocity(carIndex);
|
PositionVector currentVelocity = track.getCarVelocity(carIndex);
|
||||||
|
@ -155,12 +215,13 @@ public class PathFinderMoveStrategy implements MoveStrategy{
|
||||||
if(track.willCrashAtPosition(carIndex, point)){
|
if(track.willCrashAtPosition(carIndex, point)){
|
||||||
createMoveList();
|
createMoveList();
|
||||||
pointer = 0;
|
pointer = 0;
|
||||||
|
direction = moveList.get(pointer);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pointer += 1;
|
||||||
return moveList.get(pointer);
|
return direction;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue