diff --git a/src/main/kotlin/dartzee/achievements/AchievementSqlUtil.kt b/src/main/kotlin/dartzee/achievements/AchievementSqlUtil.kt index 7d7418b3..ee2996f6 100644 --- a/src/main/kotlin/dartzee/achievements/AchievementSqlUtil.kt +++ b/src/main/kotlin/dartzee/achievements/AchievementSqlUtil.kt @@ -52,7 +52,7 @@ fun ensureX01RoundsTableExists(playerIds: List, database: Database) { val created = database.createTableIfNotExists( X01_ROUNDS_TABLE, - "PlayerId VARCHAR(36), GameId VARCHAR(36), ParticipantId VARCHAR(36), StartingScore INT, RoundNumber INT, " + + "PlayerId VARCHAR(36), GameId VARCHAR(36), GameParams VARCHAR(255), ParticipantId VARCHAR(36), StartingScore INT, RoundNumber INT, " + "TotalDartsThrown INT, RemainingScore INT, LastDartScore INT, LastDartMultiplier INT, DtRoundFinished TIMESTAMP" ) @@ -63,13 +63,13 @@ fun ensureX01RoundsTableExists(playerIds: List, database: Database) { val tmp1 = database.createTempTable( "X01RoundsPt1", - "PlayerId VARCHAR(36), GameId VARCHAR(36), ParticipantId VARCHAR(36), StartingScore INT, RoundNumber INT, LastDartOrdinal INT" + "PlayerId VARCHAR(36), GameId VARCHAR(36), GameParams VARCHAR(255), ParticipantId VARCHAR(36), StartingScore INT, RoundNumber INT, LastDartOrdinal INT" ) database.executeUpdate( """ INSERT INTO $tmp1 - SELECT pt.PlayerId, pt.GameId, pt.RowId, drtFirst.StartingScore, drtFirst.RoundNumber, MAX(drt.Ordinal) + SELECT pt.PlayerId, pt.GameId, g.GameParams, pt.RowId, drtFirst.StartingScore, drtFirst.RoundNumber, MAX(drt.Ordinal) FROM ${EntityName.Dart} drtFirst, ${EntityName.Participant} pt, ${EntityName.Game} g, ${EntityName.Dart} drt WHERE drtFirst.ParticipantId = pt.RowId AND drtFirst.PlayerId = pt.PlayerId @@ -80,7 +80,7 @@ fun ensureX01RoundsTableExists(playerIds: List, database: Database) { AND drtFirst.ParticipantId = drt.ParticipantId AND drtFirst.RoundNumber = drt.RoundNumber ${getPlayerSql(playerIds)} - GROUP BY pt.PlayerId, pt.GameId, pt.RowId, drtFirst.StartingScore, drtFirst.RoundNumber + GROUP BY pt.PlayerId, pt.GameId, g.GameParams, pt.RowId, drtFirst.StartingScore, drtFirst.RoundNumber """ .trimIndent() ) @@ -91,6 +91,7 @@ fun ensureX01RoundsTableExists(playerIds: List, database: Database) { SELECT zz.PlayerId, zz.GameId, + zz.GameParams, zz.ParticipantId, zz.StartingScore, zz.RoundNumber, diff --git a/src/main/kotlin/dartzee/achievements/x01/AchievementX01BestGame.kt b/src/main/kotlin/dartzee/achievements/x01/AchievementX01BestGame.kt index 93e8efd8..724411c6 100644 --- a/src/main/kotlin/dartzee/achievements/x01/AchievementX01BestGame.kt +++ b/src/main/kotlin/dartzee/achievements/x01/AchievementX01BestGame.kt @@ -2,7 +2,9 @@ package dartzee.achievements.x01 import dartzee.achievements.AbstractAchievementBestGame import dartzee.achievements.AchievementType +import dartzee.game.FinishType import dartzee.game.GameType +import dartzee.game.X01Config import dartzee.utils.ResourceCache class AchievementX01BestGame : AbstractAchievementBestGame() { @@ -10,7 +12,7 @@ class AchievementX01BestGame : AbstractAchievementBestGame() { override val name = "Leg-up" override val desc = "Best game of 501" override val gameType = GameType.X01 - override val gameParams = "501" + override val gameParams = X01Config(501, FinishType.Doubles).toJson() override val redThreshold = 99 override val orangeThreshold = 60 diff --git a/src/main/kotlin/dartzee/achievements/x01/AchievementX01HighestBust.kt b/src/main/kotlin/dartzee/achievements/x01/AchievementX01HighestBust.kt index f82dcac9..29142192 100644 --- a/src/main/kotlin/dartzee/achievements/x01/AchievementX01HighestBust.kt +++ b/src/main/kotlin/dartzee/achievements/x01/AchievementX01HighestBust.kt @@ -24,7 +24,7 @@ class AchievementX01HighestBust : AbstractAchievement() { override fun populateForConversion(playerIds: List, database: Database) { val whereSql = - "RemainingScore < 0 OR RemainingSCore = 1 OR (RemainingScore = 0 AND LastDartMultiplier <> 2)" + "RemainingScore < 0 OR (GameParams LIKE '%Doubles%' AND (RemainingScore = 1 OR (RemainingScore = 0 AND LastDartMultiplier <> 2)))" unlockThreeDartAchievement(playerIds, whereSql, "StartingScore", achievementType, database) } diff --git a/src/main/kotlin/dartzee/ai/DartsAiModel.kt b/src/main/kotlin/dartzee/ai/DartsAiModel.kt index 7d689afe..86561261 100644 --- a/src/main/kotlin/dartzee/ai/DartsAiModel.kt +++ b/src/main/kotlin/dartzee/ai/DartsAiModel.kt @@ -3,6 +3,7 @@ package dartzee.ai import com.fasterxml.jackson.module.kotlin.readValue import dartzee.core.util.jsonMapper import dartzee.game.ClockType +import dartzee.game.FinishType import dartzee.logging.CODE_AI_ERROR import dartzee.`object`.ComputedPoint import dartzee.`object`.SegmentType @@ -42,7 +43,7 @@ data class DartsAiModel( private val distribution = NormalDistribution(mean.toDouble(), standardDeviation) /** X01 */ - fun throwX01Dart(score: Int): ComputedPoint { + fun throwX01Dart(score: Int, finishType: FinishType): ComputedPoint { // Check for a specific dart to aim for. It's possible to override any value for a specific // AI strategy. val drtToAimAt = getOveriddenDartToAimAt(score) @@ -55,7 +56,7 @@ data class DartsAiModel( return if (score > 60) { throwScoringDart() } else { - val defaultDrt = getDefaultDartToAimAt(score) + val defaultDrt = getX01AimDart(score, finishType) val ptToAimAt = getPointForScore(defaultDrt) throwDartAtPoint(ptToAimAt) } diff --git a/src/main/kotlin/dartzee/ai/DartsSimulationX01.kt b/src/main/kotlin/dartzee/ai/DartsSimulationX01.kt index f8c3be23..6a8e37e2 100644 --- a/src/main/kotlin/dartzee/ai/DartsSimulationX01.kt +++ b/src/main/kotlin/dartzee/ai/DartsSimulationX01.kt @@ -1,7 +1,9 @@ package dartzee.ai import dartzee.db.PlayerEntity +import dartzee.game.FinishType import dartzee.game.GameType +import dartzee.game.X01Config import dartzee.`object`.Dart import dartzee.utils.isBust import dartzee.utils.shouldStopForMercyRule @@ -15,7 +17,8 @@ class DartsSimulationX01(player: PlayerEntity, model: DartsAiModel) : private var startingScore = -1 private var currentScore = -1 - override val gameParams = "$X01" + private val config = X01Config(501, FinishType.Doubles) + override val gameParams = config.toJson() override val gameType = GameType.X01 override fun getTotalScore(): Int { @@ -37,7 +40,7 @@ class DartsSimulationX01(player: PlayerEntity, model: DartsAiModel) : startingScore = currentScore resetRound() - val pt = model.throwX01Dart(currentScore) + val pt = model.throwX01Dart(currentScore, config.finishType) dartThrown(pt) } @@ -45,7 +48,7 @@ class DartsSimulationX01(player: PlayerEntity, model: DartsAiModel) : confirmRound() // If we've bust, then reset the current score back - if (isBust(dartsThrown.last())) { + if (isBust(dartsThrown.last(), config.finishType)) { currentScore = startingScore } @@ -62,11 +65,11 @@ class DartsSimulationX01(player: PlayerEntity, model: DartsAiModel) : if ( currentScore <= 1 || dartsThrown.size == 3 || - shouldStopForMercyRule(model, startingScore, currentScore) + shouldStopForMercyRule(model, startingScore, currentScore, config.finishType) ) { finishedRound() } else { - val pt = model.throwX01Dart(currentScore) + val pt = model.throwX01Dart(currentScore, config.finishType) dartThrown(pt) } } diff --git a/src/main/kotlin/dartzee/ai/StrategyUtils.kt b/src/main/kotlin/dartzee/ai/StrategyUtils.kt index 5e408e1b..f7fbcb92 100644 --- a/src/main/kotlin/dartzee/ai/StrategyUtils.kt +++ b/src/main/kotlin/dartzee/ai/StrategyUtils.kt @@ -1,5 +1,6 @@ package dartzee.ai +import dartzee.game.FinishType import dartzee.`object`.ComputedPoint import dartzee.`object`.DartboardSegment import dartzee.`object`.SegmentType @@ -22,7 +23,13 @@ fun getComputedPointForScore(score: Int, type: SegmentType): ComputedPoint = AI_DARTBOARD.getPointToAimAt(DartboardSegment(type, score)) /** Get the application-wide default thing to aim for, which applies to any score of 60 or less */ -fun getDefaultDartToAimAt(score: Int): AimDart { +fun getX01AimDart(score: Int, finishType: FinishType) = + when (finishType) { + FinishType.Doubles -> getX01AimDartDoublesMode(score) + FinishType.Any -> getX01AimDartRelaxedMode(score) + } + +private fun getX01AimDartDoublesMode(score: Int): AimDart { // Aim for the single that puts you on double top if (score > 40) { val single = score - 40 @@ -40,6 +47,26 @@ fun getDefaultDartToAimAt(score: Int): AimDart { return AimDart(singleToAimFor, 1) } +private fun getX01AimDartRelaxedMode(score: Int): AimDart { + // Finish on single if possible + if (score <= 20) { + return AimDart(score, 1) + } + + // Go for treble finishes if possible + if (score % 3 == 0) { + return AimDart(score / 3, 3) + } + + // Aim to put ourselves on single 20 + if (score <= 40) { + return AimDart(score - 20, 1) + } + + // Just go for single 20 + return AimDart(20, 1) +} + private fun getHighestPowerOfTwoLessThan(score: Int): Int { var i = 2 while (i < score) { diff --git a/src/main/kotlin/dartzee/bean/GameParamFilterPanelX01.kt b/src/main/kotlin/dartzee/bean/GameParamFilterPanelX01.kt index a7525871..51f320c5 100644 --- a/src/main/kotlin/dartzee/bean/GameParamFilterPanelX01.kt +++ b/src/main/kotlin/dartzee/bean/GameParamFilterPanelX01.kt @@ -1,35 +1,55 @@ package dartzee.bean +import dartzee.game.FinishType +import dartzee.game.X01Config import java.awt.BorderLayout import java.awt.event.ActionListener +import javax.swing.Box +import javax.swing.JCheckBox import javax.swing.JPanel class GameParamFilterPanelX01 : GameParamFilterPanel() { private val panel = JPanel() - val spinner = SpinnerX01() + private val spinner = SpinnerX01() + private val cbFinishOnDouble = JCheckBox("Finish on double") + private val separator = Box.createHorizontalStrut(20) init { add(panel, BorderLayout.CENTER) + panel.add(cbFinishOnDouble) + panel.add(separator) panel.add(spinner) + cbFinishOnDouble.isSelected = true } - override fun getGameParams() = "${spinner.value}" + override fun getGameParams() = constructGameParams().toJson() override fun setGameParams(gameParams: String) { - spinner.value = gameParams.toInt() + val config = X01Config.fromJson(gameParams) + spinner.value = config.target + cbFinishOnDouble.isSelected = config.finishType == FinishType.Doubles } - override fun getFilterDesc() = "games of ${getGameParams()}" + private fun constructGameParams() = + X01Config( + spinner.value as Int, + if (cbFinishOnDouble.isSelected) FinishType.Doubles else FinishType.Any + ) + + override fun getFilterDesc() = "games of ${constructGameParams().description()}" override fun enableChildren(enabled: Boolean) { spinner.isEnabled = enabled + cbFinishOnDouble.isEnabled = enabled } override fun addActionListener(listener: ActionListener) { spinner.addActionListener(listener) + cbFinishOnDouble.addActionListener(listener) } override fun removeActionListener(listener: ActionListener) { spinner.removeActionListener() + cbFinishOnDouble.addActionListener(listener) } } diff --git a/src/main/kotlin/dartzee/game/GameType.kt b/src/main/kotlin/dartzee/game/GameType.kt index ab7123e4..9e761ab4 100644 --- a/src/main/kotlin/dartzee/game/GameType.kt +++ b/src/main/kotlin/dartzee/game/GameType.kt @@ -2,6 +2,8 @@ package dartzee.game import dartzee.db.DartzeeTemplateEntity +const val GAME_PARAMS_NOT_APPLICABLE = "N/A" + enum class GameType { X01, GOLF, @@ -26,11 +28,16 @@ enum class GameType { } } - fun getParamsDescription(gameParams: String) = - when (this) { - X01 -> gameParams + fun getParamsDescription(gameParams: String): String { + if (gameParams == GAME_PARAMS_NOT_APPLICABLE) { + return GAME_PARAMS_NOT_APPLICABLE + } + + return when (this) { + X01 -> X01Config.fromJson(gameParams).description() GOLF -> "$gameParams holes" ROUND_THE_CLOCK -> RoundTheClockConfig.fromJson(gameParams).getDescription() DARTZEE -> DartzeeTemplateEntity().retrieveForId(gameParams, false)?.name.orEmpty() } + } } diff --git a/src/main/kotlin/dartzee/game/X01Config.kt b/src/main/kotlin/dartzee/game/X01Config.kt new file mode 100644 index 00000000..2d4367a6 --- /dev/null +++ b/src/main/kotlin/dartzee/game/X01Config.kt @@ -0,0 +1,21 @@ +package dartzee.game + +import com.fasterxml.jackson.module.kotlin.readValue +import dartzee.core.util.jsonMapper + +enum class FinishType { + Any, + Doubles +} + +data class X01Config(val target: Int, val finishType: FinishType) { + fun toJson(): String = jsonMapper().writeValueAsString(this) + + fun description() = "$target${finishTypeDesc()}" + + private fun finishTypeDesc() = if (finishType == FinishType.Any) " (relaxed finish)" else "" + + companion object { + fun fromJson(json: String) = jsonMapper().readValue(json) + } +} diff --git a/src/main/kotlin/dartzee/game/state/X01PlayerState.kt b/src/main/kotlin/dartzee/game/state/X01PlayerState.kt index 8560fe8e..1e230da2 100644 --- a/src/main/kotlin/dartzee/game/state/X01PlayerState.kt +++ b/src/main/kotlin/dartzee/game/state/X01PlayerState.kt @@ -1,5 +1,6 @@ package dartzee.game.state +import dartzee.game.X01Config import dartzee.`object`.Dart import dartzee.utils.isBust import dartzee.utils.isFinishRound @@ -7,7 +8,7 @@ import dartzee.utils.isNearMissDouble import dartzee.utils.sumScore data class X01PlayerState( - private val startingScore: Int, + private val config: X01Config, override val wrappedParticipant: IWrappedParticipant, override val completedRounds: MutableList> = mutableListOf(), override val currentRound: MutableList = mutableListOf(), @@ -33,7 +34,7 @@ data class X01PlayerState( roundSubSet .filterNot { round -> val lastDart = round.lastOrNull() - lastDart?.let(::isBust) ?: false + lastDart?.let { isBust(it, config.finishType) } ?: false } .toMutableList() @@ -41,7 +42,7 @@ data class X01PlayerState( nonBustRounds.add(currentRound.toList()) } - return startingScore - nonBustRounds.sumOf { sumScore(it) } + return config.target - nonBustRounds.sumOf { sumScore(it) } } fun getRemainingScore() = getRemainingScoreForRound(currentRoundNumber()) @@ -53,7 +54,10 @@ data class X01PlayerState( fun getLastRound() = completedRounds.last() - fun isCurrentRoundComplete() = currentRound.size == 3 || getRemainingScore() <= 1 + fun isCurrentRoundComplete() = + currentRound.size == 3 || + getRemainingScore() <= 0 || + currentRound.lastOrNull()?.let { isBust(it, config.finishType) } ?: false override fun dartThrown(dart: Dart) { dart.startingScore = getRemainingScore() diff --git a/src/main/kotlin/dartzee/screen/ai/NewSetupRuleDialog.kt b/src/main/kotlin/dartzee/screen/ai/NewSetupRuleDialog.kt index ad5c06b0..7237a5b3 100644 --- a/src/main/kotlin/dartzee/screen/ai/NewSetupRuleDialog.kt +++ b/src/main/kotlin/dartzee/screen/ai/NewSetupRuleDialog.kt @@ -1,12 +1,13 @@ package dartzee.screen.ai import dartzee.ai.AimDart -import dartzee.ai.getDefaultDartToAimAt +import dartzee.ai.getX01AimDart import dartzee.bean.SpinnerSingleSelector import dartzee.core.bean.NumberField import dartzee.core.bean.RadioButtonPanel import dartzee.core.screen.SimpleDialog import dartzee.core.util.DialogUtil +import dartzee.game.FinishType import dartzee.`object`.Dart import dartzee.screen.ScreenCache import dartzee.utils.isBust @@ -91,30 +92,31 @@ class NewSetupRuleDialog(private val hmScoreToDart: MutableMap) : } } - fun valid(): Boolean { + private fun valid(): Boolean { val score = nfScore.getNumber() if (score == -1) { - DialogUtil.showErrorOLD("You must enter a score for this rule to apply to.") + DialogUtil.showError("You must enter a score for this rule to apply to.") return false } val drt = getDartFromSelections() if (drt.score == 25 && drt.multiplier == 3) { - DialogUtil.showErrorOLD("Treble 25 is not a valid dart!") + DialogUtil.showError("Treble 25 is not a valid dart!") return false } - if (isBust(score, Dart(drt.score, drt.multiplier))) { - DialogUtil.showErrorOLD("This target would bust the player") + val actualDart = Dart(drt.score, drt.multiplier).apply { startingScore = score } + if (isBust(actualDart, FinishType.Doubles)) { + DialogUtil.showError("This target would bust the player") return false } // If we're specifying a rule for under 60, validate whether what we're setting up is // already the default if (score <= 60) { - val defaultDart = getDefaultDartToAimAt(score) + val defaultDart = getX01AimDart(score, FinishType.Doubles) if (defaultDart == drt) { - DialogUtil.showErrorOLD( + DialogUtil.showError( "The selected dart is already the default for this starting score." ) return false diff --git a/src/main/kotlin/dartzee/screen/game/scorer/DartsScorerX01.kt b/src/main/kotlin/dartzee/screen/game/scorer/DartsScorerX01.kt index 2835b653..1dd87bd9 100644 --- a/src/main/kotlin/dartzee/screen/game/scorer/DartsScorerX01.kt +++ b/src/main/kotlin/dartzee/screen/game/scorer/DartsScorerX01.kt @@ -11,10 +11,10 @@ import javax.swing.SwingConstants class DartsScorerX01( parent: GamePanelPausable<*, *>, - gameParams: String, + target: Int, participant: IWrappedParticipant ) : AbstractDartsScorerPausable(parent, participant) { - private val lblStartingScore = JLabel(gameParams) + private val lblStartingScore = JLabel(target.toString()) init { lblStartingScore.horizontalAlignment = SwingConstants.CENTER diff --git a/src/main/kotlin/dartzee/screen/game/x01/GamePanelX01.kt b/src/main/kotlin/dartzee/screen/game/x01/GamePanelX01.kt index 0ed45f07..9c74b3d3 100644 --- a/src/main/kotlin/dartzee/screen/game/x01/GamePanelX01.kt +++ b/src/main/kotlin/dartzee/screen/game/x01/GamePanelX01.kt @@ -10,6 +10,8 @@ import dartzee.core.util.playDodgySound import dartzee.db.AchievementEntity import dartzee.db.GameEntity import dartzee.db.X01FinishEntity +import dartzee.game.FinishType +import dartzee.game.X01Config import dartzee.game.state.IWrappedParticipant import dartzee.game.state.X01PlayerState import dartzee.`object`.ComputedPoint @@ -27,14 +29,14 @@ import dartzee.utils.sumScore class GamePanelX01(parent: AbstractDartsGameScreen, game: GameEntity, totalPlayers: Int) : GamePanelPausable(parent, game, totalPlayers) { - private val startingScore = Integer.parseInt(game.gameParams) + private val config = X01Config.fromJson(game.gameParams) - override fun factoryState(pt: IWrappedParticipant) = X01PlayerState(startingScore, pt) + override fun factoryState(pt: IWrappedParticipant) = X01PlayerState(config, pt) override fun saveDartsAndProceed() { // Finalise the scorer val lastDart = getDartsThrown().last() - val bust = isBust(lastDart) + val bust = isBust(lastDart, config.finishType) val count = getCurrentPlayerState().getBadLuckCount() if (count > 0) { @@ -120,14 +122,11 @@ class GamePanelX01(parent: AbstractDartsGameScreen, game: GameEntity, totalPlaye val playerId = playerState.lastIndividual().playerId val finalRound = getCurrentPlayerState().getLastRound() - val sum = sumScore(finalRound) - AchievementEntity.updateAchievement( - AchievementType.X01_BEST_FINISH, - playerId, - getGameId(), - sum - ) + if (!finalRound.last().isDouble()) { + return + } + val sum = sumScore(finalRound) if (finalRound.count { it.multiplier > 1 } > 1) { val method = finalRound.joinToString() AchievementEntity.insertAchievement( @@ -139,6 +138,13 @@ class GamePanelX01(parent: AbstractDartsGameScreen, game: GameEntity, totalPlaye ) } + AchievementEntity.updateAchievement( + AchievementType.X01_BEST_FINISH, + playerId, + getGameId(), + sum + ) + // Insert into the X01Finishes table for the leaderboard X01FinishEntity.factoryAndSave(playerId, getGameId(), sum) @@ -151,7 +157,7 @@ class GamePanelX01(parent: AbstractDartsGameScreen, game: GameEntity, totalPlaye "" ) - if (sum in listOf(3, 5, 7, 9)) { + if (sum in listOf(3, 5, 7, 9) && config.finishType == FinishType.Doubles) { AchievementEntity.insertAchievement( AchievementType.X01_NO_MERCY, playerId, @@ -177,16 +183,18 @@ class GamePanelX01(parent: AbstractDartsGameScreen, game: GameEntity, totalPlaye val startOfRoundScore = getCurrentPlayerState().getRemainingScoreForRound(currentRoundNumber - 1) val currentScore = getCurrentPlayerState().getRemainingScore() - return if (shouldStopForMercyRule(model, startOfRoundScore, currentScore)) { + return if ( + shouldStopForMercyRule(model, startOfRoundScore, currentScore, config.finishType) + ) { stopThrowing() null } else { - model.throwX01Dart(currentScore) + model.throwX01Dart(currentScore, config.finishType) } } override fun factoryScorer(participant: IWrappedParticipant) = - DartsScorerX01(this, gameEntity.gameParams, participant) + DartsScorerX01(this, config.target, participant) override fun factoryStatsPanel(gameParams: String) = GameStatisticsPanelX01(gameParams) diff --git a/src/main/kotlin/dartzee/screen/game/x01/GameStatisticsPanelX01.kt b/src/main/kotlin/dartzee/screen/game/x01/GameStatisticsPanelX01.kt index a0efda90..d2abba19 100644 --- a/src/main/kotlin/dartzee/screen/game/x01/GameStatisticsPanelX01.kt +++ b/src/main/kotlin/dartzee/screen/game/x01/GameStatisticsPanelX01.kt @@ -5,6 +5,7 @@ import dartzee.core.util.MathsUtil import dartzee.core.util.maxOrZero import dartzee.core.util.minOrZero import dartzee.game.UniqueParticipantName +import dartzee.game.X01Config import dartzee.game.state.X01PlayerState import dartzee.`object`.Dart import dartzee.screen.game.AbstractGameStatisticsPanel @@ -35,7 +36,7 @@ open class GameStatisticsPanelX01(gameParams: String) : nfSetupThreshold.value = 100 nfSetupThreshold.addPropertyChangeListener(this) nfSetupThreshold.setMinimum(62) - nfSetupThreshold.setMaximum(Integer.parseInt(gameParams) - 1) + nfSetupThreshold.setMaximum(X01Config.fromJson(gameParams).target - 1) } override fun getRankedRowsHighestWins() = diff --git a/src/main/kotlin/dartzee/screen/reporting/ReportingGameTab.kt b/src/main/kotlin/dartzee/screen/reporting/ReportingGameTab.kt index a2503e33..637c08e3 100644 --- a/src/main/kotlin/dartzee/screen/reporting/ReportingGameTab.kt +++ b/src/main/kotlin/dartzee/screen/reporting/ReportingGameTab.kt @@ -69,6 +69,13 @@ class ReportingGameTab : JPanel(), ActionListener { add(rdbtnPendingChanges, "flowx,cell 2 7") add(rdbtnSynced, "cell 2 7") + checkBoxGameType.name = "filterGameType" + cbType.name = "filterGameParams" + cbStartDate.name = "filterStartDate" + cbFinishDate.name = "filterFinishDate" + cbPartOfMatch.name = "filterPartOfMatch" + cbSyncStatus.name = "filterSyncStatus" + createButtonGroupsAndSelectDefaults() addListeners() } diff --git a/src/main/kotlin/dartzee/screen/stats/player/StatisticsTabTotalScore.kt b/src/main/kotlin/dartzee/screen/stats/player/StatisticsTabTotalScore.kt index 5a45d244..0a6b9417 100644 --- a/src/main/kotlin/dartzee/screen/stats/player/StatisticsTabTotalScore.kt +++ b/src/main/kotlin/dartzee/screen/stats/player/StatisticsTabTotalScore.kt @@ -6,6 +6,7 @@ import dartzee.core.bean.NumberField import dartzee.core.bean.selectedItemTyped import dartzee.core.obj.HashMapCount import dartzee.core.util.TableUtil.DefaultModel +import dartzee.game.GAME_PARAMS_NOT_APPLICABLE import dartzee.screen.stats.median import dartzee.stats.GameWrapper import java.awt.BorderLayout @@ -315,7 +316,7 @@ class StatisticsTabTotalScore(private val graphTitle: String, outlierMax: Int) : // Handle 0 games if (startingScores.isEmpty()) { - startingScores.add("N/A") + startingScores.add(GAME_PARAMS_NOT_APPLICABLE) } val comboOptions = diff --git a/src/main/kotlin/dartzee/stats/GameWrapper.kt b/src/main/kotlin/dartzee/stats/GameWrapper.kt index 7fd9a7e6..4f1a88bb 100644 --- a/src/main/kotlin/dartzee/stats/GameWrapper.kt +++ b/src/main/kotlin/dartzee/stats/GameWrapper.kt @@ -6,6 +6,7 @@ import dartzee.db.GameEntity import dartzee.db.ParticipantEntity import dartzee.db.PlayerEntity import dartzee.game.GameType +import dartzee.game.X01Config import dartzee.`object`.Dart import dartzee.screen.stats.player.HoleBreakdownWrapper import dartzee.screen.stats.player.golf.OptimalHoleStat @@ -47,7 +48,7 @@ class GameWrapper( // For unfinished games, return -1 so they're sorted to the back fun getCheckoutTotal() = if (finalScore == -1) -1 else getScoreForFinalRound() - fun getGameStartValueX01() = gameParams.toInt() + fun getGameStartValueX01() = X01Config.fromJson(gameParams).target private fun getAllDartsFlattened() = hmRoundNumberToDarts.getAllValues() diff --git a/src/main/kotlin/dartzee/utils/DartsDatabaseUtil.kt b/src/main/kotlin/dartzee/utils/DartsDatabaseUtil.kt index 3b6fc9bc..4409c965 100644 --- a/src/main/kotlin/dartzee/utils/DartsDatabaseUtil.kt +++ b/src/main/kotlin/dartzee/utils/DartsDatabaseUtil.kt @@ -40,7 +40,7 @@ import org.apache.derby.jdbc.EmbeddedDriver /** Database helpers specific to Dartzee, e.g. first time initialisation */ object DartsDatabaseUtil { - const val DATABASE_VERSION = 22 + const val DATABASE_VERSION = 23 const val DATABASE_NAME = "Darts" const val OTHER_DATABASE_NAME = "DartsOther" // Tmp name used for restore from backup and/or sync diff --git a/src/main/kotlin/dartzee/utils/DatabaseMigrations.kt b/src/main/kotlin/dartzee/utils/DatabaseMigrations.kt index 85911462..24898d7b 100644 --- a/src/main/kotlin/dartzee/utils/DatabaseMigrations.kt +++ b/src/main/kotlin/dartzee/utils/DatabaseMigrations.kt @@ -1,6 +1,10 @@ package dartzee.utils +import dartzee.db.GameEntity import dartzee.db.TeamEntity +import dartzee.game.FinishType +import dartzee.game.GameType +import dartzee.game.X01Config object DatabaseMigrations { fun getConversionsMap(): Map Any>> { @@ -11,10 +15,21 @@ object DatabaseMigrations { { db -> runScript(db, 20, "Participant.sql") } ), 20 to listOf { db -> runScript(db, 21, "Dart.sql") }, - 21 to listOf { db -> runScript(db, 22, "Dart.sql") } + 21 to listOf { db -> runScript(db, 22, "Dart.sql") }, + 22 to listOf { db -> convertX01GameParams(db) } ) } + private fun convertX01GameParams(database: Database) { + val games = GameEntity(database).retrieveEntities("GameType = '${GameType.X01}'") + games.forEach { game -> + val target = game.gameParams.toInt() + val config = X01Config(target, FinishType.Doubles) + game.gameParams = config.toJson() + game.saveToDatabase() + } + } + private fun runScript(database: Database, version: Int, scriptName: String): Boolean { val resourcePath = "/sql/v$version/" val rsrc = javaClass.getResource("$resourcePath$scriptName").readText() diff --git a/src/main/kotlin/dartzee/utils/X01Util.kt b/src/main/kotlin/dartzee/utils/X01Util.kt index 38591a3c..268e53d4 100644 --- a/src/main/kotlin/dartzee/utils/X01Util.kt +++ b/src/main/kotlin/dartzee/utils/X01Util.kt @@ -1,15 +1,23 @@ package dartzee.utils import dartzee.ai.DartsAiModel +import dartzee.game.FinishType import dartzee.`object`.Dart -fun isBust(dart: Dart) = isBust(dart.startingScore, dart) +fun isBust(dart: Dart, finishType: FinishType) = isBust(dart.startingScore, dart, finishType) -fun isBust(score: Int, lastDart: Dart): Boolean { +private fun isBust(score: Int, lastDart: Dart, finishType: FinishType): Boolean { val scoreRemaining = score - lastDart.getTotal() - return (scoreRemaining < 0 || - scoreRemaining == 1 || - scoreRemaining == 0 && !lastDart.isDouble()) + + if (scoreRemaining < 0) { + return true + } + + if (finishType == FinishType.Any) { + return false + } + + return scoreRemaining == 1 || (scoreRemaining == 0 && !lastDart.isDouble()) } /** @@ -18,7 +26,16 @@ fun isBust(score: Int, lastDart: Dart): Boolean { * - The starting score was odd and < the threshold (configurable per AI) * - The current score is even, meaning we have bailed ourselves out in some way */ -fun shouldStopForMercyRule(model: DartsAiModel, startingScore: Int, currentScore: Int): Boolean { +fun shouldStopForMercyRule( + model: DartsAiModel, + startingScore: Int, + currentScore: Int, + finishType: FinishType +): Boolean { + if (finishType == FinishType.Any) { + return false + } + val mercyThreshold = model.mercyThreshold ?: return false return startingScore < mercyThreshold && startingScore % 2 != 0 && currentScore % 2 == 0 } diff --git a/src/test/kotlin/dartzee/achievements/x01/TestAchievementX01BestGame.kt b/src/test/kotlin/dartzee/achievements/x01/TestAchievementX01BestGame.kt index 09686acd..91cb388c 100644 --- a/src/test/kotlin/dartzee/achievements/x01/TestAchievementX01BestGame.kt +++ b/src/test/kotlin/dartzee/achievements/x01/TestAchievementX01BestGame.kt @@ -1,7 +1,9 @@ package dartzee.achievements.x01 import dartzee.achievements.TestAbstractAchievementBestGame +import dartzee.game.FinishType import dartzee.game.GameType +import dartzee.game.X01Config import io.kotest.matchers.shouldBe import org.junit.jupiter.api.Test @@ -13,6 +15,9 @@ class TestAchievementX01BestGame : TestAbstractAchievementBestGame + val pt = model.throwX01Dart(61, finishType) + pt.segment shouldBe DartboardSegment(SegmentType.TREBLE, 18) + } } @Test fun `Should throw at inner bull if the scoring dart is 25`() { val model = beastDartsModel(scoringDart = 25) - val pt = model.throwX01Dart(501) + val pt = model.throwX01Dart(501, FinishType.Doubles) pt.segment shouldBe DartboardSegment(SegmentType.DOUBLE, 25) } @@ -190,7 +193,7 @@ class TestDartsAiModel : AbstractTest() { val model = beastDartsModel(scoringDart = 25) for (i in 41..60) { - val pt = model.throwX01Dart(i) + val pt = model.throwX01Dart(i, FinishType.Doubles) pt.segment shouldBe DartboardSegment(SegmentType.OUTER_SINGLE, i - 40) } } @@ -199,7 +202,7 @@ class TestDartsAiModel : AbstractTest() { fun `Should aim to reduce to 32 when the score is less than 40`() { val model = beastDartsModel() - val pt = model.throwX01Dart(37) + val pt = model.throwX01Dart(37, FinishType.Doubles) pt.segment shouldBe DartboardSegment(SegmentType.OUTER_SINGLE, 5) } @@ -207,7 +210,7 @@ class TestDartsAiModel : AbstractTest() { fun `Should aim to reduce to 16 when the score is less than 32`() { val model = beastDartsModel() - val pt = model.throwX01Dart(31) + val pt = model.throwX01Dart(31, FinishType.Doubles) pt.segment shouldBe DartboardSegment(SegmentType.OUTER_SINGLE, 15) } @@ -215,7 +218,7 @@ class TestDartsAiModel : AbstractTest() { fun `Should aim to reduce to 8 when the score is less than 16`() { val model = beastDartsModel() - val pt = model.throwX01Dart(15) + val pt = model.throwX01Dart(15, FinishType.Doubles) pt.segment shouldBe DartboardSegment(SegmentType.OUTER_SINGLE, 7) } @@ -223,7 +226,7 @@ class TestDartsAiModel : AbstractTest() { fun `Should aim to reduce to 4 when the score is less than 8`() { val model = beastDartsModel() - val pt = model.throwX01Dart(7) + val pt = model.throwX01Dart(7, FinishType.Doubles) pt.segment shouldBe DartboardSegment(SegmentType.OUTER_SINGLE, 3) } @@ -233,11 +236,65 @@ class TestDartsAiModel : AbstractTest() { val scores = getCheckoutScores().filter { it <= 40 } scores.forEach { - val pt = model.throwX01Dart(it) + val pt = model.throwX01Dart(it, FinishType.Doubles) pt.segment shouldBe DartboardSegment(SegmentType.DOUBLE, it / 2) } } + /** Relaxed mode */ + @Test + fun `Should aim for the single when on one`() { + val model = beastDartsModel() + + val scores = 1..20 + scores.forEach { + val pt = model.throwX01Dart(it, FinishType.Any) + pt.segment shouldBe DartboardSegment(SegmentType.OUTER_SINGLE, it) + } + } + + @Test + fun `Should aim for treble finishes`() { + val model = beastDartsModel() + + model.throwX01Dart(21, FinishType.Any).segment shouldBe + DartboardSegment(SegmentType.TREBLE, 7) + + model.throwX01Dart(39, FinishType.Any).segment shouldBe + DartboardSegment(SegmentType.TREBLE, 13) + + model.throwX01Dart(60, FinishType.Any).segment shouldBe + DartboardSegment(SegmentType.TREBLE, 20) + } + + @Test + fun `Should aim to leave single twenty`() { + val model = beastDartsModel() + + model.throwX01Dart(40, FinishType.Any).segment shouldBe + DartboardSegment(SegmentType.OUTER_SINGLE, 20) + + model.throwX01Dart(31, FinishType.Any).segment shouldBe + DartboardSegment(SegmentType.OUTER_SINGLE, 11) + + model.throwX01Dart(29, FinishType.Any).segment shouldBe + DartboardSegment(SegmentType.OUTER_SINGLE, 9) + } + + @Test + fun `Should fall back on aiming for single twenty otherwise`() { + val model = beastDartsModel() + + model.throwX01Dart(41, FinishType.Any).segment shouldBe + DartboardSegment(SegmentType.OUTER_SINGLE, 20) + + model.throwX01Dart(50, FinishType.Any).segment shouldBe + DartboardSegment(SegmentType.OUTER_SINGLE, 20) + + model.throwX01Dart(58, FinishType.Any).segment shouldBe + DartboardSegment(SegmentType.OUTER_SINGLE, 20) + } + /** Golf behaviour */ @Test fun `Should aim for double, treble, treble by default`() { diff --git a/src/test/kotlin/dartzee/bean/TestGameParamFilterPanelX01.kt b/src/test/kotlin/dartzee/bean/TestGameParamFilterPanelX01.kt index 4d16c204..71719c3e 100644 --- a/src/test/kotlin/dartzee/bean/TestGameParamFilterPanelX01.kt +++ b/src/test/kotlin/dartzee/bean/TestGameParamFilterPanelX01.kt @@ -1,34 +1,43 @@ package dartzee.bean +import com.github.alyssaburlton.swingtest.clickChild +import com.github.alyssaburlton.swingtest.getChild import dartzee.core.helper.verifyNotCalled +import dartzee.game.FinishType +import dartzee.game.X01Config import dartzee.helper.AbstractTest import io.kotest.matchers.shouldBe import io.mockk.clearAllMocks import io.mockk.mockk import io.mockk.verify import java.awt.event.ActionListener +import javax.swing.JCheckBox import org.junit.jupiter.api.Test class TestGameParamFilterPanelX01 : AbstractTest() { @Test - fun `Should return game params based on the spinner selection`() { + fun `Should return game params based on the selection`() { val panel = GameParamFilterPanelX01() - panel.spinner.value = 701 - panel.getGameParams() shouldBe "701" + panel.getChild().value = 701 + panel.getGameParams() shouldBe X01Config(701, FinishType.Doubles).toJson() panel.getFilterDesc() shouldBe "games of 701" - panel.spinner.value = 301 - panel.getGameParams() shouldBe "301" - panel.getFilterDesc() shouldBe "games of 301" + panel.getChild().value = 301 + panel.clickChild() + panel.getGameParams() shouldBe X01Config(301, FinishType.Any).toJson() + panel.getFilterDesc() shouldBe "games of 301 (relaxed finish)" } @Test fun `Should support setting the selection by gameParams`() { + val params = X01Config(701, FinishType.Any) + val panel = GameParamFilterPanelX01() - panel.setGameParams("701") + panel.setGameParams(params.toJson()) - panel.spinner.value shouldBe 701 + panel.getChild().value shouldBe 701 + panel.getChild().isSelected shouldBe false } @Test @@ -36,10 +45,12 @@ class TestGameParamFilterPanelX01 : AbstractTest() { val panel = GameParamFilterPanelX01() panel.enableChildren(false) - panel.spinner.isEnabled shouldBe false + panel.getChild().isEnabled shouldBe false + panel.getChild().isEnabled shouldBe false panel.enableChildren(true) - panel.spinner.isEnabled shouldBe true + panel.getChild().isEnabled shouldBe true + panel.getChild().isEnabled shouldBe true } @Test @@ -49,14 +60,14 @@ class TestGameParamFilterPanelX01 : AbstractTest() { val listener = mockk(relaxed = true) panel.addActionListener(listener) - panel.spinner.value = 701 + panel.getChild().value = 701 verify { listener.actionPerformed(any()) } clearAllMocks() panel.removeActionListener(listener) - panel.spinner.value = 301 + panel.getChild().value = 301 verifyNotCalled { listener.actionPerformed(any()) } } diff --git a/src/test/kotlin/dartzee/db/TestDartsMatchEntity.kt b/src/test/kotlin/dartzee/db/TestDartsMatchEntity.kt index 4fce31de..4eaa08ab 100644 --- a/src/test/kotlin/dartzee/db/TestDartsMatchEntity.kt +++ b/src/test/kotlin/dartzee/db/TestDartsMatchEntity.kt @@ -3,6 +3,7 @@ package dartzee.db import dartzee.db.DartsMatchEntity.Companion.constructPointsJson import dartzee.game.GameType import dartzee.game.MatchMode +import dartzee.helper.DEFAULT_X01_CONFIG import dartzee.helper.getCountFromTable import dartzee.helper.insertDartsMatch import dartzee.helper.insertGame @@ -66,7 +67,7 @@ class TestDartsMatchEntity : AbstractEntityTest() { dm.games = 3 dm.mode = MatchMode.FIRST_TO dm.gameType = GameType.X01 - dm.gameParams = "501" + dm.gameParams = DEFAULT_X01_CONFIG.toJson() dm.getMatchDesc() shouldBe "Match #1 (First to 3 - 501)" } diff --git a/src/test/kotlin/dartzee/db/TestDatabaseMIgrationV21toV22.kt b/src/test/kotlin/dartzee/db/TestDatabaseMigrationV21toV22.kt similarity index 95% rename from src/test/kotlin/dartzee/db/TestDatabaseMIgrationV21toV22.kt rename to src/test/kotlin/dartzee/db/TestDatabaseMigrationV21toV22.kt index fc082281..65fd0a36 100644 --- a/src/test/kotlin/dartzee/db/TestDatabaseMIgrationV21toV22.kt +++ b/src/test/kotlin/dartzee/db/TestDatabaseMigrationV21toV22.kt @@ -11,7 +11,7 @@ import io.mockk.every import io.mockk.mockk import org.junit.jupiter.api.Test -class TestDatabaseMIgrationV21toV22 : AbstractTest() { +class TestDatabaseMigrationV21toV22 : AbstractTest() { @Test fun `Should update MISSED_BOARD darts to just MISS`() { val segmentType = mockk() diff --git a/src/test/kotlin/dartzee/db/TestDatabaseMigrationV22toV23.kt b/src/test/kotlin/dartzee/db/TestDatabaseMigrationV22toV23.kt new file mode 100644 index 00000000..f8ebe2dd --- /dev/null +++ b/src/test/kotlin/dartzee/db/TestDatabaseMigrationV22toV23.kt @@ -0,0 +1,32 @@ +package dartzee.db + +import dartzee.game.FinishType +import dartzee.game.GameType +import dartzee.game.X01Config +import dartzee.helper.AbstractTest +import dartzee.helper.insertGame +import dartzee.helper.runConversion +import io.kotest.matchers.shouldBe +import org.junit.jupiter.api.Test + +class TestDatabaseMigrationV22toV23 : AbstractTest() { + @Test + fun `Should convert games of X01`() { + val g = insertGame(gameType = GameType.X01, gameParams = "701") + + runConversion(22) + + val retrieved = GameEntity().retrieveForId(g.rowId)!! + retrieved.gameParams shouldBe X01Config(701, FinishType.Doubles).toJson() + } + + @Test + fun `Should leave other game types alone`() { + val g = insertGame(gameType = GameType.GOLF, gameParams = "18") + + runConversion(22) + + val retrieved = GameEntity().retrieveForId(g.rowId)!! + retrieved.gameParams shouldBe "18" + } +} diff --git a/src/test/kotlin/dartzee/e2e/GameHelpers.kt b/src/test/kotlin/dartzee/e2e/GameHelpers.kt index 1b1c68ee..b76cbd50 100644 --- a/src/test/kotlin/dartzee/e2e/GameHelpers.kt +++ b/src/test/kotlin/dartzee/e2e/GameHelpers.kt @@ -16,6 +16,7 @@ import dartzee.db.GameEntity import dartzee.db.IParticipant import dartzee.db.PlayerEntity import dartzee.game.prepareParticipants +import dartzee.game.state.IWrappedParticipant import dartzee.helper.beastDartsModel import dartzee.helper.insertPlayer import dartzee.helper.insertPlayerImage @@ -76,8 +77,8 @@ data class GamePanelTestSetup(val gamePanel: DartsGamePanel<*, *>, val listener: fun setUpGamePanelAndStartGame(game: GameEntity, players: List) = setUpGamePanel(game).also { it.gamePanel.startGame(players) } -fun setUpGamePanel(game: GameEntity): GamePanelTestSetup { - val parentWindow = DartsGameScreen(game, 1) +fun setUpGamePanel(game: GameEntity, totalPlayers: Int = 1): GamePanelTestSetup { + val parentWindow = DartsGameScreen(game, totalPlayers) parentWindow.isVisible = true val gamePanel = parentWindow.gamePanel @@ -87,9 +88,10 @@ fun setUpGamePanel(game: GameEntity): GamePanelTestSetup { return GamePanelTestSetup(gamePanel, listener) } -fun DartsGamePanel<*, *>.startGame(players: List) { +fun DartsGamePanel<*, *>.startGame(players: List): List { val participants = prepareParticipants(gameEntity.rowId, players, false) startNewGame(participants) + return participants } fun awaitGameFinish(game: GameEntity) { diff --git a/src/test/kotlin/dartzee/e2e/SyncE2E.kt b/src/test/kotlin/dartzee/e2e/SyncE2E.kt index 430e8ac8..a9906c0f 100644 --- a/src/test/kotlin/dartzee/e2e/SyncE2E.kt +++ b/src/test/kotlin/dartzee/e2e/SyncE2E.kt @@ -13,6 +13,7 @@ import dartzee.game.GameLaunchParams import dartzee.game.GameLauncher import dartzee.game.GameType import dartzee.helper.AbstractRegistryTest +import dartzee.helper.DEFAULT_X01_CONFIG import dartzee.helper.TEST_DB_DIRECTORY import dartzee.helper.TEST_ROOT import dartzee.helper.getCountFromTable @@ -146,7 +147,13 @@ class SyncE2E : AbstractRegistryTest() { } private fun runGame(winner: PlayerEntity, loser: PlayerEntity): String { - val params = GameLaunchParams(listOf(winner, loser), GameType.X01, "501", false) + val params = + GameLaunchParams( + listOf(winner, loser), + GameType.X01, + DEFAULT_X01_CONFIG.toJson(), + false + ) GameLauncher().launchNewGame(params) val gameId = retrieveGame().rowId diff --git a/src/test/kotlin/dartzee/e2e/TestGameLoadE2E.kt b/src/test/kotlin/dartzee/e2e/TestGameLoadE2E.kt index 11ca2e9e..da501ab3 100644 --- a/src/test/kotlin/dartzee/e2e/TestGameLoadE2E.kt +++ b/src/test/kotlin/dartzee/e2e/TestGameLoadE2E.kt @@ -8,6 +8,7 @@ import dartzee.game.GameLauncher import dartzee.game.GameType import dartzee.getRows import dartzee.helper.AbstractRegistryTest +import dartzee.helper.DEFAULT_X01_CONFIG import dartzee.helper.retrieveGame import dartzee.helper.retrieveParticipant import dartzee.`object`.Dart @@ -39,7 +40,13 @@ class TestGameLoadE2E : AbstractRegistryTest() { fun `E2E - Game load and AI resume`() { val (winner, loser) = createPlayers() - val params = GameLaunchParams(listOf(winner, loser), GameType.X01, "501", false) + val params = + GameLaunchParams( + listOf(winner, loser), + GameType.X01, + DEFAULT_X01_CONFIG.toJson(), + false + ) GameLauncher().launchNewGame(params) waitForAssertion { retrieveGame().isFinished() shouldBe true } diff --git a/src/test/kotlin/dartzee/e2e/TestMatchE2E.kt b/src/test/kotlin/dartzee/e2e/TestMatchE2E.kt index c3682c4e..20239841 100644 --- a/src/test/kotlin/dartzee/e2e/TestMatchE2E.kt +++ b/src/test/kotlin/dartzee/e2e/TestMatchE2E.kt @@ -6,11 +6,14 @@ import dartzee.core.util.DateStatics import dartzee.db.GameEntity import dartzee.db.ParticipantEntity import dartzee.db.PlayerEntity +import dartzee.game.FinishType import dartzee.game.GameLaunchParams import dartzee.game.GameLauncher import dartzee.game.GameType import dartzee.game.MatchMode +import dartzee.game.X01Config import dartzee.helper.AbstractRegistryTest +import dartzee.helper.DEFAULT_X01_CONFIG import dartzee.helper.insertDartsMatch import dartzee.helper.retrieveDartsMatch import dartzee.screen.ScreenCache @@ -47,7 +50,13 @@ class TestMatchE2E : AbstractRegistryTest() { match.gameParams = "501" val (winner, loser) = createPlayers() - val launchParams = GameLaunchParams(listOf(winner, loser), GameType.X01, "501", false) + val launchParams = + GameLaunchParams( + listOf(winner, loser), + GameType.X01, + DEFAULT_X01_CONFIG.toJson(), + false + ) GameLauncher().launchNewMatch(match, launchParams) waitForAssertion { retrieveDartsMatch().dtFinish shouldNotBe DateStatics.END_OF_TIME } @@ -60,7 +69,7 @@ class TestMatchE2E : AbstractRegistryTest() { val games = GameEntity().retrieveEntities() games.size shouldBe 2 games.forEach { - it.gameParams shouldBe "501" + it.gameParams shouldBe X01Config(501, FinishType.Doubles).toJson() it.gameType shouldBe GameType.X01 it.dtFinish shouldNotBe DateStatics.END_OF_TIME it.dartsMatchId shouldBe matchId diff --git a/src/test/kotlin/dartzee/e2e/TestResizeE2E.kt b/src/test/kotlin/dartzee/e2e/TestResizeE2E.kt index 63beabc2..11b903ea 100644 --- a/src/test/kotlin/dartzee/e2e/TestResizeE2E.kt +++ b/src/test/kotlin/dartzee/e2e/TestResizeE2E.kt @@ -3,6 +3,7 @@ package dartzee.e2e import dartzee.ai.AimDart import dartzee.game.GameType import dartzee.helper.AbstractRegistryTest +import dartzee.helper.DEFAULT_X01_CONFIG import dartzee.helper.beastDartsModel import dartzee.helper.insertGame import dartzee.helper.insertPlayer @@ -26,7 +27,7 @@ class TestResizeE2E : AbstractRegistryTest() { @Test @Tag("e2e") fun `E2E - Small dartboard`() { - val game = insertGame(gameType = GameType.X01, gameParams = "501") + val game = insertGame(gameType = GameType.X01, gameParams = DEFAULT_X01_CONFIG.toJson()) val aiModel = beastDartsModel(hmScoreToDart = mapOf(81 to AimDart(19, 3))) val player = insertPlayer(model = aiModel) diff --git a/src/test/kotlin/dartzee/e2e/TestX01E2E.kt b/src/test/kotlin/dartzee/e2e/TestX01E2E.kt index ed0d420b..871c6248 100644 --- a/src/test/kotlin/dartzee/e2e/TestX01E2E.kt +++ b/src/test/kotlin/dartzee/e2e/TestX01E2E.kt @@ -1,11 +1,15 @@ package dartzee.e2e +import com.github.alyssaburlton.swingtest.waitForAssertion import dartzee.achievements.AchievementType import dartzee.ai.AimDart +import dartzee.game.FinishType import dartzee.game.GameType +import dartzee.game.X01Config import dartzee.game.prepareParticipants import dartzee.helper.AbstractRegistryTest import dartzee.helper.AchievementSummary +import dartzee.helper.DEFAULT_X01_CONFIG import dartzee.helper.beastDartsModel import dartzee.helper.insertGame import dartzee.helper.insertPlayer @@ -14,26 +18,31 @@ import dartzee.helper.predictableDartsModel import dartzee.helper.retrieveAchievementsForPlayer import dartzee.helper.retrieveTeam import dartzee.`object`.Dart +import dartzee.utils.PREFERENCES_BOOLEAN_AI_AUTO_CONTINUE import dartzee.utils.PREFERENCES_INT_AI_SPEED import dartzee.utils.PreferenceUtil import dartzee.zipDartRounds import io.kotest.matchers.collections.shouldContainExactlyInAnyOrder +import io.kotest.matchers.ints.shouldBeGreaterThan +import io.kotest.matchers.shouldBe import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Tag import org.junit.jupiter.api.Test class TestX01E2E : AbstractRegistryTest() { - override fun getPreferencesAffected() = listOf(PREFERENCES_INT_AI_SPEED) + override fun getPreferencesAffected() = + listOf(PREFERENCES_INT_AI_SPEED, PREFERENCES_BOOLEAN_AI_AUTO_CONTINUE) @BeforeEach fun beforeEach() { PreferenceUtil.saveInt(PREFERENCES_INT_AI_SPEED, 100) + PreferenceUtil.saveBoolean(PREFERENCES_BOOLEAN_AI_AUTO_CONTINUE, true) } @Test @Tag("e2e") fun `E2E - 501 - 9 dart game`() { - val game = insertGame(gameType = GameType.X01, gameParams = "501") + val game = insertGame(gameType = GameType.X01, gameParams = DEFAULT_X01_CONFIG.toJson()) val aiModel = beastDartsModel(hmScoreToDart = mapOf(81 to AimDart(19, 3))) val player = insertPlayer(model = aiModel) @@ -67,10 +76,111 @@ class TestX01E2E : AbstractRegistryTest() { checkAchievementConversions(player.rowId) } + @Test + @Tag("e2e") + fun `E2E - 501 - 9 dart game, relaxed finish`() { + val game = + insertGame( + gameType = GameType.X01, + gameParams = X01Config(501, FinishType.Any).toJson() + ) + + val player = insertPlayer(model = beastDartsModel()) + + val (panel, listener) = setUpGamePanelAndStartGame(game, listOf(player)) + awaitGameFinish(game) + + val expectedRounds = + listOf( + listOf(Dart(20, 3), Dart(20, 3), Dart(20, 3)), + listOf(Dart(20, 3), Dart(20, 3), Dart(20, 3)), + listOf(Dart(20, 3), Dart(20, 3), Dart(7, 3)) + ) + + verifyState(panel, listener, expectedRounds, scoreSuffix = " Darts", finalScore = 9) + + retrieveAchievementsForPlayer(player.rowId) + .shouldContainExactlyInAnyOrder( + AchievementSummary(AchievementType.X01_BEST_THREE_DART_SCORE, 180, game.rowId), + ) + + checkAchievementConversions(player.rowId) + } + + @Test + @Tag("e2e") + fun `E2E - 101 - relaxed`() { + val game = + insertGame( + gameType = GameType.X01, + gameParams = X01Config(101, FinishType.Any).toJson() + ) + + val (gamePanel) = setUpGamePanel(game, 2) + + val p1Rounds = + listOf( + listOf(makeDart(20, 3), makeDart(20, 1), makeDart(20, 1)), // 1 + listOf(makeDart(20, 1)), // 1 (bust) + listOf(makeDart(1, 0), makeDart(1, 0), makeDart(1, 1)), // 0 + ) + + val p2Rounds = + listOf( + listOf(makeDart(20, 1), makeDart(5, 1), makeDart(1, 1)), // 75 + listOf(makeDart(20, 3), makeDart(5, 1), makeDart(20, 2)), // 75 (bust) + listOf(makeDart(20, 3), makeDart(5, 1), makeDart(5, 2)) // 0 + ) + + val p1Model = predictableDartsModel(p1Rounds.flatten().map { it.toAimDart() }) + val p1 = makePlayerWithModel(p1Model) + + val p2Model = predictableDartsModel(p2Rounds.flatten().map { it.toAimDart() }) + val p2 = makePlayerWithModel(p2Model, "Jeff") + + val (pt1, pt2) = gamePanel.startGame(listOf(p1, p2)) + awaitGameFinish(game) + waitForAssertion { pt2.participant.finalScore shouldBeGreaterThan -1 } + + pt1.participant.finalScore shouldBe 9 + pt1.participant.finishingPosition shouldBe 1 + pt2.participant.finalScore shouldBe 9 + pt2.participant.finishingPosition shouldBe 2 + + retrieveAchievementsForPlayer(p1.rowId) + .shouldContainExactlyInAnyOrder( + AchievementSummary(AchievementType.X01_BEST_THREE_DART_SCORE, 100, game.rowId), + AchievementSummary(AchievementType.X01_HIGHEST_BUST, 1, game.rowId), + AchievementSummary(AchievementType.X01_GAMES_WON, -1, game.rowId, "9"), + ) + + retrieveAchievementsForPlayer(p2.rowId) + .shouldContainExactlyInAnyOrder( + AchievementSummary(AchievementType.X01_HOTEL_INSPECTOR, -1, game.rowId, "20, 5, 1"), + AchievementSummary(AchievementType.X01_BEST_FINISH, 75, game.rowId), + AchievementSummary( + AchievementType.X01_STYLISH_FINISH, + 75, + game.rowId, + "T20, 5, D5" + ), + AchievementSummary(AchievementType.X01_BEST_THREE_DART_SCORE, 75, game.rowId), + AchievementSummary(AchievementType.X01_CHECKOUT_COMPLETENESS, 5, game.rowId), + AchievementSummary(AchievementType.X01_HIGHEST_BUST, 75, game.rowId), + AchievementSummary(AchievementType.X01_SUCH_BAD_LUCK, 1, game.rowId) + ) + + checkAchievementConversions(p2.rowId) + } + @Test @Tag("e2e") fun `E2E - 301 - bust and mercy rule`() { - val game = insertGame(gameType = GameType.X01, gameParams = "301") + val game = + insertGame( + gameType = GameType.X01, + gameParams = X01Config(301, FinishType.Doubles).toJson() + ) val (gamePanel, listener) = setUpGamePanel(game) @@ -109,7 +219,7 @@ class TestX01E2E : AbstractRegistryTest() { @Test @Tag("e2e") fun `E2E - 501 - Team of 2`() { - val game = insertGame(gameType = GameType.X01, gameParams = "501") + val game = insertGame(gameType = GameType.X01, gameParams = DEFAULT_X01_CONFIG.toJson()) val (gamePanel, listener) = setUpGamePanel(game) val p1Rounds = diff --git a/src/test/kotlin/dartzee/game/TestGameLauncher.kt b/src/test/kotlin/dartzee/game/TestGameLauncher.kt index fb2d6736..79398c69 100644 --- a/src/test/kotlin/dartzee/game/TestGameLauncher.kt +++ b/src/test/kotlin/dartzee/game/TestGameLauncher.kt @@ -5,6 +5,7 @@ import dartzee.db.DartsMatchEntity import dartzee.db.EntityName import dartzee.game.state.GolfPlayerState import dartzee.helper.AbstractTest +import dartzee.helper.DEFAULT_X01_CONFIG import dartzee.helper.getCountFromTable import dartzee.helper.insertDartsMatch import dartzee.helper.insertGame @@ -35,7 +36,7 @@ import org.junit.jupiter.api.Test class TestGameLauncher : AbstractTest() { @Test fun `Should launch a new game of X01 successfully`() { - testNewGameLaunch(GameType.X01, "501") + testNewGameLaunch(GameType.X01, DEFAULT_X01_CONFIG.toJson()) } @Test diff --git a/src/test/kotlin/dartzee/game/TestGameType.kt b/src/test/kotlin/dartzee/game/TestGameType.kt index d590184a..2b925cca 100644 --- a/src/test/kotlin/dartzee/game/TestGameType.kt +++ b/src/test/kotlin/dartzee/game/TestGameType.kt @@ -6,6 +6,15 @@ import io.kotest.matchers.shouldBe import org.junit.jupiter.api.Test class TestGameType : AbstractTest() { + @Test + fun `Not applicable params`() { + GameType.X01.getDescription(GAME_PARAMS_NOT_APPLICABLE) shouldBe "N/A" + GameType.GOLF.getDescription(GAME_PARAMS_NOT_APPLICABLE) shouldBe "Golf - N/A" + GameType.ROUND_THE_CLOCK.getDescription(GAME_PARAMS_NOT_APPLICABLE) shouldBe + "Round the Clock - N/A" + GameType.DARTZEE.getDescription(GAME_PARAMS_NOT_APPLICABLE) shouldBe "Dartzee - N/A" + } + @Test fun `Sensible descriptions when no params`() { GameType.X01.getDescription() shouldBe "X01" @@ -16,7 +25,8 @@ class TestGameType : AbstractTest() { @Test fun `Sensible descriptions with params`() { - GameType.X01.getDescription("701") shouldBe "701" + val x01Config = X01Config(701, FinishType.Any) + GameType.X01.getDescription(x01Config.toJson()) shouldBe x01Config.description() GameType.GOLF.getDescription("18") shouldBe "Golf - 18 holes" GameType.ROUND_THE_CLOCK.getDescription( RoundTheClockConfig(ClockType.Trebles, true).toJson() diff --git a/src/test/kotlin/dartzee/game/TestX01Config.kt b/src/test/kotlin/dartzee/game/TestX01Config.kt new file mode 100644 index 00000000..df236979 --- /dev/null +++ b/src/test/kotlin/dartzee/game/TestX01Config.kt @@ -0,0 +1,24 @@ +package dartzee.game + +import dartzee.helper.AbstractTest +import io.kotest.matchers.shouldBe +import org.junit.jupiter.api.Test + +class TestX01Config : AbstractTest() { + @Test + fun `Should serialize and deserialize correctly`() { + val config = X01Config(701, FinishType.Any) + val json = config.toJson() + + val newConfig = X01Config.fromJson(json) + newConfig shouldBe config + } + + @Test + fun `Should deserialize correctly`() { + val json = """{ "target": 301, "finishType": "Doubles" }""" + val config = X01Config.fromJson(json) + config.target shouldBe 301 + config.finishType shouldBe FinishType.Doubles + } +} diff --git a/src/test/kotlin/dartzee/game/state/TestX01PlayerState.kt b/src/test/kotlin/dartzee/game/state/TestX01PlayerState.kt index ed2fa214..c8a75255 100644 --- a/src/test/kotlin/dartzee/game/state/TestX01PlayerState.kt +++ b/src/test/kotlin/dartzee/game/state/TestX01PlayerState.kt @@ -8,6 +8,8 @@ import dartzee.drtMissTwenty import dartzee.drtOuterOne import dartzee.drtOuterTen import dartzee.drtTrebleTwenty +import dartzee.game.FinishType +import dartzee.game.X01Config import dartzee.helper.AbstractTest import dartzee.helper.insertParticipant import dartzee.helper.insertTeam @@ -99,7 +101,11 @@ class TestX01PlayerState : AbstractTest() { @Test fun `Should take into account current round when computing the remaining score`() { - val state = X01PlayerState(301, SingleParticipant(insertParticipant())) + val state = + X01PlayerState( + X01Config(301, FinishType.Doubles), + SingleParticipant(insertParticipant()) + ) state.dartThrown(makeDart(20, 3)) state.dartThrown(makeDart(20, 3)) state.dartThrown(makeDart(20, 3)) @@ -117,6 +123,20 @@ class TestX01PlayerState : AbstractTest() { state.getRemainingScore() shouldBe 121 } + @Test + fun `should compute the remaining score correctly when finishType is Any`() { + val state = + X01PlayerState(X01Config(101, FinishType.Any), SingleParticipant(insertParticipant())) + + state.dartThrown(makeDart(20, 3)) + state.dartThrown(makeDart(20, 1)) + state.dartThrown(makeDart(20, 1)) + state.getRemainingScore() shouldBe 1 + + state.commitRound() + state.getRemainingScore() shouldBe 1 + } + @Test fun `Should return a bad luck count of 0 if no darts thrown`() { val state = makeX01PlayerStateWithRounds(completedRounds = emptyList()) @@ -157,7 +177,11 @@ class TestX01PlayerState : AbstractTest() { val team = insertTeam() val pt1 = insertParticipant(teamId = team.rowId) val pt2 = insertParticipant(teamId = team.rowId) - val state = X01PlayerState(101, TeamParticipant(team, listOf(pt1, pt2))) + val state = + X01PlayerState( + X01Config(101, FinishType.Doubles), + TeamParticipant(team, listOf(pt1, pt2)) + ) val roundOne = listOf(drtTrebleTwenty(), drtOuterOne(), drtMissTwenty()) // Get down to 40 @@ -202,7 +226,11 @@ class TestX01PlayerState : AbstractTest() { @Test fun `Should set startingScore on darts as they are added`() { - val state = X01PlayerState(301, SingleParticipant(insertParticipant())) + val state = + X01PlayerState( + X01Config(301, FinishType.Doubles), + SingleParticipant(insertParticipant()) + ) val dartOne = makeDart(20, 1) val dartTwo = makeDart(25, 2) @@ -223,16 +251,34 @@ class TestX01PlayerState : AbstractTest() { val bustRound = listOf(Dart(20, 3), Dart(20, 3)) val finishedRound = listOf(Dart(17, 3), Dart(25, 2)) val incompleteRound = listOf(Dart(20, 1), Dart(20, 1)) + val leftOneRemaining = listOf(Dart(20, 3), Dart(20, 2)) stateWithCurrentRound(threeDartRound).isCurrentRoundComplete() shouldBe true stateWithCurrentRound(bustRound).isCurrentRoundComplete() shouldBe true stateWithCurrentRound(finishedRound).isCurrentRoundComplete() shouldBe true + stateWithCurrentRound(leftOneRemaining).isCurrentRoundComplete() shouldBe true stateWithCurrentRound(incompleteRound).isCurrentRoundComplete() shouldBe false stateWithCurrentRound(emptyList()).isCurrentRoundComplete() shouldBe false + + val finishedOnTreble = listOf(Dart(20, 3), Dart(20, 1), Dart(7, 3)) + stateWithCurrentRound(bustRound, FinishType.Any).isCurrentRoundComplete() shouldBe true + stateWithCurrentRound(finishedRound, FinishType.Any).isCurrentRoundComplete() shouldBe true + stateWithCurrentRound(finishedOnTreble, FinishType.Any).isCurrentRoundComplete() shouldBe + true + + stateWithCurrentRound(leftOneRemaining, FinishType.Any).isCurrentRoundComplete() shouldBe + false + stateWithCurrentRound(incompleteRound, FinishType.Any).isCurrentRoundComplete() shouldBe + false + stateWithCurrentRound(emptyList(), FinishType.Any).isCurrentRoundComplete() shouldBe false } - private fun stateWithCurrentRound(darts: List): X01PlayerState { - val state = X01PlayerState(101, SingleParticipant(insertParticipant())) + private fun stateWithCurrentRound( + darts: List, + finishType: FinishType = FinishType.Doubles + ): X01PlayerState { + val state = + X01PlayerState(X01Config(101, finishType), SingleParticipant(insertParticipant())) darts.forEach { state.dartThrown(it) } return state } diff --git a/src/test/kotlin/dartzee/helper/DartsModelFactory.kt b/src/test/kotlin/dartzee/helper/DartsModelFactory.kt index c2066eaf..913aec58 100644 --- a/src/test/kotlin/dartzee/helper/DartsModelFactory.kt +++ b/src/test/kotlin/dartzee/helper/DartsModelFactory.kt @@ -89,7 +89,7 @@ fun predictableDartsModel( every { model.throwScoringDart() } answers { throwDartFn() } every { model.throwDartzeeDart(any(), any()) } answers { throwDartFn() } - every { model.throwX01Dart(any()) } answers { throwDartFn() } + every { model.throwX01Dart(any(), any()) } answers { throwDartFn() } every { model.throwClockDart(any(), any()) } answers { throwDartFn() } every { model.throwGolfDart(any(), any()) } answers { throwDartFn() } every { model.getStopThresholdForDartNo(any()) } answers { callOriginal() } diff --git a/src/test/kotlin/dartzee/helper/InMemoryDatabaseHelper.kt b/src/test/kotlin/dartzee/helper/InMemoryDatabaseHelper.kt index acce86c3..14b5a0f3 100644 --- a/src/test/kotlin/dartzee/helper/InMemoryDatabaseHelper.kt +++ b/src/test/kotlin/dartzee/helper/InMemoryDatabaseHelper.kt @@ -21,8 +21,10 @@ import dartzee.db.PlayerEntity import dartzee.db.PlayerImageEntity import dartzee.db.TeamEntity import dartzee.db.X01FinishEntity +import dartzee.game.FinishType import dartzee.game.GameType import dartzee.game.MatchMode +import dartzee.game.X01Config import dartzee.logging.LoggingCode import dartzee.`object`.Dart import dartzee.`object`.SegmentType @@ -284,7 +286,7 @@ fun insertGameForReport( uuid: String = randomGuid(), localId: Long = mainDatabase.generateLocalId(EntityName.Game), gameType: GameType = GameType.X01, - gameParams: String = "501", + gameParams: String = X01Config(501, FinishType.Doubles).toJson(), dtFinish: Timestamp = DateStatics.END_OF_TIME, dartsMatchId: String = "", matchOrdinal: Int = -1, @@ -315,7 +317,7 @@ fun insertGame( database: Database = mainDatabase, localId: Long = database.generateLocalId(EntityName.Game), gameType: GameType = GameType.X01, - gameParams: String = "501", + gameParams: String = X01Config(501, FinishType.Doubles).toJson(), dtFinish: Timestamp = DateStatics.END_OF_TIME, dartsMatchId: String = "", matchOrdinal: Int = -1, diff --git a/src/test/kotlin/dartzee/helper/TestFactory.kt b/src/test/kotlin/dartzee/helper/TestFactory.kt index 80794807..001250ee 100644 --- a/src/test/kotlin/dartzee/helper/TestFactory.kt +++ b/src/test/kotlin/dartzee/helper/TestFactory.kt @@ -8,8 +8,10 @@ import dartzee.db.LocalIdGenerator import dartzee.db.ParticipantEntity import dartzee.db.PlayerEntity import dartzee.game.ClockType +import dartzee.game.FinishType import dartzee.game.GameType import dartzee.game.RoundTheClockConfig +import dartzee.game.X01Config import dartzee.game.state.ClockPlayerState import dartzee.game.state.GolfPlayerState import dartzee.game.state.SingleParticipant @@ -100,7 +102,7 @@ fun makeX01Rounds(startingScore: Int = 501, vararg darts: List): List = listOf() ): X01PlayerState = - X01PlayerState(startingScore, SingleParticipant(participant), mutableListOf(completedRound)) + X01PlayerState( + X01Config(startingScore, FinishType.Doubles), + SingleParticipant(participant), + mutableListOf(completedRound) + ) fun makeX01PlayerStateWithRounds( startingScore: Int = 501, @@ -173,7 +179,7 @@ fun makeX01PlayerStateWithRounds( ): X01PlayerState { completedRounds.flatten().forEach { it.participantId = participant.rowId } return X01PlayerState( - startingScore, + X01Config(startingScore, FinishType.Doubles), SingleParticipant(participant), completedRounds.toMutableList(), mutableListOf(), @@ -197,7 +203,7 @@ fun makeGolfPlayerState( fun makeGameWrapper( localId: Long = LocalIdGenerator(mainDatabase).generateLocalId(EntityName.Game), - gameParams: String = "501", + gameParams: String = DEFAULT_X01_CONFIG.toJson(), dtStart: Timestamp = Timestamp(1000), dtFinish: Timestamp = DateStatics.END_OF_TIME, finalScore: Int = -1, diff --git a/src/test/kotlin/dartzee/helper/X01TestConstants.kt b/src/test/kotlin/dartzee/helper/X01TestConstants.kt index 961eee23..e27ba4a1 100644 --- a/src/test/kotlin/dartzee/helper/X01TestConstants.kt +++ b/src/test/kotlin/dartzee/helper/X01TestConstants.kt @@ -1,5 +1,7 @@ package dartzee.helper +import dartzee.game.FinishType +import dartzee.game.X01Config import dartzee.`object`.Dart private val gameOneRounds = @@ -29,3 +31,5 @@ val GAME_WRAPPER_301_2 = makeGameWrapper(gameParams = "301", finalScore = 17, localId = 2L).also { gameTwoRounds.flatten().forEach(it::addDart) } + +val DEFAULT_X01_CONFIG = X01Config(501, FinishType.Doubles) diff --git a/src/test/kotlin/dartzee/reporting/TestReportingSqlUtil.kt b/src/test/kotlin/dartzee/reporting/TestReportingSqlUtil.kt index 2b3c1594..561de40b 100644 --- a/src/test/kotlin/dartzee/reporting/TestReportingSqlUtil.kt +++ b/src/test/kotlin/dartzee/reporting/TestReportingSqlUtil.kt @@ -81,7 +81,7 @@ class TestReportingSqlUtil : AbstractTest() { val dartzeeGameWithTemplate = insertGame(gameType = GameType.DARTZEE, gameParams = template.rowId) val dartzeeGameStandalone = insertGame(gameType = GameType.DARTZEE, gameParams = "") - val x01Game = insertGame(gameType = GameType.X01, gameParams = "501") + val x01Game = insertGame(gameType = GameType.X01) insertPlayerForGame("Alice", dartzeeGameWithTemplate.rowId) insertPlayerForGame("Bob", dartzeeGameStandalone.rowId) diff --git a/src/test/kotlin/dartzee/screen/TestGameSetupScreen.kt b/src/test/kotlin/dartzee/screen/TestGameSetupScreen.kt index 9821dc6b..b425bdeb 100644 --- a/src/test/kotlin/dartzee/screen/TestGameSetupScreen.kt +++ b/src/test/kotlin/dartzee/screen/TestGameSetupScreen.kt @@ -1,8 +1,10 @@ package dartzee.screen +import com.github.alyssaburlton.swingtest.getChild import dartzee.bean.GameParamFilterPanelDartzee import dartzee.bean.GameParamFilterPanelGolf import dartzee.bean.GameParamFilterPanelX01 +import dartzee.bean.SpinnerX01 import dartzee.bean.getAllPlayers import dartzee.core.bean.items import dartzee.dartzee.aggregate.DartzeeTotalRulePrime @@ -11,11 +13,14 @@ import dartzee.dartzee.dart.DartzeeDartRuleOdd import dartzee.db.DartsMatchEntity import dartzee.db.EntityName import dartzee.db.PlayerEntity +import dartzee.game.FinishType import dartzee.game.GameLaunchParams import dartzee.game.GameLauncher import dartzee.game.GameType import dartzee.game.MatchMode +import dartzee.game.X01Config import dartzee.helper.AbstractTest +import dartzee.helper.DEFAULT_X01_CONFIG import dartzee.helper.insertDartzeeTemplate import dartzee.helper.insertPlayer import dartzee.helper.makeDartzeeRuleDto @@ -88,12 +93,18 @@ class TestGameSetupScreen : AbstractTest() { screen.playerSelector.init(listOf(alice, clive)) val gameParamsPanel = screen.gameParamFilterPanel as GameParamFilterPanelX01 - gameParamsPanel.spinner.value = 701 + gameParamsPanel.getChild().value = 701 screen.btnLaunch.doClick() val expectedParams = - GameLaunchParams(listOf(alice, clive), GameType.X01, "701", false, null) + GameLaunchParams( + listOf(alice, clive), + GameType.X01, + X01Config(701, FinishType.Doubles).toJson(), + false, + null + ) verify { gameLauncher.launchNewGame(expectedParams) } } @@ -191,7 +202,8 @@ class TestGameSetupScreen : AbstractTest() { scrn.btnLaunch.doClick() - val launchParams = GameLaunchParams(players, GameType.X01, "501", false) + val launchParams = + GameLaunchParams(players, GameType.X01, DEFAULT_X01_CONFIG.toJson(), false) verify { gameLauncher.launchNewMatch(any(), launchParams) } val match = slot.captured diff --git a/src/test/kotlin/dartzee/screen/ai/TestNewSetupRuleDialog.kt b/src/test/kotlin/dartzee/screen/ai/TestNewSetupRuleDialog.kt index a858d07d..d1b54d9e 100644 --- a/src/test/kotlin/dartzee/screen/ai/TestNewSetupRuleDialog.kt +++ b/src/test/kotlin/dartzee/screen/ai/TestNewSetupRuleDialog.kt @@ -2,10 +2,13 @@ package dartzee.screen.ai import com.github.alyssaburlton.swingtest.clickCancel import com.github.alyssaburlton.swingtest.clickOk +import com.github.alyssaburlton.swingtest.shouldBeVisible +import com.github.alyssaburlton.swingtest.shouldNotBeVisible import dartzee.ai.AimDart +import dartzee.getDialogMessage +import dartzee.getErrorDialog import dartzee.helper.AbstractTest import io.kotest.matchers.collections.shouldBeEmpty -import io.kotest.matchers.collections.shouldContainExactly import io.kotest.matchers.maps.shouldContain import io.kotest.matchers.shouldBe import net.miginfocom.swing.MigLayout @@ -31,11 +34,14 @@ class TestNewSetupRuleDialog : AbstractTest() { @Test fun `Should not allow the score field to be left blank`() { val dlg = NewSetupRuleDialog(mutableMapOf()) + dlg.isModal = false + dlg.isVisible = true + dlg.clickOk(async = true) - dlg.valid() shouldBe false - dialogFactory.errorsShown.shouldContainExactly( + getErrorDialog().getDialogMessage() shouldBe "You must enter a score for this rule to apply to." - ) + + dlg.shouldBeVisible() } @Test @@ -46,8 +52,8 @@ class TestNewSetupRuleDialog : AbstractTest() { dlg.spinner.value = 25 dlg.rdbtnTreble.doClick() - dlg.valid() shouldBe false - dialogFactory.errorsShown.shouldContainExactly("Treble 25 is not a valid dart!") + dlg.clickOk(async = true) + getErrorDialog().getDialogMessage() shouldBe "Treble 25 is not a valid dart!" } @Test @@ -59,8 +65,8 @@ class TestNewSetupRuleDialog : AbstractTest() { dlg.spinner.value = 20 dlg.rdbtnTreble.doClick() - dlg.valid() shouldBe false - dialogFactory.errorsShown.shouldContainExactly("This target would bust the player") + dlg.clickOk(async = true) + getErrorDialog().getDialogMessage() shouldBe "This target would bust the player" } @Test @@ -71,10 +77,9 @@ class TestNewSetupRuleDialog : AbstractTest() { dlg.spinner.value = 20 dlg.rdbtnSingle.doClick() - dlg.valid() shouldBe false - dialogFactory.errorsShown.shouldContainExactly( + dlg.clickOk(async = true) + getErrorDialog().getDialogMessage() shouldBe "The selected dart is already the default for this starting score." - ) } @Test @@ -87,7 +92,7 @@ class TestNewSetupRuleDialog : AbstractTest() { dlg.rdbtnDouble.doClick() dlg.clickOk() - dialogFactory.errorsShown.shouldBeEmpty() + dlg.shouldNotBeVisible() hm.shouldContain(50, AimDart(25, 2)) hm.size shouldBe 1 } @@ -102,7 +107,6 @@ class TestNewSetupRuleDialog : AbstractTest() { dlg.rdbtnDouble.doClick() dlg.clickCancel() - dialogFactory.errorsShown.shouldBeEmpty() hm.size shouldBe 0 } diff --git a/src/test/kotlin/dartzee/screen/game/GameTestFactory.kt b/src/test/kotlin/dartzee/screen/game/GameTestFactory.kt index 1581113c..81f441d2 100644 --- a/src/test/kotlin/dartzee/screen/game/GameTestFactory.kt +++ b/src/test/kotlin/dartzee/screen/game/GameTestFactory.kt @@ -9,10 +9,12 @@ import dartzee.db.PlayerEntity import dartzee.game.ClockType import dartzee.game.GameType import dartzee.game.RoundTheClockConfig +import dartzee.game.X01Config import dartzee.game.state.AbstractPlayerState import dartzee.game.state.IWrappedParticipant import dartzee.game.state.SingleParticipant import dartzee.game.state.TeamParticipant +import dartzee.helper.DEFAULT_X01_CONFIG import dartzee.helper.insertDartsMatch import dartzee.helper.insertGame import dartzee.helper.insertParticipant @@ -50,12 +52,23 @@ fun makeGolfGamePanel(pt: IWrappedParticipant) = GamePanelGolf(FakeDartsScreen(), insertGame(gameType = GameType.GOLF, gameParams = "18"), 1) .apply { testInit(pt) } -fun makeX01GamePanel(currentPlayerId: String = randomGuid(), gameParams: String = "501") = - GamePanelX01(FakeDartsScreen(), insertGame(gameType = GameType.X01, gameParams = gameParams), 1) +fun makeX01GamePanel( + currentPlayerId: String = randomGuid(), + gameParams: X01Config = DEFAULT_X01_CONFIG +) = + GamePanelX01( + FakeDartsScreen(), + insertGame(gameType = GameType.X01, gameParams = gameParams.toJson()), + 1 + ) .apply { testInit(currentPlayerId) } -fun makeX01GamePanel(pt: IWrappedParticipant, gameParams: String = "501") = - GamePanelX01(FakeDartsScreen(), insertGame(gameType = GameType.X01, gameParams = gameParams), 1) +fun makeX01GamePanel(pt: IWrappedParticipant, gameParams: X01Config = DEFAULT_X01_CONFIG) = + GamePanelX01( + FakeDartsScreen(), + insertGame(gameType = GameType.X01, gameParams = gameParams.toJson()), + 1 + ) .apply { testInit(pt) } fun makeRoundTheClockGamePanel(playerId: String = randomGuid()) = @@ -116,7 +129,7 @@ fun DartsGamePanel<*, *>.doAiTurn(model: DartsAiModel) { fun makeMatchSummaryPanel( match: DartsMatchEntity = insertDartsMatch(), - statsPanel: GameStatisticsPanelX01 = GameStatisticsPanelX01("501") + statsPanel: GameStatisticsPanelX01 = GameStatisticsPanelX01(DEFAULT_X01_CONFIG.toJson()) ) = MatchSummaryPanel(match, statsPanel) class FakeDartsScreen : AbstractDartsGameScreen() { diff --git a/src/test/kotlin/dartzee/screen/game/TestDartsGamePanel.kt b/src/test/kotlin/dartzee/screen/game/TestDartsGamePanel.kt index fe6eea4d..be6716fe 100644 --- a/src/test/kotlin/dartzee/screen/game/TestDartsGamePanel.kt +++ b/src/test/kotlin/dartzee/screen/game/TestDartsGamePanel.kt @@ -3,7 +3,9 @@ package dartzee.screen.game import dartzee.achievements.AchievementType import dartzee.ai.DartsAiModel import dartzee.db.EntityName +import dartzee.game.FinishType import dartzee.game.GameType +import dartzee.game.X01Config import dartzee.game.state.IWrappedParticipant import dartzee.game.state.X01PlayerState import dartzee.helper.AbstractTest @@ -93,17 +95,17 @@ class TestDartsGamePanel : AbstractTest() { ) } - class TestGamePanel(gameParams: String = "501") : + class TestGamePanel(private val config: X01Config = X01Config(501, FinishType.Doubles)) : GamePanelPausable( FakeDartsScreen(), - insertGame(gameType = GameType.X01, gameParams = gameParams), + insertGame(gameType = GameType.X01, gameParams = config.toJson()), 1 ) { - override fun factoryState(pt: IWrappedParticipant) = X01PlayerState(501, pt) + override fun factoryState(pt: IWrappedParticipant) = X01PlayerState(config, pt) - override fun computeAiDart(model: DartsAiModel): ComputedPoint? { + override fun computeAiDart(model: DartsAiModel): ComputedPoint { val currentScore = getCurrentPlayerState().getRemainingScore() - return model.throwX01Dart(currentScore) + return model.throwX01Dart(currentScore, config.finishType) } override fun shouldStopAfterDartThrown() = getCurrentPlayerState().isCurrentRoundComplete() @@ -113,6 +115,6 @@ class TestDartsGamePanel : AbstractTest() { override fun factoryStatsPanel(gameParams: String) = GameStatisticsPanelX01(gameParams) override fun factoryScorer(participant: IWrappedParticipant) = - DartsScorerX01(this, gameEntity.gameParams, participant) + DartsScorerX01(this, config.target, participant) } } diff --git a/src/test/kotlin/dartzee/screen/game/TestDartsMatchScreen.kt b/src/test/kotlin/dartzee/screen/game/TestDartsMatchScreen.kt index a3029afe..01e6e9ca 100644 --- a/src/test/kotlin/dartzee/screen/game/TestDartsMatchScreen.kt +++ b/src/test/kotlin/dartzee/screen/game/TestDartsMatchScreen.kt @@ -10,6 +10,7 @@ import dartzee.db.PlayerImageEntity import dartzee.game.loadParticipants import dartzee.game.state.X01PlayerState import dartzee.helper.AbstractTest +import dartzee.helper.DEFAULT_X01_CONFIG import dartzee.helper.insertDartsMatch import dartzee.helper.insertGame import dartzee.helper.insertParticipant @@ -60,7 +61,7 @@ class TestDartsMatchScreen : AbstractTest() { @Test fun `Should update title based on selected tab`() { - val match = insertDartsMatch(gameParams = "501") + val match = insertDartsMatch(gameParams = DEFAULT_X01_CONFIG.toJson()) val scrn = setUpMatchScreen(match) val g1 = insertGame() @@ -123,7 +124,7 @@ class TestDartsMatchScreen : AbstractTest() { @Test fun `Should mark the match as complete if no more games need to be played`() { - val match = insertDartsMatch(games = 1, gameParams = "501") + val match = insertDartsMatch(games = 1, gameParams = DEFAULT_X01_CONFIG.toJson()) val scrn = setUpMatchScreen(match = match) val firstGame = insertGame() @@ -144,7 +145,7 @@ class TestDartsMatchScreen : AbstractTest() { val p2 = insertPlayer(name = "Billie") val gameOneStates = listOf(p1, p2).map { makeX01PlayerState(player = it) } - val match = insertDartsMatch(gameParams = "501") + val match = insertDartsMatch(gameParams = DEFAULT_X01_CONFIG.toJson()) val scrn = setUpMatchScreen(match = match) val firstGame = insertGame(dartsMatchId = match.rowId, matchOrdinal = 1) @@ -173,7 +174,7 @@ class TestDartsMatchScreen : AbstractTest() { val p2 = insertPlayer(name = "Billie") val gameOneStates = listOf(p1, p2).map { makeX01PlayerState(player = it) } - val match = insertDartsMatch(gameParams = "501") + val match = insertDartsMatch(gameParams = DEFAULT_X01_CONFIG.toJson()) val scrn = setUpMatchScreen(match = match) val firstGame = insertGame(dartsMatchId = match.rowId, matchOrdinal = 1) @@ -187,7 +188,7 @@ class TestDartsMatchScreen : AbstractTest() { } private fun setUpMatchScreen( - match: DartsMatchEntity = insertDartsMatch(gameParams = "501"), + match: DartsMatchEntity = insertDartsMatch(gameParams = DEFAULT_X01_CONFIG.toJson()), matchSummaryPanel: MatchSummaryPanel = MatchSummaryPanel(match, MatchStatisticsPanelX01(match.gameParams)) ): FakeMatchScreen { diff --git a/src/test/kotlin/dartzee/screen/game/TestGamePanelX01.kt b/src/test/kotlin/dartzee/screen/game/TestGamePanelX01.kt index 211055fb..22124990 100644 --- a/src/test/kotlin/dartzee/screen/game/TestGamePanelX01.kt +++ b/src/test/kotlin/dartzee/screen/game/TestGamePanelX01.kt @@ -4,8 +4,11 @@ import dartzee.achievements.AchievementType import dartzee.db.AchievementEntity import dartzee.db.EntityName import dartzee.db.X01FinishEntity +import dartzee.game.FinishType +import dartzee.game.X01Config import dartzee.helper.AbstractTest import dartzee.helper.AchievementSummary +import dartzee.helper.getCountFromTable import dartzee.helper.preparePlayers import dartzee.helper.randomGuid import dartzee.helper.retrieveAchievementsForPlayer @@ -76,6 +79,23 @@ class TestGamePanelX01 : AbstractTest() { entity.finish shouldBe 100 } + @Test + fun `Should not update finish things if finish was not on a double`() { + val playerId = randomGuid() + val panel = makeX01GamePanel(playerId, gameParams = X01Config(501, FinishType.Any)) + + val darts = listOf(Dart(20, 3), Dart(20, 30), Dart(20, 1)) + panel.addCompletedRound(darts) + panel.updateAchievementsForFinish(2, 30) + + getCountFromTable(EntityName.X01Finish) shouldBe 0 + + AchievementEntity.retrieveAchievement(AchievementType.X01_BEST_FINISH, playerId) shouldBe + null + AchievementEntity.retrieveAchievement(AchievementType.X01_STYLISH_FINISH, playerId) shouldBe + null + } + @Test fun `Should update No Mercy achievement if the game was finished on from 3, 5, 7 or 9`() { val playerId = randomGuid() @@ -94,6 +114,18 @@ class TestGamePanelX01 : AbstractTest() { } } + @Test + fun `Should not update No Mercy achievement if the game did not require finishing on a double`() { + val playerId = randomGuid() + val panel = makeX01GamePanel(playerId, X01Config(501, FinishType.Any)) + + val darts = listOf(Dart(1, 1), Dart(2, 2)) + panel.addCompletedRound(darts) + panel.updateAchievementsForFinish(1, 30) + + AchievementEntity.retrieveAchievement(AchievementType.X01_NO_MERCY, playerId) shouldBe null + } + @Test fun `Should not update No Mercy achievement if the game was finished from a higher finish`() { val playerId = randomGuid() @@ -161,7 +193,7 @@ class TestGamePanelX01 : AbstractTest() { fun `Should correctly update such bad luck achievement for a team`() { val (p1, p2) = preparePlayers(2) val team = makeTeam(p1, p2) - val panel = makeX01GamePanel(team, gameParams = "101") + val panel = makeX01GamePanel(team, gameParams = X01Config(101, FinishType.Doubles)) val gameId = panel.gameEntity.rowId panel.addCompletedRound( @@ -203,7 +235,7 @@ class TestGamePanelX01 : AbstractTest() { @Test fun `Should not update hotel inspector achievement if board is missed, or player is bust`() { val playerId = randomGuid() - val panel = makeX01GamePanel(playerId, gameParams = "101") + val panel = makeX01GamePanel(playerId, gameParams = X01Config(101, FinishType.Doubles)) panel.addCompletedRound(listOf(Dart(20, 1), Dart(3, 2), Dart(19, 0))) panel.addCompletedRound(listOf(Dart(20, 1), Dart(20, 1), Dart(20, 1))) @@ -240,7 +272,7 @@ class TestGamePanelX01 : AbstractTest() { @Test fun `Should not update chucklevision achievement if board is missed, or player is bust`() { val playerId = randomGuid() - val panel = makeX01GamePanel(playerId, gameParams = "101") + val panel = makeX01GamePanel(playerId, gameParams = X01Config(101, FinishType.Doubles)) panel.addCompletedRound(listOf(Dart(20, 3), Dart(3, 3), Dart(19, 0))) panel.addCompletedRound(listOf(Dart(5, 1), Dart(4, 1), Dart(20, 3))) @@ -262,7 +294,7 @@ class TestGamePanelX01 : AbstractTest() { private fun verifyStylishFinish(finalRound: List) { val playerId = randomGuid() - val panel = makeX01GamePanel(playerId, gameParams = "101") + val panel = makeX01GamePanel(playerId, gameParams = X01Config(101, FinishType.Doubles)) panel.addCompletedRound(listOf(Dart(20, 3), Dart(1, 1), Dart(20, 1))) panel.addCompletedRound(finalRound) @@ -290,7 +322,7 @@ class TestGamePanelX01 : AbstractTest() { private fun verifyNotStylishFinish(finalRound: List) { val playerId = randomGuid() - val panel = makeX01GamePanel(playerId, gameParams = "101") + val panel = makeX01GamePanel(playerId, gameParams = X01Config(101, FinishType.Doubles)) panel.addCompletedRound(listOf(Dart(20, 3), Dart(1, 1), Dart(20, 1))) panel.addCompletedRound(finalRound) diff --git a/src/test/kotlin/dartzee/screen/game/TestMatchSummaryPanel.kt b/src/test/kotlin/dartzee/screen/game/TestMatchSummaryPanel.kt index 96668927..d43843ee 100644 --- a/src/test/kotlin/dartzee/screen/game/TestMatchSummaryPanel.kt +++ b/src/test/kotlin/dartzee/screen/game/TestMatchSummaryPanel.kt @@ -4,6 +4,7 @@ import dartzee.game.state.IWrappedParticipant import dartzee.game.state.X01PlayerState import dartzee.getRows import dartzee.helper.AbstractTest +import dartzee.helper.DEFAULT_X01_CONFIG import dartzee.helper.insertPlayer import dartzee.`object`.Dart import dartzee.screen.game.x01.GameStatisticsPanelX01 @@ -51,7 +52,7 @@ class TestMatchSummaryPanel : AbstractTest() { localId: Long, participant: IWrappedParticipant ) { - addParticipant(localId, X01PlayerState(501, participant)) + addParticipant(localId, X01PlayerState(DEFAULT_X01_CONFIG, participant)) } @Test diff --git a/src/test/kotlin/dartzee/screen/game/scorer/TestDartsScorerX01.kt b/src/test/kotlin/dartzee/screen/game/scorer/TestDartsScorerX01.kt index 2d30fe16..265ea564 100644 --- a/src/test/kotlin/dartzee/screen/game/scorer/TestDartsScorerX01.kt +++ b/src/test/kotlin/dartzee/screen/game/scorer/TestDartsScorerX01.kt @@ -134,7 +134,7 @@ class TestDartsScorerX01 : AbstractTest() { private fun factoryScorer( participant: ParticipantEntity = insertParticipant() ): DartsScorerX01 { - val scorer = DartsScorerX01(mockk(relaxed = true), "501", SingleParticipant(participant)) + val scorer = DartsScorerX01(mockk(relaxed = true), 501, SingleParticipant(participant)) scorer.init() return scorer } diff --git a/src/test/kotlin/dartzee/screen/game/x01/TestGameStatisticsPanelX01.kt b/src/test/kotlin/dartzee/screen/game/x01/TestGameStatisticsPanelX01.kt index 7b8ac528..a39f10dc 100644 --- a/src/test/kotlin/dartzee/screen/game/x01/TestGameStatisticsPanelX01.kt +++ b/src/test/kotlin/dartzee/screen/game/x01/TestGameStatisticsPanelX01.kt @@ -1,5 +1,7 @@ package dartzee.screen.game.x01 +import dartzee.game.FinishType +import dartzee.game.X01Config import dartzee.game.state.X01PlayerState import dartzee.helper.insertPlayer import dartzee.helper.makeX01PlayerState @@ -14,17 +16,20 @@ import org.junit.jupiter.api.Test class TestGameStatisticsPanelX01 : AbstractGameStatisticsPanelTest() { - override fun factoryStatsPanel() = GameStatisticsPanelX01("501") + override fun factoryStatsPanel() = factoryStatsPanel(501) + + private fun factoryStatsPanel(startingScore: Int) = + GameStatisticsPanelX01(X01Config(startingScore, FinishType.Doubles).toJson()) override fun makePlayerState() = makeX01PlayerState(completedRound = listOf(Dart(20, 1), Dart(5, 1), Dart(1, 1))) @Test fun `Should set the maximum setupThreshold to be 1 less than the starting score`() { - val panel = GameStatisticsPanelX01("501") + val panel = factoryStatsPanel(501) panel.nfSetupThreshold.getMaximum() shouldBe 500 - val panelTwo = GameStatisticsPanelX01("301") + val panelTwo = factoryStatsPanel(301) panelTwo.nfSetupThreshold.getMaximum() shouldBe 300 } @@ -128,7 +133,7 @@ class TestGameStatisticsPanelX01 : val state = makeX01PlayerState(player = insertPlayer(name = "Alice"), completedRound = roundOne) - val statsPanel = GameStatisticsPanelX01("501") + val statsPanel = factoryStatsPanel(501) statsPanel.showStats(listOf(state)) statsPanel.shouldHaveBreakdownState(hashMapOf("20 - 39" to 1)) @@ -183,7 +188,7 @@ class TestGameStatisticsPanelX01 : val state = makeX01PlayerState(player = insertPlayer(name = "Alice"), completedRound = roundOne) - val statsPanel = GameStatisticsPanelX01("701") + val statsPanel = factoryStatsPanel(701) statsPanel.showStats(listOf(state)) statsPanel.shouldHaveBreakdownState(hashMapOf("180" to 1)) @@ -213,7 +218,7 @@ class TestGameStatisticsPanelX01 : val state = makeX01PlayerState(player = insertPlayer(name = "Alice"), completedRound = roundOne) - val statsPanel = GameStatisticsPanelX01("501") + val statsPanel = factoryStatsPanel(501) statsPanel.showStats(listOf(state)) // [20, 20, 5] diff --git a/src/test/kotlin/dartzee/screen/game/x01/TestMatchStatisticsPanelX01.kt b/src/test/kotlin/dartzee/screen/game/x01/TestMatchStatisticsPanelX01.kt index 7b37d88c..a41c7ace 100644 --- a/src/test/kotlin/dartzee/screen/game/x01/TestMatchStatisticsPanelX01.kt +++ b/src/test/kotlin/dartzee/screen/game/x01/TestMatchStatisticsPanelX01.kt @@ -1,6 +1,7 @@ package dartzee.screen.game.x01 import dartzee.game.state.X01PlayerState +import dartzee.helper.DEFAULT_X01_CONFIG import dartzee.helper.makeDart import dartzee.helper.makeX01PlayerState import dartzee.helper.makeX01PlayerStateWithRounds @@ -13,7 +14,7 @@ import org.junit.jupiter.api.Test class TestMatchStatisticsPanelX01 : AbstractGameStatisticsPanelTest() { - override fun factoryStatsPanel() = MatchStatisticsPanelX01("501") + override fun factoryStatsPanel() = MatchStatisticsPanelX01(DEFAULT_X01_CONFIG.toJson()) override fun makePlayerState() = makeX01PlayerState(completedRound = listOf(Dart(20, 1), Dart(5, 1), Dart(1, 1))) diff --git a/src/test/kotlin/dartzee/screen/reporting/TestReportingGameTab.kt b/src/test/kotlin/dartzee/screen/reporting/TestReportingGameTab.kt index 9b49ff94..5476b0ec 100644 --- a/src/test/kotlin/dartzee/screen/reporting/TestReportingGameTab.kt +++ b/src/test/kotlin/dartzee/screen/reporting/TestReportingGameTab.kt @@ -12,7 +12,9 @@ import dartzee.bean.GameParamFilterPanelX01 import dartzee.bean.SpinnerX01 import dartzee.core.bean.DateFilterPanel import dartzee.core.util.getAllChildComponentsForType +import dartzee.game.FinishType import dartzee.game.GameType +import dartzee.game.X01Config import dartzee.helper.AbstractTest import dartzee.makeInvalid import dartzee.reporting.MatchFilter @@ -32,7 +34,10 @@ class TestReportingGameTab : AbstractTest() { @Test fun `Should have the correct initial state`() { val scrn = ReportingGameTab() - val checkBoxes = scrn.getAllChildComponentsForType() + val checkBoxes = + scrn.getAllChildComponentsForType().filter { + it.name?.startsWith("filter") ?: false + } checkBoxes.forEach { it.isSelected shouldBe false } scrn.getAllChildComponentsForType().forEach { it.shouldBeDisabled() } @@ -178,10 +183,12 @@ class TestReportingGameTab : AbstractTest() { tab.generateReportParameters().gameParams shouldBe "" tab.clickChild(text = "Type") - tab.generateReportParameters().gameParams shouldBe "501" + tab.generateReportParameters().gameParams shouldBe + X01Config(501, FinishType.Doubles).toJson() tab.getChild().value = 701 - tab.generateReportParameters().gameParams shouldBe "701" + tab.clickChild(text = "Finish on double") + tab.generateReportParameters().gameParams shouldBe X01Config(701, FinishType.Any).toJson() } @Test diff --git a/src/test/kotlin/dartzee/screen/reporting/TestReportingResultsScreen.kt b/src/test/kotlin/dartzee/screen/reporting/TestReportingResultsScreen.kt index 79479675..f2d7f03a 100644 --- a/src/test/kotlin/dartzee/screen/reporting/TestReportingResultsScreen.kt +++ b/src/test/kotlin/dartzee/screen/reporting/TestReportingResultsScreen.kt @@ -3,7 +3,9 @@ package dartzee.screen.reporting import com.github.alyssaburlton.swingtest.clickChild import com.github.alyssaburlton.swingtest.getChild import dartzee.core.bean.ScrollTable +import dartzee.game.FinishType import dartzee.game.GameType +import dartzee.game.X01Config import dartzee.getColumnNames import dartzee.getDisplayValueAt import dartzee.helper.AbstractTest @@ -26,7 +28,12 @@ class TestReportingResultsScreen : AbstractTest() { fun `Should initialise with results based on the report parameters`() { val rp = makeReportParameters(game = makeReportParametersGame(gameType = GameType.X01)) - val gX01 = insertGame(localId = 1, gameType = GameType.X01, gameParams = "501") + val gX01 = + insertGame( + localId = 1, + gameType = GameType.X01, + gameParams = X01Config(501, FinishType.Doubles).toJson() + ) insertPlayerForGame("Bob", gX01.rowId) val gDartzee = insertGame(localId = 2, gameType = GameType.DARTZEE, gameParams = "") @@ -43,7 +50,12 @@ class TestReportingResultsScreen : AbstractTest() { @Test fun `Should adjust columns based on the configure dialog, without rerunning SQL`() { - val gX01 = insertGame(localId = 1, gameType = GameType.X01, gameParams = "501") + val gX01 = + insertGame( + localId = 1, + gameType = GameType.X01, + gameParams = X01Config(501, FinishType.Doubles).toJson() + ) insertPlayerForGame("Bob", gX01.rowId) val dlg = mockk(relaxed = true) diff --git a/src/test/kotlin/dartzee/screen/stats/player/x01/TestStatisticsTabX01ThreeDartAverage.kt b/src/test/kotlin/dartzee/screen/stats/player/x01/TestStatisticsTabX01ThreeDartAverage.kt index 7f2e0a31..aee8a4d5 100644 --- a/src/test/kotlin/dartzee/screen/stats/player/x01/TestStatisticsTabX01ThreeDartAverage.kt +++ b/src/test/kotlin/dartzee/screen/stats/player/x01/TestStatisticsTabX01ThreeDartAverage.kt @@ -25,6 +25,8 @@ import dartzee.drtOuterTwenty import dartzee.drtTrebleFourteen import dartzee.drtTrebleOne import dartzee.drtTrebleTwenty +import dartzee.game.FinishType +import dartzee.game.X01Config import dartzee.getRows import dartzee.helper.AbstractTest import dartzee.helper.makeGameWrapper @@ -144,7 +146,11 @@ class TestStatisticsTabX01ThreeDartAverage : AbstractTest() { listOf(drtDoubleSixteen()) // Fin. ) - val g = makeGameWrapper(gameParams = "301", dartRounds = rounds) + val g = + makeGameWrapper( + gameParams = X01Config(301, FinishType.Doubles).toJson(), + dartRounds = rounds + ) val tab = StatisticsTabX01ThreeDartAverage() tab.setFilteredGames(listOf(g), emptyList()) tab.populateStats() diff --git a/src/test/kotlin/dartzee/utils/TestX01Util.kt b/src/test/kotlin/dartzee/utils/TestX01Util.kt index 83930f36..28c482ab 100644 --- a/src/test/kotlin/dartzee/utils/TestX01Util.kt +++ b/src/test/kotlin/dartzee/utils/TestX01Util.kt @@ -1,5 +1,6 @@ package dartzee.utils +import dartzee.game.FinishType import dartzee.helper.AbstractTest import dartzee.helper.makeDart import dartzee.helper.makeDartsModel @@ -15,50 +16,54 @@ import org.junit.jupiter.api.Test class TestX01Util : AbstractTest() { @Test - fun `isBust should return the right values when just passed a dart`() { - isBust(makeDart(3, 1, startingScore = 5)) shouldBe false - isBust(makeDart(3, 1, startingScore = 4)) shouldBe true - isBust(makeDart(3, 1, startingScore = 3)) shouldBe true - - isBust(makeDart(2, 2, startingScore = 5)) shouldBe true - isBust(makeDart(2, 2, startingScore = 4)) shouldBe false - isBust(makeDart(2, 2, startingScore = 3)) shouldBe true + fun `isBust should return the right values for finishType Doubles`() { + isBust(makeDart(3, 1, startingScore = 4), FinishType.Doubles) shouldBe true + isBust(makeDart(3, 1, startingScore = 3), FinishType.Doubles) shouldBe true + isBust(makeDart(20, 3, startingScore = 60), FinishType.Doubles) shouldBe true + + isBust(makeDart(2, 2, startingScore = 5), FinishType.Doubles) shouldBe true + isBust(makeDart(2, 2, startingScore = 4), FinishType.Doubles) shouldBe false + isBust(makeDart(2, 2, startingScore = 3), FinishType.Doubles) shouldBe true + + isBust(makeDart(25, 2, startingScore = 50), FinishType.Doubles) shouldBe false + isBust(makeDart(3, 1, startingScore = 5), FinishType.Doubles) shouldBe false } @Test - fun testIsBust() { - isBust(5, Dart(3, 2)).shouldBeTrue() - isBust(10, Dart(10, 1)).shouldBeTrue() - isBust(60, Dart(20, 3)).shouldBeTrue() + fun `isBust should return correct values for finishType Any`() { + isBust(makeDart(3, 1, startingScore = 4), FinishType.Any) shouldBe false + isBust(makeDart(3, 1, startingScore = 3), FinishType.Any) shouldBe false + isBust(makeDart(20, 3, startingScore = 60), FinishType.Any) shouldBe false - isBust(41, Dart(20, 2)).shouldBeTrue() + isBust(makeDart(2, 2, startingScore = 5), FinishType.Any) shouldBe false + isBust(makeDart(2, 2, startingScore = 4), FinishType.Any) shouldBe false + isBust(makeDart(2, 2, startingScore = 3), FinishType.Any) shouldBe true - isBust(40, Dart(20, 2)).shouldBeFalse() - isBust(50, Dart(25, 2)).shouldBeFalse() - - isBust(60, Dart(20, 2)).shouldBeFalse() - isBust(40, Dart(20, 1)).shouldBeFalse() + isBust(makeDart(25, 2, startingScore = 50), FinishType.Any) shouldBe false + isBust(makeDart(3, 1, startingScore = 5), FinishType.Any) shouldBe false } @Test - fun testShouldStopForMercyRule() { + fun `mercy rule`() { var model = makeDartsModel(mercyThreshold = 19) - shouldStopForMercyRule(model, 19, 16).shouldBeFalse() - shouldStopForMercyRule(model, 17, 16).shouldBeTrue() - shouldStopForMercyRule(model, 15, 8).shouldBeTrue() - shouldStopForMercyRule(model, 16, 8).shouldBeFalse() - shouldStopForMercyRule(model, 17, 13).shouldBeFalse() - shouldStopForMercyRule(model, 17, 17).shouldBeFalse() + shouldStopForMercyRule(model, 19, 16, FinishType.Doubles).shouldBeFalse() + shouldStopForMercyRule(model, 17, 16, FinishType.Doubles).shouldBeTrue() + shouldStopForMercyRule(model, 15, 8, FinishType.Doubles).shouldBeTrue() + shouldStopForMercyRule(model, 16, 8, FinishType.Doubles).shouldBeFalse() + shouldStopForMercyRule(model, 17, 13, FinishType.Doubles).shouldBeFalse() + shouldStopForMercyRule(model, 17, 17, FinishType.Doubles).shouldBeFalse() + + shouldStopForMercyRule(model, 15, 8, FinishType.Any).shouldBeFalse() model = makeDartsModel(mercyThreshold = null) - shouldStopForMercyRule(model, 19, 16).shouldBeFalse() - shouldStopForMercyRule(model, 17, 16).shouldBeFalse() - shouldStopForMercyRule(model, 15, 8).shouldBeFalse() - shouldStopForMercyRule(model, 16, 8).shouldBeFalse() - shouldStopForMercyRule(model, 17, 13).shouldBeFalse() - shouldStopForMercyRule(model, 17, 17).shouldBeFalse() + shouldStopForMercyRule(model, 19, 16, FinishType.Doubles).shouldBeFalse() + shouldStopForMercyRule(model, 17, 16, FinishType.Doubles).shouldBeFalse() + shouldStopForMercyRule(model, 15, 8, FinishType.Doubles).shouldBeFalse() + shouldStopForMercyRule(model, 16, 8, FinishType.Doubles).shouldBeFalse() + shouldStopForMercyRule(model, 17, 13, FinishType.Doubles).shouldBeFalse() + shouldStopForMercyRule(model, 17, 17, FinishType.Doubles).shouldBeFalse() } @Test