{-|
Module      : Tarefa0_geral
Description : Funções auxiliares gerais.
Copyright   : ALUNO_1_NOME <ALUNO_1_NUMERO@alunos.uminho.pt>
              ALUNO_2_NOME <ALUNO_2_NUMERO@alunos.uminho.pt>

Módulo que define funções genéricas sobre listas e matrizes, úteis na realização do projeto de
LI1\/LP1 em 2026\/27.

__NB:__ Nenhuma função deste módulo conhece as regras do jogo. As funções específicas do jogo vivem no módulo "Tarefa0_2026".
-}
module Tarefa0_geral where

-- * Tipos de dados

-- | Uma matriz é um conjunto de elementos a duas dimensões.
--
-- Em notação matemática, é geralmente representada por:
--
-- <<https://haslab.github.io/Teaching/LI1/2627/img/matriz.png>>
--
-- O @Mapa@ do jogo, em "Labs2026", é precisamente uma matriz de blocos.
type Matriz a = [[a]]

-- | Uma posição numa matriz é dada como um par (/linha/,/colunha/).
-- As coordenadas são dois números naturais e começam com (0,0) no canto superior esquerdo, com as linhas incrementando para baixo e as colunas incrementando para a direita.
--
-- <<https://haslab.github.io/Teaching/LI1/2627/img/posicaomatriz.png>>
type Posicao = (Int, Int)

-- | Dimensão de uma matriz: (/número de linhas/, /número de colunas/).
type Dimensao = (Int, Int)

-- | Direção de um movimento numa matriz: 'Cima' e 'Baixo' mudam a linha, 'Esquerda' e 'Direita'
-- mudam a coluna.
data Direcao = Cima | Baixo | Esquerda | Direita
  deriving (Direcao -> Direcao -> Bool
(Direcao -> Direcao -> Bool)
-> (Direcao -> Direcao -> Bool) -> Eq Direcao
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Direcao -> Direcao -> Bool
== :: Direcao -> Direcao -> Bool
$c/= :: Direcao -> Direcao -> Bool
/= :: Direcao -> Direcao -> Bool
Eq, Eq Direcao
Eq Direcao =>
(Direcao -> Direcao -> Ordering)
-> (Direcao -> Direcao -> Bool)
-> (Direcao -> Direcao -> Bool)
-> (Direcao -> Direcao -> Bool)
-> (Direcao -> Direcao -> Bool)
-> (Direcao -> Direcao -> Direcao)
-> (Direcao -> Direcao -> Direcao)
-> Ord Direcao
Direcao -> Direcao -> Bool
Direcao -> Direcao -> Ordering
Direcao -> Direcao -> Direcao
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: Direcao -> Direcao -> Ordering
compare :: Direcao -> Direcao -> Ordering
$c< :: Direcao -> Direcao -> Bool
< :: Direcao -> Direcao -> Bool
$c<= :: Direcao -> Direcao -> Bool
<= :: Direcao -> Direcao -> Bool
$c> :: Direcao -> Direcao -> Bool
> :: Direcao -> Direcao -> Bool
$c>= :: Direcao -> Direcao -> Bool
>= :: Direcao -> Direcao -> Bool
$cmax :: Direcao -> Direcao -> Direcao
max :: Direcao -> Direcao -> Direcao
$cmin :: Direcao -> Direcao -> Direcao
min :: Direcao -> Direcao -> Direcao
Ord, Int -> Direcao -> ShowS
[Direcao] -> ShowS
Direcao -> String
(Int -> Direcao -> ShowS)
-> (Direcao -> String) -> ([Direcao] -> ShowS) -> Show Direcao
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Direcao -> ShowS
showsPrec :: Int -> Direcao -> ShowS
$cshow :: Direcao -> String
show :: Direcao -> String
$cshowList :: [Direcao] -> ShowS
showList :: [Direcao] -> ShowS
Show, ReadPrec [Direcao]
ReadPrec Direcao
Int -> ReadS Direcao
ReadS [Direcao]
(Int -> ReadS Direcao)
-> ReadS [Direcao]
-> ReadPrec Direcao
-> ReadPrec [Direcao]
-> Read Direcao
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
$creadsPrec :: Int -> ReadS Direcao
readsPrec :: Int -> ReadS Direcao
$creadList :: ReadS [Direcao]
readList :: ReadS [Direcao]
$creadPrec :: ReadPrec Direcao
readPrec :: ReadPrec Direcao
$creadListPrec :: ReadPrec [Direcao]
readListPrec :: ReadPrec [Direcao]
Read, Int -> Direcao
Direcao -> Int
Direcao -> [Direcao]
Direcao -> Direcao
Direcao -> Direcao -> [Direcao]
Direcao -> Direcao -> Direcao -> [Direcao]
(Direcao -> Direcao)
-> (Direcao -> Direcao)
-> (Int -> Direcao)
-> (Direcao -> Int)
-> (Direcao -> [Direcao])
-> (Direcao -> Direcao -> [Direcao])
-> (Direcao -> Direcao -> [Direcao])
-> (Direcao -> Direcao -> Direcao -> [Direcao])
-> Enum Direcao
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
$csucc :: Direcao -> Direcao
succ :: Direcao -> Direcao
$cpred :: Direcao -> Direcao
pred :: Direcao -> Direcao
$ctoEnum :: Int -> Direcao
toEnum :: Int -> Direcao
$cfromEnum :: Direcao -> Int
fromEnum :: Direcao -> Int
$cenumFrom :: Direcao -> [Direcao]
enumFrom :: Direcao -> [Direcao]
$cenumFromThen :: Direcao -> Direcao -> [Direcao]
enumFromThen :: Direcao -> Direcao -> [Direcao]
$cenumFromTo :: Direcao -> Direcao -> [Direcao]
enumFromTo :: Direcao -> Direcao -> [Direcao]
$cenumFromThenTo :: Direcao -> Direcao -> Direcao -> [Direcao]
enumFromThenTo :: Direcao -> Direcao -> Direcao -> [Direcao]
Enum, Direcao
Direcao -> Direcao -> Bounded Direcao
forall a. a -> a -> Bounded a
$cminBound :: Direcao
minBound :: Direcao
$cmaxBound :: Direcao
maxBound :: Direcao
Bounded)

