This repository has been archived on 2025-03-02. You can view files and clone it, but cannot push or open issues or pull requests.
JRummikub/src/jrummikub/control/turn/AIControl.java
Bennet Gerlach 8c6bf9781f The AI now is only computing its turn for a reasonable amount of time
git-svn-id: svn://sunsvr01.isp.uni-luebeck.de/swproj13/trunk@562 72836036-5685-4462-b002-a69064685172
2011-06-22 00:38:28 +02:00

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();
}
};
}
}