{-|
Module      : Tarefa4
Description : Implementar uma tática de jogo.

Módulo para a realização da Tarefa 4 de LI1/LP1 em 2025/26.
-}
module Tarefa4 where

import Data.Either

import Labs2025
import Tarefa2
import Tarefa3

-- | Função principal da Tarefa 4. Dado um estado retorna uma lista de jogadas, com exatamente 100 jogadas.
tatica :: Estado -> [(NumMinhoca,Jogada)]
tatica :: Estado -> [(Ticks, Jogada)]
tatica Estado
e = [(Ticks, Jogada)] -> [(Ticks, Jogada)]
forall a. [a] -> [a]
reverse ([(Ticks, Jogada)] -> [(Ticks, Jogada)])
-> [(Ticks, Jogada)] -> [(Ticks, Jogada)]
forall a b. (a -> b) -> a -> b
$ (Estado, [(Ticks, Jogada)]) -> [(Ticks, Jogada)]
forall a b. (a, b) -> b
snd ((Estado, [(Ticks, Jogada)]) -> [(Ticks, Jogada)])
-> (Estado, [(Ticks, Jogada)]) -> [(Ticks, Jogada)]
forall a b. (a -> b) -> a -> b
$ ((Estado, [(Ticks, Jogada)])
 -> Ticks -> (Estado, [(Ticks, Jogada)]))
-> (Estado, [(Ticks, Jogada)])
-> [Ticks]
-> (Estado, [(Ticks, Jogada)])
forall b a. (b -> a -> b) -> b -> [a] -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl (Estado, [(Ticks, Jogada)]) -> Ticks -> (Estado, [(Ticks, Jogada)])
avancaTatica (Estado
e,[]) [Ticks
0..Ticks
100]

-- | Aplica uma sequência de jogadas a um estado, avançando o tempo entre jogadas.
avancaTatica :: (Estado,[(NumMinhoca,Jogada)]) -> Ticks -> (Estado,[(NumMinhoca,Jogada)])
avancaTatica :: (Estado, [(Ticks, Jogada)]) -> Ticks -> (Estado, [(Ticks, Jogada)])
avancaTatica (Estado
e,[(Ticks, Jogada)]
js) Ticks
tick = ((Ticks, Jogada) -> Estado -> Estado
avancaJogada (Ticks, Jogada)
j Estado
e,(Ticks, Jogada)
j(Ticks, Jogada) -> [(Ticks, Jogada)] -> [(Ticks, Jogada)]
forall a. a -> [a] -> [a]
:[(Ticks, Jogada)]
js)
    where j :: (Ticks, Jogada)
j = Ticks -> Estado -> (Ticks, Jogada)
jogadaTatica Ticks
tick Estado
e

-- | Aplica uma jogada de uma minhoca a um estado, e avança o tempo.
avancaJogada :: (NumMinhoca,Jogada) -> Estado -> Estado
avancaJogada :: (Ticks, Jogada) -> Estado -> Estado
avancaJogada (Ticks
i,Jogada
j) e :: Estado
e@(Estado Mapa
_ [Objeto]
objetos [Minhoca]
minhocas) = (Danos -> Estado -> Estado) -> Estado -> [Danos] -> Estado
forall a b. (a -> b -> b) -> b -> [a] -> b
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr Danos -> Estado -> Estado
aplicaDanos Estado
e'' [Danos]
danoss''
    where
    e' :: Estado
e'@(Estado Mapa
mapa' [Objeto]
objetos' [Minhoca]
minhocas') = Ticks -> Jogada -> Estado -> Estado
efetuaJogada Ticks
i Jogada
j Estado
e
    minhocas'' :: [Minhoca]
minhocas'' = ((Ticks, Minhoca, Minhoca) -> Minhoca)
-> [(Ticks, Minhoca, Minhoca)] -> [Minhoca]
forall a b. (a -> b) -> [a] -> [b]
map (Estado -> (Ticks, Minhoca, Minhoca) -> Minhoca
avancaMinhocaJogada Estado
e') ([Ticks] -> [Minhoca] -> [Minhoca] -> [(Ticks, Minhoca, Minhoca)]
forall a b c. [a] -> [b] -> [c] -> [(a, b, c)]
zip3 [Ticks
0..] [Minhoca]
minhocas [Minhoca]
minhocas')
    ([Objeto]
objetos'',[Danos]
danoss'') = [Either Objeto Danos] -> ([Objeto], [Danos])
forall a b. [Either a b] -> ([a], [b])
partitionEithers ([Either Objeto Danos] -> ([Objeto], [Danos]))
-> [Either Objeto Danos] -> ([Objeto], [Danos])
forall a b. (a -> b) -> a -> b
$ ((Ticks, Objeto) -> Either Objeto Danos)
-> [(Ticks, Objeto)] -> [Either Objeto Danos]
forall a b. (a -> b) -> [a] -> [b]
map (Estado -> [Objeto] -> (Ticks, Objeto) -> Either Objeto Danos
avancaObjetoJogada Estado
e' [Objeto]
objetos) ([Ticks] -> [Objeto] -> [(Ticks, Objeto)]
forall a b. [a] -> [b] -> [(a, b)]
zip [Ticks
0..] [Objeto]
objetos')
    e'' :: Estado
e'' = Mapa -> [Objeto] -> [Minhoca] -> Estado
Estado Mapa
mapa' [Objeto]
objetos'' [Minhoca]
minhocas''

-- | Avança o tempo para o estado de uma minhoca, se não efetuou a última jogada.
avancaMinhocaJogada :: Estado -> (NumMinhoca,Minhoca,Minhoca) -> Minhoca
avancaMinhocaJogada :: Estado -> (Ticks, Minhoca, Minhoca) -> Minhoca
avancaMinhocaJogada Estado
e (Ticks
i,Minhoca
minhoca,Minhoca
minhoca') = if Minhoca -> Maybe Posicao
posicaoMinhoca Minhoca
minhoca Maybe Posicao -> Maybe Posicao -> Bool
forall a. Eq a => a -> a -> Bool
== Minhoca -> Maybe Posicao
posicaoMinhoca Minhoca
minhoca'
    then Estado -> Ticks -> Minhoca -> Minhoca
avancaMinhoca Estado
e Ticks
i Minhoca
minhoca'
    else Minhoca
minhoca'

-- | Avança o tempo para o estado de um objeto, se não foi criado pela última jogada.
avancaObjetoJogada :: Estado -> [Objeto] -> (NumObjeto,Objeto) -> Either Objeto Danos
avancaObjetoJogada :: Estado -> [Objeto] -> (Ticks, Objeto) -> Either Objeto Danos
avancaObjetoJogada Estado
e [Objeto]
objetos (Ticks
i,Objeto
objeto') = if Objeto -> [Objeto] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
elem Objeto
objeto' [Objeto]
objetos
    then Estado -> Ticks -> Objeto -> Either Objeto Danos
avancaObjeto Estado
e Ticks
i Objeto
objeto'
    else Objeto -> Either Objeto Danos
forall a b. a -> Either a b
Left Objeto
objeto'

-- | Para um número de ticks desde o início da tática, dado um estado, determina a próxima jogada.
jogadaTatica :: Ticks -> Estado -> (NumMinhoca,Jogada)
jogadaTatica :: Ticks -> Estado -> (Ticks, Jogada)
jogadaTatica Ticks
t Estado
e = (Ticks, Jogada)
forall a. HasCallStack => a
undefined