Project finished

This commit is contained in:
Salatiel Genol 2023-05-20 01:59:25 +02:00
parent db61c25b03
commit 05ee944432
9 changed files with 143 additions and 36 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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