Implemented initial meld test using new AI
git-svn-id: svn://sunsvr01.isp.uni-luebeck.de/swproj13/trunk@441 72836036-5685-4462-b002-a69064685172
This commit is contained in:
parent
751d5a3aa9
commit
3ffad85972
6 changed files with 164 additions and 26 deletions
|
@ -32,11 +32,15 @@ public class TurnLogic {
|
||||||
private GameSettings settings;
|
private GameSettings settings;
|
||||||
private int stoneCount;
|
private int stoneCount;
|
||||||
private int maxSetSize;
|
private int maxSetSize;
|
||||||
|
private int maxHandPoints;
|
||||||
|
|
||||||
private Var<Boolean> trueVar;
|
private Var<Boolean> trueVar;
|
||||||
|
private Var<Integer> totalPoints;
|
||||||
|
|
||||||
private List<Var<Boolean>> onTable = new ArrayList<Var<Boolean>>();
|
private List<Var<Boolean>> onTable = new ArrayList<Var<Boolean>>();
|
||||||
|
|
||||||
|
private List<Var<Integer>> pointsValue = new ArrayList<Var<Integer>>();
|
||||||
|
|
||||||
private List<Var<Integer>> stoneValue = new ArrayList<Var<Integer>>();
|
private List<Var<Integer>> stoneValue = new ArrayList<Var<Integer>>();
|
||||||
private List<Var<Integer>> leftStoneValue = new ArrayList<Var<Integer>>();
|
private List<Var<Integer>> leftStoneValue = new ArrayList<Var<Integer>>();
|
||||||
private List<Var<Integer>> rightStoneValue = new ArrayList<Var<Integer>>();
|
private List<Var<Integer>> rightStoneValue = new ArrayList<Var<Integer>>();
|
||||||
|
@ -76,6 +80,7 @@ public class TurnLogic {
|
||||||
|
|
||||||
trueVar = solver.makeVar(true);
|
trueVar = solver.makeVar(true);
|
||||||
|
|
||||||
|
maxHandPoints = 0;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (Stone stone : tableStones) {
|
for (Stone stone : tableStones) {
|
||||||
addStone(i, true, stone);
|
addStone(i, true, stone);
|
||||||
|
@ -89,6 +94,19 @@ public class TurnLogic {
|
||||||
for (i = 0; i < stoneCount; i++) {
|
for (i = 0; i < stoneCount; i++) {
|
||||||
addConstraints(i);
|
addConstraints(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
totalPoints = solver.makeRangeVar(settings.getInitialMeldThreshold(),
|
||||||
|
maxHandPoints);
|
||||||
|
|
||||||
|
List<Var<Integer>> points = new ArrayList<Var<Integer>>();
|
||||||
|
|
||||||
|
for (Var<Integer> var : pointsValue) {
|
||||||
|
if (var != null) {
|
||||||
|
points.add(var);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
add(sum(totalPoints, points));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addStone(int i, boolean table, Stone stone) {
|
private void addStone(int i, boolean table, Stone stone) {
|
||||||
|
@ -100,9 +118,22 @@ public class TurnLogic {
|
||||||
isJoker.add(stone.isJoker());
|
isJoker.add(stone.isJoker());
|
||||||
if (stone.isJoker()) {
|
if (stone.isJoker()) {
|
||||||
stoneValue.add(solver.makeRangeVar(1, settings.getHighestValue()));
|
stoneValue.add(solver.makeRangeVar(1, settings.getHighestValue()));
|
||||||
|
if (table) {
|
||||||
|
pointsValue.add(null);
|
||||||
|
} else {
|
||||||
|
pointsValue.add(solver.makeRangeVar(0,
|
||||||
|
settings.getHighestValue()));
|
||||||
|
maxHandPoints += settings.getHighestValue();
|
||||||
|
}
|
||||||
stoneColor.add(solver.makeVar(settings.getStoneColors()));
|
stoneColor.add(solver.makeVar(settings.getStoneColors()));
|
||||||
} else {
|
} else {
|
||||||
stoneValue.add(solver.makeVar(stone.getValue()));
|
stoneValue.add(solver.makeVar(stone.getValue()));
|
||||||
|
if (table) {
|
||||||
|
pointsValue.add(null);
|
||||||
|
} else {
|
||||||
|
pointsValue.add(solver.makeVar(0, stone.getValue()));
|
||||||
|
maxHandPoints += stone.getValue();
|
||||||
|
}
|
||||||
stoneColor.add(solver.makeVar(stone.getColor()));
|
stoneColor.add(solver.makeVar(stone.getColor()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -282,6 +313,13 @@ public class TurnLogic {
|
||||||
add(unless(onTable.get(i),
|
add(unless(onTable.get(i),
|
||||||
constant(stoneColor.get(i), StoneColor.RED)));
|
constant(stoneColor.get(i), StoneColor.RED)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// initial meld points
|
||||||
|
if (pointsValue.get(i) != null) {
|
||||||
|
add(when(onTable.get(i),
|
||||||
|
same(stoneValue.get(i), pointsValue.get(i))));
|
||||||
|
add(unless(onTable.get(i), constant(pointsValue.get(i), 0)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean solve() {
|
public boolean solve() {
|
||||||
|
@ -342,10 +380,12 @@ public class TurnLogic {
|
||||||
System.out.print("["
|
System.out.print("["
|
||||||
+ stoneColor.get(i).getValue().toString().substring(0, 1)
|
+ stoneColor.get(i).getValue().toString().substring(0, 1)
|
||||||
+ stoneValue.get(i).getValue() + "]");
|
+ stoneValue.get(i).getValue() + "]");
|
||||||
// + "," + leftNeighbor.get(i).getValue() +
|
/*
|
||||||
// hasLeftNeighbor.get(i).getValue() + lowCount.get(i).getValue() + ","
|
* + "," + leftNeighbor.get(i).getValue() +
|
||||||
// + rightNeighbor.get(i).getValue() +
|
* hasLeftNeighbor.get(i).getValue() + lowCount.get(i).getValue() + ","
|
||||||
// hasRightNeighbor.get(i).getValue() + highCount.get(i).getValue() +
|
* + rightNeighbor.get(i).getValue() +
|
||||||
// "]");
|
* hasRightNeighbor.get(i).getValue() + highCount.get(i).getValue() +
|
||||||
|
* "]");
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import jrummikub.ai.fdsolver.constraint.FilterConstraint;
|
||||||
import jrummikub.ai.fdsolver.constraint.IfConstraint;
|
import jrummikub.ai.fdsolver.constraint.IfConstraint;
|
||||||
import jrummikub.ai.fdsolver.constraint.IndexConstraint;
|
import jrummikub.ai.fdsolver.constraint.IndexConstraint;
|
||||||
import jrummikub.ai.fdsolver.constraint.LessThan;
|
import jrummikub.ai.fdsolver.constraint.LessThan;
|
||||||
|
import jrummikub.ai.fdsolver.constraint.ListSumConstraint;
|
||||||
import jrummikub.ai.fdsolver.constraint.OffsetConstraint;
|
import jrummikub.ai.fdsolver.constraint.OffsetConstraint;
|
||||||
import jrummikub.ai.fdsolver.constraint.SameConstraint;
|
import jrummikub.ai.fdsolver.constraint.SameConstraint;
|
||||||
import jrummikub.ai.fdsolver.constraint.SumConstraint;
|
import jrummikub.ai.fdsolver.constraint.SumConstraint;
|
||||||
|
@ -46,6 +47,10 @@ public class Constraints {
|
||||||
return new SumConstraint(x, y, z);
|
return new SumConstraint(x, y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Constraint sum(Var<Integer> sum, List<Var<Integer>> list) {
|
||||||
|
return new ListSumConstraint(sum, list);
|
||||||
|
}
|
||||||
|
|
||||||
public static <T extends Comparable<T>> Constraint lessThan(Var<T> x, Var<T> y) {
|
public static <T extends Comparable<T>> Constraint lessThan(Var<T> x, Var<T> y) {
|
||||||
return new LessThan<T>(false, x, y);
|
return new LessThan<T>(false, x, y);
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,6 +42,9 @@ public class Var<T> implements Comparable<Var<T>> {
|
||||||
range.remove(value);
|
range.remove(value);
|
||||||
solver.logInvalidation(this, value);
|
solver.logInvalidation(this, value);
|
||||||
makeDirty();
|
makeDirty();
|
||||||
|
if (range.size() == 0) {
|
||||||
|
solver.contradiction = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HashSet<Constraint> getConstraints() {
|
HashSet<Constraint> getConstraints() {
|
||||||
|
|
91
src/jrummikub/ai/fdsolver/constraint/ListSumConstraint.java
Normal file
91
src/jrummikub/ai/fdsolver/constraint/ListSumConstraint.java
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
package jrummikub.ai.fdsolver.constraint;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import jrummikub.ai.fdsolver.Constraint;
|
||||||
|
import jrummikub.ai.fdsolver.Propagator;
|
||||||
|
import jrummikub.ai.fdsolver.Satisfiability;
|
||||||
|
import jrummikub.ai.fdsolver.Var;
|
||||||
|
|
||||||
|
public class ListSumConstraint extends Constraint {
|
||||||
|
Var<Integer> sum;
|
||||||
|
List<Var<Integer>> list;
|
||||||
|
List<Var<?>> vars = new ArrayList<Var<?>>();
|
||||||
|
|
||||||
|
public ListSumConstraint(Var<Integer> sum, List<Var<Integer>> list) {
|
||||||
|
this.sum = sum;
|
||||||
|
this.list = list;
|
||||||
|
vars.add(sum);
|
||||||
|
vars.addAll(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<Var<?>> getWatchedVars() {
|
||||||
|
return vars;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<Propagator> getPropagators(boolean negate) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Satisfiability getSatisfiability() {
|
||||||
|
List<Integer> values = new ArrayList<Integer>();
|
||||||
|
int valueSum = 0;
|
||||||
|
boolean isTaut = sum.getRange().size()==1;
|
||||||
|
for (Var<Integer> var : list) {
|
||||||
|
Iterator<Integer> it = var.getRange().iterator();
|
||||||
|
int value = it.next();
|
||||||
|
if (it.hasNext())
|
||||||
|
isTaut = false;
|
||||||
|
values.add(value);
|
||||||
|
valueSum += value;
|
||||||
|
}
|
||||||
|
if (isTaut) {
|
||||||
|
if (valueSum == sum.getValue()) {
|
||||||
|
return Satisfiability.TAUT;
|
||||||
|
} else {
|
||||||
|
return Satisfiability.UNSAT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<Integer> reachableValues = new HashSet<Integer>();
|
||||||
|
Set<Integer> newValues = new HashSet<Integer>();
|
||||||
|
reachableValues.add(valueSum);
|
||||||
|
|
||||||
|
if (sum.getRange().contains(valueSum)) {
|
||||||
|
return Satisfiability.SAT;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < values.size(); i++) {
|
||||||
|
Var<Integer> var = list.get(i);
|
||||||
|
int offset = values.get(i);
|
||||||
|
for (int x : var.getRange()) {
|
||||||
|
if (x == offset)
|
||||||
|
continue;
|
||||||
|
newValues.clear();
|
||||||
|
for (int y : reachableValues) {
|
||||||
|
int newValue = x + y - offset;
|
||||||
|
if (!reachableValues.contains(newValue)) {
|
||||||
|
newValues.add(x + y - offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!Collections.disjoint(sum.getRange(), newValues)) {
|
||||||
|
return Satisfiability.SAT;
|
||||||
|
}
|
||||||
|
reachableValues.addAll(newValues);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Satisfiability.UNSAT;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,12 +1,15 @@
|
||||||
package jrummikub.model;
|
package jrummikub.model;
|
||||||
|
|
||||||
import static jrummikub.model.StoneTray.Direction.*;
|
import static jrummikub.model.StoneTray.Direction.LEFT;
|
||||||
|
import static jrummikub.model.StoneTray.Direction.RIGHT;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
|
|
||||||
|
import jrummikub.ai.TurnLogic;
|
||||||
import jrummikub.control.AIUtil;
|
import jrummikub.control.AIUtil;
|
||||||
import jrummikub.util.Pair;
|
import jrummikub.util.Pair;
|
||||||
|
|
||||||
|
@ -44,8 +47,8 @@ public class Hand extends StoneTray<Stone> implements IHand {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Pair<Position, Direction> fixInvalidDrop(Stone stone, Position pos,
|
protected Pair<Position, Direction> fixInvalidDrop(Stone stone,
|
||||||
Direction dir) {
|
Position pos, Direction dir) {
|
||||||
double x = pos.getX();
|
double x = pos.getX();
|
||||||
double y = pos.getY();
|
double y = pos.getY();
|
||||||
|
|
||||||
|
@ -56,9 +59,11 @@ public class Hand extends StoneTray<Stone> implements IHand {
|
||||||
return new Pair<Position, Direction>(new Position(0, y), RIGHT);
|
return new Pair<Position, Direction>(new Position(0, y), RIGHT);
|
||||||
} else {
|
} else {
|
||||||
if (getFreeRowSpace((int) y) == 0) {
|
if (getFreeRowSpace((int) y) == 0) {
|
||||||
return new Pair<Position, Direction>(new Position(0, y + 1), RIGHT);
|
return new Pair<Position, Direction>(new Position(0, y + 1),
|
||||||
|
RIGHT);
|
||||||
} else {
|
} else {
|
||||||
return new Pair<Position, Direction>(new Position(WIDTH - 1, y), LEFT);
|
return new Pair<Position, Direction>(
|
||||||
|
new Position(WIDTH - 1, y), LEFT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -80,29 +85,23 @@ public class Hand extends StoneTray<Stone> implements IHand {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isInitialMeldPossible(GameSettings settings) {
|
public boolean isInitialMeldPossible(GameSettings settings) {
|
||||||
AIUtil aiUtil = new AIUtil(settings);
|
List<Stone> handStones = new ArrayList<Stone>();
|
||||||
|
|
||||||
List<Stone> stones = new ArrayList<Stone>();
|
for (Pair<Stone, Position> entry : this) {
|
||||||
|
handStones.add(entry.getFirst());
|
||||||
for (Iterator<Pair<Stone, Position>> iter = this.iterator(); iter.hasNext();) {
|
|
||||||
stones.add(iter.next().getFirst());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Pair<TreeMap<Pair<Integer, StoneColor>, Integer>, Integer> stoneCounts = AIUtil
|
TurnLogic turnLogic = new TurnLogic(settings,
|
||||||
.countStones(stones);
|
Collections.<Stone> emptyList(), handStones);
|
||||||
|
return turnLogic.solve();
|
||||||
Pair<List<StoneSet>, Integer> result = aiUtil.findSetsWithTotalPoints(
|
|
||||||
settings.getInitialMeldThreshold(), stoneCounts.getFirst(),
|
|
||||||
stoneCounts.getSecond());
|
|
||||||
|
|
||||||
return (result.getSecond() >= settings.getInitialMeldThreshold());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getIdenticalStoneCount() {
|
public int getIdenticalStoneCount() {
|
||||||
List<Stone> stones = new ArrayList<Stone>();
|
List<Stone> stones = new ArrayList<Stone>();
|
||||||
|
|
||||||
for (Iterator<Pair<Stone, Position>> iter = this.iterator(); iter.hasNext();) {
|
for (Iterator<Pair<Stone, Position>> iter = this.iterator(); iter
|
||||||
|
.hasNext();) {
|
||||||
stones.add(iter.next().getFirst());
|
stones.add(iter.next().getFirst());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -221,7 +221,7 @@ public class HandTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** */
|
/** */
|
||||||
@Test
|
@Test(timeout = 1000)
|
||||||
public void testValidHuge() {
|
public void testValidHuge() {
|
||||||
List<Stone> stones = new ArrayList<Stone>();
|
List<Stone> stones = new ArrayList<Stone>();
|
||||||
for (int i = 1; i <= 10; i++) {
|
for (int i = 1; i <= 10; i++) {
|
||||||
|
@ -232,7 +232,7 @@ public class HandTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** */
|
/** */
|
||||||
@Test
|
@Test(timeout = 1000)
|
||||||
public void testInvalidHuge() {
|
public void testInvalidHuge() {
|
||||||
testInitialMeld(false, Arrays.asList(new Stone(1, RED), new Stone(2, RED),
|
testInitialMeld(false, Arrays.asList(new Stone(1, RED), new Stone(2, RED),
|
||||||
new Stone(4, RED), new Stone(6, RED), new Stone(8, RED), new Stone(10,
|
new Stone(4, RED), new Stone(6, RED), new Stone(8, RED), new Stone(10,
|
||||||
|
|
Reference in a new issue