How I can fix NoMethodError in Ruby? - ruby

I write a multiplayer game(snake) with backend based on Ruby. This function must receive commands for frontend and send the current state of the game. But throw NoMethod error on the four line of my function for the changeside method and I don't know why because of that class method is present.
Class method example
def changeside(nump,newSide)
opp = {'R':'L','U':'D','D':'U','L':'R'}
cx = {'L':-1,'R':1,'U':0,'D':0}
cx = {'L':0,'R':0,'U':-1,'D':1}
if newSide!=opposite[players[nump]['side']] && ['R','L','U','D'].count( newSide)==1
players[nump]['side']['cx'] = cx[newSide]
players[nump]['side']['cy'] = cy[newSide]
end
end
Error example
2020-10-07 18:01:23 - NoMethodError - undefined method `[]' for nil:NilClass:
The function I'm run
def getStatus(game)
ans = {"opStatus"=>TRUE}
puts game
$games[game['gid'.to_i]]['game'].changeside(2,game['side'])
$games[game['gid'.to_i]]['game'].move(($games[game['gid']]['fid']==game['pid']?1:2))
ans["gameStatus"] = $games[game['id']]['game'].run
ans['timer'] = $games[game['id']]['game'].timer
ans['snake'] = $games[game['id']][($games[game['id']]['fid']==game['pid']?1:2)].snake
ans['enemy'] = $games[game['id']][($games[game['id']]['fid']==game['pid']?2:1)].snake
ans['food'] = $games[game['id']]['game'].food
end
Here is JSON sent to the function
{"gid"=>"1", "side"=>"R", "pid"=>"1"}
To fix that, I debugged that moment, but I couldn't go inside a class method.
Here is the full code of the class game.
It located in another file and called by
`require_relative 'game.rb'`
Full code of the class.
class Game
attr_accessor :players, :food, :walls, :timer, :run,:winner
def initialize()
#players = {}
#winner = -1
#players[1] = {'snake'=>[[9,2],[8,2],[7,2]]}
#players[1]['cx'] = 0
#players[1]['cy'] = -1
#players[1]['side'] = 'U'
#players[2] = {'snake'=>[[2,9],[2,8],[2,7]]}
#players[2]['cx'] = -1
#players[2]['cy'] = 0
#players[2]['side'] = 'L'
#timer = 0
#run = FALSE
genFood
end
def genFood()
#food = [rand(10)+1,rand(10)+1]
while players[1]['snake'].include?(food) || players[2]['snake'].include?(food)
#food = [rand(10)+1,rand(10)+1]
end
end
def move(nump)
if #run
#timer+=0.25
#players[nump]['snake'].shift
#players[nump]['snake'].push([#players[id]['snake'][0]+#players[id]['cx'],#players[id]['snake'][1]+#players[id]['cy']])
if #players[nump]['snake'][0] == food
#players[nump]['snake'][0].unshift(food)
#food = [rand(10)+1,rand(10)+1]
while players[nump]['snake'].include(food) or players[1]['snake'].include(food)
#food = [rand(10)+1,rand(10)+1]
end
end
if #player[nump]['snake'].count(#player[nump]['snake'][-1])==2 ||
#winner = ((nump==1)?2:1)
elsif #players[((nump==1)?2:1)]['snake'].count(#player[nump]['snake'][-1])==1
#winner = 0
else
if #timer==60
if #players[1]['snake'].length()>#players[2]['snake'].length()
#winner = 1
elsif #players[1]['snake'].length()<#players[2]['snake'].length()
winner = 2
else
winner = 0
end
end
end
end
end
def changeside(nump,newSide)
opp = {'R':'L','U':'D','D':'U','L':'R'}
cx = {'L':-1,'R':1,'U':0,'D':0}
cx = {'L':0,'R':0,'U':-1,'D':1}
if newSide!=opposite[players[nump]['side']] && ['R','L','U','D'].count( newSide)==1
players[nump]['side']['cx'] = cx[newSide]
players[nump]['side']['cy'] = cy[newSide]
end
end
end

Related

Ruby instance attribute somehow being set to `true` instead of the intended value upon another attributes modification

Learning oop in Ruby and encountering some unexpected behavior in a class i've written. Here is my Radio class, I can change the volume attribute, but when I change the freq attribute, the band attribute is changed from fm to true. I cannot figure out why this is happening.
my file init.rb that's calling the Radio class:
require_relative 'classes/radio'
fm_radio = Radio.fm
fm_radio.volume = 10
puts fm_radio.status
#volume: 10 band: fm frequency: 88.0
fm_radio.freq = 99.0
puts fm_radio.status
#volume: 10 band: true frequency: 99.0
puts fm_radio.band
# true
my file radio.rb that contains the Radio class:
class Radio
attr_accessor :volume, :freq
attr_reader :band
def initialize(band)
#band = band
if band == 'am'
#freq = 540.0
else
#freq = 88.0
end
#volume = 1
end
def volume=(value)
return if value < 1 || value > 10
#volume = value
end
def freq=(value)
if #band = 'am' && (540.0..1600).include?(value)
#freq = value
elsif #band = 'fm' && (88.0..108.0).include?(value)
#freq = value
else
puts 'out of range'
end
end
def crank_it_up
#volume = 11
end
def status
"volume: #{#volume} band: #{#band} frequency: #{#freq}"
end
def self.am
Radio.new('am')
end
def self.fm
Radio.new('fm')
end
end
Your error is in these two lines:
if #band = 'am' && (540.0..1600).include?(value)
elsif #band = 'fm' && (88.0..108.0).include?(value)
Using a single =, you're assigning to #band what is evaluated from 'am' && (540.0..1600).include?(value), which eventually will be a boolean value.
You must use == to compare #band with another string.

Different obj_id but equal values in ruby?

I'm fairly new to ruby and am practicing it.
However in this exercise I'm doing it creates two bank accounts using the same method and same values, and the program expects both to be equal.
RSpec returns this to me:
Failure/Error: expect(conta1).to eql conta2
expected: #<Conta:0x3161bc8 #numero="2303-2", #nome="Jose da Silva", #saldo=1000.1, #limite=500>
got: #<Conta:0x31615f8 #numero="2303-2", #nome="Jose da Silva", #saldo=1000.1, #limite=500>
(compared using eql?)
Diff:
## -1,4 +1,4 ##
-#<Conta:0x3161bc8
+#<Conta:0x31615f8
#limite=500,
#nome="Jose da Silva",
#numero="2303-2",
The content of both the accounts are the same, but there's a conflict on the object_id, how do I resolve this?
Here is the code:
it "Two accounts with the same data should be equal" do
conta1 = cria_conta
conta2 = cria_conta
expect(conta1).to eql conta2
end
def cria_conta(numero="2303-2", nome="Jose da Silva", saldo=1000.10, limite=500)
Conta.new(numero: numero, nome: nome, saldo: saldo, limite: limite)
end
Also:
class Conta
attr_accessor :numero, :nome, :saldo, :limite
def initialize(arr)
#numero = arr[:numero]
#nome = arr[:nome]
#saldo = arr[:saldo]
#limite = arr[:limite]
end
def sacar(valor)
possibilidade = false
##valor = valor
if valor < #saldo
#saldo -= valor
possibilidade = true
elsif valor > #limite
#saldo -= valor
##saldo = #saldo
possibilidade
end
end
def no_limite?()
if ##valor > #limite
return true
elsif ##valor < #limite
return false
end
end
def depositar(valor)
#saldo += valor
end
def ==(outra_conta)
self.conta == outra_conta
end
end
I tried to define a a diffrent method for == but I was unsuccessful.
If you wants to only compare the attributes, not the object itself, here is the example code you might start with.
class Person
attr_accessor :name, :id
def initialize(id, name)
#id = id
#name = name
end
def ==(other_person)
self.instance_variables.each do |method|
method = method.to_s.gsub('#', '')
return false if self.send(method) != other_person.send(method)
end
return true
end
end
p1 = Person.new(1, 'alice')
p2 = Person.new(1, 'alice')
p3 = Person.new(1, 'tim')
puts p1 == p2 # true
puts p1 == p3 # false

syntax error, unexpected end-of-input, expecting keyword_end ( help me )!

got this error but cant figure out where i need to put an end.
test/test1:54: class definition in method body
test/test1:79: syntax error, unexpected end-of-input, expecting keyword_end
class Code
attr_reader :pegs
def initialize(pegs)
##pegs_key = { "R" => :red,"G" => :green,"B" => :blue,"Y" => :yellow,
"O" => :orange,"P" => :purple }
#pegs = pegs
end
class << self
def random
rand_pegs_set = []
4.times { rand_pegs_set << ##pegs_Key.values.sample }
Code.new(rand_pegs_set)
end
def parse(str)
str = string.split("")
pegs_set = []
str.each do |letter|
if ##pegs_key.has_key?(letter.upcase)
pegs_set << ##pegs_key[letter.upcase]
else
raise "Incorrect colors"
end
end
Code.new(pegs_set)
end
end
def exact_matches(guess)
matches = 0
pegs_set.each_with_index { |color,i| matches += 1 if self[i] == color }
matches
end
def color_counter
counter = Hash.new(0)
#pegs.each { |color| counter[color] += 1 }
counter
end
def near_matches(guess)
matches = 0
code_counter = self.color_counter
guess.color_counter.each do |color,count|
if code_counter.has_key?(color)
if code_counter[color] > count ? matches += count : matches += code_counter[color]
end
matches - self.exact_matches(guess)
end
end
class Game
attr_reader :secret_code
def initialize(secret_code = Code.random)
#secret_code = secret_code
end
def play
10.times do
puts "Enter your guess"
guess = Code.parse(gets.chomp)
if guess == #secret_code
puts "Great Job! you got it"
break
end
show_matches(guess)
end
end
def show_matches(guess)
exact_matches = #secret_code.exact_matches(guess)
near_matches = #secret_code.near_matches(guess)
puts "#{exact_matches} were exactly right"
puts "#{near_matches} were nearly a match"
end
end
Make
if code_counter[color] > count ? matches += count : matches += code_counter[color]
so
matches += (code_counter[color] > count ? count : code_counter[color])

Rubocop:method has too many lines

Hello I am new at ruby programming.
Ran rubocop inspection in my project and it says:
Method has too many lines. [13/10] def refresh_status
Here is my methods:
def refresh_status
lost = false
in_progress = false
won = false
#bets.each do |bet|
lost = true if bet.result == :lost
if bet.result == :canceled
#to_return /= bet.odd
won = true
end
in_progress = true if bet.result == :in_progress
won = true if bet.result == :won
end
def_result_after_refresh(lost, in_progress, won)
end
def def_result_after_refresh(lost, in_progress, won)
if lost
#result = :lost
elsif in_progress
#result = :in_progress
elsif won
#result = :won
end
end
Can't find a way to make that method shorter, maybe you could help?
You can use some the Enumerable methods.
def refresh_status
#to_return /= #bets.select { |bet| bet.result == :canceled }.map(&:odd).reduce(1, :*)
results = #bets.map { |bet| bet.result == :cancelled ? :won : bet.result }.uniq
#result = case
when results.include?(:lost) then :lost
when results.include?(:in_progress ) then :in_progress
when results.include?(:won) then :won
end
end

Comparing strings on Ruby

I'm new to programming in Ruby and I decided to learn to build a hangman game, but I have a problem when comparing two strings, one that comes from a gets (If I do it for me code works normal) and one that is defined.
this is my codes:
this is my 'main':
require_relative("Ahorcado")
juego = Ahorcado.new()
juego.decirPalabra
while juego.hayVidas?
juego.imprimir
lectura = gets
lectura = lectura.to_s;
juego.preguntar lectura
end
puts juego.resultado
And the Ahorcado.rb
class Ahorcado
def loadVariables
#palabras = ["java","ruby","python","go"]
#adivinados = []
#gano = false
#vidas = 7
end
def initialize
loadVariables();
#palabra = #palabras[rand(#palabras.length)].split("")
puts "Se ha iniciado un juego"
#tamano = #palabra.length
puts "Existen #{#tamano} letras"
iniciar
end
def decirPalabra
puts #palabra
end
def preguntar letra
#vidas -= 1
letra = letra.to_s
temp = #palabra.join
puts temp.eql?(letra) # -> Allways false
if letra == #palabra.join then
#gano = true
puts "gano"
else
for i in 0...#tamano
if letra.eql?(#palabra[i]) then #Allways false
#adivinados[i] = true
#vidas += 1
else
puts "Incorrecto intente otra vez"
end
end
end
end
def comparar letra
#temp = letra;
puts #temp == #palabra[0]
end
def iniciar
for i in (0...#tamano)
#adivinados[i] = false;
end
end
def hayVidas?
return #vidas > 0
end
def resultado
#gano;
end
def imprimir
for i in (0...#tamano)
if #adivinados[i] then
print #palabra[i]+" "
else
print "_ "
end
end
puts
end
end
Thanks for yours answers, and sorry if i wrote bad some sentences, i don't speak english
When you do a "gets", lectura contains newline character in the end. Trying doing a "chomp" on lectura :-
lectura = lectura.chomp
and try again. So that all the newline characters are removed. You can also use "bytes" to see the exact characters in your string for debugging purposes.
puts lectura.bytes
Refer:- http://ruby-doc.org/core-2.0/String.html#method-i-chomp

Resources