RUBY Exit minesweeper game loop - ruby

I can't figure out how to exit the game loop. I'm having a hard tried making a lose? function, I tried doing like lose?(x) that would return true when x==1 but that didn't get it to exit the run method. Here's my code for the Game class.
class Minesweeper
attr_accessor :board
def initialize
#board = Board.new
end
def run
puts "Welcome to minesweeper!"
x = nil
play_turn until win? || lose?(x)
end
def play_turn
board.render
pos, command = get_input
debugger
if !explode?(pos, command)
board.set_input(pos,command)
else
puts "You lose!"
lose?(1)
end
end
def explode?(pos, cmd)
board.grid[pos[0]][pos[1]].bomb && cmd == "reveal"
end
def get_input
pos = nil
command = nil
until pos && check_pos(pos)
puts "What position?"
pos = parse_pos(gets.chomp)
end
until command && check_command(command)
puts
puts "What would you like to do (e.g. reveal, flag... ~ else?)"
command = gets.chomp
puts
end
[pos, command]
end
#Some code here (check_pos, etc)
def lose?(x)
return true if x == 1
false
end
def win?
# board.all? {}
end
end
I had explode? in the Board class before, but for the sake of being able to end the game, moved it here. Any help is greatly appreciated!

If we expand your run method, a little, it becomes more obvious what the issue is:
def run
puts "Welcome to minesweeper!"
x = nil
until(win? || lose(x)) do
play_turn
end
end
In this method, you're creating a new variable x which is scoped to this method and has a value of nil. This variable is never set in the scope of that method, so is always nil, meaning that the check win? || lose(x) could also be written win? || lose(nil), and lose will never return true.
If you return a value from your play_turn method, you can then use that. Note that the result of the last thing executed in the method is what is returned:
def play_turn
board.render
pos, command = get_input
debugger
if !explode?(pos, command)
board.set_input(pos,command)
true
else
puts "You lose!"
false
end
end
which means your run method can then check the result:
def run
puts "Welcome to minesweeper!"
# we now know that play_turn returns true if the turn was not a loser
# (i.e. it should continue to the next loop) and false if the player
# lost, so we can use that returned value in our loop.
while(play_turn) do
if win?
puts "looks like you won!"
# if the player wins, we want to exit the loop as well. This is done
# using break
break
end
end
end
Note that this also means that you don't need a separate lose method

Related

How do I write an rspec Ruby test for this method play_turn?

class Game
def start
#player1 = Player.new("don")
#player2 = Player.new("tum")
end
def player_turn
if #turn.even?
puts "this is #{#player2.name}'s turn"
else
puts "this is #{#player1.name}'s turn"
end
end
end
I think first you are going to have to define the instance variable #turn, and how it is incremented. Additionally I would recommend changing the Game#start to #initialize, the test below assumes this.
Then you can check what is output to stdout.
RSpec.describe Game do
describe "#player_turn" do
context 'when the turn is even' do
let(:game) { Game.new }
it "tells you it is player 2's turn" do
expect do
game.player_turn
end.to output("this is tum's turn\n").to_stdout
end
end
end
end

Can't use include? with an instance variable in a method

I am trying to use 'gets' to get input and then check to see if the instance variable includes the input inside of a method but I can't get it work. Here is the code:
class Game
attr_accessor :available_moves
def initialize
#available_moves = ["0","1","2","3","4","5","6","7","8"]
end
def play_game
puts ("Welcome")
while true
puts "Player 1, choose a square"
player1_choice = gets
# v this is what I can't get to work v
if #available_moves.include?(player1_choice)
puts "yes"
break
else
puts "no"
end
end
end
end
game1 = Game.new
game1.play_game
No matter what I try, the 'else' condition is met and "no" is printed.
When the user inputs text with gets they press Enter, which sends a newline. You need to remove the newline with gets.chomp:
class Game
attr_accessor :available_moves
def initialize
#available_moves = ["0","1","2","3","4","5","6","7","8"]
end
def play_game
puts ("Welcome")
while true
puts "Player 1, choose a square"
# Note the .chomp here to remove the newline that the user inputs
player1_choice = gets.chomp
# v this is what I can't get to work v
if #available_moves.include?(player1_choice)
puts "yes"
break
else
puts "no"
end
end
end
end
game1 = Game.new
game1.play_game
Now you get:
game1.play_game
Welcome
Player 1, choose a square
1
yes
=> nil
See How does gets and gets.chomp in ruby work? for a more in-depth explanation.

New to Ruby, tried to build the simplest calculator, why is it not working?

