diff options
-rw-r--r-- | mock/jrummikub/model/MockRoundState.java | 9 | ||||
-rw-r--r-- | src/jrummikub/control/GameControl.java | 6 | ||||
-rw-r--r-- | src/jrummikub/control/RoundControl.java | 71 | ||||
-rw-r--r-- | src/jrummikub/model/IRoundState.java | 9 | ||||
-rw-r--r-- | src/jrummikub/model/RoundState.java | 9 | ||||
-rw-r--r-- | src/jrummikub/model/Score.java | 42 | ||||
-rw-r--r-- | src/jrummikub/util/Pair.java | 31 | ||||
-rw-r--r-- | test/jrummikub/control/RoundControlTest.java | 135 |
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)); + } } |