diff options
-rw-r--r-- | src/jrummikub/control/AIUtil.java | 337 | ||||
-rw-r--r-- | src/jrummikub/control/turn/AIControl.java | 10 | ||||
-rw-r--r-- | src/jrummikub/model/Hand.java | 56 |
3 files changed, 57 insertions, 346 deletions
diff --git a/src/jrummikub/control/AIUtil.java b/src/jrummikub/control/AIUtil.java deleted file mode 100644 index 92412b2..0000000 --- a/src/jrummikub/control/AIUtil.java +++ /dev/null @@ -1,337 +0,0 @@ -package jrummikub.control;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-import java.util.TreeMap;
-
-import jrummikub.model.GameSettings;
-import jrummikub.model.Stone;
-import jrummikub.model.StoneColor;
-import jrummikub.model.StoneSet;
-import jrummikub.util.Pair;
-
-/**
- * A collection of several AI utility methods with given game settings
- *
- */
-public class AIUtil {
- private GameSettings settings;
- private List<StoneColor> stoneColors;
-
- /**
- * The utility class's methods calculate their results based on the game
- * settings
- *
- * @param settings
- * the underlying game settings
- */
- public AIUtil(GameSettings settings) {
- this.settings = settings;
-
- stoneColors = new ArrayList<StoneColor>(Arrays.asList(StoneColor.values()));
- stoneColors.retainAll(settings.getStoneColors());
- }
-
- private static class SearchState {
- int pointsMissing;
- TreeMap<Pair<Integer, StoneColor>, Integer> stoneCounts;
- int jokerCount;
-
- SearchState(int pointsMissing,
- TreeMap<Pair<Integer, StoneColor>, Integer> stoneCounts, int jokerCount) {
- this.pointsMissing = pointsMissing;
- this.stoneCounts = stoneCounts;
- this.jokerCount = jokerCount;
- }
- }
-
- @SuppressWarnings("serial")
- private static class EnoughPoints extends Throwable {
- private Pair<List<StoneSet>, Integer> result;
-
- public EnoughPoints(Pair<List<StoneSet>, Integer> result) {
- this.result = result;
- }
-
- public Pair<List<StoneSet>, Integer> getResult() {
- return result;
- }
- }
-
- /**
- * Tries to find sets with a certain total of points. If only lower totals are
- * found, returns the sets with the highest cumulated point total.
- *
- * @param pointsMissing
- * the desired number of points
- * @param stoneCounts
- * the number of each stone
- * @param jokerCount
- * the total number of jokers in the game
- * @return the sets that have the desired point total or the highest found
- */
- @SuppressWarnings("unchecked")
- public Pair<List<StoneSet>, Integer> findSetsWithTotalPoints(
- int pointsMissing,
- TreeMap<Pair<Integer, StoneColor>, Integer> stoneCounts, int jokerCount) {
- Pair<List<StoneSet>, Integer> emptyResult = new Pair<List<StoneSet>, Integer>(
- Collections.<StoneSet> emptyList(), 0);
- if (pointsMissing <= 0)
- return emptyResult;
-
- stoneCounts = (TreeMap<Pair<Integer, StoneColor>, Integer>) stoneCounts
- .clone();
-
- SearchHelper searchHelper = new SearchHelper(
- pointsMissing,
- new Pair<List<StoneSet>, Integer>(Collections.<StoneSet> emptyList(), 0));
- try {
- for (int value = settings.getHighestValue(); value >= 1; value--) {
- for (StoneColor color : stoneColors) {
- Pair<Integer, StoneColor> stone = new Pair<Integer, StoneColor>(
- value, color);
-
- if (stoneCounts.containsKey(stone)) {
- SearchState searchState = new SearchState(pointsMissing - value,
- stoneCounts, jokerCount);
- decrementStoneCount(stoneCounts, stone);
- searchHelper.checkResult(findRunsWithTotalPoints(searchState,
- stone, 1));
-
- searchHelper.checkResult(findGroupsWithTotalPoints(searchState,
- value, Collections.singletonList(color), color));
- }
-
- if (jokerCount > 0) {
- SearchState searchState = new SearchState(pointsMissing - value,
- stoneCounts, jokerCount - 1);
- searchHelper.checkResult(findRunsWithTotalPoints(searchState,
- stone, 1));
-
- searchHelper.checkResult(findGroupsWithTotalPoints(searchState,
- value, Collections.singletonList(color), color));
- }
- }
- }
- } catch (EnoughPoints enoughPoints) {
- return enoughPoints.getResult();
- }
- return searchHelper.getBestResult();
- }
-
- private static class SearchHelper {
- Pair<List<StoneSet>, Integer> bestResult;
- int pointsMissing;
-
- public SearchHelper(int pointsMissing,
- Pair<List<StoneSet>, Integer> bestResult) {
- this.pointsMissing = pointsMissing;
- this.bestResult = bestResult;
- }
-
- public void checkResult(Pair<List<StoneSet>, Integer> result)
- throws EnoughPoints {
- if (result.getSecond() >= pointsMissing)
- throw new EnoughPoints(result);
- if (result.getSecond() > bestResult.getSecond())
- bestResult = result;
- }
-
- public Pair<List<StoneSet>, Integer> getBestResult() {
- return bestResult;
- }
- }
-
- private Pair<List<StoneSet>, Integer> findGroupsWithTotalPoints(
- SearchState searchState, int value, List<StoneColor> chosenColors,
- StoneColor testedColor) {
-
- StoneColor nextColor = getNextColor(testedColor);
- Pair<Integer, StoneColor> nextStone = new Pair<Integer, StoneColor>(value,
- nextColor);
-
- SearchHelper searchHelper = new SearchHelper(
- searchState.pointsMissing,
- new Pair<List<StoneSet>, Integer>(Collections.<StoneSet> emptyList(), 0));
- try {
- if (nextColor != null) {
- List<StoneColor> newColors = new ArrayList<StoneColor>(chosenColors);
- newColors.add(nextColor);
- if (searchState.stoneCounts.containsKey(nextStone)) {
- decrementStoneCount(searchState.stoneCounts, nextStone);
- searchHelper.checkResult(findGroupsWithTotalPoints(searchState,
- value, newColors, nextColor));
- incrementStoneCount(searchState.stoneCounts, nextStone);
- }
- if (searchState.jokerCount > 0) {
- searchHelper.checkResult(findGroupsWithTotalPoints(new SearchState(
- searchState.pointsMissing, searchState.stoneCounts,
- searchState.jokerCount - 1), value, newColors, nextColor));
- }
- searchHelper.checkResult(findGroupsWithTotalPoints(searchState, value,
- chosenColors, nextColor));
- }
-
- if (chosenColors.size() >= 3) {
- searchHelper.checkResult(handleFoundGroup(searchState, value,
- chosenColors));
- }
- } catch (EnoughPoints enoughPoints) {
- return enoughPoints.getResult();
- }
- return searchHelper.getBestResult();
- }
-
- private Pair<List<StoneSet>, Integer> handleFoundGroup(
- SearchState searchState, int value, List<StoneColor> chosenColors) {
- int groupPoints = chosenColors.size() * value;
- Pair<List<StoneSet>, Integer> result = findSetsWithTotalPoints(
- searchState.pointsMissing - groupPoints, searchState.stoneCounts,
- searchState.jokerCount);
- List<Stone> newStones = new ArrayList<Stone>();
- for (StoneColor color : chosenColors) {
- newStones.add(new Stone(value, color));
- }
- List<StoneSet> newResultList = new ArrayList<StoneSet>(result.getFirst());
- newResultList.add(new StoneSet(newStones));
- result = new Pair<List<StoneSet>, Integer>(newResultList,
- result.getSecond() + groupPoints);
- return result;
- }
-
- private Pair<List<StoneSet>, Integer> findRunsWithTotalPoints(
- SearchState searchState, Pair<Integer, StoneColor> testedStone,
- int runLength) {
-
- SearchHelper searchHelper = new SearchHelper(
- searchState.pointsMissing,
- new Pair<List<StoneSet>, Integer>(Collections.<StoneSet> emptyList(), 0));
- try {
- Pair<Integer, StoneColor> nextStone = null;
- if (testedStone.getFirst() > 1) {
- int nextValue = testedStone.getFirst() - 1;
- nextStone = new Pair<Integer, StoneColor>(nextValue,
- testedStone.getSecond());
-
- if (searchState.stoneCounts.containsKey(nextStone)) {
- decrementStoneCount(searchState.stoneCounts, nextStone);
- searchHelper.checkResult(findRunsWithTotalPoints(searchState,
- nextStone, runLength + 1));
- incrementStoneCount(searchState.stoneCounts, nextStone);
-
- }
- if (searchState.jokerCount > 0) {
- searchHelper.checkResult(findRunsWithTotalPoints(new SearchState(
- searchState.pointsMissing, searchState.stoneCounts,
- searchState.jokerCount - 1), nextStone, runLength + 1));
-
- }
- }
-
- if (runLength >= 3) {
- searchHelper.checkResult(handleFoundRun(searchState, testedStone,
- runLength));
- }
- } catch (EnoughPoints enoughPoints) {
- return enoughPoints.getResult();
- }
- return searchHelper.getBestResult();
- }
-
- private Pair<List<StoneSet>, Integer> handleFoundRun(SearchState searchState,
- Pair<Integer, StoneColor> testedStone, int runLength) {
- int below = testedStone.getFirst() - 1;
- int high = below + runLength;
- int runPoints = (high * (high + 1)) / 2 - (below * (below + 1)) / 2;
-
- Pair<List<StoneSet>, Integer> result = findSetsWithTotalPoints(
- searchState.pointsMissing - runPoints, searchState.stoneCounts,
- searchState.jokerCount);
-
- List<Stone> newStones = new ArrayList<Stone>();
- for (int i = 0; i < runLength; i++) {
- newStones.add(new Stone(i + testedStone.getFirst(), testedStone
- .getSecond()));
- }
- List<StoneSet> newResultList = new ArrayList<StoneSet>(result.getFirst());
- newResultList.add(new StoneSet(newStones));
- result = new Pair<List<StoneSet>, Integer>(newResultList,
- result.getSecond() + runPoints);
- return result;
- }
-
- private static void incrementStoneCount(
- TreeMap<Pair<Integer, StoneColor>, Integer> stones,
- Pair<Integer, StoneColor> stone) {
- if (stones.containsKey(stone)) {
- stones.put(stone, stones.get(stone) + 1);
- } else {
- stones.put(stone, 1);
- }
- }
-
- private static void decrementStoneCount(
- TreeMap<Pair<Integer, StoneColor>, Integer> stones,
- Pair<Integer, StoneColor> stone) {
- int count = stones.get(stone);
- count--;
-
- if (count == 0) {
- stones.remove(stone);
- } else {
- stones.put(stone, count);
- }
- }
-
- private StoneColor getNextColor(StoneColor color) {
- int index = stoneColors.indexOf(color) + 1;
- if (index >= stoneColors.size()) {
- return null;
- }
- return stoneColors.get(index);
- }
-
- private final static Comparator<Pair<Integer, StoneColor>> comparator = new Comparator<Pair<Integer, StoneColor>>() {
-
- @Override
- public int compare(Pair<Integer, StoneColor> o1,
- Pair<Integer, StoneColor> o2) {
- int firstComparison = o1.getFirst().compareTo(o2.getFirst());
- if (firstComparison != 0) {
- return -firstComparison;
- } else {
- return o1.getSecond().compareTo(o2.getSecond());
- }
- }
- };
-
- /**
- * Counts the numbers of stones
- *
- * @param stones
- * the stones to count
- * @return the numbers for all stones
- */
- public static Pair<TreeMap<Pair<Integer, StoneColor>, Integer>, Integer> countStones(
- List<Stone> stones) {
- int jokerCount = 0;
- TreeMap<Pair<Integer, StoneColor>, Integer> stoneCounts = new TreeMap<Pair<Integer, StoneColor>, Integer>(
- comparator);
-
- for (Stone stone : stones) {
- if (stone.isJoker()) {
- jokerCount++;
- } else {
- Pair<Integer, StoneColor> key = new Pair<Integer, StoneColor>(
- stone.getValue(), stone.getColor());
-
- incrementStoneCount(stoneCounts, key);
- }
- }
- return new Pair<TreeMap<Pair<Integer, StoneColor>, Integer>, Integer>(
- stoneCounts, jokerCount);
- }
-}
diff --git a/src/jrummikub/control/turn/AIControl.java b/src/jrummikub/control/turn/AIControl.java index 8ab0aa5..324c8d7 100644 --- a/src/jrummikub/control/turn/AIControl.java +++ b/src/jrummikub/control/turn/AIControl.java @@ -5,16 +5,13 @@ import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.Iterator; import java.util.List; -import java.util.TreeMap; import javax.swing.SwingUtilities; import javax.swing.Timer; import jrummikub.ai.TurnLogic; -import jrummikub.control.AIUtil; import jrummikub.model.Position; import jrummikub.model.Stone; -import jrummikub.model.StoneColor; import jrummikub.model.StoneSet; import jrummikub.util.Pair; @@ -52,7 +49,8 @@ public class AIControl extends AbstractTurnControl { long turnLength = System.currentTimeMillis() - startTime; if (useBackgroundThread) { - Timer timer = new Timer(Math.max(0, (int) (1000 + Math.random() * 2000 - turnLength)), + Timer timer = new Timer(Math.max(0, + (int) (1000 + Math.random() * 2000 - turnLength)), new ActionListener() { @Override public void actionPerformed(ActionEvent event) { @@ -105,7 +103,7 @@ public class AIControl extends AbstractTurnControl { logic.needIntialMeldThreshold(); } if (useBackgroundThread) { - + Timer timer = new Timer(10000, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { @@ -114,7 +112,7 @@ public class AIControl extends AbstractTurnControl { }); timer.setRepeats(false); timer.start(); - + Thread computeThread = new Thread(new Runnable() { @Override public void run() { diff --git a/src/jrummikub/model/Hand.java b/src/jrummikub/model/Hand.java index 6c3beca..69d659b 100644 --- a/src/jrummikub/model/Hand.java +++ b/src/jrummikub/model/Hand.java @@ -5,12 +5,12 @@ import static jrummikub.model.StoneTray.Direction.RIGHT; import java.util.ArrayList; import java.util.Collections; +import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.TreeMap; import jrummikub.ai.TurnLogic; -import jrummikub.control.AIUtil; import jrummikub.util.Pair; /** Class managing a {@link Player}'s {@link Stone}s */ @@ -96,6 +96,57 @@ public class Hand extends StoneTray<Stone> implements IHand { turnLogic.needIntialMeldThreshold(); return turnLogic.solve(); } + + + private static void incrementStoneCount( + TreeMap<Pair<Integer, StoneColor>, Integer> stones, + Pair<Integer, StoneColor> stone) { + if (stones.containsKey(stone)) { + stones.put(stone, stones.get(stone) + 1); + } else { + stones.put(stone, 1); + } + } + + private final static Comparator<Pair<Integer, StoneColor>> comparator = new Comparator<Pair<Integer, StoneColor>>() { + @Override + public int compare(Pair<Integer, StoneColor> o1, + Pair<Integer, StoneColor> o2) { + int firstComparison = o1.getFirst().compareTo(o2.getFirst()); + if (firstComparison != 0) { + return -firstComparison; + } else { + return o1.getSecond().compareTo(o2.getSecond()); + } + } + }; + + /** + * Counts the numbers of stones + * + * @param stones + * the stones to count + * @return the numbers for all stones + */ + private static Pair<TreeMap<Pair<Integer, StoneColor>, Integer>, Integer> countStones( + List<Stone> stones) { + int jokerCount = 0; + TreeMap<Pair<Integer, StoneColor>, Integer> stoneCounts = new TreeMap<Pair<Integer, StoneColor>, Integer>( + comparator); + + for (Stone stone : stones) { + if (stone.isJoker()) { + jokerCount++; + } else { + Pair<Integer, StoneColor> key = new Pair<Integer, StoneColor>( + stone.getValue(), stone.getColor()); + + incrementStoneCount(stoneCounts, key); + } + } + return new Pair<TreeMap<Pair<Integer, StoneColor>, Integer>, Integer>( + stoneCounts, jokerCount); + } @Override public int getIdenticalStoneCount() { @@ -106,8 +157,7 @@ public class Hand extends StoneTray<Stone> implements IHand { stones.add(iter.next().getFirst()); } - Pair<TreeMap<Pair<Integer, StoneColor>, Integer>, Integer> stoneCounts = AIUtil - .countStones(stones); + Pair<TreeMap<Pair<Integer, StoneColor>, Integer>, Integer> stoneCounts = countStones(stones); int pairCount = 0; |