Solucionado (ver solução)
Solucionado
(ver solução)
11
respostas

Ruby III-Aula5- Vídeo 1 Funcionamento do jogo diferente do vídeo.

Apesar da função que movimenta os fantasmas ser chamada no código da função joga depois da função que movimenta o jogador. O fantasma está capturando a bomba primeiro que jogador e esse acaba sendo pego pelo fantasma com o movimento S. O mapa que eu uso tem a mesma configuração, vejam o printsreen: https://pasteboard.co/H9KNzmY.png

Qual será o motivo? será que é um problema de condição de corrida. Eu entendo que o mapa que entra na função que move fantasmas já é um que foi atualiza, afinal a passagem é por referência

def joga nome
    mapa = le_mapa 3
    while true
        desenha_mapa mapa
           direcao = pede_movimento
        heroi = encontra_jogador mapa 
        nova_posicao = heroi.calcula_nova_posicao(direcao)
        if !posicao_valida?(mapa, nova_posicao.to_array)
           next
        end
       #Movendo o jogador
        heroi.remove_do mapa
        if mapa[nova_posicao.linha][nova_posicao.coluna]=="*"
           for direita in 1..4
               mapa[nova_posicao.linha][nova_posicao.coluna+direita]== " "
           end
        end
        nova_posicao.coloca_no mapa

        #movendo os fantasmas
        mapa = move_fantasmas mapa    
        if jogador_perdeu? mapa          
           game_over
           break;           
        end
    end
end
def  jogador_perdeu? mapa

    perdeu = !encontra_jogador(mapa)      

end
def encontra_jogador mapa

    caracter_do_heroi = "H"
    mapa.each_with_index do |linha_atual,linha|
      coluna_do_heroi = linha_atual.index caracter_do_heroi        
      if coluna_do_heroi
           jogador = Heroi.new
           jogador.linha = linha
           jogador.coluna = coluna_do_heroi
           return jogador
      end

    end
    nil
end
11 respostas

Oi Romullo, tudo bem? Me diz uma coisa, qual é o alcance da bomba? Eu não lembro bem, mas o fantasma deveria ativar a bomba também?

Olá Wanderson, a regra da bomba que foi implementada ao fim foi:bomba com raio de alcance de 4 casas em todas as direções, em cada casa do raio varrer fantasma, acima, abaixo, direita, esquerda(vizinhança de 4 ) . A bomba só apaga fantasmas.

Só o herói usa ativa a bomba, a ativação é mostrada acima no código.

Porém a regra de validação de posição do fantasma é a mesma do herói. E essa regra válida apenas, colisão com paredes e fantasma. Assim o fantasma se move para cima da bomba com se fosse um espaço vazio.

A minha dúvida, é sobre ser ou não uma situação de concorrência no nível da MV do ruby . eu quero entender essa dinâmica.

No vídeo 2 da aula cinco, a chamada inline

mapa[nova_posicao.linha][nova_posicao.coluna+direita]== " "

É trocada por uma chama da de de função:

remove mapa, nova_posicao, 4

A função remove :

def remove (mapa, posicao, quantidade)
    #outra maneira seria 
    #return unless quantidade>0
    #não execute se for maior que zero
    if quantidade ==0
       return 
    end    
    executa_remocao mapa, posicao.direita, quantidade
    executa_remocao mapa, posicao.acima, quantidade   
    executa_remocao mapa, posicao.esquerda, quantidade

    executa_remocao mapa, posicao.abaixo, quantidade    
end

Que chama

def executa_remocao mapa, posicao, quantidade
    if mapa[posicao.linha][posicao.coluna]=="X"
       return 
    end    
    posicao.remove_do mapa
    remove mapa, posicao, quantidade-1
end

Lembrando que posicao é um objeto Heroi com o método remove_do

def remove_do mapa
        mapa[linha][coluna] = " "
 end

