Ir para o conteúdo

Tudo junto e misturado

TODO

Escrever

module Main where

import Text.Read ( readMaybe )
import Data.Maybe ( fromMaybe, isNothing, fromJust )

-- Definição de novos tipos
data Direção = Norte | Sul | Leste | Oeste
    deriving (Show, Eq)

data Ação = ColocarBomba | Agir | Mover Direção | NO_OP | Sair
    deriving (Show, Eq)

data Item = Presente | Jogador Int | Parede | Grama

data DadosDoJogador = DadosDoJogador Int (Int,Int) String

type Tabuleiro = [[Item]]


-- Mapeamento de teclas para ações de cada um dos possíveis jogadores.
-- Cada linha corresponde a um jogador.
keyMaps = [(1,[('e',ColocarBomba),('r',Agir),('a', Mover Oeste),('s', Mover Sul),('d',Mover Leste),('w', Mover Norte),('Q', Sair)]),
           (2,[('o',ColocarBomba),('p',Agir),('j', Mover Oeste),('k', Mover Sul),('l',Mover Leste),('i', Mover Norte),('Q', Sair)])]

-- Dado uma tecla e um mapa, retorna o jogador e a ação a ser executada para ele.
-- Se a tecla é inválida, retorna Nothing.
mapKey :: Char -> [(Int, [(Char, Ação)])] -> Maybe (Int, Ação)
mapKey c []     = Nothing
mapKey c ((j,as):jas) = case mapKey' c as of Nothing -> mapKey c jas
                                             Just a  -> Just (j,a)
    where mapKey' c [] = Nothing
          mapKey' c ((c',a):ms)
            | c == c'   = Just a
            | otherwise = mapKey' c ms

-- Retorna IO id do jogador e ação a ser executada.
-- js é a lista dos jogadores ainda no jogo.
pegaMov :: [Int] -> IO (Maybe (Int,Ação))
pegaMov js = do
        movChar <- getChar
        let mapped = mapKey movChar keyMaps    -- Observe a ausência do `in` quando estamos dentro de um bloco IO.
        case mapped of Nothing     -> return Nothing
                       Just (j,a)  -> if j `elem` js then return mapped
                                                     else return Nothing


main :: IO ()
main = do
    loopPrincipal tabuleiro jogadores
    where (tabuleiro,jogadores) = iniciarTabuleiro

tabuleiroExemplo = [[Grama,Presente,Jogador 1],[Grama],[Grama],[Grama,Presente,Jogador 2]]
dadosDoJogadorExemplo = [DadosDoJogador 1 (0,0) "BP", 
                         DadosDoJogador 2 (1,1) "BP" ]

iniciarTabuleiro :: (Tabuleiro,[DadosDoJogador])
iniciarTabuleiro = (tabuleiroExemplo,      -- O tabuleiro deveria ser lido de um arquivo com a descrição de uma fase.
                    dadosDoJogadorExemplo) -- A lista de jogadores deveria ser lida de um menu que permitisse a escolha e configuração dos jogadores.

loopPrincipal :: Tabuleiro -> [DadosDoJogador] -> IO ()
loopPrincipal t js = do
    let ids = [i | DadosDoJogador i _ _ <- js]
    move <- pegaMov ids
    let (j,op) = fromMaybe (-1,NO_OP) move
    print $ "(Jogador,Ação)" ++ show (j,op)
    case op of
            ColocarBomba   -> let (t',js') = colocarBomba t js j in loopPrincipal t' js' -- poderia ser simplificado com uso da função uncurry
            Agir           -> let (t',js') = agir t js j         in loopPrincipal t' js'
            Mover d        -> let (t',js') = mover d t js j      in loopPrincipal t' js'
            NO_OP          -> loopPrincipal t js
            Sair           -> return ()


-- Tenta movimentar o jogador na direcao especificada.
mover :: Direção -> Tabuleiro -> [DadosDoJogador] -> Int -> (Tabuleiro, [DadosDoJogador])
mover d t js j = (t,js)

-- Descobre se alguma ação é possível para o jogador e executa.
agir :: Tabuleiro -> [DadosDoJogador] -> Int -> (Tabuleiro, [DadosDoJogador])
agir t js j = (t,js)

-- Verifica se é possível colocar a boma e coloca.
colocarBomba :: Tabuleiro -> [DadosDoJogador] -> Int -> (Tabuleiro, [DadosDoJogador])
colocarBomba t js i = (t,js)