Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion backend
128 changes: 64 additions & 64 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,30 @@ val versionNumber = "21.2.1"

val minJavaVersion = JavaVersion.VERSION_11
plugins {
val minJavaVersion = JavaVersion.VERSION_11 // Declared twice because plugins block has its own scope
require(JavaVersion.current() >= minJavaVersion) {
"Building requires at least JDK $minJavaVersion - please look into the README."
}
application
kotlin("jvm") version "1.4.20"
id("org.openjfx.javafxplugin") version "0.0.9"
id("com.github.johnrengelman.shadow") version "6.1.0"
id("com.github.ben-manes.versions") version "0.33.0"
id("se.patrikerdes.use-latest-versions") version "0.2.15"
val minJavaVersion = JavaVersion.VERSION_11 // Declared twice because plugins block has its own scope
require(JavaVersion.current() >= minJavaVersion) {
"Building requires at least JDK $minJavaVersion - please look into the README"
}
application
kotlin("jvm") version "1.4.20"
id("org.openjfx.javafxplugin") version "0.0.9"
id("com.github.johnrengelman.shadow") version "6.1.0"
id("com.github.ben-manes.versions") version "0.36.0"
id("se.patrikerdes.use-latest-versions") version "0.2.15"
}

group = "sc.gui"
version = versionNumber
try {
// Add hash suffix if git is available
version = version.toString() + "-" + Runtime.getRuntime().exec(arrayOf("git", "rev-parse", "--short", "--verify", "HEAD")).inputStream.reader().readText().trim()
} catch(_: java.io.IOException) {
// Add hash suffix if git is available
version = "$version-" + Runtime.getRuntime().exec(arrayOf("git", "rev-parse", "--short", "--verify", "HEAD")).inputStream.reader().readText().trim()
} catch (_: java.io.IOException) {
}

