How to resolve the algorithm Pig the dice game/Player step by step in the Haskell programming language

Published on 7 June 2024 03:52 AM

How to resolve the algorithm Pig the dice game/Player step by step in the Haskell programming language

Table of Contents

Problem Statement

Create a dice simulator and scorer of Pig the dice game and add to it the ability to play the game to at least one strategy.

As a stretch goal:

The game of Pig is a multiplayer game played with a single six-sided die. The object of the game is to reach 100 points or more. Play is taken in turns. On each person's turn that person has the option of either

Let's start with the solution:

Step by Step solution about How to resolve the algorithm Pig the dice game/Player step by step in the Haskell programming language

The provided Haskell code simulates a dice game played by four players named Peter, Mia, Liz, and Stephen. The game's goal is to reach a score of 100 or more points by rolling a six-sided die and accumulating points.

Here's an explanation of the code:

  1. Data Structure:

    • The PInfo data structure represents a player's information, including their stack (current roll's score), total score, number of rolls taken, whether it's their turn, whether they have won, and their name.
  2. Strategies:

    • Different strategies are defined for players to determine their actions during the game.
    • strat1: If the player has a stack value less than 20, they roll again. Otherwise, they hold their current score.
    • strat2: Similar to strat1, but the player holds after rolling 4 times to limit the risk of losing points.
    • strat3: The player rolls again if their roll count is less than 3 or their score is less than 60. Otherwise, they hold.
    • strat4: The player holds if their score is greater than 75. Otherwise, they roll again with a 25% chance of holding.
  3. Game Logic:

    • The logic function determines the next action based on the players' strategies and game state.
    • If a player has won, the game ends.
    • If it's a player's turn, their strategy is applied.
    • Otherwise, the turn is passed to the next player.
  4. Main Function:

    • In the main function:
      • Initial player information (p1, p2, p3, p4) is defined.
      • The game starts with the four players using strat1 as their strategy.
  5. Parallel Execution:

    • To improve performance, the game is simulated multiple times in parallel using the parallel function from the Control.Concurrent.ParallelIO.Global module.
    • The results (which player won) are collected and grouped to count how many times each player won.
  6. Output:

    • The final results are printed, showing how many times each player won out of the 100,000 simulations.

Additional Notes:

  • The printf statements for printing the player's actions are commented out in the final version of the code to improve performance.
  • The roll and hold functions have been modified to return Strings instead of performing I/O actions, which is more efficient for parallel execution.
  • The logic function has been modified to return the name of the winning player when a player wins, which is used to count the winners in the final results.

Source code in the haskell programming language

{-# LANGUAGE ViewPatterns #-}

module Main where

import System.Random (randomRIO)
import Text.Printf   (printf)

data PInfo = PInfo { stack :: Int
                   , score :: Int
                   , rolls :: Int
                   , next  :: Bool
                   , won   :: Bool
                   , name  :: String
                   }

type Strategy = [PInfo] -> IO ()

roll :: [PInfo] -> IO [PInfo]
roll (pinfo:xs) = do
  face <- randomRIO (1, 6)
  case (face, face + stack pinfo + score pinfo) of
      (1,_)            -> do
          printf "%s rolled 1 - stack is being resetted\n\n" (name pinfo)
          return $ pinfo { stack = 0, rolls = 0, next = True } : xs
      (_,x) | x >= 100 -> do
          printf "%s rolled %i - stack is now %i + score %i => %i - I won!\n" (name pinfo) face (face + stack pinfo) (score pinfo) x
          return $ pinfo { won = True } : xs
      (_,_)            -> do
          printf "%s rolled %i - stack is now %i\n" (name pinfo) face (face + (stack pinfo))
          return $ pinfo { stack = face + (stack pinfo), rolls = 1 + (rolls pinfo) } : xs

hold :: [PInfo] -> IO [PInfo]
hold (pinfo:xs) = do
  let score' = stack pinfo + score pinfo
  printf "%s holds - score is now %i\n\n" (name pinfo) score'
  return $ pinfo { score = score', stack = 0, rolls = 0, next = True } : xs


logic :: Strategy -> Strategy -> Strategy
logic _      _      ((won -> True)    : xs) = return ()
logic _      strat2 (p@(next -> True) : xs) = strat2 $ xs ++ [p { next = False }]
logic strat1 _      (pinfo            : xs) = strat1 (pinfo : xs)

strat1 :: Strategy
strat1 (pinfo:xs)
  | stack pinfo < 20 = roll (pinfo:xs) >>= logic strat1 strat2
  | otherwise        = hold (pinfo:xs) >>= logic strat1 strat2

strat2 :: Strategy
strat2 (pinfo:xs)
  | rolls pinfo < 4 = roll (pinfo:xs) >>= logic strat2 strat3
  | otherwise       = hold (pinfo:xs) >>= logic strat2 strat3

strat3 :: Strategy
strat3 (pinfo:xs)
  | rolls pinfo < 3 && score pinfo < 60 = roll (pinfo:xs) >>= logic strat3 strat4
  | stack pinfo < 20                    = roll (pinfo:xs) >>= logic strat3 strat4
  | otherwise                           = hold (pinfo:xs) >>= logic strat3 strat4

strat4 :: Strategy
strat4 (pinfo:xs) | score pinfo > 75 = roll (pinfo:xs) >>= logic strat4 strat1
strat4 (pinfo:xs) = do
  chance <- randomRIO (0, 3) :: IO Int
  case chance of
      0  -> hold (pinfo:xs) >>= logic strat4 strat1
      _  -> roll (pinfo:xs) >>= logic strat4 strat1

main :: IO ()
main = do
  let pInfo = PInfo 0 0 0 False False ""
      p1    = pInfo { name = "Peter"   }
      p2    = pInfo { name = "Mia"     }
      p3    = pInfo { name = "Liz"     }
      p4    = pInfo { name = "Stephen" }
  strat1 [p1, p2, p3, p4]


-- add this to the top
import Control.Concurrent.ParallelIO.Global (parallel, stopGlobalPool)
import Data.List (sort, group)

-- replace "logic _      _      ((won -> True)    : xs) = return ()" with
  logic _      _      (p@(won -> True)    : xs) = return $ name p

-- replace strat1 [p1, p2, p3, p4] in main with
  let lists = replicate 100000 [p1, p2, p3, p4]
  results <- parallel $ map strat1 lists
  stopGlobalPool
  print $ map length $ group $ sort results

-- replace type Strategy = [PInfo] -> IO () with
  type Strategy = [PInfo] -> IO String

-- comment every printf in "roll" and "hold"

-- compile with
-- ghc FILENAME.hs -O2 -threaded -with-rtsopts="-N4" -o dice


  

You may also check:How to resolve the algorithm Create an HTML table step by step in the EchoLisp programming language
You may also check:How to resolve the algorithm Zig-zag matrix step by step in the ALGOL 68 programming language
You may also check:How to resolve the algorithm Sequence of primes by trial division step by step in the AWK programming language
You may also check:How to resolve the algorithm Fork step by step in the ALGOL 68 programming language
You may also check:How to resolve the algorithm Reverse words in a string step by step in the C++ programming language