Added winner player checks
This commit is contained in:
parent
19df47972a
commit
db61c25b03
|
|
@ -0,0 +1,57 @@
|
|||
package es.genol.tictactoe
|
||||
|
||||
import es.genol.tictactoe.data.model.Ficha
|
||||
|
||||
class GameChecks(private val player: Boolean, private val gridData: List<Ficha>) {
|
||||
fun playerWinnerCheck(): Boolean {
|
||||
if (diagonalCheck() || verticalCheck() || horizontalCheck()) return true
|
||||
return false
|
||||
}
|
||||
|
||||
private fun diagonalCheck(): Boolean {
|
||||
var result: Int
|
||||
for (start in 0..2 step 2) {
|
||||
var stage = 0
|
||||
when (start){
|
||||
0 -> stage = 4
|
||||
2 -> stage = 2
|
||||
}
|
||||
result = 0
|
||||
for (gridId in start..(stage * 2 + start) step stage) {
|
||||
if (gridData[gridId].player == player) {
|
||||
result++
|
||||
}
|
||||
if (result == 3) return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun verticalCheck(): Boolean {
|
||||
var result: Int
|
||||
for (start in 0..2) {
|
||||
result = 0
|
||||
for (gridId in start..start + 6 step 3) {
|
||||
if (gridData[gridId].player == player) {
|
||||
result++
|
||||
}
|
||||
if (result == 3) return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun horizontalCheck(): Boolean {
|
||||
var result: Int
|
||||
for (start in 0..6 step 3) {
|
||||
result = 0
|
||||
for (gridId in start..start + 2) {
|
||||
if (gridData[gridId].player == player) {
|
||||
result++
|
||||
}
|
||||
if (result == 3) return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
package es.genol.tictactoe.data.model
|
||||
|
||||
data class Ficha(val row: Int, val col: Int, var player: Boolean?)
|
||||
data class Ficha(var player: Boolean? = null)
|
||||
|
|
@ -1,57 +1,30 @@
|
|||
package es.genol.tictactoe.ui.elements
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.SnackbarDuration
|
||||
import androidx.compose.material3.SnackbarHost
|
||||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalConfiguration
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import es.genol.tictactoe.ui.state.TicTacToeViewModel
|
||||
import es.genol.tictactoe.ui.state.GameState
|
||||
import es.genol.tictactoe.ui.theme.TicTacToeTheme
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun AppContent() {
|
||||
val viewModel: TicTacToeViewModel = viewModel()
|
||||
val configuration = LocalConfiguration.current
|
||||
val orientationHeight: Float
|
||||
val orientationWidth: Float
|
||||
val snackBarState = remember { SnackbarHostState() }
|
||||
|
||||
when (configuration.orientation) {
|
||||
Configuration.ORIENTATION_PORTRAIT -> {
|
||||
orientationHeight = .42f
|
||||
orientationWidth = .65f
|
||||
}
|
||||
|
||||
else -> {
|
||||
orientationHeight = 1f
|
||||
orientationWidth = .35f
|
||||
}
|
||||
}
|
||||
|
||||
val viewModel: GameState = viewModel()
|
||||
if (viewModel.isWinner) {
|
||||
LaunchedEffect(key1 = viewModel.isWinner) {
|
||||
viewModel.resetFromSnackBar(snackBarState.showSnackbar(
|
||||
message = "Ganador",
|
||||
actionLabel = "Reiniciar",
|
||||
duration = SnackbarDuration.Indefinite
|
||||
))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
TicTacToeTheme {
|
||||
|
|
@ -59,26 +32,32 @@ fun AppContent() {
|
|||
modifier = Modifier.fillMaxSize(),
|
||||
color = MaterialTheme.colorScheme.background
|
||||
) {
|
||||
Scaffold(topBar = {
|
||||
Scaffold(
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
title = { Text(text = "TicTacToe") },
|
||||
actions = {
|
||||
Button(onClick = { viewModel.boardReboot() }) {
|
||||
Button(onClick = { viewModel.gridClean() }) {
|
||||
Text(text = "REINICIAR")
|
||||
}
|
||||
})
|
||||
}, snackbarHost = { SnackbarHost(hostState = snackBarState) }) {
|
||||
Column(Modifier.padding(it)) {
|
||||
},
|
||||
) {
|
||||
Column(
|
||||
Modifier
|
||||
.padding(it)
|
||||
.padding(vertical = 15.dp)
|
||||
.fillMaxWidth(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {println("Antes de gameboard")
|
||||
GameBoard(
|
||||
boardSize = 3,
|
||||
orientationHeight = orientationHeight,
|
||||
orientationWidth = orientationWidth,
|
||||
playerValue = { row, col ->
|
||||
viewModel.getPlayer(row, col)
|
||||
playerValue = { gridId ->
|
||||
viewModel.gridState[gridId].player
|
||||
},
|
||||
buttonEnabled = !viewModel.isWinner
|
||||
) { row, col ->
|
||||
viewModel.printPosition(row, col)
|
||||
) { gridId ->
|
||||
viewModel.gridMarkPlayer(gridId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ package es.genol.tictactoe.ui.elements
|
|||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.aspectRatio
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.runtime.Composable
|
||||
|
|
@ -17,38 +17,37 @@ import androidx.compose.ui.unit.dp
|
|||
@Composable
|
||||
fun GameBoard(
|
||||
boardSize: Int,
|
||||
orientationHeight: Float,
|
||||
orientationWidth: Float,
|
||||
playerValue: (Int, Int) -> Boolean?,
|
||||
playerValue: (Int) -> Boolean?,
|
||||
buttonEnabled: Boolean,
|
||||
onButtonClick: (Int, Int) -> Unit
|
||||
onButtonClick: (Int) -> Unit
|
||||
) {
|
||||
var gridId = 0
|
||||
val grid = Array(boardSize) { IntArray(boardSize) { gridId++ } }
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.fillMaxHeight(orientationHeight),
|
||||
Modifier
|
||||
.width(240.dp)
|
||||
.aspectRatio(1f),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.SpaceAround
|
||||
) {
|
||||
if (orientationHeight == .42f) {
|
||||
Spacer(modifier = Modifier.fillMaxHeight(.05f))
|
||||
}
|
||||
repeat(boardSize) { row ->
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(orientationWidth),
|
||||
Modifier
|
||||
.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceAround
|
||||
) {
|
||||
repeat(boardSize) { col ->
|
||||
Button(
|
||||
onClick = { onButtonClick(row, col) },
|
||||
onClick = { onButtonClick(grid[row][col]) },
|
||||
modifier = Modifier.size(75.dp),
|
||||
enabled = buttonEnabled,
|
||||
shape = CircleShape
|
||||
) {
|
||||
playerValue(row, col)?.let { player ->
|
||||
playerValue(grid[row][col])?.let { player ->
|
||||
if (player) {
|
||||
CircleIcon()
|
||||
}else if(!player){
|
||||
} else {
|
||||
CrossIcon()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
package es.genol.tictactoe.ui.state
|
||||
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.runtime.toMutableStateList
|
||||
import androidx.lifecycle.ViewModel
|
||||
import es.genol.tictactoe.GameChecks
|
||||
import es.genol.tictactoe.data.model.Ficha
|
||||
import kotlin.random.Random
|
||||
|
||||
class GameState : ViewModel() {
|
||||
private var _gridState = MutableList(9) { Ficha() }.toMutableStateList()
|
||||
val gridState get() = _gridState.toList()
|
||||
private var currentPlayer = ramdomPlayer()
|
||||
|
||||
var isWinner by mutableStateOf(false)
|
||||
private set
|
||||
|
||||
fun gridMarkPlayer(gridId: Int) {
|
||||
if (_gridState[gridId].player == null) {
|
||||
_gridState[gridId] = _gridState[gridId].copy(player = currentPlayer)
|
||||
isWinner = GameChecks(currentPlayer, gridData = gridState).playerWinnerCheck()
|
||||
currentPlayer = !currentPlayer
|
||||
}
|
||||
}
|
||||
|
||||
fun gridClean() {
|
||||
repeat(9) { _gridState[it] = Ficha() }
|
||||
currentPlayer = ramdomPlayer()
|
||||
isWinner = false
|
||||
}
|
||||
|
||||
private fun ramdomPlayer() = (Random.nextBits(bitCount = 1) > 0)
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1,77 +0,0 @@
|
|||
package es.genol.tictactoe.ui.state
|
||||
|
||||
import androidx.compose.material3.SnackbarResult
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateListOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.lifecycle.ViewModel
|
||||
import es.genol.tictactoe.data.model.Ficha
|
||||
import kotlin.random.Random
|
||||
|
||||
class TicTacToeViewModel : ViewModel() {
|
||||
private var buttonStateList = mutableStateListOf<Ficha>()
|
||||
private var playerChange = ramdomPlayer()
|
||||
|
||||
var isWinner by mutableStateOf(false)
|
||||
private set
|
||||
|
||||
|
||||
init {
|
||||
fillBoardGame()
|
||||
}
|
||||
|
||||
fun printPosition(row: Int, col: Int) {
|
||||
val index = buttonStateList.indexOf(buttonStateList.find { (it.row == row && it.col == col) })
|
||||
if (buttonStateList[index].player == null) {
|
||||
buttonStateList[index] = buttonStateList[index].copy(player = playerChange)
|
||||
isWinner = horizontalCheck(player = playerChange)
|
||||
playerChange = !playerChange
|
||||
}
|
||||
}
|
||||
|
||||
fun getPlayer(row: Int, col: Int): Boolean? {
|
||||
return buttonStateList.find { (it.row == row && it.col == col) }?.player
|
||||
}
|
||||
|
||||
fun boardReboot() {
|
||||
buttonStateList.clear()
|
||||
playerChange = ramdomPlayer()
|
||||
isWinner = false
|
||||
fillBoardGame()
|
||||
}
|
||||
|
||||
private fun fillBoardGame() {
|
||||
for (row in 0..2) {
|
||||
for (col in 0..2) {
|
||||
buttonStateList.add(
|
||||
Ficha(row, col, null)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun ramdomPlayer() = (Random.nextBits(bitCount = 1) == 1)
|
||||
|
||||
private fun horizontalCheck(player: Boolean): Boolean {
|
||||
var result: Int
|
||||
for (i in 0..6 step 3) {
|
||||
result = 0
|
||||
for (n in i..i + 2) {
|
||||
if (buttonStateList[n].player == player){
|
||||
result++
|
||||
}
|
||||
if (result == 3) return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun resetFromSnackBar(result: SnackbarResult){
|
||||
when (result) {
|
||||
SnackbarResult.Dismissed -> {}
|
||||
SnackbarResult.ActionPerformed -> { boardReboot() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue