Optimizing for Newbies


#1

Since I’ve gotten the go-ahead from Christer, here’s a little newbie app
I just wrote and am looking for advice on how to better write:

=begin
=Author & Maintainer
Matthew A. Feadler
http://matthew.feadler.com
=Description
arschar.rb guides the user through the process of rolling attributes
for
an Ars Magica character using v4 rules.
=Copyright
This software is Copyright 2005 Matthew A. Feadler. All rights
reserved.
Do as you like with it, as long as you don’t claim to have written it.
And, there is certainly no warranty hereabout, express or implied.
=Version
arschar.rb 0.1 2005/Nov/30
=end
system(“clear”)
#BEGINCLASSDEFS
#Classname: Die
#Purpose: Provide arbitrarily-sided die functionality
#Notes: Only 6-sided dice display from 1, all others from 0
class Die
def initialize(sides)
@sides = sides
roll
if @sides == 6
@currentFace += 1
end
@currentFace
end
def roll
@currentFace = rand(@sides)
@currentFace
end
def showing
@currentFace
end
end
#ENDCLASSDEFS
#BEGINMETHODDEFS
#Roll 2 10-sided die and subtract 2nd from 1st to determine pair total
def rollAttributePair
rolls = Array.new
rolls.push(Die.new(10).roll)
rolls.push(Die.new(10).roll)
if (rolls[0] == 0) or (rolls[1] == 0)
total = 0
return total
else
total = (rolls[0] - rolls[1])
return total
end
end
#Obtain user allocation of scores and validate against AM rules
def getScore(total,attr)
goodAnswer = false
while goodAnswer == false
print " Enter score for " + attr + “: "
userInput = gets.chomp.strip.to_i
if (userInput < 0) and (total > 0)
puts " You rolled positively; no negatives for this pair.”
goodAnswer = false
elsif (userInput > 0) and (total < 0)
puts " You rolled negatively; no positives for this pair."
goodAnswer = false
elsif userInput > 4
puts " Rolled scores cannot be higher than 4."
goodAnswer = false
elsif userInput < -4
puts " Rolled scores cannot be lower than 4."
goodAnswer = false
else
goodAnswer = true
end
end
return userInput
end
#ENDMETHODDEFS
#BEGINVARIABLEDEFS
#Init Array to hold shortnames of the 8 Attributes
attributeShortNames = Array.new
attributeShortNames[0,7]=[“Int”, “Per”, “Str”, “Sta”, “Pre”, “Com”,
“Dex”, “Qik”]
#Init Array to hold fullnames of the 8 Attributes
attributeFullNames = Array.new
attributeFullNames[0,7]=[“Intelligence”,“Perception”,“Strength”,“Stamina”,“Presence”,“Communication”,“Dexterity”,“Quickness”]
#Init Hash to hold shortname/fullname pairs for the 8 Attributes
attributeNameMap = Hash.new
count = 0
attributeShortNames.each do |name|
attributeNameMap[name]= attributeFullNames[count]
count += 1
end
#Init Hash to hold name/value pairs for character Attributes
#charAttributes = {‘Int’ => 0, ‘Per’ => 0, ‘Str’ => 0, ‘Sta’ => 0, ‘Pre’
=> 0, ‘Com’ => 0, ‘Dex’ => 0, ‘Qik’ => 0}
charAttributes = Hash.new(0)
attributeShortNames.each do |name|
charAttributes[name]= 0
end
#ENDVARIABLEDEFS
#BEGINMAIN
x = 0
y = 1
while (x <= 6) and (y <= 7)
attr0 = attributeShortNames[x]
attr1 = attributeShortNames[y]
full0 = attributeNameMap[attr0]
full1 = attributeNameMap[attr1]
puts “Now rolling for the " + full0 + " and " + full1 + " pair…”
total = rollAttributePair
if total == 0
puts " You rolled a zero for this pair. Both " + attr0 + " and " +
attr1 + " will be set to zero."
charAttributes[attr0]= 0
charAttributes[attr1]= 0
elsif total > 0
puts " You rolled a +" + total.to_s + " for this pair."
puts " Please choose scores which are >= 0, <= 4, and which add up
to " + total.to_s + “.”
goodAnswer = false
while goodAnswer == false
temp = Array.new
val0 = getScore(total,attr0)
val1 = getScore(total,attr1)
if (val0 + val1) == total
charAttributes[attr0]= val0
charAttributes[attr1]= val1
goodAnswer = true
else
puts " Your scores add up to more than " + total.to_s + “.
Please try again.”
goodAnswer = false
end
end
else
puts " You rolled a " + total.to_s + " for this pair."
puts " Please, choose scores which are <= 0, >= -4, and which add
up to " + total.to_s + “.”
goodAnswer = false
while goodAnswer == false
temp = Array.new
val0 = getScore(total,attr0)
val1 = getScore(total,attr1)
if (val0 + val1) == total
charAttributes[attr0]= val0
charAttributes[attr1]= val1
goodAnswer = true
else
puts " Your scores add up to more than " + total.to_s + “.
Please try again.”
goodAnswer = false
end
end
end
x += 2
y += 2
puts
end
#Print charAttributes
attributeShortNames.each do |attr|
puts attr.to_s + ": " + charAttributes[attr].to_s
end
#Pause for user input before exit
puts
print “Press Enter to exit…”
gets
#ENDMAIN

