2

I'm writing a very simple dungeon adventure game in Ruby (practice for a newb). I want to address the player by name throughout, so naturally I want to be sure that if a player passes an empty name to my Player initialize method if tells them they can't do that and then prompts them to retry.

class Player
    attr_accessor :name, :location

    def initialize(name)
        if name.empty? == false
            @name = name
        else
            puts "You did not enter your name! Try again, please"
            load 'game.rb'
        end
    end
end

The file name is 'game.rb' so I'm basically reloading the entire file here each time the player decides not to enter their name. Which is stupid...

It works, but in the worst way...I had to be 'clever' about where I exited the program so that the player would be insulated from the fact that I'm basically going all Inception on everyone and launching a game within a game every time the player starts a new game and neglects to enter their name. For instance, if they don't notice 3 times that they need to input their name because they're not paying attention, I effectively have 4 games running (the original, and the 3 the prompted by not entering their name) and they'd either need to end each of those games when they're tired of playing, or else I had to basically exit the whole thing hard at one keyword.

My question is this: is there a way to write my error "You did not enter..." exit the current game session, and relaunch the game? All I really want to do is ensure an empty string doesn't get passed to my initialize method, maybe by raising an exception, and then start over at the beginning of the script without having a game-within-a-game.

Here is a link to the full code for more insight: http://repl.it/8QY

DanielNordby
  • 569
  • 2
  • 6
  • 20
  • 3
    Trying to reload game.rb sounds like entirely the wrong way to do this - why not just call gets (or whatever you are using to read input) repeatedly until valid input is provided. – Frederick Cheung Jan 17 '15 at 20:32
  • @FrederickCheung Ah, that does make much more sense. Duh. Would you suggest a simple loop surrounding the gets call to take care of this? – DanielNordby Jan 17 '15 at 20:37

3 Answers3

3

It's hard to know without seeing the whole game structure, but your main file could look like

game_initialized = false
while ! game_initialized
  begin
    # here, initialize the game, including initialization
    game_initialized = true
  rescue NoNameError
    # do nothing, but it will restart the game
  end
end
# now play the game

And in your constructor, you add

class NoNameError < Exception
end

class Player
  attr_accessor :name, :location

  def initialize(name)
    if name.empty? == false
      @name = name
    else
      puts "You did not enter your name! Try again, please"
      raise NoNameError
    end
  end
end

That should get you going.

Vincent Fourmond
  • 3,038
  • 1
  • 22
  • 24
  • 3
    While this will work, I don't think a lack of a name should be considered an exceptional scenario. I think it would be just as easy to keep asking until you get a valid name. – Justin Wood Jan 17 '15 at 20:44
  • Thanks! I really like what you did here. This is what I was trying to do the whole time, but I couldn't quite wrap my head around it. To be clear, essentially all of my code (assuming I'm being a disgusting human and putting it all of my code into one file) would go between 'begin' and 'rescue' correct? Then I could add any number of rescues I might need including my NoNameError rescue... – DanielNordby Jan 17 '15 at 20:48
  • @SkeletorDan As far as I understand, you don't need to have the whole game within the begin/rescue block, just the initialization. I'll be updating the anwser to reflect that. – Vincent Fourmond Jan 17 '15 at 22:33
  • @JustinWood What makes you think this is an exceptional scenario ? Using exceptions is just a very convenient way to control flow in this case. That's what exceptions are for. – Vincent Fourmond Jan 17 '15 at 22:35
  • 1
    @VincentFourmond Exceptions shouldn't be used as control flow. There are various control flow constructs that can be used in this scenario. Exceptions are meant to handle exceptional circumstances. [This](http://stackoverflow.com/questions/77127/when-to-throw-an-exception) is a decent explanation of when exceptions should be used. – Justin Wood Jan 18 '15 at 19:15
2

I think Vincent's answer is good, it certainly is more OO than mine but a simple approach would be to do something like this at game start:

print "Welcome!  "
in_name = ""
while true
  puts "What is your name?"
  in_name = gets.chomp
  in_name.empty? ? (puts "You must enter a name before continuing") : break
end

Example:

Welcome!  What is your name?

You must enter a name before continuing
What is your name?
Anthony
Anthony
  • 15,435
  • 4
  • 39
  • 69
  • Thanks @Anthony! I agree, Vincent has good insight that I will implement as I have time, but I've used your implementation combined with Frederick's comment at the top to make it work the way I expected. Something about looking at your own code for too long...anyways, does "break" essentially make the while loop false, effectively ending it? – DanielNordby Jan 17 '15 at 20:45
  • 1
    It doesn't actually set it to false but it terminates the while block. More details on in [here](http://ruby-doc.org/docs/keywords/1.9/Object.html#method-i-break) – Anthony Jan 17 '15 at 20:52
1

If you want your logic to be in Player, you can try something like this:

class Player
  attr_accessor :name, :location

  def initialize(name)
    @name = keep_asking_for_name_if_not_already_entered(name)
  end

  def keep_asking_for_name_if_not_already_entered(name)
    return name unless name.empty?
    loop do
      puts 'You did not enter your name! Enter a name, please:'
      name = gets.chomp
      break(name) unless name.empty?
    end
  end
end
daremkd
  • 8,244
  • 6
  • 40
  • 66
  • Makes sense. I probably shouldn't be running the logic in the initialize method, but rather create a method to handle it. Good point! Much cleaner than my attempt. – DanielNordby Jan 19 '15 at 17:47