Galton box animation: Difference between revisions

Content added Content deleted
(Updated D entry)
(Updated D entry)
Line 405: Line 405:
enum centerH = pinsBaseW + (boxW - (pinsBaseW * 2 - 1)) / 2 - 1;
enum centerH = pinsBaseW + (boxW - (pinsBaseW * 2 - 1)) / 2 - 1;


enum Cell : char { empty = ' ',
alias CellBaseType = char;
enum Cell : CellBaseType { empty = ' ',
ball = 'o',
ball = 'o',
wall = '|',
wall = '|',
corner = '+',
corner = '+',
floor = '-',
floor = '-',
pin = '.' }
pin = '.' }


Cell[boxW][boxH] box; // Galton box. Will be printed upside-down.
Cell[boxW][boxH] box; // Galton box. Will be printed upside-down.
Line 418: Line 417:
int x, y; // Position.
int x, y; // Position.


this(in int x_, in int y_) nothrow
this(in int x_, in int y_) nothrow @safe @nogc
in {
in {
assert(box[y_][x_] == Cell.empty);
assert(box[y_][x_] == Cell.empty);
Line 436: Line 435:
return; // Reached the bottom of the box.
return; // Reached the bottom of the box.


with (Cell) {
final switch (box[y - 1][x]) with (Cell) {
final switch (box[y - 1][x]) {
case empty:
case empty:
box[y][x] = Cell.empty;
box[y][x] = Cell.empty;
y--;
y--;
box[y][x] = Cell.ball;
break;
case ball, wall, corner, floor:
// It's frozen. (It always piles on other balls).
break;
case pin:
box[y][x] = Cell.empty;
y--;
if (box[y][x - 1] == Cell.empty && box[y][x + 1] == Cell.empty) {
x += uniform(0, 2) * 2 - 1;
box[y][x] = Cell.ball;
box[y][x] = Cell.ball;
break;
return;
case ball, wall, corner, floor:
} else if (box[y][x - 1] == Cell.empty) {
// It's frozen. (It always piles on other balls).
x++;
break;
} else {
case pin:
x--;
box[y][x] = Cell.empty;
}
y--;
box[y][x] = Cell.ball;
if (box[y][x - 1] == Cell.empty &&
break;
box[y][x + 1] == Cell.empty) {
x += uniform(0, 2) * 2 - 1;
box[y][x] = Cell.ball;
return;
} else if (box[y][x - 1] == Cell.empty)
x++;
else
x--;
box[y][x] = Cell.ball;
break;
}
}
}
}
}
Line 467: Line 464:
void initializeBox() {
void initializeBox() {
// Set ceiling and floor:
// Set ceiling and floor:
box[0][] = (Cell.corner ~ [Cell.floor].replicate(boxW - 2)
box[0][] = Cell.corner ~ [Cell.floor].replicate(boxW - 2) ~ Cell.corner;
~ Cell.corner)[];
box[$ - 1][] = box[0][];
box[$ - 1][] = box[0][];


// Set walls:
// Set walls:
foreach (r; 1 .. boxH - 1)
foreach (immutable r; 1 .. boxH - 1)
box[r][0] = box[r][$ - 1] = Cell.wall;
box[r][0] = box[r][$ - 1] = Cell.wall;


Line 478: Line 474:
foreach (immutable nPins; 1 .. pinsBaseW + 1)
foreach (immutable nPins; 1 .. pinsBaseW + 1)
foreach (pin; 0 .. nPins)
foreach (pin; 0 .. nPins)
box[boxH - 2 - nPins][centerH + 1 - nPins + pin * 2]
box[boxH - 2 - nPins][centerH + 1 - nPins + pin * 2] = Cell.pin;
= Cell.pin;
}
}


void drawBox() {
void drawBox() {
foreach_reverse (ref row; box)
foreach_reverse (const ref row; box)
writeln(cast(CellBaseType[])row);
writefln("%(%c%)", row);
}
}


Line 495: Line 490:
if (i < nMaxBalls)
if (i < nMaxBalls)
balls ~= Ball(centerH, boxH - 2); // Add ball.
balls ~= Ball(centerH, boxH - 2); // Add ball.
drawBox();
drawBox;


// Next step for the simulation.
// Next step for the simulation.