How to resolve the algorithm 2048 step by step in the Haskell programming language
How to resolve the algorithm 2048 step by step in the Haskell programming language
Table of Contents
Problem Statement
Implement a 2D sliding block puzzle game where blocks with numbers are combined to add their values.
The name comes from the popular open-source implementation of this game mechanic, 2048.
Let's start with the solution:
Step by Step solution about How to resolve the algorithm 2048 step by step in the Haskell programming language
The code written in Haskell implements the classic 2048 game using the Haskell programming language.
The code is organized into several sections:
-
Logic: This section contains the game logic. It defines the
Position
type as a list of lists of integers, representing the game board. It also defines thecombine
andshift
functions, which are used to combine and shift the tiles on the board when a move is made. Theprogress
function checks if a move can be made, and thelost
andwin
functions check if the game has been lost or won. -
Adding 2 or 4: This section contains the code for adding a 2 or 4 to the board. The
add2or4
function uses therandomElement
function from theSystem.Random
module to randomly select a location on the board to add a 2 or 4. Theadd
function then updates the board by adding the 2 or 4 to the selected location. -
Main loop: This section contains the main game loop. The
play
function takes a position as input and repeatedly prompts the user for a move. Thego
function then updates the board based on the user's input. Theadd2or4
function is then used to add a 2 or 4 to the board. Thedraw
function is then called to display the updated board. The game continues until the player wins or loses. -
Rendering: This section contains the code for rendering the game board. The
colors
list contains the ANSI escape codes for the different colors that are used to represent the tiles on the board. TheshowTile
function takes a number as input and returns the corresponding ANSI escape code. Thedraw
function uses theshowTile
function to generate the ASCII representation of the game board.
The game is played by repeatedly prompting the user for a move. The user can move the tiles up, down, left, or right by pressing the corresponding arrow key. The game ends when the player wins or loses.
Source code in the haskell programming language
import System.IO
import Data.List
import Data.Maybe
import Control.Monad
import Data.Random
import Data.Random.Distribution.Categorical
import System.Console.ANSI
import Control.Lens
-- Logic
-- probability to get a 4
prob4 :: Double
prob4 = 0.1
type Position = [[Int]]
combine, shift :: [Int]->[Int]
combine (x:y:l) | x==y = (2*x) : combine l
combine (x:l) = x : combine l
combine [] = []
shift l = take (length l) $ combine (filter (>0) l) ++ [0,0..]
reflect :: [[a]] ->[[a]]
reflect = map reverse
type Move = Position -> Position
left, right, up, down :: Move
left = map shift
right = reflect . left . reflect
up = transpose . left . transpose
down = transpose . right . transpose
progress :: Eq a => (a -> a) -> a -> Maybe a
progress f pos = if pos==next_pos then Nothing else Just next_pos where next_pos= f pos
lost, win:: Position -> Bool
lost pos = all isNothing [progress move pos| move<-[left,right,up,down] ]
win = any $ any (>=2048)
go :: Position -> Maybe Move -> Maybe Position
go pos move = move >>= flip progress pos
{-
-- Adding 2 or 4 without lens:
update l i a = l1 ++ a : l2 where (l1,_:l2)=splitAt i l
indicesOf l = [0..length l-1]
add a x y pos = update pos y $ update (pos !! y) x a
add2or4 :: Position -> RVar Position
add2or4 pos = do
(x,y) <- randomElement [(x,y) | y<-indicesOf pos, x<-indicesOf (pos!!y), pos!!y!!x ==0 ]
a <- categorical [(0.9::Double,2), (0.1,4) ]
return $ add a x y pos
-}
-- or with lens:
indicesOf :: [a] -> [ReifiedTraversal' [a] a]
indicesOf l = [ Traversal $ ix i | i <- [0..length l - 1] ]
indices2Of :: [[a]] -> [ReifiedTraversal' [[a]] a]
indices2Of ls = [ Traversal $ i.j | Traversal i <- indicesOf ls, let Just l = ls ^? i, Traversal j <- indicesOf l]
add2or4 :: Position -> RVar Position
add2or4 pos = do
xy <- randomElement [ xy | Traversal xy <- indices2Of pos, pos ^? xy == Just 0 ]
a <- categorical [(1-prob4, 2), (prob4, 4) ]
return $ pos & xy .~ a
-- Easy, is'n it'?
-- Main loop
play :: Position -> IO ()
play pos = do
c <- getChar
case go pos $ lookup c [('D',left),('C',right),('A',up),('B',down)] of
Nothing -> play pos
Just pos1 -> do
pos2 <- sample $ add2or4 pos1
draw pos2
when (win pos2 && not (win pos)) $ putStrLn $ "You win! You may keep going."
if lost pos2 then putStrLn "You lost!"
else play pos2
main :: IO ()
main = do
pos <- sample $ add2or4 $ replicate 4 (replicate 4 0)
draw pos
play pos
-- Rendering
-- See https://en.wikipedia.org/wiki/ANSI_escape_code#Colors
colors =
[(0,"\ESC[38;5;234;48;5;250m ")
,(2,"\ESC[38;5;234;48;5;255m 2 ")
,(4,"\ESC[38;5;234;48;5;230m 4 ")
,(8,"\ESC[38;5;15;48;5;208m 8 ")
,(16,"\ESC[38;5;15;48;5;209m 16 ")
,(32,"\ESC[38;5;15;48;5;203m 32 ")
,(64,"\ESC[38;5;15;48;5;9m 64 ")
,(128,"\ESC[38;5;15;48;5;228m 128 ")
,(256,"\ESC[38;5;15;48;5;227m 256 ")
,(512,"\ESC[38;5;15;48;5;226m 512 ")
,(1024,"\ESC[38;5;15;48;5;221m 1024")
,(2048,"\ESC[38;5;15;48;5;220m 2048")
,(4096,"\ESC[38;5;15;48;5;0m 4096")
,(8192,"\ESC[38;5;15;48;5;0m 8192")
,(16384,"\ESC[38;5;15;48;5;0m16384")
,(32768,"\ESC[38;5;15;48;5;0m32768")
,(65536,"\ESC[38;5;15;48;5;0m65536")
,(131072,"\ESC[38;5;15;48;5;90m131072")
]
showTile x = fromJust (lookup x colors) ++ "\ESC[B\^H\^H\^H\^H\^H \ESC[A\ESC[C"
draw :: Position -> IO ()
draw pos = do
setSGR [Reset]
clearScreen
hideCursor
hSetEcho stdin False
hSetBuffering stdin NoBuffering
setSGR [SetConsoleIntensity BoldIntensity]
putStr "\ESC[38;5;234;48;5;248m" -- set board color
setCursorPosition 0 0
replicateM_ 13 $ putStrLn $ replicate 26 ' '
setCursorPosition 1 1
putStrLn $ intercalate "\n\n\n\ESC[C" $ concatMap showTile `map` pos
You may also check:How to resolve the algorithm Price fraction step by step in the Smalltalk programming language
You may also check:How to resolve the algorithm Calendar - for REAL programmers step by step in the UNIX Shell programming language
You may also check:How to resolve the algorithm Sort using a custom comparator step by step in the Haskell programming language
You may also check:How to resolve the algorithm Simulate input/Keyboard step by step in the AutoHotkey programming language
You may also check:How to resolve the algorithm Perfect totient numbers step by step in the Julia programming language