Skip to content

Commit

Permalink
Merge pull request #196 from alyssaburlton/stats-screen-sql
Browse files Browse the repository at this point in the history
Fix golf stats screens
  • Loading branch information
alyssaruth authored Nov 29, 2022
2 parents 0dba561 + fb2b59e commit 16d57d6
Show file tree
Hide file tree
Showing 19 changed files with 507 additions and 247 deletions.
2 changes: 1 addition & 1 deletion src/main/kotlin/dartzee/ai/AbstractDartsSimulation.kt
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ abstract class AbstractDartsSimulation(val dartboard: Dartboard,
val totalRounds = currentRound - 1
val totalScore = getTotalScore()

val wrapper = GameWrapper(gameId, gameParams, dtStart!!, dtFinish!!, totalScore)
val wrapper = GameWrapper(gameId, gameParams, dtStart!!, dtFinish!!, totalScore, false)
wrapper.setHmRoundNumberToDartsThrown(hmRoundNumberToDarts)
wrapper.setTotalRounds(totalRounds)

Expand Down
10 changes: 7 additions & 3 deletions src/main/kotlin/dartzee/ai/SimulationRunner.kt
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
package dartzee.ai

import dartzee.`object`.DartsClient
import dartzee.core.screen.ProgressDialog
import dartzee.core.util.DialogUtil
import dartzee.db.BulkInserter
import dartzee.db.DartEntity
import dartzee.db.GameEntity
import dartzee.db.ParticipantEntity
import dartzee.logging.*
import dartzee.logging.CODE_SIMULATION_CANCELLED
import dartzee.logging.CODE_SIMULATION_ERROR
import dartzee.logging.CODE_SIMULATION_FINISHED
import dartzee.logging.CODE_SIMULATION_PROGRESS
import dartzee.logging.CODE_SIMULATION_STARTED
import dartzee.`object`.DartsClient
import dartzee.screen.stats.player.PlayerStatisticsScreen
import dartzee.stats.GameWrapper
import dartzee.utils.DurationTimer
Expand Down Expand Up @@ -117,7 +121,7 @@ class SimulationRunner: AbstractSimulationRunner()
games.add(it.gameEntity!!)
participants.add(it.participantEntity!!)

darts += it.dartEntities
darts += it.simulationDartEntities

it.clearEntities()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,10 @@ import dartzee.screen.stats.player.x01.StatisticsTabX01ThreeDartAverage
import dartzee.screen.stats.player.x01.StatisticsTabX01ThreeDartScores
import dartzee.screen.stats.player.x01.StatisticsTabX01TopFinishes
import dartzee.stats.GameWrapper
import dartzee.utils.InjectedThings.logger
import dartzee.utils.InjectedThings.mainDatabase
import dartzee.stats.retrieveGameData
import java.awt.BorderLayout
import java.awt.Dimension
import java.awt.event.ActionEvent
import java.sql.SQLException
import javax.swing.JButton
import javax.swing.JPanel
import javax.swing.JTabbedPane
Expand All @@ -33,7 +31,7 @@ import javax.swing.SwingConstants
class PlayerStatisticsScreen : EmbeddedScreen()
{
private var hmLocalIdToWrapper = mapOf<Long, GameWrapper>()
private var hmLocalIdToWrapperOther = mutableMapOf<Long, GameWrapper>()
private var hmLocalIdToWrapperOther = mapOf<Long, GameWrapper>()
private var filteredGames = listOf<GameWrapper>()
private var filteredGamesOther = listOf<GameWrapper>()

Expand Down Expand Up @@ -86,8 +84,8 @@ class PlayerStatisticsScreen : EmbeddedScreen()
filterPanelOther.isVisible = false
btnAdd.isVisible = true

hmLocalIdToWrapper = retrieveGameData(player!!.rowId)
hmLocalIdToWrapperOther.clear()
hmLocalIdToWrapper = retrieveGameData(player!!.rowId, gameType)
hmLocalIdToWrapperOther = mapOf()

resetTabs()
buildTabs()
Expand Down Expand Up @@ -144,92 +142,19 @@ class PlayerStatisticsScreen : EmbeddedScreen()
filterPanelOther.isVisible = true
btnAdd.isVisible = false

hmLocalIdToWrapperOther = retrieveGameData(player.rowId)
hmLocalIdToWrapperOther = retrieveGameData(player.rowId, gameType)
buildTabs()
}

fun removeComparison()
{
filterPanelOther.isVisible = false
btnAdd.isVisible = true
hmLocalIdToWrapperOther = mutableMapOf()
hmLocalIdToWrapperOther = mapOf()

buildTabs()
}

private fun retrieveGameData(playerId: String): MutableMap<Long, GameWrapper>
{
val hm = mutableMapOf<Long, GameWrapper>()

val zzParticipants = buildParticipantTable(playerId)
zzParticipants ?: return hm

val sb = StringBuilder()
sb.append(" SELECT zz.LocalId, zz.GameParams, zz.DtCreation, zz.DtFinish, zz.FinalScore, ")
sb.append(" drt.RoundNumber,")
sb.append(" drt.Ordinal, drt.Score, drt.Multiplier, drt.StartingScore, drt.SegmentType")
sb.append(" FROM Dart drt, $zzParticipants zz")
sb.append(" WHERE drt.ParticipantId = zz.ParticipantId")
sb.append(" AND drt.PlayerId = zz.PlayerId")

try
{
mainDatabase.executeQuery(sb).use { rs ->
while (rs.next())
{
val gameId = rs.getLong("LocalId")
val gameParams = rs.getString("GameParams")
val dtStart = rs.getTimestamp("DtCreation")
val dtFinish = rs.getTimestamp("DtFinish")
val numberOfDarts = rs.getInt("FinalScore")
val roundNumber = rs.getInt("RoundNumber")
val ordinal = rs.getInt("Ordinal")
val score = rs.getInt("Score")
val multiplier = rs.getInt("Multiplier")
val startingScore = rs.getInt("StartingScore")
val segmentType = SegmentType.valueOf(rs.getString("SegmentType"))

val wrapper = hm[gameId] ?: GameWrapper(gameId, gameParams, dtStart, dtFinish, numberOfDarts)
hm[gameId] = wrapper

val dart = Dart(score, multiplier, segmentType = segmentType)
dart.ordinal = ordinal
dart.startingScore = startingScore
dart.roundNumber = roundNumber
wrapper.addDart(dart)
}
}
}
catch (sqle: SQLException)
{
logger.logSqlException(sb.toString(), "", sqle)
}
finally
{
mainDatabase.dropTable(zzParticipants)
}

return hm
}
private fun buildParticipantTable(playerId: String): String?
{
val tmp = mainDatabase.createTempTable("ParticipantsForStats", "LocalId INT, GameParams VARCHAR(255), DtCreation TIMESTAMP, DtFinish TIMESTAMP, PlayerId VARCHAR(36), ParticipantId VARCHAR(36), FinalScore INT")
tmp ?: return null

val sb = StringBuilder()
sb.append(" INSERT INTO $tmp")
sb.append(" SELECT g.LocalId, g.GameParams, g.DtCreation, g.DtFinish, pt.PlayerId, pt.RowId AS ParticipantId, pt.FinalScore ")
sb.append(" FROM Participant pt, Game g")
sb.append(" WHERE pt.GameId = g.RowId")
sb.append(" AND pt.PlayerId = '$playerId'")
sb.append(" AND g.GameType = '$gameType'")

mainDatabase.executeUpdate("" + sb)

mainDatabase.executeUpdate("CREATE INDEX ${tmp}_PlayerId_ParticipantId ON $tmp(PlayerId, ParticipantId)")
return tmp
}

fun buildTabs()
{
filteredGames = populateFilteredGames(hmLocalIdToWrapper, filterPanel)
Expand Down Expand Up @@ -266,7 +191,6 @@ class PlayerStatisticsScreen : EmbeddedScreen()

override fun getBackTarget() = ScreenCache.get<PlayerManagementScreen>()


override fun actionPerformed(arg0: ActionEvent)
{
when (arg0.source)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package dartzee.screen.stats.player.golf

import dartzee.`object`.Dart
import dartzee.core.util.getSortedValues
import dartzee.`object`.Dart
import dartzee.screen.stats.player.AbstractStatisticsTab
import dartzee.stats.GameWrapper
import java.awt.BorderLayout
Expand Down Expand Up @@ -47,20 +47,12 @@ class StatisticsTabGolfOptimalScorecard : AbstractStatisticsTab()

private fun populateStats(filteredGames: List<GameWrapper>, panel: JPanel, other: Boolean)
{
val hmHoleToBestDarts = mutableMapOf<Int, List<Dart>>()
val hmHoleToBestGameId = mutableMapOf<Int, Long>()

// Add fudge data so we always display something, even if there are no games
for (i in 1..18)
{
hmHoleToBestDarts[i] = listOf(Dart(20, 0), Dart(20, 0), Dart(20, 0))
hmHoleToBestGameId[i] = -1
}
val hmHoleToOptimalScorecard = makeOptimalScorecardStartingMap()

val sortedGames = filteredGames.sortedBy { it.dtStart }
for (game in sortedGames)
{
game.populateOptimalScorecardMaps(hmHoleToBestDarts, hmHoleToBestGameId)
game.populateOptimalScorecardMaps(hmHoleToOptimalScorecard)
}

val testId = if (other) "scorecardOther" else "scorecardMine"
Expand All @@ -70,14 +62,28 @@ class StatisticsTabGolfOptimalScorecard : AbstractStatisticsTab()
scoreSheet.setTableForeground(Color.RED)
}

val rounds = hmHoleToBestDarts.values.toList()
scoreSheet.populateTable(rounds)

scoreSheet.addGameIds(hmHoleToBestGameId.getSortedValues())
val optimalValues = hmHoleToOptimalScorecard.getSortedValues()
scoreSheet.populateTable(optimalValues.map { it.darts })
scoreSheet.addGameIds(optimalValues.map { it.localGameId })

panel.removeAll()
panel.add(scoreSheet, BorderLayout.CENTER)
panel.revalidate()
panel.repaint()
}
}

data class OptimalHoleStat(val darts: List<Dart>, val localGameId: Long)

fun makeOptimalScorecardStartingMap(): MutableMap<Int, OptimalHoleStat>
{
val hm = mutableMapOf<Int, OptimalHoleStat>()

// Add fudge data so we always display something, even if there are no games
for (i in 1..18)
{
hm[i] = OptimalHoleStat(listOf(Dart(20, 0), Dart(20, 0), Dart(20, 0)), -1)
}

return hm
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,19 @@ import dartzee.core.bean.RowSelectionListener
import dartzee.core.bean.ScrollTable
import dartzee.core.util.TableUtil
import dartzee.screen.stats.player.AbstractStatisticsTab
import dartzee.stats.*
import dartzee.stats.GameWrapper
import dartzee.stats.GolfMode
import java.awt.BorderLayout
import java.awt.Color
import java.awt.FlowLayout
import java.awt.GridLayout
import java.awt.event.ActionEvent
import java.awt.event.ActionListener
import javax.swing.*
import javax.swing.DefaultComboBoxModel
import javax.swing.JComboBox
import javax.swing.JLabel
import javax.swing.JPanel
import javax.swing.ListSelectionModel

class StatisticsTabGolfScorecards : AbstractStatisticsTab(), ActionListener, RowSelectionListener
{
Expand Down Expand Up @@ -100,7 +105,7 @@ class StatisticsTabGolfScorecards : AbstractStatisticsTab(), ActionListener, Row

private fun addMode(modeDesc: String, mode: GolfMode, model: DefaultComboBoxModel<ComboBoxItem<GolfMode>>)
{
val validGames = filteredGames.filter { it.getRoundScore(mode) > -1 }
val validGames = filteredGames.filter { !it.teamGame && it.getRoundScore(mode) > -1 }
if (validGames.isEmpty())
{
return
Expand All @@ -110,9 +115,10 @@ class StatisticsTabGolfScorecards : AbstractStatisticsTab(), ActionListener, Row
model.addElement(item)
}

private fun populateTable(filteredGames: List<GameWrapper>, scrollTable: ScrollTableDartsGame)
private fun populateTable(games: List<GameWrapper>, scrollTable: ScrollTableDartsGame)
{
//Filter out the -1's - these are games that haven't gone on long enough to have all the data
val filteredGames = games.filter { !it.teamGame }
val validGames = filteredGames.filter { it.getRoundScore(mode) > -1 }

//Populate the table from the wrappers
Expand Down
31 changes: 19 additions & 12 deletions src/main/kotlin/dartzee/stats/GameWrapper.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import dartzee.db.PlayerEntity
import dartzee.game.GameType
import dartzee.`object`.Dart
import dartzee.screen.stats.player.HoleBreakdownWrapper
import dartzee.screen.stats.player.golf.OptimalHoleStat
import dartzee.utils.calculateThreeDartAverage
import dartzee.utils.getScoringDarts
import dartzee.utils.getScoringRounds
Expand All @@ -25,8 +26,14 @@ enum class GolfMode {
/**
* Wraps up an entire game of darts from a single player's perspective
*/
class GameWrapper(val localId: Long, val gameParams: String, val dtStart: Timestamp, val dtFinish: Timestamp, val finalScore: Int)
{
class GameWrapper(
val localId: Long,
val gameParams: String,
val dtStart: Timestamp,
val dtFinish: Timestamp,
val finalScore: Int,
val teamGame: Boolean
) {
private var hmRoundNumberToDarts = HashMapList<Int, Dart>()
private var totalRounds = 0

Expand Down Expand Up @@ -184,18 +191,18 @@ class GameWrapper(val localId: Long, val gameParams: String, val dtStart: Timest
private fun getEndHoleForMode(mode: GolfMode) =
if (mode == GolfMode.FRONT_9) 9 else 18

fun populateOptimalScorecardMaps(hmHoleToBestDarts: MutableMap<Int, List<Dart>>, hmHoleToBestGameId: MutableMap<Int, Long>)
fun populateOptimalScorecardMaps(hmHoleToOptimalHoleStat: MutableMap<Int, OptimalHoleStat>)
{
for (i in 1..totalRounds)
{
val darts = getDartsForRound(i)
val currentDarts = hmHoleToBestDarts.getValue(i)
val currentGameId = hmHoleToBestGameId.getValue(i)
if (darts.isEmpty()) continue

if (isBetterGolfRound(i, darts, currentGameId, currentDarts))
val currentValue = hmHoleToOptimalHoleStat.getValue(i)

if (isBetterGolfRound(i, darts, currentValue.localGameId, currentValue.darts))
{
hmHoleToBestDarts[i] = darts
hmHoleToBestGameId[i] = localId
hmHoleToOptimalHoleStat[i] = OptimalHoleStat(darts, localId)
}
}
}
Expand Down Expand Up @@ -224,7 +231,7 @@ class GameWrapper(val localId: Long, val gameParams: String, val dtStart: Timest
return false
}

//Equal scores, so go on number of darts thrown. Less is better.
// Equal scores, so go on number of darts thrown. Less is better.
val newSize = dartsNew.size
val currentSize = dartsCurrent.size
return newSize < currentSize
Expand Down Expand Up @@ -256,13 +263,13 @@ class GameWrapper(val localId: Long, val gameParams: String, val dtStart: Timest

var gameEntity: GameEntity? = null
var participantEntity: ParticipantEntity? = null
val dartEntities = mutableListOf<DartEntity>()
val simulationDartEntities = mutableListOf<DartEntity>()

fun clearEntities()
{
gameEntity = null
participantEntity = null
dartEntities.clear()
simulationDartEntities.clear()
}

fun generateRealEntities(gameType: GameType, player: PlayerEntity)
Expand Down Expand Up @@ -292,7 +299,7 @@ class GameWrapper(val localId: Long, val gameParams: String, val dtStart: Timest

darts.forEachIndexed { ix, drt ->
val de = DartEntity.factory(drt, player.rowId, pt.rowId, i, ix+1)
dartEntities.add(de)
simulationDartEntities.add(de)
}
}
}
Expand Down
21 changes: 0 additions & 21 deletions src/main/kotlin/dartzee/stats/PlayerSummaryUtil.kt

This file was deleted.

Loading

0 comments on commit 16d57d6

Please sign in to comment.