def get_bitmap
  a = <<HERE
....................
.oooooo.............
.o.....oooo.........
..o........ooo......
..o...........o.....
..o...........o.....
...o...oo.....o.....
..o...o.o.....o.....
..o...ooo.....oo....
..o.............o...
..o.......o.....o...
..oo.....o.o....o...
....o....o.ooooo....
....o....o..........
....o.....oooooo....
....ooo.........o...
......ooo....ooo....
.........o...o......
.......oooooo.......
....................
HERE
  a.split("\n").map {|i| i.split("")}
end

def legal(x,y)
  x < 20 and y < 20 and x >= 0 and y >= 0 and $bmp[y][x] != "o" and $bmp[y][x] != "*"
end

def fill_step(meth)
  x,y = meth == :stack ? $queue.pop : $queue.shift
  if legal(x,y)
    fill_cell(x, y)
    [[x-1,y], [x,y-1], [x,y+1], [x+1, y]].each do |i,j| 
      $queue.push [i,j] if legal(i,j)
    end
  end
end

def fill_cell(x, y)
  cfill(y, x, "#7777dd")
  $bmp[y][x] = "*"
end

def cfill(col, row, c)
  $canvas.fill c
  $canvas.rect :left => row*30, :right => (row+1)*30, :top => col*30, :bottom => (col+1)*30
  $canvas.show
end

def reset_grid
  $bmp = get_bitmap
  $bmp.each_with_index {|row, j|
    row.each_with_index {|cell, i|
      c = cell == "o" ? "#111166" : "#eeeecc" 
      cfill(j, i, c)
    }
  }
  $queue = []
end

def run_animation(meth)
  $running ? return : $running = true
  reset_grid
  x, y = rand(20), rand(20)
  while $bmp[y][x] != "."
    x, y = rand(20), rand(20)
  end
  $queue.push [x, y]
  @anim = animate(20) do
    if $queue.empty? 
      @anim.stop
      $running = false
    else 
      fill_step(meth)
    end
  end
end

Shoes.app :width => 600, :height => 700, :resizable => false, :title => "Floodfill" do 
  $canvas = image 600, 601, :top => 0, :left => 0 
  reset_grid

  stack :height => 79, :top => 620 do
    flow do
      button("Stack") { run_animation(:stack) }
      button("Queue") { run_animation(:queue) }
      button("Clear") { reset_grid }
      button("Quit")  { quit }
    end
  end
end
