21 game

You are encouraged to solve this task according to the task description, using any language you may know.
21 is a two player game, the game is played by choosing
a number (1, 2, or 3) to be added to the running total.

The game is won by the player whose chosen number causes the running total
to reach exactly 21.

The running total starts at zero.
One player will be the computer.

Players alternate supplying a number to be added to the running total.



Task

Write a computer program that will:

 do the prompting (or provide a button menu), 
 check for errors and display appropriate error messages, 
 do the additions (add a chosen number to the running total), 
 display the running total, 
 provide a mechanism for the player to quit/exit/halt/stop/close the program,
 issue a notification when there is a winner, and
 determine who goes first (maybe a random or user choice, or can be specified when the game begins). 


import System.Random
import System.IO
import System.Exit
import Control.Monad
import Text.Read
import Data.Maybe
 
promptAgain :: IO Int
promptAgain = do
  putStrLn "Invalid input - must be a number among 1,2 or 3. Try again."
  playerMove
 
playerMove :: IO Int
playerMove = do
  putStr "Your choice(1 to 3):"
  number <- getLine
  when (number == "q") $ do
    exitWith ExitSuccess
  let n = readMaybe number :: Maybe Int
  x <- if isNothing n
             then promptAgain
             else let val = read number
                   in if (val > 3 || val < 1)
                      then promptAgain
                      else return val
  return x
 
computerMove :: IO Int
computerMove = do
  x <- randomRIO (1, 3)
  putStrLn $ "Computer move:" ++ (show x)
  return x
 
gameLoop :: (IO Int, IO Int) -> IO Int
gameLoop moveorder = loop moveorder 0
  where loop moveorder total = do
        number <- fst moveorder
        let total1 = number + total
        putStrLn $ "Running total:" ++ (show total1)
        if total1 >= 21
           then return 0
           else do
             number <- snd moveorder
             let total2 = number + total1
             putStrLn $ "Running total:" ++ (show total2)
             if total2 >= 21
                then return 1
                else loop moveorder total2
 
main :: IO ()
main = do
  hSetBuffering stdout $ BlockBuffering $ Just 1
  putStrLn "Enter q to quit at any time"
  x <- randomRIO (0, 1) :: IO Int
  let (moveorder, names) = if x == 0
                 then ((playerMove, computerMove), ("Player", "Computer"))
                 else ((computerMove, playerMove), ("Computer", "Player"))
  when (x == 1) $ do
    putStrLn "Computer will start the game"
  y <- gameLoop moveorder
  when (y == 0) $ do
    putStrLn $ (fst names) ++ " has won the game"
  when (y == 1) $ do
    putStrLn $ (snd names) ++ " has won the game"