Skip to content

Instantly share code, notes, and snippets.

@JoshCheek
Last active November 17, 2017 17:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JoshCheek/f3aec0625d1f13d4575b8619ef404721 to your computer and use it in GitHub Desktop.
Save JoshCheek/f3aec0625d1f13d4575b8619ef404721 to your computer and use it in GitHub Desktop.
Drawing Sandpiles
# Video: https://t.co/FCdLtWceez
# Based on: https://www.youtube.com/watch?v=1MtEUErz7Gg
# This one is better than mine: http://people.reed.edu/~davidp/web_sandpiles/
require 'graphics'
class Sandpile < Graphics::Simulation
AVERAGE_HEIGHT = 2.1 # he mentioned this in the video
def initialize(n)
super 800, 800
register_color :sand_zero, 20, 79, 245 # blue
register_color :sand_one, 151, 198, 250 # sky
register_color :sand_two, 250, 225, 76 # yellow
register_color :sand_three, 112, 20, 12 # red
# color.default_proc = lambda { |rgb| rgb }
@n = n
ideal_diameter = 2 * Math.sqrt(n / AVERAGE_HEIGHT / Math::PI)
@pile_side = ideal_diameter.ceil.succ
@cell_side = w / @pile_side
@offset = (w - @pile_side*@cell_side)/2
@sandpile = Array.new(@pile_side) { Array.new @pile_side, 0 }
@sandpile[@pile_side/2][@pile_side/2] = n
# nil while increment! @sandpile
draw_pile @sandpile
end
def draw(i)
return if @n.zero?
@n -= 1
draw_pile @sandpile
increment! @sandpile
end
def draw_pile(sandpile)
sandpile.each_with_index do |row, y|
row.each_with_index { |cell, x| draw_cell x, y, sand_color(cell) }
end
end
def draw_cell(x, y, color)
rect @offset+x*@cell_side, @offset+y*@cell_side, @cell_side, @cell_side, color, :fill
end
def increment!(sandpile)
pending = Array.new
sandpile.each_with_index do |row, y|
row.each_with_index do |cell, x|
next if cell < 4
pending << [y, x, -4]
pending << [y-1, x, 1] if 0 < y
pending << [y+1, x, 1] if y.succ < sandpile.length
pending << [y, x-1, 1] if 0 < x
pending << [y, x+1, 1] if x.succ < row.length
end
end
pending.each { |y, x, delta| sandpile[y][x] += delta }
pending.any?
end
def sand_color(num_grains)
case num_grains
when 0 then :sand_zero
when 1 then :sand_one
when 2 then :sand_two
else :sand_three
end
end
end
Sandpile.new(2**15).run
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment