package jrummikub.control; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import jrummikub.model.Hand; import jrummikub.model.IRoundState; import jrummikub.model.IHand; 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.IEvent; import jrummikub.util.IListener; import jrummikub.util.Pair; import jrummikub.view.IView; /** * Controller that manages a single round of rummikub */ public class RoundControl { private IRoundState roundState; private IView view; private ITable clonedTable; private Event endRoundEvent = new Event(); private List connections = new ArrayList(); private boolean roundFinished; /** * Create a new RoundControl using the given gameState and view * * @param gameState * initial game state * @param view * view used for user interaction */ public RoundControl(IRoundState roundState, IView view) { this.roundState = roundState; this.view = view; } /** * End the round * * @return endRoundEvent */ public IEvent getEndRoundEvent() { return endRoundEvent; } /** * Begin the round */ public void startRound() { deal(); connections.add(view.getStartTurnEvent().add(new IListener() { @Override public void handle() { startTurn(); } })); prepareTurn(); } private void prepareTurn() { clonedTable = (ITable) roundState.getTable().clone(); view.enableStartTurnPanel(true); view.getTablePanel().setStoneSets(clonedTable); view.setCurrentPlayerName(roundState.getActivePlayer() .getPlayerSettings().getName()); view.getTablePanel().setLeftPlayerName( roundState.getNthNextPlayer(1).getPlayerSettings().getName()); view.getTablePanel().setTopPlayerName( roundState.getNthNextPlayer(2).getPlayerSettings().getName()); view.getTablePanel().setRightPlayerName( roundState.getNthNextPlayer(3).getPlayerSettings().getName()); } private void startTurn() { TurnControl turnControl = new TurnControl(roundState.getActivePlayer() .getHand(), clonedTable, view); connections.add(turnControl.getEndOfTurnEvent().add(new IListener() { @Override public void handle() { endOfTurn(); } })); turnControl.startTurn(); } void deal() { for (int i = 0; i < roundState.getPlayerCount(); i++) { IHand hand = roundState.getNthNextPlayer(i).getHand(); for (int j = 0; j < 7; j++) { hand.drop(roundState.getGameHeap().drawStone(), new Position(j, 0)); hand.drop(roundState.getGameHeap().drawStone(), new Position(j, 1)); } } } private boolean laidOutEnough() { List newSets = tableSetDifference(roundState.getTable(), clonedTable); int totalValue = 0; for (StoneSet set : newSets) { totalValue += set.classify().getSecond(); } return totalValue >= roundState.getGameSettings() .getInitialMeldThreshold(); } private void endOfTurn() { checkTurn(); if (roundState.getLastPlayer() == null) { if (roundState.getGameHeap().getSize() == 0) { roundState.setLastPlayer(roundState.getNthNextPlayer(-1)); } else { roundState.nextPlayer(); } } else { if (roundState.getActivePlayer() == roundState.getLastPlayer()) { // TODO check who has won win(); } else { roundState.nextPlayer(); } } if (!roundFinished) { prepareTurn(); } } private void checkTurn() { if (!clonedTable.isValid()) { rejectMove(); return; } if (!roundState.getActivePlayer().getLaidOut()) { // Player touched forbidden stones if (!tableSetDifference(clonedTable, roundState.getTable()).isEmpty()) { rejectMove(); return; } if (!laidOutEnough()) { rejectMove(); return; } } Set tableDiff = tableDifference(roundState.getTable(), clonedTable); roundState.setTable(clonedTable); if (tableDiff.isEmpty()) { // Player hasn't made a move dealStone(); } else { roundState.getActivePlayer().setLaidOut(true); if (roundState.getActivePlayer().getHand().getSize() == 0) { win(); } } } private void rejectMove() { Set tableDiff = tableDifference(roundState.getTable(), clonedTable); // deal penalty, reset roundState.getGameHeap().putBack(tableDiff); dealPenalty(tableDiff.size()); } static Set tableDifference(ITable oldTable, ITable newTable) { Set ret = new HashSet(); for (Pair entry : newTable) { for (Stone stone : entry.getFirst()) { ret.add(stone); } } for (Pair entry : oldTable) { for (Stone stone : entry.getFirst()) { ret.remove(stone); } } return ret; } static List tableSetDifference(ITable oldTable, ITable newTable) { List ret = new ArrayList(); for (Pair entry : newTable) { ret.add(entry.getFirst()); } for (Pair entry : oldTable) { ret.remove(entry.getFirst()); } return ret; } void dealStones(int count) { IHand hand = roundState.getActivePlayer().getHand(); int rowCount = hand.getRowCount(); for (int i = 0; i < count; ++i) { if (hand.getFreeRowSpace(rowCount - 1) == 0) { rowCount++; } hand.drop(roundState.getGameHeap().drawStone(), new Position( Hand.WIDTH - 1, rowCount - 1)); } } private void dealStone() { dealStones(1); } private void dealPenalty(int count) { dealStones(count + 3); } private void win() { for (Connection c : connections) { c.remove(); } endRoundEvent.emit(); view.enableWinPanel(true); roundFinished = true; } }