Untitled

 avatar
unknown
plain_text
a month ago
5.0 kB
3
Indexable

{-| Função para arredondar as posições para obter a posição geral

Como sabemos, na matriz toda posição em que o x pertence a [0,1] e o y pertence a [0,1] é a posição (0,0) da matriz, essa função acha essa posição "geral" da matriz.
-}

arredondarPosicao :: Posicao -> (Int, Int)
arredondarPosicao (x, y) = (floor x,floor y)

-- | Função que encontra o caminho mais curto entre as duas posições (semelhante a função da Tarefa 1)
encontrarCaminho :: Posicao -> Posicao -> Mapa -> Maybe [Posicao]
encontrarCaminho posinicial posfinal mapa = encontrarCaminhoAux [[posinicial]] []
  where
    encontrarCaminhoAux :: [[Posicao]] -> [Posicao] -> Maybe [Posicao]
    encontrarCaminhoAux [] _ = Nothing
    encontrarCaminhoAux (caminho:fila) visitados
        | arredondarPosicao atual == arredondarPosicao posfinal = Just caminho -- ^ verificar se tá na mesma posição geral do quadrado da posição final
        | atual `elem` visitados = encontrarCaminhoAux fila visitados
        | otherwise =
            let visitados' = atual : visitados
                adjacentes = filter (`notElem` visitados') (posAdjacentes atual mapa) -- ^ pos adjacentes são de terra
                novosCaminhos = [caminho ++ [adj] | adj <- adjacentes] -- ^ lista de caminhos (cada caminho é uma lista de posições)
            in (encontrarCaminhoAux (fila ++ novosCaminhos) visitados')
        where atual = last caminho -- ^ a pos final de um caminho é a que interessa para comparar 

-- | Função auxiliar que retorna as posições válidas para o inimigo se mover (nunca voltar para trás).
getPosicoesValidas :: Posicao -> Direcao -> Mapa -> [(Posicao,Direcao)]
getPosicoesValidas (x,y) dir mapa = 
    case dir of
        Norte -> filter (\((x,y),_) -> validaPosicaoTerra (x,y) mapa) [((x,y-0.501),Norte),((x+0.501,y),Este),((x-0.501,y),Oeste)]
        Sul -> filter (\((x,y),_) -> validaPosicaoTerra (x,y) mapa) [((x,y+0.501),Sul),((x+0.501,y),Este),((x-0.501,y),Oeste)]
        Este -> filter (\((x,y),_) -> validaPosicaoTerra (x,y) mapa) [((x+0.501,y),Este),((x,y-0.501),Norte),((x,y+0.501),Sul)]
        Oeste -> filter (\((x,y),_) -> validaPosicaoTerra (x,y) mapa) [((x-0.501,y),Oeste),((x,y-0.501),Norte),((x,y+0.501),Sul)]

{-| Função auxiliar que escolhe a direção que o inimigo deve seguir para chegar a base quando há mais de uma direção possível.

A primeira lista é a lista das tuplas de posições e direções válidas para o inimigo se mover.
A segunda lista é a lista de posições do caminho que o inimigo deve seguir.

-}

escolheDirecao :: [(Posicao,Direcao)] -> [Posicao] -> Maybe Direcao
escolheDirecao [] _ = Nothing
escolheDirecao _ [] = Nothing
escolheDirecao ((pos,d):rl) caminho
    | elem (posicaoArredondada pos) caminho = Just d
    | otherwise = escolheDirecao rl caminho
    where posicaoArredondada :: Posicao -> Posicao
          posicaoArredondada (x,y) = (fromIntegral (floor x),fromIntegral (floor y))

-- | Função auxiliar que verifica se uma dada posição pertence ao caminho que o inimigo deve seguir.
pertenceCaminho :: Posicao -> [Posicao] -> Bool
pertenceCaminho _ [] = False
pertenceCaminho (x,y) caminho = elem (x',y') caminho
    where (x',y') = (fromIntegral (floor x),fromIntegral (floor y)) -- ^ arredonda para pegar a posição "toda" (a da matriz)
 
-- | Função que move o inimigo de acordo com a sua direção e velocidade.
moveInimigo :: Tempo -> Inimigo -> Posicao -> Mapa -> (Direcao,Posicao)
moveInimigo t Inimigo {posicaoInimigo = (x,y), direcaoInimigo = direcao, velocidadeInimigo = velocidade, projeteisInimigo = lprojeteis} posbase mapa
    = if any (\proj -> tipoProjetil proj == Gelo) lprojeteis
      then (direcao,(x,y))
      else
        let caminho = map (\(x,y) -> (fromIntegral (floor x),fromIntegral(floor y))) (fromJust(encontrarCaminho (x,y) (posbase) mapa)) -- ^ passa o caminho para as posições "gerais"
            posicoesvalidas = getPosicoesValidas (x,y) direcao mapa
        in case direcao of
            Norte -> if pertenceCaminho (x,y-0.501) caminho
                     then (direcao,(x,y-(velocidade*t)))
                     else trace ("Posicao direcao atual:" ++ show (direcao,(x,y)) ++ "Escolhendo direção: " ++ show (posicoesvalidas, caminho)) $ (fromJust (escolheDirecao posicoesvalidas caminho), (x,y)) -- ^ tomada de decisão (mais de uma direção possível e a direção Norte não leva a base)

            Sul ->  if pertenceCaminho (x,(y+0.501)) caminho
                    then (direcao,(x,y+(velocidade*t)))
                    else (fromJust (escolheDirecao posicoesvalidas caminho), (x,y))

            Este -> if pertenceCaminho (x+0.501,y) caminho
                    then (direcao,(x+(velocidade*t),y))
                    else (fromJust (escolheDirecao posicoesvalidas caminho), (x,y))

            Oeste -> if pertenceCaminho (x-0.501,y) caminho
                     then (direcao,(x-(velocidade*t),y))
                     else (fromJust (escolheDirecao posicoesvalidas caminho), (x,y))
Editor is loading...
Leave a Comment