class Calculator
def firsti
puts "Please type first number: "
end
def initialize(x)
#x = gets.chomp
end
def opi
puts "Please type operation: "
end
def initialize(y)
#y = gets.chomp
end
def secondi
puts "Please type second number: "
end
def initialize(z)
#z = gets.chomp
end
if #y == '+'
puts #x+#z
elsif #y == '-'
puts #x-#z
elsif #y == '*'
puts #x*#z
elsif #y == '/'
puts #x/#z
else
puts "Something went wrong. Please try again."
end
end
Tried it with spaces, with or without ()-s, no error messages, I'm probably jut a noob. Any help would be appreciated. Initially tried with simple variables without a class, no result even though when I write just a simple
x = 2
y = +
z = 3
if y == '+'
puts x+z
end
and it worked. Can't seem to understand what is the problem.
Here is a "working version" of your code, which I have tried to make with minimal changes from your design:
class Calculator
def initialize
puts "Please type first number: "
#x = gets.chomp.to_i
puts "Please type operation: "
#y = gets.chomp
puts "Please type second number: "
#z = gets.chomp.to_i
end
def result
if #y == '+'
#x+#z
elsif #y == '-'
#x-#z
elsif #y == '*'
#x*#z
elsif #y == '/'
#x/#z
else
"Something went wrong. Please try again."
end
end
end
calculator = Calculator.new
puts "Result is:"
puts calculator.result
Your code has several issues preventing it from working as you expect:
You have defined multiple initialize methods in a single class. This is not possible; all you're actually doing is *re-*defining the same method.
Your code has no sense of flow control. You seem to be under the impression that "the code will all just run, from top to bottom". This is not how methods/classes work; you first define the methods/classes, and then call them. As you can see in my code, I am explicitly creating a Calculator object (Calculator.new - which constructs a new instance, calling the initialize method), and then calling the result method.
On a similar note, you are performing a conditional check on the #y variable which hasn't been defined at this point in the code's execution! #y will be nil when your if statement executes; therefore, the logic falls through to the else statement.
A more subtle point, but input from the gets command will always be a String. You need to call to_i to convert this into an Integer; otherwise, you'll get funny results like: "2" + "5" == "25"

Undefined local variable or method 'user_response'

I've read my code up and down for about 30 mins now. I can't for the life of me see where user_response is undefined. I'm very new to coding so I don't know how much of the code would be appropriate to paste in here. I figure that launch and get_action are essential but the rest couldn't hurt?
error => rb:32:in `launch!': undefined local variable or method `user_response' for
<Guide:0x007fb019984718> (NameError)
class Guide
class Config
##actions = ['list', 'find', 'add', 'quit']
def self.actions
##actions
end
end
def initialize(path=nil)
# locate the restaurant text file at path
Restaurant.filepath = path
if Restaurant.file_usable?
puts "Found restaurant file."
# or IF a new text file can't be created, create a new file
elsif Restaurant.create_file
puts "Created restaurant file."
# exit if create fails
else
puts "Exiting"
exit!
end
end
def launch! #! means that it is a strong powerful method!
introduction
# action loop
result = nil
until result == :quit
action = get_action
result = do_action(user_response)
end
conclusion
end
def get_action
action = nil
# Keep asking for user input until we get a valid action
until Guide::Config.actions.include?(action)
puts "Actions: " + Guide::Config.actions.join(", ") if action
print "> "
user_response = gets.chomp
action = user_response.downcase.strip
end
return action
end
def do_action(action)
case action
when 'list'
puts "Listing..."
when 'find'
puts "Finding..."
when 'add'
puts "Adding..."
when 'quit'
return :quit
else puts " I don't understand that command."
end
end
def introduction
puts "<<< Welcome to the Food Finder >>>"
puts "This is an interactive guide to help you find the food you crave."
end
def conclusion
puts "<<< Goodbye and Bon Appetit! >>>>"
end
end
I think you want to do this :
def launch! #! means that it is a strong powerful method!
introduction
# action loop
result = nil
until result == :quit
result = do_action(get_action)
end
conclusion
end
The only time you define a variable called user_response is in your get_action method.
The way you define it there makes it a local variable and it will not be accessible from anywhere but inside the get_action method.

How to break out from a ruby block?

