DEV Community

Cover image for Basic painting with Ruby: implementing a flood-fill algorithm with DragonRuby GTK
Cristian Molina
Cristian Molina

Posted on

Basic painting with Ruby: implementing a flood-fill algorithm with DragonRuby GTK

Continuing with my learning and experimentation with DRGTK, I wanted to implement a flood-fill algorithm on a canvas with some drawings.

This idea came from an old interview exercise I did some years ago.

The Flood Fill algorithm is commonly used in graphics software to fill an area with a specific color. It’s what powers the paint bucket tool.

So having a canvas and a pair of coordinates on that, the initial color is the one located in this location and the plan is to change it to another color, filling all adjacent pixels with the original color with the new one until a different one from the original one is reached.
My implementation is a recursive one:

 def paint(x:, y:, base_color:, new_color:, sleep_time: 0)
   return if new_color == base_color

   coords_inside_matrix = y >= 0 && y < map.size && x >= 0 && x < map[0].size

   pixel_should_be_painted = coords_inside_matrix && map[y][x] == base_color

   return unless pixel_should_be_painted

   map[y][x] = new_color  # paint the cell

   paint(x: x+1, y: y, base_color: base_color, new_color: new_color)
   paint(x: x, y: y+1, base_color: base_color, new_color: new_color)
   paint(x: x-1, y: y, base_color: base_color, new_color: new_color)
   paint(x: x, y: y-1, base_color: base_color, new_color: new_color)
 end
Enter fullscreen mode Exit fullscreen mode

I worked on my solution using TDD, with Minitest spec tests, so it was easier to start with basic scenarios and also printed it while it moved the brush position recursively.

# Running:

paint(2-1)
  changing x:2 y:1
[0, 0, 0, 0, 0]
[0, 0, 8, 0, 0]
[0, 0, 2, 3, 8]
[2, 2, 2, 0, 0]
[0, 0, 2, 0, 5]
paint(2-2)
  changing x:2 y:2
[0, 0, 0, 0, 0]
[0, 0, 8, 0, 0]
[0, 0, 8, 3, 8]
[2, 2, 2, 0, 0]
[0, 0, 2, 0, 5]
paint(2-3)
  changing x:2 y:3
[0, 0, 0, 0, 0]
[0, 0, 8, 0, 0]
[0, 0, 8, 3, 8]
[2, 2, 8, 0, 0]
[0, 0, 2, 0, 5]
paint(2-4)
  changing x:2 y:4
[0, 0, 0, 0, 0]
[0, 0, 8, 0, 0]
[0, 0, 8, 3, 8]
[2, 2, 8, 0, 0]
[0, 0, 8, 0, 5]
Enter fullscreen mode Exit fullscreen mode

On the Dragon Ruby side, I drew the matrix as a canvas and queried the mouse functions to get the cell position to paint or to change the color of the brush by clicking on a color palette box.
There is no pencil functionality so the canvas starts with a default drawing to play with it:

Application screeshot

...and that's basically it. Not sure what will be next on this series. There is a game jam with Dragon Ruby starting soon, maybe I could participate on it :) .

Links to the app and code:

Happy hacking!

Top comments (1)

Collapse
 
amirrajan profile image
Amir Rajan

If you’re rendering a lot of solids, use the sprites output. It’s significantly faster because of texture caching.

args.outputs.sprites << { 
  x: 0,
  y: 0, 
  w: 32,
  h: 32, 
  path: :solid, 
  r: 0, 
  g: 0, 
  b: 255
 }
Enter fullscreen mode Exit fullscreen mode