summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--mock/jrummikub/model/MockRoundState.java9
-rw-r--r--src/jrummikub/control/GameControl.java6
-rw-r--r--src/jrummikub/control/RoundControl.java71
-rw-r--r--src/jrummikub/model/IRoundState.java9
-rw-r--r--src/jrummikub/model/RoundState.java9
-rw-r--r--src/jrummikub/model/Score.java42
-rw-r--r--src/jrummikub/util/Pair.java31
-rw-r--r--test/jrummikub/control/RoundControlTest.java135
8 files changed, 283 insertions, 29 deletions
diff --git a/mock/jrummikub/model/MockRoundState.java b/mock/jrummikub/model/MockRoundState.java
index ee483c6..1ebc575 100644
--- a/mock/jrummikub/model/MockRoundState.java
+++ b/mock/jrummikub/model/MockRoundState.java
@@ -104,4 +104,13 @@ public class MockRoundState implements IRoundState {
}
activePlayer = j;
}
+
+ @Override
+ public IPlayer getNthPlayer(int i) {
+ int j = i % players.size();
+ if (j < 0) {
+ j += players.size();
+ }
+ return players.get(j);
+ }
}
diff --git a/src/jrummikub/control/GameControl.java b/src/jrummikub/control/GameControl.java
index 9690bb4..781af31 100644
--- a/src/jrummikub/control/GameControl.java
+++ b/src/jrummikub/control/GameControl.java
@@ -7,8 +7,10 @@ import jrummikub.model.GameSettings;
import jrummikub.model.GameState;
import jrummikub.model.IRoundState;
import jrummikub.model.RoundState;
+import jrummikub.model.Score;
import jrummikub.util.Connection;
import jrummikub.util.IListener;
+import jrummikub.util.IListener1;
import jrummikub.view.IView;
/**
@@ -68,10 +70,10 @@ public class GameControl {
roundState.setActivePlayerNumber(gameState.getFirstRoundFirstPlayer());
roundControl = new RoundControl(roundState, view);
- roundControl.getEndOfRoundEvent().add(new IListener() {
+ roundControl.getEndOfRoundEvent().add(new IListener1<Score>() {
@Override
- public void handle() {
+ public void handle(Score roundScore) {
endOfRound();
}
});
diff --git a/src/jrummikub/control/RoundControl.java b/src/jrummikub/control/RoundControl.java
index 1829725..91bf59b 100644
--- a/src/jrummikub/control/RoundControl.java
+++ b/src/jrummikub/control/RoundControl.java
@@ -6,15 +6,17 @@ import java.util.List;
import java.util.Set;
import jrummikub.model.Hand;
-import jrummikub.model.IRoundState;
import jrummikub.model.IHand;
+import jrummikub.model.IPlayer;
+import jrummikub.model.IRoundState;
import jrummikub.model.ITable;
import jrummikub.model.Position;
+import jrummikub.model.Score;
import jrummikub.model.Stone;
import jrummikub.model.StoneSet;
import jrummikub.util.Connection;
-import jrummikub.util.Event;
-import jrummikub.util.IEvent;
+import jrummikub.util.Event1;
+import jrummikub.util.IEvent1;
import jrummikub.util.IListener;
import jrummikub.util.Pair;
import jrummikub.view.IView;
@@ -26,7 +28,7 @@ public class RoundControl {
private IRoundState roundState;
private IView view;
private ITable clonedTable;
- private Event endOfRoundEvent = new Event();
+ private Event1<Score> endOfRoundEvent = new Event1<Score>();
private List<Connection> connections = new ArrayList<Connection>();
private boolean roundFinished;
@@ -48,7 +50,7 @@ public class RoundControl {
*
* @return endOfRoundEvent
*/
- public IEvent getEndOfRoundEvent() {
+ public IEvent1<Score> getEndOfRoundEvent() {
return endOfRoundEvent;
}
@@ -134,7 +136,6 @@ public class RoundControl {
}
} else {
if (roundState.getActivePlayer() == roundState.getLastPlayer()) {
- // TODO check who has won
endOfRound();
} else {
roundState.nextPlayer();
@@ -237,11 +238,65 @@ public class RoundControl {
dealStones(count + 3);
}
- private void endOfRound() {
+ void endOfRound() {
for (Connection c : connections) {
c.remove();
}
- endOfRoundEvent.emit();
+ Score roundScore = score();
+ endOfRoundEvent.emit(roundScore);
roundFinished = true;
}
+
+ private Score score() {
+ List<Boolean> winners = new ArrayList<Boolean>();
+ List<Integer> points = new ArrayList<Integer>();
+
+ boolean foundRegularWinner = false;
+ int winnerPlayerNumber = 0;
+ Pair<Integer, Integer> bestScore = new Pair<Integer, Integer>(Integer.MIN_VALUE, Integer.MAX_VALUE);
+ int pointSum = 0;
+ for (int i = 0; i < roundState.getPlayerCount(); i++) {
+ IPlayer player = roundState.getNthPlayer(i);
+ IHand playerHand = player.getHand();
+ boolean isWinner = playerHand.getSize() == 0;
+ winners.add(isWinner);
+ if (isWinner) {
+ foundRegularWinner = true;
+ winnerPlayerNumber = i;
+ }
+ int stonePoints = 0;
+
+ if (!player.getLaidOut()) {
+ stonePoints = playerHand.isInitialMeldPossible() ? 200 : 100;
+ } else {
+ stonePoints = playerHand.getStonePoints();
+ }
+
+ bestScore = updateBestScore(bestScore, -stonePoints, playerHand.getSize());
+
+ points.add(-stonePoints);
+ pointSum += stonePoints;
+ }
+
+ if (foundRegularWinner) {
+ points.set(winnerPlayerNumber, pointSum);
+ } else {
+ for (int i = 0; i < roundState.getPlayerCount(); i++) {
+ if (bestScore.equals(new Pair<Integer, Integer>(points.get(i), roundState.getNthPlayer(i).getHand().getSize()))) {
+ winners.set(i, true);
+ }
+ }
+ }
+ return new Score(winners, points);
+ }
+
+ private static Pair<Integer, Integer> updateBestScore(
+ Pair<Integer, Integer> bestScore, int stonePoints, int size) {
+ if (bestScore.getFirst() == stonePoints) {
+ return new Pair<Integer, Integer>(stonePoints, Math.min(bestScore.getSecond(), size));
+ } else if (bestScore.getFirst() < stonePoints) {
+ return new Pair<Integer, Integer>(stonePoints, size);
+ }
+ return bestScore;
+ }
}
diff --git a/src/jrummikub/model/IRoundState.java b/src/jrummikub/model/IRoundState.java
index 4dbcd9a..faed6cf 100644
--- a/src/jrummikub/model/IRoundState.java
+++ b/src/jrummikub/model/IRoundState.java
@@ -61,6 +61,15 @@ public interface IRoundState {
public IPlayer getNthNextPlayer(int i);
/**
+ * Returns the nth player
+ *
+ * @param i
+ * player number
+ * @return nth player
+ */
+ public IPlayer getNthPlayer(int i);
+
+ /**
* Sets the player that will make the last turn before the round ends when
* the heap is empty
*
diff --git a/src/jrummikub/model/RoundState.java b/src/jrummikub/model/RoundState.java
index c32c3c0..eb87247 100644
--- a/src/jrummikub/model/RoundState.java
+++ b/src/jrummikub/model/RoundState.java
@@ -70,6 +70,15 @@ public class RoundState implements IRoundState {
}
return players.get(j);
}
+
+ @Override
+ public IPlayer getNthPlayer(int i) {
+ int j = i % players.size();
+ if (j < 0) {
+ j += players.size();
+ }
+ return players.get(j);
+ }
@Override
public IPlayer getActivePlayer() {
diff --git a/src/jrummikub/model/Score.java b/src/jrummikub/model/Score.java
new file mode 100644
index 0000000..adc78a7
--- /dev/null
+++ b/src/jrummikub/model/Score.java
@@ -0,0 +1,42 @@
+package jrummikub.model;
+
+import java.util.List;
+
+/**
+ * Score of a single round
+ */
+public class Score {
+ List<Boolean> winners;
+ List<Integer> points;
+
+ /**
+ * Create a new round score
+ *
+ * @param winners
+ * set for each player among the winners
+ * @param points
+ * points of each player
+ */
+ public Score(List<Boolean> winners, List<Integer> points) {
+ this.winners = winners;
+ this.points = points;
+ }
+
+ /**
+ * Get the winner list
+ *
+ * @return set for each player among the winners
+ */
+ public List<Boolean> getWinners() {
+ return winners;
+ }
+
+ /**
+ * Get the point list
+ *
+ * @return points of each player
+ */
+ public List<Integer> getPoints() {
+ return points;
+ }
+}
diff --git a/src/jrummikub/util/Pair.java b/src/jrummikub/util/Pair.java
index e1f4112..cae0116 100644
--- a/src/jrummikub/util/Pair.java
+++ b/src/jrummikub/util/Pair.java
@@ -48,4 +48,35 @@ public class Pair<T1, T2> {
return "Pair [first=" + first + ", second=" + second + "]";
}
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((first == null) ? 0 : first.hashCode());
+ result = prime * result + ((second == null) ? 0 : second.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ Pair other = (Pair) obj;
+ if (first == null) {
+ if (other.first != null)
+ return false;
+ } else if (!first.equals(other.first))
+ return false;
+ if (second == null) {
+ if (other.second != null)
+ return false;
+ } else if (!second.equals(other.second))
+ return false;
+ return true;
+ }
+
}
diff --git a/test/jrummikub/control/RoundControlTest.java b/test/jrummikub/control/RoundControlTest.java
index e3b11cb..273a7af 100644
--- a/test/jrummikub/control/RoundControlTest.java
+++ b/test/jrummikub/control/RoundControlTest.java
@@ -29,10 +29,11 @@ import jrummikub.model.MockTable;
import jrummikub.model.PlayerSettings;
import jrummikub.model.Position;
import jrummikub.model.RoundState;
+import jrummikub.model.Score;
import jrummikub.model.Stone;
import jrummikub.model.StoneSet;
import jrummikub.model.Table;
-import jrummikub.util.IListener;
+import jrummikub.util.IListener1;
import jrummikub.util.Pair;
import jrummikub.view.MockView;
@@ -47,12 +48,13 @@ public class RoundControlTest {
private MockRoundState testRoundState;
private RoundControl testRound;
private MockTable testTable;
-
+
private GameSettings gameSettings;
private IRoundState roundState;
private RoundControl roundControl;
-
+
private boolean roundEnded;
+ private Score roundScore;
/**
* For each test create a round control initialized by a mock model and view
@@ -68,7 +70,7 @@ public class RoundControlTest {
testTable.sets.add(testRoundState.table.sets.get(0));
testRoundState.table.clonedTable = testTable;
roundEnded = false;
-
+
gameSettings = new GameSettings();
gameSettings.getPlayerList().add(new PlayerSettings("Ida", Color.RED));
@@ -154,14 +156,13 @@ public class RoundControlTest {
assertEquals(0, roundState.getTable().getSize());
assertEquals(14 + 6, hand.getSize());
}
-
+
/** */
@Test
public void laidOutValidUnchanged() {
roundControl.startRound();
view.startTurnEvent.emit();
-
IHand hand = roundState.getActivePlayer().getHand();
assertFalse(roundState.getActivePlayer().getLaidOut());
@@ -589,13 +590,13 @@ public class RoundControlTest {
@Test
public void testWinning() {
- testRound.getEndOfRoundEvent().add(new IListener() {
+ testRound.getEndOfRoundEvent().add(new IListener1<Score>() {
@Override
- public void handle() {
+ public void handle(Score roundScore) {
roundEnded = true;
}
});
-
+
testRound.startRound();
MockTable oldTable = testRoundState.table;
testTable.valid = true;
@@ -622,7 +623,9 @@ public class RoundControlTest {
view.tablePanel.clickEvent.emit(new Position(0, 0));
- testRoundState.players.get(0).hand = new Hand(gameSettings);
+ for (int i = 0; i < 4; i++) {
+ testRoundState.players.get(i).hand = new Hand(gameSettings);
+ }
resetTurnStart();
assertFalse(roundEnded);
@@ -714,32 +717,126 @@ public class RoundControlTest {
assertTrue(vanishedSets.isEmpty());
assertEquals(1, newSets.size());
}
-
+
/** */
@Test
public void heapIsEmpty() {
- roundControl.getEndOfRoundEvent().add(new IListener() {
+ roundControl.getEndOfRoundEvent().add(new IListener1<Score>() {
@Override
- public void handle() {
+ public void handle(Score roundScore) {
roundEnded = true;
}
});
-
+
roundState.getGameHeap().drawStones(106 - 14 * 4 - 1);
-
+
roundControl.startRound();
-
+
IPlayer player1 = roundState.getActivePlayer();
-
+
view.startTurnEvent.emit();
view.playerPanel.endTurnEvent.emit(); // player 1 draws a card here
-
+
assertSame(player1, roundState.getActivePlayer());
-
+
for (int i = 0; i < 4; i++) {
view.startTurnEvent.emit();
view.playerPanel.endTurnEvent.emit();
}
assertTrue(roundEnded);
}
+
+ /** */
+ @Test
+ public void testScore() {
+
+ testRound.getEndOfRoundEvent().add(new IListener1<Score>() {
+ @Override
+ public void handle(Score score) {
+ roundEnded = true;
+ roundScore = score;
+ }
+ });
+
+ testRound.startRound();
+
+ for (int i = 0; i < 4; i++) {
+ testRoundState.players.get(i).hand = new Hand(gameSettings);
+ }
+
+ testRoundState.players.get(0).laidOut = true;
+ testRoundState.players.get(0).hand.drop(new Stone(1, RED),
+ new Position(0, 0));
+ testRoundState.players.get(0).hand.drop(new Stone(2, RED),
+ new Position(0, 0));
+ testRoundState.players.get(1).laidOut = true;
+ testRoundState.players.get(1).hand.drop(new Stone(RED), new Position(0,
+ 0));
+ testRoundState.players.get(2).laidOut = false;
+ testRoundState.players.get(2).hand.drop(new Stone(9, RED),
+ new Position(0, 0));
+ testRoundState.players.get(2).hand.drop(new Stone(10, RED),
+ new Position(0, 0));
+ testRoundState.players.get(2).hand.drop(new Stone(11, RED),
+ new Position(0, 0));
+ testRoundState.players.get(3).laidOut = true;
+
+ testRound.endOfRound();
+ assertTrue(roundEnded);
+
+ for (int i = 0; i < 4; i++) {
+ assertTrue(roundScore.getWinners().get(i) == (i == 3));
+ }
+ assertEquals(-3, (int) roundScore.getPoints().get(0));
+ assertEquals(-50, (int) roundScore.getPoints().get(1));
+ assertEquals(-200, (int) roundScore.getPoints().get(2));
+ assertEquals(253, (int) roundScore.getPoints().get(3));
+ }
+
+ /** */
+ @Test
+ public void testScoreWhenHeapEmpty() {
+
+ testRound.getEndOfRoundEvent().add(new IListener1<Score>() {
+ @Override
+ public void handle(Score score) {
+ roundEnded = true;
+ roundScore = score;
+ }
+ });
+
+ testRound.startRound();
+
+ for (int i = 0; i < 4; i++) {
+ testRoundState.players.get(i).hand = new Hand(gameSettings);
+ }
+
+ testRoundState.players.get(0).laidOut = true;
+ testRoundState.players.get(0).hand.drop(new Stone(1, RED),
+ new Position(0, 0));
+ testRoundState.players.get(0).hand.drop(new Stone(2, RED),
+ new Position(0, 0));
+ testRoundState.players.get(1).laidOut = true;
+ testRoundState.players.get(1).hand.drop(new Stone(3, RED),
+ new Position(0, 0));
+ testRoundState.players.get(2).laidOut = true;
+ testRoundState.players.get(2).hand.drop(new Stone(3, BLUE),
+ new Position(0, 0));
+ testRoundState.players.get(3).laidOut = false;
+ testRoundState.players.get(3).hand.drop(new Stone(13, RED),
+ new Position(0, 0));
+
+ testRound.endOfRound();
+ assertTrue(roundEnded);
+
+ assertFalse(roundScore.getWinners().get(0));
+ assertTrue(roundScore.getWinners().get(1));
+ assertTrue(roundScore.getWinners().get(2));
+ assertFalse(roundScore.getWinners().get(3));
+
+ assertEquals(-3, (int) roundScore.getPoints().get(0));
+ assertEquals(-3, (int) roundScore.getPoints().get(1));
+ assertEquals(-3, (int) roundScore.getPoints().get(2));
+ assertEquals(-100, (int) roundScore.getPoints().get(3));
+ }
}