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

Problemas com o processo da Bomba

Ao tentar implementar o conceito recursivo no mapa 3, o mesmo retornar erro abaixo. /Users/rafaelmcorrea/Desktop/Ruby on Rails/Foge-Foge/foge-foge.rb:94:in explode_bomba': undefined method[]' for nil:NilClass (NoMethodError)

LOGIC
require_relative 'ui'
require_relative 'heroi'

def le_mapa(numero)
    arquivo = "mapa#{numero}.txt"
    texto = File.read arquivo
    mapa = texto.split "\n"
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
            heroi = Heroi.new
            heroi.linha  = linha
            heroi.coluna = coluna_do_heroi
            return heroi
        end
    end
    nil
end

def posicao_valida?(posicao, mapa)
    linhas  = mapa.size
    colunas = mapa[0].size
    estourou_linhas  = posicao[0] < 0 || posicao[0] >= linhas
    estourou_colunas = posicao[1] < 0 || posicao[1] >= colunas

    if estourou_linhas || estourou_colunas
        return false
    end

    muro = mapa[posicao[0]][posicao[1]] == "X"
    fantasma = mapa[posicao[0]][posicao[1]] == "F"

    if muro || fantasma
        return false
    end
    true
end

def soma_vetor(vetor1, vetor2)
    [vetor1[0] + vetor2[0], vetor1[1] + vetor2[1]]
end

def movimenta_fantasma_apartir_de(mapa, novo_mapa, posicao)
    posicoes  = []
    movimentos = [[+1, 0], [0, -1], [-1, 0], [0, +1]]
    movimentos.each do |movimento|
        nova_posicao = soma_vetor(movimento, posicao)

        if posicao_valida?(nova_posicao, mapa) && posicao_valida?(nova_posicao, novo_mapa)
            posicoes << nova_posicao
        end
    end
    posicoes
end

def copia_mapa(mapa)
    novo_mapa = mapa.join("\n").tr("F", " ").split "\n"
end

def movimenta_fantasma(mapa, novo_mapa, linha, coluna) 
    posicao = movimenta_fantasma_apartir_de mapa, novo_mapa, [linha, coluna]
    if posicao.empty?
        return
    end
    aleatorio = rand(posicao.size)
    posicoes = posicao[aleatorio]
    mapa[linha][coluna] = " "
    novo_mapa[posicoes[0]][posicoes[1]] = "F"
end

def move_fantasma(mapa)
    caracter_do_fantasma = "F"
    novo_mapa = copia_mapa mapa
    mapa.each_with_index do |linha_atual, linha|
        linha_atual.chars.each_with_index do |caracter_atual, coluna|
            fantasma = caracter_atual == caracter_do_fantasma
            if fantasma
                movimenta_fantasma mapa, novo_mapa, linha, coluna
            end
        end    
    end
    novo_mapa
end

def perdeu?(mapa)
    !encontra_jogador mapa
end

def explode_bomba(mapa, posicao, quantidade)
    muro = mapa[posicao.linha][posicao.coluna] == "X"
    if muro
        return
    end
    posicao.remove_do mapa
    bomba mapa, posicao, quantidade - 1
end

def bomba(mapa, posicao, quantidade)

    if quantidade == 0
        puts "qtde #{quantidade}"
        return
    end

    explode_bomba mapa, posicao.direita, quantidade
    explode_bomba mapa, posicao.esquerda, quantidade
    explode_bomba mapa, posicao.cima, quantidade
    explode_bomba mapa, posicao.baixo, quantidade
end

def valida_tecla?(direcao)
    if direcao != ("W") && direcao != ("S") &&
       direcao != ("A") && direcao != ("D") 
        tecla_invalida
        return false
    end
    true
end

