Skip to content

Commit 89359a0

Browse files
SKoschnickeanarchuser
authored andcommitted
fix(protocol): remove self-referencing playerColor
refactor(plugin): determine points per color using undeployed shapes fix(plugin): change `is first move` calculation to use undeployed
1 parent b60b354 commit 89359a0

File tree

7 files changed

+82
-74
lines changed

7 files changed

+82
-74
lines changed

plugin/src/client/sc/plugin2020/AbstractClient.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ public void onRoomMessage(String roomId, Object data) {
8888
if(data instanceof MoveRequest) {
8989
this.handler.onRequestAction();
9090
} else if(data instanceof WelcomeMessage) {
91-
this.color = (Team) ((WelcomeMessage) data).getPlayerColor();
91+
this.color = Team.valueOf(((WelcomeMessage) data).getPlayerColor());
9292
}
9393
this.roomId = roomId;
9494
}

plugin/src/client/sc/plugin2021/AbstractClient.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ abstract class AbstractClient @Throws(IOException::class) constructor(
7474
handler.onRequestAction()
7575
}
7676
if(data is WelcomeMessage) {
77-
team = data.playerColor as Team
77+
team = Team.valueOf(data.playerColor.toUpperCase())
7878
}
7979
roomID = roomId
8080
}

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ class GameState @JvmOverloads constructor(
3838
it to mutableListOf<Piece>()
3939
}.toMap()
4040

41+
@XStreamAsAttribute
42+
val lastMoveMono: MutableMap<Color, Boolean> = mutableMapOf()
43+
4144
override val currentTeam
4245
get() = currentColor.team
4346

