diff --git a/app/src/main/java/net/pokeranalytics/android/calculus/Calculator.kt b/app/src/main/java/net/pokeranalytics/android/calculus/Calculator.kt index bc784814..f07edda2 100644 --- a/app/src/main/java/net/pokeranalytics/android/calculus/Calculator.kt +++ b/app/src/main/java/net/pokeranalytics/android/calculus/Calculator.kt @@ -27,7 +27,8 @@ class Calculator { class Options( display: Display = Display.TABLE, evolutionValues: EvolutionValues = EvolutionValues.NONE, - stats: List = listOf() + stats: List = listOf(), + aggregationType: AggregationType? = null ) { /** @@ -53,6 +54,7 @@ class Calculator { var display: Display = display var evolutionValues: EvolutionValues = evolutionValues var displayedStats: List = stats + var aggregationType: AggregationType? = aggregationType /** * This function determines whether the standard deviation should be computed @@ -80,6 +82,15 @@ class Calculator { 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 { @@ -90,7 +101,7 @@ class Calculator { aggregationType: AggregationType ): Report { - val options = Options(evolutionValues = Options.EvolutionValues.STANDARD) + val options = Options(evolutionValues = Options.EvolutionValues.STANDARD, aggregationType = aggregationType) if (aggregationType == AggregationType.DURATION) { options.evolutionValues = Options.EvolutionValues.TIMED } @@ -116,6 +127,8 @@ class Calculator { ): Report { val computableGroups: MutableList = mutableListOf() + + var previousGroup: ComputableGroup? = null comparators.combined().forEach { comparatorConditions -> val allConditions = mutableListOf() @@ -123,8 +136,10 @@ class Calculator { allConditions.addAll(comparatorConditions) val group = ComputableGroup(allConditions.name(), allConditions) + group.comparedGroup = previousGroup computableGroups.add(group) + previousGroup = group } if (computableGroups.size == 0) { @@ -151,7 +166,7 @@ class Calculator { val results: ComputedResults = this.compute(realm, group, options = options) // Computes the compared sessionGroup if existing - val comparedGroup = group.comparedComputables + val comparedGroup = group.comparedGroup if (comparedGroup != null) { val comparedResults = this.compute(realm, comparedGroup, options = options) group.comparedComputedResults = comparedResults @@ -175,29 +190,70 @@ class Calculator { */ fun compute(realm: Realm, computableGroup: ComputableGroup, options: Options): ComputedResults { + val results = ComputedResults(computableGroup) + val computables = computableGroup.computables(realm) Timber.d(">>>> Start computing group ${computableGroup.name}, ${computables.size} computables") + results.addStat(NUMBER_OF_GAMES, computables.size.toDouble()) if (options.computeLongestStreak) { computables.sort("session.startDate") } - val results = ComputedResults(computableGroup) - val sum = computables.sum(ComputableResult.Field.RATED_NET.identifier).toDouble() + results.addStat(NETRESULT, sum) + 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() + results.addStat(BB_NET_RESULT, bbSum) + 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() + results.addStat(WINNING_SESSION_COUNT, winningSessionCount.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() + maxNetResult?.let { + results.addStat(MAXIMUM_NETRESULT, it) + } + 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) { 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 = (options.evolutionValues == Options.EvolutionValues.STANDARD || options.computeLongestStreak) @@ -275,6 +331,7 @@ class Calculator { } val sessionSets = computableGroup.sessionSets(realm) + results.addStat(NUMBER_OF_SETS, sessionSets.size.toDouble()) var gHourlyDuration: Double? = null var gBBSum: Double? = null @@ -389,23 +446,7 @@ class Calculator { } - var average = 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) { hourlyRate = sum / gHourlyDuration @@ -424,29 +465,6 @@ class Calculator { 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 -> results.addStat(MAXIMUM_DURATION, maxd) // (milliseconds to hours) } @@ -489,7 +507,6 @@ class Calculator { } - } class SSStats(sessionSet: SessionSet, conditions: List) { // Session Set Stats diff --git a/app/src/main/java/net/pokeranalytics/android/calculus/Report.kt b/app/src/main/java/net/pokeranalytics/android/calculus/Report.kt index b0e813a6..b4fb8b67 100644 --- a/app/src/main/java/net/pokeranalytics/android/calculus/Report.kt +++ b/app/src/main/java/net/pokeranalytics/android/calculus/Report.kt @@ -138,7 +138,7 @@ class ComputableGroup(name: String, conditions: List = listOf(), /** * A subgroup used to compute stat variation */ - var comparedComputables: ComputableGroup? = null + var comparedGroup: ComputableGroup? = null /** * 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) { - this._computedStats[stat] = ComputedStat(stat, value, secondValue = secondValue) + val computedStat = ComputedStat(stat, value, secondValue = secondValue) + this.addComputedStat(computedStat) } fun addStats(computedStats: Set) { 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) { + + this.consolidateEvolutionStat() + if (options.evolutionValues != Calculator.Options.EvolutionValues.NONE) { // Sort points as a distribution @@ -289,8 +320,9 @@ class ComputedResults(group: ComputableGroup) : StatEntry { override val entryTitle: String = this.group.name override fun formattedValue(stat: Stat, context: Context): TextFormat { - this.computedStat(stat)?.let { - return it.format(context) + this.computedStat(stat)?.secondValue?.let { + return stat.format(it, context = context) +// return it.format(context) } ?: run { throw IllegalStateException("Missing stat in results") } diff --git a/app/src/main/java/net/pokeranalytics/android/calculus/Stat.kt b/app/src/main/java/net/pokeranalytics/android/calculus/Stat.kt index a012d352..64fe617e 100644 --- a/app/src/main/java/net/pokeranalytics/android/calculus/Stat.kt +++ b/app/src/main/java/net/pokeranalytics/android/calculus/Stat.kt @@ -56,6 +56,7 @@ enum class AggregationType { enum class Stat : RowRepresentable { NETRESULT, + BB_NET_RESULT, HOURLY_RATE, AVERAGE, NUMBER_OF_SETS, @@ -77,7 +78,10 @@ enum class Stat : RowRepresentable { MAXIMUM_NETRESULT, MINIMUM_NETRESULT, MAXIMUM_DURATION, - DAYS_PLAYED + DAYS_PLAYED, + WINNING_SESSION_COUNT, + BB_SESSION_COUNT, + TOTAL_BUYIN, ; /** @@ -112,6 +116,7 @@ enum class Stat : RowRepresentable { get() { return when (this) { NETRESULT -> R.string.net_result + BB_NET_RESULT -> R.string.total_net_result_bb_ HOURLY_RATE -> R.string.average_hour_rate AVERAGE -> R.string.average NUMBER_OF_SETS -> R.string.number_of_sessions @@ -134,6 +139,7 @@ enum class Stat : RowRepresentable { MINIMUM_NETRESULT -> R.string.min_net_result MAXIMUM_DURATION -> R.string.longest_session DAYS_PLAYED -> R.string.days_played + else -> throw IllegalStateException("Stat ${this.name} name required but undefined") } }