| |
| |
|
|
| |
| SOLVED_STATE <- c(1, 2, 3, 4, 5, 6, 7, 8, 0) |
|
|
| |
| 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_solvable_puzzle <- function(moves = 100) { |
| puzzle <- SOLVED_STATE |
| blank_pos <- 9 |
| |
| |
| for(i in 1:moves) { |
| coords <- pos_to_coords(blank_pos) |
| valid_moves <- c() |
| |
| |
| directions <- list( |
| list(row = -1, col = 0), |
| list(row = 1, col = 0), |
| list(row = 0, col = -1), |
| list(row = 0, col = 1) |
| ) |
| |
| 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) |
| |
| |
| temp <- puzzle[blank_pos] |
| puzzle[blank_pos] <- puzzle[move_pos] |
| puzzle[move_pos] <- temp |
| |
| blank_pos <- move_pos |
| } |
| } |
| |
| |
| if(identical(puzzle, SOLVED_STATE)) { |
| return(create_solvable_puzzle(moves + 20)) |
| } |
| |
| return(puzzle) |
| } |
|
|
| |
| is_solved <- function(puzzle) { |
| identical(puzzle, SOLVED_STATE) |
| } |
|
|
| |
| get_blank_position <- function(puzzle) { |
| which(puzzle == 0)[1] |
| } |
|
|
| |
| get_valid_moves <- function(blank_pos) { |
| coords <- pos_to_coords(blank_pos) |
| valid_moves <- c() |
| |
| directions <- list( |
| list(row = -1, col = 0), |
| list(row = 1, col = 0), |
| list(row = 0, col = -1), |
| list(row = 0, col = 1) |
| ) |
| |
| 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 <- function(puzzle, tile_position) { |
| blank_pos <- get_blank_position(puzzle) |
| valid_moves <- get_valid_moves(blank_pos) |
| |
| if(tile_position %in% valid_moves) { |
| |
| 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)) |
| } |
|
|
| |
| is_solvable <- function(puzzle) { |
| |
| 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 |
| } |
| } |
| } |
| |
| |
| return(inversions %% 2 == 0) |
| } |
|
|
| |
| validate_puzzle <- function(puzzle) { |
| |
| if(length(puzzle) != 9) { |
| return(FALSE) |
| } |
| |
| |
| expected_tiles <- 0:8 |
| if(!setequal(puzzle, expected_tiles)) { |
| return(FALSE) |
| } |
| |
| |
| if(!is_solvable(puzzle)) { |
| return(FALSE) |
| } |
| |
| return(TRUE) |
| } |
|
|
| |
| 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) |
| } |
|
|
| |
| 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) |
| )) |
| } |