O que me deixa intrigado é que após esse encadeamento de funções substituindo a chamada inline o herói pega a bomba antes e o funcionamento do jogo é igual ao da demonstração do vídeo 1.(Observando que no vídeo 2 ainda se apagava apenas um casa para a direita, o código lá em acima implementa a regra final da bomba).

Ou seja chamando inline o fantasma tá mudando o mapa antes do herói.Mesmo o herói tendo recebido o mapa primeiro . Eu quero entender isso.

Realmente, agora que você explicou melhor, parece bem estranho mesmo. Quer dizer que antes da troca da forma como os fantasmas eram removidos, tudo funcionava corretamente, certo? O herói acionava a bomba e destruía os fantasmas, mas agora os fantasmas pegam o herói antes da bomba ser acionada. É isso?

Você pode me disponibilizar seu projeto pra mim dar uma testada pra avaliar isso mais de perto?

Quer dizer que antes da troca da forma como os fantasmas eram removidos, tudo funcionava corretamente, certo? O herói acionava a bomba e destruía os fantasmas, mas agora os fantasmas pegam o herói antes da bomba ser acionada. É isso?

Na verdade é o contrário, o que eu observei é que a demonstração no vídeo não funciona. Só funciona a partir do vídeo dois onde se faz um encadeamento com chamadas de funções. Então tem duas possibilidade ou a demonstração foi feita já com o código que seria do vídeo 2 ou tem alguma diferença entre chamar inline ou via funções para uma situação de concorrência no interpretador do Ruby. Nessa sequência da aula 5 o projeto já tinha sido refatorado com poucos conceitos de OO em Ruby. O projeto funciona

https://pastebin.com/YanYF7cV (heroi.rb) https://pastebin.com/ixi2vQ2R (ui) https://pastebin.com/2atAKTPM (fogefoge.rb sem uso de OO) https://pastebin.com/cHNDBDTy (oofogefoge.rb)

https://pastebin.com/icCXiCg3 (main chamando oofogefoge.rb)

O mapa com bombas e fantasmas usado no teste com bombas: https://pastebin.com/sAjk2F3h

Estranho que não deveria haver essa diferença. No vídeo é mostrado nas duas versões. A diferença prática é na forma como o código está sendo executado, em uma forma fazemos uso da recursão pela chamada da função dentro dela mesma até um limite e a outra forma não, estamos sendo mais diretos, mais procedurais.

Na prática as implementações são equivalentes. Lembrando que não estamos trabalhando com concorrência neste curso. Concorrência é computação paralela, e isso é feito por meio de threads (ou Fibers no Ruby). Então não podemos ter problemas de concorrência no caso, podemos ter problemas de referência de estado, um objeto alterando o estado do outro e etc.

Intrigante, eu ainda não entendi é por qual motivo a chamada inline não garante ao herói pegar a bomba apesar dele ter recebido o mapa primeiro. Não é garantido a ele a prioridade.

Eu pensei em concorrência implicitamente, no contexto do interpretador/cpu/sistema operacional . Não sei como o código é executado no interior do interpretador ou seja como o interpretador está manipulando esse blocos de códigos . Fiquei com a impressão que a chamada de função que move fantasmas passou na frente. O mapa que entraria na função move fantasma já não deveria ter o fantasma próximo a bomba. Você testou ? A sua execução foi igual ao do vídeo 1, ao apagar inline ?

Testei sim, mas já faz muito tempo que fiz esse curso e não tive tais problemas. Talvez algo tenha mudado no interpretador do Ruby nas versões mais recentes? Não sei, mas de fato, eu não tive esse problema.

Você poderia me disponibilizar um zip do seu projeto pra mim ver isso mais de perto?

Link de dropbox: https://www.dropbox.com/s/pc3cev9e0q7kh8b/fogefoge.zip?dl=0

