Change replayer drawing algo to draw only what is necessary

hh
Laurent 5 years ago
parent b19fa6823d
commit cb4206ea3a
  1. 9
      app/src/main/java/net/pokeranalytics/android/model/handhistory/Street.kt
  2. 3
      app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/HandHistoryFragment.kt
  3. 18
      app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/model/ActionList.kt
  4. 6
      app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/model/ComputedAction.kt
  5. 4
      app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/model/HandHistoryViewModel.kt
  6. 2
      app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/replayer/HandStep.kt
  7. 62
      app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/replayer/ReplayerConfiguration.kt
  8. 32
      app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/replayer/ReplayerView.kt
  9. 131
      app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/replayer/TableDrawer.kt

@ -5,7 +5,6 @@ import android.graphics.Canvas
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
import net.pokeranalytics.android.ui.modules.handhistory.replayer.HandStep import net.pokeranalytics.android.ui.modules.handhistory.replayer.HandStep
import net.pokeranalytics.android.ui.modules.handhistory.replayer.ReplayerConfiguration import net.pokeranalytics.android.ui.modules.handhistory.replayer.ReplayerConfiguration
import net.pokeranalytics.android.ui.modules.handhistory.replayer.TableDrawer
enum class Street : HandStep { enum class Street : HandStep {
PREFLOP, PREFLOP,
@ -40,9 +39,9 @@ enum class Street : HandStep {
return values()[this.ordinal + 1] return values()[this.ordinal + 1]
} }
override fun draw(configuration: ReplayerConfiguration, canvas: Canvas, context: Context) { // override fun draw(configuration: ReplayerConfiguration, canvas: Canvas, context: Context) {
TableDrawer.drawStreet(this, configuration, canvas, context) // TableDrawer.drawStreet(this, configuration, canvas, context)
} // }
override fun frames( override fun frames(
configuration: ReplayerConfiguration, configuration: ReplayerConfiguration,
@ -50,7 +49,7 @@ enum class Street : HandStep {
context: Context, context: Context,
update: () -> Unit update: () -> Unit
) { ) {
TableDrawer.drawStreet(this, configuration, canvas, context) // TableDrawer.drawStreet(this, configuration, canvas, context)
} }
} }

@ -728,7 +728,8 @@ class HandHistoryFragment : RealmFragment(), RowRepresentableDelegate, KeyboardL
val tc = TableDrawer(bitmap) val tc = TableDrawer(bitmap)
// draw initial table // draw initial table
TableDrawer.initializeTable(config, tc, requireContext()) // TableDrawer.initializeTable(config, tc, requireContext())
// TODO
val muxer = MMediaMuxer() val muxer = MMediaMuxer()
muxer.Init(requireActivity(), bitmap.width, bitmap.height, "hhVideo", "YES!") muxer.Init(requireActivity(), bitmap.width, bitmap.height, "hhVideo", "YES!")

@ -711,6 +711,9 @@ class ActionList(var listener: ActionListListener? = null) : ArrayList<ComputedA
this.removeAll { it.action.type?.isBlind == true } this.removeAll { it.action.type?.isBlind == true }
} }
/***
* Returns the ComputedAction just before the passed [action]
*/
override fun previousAction(action: ComputedAction): ComputedAction? { override fun previousAction(action: ComputedAction): ComputedAction? {
val index = this.indexOf(action) val index = this.indexOf(action)
return if (index > 0) { return if (index > 0) {
@ -720,5 +723,20 @@ class ActionList(var listener: ActionListListener? = null) : ArrayList<ComputedA
} }
} }
/***
* Returns the player stack, located at the given [position], at the action [index]
*/
fun playerRemainingStack(position: Int, index: Int): Double? {
return this.take(index + 1).lastOrNull { it.positionIndex == position }?.stackAfterActing
}
/***
* Returns the last action where the player put chips on the table for the street
*/
fun lastChipCommittingActionOfPlayer(position: Int, stepIndex: Int): ComputedAction? {
val street = this[stepIndex].street
return this.take(stepIndex + 1).filter { it.street == street }
.lastOrNull { it.positionIndex == position && it.action.type?.isPassive == false }
}
} }

