Keeping it Small and Simple

2007.12.31

Modifying Ruby’s Numeric class for fun

Filed under: Ruby Programming — Tags: , — Lorenzo E. Danielsson @ 02:22

Imagine you wanted to write a small program that calculates the length of the hypotenuse of a right-angled triangle. It might look something as follows:


1 #! /usr/bin/ruby
2
3 # Calculate the hypotenuse of a right-angled triangle.
4
5 abort "You should pass the lengths of the catheti" unless ARGV.size == 2
6
7 a, b = ARGV.shift.to_f, ARGV.shift.to_f
8 hyp = Math::sqrt(a ** 2 + b ** 2)
9 puts "The length of the hypotenuse is #{hyp}."

Notice something? Line 8 doesn’t look so nice. Wouldn’t it be nice if we could do a (a.sq + b.sq).sqrt instead? Well, you can.

Adding Numeric#square

The first thing we are going to do is add a method called Numeric#square. Since I am lazy I will also create alias it as Numeric#sqr. Here is a little test program (note that I added a Numeric#cube method as well, since I don’t have anything better to do with my time):


 1 #! /usr/bin/ruby
 2
 3 # Calculate squares and cubes.
 4
 5 class Numeric
 6   def square
 7     return self ** 2
 8   end
 9   alias :sqr :square
10
11   def cube
12     return self ** 3
13   end
14 end
15
16 abort "You have to pass in some numbers." if ARGV.empty?
17
18 ARGV.each do |n|
19   begin
20     num = n =~ /\./ ? Float(n) : Integer(n)
21     puts "#{num}² = #{num.sqr}, #{num}³ = #{num.cube} (#{num.class})"
22   rescue
23     puts "Skipping #{n} because it doesn’t smell like a number.."
24     next
25   end
26 end

Now line 20 looks highly suspect. What it does is convert the string n to either a floating point number (Float) or an integer (Fixnum) depending on whether or not it finds a decimal point. I’m just doing this to demonstrate that Numeric#square is available to both Fixnum and Float objects. That’s why we chose to modify Numeric.

If you wonder how to get the ² character in your editor, in insert mode, hit CTRL+K followed by 2S. That is, if you are using vim. If you are using another editor, chances are you have to upgrade to the Professional Enterprise++ version of your software.

Running the program above on some numbers I get:

% ruby sc.rb 2 4 5.2 -2
2² = 4, 2³ = 8 (Fixnum)
4² = 16, 4³ = 64 (Fixnum)
5.2² = 27.04, 5.2³ = 140.608 (Float)
-2² = 4, -2³ = -8 (Fixnum)

Adding Numeric#sqrt

Adding Numeric#sqrt is similar. Let’s put it to the test!


 1 #! /usr/bin/ruby
 2
 3 # Calculate square roots.
 4
 5 class Numeric
 6   def sqrt
 7     require complex if self < 0
 8     Math::sqrt(self)
 9   end
10 end
11
12 abort "I need some numbers to work with." if ARGV.empty?
13
14 ARGV.each do |arg|
15   begin
16     num = Float(arg)
17     puts "#{num} = #{num.sqrt}"
18   rescue
19     puts "You know, #{arg} is a weird number.."
20     next
21   end
22 end

This program contains one extra detail, which you can find on line 7. If the number is negative then we bring in the complex module before the call to Math::sqrt. That way it seamlessly uses complex numbers as and when they are needed. Now you may or may not think this is a good idea, but whatever the case may be, Ruby allows you to do whatever you think is right.

Testing this on a few numbers, I get:

% ruby sr.rb 100 -4.0 2.3 -64
√100.0 = 10.0
√-4.0 = 2.0i
√2.3 = 1.51657508881031
√-64.0 = 8.0i

Back to our right-angled triangle

Okay, now that we have tested that all the details work as expected, we can get back to our program, which was all about calculating the hypotenuse of a right-angled triangle. Here is our new version of that program:


 1 #! /usr/bin/ruby
 2
 3 # Calculate the hypotenuse of a right-angled triangle.
 4
 5 class Numeric
 6   def sq
 7     self ** 2
 8   end
 9
10   def sqrt
11     Math::sqrt self
12   end
13 end
14
15 abort "Please pass in the lengths of the catheti." unless ARGV.size == 2
16
17 a, b = ARGV.shift.to_f, ARGV.shift.to_f
18 hyp = (a.sq + b.sq).sqrt
19 puts "The length of the hypotenuse is #{hyp}."

