Merge branch 'master' of gitlab.com:stax-river/poker-analytics

feature/top10
Razmig Sarkissian 7 years ago
commit 3270ba59a1
  1. 2
      app/src/main/java/net/pokeranalytics/android/PokerAnalyticsApplication.kt
  2. 511
      app/src/main/java/net/pokeranalytics/android/calculus/Calculator.kt
  3. 3
      app/src/main/java/net/pokeranalytics/android/model/realm/Result.kt
  4. 9
      app/src/test/java/net/pokeranalytics/android/RealmUnitTest.kt

@ -90,7 +90,7 @@ class PokerAnalyticsApplication : Application() {
val sessions = realm.where<Session>().findAll() val sessions = realm.where<Session>().findAll()
if (sessions.size < 10) { if (sessions.size < 10) {
val numberOfSessions = 200 val numberOfSessions = 100
Timber.d("*** Start creating ${numberOfSessions} fake sessions...") Timber.d("*** Start creating ${numberOfSessions} fake sessions...")
val s = Date() val s = Date()

@ -9,249 +9,284 @@ import timber.log.Timber
*/ */
class Calculator { class Calculator {
/** /**
* The options used for calculations or display * The options used for calculations or display
*/ */
class Options { class Options {
/** /**
* The way the stats are going to be displayed * The way the stats are going to be displayed
*/ */
enum class Display { enum class Display {
TABLE, TABLE,
EVOLUTION, EVOLUTION,
COMPARISON, COMPARISON,
MAP, MAP,
POLYNOMIAL POLYNOMIAL
} }
/** /**
* The type of evolution values * The type of evolution values
*/ */
enum class EvolutionValues { enum class EvolutionValues {
NONE, NONE,
STANDARD, STANDARD,
DATED DATED
} }
var display: Display = Display.TABLE var display: Display = Display.TABLE
var evolutionValues: EvolutionValues = EvolutionValues.NONE var evolutionValues: EvolutionValues = EvolutionValues.NONE
var displayedStats: List<Stat> = listOf() var displayedStats: List<Stat> = listOf()
/** /**
* This function determines whether the standard deviation should be computed * This function determines whether the standard deviation should be computed
*/ */
fun shouldComputeStandardDeviation() : Boolean { fun shouldComputeStandardDeviation(): Boolean {
this.displayedStats.forEach { stat -> this.displayedStats.forEach { stat ->
return when (stat) { return when (stat) {
STANDARD_DEVIATION, STANDARD_DEVIATION_HOURLY, STANDARD_DEVIATION_BB_PER_100_HANDS -> true STANDARD_DEVIATION, STANDARD_DEVIATION_HOURLY, STANDARD_DEVIATION_BB_PER_100_HANDS -> true
else -> false else -> false
} }
} }
return true return true
} }
// var aggregation: Aggregation? = null // var aggregation: Aggregation? = null
} }
companion object { companion object {
fun computePreAggregation(sets: List<SessionSet>, options: Options): List<ComputedResults> { fun computePreAggregation(sets: List<SessionSet>, options: Options): List<ComputedResults> {
Timber.d("sets = ${sets.size}") Timber.d("sets = ${sets.size}")
return listOf() return listOf()
} }
/** /**
* Computes all stats for list of Session sessionGroup * Computes all stats for list of Session sessionGroup
*/ */
fun computeGroups(groups: List<SessionGroup>, options: Options): List<ComputedResults> { fun computeGroups(groups: List<SessionGroup>, options: Options): List<ComputedResults> {
val computedResults = mutableListOf<ComputedResults>() val computedResults = mutableListOf<ComputedResults>()
groups.forEach { group -> groups.forEach { group ->
// Computes actual sessionGroup stats // Computes actual sessionGroup stats
val results: ComputedResults = Calculator.compute(group, options = options) val results: ComputedResults = Calculator.compute(group, options = options)
// Computes the compared sessionGroup if existing // Computes the compared sessionGroup if existing
val comparedGroup = group.comparedSessions val comparedGroup = group.comparedSessions
if (comparedGroup != null) { if (comparedGroup != null) {
val comparedResults = Calculator.compute(comparedGroup, options = options) val comparedResults = Calculator.compute(comparedGroup, options = options)
group.comparedComputedResults = comparedResults group.comparedComputedResults = comparedResults
results.computeStatVariations(comparedResults) results.computeStatVariations(comparedResults)
} }
results.finalize(options) // later treatment, such as evolution values sorting results.finalize(options) // later treatment, such as evolution values sorting
computedResults.add(results) computedResults.add(results)
} }
return computedResults return computedResults
} }
/** // fun compute(sessionGroup: SessionGroup, options: Options): ComputedResults {
* Computes stats for a SessionSet //
*/ // var sum: Double = 0.0
fun compute(sessionGroup: SessionGroup, options: Options) : ComputedResults { // val sessions: List<SessionInterface> = sessionGroup.sessions
// val results: ComputedResults = ComputedResults(sessionGroup)
Timber.d(">>>> Start computing group ${sessionGroup.name}, ${sessionGroup.sessions.size} sessions") //
// sessions.forEach { s ->
val sessions: List<SessionInterface> = sessionGroup.sessions // sum += s.ratedNet
val sessionSets = sessionGroup.sessions.mapNotNull { it.sessionSet }.toHashSet() // }
//
val results: ComputedResults = ComputedResults(sessionGroup) // results.addStats(
// setOf(
var sum: Double = 0.0 // ComputedStat(NETRESULT, sum)
var totalHands: Double = 0.0 // )
var bbSum: Double = 0.0 // )
var bbSessionCount: Int = 0 //
var winningSessionCount: Int = 0 // return results
var totalBuyin = 0.0 // }
// Compute for each session
var index: Int = 0 /**
sessions.forEach { s -> * Computes stats for a SessionSet
index++; */
fun compute(sessionGroup: SessionGroup, options: Options): ComputedResults {
sum += s.ratedNet
bbSum += s.bbNetResult Timber.d(">>>> Start computing group ${sessionGroup.name}, ${sessionGroup.sessions.size} sessions")
bbSessionCount += s.bigBlindSessionCount
val sessions: List<SessionInterface> = sessionGroup.sessions
val sessionSets = sessionGroup.sessions.mapNotNull { it.sessionSet }.toHashSet()
val results: ComputedResults = ComputedResults(sessionGroup)
var sum: Double = 0.0
var totalHands: Double = 0.0
var bbSum: Double = 0.0
var bbSessionCount: Int = 0
var winningSessionCount: Int = 0 // sessions.filter { it.value >= 0.0 }.size
var totalBuyin = 0.0
// Compute for each session
var index: Int = 0
sessions.forEach { s ->
index++;
sum += s.ratedNet
bbSum += s.bbNetResult
bbSessionCount += s.bigBlindSessionCount
if (s.value >= 0) { if (s.value >= 0) {
winningSessionCount++ winningSessionCount++
} }
totalBuyin += s.buyin totalBuyin += s.buyin
totalHands += s.estimatedHands totalHands += s.estimatedHands
if (options.evolutionValues == Options.EvolutionValues.STANDARD) { when (options.evolutionValues) {
Options.EvolutionValues.STANDARD -> {
results.addEvolutionValue(sum, NETRESULT)
results.addEvolutionValue(sum / index, AVERAGE) results.addEvolutionValue(sum, NETRESULT)
results.addEvolutionValue(index.toDouble(), NUMBER_OF_GAMES) results.addEvolutionValue(sum / index, AVERAGE)
results.addEvolutionValue(bbSum / bbSessionCount, AVERAGE_NET_BB) results.addEvolutionValue(index.toDouble(), NUMBER_OF_GAMES)
results.addEvolutionValue((winningSessionCount / index).toDouble(), WIN_RATIO) results.addEvolutionValue(bbSum / bbSessionCount, AVERAGE_NET_BB)
results.addEvolutionValue(totalBuyin / index, AVERAGE_BUYIN) results.addEvolutionValue((winningSessionCount / index).toDouble(), WIN_RATIO)
results.addEvolutionValue(totalBuyin / index, AVERAGE_BUYIN)
val netBB100 = Stat.netBBPer100Hands(bbSum, totalHands)
if (netBB100 != null) { val netBB100 = Stat.netBBPer100Hands(bbSum, totalHands)
results.addEvolutionValue(netBB100, NET_BB_PER_100_HANDS) if (netBB100 != null) {
} results.addEvolutionValue(netBB100, NET_BB_PER_100_HANDS)
}
val roi = Stat.returnOnInvestment(sum, totalBuyin)
if (roi != null) { val roi = Stat.returnOnInvestment(sum, totalBuyin)
results.addEvolutionValue(roi, ROI) if (roi != null) {
} results.addEvolutionValue(roi, ROI)
}
}
}
} }
}
// Compute for each serie
var duration: Double = 0.0 // Compute for each serie
var hourlyRate: Double = 0.0 var duration: Double = 0.0
var hourlyRateBB: Double = 0.0 var hourlyRate: Double = 0.0
var hourlyRateBB: Double = 0.0
var gIndex = 0; var gSum = 0.0; var gTotalHands = 0.0; var gBBSum = 0.0;
sessionSets.forEach { sessionSet -> var gIndex = 0;
gIndex++ var gSum = 0.0;
duration += sessionSet.hourlyDuration var gTotalHands = 0.0;
gSum += sessionSet.ratedNet var gBBSum = 0.0;
gTotalHands += sessionSet.estimatedHands sessionSets.forEach { sessionSet ->
gBBSum += sessionSet.bbNetResult gIndex++
duration += sessionSet.hourlyDuration
hourlyRate = gSum / duration gSum += sessionSet.ratedNet
hourlyRateBB = gBBSum / duration gTotalHands += sessionSet.estimatedHands
gBBSum += sessionSet.bbNetResult
if (options.evolutionValues == Options.EvolutionValues.DATED) {
results.addEvolutionValue(gSum, duration, NETRESULT) hourlyRate = gSum / duration
results.addEvolutionValue(gSum / duration, duration, HOURLY_RATE) hourlyRateBB = gBBSum / duration
results.addEvolutionValue(hourlyRate, duration, HOURLY_RATE)
results.addEvolutionValue(gIndex.toDouble(), duration, NUMBER_OF_SETS) when (options.evolutionValues) {
results.addEvolutionValue(sessionSet.netDuration.toDouble(), duration, DURATION) Options.EvolutionValues.DATED -> {
results.addEvolutionValue(duration / gIndex, duration, AVERAGE_DURATION) results.addEvolutionValue(gSum, duration, NETRESULT)
results.addEvolutionValue(hourlyRateBB, duration, HOURLY_RATE_BB) results.addEvolutionValue(gSum / duration, duration, HOURLY_RATE)
} results.addEvolutionValue(hourlyRate, duration, HOURLY_RATE)
results.addEvolutionValue(gIndex.toDouble(), duration, NUMBER_OF_SETS)
val netBB100 = Stat.netBBPer100Hands(gBBSum, gTotalHands) results.addEvolutionValue(sessionSet.netDuration.toDouble(), duration, DURATION)
if (netBB100 != null) { results.addEvolutionValue(duration / gIndex, duration, AVERAGE_DURATION)
results.addEvolutionValue(netBB100, duration, NET_BB_PER_100_HANDS) results.addEvolutionValue(hourlyRateBB, duration, HOURLY_RATE_BB)
} else { //@todo maybe not
results.addEvolutionValue(0.0, duration, NET_BB_PER_100_HANDS) val netBB100 = Stat.netBBPer100Hands(gBBSum, gTotalHands)
} if (netBB100 != null) {
} results.addEvolutionValue(netBB100, duration, NET_BB_PER_100_HANDS)
} else { //@todo maybe not
var average = 0.0 results.addEvolutionValue(0.0, duration, NET_BB_PER_100_HANDS)
if (sessions.size > 0) { }
average = sum / sessions.size.toDouble() }
val winRatio = winningSessionCount.toDouble() / sessions.size.toDouble() }
val avgBuyin = totalBuyin / sessions.size
}
results.addStats(setOf(
ComputedStat(AVERAGE, average), var average = 0.0
ComputedStat(WIN_RATIO, winRatio), if (sessions.size > 0) {
ComputedStat(AVERAGE_BUYIN, avgBuyin) average = sum / sessions.size.toDouble()
)) val winRatio = winningSessionCount.toDouble() / sessions.size.toDouble()
} val avgBuyin = totalBuyin / sessions.size
if (sessionSets.size > 0) { results.addStats(
val avgDuration = duration / sessionSets.size setOf(
results.addStats(setOf( ComputedStat(AVERAGE, average),
ComputedStat(HOURLY_RATE, hourlyRate), ComputedStat(WIN_RATIO, winRatio),
ComputedStat(AVERAGE_DURATION, avgDuration) ComputedStat(AVERAGE_BUYIN, avgBuyin)
)) )
} )
}
// Create stats
results.addStats(setOf( if (sessionSets.size > 0) {
ComputedStat(NETRESULT, sum), val avgDuration = duration / sessionSets.size
ComputedStat(DURATION, duration), results.addStats(
ComputedStat(NUMBER_OF_SETS, sessionSets.size.toDouble()), setOf(
ComputedStat(NUMBER_OF_GAMES, sessions.size.toDouble()), ComputedStat(HOURLY_RATE, hourlyRate),
ComputedStat(HOURLY_RATE_BB, bbSum / duration), ComputedStat(AVERAGE_DURATION, avgDuration)
ComputedStat(AVERAGE_NET_BB, bbSum / bbSessionCount), )
ComputedStat(HANDS_PLAYED, totalHands) )
}
))
// Create stats
val roi = Stat.returnOnInvestment(sum, totalBuyin) results.addStats(
val netBB100 = Stat.netBBPer100Hands(bbSum, totalHands) setOf(
ComputedStat(NETRESULT, sum),
if (roi != null) { ComputedStat(DURATION, duration),
results.addStats(setOf(ComputedStat(ROI, roi))) ComputedStat(NUMBER_OF_SETS, sessionSets.size.toDouble()),
} ComputedStat(NUMBER_OF_GAMES, sessions.size.toDouble()),
if (netBB100 != null) { ComputedStat(HOURLY_RATE_BB, bbSum / duration),
results.addStats(setOf(ComputedStat(NET_BB_PER_100_HANDS, netBB100))) ComputedStat(AVERAGE_NET_BB, bbSum / bbSessionCount),
} ComputedStat(HANDS_PLAYED, totalHands)
val bbPer100Hands = bbSum / totalHands * 100 )
)
// Standard Deviation
if (options.shouldComputeStandardDeviation()) { val roi = Stat.returnOnInvestment(sum, totalBuyin)
val netBB100 = Stat.netBBPer100Hands(bbSum, totalHands)
// Session
var stdSum: Double = 0.0 if (roi != null) {
var stdBBper100HandsSum: Double = 0.0 results.addStats(setOf(ComputedStat(ROI, roi)))
sessions.forEach { session -> }
stdSum += Math.pow(session.ratedNet - average, 2.0) if (netBB100 != null) {
stdBBper100HandsSum += Math.pow(session.bbPer100Hands - bbPer100Hands, 2.0) results.addStats(setOf(ComputedStat(NET_BB_PER_100_HANDS, netBB100)))
} }
val standardDeviation: Double = Math.sqrt(stdSum / sessions.size)
val standardDeviationBBper100Hands: Double = Math.sqrt(stdBBper100HandsSum / sessions.size) val bbPer100Hands = bbSum / totalHands * 100
// Session Set // Standard Deviation
var hourlyStdSum: Double = 0.0 if (options.shouldComputeStandardDeviation()) {
sessionSets.forEach { set ->
hourlyStdSum += Math.pow(set.hourlyRate - hourlyRate, 2.0) // Session
} var stdSum: Double = 0.0
val hourlyStandardDeviation: Double = Math.sqrt(hourlyStdSum / sessionSets.size) var stdBBper100HandsSum: Double = 0.0
sessions.forEach { session ->
results.addStats(setOf( stdSum += Math.pow(session.ratedNet - average, 2.0)
ComputedStat(STANDARD_DEVIATION, standardDeviation), stdBBper100HandsSum += Math.pow(session.bbPer100Hands - bbPer100Hands, 2.0)
ComputedStat(STANDARD_DEVIATION_HOURLY, hourlyStandardDeviation), }
ComputedStat(STANDARD_DEVIATION_BB_PER_100_HANDS, standardDeviationBBper100Hands) val standardDeviation: Double = Math.sqrt(stdSum / sessions.size)
)) val standardDeviationBBper100Hands: Double = Math.sqrt(stdBBper100HandsSum / sessions.size)
}
// Session Set
return results var hourlyStdSum: Double = 0.0
} sessionSets.forEach { set ->
hourlyStdSum += Math.pow(set.hourlyRate - hourlyRate, 2.0)
} }
val hourlyStandardDeviation: Double = Math.sqrt(hourlyStdSum / sessionSets.size)
results.addStats(
setOf(
ComputedStat(STANDARD_DEVIATION, standardDeviation),
ComputedStat(STANDARD_DEVIATION_HOURLY, hourlyStandardDeviation),
ComputedStat(STANDARD_DEVIATION_BB_PER_100_HANDS, standardDeviationBBper100Hands)
)
)
}
return results
}
}
} }

@ -7,9 +7,6 @@ import io.realm.annotations.RealmClass
@RealmClass @RealmClass
open class Result : RealmObject() { open class Result : RealmObject() {
// the user associated to this session result
var player: Player? = null
// The buyin amount // The buyin amount
var buyin: Double? = null var buyin: Double? = null
set(value) { set(value) {

@ -1,7 +1,6 @@
package net.pokeranalytics.android package net.pokeranalytics.android
import io.realm.Realm import io.realm.Realm
import io.realm.RealmConfiguration
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
@ -11,15 +10,15 @@ open class RealmUnitTest {
@Before @Before
fun setup() { fun setup() {
val testConfig = RealmConfiguration.Builder().inMemory().name("test-realm").build() // val testConfig = RealmConfiguration.Builder().inMemory().name("test-realm").build()
Realm.setDefaultConfiguration(testConfig) // Realm.setDefaultConfiguration(testConfig)
mockRealm = Realm.getDefaultInstance() // mockRealm = Realm.getDefaultInstance()
} }
@After @After
@Throws(Exception::class) @Throws(Exception::class)
public fun tearDown() { public fun tearDown() {
mockRealm.close() // mockRealm.close()
} }
} }
Loading…
Cancel
Save