From 45656861ab2e618938764f0c46f830184099a71d Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Sun, 19 Jun 2011 19:46:06 +0200 Subject: Added NetworkRoundControlTest and started NetworkRoundControl and NetworkTurnControl implementation git-svn-id: svn://sunsvr01.isp.uni-luebeck.de/swproj13/trunk@491 72836036-5685-4462-b002-a69064685172 --- src/jrummikub/control/RoundControl.java | 120 +++++++++++---------- .../control/network/ConnectionControl.java | 69 +++++++++++- .../control/network/IConnectionControl.java | 14 +++ .../control/network/NetworkRoundControl.java | 55 ++++++++++ .../control/network/NetworkTurnControl.java | 53 +++++++++ src/jrummikub/control/turn/AIControl.java | 6 +- .../control/turn/AbstractTurnControl.java | 19 +++- src/jrummikub/control/turn/HumanTurnControl.java | 4 +- src/jrummikub/control/turn/ITurnControl.java | 2 +- 9 files changed, 277 insertions(+), 65 deletions(-) create mode 100644 src/jrummikub/control/network/NetworkRoundControl.java create mode 100644 src/jrummikub/control/network/NetworkTurnControl.java (limited to 'src/jrummikub/control') 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 roundStateUpdateEvent = new Event1(); private Event1 endOfRoundEvent = new Event1(); - private Event1 tableUpdateEvent = new Event1(); - private List connections = new ArrayList(); - private ITurnControl turnControl; + protected List connections = new ArrayList(); private boolean roundFinished; private boolean lastTurnNotEnoughPoints; private boolean lastTurnMeldError; @@ -61,6 +64,10 @@ public class RoundControl { this.view = view; } + public IEvent1 getRoundStateUpdateEvent() { + return roundStateUpdateEvent; + } + /** * End the round * @@ -70,10 +77,6 @@ public class RoundControl { return endOfRoundEvent; } - public IEvent1 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() { @Override - public void handle() { - endOfTurn(); + public void handle(ITable newTable) { + endOfTurn(newTable); } }); - - turnControl.getTableUpdateEvent().add(new IListener1() { - @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 invalidStoneSets() { + private List invalidStoneSets(ITable newTable) { List invalidSets = new ArrayList(); - for (Pair set : clonedTable) { + for (Pair set : newTable) { if (set.getFirst().isValid(roundState.getGameSettings())) { continue; } @@ -253,9 +263,9 @@ public class RoundControl { return invalidSets; } - private List touchedStoneSets() { + private List touchedStoneSets(ITable newTable) { List touchedSets = new ArrayList(); - 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 tableDiff = tableDifference(roundState.getTable(), clonedTable); + Set 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 tableDiff = tableDifference(roundState.getTable(), clonedTable); + private void rejectMove(ITable newTable) { + Set 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 tableUpdateEvent = new Event1(); + private Event1 turnEndEvent = new Event1(); + private Event1 turnStartEvent = new Event1(); + private GameData currentGame; private volatile GameData offeredGame; @@ -144,6 +150,21 @@ public class ConnectionControl implements IConnectionControl { return gameStartEvent; } + @Override + public IEvent1 getTableUpdateEvent() { + return tableUpdateEvent; + } + + @Override + public IEvent1 getTurnEndEvent() { + return turnEndEvent; + } + + @Override + public IEvent1 getTurnStartEvent() { + return turnStartEvent; + } + @Override public void offerGame(GameData data) { offeredGame = 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 getTableUpdateEvent(); + + public IEvent1 getTurnEndEvent(); + + public IEvent1 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() { + @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 stateUpdateEvent = new Event1(); + + + public NetworkTurnControl(IConnectionControl connectionControl) { + this.connectionControl = connectionControl; + } + + public IEvent1 getStateUpdateEvent() { + return stateUpdateEvent; + } + + @Override + public void doStartTurn() { + connections.add(connectionControl.getTableUpdateEvent().add(new IListener1() { + @Override + public void handle(ITable table) { + view.getTablePanel().setStoneSets(table); + } + })); + connections.add(connectionControl.getTurnEndEvent().add(new IListener1() { + @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 endOfTurnEvent = new Event1(); protected Event redealEvent = new Event(); protected Event1 tableUpdateEvent = new Event1(); protected TurnInfo turnInfo; @@ -27,9 +27,10 @@ public abstract class AbstractTurnControl implements ITurnControl { protected IView view; protected ITurnTimer timer; protected List connections = new ArrayList(); + private boolean started = false; @Override - public IEvent getEndOfTurnEvent() { + public IEvent1 getEndOfTurnEvent() { return endOfTurnEvent; } @@ -37,7 +38,7 @@ public abstract class AbstractTurnControl implements ITurnControl { public IEvent getRedealEvent() { return redealEvent; } - + @Override public IEvent1 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 getEndOfTurnEvent(); /** * Emitted when the round is aborted and needs to be restarted -- cgit v1.2.3