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

feature/top10
Aurelien Hubert 7 years ago
commit 4b39cc7884
  1. 4
      app/src/androidTest/java/net/pokeranalytics/android/BankrollInstrumentedUnitTest.kt
  2. 74
      app/src/androidTest/java/net/pokeranalytics/android/StatsInstrumentedUnitTest.kt
  3. 18
      app/src/androidTest/java/net/pokeranalytics/android/filter/SessionFilterInstrumentedUnitTest.kt
  4. 64
      app/src/main/java/net/pokeranalytics/android/PokerAnalyticsApplication.kt
  5. 52
      app/src/main/java/net/pokeranalytics/android/calculus/Calculator.kt
  6. 12
      app/src/main/java/net/pokeranalytics/android/calculus/ComputableGroup.kt
  7. 40
      app/src/main/java/net/pokeranalytics/android/calculus/bankroll/BankrollCalculator.kt
  8. 122
      app/src/main/java/net/pokeranalytics/android/calculus/bankroll/BankrollReport.kt
  9. 17
      app/src/main/java/net/pokeranalytics/android/calculus/interfaces/Computable.kt
  10. 11
      app/src/main/java/net/pokeranalytics/android/calculus/interfaces/Datable.kt
  11. 2
      app/src/main/java/net/pokeranalytics/android/model/filter/FilterComponent.kt
  12. 2
      app/src/main/java/net/pokeranalytics/android/model/filter/Filterable.kt
  13. 92
      app/src/main/java/net/pokeranalytics/android/model/filter/SessionFilterable.kt
  14. 51
      app/src/main/java/net/pokeranalytics/android/model/realm/ComputableResult.kt
  15. 19
      app/src/main/java/net/pokeranalytics/android/model/realm/Currency.kt
  16. 67
      app/src/main/java/net/pokeranalytics/android/model/realm/Result.kt
  17. 42
      app/src/main/java/net/pokeranalytics/android/model/realm/Session.kt
  18. 2
      app/src/main/java/net/pokeranalytics/android/model/realm/SessionSet.kt
  19. 54
      app/src/main/java/net/pokeranalytics/android/ui/fragment/StatsFragment.kt
  20. 6
      app/src/main/java/net/pokeranalytics/android/ui/fragment/components/SessionObserverFragment.kt
  21. 4
      app/src/test/java/net/pokeranalytics/android/ExampleUnitTest.kt