-- * Funções não-recursivas

-- | Verifica se o índice pertence à lista.
--
-- >>> eIndiceListaValido 2 "abc"
-- True
-- >>> eIndiceListaValido (-1) "abc"
-- False
eIndiceListaValido :: Int -> [a] -> Bool
eIndiceListaValido :: forall a. Int -> [a] -> Bool
eIndiceListaValido = Int -> [a] -> Bool
forall a. HasCallStack => a
undefined

-- | Calcula a dimensão de uma matriz.
--
-- __NB:__ Não existem matrizes de dimensão /m * 0/ ou /0 * n/; qualquer matriz vazia tem
-- dimensão /0 * 0/.
--
-- >>> dimensaoMatriz [[1,2,3],[4,5,6]]
-- (2,3)
-- >>> dimensaoMatriz [[],[]]
-- (0,0)
dimensaoMatriz :: Matriz a -> Dimensao
dimensaoMatriz :: forall a. Matriz a -> Dimensao
dimensaoMatriz = Matriz a -> Dimensao
forall a. HasCallStack => a
undefined

-- | Verifica se a posição pertence à matriz.
--
-- __NB:__ Posições com coordenadas negativas nunca pertencem a uma matriz.
--
-- Vamos buscar a linha pedida e vemos se a coluna existe /nessa/ linha, para que a função também
-- dê a resposta certa se as linhas tiverem tamanhos diferentes.
ePosicaoMatrizValida :: Posicao -> Matriz a -> Bool
ePosicaoMatrizValida :: forall a. Dimensao -> Matriz a -> Bool
ePosicaoMatrizValida = Dimensao -> Matriz a -> Bool
forall a. HasCallStack => a
undefined

