A problem involving each and arrays

Hello

I have a problem with a program I'm writing and I was wondering if
anybody here could help. I have attached the relevant portion of the
program to this message.

The full version of the program is intended to produce files in which
each line is either "write" or a list of three numbers. A machine uses
these files as input. It interprets each line of the file that has three
numbers on it as a point in space and it draws a line between any two
points that don't have a "write" between them.

To that end I have written some methods that generate arrays whose
elements are arrays. Each of the subarrays consists either of the string
"write" or has three entries each of which is a number.

I have a method called "horizblocks". It produces an array that
represents a set of layers arranged vertically. Each layer consists of a
set of parallel horizontal lines.

Another method, called "rotateblock" takes an array and performs an
operation that is equivalent to rotating it about (0,0) in the (x,y)
plane if it is of the same form as the arrays coming out of
"horizblocks".

The method "polyparams" generates a has that contains some parameters
that are involved in the rotation and appear in several other methods in
the full program.

The method "horizcornerblocks" is supposed to generate a block whose
bottom left corner is at (0,0). It should then generate several blocks
that are rotated with respect to one another around (0,0). I intended
that it would generate an array called "blockies" whose first entry is
an array representing a block whose bottom left corner is at (0,0). It
would then produce a new array that represented a rotated version of
that block and push it into "blockies". It does this by taking
"blockies.last", applying "rotateblock" to it and pushing the result
into "blockies". The next step is to take "blockies.last", which is now
the rotated version of the first block and repeating this process a
fixed number of times.

The line that is supposed to do this last step reads

(1..numsides-1).to_a.each{blockies.push(rotateblock(blockies.last,polypar["cos"],polypar["sin"]))}

The program doesn't do what I intended it to do. It gives the error
minimum.rb:41:in `*': Array can't be coerced into Float (TypeError)
from minimum.rb:41:in `block in rotateblock'
from minimum.rb:37:in `each'
from minimum.rb:37:in `rotateblock'
from minimum.rb:53:in `block in horizcornerblocks'
from minimum.rb:53:in `each'
from minimum.rb:53:in `horizcornerblocks'
from minimum.rb:57:in `<main>'

I tested the first three methods and they seem to work. I can generate a
suitable array with "horizblock" and "rotateblock" will rotate it. I
guess the problem must be with "horizcornerblocks" but I haven't worked
out what the problem is.

I have tried using irb to do things like define arrays a = [[1,2]] and b
= [3,4], then write
(0..3).to_a.each{a.push([a.last[0]+b[0]],a.last[1]+b[1])}
and then irb tells me that a is
[[1,2],[4,6],[7,10],[10,14],[13,18]]
which is what I expect.

I am perplexed. Any help would be appreciated.

Alan Forrester

Attachments:
http://www.ruby-forum.com/attachment/7869/minimum.rb

···

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

Hi,

the method stumbles upon the ['write'] entries being in myblock. A
possible workaround would be:

...
if myblock[i].any?{|c| c.class.to_s == "String"}
  newblock.push([myblock[i]])
else
  next if myblock[i][0] == ['write'] # <---
  newblock.push([costhingy*myblock[i][0] ...])
end
...

But I haven't gone through the whole code, so I have no idea if there
are deeper issues.

Apart from that, I think the main problem is that you didn't structure
the code. This makes it hard to understand and very error-prone. Some
parts also look strange and overly complicated (e. g. all the "for ...
in" loops that are completely useless in ruby).

So unless this is supposed to be just a quick hack, it might be a good
idea to start from scratch and make a clean design. For example, how
about defining classes for a canvas, a line and a shape (group of
lines)? The canvas receives lines and shapes and generates the output
file. And a shape is for grouping lines and transforming them (shift,
rotate etc.).

Something like that:

canvas = Canvas.new
line = Line.new x: 3, y: 2, z: 4
canvas << line
line.move x: 12
output = canvas.generate_data

You see? It's much clearer than a bunch of loops and array stuff,
because you can actually *see* what happens. Custom shapes like a plane
or a block could then simply be created by copying and transforming
lines.

···

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

Jan E. wrote in post #1083732:

Apart from that, I think the main problem is that you didn't structure
the code. This makes it hard to understand and very error-prone. Some
parts also look strange and overly complicated (e. g. all the "for ...
in" loops that are completely useless in ruby).

So unless this is supposed to be just a quick hack, it might be a good
idea to start from scratch and make a clean design. For example, how
about defining classes for a canvas, a line and a shape (group of
lines)? The canvas receives lines and shapes and generates the output
file. And a shape is for grouping lines and transforming them (shift,
rotate etc.).

Something like that:

canvas = Canvas.new
line = Line.new [2, 3, 1], [5, 2, 1]
canvas << line
line.move x: 12
output = canvas.generate_data

You see? It's much clearer than a bunch of loops and array stuff,
because you can actually *see* what happens. Custom shapes like a plane
or a block could then simply be created by copying and transforming
lines.

Thanks. I will clean up the code and try again.

Alan Forrester

···

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