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; private boolean turnDone = false; boolean useBackgroundThread = true; long startTime; @Override public void startTurn() { timer.startTimer(); startTime = System.currentTimeMillis(); compute(); } protected void timeOut() { executeTurn(); } @Override protected void cleanUp() { if (logic != null) logic.abort(); turnDone = true; super.cleanUp(); } private void emitEndOfTurn() { 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) { cleanUp(); endOfTurnEvent.emit(); } }); timer.setRepeats(false); timer.start(); } else { cleanUp(); endOfTurnEvent.emit(); } } private void compute() { switch (turnInfo.getTurnMode()) { case MAY_REDEAL: emitEndOfTurn(); break; case INSPECT_ONLY: emitEndOfTurn(); break; case NORMAL_TURN: turn(); break; } } private void turn() { List tableStones = new ArrayList(); List handStones = new ArrayList(); for (Pair entry : turnInfo.getHand()) { handStones.add(entry.getFirst()); } if (turnInfo.getLaidOut()) { for (Pair entry : turnInfo.getTable()) { for (Stone stone : entry.getFirst()) { tableStones.add(stone); } } } logic = new TurnLogic(settings, tableStones, handStones); if (!turnInfo.getLaidOut()) { logic.needIntialMeldThreshold(); } if (useBackgroundThread) { Timer timer = new Timer(10000, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { logic.autoAbort(); } }); timer.setRepeats(false); timer.start(); 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 executeTurn() { if (turnDone) { return; } List result = logic.getResult(); if (result != null) { if (turnInfo.getLaidOut()) { outerLoop: for (Iterator> it = turnInfo .getTable().iterator(); it.hasNext();) { Pair pair = it.next(); setSearch: for (Iterator 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(); } } 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); } } } emitEndOfTurn(); } /** * 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(); } }; } }