Untitled

 avatar
unknown
plain_text
a month ago
9.2 kB
2
Indexable
{-|
Module      : Tarefa1
Description : Invariantes do Jogo
Copyright   : Matheus Henrique Monteiro da Silva Azevedo <a111430@alunos.uminho.pt>
              Francisco Luciano Martins <a111775@alunos.uminho.pt>


Módulo para a realização da Tarefa 1 de LI1 em 2024/25.
-}
module Tarefa1 where

import LI12425

-- | Função auxiliar que dado uma posição e o mapa verifica qual o tipo de terreno nessa posição
tipoTerreno :: Posicao -> Mapa -> Maybe Terreno
tipoTerreno (x,y) mapa
    | y' < 0 || y' >= fromIntegral (length (mapa)) = Nothing
    | x' < 0 || x' >= fromIntegral (length (mapa !! y')) = Nothing
    | otherwise = Just ((mapa !! y') !! x')  -- Acessa o terreno na coordenada (x, y)
    where x' = floor x
          y' = floor y

-- | Função que verifica se em uma certa posição o tipo do terreno é Terra.
validaPosicaoTerra :: Posicao -> Mapa -> Bool
validaPosicaoTerra (x,y) mapa = case t of
    Just Terra -> True
    _ -> False
    where t = tipoTerreno (x,y) mapa

{-| Função que dada uma posição retorna as posições que estão em volta que são válidas (tem terreno com Terra)

Como a função validaPosicaoTerra (que é utilizada dentro do filter) utiliza a função tipoTerreno, não é necessário verificar se as posições adjacentes são válidas.
     
-}   

posAdjacentes :: Posicao -> Mapa -> [Posicao]
posAdjacentes (x,y) mapa = filter (\(cx,cy) -> validaPosicaoTerra (cx,cy) mapa) [(x - 1, y), (x + 1, y), (x, y - 1), (x, y + 1)]

-- | Função auxiliar que verifica se existe um caminho entre duas posições.
verificaCaminho :: Posicao -> Posicao -> Mapa -> Bool
verificaCaminho posinicial posfinal mapa = buscaCaminho [posinicial] []
  where
    buscaCaminho [] _ = False
    buscaCaminho (atual:fila) visitados
        | atual == posfinal    = True
        | elem atual visitados = buscaCaminho fila visitados  -- ^ Se a posição atual já foi visitada, passa a procurar para a próxima posição
        | otherwise            =
            let visitados' = atual : visitados  -- ^ Adiciona a posição atual à lista de visitados
                adjacentes = filter (`notElem` visitados') (posAdjacentes atual mapa) -- ^ Filtra as posições adjacentes válidas que ainda não foram visitadas
            in buscaCaminho (fila ++ adjacentes) visitados'

verificaSobreposicao :: Posicao -> [Torre] -> Base -> Bool
verificaSobreposicao (x,y) [] Base {posicaoBase = posBase} = (x,y) /= posBase
verificaSobreposicao (x,y) (Torre { posicaoTorre = (xt,yt)} :rl) base@(Base {posicaoBase = posBase})
            = (x,y) /= (xt,yt) && verificaSobreposicao (x,y) rl base


-- Função auxiliar que dado um portal e uma lista de ondas verifica se há no máximo um portal com a onda iniciada.
verificaOndas :: Portal -> [Onda] -> Bool
verificaOndas _ [] = True
verificaOndas portal ondas = length ondasiniciadas == 1 || length ondasiniciadas == 0
    where ondasiniciadas = filter (\onda -> (entradaOnda onda) == 0) ondas

-- | Função que verifica se o estado de jogo está válido para os Portais
validaPortais :: [Portal] -> Mapa -> Base -> [Torre] -> Bool
validaPortais [] _ _ _ = False -- ^ Verifica se há pelo menos um portal
validaPortais portais mapa base torres =
    all (\p -> validaPosicaoTerra (posicaoPortal p) mapa) portais &&   -- ^ Verifica se a posição de cada portal é válida
    all (\p -> verificaCaminho (posicaoPortal p) (posicaoBase base) mapa) portais && -- ^ Verifica se para cada portal há um caminho entre ele e a base
    all (\p -> verificaSobreposicao (posicaoPortal p) (torres) (base)) portais && -- ^ Verifica se para cada portal ele não está sobreposto a uma torre/base
    all (\p -> verificaOndas p (ondasPortal p)) portais -- ^ Verifica se para cada portal tem no máximo uma onda ativa


-- | Função que dada a posição do portal e um inimigo, verifica se o inimigo cumpre as restrições da alínea a)
verificaRestricoes :: Posicao -> Inimigo -> Bool
verificaRestricoes posPortal Inimigo {posicaoInimigo = pos, vidaInimigo = vida, projeteisInimigo = lprojeteis}
            = posPortal == pos && vida > 0 && (lprojeteis == [])

-- | Função que dada uma onda em que cada onda tem uma lista de inimigos, concatena estas listas e retorna uma lista de inimigos geral
concatenaInimigos :: [Onda] -> [Inimigo]
concatenaInimigos [] = []
concatenaInimigos (onda:rl) = (inimigosOnda onda) ++ concatenaInimigos rl

-- | Função auxiliar que verifica se um inimigo está sobreposto a alguma torre
verificaSobreposicaoInimigoTorres :: [Torre] -> Inimigo -> Bool
verificaSobreposicaoInimigoTorres torres inimigo = all (\torre -> (posicaoTorre torre) /= (posicaoInimigo inimigo)) torres

-- | Função auxiliar que verifica se a velocidade de um inimigo é válida (não é negativa)
validaVelocidade :: Inimigo -> Bool
validaVelocidade inimigo = (velocidadeInimigo (inimigo)) >= 0

-- | Função que verifica se a lista de projéteis ativos é válida
validaProjeteis :: [Projetil] -> Bool
validaProjeteis lp = length(lfogos) <=1 && 
                     length(lgelos) <=1 && 
                     length(lresinas) <=1 &&
                     (if length(lfogos) == 1 && length(lresinas) /= 0 then False
                      else if length(lresinas) == 1 && length(lfogos) /= 0 then False
                      else if length(lfogos) == 1 && length(lgelos) /= 0 then False
                      else if length (lgelos) == 1 && length(lfogos) /= 0 then False
                      else True)
                        where listatiposp@(tp1:rtps) = map (tipoProjetil) lp
                              lfogos = filter (== Fogo) listatiposp
                              lgelos = filter (== Gelo) listatiposp
                              lresinas = filter (== Resina) listatiposp

-- | Função que verifica se todos os inimigos de todas as ondas cumprem as restrições da alínea a)
validaInimigosPortal :: Posicao -> [Onda] -> Bool
validaInimigosPortal posPortal ondasPortal =
    all (\i -> verificaRestricoes posPortal i) inimigosPortal
    where inimigosPortal = concatenaInimigos ondasPortal

-- | Função que verifica todas as restrições estabelecidas para os inimigos em jogo
validaInimigosEmJogo :: [Inimigo] -> [Torre] -> Mapa -> Bool
validaInimigosEmJogo inimigosemjogo torres mapa = 
    all (\i -> validaPosicaoTerra (posicaoInimigo i) mapa) inimigosemjogo &&
    all (\i -> verificaSobreposicaoInimigoTorres torres i) inimigosemjogo &&
    all (\i -> validaVelocidade i) inimigosemjogo &&
    all (\i -> validaProjeteis (projeteisInimigo i)) inimigosemjogo

-- | Função que verifica se em uma certa posição o tipo do terreno é Relva.
validaPosicaoRelva :: Posicao -> Mapa -> Bool
validaPosicaoRelva (x,y) mapa = case t of
    Just Relva -> True
    _ -> False
    where t = tipoTerreno (x,y) mapa

validaAlcanceTorre :: Torre -> Bool
validaAlcanceTorre torre = (alcanceTorre (torre)) > 0

validaRajadaTorre :: Torre -> Bool
validaRajadaTorre torre = (rajadaTorre (torre)) > 0

validaCicloTorre :: Torre -> Bool
validaCicloTorre torre = (cicloTorre (torre)) >= 0

verificaSobreposicaoTorres :: [Torre] -> [Torre] -> Bool
verificaSobreposicaoTorres  [] torres = True
verificaSobreposicaoTorres (t:r) l  = length (filter (== posicaoTorre t) (map (posicaoTorre) l)) == 1 && verificaSobreposicaoTorres r l

validaTorres :: [Torre] -> Mapa -> Bool
validaTorres torres mapa = 
    all (\torre -> validaPosicaoRelva (posicaoTorre torre) mapa) torres && -- ^ Verifica se as torres estão sobre relva
    all (\torre -> validaAlcanceTorre torre) torres &&
    all (\torre -> validaRajadaTorre torre) torres &&
    all (\torre -> validaCicloTorre torre) torres &&
    verificaSobreposicaoTorres torres torres

validaCreditoBase :: Base -> Bool
validaCreditoBase base = (creditosBase (base)) >= 0

verificaSobreposicaoBase :: Posicao -> [Torre] -> [Portal] -> Bool
verificaSobreposicaoBase (x,y) [] [] = True
verificaSobreposicaoBase (x,y) [] (Portal { posicaoPortal = posPortal} :rp)= (x,y) /= posPortal && verificaSobreposicaoBase (x,y) [] rp
verificaSobreposicaoBase (x,y) (Torre { posicaoTorre = posTorre} :rl) [] = (x,y) /= posTorre && verificaSobreposicaoBase (x,y) rl []
verificaSobreposicaoBase (x,y) (Torre { posicaoTorre = posTorre} :rl) (Portal {posicaoPortal = posPortal} :rp)
            = verificaSobreposicaoBase (x,y) (Torre { posicaoTorre = posTorre} :rl) [] && verificaSobreposicaoBase (x,y) [] (Portal {posicaoPortal = posPortal} :rp)

validaBase :: Base -> Mapa -> [Torre] -> [Portal] -> Bool
validaBase base mapa torres portais =
    validaPosicaoTerra (posicaoBase base) mapa &&
    validaCreditoBase base &&
    verificaSobreposicaoBase (posicaoBase base) torres portais 

-- | Função principal que verifica todas as condições estabelecidas para o jogo
validaJogo :: Jogo -> Bool
validaJogo Jogo {baseJogo = base, portaisJogo = portais, torresJogo = torres, mapaJogo = mapa, inimigosJogo = inimigos} =
    validaPortais portais mapa base torres &&
    all (\p -> validaInimigosPortal (posicaoPortal p) (ondasPortal p)) portais && -- ^ Valida inimigos por lançar
    validaInimigosEmJogo inimigos torres mapa && -- ^ Valida inimigos em jogo
    validaTorres torres mapa &&
    validaBase base mapa torres portais

Leave a Comment