Learn to Program, by Chris Pine

He Fa:

Good Job! However, I don't fully understand how this worked.

words_array.each do |word|
  if word.to_s.downcase > sorted_array.last.to_s.downcase
    #add word to the end of sorted_array
    sorted_array.push word

  else
    index = (sorted_array.length) - 1
    initial_number = index
    temp_array =

The second WHILE section was where I got really confused.

    #check word against next word in sorted_array and repeat
    while word.to_s.downcase < sorted_array[index].to_s.downcase
      #add the sorted_array to a temp_array up to that point
      temp_array[index] = sorted_array[index]
      #erase words in sorted_array up to that point
      sorted_array.pop
      index = index - 1
    end

    #add the word to sorted_array
    sorted_array.push word

    #add one by one the words from temp_array to sorted_array
    while index < initial_number
      sorted_array.push temp_array[index + 1]
      index = index + 1
    end
  end
end

puts sorted_array

I've been wrapping my head around my own version of the non-recursive
sort for days and haven't made it work.

···

--
Posted via http://www.ruby-forum.com/\.

BTW a little trick for later, if you i.e. have an array, and find
yourself using a counter, you can stop using the counter and instead use
array.size and check on that value.

I like "Learn to Program" but I never bothered to make the examples.
Like with homework in school many years ago - I did this in school. Not
at home... :slight_smile:

···

--
Posted via http://www.ruby-forum.com/.

actually ROMAN[key] and not working with numbers having a 9.

···

On Feb 3, 2008 4:02 AM, Todd Benson <caduceass@gmail.com> wrote:

On Feb 2, 2008 8:49 PM, Todd Benson <caduceass@gmail.com> wrote:
> Actually, better production code that keeps in line with OO concepts
would be...
>
> class Integer
> ROMAN = {
> 1 => "I",
> 5 => "V",
> 10 => "X",
> 50 => "L",
> 100 => "C",
> 500 => "D",
> 1000 => "M"
> }
>
> def roman
> number, roman_string = self, ""
> ROMAN.keys.sort.reverse.each do |key|
> roman_string << (ROMAN[n] * (number/key)
> n %= key
> end
> roman_string
> end
> end
>
> #usage
> puts 2137.roman
> # => "MMCCCXVII"
>
> I'm pretty sure there were better and more thorough examples at
> http://www.rubyquiz.com/quiz22.html\.

gsub('number', 'n') on that code...and there's a missing parenthesis
")" number/key line

Yeah, yeah

That's what I get for not using cut and paste :slight_smile:

Todd

You're right, I didn't implement one of the features after reading the
exercise instructions again. Oh well. I'll do it tomorrow.

But I just ran your solution and it doesn't work :slight_smile:

Hello Grandma

HUH!? SPEAK UP, SONNY!

HELLO GRANDMA

NO, NOT SINCE 1938!

BYE

NO, NOT SINCE 1941!

BYE

NO, NOT SINCE 1945!

BYE

NO, NOT SINCE 1941!

BYE

BYE, BYE

I needed 4 BYE's to get out, not 3.

···

On Thu, 30 Mar 2006 22:53:30 GMT, "Dave Burt" <dave@burt.id.au> wrote:

num_s = num.to_s
(0...(num_s.length)).inject(0) { |s, i| s += (num_s[i] - ?0) }

Just to increase confusion and to rely on the properties of ASCII

···

On Apr 1, 2006, at 9:29 AM, James Edward Gray II wrote:

On Apr 1, 2006, at 7:22 AM, Marcus Lunzenauer wrote:

Hello!

To sum the digits of an Integer I have got

class Integer
  def sum_digits()
    sum = 0
    n = self
    begin sum += n % 10; n /= 10 end while n > 0
    sum
  end
end

Is there a more Ruby Way to do this? The above method smells of Java, doesn't it?

Here is what I thought of when reading this:

>> class Integer
>> def sum_digits
>> to_s.split("").inject(0) { |sum, n| sum + n.to_i }
>> end
>> end
=> nil
>> 1234.sum_digits
=> 10

Hope that helps.

James Edward Gray II

Hi Mike,

   I don't know the book and that is probably true for a lot of the people here. Maybe you should include the full source code. Especially interesting would be to see the line numbers as the interpreter clearly indicates where the problem occurs.

   As a totally wild guess ... The error message says that the right side of an addition is nil. So looking at your code, "size" seems to be set, maybe continent_size does return nil?

   What I also think is strange is that "world" seems to be a two dimensional array when you first mention it (world[y] = 'counted land'), but later on you pass it to continent size along with two parameters. This might be ok, if continent_size defines three parameters, like this:

   def continent_size(world, x, y); end

   and you use x and y to access the array then?!

   I don't know about the conditional. What are you trying to check? That both x and y are between 1 and 10? That should work ... Even though you wouldn't need the braces as it all of the conditionals need to be true for the whole expression to become true. This would be different if you use "or".

   Hope that helps!

Cheers,
Mariano

···

On Oct 9, 2006, at 4:46 AM, Mike Agres wrote:

I'm having some issues modifying the Civ continent example from ch. 10
to account for coordinates that are outside the array. I added the
following line:

if ((y <= 10 && y > 0) && (x <= 10 && x > 0))

before...

  # So, first we count this tile...
  size = 1
  world[y] = 'counted land'

    # ...then we count all of the
    # neighboring eigth tiles (and,
    # of course, their neighbors via recursion)
    size = size + continent_size(world, x-1, y-1) #4,4
    size = size + continent_size(world, x , y-1) #5,4
    size = size + continent_size(world, x+1, y-1) #6,4
    size = size + continent_size(world, x-1, y ) #4,5
    size = size + continent_size(world, x+1, y ) #6,5
    size = size + continent_size(world, x-1, y+1) #4,6
    size = size + continent_size(world, x , y+1) #5,6
    size = size + continent_size(world, x+1, y+1) #6,6
    size
end

As a result, I get the following error:

TypeError: nil can't be coerced into Fixnum

method + in civilization.rb at line 35
method continent_size in civilization.rb at line 35
method continent_size in civilization.rb at line 36
method continent_size in civilization.rb at line 35
method continent_size in civilization.rb at line 40
method continent_size in civilization.rb at line 39
method continent_size in civilization.rb at line 41
method continent_size in civilization.rb at line 39
method continent_size in civilization.rb at line 41
method continent_size in civilization.rb at line 39
method continent_size in civilization.rb at line 36
method continent_size in civilization.rb at line 35
at top level in civilization.rb at line 48

This error appears regardless of whether the arguments I pass are in 5,5
(as in the example Chris Pine wrote out) or something like 10,10 (which
is on the edge of the 'continent').

Is that the right conditional statement? Could it be in the wrong place
in the method?

--
Posted via http://www.ruby-forum.com/\.

Here's the copy and pasted code...

class Integer
ROMAN = {
   1 => "I",
   5 => "V",
   10 => "X",
   50 => "L",
   100 => "C",
   500 => "D",
   1000 => "M"
}

def roman
   n, roman_string = self, ""
   ROMAN.keys.sort.reverse.each do |key|
     roman_string << (ROMAN[key] * (n/key))
     n %= key
   end
   roman_string
end
end

#usage
puts 2319.roman
# => "MMCCCXVIIII"

cheers,
Todd

···

On Feb 4, 2008 12:20 PM, Moises Trovo <moises.trovo@gmail.com> wrote:

actually ROMAN[key] and not working with numbers having a 9.

Here's the fix:

byes = 0

until byes == 3
  input = gets.chomp
  
  if input == "BYE"
    byes = byes + 1
  else
    byes = 0
  end
  if input == input.upcase
    puts "NO, NOT SINCE " + (1930 + rand(21)).to_s + "!"
  else
    puts "HUH!? SPEAK UP, SONNY!"
  end
end
puts "BYE, BYE"

···

On Fri, 31 Mar 2006 10:22:03 -0500, Jan_K <non@none.com> wrote:

On Thu, 30 Mar 2006 22:53:30 GMT, "Dave Burt" <dave@burt.id.au> wrote:

You're right, I didn't implement one of the features after reading the
exercise instructions again. Oh well. I'll do it tomorrow.

But I just ran your solution and it doesn't work :slight_smile:

Hello Grandma

HUH!? SPEAK UP, SONNY!

HELLO GRANDMA

NO, NOT SINCE 1938!

BYE

NO, NOT SINCE 1941!

BYE

NO, NOT SINCE 1945!

BYE

NO, NOT SINCE 1941!

BYE

BYE, BYE

I needed 4 BYE's to get out, not 3.

Logan Capaldo wrote:

num_s = num.to_s
(0...(num_s.length)).inject(0) { |s, i| s += (num_s[i] - ?0) }

require 'enumerator'
num.to_s.enum_for(:each_byte).inject(0) { |sum, c| sum + c - ?0 }

Or, in Ruby 1.9 (I think):
num.to_s.each_byte.inject(0) { |sum, c| sum + c - ?0 }

Cheers,
Dave

here's the whole code...

# These are just to make the map easier to read. "M" is
# visually more dense than "o".

M = 'land'
o = 'water'

world = [[M,o,o,o,o,o,o,o,o,o,M],
              [o,M,M,o,M,M,o,o,o,M,M],
              [o,o,M,M,o,o,o,o,M,M,o],
              [o,o,o,M,o,o,o,o,o,M,o],
              [o,o,o,M,o,M,M,o,o,o,o],
              [o,o,o,o,M,M,M,M,o,o,o],
              [o,o,o,M,M,M,M,M,M,M,o],
              [o,o,o,M,M,o,M,M,M,o,o],
              [o,o,M,M,o,o,M,M,M,o,o],
              [o,M,M,M,o,M,o,o,o,M,M],
              [M,o,o,o,o,o,o,o,o,o,M]]

def continent_size world, x, y
  if world[y][x] != 'land'
    # either it's water or we've already counted it; we don't want to
count it
    # again
    return 0
  end

  if ((y <= 10 && y > 0) && (x <= 10 && x > 0))
  # So, first we count this tile...
  size = 1
  world[y][x] = 'counted land'

    # ...then we count all of the
    # neighboring eigth tiles (and,
    # of course, their neighbors via recursion)
    size = size + continent_size(world, x-1, y-1)
    size = size + continent_size(world, x , y-1)
    size = size + continent_size(world, x+1, y-1)
    size = size + continent_size(world, x-1, y )
    size = size + continent_size(world, x+1, y )
    size = size + continent_size(world, x-1, y+1)
    size = size + continent_size(world, x , y+1)
    size = size + continent_size(world, x+1, y+1)
    size
  end
end

puts continent_size(world, 5, 5) #this should be fine; but what about
(11,11)?

···

--
Posted via http://www.ruby-forum.com/.

Hey everyone I was having a slight problem with one of the examples in
the book. I was doing the '99 beers' example and ran into a problem at
the end. The task asks you to create a prog that will recite the lyrics
for '99 beers on the wall' which seemed fairly easy to do but I wanted
to make it more challenging for myself and make it more grammatically
correct. So I tried to create an if statement to change the word
'bottles' to 'bottle' when bottles = 1. I have seen another example
creating a working solution but requires many more lines of code and I
was trying to do it in a more clever way (maybe it is backfiring). I
just can't figure out why it is not working properly. Anyway here is
the code:

[code]
bottles = 99
bword = ' bottles'
while bottles != 0
  puts(bottles.to_s + bword + " of beer on the wall!")
  puts(bottles.to_s + bword + " of beer!")
  puts("Take one down and pass it around!")
  bottles = bottles - 1
  puts(bottles.to_s + bword + " of beer on the wall!")
  puts ''
  if bottles == 1
    bword = ' bottle'
  else
    bword = ' bottles'
  end
end
[/code]

and here is the output that isn't showing up as planned:

2 bottles of beer on the wall!
2 bottles of beer!
Take one down and pass it around!
1 bottles of beer on the wall!

1 bottle of beer on the wall!
1 bottle of beer!
Take on down and pass it around!
0 bottle of beer on the wall!

It doesn't work for the first line with a 1 on it and I wanted it to
switch back to 'bottles' with the zero on the last line. Any thoughts?

···

--
Posted via http://www.ruby-forum.com/.

Jan K wrote:

You're right, I didn't implement one of the features after reading the
exercise instructions again. Oh well. I'll do it tomorrow.

But I just ran your solution and it doesn't work :slight_smile:
...
I needed 4 BYE's to get out, not 3.

You're absolutely right. I should claim that I put the error in deliberately
so you could debug it, but I didn't. So the lesson (for me) is: TEST your
code, Dave!

Here's the fix:
...

Great work. You fixed it without making it longer; in fact, you made it
shorter!

Sounds to me like you'll be fine, but of course you can ask the list here
any questions you have along the way, we love to help.

Cheers,
Dave

Thanks a lot! I will try one of your solutions.

Bye, Marcus

Hi Mike,

   what your guard should do is prevent the recursion go across the boundaries of your world, right?

   I would put the guard at the beginning of the method to make sure that the rest of the method can be sure of handling valid data.

   if x < 0 || x > 10 || y < 0 || y > 10
     return 0 # respect the world's boundaries
   end

def continent_size world, x, y
  if world[y] != 'land'
    # either it's water or we've already counted it; we don't want to
count it
    # again
    return 0
  end

That's a bit of a problem as your code might already call with out of bounds coordinates.
Put the boundary guard (see above) before that.

  if ((y <= 10 && y > 0) && (x <= 10 && x > 0))

An array starts to count at zero ... so it needs to be (y <= 10 && y >= 0), right?
You have eleven columns and eleven rows. So the array indices are 0..10.

  # So, first we count this tile...
  size = 1
  world[y] = 'counted land'

    # ...then we count all of the
    # neighboring eigth tiles (and,
    # of course, their neighbors via recursion)
    size = size + continent_size(world, x-1, y-1)
    size = size + continent_size(world, x , y-1)
    size = size + continent_size(world, x+1, y-1)
    size = size + continent_size(world, x-1, y )
    size = size + continent_size(world, x+1, y )
    size = size + continent_size(world, x-1, y+1)
    size = size + continent_size(world, x , y+1)
    size = size + continent_size(world, x+1, y+1)
    size

Ok, you're returning the size here, but

  end

what are you returning here, if you haven't been in this if-block?

nil. That is a major part of your problem...

end

Use the code above and put it after the definition of the method. Remove your own "if" and your method should work.

puts continent_size(world, 5, 5) #this should be fine; but what about
(11,11)?

That's up to you. In my code (the guard) it returns 0. So that 11,11 will return 0.
You could also raise an exception that the coordinates are out-of-bounds, but I guess that will come later in your book and is not that straight forward applicable here.

Cheers,
Mariano

You need to reorder your logic slightly so that bword is changed as soon as the bottle count is decremented:

bottle = 99
bword = 'bottles'
while bottles != 0
  puts(bottles.to_s + bword + " of beer on the wall!")
  puts(bottles.to_s + bword + " of beer!")
  puts("Take one down and pass it around!")
  bottles = bottles - 1
  if bottles == 1
    bword = ' bottle'
  else
    bword = ' bottles'
  end
  puts(bottles.to_s + bword + " of beer on the wall!")
  puts ''
end

Ellie

Eleanor McHugh
Games With Brains
http://slides.games-with-brains.net

···

On 28 May 2008, at 18:05, Patrick Hummer wrote:

bottles = 99
bword = ' bottles'
while bottles != 0
puts(bottles.to_s + bword + " of beer on the wall!")
puts(bottles.to_s + bword + " of beer!")
puts("Take one down and pass it around!")
bottles = bottles - 1
puts(bottles.to_s + bword + " of beer on the wall!")
puts ''
if bottles == 1
   bword = ' bottle'
else
   bword = ' bottles'
end
end

----
raise ArgumentError unless @reality.responds_to? :reason

Just one more way, since I haven't seen a solution that takes advantage
of the no-parameter inject call:

1234.to_s.split('').map {|c| c.to_i }.inject {|i,j| i+j }
=> 10

That worked! Thanks.

-Mike

···

--
Posted via http://www.ruby-forum.com/.