@ -313,9 +313,9 @@ class ComputedAction(var manager: ActionManager,
return this.manager.previousAction(this) return this.manager.previousAction(this)
} }
override fun draw(configuration: ReplayerConfiguration, canvas: Canvas, context: Context) { // override fun draw(configuration: ReplayerConfiguration, canvas: Canvas, context: Context) {
TableDrawer.drawAction(this, true, configuration, canvas, context) // TableDrawer.drawAction(this, true, configuration, canvas, context)
} // }
override fun frames( override fun frames(
configuration: ReplayerConfiguration, configuration: ReplayerConfiguration,

@ -1032,8 +1032,4 @@ class HandHistoryViewModel : ViewModel(), RowRepresentableDataSource, CardCentra
this.createRowRepresentation() this.createRowRepresentation()
} }
fun changeSpeed() {
TODO("Not yet implemented")
}
} }

@ -10,7 +10,7 @@ interface HandStep {
fun frames(configuration: ReplayerConfiguration, canvas: Canvas, context: Context, update: () -> (Unit)) fun frames(configuration: ReplayerConfiguration, canvas: Canvas, context: Context, update: () -> (Unit))
fun draw(configuration: ReplayerConfiguration, canvas: Canvas, context: Context) // fun draw(configuration: ReplayerConfiguration, canvas: Canvas, context: Context)
companion object { companion object {

@ -18,29 +18,20 @@ class ReplayerConfiguration(var handHistory: HandHistory) {
private var lastBlindIndex: Int = 0 private var lastBlindIndex: Int = 0
private var currentStep: Int = 0 private var stepIndex: Int = 0
init { init {
this.actionList.load(this.handHistory) this.actionList.load(this.handHistory)
this.lastBlindIndex = max(this.actionList.indexOfLast { it.action.type?.isBlind == true }, 0) this.lastBlindIndex = max(this.actionList.indexOfLast { it.action.type?.isBlind == true }, 0)
this.currentStep = this.lastBlindIndex + 1 // initialize at big blind this.stepIndex = this.lastBlindIndex + 1 // initialize at big blind
this.steps = HandStep.createSteps(this.handHistory) this.steps = HandStep.createSteps(this.handHistory)
} }
data class Size(var width: Float, var height: Float) data class Size(var width: Float, var height: Float)
data class Circle(var x: Float, var y: Float, var radius: Float) { data class Circle(var x: Float, var y: Float, var radius: Float)
fun toRect(): RectF { data class TextPoint(var x: Float, var y: Float, var fontSize: Float)
return RectF(x - radius, y - radius, x + radius, y + radius)
}
}
data class TextPoint(var x: Float, var y: Float, var fontSize: Float) {
fun toRect(): RectF {
val wRatio = 1.5f
return RectF(x - wRatio * fontSize, y - fontSize, x + wRatio * fontSize, y + fontSize * 0.1f)
}
}
private val maxCards = 5 private val maxCards = 5
@ -309,41 +300,64 @@ class ReplayerConfiguration(var handHistory: HandHistory) {
} }
fun next() { fun next() {
if (this.steps.size > this.currentStep + 1) { if (this.steps.size > this.stepIndex + 1) {
this.currentStep += 1 this.stepIndex += 1
} }
} }
fun previous() { fun previous() {
if (this.currentStep > this.lastBlindIndex + 1) { if (this.stepIndex > this.lastBlindIndex + 1) {
this.currentStep -= 1 this.stepIndex -= 1
} }
} }
val stepsToDraw: List<HandStep> val currentStep: HandStep
get() { get() {
return this.steps.take(this.currentStep + 1) return this.steps[this.stepIndex]
} }
val activePositions: List<Int> // val stepsToDraw: List<HandStep>
// get() {
// return this.steps.take(this.stepIndex + 1)
// }
private val lastActionAtStep: ComputedAction?
get() { get() {
val action = when (val step = this.steps[currentStep]) { return when (val step = this.steps[stepIndex]) {
is ComputedAction -> { is ComputedAction -> {
step step
} }
is Street -> { is Street -> {
if (currentStep > 0) { if (stepIndex > 0) {
this.steps[currentStep - 1] as ComputedAction? this.steps[stepIndex - 1] as ComputedAction?
} else { } else {
null null
} }
} }
else -> throw PAIllegalStateException("unmanaged step: $step") else -> throw PAIllegalStateException("unmanaged step: $step")
} }
val index = action?.action?.index ?: 0 }
val activePositions: List<Int>
get() {
val index = this.lastActionAtStep?.action?.index ?: 0
return this.actionList.activePositionIndexes(index) return this.actionList.activePositionIndexes(index)
} }
fun playerRemainingStack(i: Int): Double? {
this.lastActionAtStep?.action?.index?.let { index ->
return this.actionList.playerRemainingStack(i, index)
}
return null
}
fun lastSignificantActionOfPlayer(i: Int): ComputedAction? {
this.lastActionAtStep?.action?.index?.let { index ->
return this.actionList.lastChipCommittingActionOfPlayer(i, index)
}
return null
}
} }

@ -4,10 +4,11 @@ import android.content.Context
import android.graphics.Canvas import android.graphics.Canvas
import android.util.AttributeSet import android.util.AttributeSet
import android.view.View import android.view.View
import net.pokeranalytics.android.exceptions.PAIllegalStateException
import net.pokeranalytics.android.model.handhistory.Street
import net.pokeranalytics.android.ui.modules.handhistory.model.ComputedAction
import timber.log.Timber import timber.log.Timber
private data class ReplayerAction(val step: HandStep, val draw: Boolean)
class ReplayerView(context: Context, attrs: AttributeSet) : View(context, attrs) { class ReplayerView(context: Context, attrs: AttributeSet) : View(context, attrs) {
lateinit var configuration: ReplayerConfiguration lateinit var configuration: ReplayerConfiguration
@ -24,21 +25,6 @@ class ReplayerView(context: Context, attrs: AttributeSet) : View(context, attrs)
this.invalidate() this.invalidate()
} }
// fun previous(handStep: HandStep) {
// val action = ReplayerAction(handStep, false)
// this.addAction(action)
// }
//
// fun next(handStep: HandStep) {
// val action = ReplayerAction(handStep, true)
// this.addAction(action)
// }
//
// private fun addAction(action: ReplayerAction) {
// this.actionsToDraw.add(action)
// this.invalidate()
// }
override fun onDraw(canvas: Canvas?) { override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas) super.onDraw(canvas)
@ -46,17 +32,7 @@ class ReplayerView(context: Context, attrs: AttributeSet) : View(context, attrs)
canvas?.let { canvas?.let {
TableDrawer.initializeTable(configuration, canvas, context) TableDrawer.drawTable(configuration, canvas, context)
// show cards
configuration.activePositions.forEach {
TableDrawer.drawCards(it, configuration, canvas, context)
}
// action
this.configuration.stepsToDraw.forEach { step ->
step.draw(this.configuration, canvas, context)
}
} }

@ -5,6 +5,7 @@ import android.graphics.*
import androidx.core.content.res.ResourcesCompat import androidx.core.content.res.ResourcesCompat
import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
import net.pokeranalytics.android.exceptions.PAIllegalStateException
import net.pokeranalytics.android.model.handhistory.Position import net.pokeranalytics.android.model.handhistory.Position
import net.pokeranalytics.android.model.handhistory.Street import net.pokeranalytics.android.model.handhistory.Street
import net.pokeranalytics.android.model.realm.handhistory.Action import net.pokeranalytics.android.model.realm.handhistory.Action
@ -66,10 +67,78 @@ class TableDrawer(bitmap: Bitmap) : Canvas(bitmap) {
cardTextPaint.isAntiAlias = true cardTextPaint.isAntiAlias = true
} }
fun drawTable(config: ReplayerConfiguration, canvas: Canvas, context: Context) {
// base
initializeTable(config, canvas, context)
val step = config.currentStep
val street: Street
var computedAction: ComputedAction? = null
when (step) {
is Street -> {
street = step
config.lastActionBeforeStreet(street)?.let {
drawPot(it, config, canvas, context)
}
}
is ComputedAction -> {
street = step.street
computedAction = step
drawPot(step, config, canvas, context)
}
else -> throw PAIllegalStateException("Step unmanaged: $step")
}
drawBoardCards(street, config, canvas, context)
val hh = config.handHistory
for (i in 0 until hh.numberOfPlayers) {
Timber.d("Getting player $i setup ")
// draw player rectangles with action or name + stack
val actionType = computedAction?.action?.type
if (computedAction?.positionIndex == i && actionType != null) {
drawPlayerRectangle(i, true, config, canvas, context)
drawAction(i, actionType, config, canvas, context)
} else {
val remainingStack = config.playerRemainingStack(i)
drawPlayerRectangle(i, false, config, canvas, context)
drawPositionAndStack(i, remainingStack, config, canvas, context)
}
// draw chips
// when does a chip appears ?
// when the player has put some money during the current street
config.lastSignificantActionOfPlayer(i)?.let { action ->
when {
action.action.type?.isSignificant == true -> {
action.action.amount?.let { amount ->
drawChip(amount, action.positionIndex, config, canvas, context)
}
}
action.action.type?.isCall == true -> {
action.getStreetLastSignificantAction()?.action?.amount?.let { amount ->
drawChip(amount, action.positionIndex, config, canvas, context)
}
}
else -> {}
}
}
}
// show player cards
config.activePositions.forEach {
drawCards(it, config, canvas, context)
}
}
/*** /***
* WARNING: Avoid instancing objects here, as it's called from onDraw method * WARNING: Avoid instancing objects here, as it's called from onDraw method
*/ */
fun initializeTable(config: ReplayerConfiguration, canvas: Canvas, context: Context) { private fun initializeTable(config: ReplayerConfiguration, canvas: Canvas, context: Context) {
canvas.drawColor(context.getColor(backgroundColor)) canvas.drawColor(context.getColor(backgroundColor))
@ -83,7 +152,7 @@ class TableDrawer(bitmap: Bitmap) : Canvas(bitmap) {
// drawCards(i, config, canvas, context) // drawCards(i, config, canvas, context)
drawPlayerRectangle(i,false, config, canvas, context) drawPlayerRectangle(i,false, config, canvas, context)
drawPositionAndStack(i, playerSetup?.stack, config, canvas, context) // drawPositionAndStack(i, playerSetup?.stack, config, canvas, context)
drawPlayerCircle(i, config, canvas, context) drawPlayerCircle(i, config, canvas, context)
@ -121,8 +190,8 @@ class TableDrawer(bitmap: Bitmap) : Canvas(bitmap) {
private fun drawChip(amount: Double, chipText: ReplayerConfiguration.TextPoint, chipCircle: ReplayerConfiguration.Circle, canvas: Canvas, context: Context) { private fun drawChip(amount: Double, chipText: ReplayerConfiguration.TextPoint, chipCircle: ReplayerConfiguration.Circle, canvas: Canvas, context: Context) {
clearText(chipText, canvas) // clearText(chipText, canvas)
clearCircle(chipCircle, canvas) // clearCircle(chipCircle, canvas)
this.fillPaint.color = context.getColor(R.color.green) this.fillPaint.color = context.getColor(R.color.green)
canvas.drawCircle(chipCircle.x, chipCircle.y, chipCircle.radius, this.fillPaint) canvas.drawCircle(chipCircle.x, chipCircle.y, chipCircle.radius, this.fillPaint)
@ -139,19 +208,19 @@ class TableDrawer(bitmap: Bitmap) : Canvas(bitmap) {
} }
private fun clearText(textPoint: ReplayerConfiguration.TextPoint, canvas: Canvas) { // private fun clearText(textPoint: ReplayerConfiguration.TextPoint, canvas: Canvas) {
this.clearRect(textPoint.toRect(), canvas) // this.clearRect(textPoint.toRect(), canvas)
} // }
//
private fun clearCircle(circle: ReplayerConfiguration.Circle, canvas: Canvas) { // private fun clearCircle(circle: ReplayerConfiguration.Circle, canvas: Canvas) {
this.clearRect(circle.toRect(), canvas) // this.clearRect(circle.toRect(), canvas)
} // }
//
private fun clearRect(rect: RectF, canvas: Canvas) { // private fun clearRect(rect: RectF, canvas: Canvas) {
canvas.drawRect(rect, this.backgroundPaint) // canvas.drawRect(rect, this.backgroundPaint)
} // }
fun drawCards(playerIndex: Int, config: ReplayerConfiguration, canvas: Canvas, context: Context) { private fun drawCards(playerIndex: Int, config: ReplayerConfiguration, canvas: Canvas, context: Context) {
val playerSetup = config.handHistory.playerSetupForPosition(playerIndex) val playerSetup = config.handHistory.playerSetupForPosition(playerIndex)
val cardRects = config.cardRects(playerIndex) val cardRects = config.cardRects(playerIndex)
@ -195,12 +264,12 @@ class TableDrawer(bitmap: Bitmap) : Canvas(bitmap) {
} }
fun drawPlayerPositionAndStack(action: ComputedAction, config: ReplayerConfiguration, canvas: Canvas, context: Context) { private fun drawPlayerPositionAndStack(action: ComputedAction, config: ReplayerConfiguration, canvas: Canvas, context: Context) {
drawPlayerRectangle(action.positionIndex,false, config, canvas, context) drawPlayerRectangle(action.positionIndex,false, config, canvas, context)
drawPositionAndStack(action.positionIndex, action.stackAfterActing, config, canvas, context) drawPositionAndStack(action.positionIndex, action.stackAfterActing, config, canvas, context)
} }
fun drawAction(action: ComputedAction, highlighted: Boolean = true, config: ReplayerConfiguration, canvas: Canvas, context: Context) { private fun drawAction(action: ComputedAction, highlighted: Boolean = true, config: ReplayerConfiguration, canvas: Canvas, context: Context) {
// show that action is on the player by highlighting // show that action is on the player by highlighting
drawPlayerRectangle(action.positionIndex, highlighted, config, canvas, context) drawPlayerRectangle(action.positionIndex, highlighted, config, canvas, context)
@ -265,7 +334,7 @@ class TableDrawer(bitmap: Bitmap) : Canvas(bitmap) {
/*** /***
* [i] is the player position in the hand * [i] is the player position in the hand
*/ */
private fun drawPlayerRectangle(i: Int, highlighted: Boolean, config: ReplayerConfiguration, canvas: Canvas, context: Context) { private fun drawPlayerRectangle(i: Int, highlighted: Boolean, config: ReplayerConfiguration, canvas: Canvas, context: Context) {
val rect = config.stackRectForPlayer(i) val rect = config.stackRectForPlayer(i)
val rectRadius = (rect.bottom - rect.top) / 4 val rectRadius = (rect.bottom - rect.top) / 4
@ -306,7 +375,7 @@ class TableDrawer(bitmap: Bitmap) : Canvas(bitmap) {
canvas.drawText(actionName, pnPoint.x, pnPoint.y, this.textPaint) canvas.drawText(actionName, pnPoint.x, pnPoint.y, this.textPaint)
} }
fun drawStreet(street: Street, config: ReplayerConfiguration, canvas: Canvas, context: Context) { private fun drawBoardCards(street: Street, config: ReplayerConfiguration, canvas: Canvas, context: Context) {
val cards = config.handHistory.cardsForStreet(street) val cards = config.handHistory.cardsForStreet(street)
config.boardCardRects.take(street.totalBoardCards).forEachIndexed { index, rectF -> config.boardCardRects.take(street.totalBoardCards).forEachIndexed { index, rectF ->
@ -314,18 +383,18 @@ class TableDrawer(bitmap: Bitmap) : Canvas(bitmap) {
} }
// Clear all chips // Clear all chips
val hh = config.handHistory // val hh = config.handHistory
for (i in 0 until hh.numberOfPlayers) { // for (i in 0 until hh.numberOfPlayers) {
val pc = config.chipCircle(i) // val pc = config.chipCircle(i)
clearCircle(pc, canvas) // clearCircle(pc, canvas)
val pct = config.chipText(i) // val pct = config.chipText(i)
clearText(pct, canvas) // clearText(pct, canvas)
} // }
// Clear last action before street // Clear last action before street
config.lastActionBeforeStreet(street)?.let { action -> // config.lastActionBeforeStreet(street)?.let { action ->
drawPlayerPositionAndStack(action, config, canvas, context) // drawPlayerPositionAndStack(action, config, canvas, context)
} // }
} }
@ -339,7 +408,7 @@ class TableDrawer(bitmap: Bitmap) : Canvas(bitmap) {
this.textPaint.textSize = tpTextPoint.fontSize this.textPaint.textSize = tpTextPoint.fontSize
this.textPaint.color = context.getColor(R.color.white) this.textPaint.color = context.getColor(R.color.white)
clearText(config.totalPotTextPoint, canvas) // clearText(config.totalPotTextPoint, canvas)
canvas.drawText(totalPot.formatted, config.totalPotTextPoint.x, config.totalPotTextPoint.y, this.textPaint) canvas.drawText(totalPot.formatted, config.totalPotTextPoint.x, config.totalPotTextPoint.y, this.textPaint)
} }

Loading…
Cancel
Save