Added winner player checks

This commit is contained in:
Salatiel Genol 2023-05-19 23:01:10 +02:00
parent 19df47972a
commit db61c25b03
6 changed files with 139 additions and 144 deletions

View File

@ -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
}
}

View File

@ -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)

View File

@ -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)
}
}
}

View File

@ -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 ->
if (player){
playerValue(grid[row][col])?.let { player ->
if (player) {
CircleIcon()
}else if(!player){
} else {
CrossIcon()
}
}

View File

@ -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)
}

View File

@ -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() }
}
}
}