How to resolve the algorithm Galton box animation step by step in the D programming language
How to resolve the algorithm Galton box animation step by step in the D programming language
Table of Contents
Problem Statement
A Galton device Sir Francis Galton's device is also known as a bean machine, a Galton Board, or a quincunx.
In a Galton box, there are a set of pins arranged in a triangular pattern. A number of balls are dropped so that they fall in line with the top pin, deflecting to the left or the right of the pin. The ball continues to fall to the left or right of lower pins before arriving at one of the collection points between and to the sides of the bottom row of pins. Eventually the balls are collected into bins at the bottom (as shown in the image), the ball column heights in the bins approximate a bell curve. Overlaying Pascal's triangle onto the pins shows the number of different paths that can be taken to get to each bin.
Generate an animated simulation of a Galton device.
Let's start with the solution:
Step by Step solution about How to resolve the algorithm Galton box animation step by step in the D programming language
Source code in the d programming language
import std.stdio, std.algorithm, std.random, std.array;
enum int boxW = 41, boxH = 37; // Galton box width and height.
enum int pinsBaseW = 19; // Pins triangle base size.
enum int nMaxBalls = 55; // Number of balls.
static assert(boxW >= 2 && boxH >= 2);
static assert((boxW - 4) >= (pinsBaseW * 2 - 1));
static assert((boxH - 3) >= pinsBaseW);
enum centerH = pinsBaseW + (boxW - (pinsBaseW * 2 - 1)) / 2 - 1;
enum Cell : char { empty = ' ',
ball = 'o',
wall = '|',
corner = '+',
floor = '-',
pin = '.' }
Cell[boxW][boxH] box; // Galton box. Will be printed upside-down.
struct Ball {
int x, y; // Position.
this(in int x_, in int y_) nothrow @safe @nogc
in {
assert(box[y_][x_] == Cell.empty);
} body {
this.x = x_;
this.y = y_;
box[y][x] = Cell.ball;
}
nothrow const @safe @nogc invariant {
assert(x >= 0 && x < boxW && y >= 0 && y < boxH);
assert(box[y][x] == Cell.ball);
}
void doStep() {
if (y <= 0)
return; // Reached the bottom of the box.
final switch (box[y - 1][x]) with (Cell) {
case empty:
box[y][x] = Cell.empty;
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;
return;
} else if (box[y][x - 1] == Cell.empty) {
x++;
} else {
x--;
}
box[y][x] = Cell.ball;
break;
}
}
}
void initializeBox() {
// Set ceiling and floor:
box[0][] = Cell.corner ~ [Cell.floor].replicate(boxW - 2) ~ Cell.corner;
box[$ - 1][] = box[0][];
// Set walls:
foreach (immutable r; 1 .. boxH - 1)
box[r][0] = box[r][$ - 1] = Cell.wall;
// Set pins:
foreach (immutable nPins; 1 .. pinsBaseW + 1)
foreach (pin; 0 .. nPins)
box[boxH - 2 - nPins][centerH + 1 - nPins + pin * 2] = Cell.pin;
}
void drawBox() {
foreach_reverse (const ref row; box)
writefln("%(%c%)", row);
}
void main() {
initializeBox;
Ball[] balls;
foreach (const i; 0 .. nMaxBalls + boxH) {
writefln("\nStep %d:", i);
if (i < nMaxBalls)
balls ~= Ball(centerH, boxH - 2); // Add ball.
drawBox;
// Next step for the simulation.
// Frozen balls are kept in balls array for simplicity.
foreach (ref b; balls)
b.doStep;
}
}
You may also check:How to resolve the algorithm Ternary logic step by step in the ALGOL 68 programming language
You may also check:How to resolve the algorithm Collections step by step in the EchoLisp programming language
You may also check:How to resolve the algorithm Reflection/List properties step by step in the Factor programming language
You may also check:How to resolve the algorithm Doubly-linked list/Traversal step by step in the C programming language
You may also check:How to resolve the algorithm Angle difference between two bearings step by step in the Racket programming language