summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/jrummikub/ai/TurnLogic.java169
1 files changed, 130 insertions, 39 deletions
diff --git a/src/jrummikub/ai/TurnLogic.java b/src/jrummikub/ai/TurnLogic.java
index 93952d7..214288a 100644
--- a/src/jrummikub/ai/TurnLogic.java
+++ b/src/jrummikub/ai/TurnLogic.java
@@ -36,19 +36,43 @@ public class TurnLogic {
private int neededPoints = 0;
private double neededScore = 0;
+ /**
+ * A Contradiction is thrown once a state is reached that isn't legal
+ */
@SuppressWarnings("serial")
private static class Contradiction extends Throwable {
}
+ /**
+ * The state the search is in, containing {@link StoneState}s
+ */
private class State {
+ /**
+ * A list of all stones
+ */
ArrayList<StoneState> stones = new ArrayList<StoneState>();
+ /**
+ * The stones that were changed since the previous state
+ */
HashSet<Integer> changedStones = new HashSet<Integer>();
+ /**
+ * The position of the jokers in the other lists
+ */
ArrayList<Integer> jokerIDs = new ArrayList<Integer>();
+ /**
+ * Create a new
+ */
public State() {
}
+ /**
+ * Create a copy of a state
+ *
+ * @param state
+ * the state to copy
+ */
public State(State state) {
for (StoneState stone : state.stones) {
stones.add(new StoneState(stone));
@@ -56,6 +80,12 @@ public class TurnLogic {
jokerIDs = state.jokerIDs;
}
+ /**
+ * Adds stones to be considered in the state
+ *
+ * @param stone
+ * the stone to add
+ */
public void add(StoneState stone) {
stones.add(stone);
changedStones.add(stones.size() - 1);
@@ -64,6 +94,12 @@ public class TurnLogic {
}
}
+ /**
+ * Update the stones to consider the changes of the changed stones
+ *
+ * @throws Contradiction
+ * Is thrown if the changes contradict each other
+ */
public void updateStones() throws Contradiction {
checkJokerCount();
for (int i : changedStones) {
@@ -81,6 +117,12 @@ public class TurnLogic {
}
}
+ /**
+ * One step in the update process
+ *
+ * @throws Contradiction
+ * Is thrown if changes contradict each other
+ */
public void updateStonesStep() throws Contradiction {
HashSet<Integer> newChangedStones = new HashSet<Integer>();
for (int i = 0; i < stoneCount; i++) {
@@ -94,6 +136,12 @@ public class TurnLogic {
changedStones = newChangedStones;
}
+ /**
+ * Returns whether the stones have a definite value and the state is thereby
+ * solved
+ *
+ * @return whether the state is solved
+ */
public boolean isSolved() {
for (StoneState stone : stones) {
if (!stone.isSolved()) {
@@ -103,6 +151,12 @@ public class TurnLogic {
return true;
}
+ /**
+ * Checks that not too many jokers are trying to be used
+ *
+ * @throws Contradiction
+ * Is thrown if too many jokers are trying to be used
+ */
private void checkJokerCount() throws Contradiction {
int jokersLeft = jokerIDs.size();
int jokersRight = jokerIDs.size();
@@ -122,6 +176,12 @@ public class TurnLogic {
}
}
+ /**
+ * Checks that enough points and a high enough score are reached
+ *
+ * @throws Contradiction
+ * Is thrown if points are too few or score is too low
+ */
public void checkScoreAndPoints() throws Contradiction {
if (getPoints() < neededPoints) {
throw new Contradiction();
@@ -131,6 +191,11 @@ public class TurnLogic {
}
}
+ /**
+ * Returns the points
+ *
+ * @return the amount of points
+ */
public int getPoints() {
int sum = 0;
for (StoneState stone : stones) {
@@ -141,6 +206,11 @@ public class TurnLogic {
return sum;
}
+ /**
+ * Returns the score
+ *
+ * @return the total score reached
+ */
public double getScore() {
double sum = 0;
for (StoneState stone : stones) {
@@ -153,6 +223,10 @@ public class TurnLogic {
}
}
+ /**
+ * Contains the remaining possible values, colors, positions, etc. a stone can
+ * take and its possible neighbors in a group or run
+ */
private class StoneState {
int id;
boolean joker;
@@ -165,6 +239,16 @@ public class TurnLogic {
HashSet<Integer> leftGroup;
HashSet<Integer> rightGroup;
+ /**
+ * Creates a new
+ *
+ * @param id
+ * the stone's identifier
+ * @param stone
+ * the stone
+ * @param table
+ * whether is on the table
+ */
public StoneState(int id, Stone stone, boolean table) {
this.id = id;
joker = stone.isJoker();
@@ -180,6 +264,12 @@ public class TurnLogic {
rightGroup = makeFullSet();
}
+ /**
+ * Creates a copy
+ *
+ * @param stone
+ * the state to copy
+ */
public StoneState(StoneState stone) {
this.id = stone.id;
this.joker = stone.joker;
@@ -193,6 +283,11 @@ public class TurnLogic {
this.rightGroup = new HashSet<Integer>(stone.rightGroup);
}
+ /**
+ * Returns a set containing all possible neighbors
+ *
+ * @return the set
+ */
private HashSet<Integer> makeFullSet() {
HashSet<Integer> set = new HashSet<Integer>();
for (int i = 0; i < stoneCount; i++) {
@@ -204,11 +299,18 @@ public class TurnLogic {
return set;
}
+ /**
+ * Returns whether the recent changes affect the stone
+ *
+ * @param changes
+ * the changes
+ * @return whether the stone is affected
+ */
public boolean isInterested(HashSet<Integer> changes) {
return !(Collections.disjoint(changes, leftRun)
&& Collections.disjoint(changes, rightRun)
- && Collections.disjoint(changes, leftGroup) && Collections
- .disjoint(changes, rightGroup));
+ && Collections.disjoint(changes, leftGroup) && Collections.disjoint(
+ changes, rightGroup));
}
public <T extends Comparable<T>> boolean lessThan(T a, T b) {
@@ -274,8 +376,7 @@ public class TurnLogic {
return a != null && b != null && a.equals(b);
}
- private void breakSymmetries(HashSet<Integer> changes)
- throws Contradiction {
+ private void breakSymmetries(HashSet<Integer> changes) throws Contradiction {
Integer mySym = symmetryBreakerValue();
if (mySym == null) {
return;
@@ -286,8 +387,7 @@ public class TurnLogic {
}
StoneState otherStone = top.stones.get(other);
if (!(joker && otherStone.joker || nonNullEquals(value,
- otherStone.value)
- && nonNullEquals(color, otherStone.color))) {
+ otherStone.value) && nonNullEquals(color, otherStone.color))) {
continue;
}
Integer otherSym = top.stones.get(other).symmetryBreakerValue();
@@ -306,8 +406,8 @@ public class TurnLogic {
if (onTable != Boolean.TRUE) {
return -1;
}
- if (leftRun.size() > 1 || leftGroup.size() > 1
- || rightRun.size() > 1 || rightGroup.size() > 1) {
+ if (leftRun.size() > 1 || leftGroup.size() > 1 || rightRun.size() > 1
+ || rightGroup.size() > 1) {
return null;
}
int mode;
@@ -347,8 +447,7 @@ public class TurnLogic {
if (!other.runNeighbor(this) || !other.rightRun.contains(id)) {
leftRun.remove(i);
changed = true;
- } else if (other.rightRun.size() == 1
- && other.onTable == Boolean.TRUE) {
+ } else if (other.rightRun.size() == 1 && other.onTable == Boolean.TRUE) {
changed |= leftRun.retainAll(Arrays.asList(i));
changed |= onTable != Boolean.TRUE;
onTable = true;
@@ -368,8 +467,7 @@ public class TurnLogic {
if (!this.runNeighbor(other) || !other.leftRun.contains(id)) {
rightRun.remove(i);
changed = true;
- } else if (other.leftRun.size() == 1
- && other.onTable == Boolean.TRUE) {
+ } else if (other.leftRun.size() == 1 && other.onTable == Boolean.TRUE) {
changed |= rightRun.retainAll(Arrays.asList(i));
changed |= onTable != Boolean.TRUE;
onTable = true;
@@ -386,8 +484,7 @@ public class TurnLogic {
relevantChanges.retainAll(changes);
for (int i : relevantChanges) {
StoneState other = top.stones.get(i);
- if (!other.groupNeighbor(this)
- || !other.rightGroup.contains(id)) {
+ if (!other.groupNeighbor(this) || !other.rightGroup.contains(id)) {
leftGroup.remove(i);
changed = true;
} else if (other.rightGroup.size() == 1
@@ -412,8 +509,7 @@ public class TurnLogic {
if (!this.groupNeighbor(other) || !other.leftGroup.contains(id)) {
rightGroup.remove(i);
changed = true;
- } else if (other.leftGroup.size() == 1
- && other.onTable == Boolean.TRUE) {
+ } else if (other.leftGroup.size() == 1 && other.onTable == Boolean.TRUE) {
changed |= rightGroup.retainAll(Arrays.asList(i));
changed |= onTable != Boolean.TRUE;
onTable = true;
@@ -470,9 +566,8 @@ public class TurnLogic {
private boolean checkLonelyStone() {
boolean changed = false;
@SuppressWarnings("unchecked")
- List<HashSet<Integer>> sets = Arrays.<HashSet<Integer>> asList(
- leftGroup, rightGroup, leftRun, rightRun, leftGroup,
- rightGroup, leftRun);
+ List<HashSet<Integer>> sets = Arrays.<HashSet<Integer>> asList(leftGroup,
+ rightGroup, leftRun, rightRun, leftGroup, rightGroup, leftRun);
for (int i = 0; i < 4; i++) {
if (isNullSet(sets.get(i)) && isNullSet(sets.get(i + 1))
&& isNullSet(sets.get(i + 2))) {
@@ -506,8 +601,8 @@ public class TurnLogic {
private boolean checkStoneCanBeOnTable() throws Contradiction {
boolean changed = false;
- if (leftGroup.isEmpty() || rightGroup.isEmpty()
- || leftRun.isEmpty() || rightRun.isEmpty()) {
+ if (leftGroup.isEmpty() || rightGroup.isEmpty() || leftRun.isEmpty()
+ || rightRun.isEmpty()) {
if (onTable == Boolean.TRUE) {
throw new Contradiction();
}
@@ -545,8 +640,7 @@ public class TurnLogic {
} else if (isSingleNonNullSet(rightRun)) {
Integer value = top.stones.get(rightRun.iterator().next()).value;
if (value != null) {
- this.value = (value - 2) % settings.getHighestValue()
- + 1;
+ this.value = (value - 2) % settings.getHighestValue() + 1;
}
}
changed |= this.value != null;
@@ -574,8 +668,8 @@ public class TurnLogic {
if (onTable == null || color == null || value == null) {
return false;
}
- if (leftRun.size() > 1 || rightRun.size() > 1
- || leftGroup.size() > 1 || rightGroup.size() > 1) {
+ if (leftRun.size() > 1 || rightRun.size() > 1 || leftGroup.size() > 1
+ || rightGroup.size() > 1) {
return false;
}
return true;
@@ -603,9 +697,8 @@ public class TurnLogic {
if (onTable != Boolean.TRUE) {
return false;
}
- for (HashSet<Integer> set : side ? Arrays
- .asList(leftGroup, leftRun) : Arrays.asList(rightGroup,
- rightRun)) {
+ for (HashSet<Integer> set : side ? Arrays.asList(leftGroup, leftRun)
+ : Arrays.asList(rightGroup, rightRun)) {
cancle: if (!set.contains(null)) {
for (int idx : set) {
if (!top.stones.get(idx).joker) {
@@ -632,11 +725,11 @@ public class TurnLogic {
* Creates new turn logic
*
* @param settings
- * the game settings
+ * the game settings
* @param tableStones
- * all stones on the table
+ * all stones on the table
* @param handStones
- * all stones on the hand
+ * all stones on the hand
*/
public TurnLogic(GameSettings settings, Collection<Stone> tableStones,
Collection<Stone> handStones) {
@@ -665,18 +758,17 @@ public class TurnLogic {
@Override
public int compare(Pair<Stone, Boolean> o1, Pair<Stone, Boolean> o2) {
int cmp;
- cmp = ((Boolean) o1.getFirst().isJoker()).compareTo(o2
- .getFirst().isJoker());
+ cmp = ((Boolean) o1.getFirst().isJoker()).compareTo(o2.getFirst()
+ .isJoker());
if (cmp != 0) {
return -cmp;
}
- cmp = (o1.getFirst().getColor()).compareTo(o2.getFirst()
- .getColor());
+ cmp = (o1.getFirst().getColor()).compareTo(o2.getFirst().getColor());
if (cmp != 0) {
return cmp;
}
- cmp = ((Integer) o1.getFirst().getValue()).compareTo(o2
- .getFirst().getValue());
+ cmp = ((Integer) o1.getFirst().getValue()).compareTo(o2.getFirst()
+ .getValue());
return cmp;
}
});
@@ -743,8 +835,7 @@ public class TurnLogic {
ArrayList<Stone> setStones = new ArrayList<Stone>();
while (true) {
setStones.add(inputStones.get(stone.id));
- if (isNullSet(stone.rightRun)
- && isNullSet(stone.rightGroup)) {
+ if (isNullSet(stone.rightRun) && isNullSet(stone.rightGroup)) {
break;
}
Integer rightRunID = stone.rightRun.iterator().next();