Adds Player rows at SUMMARY + fixes

hh
Laurent 6 years ago
parent 2c30a32e2e
commit f775b60f88
  1. 16
      app/src/main/java/net/pokeranalytics/android/model/handhistory/ComputedAction.kt
  2. 195
      app/src/main/java/net/pokeranalytics/android/model/handhistory/HHBuilder.kt
  3. 11
      app/src/main/java/net/pokeranalytics/android/model/realm/handhistory/Action.kt
  4. 4
      app/src/main/java/net/pokeranalytics/android/model/realm/handhistory/HandHistory.kt
  5. 108
      app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/HandHistoryAdapter.kt
  6. 12
      app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/views/PlayerCardsRow.kt
  7. 10
      app/src/main/res/layout/row_hand_action.xml
  8. 33
      app/src/main/res/layout/row_hand_player_summary.xml

@ -22,15 +22,15 @@ class ComputedAction(var action: Action,
/***
* Returns whether the action requires the user to enter an amount for the selected action
*/
val requiresAmount: Boolean
get() {
return when(this.action.type) {
Action.Type.POST_SB, Action.Type.POST_BB,
Action.Type.BET, Action.Type.RAISE -> (this.action.amount == null)
Action.Type.BET_ALLIN, Action.Type.RAISE_ALLIN -> (this.playerRemainingStack == null && this.action.amount == null)
else -> false
private val requiresAmount: Boolean
get() {
return when(this.action.type) {
Action.Type.POST_SB, Action.Type.POST_BB,
Action.Type.BET, Action.Type.RAISE -> (this.action.amount == null)
Action.Type.BET_ALLIN, Action.Type.RAISE_ALLIN -> (this.playerRemainingStack == null && this.action.amount == null)
else -> false
}
}
}
/***
* Sets the effective amount of the action

@ -6,6 +6,7 @@ import net.pokeranalytics.android.model.realm.handhistory.Action
import net.pokeranalytics.android.model.realm.handhistory.Card
import net.pokeranalytics.android.model.realm.handhistory.HandHistory
import net.pokeranalytics.android.ui.modules.handhistory.HandRowType
import net.pokeranalytics.android.ui.modules.handhistory.views.PlayerCardsRow
import net.pokeranalytics.android.ui.modules.handhistory.views.StreetCardView
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.rowrepresentable.CustomizableRowRepresentable
@ -100,7 +101,7 @@ class HHBuilder : BoardChangedListener {
*/
private fun availableActions(index: Int) : Set<Action.Type> {
val lastSignificantAction: ComputedAction? = getLastSignificantAction(index)
val lastSignificantAction: ComputedAction? = getStreetLastSignificantAction(index)
val lastUserAction: ComputedAction? = getLastUserAction(index)
return if (lastSignificantAction != null) {
@ -122,7 +123,7 @@ class HHBuilder : BoardChangedListener {
Action.Type.RAISE_ALLIN, Action.Type.BET_ALLIN -> {
if (remainingStack != null && actionAmount != null && remainingStack <= actionAmount) {
setOf(Action.Type.FOLD, Action.Type.CALL_ALLIN)
} else if (unfoldedPositions(index).size == 2 && remainingStack != null && actionAmount != null && remainingStack > actionAmount) {
} else if (activePositions(index).size == 2 && remainingStack != null && actionAmount != null && remainingStack > actionAmount) {
setOf(Action.Type.FOLD, Action.Type.CALL)
} else {
setOf(Action.Type.FOLD, Action.Type.CALL, Action.Type.RAISE, Action.Type.UNDEFINED_ALLIN)
@ -160,7 +161,7 @@ class HHBuilder : BoardChangedListener {
when (actionType) {
Action.Type.CALL -> {
val significantAction = getLastSignificantAction(index)
val significantAction = getStreetLastSignificantAction(index)
?: throw PAIllegalStateException("There must be a previously set significant action for a call to be set")
val significantAmount = significantAction.action.amount
?: throw PAIllegalStateException("There must be a set amount on the action for the call to be set")
@ -184,7 +185,7 @@ class HHBuilder : BoardChangedListener {
val modifiedActions = mutableListOf<ComputedAction>()
getPreviousEmptyActions(index).forEach {
modifiedActions.add(it)
val lastSignificant = getLastSignificantAction(index)
val lastSignificant = getStreetLastSignificantAction(index)
if (lastSignificant != null) {
it.action.type = Action.Type.FOLD
} else {
@ -226,7 +227,7 @@ class HHBuilder : BoardChangedListener {
val computedAction = this.actionForIndex(index)
val indexPosition = computedAction.position
val activePositions = unfoldedPositions(index)
val activePositions = activePositions(index)
activePositions.remove(indexPosition)
// We want to remove positions that already have an action after [index]
@ -264,14 +265,16 @@ class HHBuilder : BoardChangedListener {
this.rowRepresentables.add(computedAction)
}
/***
* Returns the list of position still in play before the given[index]
*/
private fun unfoldedPositions(index: Int) : MutableList<Position> {
val folds = this.sortedActions.take(index).filter { it.action.type == Action.Type.FOLD }
.map { it.position }
val allPositions = this.positions
allPositions.removeAll(folds)
/***
* Returns the list of position still in play before the given [index]
*/
private fun activePositions(index: Int) : MutableList<Position> {
val oustedPositions = this.sortedActions.take(index + 1)
.filter { it.action.type?.isPullOut ?: false }
.map { it.position }
val allPositions = this.positions
allPositions.removeAll(oustedPositions)
return allPositions.toMutableList()
}
@ -280,37 +283,56 @@ class HHBuilder : BoardChangedListener {
* Returns true if a street has been created
*/
private fun createNextStreetIfNecessary(index: Int) : Boolean {
val computedAction = this.actionForIndex(index)
val currentStreet = this.actionForIndex(index).action.street // TODO is it useful?
getLastSignificantAction(index)?.let { significantAction ->
val activePositions = unfoldedPositions(index)
val activePlayerCount = activePositions.size // don't move this line because of removes
activePositions.remove(significantAction.position)
val significantIndex = significantAction.action.index
for (i in significantIndex + 1 until this.sortedActions.size) {
val ca = this.sortedActions[i]
val type = ca.action.type
if (type != null && !type.isSignificant) { // Calls and folds
activePositions.remove(ca.position)
}
}
if (activePositions.isEmpty()) {
if (activePlayerCount >= 2) {
createStreet(currentStreet.next)
} else {
createStreet(Street.SUMMARY)
}
return true
}
val nextStreet = isStreetActionClosed(index)
if (nextStreet != null) {
createStreet(nextStreet)
return true
}
return false
// val computedAction = this.actionForIndex(index)
// val currentStreet = this.actionForIndex(index).action.street
//
// getStreetLastSignificantAction(index)?.let { significantAction ->
//
// val activePositions = activePositions(index)
// val activePlayerCount = activePositions.size // don't move this line because of removes
//
// activePositions.remove(significantAction.position)
//
// val significantIndex = significantAction.action.index
// for (i in significantIndex + 1 until this.sortedActions.size) {
// val ca = this.sortedActions[i]
// val type = ca.action.type
// if (type != null && !type.isSignificant) { // Calls and folds
// activePositions.remove(ca.position)
// }
// }
//
// if (activePositions.isEmpty()) {
//
// if (activePlayerCount >= 2 && currentStreet != Street.RIVER) {
// createStreet(currentStreet.next)
// } else {
// createStreet(Street.SUMMARY)
// }
// return true
// }
//
// }
//
// val allCheck = this.sortedActions.filter { it.action.street == currentStreet }.all { it.action.type == Action.Type.CHECK }
// if (allCheck) {
// if (currentStreet != Street.RIVER) {
// createStreet(currentStreet.next)
// } else {
// createStreet(Street.SUMMARY)
// }
// return true
// }
//
// return false
}
/***
@ -322,14 +344,22 @@ class HHBuilder : BoardChangedListener {
private fun createStreet(street: Street) {
val lastComputedAction = this.sortedActions.last()
val lastActionIndex = lastComputedAction.action.index
val totalPotSize = lastComputedAction.totalPotSize
addStreetHeader(this.rowRepresentables, street, totalPotSize)
unfoldedPositions(lastActionIndex).sortedBy { it.ordinal }.forEach {
addNewEmptyAction(it, street, totalPotSize, lastRemainingStack(it, lastActionIndex))
val lastActionIndex = lastComputedAction.action.index
activePositions(lastActionIndex).sortedBy { it.ordinal }.forEach {
when (street) {
Street.SUMMARY -> {
this.rowRepresentables.add(PlayerCardsRow(it))
}
else -> {
addNewEmptyAction(it, street, totalPotSize, lastRemainingStack(it, lastActionIndex))
}
}
}
}
@ -372,7 +402,7 @@ class HHBuilder : BoardChangedListener {
}
Action.Type.UNDEFINED_ALLIN -> {
getLastSignificantAction(index)?.action?.amount?.let { significantActionAmount ->
getStreetLastSignificantAction(index)?.action?.amount?.let { significantActionAmount ->
val committedAmount = getPreviousCommittedAmount(index) ?: 0.0
val askedAmount = significantActionAmount - committedAmount
@ -425,7 +455,7 @@ class HHBuilder : BoardChangedListener {
return when (previousAction.type) {
Action.Type.POST_BB, Action.Type.POST_SB, Action.Type.STRADDLE, Action.Type.BET, Action.Type.RAISE -> previousAction.amount
Action.Type.CALL -> getLastSignificantAction(previousAction.index)?.action?.amount
Action.Type.CALL -> getStreetLastSignificantAction(previousAction.index)?.action?.amount
else -> null
}
}
@ -466,7 +496,7 @@ class HHBuilder : BoardChangedListener {
/***
* Returns the last significant player action, if any, for the action at the provided [index]
*/
private fun getLastSignificantAction(index: Int): ComputedAction? {
private fun getStreetLastSignificantAction(index: Int): ComputedAction? {
val street = this.actionForIndex(index).action.street
Timber.d("**** this.sortedActions.size = ${this.sortedActions.size}")
val previousActions = this.sortedActions.take(index).filter { it.action.street == street }
@ -648,22 +678,79 @@ class HHBuilder : BoardChangedListener {
val actions = this.sortedActions.filter { it.action.street == street }
if (actions.isNotEmpty()) {
when (street) {
Street.SUMMARY -> {
val lastActionIndex = this.sortedActions.size - 1
addStreetHeader(rows, street, potSize)
if (activePositions(lastActionIndex).size < 2 || isStreetActionClosed(lastActionIndex) == Street.SUMMARY) {
addStreetHeader(rows, street, potSize)
// Actions
rows.addAll(actions)
potSize = actions.last().totalPotSize
activePositions(lastActionIndex).forEach {
val positionIndex = this.positions.indexOf(it)
val playerCardsRow = PlayerCardsRow(it, this.handHistory.cardsForPosition(positionIndex))
this.rowRepresentables.add(playerCardsRow)
}
}
}
else -> {
if (actions.isNotEmpty()) {
addStreetHeader(rows, street, potSize)
rows.addAll(actions)
potSize = actions.last().totalPotSize
}
}
}
}
this.rowRepresentables = rows
// return rows
}
private fun isStreetActionClosed(index: Int) : Street? {
val currentStreet = this.actionForIndex(index).action.street
getStreetLastSignificantAction(index)?.let { significantAction ->
val activePositions = activePositions(index)
val activePlayerCount = activePositions.size // don't move this line because of removes
activePositions.remove(significantAction.position)
val significantIndex = significantAction.action.index
for (i in significantIndex + 1 until this.sortedActions.size) {
val ca = this.sortedActions[i]
val type = ca.action.type
if (type != null && !type.isSignificant) { // Calls and folds
activePositions.remove(ca.position)
}
}
if (activePositions.isEmpty()) {
return if (activePlayerCount >= 2 && currentStreet != Street.RIVER) {
currentStreet.next
} else {
Street.SUMMARY
}
}
}
val allCheck = this.sortedActions.filter { it.action.street == currentStreet }.all { it.action.type == Action.Type.CHECK }
if (allCheck) {
return if (currentStreet != Street.RIVER) {
currentStreet.next
} else {
Street.SUMMARY
}
}
return null
}
private fun addStreetHeader(rowRepresentables: MutableList<RowRepresentable>, street: Street, potSize: Double) {
val headerView = CustomizableRowRepresentable(customViewType = HandRowType.HEADER, resId = street.resId)
rowRepresentables.add(headerView)

@ -34,6 +34,17 @@ open class Action : RealmObject() {
}
}
/***
* Tells if the action pulls the player out from any new decision
*/
val isPullOut: Boolean
get() {
return when (this) {
FOLD, BET_ALLIN, RAISE_ALLIN, CALL_ALLIN, UNDEFINED_ALLIN -> true
else -> false
}
}
val requiresOpponentDecision: Boolean
get() {
return when(this) {

@ -128,4 +128,8 @@ open class HandHistory : RealmObject(), RowRepresentable, Identifiable, Filterab
return this.board.sortedBy { it.index }.take(street.totalBoardCards).toMutableList()
}
fun cardsForPosition(position: Int): List<Card> {
return this.playerSetups.first { it.position == position }.cards
}
}

@ -22,6 +22,7 @@ import net.pokeranalytics.android.ui.adapter.RecyclerAdapter
import net.pokeranalytics.android.ui.adapter.RowRepresentableDataSource
import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.extensions.hideKeyboard
import net.pokeranalytics.android.ui.modules.handhistory.views.PlayerCardsRow
import net.pokeranalytics.android.ui.modules.handhistory.views.StreetCardView
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.holder.RowViewHolder
@ -32,6 +33,7 @@ import timber.log.Timber
enum class HandRowType(var layoutRes: Int) : ViewIdentifier {
HEADER(R.layout.row_header_title),
ACTION(R.layout.row_hand_action),
PLAYER_SUMMARY(R.layout.row_hand_player_summary),
STREET(R.layout.row_hand_cards);
override val identifier: Int
@ -55,6 +57,7 @@ class HandHistoryAdapter(
HandRowType.HEADER -> RowViewHolder(layout)
HandRowType.ACTION -> RowHandAction(layout)
HandRowType.STREET -> RowHandStreet(layout)
HandRowType.PLAYER_SUMMARY -> RowHandPlayerSummary(layout)
}
}
@ -79,22 +82,6 @@ class HandHistoryAdapter(
}
}
// inner class TextListener : TextWatcher {
//
// var position: Int = 0
//
// override fun afterTextChanged(s: Editable?) {}
//
// override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
//
// override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
// val row = dataSource.rowRepresentableForPosition(position)
// ?: throw PAIllegalStateException("Row Representable not found at index: $position")
// delegate?.onRowValueChanged(s.toString(), row)
// }
//
// }
abstract inner class RowHandHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var currentPosition = 0
@ -236,25 +223,12 @@ class HandHistoryAdapter(
}
// private fun requestFocusAndShowKeyboard(editText: EditText) {
//
// if (editText.requestFocus()) {
// val imm = itemView.context.getSystemService(InputMethodManager::class.java)
// imm.toggleSoftInput(0, InputMethodManager.HIDE_IMPLICIT_ONLY)
// val imm = itemView.context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
// imm.toggleSoftInput(InputMethodManager.SHOW_IMPLICIT, 0)
// imm.showSoftInput(editText, InputMethodManager.SHOW_IMPLICIT)
// }
//
// }
}
/**
* Display a hand street
*/
inner class RowHandStreet(itemView: View) : RowHandHolder(itemView),
BindableHolder {
inner class RowHandStreet(itemView: View) : RowHandHolder(itemView), BindableHolder {
init {
@ -325,4 +299,78 @@ class HandHistoryAdapter(
}
/**
* Display a hand action
*/
inner class RowHandPlayerSummary(itemView: View) : RowHandHolder(itemView),
BindableHolder {
// private var actionCanBeEdited = true
// private var amountCanBeEdited = true
init {
// Cards
itemView.findViewById<EditText>(R.id.cardsEditText)?.let { amountEditText ->
amountEditText.isFocusableInTouchMode = true
amountEditText.setOnTouchListener { _, event ->
if (event.action == MotionEvent.ACTION_UP) {
// Both are required, otherwise requestFocus() fails
amountEditText.isFocusable = true
amountEditText.isFocusableInTouchMode = true
amountEditText.requestFocus()
editTextSelected(amountEditText, true, HHKeyboard.AMOUNT.ordinal)
}
return@setOnTouchListener true
}
}
}
override fun onBind(position: Int, row: RowRepresentable, adapter: RecyclerAdapter) {
Timber.d("onbind @position = $position")
this.currentPosition = position
val playerCardView = row as PlayerCardsRow
// Position
itemView.findViewById<Button>(R.id.positionButton)?.let { button ->
button.text = playerCardView.position.value
}
// Amount
itemView.findViewById<EditText>(R.id.cardsEditText)?.let { amountEditText ->
val tag = HHKeyboard.AMOUNT.ordinal
val selected = adapter.dataSource.isSelected(position, row, tag)
// Both are required, otherwise requestFocus() fails
amountEditText.isFocusable = selected
amountEditText.isFocusableInTouchMode = selected
Timber.d("Amount at $position is selected: $selected, focusable = ${amountEditText.isFocusable}, isFocusableInTouchMode = ${amountEditText.isFocusableInTouchMode}, hasFocus = ${amountEditText.hasFocus()}, enabled = ${amountEditText.isEnabled}")
amountEditText.setBackgroundColor(color(selected))
amountEditText.setText(playerCardView.cards.formatted(itemView.context))
if (selected) {
amountEditText.requestFocus()
} else {
amountEditText.clearFocus()
}
}
}
}
}

@ -0,0 +1,12 @@
package net.pokeranalytics.android.ui.modules.handhistory.views
import net.pokeranalytics.android.model.handhistory.Position
import net.pokeranalytics.android.model.realm.handhistory.Card
import net.pokeranalytics.android.ui.modules.handhistory.HandRowType
import net.pokeranalytics.android.ui.view.RowRepresentable
class PlayerCardsRow(var position: Position, var cards: List<Card> = listOf()) : RowRepresentable {
override val viewType: Int = HandRowType.PLAYER_SUMMARY.ordinal
}

@ -25,16 +25,6 @@
android:layout_height="44dp"
android:layout_marginStart="8dp"/>
<!-- <androidx.appcompat.widget.AppCompatEditText-->
<!-- android:id="@+id/actionEditText"-->
<!-- style="@style/PokerAnalyticsTheme.EditText"-->
<!-- android:layout_width="0dp"-->
<!-- android:layout_weight="1"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:layout_marginStart="8dp"-->
<!-- android:gravity="center"-->
<!-- android:maxLines="1" />-->
<androidx.appcompat.widget.AppCompatEditText
android:id="@+id/amountEditText"
style="@style/PokerAnalyticsTheme.EditText"

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.button.MaterialButton
android:id="@+id/playerButton"
style="@style/PokerAnalyticsTheme.HHButton"
android:layout_width="44dp"
android:layout_height="44dp"
android:layout_marginStart="8dp"/>
<com.google.android.material.button.MaterialButton
android:id="@+id/positionButton"
style="@style/PokerAnalyticsTheme.HHButton"
android:layout_width="64dp"
android:layout_height="44dp"
android:layout_marginStart="8dp"/>
<androidx.appcompat.widget.AppCompatEditText
android:id="@+id/cardsEditText"
style="@style/PokerAnalyticsTheme.EditText"
android:inputType="numberDecimal"
android:layout_width="0dp"
android:layout_weight="2"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:gravity="center"
android:maxLines="1" />
</LinearLayout>
Loading…
Cancel
Save