Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix team win achievements for Golf & Dartzee #317

Merged
merged 5 commits into from
Mar 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/main/kotlin/dartzee/core/util/ExtensionFunctions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ fun <E> MutableList<E>.addUnique(element: E) {
}
}

fun <K : Comparable<K>, V> Map<K, V>.getSortedValues(): List<V> =
entries.sortedBy { it.key }.map { it.value }
fun <K : Comparable<K>, V> Map<K, V>.getSortedValues(descending: Boolean = false): List<V> =
entries.sortedBy(descending) { it.key }.map { it.value }

fun List<Int>.minOrZero() = minOrNull() ?: 0

Expand Down
5 changes: 0 additions & 5 deletions src/main/kotlin/dartzee/db/IParticipant.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,4 @@ interface IParticipant {
fun isActive() = isEndOfTime(dtFinished)

fun getFinishingPositionDesc(): String = StringUtil.convertOrdinalToText(finishingPosition)

fun saveFinishingPosition(game: GameEntity, position: Int) {
this.finishingPosition = position
this.saveToDatabase()
}
}
10 changes: 0 additions & 10 deletions src/main/kotlin/dartzee/db/ParticipantEntity.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package dartzee.db

import dartzee.achievements.getWinAchievementType
import dartzee.core.util.DateStatics
import dartzee.core.util.getSqlDateNow
import dartzee.utils.Database
Expand Down Expand Up @@ -46,15 +45,6 @@ class ParticipantEntity(database: Database = mainDatabase) :

override fun saveToDatabase() = saveToDatabase(getSqlDateNow())

override fun saveFinishingPosition(game: GameEntity, position: Int) {
super.saveFinishingPosition(game, position)

if (position == 1) {
val type = getWinAchievementType(game.gameType)
AchievementEntity.insertAchievement(type, playerId, game.rowId, "$finalScore")
}
}

/** Helpers */
fun isAi() = getPlayer().isAi()

Expand Down
2 changes: 2 additions & 0 deletions src/main/kotlin/dartzee/game/state/IWrappedParticipant.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ sealed interface IWrappedParticipant {

fun ordinal() = participant.ordinal

fun getPlayerIds() = individuals.map { it.playerId }

fun getIndividual(roundNumber: Int): ParticipantEntity

fun getUniqueParticipantName() =
Expand Down
60 changes: 31 additions & 29 deletions src/main/kotlin/dartzee/screen/game/DartsGamePanel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -408,41 +408,43 @@ abstract class DartsGamePanel<
val numberOfDarts = state.getScoreSoFar()
state.participantFinished(finishingPosition, numberOfDarts)

updateAchievementsForFinish(getCurrentPlayerState(), finishingPosition, numberOfDarts)
updateAchievementsForFinish(getCurrentPlayerState(), numberOfDarts)

return finishingPosition
}

