diff --git a/src/main/java/seng302/gameServer/GameState.java b/src/main/java/seng302/gameServer/GameState.java index ea8c1004..913f4f37 100644 --- a/src/main/java/seng302/gameServer/GameState.java +++ b/src/main/java/seng302/gameServer/GameState.java @@ -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 yachts; private static Boolean isRaceStarted; private static GameStages currentStage; + private static MarkOrder markOrder; private static long startTime; private static Map 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; } diff --git a/src/main/java/seng302/model/Yacht.java b/src/main/java/seng302/model/Yacht.java index d7cd1f9e..1c9e7ec6 100644 --- a/src/main/java/seng302/model/Yacht.java +++ b/src/main/java/seng302/model/Yacht.java @@ -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 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; } diff --git a/src/main/java/seng302/model/mark/MarkOrder.java b/src/main/java/seng302/model/mark/MarkOrder.java index ca2b4356..141d5c6d 100644 --- a/src/main/java/seng302/model/mark/MarkOrder.java +++ b/src/main/java/seng302/model/mark/MarkOrder.java @@ -24,7 +24,7 @@ import java.util.Map; * Class to hold the order of the marks in the race. */ public class MarkOrder { - private List raceMarkOrder; + private List 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 getMarkOrder(){ + public List 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 loadRaceOrderFromXML(String xml){ + private List loadRaceOrderFromXML(String xml){ DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db; @@ -92,11 +101,11 @@ public class MarkOrder { logger.debug("Loaded RaceXML for mark order"); List corners = data.getMarkSequence(); Map marks = data.getCompoundMarks(); - List course = new ArrayList<>(); + List 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); } -} +} \ No newline at end of file diff --git a/src/main/java/seng302/model/mark/RacePosition.java b/src/main/java/seng302/model/mark/RacePosition.java deleted file mode 100644 index fc160b10..00000000 --- a/src/main/java/seng302/model/mark/RacePosition.java +++ /dev/null @@ -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; - } -} diff --git a/src/test/java/seng302/model/YachtTest.java b/src/test/java/seng302/model/YachtTest.java index 7937b43c..739c8a28 100644 --- a/src/test/java/seng302/model/YachtTest.java +++ b/src/test/java/seng302/model/YachtTest.java @@ -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); +// } } \ No newline at end of file diff --git a/src/test/java/seng302/models/MarkOrderTest.java b/src/test/java/seng302/models/MarkOrderTest.java index 8db06ec8..42531563 100644 --- a/src/test/java/seng302/models/MarkOrderTest.java +++ b/src/test/java/seng302/models/MarkOrderTest.java @@ -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