Project finished
This commit is contained in:
parent
db61c25b03
commit
05ee944432
|
|
@ -1,11 +1,19 @@
|
||||||
package es.genol.tictactoe.ui.elements
|
package es.genol.tictactoe.ui.elements
|
||||||
|
|
||||||
|
import androidx.compose.foundation.border
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.fillMaxHeight
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.Close
|
||||||
|
import androidx.compose.material3.BottomAppBar
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.Button
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.Surface
|
import androidx.compose.material3.Surface
|
||||||
|
|
@ -14,17 +22,25 @@ import androidx.compose.material3.TopAppBar
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import es.genol.tictactoe.ui.state.GameState
|
import es.genol.tictactoe.ui.state.GameState
|
||||||
|
import es.genol.tictactoe.ui.theme.CrossIcon
|
||||||
|
import es.genol.tictactoe.ui.theme.DrawIcon
|
||||||
import es.genol.tictactoe.ui.theme.TicTacToeTheme
|
import es.genol.tictactoe.ui.theme.TicTacToeTheme
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun AppContent() {
|
fun AppContent() {
|
||||||
val viewModel: GameState = viewModel()
|
val viewModel: GameState = viewModel()
|
||||||
if (viewModel.isWinner) {
|
|
||||||
|
|
||||||
|
if (viewModel.isWinner) {
|
||||||
|
WinnerDialog(winner = viewModel.currentPlayer, behavior = { viewModel.cleanGrid() })
|
||||||
|
}
|
||||||
|
|
||||||
|
if (viewModel.moveNumber == 9) {
|
||||||
|
DrawDialog(behavior = { viewModel.cleanGrid() })
|
||||||
}
|
}
|
||||||
|
|
||||||
TicTacToeTheme {
|
TicTacToeTheme {
|
||||||
|
|
@ -37,8 +53,10 @@ fun AppContent() {
|
||||||
TopAppBar(
|
TopAppBar(
|
||||||
title = { Text(text = "TicTacToe") },
|
title = { Text(text = "TicTacToe") },
|
||||||
actions = {
|
actions = {
|
||||||
Button(onClick = { viewModel.gridClean() }) {
|
if (viewModel.moveNumber != null) {
|
||||||
Text(text = "REINICIAR")
|
Button(onClick = { viewModel.cleanGrid() }) {
|
||||||
|
Text(text = "REINICIAR")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
@ -49,18 +67,19 @@ fun AppContent() {
|
||||||
.padding(vertical = 15.dp)
|
.padding(vertical = 15.dp)
|
||||||
.fillMaxWidth(),
|
.fillMaxWidth(),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
) {println("Antes de gameboard")
|
) {
|
||||||
GameBoard(
|
GameBoard(
|
||||||
boardSize = 3,
|
boardSize = 3,
|
||||||
playerValue = { gridId ->
|
playerValue = { gridId ->
|
||||||
viewModel.gridState[gridId].player
|
viewModel.gridState[gridId].player
|
||||||
},
|
},
|
||||||
buttonEnabled = !viewModel.isWinner
|
buttonEnabled = !viewModel.isWinner && viewModel.moveNumber != 9
|
||||||
) { gridId ->
|
) { gridId ->
|
||||||
viewModel.gridMarkPlayer(gridId)
|
viewModel.playerMarkGrid(gridId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,12 +8,3 @@ import androidx.compose.ui.res.painterResource
|
||||||
import es.genol.tictactoe.R
|
import es.genol.tictactoe.R
|
||||||
import es.genol.tictactoe.ui.theme.CustomGreen
|
import es.genol.tictactoe.ui.theme.CustomGreen
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun CircleIcon() {
|
|
||||||
Icon(
|
|
||||||
painter = painterResource(id = R.drawable.outline_circle_24),
|
|
||||||
contentDescription = "Cross red icon",
|
|
||||||
modifier = Modifier.fillMaxSize(),
|
|
||||||
tint = CustomGreen
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
@ -8,12 +8,3 @@ import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import es.genol.tictactoe.ui.theme.CustomRed
|
import es.genol.tictactoe.ui.theme.CustomRed
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun CrossIcon() {
|
|
||||||
Icon(
|
|
||||||
Icons.Default.Close,
|
|
||||||
contentDescription = "Cross red icon",
|
|
||||||
modifier = Modifier.fillMaxSize(),
|
|
||||||
tint = CustomRed
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
@ -13,6 +13,8 @@ import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import es.genol.tictactoe.ui.theme.CircleIcon
|
||||||
|
import es.genol.tictactoe.ui.theme.CrossIcon
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun GameBoard(
|
fun GameBoard(
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
package es.genol.tictactoe.ui.elements
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.material3.AlertDialog
|
||||||
|
import androidx.compose.material3.Button
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import es.genol.tictactoe.ui.theme.CircleIcon
|
||||||
|
import es.genol.tictactoe.ui.theme.CrossIcon
|
||||||
|
import es.genol.tictactoe.ui.theme.DrawIcon
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun WinnerDialog(
|
||||||
|
winner: Boolean,
|
||||||
|
behavior: () -> Unit
|
||||||
|
){
|
||||||
|
AlertDialog(
|
||||||
|
onDismissRequest = behavior,
|
||||||
|
confirmButton = { Button(onClick = behavior) {
|
||||||
|
Text(text = "Otra partida")
|
||||||
|
} },
|
||||||
|
Modifier.fillMaxSize(.95f),
|
||||||
|
title = { Text(text = "Ganador!!!")},
|
||||||
|
text = {
|
||||||
|
if (winner) {
|
||||||
|
CircleIcon()
|
||||||
|
} else {
|
||||||
|
CrossIcon()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun DrawDialog(
|
||||||
|
behavior: () -> Unit
|
||||||
|
){
|
||||||
|
AlertDialog(
|
||||||
|
onDismissRequest = behavior,
|
||||||
|
confirmButton = { Button(onClick = behavior) {
|
||||||
|
Text(text = "Otra partida")
|
||||||
|
} },
|
||||||
|
Modifier.fillMaxSize(.95f),
|
||||||
|
title = { Text(text = "Empate")},
|
||||||
|
text = {
|
||||||
|
DrawIcon()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -12,23 +12,31 @@ import kotlin.random.Random
|
||||||
class GameState : ViewModel() {
|
class GameState : ViewModel() {
|
||||||
private var _gridState = MutableList(9) { Ficha() }.toMutableStateList()
|
private var _gridState = MutableList(9) { Ficha() }.toMutableStateList()
|
||||||
val gridState get() = _gridState.toList()
|
val gridState get() = _gridState.toList()
|
||||||
private var currentPlayer = ramdomPlayer()
|
|
||||||
|
|
||||||
var isWinner by mutableStateOf(false)
|
private var _currentPlayer = ramdomPlayer()
|
||||||
private set
|
val currentPlayer get() = !_currentPlayer
|
||||||
|
|
||||||
fun gridMarkPlayer(gridId: Int) {
|
private var _isWinner by mutableStateOf(false)
|
||||||
|
val isWinner get() = _isWinner
|
||||||
|
|
||||||
|
private var _moveNumber by mutableStateOf<Int?>(null)
|
||||||
|
val moveNumber get() = _moveNumber
|
||||||
|
|
||||||
|
|
||||||
|
fun playerMarkGrid(gridId: Int) {
|
||||||
if (_gridState[gridId].player == null) {
|
if (_gridState[gridId].player == null) {
|
||||||
_gridState[gridId] = _gridState[gridId].copy(player = currentPlayer)
|
_gridState[gridId] = _gridState[gridId].copy(player = _currentPlayer)
|
||||||
isWinner = GameChecks(currentPlayer, gridData = gridState).playerWinnerCheck()
|
_isWinner = GameChecks(_currentPlayer, gridData = gridState).playerWinnerCheck()
|
||||||
currentPlayer = !currentPlayer
|
_moveNumber = (_gridState.count { it.player != null })
|
||||||
|
_currentPlayer = !_currentPlayer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun gridClean() {
|
fun cleanGrid() {
|
||||||
repeat(9) { _gridState[it] = Ficha() }
|
repeat(9) { _gridState[it] = Ficha() }
|
||||||
currentPlayer = ramdomPlayer()
|
_currentPlayer = ramdomPlayer()
|
||||||
isWinner = false
|
_isWinner = false
|
||||||
|
_moveNumber = null
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ramdomPlayer() = (Random.nextBits(bitCount = 1) > 0)
|
private fun ramdomPlayer() = (Random.nextBits(bitCount = 1) > 0)
|
||||||
|
|
|
||||||
|
|
@ -12,3 +12,4 @@ val Pink40 = Color(0xFF7D5260)
|
||||||
|
|
||||||
val CustomRed = Color(0xFFF72F2F)
|
val CustomRed = Color(0xFFF72F2F)
|
||||||
val CustomGreen = Color(0xFF4DF72F)
|
val CustomGreen = Color(0xFF4DF72F)
|
||||||
|
val CustomBlue = Color(0xFF2FA0F7)
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
package es.genol.tictactoe.ui.theme
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.Close
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import es.genol.tictactoe.R
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun CrossIcon() {
|
||||||
|
Icon(
|
||||||
|
Icons.Default.Close,
|
||||||
|
contentDescription = "Cross red icon",
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
tint = CustomRed
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun CircleIcon() {
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(id = R.drawable.outline_circle_24),
|
||||||
|
contentDescription = "Cross red icon",
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
tint = CustomGreen
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun DrawIcon() {
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(id = R.drawable.baseline_handshake_24),
|
||||||
|
contentDescription = "Draw blue icon",
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
tint = CustomBlue
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
<vector android:height="24dp" android:tint="#000000"
|
||||||
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M16.48,10.41c-0.39,0.39 -1.04,0.39 -1.43,0l-4.47,-4.46l-7.05,7.04l-0.66,-0.63c-1.17,-1.17 -1.17,-3.07 0,-4.24l4.24,-4.24c1.17,-1.17 3.07,-1.17 4.24,0L16.48,9C16.87,9.39 16.87,10.02 16.48,10.41zM17.18,8.29c0.78,0.78 0.78,2.05 0,2.83c-1.27,1.27 -2.61,0.22 -2.83,0l-3.76,-3.76l-5.57,5.57c-0.39,0.39 -0.39,1.02 0,1.41c0.39,0.39 1.02,0.39 1.42,0l4.62,-4.62l0.71,0.71l-4.62,4.62c-0.39,0.39 -0.39,1.02 0,1.41c0.39,0.39 1.02,0.39 1.42,0l4.62,-4.62l0.71,0.71l-4.62,4.62c-0.39,0.39 -0.39,1.02 0,1.41c0.39,0.39 1.02,0.39 1.41,0l4.62,-4.62l0.71,0.71l-4.62,4.62c-0.39,0.39 -0.39,1.02 0,1.41c0.39,0.39 1.02,0.39 1.41,0l8.32,-8.34c1.17,-1.17 1.17,-3.07 0,-4.24l-4.24,-4.24c-1.15,-1.15 -3.01,-1.17 -4.18,-0.06L17.18,8.29z"/>
|
||||||
|
</vector>
|
||||||
Loading…
Reference in New Issue