open fun updateAchievementsForFinish(
playerState: PlayerState,
finishingPosition: Int,
score: Int
) {
if (playerState.hasMultiplePlayers()) {
if (finishingPosition == 1) {
val type = getTeamWinAchievementType(gameEntity.gameType)
playerState.getPlayerIds().forEach { playerId ->
AchievementEntity.insertAchievement(type, playerId, gameEntity.rowId, "$score")
}
}
} else {
val playerId = playerState.lastIndividual().playerId
if (finishingPosition == 1) {
val type = getWinAchievementType(gameEntity.gameType)
AchievementEntity.insertAchievement(type, playerId, gameEntity.rowId, "$score")
}
open fun updateAchievementsForFinish(playerState: PlayerState, score: Int) {
updateWinAchievement(playerState.wrappedParticipant)

// Update the 'best game' achievement
val aa = getBestGameAchievement(gameEntity.gameType) ?: return
val gameParams = aa.gameParams
if (gameParams == gameEntity.gameParams) {
AchievementEntity.updateAchievement(
aa.achievementType,
playerId,
gameEntity.rowId,
score
)
// Update the 'best game' achievement
val playerId = playerState.lastIndividual().playerId
val aa = getBestGameAchievement(gameEntity.gameType) ?: return
val gameParams = aa.gameParams
if (gameParams == gameEntity.gameParams && !playerState.hasMultiplePlayers()) {
AchievementEntity.updateAchievement(
aa.achievementType,
playerId,
gameEntity.rowId,
score
)
}
}

protected fun updateWinAchievement(participant: IWrappedParticipant) {
if (participant.participant.finishingPosition != 1) {
return
}

val playerIds = participant.getPlayerIds()
val score = participant.participant.finalScore
if (playerIds.size > 1) {
val type = getTeamWinAchievementType(gameEntity.gameType)
playerIds.forEach { playerId ->
AchievementEntity.insertAchievement(type, playerId, gameEntity.rowId, "$score")
}
} else {
val type = getWinAchievementType(gameEntity.gameType)
AchievementEntity.insertAchievement(type, playerIds.first(), gameEntity.rowId, "$score")
}
}

Expand Down
2 changes: 2 additions & 0 deletions src/main/kotlin/dartzee/screen/game/GamePanelFixedLength.kt
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ abstract class GamePanelFixedLength<
// Get the participants sorted by score so we can assign finishing positions
setFinishingPositions(getParticipants().map { it.participant }, gameEntity)

getPlayerStates().forEach { updateWinAchievement(it.wrappedParticipant) }

allPlayersFinished()

parentWindow.startNextGameIfNecessary()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,12 +157,8 @@ class GamePanelDartzee(
updateCarousel()
}

override fun updateAchievementsForFinish(
playerState: DartzeePlayerState,
finishingPosition: Int,
score: Int
) {
super.updateAchievementsForFinish(playerState, finishingPosition, score)
override fun updateAchievementsForFinish(playerState: DartzeePlayerState, score: Int) {
super.updateAchievementsForFinish(playerState, score)
if (totalRounds < DARTZEE_ACHIEVEMENT_MIN_ROUNDS) {
return
}
Expand Down
8 changes: 2 additions & 6 deletions src/main/kotlin/dartzee/screen/game/golf/GamePanelGolf.kt
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,8 @@ class GamePanelGolf(parent: AbstractDartsGameScreen, game: GameEntity, totalPlay
finishRound()
}

override fun updateAchievementsForFinish(
playerState: GolfPlayerState,
finishingPosition: Int,
score: Int
) {
super.updateAchievementsForFinish(playerState, finishingPosition, score)
override fun updateAchievementsForFinish(playerState: GolfPlayerState, score: Int) {
super.updateAchievementsForFinish(playerState, score)

if (!playerState.hasMultiplePlayers()) {
val scores = playerState.completedRounds.map { it.last().getGolfScore() }
Expand Down
8 changes: 2 additions & 6 deletions src/main/kotlin/dartzee/screen/game/x01/GamePanelX01.kt
Original file line number Diff line number Diff line change
Expand Up @@ -112,12 +112,8 @@ class GamePanelX01(parent: AbstractDartsGameScreen, game: GameEntity, totalPlaye

override fun currentPlayerHasFinished() = getCurrentPlayerState().getRemainingScore() == 0

override fun updateAchievementsForFinish(
playerState: X01PlayerState,
finishingPosition: Int,
score: Int
) {
super.updateAchievementsForFinish(playerState, finishingPosition, score)
override fun updateAchievementsForFinish(playerState: X01PlayerState, score: Int) {
super.updateAchievementsForFinish(playerState, score)

val playerId = playerState.lastIndividual().playerId
val finalRound = getCurrentPlayerState().getLastRound()
Expand Down
18 changes: 10 additions & 8 deletions src/main/kotlin/dartzee/utils/GameUtil.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import dartzee.bean.GameParamFilterPanelDartzee
import dartzee.bean.GameParamFilterPanelGolf
import dartzee.bean.GameParamFilterPanelRoundTheClock
import dartzee.bean.GameParamFilterPanelX01
import dartzee.core.util.sortedBy
import dartzee.core.util.getSortedValues
import dartzee.db.GameEntity
import dartzee.db.IParticipant
import dartzee.game.GameType
Expand Down Expand Up @@ -32,16 +32,18 @@ fun setFinishingPositions(participants: List<IParticipant>, game: GameEntity) {
return
}

val entries =
val sortedParticipants =
participants
.filterNot { it.resigned }
.groupBy { it.finalScore }
.entries
.sortedBy(doesHighestWin(game.gameType)) { it.key }
.getSortedValues(doesHighestWin(game.gameType))

var finishPos = 1
entries.forEach { (_, participants) ->
participants.forEach { it.saveFinishingPosition(game, finishPos) }
finishPos += participants.size
sortedParticipants.fold(1) { finishPos, participantGroup ->
participantGroup.forEach { pt ->
pt.finishingPosition = finishPos
pt.saveToDatabase()
}

finishPos + participantGroup.size
}
}
3 changes: 2 additions & 1 deletion src/main/resources/ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@
+ Leaderboards for best/worst games now include teams
+ AI will now use checkout suggestions in X01 where they exist (so e.g. on 81 will aim for T19 not T20)
= Normalised audio assets so they all play at a similar volume
- Fix bug where "team win" achievements did not unlock properly in Golf and Dartzee modes
= Fixed game report to display teams properly, and to display players in throw order
= Dartzee "total divisible by" rule no longer treats 0 as a pass
- Manual setup configuration per AI (never used, and superseded by checkout suggestion improvement)
= 93.3% test coverage (14163 / 15173 lines covered by 2425 tests)
= 93.5% test coverage (14153 / 15139 lines covered by 2442 tests)

--------- v7.0.1 ---------

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ class TestExtensionFunctions : AbstractTest() {
map[4] = "Fourth"

map.getSortedValues().shouldContainExactly("First", "Second", "Third", "Fourth")
map.getSortedValues(true).shouldContainExactly("Fourth", "Third", "Second", "First")
}

@Test
Expand Down
20 changes: 16 additions & 4 deletions src/test/kotlin/dartzee/screen/game/GameTestFactory.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import dartzee.game.ClockType
import dartzee.game.GameType
import dartzee.game.RoundTheClockConfig
import dartzee.game.X01Config
import dartzee.game.prepareParticipants
import dartzee.game.state.AbstractPlayerState
import dartzee.game.state.IWrappedParticipant
import dartzee.game.state.SingleParticipant
Expand Down Expand Up @@ -48,9 +49,18 @@ fun makeGolfGamePanel(currentPlayerId: String = randomGuid(), gameParams: String
)
.apply { testInit(currentPlayerId) }

fun makeGolfGamePanel(pt: IWrappedParticipant) =
GamePanelGolf(FakeDartsScreen(), insertGame(gameType = GameType.GOLF, gameParams = "18"), 1)
.apply { testInit(pt) }
fun makeGolfGamePanel(
players: List<PlayerEntity>,
teamMode: Boolean,
gameParams: String
): GamePanelGolf {
val g = insertGame(gameType = GameType.GOLF, gameParams = gameParams)
val participants = prepareParticipants(g.rowId, players, teamMode)

val panel = GamePanelGolf(FakeDartsScreen(), g, participants.size)
panel.startNewGame(participants)
return panel
}

fun makeX01GamePanel(
currentPlayerId: String = randomGuid(),
Expand Down Expand Up @@ -119,7 +129,9 @@ fun DartsGamePanel<*, *>.addCompletedRound(dartsThrown: List<Dart>) {

fun <PlayerState : AbstractPlayerState<PlayerState>> DartsGamePanel<*, PlayerState>
.updateAchievementsForFinish(finishingPosition: Int, score: Int) {
updateAchievementsForFinish(getPlayerStates().first(), finishingPosition, score)
val state = getPlayerStates().first()
state.participantFinished(finishingPosition, score)
updateAchievementsForFinish(state, score)
}

fun DartsGamePanel<*, *>.doAiTurn(model: DartsAiModel) {
Expand Down
4 changes: 4 additions & 0 deletions src/test/kotlin/dartzee/screen/game/TestDartsGamePanel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ class TestDartsGamePanel : AbstractTest() {
val team = makeTeam(p1, p2)
val panel = TestGamePanel()
panel.startNewGame(listOf(team))
panel.addCompletedRound(Dart(20, 1))

panel.updateAchievementsForFinish(1, 50)

Expand Down Expand Up @@ -123,6 +124,7 @@ class TestDartsGamePanel : AbstractTest() {
val team = makeTeam(p1, p2)
val panel = TestGamePanel()
panel.startNewGame(listOf(team))
panel.addCompletedRound(Dart(20, 1))

panel.updateAchievementsForFinish(2, 50)

Expand All @@ -134,6 +136,7 @@ class TestDartsGamePanel : AbstractTest() {
val panel = TestGamePanel()
val pt = makeSingleParticipant(insertPlayer(), panel.gameEntity.rowId)
panel.startNewGame(listOf(pt))
panel.addCompletedRound(Dart(20, 1))

panel.updateAchievementsForFinish(1, 50)

Expand All @@ -149,6 +152,7 @@ class TestDartsGamePanel : AbstractTest() {
val panel = TestGamePanel()
val pt = makeSingleParticipant(insertPlayer(), panel.gameEntity.rowId)
panel.startNewGame(listOf(pt))
panel.addCompletedRound(Dart(20, 1))

panel.updateAchievementsForFinish(3, 50)

Expand Down
Loading