puzzle8 / minimal_global.R
aephiday's picture
Create minimal_global.R
ea72b5a verified
# Minimal Global Functions for Puzzle8 Game
# Simple, fast, and focused on core gameplay
# Constants
SOLVED_STATE <- c(1, 2, 3, 4, 5, 6, 7, 8, 0)
# Utility functions
pos_to_coords <- function(pos) {
list(row = (pos - 1) %/% 3 + 1, col = (pos - 1) %% 3 + 1)
}
coords_to_pos <- function(row, col) {
(row - 1) * 3 + col
}
is_valid_position <- function(row, col) {
row >= 1 && row <= 3 && col >= 1 && col <= 3
}
# Create a solvable puzzle using simple shuffling
create_solvable_puzzle <- function(moves = 100) {
puzzle <- SOLVED_STATE
blank_pos <- 9
# Simple shuffling with valid moves
for(i in 1:moves) {
coords <- pos_to_coords(blank_pos)
valid_moves <- c()
# Check all four directions
directions <- list(
list(row = -1, col = 0), # Up
list(row = 1, col = 0), # Down
list(row = 0, col = -1), # Left
list(row = 0, col = 1) # Right
)
for(dir in directions) {
new_row <- coords$row + dir$row
new_col <- coords$col + dir$col
if(is_valid_position(new_row, new_col)) {
valid_moves <- c(valid_moves, coords_to_pos(new_row, new_col))
}
}
if(length(valid_moves) > 0) {
move_pos <- sample(valid_moves, 1)
# Swap tiles
temp <- puzzle[blank_pos]
puzzle[blank_pos] <- puzzle[move_pos]
puzzle[move_pos] <- temp
blank_pos <- move_pos
}
}
# Ensure puzzle is not already solved
if(identical(puzzle, SOLVED_STATE)) {
return(create_solvable_puzzle(moves + 20))
}
return(puzzle)
}
# Check if puzzle is solved
is_solved <- function(puzzle) {
identical(puzzle, SOLVED_STATE)
}
# Get blank position
get_blank_position <- function(puzzle) {
which(puzzle == 0)[1]
}
# Get valid moves for current blank position
get_valid_moves <- function(blank_pos) {
coords <- pos_to_coords(blank_pos)
valid_moves <- c()
directions <- list(
list(row = -1, col = 0), # Up
list(row = 1, col = 0), # Down
list(row = 0, col = -1), # Left
list(row = 0, col = 1) # Right
)
for(dir in directions) {
new_row <- coords$row + dir$row
new_col <- coords$col + dir$col
if(is_valid_position(new_row, new_col)) {
valid_moves <- c(valid_moves, coords_to_pos(new_row, new_col))
}
}
return(valid_moves)
}
# Move tile with validation - core game mechanic
move_tile <- function(puzzle, tile_position) {
blank_pos <- get_blank_position(puzzle)
valid_moves <- get_valid_moves(blank_pos)
if(tile_position %in% valid_moves) {
# Create new puzzle state
new_puzzle <- puzzle
new_puzzle[blank_pos] <- puzzle[tile_position]
new_puzzle[tile_position] <- 0
return(list(puzzle = new_puzzle, moved = TRUE))
}
return(list(puzzle = puzzle, moved = FALSE))
}
# Check if puzzle is solvable using inversion count
is_solvable <- function(puzzle) {
# Count inversions (excluding blank tile)
tiles <- puzzle[puzzle != 0]
inversions <- 0
for(i in 1:(length(tiles) - 1)) {
for(j in (i + 1):length(tiles)) {
if(tiles[i] > tiles[j]) {
inversions <- inversions + 1
}
}
}
# For 3x3 puzzle, solvable if inversions are even
return(inversions %% 2 == 0)
}
# Validate puzzle state
validate_puzzle <- function(puzzle) {
# Check length
if(length(puzzle) != 9) {
return(FALSE)
}
# Check if all numbers 0-8 are present exactly once
expected_tiles <- 0:8
if(!setequal(puzzle, expected_tiles)) {
return(FALSE)
}
# Check if solvable
if(!is_solvable(puzzle)) {
return(FALSE)
}
return(TRUE)
}
# Generate test puzzles for development
generate_test_puzzles <- function(n = 5) {
puzzles <- list()
for(i in 1:n) {
repeat {
puzzle <- create_solvable_puzzle()
if(validate_puzzle(puzzle) && !is_solved(puzzle)) {
puzzles[[i]] <- puzzle
break
}
}
}
return(puzzles)
}
# Simple puzzle statistics
get_puzzle_stats <- function(puzzle) {
blank_pos <- get_blank_position(puzzle)
valid_moves <- get_valid_moves(blank_pos)
return(list(
blank_position = blank_pos,
valid_moves = valid_moves,
num_valid_moves = length(valid_moves),
is_solved = is_solved(puzzle),
is_valid = validate_puzzle(puzzle)
))
}