# Optimizing for Newbies

**URL:** <https://www.ruby-forum.com/t/optimizing-for-newbies/49266>\
**Category:** Ruby\
**Created:** [December 1, 2005, 11:03pm UTC](https://www.ruby-forum.com/t/optimizing-for-newbies/49266 "2005-12-01T23:03:16Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![mfeadler](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/f6c823/32.png) [@mfeadler](https://www.ruby-forum.com/u/mfeadler)\
**Post date:** [December 1, 2005, 11:03pm UTC](https://www.ruby-forum.com/t/optimizing-for-newbies/49266/1 "2005-12-01T23:03:16Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![mfeadler](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/f6c823/32.png) [@mfeadler](https://www.ruby-forum.com/u/mfeadler)\
**Post date:** [December 1, 2005, 11:52pm UTC](https://www.ruby-forum.com/t/optimizing-for-newbies/49266/2 "2005-12-01T23:52:33Z")

</div>

On 12/1/05, Matthew F. [removed\_email\_address@domain.invalid](mailto: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

---

<div class="post-metadata">

**Author:** ![mfeadler](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/f6c823/32.png) [@mfeadler](https://www.ruby-forum.com/u/mfeadler)\
**Post date:** [December 2, 2005, 12:04am UTC](https://www.ruby-forum.com/t/optimizing-for-newbies/49266/3 "2005-12-02T00:04:41Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![mfeadler](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/f6c823/32.png) [@mfeadler](https://www.ruby-forum.com/u/mfeadler)\
**Post date:** [December 2, 2005, 7:24pm UTC](https://www.ruby-forum.com/t/optimizing-for-newbies/49266/4 "2005-12-02T19:24:02Z")

</div>

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 🙂 )  
> 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](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](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  
([ruby zip method - Google Search](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](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. 😉

-Matthew

---

<div class="post-metadata">

**Author:** ![mfeadler](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/f6c823/32.png) [@mfeadler](https://www.ruby-forum.com/u/mfeadler)\
**Post date:** [December 2, 2005, 12:00am UTC](https://www.ruby-forum.com/t/optimizing-for-newbies/49266/5 "2005-12-02T00:00:39Z")

</div>

On 12/1/05, Simon S. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> On 12/1/05, Matthew F. [removed\_email\_address@domain.invalid](mailto: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)]

---

<div class="post-metadata">

**Author:** ![mfeadler](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/f6c823/32.png) [@mfeadler](https://www.ruby-forum.com/u/mfeadler)\
**Post date:** [December 2, 2005, 7:43pm UTC](https://www.ruby-forum.com/t/optimizing-for-newbies/49266/6 "2005-12-02T19:43:07Z")

</div>

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  
> ([ruby zip method - Google Search](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:

[class Array - RDoc Documentation](http://www.ruby-doc.org/core/classes/Array.html#M000391)

James Edward G. II

---

<div class="post-metadata">

**Author:** ![mfeadler](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/f6c823/32.png) [@mfeadler](https://www.ruby-forum.com/u/mfeadler)\
**Post date:** [December 2, 2005, 8:06pm UTC](https://www.ruby-forum.com/t/optimizing-for-newbies/49266/7 "2005-12-02T20:06:20Z")

</div>

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:
> 
> [class Array - RDoc Documentation](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

---

<div class="post-metadata">

**Author:** ![mfeadler](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/f6c823/32.png) [@mfeadler](https://www.ruby-forum.com/u/mfeadler)\
**Post date:** [December 3, 2005, 1:04am UTC](https://www.ruby-forum.com/t/optimizing-for-newbies/49266/8 "2005-12-03T01:04:51Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![mfeadler](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/f6c823/32.png) [@mfeadler](https://www.ruby-forum.com/u/mfeadler)\
**Post date:** [December 2, 2005, 5:29pm UTC](https://www.ruby-forum.com/t/optimizing-for-newbies/49266/9 "2005-12-02T17:29:01Z")

</div>

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](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 🙂 )  
> This brings back memories.  
> V.-  
> –  
> [http://www.braveworld.net/riva](http://www.braveworld.net/riva)