I’ve cut out things from the Numeric class that we don’t need for our program, such as Numeric#cube and requiring complex, since we cannot get a negative number from the sum of two numbers squared. Also, I got extra lazy and shortened the square method to Numeric#sq (which seems to make sense, since square meters is abbreviated sq m).

Our second version of the hypotenuse calculator is a whole lot longer, 19 lines instead of 9 lines. But wasn’t it worth it, just to clean up that single ugly Math::sqrt(a ** 2 + b ** 2) expression? 😀

2007.12.29

Rbcatcher 0.0.1

Filed under: Ruby Programming, Software — Tags: , , — Lorenzo E. Danielsson @ 19:54

In a recent post, I mentioned that I have been using hpodder for all my podcatching needs. Of course, just as I had finished praising it, it decided to fail me, as I tried adding this podcast.

Hpodder incorrectly thinks the eposides of The History of Rome are mp3 files, so it starts tagging them up with id3 tags. But these are not mp3 files, so the files get corrupted. I had never had this problem before because all the podcasts I have been subscribed to have used mp3 files.

There is a bug report about it on the hpodder site, but it seems development of hpodder has stagnated. I had a quick look at the code, and I’m sure I could have figured out where hpodder injects the id3 tags and remove those lines. But, I’m not fluent in Haskell (at least not yet). I also took a look at bashpodder and some of its derivates but, although they are cool, they don’t work the way I want. Most of the other alternatives where GUI clients, which I emphatically do not want.

So I decided to roll my own. I used Ruby, SQLite and wget. In just a day I have been able to come up with something that I can use. It’s still very rough around the edges, but for most parts it does what I need it to. It works very similar to hpodder. I have even used the same command set. I also took the liberty to add a few extensions such as episode priority.

The great part is that it works exactly the way *I* want which leads me to one of issues right now. Rbcatcher is not very configurable, to say the least. Most of the settings are hard-coded into the script. I hope to change that. I need more people to test it and give me feedback. If you’re interested in a console-based podcatcher, let me know! I don’t have anywhere to host the code at the moment, but I’ll ask around a bit.

2007.12.27

Rubygame 2.2.0 released

Filed under: Rubygame — Tags: , — Lorenzo E. Danielsson @ 13:15

It bit of old news perhaps, but I’ll blame it on the season. 😉

Rubygame 2.2.0 was released on 2007.12.19. Among the changes you will notice that Surface#set_at is back. This means you’ll no longer need the kludge to add your own set_at method.

For those of you who are following my Rubygame tutorial, once you’ve installed Rubygame 2.2.0, you may want to update your programs. You can get rid of the Surface#put_pixel method. You will also need to change the call to put_pixel to instead call set_at.
Hm.. Maybe I’ll just have to give an example in my next tutorial.

2007.12.26

Using multiple keymaps in X

Filed under: X Windows — Tags: , , , , , — Lorenzo E. Danielsson @ 02:12

The other day I blogged about my frustration over Opera not recognizing when I changed keymaps with setxkbmap. Well, it turned out that not only Opera had a problem, but all Qt and Gtk2 applications. (I guess that tells a bit about me that I haven’t realized this until now).

My ~/.fluxbox/keys file contained the follwing lines, which worked well in the applications that I happen to use most of the time (rxvt-unicode, vim):

Mod4 G :Exec setxkbmap -layout gh -variant ga
Mod4 S :Exec setxkbmap -layout se -variant nodeadkeys
Mod4 U :Exec setxkbmap -layout us

I noticed one thing. If I changed the keymap before launching Opera, the browser would use that keymap. So if, at the time of starting Opera, I was using a Swedish keymap, then I would be able to enter Swedish keys in Opera. But changing the keymap while Opera was running had no effect.

The fix for the problem was simple, after a bit of Googling. I modified ~/.xinitrc to look as follows:

setxkbmap -option grp:switch,grp:shift_toggle,grp_led:scroll us,se,gh -variant ',,ga'
exec startfluxbox

Now the few Qt and Gtk applications that I use behave well! I can switch between US, Swedish and Ga keyboards in all X applications.

Moral: if somethings doesn’t work as you like, don’t get frustrated, get searching. Somebody has had the problem before, fixed it and documented it.

2007.12.24

The only thing I don’t like about Opera (the browser)

Filed under: Software — Tags: , , , , , — Lorenzo E. Danielsson @ 12:48

Although I have Firef.. um.., Iceweasel [ 😦 ] on my system, I tend to use Opera most of the time (at least when I need a graphical browser).