-- | Move uma posição uma unidade no sentido de uma direção.
--
-- Recorde que a linha cresce para baixo: 'Cima' /decrementa/ a linha.
--
-- >>> movePosicao Cima (3,4)
-- (2,4)
-- >>> movePosicao Direita (3,4)
-- (3,5)
movePosicao :: Direcao -> Posicao -> Posicao
movePosicao :: Direcao -> Dimensao -> Dimensao
movePosicao = Direcao -> Dimensao -> Dimensao
forall a. HasCallStack => a
undefined

-- | Distância de Chebyshev entre duas posições, ou seja, o número de passos necessários para ir
-- de uma à outra podendo mover-se também na diagonal.
--
-- >>> distanciaChebyshev (0,0) (1,3)
-- 3
distanciaChebyshev :: Posicao -> Posicao -> Int
distanciaChebyshev :: Dimensao -> Dimensao -> Int
distanciaChebyshev = Dimensao -> Dimensao -> Int
forall a. HasCallStack => a
undefined

-- | Todas as posições a uma distância de Chebyshev menor ou igual a um dado raio, incluindo a
-- própria posição central.
--
-- __NB:__ A lista pode conter posições fora de qualquer matriz, incluindo posições com
-- coordenadas negativas. Cabe a quem usa esta função filtrá-las.
--
-- >>> vizinhancaPosicao 1 (0,0)
-- [(-1,-1),(-1,0),(-1,1),(0,-1),(0,0),(0,1),(1,-1),(1,0),(1,1)]
vizinhancaPosicao :: Int -> Posicao -> [Posicao]
vizinhancaPosicao :: Int -> Dimensao -> [Dimensao]
vizinhancaPosicao = Int -> Dimensao -> [Dimensao]
forall a. HasCallStack => a
undefined

-- * Funções recursivas

-- | Devolve o elemento num dado índice de uma lista.
--
-- __NB:__ Devolve @Nothing@ se o índice não existir, /incluindo quando é negativo/.
--
-- >>> encontraIndiceLista 1 "abc"
-- Just 'b'
-- >>> encontraIndiceLista 5 "abc"
-- Nothing
encontraIndiceLista :: Int -> [a] -> Maybe a
encontraIndiceLista :: forall a. Int -> [a] -> Maybe a
encontraIndiceLista = Int -> [a] -> Maybe a
forall a. HasCallStack => a
undefined

-- | Modifica um elemento num dado índice.
--
-- __NB:__ Devolve a própria lista se o índice não existir.
--
-- >>> atualizaIndiceLista 0 'z' "abc"
-- "zbc"
atualizaIndiceLista :: Int -> a -> [a] -> [a]
atualizaIndiceLista :: forall a. Int -> a -> [a] -> [a]
atualizaIndiceLista = Int -> a -> [a] -> [a]
forall a. HasCallStack => a
undefined

-- | Devolve o elemento numa dada posição de uma matriz.
--
-- __NB:__ Devolve @Nothing@ se a posição não existir.
encontraPosicaoMatriz :: Posicao -> Matriz a -> Maybe a
encontraPosicaoMatriz :: forall a. Dimensao -> Matriz a -> Maybe a
encontraPosicaoMatriz = Dimensao -> Matriz a -> Maybe a
forall a. HasCallStack => a
undefined

-- | Modifica um elemento numa dada posição de uma matriz.
--
-- __NB:__ Devolve a própria matriz se a posição não existir.
atualizaPosicaoMatriz :: Posicao -> a -> Matriz a -> Matriz a
atualizaPosicaoMatriz :: forall a. Dimensao -> a -> Matriz a -> Matriz a
atualizaPosicaoMatriz = Dimensao -> a -> Matriz a -> Matriz a
forall a. HasCallStack => a
undefined

-- | Verifica se uma matriz é válida, no sentido em que modela um retângulo.
--
-- __NB:__ Todas as linhas devem ter o mesmo número de colunas, e esse número não pode ser 0.
--
-- >>> eMatrizValida [[1,2],[3,4]]
-- True
-- >>> eMatrizValida [[1,2],[3]]
-- False
eMatrizValida :: Matriz a -> Bool
eMatrizValida :: forall a. Matriz a -> Bool
eMatrizValida = Matriz a -> Bool
forall a. HasCallStack => a
undefined