Thanks to all in advance!

-Matthew


#2

On 12/1/05, Matthew F. removed_email_address@domain.invalid wrote:

Since I’ve gotten the go-ahead from Christer, here’s a little newbie app
I just wrote and am looking for advice on how to better write:
[snip]

def rollAttributePair
rolls = Array.new
rolls.push(Die.new(10).roll)
rolls.push(Die.new(10).roll)
if (rolls[0] == 0) or (rolls[1] == 0)
total = 0
return total
else
total = (rolls[0] - rolls[1])
return total
end
end

maybe write it like this (untested)

def roll_attribute_pair
r1 = Die.new(10).roll
r2 = Die.new(10).roll
return 0 if (r1 == 0) or (r2 == 0)
(r1 - r2)
end


#3

Simon S. wrote:

rolls.push(Die.new(10).roll)


Simon S.

or if you like your Array:

def rollAttributePair
rolls = Array.new(2){Die.new(10).roll}
return 0 if rolls.any?{|r|r.zero?}
rolls[0] - rolls[1]
end

you may also look at ‘Struct’ for the charAttributes
(may just be better suited than a hash)

cheers

Simon


#4

damphyr wrote:

Jeeez, I haven’t seen Ars Magica in a long, long while. Will probably
look at the code, but I just had to admire the fact that it still exists
(I’ve got almost all of 3rd Eds).
I always loved it (a lot more than D&D a bit less then CoC :slight_smile: )
This brings back memories.

In reverse order:

Glad I could spark the recollection, Damphyr. It certainly
is my favorite system.

Simon, I was unfamiliar with ‘Struct’ before your mention. Loking
briefly here: http://www.rubycentral.com/book/ref_c_struct.html, it
doesn’t seem there’s a way to establish relationships between the
elements of the ‘Struct’, which I think defeats my purpose. Please
enlighten me if I’ve misunderstood. Also, these

rolls = Array.new(2){Die.new(10).roll}
return 0 if rolls.any?{|r|r.zero?}

are very cool. I was originally under the impression that the first
line would create a two-element array with the same Die instance in
each element
, which would, of course, always result in a 0 total
further down the code. I’ve tested it now, and realize that each
element contains a seperate Die instance. VERY handy knowledge. The
second line is an example of Ruby’s lovely ? notation, which I’ve
noticed all over, but have yet to really grasp/master. Thanks for this
example.

Neoneye, I had never seen the %w in this

attributeShortNames=%w(Int Per Str Sta Pre Com Dex Qik)

before, but looking here: http://www.rubycentral.com/book/intro.html I
found it. Exactly the sort of Ruby shorthand I’m looking for. Now this

Hash[*(attributeShortNames.zip(attributeFullNames).flatten)]