It’s a nice browser, does what I need it to, and is much more lightweight than Firefox. It also seems to render pages much faster. The few times when I hit a site that does not render well on Opera, I can always switch to Firefox for that particular site.

However, there one thing that does get to me. I have the following bindings set up in ~/.fluxbox/keys:


Mod4 G :Exec setxkbmap -layout gh -variant ga
Mod4 S :Exec setxkbmap -layout se -variant nodeadkeys
Mod4 U :Exec setxkbmap -layout us

These bindings allow me quickly to switch between American English, Swedish and Ga keyboard layouts. This works well in *every* single application I use, except for Opera. Rxvt handles it, Gvim handles it, Firefox handles it, Zim handles it, so why not Opera? Opera just keeps printing [, and ; even when I have Swedish keyboard selected and would expect å, ä and ö.

I wonder if it is a Qt thing? I don’t really use many Qt applications, and Opera would be the only one where I need to switch between different keyboard layouts. I’m using Opera 9.5beta, but have had the same issue with previous versions.

It’s too bad, because apart from that I’m happy with Opera. But, why, why, can’t I use standard tools and expect Opera to behave like everything else? Opera developers, for next year’s Yule, could you *please* fix this minor dent in you browser?

Oh, yeah, I got *inspired* to write this because I had to type a post in Swedish and had to go through the type-characte-rselect-switch-to-opera-middle-click hell once more! 😦

Oh, and lest I forget: Happy Yule to all!


Edit: see my next post for a solution and why Opera is not to be blamed.

God jul!

Filed under: Swedish — Tags: , , — Lorenzo E. Danielsson @ 12:21

God jul!

Jag hoppas alla får riktigt trevlig jul. Här i Ghana är det riktigt varmt. Det är säkert det varmaste året på länge.

Julafton är nog den enda dagen på året då jag riktigt saknar snön och kylan. Och Enrique och Vanessa frågar jämt och ständigt om julen is Sverige. Jag har försökt att visa lite bilder, spelat några julvisor, men den svenska julen kan inte riktigt beskrivas med bild och sång. Den måste upplevas!

*suck*, nästa år måste jag försöka ta mig hem. Det är verkligen på tiden att barnen får se Sverige.

2007.12.23

Xorg 7.3 in Sid: harmful

Filed under: Debian — Tags: — Lorenzo E. Danielsson @ 23:39

If you are running Debian Sid and your system has begun to crawl, then try reverting Xorg. This hit me a few days ago, when I decided to do a few upgrades. All of a sudden my system became *very* slow. Xorg was using up 80-90% of my CPU and eating all the memory it could get. It was as if I were running Gnome or KDE.

The solution was simple. I reverted Xorg and the problem was gone. Now my system is fast and responsive again.

2007.12.22

Catching pods with hpodder

Filed under: Software — Tags: , , , — Lorenzo E. Danielsson @ 22:21

I am subscribed to quite a few podcasts. There are so many interesting ones out there if you just spend a little time searching for them. Obviously, keeping a track of all your podcasts requires a good podcatcher. The one I use is hpodder, and I’m really happy with it. It does what I need it to, is really easy to use, and doesn’t add loads of functionality that I don’t need.

Hpodder was written in Haskell, which is definitely in interesting language. It uses cURL for downloading. It has been very stable for me. I have never had a single issue with it. Another thing I like is that hpodder doesn’t try to be anything but a podcatcher. Once it has downloaded an episode for you, you decide which tool you want to use to play the episode. I usually use mpd/mpc for music, but with podcasts I tend to just use mpg123.

I also like the fact that hpodder doesn’t force a GUI on me. It is a well-behaved command-line tool that I can easily invoke from a cron job or a login script or whatever. I can use it on a machine that doesn’t have X installed (several of my boxes don’t). And, if for some reason, you would “need” a GUI front-end for it, that would be trivial to implement (there might already exist some).

Here are some usage examples. To add a new podcast:
% hpodder add <url>

To update your casts:
% hpodder update

To download new episodes:
% hpodder download

Or, if you are lazy (as I am), you can update and download in one with:
% hpodder fetch

There are loads of things you can do with hpodder. You can specify to download only a specific podcast, or specific episodes, etc. There hasn’t been anything that I have needed to do with regards to podcatching that hpodder hasn’t been able to perform.

There are of course a number of other podcatchers out there. I am sure that several of them are really good as well. Me saying hpodder is good should not be taken as me saying podcatcher X sucks. There are also several media players that also have podcasting support. Banshee, Rhythmbox and Amarok all support podcasting. Of course, they will also eat all your RAM. 😉

2007.12.20

Rubygame tutorial #2: pixels

Filed under: Rubygame, Rubygame Tutorial — Tags: , , , , — Lorenzo E. Danielsson @ 13:10

Welcome to my second rubygame tutorial. This time we will look at pixels, which are the smallest of the building blocks available to you. We will also have a short introduction to timing. At the end of this tutorial you will have a framework for most of the applications that we will be writing over the next few tutorials.

Pixels

A pixel is the smallest possible unit that can be displayed on the screen. There are three attributes of a pixel that you always need to keep in mind: its x-coordinate, its y-coordinate and its color.

In contrast to pygame and just about every single game development library on the planet, Rubygame does not have a method to plot individual pixels. It used to but it was removed. Its not really a problem, because we can easily create our own, but it is a little annoying that something that you need so frequently is not there. Oh, well, let us not worry about such details now.

I normally learn best by looking at examples, so here we go. The following program plots random pixels to the screen.


 1 #! /usr/bin/ruby
 2
 3 # Plot random pixels.
 4
 5 require rubygame
 6
 7 Width = 640
 8 Height = 400
 9
10 module Rubygame
11   class Surface
12     def put_pixel(point, color)
13       self.draw_box point, point, color
14     end
15   end
16 end
17
18 class RandomPixels
19   include Rubygame
20
21   def initialize
22     @screen = Screen.new [Width, Height]
23     @events = EventQueue.new
24
25     @screen.fill [0, 0, 0]
26     @screen.update
27   end
28
29   def event_loop
30     loop do
31       @events.each { |event|
32         case event
33         when QuitEvent
34           return
35         end
36       }
37
38       draw
39       @screen.update
40     end
41   end
42
43   def draw
44     point = [rand(Width), rand(Height)]
45     color = [rand(255), rand(255), rand(255)]
46     @screen.put_pixel point, color
47   end
48 end
49
50 Rubygame.init
51 RandomPixels.new.event_loop
52 Rubygame.quit

The first thing we do is inject a little extra functionality into Rubygame’s Surface class. I chose to call it put_pixel (reminds me of Turbo Pascal’s graph library), but feel free to call it anything you want. The put_pixel method simple draws a box which is a single pixel high and a single pixel wide. The result is that I’ve plotted a single pixel.

Most of the rest of the program should be familiar to you, at least if you have already read tutorial #1. What is new is that there is a call to the draw method inside the event loop. The draw method creates a random point (x, y) and a random color (red, green, blue). Then it calls our Surface#putpixel method, passing in the point and color.

Notice that since the draw method is called inside the event loop, this program will continuously plot randomly colored pixels and random coordinates. There is also a call to Surface#update in the event loop. More about what that does below.

Exercises

  1. Modify the above program to only plot pixels that are random shades of blue.
  2. Modify the above program to only plot pixels of a single color, such as orange.
  3. Modify the above program to keep count of how many pixels have been plotted.
  4. Modify the program to only plot pixels in the top half of the screen.

Timing

Try running the above program. While it is running, open up a terminal and start ‘top’. You can also use any other utility that lets you see your system’s resource usage (such as Gnome system monitor). You may notice that CPU usage is quite high. What is happening?

Our program is actually very busy all the time, it is plotting points and checking if any event have occured, and its doing this constantly. Because of that, the program signals the kernel that “Hey, I’ve got a heavy workload over here. Better help me out!”

The fact is that the program isn’t really that busy. There is time for it to just relax a bit once in a while. If we can let our program take a break, it means there is more time available for the kernel to help out other tasks that are running on your system, and the whole system ends up being happier.

That is obvioulsy grossly over-simplified, but i think you get the point. We need to let our program “go to sleep” every so often. This can be achieved with the help of a clock. The following program looks like the previous one, but we have added a clock to it.


 1 #! /usr/bin/ruby
 2
 3 # Plot random pixels.
 4
 5 require rubygame
 6
 7 Width = 640
 8 Height = 400
 9
10 module Rubygame
11   class Surface
12     def put_pixel(point, color)
13       self.draw_box point, point, color
14     end
15   end
16 end
17
18 class RandomPixels
19   include Rubygame
20
21   def initialize
22     @screen = Screen.new [Width, Height]
23     @events = EventQueue.new
24     @clock = Clock.new
25     @clock.target_framerate = 120
26
27     @screen.fill [0, 0, 0]
28     @screen.update
29   end
30
31   def event_loop
32     loop do
33       @events.each { |event|
34         case event
35         when QuitEvent
36           return
37         end
38       }
39
40       draw
41       @clock.tick
42       @screen.update
43     end
44   end
45
46   def draw
47     point = [rand(Width), rand(Height)]
48     color = [rand(255), rand(255), rand(255)]
49     @screen.put_pixel point, color
50   end
51 end
52
53 Rubygame.init
54 RandomPixels.new.event_loop
55 Rubygame.quit

There are two things that are important here. The first happens on lines 24 and 25, where we initialize a clock and set a desired framerate for it. I’m going to let you experiment a little with the target_framerate. Set it to different values, high as well as low ones. Each time you do, run the program and see how “fast” the program itself seems to run. Also check the CPU usage. What do you notice?

The second thing that you should notice is that in the event loop, we added an extra line. On line 41 we call Clock#tick. This is the line that puts our program to rest for a short while. This call is inside the event loop so it gets called frequently.

Timing the program has other uses than just to lower its CPU usage, but we will look at that more in a later tutorial.

Exercises

  1. Set Clock#target_framerate to 10. What happens to your program? What happens to CPU usage while the program is running?
  2. Set Clock#target_framerate to 1000. What happens to your program? What happens to CPU usage while the program is running?

Doing more than one thing at once

Our program plots a single pixel every iteration of the event loop. Plotting just a single pixel is an expensive operation since @clock.tick and @screen.update take significant time (relatively speaking). In order to speed things up, it is better that we perform more than a single drawing operation at a time. In the following program we plot one hundred pixels each cycle of the event loop.


 1 #! /usr/bin/ruby
 2
 3 # Plot random pixels.
 4
 5 require rubygame
 6
 7 Width = 640
 8 Height = 400
 9
10 module Rubygame
11   class Surface
12     def put_pixel(point, color)
13       self.draw_box point, point, color
14     end
15   end
16 end
17
18 class RandomPixels2
19   include Rubygame
20
21   def initialize
22     @screen = Screen.new [Width, Height]
23     @events = EventQueue.new
24     @clock = Clock.new
25     @clock.target_framerate = 120
26
27     @screen.fill [0, 0, 0]
28     @screen.update
29   end
30
31   def event_loop
32     loop do
33       @events.each { |event|
34         case event
35         when QuitEvent
36           return
37         end
38       }
39
40       draw
41       @clock.tick
42       @screen.update
43     end
44   end
45
46   def draw
47     100.times do
48       point = [rand(Width), rand(Height)]
49       color = [rand(255), rand(255), rand(255)]
50       @screen.put_pixel point, color
51     end
52   end
53 end
54
55 Rubygame.init
56 RandomPixels2.new.event_loop
57 Rubygame.quit

Normally we want to assemble our whole frame before displaying it. If we were to draw directly to the screen, we would get a lot of flicker. So instead we perform all our drawing on a hidden buffer. When we have drawn the entire frame, we call Surface#update to make the new frame visible.

This happens at a very high speed, so our eyes don’t see that what we are doing is switching buffers all the time. But updating the screen is relatively time-consuming. At a later stage we will see how we can update only those parts of our surface that have changed since the previous frame.

Since we only call Surface#update once our whole frame is assembled, it also means we have a limited time to perform all our drawing. If it takes a minute to draw a frame then our framerate will be 1 frame per minute. Any gamer who plays your game for more than a minute deserves a reward, for patience or stupidity, whichever comes first.

Exercises

  1. In the last program, experiement with the number of pixels to plot in the draw method. Try a relatively low number such as 10. Also try higher number such as 1000 or 10000. What do you think would happen to the program if you choose a very large number?
  2. In the Surface#set_pixel method we are calling Surface#draw_box with two points that are the same. Modify the method so that the second point is 5×5 points away from the first. What happens to the program.

Conclusion

Now you are able to create a Rubygame screen and plot pixels onto it. There is actually quite a bit we can do armed with only that knowledge. We will continue plotting pixels for a little longer, while we look at some interesting events that we can let our program respond to.

2007.12.19

Ghosts ‘n Goblins

Filed under: Commodore 64, Computer Games, Retrogames — Tags: , , , , , — Lorenzo E. Danielsson @ 21:34

I played Ghosts ‘n Goblins for an hour or two today and my mind just drifted back to the good old times. *sob, sob*

Ghosts ‘n Goblins: title screen

The graphics! The music! The atmosphere! Even, the title screen! (You kids of today certainly will not understand..)

Ghosts ‘n Goblins: croaking at the very beginning

I obviously haven’t played this for like 15 years or so. Here I am croaking at the very beginning of the game.

Older Posts »

Blog at WordPress.com.