Skip to content

Instantly share code, notes, and snippets.

@ardakazanci
Created January 8, 2024 16:49
Show Gist options
  • Save ardakazanci/ed9cbca5da1df610c1430e7648b8f46f to your computer and use it in GitHub Desktop.
Save ardakazanci/ed9cbca5da1df610c1430e7648b8f46f to your computer and use it in GitHub Desktop.
Tic Tac Toe - Jetpack Compose
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
TicTacToeGameTheme {
TicTacToeGame()
}
}
}
}
@Composable
fun TicTacToeGame() {
val gridSize = 3
val cellSizeDp = 200.dp / gridSize
val cellSizePx = with(LocalDensity.current) { cellSizeDp.toPx() }
var grid by remember { mutableStateOf(Array(gridSize) { CharArray(gridSize) { ' ' } }) }
var currentPlayer by remember { mutableStateOf('X') }
var winner by remember { mutableStateOf<Char?>(null) }
var animationOffset by remember { mutableStateOf(0.dp) }
LaunchedEffect(winner) {
if (winner != null) {
animationOffset = -300.dp
}
}
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Canvas(modifier = Modifier
.size(200.dp)
.pointerInput(Unit) {
detectTapGestures { offset ->
val x = (offset.x / cellSizePx).toInt()
val y = (offset.y / cellSizePx).toInt()
if (grid[y][x] == ' ' && winner == null) {
grid = grid.copyOf().also { it[y][x] = currentPlayer }
currentPlayer = if (currentPlayer == 'X') 'O' else 'X'
winner = checkWinner(grid)
}
}
}) {
val gradientBrush = Brush.linearGradient(
colors = listOf(Color.Yellow, Color.Magenta)
)
for (i in 1 until gridSize) {
drawLine(
brush = gradientBrush,
start = Offset(x = cellSizePx * i, y = 0f),
end = Offset(x = cellSizePx * i, y = 200.dp.toPx()),
strokeWidth = 4.dp.toPx()
)
drawLine(
brush = gradientBrush,
start = Offset(x = 0f, y = cellSizePx * i),
end = Offset(x = 200.dp.toPx(), y = cellSizePx * i),
strokeWidth = 4.dp.toPx()
)
}
for (i in 0 until gridSize) {
for (j in 0 until gridSize) {
val offsetX = cellSizePx * j
val offsetY = cellSizePx * i
when (grid[i][j]) {
'X' -> drawX(offsetX, offsetY, cellSizePx)
'O' -> drawO(offsetX, offsetY, cellSizePx)
}
}
}
}
AnimatedVisibility(visible = winner != null) {
Row(
verticalAlignment = Alignment.Top,
horizontalArrangement = Arrangement.Center,
modifier = Modifier.fillMaxWidth()
) {
Text(
text = "Winner: ${winner ?: ""}",
fontSize = 24.sp,
fontWeight = FontWeight.Bold,
color = Color.Red,
modifier = Modifier.padding(16.dp)
)
}
}
}
}
private fun checkWinner(grid: Array<CharArray>): Char? {
for (row in grid) {
if (row[0] != ' ' && row[0] == row[1] && row[0] == row[2]) {
return row[0]
}
}
for (col in 0..2) {
if (grid[0][col] != ' ' && grid[0][col] == grid[1][col] && grid[0][col] == grid[2][col]) {
return grid[0][col]
}
}
if (grid[0][0] != ' ' && grid[0][0] == grid[1][1] && grid[0][0] == grid[2][2]) {
return grid[0][0]
}
if (grid[0][2] != ' ' && grid[0][2] == grid[1][1] && grid[0][2] == grid[2][0]) {
return grid[0][2]
}
if (grid.all { row -> row.all { cell -> cell != ' ' } }) {
return 'D'
}
return null
}
private fun DrawScope.drawX(offsetX: Float, offsetY: Float, size: Float) {
val gradientBrush = Brush.linearGradient(
colors = listOf(Color.Black, Color.Cyan)
)
drawLine(
brush = gradientBrush,
start = Offset(offsetX, offsetY),
end = Offset(offsetX + size, offsetY + size),
strokeWidth = 14F
)
drawLine(
brush = gradientBrush,
start = Offset(offsetX + size, offsetY),
end = Offset(offsetX, offsetY + size),
strokeWidth = 14F
)
}
private fun DrawScope.drawO(offsetX: Float, offsetY: Float, size: Float) {
val gradientBrush = Brush.linearGradient(
colors = listOf(Color.Blue, Color.Red)
)
drawCircle(
brush = gradientBrush,
radius = size / 2,
center = Offset(offsetX + size / 2, offsetY + size / 2),
style = Stroke(width = 6.dp.toPx())
)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment