Skip to content

Instantly share code, notes, and snippets.

@ardakazanci
Created November 22, 2024 17:31
Show Gist options
  • Save ardakazanci/23e5aabc42fb35e5bd34478aa0620e59 to your computer and use it in GitHub Desktop.
Save ardakazanci/23e5aabc42fb35e5bd34478aa0620e59 to your computer and use it in GitHub Desktop.
Maze Generator Jetpack Compose
enum class CellType {
Space, Wall
}
data class MazeTile(val x: Int, val y: Int, var type: CellType = CellType.Wall)
@RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
class Maze(private val width: Int, private val height: Int) {
val maze: Array<Array<MazeTile>> = Array(height) { y ->
Array(width) { x -> MazeTile(x, y) }
}
val visited: Array<Array<Boolean>> = Array(height) { Array(width) { false } }
val stack: MutableList<MazeTile> = mutableListOf()
init {
generateMaze(1, 1)
addEntranceAndExit()
}
@RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
private fun generateMaze(x: Int, y: Int) {
val startTile = maze[y][x]
stack.add(startTile)
visited[y][x] = true
startTile.type = CellType.Space
while (stack.isNotEmpty()) {
val currentTile = stack.last()
val neighbors = mutableListOf<MazeTile>()
listOf(
currentTile.x to (currentTile.y + 2),
currentTile.x to (currentTile.y - 2),
(currentTile.x + 2) to currentTile.y,
(currentTile.x - 2) to currentTile.y
).forEach { (nx, ny) ->
if (isValidCoordinate(nx, ny) && !visited[ny][nx]) {
neighbors.add(maze[ny][nx])
}
}
if (neighbors.isNotEmpty()) {
val nextTile = neighbors.random()
stack.add(nextTile)
nextTile.type = CellType.Space
visited[nextTile.y][nextTile.x] = true
val wallX = (currentTile.x + nextTile.x) / 2
val wallY = (currentTile.y + nextTile.y) / 2
maze[wallY][wallX].type = CellType.Space
} else {
stack.removeLast()
}
}
}
private fun addEntranceAndExit() {
maze[0][1].type = CellType.Space
maze[height - 1][width - 2].type = CellType.Space
}
private fun isValidCoordinate(x: Int, y: Int) =
x in 1 until width - 1 && y in 1 until height - 1
}
@Composable
fun MazeCanvas(maze: Maze, cellSize: Float, modifier: Modifier = Modifier) {
Canvas(modifier) {
maze.maze.forEach { row ->
row.forEach { tile ->
if (tile.type == CellType.Wall) {
drawRect(
color = Color.Black,
topLeft = Offset((tile.x * cellSize), (tile.y * cellSize)),
size = androidx.compose.ui.geometry.Size(cellSize, cellSize)
)
}
}
}
}
}
@RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
@Composable
fun MazeScreen(modifier: Modifier = Modifier) {
var width by remember { mutableIntStateOf(21) }
var height by remember { mutableIntStateOf(21) }
var cellSize by remember { mutableFloatStateOf(40f) }
val maze = remember(width, height) { Maze(width, height) }
Column(modifier = modifier.padding(16.dp), horizontalAlignment = Alignment.CenterHorizontally) {
Text(text = "Maze Size: Width ($width), Height ($height)")
Slider(
value = width.toFloat(),
onValueChange = {
width = it.toInt().coerceIn(5, 51)
height = it.toInt().coerceIn(5, 51)
},
valueRange = 5f..51f,
modifier = Modifier.padding(vertical = 8.dp)
)
Text(text = "Cell Size: ${cellSize.toInt()} px")
Slider(
value = cellSize,
onValueChange = {
cellSize = it.coerceIn(20f, 80f)
},
valueRange = 20f..80f,
modifier = Modifier.padding(vertical = 8.dp)
)
Box(modifier = Modifier.padding(16.dp)) {
MazeCanvas(
maze,
cellSize,
modifier = Modifier.size((width * cellSize).dp, (height * cellSize).dp)
)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment