diff --git a/app/src/main/java/net/pokeranalytics/android/model/handhistory/HHBuilder.kt b/app/src/main/java/net/pokeranalytics/android/model/handhistory/HHBuilder.kt index 2a1a0d6f..c1ad9256 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/handhistory/HHBuilder.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/handhistory/HHBuilder.kt @@ -90,8 +90,9 @@ class HHBuilder : BoardChangedListener { } this.sortedActions = computedActions -// this.sortedBoardCards = this.handHistory.board.sortedBy { it.index }.toMutableList() this.boardManager = BoardManager(this.handHistory.board, this) + + this.createRowRepresentation() } /*** @@ -121,7 +122,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 (this.remainingPlayerCount(index) == 2 && remainingStack != null && actionAmount != null && remainingStack > actionAmount) { + } else if (unfoldedPositions(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) @@ -138,13 +139,6 @@ class HHBuilder : BoardChangedListener { } - /*** - * Returns the remaining player count at the provided [index] - */ - private fun remainingPlayerCount(index: Int): Int { - return 0 // TODO - } - /*** * Selects an action type for the action at the provided [index] * If the user changes the current action, @@ -184,7 +178,7 @@ class HHBuilder : BoardChangedListener { val dropedIndex = dropNextActionsIfNecessary(index) - this.updateFollowupActions(index) + val structureModified = this.updateFollowupActions(index) // Automatically sets action for the previous empty actions val modifiedActions = mutableListOf() @@ -198,32 +192,37 @@ class HHBuilder : BoardChangedListener { } } - if (dropedIndex != null) return null - return modifiedActions.map { this.currentRowRepresentables.indexOf(it) } + if (dropedIndex != null || structureModified) return null + return modifiedActions.map { this.rowRepresentables.indexOf(it) } } /*** * Adds, if necessary, new ComputedAction for players that needs to act * Also adds, if necessary, the Street separators and board selectors */ - private fun updateFollowupActions(index: Int) { + private fun updateFollowupActions(index: Int) : Boolean { val computedAction = this.actionForIndex(index) val type = computedAction.action.type - when (type?.isSignificant) { + return when (type?.isSignificant) { true -> { // opens the action and requires action from other addsFollowupActionsIfNecessary(index) } false -> { // closes the action, pass to next street if necessary createNextStreetIfNecessary(index) } - else -> { } + else -> false } } - private fun addsFollowupActionsIfNecessary(index: Int) { + /*** + * Check if some positions are still required to play, + * and adds new actions if none exists after [index] + * Returns true if actions have been added + */ + private fun addsFollowupActionsIfNecessary(index: Int) : Boolean { val computedAction = this.actionForIndex(index) val indexPosition = computedAction.position @@ -240,24 +239,34 @@ class HHBuilder : BoardChangedListener { val firstPositionAfterCurrent = max(0, activePositions.indexOfFirst { it.ordinal > indexPosition.ordinal }) for (i in 0 until activePositions.size) { val position = activePositions[(firstPositionAfterCurrent + i) % activePositions.size] - this.addNewEmptyAction(position, computedAction.totalPotSize, lastRemainingStack(position, index)) + this.addNewEmptyAction(position, computedAction.action.street, computedAction.totalPotSize, lastRemainingStack(position, index)) } - + return activePositions.isNotEmpty() } - + /*** + * Returns the last remaining stack of the player, if available + */ private fun lastRemainingStack(position: Position, index: Int): Double? { return this.sortedActions.take(index).lastOrNull { it.position == position }?.playerRemainingStack } - private fun addNewEmptyAction(position: Position, currentPotSize: Double, remainingStack: Double?) { + /*** + * Creates a new action at the end of the action stack, and in the HH representation + */ + private fun addNewEmptyAction(position: Position, street: Street, currentPotSize: Double, remainingStack: Double?) { val action = Action() action.index = this.sortedActions.size action.position = position.ordinal + action.street = street val computedAction = ComputedAction(action, currentPotSize, remainingStack, position) this.sortedActions.add(computedAction) + this.rowRepresentables.add(computedAction) } + /*** + * Returns the list of position still in play before the given[index] + */ private fun unfoldedPositions(index: Int) : MutableList { val folds = this.sortedActions.take(index).filter { it.action.type == Action.Type.FOLD } .map { it.position } @@ -266,16 +275,22 @@ class HHBuilder : BoardChangedListener { return allPositions.toMutableList() } - private fun createNextStreetIfNecessary(index: Int) { + /*** + * Creates a new street if no player needs to act + * 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)?.action?.index?.let { significantIndex -> - - val indexPosition = computedAction.position + getLastSignificantAction(index)?.let { significantAction -> val activePositions = unfoldedPositions(index) - activePositions.remove(indexPosition) + 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 @@ -285,14 +300,37 @@ class HHBuilder : BoardChangedListener { } if (activePositions.isEmpty()) { - createNextStreet(index) + + if (activePlayerCount >= 2) { + createStreet(currentStreet.next) + } else { + createStreet(Street.SUMMARY) + } + return true } } + return false } - private fun createNextStreet(index: Int) { - // TODO + /*** + * Creates a new street: + * - Adds a Street Header + * - Adds a Board if necessary + * - Adds empty actions for the remaining players + */ + 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)) + } } /*** @@ -314,13 +352,6 @@ class HHBuilder : BoardChangedListener { return null } - /*** - * Returns the number of active players at the beginning of the street - */ - private fun remainingActivePlayerCountAtStreetStart(index: Int) : Int { - return 0 - } - /*** * Sets the amount for the action at the provided [index] * In the case of an UNDEFINED_ALLIN, define if it's a RAISE_ALLIN or a CALL_ALLIN @@ -449,7 +480,7 @@ class HHBuilder : BoardChangedListener { private fun getNextSignificantAction(index: Int): ComputedAction? { val street = this.actionForIndex(index).action.street val nextActions = this.sortedActions.drop(index + 1).filter { it.action.street == street } - return nextActions.firstOrNull() { it.action.isActionSignificant } + return nextActions.firstOrNull { it.action.isActionSignificant } } /*** @@ -471,53 +502,10 @@ class HHBuilder : BoardChangedListener { } /*** - * Saves the current hand state in the database - */ - private fun save() { - - } - - /*** - * The list of row representables, generated from the hand history actions - */ - private var currentRowRepresentables = mutableListOf() - - fun rowRepresentables() : List { - val rows: MutableList = mutableListOf() - - rows.add(CustomizableRowRepresentable(customViewType = HandRowType.HEADER, resId = R.string.settings)) - - var potSize = 0.0 - Street.values().forEach { street -> - - val actions = this.sortedActions.filter { it.action.street == street } - - if (actions.isNotEmpty()) { - // Name of the street + pot size if not preflop - rows.add(CustomizableRowRepresentable(customViewType = HandRowType.HEADER, resId = street.resId)) - - // Cards if not preflop - if (street.totalBoardCards >= 0) { - rows.add(StreetCardView(street, this.handHistory.cardsForStreet(street), potSize)) - } - - // Actions - rows.addAll(actions) - - potSize = actions.last().totalPotSize - } - - } - - this.currentRowRepresentables = rows - return rows - } - - /*** - * Returns the [index] of a ComputedAction given its [rowRepresentableIndex] + * Returns the index of a ComputedAction given its [rowRepresentableIndex] */ fun indexOfComputedAction(rowRepresentableIndex: Int) : Int { - val computedAction = this.currentRowRepresentables[rowRepresentableIndex] as ComputedAction + val computedAction = this.rowRepresentables[rowRepresentableIndex] as ComputedAction return computedAction.action.index } @@ -527,7 +515,7 @@ class HHBuilder : BoardChangedListener { */ fun findIndexForEdition(startIndex: Int, keyboard: HHKeyboard? = null): HHSelection? { - this.currentRowRepresentables.forEachIndexed { index, rowRepresentable -> + this.rowRepresentables.forEachIndexed { index, rowRepresentable -> if (index >= startIndex && rowRepresentable is HandHistoryRow) { // Timber.d("Check keyboard for index = $index") val foundKeyboard = rowRepresentable.keyboardForCompletion() @@ -553,7 +541,7 @@ class HHBuilder : BoardChangedListener { while (true) { val computedAction = this.actionForIndex(i) if (computedAction.position == position) { - return this.rowRepresentables().indexOf(computedAction) + return this.rowRepresentables.indexOf(computedAction) } i++ if (i > this.sortedActions.size) throw PAIllegalStateException("algo sucks") @@ -564,7 +552,7 @@ class HHBuilder : BoardChangedListener { * Adds a card with the selected [value] */ fun cardValueSelected(value: Card.Value, currentSelection: HHSelection) { - when (this.currentRowRepresentables[currentSelection.index]) { + when (this.rowRepresentables[currentSelection.index]) { is StreetCardView -> { val card = Card.newInstance(value.value) this.boardManager.add(card) @@ -578,7 +566,7 @@ class HHBuilder : BoardChangedListener { */ fun cardSuitSelected(suit: Card.Suit, currentSelection: HHSelection) { - when (val row = this.currentRowRepresentables[currentSelection.index]) { + when (val row = this.rowRepresentables[currentSelection.index]) { is StreetCardView -> { val addNewCard = this.boardManager.lastCard(row.street)?.let { @@ -603,8 +591,7 @@ class HHBuilder : BoardChangedListener { * Deletes all the card of the selected street */ fun clearCards(currentSelection: HHSelection) { - val row = this.currentRowRepresentables[currentSelection.index] - when (row) { + when (val row = this.rowRepresentables[currentSelection.index]) { is StreetCardView -> { this.boardManager.clearStreet(row.street) } @@ -619,8 +606,7 @@ class HHBuilder : BoardChangedListener { */ fun deleteLastCardProperty(currentSelection: HHSelection) { - val row = this.currentRowRepresentables[currentSelection.index] - when (row) { + when (val row = this.rowRepresentables[currentSelection.index]) { is StreetCardView -> { this.boardManager.lastCard(row.street)?.let { card -> if (card.value != null && card.suit != null) { @@ -634,10 +620,60 @@ class HHBuilder : BoardChangedListener { } override fun boardChanged() { - this.currentRowRepresentables.filterIsInstance().forEach { + this.rowRepresentables.filterIsInstance().forEach { it.cards = this.boardManager.allCards } } + /*** + * Saves the current hand state in the database + */ + private fun save() { + + } + + /*** + * The list of row representables, generated from the hand history actions + */ + var rowRepresentables = mutableListOf() + private set + + private fun createRowRepresentation() { + val rows: MutableList = mutableListOf() + + rows.add(CustomizableRowRepresentable(customViewType = HandRowType.HEADER, resId = R.string.settings)) + + var potSize = 0.0 + Street.values().forEach { street -> + + val actions = this.sortedActions.filter { it.action.street == street } + + if (actions.isNotEmpty()) { + + addStreetHeader(rows, street, potSize) + + // Actions + rows.addAll(actions) + + potSize = actions.last().totalPotSize + } + + } + + this.rowRepresentables = rows +// return rows + } + + private fun addStreetHeader(rowRepresentables: MutableList, street: Street, potSize: Double) { + val headerView = CustomizableRowRepresentable(customViewType = HandRowType.HEADER, resId = street.resId) + rowRepresentables.add(headerView) + + if (street.totalBoardCards > 0) { + val boardView = StreetCardView(street, this.handHistory.cardsForStreet(street), potSize) + rowRepresentables.add(boardView) + } + + } + } diff --git a/app/src/main/java/net/pokeranalytics/android/model/handhistory/Street.kt b/app/src/main/java/net/pokeranalytics/android/model/handhistory/Street.kt index 861e5c11..58fd50f0 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/handhistory/Street.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/handhistory/Street.kt @@ -6,7 +6,8 @@ enum class Street { PREFLOP, FLOP, TURN, - RIVER; + RIVER, + SUMMARY; val totalBoardCards: Int get() { @@ -14,7 +15,7 @@ enum class Street { PREFLOP -> 0 FLOP -> 3 TURN -> 4 - RIVER -> 5 + RIVER, SUMMARY -> 5 } } @@ -25,8 +26,14 @@ enum class Street { FLOP -> R.string.street_flop TURN -> R.string.street_turn RIVER -> R.string.street_river + SUMMARY -> R.string.summary } } + val next: Street + get() { + return values()[this.ordinal + 1] + } + } diff --git a/app/src/main/java/net/pokeranalytics/android/model/realm/handhistory/HandHistory.kt b/app/src/main/java/net/pokeranalytics/android/model/realm/handhistory/HandHistory.kt index dc578a96..6942e108 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/realm/handhistory/HandHistory.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/realm/handhistory/HandHistory.kt @@ -59,7 +59,7 @@ open class HandHistory : RealmObject(), RowRepresentable, Identifiable, Filterab /*** * Number of players in the hand */ - var numberOfPlayers: Int = 9 + var numberOfPlayers: Int = 4 /*** * Number of players in the hand @@ -104,26 +104,26 @@ open class HandHistory : RealmObject(), RowRepresentable, Identifiable, Filterab handSetup.smallBlind?.let { this.smallBlind = it } handSetup.bigBlind?.let { this.bigBlind = it } - for (i in 0 until this.numberOfPlayers) { - val action = Action() - action.index = i - action.position = i - when (i) { - 0 -> { - action.type = Action.Type.POST_SB - action.amount = this.smallBlind - } -// 1 -> { -// action.type = Action.Type.POST_BB -// action.amount = this.bigBlind -// } - else -> {} - } - this.actions.add(action) + this.addAction(0, 0, Action.Type.POST_SB, this.smallBlind) +// this.addAction(1, 1, Action.Type.POST_BB, this.bigBlind) + + val totalActions = this.actions.size + + for (i in totalActions until this.numberOfPlayers + totalActions - 1) { + this.addAction(i, i % this.numberOfPlayers) } } + private fun addAction(index: Int, position: Int, type: Action.Type? = null, amount: Double? = null) { + val action = Action() + action.index = index + action.position = position + action.type = type + action.amount = amount + this.actions.add(action) + } + fun cardsForStreet(street: Street): MutableList { return this.board.sortedBy { it.index }.take(street.totalBoardCards).toMutableList() } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/HandHistoryFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/HandHistoryFragment.kt index 7d07fdf9..90b70511 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/HandHistoryFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/HandHistoryFragment.kt @@ -14,7 +14,6 @@ import net.pokeranalytics.android.model.handhistory.* 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.adapter.RowRepresentableDataSource import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate import net.pokeranalytics.android.ui.fragment.components.RealmFragment import net.pokeranalytics.android.ui.modules.handhistory.views.KeyboardListener @@ -25,13 +24,13 @@ import net.pokeranalytics.android.util.extensions.findById import net.pokeranalytics.android.util.extensions.noGroupingFormatted import timber.log.Timber -class HandHistoryFragment : RealmFragment(), RowRepresentableDataSource, RowRepresentableDelegate, KeyboardListener { +class HandHistoryFragment : RealmFragment(), RowRepresentableDelegate, KeyboardListener { private lateinit var model: HandHistoryViewModel private lateinit var handHistoryAdapter: HandHistoryAdapter - private var rows: List = listOf() +// private var rows: List = listOf() companion object { @@ -84,7 +83,7 @@ class HandHistoryFragment : RealmFragment(), RowRepresentableDataSource, RowRepr } this.model.setBuilder(builder) - this.rows = this.model.builderLiveData.value?.rowRepresentables() ?: listOf() +// this.rows = this.model.builderLiveData.value?.rowRepresentables() ?: listOf() } @@ -96,11 +95,7 @@ class HandHistoryFragment : RealmFragment(), RowRepresentableDataSource, RowRepr // SmoothScrollLinearLayoutManager(requireContext()) // val viewManager = LinearLayoutManager(requireContext()) - this.handHistoryAdapter = - HandHistoryAdapter( - this, - this - ) + this.handHistoryAdapter = HandHistoryAdapter(this.model,this) recyclerView.apply { setHasFixedSize(true) @@ -140,7 +135,7 @@ class HandHistoryFragment : RealmFragment(), RowRepresentableDataSource, RowRepr private fun retrieveEditTextInputConnection(position: Int) { - val computedAction = this.rowRepresentableForPosition(position) as? ComputedAction + val computedAction = this.model.rowRepresentableForPosition(position) as? ComputedAction val holder = recyclerView.findViewHolderForAdapterPosition(position) as? HandHistoryAdapter.RowHandAction holder?.let { @@ -155,6 +150,7 @@ class HandHistoryFragment : RealmFragment(), RowRepresentableDataSource, RowRepr private fun edit() { this.model.isEdited = true findNextActionToEdit(0) +// this.handHistoryAdapter.notifyDataSetChanged() } private fun closeEdition() { @@ -176,24 +172,6 @@ class HandHistoryFragment : RealmFragment(), RowRepresentableDataSource, RowRepr this.refreshCells(startIndex) } - // RowRepresentableDataSource - - override fun adapterRows(): List? { - return this.rows - } - - override fun rowRepresentableForPosition(position: Int): RowRepresentable? { - return this.rows[position] - } - - override fun numberOfRows(): Int { - return this.rows.size - } - - override fun viewTypeForPosition(position: Int): Int { - return this.rows[position].viewType - } - override fun onRowSelected(position: Int, row: RowRepresentable, tag: Int) { super.onRowSelected(position, row, tag) @@ -242,13 +220,6 @@ class HandHistoryFragment : RealmFragment(), RowRepresentableDataSource, RowRepr this.model.currentAmount = value as String } - override fun isSelected(position: Int, row: RowRepresentable, tag: Int): Boolean { - val currentSelection = this.model.selectionLiveData - val isSelectedIndex = (position == currentSelection.value?.index) - val isSelectedAction = (tag == currentSelection.value?.keyboard?.ordinal) -// Timber.d("position = $position, tag = $tag, current index = ${currentSelection?.index}, kb = ${currentSelection?.keyboard}") - return isSelectedIndex && isSelectedAction - } // Keyboard Listener @@ -321,7 +292,7 @@ class HandHistoryFragment : RealmFragment(), RowRepresentableDataSource, RowRepr override fun positionSelected(position: Position) { val rowRepresentableIndex = this.model.nextActionIndexForPosition(position) - this.rowRepresentableForPosition(rowRepresentableIndex)?.let { + this.model.rowRepresentableForPosition(rowRepresentableIndex)?.let { onRowSelected(rowRepresentableIndex, it, HHKeyboard.ACTION.ordinal) this.handHistoryAdapter.notifyItemChanged(rowRepresentableIndex) } ?: throw PAIllegalStateException("Rowrepresentable not fouind at index $rowRepresentableIndex") diff --git a/app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/HandHistoryViewModel.kt b/app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/HandHistoryViewModel.kt index c9bd097f..619cd970 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/HandHistoryViewModel.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/HandHistoryViewModel.kt @@ -9,12 +9,13 @@ import net.pokeranalytics.android.model.handhistory.HHSelection import net.pokeranalytics.android.model.handhistory.Position import net.pokeranalytics.android.model.realm.handhistory.Action import net.pokeranalytics.android.model.realm.handhistory.Card -import net.pokeranalytics.android.model.realm.handhistory.CardProperty +import net.pokeranalytics.android.ui.adapter.RowRepresentableDataSource +import net.pokeranalytics.android.ui.view.RowRepresentable import timber.log.Timber -class HandHistoryViewModel : ViewModel() { +class HandHistoryViewModel : ViewModel(), RowRepresentableDataSource { - var builderLiveData = MutableLiveData() + private var builderLiveData = MutableLiveData() val builder: HHBuilder get() { @@ -30,8 +31,6 @@ class HandHistoryViewModel : ViewModel() { var currentAmount: String? = null - var lastCardPropertySelection: CardProperty? = null - fun setBuilder(builder: HHBuilder) { this.builderLiveData.value = builder } @@ -100,4 +99,29 @@ class HandHistoryViewModel : ViewModel() { return this.builder.nextActionIndex(this.actionIndexForSelection, position) } + // Row Representable Datasource + + override fun adapterRows(): List? { + return this.builder.rowRepresentables + } + + override fun rowRepresentableForPosition(position: Int): RowRepresentable? { + return this.builder.rowRepresentables[position] + } + + override fun numberOfRows(): Int { + return this.builder.rowRepresentables.size + } + + override fun viewTypeForPosition(position: Int): Int { + return this.builder.rowRepresentables[position].viewType + } + + override fun isSelected(position: Int, row: RowRepresentable, tag: Int): Boolean { + val currentSelection = this.selectionLiveData + val isSelectedIndex = (position == currentSelection.value?.index) + val isSelectedAction = (tag == currentSelection.value?.keyboard?.ordinal) + return isSelectedIndex && isSelectedAction + } + } \ No newline at end of file