def joga(nome)
    mapa = le_mapa 3
    while true
        desenha mapa
        direcao = pede_movimento

        if !valida_tecla?(direcao)
            next
        end

        heroi = encontra_jogador mapa
        nova_direcao = heroi.calcula_nova_posicao direcao

        if !posicao_valida? nova_direcao.to_array, mapa
            next
        end

        heroi.remove_do mapa

        if mapa[nova_direcao.linha][nova_direcao.coluna] == "*"
            bomba mapa, nova_direcao, 4
            puts "retorno funcao bomba, funcao atu joga"
        end

        nova_direcao.coloca_no mapa
        mapa = move_fantasma mapa

        if  perdeu? mapa
            game_over
            break
        end
    end 
end

def inicia_foge_foge
    nome = da_boas_vindas
    joga nome
end

UI
require_relative 'ui'

def da_boas_vindas
    puts "Bem vindo ao jogo Foge-Foge"
    puts "Qual é o seu nome?"
    nome = gets.strip
    puts "\n\n\n"
    puts "Comecaremos o jogo para voce, #{nome}"
    nome
end

def desenha(mapa)
    puts mapa
end

def tecla_invalida
    puts "Tecla inválida! Favor informar apenas movimentos validos."
    puts "\n"
    puts "***********************************"
    puts "* Movimentos validos W - Cima     *"
    puts "*                    S - Baixo    *"
    puts "*                    A - Direita  *"
    puts "*                    D - Esquerda *"
    puts "***********************************"
    puts "\n"
end

def pede_movimento
    puts "Para qual direcao deseja ir?"
    movimento = gets.strip.upcase
end

def game_over
    puts "\n\n\n"
    puts "Game Over!"
end

CLASS Heroi

class Heroi
    attr_accessor :linha, :coluna

    def calcula_nova_posicao(direcao)
        novo_heroi = dup
        movimentos = 
            {
                "W" => [-1,0],
                "S" => [+1,0],
                "A" => [0,-1],
                "D" => [0,+1]
            }
        movimento = movimentos[direcao]
        novo_heroi.linha  += movimento[0]
        novo_heroi.coluna += movimento[1]
        novo_heroi
    end

    def cima
        calcula_nova_posicao("W")
    end

    def baixo
        calcula_nova_posicao("S")
    end

    def esquerda
        calcula_nova_posicao("A")
    end

    def direita
        calcula_nova_posicao("D")
    end

    def to_array
        [linha, coluna]    
    end

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

    def coloca_no(mapa)
        mapa[linha][coluna] = "H"
    end

end
3 respostas

Oi Rafael, tudo bem? Pelo erro, me parece que você em uma posição inválida no mapa, onde deveria ter um espaço em branco, não tem nada e ai na leitura, o ruby passa um nil e você tenta acessar como se fosse um array, por isso o erro. Já verificou se o mapa tá certinho?

solução!

Opa, boa tarde Wanderson! ... Entao eu olhei sim o mapa3 e me pareceu tudo certo, ao menos nao vi nada fora do normal. Inclusive incluir algumas bombas a mais no mapa.

Mapa3.txt
XXXXXXXXXXXXXXXXX
X   FFF  X    * X
X X XX X X X XX X
X X X* X     X  X
X * X XXXX XXX XX
  X     XX  X   X
 XXX XX XXX*X X X
  X         X X X
X   X X*XXX FFF X
X X   * XXX XXX X
X X*XXX   X XXX X
X  HXXX X X   X X
XXX*FXXFX   X   X

Coloquei um tratamento para nulidade , após muito apanhar e funcionou, nao sei se foi a melhor solucao, mas foi o que conseguir fazer.

Foge-foge.rb
require_relative 'ui'
require_relative 'heroi'

def le_mapa(numero)
    arquivo = "mapa#{numero}.txt"
    texto = File.read arquivo
    mapa = texto.split "\n"
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
            heroi = Heroi.new
            heroi.linha  = linha
            heroi.coluna = coluna_do_heroi
            return heroi
        end
    end
    nil
end

def posicao_valida_nul?(posicao, mapa)
    linhas  = mapa.size
    colunas = mapa[0].size
    estourou_linhas  = posicao[0] < 0 || posicao[0] >= linhas  || nil
    estourou_colunas = posicao[1] < 0 || posicao[1] >= colunas || nil

    if estourou_linhas || estourou_colunas
        return false
    end

    muro = mapa[posicao[0]][posicao[1]] == "X"
    if muro
        return false
    end
    true