@@ -95,8 +98,9 @@ class GameState @JvmOverloads constructor(
9598
(team as Team).colors.map { getPointsForColor(it) }.sum()
9699

97100
private fun getPointsForColor(color: Color): Int {
98-
val pieces = deployedPieces[color].let{listOf<Piece>()}
99-
return GameRuleLogic.getPointsFromDeployedPieces(pieces)
101+
val pieces = undeployedPieceShapes.getValue(color)
102+
val lastMono = lastMoveMono[color] ?: false
103+
return GameRuleLogic.getPointsFromUndeployed(pieces, lastMono)
100104
}
101105

102106
/** Removes the currently active color from the queue.

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

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,16 @@ object GameRuleLogic {
99

1010
const val SMALLEST_SCORE_POSSIBLE = -89
1111

12-
/** Calculates the score for the given list in pieces.
13-
* Assumes the game has ended and the pieces are in order of placement.
12+
/**
13+
* Calculates the score for a given set of unused [PieceShape]s.
14+
* Needs an additional flag to give out 5 extra points if the Monomino was placed last.
1415
*/
1516
@JvmStatic
16-
fun getPointsFromDeployedPieces(deployed: List<Piece>): Int {
17-
if (deployed.size == Constants.TOTAL_PIECE_SHAPES) {
18-
// Perfect score: 15 Points completion + 5 Points for solitary block last
19-
return if (deployed.last().kind == PieceShape.MONO) 20
20-
// Placed each piece: 15 Points completion bonus
21-
else 15
17+
fun getPointsFromUndeployed(undeployed: Set<PieceShape>, monoLast: Boolean = false): Int {
18+
return if (undeployed.isEmpty()) {
19+
if (monoLast) 20 else 15
2220
}
23-
// One malus point per block per piece not placed
24-
return SMALLEST_SCORE_POSSIBLE + deployed.map { it.coordinates.size }.sum()
21+
else - undeployed.map { it.coordinates.size }.sum()
2522
}
2623

2724
/** Performs the given [move] on the [gameState] if possible. */
@@ -45,8 +42,10 @@ object GameRuleLogic {
4542
gameState.deployedPieces.getValue(move.color).add(move.piece)
4643

4744
// If it was the last piece for this color, remove him from the turn queue
48-
if (gameState.undeployedPieceShapes.getValue(move.color).isEmpty())
45+
if (gameState.undeployedPieceShapes.getValue(move.color).isEmpty()) {
46+
gameState.lastMoveMono += move.color to (move.piece.kind == PieceShape.MONO)
4947
gameState.removeActiveColor()
48+
}
5049
}
5150
}
5251
if (gameState.orderedColors.isNotEmpty())
@@ -141,7 +140,7 @@ object GameRuleLogic {
141140

142141
@JvmStatic
143142
fun isFirstMove(gameState: GameState) =
144-
gameState.deployedPieces.getValue(gameState.currentColor).isEmpty()
143+
gameState.undeployedPieceShapes.getValue(gameState.currentColor).size == Constants.TOTAL_PIECE_SHAPES
145144

146145
/** Returns a random pentomino which is not the `x` one (Used to get a valid starting piece). */
147146
@JvmStatic

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,23 +79,23 @@ class GameRuleLogicTest: StringSpec({
7979
}
8080
}
8181
"Point score calculation works" {
82-
GameRuleLogic.getPointsFromDeployedPieces(emptyList()) shouldBe GameRuleLogic.SMALLEST_SCORE_POSSIBLE
82+
GameRuleLogic.getPointsFromUndeployed(emptySet()) shouldBe GameRuleLogic.SMALLEST_SCORE_POSSIBLE
8383

8484
val fewPieces = listOf(
8585
Piece(Color.BLUE, PieceShape.TRIO_I, Rotation.NONE, true),
8686
Piece(Color.BLUE, PieceShape.TETRO_O, Rotation.NONE, true),
8787
Piece(Color.BLUE, PieceShape.PENTO_P, Rotation.NONE, true),
8888
Piece(Color.BLUE, PieceShape.MONO, Rotation.NONE, true)
8989
)
90-
GameRuleLogic.getPointsFromDeployedPieces(fewPieces) shouldBe -76
90+
GameRuleLogic.getPointsFromUndeployed(fewPieces.map{it.kind}.toSet()) shouldBe -76
9191

9292
val allPieces = PieceShape.shapes.map{
9393
Piece(Color.BLUE, it.key, Rotation.NONE, false)
9494
}.toList()
95-
GameRuleLogic.getPointsFromDeployedPieces(allPieces) shouldBe 15
95+
GameRuleLogic.getPointsFromUndeployed(allPieces.map{it.kind}.toSet(), false) shouldBe 15
9696

9797
val perfectPieces = allPieces.reversed()
98-
GameRuleLogic.getPointsFromDeployedPieces(perfectPieces) shouldBe 20
98+
GameRuleLogic.getPointsFromUndeployed(perfectPieces.map{it.kind}.toSet(), true) shouldBe 20
9999
}
100100
"After the color check, PassMoves throw" {
101101
val state = GameState()

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

Lines changed: 57 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -10,61 +10,61 @@ import sc.shared.InvalidMoveException
1010

1111
class GameStateTest: StringSpec({
1212
"GameState starts correctly" {
13-
val gameState = GameState()
13+
val state = GameState()
1414

15-
gameState.board shouldBe Board()
15+
state.board shouldBe Board()
1616

17-
gameState.undeployedPieceShapes[Color.BLUE] shouldBe PieceShape.values().toSet()
18-
gameState.undeployedPieceShapes[Color.YELLOW] shouldBe PieceShape.values().toSet()
19-
gameState.undeployedPieceShapes[Color.RED] shouldBe PieceShape.values().toSet()
20-
gameState.undeployedPieceShapes[Color.GREEN] shouldBe PieceShape.values().toSet()
17+
state.undeployedPieceShapes[Color.BLUE] shouldBe PieceShape.values().toSet()
18+
state.undeployedPieceShapes[Color.YELLOW] shouldBe PieceShape.values().toSet()
19+
state.undeployedPieceShapes[Color.RED] shouldBe PieceShape.values().toSet()
20+
state.undeployedPieceShapes[Color.GREEN] shouldBe PieceShape.values().toSet()
2121

22-
gameState.deployedPieces[Color.BLUE] shouldBe mutableListOf<Piece>()
23-
gameState.deployedPieces[Color.YELLOW] shouldBe mutableListOf<Piece>()
24-
gameState.deployedPieces[Color.RED] shouldBe mutableListOf<Piece>()
25-
gameState.deployedPieces[Color.GREEN] shouldBe mutableListOf<Piece>()
22+
state.deployedPieces[Color.BLUE] shouldBe mutableListOf<Piece>()
23+
state.deployedPieces[Color.YELLOW] shouldBe mutableListOf<Piece>()
24+
state.deployedPieces[Color.RED] shouldBe mutableListOf<Piece>()
25+
state.deployedPieces[Color.GREEN] shouldBe mutableListOf<Piece>()
2626

2727
// TODO: adjust values accordingly
28-
gameState.getPointsForPlayer(Team.ONE) shouldBe -178 // Twice the lowest score, once per color
29-
gameState.getPointsForPlayer(Team.TWO) shouldBe -178
28+
state.getPointsForPlayer(Team.ONE) shouldBe -178 // Twice the lowest score, once per color
29+
state.getPointsForPlayer(Team.TWO) shouldBe -178
3030
}
3131
"GameStates know currently active Color" {
3232
var colorIter = Color.RED
33-
val gameState = GameState(startColor = colorIter)
33+
val state = GameState(startColor = colorIter)
3434

3535
for (x in 0 until 4) {
36-
gameState.currentColor shouldBe colorIter
37-
gameState.turn++
36+
state.currentColor shouldBe colorIter
37+
state.turn++
3838
colorIter = colorIter.next
3939
}
4040

41-
gameState.currentColor shouldBe Color.RED
42-
gameState.turn++
43-
gameState.currentColor shouldBe Color.GREEN
44-
gameState.turn += 2
45-
gameState.currentColor shouldBe Color.YELLOW
41+
state.currentColor shouldBe Color.RED
42+
state.turn++
43+
state.currentColor shouldBe Color.GREEN
44+
state.turn += 2
45+
state.currentColor shouldBe Color.YELLOW
4646
}
4747
"Pieces can only be placed once" {
48-
val gameState = GameState(startPiece = PieceShape.PENTO_I)
48+
val state = GameState(startPiece = PieceShape.PENTO_I)
4949
val move = SetMove(
5050
Piece(Color.BLUE, PieceShape.PENTO_I, Rotation.RIGHT, true))
5151

52-
gameState.undeployedPieceShapes.getValue(Color.BLUE).size shouldBe 21
53-
gameState.deployedPieces.getValue(Color.BLUE).size shouldBe 0
52+
state.undeployedPieceShapes.getValue(Color.BLUE).size shouldBe 21
53+
state.deployedPieces.getValue(Color.BLUE).size shouldBe 0
5454
assertDoesNotThrow {
55-
GameRuleLogic.performMove(gameState, move)
55+
GameRuleLogic.performMove(state, move)
5656
}
57-
gameState.undeployedPieceShapes.getValue(Color.BLUE).size shouldBe 20
58-
gameState.deployedPieces.getValue(Color.BLUE).size shouldBe 1
59-
gameState.deployedPieces.getValue(Color.BLUE)[0] shouldBe move.piece
57+
state.undeployedPieceShapes.getValue(Color.BLUE).size shouldBe 20
58+
state.deployedPieces.getValue(Color.BLUE).size shouldBe 1
59+
state.deployedPieces.getValue(Color.BLUE)[0] shouldBe move.piece
6060

61-
gameState.turn += 4
61+
state.turn += 4
6262
assertThrows<InvalidMoveException> {
63-
GameRuleLogic.performMove(gameState, move)
63+
GameRuleLogic.performMove(state, move)
6464
}
65-
gameState.undeployedPieceShapes.getValue(Color.BLUE).size shouldBe 20
66-
gameState.deployedPieces.getValue(Color.BLUE).size shouldBe 1
67-
gameState.deployedPieces.getValue(Color.BLUE)[0] shouldBe move.piece
65+
state.undeployedPieceShapes.getValue(Color.BLUE).size shouldBe 20
66+
state.deployedPieces.getValue(Color.BLUE).size shouldBe 1
67+
state.deployedPieces.getValue(Color.BLUE)[0] shouldBe move.piece
6868

6969
}
7070
"XML conversion works" {
@@ -73,31 +73,36 @@ class GameStateTest: StringSpec({
7373

7474
xstream.fromXML(xstream.toXML(state)).toString() shouldBe state.toString()
7575
xstream.fromXML(xstream.toXML(state)) shouldBe state
76+
77+
val transformed = xstream.fromXML(xstream.toXML(GameState())) as GameState
78+
transformed.deployedPieces shouldBe null
79+
GameRuleLogic.isFirstMove(transformed) shouldBe true
80+
transformed.getPointsForPlayer(Team.ONE)
7681
}
7782
"GameStates advance accordingly" {
78-
var gameState = GameState(startTurn = 2)
79-
gameState.turn shouldBe 2
80-
gameState.round shouldBe 1
81-
gameState.currentColor shouldBe Color.RED
83+
var state = GameState(startTurn = 2)
84+
state.turn shouldBe 2
85+
state.round shouldBe 1
86+
state.currentColor shouldBe Color.RED
8287

83-
gameState = GameState()
84-
gameState.turn shouldBe 0
85-
gameState.round shouldBe 1
86-
gameState.currentColor shouldBe Color.BLUE
88+
state = GameState()
89+
state.turn shouldBe 0
90+
state.round shouldBe 1
91+
state.currentColor shouldBe Color.BLUE
8792

88-
gameState.turn +=10
89-
gameState.turn shouldBe 10
90-
gameState.round shouldBe 3
91-
gameState.currentColor shouldBe Color.RED
93+
state.turn +=10
94+
state.turn shouldBe 10
95+
state.round shouldBe 3
96+
state.currentColor shouldBe Color.RED
9297

93-
gameState.turn++
94-
gameState.turn shouldBe 11
95-
gameState.round shouldBe 3
96-
gameState.currentColor shouldBe Color.GREEN
98+
state.turn++
99+
state.turn shouldBe 11
100+
state.round shouldBe 3
101+
state.currentColor shouldBe Color.GREEN
97102

98-
gameState.turn++
99-
gameState.turn shouldBe 12
100-
gameState.round shouldBe 4
101-
gameState.currentColor shouldBe Color.BLUE
103+
state.turn++
104+
state.turn shouldBe 12
105+
state.round shouldBe 4
106+
state.currentColor shouldBe Color.BLUE
102107
}
103108
})

socha-sdk/src/framework/sc/shared/WelcomeMessage.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,6 @@ private constructor(
1515

1616
constructor(color: ITeam<*>): this(color.toString().toLowerCase())
1717

18-
val playerColor: ITeam<*>
19-
get() = playerColor
18+
val playerColor: String
19+
get() = color
2020
}

0 commit comments

Comments
 (0)