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 482b6c01..f7ed7486 100644 --- a/app/src/main/java/net/pokeranalytics/android/calculus/Calculator.kt +++ b/app/src/main/java/net/pokeranalytics/android/calculus/Calculator.kt @@ -94,16 +94,12 @@ class Calculator { var results: ComputedResults = ComputedResults(sessionGroup) - if (sessions.size == 0) { - return results - } - var sum: Double = 0.0 var totalHands: Double = 0.0 var bbSum: Double = 0.0 var bbSessionCount: Int = 0 var winningSessionCount: Int = 0 - var totalBuyin: Double = 0.0 + var totalBuyin = 0.0 // Compute for each session var index: Int = 0 @@ -125,10 +121,19 @@ class Calculator { results.addEvolutionValue(sum / index, AVERAGE) results.addEvolutionValue(index.toDouble(), NUMBER_OF_GAMES) results.addEvolutionValue(bbSum / bbSessionCount, AVERAGE_NET_BB) - results.addEvolutionValue(Stat.netBBPer100Hands(bbSum, totalHands), NET_BB_PER_100_HANDS) results.addEvolutionValue((winningSessionCount / index).toDouble(), WIN_RATIO) results.addEvolutionValue(totalBuyin / index, AVERAGE_BUYIN) - results.addEvolutionValue(Stat.returnOnInvestment(sum, totalBuyin), ROI) + + val netBB100 = Stat.netBBPer100Hands(bbSum, totalHands) + if (netBB100 != null) { + results.addEvolutionValue(netBB100, NET_BB_PER_100_HANDS) + } + + val roi = Stat.returnOnInvestment(sum, totalBuyin) + if (roi != null) { + results.addEvolutionValue(roi, ROI) + } + } } @@ -152,36 +157,59 @@ class Calculator { if (options.evolutionValues == Options.EvolutionValues.DATED) { results.addEvolutionValue(gSum, duration, NETRESULT) results.addEvolutionValue(gSum / duration, duration, HOURLY_RATE) - results.addEvolutionValue(Stat.netBBPer100Hands(gBBSum, gTotalHands), duration, NET_BB_PER_100_HANDS) results.addEvolutionValue(hourlyRate, duration, HOURLY_RATE) results.addEvolutionValue(gIndex.toDouble(), duration, NUMBER_OF_SETS) results.addEvolutionValue(sessionSet.duration.toDouble(), duration, DURATION) results.addEvolutionValue(duration / gIndex, duration, AVERAGE_DURATION) results.addEvolutionValue(hourlyRateBB, duration, HOURLY_RATE_BB) } + + val netBB100 = Stat.netBBPer100Hands(gBBSum, gTotalHands) + if (netBB100 != null) { + results.addEvolutionValue(netBB100, duration, NET_BB_PER_100_HANDS) + } else { //@todo maybe not + results.addEvolutionValue(0.0, duration, NET_BB_PER_100_HANDS) + } } - val average: Double = sum / sessions.size.toDouble() + var average = 0.0 + if (sessions.size > 0) { + average = sum / sessions.size.toDouble() + val avgDuration = duration / sessions.size + val winRatio = (winningSessionCount / sessions.size).toDouble() + val avgBuyin = totalBuyin / sessions.size + + results.addStats(setOf( + ComputedStat(AVERAGE, average), + ComputedStat(AVERAGE_DURATION, avgDuration), + ComputedStat(WIN_RATIO, winRatio), + ComputedStat(AVERAGE_BUYIN, avgBuyin) + )) + } // Create stats results.addStats(setOf( ComputedStat(NETRESULT, sum), ComputedStat(HOURLY_RATE, hourlyRate), - ComputedStat(AVERAGE, average), ComputedStat(DURATION, duration), ComputedStat(NUMBER_OF_SETS, sessionSets.size.toDouble()), ComputedStat(NUMBER_OF_GAMES, sessions.size.toDouble()), - ComputedStat(AVERAGE_DURATION, duration / sessions.size), - ComputedStat(NET_BB_PER_100_HANDS, Stat.netBBPer100Hands(bbSum, totalHands)), ComputedStat(HOURLY_RATE_BB, bbSum / duration), ComputedStat(AVERAGE_NET_BB, bbSum / bbSessionCount), - ComputedStat(WIN_RATIO, (winningSessionCount / sessions.size).toDouble()), - ComputedStat(AVERAGE_BUYIN, totalBuyin / sessions.size), - ComputedStat(ROI, Stat.returnOnInvestment(sum, totalBuyin)), ComputedStat(HANDS_PLAYED, totalHands) )) + val roi = Stat.returnOnInvestment(sum, totalBuyin) + val netBB100 = Stat.netBBPer100Hands(bbSum, totalHands) + + if (roi != null) { + results.addStats(setOf(ComputedStat(ROI, roi))) + } + if (netBB100 != null) { + results.addStats(setOf(ComputedStat(NET_BB_PER_100_HANDS, netBB100))) + } + val bbPer100Hands = bbSum / totalHands * 100 // Standard Deviation diff --git a/app/src/main/java/net/pokeranalytics/android/calculus/Computable.kt b/app/src/main/java/net/pokeranalytics/android/calculus/Computable.kt index f149e38c..fd4fa66f 100644 --- a/app/src/main/java/net/pokeranalytics/android/calculus/Computable.kt +++ b/app/src/main/java/net/pokeranalytics/android/calculus/Computable.kt @@ -25,15 +25,31 @@ interface SessionInterface : Summable { /** * A sessionGroup of computable items identified by a name */ -class SessionGroup(name: String, sessions: List) { +class SessionGroup(name: String, sessions: List, stats: List? = null) { + /** + * The display name of the group + */ var name: String = name + + /** + * The list of sessions to compute + */ var sessions: List = sessions - // A subgroup used to compute stat variation + /** + * The list of stats to display + */ + var stats: List? = stats + + /** + * A subgroup used to compute stat variation + */ var comparedSessions: SessionGroup? = null - // The computed stats of the comparable sessionGroup + /** + * The computed stats of the comparable sessionGroup + */ var comparedComputedResults: ComputedResults? = null } 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 3d65b671..dd70d1d9 100644 --- a/app/src/main/java/net/pokeranalytics/android/calculus/Stat.kt +++ b/app/src/main/java/net/pokeranalytics/android/calculus/Stat.kt @@ -45,11 +45,17 @@ enum class Stat : RowRepresentable { companion object { - fun returnOnInvestment(netResult: Double, buyin: Double) : Double { + fun returnOnInvestment(netResult: Double, buyin: Double) : Double? { + if (buyin == 0.0) { + return null + } return netResult / buyin } - fun netBBPer100Hands(netBB: Double, numberOfHands: Double) : Double { + fun netBBPer100Hands(netBB: Double, numberOfHands: Double) : Double? { + if (numberOfHands == 0.0) { + return null + } return netBB / numberOfHands * 100 } @@ -119,7 +125,8 @@ class ComputedStat(stat: Stat, value: Double) { /** * Formats the value of the stat to be suitable for display */ - fun format(context: Context) : TextFormat { + fun format(context: Context): TextFormat { + when (this.stat) { // Amounts + red/green Stat.NETRESULT, Stat.HOURLY_RATE, Stat.AVERAGE, Stat.NET_BB_PER_100_HANDS, Stat.HOURLY_RATE_BB, @@ -131,14 +138,14 @@ class ComputedStat(stat: Stat, value: Double) { return TextFormat(numberFormat.format(this.value), color) } // white integers Stat.NUMBER_OF_SETS, Stat.NUMBER_OF_GAMES, Stat.HANDS_PLAYED -> { - return TextFormat("${this.value.toInt()}") + return TextFormat("${value.toInt()}") } // white durations Stat.DURATION, Stat.AVERAGE_DURATION -> { - return TextFormat("${this.value.toLong().toMinutes()}") + return TextFormat("${value.toLong().toMinutes()}") } // red/green percentages Stat.WIN_RATIO, Stat.ROI -> { - val color = if (this.value >= this.stat.threshold) R.color.green else R.color.red - return TextFormat("${this.value.formatted()}%", color) + val color = if (value >= this.stat.threshold) R.color.green else R.color.red + return TextFormat("${value.formatted()}%", color) } // white amounts Stat.AVERAGE_BUYIN, Stat.STANDARD_DEVIATION, Stat.STANDARD_DEVIATION_HOURLY, Stat.STANDARD_DEVIATION_BB_PER_100_HANDS -> { @@ -149,7 +156,6 @@ class ComputedStat(stat: Stat, value: Double) { } else -> throw FormattingException("Stat formatting of ${this.stat.name} not handled") } - } /** diff --git a/app/src/main/java/net/pokeranalytics/android/model/StatRepresentable.kt b/app/src/main/java/net/pokeranalytics/android/model/StatRepresentable.kt index 0ac311ab..a7f325e7 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/StatRepresentable.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/StatRepresentable.kt @@ -1,18 +1,20 @@ package net.pokeranalytics.android.model import net.pokeranalytics.android.calculus.ComputedStat +import net.pokeranalytics.android.calculus.Stat import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowViewType -class StatRepresentable(stat: ComputedStat) : RowRepresentable { +class StatRepresentable(stat: Stat, computedStat: ComputedStat?) : RowRepresentable { - var computedStat: ComputedStat = stat + var stat: Stat = stat + var computedStat: ComputedStat? = computedStat override val viewType: Int get() = RowViewType.STAT.ordinal override val resId: Int? - get() = this.computedStat.stat.resId + get() = this.stat.resId } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/StatsFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/StatsFragment.kt index 876d659a..8655dbce 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/StatsFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/StatsFragment.kt @@ -9,10 +9,7 @@ import io.realm.Realm import kotlinx.android.synthetic.main.fragment_stats.* import kotlinx.coroutines.runBlocking import net.pokeranalytics.android.R -import net.pokeranalytics.android.calculus.Calculator -import net.pokeranalytics.android.calculus.ComputedResults -import net.pokeranalytics.android.calculus.SessionGroup -import net.pokeranalytics.android.calculus.TextFormat +import net.pokeranalytics.android.calculus.* import net.pokeranalytics.android.model.StatRepresentable import net.pokeranalytics.android.model.realm.Session import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter @@ -21,6 +18,7 @@ import net.pokeranalytics.android.ui.fragment.components.PokerAnalyticsFragment import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowViewType import net.pokeranalytics.android.ui.view.rowrepresentable.HeaderRowRepresentable +import net.pokeranalytics.android.util.NULL_TEXT class StatsFragment : PokerAnalyticsFragment(), RowRepresentableDataSource { @@ -60,23 +58,13 @@ class StatsFragment : PokerAnalyticsFragment(), RowRepresentableDataSource { override fun statFormatForRow(row: RowRepresentable): TextFormat { if (row is StatRepresentable) { - context?.let { - return row.computedStat.format(it) + context?.let { context -> + row.computedStat?.let { return it.format(context) } } } - return TextFormat("shouldn't happen :)") + return TextFormat(NULL_TEXT) } -// override fun stringForRow(row: RowRepresentable): String { -// if (row is StatRepresentable) { -// context?.let { -// val format = row.computedStat.format(it) -// return format.text -// } -// } -// return "shouldn't happen :)" -// } - /** * Init data */ @@ -103,9 +91,12 @@ class StatsFragment : PokerAnalyticsFragment(), RowRepresentableDataSource { } } - val allSessionGroup = SessionGroup(getString(R.string.all), allSessions) - val cgSessionGroup = SessionGroup(getString(R.string.cash_game), cgSessions) - val tSessionGroup = SessionGroup(getString(R.string.tournament), tSessions) + val allStats: List = listOf(Stat.NETRESULT, Stat.HOURLY_RATE, Stat.AVERAGE, Stat.NUMBER_OF_GAMES, Stat.AVERAGE_DURATION, Stat.DURATION) + val allSessionGroup = SessionGroup(getString(R.string.all), allSessions, allStats) + val cgStats: List = listOf(Stat.NETRESULT, Stat.HOURLY_RATE, Stat.NET_BB_PER_100_HANDS, Stat.HOURLY_RATE_BB, Stat.AVERAGE, Stat.STANDARD_DEVIATION_HOURLY, Stat.WIN_RATIO, Stat.NUMBER_OF_GAMES, Stat.AVERAGE_BUYIN) + val cgSessionGroup = SessionGroup(getString(R.string.cash_game), cgSessions, cgStats) + val tStats: List = listOf(Stat.NETRESULT, Stat.HOURLY_RATE, Stat.ROI, Stat.WIN_RATIO, Stat.NUMBER_OF_GAMES, Stat.AVERAGE_BUYIN) + val tSessionGroup = SessionGroup(getString(R.string.tournament), tSessions, tStats) results = Calculator.computeGroups(listOf(allSessionGroup, cgSessionGroup, tSessionGroup), Calculator.Options()) @@ -127,14 +118,14 @@ class StatsFragment : PokerAnalyticsFragment(), RowRepresentableDataSource { } - fun convertResultsIntoRepresentables(results: List) : ArrayList { + private fun convertResultsIntoRepresentables(results: List) : ArrayList { - val rows: ArrayList = ArrayList() + val rows: ArrayList = ArrayList() - results.forEach { - rows.add(HeaderRowRepresentable(RowViewType.TITLE, title = it.group.name)) - it.allStats().forEach { - rows.add(StatRepresentable(it)) + results.forEach { results -> + rows.add(HeaderRowRepresentable(RowViewType.TITLE, title = results.group.name)) + results.group.stats?.forEach { stat -> + rows.add(StatRepresentable(stat, results.computedStat(stat))) } } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/view/RowRepresentable.kt b/app/src/main/java/net/pokeranalytics/android/ui/view/RowRepresentable.kt index 3b74557a..2358c012 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/view/RowRepresentable.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/view/RowRepresentable.kt @@ -3,6 +3,7 @@ package net.pokeranalytics.android.ui.view import android.content.Context import net.pokeranalytics.android.model.LiveData import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetType +import net.pokeranalytics.android.util.NULL_TEXT /** * An interface extending Displayable to add a way to represent an object as a String @@ -10,7 +11,7 @@ import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheet interface RowRepresentable : Displayable { fun getDisplayName(): String { - return "UNKNOWN NAME" + return NULL_TEXT } } diff --git a/app/src/main/java/net/pokeranalytics/android/util/Global.kt b/app/src/main/java/net/pokeranalytics/android/util/Global.kt new file mode 100644 index 00000000..978e6109 --- /dev/null +++ b/app/src/main/java/net/pokeranalytics/android/util/Global.kt @@ -0,0 +1,3 @@ +package net.pokeranalytics.android.util + +val NULL_TEXT: String = "--"