is marvellous. A quick google
(http://www.google.com/search?hl=en&lr=&q=ruby+zip+method&btnG=Search)
doesn’t give much for the zip method, so it’s still a bit magical to me.
Any references to recommend? As for the flatten method, looking here:
http://www.rubycentral.com/book/ref_c_array.html, I see how it works.
Very lovely.

Thanks tremendously, all. You’ve given me much food for thought and
practice. But don’t stop advising on my account. :wink:

-Matthew


#5

On 12/1/05, Simon S. removed_email_address@domain.invalid wrote:

On 12/1/05, Matthew F. removed_email_address@domain.invalid wrote:

Since I’ve gotten the go-ahead from Christer, here’s a little newbie app
I just wrote and am looking for advice on how to better write:
[snip]

#Init Array to hold shortnames of the 8 Attributes
attributeShortNames = Array.new
attributeShortNames[0,7]=[“Int”, “Per”, “Str”, “Sta”, “Pre”, “Com”,
“Dex”, “Qik”]

can simplified:

attributeShortNames=[“Int”, “Per”, “Str”, “Sta”, “Pre”, “Com”, “Dex”,
“Qik”]

which again can be even more simpified:

attributeShortNames=%w(Int Per Str Sta Pre Com Dex Qik)

#Init Hash to hold shortname/fullname pairs for the 8 Attributes
attributeNameMap = Hash.new
count = 0
attributeShortNames.each do |name|
attributeNameMap[name]= attributeFullNames[count]
count += 1
end

can be simplified:

attributeNameMap =
Hash[*(attributeShortNames.zip(attributeFullNames).flatten)]


#6

On Dec 2, 2005, at 12:24 PM, Matthew F. wrote:

Also, these

rolls = Array.new(2){Die.new(10).roll}
return 0 if rolls.any?{|r|r.zero?}

are very cool. I was originally under the impression that the first
line would create a two-element array with the same Die instance in
each element
, which would, of course, always result in a 0 total
further down the code.

Nope. The block is executed to create each element.

The second line is an example of Ruby’s lovely ? notation, which I’ve
noticed all over, but have yet to really grasp/master. Thanks for
this
example.

By convention, a method ending in a ? returns a true/false answer to
the question implied by the call.

A quick google
(http://www.google.com/search?hl=en&lr=&q=ruby+zip+method&btnG=Search)
doesn’t give much for the zip method, so it’s still a bit magical
to me.
Any references to recommend?

If you have Ruby’s documentation installed just feed your command-line:

ri Array.zip

Or you can look it up here:

http://www.ruby-doc.org/core/classes/Array.html#M000391

James Edward G. II


#7

bbazzarrakk wrote:

rolls = Array.new(2){Die.new(10).roll}

Nope. The block is executed to create each element.

This highlights exactly what I wasn’t grasping about that line
previously: the {} delimits a block. I was (wrongly, of course)
equating it to

rolls = Array.new(2,Die.new)

Now I get it. Thanks!

If you have Ruby’s documentation installed just feed your command-line:

ri Array.zip

Or you can look it up here:

http://www.ruby-doc.org/core/classes/Array.html#M000391

Both excellent reference sources of which I was not aware. Much
appreciated. Now the zip method makes perfect sense.

-Matthew


#8

This isn’t meant as ‘the’ solution of your problem,
its just a bit more like it would look like if i had
to write the same program (i was bored, obviously):


require ‘enumerator’

$stdout.sync = true
system(“clear”)

#Roll 2 10-sided die and subtract 2nd from 1st to determine pair total
def rollAttributePair
rolls = Array.new(2){rand(10)}
return 0 if rolls.any?{|r|r.zero?}
rolls[0] - rolls[1]
end

#Obtain user allocation of scores and validate against AM rules
def getScore(total,attr)
loop do
print " Enter score for " + attr + “: "
userInput = gets.chomp.strip.to_i
if (userInput < 0) && (total > 0)
puts " You rolled positively; no negatives for this pair.”
elsif (userInput > 0) && (total < 0)
puts " You rolled negatively; no positives for this pair."
elsif userInput > 4
puts " Rolled scores cannot be higher than 4."
elsif userInput < -4
puts " Rolled scores cannot be lower than 4."
else
return userInput
end
end
end

Attribute = Struct.new(:long, :short)
long = %w(Intelligence Perception Strength Stamina Presence
Communication Dexterity Quickness)
short = %w(Int Per Str Sta Pre Com Dex Qik)
attributes = long.zip(short).map{|a| Attribute.new *a}

#Init Hash to hold name/value pairs for character Attributes
charAttributes = Hash.new(0)

attributes.each_slice(2) do |attr|
puts “Now rolling for the #{attr[0].long} and #{attr[1].long}
pair…”
total = rollAttributePair
if total == 0
puts " You rolled a zero for this pair. Both #{attr[0].short} and
#{attr[1].short} will be set to zero."
attr.each{|a| charAttributes[a] = 0}
else
puts " You rolled a #{total} for this pair."
if total > 0
puts " Please choose scores which are >= 0, <= 4, and which add
up to #{total}."
else
puts " Please, choose scores which are <= 0, >= -4, and which
add up to #{total}."
end

 loop do
   attr.each{|a| charAttributes[a] = getScore(total, a.short)}
   break if (charAttributes[attr[0]] + charAttributes[attr[1]]) == 

total
puts " Your scores add up to more than #{total}. Please try
again."
end
end
puts
end

#Print charAttributes
attributes.each{|attr| puts attr.long + “: #{charAttributes[attr]}”}

#Pause for user input before exit
print “\nPress Enter to exit…”
gets

maybe it’s helpfull, maybe not…

cheers

Simon


#9

Matthew F. wrote:

Since I’ve gotten the go-ahead from Christer, here’s a little newbie
app I just wrote and am looking for advice on how to better write:

=begin =Author & Maintainer Matthew A. Feadler
http://matthew.feadler.com =Description arschar.rb guides the user
through the process of rolling attributes for an Ars Magica character
using v4 rules.
Jeeez, I haven’t seen Ars Magica in a long, long while. Will probably
look at the code, but I just had to admire the fact that it still exists
(I’ve got almost all of 3rd Eds).
I always loved it (a lot more than D&D a bit less then CoC :slight_smile: )
This brings back memories.
V.-

http://www.braveworld.net/riva