How to resolve the algorithm 15 puzzle game step by step in the Haskell programming language
Published on 7 June 2024 03:52 AM
How to resolve the algorithm 15 puzzle game step by step in the Haskell programming language
Table of Contents
Problem Statement
Implement the Fifteen Puzzle Game.
The 15-puzzle is also known as:
Let's start with the solution:
Step by Step solution about How to resolve the algorithm 15 puzzle game step by step in the Haskell programming language
Explanation of the Haskell Code:
Importing Libraries:
import Data.Array
import System.Random
Data.Array
provides functions for working with arrays.System.Random
provides functions for generating random numbers.
Main Function:
main :: IO ()
- The
main
function is the entry point of the program.
User Input and Difficulty Selection:
putStrLn "Please enter the difficulty level: 0, 1 or 2"
userInput <- getLine
let diffLevel = read userInput
- Gets user input for the difficulty level, which can be 0, 1, or 2.
Validating User Input:
if userInput == "" || any (\c -> c < '0' || c > '9') userInput || diffLevel > 2 || diffLevel < 0
then putStrLn "That is not a valid difficulty level." >> main
- Checks if the user input is empty, contains non-digits, or is outside the valid difficulty range. If so, it prompts the user for correct input.
Game Loop Function:
gameLoop :: Puzzle -> IO ()
gameLoop
is a recursive function that runs the game. It takes the current puzzle state as input.
Checking if the Puzzle is Solved:
if puzzle == solvedPuzzle = putStrLn "You solved the puzzle!" >> printPuzzle puzzle
- Compares the current puzzle to the
solvedPuzzle
and prints a success message if they are equal.
Otherwise, Displaying the Puzzle and Getting User Input:
else do
printPuzzle puzzle
putStrLn "Please enter number to move"
userInput <- getLine
- Prints the puzzle and prompts the user to enter a number to move.
Validating User Move:
if any (\c -> c < '0' || c > '9') userInput
then putStrLn "That is not a valid number." >> gameLoop puzzle
- Checks if the user input is empty or contains non-digits. If so, it prompts the user for correct input.
Finding Valid Moves:
let move = read userInput
validMoves puzzle = [puzzle ! (row', column') |
row' <- [rowEmpty-1..rowEmpty+1], column' <- [columnEmpty-1..columnEmpty+1],
row' < 4, row' >= 0, column' < 4, column' >= 0,
(row' == rowEmpty) /= (column' == columnEmpty)]
validMoves
finds all the valid moves around the empty tile in the puzzle.
Applying the Move:
gameLoop (applyMove move puzzle)
- If the user's move is valid, it applies the move using
applyMove
and continues the game loop.
Finding the Empty Tile's Index:
findIndexOfNumber :: Int -> Puzzle -> (Int, Int)
findIndexOfNumber number puzzle = case filter (\idx -> number == puzzle ! idx)
(indices puzzle) of
[idx] -> idx
_ -> error "BUG: number not in puzzle"
findIndexOfNumber
finds the index of the empty tile in the puzzle.
Applying a Move:
applyMove :: Int -> Puzzle -> Puzzle
applyMove numberToMove puzzle = puzzle // [(indexToMove, 16), (emptyIndex, numberToMove)]
applyMove
applies a move by swapping the empty tile and the tile with the specified number.
Printing the Puzzle:
printPuzzle :: Puzzle -> IO ()
printPuzzle
prints the current puzzle state using a custom formatting function.
Generating a Solved Puzzle:
solvedPuzzle :: Puzzle
solvedPuzzle = listArray ((0, 0), (3, 3)) [1..16]
solvedPuzzle
represents the solved puzzle where numbers are arranged in order from 1 to 16.
Shuffling the Puzzle:
shufflePuzzle :: Int -> Puzzle -> IO Puzzle
shufflePuzzle 0 puzzle = return puzzle
shufflePuzzle numOfShuffels puzzle = do
let moves = validMoves puzzle
randomIndex <- randomRIO (0, length moves - 1)
let move = moves !! randomIndex
shufflePuzzle (numOfShuffels - 1) (applyMove move puzzle)
shufflePuzzle
shuffles the puzzle by applying random valid moves. It takes the number of shuffles and the current puzzle as input.
Source code in the haskell programming language
import Data.Array
import System.Random
type Puzzle = Array (Int, Int) Int
main :: IO ()
main = do
putStrLn "Please enter the difficulty level: 0, 1 or 2"
userInput <- getLine
let diffLevel = read userInput
if userInput == "" || any (\c -> c < '0' || c > '9') userInput || diffLevel > 2 || diffLevel < 0
then putStrLn "That is not a valid difficulty level." >> main
else shufflePuzzle ([10, 50, 100] !! diffLevel) solvedPuzzle >>= gameLoop
gameLoop :: Puzzle -> IO ()
gameLoop puzzle
| puzzle == solvedPuzzle = putStrLn "You solved the puzzle!" >> printPuzzle puzzle
| otherwise = do
printPuzzle puzzle
putStrLn "Please enter number to move"
userInput <- getLine
if any (\c -> c < '0' || c > '9') userInput
then putStrLn "That is not a valid number." >> gameLoop puzzle
else let move = read userInput in
if move `notElem` validMoves puzzle
then putStrLn "This move is not available." >> gameLoop puzzle
else gameLoop (applyMove move puzzle)
validMoves :: Puzzle -> [Int]
validMoves puzzle = [puzzle ! (row', column') |
row' <- [rowEmpty-1..rowEmpty+1], column' <- [columnEmpty-1..columnEmpty+1],
row' < 4, row' >= 0, column' < 4, column' >= 0,
(row' == rowEmpty) /= (column' == columnEmpty)]
where (rowEmpty, columnEmpty) = findIndexOfNumber 16 puzzle
applyMove :: Int -> Puzzle -> Puzzle
applyMove numberToMove puzzle = puzzle // [(indexToMove, 16), (emptyIndex, numberToMove)]
where indexToMove = findIndexOfNumber numberToMove puzzle
emptyIndex = findIndexOfNumber 16 puzzle
findIndexOfNumber :: Int -> Puzzle -> (Int, Int)
findIndexOfNumber number puzzle = case filter (\idx -> number == puzzle ! idx)
(indices puzzle) of
[idx] -> idx
_ -> error "BUG: number not in puzzle"
printPuzzle :: Puzzle -> IO ()
printPuzzle puzzle = do
putStrLn "+--+--+--+--+"
putStrLn $ "|" ++ formatCell (0, 0) ++ "|" ++ formatCell (0, 1) ++ "|" ++ formatCell (0, 2) ++ "|" ++ formatCell (0, 3) ++ "|"
putStrLn "+--+--+--+--+"
putStrLn $ "|" ++ formatCell (1, 0) ++ "|" ++ formatCell (1, 1) ++ "|" ++ formatCell (1, 2) ++ "|" ++ formatCell (1, 3) ++ "|"
putStrLn "+--+--+--+--+"
putStrLn $ "|" ++ formatCell (2, 0) ++ "|" ++ formatCell (2, 1) ++ "|" ++ formatCell (2, 2) ++ "|" ++ formatCell (2, 3) ++ "|"
putStrLn "+--+--+--+--+"
putStrLn $ "|" ++ formatCell (3, 0) ++ "|" ++ formatCell (3, 1) ++ "|" ++ formatCell (3, 2) ++ "|" ++ formatCell (3, 3) ++ "|"
putStrLn "+--+--+--+--+"
where formatCell idx
| i == 16 = " "
| i > 9 = show i
| otherwise = " " ++ show i
where i = puzzle ! idx
solvedPuzzle :: Puzzle
solvedPuzzle = listArray ((0, 0), (3, 3)) [1..16]
shufflePuzzle :: Int -> Puzzle -> IO Puzzle
shufflePuzzle 0 puzzle = return puzzle
shufflePuzzle numOfShuffels puzzle = do
let moves = validMoves puzzle
randomIndex <- randomRIO (0, length moves - 1)
let move = moves !! randomIndex
shufflePuzzle (numOfShuffels - 1) (applyMove move puzzle)
You may also check:How to resolve the algorithm First-class functions step by step in the J programming language
You may also check:How to resolve the algorithm 100 doors step by step in the Klingphix programming language
You may also check:How to resolve the algorithm Memory allocation step by step in the Ada programming language
You may also check:How to resolve the algorithm Cholesky decomposition step by step in the Delphi programming language
You may also check:How to resolve the algorithm Quaternion type step by step in the zkl programming language