1
resposta

posicao_valida?': undefined method `[]' for nil:NilClass (NoMethodError)

Oi pessoal,

Não estou conseguindo entender porque que o "mapa[nova_posicao[0]]" esta aparecendo como nulo, como assim ele é nulo? Nós já não definimos o valor da "nova_posicao[0]" retornando o heroi na "calcula_nova_posicao heroi, direcao"?

O meu código está assim:

require_relative 'ui'

def le_mapa(numero)
    arquivo = "mapa#{numero}.txt"
    texto = File.read arquivo
    mapa = texto.split "\n"
end

def encontra_jogador(mapa)
    caractere_do_heroi = "H"
    mapa.each_with_index do |linha_atual, numero_da_linha|
        coluna_do_heroi = linha_atual.index caractere_do_heroi
        if coluna_do_heroi
            return [numero_da_linha, coluna_do_heroi]
        end
    end
    # nao achei
end

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

    movimento = movimentos[direcao]
    heroi[0] += movimento[0]
    heroi[1] += movimento[1]
    heroi
end

def posicao_valida? (mapa, nova_posicao)

    estourou_linhas = nova_posicao[0] < 0 || nova_posicao[0] >= mapa.size
    estourou_colunas = nova_posicao[1] < 0 || nova_posicao[1] >= mapa[0].size

    if estourou_linhas || estourou_colunas
        return false
    end


    tem_muro = mapa[nova_posicao[0]][nova_posicao[1]] == "X"
    tem_fantasma = mapa[nova_posicao[0]][nova_posicao[1]] == "F"


    if tem_muro || tem_fantasma
        return false
   end

   true

end



def move_fantasmas(mapa)
    caractere_do_fantasma = "F"
    mapa.each_with_index do |linha_atual, linha|
        linha_atual.chars.each_with_index do |caractere_atual, coluna|
            eh_fantasma = caractere_atual == caractere_do_fantasma
            if eh_fantasma
                move_fantasma mapa, linha, coluna
            end
        end
    end
end

def posicoes_validas_a_partir_de (mapa, nova_posicao)
    posicoes = []

    baixo = [nova_posicao[0] + 1, nova_posicao[1]]
    if posicao_valida? mapa, baixo
        posicoes << baixo
    end

    direita = [nova_posicao[0], nova_posicao[1] + 1]
    if posicao_valida? mapa, direita
        posicoes << direita
    end

    cima = [nova_posicao[0] - 1, nova_posicao[1]]
    if posicao_valida? mapa, cima
        posicoes << cima
    end

    esquerda = [nova_posicao[0], nova_posicao[1] - 1]
    if posicao_valida? mapa, esquerda
        posicoes << esquerda
    end

    posicoes
end

def move_fantasma (mapa, linha, coluna)
    posicoes = posicoes_validas_a_partir_de mapa, [linha, coluna]

    if posicoes.empty?
        return
    end


    nova_posicao = posicoes[0]

    if posicao_valida? mapa, nova_posicao
        mapa[linha][coluna] = " "
        mapa[nova_posicao[0]][nova_posicao[1]] = "F"
    end
end


def joga(nome)
    mapa = le_mapa 2

    while true
        desenha mapa
        direcao = pede_movimento
        heroi = encontra_jogador mapa
        nova_posicao = calcula_nova_posicao heroi, direcao
        if !posicao_valida? mapa, nova_posicao
            next
        end
        mapa[heroi[0]][heroi[1]] = " "
        mapa[nova_posicao[0]][nova_posicao[1]] = "H"

        move_fantasmas mapa
    end

end


def inicia_fogefoge
    nome = da_boas_vindas
    joga nome
end

Quando eu rodo ele no terminal e entro com alguma das letras ("W", "A", "S", "D") para mover o herói funciona perfeitamente, porém, se eu inverter a ordem da checagem das posições validas, ou seja, se eu checar primeiro se tem fantasma e se tem muro e depois checar se estourou linha ou estourou coluna da erro.

A diferença no código seria essa:

def posicao_valida? (mapa, nova_posicao)

    tem_muro = mapa[nova_posicao[0]][nova_posicao[1]] == "X"
    tem_fantasma = mapa[nova_posicao[0]][nova_posicao[1]] == "F"


    if tem_muro || tem_fantasma
        return false
   end

    estourou_linhas = nova_posicao[0] < 0 || nova_posicao[0] >= mapa.size
    estourou_colunas = nova_posicao[1] < 0 || nova_posicao[1] >= mapa[0].size

    if estourou_linhas || estourou_colunas
        return false
    end

   true

end

Se eu rodar o código dessa maneira aparece o seguinte erro:

rb:37:in posicao_valida?': undefined method[]' for nil:NilClass (NoMethodError)

Não consigo entender porque! Porque eu tenho que necessariamente checar primeiro se estourou linha ou coluna antes de checar se tem fantasma ou muro?

Desde já agradeço!!

Garanta sua matrícula hoje e ganhe + 2 meses grátis

Continue sua jornada tech com ainda mais tempo para aprender e evoluir

Quero aproveitar agora
1 resposta

Nossa Henrique, pra mim também não faz sentido, não entendi. A ordem das verificações não deveria importar nesse caso.

Você consegue subir seu projeto no GitHub do jeito que ele tá para que eu consiga testar com seus arquivos originais e verificar o problema mais de perto.?

Olhando o código de longe assim eu não vou conseguir simular bem o problema.