hfiar-1.2.0: src/HFiaR/GUI.hs
-- | This module provides the HFiaR GUI
module HFiaR.GUI ( gui ) where
import HFiaR
import HFiaR.AI
import qualified HFiaR.Server as HFS
import Data.List (transpose)
import Control.Monad
import Graphics.UI.WXCore
import Graphics.UI.WX
data GUIColumn = GUICol { colNumber :: Int,
colCells :: [Panel ()],
colButton :: Button () }
data GUIContext = GUICtx { guiPlayers :: Var Int,
guiWin :: Frame (),
guiPlayer :: StaticText (),
guiColumns :: [GUIColumn],
guiModel :: Var HFS.ServerHandle }
gui :: IO ()
gui = do
model <- HFS.start
modelVar <- varCreate model
win <- frame [text := "Four in a Row"]
set win [on closing := HFS.stop model >> propagateEvent]
playerText <- staticText win [text := "Green Player Turn"]
columns <- forM [0..6] (\c ->
do
cells <- forM [0.. 6] (\r -> panelCreate win (cellId c r) rectNull 0)
forM_ cells $ \cell -> set cell [bgcolor := grey]
btn <- button win [identity := buttonId c,
bgcolor := grey,
text := "Select"]
return $ GUICol c cells btn
)
status <- statusField [text := ""] --NOTE: Just decorative
set win [statusBar := [status]]
playersVar <- varCreate 2
let guiCtx = GUICtx playersVar win playerText columns modelVar
forM_ columns $ \GUICol{colButton = b, colNumber = c} ->
set b [on command := do
selectColumn c guiCtx
refreshGUI guiCtx]
-- Menu bar...
mnuGame <- menuPane [text := "Game"]
menuAppend mnuGame 5002 "&New (2 Players)\tCtrl-n" "New Game (2 Players)" False
menuAppend mnuGame 5003 "&New (1 Player)\tCtrl-Shift-n" "New Game (1 Player)" False
evtHandlerOnMenuCommand win 5002 $ varSet playersVar 2 >> restartGame guiCtx >> refreshGUI guiCtx
evtHandlerOnMenuCommand win 5003 $ varSet playersVar 1 >> restartGame guiCtx >> refreshGUI guiCtx
menuQuit mnuGame [on command := wxcAppExit]
mnuHelp <- menuHelp []
menuAppend mnuHelp 5009 "&Instructions\tCtrl-h" "Open the Instructions Page" False
menuAbout mnuHelp [on command := infoDialog win "About HFiaR" "Author: Fernando Brujo Benavides"]
set win [menuBar := [mnuGame, mnuHelp]]
let columnLayout GUICol{colCells = cs, colButton = b} =
(hfill $ widget b) : (map (fill . widget) $ reverse cs)
set win [layout := column 5 [hfill . boxed "" . floatCenter $ widget playerText,
grid 1 1 . transpose $ map columnLayout columns],
clientSize := sz 500 500]
-------------------------------------------------------------------------------------------------------------------------
selectColumn :: Int -> GUIContext -> IO ()
selectColumn c GUICtx{guiPlayers = playersVar, guiWin = win, guiModel = modelVar} =
do
model <- varGet modelVar
players <- varGet playersVar
res <- HFS.runIn model $ dropIn c
case res of
Left err ->
errorDialog win "Four in a Row" $ show err
Right () ->
case players of
1 -> do
res2 <- HFS.runIn model $ aiDropIn
case res2 of
Left err ->
errorDialog win "Four in a Row" $ show err
Right () ->
return ()
_ -> return ()
restartGame :: GUIContext -> IO ()
restartGame GUICtx{guiPlayers = players, guiModel = modelVar} =
--TODO: Verify if the player wants to restart the game even if it hasn't ended yet
do
model <- varGet modelVar
HFS.stop model
newModel <- HFS.start
varSet modelVar newModel
refreshGUI :: GUIContext -> IO ()
refreshGUI GUICtx{guiPlayer = playerText, guiColumns = columns, guiWin = win, guiModel = modelVar} =
do
model <- varGet modelVar
res1 <- HFS.runIn model player
case res1 of
Left GameEnded ->
do
forM_ columns $ \GUICol{colButton = b} -> set b [enabled := False]
res2 <- HFS.runIn model result
case res2 of
Left err ->
errorDialog win "Four in a Row" $ show err
Right Tie ->
set playerText [text := "It was a tie"]
Right (WonBy p) ->
set playerText [text := show p ++ " Player won!!"]
Left err ->
errorDialog win "Four in a Row" $ show err
Right p ->
do
forM_ columns $ \GUICol{colButton = b} -> set b [enabled := True]
set playerText [text := (show p) ++ " Player turn"]
cols <- HFS.runIn model board
forM_ columns $ \GUICol{colCells = cells,
colNumber= coln} ->
do
forM_ cells $ \cell -> set cell [bgcolor := grey]
zipWithM_ (\cell val -> set cell [bgcolor := case val of
Red -> red
Green -> green
])
cells (reverse $ cols !! coln)
-------------------------------------------------------------------------------------------------------------------------
cellId :: Int -> Int -> Id
cellId c r = 5300 + c * 10 + r
buttonId :: Int -> Id
buttonId c = 5300 + c * 10