From 4b10acce583596c2fcffe357176782dda0a6ae8b Mon Sep 17 00:00:00 2001 From: Laurent Date: Mon, 11 Feb 2019 14:46:58 +0100 Subject: [PATCH] add model + stat drafts --- .../java/net/pokeranalytics/android/Model.kt | 169 ++++++++++++++++++ .../android/calculus/Aggregator.kt | 12 ++ .../android/calculus/Calculator.kt | 109 +++++++++++ .../android/calculus/Computable.kt | 111 ++++++++++++ .../pokeranalytics/android/calculus/Format.kt | 8 + .../pokeranalytics/android/calculus/Stat.kt | 65 +++++++ 6 files changed, 474 insertions(+) create mode 100644 app/src/main/java/net/pokeranalytics/android/Model.kt create mode 100644 app/src/main/java/net/pokeranalytics/android/calculus/Aggregator.kt create mode 100644 app/src/main/java/net/pokeranalytics/android/calculus/Calculator.kt create mode 100644 app/src/main/java/net/pokeranalytics/android/calculus/Computable.kt create mode 100644 app/src/main/java/net/pokeranalytics/android/calculus/Format.kt create mode 100644 app/src/main/java/net/pokeranalytics/android/calculus/Stat.kt diff --git a/app/src/main/java/net/pokeranalytics/android/Model.kt b/app/src/main/java/net/pokeranalytics/android/Model.kt new file mode 100644 index 00000000..989fb127 --- /dev/null +++ b/app/src/main/java/net/pokeranalytics/android/Model.kt @@ -0,0 +1,169 @@ +package net.pokeranalytics.android + +import java.util.* + +class Session(bankroll: Bankroll, timeFrame: TimeFrame) { + + // A comment written by the user + var comment: String? = null + + // The date of creation of the session + var creationDate: Date = Date() + + var limit: Int? = null + var game: Game? = null + var numberOfTables: Int = 1 + var tableSize: Int? = null + + var bankroll: Bankroll = bankroll + + var hands: List = listOf() + + var timeFrame: TimeFrame = timeFrame + + var location: Location? = null + + var result: Result = Result() + + var opponents: List = listOf() + + // @todo serie + + // @todo cash game blind: 2/5/10, short deck ante, big bets in fixed limit + + // Tournament + + var entryFee: Double? = null + var numberOfPlayers: Int? = null + + // @todo tournament type? + + + + +} + +class TimeFrame { + + var startDate: Date = Date() + var endDate: Date? = null + + var breakDuration: Double = 0.0 + var duration: Double = 0.0 + var paused: Boolean = false + +} + +open class TimeFrameGroup(timeFrame: TimeFrame) { + var timeFrame: TimeFrame = timeFrame + var timeFrames: List = listOf() +} + +class Serie(timeFrame: TimeFrame) : TimeFrameGroup(timeFrame) { + +} + +class Result { + var buyin: Double? = null + var cashout: Double? = null + var netResult: Double? = null + var net: Double? = null + + var transactions: List = listOf() + + // @todo tips? + + var finalPosition: Int? = null + +// var player: Player? = null +} + +class Bankroll(name: String) { + + var live: Boolean = true + var name: String = name + var transactions: List = listOf() + var currency: Currency? = null + + // @todo rate management +} + +class Currency { + var code: String? = null + var rate: Double? = null +} + +class Transaction(value: Double, type: TransactionType) { + var value: Double = value + var date: Date = Date() + var comment: String? = null + var type: TransactionType = type + +} + +enum class TransactionKind { + WITHDRAWAL, + DEPOSIT +} + +class TransactionType(name: String) { + var name: String = name + var additive: Boolean = false + var lock: Boolean = false + var kind: TransactionKind? = null + +} + +class Game(name: String) { + var name: String = name + var shortName: String? = null +} + +class Location(name: String) { + var name: String = name + var longitude: Double? = null + var latitude: Double? = null + +} + +class TournamentType(name: String) { + var name: String = name +} + +class Player {} + +enum class ReportDisplay { + TABLE, + GRAPH, + MAP +} + +class Report(name: String) { + var name: String = name + var display: ReportDisplay = ReportDisplay.TABLE + + // @todo define the configuration options + + var comparators: List = listOf() + var stats: List = listOf() + var filters: List = listOf() + +} + +class Filter(name: String) { + var name: String = name + var usageCount: Int = 0 + var components: List = listOf() +} + +class FilterComponent { + // @todo how to store sub-filters? +} + +class HandHistory { + // @todo +} + +class CustomField { + // @todo +} \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/calculus/Aggregator.kt b/app/src/main/java/net/pokeranalytics/android/calculus/Aggregator.kt new file mode 100644 index 00000000..cf0bf178 --- /dev/null +++ b/app/src/main/java/net/pokeranalytics/android/calculus/Aggregator.kt @@ -0,0 +1,12 @@ +package net.pokeranalytics.android.calculus + +class AggregationParameter { + var values: List? = null +} + +class Aggregator { + + var parameters: List> = listOf() + +} + diff --git a/app/src/main/java/net/pokeranalytics/android/calculus/Calculator.kt b/app/src/main/java/net/pokeranalytics/android/calculus/Calculator.kt new file mode 100644 index 00000000..b585d885 --- /dev/null +++ b/app/src/main/java/net/pokeranalytics/android/calculus/Calculator.kt @@ -0,0 +1,109 @@ +package net.pokeranalytics.android.calculus + +import net.pokeranalytics.android.Serie + + +class Calculator { + + class Options { + + enum class Display { + TABLE, + EVOLUTION, + COMPARISON, + MAP, + POLYNOMIAL + } + + enum class EvolutionValues { + NONE, + STANDARD, + DATED + } + + var display: Display = Display.TABLE + var evolutionValues: EvolutionValues = EvolutionValues.NONE + var displayedStats: List = listOf() + +// var aggregation: Aggregation? = null + } + + companion object { + + fun computePreAggregation(groups: List, options: Options): List { + return listOf() + } + + // Computes all stats for list of Session group + fun computeGroups(groups: List, options: Options): List { + + var computedGroups: MutableList = mutableListOf() + groups.forEach { group -> + // Computes actual group stats + val results: ComputedResults = Calculator.compute(group, options = options) + + // Computes the compared group if existing + val comparedGroup = group.comparedGroup + if (comparedGroup != null) { + val comparedResults = Calculator.compute(comparedGroup, options = options) + group.comparedComputedGroup = ComputedGroup(comparedGroup, comparedResults) + + results.computeStatVariations(comparedResults) + } + + results.finalize(options) + computedGroups.add(ComputedGroup(group, results)) + } + + return computedGroups + } + + // Computes stats for a SessionGroup + fun compute(group: SessionGroup, options: Options) : ComputedResults { + + val sessions: List = group.sessionGroup + val series: Set = setOf() // @todo get unique list of serie + var results: ComputedResults = ComputedResults() + + var sum: Double = 0.0 + var duration: Double = 0.0 + // @todo add all stats + + // Compute for each session + sessions.forEach { item -> + sum += item.value + + when (options.evolutionValues) { + Options.EvolutionValues.STANDARD -> { + results.addEvolutionValue(sum, Stat.NETRESULT) + } + Options.EvolutionValues.DATED -> { + results.addEvolutionValue(sum, duration, Stat.NETRESULT) + } + } + + } + + // Compute for each serie + series.forEach { serie -> + duration += serie.timeFrame.duration + + if (options.evolutionValues != Options.EvolutionValues.NONE) { + results.addEvolutionValue(duration, Stat.DURATION) + } + } + + // Create stats + results.addStats(setOf( + ComputedStat(Stat.NETRESULT, sum), + ComputedStat(Stat.AVERAGE,sum / sessions.size), + ComputedStat(Stat.DURATION, duration) + )) + + return results + } + + } + + +} \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/calculus/Computable.kt b/app/src/main/java/net/pokeranalytics/android/calculus/Computable.kt new file mode 100644 index 00000000..448cb7f0 --- /dev/null +++ b/app/src/main/java/net/pokeranalytics/android/calculus/Computable.kt @@ -0,0 +1,111 @@ +package net.pokeranalytics.android.calculus + +import net.pokeranalytics.android.Serie + +// An interface to describe objects that can be summed +interface Summable { + var value: Double +} + +// An interface describing some class that can be computed +interface SessionInterface : Summable { + var serie: Serie +} + +/** + * A group of computable items identified by a name + */ +class SessionGroup(name: String, sessions: List) { + + var name: String = name + var sessionGroup: List = sessions + + // A subgroup used to compute stat variation + var comparedGroup: SessionGroup? = null + + // The computed stats of the comparable group + var comparedComputedGroup: ComputedGroup? = null + +} + +class ComputedGroup(group: SessionGroup, computedResults: ComputedResults) { + // A computable group + var group: SessionGroup = group + + // The computed stats of the group + var computedResults: ComputedResults = computedResults + + fun statValue(stat: Stat) : Double? { + return computedResults.computedStat(stat)?.value + } + +} + +class ComputedResults() { + + // The computed stats of the group + private var _computedStats: MutableMap = mutableMapOf() + + // The map containing all evolution values for all stats + private var _evolutionValues: MutableMap> = mutableMapOf() + + fun addEvolutionValue(value: Double, stat: Stat) { + this._addEvolutionValue(Point(value), stat = stat) + } + + fun addEvolutionValue(value: Double, duration: Double, stat: Stat) { + this._addEvolutionValue(Point(value, y = duration), stat = stat) + } + + private fun _addEvolutionValue(point: Point, stat: Stat) { + var evolutionValues = this._evolutionValues[stat] + if (evolutionValues != null) { + evolutionValues.add(point) + } else { + var values: MutableList = mutableListOf(point) + this._evolutionValues[stat] = values + } + } + + fun addStats(computedStats: Set) { + computedStats.forEach { + this._computedStats[it.stat] = it + } + } + + fun computedStat(stat: Stat) : ComputedStat? { + return this._computedStats[stat] + } + + fun computeStatVariations(resultsToCompare: ComputedResults) { + this._computedStats.keys.forEach { stat -> + var computedStat = this.computedStat(stat) + val comparedStat = resultsToCompare.computedStat(stat) + if (computedStat != null && comparedStat != null) { + computedStat.variation = (computedStat.value - comparedStat.value) / comparedStat.value + } + } + } + + fun finalize(options: Calculator.Options) { + if (options.evolutionValues != Calculator.Options.EvolutionValues.NONE) { + + // Sort points as a distribution + this._computedStats.keys.filter { it.hasDistributionSorting() }.forEach { stat -> + // @todo sort +// var evolutionValues = this._evolutionValues[stat] +// evolutionValues.so + } + + } + } + +} + +class Point(x: Double, y: Double) { + val x: Double = x + val y: Double = y + + constructor(x: Double) : this(x, 1.0) + +} \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/calculus/Format.kt b/app/src/main/java/net/pokeranalytics/android/calculus/Format.kt new file mode 100644 index 00000000..123b770f --- /dev/null +++ b/app/src/main/java/net/pokeranalytics/android/calculus/Format.kt @@ -0,0 +1,8 @@ +package net.pokeranalytics.android.calculus + +import android.graphics.Color + +class StatFormat { + var text: String = "" + var color: Int = Color.BLUE +} \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/calculus/Stat.kt b/app/src/main/java/net/pokeranalytics/android/calculus/Stat.kt new file mode 100644 index 00000000..d3a9afda --- /dev/null +++ b/app/src/main/java/net/pokeranalytics/android/calculus/Stat.kt @@ -0,0 +1,65 @@ +package net.pokeranalytics.android.calculus + +interface AnyStat { + +} + +enum class Stat : AnyStat { + + NETRESULT, + HOURLYRATE, + DURATION, + AVERAGE, + STANDARDDEVIATION, + HOURLYSTANDARDDEVIATION; + + fun label() : String = when (this) { + NETRESULT -> "" + HOURLYRATE -> "" + else -> throw IllegalArgumentException("Label not defined") + } + + fun hasDistributionSorting() : Boolean { + when (this) { + STANDARDDEVIATION, HOURLYSTANDARDDEVIATION -> return true + else -> return false + } + } + +} + +enum class CashSessionStat : AnyStat { + NETBB, + AVERAGEBB +} + +class ComputedStat(stat: Stat, value: Double) { + + constructor(stat: Stat, value: Double, previousValue: Double?) : this(stat, value) { + if (previousValue != null) { + this.variation = (value - previousValue) / previousValue + } + } + + // The statistic type + var stat: Stat = stat + + // The stat value + var value: Double = value + + // The variation of the stat + var variation: Double? = null + + // The data points leading to the current stat value +// var points: List = mutableListOf() + + // Formats the value of the stat to be suitable for display + fun format() : StatFormat { + return StatFormat() + } + + fun evolutionValueFormat(index: Int) : StatFormat { + return StatFormat() + } + +}