diff options
Diffstat (limited to 'src/jrummikub/control')
-rw-r--r-- | src/jrummikub/control/RoundControl.java | 120 | ||||
-rw-r--r-- | src/jrummikub/control/network/ConnectionControl.java | 69 | ||||
-rw-r--r-- | src/jrummikub/control/network/IConnectionControl.java | 14 | ||||
-rw-r--r-- | src/jrummikub/control/network/NetworkRoundControl.java | 55 | ||||
-rw-r--r-- | src/jrummikub/control/network/NetworkTurnControl.java | 53 | ||||
-rw-r--r-- | src/jrummikub/control/turn/AIControl.java | 6 | ||||
-rw-r--r-- | src/jrummikub/control/turn/AbstractTurnControl.java | 19 | ||||
-rw-r--r-- | src/jrummikub/control/turn/HumanTurnControl.java | 4 | ||||
-rw-r--r-- | src/jrummikub/control/turn/ITurnControl.java | 2 |
9 files changed, 277 insertions, 65 deletions
diff --git a/src/jrummikub/control/RoundControl.java b/src/jrummikub/control/RoundControl.java index d8435af..a19a2ab 100644 --- a/src/jrummikub/control/RoundControl.java +++ b/src/jrummikub/control/RoundControl.java @@ -8,6 +8,8 @@ import java.util.HashSet; import java.util.List; import java.util.Set; +import jrummikub.control.turn.AIControl; +import jrummikub.control.turn.HumanTurnControl; import jrummikub.control.turn.ITurnControl; import jrummikub.control.turn.TurnControlFactory; import jrummikub.control.turn.TurnMode; @@ -16,6 +18,7 @@ import jrummikub.model.IHand; import jrummikub.model.IPlayer; import jrummikub.model.IRoundState; import jrummikub.model.ITable; +import jrummikub.model.PlayerSettings; import jrummikub.model.Position; import jrummikub.model.Score; import jrummikub.model.Stone; @@ -35,15 +38,15 @@ import jrummikub.view.IView.BottomPanelType; * Controller that manages a single round of rummikub */ public class RoundControl { - IRoundState roundState; + private ITurnControl turnControl; + protected IRoundState roundState; private IView view; private ITable clonedTable; IHand clonedHand; private Event restartRoundEvent = new Event(); + private Event1<IRoundState> roundStateUpdateEvent = new Event1<IRoundState>(); private Event1<Score> endOfRoundEvent = new Event1<Score>(); - private Event1<ITable> tableUpdateEvent = new Event1<ITable>(); - private List<Connection> connections = new ArrayList<Connection>(); - private ITurnControl turnControl; + protected List<Connection> connections = new ArrayList<Connection>(); private boolean roundFinished; private boolean lastTurnNotEnoughPoints; private boolean lastTurnMeldError; @@ -61,6 +64,10 @@ public class RoundControl { this.view = view; } + public IEvent1<IRoundState> getRoundStateUpdateEvent() { + return roundStateUpdateEvent; + } + /** * End the round * @@ -70,10 +77,6 @@ public class RoundControl { return endOfRoundEvent; } - public IEvent1<ITable> getTableUpdateEvent() { - return tableUpdateEvent; - } - /** * Begin the round */ @@ -122,16 +125,11 @@ public class RoundControl { clonedTable = (ITable) roundState.getTable().clone(); clonedHand = (IHand) roundState.getActivePlayer().getHand().clone(); - if (!oneHuman) { - view.setBottomPanel(isHuman ? BottomPanelType.START_TURN_PANEL - : BottomPanelType.COMPUTER_HAND_PANEL); + if (isHuman) { + view.setBottomPanel(oneHuman ? BottomPanelType.HUMAN_HAND_PANEL + : BottomPanelType.START_TURN_PANEL); } else { - if (!isHuman) { - view.setBottomPanel(BottomPanelType.COMPUTER_HAND_PANEL); - } else { - view.setBottomPanel(BottomPanelType.HUMAN_HAND_PANEL); - startTurn(); - } + view.setBottomPanel(BottomPanelType.NONHUMAN_HAND_PANEL); } view.getTablePanel().setStoneSets(clonedTable.clone()); @@ -141,13 +139,17 @@ public class RoundControl { .getColor()); view.setCurrentPlayerHasLaidOut(roundState.getActivePlayer().getLaidOut()); - if (!isHuman) + turnControl = createTurnControl(roundState.getActivePlayer() + .getPlayerSettings()); + + boolean isAI = (turnControl instanceof AIControl); + + if (isAI || (isHuman && oneHuman)) { startTurn(); + } } - private void startTurn() { - if (turnControl != null) - return; + protected void startTurn() { boolean isHuman = roundState.getActivePlayer().getPlayerSettings() .getType() == HUMAN; @@ -164,34 +166,35 @@ public class RoundControl { if (isHuman) { view.getPlayerPanel().setEndTurnMode(turnMode); } - turnControl = TurnControlFactory.getFactory( - roundState.getActivePlayer().getPlayerSettings().getType()).create(); + turnControl.setup(new ITurnControl.TurnInfo(clonedTable, clonedHand, roundState.getActivePlayer().getLaidOut(), turnMode), roundState .getGameSettings(), view); - turnControl.getEndOfTurnEvent().add(new IListener() { + turnControl.getEndOfTurnEvent().add(new IListener1<ITable>() { @Override - public void handle() { - endOfTurn(); + public void handle(ITable newTable) { + endOfTurn(newTable); } }); - - turnControl.getTableUpdateEvent().add(new IListener1<ITable>() { - @Override - public void handle(ITable table) { - tableUpdateEvent.emit(table); - } - }); - turnControl.getRedealEvent().add(new IListener() { @Override public void handle() { redeal(); } }); + addTurnControlListeners(turnControl); + turnControl.startTurn(); } + /** Override this */ + protected void addTurnControlListeners(ITurnControl turnControl) { + } + + protected ITurnControl createTurnControl(PlayerSettings playerSettings) { + return TurnControlFactory.getFactory(playerSettings.getType()).create(); + } + void deal() { for (int i = 0; i < roundState.getPlayerCount(); i++) { IHand hand = roundState.getNthNextPlayer(i).getHand(); @@ -214,37 +217,44 @@ public class RoundControl { || totalValue >= roundState.getGameSettings().getInitialMeldThreshold(); } - private void endOfTurn() { + private void endOfTurn(ITable newTable) { + boolean wasHuman = (turnControl instanceof HumanTurnControl); + boolean wasAI = (turnControl instanceof AIControl); + turnControl = null; + roundState.getActivePlayer().setHand(clonedHand); boolean goToNextPlayer = true; lastTurnNotEnoughPoints = false; lastTurnMeldError = false; if (roundState.getTurnNumber() >= 1) { - goToNextPlayer = checkTurn(); + goToNextPlayer = checkTurn(newTable); } - if (goToNextPlayer) { + if (goToNextPlayer || wasAI) { nextPlayer(); } else { - view.setBottomPanel(BottomPanelType.INVALID_TURN_PANEL); + if (wasHuman) { + view.setBottomPanel(BottomPanelType.INVALID_TURN_PANEL); + } + if (lastTurnNotEnoughPoints) { view.setInitialMeldError(roundState.getGameSettings() .getInitialMeldThreshold()); view.setInvalidStoneSets(tableSetDifference(roundState.getTable(), - clonedTable)); + newTable)); } else if (lastTurnMeldError) { view.setInitialMeldFirstError(); - view.setInvalidStoneSets(touchedStoneSets()); + view.setInvalidStoneSets(touchedStoneSets(newTable)); } else { view.setStoneCollectionHidden(true); - view.setInvalidStoneSets(invalidStoneSets()); + view.setInvalidStoneSets(invalidStoneSets(newTable)); } } } - private List<StoneSet> invalidStoneSets() { + private List<StoneSet> invalidStoneSets(ITable newTable) { List<StoneSet> invalidSets = new ArrayList<StoneSet>(); - for (Pair<StoneSet, Position> set : clonedTable) { + for (Pair<StoneSet, Position> set : newTable) { if (set.getFirst().isValid(roundState.getGameSettings())) { continue; } @@ -253,9 +263,9 @@ public class RoundControl { return invalidSets; } - private List<StoneSet> touchedStoneSets() { + private List<StoneSet> touchedStoneSets(ITable newTable) { List<StoneSet> touchedSets = new ArrayList<StoneSet>(); - for (StoneSet set : tableSetDifference(roundState.getTable(), clonedTable)) { + for (StoneSet set : tableSetDifference(roundState.getTable(), newTable)) { for (Stone stone : set) { if (!roundState.getActivePlayer().getHand().contains(stone)) { touchedSets.add(set); @@ -293,27 +303,27 @@ public class RoundControl { } } - private boolean checkTurn() { - if (!clonedTable.isValid()) { - rejectMove(); + private boolean checkTurn(ITable newTable) { + if (!newTable.isValid()) { + rejectMove(newTable); return false; } if (!roundState.getActivePlayer().getLaidOut()) { // Player touched forbidden stones - if (!tableSetDifference(clonedTable, roundState.getTable()).isEmpty()) { - rejectMove(); + if (!tableSetDifference(newTable, roundState.getTable()).isEmpty()) { + rejectMove(newTable); lastTurnMeldError = true; return false; } if (!laidOutValidPoints()) { - rejectMove(); + rejectMove(newTable); lastTurnNotEnoughPoints = true; return false; } } - Set<Stone> tableDiff = tableDifference(roundState.getTable(), clonedTable); + Set<Stone> tableDiff = tableDifference(roundState.getTable(), newTable); - roundState.setTable(clonedTable); + roundState.setTable(newTable); if (tableDiff.isEmpty()) { // Player hasn't made a move @@ -327,8 +337,8 @@ public class RoundControl { return true; } - private void rejectMove() { - Set<Stone> tableDiff = tableDifference(roundState.getTable(), clonedTable); + private void rejectMove(ITable newTable) { + Set<Stone> tableDiff = tableDifference(roundState.getTable(), newTable); // deal penalty, reset roundState.getGameHeap().putBack(tableDiff); dealPenalty(tableDiff.size()); diff --git a/src/jrummikub/control/network/ConnectionControl.java b/src/jrummikub/control/network/ConnectionControl.java index 0a36ebd..acccbdc 100644 --- a/src/jrummikub/control/network/ConnectionControl.java +++ b/src/jrummikub/control/network/ConnectionControl.java @@ -6,6 +6,8 @@ import java.util.UUID; import javax.swing.SwingUtilities; import jrummikub.model.GameSettings; +import jrummikub.model.IRoundState; +import jrummikub.model.ITable; import jrummikub.util.Event; import jrummikub.util.Event1; import jrummikub.util.Event2; @@ -58,6 +60,10 @@ public class ConnectionControl implements IConnectionControl { private Event gameStartEvent = new Event(); + private Event1<ITable> tableUpdateEvent = new Event1<ITable>(); + private Event1<ITable> turnEndEvent = new Event1<ITable>(); + private Event1<IRoundState> turnStartEvent = new Event1<IRoundState>(); + private GameData currentGame; private volatile GameData offeredGame; @@ -145,6 +151,21 @@ public class ConnectionControl implements IConnectionControl { } @Override + public IEvent1<ITable> getTableUpdateEvent() { + return tableUpdateEvent; + } + + @Override + public IEvent1<ITable> getTurnEndEvent() { + return turnEndEvent; + } + + @Override + public IEvent1<IRoundState> getTurnStartEvent() { + return turnStartEvent; + } + + @Override public void offerGame(GameData data) { offeredGame = data; currentGame = data; @@ -235,7 +256,6 @@ public class ConnectionControl implements IConnectionControl { Base64.encodeObject(color, Base64.GZIP)); } }); - } @Override @@ -248,7 +268,45 @@ public class ConnectionControl implements IConnectionControl { extension.setValue("uuid", uuid.toString()); } }); + } + + @Override + public void updateTable(final ITable table) { + final UUID uuid = currentGame.getGameID(); + run(new SendRunner() { + @Override + protected void addData(DefaultPacketExtension extension) { + extension.setValue("messageType", "table_update"); + extension.setValue("uuid", uuid.toString()); + extension.setValue("table", Base64.encodeObject(table, Base64.GZIP)); + } + }); + } + + @Override + public void endTurn(final ITable table) { + final UUID uuid = currentGame.getGameID(); + run(new SendRunner() { + @Override + protected void addData(DefaultPacketExtension extension) { + extension.setValue("messageType", "turn_end"); + extension.setValue("uuid", uuid.toString()); + extension.setValue("table", Base64.encodeObject(table, Base64.GZIP)); + } + }); + } + @Override + public void startTurn(final IRoundState state) { + final UUID uuid = currentGame.getGameID(); + run(new SendRunner() { + @Override + protected void addData(DefaultPacketExtension extension) { + extension.setValue("messageType", "turn_start"); + extension.setValue("uuid", uuid.toString()); + extension.setValue("state", Base64.encodeObject(state, Base64.GZIP)); + } + }); } private void sendGameOffer() { @@ -348,6 +406,15 @@ public class ConnectionControl implements IConnectionControl { (Color) Base64.decodeToObject(extension.getValue("color"))); } else if (messageType.equals("game_start")) { gameStartEvent.emit(); + } else if (messageType.equals("table_update")) { + tableUpdateEvent.emit((ITable) Base64.decodeToObject(extension + .getValue("table"))); + } else if (messageType.equals("turn_end")) { + turnEndEvent.emit((ITable) Base64.decodeToObject(extension + .getValue("table"))); + } else if (messageType.equals("turn_start")) { + turnStartEvent.emit((IRoundState) Base64.decodeToObject(extension + .getValue("state"))); } else { System.err.println("Received unrecognized message of type '" + messageType + "'"); diff --git a/src/jrummikub/control/network/IConnectionControl.java b/src/jrummikub/control/network/IConnectionControl.java index feacf19..b329b4c 100644 --- a/src/jrummikub/control/network/IConnectionControl.java +++ b/src/jrummikub/control/network/IConnectionControl.java @@ -3,6 +3,8 @@ package jrummikub.control.network; import java.awt.Color; import java.util.UUID; +import jrummikub.model.IRoundState; +import jrummikub.model.ITable; import jrummikub.util.GameData; import jrummikub.util.IEvent; import jrummikub.util.IEvent1; @@ -34,6 +36,12 @@ interface IConnectionControl { public IEvent getGameStartEvent(); + public IEvent1<ITable> getTableUpdateEvent(); + + public IEvent1<ITable> getTurnEndEvent(); + + public IEvent1<IRoundState> getTurnStartEvent(); + public void offerGame(GameData data); public void withdrawGame(); @@ -52,4 +60,10 @@ interface IConnectionControl { public void startGame(); + public void updateTable(ITable table); + + public void endTurn(ITable table); + + public void startTurn(IRoundState state); + }
\ No newline at end of file diff --git a/src/jrummikub/control/network/NetworkRoundControl.java b/src/jrummikub/control/network/NetworkRoundControl.java new file mode 100644 index 0000000..d7de9ea --- /dev/null +++ b/src/jrummikub/control/network/NetworkRoundControl.java @@ -0,0 +1,55 @@ +package jrummikub.control.network; + +import jrummikub.control.RoundControl; +import jrummikub.control.turn.ITurnControl; +import jrummikub.model.IRoundState; +import jrummikub.model.ITable; +import jrummikub.model.PlayerSettings; +import jrummikub.util.IListener1; +import jrummikub.view.IView; + +public class NetworkRoundControl extends RoundControl { + private IConnectionControl connectionControl; + private boolean currentlyActive; + + public NetworkRoundControl(IRoundState roundState, IView view, IConnectionControl connectionControl, boolean startActive) { + super(roundState, view); + + this.connectionControl = connectionControl; + currentlyActive = startActive; + } + + @Override + protected void addTurnControlListeners(ITurnControl turnControl) { + turnControl.getTableUpdateEvent().add(new IListener1<ITable>() { + @Override + public void handle(ITable table) { + connectionControl.updateTable(table); + } + }); + } + + @Override + protected ITurnControl createTurnControl(PlayerSettings playerSettings) { + switch (playerSettings.getType()) { + case HUMAN: + currentlyActive = true; + break; + case NETWORK: + currentlyActive = false; + break; + } + + if (!currentlyActive) { + return new NetworkTurnControl(connectionControl); + } + + return super.createTurnControl(playerSettings); + } + + @Override + protected void startTurn() { + connectionControl.startTurn(roundState); + super.startTurn(); + } +} diff --git a/src/jrummikub/control/network/NetworkTurnControl.java b/src/jrummikub/control/network/NetworkTurnControl.java new file mode 100644 index 0000000..d80c9b3 --- /dev/null +++ b/src/jrummikub/control/network/NetworkTurnControl.java @@ -0,0 +1,53 @@ +package jrummikub.control.network; + +import jrummikub.control.turn.AbstractTurnControl; +import jrummikub.model.IRoundState; +import jrummikub.model.ITable; +import jrummikub.util.Event1; +import jrummikub.util.IEvent1; +import jrummikub.util.IListener1; + +public class NetworkTurnControl extends AbstractTurnControl { + private IConnectionControl connectionControl; + private Event1<IRoundState> stateUpdateEvent = new Event1<IRoundState>(); + + + public NetworkTurnControl(IConnectionControl connectionControl) { + this.connectionControl = connectionControl; + } + + public IEvent1<IRoundState> getStateUpdateEvent() { + return stateUpdateEvent; + } + + @Override + public void doStartTurn() { + connections.add(connectionControl.getTableUpdateEvent().add(new IListener1<ITable>() { + @Override + public void handle(ITable table) { + view.getTablePanel().setStoneSets(table); + } + })); + connections.add(connectionControl.getTurnEndEvent().add(new IListener1<ITable>() { + @Override + public void handle(ITable table) { + endOfTurn(table); + } + })); + + timer.startTimer(); + } + + private void endOfTurn(ITable newTable) { + cleanUp(); + endOfTurnEvent.emit(newTable); + } + + @Override + protected void timeOut() { + } + + @Override + protected void pauseTurn() { + } +} diff --git a/src/jrummikub/control/turn/AIControl.java b/src/jrummikub/control/turn/AIControl.java index b69d72b..ba222ea 100644 --- a/src/jrummikub/control/turn/AIControl.java +++ b/src/jrummikub/control/turn/AIControl.java @@ -21,7 +21,7 @@ import jrummikub.util.Pair; */ public class AIControl extends AbstractTurnControl { private TurnLogic logic; - boolean useBackgroundThread = true; + public static boolean useBackgroundThread = true; long startTime; private boolean isPaused = false; @@ -30,7 +30,7 @@ public class AIControl extends AbstractTurnControl { private boolean aborted = false; @Override - public void startTurn() { + protected void doStartTurn() { timer.startTimer(); startTime = System.currentTimeMillis(); compute(); @@ -221,7 +221,7 @@ public class AIControl extends AbstractTurnControl { return; } cleanUp(); - endOfTurnEvent.emit(); + endOfTurnEvent.emit(turnInfo.getTable()); } /** diff --git a/src/jrummikub/control/turn/AbstractTurnControl.java b/src/jrummikub/control/turn/AbstractTurnControl.java index fd88370..f129f24 100644 --- a/src/jrummikub/control/turn/AbstractTurnControl.java +++ b/src/jrummikub/control/turn/AbstractTurnControl.java @@ -19,7 +19,7 @@ import jrummikub.view.IView; * Abstract base class for TurnControls */ public abstract class AbstractTurnControl implements ITurnControl { - protected Event endOfTurnEvent = new Event(); + protected Event1<ITable> endOfTurnEvent = new Event1<ITable>(); protected Event redealEvent = new Event(); protected Event1<ITable> tableUpdateEvent = new Event1<ITable>(); protected TurnInfo turnInfo; @@ -27,9 +27,10 @@ public abstract class AbstractTurnControl implements ITurnControl { protected IView view; protected ITurnTimer timer; protected List<Connection> connections = new ArrayList<Connection>(); + private boolean started = false; @Override - public IEvent getEndOfTurnEvent() { + public IEvent1<ITable> getEndOfTurnEvent() { return endOfTurnEvent; } @@ -37,7 +38,7 @@ public abstract class AbstractTurnControl implements ITurnControl { public IEvent getRedealEvent() { return redealEvent; } - + @Override public IEvent1<ITable> getTableUpdateEvent() { return tableUpdateEvent; @@ -53,6 +54,18 @@ public abstract class AbstractTurnControl implements ITurnControl { view.enablePauseMode(false); } + @Override + public void startTurn() { + if (started) { + return; + } + + started = true; + doStartTurn(); + } + + protected abstract void doStartTurn(); + protected abstract void timeOut(); @Override diff --git a/src/jrummikub/control/turn/HumanTurnControl.java b/src/jrummikub/control/turn/HumanTurnControl.java index 3efad2f..51f77e4 100644 --- a/src/jrummikub/control/turn/HumanTurnControl.java +++ b/src/jrummikub/control/turn/HumanTurnControl.java @@ -54,7 +54,7 @@ public class HumanTurnControl extends AbstractTurnControl { } @Override - public void startTurn() { + public void doStartTurn() { addButtonHandlers(); addHandPanelHandlers(); @@ -449,7 +449,7 @@ public class HumanTurnControl extends AbstractTurnControl { if (redeal) { redealEvent.emit(); } else { - endOfTurnEvent.emit(); + endOfTurnEvent.emit(turnInfo.getTable()); } } diff --git a/src/jrummikub/control/turn/ITurnControl.java b/src/jrummikub/control/turn/ITurnControl.java index 0039a42..1860d69 100644 --- a/src/jrummikub/control/turn/ITurnControl.java +++ b/src/jrummikub/control/turn/ITurnControl.java @@ -30,7 +30,7 @@ public interface ITurnControl { * * @return end of turn event */ - public IEvent getEndOfTurnEvent(); + public IEvent1<ITable> getEndOfTurnEvent(); /** * Emitted when the round is aborted and needs to be restarted |