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