package jrummikub.control.turn; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.LinkedList; import java.util.List; import jrummikub.control.ITurnTimer; import jrummikub.model.Hand; import jrummikub.model.Position; import jrummikub.model.Stone; import jrummikub.model.StoneColor; import jrummikub.model.StoneSet; import jrummikub.util.IListener; import jrummikub.util.IListener1; import jrummikub.util.IListener2; import jrummikub.util.Pair; import jrummikub.view.IView.BottomPanelType; /** * Controller for a single turn made by a human player */ public class HumanTurnControl extends AbstractTurnControl { private List selectedStones = new ArrayList(); /** * Create a new human player's turn control */ public HumanTurnControl() { } /** * Get a factory for this turn control * * @return factory */ public static TurnControlFactory getFactory() { return new TurnControlFactory() { @Override public ITurnControl create() { return new HumanTurnControl(); } }; } /** Test only constructor **/ HumanTurnControl(ITurnTimer testTimer) { this.timer = testTimer; } protected void timeOut() { endOfTurn(false); } @Override public void doStartTurn() { addButtonHandlers(); addHandPanelHandlers(); addStoneCollectionHandlers(); if (turnInfo.getTurnMode() == TurnMode.NORMAL_TURN) { addTablePanelHandlers(); } view.getHandPanel().setStones(turnInfo.getHand().clone()); view.getHandPanel().resetCurrentRow(); view.setBottomPanel(BottomPanelType.HUMAN_HAND_PANEL); timer.startTimer(); } private void addButtonHandlers() { 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(); } })); connections.add(view.getPlayerPanel().getEndTurnEvent() .add(new IListener() { @Override public void handle() { endOfTurn(false); } })); connections.add(view.getPlayerPanel().getRedealEvent().add(new IListener() { @Override public void handle() { endOfTurn(true); } })); } 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 (turnInfo.getHand().pickUp(s)) { handStones.add(s); } } int i = 0; for (Stone s : handStones) { double x = Math.max(0, Math.min(13, pos.getX() - handStones.size() / 2.0f + i)); turnInfo.getHand().drop(s, new Position(x, (float) Math.floor(pos.getY()))); selectedStones.remove(s); i++; } view.setSelectedStones(selectedStones); view.getHandPanel().setStones(turnInfo.getHand()); } private void sortStones(Comparator comparator) { List stones = new ArrayList(); for (Pair entry : turnInfo.getHand()) { stones.add(entry.getFirst()); } for (Stone stone : stones) { turnInfo.getHand().pickUp(stone); } Collections.sort(stones, comparator); int x = 0, y = 0; for (Stone stone : stones) { turnInfo.getHand().drop(stone, new Position(x, y)); x++; if (x >= Hand.WIDTH) { x = 0; y++; } } view.getHandPanel().setStones(turnInfo.getHand()); view.getHandPanel().resetCurrentRow(); } 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) { turnInfo.getHand().pickUp(stone); turnInfo.getTable().pickUpStone(stone); } } private void updateTable() { view.getTablePanel().setStoneSets(turnInfo.getTable()); view.getHandPanel().setStones(turnInfo.getHand()); view.setSelectedStones(selectedStones); tableUpdateEvent.emit(turnInfo.getTable()); } private void tableClick(Position position) { if (selectedStones.isEmpty()) { return; } pickUpSelectedStones(); turnInfo.getTable().drop( new StoneSet(selectedStones), new Position(position.getX() - selectedStones.size() * 0.5f, position .getY() - 0.5f)); selectedStones.clear(); updateTable(); } private void tableSetClick(Stone stone, boolean collect) { if (!collect) { selectedStones.clear(); } StoneSet selectedSet = turnInfo.getTable().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 = turnInfo.getTable().findStoneSet(lastStone); StoneSet selectedSet = turnInfo.getTable().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 = turnInfo.getTable().findStoneSet(lastStone); if (lastSet != null) { stoneClick(stone, true); return; } List> handPairs = new ArrayList>(); for (Pair entry : turnInfo.getHand()) { 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 = turnInfo.getTable().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 = turnInfo.getTable().findStoneSet(stone); if (newSet != null) { break; } } if (newSet != null) { Position newPos = turnInfo.getTable().getPosition(newSet); turnInfo.getTable().pickUp(newSet); if (right) { StoneSet joinedSet = newSet.join(new StoneSet(selectedStones)); turnInfo.getTable().drop(joinedSet, newPos); } else { StoneSet joinedSet = new StoneSet(selectedStones).join(newSet); turnInfo.getTable().drop(joinedSet, new Position(newPos.getX() - selectedStones.size(), newPos.getY())); } } else { turnInfo.getTable().drop( new StoneSet(selectedStones), new Position(pos.getX() + (set.getSize() - selectedStones.size()) * 0.5f, pos.getY())); } selectedStones.clear(); updateTable(); } private void endOfTurn(boolean redeal) { cleanUp(); view.setSelectedStones(Collections. emptyList()); if (redeal) { redealEvent.emit(); } else { endOfTurnEvent.emit(turnInfo.getRoundState(), checkTurn()); } } 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; } } } } }