application {
mainClassName = "sc.gui.GuiAppKt"
mainClassName = "sc.gui.GuiAppKt" // not migrating from legacy because of https://github.com/johnrengelman/shadow/issues/609
// these are required because of using JDK >8,
// see https://github.com/controlsfx/controlsfx/wiki/Using-ControlsFX-with-JDK-9-and-above
applicationDefaultJvmArgs = listOf(
Expand All @@ -39,67 +39,67 @@ application {
// For accessing InputMap used in RangeSliderBehavior
"--add-exports=javafx.controls/com.sun.javafx.scene.control.inputmap=ALL-UNNAMED"
)

}

repositories {
mavenCentral()
maven {
url = uri("https://oss.sonatype.org/content/repositories/snapshots")
}
maven("https://oss.sonatype.org/content/repositories/snapshots")
}

val backend = gradle.includedBuilds.last()

dependencies {
implementation(kotlin("stdlib-jdk8"))
implementation(kotlin("reflect"))
implementation(kotlin("stdlib-jdk8"))
implementation(kotlin("reflect"))
implementation("no.tornado", "tornadofx", "2.0.0-SNAPSHOT") { exclude("org.jetbrains.kotlin", "kotlin-reflect") }
implementation("io.github.microutils", "kotlin-logging-jvm", "2.0.3")
implementation("io.github.microutils", "kotlin-logging-jvm", "2.0.4")

implementation(fileTree(backend.name + "/server/build/runnable") { include("**/*.jar") })
}

tasks {
compileJava {
options.release.set(minJavaVersion.majorVersion.toInt())
}
processResources {
doFirst{
sourceSets.main.get().resources.srcDirs.first().resolve("version.txt").writeText(version.toString())
}
}
withType<KotlinCompile> {
dependsOn(backend.task(":server:deploy"))
kotlinOptions{
jvmTarget = minJavaVersion.toString()
freeCompilerArgs = listOf("-Xjvm-default=all")
}
}

javafx {
version = "13"
modules("javafx.controls", "javafx.fxml", "javafx.base", "javafx.graphics")
}

shadowJar {
destinationDirectory.set(buildDir)
archiveClassifier.set(OperatingSystem.current().familyName)
}

run.configure {
workingDir(buildDir.resolve("run").apply { mkdirs() })
}

val release by creating {
dependsOn(check)
group = "distribution"
description = "Creates and pushes a tagged commit with the current version"
doLast {
exec { commandLine("git", "commit", "-a", "-m", "release: $versionNumber") }
exec { commandLine("git", "tag", versionNumber) }
exec { commandLine("git", "push", "origin", versionNumber, "master") }
}
}
compileJava {
options.release.set(minJavaVersion.majorVersion.toInt())
}
processResources {
doFirst {
sourceSets.main.get().resources.srcDirs.single().resolve("version.txt").writeText(version.toString())
}
}
withType<KotlinCompile> {
dependsOn(backend.task(":server:deploy"))
kotlinOptions {
jvmTarget = minJavaVersion.toString()
freeCompilerArgs = listOf("-Xjvm-default=all")
}
}

javafx {
version = "13"
modules("javafx.controls", "javafx.fxml", "javafx.base", "javafx.graphics")
}

shadowJar {
destinationDirectory.set(buildDir)
archiveClassifier.set(OperatingSystem.current().familyName)
}

run.configure {
workingDir(buildDir.resolve("tmp"))
doFirst {
workingDir.mkdirs()
}
}

val release by creating {
dependsOn(check)
group = "distribution"
description = "Creates and pushes a tagged commit with the current version"
doLast {
exec { commandLine("git", "commit", "-a", "-m", "release: $versionNumber") }
exec { commandLine("git", "tag", versionNumber) }
exec { commandLine("git", "push", "origin", versionNumber, "master") }
}
}
}
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
71 changes: 27 additions & 44 deletions src/main/kotlin/sc/gui/controller/GameController.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import sc.plugin2021.util.GameRuleLogic
import sc.shared.GameResult
import tornadofx.Controller
import tornadofx.objectProperty
import java.util.*
import kotlin.math.max

// The following *Binding-classes are necessary to automatically unbind and rebind to a new piece (when switched)
Expand All @@ -34,7 +35,6 @@ class ColorBinding(piece: Property<PiecesModel>) : ObjectBinding<Color>() {
}

override fun computeValue(): Color {
logger.debug("Color: {}", model.value.colorProperty().get())
return model.value.colorProperty().get()
}

Expand Down Expand Up @@ -149,20 +149,17 @@ class GameController : Controller() {
val teamTwoScore = objectProperty(0)

val playerNames = objectProperty<Array<String>>()
val gameResult: ObjectProperty<GameResult?> = objectProperty(null)
val gameResult = objectProperty<GameResult>()

// we need to have them split separately otherwise we cannot listen to a specific color alone
val undeployedRedPieces = objectProperty(PieceShape.shapes.values)
val undeployedBluePieces = objectProperty(PieceShape.shapes.values)
val undeployedGreenPieces = objectProperty(PieceShape.shapes.values)
val undeployedYellowPieces = objectProperty(PieceShape.shapes.values)
val undeployedPieces: Map<Color, ObjectProperty<Collection<PieceShape>>> = EnumMap(
Color.values().associateWith { objectProperty(PieceShape.shapes.values) })

val validRedPieces = objectProperty(ArrayList<PieceShape>())
val validBluePieces = objectProperty(ArrayList<PieceShape>())
val validGreenPieces = objectProperty(ArrayList<PieceShape>())
val validYellowPieces = objectProperty(ArrayList<PieceShape>())
val validPieces: Map<Color, ObjectProperty<Collection<PieceShape>>> = EnumMap(
Color.values().associateWith { objectProperty(emptyList()) })

// use selected* to access the property of currentPiece in order to always correctly be automatically rebind
// TODO maybe this should be nullable rather than having a random default -
// then it could also be unset to prevent spurious errors like https://github.com/CAU-Kiel-Tech-Inf/gui/issues/43
val currentPiece = objectProperty(PiecesModel(Color.RED, PieceShape.MONO))
val selectedColor: ColorBinding = ColorBinding(currentPiece)
val selectedShape: ShapeBinding = ShapeBinding(currentPiece)
Expand All @@ -180,50 +177,39 @@ class GameController : Controller() {
gameState.set(state)
canSkip.set(false)

// I don't know why orderedColors becomes an empty array and results in CurrentColor being inaccessible (throwing error) when the game ended,
// but this is how we can avoid it for now TODO("fix this in the plugin")
if (state.orderedColors.isNotEmpty()) {
previousColor.set(currentColor.get())
currentColor.set(state.currentColor)
currentTeam.set(state.currentTeam)
}
playerNames.set(state.playerNames)
undeployedRedPieces.set(state.undeployedPieceShapes(Color.RED))
undeployedBluePieces.set(state.undeployedPieceShapes(Color.BLUE))
undeployedGreenPieces.set(state.undeployedPieceShapes(Color.GREEN))
undeployedYellowPieces.set(state.undeployedPieceShapes(Color.YELLOW))
previousColor.set(currentColor.get())
currentColor.set(state.currentColor)
currentTeam.set(state.currentTeam)
boardController.board.boardProperty().set(state.board)
validRedPieces.set(ArrayList())
validBluePieces.set(ArrayList())
validGreenPieces.set(ArrayList())
validYellowPieces.set(ArrayList())
undeployedPieces.forEach { (color, pieces) ->
pieces.set(state.undeployedPieceShapes(color))
}
validPieces.forEach { (_, pieces) ->
pieces.set(emptyList())
}

availableTurns.set(max(availableTurns.get(), state.turn))
playerNames.set(state.playerNames)
currentTurn.set(state.turn)
currentRound.set(state.round)
teamOneScore.set(state.getPointsForPlayer(Team.ONE))
teamTwoScore.set(state.getPointsForPlayer(Team.TWO))
}
subscribe<HumanMoveRequest> { event ->
val state = event.gameState
logger.debug("Human move request for ${state.currentColor}")

val moves = state.undeployedPieceShapes().map {
it to GameRuleLogic.getPossibleMovesForShape(state, it)
}.toMap()
logger.debug("Number of possible moves: ${moves.toList().flatMap { it.second }.size}")

logger.debug("Human move request for {} - {} possible moves",
state.currentColor,
moves.values.sumBy { it.size })

isHumanTurn.set(true)
canSkip.set(!gameEnded() && isHumanTurn.get() && !GameRuleLogic.isFirstMove(state))
boardController.calculateIsPlaceableBoard(state.board, state.currentColor)

when (state.currentColor) {
Color.RED -> validRedPieces
Color.BLUE -> validBluePieces
Color.GREEN -> validGreenPieces
Color.YELLOW -> validYellowPieces
}.set(state.undeployedPieceShapes(state.currentColor).filter { shape ->
moves[shape]!!.isNotEmpty()
} as ArrayList<PieceShape>?)

validPieces.getValue(state.currentColor)
.set(moves.filterValues { it.isNotEmpty() }.keys)
}
subscribe<GameOverEvent> { event ->
gameResult.set(event.result)
Expand All @@ -238,10 +224,7 @@ class GameController : Controller() {
availableTurns.set(0)
currentTurn.set(0)
currentRound.set(0)
undeployedRedPieces.set(PieceShape.values().toList())
undeployedBluePieces.set(PieceShape.values().toList())
undeployedGreenPieces.set(PieceShape.values().toList())
undeployedYellowPieces.set(PieceShape.values().toList())
undeployedPieces.forEach { (_, pieces) -> pieces.set(PieceShape.values().toList()) }
}

fun selectPiece(piece: PiecesModel) {
Expand Down
16 changes: 9 additions & 7 deletions src/main/kotlin/sc/gui/view/AppView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,12 @@ class AppView : View("Software-Challenge Germany") {
logger.debug("Quitting!")
Platform.exit()
}
item("Neues Spiel", "Shortcut+N").action {
item("Neues Spiel", "Shortcut+N") {
enableWhen(controller.model.currentView.isNotEqualTo(ViewType.GAME_CREATION))
logger.debug("New Game!")
if (controller.model.currentView.get() == ViewType.GAME) {
alert(
action {
logger.debug("New Game!")
if (controller.model.currentView.get() == ViewType.GAME) {
alert(
type = Alert.AlertType.CONFIRMATION,
header = "Neues Spiel anfangen",
content = "Willst du wirklich dein aktuelles Spiel verwerfen und ein neues anfangen?",
Expand All @@ -42,9 +43,10 @@ class AppView : View("Software-Challenge Germany") {
gameController.clearGame()
}
}
)
} else if (controller.model.currentView.get() != ViewType.GAME_CREATION) {
controller.changeViewTo(ViewType.GAME_CREATION)
)
} else if (controller.model.currentView.get() != ViewType.GAME_CREATION) {
controller.changeViewTo(ViewType.GAME_CREATION)
}
}
}
item("Toggle Darkmode").action {
Expand Down
28 changes: 13 additions & 15 deletions src/main/kotlin/sc/gui/view/GameView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,26 @@ import javafx.geometry.Insets
import javafx.scene.input.KeyCode
import javafx.scene.input.MouseButton
import org.slf4j.LoggerFactory
import sc.gui.controller.*
import sc.plugin2021.*
import sc.gui.controller.GameController
import sc.plugin2021.Color
import sc.plugin2021.Rotation
import sc.plugin2021.Team
import sc.plugin2021.util.Constants
import tornadofx.*
import java.util.*

class GameView : View() {
private val gameController: GameController by inject()
private val redUndeployedPieces = UndeployedPiecesFragment(Color.RED, gameController.undeployedRedPieces, gameController.validRedPieces)
private val blueUndeployedPieces = UndeployedPiecesFragment(Color.BLUE, gameController.undeployedBluePieces, gameController.validBluePieces)
private val greenUndeployedPieces = UndeployedPiecesFragment(Color.GREEN, gameController.undeployedGreenPieces, gameController.validGreenPieces)
private val yellowUndeployedPieces = UndeployedPiecesFragment(Color.YELLOW, gameController.undeployedYellowPieces, gameController.validYellowPieces)

private val undeployedPieces = EnumMap(
Color.values().associateWith { color ->
UndeployedPiecesFragment(color, gameController.undeployedPieces.getValue(color), gameController.validPieces.getValue(color))
})
private val leftPane = vbox {
this += blueUndeployedPieces
this += redUndeployedPieces
replaceChildren(*undeployedPieces.filterKeys { it.team == Team.ONE }.values.toTypedArray())
}
private val rightPane = vbox {
this += yellowUndeployedPieces
this += greenUndeployedPieces
replaceChildren(*undeployedPieces.filterKeys { it.team == Team.TWO }.values.toTypedArray())
}
val game = borderpane {
top(StatusView::class)
Expand Down Expand Up @@ -105,10 +106,7 @@ class GameView : View() {
}

init {
redUndeployedPieces.root.prefHeightProperty().bind(root.heightProperty())
blueUndeployedPieces.root.prefHeightProperty().bind(root.heightProperty())
yellowUndeployedPieces.root.prefHeightProperty().bind(root.heightProperty())
greenUndeployedPieces.root.prefHeightProperty().bind(root.heightProperty())
undeployedPieces.forEach { (_, pieces) -> pieces.root.prefHeightProperty().bind(root.heightProperty()) }

val resizer = ChangeListener<Number> { _, _, _ -> resize() }
// responsive scaling
Expand Down
Loading