Where am I missing an "end" in this Ruby script? - ruby

I am banging my head against the error message I keep getting, reading that "syntax error, unexpected keyword_end, expecting end-of-input." I cannot find my mistake for the life of me. It's probably sloppy-looking, I am a newbie. And any tips on preventing this specific issue in the future would also be greatly appreciated!
$move_direction_hash = {"N" => [0,1], "E" => [1,0], "S" => [0,-1], "W" => [-1,0]}
$cardinal_directions = ["N", "E", "S", "W"]
class Martian
attr_accessor :coordinate_x, :coordinate_y, :bearing, :direction_string
def initialize (coordinate_x, coordinate_y, bearing, direction_string)
#coordinate_x = coordinate_x
#coordinate_y = coordinate_y
#bearing = bearing
#direction_string = direction_string
end
def check_valid
#coordinate_x.between?(0, $boundaries[0]) && coordinate_y.between?(0, $boundaries[1])
return true
end
end
#will be second and last called in source code
def get_final
return "#{coordinate_x} #{coordinate_y} #{bearing}"
end
def move_forward
# find where in the hash the bearing is
position_array = $move_direction_hash[#bearing]
# returns a temporary variable
# that is the
test_x = #coordinate_x + position_array[0]
test_y = #coordinate_y + position_array[1]
if $rovers_on_grid.include?([test_x.to_s, test_y.to_s])
puts "Stopping Martian. You're about to crash!"
get_final
break
else
#coordinate_x = test_x
#coordinate_y = test_y
if check_valid == false
puts "Stopping Martian. About to run off the plateau."
get_final
break
else
return #coordinate_x, #coordinate_y
end
end
end
def add_to_grid
$rovers_on_grid << [#x_coordinate, #y_coordinate]
end
def read_instructions
#direction_string.each_char do |direction|
if direction == "L" || direction == "R"
position = $cardinal_directions.index(#bearing)
if direction == "L"
position = (position - 1)%4
$cardinal_directions[position]
elsif direction == "R"
position = (position + 1)%4
$cardinal_directions[position]
else
puts "Error!"
end
#bearing = $cardinal_directions[position]
elsif direction == "M"
move_forward
end
end
end
end

This error is located in the check_valid method. You missed the if.
def check_valid
if #coordinate_x.between?(0, $boundaries[0]) && coordinate_y.between?(0, $boundaries[1])
return true
end
end
Like steenslag mentioned the if statement is not required. You can write:
def check_valid
return #coordinate_x.between?(0, $boundaries[0]) && coordinate_y.between?(0, $boundaries[1])
end

Related

How to update hashmap value based on a conditional statement

I need help updating the value of my HashMap. The idea is that the user will input the Rover Direction as N. The user then inputs the behaviour as L (for left). The move_left method then updates the Hashmap key "D" to equal "W" instead of the "N" which the user inputs. However, this piece of code is not updating it to "W". Any help would be great. I am an absolute beginner, so any recommendations would be great!
def rover_direction
puts " \n Please input the direction which the rover is facing
(N,E,S,W): "
user_input = gets.chomp.upcase
#direction = {"D" => user_input}
end
def rover_behaviour
puts " \n Please input the behaviour of the rover(L,R & M): "
input = gets.chomp.upcase
#behaviour = input.scan /\w/
if #behaviour[0] == "L"
move_left
elsif #behaviour[0] == "R"
move_right
elsif #behaviour[0] == "M"
move_forward
end
end
#move rover left as per behaviour input
def move_left
if #direction[0] == "N"
#direction.update("D") { |key, user_input| user_input == W }
elsif #direction[0] == "W"
#direction.update("D") { |key, user_input| user_input == "S" }
elsif #direction[0] == "S"
#direction.update("D") { |key, user_input| user_input == "E" }
elsif #direction[0] == "E"
#direction.update("D") { |key, user_input| user_input == "N" }
end
end

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])

Implementing operator precedence in my calculator interpreter

As part of learning Ruby am trying to implement a basic interpreter which reads input and do basic arithmetic calculations. So far basic arithmetic operations are working but having problem in operator precedence. Which is not handled yet. This is the code. Am at a beginner level. Any mistakes in this code are due to my lack of knowledge. How this code can be modified to handle operator precedence.
Sample output
2+2+2 = 6 #correct
10+10/2 = 10 # incorrect as in irb answer must be 15
Github Repo of this interpreter
=begin
Basic calculator Interpreter
can add, substract, multiply , divide with any number of operands at a time
Drawback : Lacks operator precedence
=end
class Interpreter
attr_accessor :input
def initialize
#input = gets.chomp
end
def intepret
first_operand = []
f = []
operator = '+'
array = Array.new
lc = 0
#input.split.join.split("").each_with_index.map do |i, index|
if i.is_number?
first_operand.push(i)
if index == #input.length-1
array.push(first_operand.join("").to_i)
end
elsif i.is_plus?
f = first_operand
first_operand = nil
first_operand = []
array.push(f.join("").to_i)
array.push("+")
elsif i.is_minus?
f = first_operand
first_operand = nil
first_operand = []
operator = '-'
array.push(f.join("").to_i)
array.push("-")
elsif i.is_multi?
f = first_operand
first_operand = nil
first_operand = []
operator = '*'
array.push(f.join("").to_i)
array.push("*")
elsif i.is_divide?
f = first_operand
first_operand = nil
first_operand = []
operator = '/'
array.push(f.join("").to_i)
array.push("/")
else
puts "Illegal input exiting.."
exit
end
lc = lc+1
end
#apply the appropriate operation on the inputs based on the operand
#puts "=======TOKENS======"
#puts array.inspect
result = 0
array.each_with_index.map do |x, key|
result = x if key == 0
if x == '+'
if key == 0
result = add(result, array[key+1])
else
result = add(result, array [key+1])
end
elsif x == '-'
if key == 0
result = minus(result, array[key+1])
else
result = minus(result, array [key+1])
end
elsif x == '*'
if key == 0
result = multi(result, array[key+1])
else
result = multi(result, array [key+1])
end
elsif x == '/'
begin
if key == 0
result = divide(result, array[key+1])
else
result = divide(result, array [key+1])
end
rescue
puts "Zero Divsion error"
exit
end
end
end
puts "Result is: "+result.to_s
end
def print_token(type, value)
puts type + ' '+ value
end
def add(f,s)
return f.to_i + s.to_i
end
def minus(f,s)
return f.to_i - s.to_i
end
def multi(f,s)
return f.to_i * s.to_i
end
def divide(f,s)
return f.to_i / s.to_i
end
end
# Override the string class, to directly use methods like obj.is_number? rather than is_number?(obj)
class String
def is_number?
true if Float(self) rescue false
end
def is_plus?
true if self == '+' rescue false
end
def is_minus?
true if self == '-' rescue false
end
def is_multi?
true if self == '*' rescue false
end
def is_divide?
true if self == '/' rescue false
end
end
#continue accepting inputs until exit CTRL + D
while true
print 'pck>:'
i_obj = Interpreter.new
i_obj.intepret
end
First, process the input using the Shunting-yard algorithm. This should give a list of tokens in Reverse Polish notation (RPN). Then you can evaluate the RPN expression.

Ruby Minesweeper

I am trying to get this Ruby game I made to loop after the first round, and end with a "game over" if the player hits a mine. I have it to where it will build the board, which is a pre-built layout in a .txt file, and it will loop, but the game doesn't end. Here is my code
def load_board
mine_field = []
File.open("mines.txt", 'r') do |f|
f.gets
f.each_line do |line|
mine_field.push line.chomp.split('')
end
end
return mine_field
end
def create_hint_board(board)
hint = Array.new
for i in (0..board.size-1)
hint[i] = []
for j in (0..board[i].size-1)
hint
if board[i][j] == '*'
hint[i].push '*'
else
bombs = 0
for x in (-1..1)
for y in (-1..1)
if i-x >= 0 &&
i-x < board.size &&
j-y >= 0 &&
j-y < board[i].size &&
board [i-x][j-y] == '*'
bombs += 1
end
end
end
hint[i][j] = bombs
end
end
end
return hint
end
def print_board (board)
board.each do |row|
p row
end
end
def pp_board (board)
puts Array.new(board[0].size*2+1, '-').join('')
board.each do |row|
puts "|" + row.join('|') + "|"
puts Array.new(row.size*2+1, '-').join('')
end
end
def copy_to_blank(board)
blank = Array.new
for i in 0..(board.size-1)
blank << Array.new(board[i].size, '.')
end
blank
end
def play(board)
puts "Welcome to Minesweeper!"
puts
puts
puts
hint = create_hint_board(board)
game = copy_to_blank(board)
puts "Starting"
pp_board game
#copy coords user puts in
coords = gets.chomp.split(' ')
i = coords[0].to_i
j = coords[1].to_i
game[i][j] =
hint[i][j]
pp_board game
puts
puts "Hint"
pp_board hint
end
end
#start the game
play load_board
Also, mines.txt looks like this...
4 3
*...
..*.
....
I would appreciate any feedback you can give.
This will get you looping:
# start while loop
while true
coords = gets.chomp.split
i = coords[0].to_i
j = coords[1].to_i
if hint[i][j] == "*"
puts "you lose"
break
end
game[i][j] = hint[i][j]
pp_board game
puts "\nHint"
pp_board hint
end
#end while loop
Ctrl-c to bust out. You can also use break to exit the loop:
break if game_over?

Need help indenting tags in the output in Ruby

UPDATE: OK, so I implemented your code, but now the indentation is not showing up! Any ideas what might be wrong? I modified the code so that it would attempt to pass my original test (this is only an exercise so in real life I would not be overriding the XmlDocument class) and here is the modified code:
class XmlDocument
attr_reader :indent_depth, :bool
def initialize(bool = false, indent_depth = 0)
#indent_depth = indent_depth
#bool = bool
end
def method_missing(name, *args)
indentation = ' '*indent_depth
attrs = (args[0] || {}).map { |k, v| " #{k}='#{v}'" }.join(' ')
if block_given?
puts indent_depth
opening = "#{indentation}<#{name}#{attrs}>"
contents = yield(XmlDocument.new(true,indent_depth+1))
closing = "#{indentation}</#{name}>"
bool ? opening + "\n" + contents + "\n" + closing : opening + contents + closing
else
"#{indentation}<#{name}#{attrs}/>"
end
end
end
I'm trying to get the method to pass this test:
it "indents" do
#xml = XmlDocument.new(true)
#xml.hello do
#xml.goodbye do
#xml.come_back do
#xml.ok_fine(:be => "that_way")
end
end
end.should ==
"<hello>\n" +
" <goodbye>\n" +
" <come_back>\n" +
" <ok_fine be='that_way'/>\n" +
" </come_back>\n" +
" </goodbye>\n" +
"</hello>\n"
...but I'm unsure as to where to go with my code, below. I was thinking of using a counter to keep track of how far indented we have to go. I tried some code, but then deleted it because it was getting too messy and I have a feeling that the indentation should not be too complicated to implement.
class XmlDocument
def initialize(bool = false)
#bool = bool
end
def send(tag_name)
"<#{tag_name}/>"
end
def method_missing(meth, arg={}, &block)
arbitrary_method = meth.to_s
tag_string = ''
# 1) test for block
# 2) test for arguments
# 3) test for hash
if block_given? # check for #xml.hello do; #xml.goodbye; end
if yield.class == String # base case: #xml.hello do; "yellow"; end
"<#{arbitrary_method}>#{yield}</#{arbitrary_method}>"
else # in the block we do not have a string, we may have another method
method_missing(yield)
end
elsif arg.empty? # no arguments e.g. #xml.hello
send(arbitrary_method)
else # hash as argument e.g. #xml.hello(:name => 'dolly')
send("#{arbitrary_method} #{arg.keys[0]}='#{arg.values[0]}'")
end
end
end
Your code needs a lot of work - some pointers:
Do not override the send method!
Don't call yield over and over - you don't know what side effects you might cause, not to mention a performance hit - call it once, and remember the return value.
You might want to read up on how to write a DSL (here is a blogpost on the subject), to see how it was done correctly in other places.
Ignoring the above, I will try to answer your question regarding indentation.
In a DSL use case, you might want to use a context object which holds the indentation depth as state:
class Indented
attr_reader :indent_depth
def initialize(indent_depth = 0)
#indent_depth = indent_depth
end
def method_missing(name, *args)
indentation = ' ' * indent_depth
attrs = (args[0] || {}).map { |k, v| "#{k}='#{v}'" }.join(' ')
if block_given?
"#{indentation}<#{name} #{attrs}>\n" +
yield(Indented.new(indent_depth + 1)) +
"\n#{indentation}</#{name}>"
else
"#{indentation}<#{name} #{attrs}/>"
end
end
end
xml = Indented.new
puts xml.hello do |x|
x.goodbye do |x|
x.come_back do |x|
x.ok_fine(:be => "that_way")
end
end
end
# => <hello >
# => <goodbye >
# => <come_back >
# => <ok_fine be='that_way'/>
# => </come_back>
# => </goodbye>
# => </hello>

Resources