1

I'm making myself and a few of my friends a combat assistant for Dungeons and Dragons, since most of the keeping track is pretty repetitive so I thought I could Ruby something up. It was going well but now I've hit a roadblock.

This is my code

def party8
  party7
  puts "Last one! What's your eighth player's name?"
  player8name = gets.chomp
  puts "What's their AC?"
  player8ac = gets.chomp.to_i
  puts "Got it. What's their max HP?"
  player8maxhp = gets.chomp.to_i
end

def partysetup
  puts "hi"
  if 8 == playercount
    party8
  else
    party1
    end

end

#intro----------------------------------------------------------------------


puts "-Hello. I am l1fecount, the DM's combat assistant."
puts "-Before we begin, would you like to see in-depth information about me?"
infoq = gets.chomp
infoq.downcase!

if infoq == "yes"
    puts "-Very well, I'm glad to explain. I am l1fecount, a program designed to keep track of up to 5 types of mobs, with up to 10 
    of each. I can also keep track of up to 8 players. I keep track of turn order, current HP vs max HP, CR, and armor 
    class. I am still very young, so please be patient with me. ^^; "
else 
    puts "-Right then."

end

puts "-So, let's begin."

#intro end----------------------------------------------------------------


#party---------------------------------------------------------------------

loop do
  puts "How many players today?"  
  playercount = gets.chomp.to_i
    if 0 >= playercount
      puts "You can't have no players in a party. That's not D&D, that's you having no friends."
      redo
   elsif 8 < playercount
     puts "Hey now, that's a huge party. I can only handle eight players at once."
     redo
    elsif 8 >= playercount
      break     
   else 
     puts "A number between 1 and 8, please."
     redo
   end
end

partysetup

`

(party1-7 exists, but is identical to party 8, so I didn't include it for brevity's sake.)

It runs just fine until I try to run partysetup. I added a puts statement so I could see if the method was being called, and it is, but I keep getting this:

    -Hello. I am l1fecount, the DM's combat assistant.
-Before we begin, would you like to see in-depth information about me?
no
-Right then.
-So, let's begin.
How many players today?
8
hi
Error: undefined method `playercount' for main:Object

I've tried looking for simple spelling errors, converting playercount to a string or a symbol, but nothing has fixed this issue. Help please?

Nemus
  • 3,879
  • 12
  • 38
  • 57
candistars
  • 25
  • 6
  • try putting `playercount = nil` right before the loop. Otherwise when you define the variable inside the loop, the reference will be local to the loop only. – max pleaner May 09 '17 at 22:33
  • Please read "[mcve]" including the linked pages. Your code doesn't run to demonstrate the problem, and, to help you we'll have to modify it. You need to help us help you by stripping the code to the bare minimum. http://ericlippert.com/2014/03/05/how-to-debug-small-programs/ helps explain it. – the Tin Man May 09 '17 at 22:36
  • See [difference-between-various-variables-scopes-in-ruby](http://stackoverflow.com/questions/11495098/difference-between-various-variables-scopes-in-ruby) as well – max pleaner May 09 '17 at 22:38
  • This sort of copy-paste style of coding isn't sustainable. Try and organize your data into arrays, hashes, or other data structures that aren't arbitrarily bounded. It will dramatically minimize how much code you produce and vastly decrease needless repetition. – tadman May 09 '17 at 23:31

1 Answers1

2

playercount is defined within the loop. Since it doesn't have a prefix, it's a local variable. In this case, it's only visible within the loop itself. It isn't visible to the method you defined at the top of the file.

Almost certainly you don't want to define 8 (or more!) methods with virtually the same code. One solution is to take the party count as a method parameter:

def party(n)

Then you can define partysetup to call party thusly:

def partysetup(playercount)
  # Setup stuff
  party(playercount)
end

There are several ways to write party to work for n players. It might not be the best solution, but I immediately thought of a recursive algorithm:

$players = [] 
def party(n)
  return if n == 0
  party(n-1)

  player = {}
  puts "What's player #{n}'s name?"
  player[:name] = gets.chomp
  puts "What's their AC?"
  player[:ac] = gets.chomp.to_i
  puts "Got it. What's their max HP?"
  player[:maxhp] = gets.chomp.to_i
  $players[n] = player
end

Notice I used a dollar sign ($) as a prefix in the $players array. That means it's a global variable which is available to all parts of the program. Generally you want to avoid global variables, but it can be pretty convenient to have access to things like the player data everywhere in your code.

But Ruby offers options between global and local scope. An even better solution would be to create a class to manage your game and store the player data in an instance variable (@players). This gives you a lot more flexibility (maybe run multiple games at once?) and gets you into the habit of managing scope.

Graham
  • 7,431
  • 18
  • 59
  • 84
Kathryn
  • 1,557
  • 8
  • 12
  • Good idea of using an array, but the heavy-handed approach of using a global is really out of line and not recommended, this is a very bad habit to get into. This could be encapsulated inside a simple class without that sort of mess, a simple instance variable like `@players` is then used and is neat, tidy, and self-explanatory. – tadman May 09 '17 at 23:32
  • 1
    @tadman: Good point. I've added another paragraph explaining that suggestion. That look better? – Kathryn May 10 '17 at 00:06
  • Yeah, getting there. I took a stab at refactoring this but it quickly got out of hand, so I abandoned that effort. A proper `Player` and `Party` class really does help simplify this code, though. – tadman May 10 '17 at 02:07