Forum: Ruby Optimizing for Newbies

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Matthew F. (Guest)
on 2005-12-02 00:03
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
neoneye (Guest)
on 2005-12-02 00:52
(Received via mailing list)
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
neoneye (Guest)
on 2005-12-02 01:00
(Received via mailing list)
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)]
SimonKroeger (Guest)
on 2005-12-02 01:04
(Received via mailing list)
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
damphyr (Guest)
on 2005-12-02 18:29
(Received via mailing list)
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 :) )
This brings back memories.
V.-
--
http://www.braveworld.net/riva
Matthew F. (Guest)
on 2005-12-02 20:24
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:

<chuckles> 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+...)
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. ;)

-Matthew
James G. (Guest)
on 2005-12-02 20:43
(Received via mailing list)
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+...)
> 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
Matthew F. (Guest)
on 2005-12-02 21:06
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
SimonKroeger (Guest)
on 2005-12-03 02:04
(Received via mailing list)
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
This topic is locked and can not be replied to.