
git-svn-id: svn://sunsvr01.isp.uni-luebeck.de/swproj13/trunk@562 72836036-5685-4462-b002-a69064685172
259 lines
5.1 KiB
Java
259 lines
5.1 KiB
Java
package jrummikub.control.turn;
|
|
|
|
import java.awt.event.ActionEvent;
|
|
import java.awt.event.ActionListener;
|
|
import java.util.ArrayList;
|
|
import java.util.Iterator;
|
|
import java.util.List;
|
|
|
|
import javax.swing.SwingUtilities;
|
|
import javax.swing.Timer;
|
|
|
|
import jrummikub.ai.TurnLogic;
|
|
import jrummikub.model.Position;
|
|
import jrummikub.model.Stone;
|
|
import jrummikub.model.StoneSet;
|
|
import jrummikub.util.Pair;
|
|
|
|
/**
|
|
* Base class for AI players
|
|
*
|
|
*/
|
|
public class AIControl extends AbstractTurnControl {
|
|
private TurnLogic logic;
|
|
/**
|
|
* Does the AI control currently use an internal timer
|
|
*/
|
|
public static boolean useBackgroundThread = true;
|
|
long startTime;
|
|
|
|
private boolean isPaused = false;
|
|
private boolean turnDone = false;
|
|
private boolean readyToEmit = false;
|
|
private boolean aborted = false;
|
|
|
|
@Override
|
|
protected void doStartTurn() {
|
|
timer.startTimer();
|
|
startTime = System.currentTimeMillis();
|
|
compute();
|
|
}
|
|
|
|
@Override
|
|
protected void timeOut() {
|
|
executeTurn();
|
|
}
|
|
|
|
@Override
|
|
protected void pauseTurn() {
|
|
super.pauseTurn();
|
|
isPaused = true;
|
|
}
|
|
|
|
@Override
|
|
protected void resumeTurn() {
|
|
super.resumeTurn();
|
|
isPaused = false;
|
|
if (readyToEmit) {
|
|
emitEndOfTurn();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void cleanUp() {
|
|
if (logic != null)
|
|
logic.abort();
|
|
turnDone = true;
|
|
super.cleanUp();
|
|
}
|
|
|
|
@Override
|
|
public void abortTurn() {
|
|
aborted = true;
|
|
super.abortTurn();
|
|
}
|
|
|
|
private void compute() {
|
|
switch (turnInfo.getTurnMode()) {
|
|
case MAY_REDEAL:
|
|
endTurn();
|
|
break;
|
|
case INSPECT_ONLY:
|
|
endTurn();
|
|
break;
|
|
case NORMAL_TURN:
|
|
turn();
|
|
break;
|
|
}
|
|
}
|
|
|
|
private void turn() {
|
|
List<Stone> tableStones = new ArrayList<Stone>();
|
|
List<Stone> handStones = new ArrayList<Stone>();
|
|
|
|
addHandStones(handStones);
|
|
|
|
addTableStones(tableStones);
|
|
|
|
logic = new TurnLogic(settings, tableStones, handStones);
|
|
|
|
if (!turnInfo.getLaidOut()) {
|
|
logic.needIntialMeldThreshold();
|
|
}
|
|
if (useBackgroundThread) {
|
|
|
|
startTimers();
|
|
|
|
Thread computeThread = new Thread(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
logic.optimize();
|
|
SwingUtilities.invokeLater(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
executeTurn();
|
|
}
|
|
});
|
|
}
|
|
});
|
|
computeThread.start();
|
|
} else {
|
|
logic.optimize();
|
|
executeTurn();
|
|
}
|
|
|
|
}
|
|
|
|
private void startTimers() {
|
|
Timer timer = new Timer(10000, new ActionListener() {
|
|
@Override
|
|
public void actionPerformed(ActionEvent e) {
|
|
logic.autoAbort();
|
|
}
|
|
});
|
|
timer.setRepeats(false);
|
|
timer.start();
|
|
|
|
timer = new Timer((int) (turnInfo.getRoundState().getGameSettings()
|
|
.getTotalTime() * 1000 * (0.5 + 0.25 * Math.random())),
|
|
new ActionListener() {
|
|
@Override
|
|
public void actionPerformed(ActionEvent e) {
|
|
executeTurn();
|
|
}
|
|
});
|
|
timer.setRepeats(false);
|
|
timer.start();
|
|
}
|
|
|
|
private void addHandStones(List<Stone> handStones) {
|
|
for (Pair<Stone, Position> entry : turnInfo.getHand()) {
|
|
handStones.add(entry.getFirst());
|
|
}
|
|
}
|
|
|
|
private void addTableStones(List<Stone> tableStones) {
|
|
if (turnInfo.getLaidOut()) {
|
|
for (Pair<StoneSet, Position> entry : turnInfo.getTable()) {
|
|
for (Stone stone : entry.getFirst()) {
|
|
tableStones.add(stone);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void executeTurn() {
|
|
if (turnDone) {
|
|
return;
|
|
}
|
|
|
|
List<StoneSet> result = logic.getResult();
|
|
|
|
if (result != null) {
|
|
|
|
if (turnInfo.getLaidOut()) {
|
|
doNotMoveExistingSets(result);
|
|
}
|
|
|
|
for (StoneSet set : result) {
|
|
turnInfo.getTable().drop(
|
|
set,
|
|
new Position(10 * (Math.random() * 2 - 1),
|
|
5 * (Math.random() * 2 - 1)));
|
|
for (Stone stone : set) {
|
|
turnInfo.getHand().pickUp(stone);
|
|
}
|
|
}
|
|
}
|
|
|
|
endTurn();
|
|
}
|
|
|
|
private void doNotMoveExistingSets(List<StoneSet> result) {
|
|
|
|
outerLoop: for (Iterator<Pair<StoneSet, Position>> it = turnInfo.getTable()
|
|
.iterator(); it.hasNext();) {
|
|
Pair<StoneSet, Position> pair = it.next();
|
|
setSearch: for (Iterator<StoneSet> it2 = result.iterator(); it2.hasNext();) {
|
|
StoneSet set = it2.next();
|
|
if (set.getSize() != pair.getFirst().getSize()) {
|
|
continue;
|
|
}
|
|
for (int i = 0; i < set.getSize(); i++) {
|
|
if (set.get(i) != pair.getFirst().get(i)) {
|
|
continue setSearch;
|
|
}
|
|
}
|
|
it2.remove();
|
|
continue outerLoop;
|
|
}
|
|
it.remove();
|
|
}
|
|
}
|
|
|
|
private void endTurn() {
|
|
turnDone = true;
|
|
|
|
long turnLength = System.currentTimeMillis() - startTime;
|
|
|
|
if (useBackgroundThread) {
|
|
Timer timer = new Timer(Math.max(0,
|
|
(int) (1000 + Math.random() * 2000 - turnLength)),
|
|
new ActionListener() {
|
|
@Override
|
|
public void actionPerformed(ActionEvent event) {
|
|
emitEndOfTurn();
|
|
}
|
|
});
|
|
timer.setRepeats(false);
|
|
timer.start();
|
|
} else {
|
|
emitEndOfTurn();
|
|
}
|
|
|
|
}
|
|
|
|
private void emitEndOfTurn() {
|
|
readyToEmit = true;
|
|
if (isPaused || aborted) {
|
|
return;
|
|
}
|
|
cleanUp();
|
|
endOfTurnEvent.emit(turnInfo.getRoundState(), checkTurn());
|
|
}
|
|
|
|
/**
|
|
* Get the factory for the base AI control
|
|
*
|
|
* @return the factory
|
|
*/
|
|
static public TurnControlFactory getFactory() {
|
|
return new TurnControlFactory() {
|
|
@Override
|
|
public ITurnControl create() {
|
|
return new AIControl();
|
|
}
|
|
};
|
|
}
|
|
|
|
}
|