package jrummikub.control; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.LinkedList; import java.util.List; import jrummikub.model.Hand; import jrummikub.model.IHand; import jrummikub.model.ITable; import jrummikub.model.Position; import jrummikub.model.Stone; import jrummikub.model.StoneColor; import jrummikub.model.StoneSet; import jrummikub.util.Connection; import jrummikub.util.Event; import jrummikub.util.IEvent; import jrummikub.util.IListener; import jrummikub.util.IListener1; import jrummikub.util.IListener2; import jrummikub.util.Pair; import jrummikub.view.IView; /** * Controller for a single turn made by a human player */ public class TurnControl { private IHand hand; private ITable table; private ITurnTimer timer; private IView view; private List selectedStones = new ArrayList(); private Event endOfTurnEvent = new Event(); private List connections = new ArrayList(); /** * Create a new TurnControl using a given hand (of the active player), a given * table and a given view for user interaction. * * @param hand * active player's hand * @param table * current table * @param view * view for user interaction. */ public TurnControl(IHand hand, ITable table, IView view) { this.hand = hand; this.table = table; this.view = view; this.timer = new TurnTimer(view); } /** Test only constructor **/ TurnControl(IHand hand, ITable table, IView view, ITurnTimer testTimer) { this.hand = hand; this.table = table; this.view = view; this.timer = testTimer; } /** * Start the turn */ public void startTurn() { IListener endOfTurnListener = new IListener() { @Override public void handle() { endOfTurn(); } }; connections.add(timer.getTimeRunOutEvent().add(endOfTurnListener)); connections.add(view.getPlayerPanel().getEndTurnEvent() .add(endOfTurnListener)); addHandPanelHandlers(); addStoneCollectionHandlers(); addTablePanelHandlers(); connections.add(view.getPlayerPanel().getSortByGroupsEvent() .add(new IListener() { @Override public void handle() { sortByGroups(); } })); connections.add(view.getPlayerPanel().getSortByRunsEvent() .add(new IListener() { @Override public void handle() { sortByRuns(); } })); view.getHandPanel().setStones(hand.clone()); view.getHandPanel().resetCurrentRow(); view.enableStartTurnPanel(false); timer.startTimer(); } private void addHandPanelHandlers() { connections.add(view.getHandPanel().getClickEvent() .add(new IListener1() { @Override public void handle(Position pos) { handClick(pos); } })); connections.add(view.getHandPanel().getStoneClickEvent() .add(new IListener2() { @Override public void handle(Stone stone, Boolean collect) { stoneClick(stone, collect); } })); connections.add(view.getHandPanel().getRangeClickEvent() .add(new IListener2() { @Override public void handle(Stone stone, Boolean collect) { handRangeClick(stone, collect); } })); } private void addStoneCollectionHandlers() { connections.add(view.getTablePanel().getStoneCollectionPanel() .getStoneClickEvent().add(new IListener2() { @Override public void handle(Stone stone, Boolean collect) { collectionStoneClick(stone, collect); } })); connections.add(view.getTablePanel().getStoneCollectionPanel() .getSetClickEvent().add(new IListener2() { @Override public void handle(Stone stone, Boolean collect) { collectionSetClick(stone, collect); } })); } private void addTablePanelHandlers() { connections.add(view.getTablePanel().getStoneClickEvent() .add(new IListener2() { @Override public void handle(Stone stone, Boolean collect) { stoneClick(stone, collect); } })); connections.add(view.getTablePanel().getSetClickEvent() .add(new IListener2() { @Override public void handle(Stone stone, Boolean collect) { tableSetClick(stone, collect); } })); connections.add(view.getTablePanel().getRangeClickEvent() .add(new IListener2() { @Override public void handle(Stone stone, Boolean collect) { tableRangeClick(stone, collect); } })); connections.add(view.getTablePanel().getClickEvent() .add(new IListener1() { @Override public void handle(Position pos) { tableClick(pos); } })); addTablePanelConnectorClickHandlers(); } private void addTablePanelConnectorClickHandlers() { connections.add(view.getTablePanel().getLeftConnectorClickEvent() .add(new IListener1() { @Override public void handle(StoneSet set) { connectorClick(set, false); } })); connections.add(view.getTablePanel().getRightConnectorClickEvent() .add(new IListener1() { @Override public void handle(StoneSet set) { connectorClick(set, true); } })); } private void handClick(Position pos) { List handStones = new ArrayList(); for (Stone s : selectedStones) { if (hand.pickUp(s)) { handStones.add(s); } } int i = 0; for (Stone s : handStones) { float x = Math.max(0, Math.min(13, pos.getX() - handStones.size() / 2.0f + i)); hand.drop(s, new Position(x, (float) Math.floor(pos.getY()))); selectedStones.remove(s); i++; } view.setSelectedStones(selectedStones); view.getHandPanel().setStones(hand); } private void sortStones(Comparator comparator) { List stones = new ArrayList(); for (Pair entry : hand) { stones.add(entry.getFirst()); } for (Stone stone : stones) { hand.pickUp(stone); } Collections.sort(stones, comparator); int x = 0, y = 0; for (Stone stone : stones) { hand.drop(stone, new Position(x, y)); x++; if (x >= Hand.WIDTH) { x = 0; y++; } } view.getHandPanel().setStones(hand); } private void sortByRuns() { sortStones(new RunComparator()); } private void sortByGroups() { sortStones(new GroupComparator()); } private void stoneClick(Stone stone, boolean collect) { if (collect) { if (!selectedStones.remove(stone)) { selectedStones.add(stone); } } else { selectedStones.clear(); selectedStones.add(stone); } view.setSelectedStones(selectedStones); } private void collectionStoneClick(Stone stone, boolean collect) { selectedStones.remove(stone); if (collect) { selectedStones.add(stone); } view.setSelectedStones(selectedStones); } private void collectionSetClick(Stone stone, Boolean collect) { selectedStones.clear(); view.setSelectedStones(selectedStones); } private void pickUpSelectedStones() { for (Stone stone : selectedStones) { hand.pickUp(stone); table.pickUpStone(stone); } } private void tableClick(Position position) { if (selectedStones.isEmpty()) { return; } pickUpSelectedStones(); table.drop(new StoneSet(selectedStones), new Position(position.getX() - selectedStones.size() * 0.5f, position.getY() - 0.5f)); selectedStones.clear(); view.getTablePanel().setStoneSets(table); view.getHandPanel().setStones(hand); view.setSelectedStones(selectedStones); } private void tableSetClick(Stone stone, Boolean collect) { if (!collect) { selectedStones.clear(); } StoneSet selectedSet = table.findStoneSet(stone); for (Stone setStone : selectedSet) { selectedStones.remove(setStone); selectedStones.add(setStone); } view.setSelectedStones(selectedStones); } private void tableRangeClick(Stone stone, Boolean collect) { if (selectedStones.isEmpty()) { stoneClick(stone, true); return; } Stone lastStone = selectedStones.get(selectedStones.size() - 1); StoneSet lastSet = table.findStoneSet(lastStone); StoneSet selectedSet = table.findStoneSet(stone); if (lastSet != selectedSet) { stoneClick(stone, true); return; } List setStones = new ArrayList(); for (Stone s : selectedSet) { setStones.add(s); } int firstIndex = setStones.indexOf(lastStone); int lastIndex = setStones.indexOf(stone); if (firstIndex > lastIndex) { int temp = firstIndex; firstIndex = lastIndex; lastIndex = temp; } for (int i = firstIndex; i <= lastIndex; i++) { Stone s = setStones.get(i); selectedStones.remove(s); selectedStones.add(s); } view.setSelectedStones(selectedStones); } private void handRangeClick(Stone stone, Boolean collect) { if (selectedStones.isEmpty()) { stoneClick(stone, true); return; } Stone lastStone = selectedStones.get(selectedStones.size() - 1); StoneSet lastSet = table.findStoneSet(lastStone); if (lastSet != null) { stoneClick(stone, true); return; } List> handPairs = new ArrayList>(); for (Pair entry : hand) { handPairs.add(entry); } Collections.sort(handPairs, new HandStonePositionComparator()); List handStones = new ArrayList(); for (Pair entry : handPairs) { handStones.add(entry.getFirst()); } int firstIndex = handStones.indexOf(lastStone); int lastIndex = handStones.indexOf(stone); if (firstIndex > lastIndex) { int temp = firstIndex; firstIndex = lastIndex; lastIndex = temp; } for (int i = firstIndex; i <= lastIndex; i++) { Stone s = handStones.get(i); selectedStones.remove(s); selectedStones.add(s); } view.setSelectedStones(selectedStones); } private void connectorClick(StoneSet set, boolean right) { List stones = new LinkedList(); Position pos = table.getPosition(set); for (Stone stone : set) { stones.add(stone); } stones.removeAll(selectedStones); if (right) { Collections.reverse(stones); } pickUpSelectedStones(); StoneSet newSet = null; for (Stone stone : stones) { newSet = table.findStoneSet(stone); if (newSet != null) { break; } } if (newSet != null) { Position newPos = table.getPosition(newSet); table.pickUp(newSet); if (right) { StoneSet joinedSet = newSet.join(new StoneSet(selectedStones)); table.drop(joinedSet, newPos); } else { StoneSet joinedSet = new StoneSet(selectedStones).join(newSet); table.drop(joinedSet, new Position(newPos.getX() - selectedStones.size(), newPos.getY())); } } else { table.drop( new StoneSet(selectedStones), new Position( pos.getX() + (set.size() - selectedStones.size()) * 0.5f, pos .getY())); } selectedStones.clear(); view.getTablePanel().setStoneSets(table); view.getHandPanel().setStones(hand); view.setSelectedStones(selectedStones); } private void endOfTurn() { timer.stopTimer(); endOfTurnEvent.emit(); for (Connection c : connections) { c.remove(); } view.setSelectedStones(new ArrayList()); } /** * Get the event that is emitted when the turn is over * * @return end of turn event */ public IEvent getEndOfTurnEvent() { return endOfTurnEvent; } static private int compareJokers(Stone s1, Stone s2) { if (!s1.isJoker() && s2.isJoker()) { return -1; } else if (s1.isJoker() && !s2.isJoker()) { return 1; } else { return 0; } } static private int compareColors(Stone s1, Stone s2) { if (s1.getColor() == s2.getColor()) return 0; for (StoneColor color : StoneColor.values()) { if (s1.getColor() == color) { return -1; } else if (s2.getColor() == color) { return 1; } } return 0; } static private int compareValues(Stone s1, Stone s2) { if (s1.getValue() < s2.getValue()) { return -1; } else if (s1.getValue() > s2.getValue()) { return 1; } else { return 0; } } private static class RunComparator implements Comparator { @Override public int compare(Stone s1, Stone s2) { int jokerCompare = compareJokers(s1, s2); if (jokerCompare != 0) { return jokerCompare; } int colorCompare = compareColors(s1, s2); if (colorCompare != 0) { return colorCompare; } return compareValues(s1, s2); } } private static class GroupComparator implements Comparator { @Override public int compare(Stone s1, Stone s2) { int jokerCompare = compareJokers(s1, s2); if (jokerCompare != 0) { return jokerCompare; } int valueCompare = compareValues(s1, s2); if (valueCompare != 0) { return valueCompare; } return compareColors(s1, s2); } } static class HandStonePositionComparator implements Comparator> { @Override public int compare(Pair pair1, Pair pair2) { Position pos1 = pair1.getSecond(), pos2 = pair2.getSecond(); if (pos1.getY() < pos2.getY()) { return -1; } else if (pos1.getY() > pos2.getY()) { return 1; } else { if (pos1.getX() < pos2.getX()) { return -1; } else if (pos1.getX() > pos2.getX()) { return 1; } else { return 0; } } } } }