[QUIZ] Equation Graphing (#176)

M

Matthew Moss

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

The three rules of Ruby Quiz 2:

1. Please do not post any solutions or spoiler discussion for this
quiz until 48 hours have passed from the time on this message.

2. Support Ruby Quiz 2 by submitting ideas as often as you can! (A
permanent, new website is in the works for Ruby Quiz 2. Until then,
please visit the temporary website at

<http://splatbang.com/rubyquiz/>.

3. Enjoy!

Suggestion: A [QUIZ] in the subject of emails about the problem
helps everyone on Ruby Talk follow the discussion. Please reply to
the original quiz message, if you can.

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-


This week's quiz idea provided and written by Martin DeMello.

## Equation Graphing (#176)

Back when the world was shiny and new, and BBC Basic my language of
choice and necessity, one of the fun little programs I wrote was a
simple equation grapher. Two things that made it simple were (i) the
ever-useful EVAL function, and (ii) the almost trivial ability to pick
a colour and a pair of coordinates and put a friendly glowing pixel
onto the screen. Instant gratification writ large. Well, anything that
Basic can do, Ruby should be able to, so your task this week is to
whip out your favourite graphics toolkit or library and write a
program that

1. Asks for a function of one variable, x
2. Asks for the region of the graph to display (xmin, xmax, ymin, ymax)
3. Plots the graph

You can trust the user to input a syntactically correct function, but
don't forget that it might behave badly for certain values of x (e.g.
1/x where x=0). Style points for making the main loop look trivial :)

Here's a neat little online grapher you can use to visually check your
output: <http://www.walterzorn.com/grapher/grapher_e.htm>.
 
M

Martin DeMello

Here's my solution, using _why's wonderful little shoes toolkit. Run like

shoes graph.rb "x*x; -5; 5; 0; 25"

The args are "fn; xmin; xmax; ymin; ymax"

I tried to make the code as straightforward as possible, to recapture
the feel of the old Basic days. A few inevitable complications, due to
shoes being a work in progress: the Grapher class is to work around
scoping quirks, and the range check is due to a bug that doesn't let
the exception handler catch an overflowing Bignum -> long conversion
in the canvas code (it would've been nice to simply draw to a point
off-canvas and let the drawing engine cope). Also shoes's argv
handling code puts the filename in ARGV[0] and doesn't like negative
numbers as plain command line args (they are treated as shoes args),
so a single quoted string was the simplest thing that worked.

#------------------------------------------------------------------------------------------------------
# ARGV[0] is the filename, since we launch via shoes graph.rb args
ARGV.shift
args = ARGV[0].split(";").map {|i| i.chomp}
F = args.shift
Xmin, Xmax, Ymin, Ymax = args.map {|i| i.to_f}

X = Y = 800

XScale = X * 1.0/(Xmax - Xmin)
YScale = Y * 1.0/(Ymax - Ymin)

class Grapher
def at(x,y)
[((x -Xmin)* XScale).to_i, Y - ((y - Ymin) * YScale).to_i] rescue nil
end

def bounded?(x,y)
x && y && 0 <= x && x <= X && 0 <= y && y <= Y
end

def fn(x)
y = eval(F)
end
end

Shoes.app :height => Y, :width => X do
g = Grapher.new
background rgb(255, 255, 255)

fill white
stroke black
strokewidth 1
u, v = nil
Xmin.step(Xmax, (Xmax - Xmin)/(X*1.0)) {|i|
begin
x0, y0 = g.at(u,v)
u, v = i, g.fn(i)
x, y = g.at(u,v)
if g.bounded?(x,y) and g.bounded?(x0,y0)
line(x0, y0, x, y)
end
rescue
end
}
end
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,955
Messages
2,570,117
Members
46,705
Latest member
v_darius

Latest Threads

Top