packages feed

midimory-0.0.2: src/Main.hs

module Main where

import qualified Game
import qualified Configuration as Config
import qualified Option
import qualified MIDI
import Game (Choice(First,Second), Player(PlayerA,PlayerB), switchPlayer)

import qualified Sound.ALSA.Sequencer.Event as Event

import qualified Graphics.UI.WX as WX
import Graphics.UI.WX
   (Prop((:=)), set, get, text, selection, command, on,
    close, container, widget,
    layout, margin, row, column, )

import qualified System.Random as Rnd

import qualified Control.Monad.Trans.State as MS
import Control.Monad (forM, )
import Control.Applicative (liftA2, (<$>))

import Data.Array (Array, (!))
import Data.IORef (newIORef, readIORef, writeIORef, modifyIORef, )


shufflePitches :: Config.T -> IO (Array (Int, Int) Event.Pitch)
shufflePitches cfg =
   MS.evalState (Game.shufflePitches cfg) . Rnd.mkStdGen <$> Rnd.randomIO

makeGUI :: Config.T -> MIDI.Sequencer -> IO ()
makeGUI cfg sequ = do
   f <- WX.frame [text := "Midimory"]
   p <- WX.panel f []
   pitches <- newIORef =<< shufflePitches cfg
   selected <- newIORef Nothing
   player <- newIORef PlayerA
   message <- WX.staticText p [ text := Game.makeMessage PlayerA First ]
   let maxScore = div (Config.rows cfg * Config.columns cfg) 2
   scoreA <- WX.vgauge p maxScore []
   scoreB <- WX.vgauge p maxScore []
   let playerScore pl =
          case pl of
             PlayerA -> scoreA
             PlayerB -> scoreB
   matrix <-
      forM (zip [0..] (Config.texts cfg)) $ \(r,ln) ->
         forM (zip [0..] ln) $ \(c,label) -> do
            b <- WX.button p [ text := label ]
            set b [
               on command := do
                  pitch <- (! (r,c)) <$> readIORef pitches
                  MIDI.sendNote sequ pitch
                  mfirst <- readIORef selected
                  case mfirst of
                     Nothing -> do
                        writeIORef selected $ Just (b, pitch)
                        set b [ WX.enabled := False ]
                        pl <- readIORef player
                        set message [ text := Game.makeMessage pl Second ]
                     Just (firstButton, firstPitch) -> do
                        writeIORef selected Nothing
                        pl <- readIORef player
                        if firstPitch == pitch
                          then do
                             set b [ WX.enabled := False ]
                             let score = playerScore pl
                             n <- get score selection
                             set score [ selection := succ n ]
                          else do
                             set firstButton [ WX.enabled := True ]
                             modifyIORef player switchPlayer
                        newpl <- readIORef player
                        score <-
                           liftA2 (,)
                              (get scoreA selection)
                              (get scoreB selection)
                        set message
                           [ text := Game.completeMessage maxScore newpl score ]
             ]
            return b
   restart <-
      WX.button p [
         text := "Restart",
         on command := do
            mapM_ (mapM_ (\b -> set b [ WX.enabled := True ])) matrix
            set scoreA [ selection := 0 ]
            set scoreB [ selection := 0 ]
            set message [ text := Game.makeMessage PlayerA First ]
            writeIORef selected Nothing
            writeIORef player PlayerA
            writeIORef pitches =<< shufflePitches cfg
         ]
   quit <- WX.button p [text := "Quit", on command := close f]
   set f [layout :=
      container p $ margin 10 $
         row 5 $
            WX.vfill (widget scoreA) :
            (column 5 $
                WX.hfill (widget message) :
                WX.grid (Config.columns cfg) (Config.rows cfg)
                   (map (map (WX.fill . widget)) matrix) :
                row 5 [WX.hfill (widget restart), WX.hfill (widget quit)] :
                []) :
            WX.vfill (widget scoreB) :
            []
    ]


main :: IO ()
main = do
   (config, (dests,chan)) <- Option.multiArgs "Concentration game for tones"
   MIDI.withSequencer "Midimory" chan $ \sequ -> do
      mapM_ (MIDI.parseAndConnect sequ) dests
      WX.start $ makeGUI config sequ