end

def posicao_valida?(posicao, mapa)
    linhas  = mapa.size
    colunas = mapa[0].size
    estourou_linhas  = posicao[0] < 0 || posicao[0] >= linhas
    estourou_colunas = posicao[1] < 0 || posicao[1] >= colunas

    if estourou_linhas || estourou_colunas
        return false
    end

    muro = mapa[posicao[0]][posicao[1]] == "X"
    fantasma = mapa[posicao[0]][posicao[1]] == "F"

    if muro || fantasma
        return false
    end
    true
end

def soma_vetor(vetor1, vetor2)
    [vetor1[0] + vetor2[0], vetor1[1] + vetor2[1]]
end

def movimenta_fantasma_apartir_de(mapa, novo_mapa, posicao)
    posicoes  = []
    movimentos = [[+1, 0], [0, -1], [-1, 0], [0, +1]]
    movimentos.each do |movimento|
        nova_posicao = soma_vetor(movimento, posicao)

        if posicao_valida?(nova_posicao, mapa) && posicao_valida?(nova_posicao, novo_mapa)
            posicoes << nova_posicao
        end
    end
    posicoes
end

def copia_mapa(mapa)
    novo_mapa = mapa.join("\n").tr("F", " ").split "\n"
end

def movimenta_fantasma(mapa, novo_mapa, linha, coluna) 
    posicao = movimenta_fantasma_apartir_de mapa, novo_mapa, [linha, coluna]
    if posicao.empty?
        return
    end
    aleatorio = rand(posicao.size)
    posicoes = posicao[aleatorio]
    mapa[linha][coluna] = " "
    novo_mapa[posicoes[0]][posicoes[1]] = "F"
end

def move_fantasma(mapa)
    caracter_do_fantasma = "F"
    novo_mapa = copia_mapa mapa
    mapa.each_with_index do |linha_atual, linha|
        linha_atual.chars.each_with_index do |caracter_atual, coluna|
            fantasma = caracter_atual == caracter_do_fantasma
            if fantasma
                movimenta_fantasma mapa, novo_mapa, linha, coluna
            end
        end    
    end
    novo_mapa
end

def perdeu?(mapa)
    !encontra_jogador mapa
end

def explode_bomba(mapa, posicao, quantidade)
    if posicao_valida_nul?(posicao.to_array, mapa)
        posicao.remove_do mapa
        bomba mapa, posicao, quantidade - 1
    else
        return
    end    
end

def bomba(mapa, posicao, quantidade)
    if quantidade == 0
        return
    end
    explode_bomba mapa, posicao.direita, quantidade
    explode_bomba mapa, posicao.esquerda, quantidade
    explode_bomba mapa, posicao.cima, quantidade
    explode_bomba mapa, posicao.baixo, quantidade
end

def valida_tecla?(direcao)
    if direcao != ("W") && direcao != ("S") &&
       direcao != ("A") && direcao != ("D") 
        tecla_invalida
        return false
    end
    true
end

def joga(nome)
    mapa = le_mapa 4
    while true
        desenha mapa
        direcao = pede_movimento

        if !valida_tecla?(direcao)
            next
        end

        heroi = encontra_jogador mapa
        nova_direcao = heroi.calcula_nova_posicao direcao

        if !posicao_valida? nova_direcao.to_array, mapa
            next
        end

        heroi.remove_do mapa

        if mapa[nova_direcao.linha][nova_direcao.coluna] == "*"
            bomba mapa, nova_direcao, 4
        end

        nova_direcao.coloca_no mapa
        mapa = move_fantasma mapa

        if  perdeu? mapa
            game_over
            break
        end
    end 
end

def inicia_foge_foge
    nome = da_boas_vindas
    joga nome
end

Apos o tratamento funcionou para todos os mapas, obrigado pela ajuda!

Ainda acho que seja algum problema no mapa, mas fico feliz que tenha resolvido.