Skip to content

Commit e6f8650

Browse files
TomekRDxeruf
authored andcommitted
feat(plugin26): add Board, add Fields
1 parent 868a439 commit e6f8650

File tree

5 files changed

+187
-6
lines changed

5 files changed

+187
-6
lines changed
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package sc.plugin2026
2+
3+
import com.thoughtworks.xstream.annotations.XStreamAlias
4+
import com.thoughtworks.xstream.annotations.XStreamImplicit
5+
import sc.api.plugins.IBoard
6+
import sc.plugin2026.FieldState.OBSTRUCTED
7+
import sc.plugin2026.util.*
8+
import java.util.*
9+
10+
/** Spielbrett für Piranhas mit [PiranhaConstants.BOARD_LENGTH]² Feldern. */
11+
@XStreamAlias(value = "board")
12+
class Board : IBoard {
13+
14+
@XStreamImplicit(itemFieldName = "fields")
15+
private var fields: Array<Array<Field>>
16+
17+
constructor() {
18+
this.fields = randomFields()
19+
}
20+
21+
22+
constructor(boardToClone: Board) {
23+
this.fields = generateFields { x, y -> boardToClone.fields[x][y].clone() }
24+
}
25+
26+
public override fun clone(): Board = Board(this)
27+
28+
override fun equals(other: Any?): Boolean = other is Board && Arrays.equals(other.fields, this.fields)
29+
30+
private fun generateFields(generator: (Int, Int) -> Field): Array<Array<Field>> {
31+
return Array(PiranhaConstants.BOARD_LENGTH) { x ->
32+
Array(PiranhaConstants.BOARD_LENGTH) { y ->
33+
generator(x, y)
34+
}
35+
}
36+
}
37+
38+
/** Erstellt eine zufälliges Spielbrett. */
39+
private fun randomFields(): Array<Array<Field>> {
40+
val fields = generateFields { x, y -> Field(x, y) }
41+
42+
// Place Piranhas
43+
for(index in 1 until PiranhaConstants.BOARD_LENGTH - 1) {
44+
fields[0][index].setPiranha(Team.ONE)
45+
fields[PiranhaConstants.BOARD_LENGTH - 1][index].setPiranha(Team.ONE)
46+
fields[index][0].setPiranha(Team.TWO)
47+
fields[index][PiranhaConstants.BOARD_LENGTH - 1].setPiranha(Team.TWO)
48+
}
49+
50+
// Place Obstacles
51+
// only consider fields in the middle of the board
52+
var blockableFields: List<Field> = fields.slice(PiranhaConstants.OBSTACLES_START..PiranhaConstants.OBSTACLES_END).flatMap { it.slice(PiranhaConstants.OBSTACLES_START..PiranhaConstants.OBSTACLES_END) }
53+
// set fields with randomly selected coordinates to blocked
54+
// coordinates may not lay on same horizontal, vertical or diagonal lines with other selected coordinates
55+
for(i in 0 until PiranhaConstants.NUM_OBSTACLES) {
56+
val indexOfFieldToBlock = Math.floor(Math.random() * blockableFields.size).toInt()
57+
val selectedField = blockableFields[indexOfFieldToBlock]
58+
selectedField.state = OBSTRUCTED
59+
blockableFields = blockableFields.filter { field ->
60+
!(field.x == selectedField.x || field.y == selectedField.y ||
61+
field.x - field.y == selectedField.x - selectedField.y ||
62+
field.x + field.y == selectedField.x + selectedField.y)
63+
}
64+
}
65+
return fields
66+
}
67+
68+
override fun toString() =
69+
"Board " + fields.joinToString(" ", "[", "]") { column -> column.joinToString(", ", prefix = "[", postfix = "]") { it.toString() } }
70+
71+
val line = "-".repeat(PiranhaConstants.BOARD_LENGTH + 2)
72+
fun prettyString(): String {
73+
val map = Array(PiranhaConstants.BOARD_LENGTH) { StringBuilder("|") }
74+
fields.forEach {
75+
it.forEachIndexed { index, field ->
76+
map[index].append(field.state.asLetter())
77+
}
78+
}
79+
return map.joinToString("\n", line + "\n", "\n" + line) { it.append('|').toString() }
80+
}
81+
82+
fun getField(x: Int, y: Int): Field =
83+
this.fields[x][y]
84+
85+
}
86+
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package sc.plugin2026
2+
3+
import com.thoughtworks.xstream.annotations.XStreamAlias
4+
import com.thoughtworks.xstream.annotations.XStreamAsAttribute
5+
import sc.api.plugins.IField
6+
import sc.plugin2026.FieldState.Companion.from
7+
import java.util.Optional
8+
9+
/**
10+
* Ein Feld des Spielfelds. Ein Spielfeld hat eine x- und y-Koordinate und einen [FieldState], der anzeigt ob sich etwas auf diesem Feld befindet.
11+
*/
12+
@XStreamAlias(value = "field")
13+
class Field @JvmOverloads constructor(
14+
@field:XStreamAsAttribute var x: Int,
15+
@field:XStreamAsAttribute var y: Int,
16+
@field:XStreamAsAttribute var state: FieldState = FieldState.EMPTY
17+
):
18+
IField<Field> {
19+
constructor(x: Int, y: Int, piranha: PlayerColor): this(x, y, from(piranha))
20+
21+
constructor(x: Int, y: Int, isObstructed: Boolean): this(
22+
x,
23+
y,
24+
if(isObstructed) FieldState.OBSTRUCTED else FieldState.EMPTY
25+
)
26+
27+
constructor(fieldToClone: Field): this(fieldToClone.x, fieldToClone.y, fieldToClone.state)
28+
29+
override fun clone(): Field {
30+
return Field(this)
31+
}
32+
33+
override fun equals(obj: Any?): Boolean {
34+
if(obj !is Field) return false
35+
val field = obj
36+
return x == field.x && y == field.y && state == field.state
37+
}
38+
39+
override fun toString(): String {
40+
return String.format("Field(%d|%d){%s}", x, y, state)
41+
}
42+
43+
val piranha: Optional<PlayerColor>
44+
get() {
45+
if(state == FieldState.RED) return Optional.of(Team.ONE)
46+
else if(state == FieldState.BLUE) return Optional.of(Team.TWO)
47+
48+
return Optional.empty()
49+
}
50+
51+
/** Nur für den Server relevant. */
52+
fun setPiranha(piranha: PlayerColor) {
53+
state = from(piranha)
54+
}
55+
56+
val isObstructed: Boolean
57+
get() = state == FieldState.OBSTRUCTED
58+
59+
override val isEmpty: Boolean
60+
get() = false
61+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package sc.plugin2026
2+
3+
enum class FieldState {
4+
RED,
5+
BLUE,
6+
OBSTRUCTED,
7+
EMPTY;
8+
9+
override fun toString() = when(this) {
10+
OBSTRUCTED -> "Obstructed"
11+
RED -> "Red"
12+
BLUE -> "Blue"
13+
else -> "empty"
14+
}
15+
16+
fun asLetter() = when(this) {
17+
OBSTRUCTED -> 'O'
18+
RED -> 'R'
19+
BLUE -> 'B'
20+
else -> ' '
21+
}
22+
23+
companion object {
24+
@JvmStatic
25+
fun from(color: PlayerColor): FieldState {
26+
return when(color) {
27+
Team.ONE -> RED
28+
Team.TWO -> BLUE
29+
}
30+
}
31+
}
32+
}

plugin2026/src/main/kotlin/sc/plugin2026/util/Constants.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,9 @@ package sc.plugin2026.util
44
object PiranhaConstants {
55
const val BOARD_LENGTH: Int = 10
66

7+
const val OBSTACLES_START: Int = 2
8+
const val OBSTACLES_END: Int = 7
9+
const val NUM_OBSTACLES: Int = 2
10+
711
const val ROUND_LIMIT: Int = 30
812
}

plugin2026/src/main/kotlin/sc/plugin2026/util/GamePlugin.kt

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,9 @@ import sc.shared.*
1212
// TODO
1313

1414
@XStreamAlias(value = "winreason")
15-
enum class HuIWinReason(override val message: String, override val isRegular: Boolean = true): IWinReason {
16-
DIFFERING_SCORES("%s ist weiter vorne."),
17-
DIFFERING_CARROTS("%s hat weniger Karotten uebrig."),
18-
GOAL("%s hat das Ziel zuerst erreicht."),
15+
enum class PiranhasWinReason(override val message: String, override val isRegular: Boolean = true): IWinReason {
16+
BIGGER_SWARM("%s hat den größeren Schwarm")
17+
1918
}
2019

2120
class GamePlugin: IGamePlugin<Move> {
@@ -24,8 +23,7 @@ class GamePlugin: IGamePlugin<Move> {
2423
val scoreDefinition: ScoreDefinition =
2524
ScoreDefinition(arrayOf(
2625
ScoreFragment("Siegpunkte", WinReason("%s hat gewonnen."), ScoreAggregation.SUM),
27-
ScoreFragment("Feldnummer", HuIWinReason.DIFFERING_SCORES, ScoreAggregation.AVERAGE),
28-
ScoreFragment("Karotten", HuIWinReason.DIFFERING_CARROTS, ScoreAggregation.AVERAGE, true),
26+
ScoreFragment("Schwarmgroeße", PiranhasWinReason.BIGGER_SWARM, ScoreAggregation.AVERAGE),
2927
))
3028
}
3129

0 commit comments

Comments
 (0)