diff options
Diffstat (limited to 'src/jrummikub/control/turn')
-rw-r--r-- | src/jrummikub/control/turn/AIControl.java | 2 | ||||
-rw-r--r-- | src/jrummikub/control/turn/AbstractTurnControl.java | 169 | ||||
-rw-r--r-- | src/jrummikub/control/turn/HumanTurnControl.java | 2 | ||||
-rw-r--r-- | src/jrummikub/control/turn/ITurnControl.java | 68 |
4 files changed, 215 insertions, 26 deletions
diff --git a/src/jrummikub/control/turn/AIControl.java b/src/jrummikub/control/turn/AIControl.java index b633f96..f480143 100644 --- a/src/jrummikub/control/turn/AIControl.java +++ b/src/jrummikub/control/turn/AIControl.java @@ -225,7 +225,7 @@ public class AIControl extends AbstractTurnControl { return; } cleanUp(); - endOfTurnEvent.emit(null, null, turnInfo.getTable()); + endOfTurnEvent.emit(turnInfo.getRoundState(), checkTurn()); } /** diff --git a/src/jrummikub/control/turn/AbstractTurnControl.java b/src/jrummikub/control/turn/AbstractTurnControl.java index 8b481bc..d64ee62 100644 --- a/src/jrummikub/control/turn/AbstractTurnControl.java +++ b/src/jrummikub/control/turn/AbstractTurnControl.java @@ -1,28 +1,39 @@ package jrummikub.control.turn; import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; import java.util.List; +import java.util.Set; import jrummikub.control.ITurnTimer; +import jrummikub.control.RoundControl.InvalidTurnInfo; +import jrummikub.control.RoundControl.InvalidTurnType; import jrummikub.control.TurnTimer; import jrummikub.model.GameSettings; +import jrummikub.model.Hand; import jrummikub.model.IHand; +import jrummikub.model.IRoundState; import jrummikub.model.ITable; +import jrummikub.model.Position; +import jrummikub.model.Stone; +import jrummikub.model.StoneSet; import jrummikub.util.Connection; import jrummikub.util.Event; import jrummikub.util.Event1; -import jrummikub.util.Event3; +import jrummikub.util.Event2; import jrummikub.util.IEvent; import jrummikub.util.IEvent1; -import jrummikub.util.IEvent3; +import jrummikub.util.IEvent2; import jrummikub.util.IListener; +import jrummikub.util.Pair; import jrummikub.view.IView; /** * Abstract base class for TurnControls */ public abstract class AbstractTurnControl implements ITurnControl { - protected Event3<IHand, ITable, ITable> endOfTurnEvent = new Event3<IHand, ITable, ITable>(); + protected Event2<IRoundState, InvalidTurnInfo> endOfTurnEvent = new Event2<IRoundState, InvalidTurnInfo>(); protected Event redealEvent = new Event(); protected Event1<ITable> tableUpdateEvent = new Event1<ITable>(); protected TurnInfo turnInfo; @@ -33,7 +44,7 @@ public abstract class AbstractTurnControl implements ITurnControl { private boolean started = false; @Override - public IEvent3<IHand, ITable, ITable> getEndOfTurnEvent() { + public IEvent2<IRoundState, InvalidTurnInfo> getEndOfTurnEvent() { return endOfTurnEvent; } @@ -114,4 +125,154 @@ public abstract class AbstractTurnControl implements ITurnControl { cleanUp(); } + protected InvalidTurnInfo checkTurn() { + turnInfo.getRoundState().getActivePlayer().setLastTurnInvalid(false); + turnInfo + .getRoundState() + .getActivePlayer() + .setLastTurnStoneCount( + turnInfo.getOldHand().getSize() - turnInfo.getHand().getSize()); + + turnInfo.getRoundState().getActivePlayer().setHand(turnInfo.getHand()); + + if (turnInfo.getRoundState().getTurnNumber() < 1) { + return new InvalidTurnInfo(turnInfo.getTable(), null, + Collections.<StoneSet> emptyList()); + } + + if (!turnInfo.getTable().isValid()) { + rejectMove(); + return new InvalidTurnInfo(turnInfo.getTable(), + InvalidTurnType.INVALID_SETS, invalidStoneSets()); + } + if (!turnInfo.getLaidOut()) { + // Player touched forbidden stones + if (!tableSetDifference(turnInfo.getTable(), turnInfo.getOldTable()) + .isEmpty()) { + rejectMove(); + return new InvalidTurnInfo(turnInfo.getTable(), + InvalidTurnType.INITIAL_MELD_ERROR, touchedStoneSets()); + } + if (!laidOutValidPoints()) { + rejectMove(); + return new InvalidTurnInfo(turnInfo.getTable(), + InvalidTurnType.NOT_ENOUGH_POINTS, tableSetDifference( + turnInfo.getOldTable(), turnInfo.getTable())); + } + } + Set<Stone> tableDiff = tableDifference(turnInfo.getOldTable(), + turnInfo.getTable()); + + turnInfo.getRoundState().setTable(turnInfo.getTable()); + + if (tableDiff.isEmpty()) { + // Player hasn't made a move + dealStone(); + } else { + turnInfo.getRoundState().getActivePlayer().setLaidOut(true); + } + return new InvalidTurnInfo(turnInfo.getTable(), null, + Collections.<StoneSet> emptyList()); + } + + private List<StoneSet> invalidStoneSets() { + List<StoneSet> invalidSets = new ArrayList<StoneSet>(); + for (Pair<StoneSet, Position> set : turnInfo.getTable()) { + if (set.getFirst().isValid(turnInfo.getRoundState().getGameSettings())) { + continue; + } + invalidSets.add(set.getFirst()); + } + return invalidSets; + } + + private List<StoneSet> touchedStoneSets() { + List<StoneSet> touchedSets = new ArrayList<StoneSet>(); + for (StoneSet set : tableSetDifference(turnInfo.getOldTable(), + turnInfo.getTable())) { + for (Stone stone : set) { + if (!turnInfo.getOldHand().contains(stone)) { + touchedSets.add(set); + break; + } + } + } + + return touchedSets; + } + + private boolean laidOutValidPoints() { + List<StoneSet> newSets = tableSetDifference(turnInfo.getOldTable(), + turnInfo.getTable()); + + int totalValue = 0; + for (StoneSet set : newSets) { + totalValue += set.classify(turnInfo.getRoundState().getGameSettings()) + .getSecond(); + } + + return totalValue == 0 + || totalValue >= turnInfo.getRoundState().getGameSettings() + .getInitialMeldThreshold(); + } + + private void rejectMove() { + Set<Stone> tableDiff = tableDifference(turnInfo.getOldTable(), + turnInfo.getTable()); + // deal penalty, reset + turnInfo.getRoundState().getGameHeap().putBack(tableDiff); + turnInfo.getRoundState().getActivePlayer().setLastTurnInvalid(true); + dealPenalty(tableDiff.size()); + } + + private void dealStones(int count) { + IHand hand = turnInfo.getRoundState().getActivePlayer().getHand(); + int rowCount = hand.getRowCount(); + + for (int i = 0; i < count; ++i) { + if (hand.getFreeRowSpace(rowCount - 1) == 0) { + rowCount++; + } + + hand.drop(turnInfo.getRoundState().getGameHeap().drawStone(), + new Position(Hand.WIDTH - 1, rowCount - 1)); + } + + } + + private void dealStone() { + dealStones(1); + } + + private void dealPenalty(int count) { + dealStones(count + 3); + } + + static Set<Stone> tableDifference(ITable oldTable, ITable newTable) { + Set<Stone> ret = new HashSet<Stone>(); + + for (Pair<StoneSet, Position> entry : newTable) { + for (Stone stone : entry.getFirst()) { + ret.add(stone); + } + } + for (Pair<StoneSet, Position> entry : oldTable) { + for (Stone stone : entry.getFirst()) { + ret.remove(stone); + } + } + return ret; + } + + static List<StoneSet> tableSetDifference(ITable oldTable, ITable newTable) { + List<StoneSet> ret = new ArrayList<StoneSet>(); + + for (Pair<StoneSet, Position> entry : newTable) { + ret.add(entry.getFirst()); + } + for (Pair<StoneSet, Position> entry : oldTable) { + ret.remove(entry.getFirst()); + } + return ret; + } }
\ No newline at end of file diff --git a/src/jrummikub/control/turn/HumanTurnControl.java b/src/jrummikub/control/turn/HumanTurnControl.java index e43ec5b..43c2317 100644 --- a/src/jrummikub/control/turn/HumanTurnControl.java +++ b/src/jrummikub/control/turn/HumanTurnControl.java @@ -448,7 +448,7 @@ public class HumanTurnControl extends AbstractTurnControl { if (redeal) { redealEvent.emit(); } else { - endOfTurnEvent.emit(null, null, turnInfo.getTable()); + endOfTurnEvent.emit(turnInfo.getRoundState(), checkTurn()); } } diff --git a/src/jrummikub/control/turn/ITurnControl.java b/src/jrummikub/control/turn/ITurnControl.java index 5c91c0c..6994466 100644 --- a/src/jrummikub/control/turn/ITurnControl.java +++ b/src/jrummikub/control/turn/ITurnControl.java @@ -1,11 +1,13 @@ package jrummikub.control.turn; +import jrummikub.control.RoundControl.InvalidTurnInfo; import jrummikub.model.GameSettings; import jrummikub.model.IHand; +import jrummikub.model.IRoundState; import jrummikub.model.ITable; import jrummikub.util.IEvent; import jrummikub.util.IEvent1; -import jrummikub.util.IEvent3; +import jrummikub.util.IEvent2; import jrummikub.view.IView; /** @@ -17,12 +19,12 @@ public interface ITurnControl { * Start the turn * * @param info - * the current turn state + * the current turn state * * @param settings - * the game settings + * the game settings * @param view - * view for user interaction. + * view for user interaction. */ public void setup(TurnInfo info, GameSettings settings, IView view); @@ -31,7 +33,7 @@ public interface ITurnControl { * * @return end of turn event */ - public IEvent3<IHand, ITable, ITable> getEndOfTurnEvent(); + public IEvent2<IRoundState, InvalidTurnInfo> getEndOfTurnEvent(); /** * Emitted when the round is aborted and needs to be restarted @@ -58,35 +60,61 @@ public interface ITurnControl { public IEvent1<ITable> getTableUpdateEvent(); /** - * The TurnInfo class encapsulates all information concerning the current - * turn + * The TurnInfo class encapsulates all information concerning the current turn */ public class TurnInfo { + private IRoundState roundState; + + private ITable oldTable; + private IHand oldHand; + private ITable table; private IHand hand; - private boolean hasLaidOut; + private TurnMode turnMode; /** * Creates a new TurnInfo instance * - * @param table - * the current table - * @param hand - * the current player's hand * @param hasLaidOut - * has the player laid out yet? + * has the player laid out yet? * @param turnMode - * the turn mode + * the turn mode */ - public TurnInfo(ITable table, IHand hand, boolean hasLaidOut, - TurnMode turnMode) { - this.table = table; - this.hand = hand; - this.hasLaidOut = hasLaidOut; + public TurnInfo(IRoundState roundState, TurnMode turnMode) { + this.roundState = roundState; + + oldTable = roundState.getTable(); + oldHand = roundState.getActivePlayer().getHand(); + + this.table = (ITable) oldTable.clone(); + this.hand = (IHand) oldHand.clone(); + this.turnMode = turnMode; } + public IRoundState getRoundState() { + return roundState; + } + + /** + * Gets the table at the beginning of the turn + * + * @return the table + */ + public ITable getOldTable() { + return oldTable; + } + + /** + * Gets the current player's hand at the beginning of the turn + * + * @return the hand + */ + public IHand getOldHand() { + return oldHand; + } + /** * Gets the current table * @@ -111,7 +139,7 @@ public interface ITurnControl { * @return if the player has laid out */ public boolean getLaidOut() { - return hasLaidOut; + return roundState.getActivePlayer().getLaidOut(); } /** |