diff --git a/.gitignore b/.gitignore index 431564c..7bfb0d4 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ # https://www.atlassian.com/git/tutorials/saving-changes/gitignore solver results/** +Ranges *.gto *.cfr diff --git a/src/main/java/com/gtohelper/datafetcher/models/WorkQueueModel.java b/src/main/java/com/gtohelper/datafetcher/models/WorkQueueModel.java index d301198..984c311 100644 --- a/src/main/java/com/gtohelper/datafetcher/models/WorkQueueModel.java +++ b/src/main/java/com/gtohelper/datafetcher/models/WorkQueueModel.java @@ -35,7 +35,7 @@ public class WorkQueueModel extends Saveable { // No indexable java.concurrent structure with .take() exists. So // we use the BlockingQueue and lock it for rebuilds to move item indexes ~ which are only valid if the Queue size > 2. - private Object pendingQueueLock = new Object(); + private final Object pendingQueueLock = new Object(); private LinkedBlockingQueue pendingWorkQueue; public WorkQueueModel(SaveFileHelper saveHelper, Consumer solverStatusCallback, Consumer startedOnTaskCallback, diff --git a/src/main/java/com/gtohelper/domain/HandData.java b/src/main/java/com/gtohelper/domain/HandData.java index 14a3c6b..4e616f0 100644 --- a/src/main/java/com/gtohelper/domain/HandData.java +++ b/src/main/java/com/gtohelper/domain/HandData.java @@ -245,7 +245,7 @@ public static class PlayerHandData implements Serializable { // Calculated fields to be set // These 3 fields are the info for the last action taken by the player. - public class LastActionForStreet implements Serializable{ + public class LastActionForStreet implements Serializable { private static final long serialVersionUID = 1L; public short betLevel; public Seat vsSeat; diff --git a/src/main/java/com/gtohelper/domain/PreflopState.java b/src/main/java/com/gtohelper/domain/PreflopState.java index e7d1e26..e5b50b6 100644 --- a/src/main/java/com/gtohelper/domain/PreflopState.java +++ b/src/main/java/com/gtohelper/domain/PreflopState.java @@ -88,46 +88,6 @@ public static int getBetLevelFromSituationAndLastAction(Situation situation, Las } } - private void fromString(String string) { - String[] splitStrings = string.split(delimiter); - - // peel off the first segments until we find the leading 'situation' - int index = 0; - for(; index < splitStrings.length && situation == null; index++) { - String split = splitStrings[index]; - // Check to see if it's a defined Situation - for(Situation s : Situation.values()) { - if(s.name.equals(split)) { - situation = s; - break; - } - } - } - - assert index < splitStrings.length; - - // index is now pointing at the split _after_ we find the 'situation'. - // This is because index++ is called before the break condition. - if(situation == Situation.LIMP) { - limpFromString(splitStrings[index]); - } else if(situation == Situation.RFI) { - rfiFromString(splitStrings[index]); - } else if(situation == Situation.VRFI) { - // Note that these FromStrings() have Villain, then hero as their parameter. - vRfiFromString(splitStrings[index], splitStrings[index + 1], splitStrings[index + 2]); - } else if(situation == Situation.V3BET) { - v3BetFromString(splitStrings[index + 1], splitStrings[index], splitStrings[index + 2]); - } else if(situation == Situation.V4BET) { - v4BetFromString(splitStrings[index], splitStrings[index + 1], splitStrings[index + 2]); - } else if(situation == Situation.V5BET) { - call5BetFromString(splitStrings[index + 1], splitStrings[index], splitStrings[index + 2]); - } else { - // todo: log error. - assert false; - } - - } - @Override public boolean equals(Object obj) { if(obj == this) @@ -161,65 +121,29 @@ else if(situation == Situation.V4BET) else if(situation == Situation.V5BET) return call5BetToString(); else - return ""; - } - - private void limpFromString(String heroPosition) { - heroSeat = Seat.fromString(heroPosition); - villainSeat = Seat.BB; - lastHeroAction = LastAction.CALL; + return "Invalid preflop state"; } private String limpToString() { return situation.name + delimiter + heroSeat.name; } - private void rfiFromString(String heroPosition) { - heroSeat = Seat.fromString(heroPosition); - villainSeat = Seat.BB; - lastHeroAction = LastAction.RAISE; - } - private String rfiToString() { return situation.name + delimiter + heroSeat.name; } - private void vRfiFromString(String villainPosition, String heroPosition, String lastAction) { - heroSeat = Seat.fromString(heroPosition); - villainSeat = Seat.fromString(villainPosition.substring(1)); // remove the starting "v" - lastHeroAction = LastAction.fromString(lastAction); - } - private String vRfiToString() { return situation.name + delimiter + "v" + villainSeat.name + delimiter + heroSeat.name + delimiter + lastHeroAction; } - private void v3BetFromString(String villainPosition, String heroPosition, String lastAction) { - heroSeat = Seat.fromString(heroPosition); - villainSeat = Seat.fromString(villainPosition.substring(1)); // remove the starting "v" - lastHeroAction = LastAction.fromString(lastAction); - } - private String v3BetToString() { return situation.name + delimiter + heroSeat.name + delimiter + "v" + villainSeat.name + delimiter + lastHeroAction; } - private void v4BetFromString(String villainPosition, String heroPosition, String lastAction) { - heroSeat = Seat.fromString(heroPosition); - villainSeat = Seat.fromString(villainPosition.substring(1)); // remove the starting "v" - lastHeroAction = LastAction.fromString(lastAction); - } - private String v4BetToString() { return situation.name + delimiter + "v" + villainSeat.name + delimiter + heroSeat.name + delimiter + lastHeroAction; } - private void call5BetFromString(String villainPosition, String heroPosition, String lastAction) { - heroSeat = Seat.fromString(heroPosition); - villainSeat = Seat.fromString(villainPosition.substring(1)); // remove the starting "v" - lastHeroAction = LastAction.fromString(lastAction); - } - private String call5BetToString() { return situation.name + delimiter + heroSeat.name + delimiter + "v" + villainSeat.name + delimiter + lastHeroAction; } diff --git a/src/main/java/com/gtohelper/domain/Ranges.java b/src/main/java/com/gtohelper/domain/Ranges.java index 3bd572c..2239f26 100644 --- a/src/main/java/com/gtohelper/domain/Ranges.java +++ b/src/main/java/com/gtohelper/domain/Ranges.java @@ -60,23 +60,15 @@ public void fillEmptyRanges() { } private void fillNoVillainMap(HashMap map, Situation sit, LastAction lastAction) { - RangeData lastRangeData = null; - - PreflopState action = new PreflopState(sit, Seat.BB, Seat.SB, lastAction); - action.lastHeroAction = lastAction; + PreflopState action = new PreflopState(); action.situation = sit; - action.heroSeat = Seat.BB; - action.villainSeat = Seat.SB; - - // This edge case is needed because the villainSeat is different. - RangeData data = map.get(action); - lastRangeData = data; - action.villainSeat = Seat.BB; + action.lastHeroAction = lastAction; - for(int heroIndex = 1; heroIndex < Seat.preflopPositionsDESC.length; heroIndex++) { + RangeData lastRangeData = null; + for(int heroIndex = 0; heroIndex < Seat.preflopPositionsDESC.length; heroIndex++) { action.heroSeat = Seat.preflopPositionsDESC[heroIndex]; - data = map.get(action); + RangeData data = map.get(action); if ((data == null || data.isTheEmptyRange) && (lastRangeData != null && !lastRangeData.isTheEmptyRange)) map.put(new PreflopState(action), lastRangeData); else @@ -162,7 +154,11 @@ private void fillOPMap(HashMap map, Situation sit, Last @Override public RangeData put(PreflopState action, RangeData data) { switch (action.situation) { - case LIMP -> limpMap.put(action, data); + case LIMP -> { + PreflopState noVersusAction = new PreflopState(action); + noVersusAction.villainSeat = null; + limpMap.put(noVersusAction, data); + } case RFI -> RFIMap.put(action, data); case VRFI -> vsRFIMap.put(action, data); case V3BET -> vs3BetMap.put(action, data); @@ -177,11 +173,16 @@ public RangeData put(PreflopState action, RangeData data) { @Override public RangeData get(Object obj) { - if (!(obj instanceof PreflopState action)) { + if (!(obj instanceof PreflopState)) { return null; } - return getBestMatch(action); + PreflopState newState = new PreflopState((PreflopState) obj); + if(newState.situation == Situation.LIMP) { + newState.villainSeat = null; + } + + return getBestMatch(newState); } private RangeData getBestMatch(PreflopState action) { diff --git a/src/main/java/com/gtohelper/pt4datamanager/PT4HandDataDM.java b/src/main/java/com/gtohelper/pt4datamanager/PT4HandDataDM.java index e24b0e4..9b7989e 100644 --- a/src/main/java/com/gtohelper/pt4datamanager/PT4HandDataDM.java +++ b/src/main/java/com/gtohelper/pt4datamanager/PT4HandDataDM.java @@ -195,11 +195,26 @@ private void computeCalculatedFieldsForHandData(ArrayList hands, int h private void resolvePreflopActionForPlayersInHand(HandData hand) { // Manually handle the all-limp case, to make edge cases in the following code chunk easier. if(hand.highestPreflopBetLevel == 1) { + Seat earliestLimpSeat = Seat.BB; + for(PlayerHandData handData : hand.playerHandData) { + if(handData.seat.preflopPosition < earliestLimpSeat.preflopPosition) { + earliestLimpSeat = handData.seat; + } + } + for(PlayerHandData handData : hand.playerHandData) { LastActionForStreet lastPreflopAction = handData.getLastActionForStreet(Street.PRE); lastPreflopAction.betLevel = 1; - lastPreflopAction.vsSeat = Seat.BB; - lastPreflopAction.action = Action.CALL; + + if(handData.seat == earliestLimpSeat) + lastPreflopAction.vsSeat = Seat.BB; + else + lastPreflopAction.vsSeat = earliestLimpSeat; + + if(handData.seat == Seat.BB) + lastPreflopAction.action = Action.CHECK; + else + lastPreflopAction.action = Action.CALL; } return; } @@ -246,7 +261,7 @@ private void resolvePostflopActionForPlayersInHand(HandData hand, Street street, LastActionForStreet lastAction = handData.getLastActionForStreet(street); lastAction.betLevel = 0; lastAction.vsSeat = null; - lastAction.action = Action.CALL; + lastAction.action = Action.CHECK; } return; }