Starting to add evolution values at Results/Group level + refactoring

feature/top10
Laurent 7 years ago
parent a75b0aea83
commit 90af71fd29
  1. 107
      app/src/main/java/net/pokeranalytics/android/calculus/Calculator.kt
  2. 42
      app/src/main/java/net/pokeranalytics/android/calculus/Report.kt
  3. 8
      app/src/main/java/net/pokeranalytics/android/calculus/Stat.kt

@ -27,7 +27,8 @@ class Calculator {
class Options( class Options(
display: Display = Display.TABLE, display: Display = Display.TABLE,
evolutionValues: EvolutionValues = EvolutionValues.NONE, evolutionValues: EvolutionValues = EvolutionValues.NONE,
stats: List<Stat> = listOf() stats: List<Stat> = listOf(),
aggregationType: AggregationType? = null
) { ) {
/** /**
@ -53,6 +54,7 @@ class Calculator {
var display: Display = display var display: Display = display
var evolutionValues: EvolutionValues = evolutionValues var evolutionValues: EvolutionValues = evolutionValues
var displayedStats: List<Stat> = stats var displayedStats: List<Stat> = stats
var aggregationType: AggregationType? = aggregationType
/** /**
* This function determines whether the standard deviation should be computed * This function determines whether the standard deviation should be computed
@ -80,6 +82,15 @@ class Calculator {
return this.displayedStats.contains(DAYS_PLAYED) return this.displayedStats.contains(DAYS_PLAYED)
} }
val evolutionForAggregatedValues: Boolean
get() {
if (this.aggregationType != null) {
return this.aggregationType == AggregationType.MONTH || this.aggregationType == AggregationType.YEAR
} else {
return false
}
}
} }
companion object { companion object {
@ -90,7 +101,7 @@ class Calculator {
aggregationType: AggregationType aggregationType: AggregationType
): Report { ): Report {
val options = Options(evolutionValues = Options.EvolutionValues.STANDARD) val options = Options(evolutionValues = Options.EvolutionValues.STANDARD, aggregationType = aggregationType)
if (aggregationType == AggregationType.DURATION) { if (aggregationType == AggregationType.DURATION) {
options.evolutionValues = Options.EvolutionValues.TIMED options.evolutionValues = Options.EvolutionValues.TIMED
} }
@ -116,6 +127,8 @@ class Calculator {
): Report { ): Report {
val computableGroups: MutableList<ComputableGroup> = mutableListOf() val computableGroups: MutableList<ComputableGroup> = mutableListOf()
var previousGroup: ComputableGroup? = null
comparators.combined().forEach { comparatorConditions -> comparators.combined().forEach { comparatorConditions ->
val allConditions = mutableListOf<QueryCondition>() val allConditions = mutableListOf<QueryCondition>()
@ -123,8 +136,10 @@ class Calculator {
allConditions.addAll(comparatorConditions) allConditions.addAll(comparatorConditions)
val group = ComputableGroup(allConditions.name(), allConditions) val group = ComputableGroup(allConditions.name(), allConditions)
group.comparedGroup = previousGroup
computableGroups.add(group) computableGroups.add(group)
previousGroup = group
} }
if (computableGroups.size == 0) { if (computableGroups.size == 0) {
@ -151,7 +166,7 @@ class Calculator {
val results: ComputedResults = this.compute(realm, group, options = options) val results: ComputedResults = this.compute(realm, group, options = options)
// Computes the compared sessionGroup if existing // Computes the compared sessionGroup if existing
val comparedGroup = group.comparedComputables val comparedGroup = group.comparedGroup
if (comparedGroup != null) { if (comparedGroup != null) {
val comparedResults = this.compute(realm, comparedGroup, options = options) val comparedResults = this.compute(realm, comparedGroup, options = options)
group.comparedComputedResults = comparedResults group.comparedComputedResults = comparedResults
@ -175,29 +190,70 @@ class Calculator {
*/ */
fun compute(realm: Realm, computableGroup: ComputableGroup, options: Options): ComputedResults { fun compute(realm: Realm, computableGroup: ComputableGroup, options: Options): ComputedResults {
val results = ComputedResults(computableGroup)
val computables = computableGroup.computables(realm) val computables = computableGroup.computables(realm)
Timber.d(">>>> Start computing group ${computableGroup.name}, ${computables.size} computables") Timber.d(">>>> Start computing group ${computableGroup.name}, ${computables.size} computables")
results.addStat(NUMBER_OF_GAMES, computables.size.toDouble())
if (options.computeLongestStreak) { if (options.computeLongestStreak) {
computables.sort("session.startDate") computables.sort("session.startDate")
} }
val results = ComputedResults(computableGroup)
val sum = computables.sum(ComputableResult.Field.RATED_NET.identifier).toDouble() val sum = computables.sum(ComputableResult.Field.RATED_NET.identifier).toDouble()
results.addStat(NETRESULT, sum)
val totalHands = computables.sum(ComputableResult.Field.ESTIMATED_HANDS.identifier).toDouble() val totalHands = computables.sum(ComputableResult.Field.ESTIMATED_HANDS.identifier).toDouble()
results.addStat(HANDS_PLAYED, totalHands)
val bbSum = computables.sum(ComputableResult.Field.BB_NET.identifier).toDouble() val bbSum = computables.sum(ComputableResult.Field.BB_NET.identifier).toDouble()
results.addStat(BB_NET_RESULT, bbSum)
val bbSessionCount = computables.sum(ComputableResult.Field.HAS_BIG_BLIND.identifier).toInt() val bbSessionCount = computables.sum(ComputableResult.Field.HAS_BIG_BLIND.identifier).toInt()
results.addStat(BB_SESSION_COUNT, bbSessionCount.toDouble())
val winningSessionCount = computables.sum(ComputableResult.Field.IS_POSITIVE.identifier).toInt() val winningSessionCount = computables.sum(ComputableResult.Field.IS_POSITIVE.identifier).toInt()
results.addStat(WINNING_SESSION_COUNT, winningSessionCount.toDouble())
val totalBuyin = computables.sum(ComputableResult.Field.RATED_BUYIN.identifier).toDouble() val totalBuyin = computables.sum(ComputableResult.Field.RATED_BUYIN.identifier).toDouble()
results.addStat(TOTAL_BUYIN, totalBuyin)
val maxNetResult = computables.max(ComputableResult.Field.RATED_NET.identifier)?.toDouble() val maxNetResult = computables.max(ComputableResult.Field.RATED_NET.identifier)?.toDouble()
maxNetResult?.let {
results.addStat(MAXIMUM_NETRESULT, it)
}
val minNetResult = computables.min(ComputableResult.Field.RATED_NET.identifier)?.toDouble() val minNetResult = computables.min(ComputableResult.Field.RATED_NET.identifier)?.toDouble()
minNetResult?.let {
results.addStat(MINIMUM_NETRESULT, it)
}
Stat.netBBPer100Hands(bbSum, totalHands)?.let { netBB100 ->
results.addStat(NET_BB_PER_100_HANDS, netBB100)
}
Stat.returnOnInvestment(sum, totalBuyin)?.let { roi ->
results.addStat(ROI, roi)
}
if (options.computeLocationsPlayed) { if (options.computeLocationsPlayed) {
results.addStat(LOCATIONS_PLAYED, computables.distinctBy { it.session?.location?.id }.size.toDouble()) results.addStat(LOCATIONS_PLAYED, computables.distinctBy { it.session?.location?.id }.size.toDouble())
} }
var average = 0.0 // also used for standard deviation later
if (computables.size > 0) {
average = sum / computables.size.toDouble()
val winRatio = winningSessionCount.toDouble() / computables.size.toDouble()
val avgBuyin = totalBuyin / computables.size.toDouble()
results.addStats(
setOf(
ComputedStat(AVERAGE, average),
ComputedStat(WIN_RATIO, winRatio),
ComputedStat(AVERAGE_BUYIN, avgBuyin)
)
)
}
val shouldIterateOverComputables = val shouldIterateOverComputables =
(options.evolutionValues == Options.EvolutionValues.STANDARD || options.computeLongestStreak) (options.evolutionValues == Options.EvolutionValues.STANDARD || options.computeLongestStreak)
@ -275,6 +331,7 @@ class Calculator {
} }
val sessionSets = computableGroup.sessionSets(realm) val sessionSets = computableGroup.sessionSets(realm)
results.addStat(NUMBER_OF_SETS, sessionSets.size.toDouble())
var gHourlyDuration: Double? = null var gHourlyDuration: Double? = null
var gBBSum: Double? = null var gBBSum: Double? = null
@ -389,23 +446,7 @@ class Calculator {
} }
var average = 0.0
var hourlyRate = 0.0 var hourlyRate = 0.0
if (computables.size > 0) {
average = sum / computables.size.toDouble()
val winRatio = winningSessionCount.toDouble() / computables.size.toDouble()
val avgBuyin = totalBuyin / computables.size
results.addStats(
setOf(
ComputedStat(AVERAGE, average),
ComputedStat(WIN_RATIO, winRatio),
ComputedStat(AVERAGE_BUYIN, avgBuyin)
)
)
}
if (gHourlyDuration != null) { if (gHourlyDuration != null) {
hourlyRate = sum / gHourlyDuration hourlyRate = sum / gHourlyDuration
@ -424,29 +465,6 @@ class Calculator {
results.addStat(AVERAGE_NET_BB, gBBSum / bbSessionCount) results.addStat(AVERAGE_NET_BB, gBBSum / bbSessionCount)
} }
// Create stats
results.addStats(
setOf(
ComputedStat(NETRESULT, sum),
ComputedStat(NUMBER_OF_SETS, sessionSets.size.toDouble()),
ComputedStat(NUMBER_OF_GAMES, computables.size.toDouble()),
ComputedStat(HANDS_PLAYED, totalHands)
)
)
Stat.returnOnInvestment(sum, totalBuyin)?.let { roi ->
results.addStat(ROI, roi)
}
Stat.netBBPer100Hands(bbSum, totalHands)?.let { netBB100 ->
results.addStat(NET_BB_PER_100_HANDS, netBB100)
}
maxNetResult?.let { max ->
results.addStat(MAXIMUM_NETRESULT, max)
}
minNetResult?.let { min ->
results.addStat(MINIMUM_NETRESULT, min)
}
maxDuration?.let { maxd -> maxDuration?.let { maxd ->
results.addStat(MAXIMUM_DURATION, maxd) // (milliseconds to hours) results.addStat(MAXIMUM_DURATION, maxd) // (milliseconds to hours)
} }
@ -489,7 +507,6 @@ class Calculator {
} }
} }
class SSStats(sessionSet: SessionSet, conditions: List<QueryCondition>) { // Session Set Stats class SSStats(sessionSet: SessionSet, conditions: List<QueryCondition>) { // Session Set Stats

@ -138,7 +138,7 @@ class ComputableGroup(name: String, conditions: List<QueryCondition> = listOf(),
/** /**
* A subgroup used to compute stat variation * A subgroup used to compute stat variation
*/ */
var comparedComputables: ComputableGroup? = null var comparedGroup: ComputableGroup? = null
/** /**
* The computed stats of the comparable sessionGroup * The computed stats of the comparable sessionGroup
@ -198,12 +198,40 @@ class ComputedResults(group: ComputableGroup) : StatEntry {
} }
fun addStat(stat: Stat, value: Double, secondValue: Double? = null) { fun addStat(stat: Stat, value: Double, secondValue: Double? = null) {
this._computedStats[stat] = ComputedStat(stat, value, secondValue = secondValue) val computedStat = ComputedStat(stat, value, secondValue = secondValue)
this.addComputedStat(computedStat)
} }
fun addStats(computedStats: Set<ComputedStat>) { fun addStats(computedStats: Set<ComputedStat>) {
computedStats.forEach { computedStats.forEach {
this._computedStats[it.stat] = it this.addComputedStat(it)
}
}
private fun addComputedStat(computedStat: ComputedStat) {
this.group.comparedComputedResults?.let { result ->
result.computedStat(computedStat.stat)?.let { previousComputedStat ->
val previousValue = previousComputedStat.secondValue ?: previousComputedStat.value
when (computedStat.stat) {
Stat.NETRESULT, Stat.DURATION, Stat.BB_NET_RESULT -> {
computedStat.secondValue = previousValue + computedStat.value
}
}
}
}
this._computedStats[computedStat.stat] = computedStat
}
fun consolidateEvolutionStat() {
this.allStats().forEach { computedStat ->
when (computedStat.stat) {
}
} }
} }
@ -222,6 +250,9 @@ class ComputedResults(group: ComputableGroup) : StatEntry {
} }
fun finalize(options: Calculator.Options) { fun finalize(options: Calculator.Options) {
this.consolidateEvolutionStat()
if (options.evolutionValues != Calculator.Options.EvolutionValues.NONE) { if (options.evolutionValues != Calculator.Options.EvolutionValues.NONE) {
// Sort points as a distribution // Sort points as a distribution
@ -289,8 +320,9 @@ class ComputedResults(group: ComputableGroup) : StatEntry {
override val entryTitle: String = this.group.name override val entryTitle: String = this.group.name
override fun formattedValue(stat: Stat, context: Context): TextFormat { override fun formattedValue(stat: Stat, context: Context): TextFormat {
this.computedStat(stat)?.let { this.computedStat(stat)?.secondValue?.let {
return it.format(context) return stat.format(it, context = context)
// return it.format(context)
} ?: run { } ?: run {
throw IllegalStateException("Missing stat in results") throw IllegalStateException("Missing stat in results")
} }

@ -56,6 +56,7 @@ enum class AggregationType {
enum class Stat : RowRepresentable { enum class Stat : RowRepresentable {
NETRESULT, NETRESULT,
BB_NET_RESULT,
HOURLY_RATE, HOURLY_RATE,
AVERAGE, AVERAGE,
NUMBER_OF_SETS, NUMBER_OF_SETS,
@ -77,7 +78,10 @@ enum class Stat : RowRepresentable {
MAXIMUM_NETRESULT, MAXIMUM_NETRESULT,
MINIMUM_NETRESULT, MINIMUM_NETRESULT,
MAXIMUM_DURATION, MAXIMUM_DURATION,
DAYS_PLAYED DAYS_PLAYED,
WINNING_SESSION_COUNT,
BB_SESSION_COUNT,
TOTAL_BUYIN,
; ;
/** /**
@ -112,6 +116,7 @@ enum class Stat : RowRepresentable {
get() { get() {
return when (this) { return when (this) {
NETRESULT -> R.string.net_result NETRESULT -> R.string.net_result
BB_NET_RESULT -> R.string.total_net_result_bb_
HOURLY_RATE -> R.string.average_hour_rate HOURLY_RATE -> R.string.average_hour_rate
AVERAGE -> R.string.average AVERAGE -> R.string.average
NUMBER_OF_SETS -> R.string.number_of_sessions NUMBER_OF_SETS -> R.string.number_of_sessions
@ -134,6 +139,7 @@ enum class Stat : RowRepresentable {
MINIMUM_NETRESULT -> R.string.min_net_result MINIMUM_NETRESULT -> R.string.min_net_result
MAXIMUM_DURATION -> R.string.longest_session MAXIMUM_DURATION -> R.string.longest_session
DAYS_PLAYED -> R.string.days_played DAYS_PLAYED -> R.string.days_played
else -> throw IllegalStateException("Stat ${this.name} name required but undefined")
} }
} }

Loading…
Cancel
Save