mirror of
https://github.com/michaelrausch/Party-Parrots-At-Sea.git
synced 2026-05-09 06:18:44 +00:00
WIP: Implemented basic mark rounding algorithm.
Removed RacePosition class. Instead marks are just grabbed from the mark order class when necessary. No marks are stored as an attribute in the yacht class but the 'currentMarkSeqID' which is used to get current, and surrounding marks. Works for all marks in between but not including starting and finishing gate as no angle can be made with them. Still to work out how to implement this #story[1124]
This commit is contained in:
@@ -4,9 +4,12 @@ import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import seng302.gameServer.server.messages.BoatActionType;
|
||||
import seng302.model.Player;
|
||||
import seng302.model.Yacht;
|
||||
import seng302.model.mark.MarkOrder;
|
||||
|
||||
/**
|
||||
* A Static class to hold information about the current state of the game (model)
|
||||
@@ -14,6 +17,8 @@ import seng302.model.Yacht;
|
||||
*/
|
||||
public class GameState implements Runnable {
|
||||
|
||||
private Logger logger = LoggerFactory.getLogger(MarkOrder.class);
|
||||
|
||||
private static Integer STATE_UPDATES_PER_SECOND = 60;
|
||||
|
||||
private static Long previousUpdateTime;
|
||||
@@ -25,6 +30,7 @@ public class GameState implements Runnable {
|
||||
private static Map<Integer, Yacht> yachts;
|
||||
private static Boolean isRaceStarted;
|
||||
private static GameStages currentStage;
|
||||
private static MarkOrder markOrder;
|
||||
private static long startTime;
|
||||
|
||||
private static Map<Player, String> playerStringMap = new HashMap<>();
|
||||
@@ -53,8 +59,9 @@ public class GameState implements Runnable {
|
||||
//set this when game stage changes to prerace
|
||||
previousUpdateTime = System.currentTimeMillis();
|
||||
yachts = new HashMap<>();
|
||||
markOrder = new MarkOrder(); //This could be instantiated at some point with a select map?
|
||||
|
||||
new Thread(this).start();
|
||||
new Thread(this).start(); //Run the auto updates on the game state
|
||||
}
|
||||
|
||||
public static String getHostIpAddress() {
|
||||
@@ -100,6 +107,10 @@ public class GameState implements Runnable {
|
||||
GameState.currentStage = currentStage;
|
||||
}
|
||||
|
||||
public static MarkOrder getMarkOrder() {
|
||||
return markOrder;
|
||||
}
|
||||
|
||||
public static long getStartTime(){
|
||||
return startTime;
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ public class Yacht {
|
||||
void notifyLocation(Yacht yacht, double lat, double lon, double heading, double velocity);
|
||||
}
|
||||
|
||||
private static final Double ROUNDING_DISTANCE = 15d; // TODO: 3/08/17 wmu16 - Look into this value further
|
||||
private static final Double ROUNDING_DISTANCE = 50d; // TODO: 3/08/17 wmu16 - Look into this value further
|
||||
|
||||
//BOTH AFAIK
|
||||
private String boatType;
|
||||
@@ -39,11 +39,10 @@ public class Yacht {
|
||||
private String country;
|
||||
|
||||
private Long estimateTimeAtFinish;
|
||||
private Long lastMark;
|
||||
private Integer currentMarkSeqID = 1;
|
||||
private Long markRoundTime;
|
||||
private Double distanceToNextMark;
|
||||
private Long timeTillNext;
|
||||
private CompoundMark nextMark;
|
||||
private Double heading;
|
||||
private Integer legNumber = 0;
|
||||
|
||||
@@ -58,7 +57,6 @@ public class Yacht {
|
||||
private GeoPoint lastLocation; //For purposes of mark rounding calculations
|
||||
private Boolean hasEnteredRoundingZone; //The distance that the boat must be from the mark to round
|
||||
private Boolean hasPassedFirstLine; //The line extrapolated from the next mark to the current mark
|
||||
private Boolean hasPassedSecondLine; //The line extrapolated from the last mark to the current mark
|
||||
|
||||
//CLIENT SIDE
|
||||
private List<YachtLocationListener> locationListeners = new ArrayList<>();
|
||||
@@ -85,7 +83,6 @@ public class Yacht {
|
||||
|
||||
this.hasEnteredRoundingZone = false;
|
||||
this.hasPassedFirstLine = false;
|
||||
this.hasPassedSecondLine = false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -125,24 +122,24 @@ public class Yacht {
|
||||
location = GeoUtility.getGeoCoordinate(location, heading, velocity * secondsElapsed);
|
||||
|
||||
//CHECK FOR MARK ROUNDING
|
||||
distanceToNextMark = calcDistanceToNextMark();
|
||||
if (distanceToNextMark < ROUNDING_DISTANCE) {
|
||||
hasEnteredRoundingZone = true;
|
||||
}
|
||||
//Algorithm wont currently work on last gate and start gate
|
||||
checkForMarkRounding();
|
||||
|
||||
// TODO: 3/08/17 wmu16 - Implement line cross check here
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculates the distance to the next mark (closest of the two if a gate mark).
|
||||
*
|
||||
* Calculates the distance to the next mark (closest of the two if a gate mark). For purposes
|
||||
* of mark rounding
|
||||
* @return A distance in metres. Returns -1 if there is no next mark
|
||||
* @throws IndexOutOfBoundsException If the next mark is null (ie the last mark in the race)
|
||||
* Check first using {@link seng302.model.mark.MarkOrder#isLastMark(Integer)}
|
||||
*/
|
||||
public Double calcDistanceToNextMark() {
|
||||
if (nextMark == null) {
|
||||
return -1d;
|
||||
} else if (nextMark.isGate()) {
|
||||
public Double calcDistanceToNextMark() throws IndexOutOfBoundsException {
|
||||
CompoundMark nextMark = GameState.getMarkOrder().getCurrentMark(currentMarkSeqID);
|
||||
|
||||
if (nextMark.isGate()) {
|
||||
Mark sub1 = nextMark.getSubMark(1);
|
||||
Mark sub2 = nextMark.getSubMark(2);
|
||||
Double distance1 = GeoUtility.getDistance(location, sub1);
|
||||
@@ -153,6 +150,62 @@ public class Yacht {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This algorithm checks for mark rounding. And increments the currentMarSeqID number attribute
|
||||
* of the yacht if so.
|
||||
* The algorithm works by using the last mark, the current mark, the next mark and the change in
|
||||
* boats location, like so:
|
||||
* -Condition 1:
|
||||
* The boat has entered the mark rounding distance
|
||||
* -Condition 2:
|
||||
* The boat has passed the line extending from the last mark to the current mark
|
||||
* -Condition 3:
|
||||
* The boat has passed the line extending from the next mark to the current mark
|
||||
*
|
||||
* A more visual representation of this algorithm can be seen on the Wiki under
|
||||
* 'mark passing algorithm'
|
||||
*/
|
||||
private void checkForMarkRounding() {
|
||||
if (!GameState.getMarkOrder().isLastMark(currentMarkSeqID) && currentMarkSeqID != 0) {
|
||||
distanceToNextMark = calcDistanceToNextMark();
|
||||
// System.out.println("distanceToNextMark = " + distanceToNextMark);
|
||||
CompoundMark nextMark = GameState.getMarkOrder().getNextMark(currentMarkSeqID);
|
||||
CompoundMark currentMark = GameState.getMarkOrder().getCurrentMark(currentMarkSeqID);
|
||||
CompoundMark prevMark = GameState.getMarkOrder().getPreviousMark(currentMarkSeqID);
|
||||
|
||||
//1 TEST FOR ENTERING THE ROUDNING DISTANCE
|
||||
if (distanceToNextMark < ROUNDING_DISTANCE) {
|
||||
hasEnteredRoundingZone = true;
|
||||
// System.out.println("Entered rounding zone!");
|
||||
}
|
||||
|
||||
//If the current mark is a gate mark we need to check both its marks for rounding, thus
|
||||
//we loop
|
||||
for (Mark thisCurrentMark : currentMark.getMarks()) {
|
||||
|
||||
//2 TEST FOR CROSSING NEXT - CURRENT LINE FIRST
|
||||
if (GeoUtility.isPointInTriangle(lastLocation, location, nextMark.getMarks().get(0),
|
||||
thisCurrentMark)) {
|
||||
hasPassedFirstLine = true;
|
||||
System.out.println("Passed first line!");
|
||||
}
|
||||
|
||||
//3 TEST FOR CROSSING PREV - CURRENT LINE SECOND
|
||||
if (GeoUtility.isPointInTriangle(lastLocation, location, prevMark.getMarks().get(0),
|
||||
thisCurrentMark)) {
|
||||
if (hasPassedFirstLine && hasEnteredRoundingZone) {
|
||||
currentMarkSeqID++;
|
||||
hasPassedFirstLine = false;
|
||||
hasEnteredRoundingZone = false;
|
||||
System.out.println("SUCCESFUL ROUDNING!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void adjustHeading(Double amount) {
|
||||
Double newVal = heading + amount;
|
||||
lastHeading = heading;
|
||||
@@ -357,14 +410,6 @@ public class Yacht {
|
||||
this.lastMarkRounded = lastMarkRounded;
|
||||
}
|
||||
|
||||
public void setNextMark(CompoundMark nextMark) {
|
||||
this.nextMark = nextMark;
|
||||
}
|
||||
|
||||
public CompoundMark getNextMark(){
|
||||
return nextMark;
|
||||
}
|
||||
|
||||
public GeoPoint getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ import java.util.Map;
|
||||
* Class to hold the order of the marks in the race.
|
||||
*/
|
||||
public class MarkOrder {
|
||||
private List<Mark> raceMarkOrder;
|
||||
private List<CompoundMark> raceMarkOrder;
|
||||
private Logger logger = LoggerFactory.getLogger(MarkOrder.class);
|
||||
|
||||
public MarkOrder(){
|
||||
@@ -35,7 +35,7 @@ public class MarkOrder {
|
||||
* @return An ordered list of marks in the race
|
||||
* OR null if the mark order could not be loaded
|
||||
*/
|
||||
public List<Mark> getMarkOrder(){
|
||||
public List<CompoundMark> getMarkOrder(){
|
||||
if (raceMarkOrder == null){
|
||||
logger.warn("Race order accessed but not instantiated");
|
||||
return null;
|
||||
@@ -45,26 +45,35 @@ public class MarkOrder {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the mark in the race after the previous mark
|
||||
* @param position The current race position
|
||||
* @return the next race position
|
||||
* OR null if there is no position
|
||||
* @param seqID The seqID of the current mark the boat is heading to
|
||||
* @return A Boolean indicating if this coming mark is the last one (finish line)
|
||||
*/
|
||||
public RacePosition getNextPosition(RacePosition position){
|
||||
Mark previousMark = position.getNextMark();
|
||||
Mark nextMark;
|
||||
public Boolean isLastMark(Integer seqID) {
|
||||
return seqID == raceMarkOrder.size() - 1;
|
||||
}
|
||||
|
||||
if (position.getPositionIndex() + 1 >= raceMarkOrder.size() - 1){
|
||||
RacePosition nextRacePosition = new RacePosition(raceMarkOrder.size() - 1, null, previousMark);
|
||||
nextRacePosition.setFinishingLeg();
|
||||
/**
|
||||
* @param currentSeqID The seqID of the current mark the boat is heading to
|
||||
* @return The mark last passed
|
||||
* @throws IndexOutOfBoundsException if there is no next mark.
|
||||
* Check seqID != 0 first
|
||||
*/
|
||||
public CompoundMark getPreviousMark(Integer currentSeqID) throws IndexOutOfBoundsException{
|
||||
return raceMarkOrder.get(currentSeqID - 1);
|
||||
}
|
||||
|
||||
return nextRacePosition;
|
||||
}
|
||||
public CompoundMark getCurrentMark(Integer currentSeqID) {
|
||||
return raceMarkOrder.get(currentSeqID);
|
||||
}
|
||||
|
||||
Integer nextPositionIndex = position.getPositionIndex() + 1;
|
||||
RacePosition nextRacePosition = new RacePosition(nextPositionIndex, raceMarkOrder.get(nextPositionIndex), previousMark);
|
||||
|
||||
return nextRacePosition;
|
||||
/**
|
||||
* @param currentSeqID The seqID of the current mark the boat is heading to
|
||||
* @return The mark following the mark that the boat is heading to
|
||||
* @throws IndexOutOfBoundsException if there is no next mark.
|
||||
* Check using {@link #isLastMark(Integer)}
|
||||
*/
|
||||
public CompoundMark getNextMark(Integer currentSeqID) throws IndexOutOfBoundsException{
|
||||
return raceMarkOrder.get(currentSeqID + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -72,7 +81,7 @@ public class MarkOrder {
|
||||
* @param xml An AC35 RaceXML
|
||||
* @return An ordered list of marks in the race
|
||||
*/
|
||||
private List<Mark> loadRaceOrderFromXML(String xml){
|
||||
private List<CompoundMark> loadRaceOrderFromXML(String xml){
|
||||
|
||||
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
||||
DocumentBuilder db;
|
||||
@@ -92,11 +101,11 @@ public class MarkOrder {
|
||||
logger.debug("Loaded RaceXML for mark order");
|
||||
List<Corner> corners = data.getMarkSequence();
|
||||
Map<Integer, CompoundMark> marks = data.getCompoundMarks();
|
||||
List<Mark> course = new ArrayList<>();
|
||||
List<CompoundMark> course = new ArrayList<>();
|
||||
|
||||
for (Corner corner : corners){
|
||||
CompoundMark compoundMark = marks.get(corner.getCompoundMarkID());
|
||||
course.add(compoundMark.getMarks().get(0));
|
||||
course.add(compoundMark);
|
||||
}
|
||||
|
||||
return course;
|
||||
@@ -105,17 +114,6 @@ public class MarkOrder {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The first position in the race
|
||||
*/
|
||||
public RacePosition getFirstPosition(){
|
||||
if (raceMarkOrder.size() > 0){
|
||||
return new RacePosition(-1, raceMarkOrder.get(0), null);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the raceXML and mark order
|
||||
*/
|
||||
@@ -132,4 +130,4 @@ public class MarkOrder {
|
||||
}
|
||||
raceMarkOrder = loadRaceOrderFromXML(raceXML);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
package seng302.model.mark;
|
||||
|
||||
/**
|
||||
* Represents a boats position between two marks
|
||||
*/
|
||||
public class RacePosition {
|
||||
private Integer positionIndex;
|
||||
private Mark nextMark;
|
||||
private Mark previousMark;
|
||||
private Boolean isFinishingLeg;
|
||||
|
||||
public RacePosition(Integer positionIndex, Mark nextMark, Mark previousMark){
|
||||
this.positionIndex = positionIndex;
|
||||
this.nextMark = nextMark;
|
||||
this.previousMark = previousMark;
|
||||
isFinishingLeg = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The position of the boat (0...number of marks in race - 1)
|
||||
*/
|
||||
public Integer getPositionIndex(){
|
||||
return positionIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The mark the boat is heading to
|
||||
* will return NULL if this is the finishing legg
|
||||
*/
|
||||
public Mark getNextMark(){
|
||||
return nextMark;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The mark the boat is heading away from,
|
||||
* Will return NULL if this is the starting leg
|
||||
*/
|
||||
public Mark getPreviousMark(){
|
||||
return previousMark;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a flag that this is the last leg in the race
|
||||
*/
|
||||
public void setFinishingLeg(){
|
||||
isFinishingLeg = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if this is the last leg in the race
|
||||
*/
|
||||
public boolean getIsFinishingLeg() {
|
||||
return isFinishingLeg;
|
||||
}
|
||||
}
|
||||
@@ -38,17 +38,19 @@ public class YachtTest {
|
||||
Mark subMark2 = new Mark("H", 57.670822, 11.843392, 0);
|
||||
compoundMark.addSubMarks(subMark1, subMark2);
|
||||
|
||||
yacht.setNextMark(compoundMark);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testDistanceToNextMark() {
|
||||
Double actual, expected;
|
||||
actual = yacht.calcDistanceToNextMark();
|
||||
expected = 927d;
|
||||
assertEquals(expected, actual, expected * toleranceRatio);
|
||||
}
|
||||
//This will no longer work as we cant set the next mark any more as we no longer hold it in
|
||||
//yacht class as an attribute
|
||||
|
||||
// @Test
|
||||
// public void testDistanceToNextMark() {
|
||||
// Double actual, expected;
|
||||
// actual = yacht.calcDistanceToNextMark();
|
||||
// expected = 927d;
|
||||
// assertEquals(expected, actual, expected * toleranceRatio);
|
||||
// }
|
||||
|
||||
|
||||
}
|
||||
@@ -3,19 +3,22 @@ package seng302.models;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import seng302.model.mark.CompoundMark;
|
||||
import seng302.model.mark.Mark;
|
||||
import seng302.model.mark.MarkOrder;
|
||||
import seng302.model.mark.RacePosition;
|
||||
|
||||
import static junit.framework.TestCase.assertEquals;
|
||||
import static junit.framework.TestCase.assertFalse;
|
||||
import static junit.framework.TestCase.assertTrue;
|
||||
|
||||
public class MarkOrderTest {
|
||||
private static MarkOrder markOrder;
|
||||
private static Integer currentSeqID;
|
||||
|
||||
@BeforeClass
|
||||
public static void setup(){
|
||||
markOrder = new MarkOrder();
|
||||
currentSeqID = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -26,54 +29,39 @@ public class MarkOrderTest {
|
||||
assertTrue(markOrder != null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if .getNextMark() returns null if it is called with the final mark in the race
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void testNextMarkAtEnd(){
|
||||
// There are no marks in the XML, therefore this can't be tested
|
||||
if (markOrder.getMarkOrder().size() == 0){
|
||||
return;
|
||||
}
|
||||
public void testIsLastMark() {
|
||||
currentSeqID = 0;
|
||||
assertFalse(markOrder.isLastMark(currentSeqID));
|
||||
|
||||
Mark lastMark = markOrder.getMarkOrder().get(markOrder.getMarkOrder().size() - 1);
|
||||
Integer lastIndex = markOrder.getMarkOrder().size() - 1;
|
||||
|
||||
RacePosition lastRacePosition = new RacePosition(lastIndex, lastMark, null);
|
||||
|
||||
assertEquals(null, markOrder.getNextPosition(lastRacePosition).getNextMark());
|
||||
currentSeqID = markOrder.getMarkOrder().size() - 1;
|
||||
assertTrue(markOrder.isLastMark(currentSeqID));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if .getNextMark() method returns the next mark in the race
|
||||
*/
|
||||
@Test
|
||||
public void testNextMark(){
|
||||
// There are not enough marks for this to be tested
|
||||
if (markOrder.getMarkOrder().size() < 2){
|
||||
return;
|
||||
}
|
||||
public void testGetNextMark() {
|
||||
currentSeqID = 4;
|
||||
CompoundMark nextMark = markOrder.getMarkOrder().get(4 + 1);
|
||||
assertEquals(nextMark, markOrder.getNextMark(currentSeqID));
|
||||
|
||||
RacePosition firstRacePos = new RacePosition(0, markOrder.getMarkOrder().get(0), null);
|
||||
|
||||
assertEquals(markOrder.getMarkOrder().get(1).getName(), markOrder.getNextPosition(firstRacePos).getNextMark().getName());
|
||||
currentSeqID = 3;
|
||||
nextMark = markOrder.getMarkOrder().get(3 + 1);
|
||||
assertEquals(nextMark, markOrder.getNextMark(currentSeqID));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if a whole race can be completed
|
||||
*/
|
||||
@Test
|
||||
public void testMarkSequence(){
|
||||
RacePosition current = markOrder.getFirstPosition();
|
||||
public void testGetCurrentMark() {
|
||||
currentSeqID = 0;
|
||||
CompoundMark currentMark = markOrder.getMarkOrder().get(0);
|
||||
assertEquals(currentMark, markOrder.getCurrentMark(0));
|
||||
}
|
||||
|
||||
while (!current.getIsFinishingLeg()){
|
||||
|
||||
current = markOrder.getNextPosition(current);
|
||||
|
||||
if (current.getIsFinishingLeg()){
|
||||
assertEquals(null, current.getNextMark());
|
||||
}
|
||||
}
|
||||
@Test
|
||||
public void testGetPreviousMark() {
|
||||
currentSeqID = 1;
|
||||
CompoundMark prevMark = markOrder.getMarkOrder().get(0);
|
||||
assertEquals(prevMark, markOrder.getPreviousMark(currentSeqID));
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
|
||||
Reference in New Issue
Block a user