A funcionalidade da bomba foi implementada após a refatoração usando um objeto do tipo herói no arquivo heroi.rb. O arquivo com as regras de negócios refatoradas então em oofogefoge.rb

Obrigado por querer olhar o código. Lembrando que mando a versão final do projeto do curso que funciona como esperado a partir do segundo vídeo. Para ver a anomalia basta trocar

def joga nome
    mapa = le_mapa 4
    while true
        desenha_mapa mapa
           direcao = pede_movimento
        heroi = encontra_jogador mapa 
        nova_posicao = heroi.calcula_nova_posicao(direcao)
        if !posicao_valida?(mapa, nova_posicao.to_array)
           next
        end
        heroi.remove_do mapa
        if mapa[nova_posicao.linha][nova_posicao.coluna]=="*"
           remove mapa, nova_posicao, 4
        end
        nova_posicao.coloca_no mapa

        mapa = move_fantasmas mapa    
        if jogador_perdeu? mapa          
           game_over
           break;           
        end
    end
end

Por

def joga nome
    mapa = le_mapa 4
    while true
        desenha_mapa mapa
           direcao = pede_movimento
        heroi = encontra_jogador mapa 
        nova_posicao = heroi.calcula_nova_posicao(direcao)
        if !posicao_valida?(mapa, nova_posicao.to_array)
           next
        end
        heroi.remove_do mapa
        if mapa[nova_posicao.linha][nova_posicao.coluna]=="*"
           for direita in 1..4
               mapa[nova_posicao.linha][nova_posicao.coluna+direita]== " "
           end
        end
        end
        nova_posicao.coloca_no mapa

        mapa = move_fantasmas mapa    
        if jogador_perdeu? mapa          
           game_over
           break;           
        end
    end
end
solução!

Romullo, dei uma bela investigada no código e encontrei o problema que parece ser o mais besta! Acredite, foi apenas um detalhe que deixamos passar.

Olha a linha que remove os fantasmas quando a bomba é acionada.

mapa[nova_posicao.linha][nova_posicao.coluna+direita]== " "

Ela tem dois iguais! Estamos comparando o valor do mapa a nada e assim não removemos o fantasma!

O que acontece então? O herói se move, encontra a bomba e a bomba sai do mapa, mas como ela não destrói nada, no movimento seguinte, que é a vez do fantasma, o fantasma acaba destruindo o herói. Incrível não? Apenas um sinal de igual pra acabar com o jogo inteiro.

Solução? Trocar a comparação pela atribuição!

mapa[nova_posicao.linha][nova_posicao.coluna+direita] = " "

Incrível que até a versão do Ruby eu mudei pensando que fosse algo no interpretador. Mas era apenas um igual mesmo. Acontece!

Testa pra mim? Aqui deu tudo certo nas duas formas!

Aqui vai a produção de provas contra mim: kkkkkkkk https://pasteboard.co/Hb9A3h5.png https://pasteboard.co/Hb9AJ75.png

Vou ver o pelo lado bom, o interpretador não estava bugado.

Tenho que ser mais humilde, sempre vai ser erro humano.

Outro dia no curso de android eu não conseguia carregar a foto pelo seguinte motivo: adinâmica era essa

String caminhoFoto = "\pasta\subpasta\caminho\foto.jpg"

//E na hora de passar a string caminhoFoto para 
//a função que carraga a foto  usando  a String 
//acima 

carregaFoto("caminhoFoto")

Até hoje eu não sei de onde veio o " " em torno de caminhoFoto

Muito obrigado!

Opa, nem sempre será erro humano Romullo, as vezes a gente cai em pequenas mudanças da linguagem que nos deixa meio de cabelo em pé. É um pouco mais raro, mas acontece.

O mais engraçado é que tivemos uma longa discussão em torno de um problema tão pequeno, mas que não fomos capazes de perceber inicialmente. Faz parte!

Em caso de mais problemas, pode contar com a gente, estaremos sempre por aqui!