Skip to content

Commit 36e00f8

Browse files
committed
fix(plugin): remove issues caused by turn increments
1 parent 54553fe commit 36e00f8

File tree

11 files changed

+68
-38
lines changed

11 files changed

+68
-38
lines changed

plugin/src/server/sc/plugin2021/Game.kt

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@ import sc.plugin2021.util.GameRuleLogic
1111
import sc.plugin2021.util.WinReason
1212
import sc.protocol.responses.ProtocolMessage
1313
import sc.shared.*
14-
import kotlin.math.log
15-
1614

1715
@XStreamAlias(value = "game")
1816
class Game(UUID: String = GamePlugin.PLUGIN_UUID): RoundBasedGameInstance() {
@@ -70,9 +68,9 @@ class Game(UUID: String = GamePlugin.PLUGIN_UUID): RoundBasedGameInstance() {
7068
it to gameState.getPointsForPlayer(it)
7169
}.toMap()
7270

73-
if (scoreMap[Team.ONE]!! > scoreMap[Team.TWO]!!)
71+
if (scoreMap.getValue(Team.ONE) > scoreMap.getValue(Team.TWO))
7472
return WinCondition(Team.ONE, WinReason.DIFFERING_SCORES)
75-
if (scoreMap[Team.TWO]!! > scoreMap[Team.ONE]!!)
73+
if (scoreMap.getValue(Team.TWO) > scoreMap.getValue(Team.ONE))
7674
return WinCondition(Team.TWO, WinReason.DIFFERING_SCORES)
7775
return WinCondition(null, WinReason.EQUAL_SCORE)
7876
}
@@ -96,7 +94,7 @@ class Game(UUID: String = GamePlugin.PLUGIN_UUID): RoundBasedGameInstance() {
9694
val winCondition = checkWinCondition()
9795

9896
var cause: ScoreCause = ScoreCause.REGULAR
99-
var reason: String = ""
97+
var reason = ""
10098
var score: Int = Constants.LOSE_SCORE
10199
val points = gameState.getPointsForPlayer(team)
102100

@@ -143,19 +141,15 @@ class Game(UUID: String = GamePlugin.PLUGIN_UUID): RoundBasedGameInstance() {
143141

144142
@Throws(InvalidMoveException::class, InvalidGameStateException::class)
145143
override fun onRoundBasedAction(fromPlayer: Player, data: ProtocolMessage) {
146-
// This check is already done by super.onAction()
147-
assert(fromPlayer == activePlayer)
148-
149144
try {
150145
if (data !is Move)
151-
throw InvalidMoveException("${fromPlayer.displayName} hat keinen validen Zug gesendet.")
146+
throw InvalidMoveException("${fromPlayer.displayName} did not send a proper move.")
152147

153148
logger.debug("Current State: $gameState")
154149
logger.debug("Performing Move $data")
155150
GameRuleLogic.performMove(gameState, data)
156-
gameState.turn++
151+
next(if(gameState.orderedColors.isNotEmpty()) gameState.currentPlayer else null)
157152
logger.debug("Current Board:\n${gameState.board}")
158-
next(gameState.currentPlayer)
159153
} catch(e: InvalidMoveException) {
160154
super.catchInvalidMove(e, fromPlayer)
161155
}

plugin/src/shared/sc/plugin2020/GameState.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ class GameState @JvmOverloads constructor(
2020
override var lastMove: Move? = null
2121
): TwoPlayerGameState<Player>(Team.RED) {
2222

23+
override val round: Int
24+
get() = turn / 2
25+
2326
@XStreamOmitField
2427
private var allPieces: Collection<Piece> = undeployedBluePieces + undeployedRedPieces + board.getPieces()
2528

plugin/src/shared/sc/plugin2021/GameState.kt

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@ package sc.plugin2021
22

33
import com.thoughtworks.xstream.annotations.XStreamAlias
44
import com.thoughtworks.xstream.annotations.XStreamAsAttribute
5+
import org.slf4j.LoggerFactory
56
import sc.api.plugins.TwoPlayerGameState
67
import sc.framework.plugins.Player
78
import sc.api.plugins.ITeam
9+
import sc.api.plugins.exceptions.GameLogicException
10+
import sc.framework.plugins.RoundBasedGameInstance
811
import sc.plugin2021.util.Constants
912
import sc.plugin2021.util.GameRuleLogic
1013

@@ -13,11 +16,15 @@ class GameState @JvmOverloads constructor(
1316
override var first: Player = Player(Team.ONE),
1417
override var second: Player = Player(Team.TWO),
1518
override var lastMove: Move? = null,
16-
startTurn: Int = 1,
19+
startTurn: Int = 0,
1720
val startColor: Color = Color.BLUE,
1821
@XStreamAsAttribute val startPiece: PieceShape = GameRuleLogic.getRandomPentomino()
1922
): TwoPlayerGameState<Player>(Team.ONE) {
2023

24+
companion object {
25+
val logger = LoggerFactory.getLogger(GameState::class.java)
26+
}
27+
2128
@XStreamAsAttribute
2229
override val board: Board = Board()
2330

@@ -44,7 +51,7 @@ class GameState @JvmOverloads constructor(
4451
get() = orderedColors[currentColorIndex]
4552

4653
@XStreamAsAttribute
47-
override var turn: Int = 1
54+
override var turn: Int = 0
4855
set(value) {
4956
advance(value - field)
5057
field = value
@@ -65,6 +72,9 @@ class GameState @JvmOverloads constructor(
6572
private fun advance(turns: Int) {
6673
if (turns < 0) throw IndexOutOfBoundsException("Can't go back in turns (Request was $turns), expected value bigger than $turn")
6774

75+
if (orderedColors.isEmpty())
76+
throw GameLogicException("Game has ended...")
77+
6878
val roundIncrementHelper = currentColorIndex + turns
6979
currentColorIndex = roundIncrementHelper % orderedColors.size
7080
round += (roundIncrementHelper - currentColorIndex) / orderedColors.size
@@ -91,7 +101,8 @@ class GameState @JvmOverloads constructor(
91101
*/
92102
fun removeActiveColor() {
93103
orderedColors.remove(currentColor)
94-
currentColorIndex = (currentColorIndex + orderedColors.size - 1) % orderedColors.size
104+
if (orderedColors.isNotEmpty())
105+
currentColorIndex = (currentColorIndex + orderedColors.size - 1) % orderedColors.size
95106
}
96107

97108
override fun toString(): String = "GameState $round/$turn -> $currentColor"

plugin/src/shared/sc/plugin2021/util/GameRuleLogic.kt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
package sc.plugin2021.util
22

3+
import org.slf4j.LoggerFactory
4+
import sc.api.plugins.exceptions.GameLogicException
35
import sc.plugin2021.*
46
import sc.shared.InvalidMoveException
57

68
object GameRuleLogic {
9+
val logger = LoggerFactory.getLogger(GameLogicException::class.java)
10+
711
const val SMALLEST_SCORE_POSSIBLE = -89
812

913
// TODO: Add all the needed logic as static (@JvmStatic) functions here
@@ -47,13 +51,16 @@ object GameRuleLogic {
4751
gameState.removeActiveColor()
4852
}
4953
}
54+
if (gameState.orderedColors.isNotEmpty())
55+
gameState.turn++
56+
gameState.lastMove = move
5057
}
5158

5259
/** Checks if the given [move] has the right [Color]. */
5360
@JvmStatic
5461
fun validateMoveColor(gameState: GameState, move: Move) {
5562
if (move.color != gameState.currentColor)
56-
throw InvalidMoveException("The given Move comes from an inactive color", move)
63+
throw InvalidMoveException("Expected move from ${gameState.currentColor}", move)
5764
}
5865

5966
/** Checks if the given [move] is able to be performed for the given [gameState]. */

plugin/src/test/sc/plugin2021/GameRuleLogicTest.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,15 +67,16 @@ class GameRuleLogicTest: StringSpec({
6767
assertThrows<InvalidMoveException> {
6868
invalidPieces.forEach {
6969
GameRuleLogic.performMove(gameState, SetMove(it))
70-
gameState.turn++
7170
}
7271
}
7372
}
7473
assertDoesNotThrow {
7574
val gameState = GameState(startPiece = PieceShape.PENTO_S)
75+
println(gameState.orderedColors)
7676
validPieces.forEach {
77+
println("Move: ${it.color} - Active: ${gameState.currentColor}")
78+
println("Turn: ${gameState.turn}")
7779
GameRuleLogic.performMove(gameState, SetMove(it))
78-
gameState.turn++
7980
}
8081
}
8182
}

plugin/src/test/sc/plugin2021/GameStateTest.kt

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -75,52 +75,46 @@ class GameStateTest: StringSpec({
7575
xstream.fromXML(xstream.toXML(state)) shouldBe state
7676
}
7777
"GameStates advance accordingly" {
78-
var gameState = GameState(startTurn = 3)
79-
gameState.turn shouldBe 3
78+
var gameState = GameState(startTurn = 2)
79+
gameState.turn shouldBe 2
8080
gameState.round shouldBe 1
8181
gameState.currentColor shouldBe Color.RED
8282

8383
gameState = GameState()
84-
gameState.turn shouldBe 1
84+
gameState.turn shouldBe 0
8585
gameState.round shouldBe 1
8686
gameState.currentColor shouldBe Color.BLUE
8787

8888
gameState.turn +=10
89-
gameState.turn shouldBe 11
89+
gameState.turn shouldBe 10
9090
gameState.round shouldBe 3
9191
gameState.currentColor shouldBe Color.RED
9292

9393
gameState.turn++
94-
gameState.turn shouldBe 12
94+
gameState.turn shouldBe 11
9595
gameState.round shouldBe 3
9696
gameState.currentColor shouldBe Color.GREEN
9797

9898
gameState.turn++
99-
gameState.turn shouldBe 13
99+
gameState.turn shouldBe 12
100100
gameState.round shouldBe 4
101101
gameState.currentColor shouldBe Color.BLUE
102102
}
103103
"Passed out colors behave correctly" {
104-
val gameState = GameState(startTurn = 3)
104+
val gameState = GameState(startTurn = 2)
105105
gameState.orderedColors shouldBe listOf(Color.BLUE, Color.YELLOW, Color.RED, Color.GREEN)
106106
gameState.currentColor shouldBe Color.RED
107107

108108
GameRuleLogic.performMove(gameState, PassMove(Color.RED))
109109
gameState.orderedColors shouldBe listOf(Color.BLUE, Color.YELLOW, Color.GREEN)
110-
gameState.currentColor shouldBe Color.YELLOW
111-
gameState.turn++
112110
gameState.currentColor shouldBe Color.GREEN
113111

114112
GameRuleLogic.performMove(gameState, PassMove(Color.GREEN))
115113
gameState.orderedColors shouldBe listOf(Color.BLUE, Color.YELLOW)
116-
gameState.currentColor shouldBe Color.YELLOW
117-
gameState.turn++
118114
gameState.currentColor shouldBe Color.BLUE
119115

120116
GameRuleLogic.performMove(gameState, PassMove(Color.BLUE))
121117
gameState.orderedColors shouldBe listOf(Color.YELLOW)
122118
gameState.currentColor shouldBe Color.YELLOW
123-
gameState.turn++
124-
gameState.currentColor shouldBe Color.YELLOW
125119
}
126120
})

plugin/src/test/sc/plugin2021/GameTest.kt

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,27 @@ package sc.plugin2021
22

33
import io.kotlintest.shouldBe
44
import io.kotlintest.specs.StringSpec
5+
import sc.plugin2020.util.Constants
6+
import sc.shared.PlayerScore
7+
import sc.shared.ScoreCause
58

69
class GameTest: StringSpec({
7-
"Start a game" {
10+
"Start and stop" {
11+
Color.BLUE.team
812
val game = Game()
13+
val state = game.gameState
914
val playerOne = game.onPlayerJoined()
1015
val playerTwo = game.onPlayerJoined()
1116

1217
playerOne.color shouldBe Team.ONE
1318
playerTwo.color shouldBe Team.TWO
1419
game.start()
20+
21+
game.onAction(state.currentPlayer, PassMove(state.currentColor))
22+
game.onAction(state.currentPlayer, PassMove(state.currentColor))
23+
game.onAction(state.currentPlayer, PassMove(state.currentColor))
24+
game.onAction(state.currentPlayer, PassMove(state.currentColor))
25+
26+
game.playerScores shouldBe List(2) { PlayerScore(ScoreCause.REGULAR, "", Constants.DRAW_SCORE, -178) }
1527
}
1628
})

server/src/sc/server/gaming/GameRoom.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -584,7 +584,7 @@ public synchronized void pause(boolean pause) {
584584

585585
logger.info("Switching PAUSE from {} to {}.", isPauseRequested(), pause);
586586
this.pauseRequested = pause;
587-
RoundBasedGameInstance<Player> pausableGame = (RoundBasedGameInstance<Player>) this.game;
587+
RoundBasedGameInstance pausableGame = (RoundBasedGameInstance) this.game;
588588
// pause game after current turn has finished
589589
pausableGame.setPauseMode(pause);
590590

@@ -615,7 +615,7 @@ public synchronized void step(boolean forced)
615615
}
616616
if (isPauseRequested()) {
617617
logger.info("Stepping.");
618-
((RoundBasedGameInstance<Player>) this.game).afterPause();
618+
((RoundBasedGameInstance) this.game).afterPause();
619619
} else {
620620
logger.warn("Can't step if the game is not paused.");
621621
}
@@ -706,7 +706,7 @@ protected void setStatus(GameStatus status) {
706706
}
707707

708708
/**
709-
* Remove specific player by calling {@link IGameInstance#onPlayerLeft(Player) onPlayerLeft(player)}
709+
* Remove specific player by calling {@link IGameInstance#onPlayerLeft(Player, ScoreCause) onPlayerLeft(player)}
710710
*
711711
* @param player to be removed
712712
*/

socha-sdk/src/server-api/sc/api/plugins/IGameState.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,4 @@ interface IGameState : ProtocolMessage, Cloneable {
3131

3232
/** Aktuelle Rundenzahl */
3333
val round: Int
34-
get() = turn / 2
3534
}

socha-sdk/src/server-api/sc/api/plugins/TwoPlayerGameState.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ abstract class TwoPlayerGameState<P : Player>(
2424
abstract val currentTeam: ITeam<*>
2525

2626
/** The Player whose team's turn it is. */
27-
val currentPlayer: P
27+
open val currentPlayer: P
2828
get() = getPlayer(currentTeam)!!
2929

3030
/** The player opposite to the currently active one. */

0 commit comments

Comments
 (0)