Here is Bar#do_things:
class Bar
def do_things
Foo.some_method(x) do |x|
y = x.do_something
return y_is_bad if y.bad? # how do i tell it to stop and return do_things?
y.do_something_else
end
keep_doing_more_things
end
end
And here is Foo#some_method:
class Foo
def self.some_method(targets, &block)
targets.each do |target|
begin
r = yield(target)
rescue
failed << target
end
end
end
end
I thought about using raise, but I am trying to make it generic, so I don't want to put anything any specific in Foo.
Use the keyword next. If you do not want to continue to the next item, use break.
When next is used within a block, it causes the block to exit immediately, returning control to the iterator method, which may then begin a new iteration by invoking the block again:
f.each do |line| # Iterate over the lines in file f
next if line[0,1] == "#" # If this line is a comment, go to the next
puts eval(line)
end
When used in a block, break transfers control out of the block, out of the iterator that invoked the block, and to the first expression following the invocation of the iterator:
f.each do |line| # Iterate over the lines in file f
break if line == "quit\n" # If this break statement is executed...
puts eval(line)
end
puts "Good bye" # ...then control is transferred here
And finally, the usage of return in a block:
return always causes the enclosing method to return, regardless of how deeply nested within blocks it is (except in the case of lambdas):
def find(array, target)
array.each_with_index do |element,index|
return index if (element == target) # return from find
end
nil # If we didn't find the element, return nil
end
I wanted to just be able to break out of a block - sort of like a forward goto, not really related to a loop. In fact, I want to break of of a block that is in a loop without terminating the loop. To do that, I made the block a one-iteration loop:
for b in 1..2 do
puts b
begin
puts 'want this to run'
break
puts 'but not this'
end while false
puts 'also want this to run'
end
Hope this helps the next googler that lands here based on the subject line.
If you want your block to return a useful value (e.g. when using #map, #inject, etc.), next and break also accept an argument.
Consider the following:
def contrived_example(numbers)
numbers.inject(0) do |count, x|
if x % 3 == 0
count + 2
elsif x.odd?
count + 1
else
count
end
end
end
The equivalent using next:
def contrived_example(numbers)
numbers.inject(0) do |count, x|
next count if x.even?
next (count + 2) if x % 3 == 0
count + 1
end
end
Of course, you could always extract the logic needed into a method and call that from inside your block:
def contrived_example(numbers)
numbers.inject(0) { |count, x| count + extracted_logic(x) }
end
def extracted_logic(x)
return 0 if x.even?
return 2 if x % 3 == 0
1
end
use the keyword break instead of return
Perhaps you can use the built-in methods for finding particular items in an Array, instead of each-ing targets and doing everything by hand. A few examples:
class Array
def first_frog
detect {|i| i =~ /frog/ }
end
def last_frog
select {|i| i =~ /frog/ }.last
end
end
p ["dog", "cat", "godzilla", "dogfrog", "woot", "catfrog"].first_frog
# => "dogfrog"
p ["hats", "coats"].first_frog
# => nil
p ["houses", "frogcars", "bottles", "superfrogs"].last_frog
# => "superfrogs"
One example would be doing something like this:
class Bar
def do_things
Foo.some_method(x) do |i|
# only valid `targets` here, yay.
end
end
end
class Foo
def self.failed
#failed ||= []
end
def self.some_method(targets, &block)
targets.reject {|t| t.do_something.bad? }.each(&block)
end
end
next and break seem to do the correct thing in this simplified example!
class Bar
def self.do_things
Foo.some_method(1..10) do |x|
next if x == 2
break if x == 9
print "#{x} "
end
end
end
class Foo
def self.some_method(targets, &block)
targets.each do |target|
begin
r = yield(target)
rescue => x
puts "rescue #{x}"
end
end
end
end
Bar.do_things
output: 1 3 4 5 6 7 8
You have four ways to unwind the stack in 'non-exceptional' ways: next, break, return, and throw.
next will cause the block to return.
break will cause the method that yielded to the block to return.
return will cause the method where the block is defined to return.
throw will traverse up the stack until it finds a catch with a matching symbol, and cause that to return. This is much like a 'lightweight' exception for non-exceptional situations.
All of them can take a return value that will be returned by whatever they caused to return instead of the value their last expression which they would return normally.
Here are some examples:
def doSomething
puts "> doSomething"
yield
puts "< doSomething"
end
def withNext
puts "> withNext"
doSomething do
puts "> block"
puts "* NEXT! causes the block to return to doSomething"
next
puts "< block"
end
puts "< withNext"
end
def withBreak
puts "> withBreak"
doSomething do
puts "> block"
puts "* BREAK! causes doSomething to return to withBreak"
break
puts "< block"
end
puts "< withBreak"
end
def withReturn
puts "> withReturn"
doSomething do
puts "> block"
puts "* RETURN! causes withReturn to return"
return
puts "< block"
end
puts "< withReturn"
end
def withThrow
puts "> withThrow"
catch :label do
puts "> catch :label"
doSomething do
puts "> block 1"
doSomething do
puts "> block 2"
puts "* THROW! causes catch :label to return to withThrow"
throw :label
puts "< block 2"
end
puts "< block 1"
end
puts "< catch :label"
end
puts "< withThrow"
end
withNext
puts "* Done"
puts
withBreak
puts "* Done"
puts
withReturn
puts "* Done"
puts
withThrow
puts "* Done"
output:
> withNext
> doSomething
> block
* NEXT! causes the block to return to doSomething
< doSomething
< withNext
* Done
> withBreak
> doSomething
> block
* BREAK! causes doSomething to return to withBreak
< withBreak
* Done
> withReturn
> doSomething
> block
* RETURN! causes withReturn to return
* Done
> withThrow
> catch :label
> doSomething
> block 1
> doSomething
> block 2
* THROW! causes catch :label to return to withThrow
< withThrow
* Done
To break out from a ruby block simply use return keyword return if value.nil? next.
next terminates lambda, block, or proc it is in.
break terminates the method that yielded to the block or invoked the proc or lambda it is in.
Credit to: Ruby block return, break, next

Resources