-
Notifications
You must be signed in to change notification settings - Fork 33
/
sandpiles.pl
executable file
·95 lines (69 loc) · 2.42 KB
/
sandpiles.pl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#!/usr/bin/perl
# Simulate the toppling of sandpiles.
# See also:
# https://en.wikipedia.org/wiki/Abelian_sandpile_model
# https://www.youtube.com/watch?v=1MtEUErz7Gg -- Sandpiles - Numberphile
# https://www.youtube.com/watch?v=diGjw5tghYU -- Coding Challenge #107: Sandpiles (by Daniel Shiffman)
use 5.020;
use strict;
use warnings;
use Imager;
use experimental qw(signatures);
package Sandpile {
sub new ($class, %opt) {
my $state = {
width => 100,
height => 100,
%opt,
};
bless $state, $class;
}
sub create_plane ($self) {
[map { [(0) x $self->{width}] } 1 .. $self->{height}];
}
sub topple ($self, $plane) {
my $nextplane = $self->create_plane;
foreach my $y (0 .. $self->{height} - 1) {
foreach my $x (0 .. $self->{width} - 1) {
my $pile = $plane->[$y][$x];
if ($pile < 4) {
$nextplane->[$y][$x] = $pile;
}
}
}
foreach my $y (1 .. $self->{height} - 2) {
foreach my $x (1 .. $self->{width} - 2) {
my $pile = $plane->[$y][$x];
if ($pile >= 4) {
$nextplane->[$y][$x] += $pile - 4;
$nextplane->[$y - 1][$x]++;
$nextplane->[$y + 1][$x]++;
$nextplane->[$y][$x - 1]++;
$nextplane->[$y][$x + 1]++;
}
}
}
return $nextplane;
}
sub generate ($self, $pile_of_sand, $topple_times) {
my $plane = $self->create_plane;
$plane->[$self->{height} / 2][$self->{width} / 2] = $pile_of_sand;
for (1 .. $topple_times) {
$plane = $self->topple($plane);
}
my $img = Imager->new(xsize => $self->{width}, ysize => $self->{height});
my @colors = map { Imager::Color->new($_) } ('black', 'blue', 'green', 'white');
foreach my $y (0 .. $self->{height} - 1) {
foreach my $x (0 .. $self->{width} - 1) {
my $pile = $plane->[$y][$x];
if ($pile <= 3) {
$img->setpixel(x => $x, y => $y, color => $colors[$pile]);
}
}
}
return $img;
}
}
my $obj = Sandpile->new;
my $img = $obj->generate(10**5, 10**4);
$img->write(file => 'sandpiles.png');