summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/jrummikub/ai/TurnLogic.java235
-rw-r--r--src/jrummikub/control/RoundControl.java18
-rw-r--r--src/jrummikub/control/network/ConnectionControl.java5
-rw-r--r--src/jrummikub/control/network/GameJoinControl.java16
-rw-r--r--src/jrummikub/control/network/GameOfferControl.java17
-rw-r--r--src/jrummikub/control/network/NetworkControl.java58
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) {