summaryrefslogtreecommitdiffstats
path: root/src/jrummikub/control/turn/HumanTurnControl.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/jrummikub/control/turn/HumanTurnControl.java')
-rw-r--r--src/jrummikub/control/turn/HumanTurnControl.java552
1 files changed, 552 insertions, 0 deletions
diff --git a/src/jrummikub/control/turn/HumanTurnControl.java b/src/jrummikub/control/turn/HumanTurnControl.java
new file mode 100644
index 0000000..9b44f4e
--- /dev/null
+++ b/src/jrummikub/control/turn/HumanTurnControl.java
@@ -0,0 +1,552 @@
+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.control.TurnTimer;
+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.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 HumanTurnControl extends AbstractTurnControl {
+ private IHand hand;
+ private ITable table;
+ private ITurnTimer timer;
+ private IView view;
+
+ private List<Stone> selectedStones = new ArrayList<Stone>();
+
+ private List<Connection> connections = new ArrayList<Connection>();
+
+ private boolean inspectOnly;
+
+ /**
+ * 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.
+ * @param inspectOnly
+ * the current turn doesn't allow any table manipulation
+ */
+ public HumanTurnControl(IHand hand, ITable table, IView view, boolean inspectOnly) {
+ this.hand = hand;
+ this.table = table;
+ this.view = view;
+ this.inspectOnly = inspectOnly;
+ this.timer = new TurnTimer(view);
+ }
+
+ /** Test only constructor **/
+ HumanTurnControl(IHand hand, ITable table, IView view, ITurnTimer testTimer) {
+ this.hand = hand;
+ this.table = table;
+ this.view = view;
+ this.timer = testTimer;
+ this.inspectOnly = false;
+ }
+
+ @Override
+ public void startTurn() {
+
+ IListener endOfTurnListener = new IListener() {
+
+ @Override
+ public void handle() {
+ endOfTurn(false);
+ }
+ };
+ connections.add(timer.getTimeRunOutEvent().add(endOfTurnListener));
+ connections.add(view.getPlayerPanel().getEndTurnEvent()
+ .add(endOfTurnListener));
+
+ connections.add(view.getPlayerPanel().getRedealEvent().add(new IListener() {
+ @Override
+ public void handle() {
+ endOfTurn(true);
+ }
+ }));
+
+ addHandPanelHandlers();
+ addStoneCollectionHandlers();
+ if (!inspectOnly)
+ 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<Position>() {
+ @Override
+ public void handle(Position pos) {
+ handClick(pos);
+ }
+ }));
+
+ connections.add(view.getHandPanel().getStoneClickEvent()
+ .add(new IListener2<Stone, Boolean>() {
+
+ @Override
+ public void handle(Stone stone, Boolean collect) {
+ stoneClick(stone, collect);
+ }
+ }));
+
+ connections.add(view.getHandPanel().getRangeClickEvent()
+ .add(new IListener2<Stone, Boolean>() {
+
+ @Override
+ public void handle(Stone stone, Boolean collect) {
+ handRangeClick(stone, collect);
+ }
+ }));
+ }
+
+ private void addStoneCollectionHandlers() {
+ connections.add(view.getTablePanel().getStoneCollectionPanel()
+ .getStoneClickEvent().add(new IListener2<Stone, Boolean>() {
+
+ @Override
+ public void handle(Stone stone, Boolean collect) {
+ collectionStoneClick(stone, collect);
+ }
+ }));
+
+ connections.add(view.getTablePanel().getStoneCollectionPanel()
+ .getSetClickEvent().add(new IListener2<Stone, Boolean>() {
+
+ @Override
+ public void handle(Stone stone, Boolean collect) {
+ collectionSetClick(stone, collect);
+ }
+ }));
+ }
+
+ private void addTablePanelHandlers() {
+ connections.add(view.getTablePanel().getStoneClickEvent()
+ .add(new IListener2<Stone, Boolean>() {
+
+ @Override
+ public void handle(Stone stone, Boolean collect) {
+ stoneClick(stone, collect);
+ }
+ }));
+
+ connections.add(view.getTablePanel().getSetClickEvent()
+ .add(new IListener2<Stone, Boolean>() {
+
+ @Override
+ public void handle(Stone stone, Boolean collect) {
+ tableSetClick(stone, collect);
+ }
+ }));
+
+ connections.add(view.getTablePanel().getRangeClickEvent()
+ .add(new IListener2<Stone, Boolean>() {
+
+ @Override
+ public void handle(Stone stone, Boolean collect) {
+ tableRangeClick(stone, collect);
+ }
+ }));
+
+ connections.add(view.getTablePanel().getClickEvent()
+ .add(new IListener1<Position>() {
+ @Override
+ public void handle(Position pos) {
+ tableClick(pos);
+ }
+ }));
+
+ addTablePanelConnectorClickHandlers();
+ }
+
+ private void addTablePanelConnectorClickHandlers() {
+ connections.add(view.getTablePanel().getLeftConnectorClickEvent()
+ .add(new IListener1<StoneSet>() {
+ @Override
+ public void handle(StoneSet set) {
+ connectorClick(set, false);
+ }
+ }));
+
+ connections.add(view.getTablePanel().getRightConnectorClickEvent()
+ .add(new IListener1<StoneSet>() {
+ @Override
+ public void handle(StoneSet set) {
+ connectorClick(set, true);
+ }
+ }));
+ }
+
+ private void handClick(Position pos) {
+ List<Stone> handStones = new ArrayList<Stone>();
+ 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<Stone> comparator) {
+ List<Stone> stones = new ArrayList<Stone>();
+ for (Pair<Stone, Position> 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<Stone> setStones = new ArrayList<Stone>();
+ 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<Pair<Stone, Position>> handPairs = new ArrayList<Pair<Stone, Position>>();
+ for (Pair<Stone, Position> entry : hand) {
+ handPairs.add(entry);
+ }
+
+ Collections.sort(handPairs, new HandStonePositionComparator());
+
+ List<Stone> handStones = new ArrayList<Stone>();
+ for (Pair<Stone, Position> 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<Stone> stones = new LinkedList<Stone>();
+ 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(boolean redeal) {
+ timer.stopTimer();
+ if (redeal) {
+ redealEvent.emit();
+ } else {
+ endOfTurnEvent.emit();
+ }
+ for (Connection c : connections) {
+ c.remove();
+ }
+ view.setSelectedStones(new ArrayList<Stone>());
+ }
+
+ 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<Stone> {
+ @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<Stone> {
+ @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<Pair<Stone, Position>> {
+ @Override
+ public int compare(Pair<Stone, Position> pair1,
+ Pair<Stone, Position> 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;
+ }
+ }
+ }
+ }
+
+}