diff options
-rw-r--r-- | src/jrummikub/ai/TurnLogic.java | 169 |
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(); |