Skip to content

Commit 8c72db9

Browse files
committed
fix: RectangularBoard serialization - all tests pass
1 parent c59f78c commit 8c72db9

File tree

6 files changed

+39
-16
lines changed

6 files changed

+39
-16
lines changed

.dev/githooks/commit-msg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ scopes_file=".dev/scopes.txt"
55
test -r $scopes_file &&
66
scopes="($(cat "$scopes_file" | sed '/^\(#.*\|\)$/d' | sed ':a;N;s/\n/|/g;ta'))"
77

8-
grep -Eq "(fix|feat|docs|style|refactor|test|chore|rework|release)(\(${scopes:-.*}(/.+)?\))?: [a-z]" "$1"
8+
grep -Eq "(fix|feat|docs|style|refactor|test|chore|rework|release)(\(${scopes:-.*}(/.+)?\))?: [A-z]" "$1"
99
result=$?
1010
if test $result -ne 0
1111
then echo "Please check the guidelines at http://karma-runner.github.io/latest/dev/git-commit-msg.html$(test -n "$scopes" && echo ", the scope should be one of $scopes as defined in $scopes_file")"

plugin/src/test/kotlin/sc/plugin2023/GamePlayTest.kt

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import io.kotest.matchers.booleans.*
77
import io.kotest.matchers.collections.shouldNotBeEmpty
88
import io.kotest.matchers.shouldBe
99
import io.kotest.matchers.shouldNotBe
10+
import org.slf4j.LoggerFactory
1011
import sc.api.plugins.IGamePlugin
1112
import sc.api.plugins.IGameState
1213
import sc.api.plugins.Team
@@ -25,6 +26,7 @@ import kotlin.time.ExperimentalTime
2526
* It is the only test that should stay between seasons. */
2627
@OptIn(ExperimentalTime::class)
2728
class GamePlayTest: WordSpec({
29+
val logger = LoggerFactory.getLogger(GamePlayTest::class.java)
2830
isolationMode = IsolationMode.SingleInstance
2931
fun createGame() = IGamePlugin.loadPlugin().createGame() as AbstractGame
3032
"A Game" should {
@@ -62,13 +64,14 @@ class GamePlayTest: WordSpec({
6264
var finalState: Int? = null
6365
game.addGameListener(object: IGameListener {
6466
override fun onGameOver(results: Map<Player, PlayerScore>) {
65-
println("Game over: $results")
67+
logger.info("Game over: $results")
6668
}
6769

6870
override fun onStateChanged(data: IGameState, observersOnly: Boolean) {
6971
data.hashCode() shouldNotBe finalState
7072
// hashing it to avoid cloning, since we get the original mutable object
7173
finalState = data.hashCode()
74+
logger.debug("Updating state to $finalState")
7275
}
7376
})
7477

@@ -77,14 +80,18 @@ class GamePlayTest: WordSpec({
7780
try {
7881
val condition = game.checkWinCondition()
7982
if (condition != null) {
80-
println("Game ended with $condition")
83+
logger.info("Game ended with $condition")
8184
break
8285
}
86+
87+
if(finalState != null)
88+
finalState shouldBe state.hashCode()
89+
8390
val moves = state.getPossibleMoves()
8491
moves.shouldNotBeEmpty()
8592
game.onAction(game.players[state.currentTeam.index], moves.random())
8693
} catch (e: Exception) {
87-
println(e.message)
94+
logger.warn(e.message)
8895
break
8996
}
9097
}

sdk/src/main/server-api/sc/api/plugins/RectangularBoard.kt

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ open class RectangularBoard<FIELD: IField<FIELD>>(
6868
override fun toString() =
6969
gameField.joinToString(separator = "\n") { row ->
7070
row.joinToString(separator = "") { it.toString() }
71-
}
71+
}.ifEmpty { "Empty Board@" + System.identityHashCode(this) }
7272

7373
override fun clone() = RectangularBoard(this.gameField)
7474

@@ -98,15 +98,24 @@ open class RectangularBoard<FIELD: IField<FIELD>>(
9898
}
9999
}
100100

101-
override fun containsAll(elements: Collection<FIELD>): Boolean {
102-
TODO("Not yet implemented")
103-
}
101+
override fun containsAll(elements: Collection<FIELD>): Boolean = elements.all { contains(it) }
104102

105-
override fun contains(element: FIELD): Boolean {
106-
TODO("Not yet implemented")
107-
}
103+
override fun contains(element: FIELD): Boolean = gameField.any { it.contains(element) }
108104

109105
// TODO do this properly for non-squared boards
110106
operator fun get(index: Int): FIELD =
111107
gameField[index.div(gameField.size)][index.mod(gameField.size)]
108+
109+
fun readResolve(): Any {
110+
if(gameField == null) {
111+
val field = RectangularBoard::class.java.getDeclaredField("gameField")
112+
field.isAccessible = true
113+
field.set(this, ArrayList<MutableList<FIELD>>())
114+
}
115+
return this
116+
}
117+
118+
override fun equals(other: Any?) = gameField == (other as? RectangularBoard<*>)?.gameField
119+
120+
override fun hashCode(): Int = gameField.hashCode()
112121
}
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package sc.framework
22

3-
interface PublicCloneable<T: Cloneable>: Cloneable {
3+
import java.io.Serializable
4+
5+
interface PublicCloneable<T: Cloneable>: Cloneable, Serializable {
46
/** Eine tiefe Kopie des Objekts. */
57
public override fun clone(): T
68
}

sdk/src/main/server-api/sc/framework/plugins/AbstractGame.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,8 @@ abstract class AbstractGame(override val pluginUUID: String): IGameInstance, Pau
242242

243243
protected fun notifyOnNewState(mementoState: IGameState, observersOnly: Boolean) {
244244
listeners.forEach {
245-
logger.debug("Notifying $it about new game state")
245+
if(logger.isDebugEnabled)
246+
logger.debug("Notifying $it about new game state with hash ${mementoState.hashCode()}")
246247
try {
247248
it.onStateChanged(mementoState, observersOnly)
248249
} catch(e: Exception) {

sdk/src/test/config/sc/helpers/XStreamMatcher.kt

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,16 @@ object XStreamProjectListener: ProjectListener {
1515

1616
lateinit var testXStream: XStream
1717

18-
inline infix fun <reified T : Any> T.shouldSerializeTo(serialized: String)
19-
= checkSerialization(testXStream, this, serialized)
18+
inline infix fun <reified T: Any> T.shouldSerializeTo(serialized: String) =
19+
checkSerialization(testXStream, this, serialized)
2020

2121
inline fun <reified T: Any> checkSerialization(
2222
xStream: XStream, obj: T, serialized: String,
23-
matcher: (obj: T, deserialized: T) -> Unit = { original, deserialized -> deserialized shouldBe original }) {
23+
matcher: (obj: T, deserialized: T) -> Unit = { original, deserialized ->
24+
deserialized shouldBe original
25+
deserialized.hashCode() shouldBe original.hashCode()
26+
},
27+
) {
2428
xStream.toXML(obj) shouldBe serialized
2529
val deserialized = xStream.fromXML(serialized)
2630
deserialized.javaClass shouldBe obj.javaClass

0 commit comments

Comments
 (0)