diff options
Diffstat (limited to 'src/jrummikub')
-rw-r--r-- | src/jrummikub/ai/TurnLogic.java | 235 | ||||
-rw-r--r-- | src/jrummikub/control/RoundControl.java | 18 | ||||
-rw-r--r-- | src/jrummikub/control/network/ConnectionControl.java | 5 | ||||
-rw-r--r-- | src/jrummikub/control/network/GameJoinControl.java | 16 | ||||
-rw-r--r-- | src/jrummikub/control/network/GameOfferControl.java | 17 | ||||
-rw-r--r-- | src/jrummikub/control/network/NetworkControl.java | 58 |
6 files changed, 253 insertions, 96 deletions
diff --git a/src/jrummikub/ai/TurnLogic.java b/src/jrummikub/ai/TurnLogic.java index b9e2a2a..81391a7 100644 --- a/src/jrummikub/ai/TurnLogic.java +++ b/src/jrummikub/ai/TurnLogic.java @@ -14,6 +14,9 @@ import jrummikub.model.StoneColor; import jrummikub.model.StoneSet; import jrummikub.util.Pair; +/** + * Logic behind the ai turns + */ public class TurnLogic { private GameSettings settings; private int stoneCount; @@ -264,13 +267,15 @@ public class TurnLogic { public boolean update(HashSet<Integer> changes) throws Contradiction { boolean changed = false; - changed |= updateRuns(changes); - changed |= updateGroups(changes); + changed |= updateRightRuns(changes); + changed |= updateLeftRuns(changes); + changed |= updateRightGroups(changes); + changed |= updateLeftGroups(changes); changed |= checkState(); return changed; } - public boolean updateRuns(HashSet<Integer> changes) + public boolean updateRightRuns(HashSet<Integer> changes) throws Contradiction { boolean changed = false; HashSet<Integer> relevantChanges = new HashSet<Integer>(leftRun); @@ -288,7 +293,13 @@ public class TurnLogic { break; } } - relevantChanges = new HashSet<Integer>(rightRun); + return changed; + } + + public boolean updateLeftRuns(HashSet<Integer> changes) + throws Contradiction { + boolean changed = false; + HashSet<Integer> relevantChanges = new HashSet<Integer>(rightRun); relevantChanges.retainAll(changes); for (int i : relevantChanges) { StoneState other = top.stones.get(i); @@ -306,7 +317,7 @@ public class TurnLogic { return changed; } - public boolean updateGroups(HashSet<Integer> changes) + public boolean updateRightGroups(HashSet<Integer> changes) throws Contradiction { boolean changed = false; HashSet<Integer> relevantChanges = new HashSet<Integer>(leftGroup); @@ -325,6 +336,13 @@ public class TurnLogic { break; } } + return changed; + } + + public boolean updateLeftGroups(HashSet<Integer> changes) + throws Contradiction { + boolean changed = false; + HashSet<Integer> relevantChanges = new HashSet<Integer>(leftGroup); relevantChanges = new HashSet<Integer>(rightGroup); relevantChanges.retainAll(changes); for (int i : relevantChanges) { @@ -345,6 +363,7 @@ public class TurnLogic { public boolean checkState() throws Contradiction { boolean changed = false; + if (onTable == Boolean.FALSE) { if (leftRun.size() + rightRun.size() + leftGroup.size() + rightGroup.size() != 0) { @@ -357,6 +376,23 @@ public class TurnLogic { return false; } + changed |= checkSetTypeKnown(); + + changed |= checkLonelyStone(); + + changed |= checkNeighborStoneNeeded(); + + changed |= checkStoneCanBeOnTable(); + + checkGroupRunExclusive(); + + changed |= checkJoker(); + + return changed; + } + + private boolean checkSetTypeKnown() { + boolean changed = false; if (!(leftGroup.contains(null) || rightGroup.contains(null))) { changed |= leftRun.retainAll(Arrays.asList((Integer) null)) | rightRun.retainAll(Arrays.asList((Integer) null)); @@ -365,7 +401,11 @@ public class TurnLogic { changed |= leftGroup.retainAll(Arrays.asList((Integer) null)) | rightGroup.retainAll(Arrays.asList((Integer) null)); } + return changed; + } + private boolean checkLonelyStone() { + boolean changed = false; @SuppressWarnings("unchecked") List<HashSet<Integer>> sets = Arrays.<HashSet<Integer>> asList( leftGroup, rightGroup, leftRun, rightRun, leftGroup, @@ -376,7 +416,11 @@ public class TurnLogic { changed |= sets.get(i + 3).remove(null); } } + return changed; + } + private boolean checkNeighborStoneNeeded() { + boolean changed = false; if (isSingleNonNullSet(leftRun) && isNullSet(top.stones.get(leftRun.iterator().next()).leftRun)) { changed |= rightRun.remove(null); @@ -394,7 +438,11 @@ public class TurnLogic { && isNullSet(top.stones.get(rightGroup.iterator().next()).rightGroup)) { changed |= leftGroup.remove(null); } + return changed; + } + private boolean checkStoneCanBeOnTable() throws Contradiction { + boolean changed = false; if (leftGroup.isEmpty() || rightGroup.isEmpty() || leftRun.isEmpty() || rightRun.isEmpty()) { if (onTable == Boolean.TRUE) { @@ -409,15 +457,14 @@ public class TurnLogic { changed = true; } } + return changed; + } + private void checkGroupRunExclusive() throws Contradiction { if ((isSingleNonNullSet(leftGroup) || isSingleNonNullSet(rightGroup)) && (isSingleNonNullSet(leftRun) || isSingleNonNullSet(rightRun))) { throw new Contradiction(); } - - changed |= checkJoker(); - - return changed; } private boolean checkJoker() { @@ -425,16 +472,22 @@ public class TurnLogic { } public boolean isSolved() { + boolean solved = false; if (onTable == Boolean.FALSE) { - return true; + return solved; } if (onTable == null || color == null || value == null) { - return false; + return solved; } if (leftRun.size() > 1 || rightRun.size() > 1 || leftGroup.size() > 1 || rightGroup.size() > 1) { - return false; + return solved; } + solved = bothGoupAndRun(); + return solved; + } + + private boolean bothGoupAndRun() { if (!((isNullSet(leftRun) && isNullSet(rightRun)) || (isNullSet(leftGroup) && isNullSet(rightGroup)))) { return false; } @@ -467,6 +520,16 @@ public class TurnLogic { return i.size() == 1 && !i.contains(null); } + /** + * Creates new turn logic + * + * @param settings + * the game settings + * @param tableStones + * all stones on the table + * @param handStones + * all stones on the hand + */ public TurnLogic(GameSettings settings, Collection<Stone> tableStones, Collection<Stone> handStones) { this.settings = settings; @@ -517,6 +580,9 @@ public class TurnLogic { } } + /** + * Include initial meld threshold into turn logic + */ public void needIntialMeldThreshold() { neededPoints = settings.getInitialMeldThreshold(); } @@ -542,10 +608,18 @@ public class TurnLogic { top = stack.get(stack.size() - 1); } + /** + * Aborts currently running solve call + */ public void abort() { abort = true; } + /** + * Get the found stones and create output sets + * + * @return output sets to put on table + */ public List<StoneSet> getResult() { State result = bestState; @@ -574,10 +648,14 @@ public class TurnLogic { outputSets.add(new StoneSet(setStones)); } } - return outputSets; } + /** + * Solves next state on stack while not aborted + * + * @return solved + */ public boolean solve() { if (top.isSolved()) { pop(); @@ -601,6 +679,11 @@ public class TurnLogic { return false; } + /** + * Optimizes the solution found as long as stopped from control + * + * @return score of found solution + */ public double optimize() { while (!autoAbort && solve()) { neededScore = top.getScore(); @@ -613,77 +696,37 @@ public class TurnLogic { StoneState stone = top.stones.get(i); if (stone.onTable == null) { replace(); - State newState = new State(top); - newState.stones.get(i).onTable = false; - newState.changedStones.add(i); - State altState = new State(top); - altState.stones.get(i).onTable = true; - altState.changedStones.add(i); - pushes(altState, newState); + branchOnHand(i); return; } if (stone.leftRun.size() > 1) { replace(); - for (Integer id : stone.leftRun) { - State newState = new State(top); - newState.stones.get(i).leftRun.clear(); - newState.stones.get(i).leftRun.add(id); - newState.changedStones.add(i); - pushes(newState); - } + branchLeftRun(i, stone); return; } if (stone.rightRun.size() > 1) { replace(); - for (Integer id : stone.rightRun) { - State newState = new State(top); - newState.stones.get(i).rightRun.clear(); - newState.stones.get(i).rightRun.add(id); - newState.changedStones.add(i); - pushes(newState); - } + branchRightRun(i, stone); return; } if (stone.leftGroup.size() > 1) { replace(); - for (Integer id : stone.leftGroup) { - State newState = new State(top); - newState.stones.get(i).leftGroup.clear(); - newState.stones.get(i).leftGroup.add(id); - newState.changedStones.add(i); - pushes(newState); - } + branchLeftGroup(i, stone); return; } if (stone.rightGroup.size() > 1) { replace(); - for (Integer id : stone.rightGroup) { - State newState = new State(top); - newState.stones.get(i).rightGroup.clear(); - newState.stones.get(i).rightGroup.add(id); - newState.changedStones.add(i); - pushes(newState); - } + branchRightGroup(i, stone); return; } if (stone.color == null) { replace(); - for (StoneColor color : stoneColors) { - State newState = new State(top); - newState.stones.get(i).color = color; - newState.changedStones.add(i); - pushes(newState); - } + branchColor(i); return; } if (stone.value == null) { replace(); - for (int value = 1; value <= settings.getHighestValue(); value++) { - State newState = new State(top); - newState.stones.get(i).value = value; - newState.changedStones.add(i); - pushes(newState); - } + branchValue(i); return; } } @@ -691,11 +734,81 @@ public class TurnLogic { throw new Error("Internal AI error"); } + private void branchValue(int i) { + for (int value = 1; value <= settings.getHighestValue(); value++) { + State newState = new State(top); + newState.stones.get(i).value = value; + newState.changedStones.add(i); + pushes(newState); + } + } + + private void branchColor(int i) { + for (StoneColor color : stoneColors) { + State newState = new State(top); + newState.stones.get(i).color = color; + newState.changedStones.add(i); + pushes(newState); + } + } + + private void branchRightGroup(int i, StoneState stone) { + for (Integer id : stone.rightGroup) { + State newState = new State(top); + newState.stones.get(i).rightGroup.clear(); + newState.stones.get(i).rightGroup.add(id); + newState.changedStones.add(i); + pushes(newState); + } + } + + private void branchLeftGroup(int i, StoneState stone) { + for (Integer id : stone.leftGroup) { + State newState = new State(top); + newState.stones.get(i).leftGroup.clear(); + newState.stones.get(i).leftGroup.add(id); + newState.changedStones.add(i); + pushes(newState); + } + } + + private void branchRightRun(int i, StoneState stone) { + for (Integer id : stone.rightRun) { + State newState = new State(top); + newState.stones.get(i).rightRun.clear(); + newState.stones.get(i).rightRun.add(id); + newState.changedStones.add(i); + pushes(newState); + } + } + + private void branchLeftRun(int i, StoneState stone) { + for (Integer id : stone.leftRun) { + State newState = new State(top); + newState.stones.get(i).leftRun.clear(); + newState.stones.get(i).leftRun.add(id); + newState.changedStones.add(i); + pushes(newState); + } + } + + private void branchOnHand(int i) { + State newState = new State(top); + newState.stones.get(i).onTable = false; + newState.changedStones.add(i); + State altState = new State(top); + altState.stones.get(i).onTable = true; + altState.changedStones.add(i); + pushes(altState, newState); + } + + /** + * Abort as soon as a solution is found + */ public void autoAbort() { if (bestState != null) { abort = true; } autoAbort = true; - } } diff --git a/src/jrummikub/control/RoundControl.java b/src/jrummikub/control/RoundControl.java index f060420..fb4ab0c 100644 --- a/src/jrummikub/control/RoundControl.java +++ b/src/jrummikub/control/RoundControl.java @@ -228,10 +228,12 @@ public class RoundControl { } else { List<Stone> markedStones = new ArrayList<Stone>(); for (Pair<StoneSet, Position> set : clonedTable) { - if (!set.getFirst().isValid(roundState.getGameSettings())) { - for (Stone stone : set.getFirst()) { - markedStones.add(stone); - } + if (set.getFirst().isValid(roundState.getGameSettings())) { + continue; + } + for (Stone stone : set.getFirst()) { + markedStones.add(stone); + } } view.setStoneCollectionHidden(true); @@ -401,8 +403,8 @@ public class RoundControl { .getGameSettings()); } - bestScore = updateBestScore(bestScore, -stonePoints, - playerHand.getSize()); + bestScore = updateBestScore(bestScore, -stonePoints, playerHand + .getSize()); points.add(-stonePoints); pointSum += stonePoints; @@ -424,8 +426,8 @@ public class RoundControl { private static Pair<Integer, Integer> updateBestScore( Pair<Integer, Integer> bestScore, int stonePoints, int size) { if (bestScore.getFirst() == stonePoints) { - return new Pair<Integer, Integer>(stonePoints, Math.min( - bestScore.getSecond(), size)); + return new Pair<Integer, Integer>(stonePoints, Math.min(bestScore + .getSecond(), size)); } else if (bestScore.getFirst() < stonePoints) { return new Pair<Integer, Integer>(stonePoints, size); } diff --git a/src/jrummikub/control/network/ConnectionControl.java b/src/jrummikub/control/network/ConnectionControl.java index ca8537d..28684b2 100644 --- a/src/jrummikub/control/network/ConnectionControl.java +++ b/src/jrummikub/control/network/ConnectionControl.java @@ -299,6 +299,11 @@ class ConnectionControl implements IConnectionControl { String messageType = extension.getValue("messageType"); + handleMessageTypes(extension, sender, messageType); + } + + private void handleMessageTypes(DefaultPacketExtension extension, + String sender, String messageType) { if (messageType.equals("game_offer")) { UUID uuid = UUID.fromString(extension.getValue("uuid")); GameSettings settings = (GameSettings) Base64 diff --git a/src/jrummikub/control/network/GameJoinControl.java b/src/jrummikub/control/network/GameJoinControl.java index 4adc61d..489199e 100644 --- a/src/jrummikub/control/network/GameJoinControl.java +++ b/src/jrummikub/control/network/GameJoinControl.java @@ -10,8 +10,21 @@ import jrummikub.util.IListener1; import jrummikub.view.ISettingsPanel.SettingsMode; import jrummikub.view.IView; +/** + * Control for joining a network game + */ public class GameJoinControl extends AbstractGameBeginControl { + /** + * Creates new game join control + * + * @param connectionControl + * the current connection control for events and messages + * @param gameData + * the game data for settings, game id + * @param view + * the view + */ public GameJoinControl(final IConnectionControl connectionControl, final GameData gameData, final IView view) { super(connectionControl, view, gameData, SettingsMode.NETWORK_JOIN); @@ -54,6 +67,9 @@ public class GameJoinControl extends AbstractGameBeginControl { } } + /** + * Starts the join control and sets the settings panel in game join mode + */ public void startGameJoin() { view.showSettingsPanel(true); } diff --git a/src/jrummikub/control/network/GameOfferControl.java b/src/jrummikub/control/network/GameOfferControl.java index af060fd..0c94c1f 100644 --- a/src/jrummikub/control/network/GameOfferControl.java +++ b/src/jrummikub/control/network/GameOfferControl.java @@ -11,8 +11,21 @@ import jrummikub.util.IListener1; import jrummikub.view.ISettingsPanel.SettingsMode; import jrummikub.view.IView; +/** + * Control for network game host + */ public class GameOfferControl extends AbstractGameBeginControl { + /** + * Creates new game offer control + * + * @param connectionControl + * for events (listening and handling) + * @param settings + * the game settings for player list, colors, names + * @param view + * the view + */ public GameOfferControl(final IConnectionControl connectionControl, final GameSettings settings, final IView view) { super(connectionControl, view, @@ -57,6 +70,10 @@ public class GameOfferControl extends AbstractGameBeginControl { })); } + /** + * sends the game offer and starts the settings panel for host using network + * offer type + */ public void startGameOffer() { connectionControl.offerGame(gameData); diff --git a/src/jrummikub/control/network/NetworkControl.java b/src/jrummikub/control/network/NetworkControl.java index 95f48a4..a8faac5 100644 --- a/src/jrummikub/control/network/NetworkControl.java +++ b/src/jrummikub/control/network/NetworkControl.java @@ -44,26 +44,27 @@ public class NetworkControl { this.view = view; connectionControl = new ConnectionControl(loginData); + addConnectionSetupListeners(loginData, view); addConnectionControlListeners(loginData, view); - connections.add(view.getGameListPanel().getJoinEvent() - .add(new IListener1<GameData>() { + connections.add(view.getGameListPanel().getJoinEvent().add( + new IListener1<GameData>() { @Override public void handle(GameData gameData) { join(gameData); } })); - connections.add(view.getGameListPanel().getOpenNewGameEvent() - .add(new IListener() { + connections.add(view.getGameListPanel().getOpenNewGameEvent().add( + new IListener() { @Override public void handle() { createSettingsControl(); } })); - connections.add(view.getGameListPanel().getCancelEvent() - .add(new IListener() { + connections.add(view.getGameListPanel().getCancelEvent().add( + new IListener() { @Override public void handle() { abort(); @@ -87,25 +88,6 @@ public class NetworkControl { */ public void addConnectionControlListeners(final LoginData loginData, final IView view) { - connections.add(connectionControl.getConnectedEvent().add( - new IListener() { - @Override - public void handle() { - view.getGameListPanel().setChannelName( - loginData.getChannelName()); - view.showGameListPanel(true); - } - })); - - connections.add(connectionControl.getConnectionFailedEvent().add( - new IListener() { - @Override - public void handle() { - // TODO Auto-generated method stub - - } - })); - connections.add(connectionControl.getGameOfferEvent().add( new IListener1<GameData>() { @Override @@ -149,6 +131,28 @@ public class NetworkControl { })); } + private void addConnectionSetupListeners(final LoginData loginData, + final IView view) { + connections.add(connectionControl.getConnectedEvent().add( + new IListener() { + @Override + public void handle() { + view.getGameListPanel().setChannelName( + loginData.getChannelName()); + view.showGameListPanel(true); + } + })); + + connections.add(connectionControl.getConnectionFailedEvent().add( + new IListener() { + @Override + public void handle() { + // TODO Auto-generated method stub + + } + })); + } + private void updateGameList() { List<GameData> gameList = new ArrayList<GameData>(); @@ -220,8 +224,8 @@ public class NetworkControl { } view.showGameListPanel(false); - settingsControl = new NetworkSettingsControl( - connectionControl.getNickname(), view, new GameSettings()); + settingsControl = new NetworkSettingsControl(connectionControl + .getNickname(), view, new GameSettings()); settingsControl.getOfferGameEvent().add(new IListener1<GameSettings>() { @Override public void handle(GameSettings settings) { |