@ -3,7 +3,7 @@ package net.pokeranalytics.android
import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4
import net.pokeranalytics.android.calculus.Calculator import net.pokeranalytics.android.calculus.Calculator
import net.pokeranalytics.android.calculus.ComputedResults import net.pokeranalytics.android.calculus.ComputedResults
import net.pokeranalytics.android.calculus.SessionGroup import net.pokeranalytics.android.calculus.ComputableGroup
import net.pokeranalytics.android.calculus.Stat import net.pokeranalytics.android.calculus.Stat
import net.pokeranalytics.android.model.realm.Bankroll import net.pokeranalytics.android.model.realm.Bankroll
import net.pokeranalytics.android.model.realm.Currency import net.pokeranalytics.android.model.realm.Currency
@ -56,7 +56,7 @@ class BankrollInstrumentedUnitTest : RealmInstrumentedUnitTest() {
realm.commitTransaction() realm.commitTransaction()
val sessions = realm.where(Session::class.java).findAll() val sessions = realm.where(Session::class.java).findAll()
val group = SessionGroup(name = "test", sessions = sessions) val group = ComputableGroup(name = "test", computables = sessions)
val options = Calculator.Options() val options = Calculator.Options()

@ -1,18 +1,24 @@
package net.pokeranalytics.android package net.pokeranalytics.android
import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4
import io.realm.Realm
import io.realm.RealmList
import io.realm.RealmResults import io.realm.RealmResults
import io.realm.kotlin.where
import net.pokeranalytics.android.calculus.Calculator import net.pokeranalytics.android.calculus.Calculator
import net.pokeranalytics.android.calculus.ComputedResults import net.pokeranalytics.android.calculus.ComputedResults
import net.pokeranalytics.android.calculus.SessionGroup import net.pokeranalytics.android.calculus.ComputableGroup
import net.pokeranalytics.android.calculus.Stat import net.pokeranalytics.android.calculus.Stat
import net.pokeranalytics.android.model.realm.Session import net.pokeranalytics.android.model.Limit
import net.pokeranalytics.android.model.realm.SessionSet import net.pokeranalytics.android.model.realm.*
import org.junit.Assert import org.junit.Assert
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import timber.log.Timber
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.time.LocalDate
import java.time.Period
import java.util.* import java.util.*
/** /**
@ -24,14 +30,58 @@ import java.util.*
class StatsInstrumentedUnitTest : RealmInstrumentedUnitTest() { class StatsInstrumentedUnitTest : RealmInstrumentedUnitTest() {
// convenience extension // convenience extension
fun Session.Companion.testInstance(netResult: Double, startDate: Date, endDate: Date?): Session { fun Session.Companion.testInstance(
val session: Session = Session.newInstance(super.mockRealm, false) netResult: Double = 0.0,
isTournament: Boolean = false,
startDate: Date = Date(),
endDate: Int = 1,
bankroll: Bankroll? = null,
game: Game? = null,
location : Location? = null,
tournamentName: TournamentName? = null,
tournamentFeatures: RealmList<TournamentFeature> = RealmList(),
numberOfTable: Int = 1,
limit: Int? = null,
tableSize: Int? = null
): Session {
val session: Session = Session.newInstance(super.mockRealm, isTournament, bankroll)
session.game = game
session.location = location
session.tournamentFeatures = tournamentFeatures
session.tournamentName = tournamentName
session.limit = limit
session.numberOfTables = numberOfTable
session.tableSize = tableSize
session.result?.netResult = netResult session.result?.netResult = netResult
session.startDate = startDate session.startDate = startDate
session.endDate = endDate val cal = Calendar.getInstance() // creates calendar
cal.time = startDate // sets calendar time/date
cal.add(Calendar.HOUR_OF_DAY, endDate) // adds one hour
session.endDate = cal.time // returns new date object, one hour in the future
return session return session
} }
@Test
fun testSessionNetResultOnLoad() {
val realm = mockRealm
realm.beginTransaction()
for (index in 0..100) {
Session.testInstance((-2000..2000).random().toDouble())
println("*** creating ${index}")
}
realm.commitTransaction()
var d1 = Date()
var result = realm.where(Result::class.java).sum("netResult")
var d2 = Date()
val duration = (d2.time - d1.time)
println("*** ended in ${duration} milliseconds")
}
@Test @Test
fun testSessionStats() { fun testSessionStats() {
@ -77,7 +127,7 @@ class StatsInstrumentedUnitTest : RealmInstrumentedUnitTest() {
realm.commitTransaction() realm.commitTransaction()
val sessions = realm.where(Session::class.java).findAll() val sessions = realm.where(Session::class.java).findAll()
val group = SessionGroup(name = "test", sessions = sessions) val group = ComputableGroup(name = "test", computables = sessions)
val options = Calculator.Options() val options = Calculator.Options()
options.displayedStats = listOf(Stat.STANDARD_DEVIATION_BB_PER_100_HANDS, Stat.STANDARD_DEVIATION) options.displayedStats = listOf(Stat.STANDARD_DEVIATION_BB_PER_100_HANDS, Stat.STANDARD_DEVIATION)
@ -227,7 +277,7 @@ class StatsInstrumentedUnitTest : RealmInstrumentedUnitTest() {
realm.commitTransaction() realm.commitTransaction()
val sessions = realm.where(Session::class.java).findAll() val sessions = realm.where(Session::class.java).findAll()
val group = SessionGroup(name = "test", sessions = sessions) val group = ComputableGroup(name = "test", computables = sessions)
val options = Calculator.Options() val options = Calculator.Options()
options.displayedStats = listOf(Stat.STANDARD_DEVIATION_BB_PER_100_HANDS, Stat.STANDARD_DEVIATION) options.displayedStats = listOf(Stat.STANDARD_DEVIATION_BB_PER_100_HANDS, Stat.STANDARD_DEVIATION)
@ -294,7 +344,7 @@ class StatsInstrumentedUnitTest : RealmInstrumentedUnitTest() {
realm.commitTransaction() realm.commitTransaction()
val sessions = realm.where(Session::class.java).findAll() val sessions = realm.where(Session::class.java).findAll()
val group = SessionGroup(name = "test", sessions = sessions) val group = ComputableGroup(name = "test", computables = sessions)
val options = Calculator.Options() val options = Calculator.Options()
options.displayedStats = listOf(Stat.STANDARD_DEVIATION_BB_PER_100_HANDS, Stat.STANDARD_DEVIATION) options.displayedStats = listOf(Stat.STANDARD_DEVIATION_BB_PER_100_HANDS, Stat.STANDARD_DEVIATION)
@ -377,7 +427,7 @@ class StatsInstrumentedUnitTest : RealmInstrumentedUnitTest() {
realm.commitTransaction() realm.commitTransaction()
val sessions = realm.where(Session::class.java).findAll() val sessions = realm.where(Session::class.java).findAll()
val group = SessionGroup(name = "test", sessions = sessions) val group = ComputableGroup(name = "test", computables = sessions)
val options = Calculator.Options() val options = Calculator.Options()
options.displayedStats = listOf(Stat.STANDARD_DEVIATION_BB_PER_100_HANDS, Stat.STANDARD_DEVIATION) options.displayedStats = listOf(Stat.STANDARD_DEVIATION_BB_PER_100_HANDS, Stat.STANDARD_DEVIATION)
@ -396,7 +446,7 @@ class StatsInstrumentedUnitTest : RealmInstrumentedUnitTest() {
s1.deleteFromRealm() s1.deleteFromRealm()
} }
val group2 = SessionGroup(name = "test", sessions = sessions) val group2 = ComputableGroup(name = "test", computables = sessions)
val results2: ComputedResults = Calculator.compute(group2, options) val results2: ComputedResults = Calculator.compute(group2, options)
val duration2 = results2.computedStat(Stat.DURATION) val duration2 = results2.computedStat(Stat.DURATION)
@ -548,7 +598,7 @@ class StatsInstrumentedUnitTest : RealmInstrumentedUnitTest() {
} }
val sessions = realm.where(Session::class.java).findAll() val sessions = realm.where(Session::class.java).findAll()
val group = SessionGroup(name = "test", sessions = sessions) val group = ComputableGroup(name = "test", computables = sessions)
val options = Calculator.Options() val options = Calculator.Options()
// options.displayedStats = listOf(Stat.STANDARD_DEVIATION_BB_PER_100_HANDS, Stat.STANDARD_DEVIATION) // options.displayedStats = listOf(Stat.STANDARD_DEVIATION_BB_PER_100_HANDS, Stat.STANDARD_DEVIATION)

@ -288,7 +288,7 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
Assert.assertEquals(6, sessions.size) Assert.assertEquals(6, sessions.size)
val result = arrayListOf(l2.id, l3.id) val result = arrayListOf(l1.id, l3.id)
sessions.forEach { sessions.forEach {
Assert.assertTrue(result.contains((it as Session).location?.id)) Assert.assertTrue(result.contains((it as Session).location?.id))
@ -384,7 +384,7 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
) )
Assert.assertEquals(1, sessions.size) Assert.assertEquals(1, sessions.size)
(sessions[0] as Session)?.run { (sessions[0] as Session).run {
Assert.assertEquals(s.id, this.id) Assert.assertEquals(s.id, this.id)
} }
} }
@ -492,7 +492,7 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
realm.commitTransaction() realm.commitTransaction()
val filter = SessionFilterable.MORE_THAN_NET_RESULT val filter = SessionFilterable.MORE_THAN_NET_RESULT
filter.valueMap = mapOf("net" to 204.0) filter.valueMap = mapOf("value" to 204.0)
val sessions = FilterManager().filter( val sessions = FilterManager().filter(
realm, realm,
@ -519,7 +519,7 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
realm.commitTransaction() realm.commitTransaction()
val filter = SessionFilterable.LESS_THAN_NET_RESULT val filter = SessionFilterable.LESS_THAN_NET_RESULT
filter.valueMap = mapOf("net" to 540.0) filter.valueMap = mapOf("value" to 540.0)
val sessions = FilterManager().filter( val sessions = FilterManager().filter(
realm, realm,
@ -540,21 +540,21 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
val realm = this.mockRealm val realm = this.mockRealm
realm.beginTransaction() realm.beginTransaction()
val s1 = Session.testInstance(netResult = 200.0) val s1 = Session.testInstance(netResult = 200.0)
val s2 = Session.testInstance(netResult = 500.0) Session.testInstance(netResult = 500.0)
val s3 = Session.testInstance(netResult = 50.0) val s2 = Session.testInstance(netResult = 50.0)
Session.testInstance(netResult = 570.0) Session.testInstance(netResult = 570.0)
realm.commitTransaction() realm.commitTransaction()
val filterMore = SessionFilterable.MORE_THAN_NET_RESULT val filterMore = SessionFilterable.MORE_THAN_NET_RESULT
filterMore.valueMap = mapOf("net" to 200.0) filterMore.valueMap = mapOf("value" to 200.0)
val filterLess = SessionFilterable.LESS_THAN_NET_RESULT val filterLess = SessionFilterable.LESS_THAN_NET_RESULT
filterLess.valueMap = mapOf("net" to 400.0) filterLess.valueMap = mapOf("value" to 400.0)
val sessions = FilterManager().filter( val sessions = FilterManager().filter(
realm, realm,
Session::class.java, Session::class.java,
arrayListOf(filterLess, filterMore) arrayListOf(filterMore, filterLess)
) )
Assert.assertEquals(1, sessions.size) Assert.assertEquals(1, sessions.size)

@ -70,6 +70,64 @@ class PokerAnalyticsApplication : Application() {
} }
} }
//
// private fun createFakeStats() {
//
// val buyinList = arrayListOf(100.0, 200.0, 300.0, 500.0, 1000.0, 2000.0)
// val resultsList = arrayListOf(
// -2500.0, -2000.0, -1500.0, -1000.0, -500.0, 200.0, 1000.0, 1500.0, 2500.0
// )
//
// val commitFrequency = 100
//
// Thread() {
//
// try {
//
// val realm = Realm.getDefaultInstance()
//
// // Test endedSessions
// val pstats = realm.where<ComputableResult>().findAll()
// if (pstats.size < 10) {
//
// val numberOfSessions = 2000
// Timber.d("*** Start creating ${numberOfSessions} fake computables...")
//
// val s = Date()
//
// realm.beginTransaction()
//
// for (index in 0..numberOfSessions) {
//
// if (index % commitFrequency == 0) {
// Timber.d("****** committing at ${index} computables...")
// realm.commitTransaction()
// realm.beginTransaction()
// }
//
// val ps = realm.createObject(ComputableResult::class.java)
// ps.ratedBuyin = buyinList.random()
// ps.ratedNet = resultsList.random()
//
// }
//
// realm.commitTransaction()
//
// val e = Date()
// val duration = (e.time - s.time) / 1000.0
// Timber.d("*** ended in ${duration} seconds")
//
// }
//
// realm.close()
//
// } catch (e: Exception) {
// Timber.e(e)
// }
//
// }.start()
//
// }
private fun createFakeSessions() { private fun createFakeSessions() {
@ -92,8 +150,8 @@ 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 = 2000
Timber.d("*** Start creating ${numberOfSessions} fake sessions...") Timber.d("*** Start creating ${numberOfSessions} fake computables...")
val s = Date() val s = Date()
@ -102,7 +160,7 @@ class PokerAnalyticsApplication : Application() {
for (index in 0..numberOfSessions) { for (index in 0..numberOfSessions) {
if (index % commitFrequency == 0) { if (index % commitFrequency == 0) {
Timber.d("****** committing at ${index} sessions...") Timber.d("****** committing at ${index} computables...")
realm.commitTransaction() realm.commitTransaction()
realm.beginTransaction() realm.beginTransaction()
} }

@ -1,7 +1,7 @@
package net.pokeranalytics.android.calculus package net.pokeranalytics.android.calculus
import net.pokeranalytics.android.calculus.Stat.* import net.pokeranalytics.android.calculus.Stat.*
import net.pokeranalytics.android.model.realm.Session import net.pokeranalytics.android.calculus.interfaces.Computable
import net.pokeranalytics.android.model.realm.SessionSet import net.pokeranalytics.android.model.realm.SessionSet
import timber.log.Timber import timber.log.Timber
import java.util.* import java.util.*
@ -66,7 +66,7 @@ class Calculator {
/** /**
* 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<ComputableGroup>, options: Options): List<ComputedResults> {
val computedResults = mutableListOf<ComputedResults>() val computedResults = mutableListOf<ComputedResults>()
groups.forEach { group -> groups.forEach { group ->
@ -75,7 +75,7 @@ class Calculator {
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.comparedComputables
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
@ -94,13 +94,13 @@ class Calculator {
return computedResults return computedResults
} }
// fun compute(sessionGroup: SessionGroup, options: Options): ComputedResults { // fun compute(sessionGroup: ComputableGroup, options: Options): ComputedResults {
// //
// var sum: Double = 0.0 // var sum: Double = 0.0
// val sessions: List<SessionInterface> = sessionGroup.sessions // val computables: List<SessionInterface> = sessionGroup.computables
// val results: ComputedResults = ComputedResults(sessionGroup) // val results: ComputedResults = ComputedResults(sessionGroup)
// //
// sessions.forEach { s -> // computables.forEach { s ->
// sum += s.ratedNet // sum += s.ratedNet
// } // }
// //
@ -117,34 +117,34 @@ class Calculator {
/** /**
* Computes stats for a SessionSet * Computes stats for a SessionSet
*/ */
fun compute(sessionGroup: SessionGroup, options: Options): ComputedResults { fun compute(computableGroup: ComputableGroup, options: Options): ComputedResults {
Timber.d(">>>> Start computing group ${sessionGroup.name}, ${sessionGroup.sessions.size} sessions") Timber.d(">>>> Start computing group ${computableGroup.name}, ${computableGroup.computables.size} computables")
val sessions: List<Session> = sessionGroup.sessions val computables: List<Computable> = computableGroup.computables
val sessionSets = sessionGroup.sessions.mapNotNull { it.sessionSet }.toHashSet() val sessionSets = computableGroup.computables.mapNotNull { it.sessionSet }.toHashSet()
val results: ComputedResults = ComputedResults(sessionGroup) val results: ComputedResults = ComputedResults(computableGroup)
var sum: Double = 0.0 var sum: Double = 0.0
var totalHands: Double = 0.0 var totalHands: Double = 0.0
var bbSum: Double = 0.0 var bbSum: Double = 0.0
var bbSessionCount: Int = 0 var bbSessionCount: Int = 0
var winningSessionCount: Int = 0 // sessions.filter { it.value >= 0.0 }.size var winningSessionCount: Int = 0 // computables.filter { it.value >= 0.0 }.size
var totalBuyin = 0.0 var totalBuyin = 0.0
// Compute for each session // Compute for each session
var index: Int = 0 var index: Int = 0
sessions.forEach { s -> computables.forEach { s ->
index++; index++;
val result = s.result!! // ok to crash to see problems // val result = s.result!! // ok to crash to see problems
sum += result.ratedNet sum += s.ratedNet
bbSum += s.bbNetResult bbSum += s.bbNetResult
bbSessionCount += s.hasBigBlind bbSessionCount += s.hasBigBlind
winningSessionCount = result.isPositive winningSessionCount += s.isPositive
totalBuyin += s.buyin totalBuyin += s.ratedBuyin
totalHands += s.estimatedHands totalHands += s.estimatedHands
when (options.evolutionValues) { when (options.evolutionValues) {
@ -212,10 +212,10 @@ class Calculator {
} }
var average = 0.0 var average = 0.0
if (sessions.size > 0) { if (computables.size > 0) {
average = sum / sessions.size.toDouble() average = sum / computables.size.toDouble()
val winRatio = winningSessionCount.toDouble() / sessions.size.toDouble() val winRatio = winningSessionCount.toDouble() / computables.size.toDouble()
val avgBuyin = totalBuyin / sessions.size val avgBuyin = totalBuyin / computables.size
results.addStats( results.addStats(
setOf( setOf(
@ -242,7 +242,7 @@ class Calculator {
ComputedStat(NETRESULT, sum), ComputedStat(NETRESULT, sum),
ComputedStat(DURATION, duration), ComputedStat(DURATION, duration),
ComputedStat(NUMBER_OF_SETS, sessionSets.size.toDouble()), ComputedStat(NUMBER_OF_SETS, sessionSets.size.toDouble()),
ComputedStat(NUMBER_OF_GAMES, sessions.size.toDouble()), ComputedStat(NUMBER_OF_GAMES, computables.size.toDouble()),
ComputedStat(HOURLY_RATE_BB, bbSum / duration), ComputedStat(HOURLY_RATE_BB, bbSum / duration),
ComputedStat(AVERAGE_NET_BB, bbSum / bbSessionCount), ComputedStat(AVERAGE_NET_BB, bbSum / bbSessionCount),
ComputedStat(HANDS_PLAYED, totalHands) ComputedStat(HANDS_PLAYED, totalHands)
@ -268,12 +268,12 @@ class Calculator {
// Session // Session
var stdSum: Double = 0.0 var stdSum: Double = 0.0
var stdBBper100HandsSum: Double = 0.0 var stdBBper100HandsSum: Double = 0.0
sessions.forEach { session -> computables.forEach { session ->
stdSum += Math.pow(session.result!!.ratedNet - average, 2.0) stdSum += Math.pow(session.ratedNet - average, 2.0)
stdBBper100HandsSum += Math.pow(session.bbPer100Hands - bbPer100Hands, 2.0) stdBBper100HandsSum += Math.pow(session.bbPer100Hands - bbPer100Hands, 2.0)
} }
val standardDeviation: Double = Math.sqrt(stdSum / sessions.size) val standardDeviation: Double = Math.sqrt(stdSum / computables.size)
val standardDeviationBBper100Hands: Double = Math.sqrt(stdBBper100HandsSum / sessions.size) val standardDeviationBBper100Hands: Double = Math.sqrt(stdBBper100HandsSum / computables.size)
// Session Set // Session Set
var hourlyStdSum: Double = 0.0 var hourlyStdSum: Double = 0.0

@ -1,11 +1,11 @@
package net.pokeranalytics.android.calculus package net.pokeranalytics.android.calculus
import net.pokeranalytics.android.model.realm.Session import net.pokeranalytics.android.calculus.interfaces.Computable
/** /**
* A sessionGroup of computable items identified by a name * A sessionGroup of computable items identified by a name
*/ */
class SessionGroup(name: String, sessions: List<Session>, stats: List<Stat>? = null) { class ComputableGroup(name: String, computables: List<Computable>, stats: List<Stat>? = null) {
/** /**
* The display name of the group * The display name of the group
@ -15,7 +15,7 @@ class SessionGroup(name: String, sessions: List<Session>, stats: List<Stat>? = n
/** /**
* The list of endedSessions to compute * The list of endedSessions to compute
*/ */
var sessions: List<Session> = sessions var computables: List<Computable> = computables
/** /**
* The list of stats to display * The list of stats to display
@ -25,7 +25,7 @@ class SessionGroup(name: String, sessions: List<Session>, stats: List<Stat>? = n
/** /**
* A subgroup used to compute stat variation * A subgroup used to compute stat variation
*/ */
var comparedSessions: SessionGroup? = null var comparedComputables: ComputableGroup? = null
/** /**
* The computed stats of the comparable sessionGroup * The computed stats of the comparable sessionGroup
@ -34,12 +34,12 @@ class SessionGroup(name: String, sessions: List<Session>, stats: List<Stat>? = n
} }
class ComputedResults(group: SessionGroup) { class ComputedResults(group: ComputableGroup) {
/** /**
* The session group used to computed the stats * The session group used to computed the stats
*/ */
var group: SessionGroup = group var group: ComputableGroup = group
// The computed stats of the sessionGroup // The computed stats of the sessionGroup
private var _computedStats: MutableMap<Stat, ComputedStat> = mutableMapOf() private var _computedStats: MutableMap<Stat, ComputedStat> = mutableMapOf()

@ -0,0 +1,40 @@
package net.pokeranalytics.android.calculus.bankroll
import io.realm.Realm
import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.model.realm.Transaction
class BankrollCalculator {
companion object {
fun computeReport(setup: BankrollReportSetup) : BankrollReport {
val realm = Realm.getDefaultInstance()
val report = BankrollReport(setup)
val sessionQuery = realm.where(Session::class.java)
if (setup.bankroll != null) {
sessionQuery.equalTo("bankroll.id", setup.bankroll.id)
}
val sessions = sessionQuery.findAll()
val transactionQuery = realm.where(Transaction::class.java)
if (setup.bankroll != null) {
transactionQuery.equalTo("bankroll.id", setup.bankroll.id).findAll()
}
val transactions = transactionQuery.findAll()
val sessionsNet = sessions.sum("result.net")
val transactionsNet = transactions.sum("value")
transactions.forEach {
report.addTransaction(it)
}
return report
}
}
}

@ -0,0 +1,122 @@
package net.pokeranalytics.android.calculus.bankroll
import net.pokeranalytics.android.calculus.interfaces.DatableValue
import net.pokeranalytics.android.model.realm.Bankroll
import net.pokeranalytics.android.model.realm.Transaction
import java.util.*
import kotlin.collections.HashMap
/**
* A class describing the parameters required to launch a bankroll report
*
*/
class BankrollReportSetup(bankroll: Bankroll?, from: Date? = null, to: Date? = null) {
/**
* The bankroll to compute. If null, the virtual global bankroll
*/
val bankroll = bankroll
/**
* The start of the report
*/
val from = from
/**
* The end of the report
*/
val to = to
}
class TransactionBucket(useRate: Boolean = false) {
var transactions: MutableList<Transaction> = mutableListOf()
private set
var total: Double = 0.0
private set
var useRate: Boolean = useRate
private set
fun addTransaction(transaction: Transaction) {
this.transactions.add(transaction)
var rate = 1.0
if (this.useRate) {
rate = transaction.bankroll?.currency?.rate ?: 1.0
}
val ratedAmount = rate * transaction.amount
this.total += ratedAmount
}
}
class BRGraphPoint {
var value: Double = 0.0
var variation: Double = 0.0
var date: Date? = null
}
class BankrollReport(setup: BankrollReportSetup) {
/**
* The setup used to compute the report
*/
var setup: BankrollReportSetup = setup
/**
* The value of the bankroll
*/
var total: Double = 0.0
private set
/**
* The net result from poker computables
*/
var netResult: Double = 0.0
private set
/**
* The difference between withdrawals and deposits
*/
var netBanked: Double = 0.0
private set
/**
* The risk of ruin
*/
var riskOfRuin: Double = 0.0
private set
var transactions: List<Transaction> = mutableListOf()
private set
var transactionBuckets: HashMap<String, TransactionBucket> = HashMap()
var evolutionPoints: Array<BRGraphPoint> = arrayOf()
var evolutionItems: Array<DatableValue> = arrayOf()
fun addTransaction(transaction: Transaction) {
transaction.type?.let { type ->
var bucket = this.transactionBuckets[type.id]
if (bucket == null) {
val b = TransactionBucket(this.setup.bankroll == null)
this.transactionBuckets[type.id] = b
bucket = b
}
bucket.addTransaction(transaction)
} ?: run {
throw Exception("Transaction has no type")
}
}
}

@ -0,0 +1,17 @@
package net.pokeranalytics.android.calculus.interfaces
import net.pokeranalytics.android.model.realm.SessionSet
interface Computable {
var ratedNet: Double
var bbNetResult: Double
var hasBigBlind: Int
var isPositive: Int
var ratedBuyin: Double
var estimatedHands: Double
var bbPer100Hands: Double
var sessionSet: SessionSet?
}

@ -0,0 +1,11 @@
package net.pokeranalytics.android.calculus.interfaces
import java.util.*
interface Datable {
var date: Date
}
interface DatableValue : Datable {
var value: Double
}

@ -2,4 +2,4 @@ package net.pokeranalytics.android.model.filter
enum class FilterComponent { enum class FilterComponent {
} }

@ -36,7 +36,7 @@ class FilterManager {
fun filter(realm:Realm, relatedEntity: Class<out RealmObject>, queries:List<Filterable>): RealmResults<*> { fun filter(realm:Realm, relatedEntity: Class<out RealmObject>, queries:List<Filterable>): RealmResults<*> {
var realmQuery : RealmQuery<out RealmObject> = realm.where(relatedEntity) var realmQuery : RealmQuery<out RealmObject> = realm.where(relatedEntity)
queries.forEach { queries.forEach {
realmQuery = (it.filter(realmQuery)).and() realmQuery = (it.filter(realmQuery))
} }
return realmQuery.findAll() return realmQuery.findAll()
} }

@ -6,7 +6,7 @@ import net.pokeranalytics.android.exceptions.FilterValueMapException
import net.pokeranalytics.android.model.filter.interfaces.Filterable import net.pokeranalytics.android.model.filter.interfaces.Filterable
import net.pokeranalytics.android.model.realm.Session import net.pokeranalytics.android.model.realm.Session
enum class SessionFilterable(private var fieldName:String? = null): Filterable { enum class SessionFilterable(private var fieldName:String? = null, private var subType:SubType? = null): Filterable {
LIVE, LIVE,
CASH, CASH,
ONLINE, ONLINE,
@ -19,13 +19,33 @@ enum class SessionFilterable(private var fieldName:String? = null): Filterable {
LOCATION("location.id"), LOCATION("location.id"),
LIMIT("limit"), LIMIT("limit"),
TABLE_SIZE("tableSize"), TABLE_SIZE("tableSize"),
NUMBER_OF_TABLE("numberOfTable"),
TOURNAMENT_TYPE("tournamentType"), TOURNAMENT_TYPE("tournamentType"),
BLINDS, BLINDS,
LESS_THAN_NET_RESULT, MORE_NUMBER_OF_TABLE(Field.NUMBER_OF_TABLE.fieldName, SubType.MORE),
MORE_THAN_NET_RESULT, LESS_NUMBER_OF_TABLE(Field.NUMBER_OF_TABLE.fieldName, SubType.LESS),
BETWEEN_NUMBER_OF_TABLE(Field.NUMBER_OF_TABLE.fieldName, SubType.BETWEEN),
MORE_THAN_NET_RESULT(Field.NET_RESULT.fieldName, SubType.MORE),
LESS_THAN_NET_RESULT(Field.NET_RESULT.fieldName, SubType.LESS),
MORE_THAN_BUY_IN(Field.BUY_IN.fieldName, SubType.MORE),
LESS_THAN_BUY_IN(Field.BUY_IN.fieldName, SubType.LESS),
MORE_THAN_CASH_OUT(Field.CASH_OUT.fieldName, SubType.MORE),
LESS_THAN_CASH_OUT(Field.CASH_OUT.fieldName, SubType.LESS),
MORE_THAN_TIPS(Field.TIPS.fieldName, SubType.MORE),
LESS_THAN_TIPS(Field.TIPS.fieldName, SubType.LESS),
MORE_THAN_NUMBER_OF_PLAYER(Field.NUMBER_OF_PLAYER.fieldName, SubType.MORE),
LESS_THAN_NUMBER_OF_PLAYER(Field.NUMBER_OF_PLAYER.fieldName, SubType.LESS),
BETWEEN_NUMBER_OF_PLAYER(Field.NUMBER_OF_PLAYER.fieldName, SubType.BETWEEN),
MORE_THAN_TOURNAMENT_FEE(Field.NET_RESULT.fieldName, SubType.MORE),
LESS_THAN_TOURNAMENT_FEE(Field.NET_RESULT.fieldName, SubType.LESS),
BETWEEN_TOURNAMENT_FEE(Field.TOURNAMENT_FEE.fieldName, SubType.BETWEEN),
; ;
enum class SubType {
BETWEEN,
MORE,
LESS;
}
private enum class Field(var fieldName:String) { private enum class Field(var fieldName:String) {
LIVE("bankroll.live"), LIVE("bankroll.live"),
CASH("type"), CASH("type"),
@ -35,12 +55,13 @@ enum class SessionFilterable(private var fieldName:String? = null): Filterable {
SMALL_BLIND("cgSmallBlind"), SMALL_BLIND("cgSmallBlind"),
COMMENT("comment"), COMMENT("comment"),
TOURNAMENT_FEATURES("tournamentFeatures.id"), TOURNAMENT_FEATURES("tournamentFeatures.id"),
TOURNAMENT_NUMBER_OF_PLAYER("tournamentNumberOfPlayers"), NET_RESULT("result.ratedNet"),
TOURNAMENT_ENTRY_FEE("tournamentEntryFee"), BUY_IN("result.buyin"),
RESULT_BUY_IN("result.buyin"), CASH_OUT("result.cashout"),
RESULT_CASHED_OUT("result.cashout"), TIPS("result.tips"),
RESULT_NET("result.ratedNet"), NUMBER_OF_TABLE("numberOfTable"),
RESULT_TIPS("result.tips"), NUMBER_OF_PLAYER("tournamentNumberOfPlayers"),
TOURNAMENT_FEE("tournamentEntryFee"),
; ;
} }
@ -48,21 +69,46 @@ enum class SessionFilterable(private var fieldName:String? = null): Filterable {
override val filterValuesExceptedKeys : Array<String>? override val filterValuesExceptedKeys : Array<String>?
get() { get() {
this.subType?.let {
return when (it) {
SubType.BETWEEN -> arrayOf("leftValue", "rightValue")
else -> arrayOf("value")
}
}
return when (this) { return when (this) {
BANKROLL, GAME, LOCATION, ANY_TOURNAMENT_FEATURES, ALL_TOURNAMENT_FEATURES -> arrayOf("ids") BANKROLL, GAME, LOCATION, ANY_TOURNAMENT_FEATURES, ALL_TOURNAMENT_FEATURES -> arrayOf("ids")
LIMIT, TOURNAMENT_TYPE, TABLE_SIZE, NUMBER_OF_TABLE -> arrayOf("values") LIMIT, TOURNAMENT_TYPE, TABLE_SIZE -> arrayOf("values")
BLINDS -> arrayOf("map") BLINDS -> arrayOf("map")
MORE_THAN_NET_RESULT, LESS_THAN_NET_RESULT -> arrayOf("net")
else -> null else -> null
} }
} }
var between: Boolean = false
var moreThan: Boolean = false
var lessThan: Boolean = false
var strict: Boolean = false
override fun filter(realmQuery: RealmQuery<out RealmObject>): RealmQuery<out RealmObject> { override fun filter(realmQuery: RealmQuery<out RealmObject>): RealmQuery<out RealmObject> {
this.subType?.let {subType ->
this.fieldName?.let {
return when (subType) {
SubType.LESS -> {
val value: Double by filterValues
println("filter test less")
realmQuery.lessThanOrEqualTo(it, value)
}
SubType.MORE -> {
println("filter test more")
val value: Double by filterValues
realmQuery.greaterThanOrEqualTo(it, value)
}
SubType.BETWEEN -> {
val leftValue: Double by filterValues
val rightValue: Double by filterValues
realmQuery.between(it, leftValue, rightValue)
}
}
} ?: run {
throw FilterValueMapException("fieldName is missing")
}
}
return when (this) { return when (this) {
LIVE -> realmQuery.equalTo(Field.LIVE.fieldName, true) LIVE -> realmQuery.equalTo(Field.LIVE.fieldName, true)
CASH -> realmQuery.equalTo(Field.CASH.fieldName, Session.Type.CASH_GAME.ordinal) CASH -> realmQuery.equalTo(Field.CASH.fieldName, Session.Type.CASH_GAME.ordinal)
@ -87,7 +133,7 @@ enum class SessionFilterable(private var fieldName:String? = null): Filterable {
throw FilterValueMapException("fieldName is missing") throw FilterValueMapException("fieldName is missing")
} }
} }
LIMIT, TOURNAMENT_TYPE, TABLE_SIZE, NUMBER_OF_TABLE -> { LIMIT, TOURNAMENT_TYPE, TABLE_SIZE -> {
val values : Array<Int?>? by filterValues val values : Array<Int?>? by filterValues
this.fieldName?.let { this.fieldName?.let {
realmQuery.`in`(it, values) realmQuery.`in`(it, values)
@ -95,13 +141,6 @@ enum class SessionFilterable(private var fieldName:String? = null): Filterable {
throw FilterValueMapException("fieldName is missing") throw FilterValueMapException("fieldName is missing")
} }
} }
MORE_THAN_NET_RESULT, LESS_THAN_NET_RESULT -> {
val net : Double by filterValues
if (this == LESS_THAN_NET_RESULT) {
realmQuery.not()
}
realmQuery.greaterThanOrEqualTo(Field.RESULT_NET.fieldName, net)
}
BLINDS -> { BLINDS -> {
val map : Array<Map<String,Any?>> by filterValues val map : Array<Map<String,Any?>> by filterValues
val expectedSubKeys = arrayOf("sb", "bb", "code") val expectedSubKeys = arrayOf("sb", "bb", "code")
@ -142,6 +181,9 @@ enum class SessionFilterable(private var fieldName:String? = null): Filterable {
} }
realmQuery realmQuery
} }
else -> {
realmQuery
}
} }
} }
} }

@ -0,0 +1,51 @@
package net.pokeranalytics.android.model.realm
import io.realm.RealmObject
import io.realm.RealmResults
import io.realm.annotations.Ignore
import io.realm.annotations.LinkingObjects
import net.pokeranalytics.android.calculus.interfaces.Computable
open class ComputableResult : RealmObject(), Computable {
override var ratedNet: Double = 0.0
override var bbNetResult: Double = 0.0
override var hasBigBlind: Int = 0
override var isPositive: Int = 0
override var ratedBuyin: Double = 0.0
override var estimatedHands: Double = 0.0
override var bbPer100Hands: Double = 0.0
override var sessionSet: SessionSet? = null
@LinkingObjects("computableResult")
private val sessions: RealmResults<Session>? = null
@Ignore
val session: Session? = this.sessions?.firstOrNull()
fun updateWith(session: Session) {
val rate = session.bankroll?.currency?.rate ?: 1.0
session.result?.let { result ->
this.ratedNet = result.net * rate
this.isPositive = result.isPositive
this.ratedBuyin = (result.buyin ?: 0.0) * rate
}
this.bbNetResult = session.bbNetResult
this.hasBigBlind = session.hasBigBlind
this.estimatedHands = session.estimatedHands
this.bbPer100Hands = session.bbPer100Hands
this.sessionSet = session.sessionSet
}
}

@ -15,5 +15,24 @@ open class Currency : RealmObject() {
// The rate of the currency with the main currency // The rate of the currency with the main currency
var rate: Double? = null var rate: Double? = null
set(value) {
field = value
val rate = value ?: 1.0
// could be async
val cResults = this.realm.where(ComputableResult::class.java).equalTo("session.bankroll.currency", this.id).findAll()
cResults.forEach { computable ->
computable.session?.result?.net?.let {
computable.ratedNet = it * rate
}
computable.session?.result?.buyin?.let {
computable.ratedBuyin = it * rate
}
}
}
} }

@ -2,47 +2,52 @@ package net.pokeranalytics.android.model.realm
import io.realm.RealmList import io.realm.RealmList
import io.realm.RealmObject import io.realm.RealmObject
import io.realm.RealmResults
import io.realm.annotations.Ignore
import io.realm.annotations.LinkingObjects
import io.realm.annotations.RealmClass import io.realm.annotations.RealmClass
@RealmClass @RealmClass
open class Result : RealmObject() { open class Result : RealmObject() {
// The buyin amount /**
* The buyin amount
*/
var buyin: Double? = null var buyin: Double? = null
set(value) { set(value) {
field = value field = value
this.computeNet() this.computeNet()
} }
// the cashed out amount /**
* The cashed out amount
*/
var cashout: Double? = null var cashout: Double? = null
set(value) { set(value) {
field = value field = value
this.computeNet() this.computeNet()
} }
// Tips
var tips: Double? = null
// The net result
var netResult: Double? = null
set(value) {
field = value
this.computeNet()
}
/** /**
* The pre-computed net (readonly) * The net result
*/ */
var net: Double = 0.0 var netResult: Double? = null
private set set(value) {
field = value
this.computeNet()
}
/** /**
* The pre-computed rated net (readonly) * The pre-computed net (readonly)
*/ */
var ratedNet: Double = 0.0 var net: Double = 0.0
private set private set
/**
* Tips
*/
var tips: Double? = null
// The transactions associated with the Result, impacting the result // The transactions associated with the Result, impacting the result
var transactions: RealmList<Transaction> = RealmList() var transactions: RealmList<Transaction> = RealmList()
set(value) { set(value) {
@ -53,23 +58,17 @@ open class Result : RealmObject() {
// The tournament final position, if applicable // The tournament final position, if applicable
var tournamentFinalPosition: Int? = null var tournamentFinalPosition: Int? = null
/** @LinkingObjects("result")
* The automatically Realm-updated sessions list private val sessions: RealmResults<Session>? = null
* Should contain only one element
*/
// @LinkingObjects("result")
// private val sessions: RealmResults<Session>? = null
/** @Ignore
* The associated Session val session: Session? = this.sessions?.firstOrNull()
*/
// @Ignore
// val session: Session? = this.sessions?.firstOrNull()
/** /**
* Returns 1 if the session is positive * Returns 1 if the session is positive
*/ */
var isPositive: Int = 0 @Ignore
val isPositive: Int = if (this.net >= 0.0) 1 else 0
// Computes the Net // Computes the Net
private fun computeNet() { private fun computeNet() {
@ -82,11 +81,11 @@ open class Result : RealmObject() {
val cashOut = this.cashout ?: 0.0 val cashOut = this.cashout ?: 0.0
this.net = cashOut - buyin + transactionsSum this.net = cashOut - buyin + transactionsSum
} }
this.ratedNet = this.net * 1.0
this.isPositive = if (this.ratedNet >= 0.0) 1 else 0 // Update ComputableResult
this.session?.updateComputableResult()
} }
// private var rate: Double = (this.session?.bankroll?.currency?.rate ?: 1.0) // @todo tips?
// @todo tips?
} }

@ -5,6 +5,7 @@ import io.realm.Realm
import io.realm.RealmList import io.realm.RealmList
import io.realm.RealmObject import io.realm.RealmObject
import io.realm.annotations.Ignore import io.realm.annotations.Ignore
import io.realm.annotations.Index
import io.realm.annotations.PrimaryKey import io.realm.annotations.PrimaryKey
import io.realm.kotlin.where import io.realm.kotlin.where
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
@ -39,6 +40,18 @@ import kotlin.collections.ArrayList
open class Session : RealmObject(), Manageable, StaticRowRepresentableDataSource, RowRepresentable, Timed, open class Session : RealmObject(), Manageable, StaticRowRepresentableDataSource, RowRepresentable, Timed,
TimeFilterable { TimeFilterable {
// @Ignore
// var rate: Double = 0.0
// get() = this.bankroll?.currency?.rate ?: 0.0
//
// @Ignore
// override var ratedNet: Double = 0.0
// get() = this.result!!.net * this.rate
//
// @Ignore
// override var isPositive: Int = 0
// get() = this.result!!.isPositive
enum class Type { enum class Type {
CASH_GAME, CASH_GAME,
TOURNAMENT TOURNAMENT
@ -48,6 +61,7 @@ open class Session : RealmObject(), Manageable, StaticRowRepresentableDataSource
fun newInstance(realm: Realm, isTournament: Boolean, bankroll: Bankroll? = null): Session { fun newInstance(realm: Realm, isTournament: Boolean, bankroll: Bankroll? = null): Session {
val session = Session() val session = Session()
session.result = Result() session.result = Result()
session.computableResult = ComputableResult()
if (bankroll != null) { if (bankroll != null) {
session.bankroll = bankroll session.bankroll = bankroll
} else { } else {
@ -69,6 +83,11 @@ open class Session : RealmObject(), Manageable, StaticRowRepresentableDataSource
// The result of the main user // The result of the main user
var result: Result? = null var result: Result? = null
/**
* Optimized result for faster stats
*/
var computableResult: ComputableResult? = null
// Timed interface // Timed interface
override var dayOfWeek : Int? = null override var dayOfWeek : Int? = null
@ -84,23 +103,24 @@ open class Session : RealmObject(), Manageable, StaticRowRepresentableDataSource
this.updateTimeParameter(field) this.updateTimeParameter(field)
this.computeNetDuration() this.computeNetDuration()
this.computeStats()
// nullifies endate when setting the start date after the end date // nullifies endate when setting the start date after the end date
if (value != null && this.endDate != null && value.after(this.endDate)) { if (value != null && this.endDate != null && value.after(this.endDate)) {
this.endDate = null this.endDate = null
} }
this.dateChanged() this.dateChanged()
this.computeStats()
} }
/** /**
* the end date of the session * the end date of the session
*/ */
@Index
var endDate: Date? = null var endDate: Date? = null
set(value) { set(value) {
field = value field = value
this.computeNetDuration() this.computeNetDuration()
this.computeStats()
this.dateChanged() this.dateChanged()
this.computeStats()
} }
/** /**
@ -175,6 +195,7 @@ open class Session : RealmObject(), Manageable, StaticRowRepresentableDataSource
set(value) { set(value) {
this.hasBigBlind = if (value != null) 1 else 0 this.hasBigBlind = if (value != null) 1 else 0
field = value field = value
this.updateComputableResult()
} }
// Tournament // Tournament
@ -204,6 +225,7 @@ open class Session : RealmObject(), Manageable, StaticRowRepresentableDataSource
} else if (this.sessionSet != null) { } else if (this.sessionSet != null) {
SessionSetManager.removeFromTimeline(this) SessionSetManager.removeFromTimeline(this)
} }
this.updateComputableResult()
this.updateRowRepresentation() this.updateRowRepresentation()
} }
@ -267,6 +289,15 @@ open class Session : RealmObject(), Manageable, StaticRowRepresentableDataSource
this.computeEstimatedHands() this.computeEstimatedHands()
this.computeBBNetResult() this.computeBBNetResult()
this.computeBBPer100Hands() this.computeBBPer100Hands()
this.updateComputableResult()
}
fun updateComputableResult() {
this.computableResult?.let {
it.updateWith(this)
} ?: run {
throw IllegalStateException("Session should always have a Light Result")
}
} }
/** /**
@ -304,7 +335,7 @@ open class Session : RealmObject(), Manageable, StaticRowRepresentableDataSource
private set private set
@Ignore @Ignore
var buyin: Double = 0.0 var ratedBuyin: Double = 0.0
get() { get() {
this.result?.let { result -> this.result?.let { result ->
result.buyin?.let { result.buyin?.let {
@ -481,7 +512,7 @@ open class Session : RealmObject(), Manageable, StaticRowRepresentableDataSource
} }
@Ignore @Ignore
private var rowRepresentationForCurrentState : List<RowRepresentable> = this.updatedRowRepresentationForCurrentState() private var rowRepresentationForCurrentState : List<RowRepresentable> = mutableListOf()
private fun updatedRowRepresentationForCurrentState(): List<RowRepresentable> { private fun updatedRowRepresentationForCurrentState(): List<RowRepresentable> {
val rows = ArrayList<RowRepresentable>() val rows = ArrayList<RowRepresentable>()
@ -550,7 +581,6 @@ open class Session : RealmObject(), Manageable, StaticRowRepresentableDataSource
override fun adapterRows(): List<RowRepresentable>? { override fun adapterRows(): List<RowRepresentable>? {
return this.rowRepresentationForCurrentState return this.rowRepresentationForCurrentState
} }
override fun boolForRow(row: RowRepresentable): Boolean { override fun boolForRow(row: RowRepresentable): Boolean {
@ -635,7 +665,7 @@ open class Session : RealmObject(), Manageable, StaticRowRepresentableDataSource
SessionRow.BUY_IN -> row.editingDescriptors(mapOf( SessionRow.BUY_IN -> row.editingDescriptors(mapOf(
"bb" to cgBigBlind, "bb" to cgBigBlind,
"fee" to this.tournamentEntryFee, "fee" to this.tournamentEntryFee,
"buyin" to buyin "ratedBuyin" to ratedBuyin
)) ))
SessionRow.BREAK_TIME -> row.editingDescriptors(mapOf()) SessionRow.BREAK_TIME -> row.editingDescriptors(mapOf())
SessionRow.CASHED_OUT, SessionRow.PRIZE, SessionRow.NET_RESULT -> row.editingDescriptors(mapOf( SessionRow.CASHED_OUT, SessionRow.PRIZE, SessionRow.NET_RESULT -> row.editingDescriptors(mapOf(

@ -68,7 +68,7 @@ open class SessionSet : RealmObject(), Timed {
val sessions: RealmResults<Session>? = null val sessions: RealmResults<Session>? = null
@Ignore @Ignore
val ratedNet: Double = this.sessions?.sumByDouble { it.result!!.ratedNet } ?: 0.0 val ratedNet: Double = this.sessions?.sumByDouble { it.computableResult!!.ratedNet } ?: 0.0
@Ignore @Ignore
val hourlyRate: Double = this.ratedNet / this.hourlyDuration val hourlyRate: Double = this.ratedNet / this.hourlyDuration

@ -10,8 +10,9 @@ import kotlinx.android.synthetic.main.fragment_stats.*
import kotlinx.coroutines.* import kotlinx.coroutines.*
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
import net.pokeranalytics.android.calculus.* import net.pokeranalytics.android.calculus.*
import net.pokeranalytics.android.calculus.interfaces.Computable
import net.pokeranalytics.android.model.StatRepresentable import net.pokeranalytics.android.model.StatRepresentable
import net.pokeranalytics.android.model.realm.Session import net.pokeranalytics.android.model.realm.ComputableResult
import net.pokeranalytics.android.ui.adapter.DisplayDescriptor import net.pokeranalytics.android.ui.adapter.DisplayDescriptor
import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter
import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource
@ -97,7 +98,7 @@ class StatsFragment : SessionObserverFragment(), StaticRowRepresentableDataSourc
// Override // Override
override fun sessionsChanged() { override fun sessionsChanged() {
// this.launchStatComputation() this.launchStatComputation()
this.statsAdapter.notifyDataSetChanged() this.statsAdapter.notifyDataSetChanged()
} }
@ -132,26 +133,6 @@ class StatsFragment : SessionObserverFragment(), StaticRowRepresentableDataSourc
private fun launchStatComputation() { private fun launchStatComputation() {
// Thread() {
//// var results = listOf<ComputedResults>()
// val s = Date()
// Timber.d(">>> start...")
//
// val results = createSessionGroupsAndStartCompute()
//
// val e = Date()
// val duration = (e.time - s.time) / 1000.0
// Timber.d(">>> ended in ${duration} seconds")
//
//
// val mainHandler = Handler(Looper.getMainLooper())
// val runnable = Runnable {
// showResults(results)
// }
// mainHandler.post(runnable)
//
// }.start()
GlobalScope.launch(coroutineContext) { GlobalScope.launch(coroutineContext) {
var results = listOf<ComputedResults>() var results = listOf<ComputedResults>()
@ -177,35 +158,36 @@ class StatsFragment : SessionObserverFragment(), StaticRowRepresentableDataSourc
private fun createSessionGroupsAndStartCompute() : List<ComputedResults> { private fun createSessionGroupsAndStartCompute() : List<ComputedResults> {
val cgSessions = mutableListOf<Session>() val cgSessions = mutableListOf<Computable>()
val tSessions = mutableListOf<Session>() val tSessions = mutableListOf<Computable>()
val s = Date() val s = Date()
val realm = Realm.getDefaultInstance() val realm = Realm.getDefaultInstance()
val allSessions = realm.where(Session::class.java).isNotNull("endDate").findAll() // val allSessions = realm.where(ComputableResult::class.java).findAll()
Timber.d(">>>>> number of sessions to compute = ${allSessions.size}") val allSessions = realm.where(ComputableResult::class.java).isNotNull("sessions.endDate").findAll()
Timber.d(">>>>> number of computables to compute = ${allSessions.size}")
val sessionsList = allSessions.toList()
val e = Date() val computableList = realm.copyFromRealm(allSessions)
val duration = (e.time - s.time) / 1000.0 realm.close()
Timber.d(">>> filtering in ${duration} seconds")
sessionsList.forEach { session -> computableList.forEach { session ->
if (session.isCashGame()) { if (true) { // @todo
cgSessions.add(session) cgSessions.add(session)
} else { } else {
tSessions.add(session) tSessions.add(session)
} }
} }
val e = Date()
val duration = (e.time - s.time) / 1000.0
Timber.d(">>> filtering in ${duration} seconds")
val allStats: List<Stat> = listOf(Stat.NETRESULT, Stat.HOURLY_RATE, Stat.AVERAGE, Stat.NUMBER_OF_SETS, Stat.AVERAGE_DURATION, Stat.DURATION) val allStats: List<Stat> = listOf(Stat.NETRESULT, Stat.HOURLY_RATE, Stat.AVERAGE, Stat.NUMBER_OF_SETS, Stat.AVERAGE_DURATION, Stat.DURATION)
val allSessionGroup = SessionGroup(stringAll, sessionsList, allStats) val allSessionGroup = ComputableGroup(getString(R.string.all), computableList, allStats)
val cgStats: List<Stat> = 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 cgStats: List<Stat> = 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(stringCashGame, cgSessions, cgStats) val cgSessionGroup = ComputableGroup(getString(R.string.cash_game), cgSessions, cgStats)
val tStats: List<Stat> = listOf(Stat.NETRESULT, Stat.HOURLY_RATE, Stat.ROI, Stat.WIN_RATIO, Stat.NUMBER_OF_GAMES, Stat.AVERAGE_BUYIN) val tStats: List<Stat> = listOf(Stat.NETRESULT, Stat.HOURLY_RATE, Stat.ROI, Stat.WIN_RATIO, Stat.NUMBER_OF_GAMES, Stat.AVERAGE_BUYIN)
val tSessionGroup = SessionGroup(stringTournament, tSessions, tStats) val tSessionGroup = ComputableGroup(getString(R.string.tournament), tSessions, tStats)
Timber.d(">>>>> Start computations...") Timber.d(">>>>> Start computations...")

@ -2,15 +2,15 @@ package net.pokeranalytics.android.ui.fragment.components
import io.realm.Realm import io.realm.Realm
import io.realm.RealmResults import io.realm.RealmResults
import net.pokeranalytics.android.model.realm.Session import net.pokeranalytics.android.model.realm.ComputableResult
open class SessionObserverFragment : PokerAnalyticsFragment() { open class SessionObserverFragment : PokerAnalyticsFragment() {
val endedSessions: RealmResults<Session> val endedSessions: RealmResults<ComputableResult>
init { init {
val realm = Realm.getDefaultInstance() val realm = Realm.getDefaultInstance()
this.endedSessions = realm.where(Session::class.java).isNotNull("endDate").findAll() this.endedSessions = realm.where(ComputableResult::class.java).isNotNull("sessions.endDate").findAll()
this.endedSessions.addChangeListener { _, _ -> this.endedSessions.addChangeListener { _, _ ->
this.sessionsChanged() this.sessionsChanged()
} }

@ -27,7 +27,7 @@ class ExampleUnitTest : RealmUnitTest() {
// override var estimatedHands: Double = 0.0 // override var estimatedHands: Double = 0.0
// override var bbNetResult: Double = 0.0 // override var bbNetResult: Double = 0.0
// override var bigBlindSessionCount: Int = 0 // 0 or 1 // override var bigBlindSessionCount: Int = 0 // 0 or 1
// override var buyin: Double = 0.0 // override var ratedBuyin: Double = 0.0
// //
// } // }
// //
@ -35,7 +35,7 @@ class ExampleUnitTest : RealmUnitTest() {
// fun testStats() { // fun testStats() {
// //
// val grades: List<Grade> = listOf(Grade(10.0), Grade(20.0)) // val grades: List<Grade> = listOf(Grade(10.0), Grade(20.0))
// val group = SessionGroup(name = "test", sessions = grades) // val group = ComputableGroup(name = "test", computables = grades)
// //
// val results: ComputedResults = Calculator.compute(group, Calculator.Options()) // val results: ComputedResults = Calculator.compute(group, Calculator.Options())
// //

Loading…
Cancel
Save