1. Este site usa cookies. Ao continuar a usar este site está a concordar com o nosso uso de cookies. Saber Mais.

[Dúvida] HASKELL

Discussão em 'Programação' iniciada por kripton2007, 22 de Dezembro de 2008. (Respostas: 29; Visualizações: 1933)

  1. kripton2007

    kripton2007 Power Member

    Boas...

    Ja expus as minhas dúvidas sobre este assunto num outro tópico que não era meu mas que era sobre o mesmo trabalho, no entanto as dúvidas do criador desse tópico foram esclarecidas e como tal o tópico foi dado como [Resolvido].
    Tendo em conta que ainda estou à rasca nesta matéria decidi por bem criar um tópico novo para esclarecer tudo aquilo em que tenho dúvidas.

    Então aqui vai informação:

    É o seguinte, tenho um trabalho prático para fazer até dia 4 de Janeiro para a disciplina de Laboratórios de Informática de LEI 1º Ano. Este trabalho consiste em fazer um jogo em Haskell, sendo ele o conhecido 4 em Linha. Em cada jogada, o jogador pode colocar uma das suas peças numa coluna não cheia. A posição dessa coluna que é ocupada é a seguinte à última que foi ocupada.

    No entanto, fazer o jogo tal como o conhecemos não basta... o prof. quer que implementemos uma variante do jogo a qual se vai dar o nome "Segmentos". O objectivo do jogo é acumular o maior número de pontos possível. Os pontos são conseguidos quando se obtêm linhas de n peças iguais. Essas linhas podem ser verticais, horizontais ou na diagonal. A pontuação será diferente, consoante o número de peças em linha. Fica aqui o exemplo:

    2 peças = 1 ponto
    3 peças = 3 pontos
    4 peças = 6 pontos
    5 peças = 10 pontos
    6 peças = 15 pontos
    7 peças = 21 pontos
    ...

    Desta forma, o jogo não termina assim que um jogador faça o 4 em linha, mas sim quando o tabuleiro do jogo ficar cheio... sendo que os pontos acumulados por cada jogador serão contabilizados no decorrer do jogo, e ganha o jogador com maior número de pontos.


    Ora, o 1º passo sugerido para a elaboração do trabalho passa por definir os tipos apropriados para representar tabuleiros e jogadas e definir o tipo dos tabuleiros como uma instância de classes (a mais apropriada, por exemplo: SHOW).

    Posto isto, comecei por definir os tipos para o tabuleiro:

    Código:
    type J            = Int 
    type Jogada    = (J)
    type Coluna    = [Jogada]
    type Tabuleiro = [Coluna]

    De seguida, e seguindo as indicações do prof. decidi elaborar o tabuleiro como sendo uma lista de listas, o que iria dar algo deste género:

    Código:
    tabuleiroJogo :: Int -> Int -> Tabuleiro                
    tabuleiroJogo coluna linha = (tabela coluna linha)      
    tabela l c = [ [(0) | y <- [1..c] ] | x<- [1..l] ] 
    em que o seu resultado seria o seguinte:

    > tabuleiroJogo 2 2
    > [[0,0],[0,0]]


    Acontece que agora não consigo passar daqui, bloqueei por completo. A ideia é passar o tabuleiro para um modo gráfico do género:

    |___|___|___|___|
    |_X_|_X_|_O_|___|
    |_O_|_X_|_O_|_X_|


    Tenho também algum código que um colega meu escreveu para esse efeito, mas acontece que não sei bem como implementá-lo no programa. No entanto aqui fica ele:

    Código:
    type BoardLine = [FieldValue]
    type Board     = [BoardLine]
     
    data FieldValue = Null
                          | P1
                          | P2
     
    drawBoard :: Board -> IO ()
    drawBoard []    = return ()
    drawBoard (line:lines) = do drawBoardLine line
                                         drawBoard lines
     
    drawBoardLine :: BoardLine -> IO ()
    drawBoardLine []     = putStrLn ("|")
    drawBoardLine (c:cs) = do
                             drawBoardField c
                             drawBoardLine cs
     
    drawBoardField :: FieldValue -> IO ()
    drawBoardField value = putStr ("|_"++ signal ++ "_")
                                    where signal = case (value) of
                                                            Null -> "_"
                                                            P1   -> "X"
                                                            P2   -> "O"
    

    Gostava que alguém me pudesse ajudar com isto... visto estar a ficar com pouco tempo!

    Obrigado


    Cumps kripton2007
     
  2. kripton2007

    kripton2007 Power Member

    Ajudas plz...

    :S
     
  3. Baderous

    Baderous Banido

    Aconselhava-te a passares pelo [email protected]. Lá tens mais pessoal que te pode ajudar do que aqui, existe até uma secção dedicada ao Haskell já com várias dúvidas desse trabalho.
     
  4. kripton2007

    kripton2007 Power Member

    Yah.. eu ja passei por la, mas não consegui obter nada de concreto! :S
    e o k é certo é k estou a dar em maluco com a carrada de trabalhos que tenho para entregar em tão curto período de tempo!

    eu não queria chegar a estes termos, mas não se consegue arranjar algum programa relativamente parecido com o trbalho proposto para que eu possa fazer uma adaptação ou para que possa modificar alguma coisa.

    Estou mesmo a ficar desesperado! :(
     
  5. Baderous

    Baderous Banido

    Quanto aos tipos que definiste, não os podes definir como instâncias de Show, pois estas têm de ter como tipo parâmetro um tipo polimórfico do tipo T a b c, ou seja, daqueles tipos definidos com a keyword "data".
     
  6. kripton2007

    kripton2007 Power Member

    estás a falar do 1º código que aparece neste post certo?
     
  7. kripton2007

    kripton2007 Power Member

    pois... disseram-me k não preciso desses tipos para nada, que posso fazer tudo através daquilo que fiz no ultimo código aqui apresentado!

    é verdade?
     
  8. kripton2007

    kripton2007 Power Member

    Ora então precisava de ajuda para o seguinte. Utilizando esta solução para fazer o tabuleiro, pretendo criar uma função "comecarJogo" em que vai chamar a função de um jogo com um tabuleiro vazio.
    De seguida criar a função "jogar" que irá verificar se é possivel jogar, ou seja, se o tabuleiro està ou não cheio, e vai fazendo a alternância entre o jogador 1 e 2.
    É também necessário criar a função "pedeJogada" que vai perguntar qual a coluna em que o jogador pretende colocar a peça, e de seguida coloca a peça desse jogador na coluna pretendida e apresenta o tabuleiro actualizado.

    Código:
    type BoardLine = [FieldValue]
    type Board     = [BoardLine]
     
    data FieldValue = Null
                          | P1
                          | P2
     
    drawBoard :: Board -> IO ()
    drawBoard []    = return ()
    drawBoard (line:lines) = do drawBoardLine line
                                         drawBoard lines
     
    drawBoardLine :: BoardLine -> IO ()
    drawBoardLine []     = putStrLn ("|")
    drawBoardLine (c:cs) = do
                             drawBoardField c
                             drawBoardLine cs
     
    drawBoardField :: FieldValue -> IO ()
    drawBoardField value = putStr ("|_"++ signal ++ "_")
                                    where signal = case (value) of
                                                            Null -> "_"
                                                            P1   -> "X"
                                                            P2   -> "O"
    

    Resumindo eu sei aquilo que tenho que fazer, mas o que é certo é k não sei como fazer, uma vez que não percebo muito de Haskell e tenho dificuldades com o código! :S

    Alguém me pode ajudar com o código disto??


    Cumps
     
  9. kripton2007

    kripton2007 Power Member

  10. Baderous

    Baderous Banido

    Na função "jogar" tens de percorrer a lista de listas e verificar se existe pelo menos um valor Null, o que te indica se há ou não uma casa para ser preenchida.
    Para a função "pedeJogada", o ideal seria dividir em 2: uma em que, dado um tabuleiro e as coordenadas de uma posição, insere uma peça no tabuleiro conforme as coordenadas; outra em que pede ao utilizador para inserir as coordenadas e depois chama a função que referi com as tais coordenadas como parâmetro. No fim, basta invocar a função que desenha o tabuleiro. Não te esqueças que tens de verificar se a posição escolhida pelo jogador já está preenchida (outra função).
    Depois a função "começarJogo" basicamente seria a função que ia chamando estas auxiliares até acabar o jogo.
     
  11. kripton2007

    kripton2007 Power Member

    pois.. o meu problema está mesmo em escrever o código! Como ja disse não percebo praticamente nada de Haskell (o facto de não gostar também ajuda), o que faz com que tenha dificuldade em programar nesta linguagem!

    Não podem dar uma ajudinha aì com o código??

    Cumps
    Obrigado


    edit: Entretanto fiz isto com ajuda de um colega meu


    --Criar Tabuleiro Novo
    criarTabuleiro :: Int -> Int -> [[Int]]
    criarTabuleiro 0 _ = []
    criarTabuleiro altura largura = (criarLinha largura) : (criarTabuleiro (altura-1) largura)

    criarLinha :: Int -> [Int]
    criarLinha 0 = []
    criarLinha largura = 0 : criarLinha (largura -1)

    --Verificar se o tabuleiro está cheio
    estaCheio :: [[Int]] -> Bool
    estaCheio (x:xs) = (length listaFiltrada) == 0
    where listaFiltrada = filter (==0) x


    com isto, falta a função para jogar, a função para pedir a jogada, para começar o jogo, da pontuação e para associar tudo isto à parte gráfica que está acima descrita.
     
    Última edição: 27 de Dezembro de 2008
  12. Baderous

    Baderous Banido

    Tens aqui um exemplo, em point-free (sem usar variáveis), da função "jogar":

    Código:
    isNull Null = True
    isNull _ = False
    
    jogar = not . null . filter (isNull) . concat
    Se quiseres com variáveis basta:

    Código:
    jogar t = not $ null $ filter (isNull)$ concat t
    O que faço é apenas a verificação de existência de um valor Null. Primeiro junto a lista de listas numa lista só com o concat, depois filtro numa lista os valores que são Null e depois verifico se essa lista é vazia através do null. O not só está lá para negar o resultado do null, isto é, se houver posições para jogar, a função "joga" retorna verdadeiro (porque como o null, nesse caso retorna falso, pois a lista não é vazia, então o not do null retorna True).
     
  13. kripton2007

    kripton2007 Power Member

    sendo assim, a tua solução para verificar se é ou não vazio é melhor que o código que coloquei agora em cima certo???
    pelo menos está mais direccionado para o restante codigo...
     
  14. Baderous

    Baderous Banido

    Eu fiz a função de acordo com os tipos de dados que me forneceste há uns posts atrás. O que tu fizeste com o teu colega está certo (supondo que a lista de listas representa um conjunto de linhas do tabuleiro. de cima para baixo e que, como tal, para verificar se o tabuleiro está cheio, basta verificar se a primeira linha está preenchida) , mas ele está a considerar uma forma de representar o tabuleiro em que as posições vazias são indicadas pelo valor 0, enquanto que eu considerei que era quando existisse o valor Null.
     
  15. kripton2007

    kripton2007 Power Member

    exacto... ja percebi!

    agora como faço para começar a jogar? suponho que faltam apenas as funções para ler a jogada, verificar se a jogada é valida, alternar de jogador, colocar a peça correspondente no tabuleiro e gerar um tabuleiro actualizado. Vou esquecer por enquanto as pontuações.

    Como faço em relação ao código dessas funções?
     
  16. MPalhas

    MPalhas Power Member

    ler a jogada pode ser tão simples como fazer um getLine para ler um valor do ecrã. se quiseres validar esse valor, para impedir erros é que já pode complicar mais. podes ver no tópico que eu criei a uns dias que eu pus lá uma parte do código que uso para isso.

    para verificar se a jogada é valida, basta verificar se a coluna escolhida tem espaço livre. como é uma lista de linhas, fica ainda mais simples. basta ver se o elemento dessa coluna na primeira linha é vazio.

    Código:
    eValida :: [[Int]] -> Int -> Bool
    eValida (linha1:linhas) col = (linha1 !! (col-1)) == 0
    
    -- ou, como não nos chegaram a ensinar aquele !!, isto faz o mesmo:
    
    eValida (linha1:linhas) col = last (take col linha1) == 0
    
    no segundo caso, pega na lista até ao elemento pretendido, e verifica se o ultimo elemento (que é o da coluna que se quer) é igual a 0. se for, quer dizer que essa coluna não está cheia e a jogada é valida


    para alternar entre os jogadores, basta que a função que vai pedindo as jogadas receba um parametro que vá alternando entre dois valores (1 e 0, True e False, qualquer coisa). um deles irá corresponder ao jogador 1 e o outro ao jogador 2 e assim saberás sempre quem é o proximo a jogar
     
  17. Baderous

    Baderous Banido

    Se fosse a ti, primeiro fazia as funções de verificar se a jogada é válida e colocar a peça no tabuleiro. Para a 1ª tens de receber o tabuleiro e as coordenadas e verificar se essa posição já está preenchida ou não. Para a 2ª é inserir um elemento numa lista.
     
  18. casdio

    casdio Power Member

    A parte da jogada ja conseguimos fazer, mas so pela consola.

    temos que fazer "jogada it (para chamar o tabuleiro modificado) 3 (nº da coluna) P1 (jogador)"

    Agora o problema e por isto a funcionar com IO's... Ai e que n tamos a ver como se faz :S
     
  19. kripton2007

    kripton2007 Power Member

    e como faço isso?
     

Partilhar esta Página