Galton box animation: Difference between revisions

m
 
(23 intermediate revisions by 13 users not shown)
Line 2:
[[Category:Randomness]]
{{omit from|GUISS}}
[[File:Galtonbox-Unicon.PNG|thumb|Example of a Galton Box at the end of animation.]]
 
Generate an animated simulation of [[wp:Bean_machine|Sir Francis Galton's device]].
An example can be found to the right. [[File:Galtonbox-Unicon.PNG|thumb|Example of a Galton Box at the end of animation.]]
 
A   '''Galton device'''   [[wp:Bean_machine|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 subsequent pins before arriving at one of the collection points between and to the sides of the bottom row of pins.
 
For the purpose of this task the box should have at least 5 pins on the bottom row.
Your solution can use graphics or ASCII animation.
Provide a sample of the output/display such as a screenshot.
 
;Description of operation:
Your solution can have either one or more balls in flight at the same time.
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.
If multiple balls are in flight, ensure they don't interfere with each other.
 
Eventually the balls are collected into bins at the bottom   (as shown in the image),   the ball column heights in the bins approximate a   [https://mathworld.wolfram.com/NormalDistribution.html bell curve].   Overlaying   [https://en.wikipedia.org/wiki/Pascal%27s_triangle Pascal's triangle]   onto the pins shows the number of different paths that can be taken to get to each bin.
Your solution should allow users to specify the number of balls or it should run until full or a preset limit. Optionally, display the number of balls.
 
 
;Task:
Generate an animated simulation of a Galton device.
 
 
;Task requirements:
::*   The box should have at least 5 pins on the bottom row.
::*   A solution can use graphics or ASCII animation.
::*   Provide a sample of the output/display such as a screenshot.
::*   There can be one or more balls in flight at the same time.
::*   If multiple balls are in flight, ensure they don't interfere with each other.
::*   A solution should allow users to specify the number of balls, or it should run until full or a preset limit.
::*   Optionally,   display the number of balls.
<br><br>
 
=={{header|AutoHotkey}}==
Uses an edit box for the (text based) animation
<langsyntaxhighlight AutoHotkeylang="autohotkey">AutoTrim Off
; User settings
bottompegs := 6
Line 108 ⟶ 118:
StringTrimRight, out, out, 1 ; removes the last newline
return out
}</langsyntaxhighlight>While the number of pegs, and falling space are configurable, here's output shortly after starting one configuration:
<pre>
*
Line 126 ⟶ 136:
=={{header|BASIC256}}==
[[File:Galton box BASIC-256.gif|right|150px|thumb|Galton box animation created with BASIC-256]]
<langsyntaxhighlight lang="basic256">graphsize 150,125
fastgraphics
color black
Line 241 ⟶ 251:
iters = iters + 1
refresh
return</langsyntaxhighlight>
 
=={{header|BBC BASIC}}==
{{works with|BBC BASIC for Windows}}
[[Image:quincunx_bbc.gif|right]]
<langsyntaxhighlight lang="bbcbasic"> maxBalls% = 10
DIM ballX%(maxBalls%), ballY%(maxBalls%)
Line 294 ⟶ 304:
NEXT
tick% += 1
UNTIL FALSE</langsyntaxhighlight>
 
=={{header|C}}==
<langsyntaxhighlight lang="c">#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Line 386 ⟶ 396:
 
return 0;
}</langsyntaxhighlight>
Sample out put at begining of a run:<pre>
*
Line 401 ⟶ 411:
=={{header|C++}}==
Windows GDI version.
<langsyntaxhighlight lang="cpp">
#include "stdafx.h"
#include <windows.h>
Line 620 ⟶ 630:
return myWnd.Run( hInstance );
}
</syntaxhighlight>
</lang>
 
=={{header|Clojure}}==
<syntaxhighlight lang="clojure">(def n 8)
(def balls* (atom [{:x n :y 0}]))
(def board* (atom (vec (repeat (inc n) (vec (repeat (inc (* 2 n)) " "))))))
(doseq [y (range (inc n))
i (range y)]
(swap! board* assoc-in [y (+ (- n y) (* 2 i) 1)] "^"))
(def histogram* (atom (vec (repeat (inc (* 2 n)) 0))))
 
(loop [frame 0]
(print "\033[0;0f\033[2J")
(doseq [row @board*] (println (apply str row)))
(let [depth (inc (apply max (map #(quot % 8) @histogram*)))]
(dotimes [y depth]
(doseq [i @histogram*]
(print (nth " ▁▂▃▄▅▆▇█" (min 8 (max 0 (- i (* (- depth y 1) 8)))))))
(print "\n")))
(println "\n")
(flush)
(doseq [[i {:keys [x y]}] (map-indexed vector @balls*)]
(swap! board* assoc-in [y x] " ")
(let [[new-x new-y] [(if (< 0.5 (rand)) (inc x) (dec x)) (inc y)]]
(if (> new-y n)
(do (swap! histogram* update x inc)
(swap! balls* assoc i {:x n :y 0}))
(do (swap! board* assoc-in [new-y new-x] "*")
(swap! balls* assoc i {:x new-x :y new-y})))))
(Thread/sleep 200)
(when (< (count @balls*) n) (swap! balls* conj {:x n :y 0}))
(when (< frame 200) (recur (inc frame))))
</syntaxhighlight>
 
Sample output:
<pre>
^*
^*^
^ ^ ^
^ ^ ^*^
^*^ ^ ^ ^
^ ^ ^*^ ^ ^
^ ^ ^ ^*^ ^ ^
^ ^ ^*^ ^ ^ ^ ^
▅ ▅
█ █ ▂
█ █ █
▃ █ █ █
█ █ █ █ █
▁ ▇ █ █ █ █ █ ▃ ▁
</pre>
 
=={{header|D}}==
To keep the code simpler some corner cases are ignored.
<langsyntaxhighlight lang="d">import std.stdio, std.algorithm, std.random, std.array;
 
enum int boxW = 41, boxH = 37; // Galton box width and height.
Line 727 ⟶ 787:
b.doStep;
}
}</langsyntaxhighlight>
{{out}}
<pre>
Line 850 ⟶ 910:
| o o o o o o o o o o o |
+---------------------------------------+</pre>
 
=={{header|EasyLang}}==
[https://easylang.dev/show/#cod=dVNdc4IwEHzPr9iZvqgMlCDYOlP8Ix0f+IhtFBMnYIV/3wkEJIAvcLcc2d27S9mUqOStYKeKvIHclMyQq+Rx46KEB48AOEkFjkpirzMDnDXADQDgKv8YVjSCC77GBls4OGODHXj7dBA8izOusoLB9z4M1vJ4xCOZLKRCFEWkV0HSJLv8KHkXOVyqRRZMIJX19xHUb5NR2HRhb6X8lY9U1jMn1DfENeJBII2m/jQLP05M1qC+D7d1Fy76CqauWi1c8Oq1kI4KMQZlo1Sf8Ya+OeGWSIGKX5nSH/kJ6b1sdC0SkUMlIueiQogYtD+9K6AjgzZ9d85EgiUk/LTQpkMDC0wVSy4DS9+B/s2Kktl6jDnduYIlrRszsdfTGk1EK8YBtodW2FeMaDfX60wF9/VXmWM3s9MyOjG22GDVtzXABgFcbNez2q4ltYV7z2zk37Dn2tCqhgsarfGOZcnhouRDjP0Obrc4eX3U2/hCkT/Fh3+ceDytgWD4frA25FkieLUAz8Y/a4GdjUJzsxrrui1fJ6DbffgeJR4xMSH/ Run it]
 
<syntaxhighlight>
sys topleft
#
proc drawpins . .
for i to 9
for j to i
move (15 - i) * 3 + j * 6 i * 6 + 2
circle 0.7
.
.
.
color 555
drawpins
background -1
#
len box[] 10
len x[] 10
len y[] 10
#
proc showbox . .
for i to 10
x = i * 6 + 15
for j to box[i]
move x 100 - j * 4 + 2
circle 2
.
.
.
proc init . .
for i to 10
box[i] = 0
x[i] = 0
.
.
#
color 543
on timer
if busy = 0 and randint 4 = 1
busy = 1
for i to 10
if x[i] = 0
x[i] = 48
y[i] = 2
break 1
.
.
else
busy = 0
.
clear
showbox
for i to 10
x = x[i]
if x > 0
if y[i] <= 56
y[i] += 2
if y[i] mod 6 = 2
x += 3 * (randint 2 * 2 - 3)
x[i] = x
.
else
idx = (x - 15) / 6
y[i] += 4
if y[i] >= 96 - box[idx] * 4
x[i] = 0
box[idx] += 1
if box[idx] > 10
init
break 1
.
.
.
move x y[i]
circle 2
.
.
timer 0.1
.
timer 0
</syntaxhighlight>
 
=={{header|Elm}}==
<langsyntaxhighlight lang="elm">import Html.App exposing (program)
import Time exposing (Time, every, millisecond)
import Color exposing (Color, black, red, blue, green)
Line 1,061 ⟶ 1,205:
, update = update
, subscriptions = subscriptions
}</langsyntaxhighlight>
 
Link to live demo: http://dc25.github.io/galtonBoxAnimationElm/ . Follow the link, enter a number and press the GO button.
Line 1,067 ⟶ 1,211:
=={{header|Factor}}==
{{works with|Factor|0.99 development release 2019-03-17}}
<langsyntaxhighlight lang="factor">USING: accessors arrays calendar colors combinators
combinators.short-circuit fonts fry generalizations kernel
literals locals math math.ranges math.vectors namespaces opengl
Line 1,175 ⟶ 1,319:
{ window-controls
{ normal-title-bar close-button minimize-button } }
} <galton-gadget> >>gadgets ;</langsyntaxhighlight>
{{out}}
Image taken from the program mid-animation: [https://i.imgur.com/E2ge7LE.png]
Line 1,181 ⟶ 1,325:
=={{header|Go}}==
{{trans|D}}
<langsyntaxhighlight lang="go">package main
 
import (
Line 1,307 ⟶ 1,451:
}
}
}</langsyntaxhighlight>
 
{{out}}
Line 1,353 ⟶ 1,497:
 
=={{header|Haskell}}==
<langsyntaxhighlight lang="haskell">import Data.Map hiding (map, filter)
import Graphics.Gloss
import Control.Monad.Random
Line 1,399 ⟶ 1,543:
where balls = mapM makeBall [1..]
makeBall y = Ball (0, y) <$> randomTurns
randomTurns = filter (/=0) <$> getRandomRs (-1, 1)</langsyntaxhighlight>
 
=={{header|Icon}} and {{header|Unicon}}==
Line 1,405 ⟶ 1,549:
[[File:Galtonbox-Unicon.PNG|thumb|right]]
 
<langsyntaxhighlight Iconlang="icon">link graphics
 
global pegsize, pegsize2, height, width, delay
Line 1,469 ⟶ 1,613:
initial ballcounts := table(0)
FillArc(x, height-(ballcounts[x] +:= 1)*pegsize, pegsize, pegsize)
end</langsyntaxhighlight>
 
=={{header|J}}==
Line 1,475 ⟶ 1,619:
First, we need to represent our pins:
 
<langsyntaxhighlight lang="j">initpins=: '* ' {~ '1'&i.@(-@|. |."_1 [: ":@-.&0"1 <:~/~)@i.</langsyntaxhighlight>
 
For example:
 
<langsyntaxhighlight lang="j"> initpins 4
*
* *
* * *
* * * *</langsyntaxhighlight>
 
Note that we could introduce other pin arrangements, for example a Sierpinski triangle:
 
<langsyntaxhighlight lang="j">initSpins=: [: }.@|. (1- 2&^@>:) ]\ [: ,] (,~ ,.~)@]^:[ ,: bind '* '</langsyntaxhighlight>
 
... but this will not be too interesting to use, because of the lack of interior pins for the balls to bounce off of.
Line 1,493 ⟶ 1,637:
Anyways, once we have that, we can add balls to our picture:
 
<langsyntaxhighlight lang="j">init=: ' ',. ' ',.~ ] ,~ ' ',~ ' o' {~ (# ' ' ~: 1&{.)</langsyntaxhighlight>
 
For example:
 
<langsyntaxhighlight lang="j"> 3 (init initpins) 4
o
o
Line 1,505 ⟶ 1,649:
* *
* * *
* * * * </langsyntaxhighlight>
 
Now we just need some way of updating our datastructure.
Line 1,511 ⟶ 1,655:
We will need a mechanism to shift a ball left or right if it's above a pin:
 
<syntaxhighlight lang="text">bounce=: (C.~ ] <"1@:+ 0 1 -~/~ ? @: (2"0))"1 [: I. 'o*'&E."1&.|:</langsyntaxhighlight>
 
And, a mechanism to make the balls fall:
 
<syntaxhighlight lang="text">shift=: 4 :0
fill=. {.0#,y
x |.!.fill y
)</langsyntaxhighlight>
 
And then we need to separate out the balls from the pins, so the balls fall and the pins do not. Note also that in this representation, balls will have to fall when they bounce because they cannot occupy the same space that a pin occupies.
Line 1,524 ⟶ 1,668:
We will also want some way of preventing the balls from falling forever. For this task it's probably sufficient to introduce a baseline just deep enough to hold the stacks (which have passed through the pins) and have later balls instantly fall as close as they can to the baseline once they are passed the pins.
 
<langsyntaxhighlight lang="j">pins=: '*'&=
balls=: 'o'&=
 
Line 1,533 ⟶ 1,677:
clean2=: ({. , -.&' '"1&.|:&.|.@}.)~ 1 + >./@(# | '*' i:~"1 |:)
clean1=: #~ 1 1 -.@E. *./"1@:=&' '
clean=: clean1@clean2</langsyntaxhighlight>
 
For example:
 
<langsyntaxhighlight lang="j"> nxt nxt 3 (init initpins) 4
o
Line 1,545 ⟶ 1,689:
* * *
* * * *
</langsyntaxhighlight>
 
Or, showing an entire animation sequence:
 
<langpre jstyle="overflow-x: scroll; white-space: pre; width: 100%"> nxt&.>^:a: <7 (init ' ',.' ',.~ initpins) 5
┌─────────────┬─────────────┬─────────────┬─────────────┬─────────────┬─────────────┬─────────────┬─────────────┬─────────────┬─────────────┬─────────────┬─────────────┬─────────────┬─────────────┐
│ o │ │ │ │ │ │ │ │ │ │ │ │ │ │
Line 1,565 ⟶ 1,709:
│ * * * * * │ * * * * * │ │ │ │ │ │ │ │ │ │ │ │ │
│ │ │ │ │ │ │ │ │ │ │ │ │ │ │
└─────────────┴─────────────┴─────────────┴─────────────┴─────────────┴─────────────┴─────────────┴─────────────┴─────────────┴─────────────┴─────────────┴─────────────┴─────────────┴─────────────┘</langpre>
 
=={{header|Java}}==
The balls keep track of where they are, and we just have to move them down and print. You might easily adjust this to take command line input for the numbers of pins and balls. I'm sure that this could be a lot shorter...
<langsyntaxhighlight Javalang="java">import java.util.Random;
import java.util.List;
import java.util.ArrayList;
Line 1,699 ⟶ 1,843:
return result;
}
}</langsyntaxhighlight>
{{out}}
When only five balls have begun to fall through the pins:
Line 1,815 ⟶ 1,959:
=={{header|JavaScript}}==
Works with NodeJs
<langsyntaxhighlight JavaScriptlang="javascript">const readline = require('readline');
 
/**
Line 1,940 ⟶ 2,084:
};
 
galtonBox(12, 50);</langsyntaxhighlight>
{{out}}
<pre>
Line 1,980 ⟶ 2,124:
{{works with|Julia|1.0}}
 
<langsyntaxhighlight lang="julia">using Random
function drawball(timer)
global r, c, d
Line 2,006 ⟶ 2,150:
while r < 15 sleep(0.01) end
print("\e[40;1H") # move cursor far down
end</langsyntaxhighlight>
{{out}}
<pre>
Line 2,040 ⟶ 2,184:
=={{header|Kotlin}}==
{{trans|D}}
<langsyntaxhighlight lang="scala">// version 1.2.10
 
import java.util.Random
Line 2,141 ⟶ 2,285:
for (b in balls) b.doStep()
}
}</langsyntaxhighlight>
 
Sample output (showing final step only):
Line 2,187 ⟶ 2,331:
=={{header|Liberty BASIC}}==
User can choose the number of balls to run through the simulation.
<syntaxhighlight lang="lb">
<lang lb>
[setup]
nomainwin
Line 2,311 ⟶ 2,455:
unloadbmp "bg"
end
</syntaxhighlight>
</lang>
 
=={{header|Lua}}==
Uses Bitmap class [[Bitmap#Lua|here]], with an ASCII pixel representation, then extending..
<syntaxhighlight lang="lua">Bitmap.render = function(self)
for y = 1, self.height do
print(table.concat(self.pixels[y], " "))
end
end
 
-- globals (tweak here as desired)
math.randomseed(os.time())
local W, H, MIDX = 15, 40, 7
local bitmap = Bitmap(W, H)
local AIR, PIN, BALL, FLOOR = ".", "▲", "☻", "■"
local nballs, balls = 60, {}
local frame, showEveryFrame = 1, false
 
-- the game board:
bitmap:clear(AIR)
for row = 1, 7 do
for col = 0, row-1 do
bitmap:set(MIDX-row+col*2+1, 1+row*2, PIN)
end
end
for col = 0, W-1 do
bitmap:set(col, H-1, FLOOR)
end
 
-- ball class
Ball = {
new = function(self, x, y, bitmap)
local instance = setmetatable({ x=x, y=y, bitmap=bitmap, alive=true }, self)
return instance
end,
update = function(self)
if not self.alive then return end
self.bitmap:set(self.x, self.y, AIR)
local newx, newy = self.x, self.y+1
local below = self.bitmap:get(newx, newy)
if below==PIN then
newx = newx + (math.random(2)-1)*2-1
end
local there = self.bitmap:get(newx, newy)
if there==AIR then
self.x, self.y = newx, newy
else
self.alive = false
end
self.bitmap:set(self.x, self.y, BALL)
end,
}
Ball.__index = Ball
setmetatable(Ball, { __call = function (t, ...) return t:new(...) end })
 
-- simulation:
local function spawn()
if nballs > 0 then
balls[#balls+1] = Ball(MIDX, 0, bitmap)
nballs = nballs - 1
end
end
 
spawn()
while #balls > 0 do
if frame%2==0 then spawn() end
alive = {}
for _,ball in ipairs(balls) do
ball:update()
if ball.alive then alive[#alive+1]=ball end
end
balls = alive
if frame%50==0 or #alive==0 or showEveryFrame then
print("FRAME "..frame..":")
bitmap:render()
end
frame = frame + 1
end</syntaxhighlight>
{{out}}
<pre>FRAME 50:
. . . . . . . . . . . . . . .
. . . . . . . ☻ . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . ☻ ▲ . . . . . . .
. . . . . . . . . . . . . . .
. . . . . ☻ ▲ . ▲ . . . . . .
. . . . . . . . . . . . . . .
. . . . . ▲ ☻ ▲ . ▲ . . . . .
. . . . . . . . . . . . . . .
. . . . ▲ . ▲ . ▲ ☻ ▲ . . . .
. . . . . . . . . . . . . . .
. . . ▲ . ▲ ☻ ▲ . ▲ . ▲ . . .
. . . . . . . . . . . . . . .
. . ▲ . ▲ . ▲ ☻ ▲ . ▲ . ▲ . .
. . . . . . . . . . . . . . .
. ▲ . ▲ . ▲ . ▲ ☻ ▲ . ▲ . ▲ .
. . . . . . . . . . . . . . .
. . . . ☻ . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . ☻ . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . ☻ . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . ☻ . . . .
. . . . . . . . . . . . . . .
. . . . . . ☻ . . . . . . . .
. . . . . . . . . . . . . . .
. . . . ☻ . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . ☻ . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . ☻ . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . ☻
. . . . . . . . . . . . . . .
. . . . . . ☻ . . . . . . . .
. . . . . . ☻ . . . . . . . .
. . ☻ . . . ☻ . . . ☻ . . . .
. . ☻ . . . ☻ . ☻ . ☻ . . . .
■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■
FRAME 100:
. . . . . . . . . . . . . . .
. . . . . . . ☻ . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . ☻ ▲ . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . ▲ ☻ ▲ . . . . . .
. . . . . . . . . . . . . . .
. . . . . ▲ ☻ ▲ . ▲ . . . . .
. . . . . . . . . . . . . . .
. . . . ▲ . ▲ . ▲ ☻ ▲ . . . .
. . . . . . . . . . . . . . .
. . . ▲ . ▲ . ▲ ☻ ▲ . ▲ . . .
. . . . . . . . . . . . . . .
. . ▲ . ▲ ☻ ▲ . ▲ . ▲ . ▲ . .
. . . . . . . . . . . . . . .
. ▲ ☻ ▲ . ▲ . ▲ . ▲ . ▲ . ▲ .
. . . . . . . . . . . . . . .
. . . . . . ☻ . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . ☻ . . . . . . . .
. . . . . . . . . . . . . . .
. . . . ☻ . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . ☻ . . . . . .
. . . . . . . . . . . . . . .
. . . . . . ☻ . ☻ . . . . . .
. . . . . . ☻ . . . . . . . .
. . . . ☻ . ☻ . . . . . . . .
. . . . . . ☻ . . . . . . . .
. . . . . . ☻ . ☻ . . . . . .
. . . . . . ☻ . . . . . . . .
. . . . ☻ . ☻ . . . . . . . .
. . . . . . ☻ . ☻ . . . . . .
. . . . . . ☻ . ☻ . . . . . .
. . . . . . ☻ . ☻ . ☻ . . . .
. . . . ☻ . ☻ . ☻ . ☻ . . . .
. . ☻ . ☻ . ☻ . ☻ . ☻ . . . .
. . ☻ . ☻ . ☻ . ☻ . ☻ . . . .
☻ . ☻ . ☻ . ☻ . ☻ . ☻ . . . ☻
■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■
FRAME 147:
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . ▲ . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . ▲ . ▲ . . . . . .
. . . . . . . . . . . . . . .
. . . . . ▲ . ▲ . ▲ . . . . .
. . . . . . . . . . . . . . .
. . . . ▲ . ▲ . ▲ . ▲ . . . .
. . . . . . . . . . . . . . .
. . . ▲ . ▲ . ▲ . ▲ . ▲ . . .
. . . . . . . . . . . . . . .
. . ▲ . ▲ . ▲ . ▲ . ▲ . ▲ . .
. . . . . . . . . . . . . . .
. ▲ . ▲ . ▲ . ▲ . ▲ . ▲ . ▲ .
. . . . . . ☻ . . . . . . . .
. . . . . . ☻ . . . . . . . .
. . . . . . ☻ . . . . . . . .
. . . . . . ☻ . . . . . . . .
. . . . . . ☻ . . . . . . . .
. . . . . . ☻ . . . . . . . .
. . . . . . ☻ . . . . . . . .
. . . . . . ☻ . . . . . . . .
. . . . . . ☻ . . . . . . . .
. . . . . . ☻ . ☻ . . . . . .
. . . . . . ☻ . ☻ . . . . . .
. . . . . . ☻ . ☻ . . . . . .
. . . . . . ☻ . ☻ . . . . . .
. . . . . . ☻ . ☻ . . . . . .
. . . . ☻ . ☻ . ☻ . . . . . .
. . . . ☻ . ☻ . ☻ . . . . . .
. . . . ☻ . ☻ . ☻ . . . . . .
. . . . ☻ . ☻ . ☻ . ☻ . . . .
. . ☻ . ☻ . ☻ . ☻ . ☻ . . . .
. . ☻ . ☻ . ☻ . ☻ . ☻ . . . .
. . ☻ . ☻ . ☻ . ☻ . ☻ . . . .
. . ☻ . ☻ . ☻ . ☻ . ☻ . . . .
☻ . ☻ . ☻ . ☻ . ☻ . ☻ . ☻ . ☻
■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■
</pre>
 
=={{header|Mathematica}} / {{header|Wolfram Language}}==
<syntaxhighlight lang="mathematica">ClearAll[MakePathFunction]
MakePathFunction[{path_, acumpath_}] :=
Module[{f1, f2, f3, pf, n = Length[path]},
f1 = MapThread[{#1/2, #2 + 0.5 < z <= #2 + 1} &, {acumpath,
n - Range[n + 1]}];
f2 = MapThread[{#1/2 + #2 Sqrt[1/4 - (z - #3)^2], #3 <
z <= #3 + 1/2} &, {acumpath // Most, path, n - Range[n]}];
f3 = {{acumpath[[-1]]/2, z <= 0}};
pf = Piecewise[Evaluate[Join[f1, f2, f3]], 0];
pf
]
MakeScene[pfs_List, zfinals_List, n_Integer, t_] :=
Module[{durations, accumduration, if, part, fixed, relt},
durations = n - zfinals;
accumduration = Accumulate[Prepend[durations, 0]];
if = Interpolation[{accumduration, Range[Length[zfinals] + 1]} //
Transpose, InterpolationOrder -> 1];
part = Floor[if[t]];
If[part > 0,
fixed = Table[{pfs[[i]], z} /. z -> zfinals[[i]], {i, part - 1}];
,
fixed = {};
];
relt = t - accumduration[[part]];
relt = n - relt;
Append[fixed, {pfs[[part]] /. z -> relt, relt}]
]
SeedRandom[1234];
n = 6;
m = 150;
r = 0.25; (* fixed *)
dots =
Catenate@Table[{# - i/2 - 1/2, n - i} & /@ Range[i], {i, n}];
g = Graphics[Disk[#, r] & /@ dots, Axes -> True];
 
paths = RandomChoice[{-1, 1}, {m, n}];
paths = {#, Accumulate[Prepend[#, 0]]} & /@ paths;
xfinals = paths[[All, 2, -1]];
types = DeleteDuplicates[xfinals];
zfinals = ConstantArray[0, Length[paths]];
Do[
pos = Flatten[Position[xfinals, t]];
zfinals[[pos]] += 0.5 Range[Length[pos]];
,
{t, types}
];
max = Max[zfinals] + 1;
zfinals -= max;
pfs = MakePathFunction /@ paths;
Manipulate[
Graphics[{Disk[#, r] & /@ dots, Red,
Disk[#, r] & /@ MakeScene[pfs, zfinals, n, t]},
PlotRange -> {{-n, n}, {Min[zfinals] - 1, n + 2}},
ImageSize -> 150], {t, 0, Total[n - zfinals] - 0.001}]</syntaxhighlight>
 
=={{header|Nim}}==
{{trans|Go}}
<syntaxhighlight lang="nim">import random, strutils
 
const
BoxW = 41 # Galton box width.
BoxH = 37 # Galton box height.
PinsBaseW = 19 # Pins triangle base.
NMaxBalls = 55 # Number of balls.
 
const CenterH = PinsBaseW + (BoxW - (PinsBaseW * 2 - 1)) div 2 - 1
 
type
 
Cell = enum
cEmpty = " "
cBall = "o"
cWall = "|"
cCorner = "+"
cFloor = "-"
cPin = "."
 
# Galton box. Will be printed upside-down.
Box = array[BoxH, array[BoxW, Cell]]
 
Ball = ref object
x, y: int
 
 
func initBox(): Box =
 
# Set ceiling and floor.
result[0][0] = cCorner
result[0][^1] = cCorner
for i in 1..(BoxW - 2):
result[0][i] = cFloor
result[^1] = result[0]
 
# Set walls.
for i in 1..(BoxH - 2):
result[i][0] = cWall
result[i][^1] = cWall
 
# Set rest to Empty initially.
for i in 1..(BoxH - 2):
for j in 1..(BoxW - 2):
result[i][j] = cEmpty
 
# Set pins.
for nPins in 1..PinsBaseW:
for p in 0..<nPins:
result[BoxH - 2 - nPins][CenterH + 1 - nPins + p * 2] = cPin
 
 
func newBall(box: var Box; x, y: int): Ball =
 
doAssert box[y][x] == cEmpty, "Tried to create a new ball in a non-empty cell"
result = Ball(x: x, y: y)
box[y][x] = cBall
 
 
proc doStep(box: var Box; b: Ball) =
 
if b.y <= 0:
return # Reached the bottom of the box.
 
case box[b.y-1][b.x]
 
of cEmpty:
box[b.y][b.x] = cEmpty
dec b.y
box[b.y][b.x] = cBall
 
of cPin:
box[b.y][b.x] = cEmpty
dec b.y
if box[b.y][b.x-1] == cEmpty and box[b.y][b.x+1] == cEmpty:
inc b.x, 2 * rand(1) - 1
elif box[b.y][b.x-1] == cEmpty:
inc b.x
else:
dec b.x
box[b.y][b.x] = cBall
 
else:
# It's frozen - it always piles on other balls.
discard
 
 
proc draw(box: Box) =
for r in countdown(BoxH - 1, 0):
echo box[r].join()
 
 
#———————————————————————————————————————————————————————————————————————————————————————————————————
 
randomize()
var box = initBox()
var balls: seq[Ball]
 
for i in 0..<(NMaxBalls + BoxH):
 
echo "Step ", i, ':'
if i < NMaxBalls:
balls.add box.newBall(CenterH, BoxH - 2)
box.draw()
 
# Next step for the simulation.
# Frozen balls are kept in balls slice for simplicity.
for ball in balls:
box.doStep(ball)</syntaxhighlight>
 
{{out}}
Sample output (showing last step only):
<pre>Step 91:
+---------------------------------------+
| |
| . |
| . . |
| . . . |
| . . . . |
| . . . . . |
| . . . . . . |
| . . . . . . . |
| . . . . . . . . |
| . . . . . . . . . |
| . . . . . . . . . . |
| . . . . . . . . . . . |
| . . . . . . . . . . . . |
| . . . . . . . . . . . . . |
| . . . . . . . . . . . . . . |
| . . . . . . . . . . . . . . . |
| . . . . . . . . . . . . . . . . |
| . . . . . . . . . . . . . . . . . |
| . . . . . . . . . . . . . . . . . . |
| . . . . . . . . . . . . . . . . . . . |
| |
| |
| |
| o |
| o |
| o |
| o o |
| o o |
| o o o |
| o o o o o |
| o o o o o o o |
| o o o o o o o |
| o o o o o o o o |
| o o o o o o o o o |
| o o o o o o o o o |
+---------------------------------------+</pre>
 
=={{header|Perl}}==
=== translated from Raku ===
Output shows of final state for a run with 50 coins.
{{trans|Raku}}
<langsyntaxhighlight lang="perl">use strict;
use warnings;
 
Line 2,453 ⟶ 3,009:
? not 0 == ($x - $y) % 2
: 0
}</langsyntaxhighlight>
{{out}}
<pre> ^
Line 2,473 ⟶ 3,029:
▀ █ █
</pre>
 
=== native Perl ===
Runs until a bottom column overflows.
<syntaxhighlight lang="perl">#!/usr/bin/perl
 
use strict; # https://rosettacode.org/wiki/Galton_box_animation
use warnings;
$| = 1;
 
my $width = shift // 7;
my $bottom = 15;
my $blank = ' ' x ( 2 * $width + 1 ) . "\n";
my $line = ' ' x $width . '*' . ' ' x $width . "\n";
local $_ = join '', $blank x 5 . $line,
map({ $line =~ s/ \* (.*) /* * $1/; ($blank, $line) } 2 .. $width ),
$blank x $bottom;
 
my $gap = / \n/ && $-[0];
my $gl = qr/.{$gap}/s;
my $g = qr/.$gl/s;
my $center = $gap >> 1;
my %path = ('O* ' => 'O*X', ' *O' => 'X*O');
 
print "\e[H\e[J$_";
while( not /(?:O$g){$bottom}/ )
{
my $changes = s!O($gl)( \* |O\* | \*O)! " $1" .
($path{$2} // (rand(2) < 1 ? "X* " : " *X")) !ge +
s/O($g) / $1X/g +
s/^ {$center}\K ($g $g) /O$1 /;
tr/X/O/;
print "\e[H$_";
$changes or last;
select undef, undef, undef, 0.05;
}</syntaxhighlight>
{{out}}
<pre>
O
*O
* *
O
* * *
*O* * *
* * * * *
O
* * * * * *
* * *O* * * *
O
O
O O
O
O
O
O
O O
O O
O O O
O O O O
O O O O
O O O O
O O O O
O O O O O O
</pre>
 
Line 2,478 ⟶ 3,105:
=== console ===
First, a console version:
<!--<syntaxhighlight lang="phix">(phixonline)-->
<lang Phix>constant balls = 80
<span style="color: #008080;">without</span> <span style="color: #008080;">js</span> <span style="color: #000080;font-style:italic;">-- clear_screen(), text_color(), position(), sleep(), get_key()...</span>
clear_screen()
<span style="color: #008080;">constant</span> <span style="color: #000000;">balls</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">80</span>
sequence screen = repeat(repeat(' ',23),12)
<span style="color: #7060A8;">clear_screen</span><span style="color: #0000FF;">()</span>
& repeat(join(repeat(':',12)),12)
<span style="color: #004080;">sequence</span> <span style="color: #000000;">screen</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #008000;">' '</span><span style="color: #0000FF;">,</span><span style="color: #000000;">23</span><span style="color: #0000FF;">),</span><span style="color: #000000;">12</span><span style="color: #0000FF;">)</span>
& {repeat('.',23)},
<span style="color: #0000FF;">&</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">join</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #008000;">':'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">12</span><span style="color: #0000FF;">)),</span><span style="color: #000000;">12</span><span style="color: #0000FF;">)</span>
Pxy = repeat({12,1},balls)
<span style="color: #0000FF;">&</span> <span style="color: #0000FF;">{</span><span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #008000;">'.'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">23</span><span style="color: #0000FF;">)},</span>
for peg=1 to 10 do
<span style="color: #000000;">Pxy</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">({</span><span style="color: #000000;">12</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">},</span><span style="color: #000000;">balls</span><span style="color: #0000FF;">)</span>
screen[peg+2][13-peg..11+peg] = join(repeat('.',peg))
<span style="color: #008080;">for</span> <span style="color: #000000;">peg</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">10</span> <span style="color: #008080;">do</span>
end for
<span style="color: #000000;">screen</span><span style="color: #0000FF;">[</span><span style="color: #000000;">peg</span><span style="color: #0000FF;">+</span><span style="color: #000000;">2</span><span style="color: #0000FF;">][</span><span style="color: #000000;">13</span><span style="color: #0000FF;">-</span><span style="color: #000000;">peg</span><span style="color: #0000FF;">..</span><span style="color: #000000;">11</span><span style="color: #0000FF;">+</span><span style="color: #000000;">peg</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">join</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #008000;">'.'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">peg</span><span style="color: #0000FF;">))</span>
puts(1,join(screen,"\n"))
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
text_color(BRIGHT_RED)
<span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">join</span><span style="color: #0000FF;">(</span><span style="color: #000000;">screen</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"\n"</span><span style="color: #0000FF;">))</span>
bool moved = true
<span style="color: #000000;">text_color</span><span style="color: #0000FF;">(</span><span style="color: #000000;">BRIGHT_RED</span><span style="color: #0000FF;">)</span>
integer top = ' ' -- (new drop every other iteration)
<span style="color: #004080;">bool</span> <span style="color: #000000;">moved</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">true</span>
while moved or top!=' ' do
<span style="color: #004080;">integer</span> <span style="color: #7060A8;">top</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">' '</span> <span style="color: #000080;font-style:italic;">-- (new drop every other iteration)</span>
moved = false
<span style="color: #008080;">while</span> <span style="color: #000000;">moved</span> <span style="color: #008080;">or</span> <span style="color: #7060A8;">top</span><span style="color: #0000FF;">!=</span><span style="color: #008000;">' '</span> <span style="color: #008080;">do</span>
for i=1 to balls do
<span style="color: #000000;">moved</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">false</span>
integer {Px,Py} = Pxy[i]
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">balls</span> <span style="color: #008080;">do</span>
if Py!=1 or top=' ' then
<span style="color: #004080;">integer</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">Px</span><span style="color: #0000FF;">,</span><span style="color: #000000;">Py</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">Pxy</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span>
integer Dx = 0, Dy = 0
<span style="color: #008080;">if</span> <span style="color: #000000;">Py</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">1</span> <span style="color: #008080;">or</span> <span style="color: #7060A8;">top</span><span style="color: #0000FF;">=</span><span style="color: #008000;">' '</span> <span style="color: #008080;">then</span>
if screen[Py+1,Px]=' ' then -- can vertical?
<span style="color: #004080;">integer</span> <span style="color: #000000;">Dx</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">Dy</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
Dy = 1
<span style="color: #008080;">if</span> <span style="color: #000000;">screen</span><span style="color: #0000FF;">[</span><span style="color: #000000;">Py</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">Px</span><span style="color: #0000FF;">]=</span><span style="color: #008000;">' '</span> <span style="color: #008080;">then</span> <span style="color: #000080;font-style:italic;">-- can vertical?</span>
else
<span style="color: #000000;">Dy</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
Dx = {-1,+1}[rand(2)] -- try l;r or r;l
<span style="color: #008080;">else</span>
if screen[Py+1,Px+Dx]!=' ' then Dx = -Dx end if
<span style="color: #000000;">Dx</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">}[</span><span style="color: #7060A8;">rand</span><span style="color: #0000FF;">(</span><span style="color: #000000;">2</span><span style="color: #0000FF;">)]</span> <span style="color: #000080;font-style:italic;">-- try l;r or r;l</span>
if screen[Py+1,Px+Dx]==' ' then
<span style="color: #008080;">if</span> <span style="color: #000000;">screen</span><span style="color: #0000FF;">[</span><span style="color: #000000;">Py</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">Px</span><span style="color: #0000FF;">+</span><span style="color: #000000;">Dx</span><span style="color: #0000FF;">]!=</span><span style="color: #008000;">' '</span> <span style="color: #008080;">then</span> <span style="color: #000000;">Dx</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">Dx</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
Dy = 1
<span style="color: #008080;">if</span> <span style="color: #000000;">screen</span><span style="color: #0000FF;">[</span><span style="color: #000000;">Py</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">Px</span><span style="color: #0000FF;">+</span><span style="color: #000000;">Dx</span><span style="color: #0000FF;">]==</span><span style="color: #008000;">' '</span> <span style="color: #008080;">then</span>
end if
<span style="color: #000000;">Dy</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
end if
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
if Dy then
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
position(Py,Px) puts(1," ") screen[Py,Px] = ' '
<span style="color: #008080;">if</span> <span style="color: #000000;">Dy</span> <span style="color: #008080;">then</span>
Px += Dx
<span style="color: #7060A8;">position</span><span style="color: #0000FF;">(</span><span style="color: #000000;">Py</span><span style="color: #0000FF;">,</span><span style="color: #000000;">Px</span><span style="color: #0000FF;">)</span> <span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">" "</span><span style="color: #0000FF;">)</span> <span style="color: #000000;">screen</span><span style="color: #0000FF;">[</span><span style="color: #000000;">Py</span><span style="color: #0000FF;">,</span><span style="color: #000000;">Px</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">' '</span>
Py += Dy
<span style="color: #000000;">Px</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">Dx</span>
position(Py,Px) puts(1,"o") screen[Py,Px] = 'o'
<span style="color: #000000;">Py</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">Dy</span>
Pxy[i] = {Px,Py}
<span style="color: #7060A8;">position</span><span style="color: #0000FF;">(</span><span style="color: #000000;">Py</span><span style="color: #0000FF;">,</span><span style="color: #000000;">Px</span><span style="color: #0000FF;">)</span> <span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"o"</span><span style="color: #0000FF;">)</span> <span style="color: #000000;">screen</span><span style="color: #0000FF;">[</span><span style="color: #000000;">Py</span><span style="color: #0000FF;">,</span><span style="color: #000000;">Px</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">'o'</span>
moved = true
<span style="color: #000000;">Pxy</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">Px</span><span style="color: #0000FF;">,</span><span style="color: #000000;">Py</span><span style="color: #0000FF;">}</span>
if Py=2 then top = 'o' end if
<span style="color: #000000;">moved</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">true</span>
end if
<span style="color: #008080;">if</span> <span style="color: #000000;">Py</span><span style="color: #0000FF;">=</span><span style="color: #000000;">2</span> <span style="color: #008080;">then</span> <span style="color: #7060A8;">top</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">'o'</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
end if
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
end for
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
position(26,1)
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
sleep(0.2)
<span style="color: #7060A8;">position</span><span style="color: #0000FF;">(</span><span style="color: #000000;">26</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span>
if get_key()!=-1 then exit end if
<span style="color: #7060A8;">sleep</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0.2</span><span style="color: #0000FF;">)</span>
top = screen[2][12]
<span style="color: #008080;">if</span> <span style="color: #7060A8;">get_key</span><span style="color: #0000FF;">()!=-</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span> <span style="color: #008080;">exit</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
end while</lang>
<span style="color: #7060A8;">top</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">screen</span><span style="color: #0000FF;">[</span><span style="color: #000000;">2</span><span style="color: #0000FF;">][</span><span style="color: #000000;">12</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<!--</syntaxhighlight>-->
{{out}}
<pre>
Line 2,551 ⟶ 3,181:
Also, here is a slightly nicer and resize-able gui version:
{{libheader|Phix/pGUI}}
{{libheader|Phix/online}}
<lang Phix>-- demo\rosetta\GaltonBox.exw
You can run this online [http://phix.x10.mx/p2js/galtonbox.htm here].
constant TITLE = "Galton Box"
<!--<syntaxhighlight lang="phix">(phixonline)-->
 
<span style="color: #000080;font-style:italic;">--
include pGUI.e
-- demo\rosetta\GaltonBox.exw
 
-- ==========================
Ihandle dlg, canvas, timershow
--
cdCanvas cddbuffer, cdcanvas
-- Author Pete Lomax, May 2017
 
--</span>
integer brem = 80
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
sequence balls = {{0,1,0}}
<span style="color: #008080;">constant</span> <span style="color: #000000;">TITLE</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"Galton Box"</span>
sequence bins = repeat(0,8)
 
<span style="color: #008080;">include</span> <span style="color: #000000;">pGUI</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span>
function redraw_cb(Ihandle /*ih*/, integer /*posx*/, integer /*posy*/)
integer {w, h} = IupGetIntInt(canvas, "DRAWSIZE"), x, y
<span style="color: #004080;">Ihandle</span> <span style="color: #000000;">dlg</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">canvas</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">timershow</span>
atom xx, yy
<span style="color: #004080;">cdCanvas</span> <span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">cdcanvas</span>
cdCanvasActivate(cddbuffer)
cdCanvasClear(cddbuffer)
<span style="color: #004080;">integer</span> <span style="color: #000000;">brem</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">80</span>
-- draw the pins, then balls, then bins
<span style="color: #004080;">sequence</span> <span style="color: #000000;">balls</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">}}</span>
cdCanvasSetForeground(cddbuffer, CD_DARK_GREEN)
<span style="color: #004080;">sequence</span> <span style="color: #000000;">bins</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">8</span><span style="color: #0000FF;">)</span>
integer pinsize = min(floor(h/40),floor(w/50))
for y=4 to 16 by 2 do
<span style="color: #008080;">function</span> <span style="color: #000000;">redraw_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandle</span> <span style="color: #000080;font-style:italic;">/*ih*/</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">integer</span> <span style="color: #000080;font-style:italic;">/*posx*/</span><span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">/*posy*/</span><span style="color: #0000FF;">)</span>
for x=-(y-4) to (y-4) by 4 do
<span style="color: #004080;">integer</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">w</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">h</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupGetIntInt</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"DRAWSIZE"</span><span style="color: #0000FF;">),</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">y</span>
xx = w/2 + x*w/32
<span style="color: #004080;">atom</span> <span style="color: #000000;">xx</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">yy</span>
yy = h -y*h/32
<span style="color: #7060A8;">cdCanvasActivate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">)</span>
cdCanvasSector(cddbuffer, xx, yy, pinsize, pinsize, 0, 360)
<span style="color: #7060A8;">cdCanvasClear</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">)</span>
end for
<span style="color: #000080;font-style:italic;">-- draw the pins, then balls, then bins</span>
end for
<span style="color: #7060A8;">cdCanvasSetForeground</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #004600;">CD_DARK_GREEN</span><span style="color: #0000FF;">)</span>
cdCanvasSetForeground(cddbuffer, CD_INDIGO)
<span style="color: #004080;">integer</span> <span style="color: #000000;">pinsize</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">min</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">floor</span><span style="color: #0000FF;">(</span><span style="color: #000000;">h</span><span style="color: #0000FF;">/</span><span style="color: #000000;">40</span><span style="color: #0000FF;">),</span><span style="color: #7060A8;">floor</span><span style="color: #0000FF;">(</span><span style="color: #000000;">w</span><span style="color: #0000FF;">/</span><span style="color: #000000;">50</span><span style="color: #0000FF;">))</span>
for i=1 to length(balls) do
<span style="color: #008080;">for</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">=</span><span style="color: #000000;">4</span> <span style="color: #008080;">to</span> <span style="color: #000000;">16</span> <span style="color: #008080;">by</span> <span style="color: #000000;">2</span> <span style="color: #008080;">do</span>
{x, y} = balls[i]
<span style="color: #008080;">for</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">=-(</span><span style="color: #000000;">y</span><span style="color: #0000FF;">-</span><span style="color: #000000;">4</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">to</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">y</span><span style="color: #0000FF;">-</span><span style="color: #000000;">4</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">by</span> <span style="color: #000000;">4</span> <span style="color: #008080;">do</span>
xx = w/2 + x*w/32
<span style="color: #000000;">xx</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">w</span><span style="color: #0000FF;">/</span><span style="color: #000000;">2</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">*</span><span style="color: #000000;">w</span><span style="color: #0000FF;">/</span><span style="color: #000000;">32</span>
yy = h -y*h/32
<span style="color: #000000;">yy</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">h</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">y</span><span style="color: #0000FF;">*</span><span style="color: #000000;">h</span><span style="color: #0000FF;">/</span><span style="color: #000000;">32</span>
cdCanvasSector(cddbuffer, xx, yy, pinsize*4, pinsize*4, 0, 360)
<span style="color: #7060A8;">cdCanvasSector</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">xx</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">yy</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">pinsize</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">pinsize</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">360</span><span style="color: #0000FF;">)</span>
end for
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
cdCanvasLineWidth(cddbuffer,w/9)
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
for i=1 to length(bins) do
<span style="color: #7060A8;">cdCanvasSetForeground</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #004600;">CD_INDIGO</span><span style="color: #0000FF;">)</span>
xx = w/2+(i*4-18)*w/32
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">balls</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
yy = bins[i]*h/64+10
<span style="color: #0000FF;">{</span><span style="color: #000000;">x</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">balls</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span>
cdCanvasLine(cddbuffer,xx,10,xx,yy)
<span style="color: #000000;">xx</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">w</span><span style="color: #0000FF;">/</span><span style="color: #000000;">2</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">*</span><span style="color: #000000;">w</span><span style="color: #0000FF;">/</span><span style="color: #000000;">32</span>
end for
<span style="color: #000000;">yy</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">h</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">y</span><span style="color: #0000FF;">*</span><span style="color: #000000;">h</span><span style="color: #0000FF;">/</span><span style="color: #000000;">32</span>
cdCanvasFlush(cddbuffer)
<span style="color: #7060A8;">cdCanvasSector</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">xx</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">yy</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">pinsize</span><span style="color: #0000FF;">*</span><span style="color: #000000;">4</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">pinsize</span><span style="color: #0000FF;">*</span><span style="color: #000000;">4</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">360</span><span style="color: #0000FF;">)</span>
return IUP_DEFAULT
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
end function
<span style="color: #7060A8;">cdCanvasSetLineWidth</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span><span style="color: #000000;">w</span><span style="color: #0000FF;">/</span><span style="color: #000000;">9</span><span style="color: #0000FF;">)</span>
 
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">bins</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
function timer_cb(Ihandle ih)
<span style="color: #000000;">xx</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">w</span><span style="color: #0000FF;">/</span><span style="color: #000000;">2</span><span style="color: #0000FF;">+(</span><span style="color: #000000;">i</span><span style="color: #0000FF;">*</span><span style="color: #000000;">4</span><span style="color: #0000FF;">-</span><span style="color: #000000;">18</span><span style="color: #0000FF;">)*</span><span style="color: #000000;">w</span><span style="color: #0000FF;">/</span><span style="color: #000000;">32</span>
integer x, y=9, dx
<span style="color: #000000;">yy</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">bins</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]*</span><span style="color: #000000;">h</span><span style="color: #0000FF;">/</span><span style="color: #000000;">64</span><span style="color: #0000FF;">+</span><span style="color: #000000;">10</span>
if length(balls) then
<span style="color: #7060A8;">cdCanvasLine</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span><span style="color: #000000;">xx</span><span style="color: #0000FF;">,</span><span style="color: #000000;">10</span><span style="color: #0000FF;">,</span><span style="color: #000000;">xx</span><span style="color: #0000FF;">,</span><span style="color: #000000;">yy</span><span style="color: #0000FF;">)</span>
{x,y,dx} = balls[1]
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
if y>20 then
<span style="color: #7060A8;">cdCanvasFlush</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">)</span>
bins[(x+18)/4] += 1
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_DEFAULT</span>
balls = balls[2..$]
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
end if
end if
<span style="color: #008080;">function</span> <span style="color: #000000;">timer_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandle</span> <span style="color: #000000;">ih</span><span style="color: #0000FF;">)</span>
for i=1 to length(balls) do
<span style="color: #004080;">integer</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">=</span><span style="color: #000000;">9</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">dx</span>
{x,y,dx} = balls[i]
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">balls</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
if y>15 then
<span style="color: #0000FF;">{</span><span style="color: #000000;">x</span><span style="color: #0000FF;">,</span><span style="color: #000000;">y</span><span style="color: #0000FF;">,</span><span style="color: #000000;">dx</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">balls</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span>
dx = 0
<span style="color: #008080;">if</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">></span><span style="color: #000000;">20</span> <span style="color: #008080;">then</span>
elsif and_bits(y,1)=0 then
<span style="color: #004080;">integer</span> <span style="color: #000000;">bindx</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">x</span><span style="color: #0000FF;">+</span><span style="color: #000000;">18</span><span style="color: #0000FF;">)/</span><span style="color: #000000;">4</span>
dx = {-1,+1}[rand(2)]
<span style="color: #000000;">bins</span><span style="color: #0000FF;">[</span><span style="color: #000000;">bindx</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
end if
<span style="color: #000000;">balls</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">balls</span><span style="color: #0000FF;">[</span><span style="color: #000000;">2</span><span style="color: #0000FF;">..$]</span>
balls[i] = {x+dx,y+1,dx}
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
end for
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
if y>4 and brem!=0 then
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">balls</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
brem -= 1
<span style="color: #0000FF;">{</span><span style="color: #000000;">x</span><span style="color: #0000FF;">,</span><span style="color: #000000;">y</span><span style="color: #0000FF;">,</span><span style="color: #000000;">dx</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">balls</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span>
balls = append(balls,{0,1,0})
<span style="color: #008080;">if</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">></span><span style="color: #000000;">15</span> <span style="color: #008080;">then</span>
end if
<span style="color: #000000;">dx</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
if brem=0 and length(balls)=0 then
<span style="color: #008080;">elsif</span> <span style="color: #7060A8;">and_bits</span><span style="color: #0000FF;">(</span><span style="color: #000000;">y</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
IupSetAttribute(timershow,"RUN","NO")
<span style="color: #000000;">dx</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">}[</span><span style="color: #7060A8;">rand</span><span style="color: #0000FF;">(</span><span style="color: #000000;">2</span><span style="color: #0000FF;">)]</span>
end if
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
IupUpdate(canvas)
<span style="color: #000000;">balls</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">x</span><span style="color: #0000FF;">+</span><span style="color: #000000;">dx</span><span style="color: #0000FF;">,</span><span style="color: #000000;">y</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">dx</span><span style="color: #0000FF;">}</span>
return IUP_IGNORE
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
end function
<span style="color: #008080;">if</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">></span><span style="color: #000000;">4</span> <span style="color: #008080;">and</span> <span style="color: #000000;">brem</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
 
<span style="color: #000000;">brem</span> <span style="color: #0000FF;">-=</span> <span style="color: #000000;">1</span>
function map_cb(Ihandle ih)
<span style="color: #000000;">balls</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">balls</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">})</span>
cdcanvas = cdCreateCanvas(CD_IUP, ih)
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
cddbuffer = cdCreateCanvas(CD_DBUFFER, cdcanvas)
<span style="color: #008080;">if</span> <span style="color: #000000;">brem</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">and</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">balls</span><span style="color: #0000FF;">)=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
cdCanvasSetBackground(cddbuffer, CD_GREY)
<span style="color: #7060A8;">IupSetAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">timershow</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"RUN"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"NO"</span><span style="color: #0000FF;">)</span>
return IUP_DEFAULT
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
end function
<span style="color: #7060A8;">IupUpdate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">)</span>
 
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_IGNORE</span>
procedure main()
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
IupOpen()
 
<span style="color: #008080;">function</span> <span style="color: #000000;">map_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandle</span> <span style="color: #000000;">ih</span><span style="color: #0000FF;">)</span>
canvas = IupCanvas(NULL)
<span style="color: #000000;">cdcanvas</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">cdCreateCanvas</span><span style="color: #0000FF;">(</span><span style="color: #004600;">CD_IUP</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">ih</span><span style="color: #0000FF;">)</span>
IupSetAttribute(canvas, "RASTERSIZE", "640x380")
<span style="color: #000000;">cddbuffer</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">cdCreateCanvas</span><span style="color: #0000FF;">(</span><span style="color: #004600;">CD_DBUFFER</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">cdcanvas</span><span style="color: #0000FF;">)</span>
IupSetCallback(canvas, "MAP_CB", Icallback("map_cb"))
<span style="color: #7060A8;">cdCanvasSetBackground</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #004600;">CD_GREY</span><span style="color: #0000FF;">)</span>
IupSetCallback(canvas, "ACTION", Icallback("redraw_cb"))
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_DEFAULT</span>
 
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
timershow = IupTimer(Icallback("timer_cb"), 80)
 
<span style="color: #008080;">procedure</span> <span style="color: #000000;">main</span><span style="color: #0000FF;">()</span>
dlg = IupDialog(canvas)
<span style="color: #7060A8;">IupOpen</span><span style="color: #0000FF;">()</span>
IupSetAttribute(dlg, "TITLE", TITLE)
IupCloseOnEscape(dlg)
<span style="color: #000000;">canvas</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupCanvas</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"RASTERSIZE=360x600"</span><span style="color: #0000FF;">)</span>
IupShow(dlg)
<span style="color: #7060A8;">IupSetCallbacks</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">,</span> <span style="color: #0000FF;">{</span><span style="color: #008000;">"MAP_CB"</span><span style="color: #0000FF;">,</span> <span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"map_cb"</span><span style="color: #0000FF;">),</span>
IupSetAttribute(canvas, "RASTERSIZE", NULL)
<span style="color: #008000;">"ACTION"</span><span style="color: #0000FF;">,</span> <span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"redraw_cb"</span><span style="color: #0000FF;">)})</span>
IupMainLoop()
IupClose()
<span style="color: #000000;">timershow</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupTimer</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"timer_cb"</span><span style="color: #0000FF;">),</span> <span style="color: #000000;">80</span><span style="color: #0000FF;">)</span>
end procedure
 
<span style="color: #000000;">dlg</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupDialog</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">`TITLE="%s"`</span><span style="color: #0000FF;">,</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">TITLE</span><span style="color: #0000FF;">})</span>
main()</lang>
<span style="color: #7060A8;">IupShow</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dlg</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">IupSetAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"RASTERSIZE"</span><span style="color: #0000FF;">,</span> <span style="color: #004600;">NULL</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">platform</span><span style="color: #0000FF;">()!=</span><span style="color: #004600;">JS</span> <span style="color: #008080;">then</span>
<span style="color: #7060A8;">IupMainLoop</span><span style="color: #0000FF;">()</span>
<span style="color: #7060A8;">IupClose</span><span style="color: #0000FF;">()</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #000000;">main</span><span style="color: #0000FF;">()</span>
<!--</syntaxhighlight>-->
 
=={{header|PicoLisp}}==
<langsyntaxhighlight PicoLisplang="picolisp">(de galtonBox (Pins Height)
(let (Bins (need (inc (* 2 Pins)) 0) X 0 Y 0)
(until (= Height (apply max Bins))
Line 2,677 ⟶ 3,318:
(prin (if (>= B H) "o" " ")) )
(prinl) )
(wait 200) ) ) )</langsyntaxhighlight>
Test:
<syntaxhighlight lang PicoLisp="picolisp">(galtonBox 9 11)</langsyntaxhighlight>
{{Out}}
<pre># Snapshot after a few seconds:
Line 2,728 ⟶ 3,369:
=={{header|Prolog}}==
Works with SWI-Prolog and XPCE.[[File:Prolog_Galton_Box_1.png|thumb|Sample display of Prolog solution]]
<langsyntaxhighlight Prologlang="prolog">:- dynamic tubes/1.
:- dynamic balls/2.
:- dynamic stop/1.
Line 2,926 ⟶ 3,567:
send(Ch, append, T),
send(D, display, T))).
</syntaxhighlight>
</lang>
 
=={{header|PureBasic}}==
{{trans|Unicon}}
[[File:PureBasic_galtonbox.png|thumb|Sample display of PureBasic solution]]
<langsyntaxhighlight lang="purebasic">Global pegRadius, pegSize, pegSize2, height, width, delay, histogramSize, ball
 
Procedure eventLoop()
Line 3,057 ⟶ 3,698:
If Not galton(pegRows): Break: EndIf
Next
Repeat: eventLoop(): ForEver</langsyntaxhighlight>
 
=={{header|Python}}==
<langsyntaxhighlight Pythonlang="python">#!/usr/bin/python
 
import sys, os
Line 3,144 ⟶ 3,785:
 
if __name__=="__main__":
main()</langsyntaxhighlight>
 
=={{header|Racket}}==
Line 3,150 ⟶ 3,791:
Multiple balls are added each step, but they do not collide.
 
<syntaxhighlight lang="racket">
<lang Racket>
;a ball's position...row is a natural number and col is an integer where 0 is the center
(define-struct pos (row col))
Line 3,269 ⟶ 3,910:
(on-tick (λ (ps) (tock height ps)) 0.5)
(to-draw (λ (ps) (draw height ps)))))
</syntaxhighlight>
</lang>
 
=={{header|Raku}}==
Line 3,275 ⟶ 3,916:
[[File:Galton_box_perl6.gif|thumb|UPPER HALF BLOCK and LOWER HALF BLOCK alternate to give a somewhat smooth animation.]]
{{works with|rakudo|2015-09-12}}
<syntaxhighlight lang="raku" perl6line>my $row-count = 6;
constant $peg = "*";
Line 3,420 ⟶ 4,061:
$row-count = $peg-lines;
simulate($coins);
}</langsyntaxhighlight>
 
=={{header|REXX}}==
Line 3,427 ⟶ 4,068:
Balls are dropped continuously &nbsp; (up to a number specified or the default), &nbsp; the default is enough rows of
<br>pins to fill the top &nbsp; <big><sup>1</sup>/<sub>3</sub></big> &nbsp; rows of the terminal screen.
<langsyntaxhighlight lang="rexx">/*REXX pgm simulates Sir Francis Galton's box, aka: Galton Board, quincunx, bean machine*/
trace off /*suppress any messages for negative RC*/
if !all(arg()) then exit /*Any documentation was wanted? Done.*/
if !cms then address '' /*handle ADDRESS for CMS oper. system. */
trace off /*suppress error messages from a HALT. */
signal on halt /*allow the user to halt the program.*/
parse arg rows balls freeze seed . /*obtain optional arguments from the CL*/
Line 3,437 ⟶ 4,077:
if freeze=='' | freeze=="," then freeze= 0 /* " " " " " " */
if datatype(seed, 'W') then call random ,,seed /*Was a seed specified? Then use seed.*/
parsepin value = scrsize()'·'; with sd sw . ball = '☼' /*obtaindefine thechars terminalfor a pin depth and width.a ball.*/
parse value scrsize() with sd sw . /*obtain the terminal depth and width. */
if sd==0 then sd= 40 /*Not defined by the OS? Use a default*/
if sw==0 then sw= 80 /* " " " " " " " " */
sd= sd - 3 /*define the usable screen depth.*/
sw= sw - 1; if sw//2 then sw= sw -1 1 /* " " " odd " width.*/
if rows==0 then rows= (sw - 2 ) % 3 /*pins are on the first third of screen*/
pin = '·'; ball = '☼' /*define chars for a pin and a ball.*/
call gen /*gen a triangle of pins with some rows*/
call run do step=1; call drop; call show /*simulateshow aanimation Galton'til boxrun without someof balls.*/
exit end /*step*/ /* [↑] the dropping/*stickshowing a fork in" it, we're" all done. */
exit 0 /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
gen: @.=; do r=10 for rows; by 2 to rows; $= /*build a triangle of pins for the box.*/
if r//2 then iterate do pins=1 for r%2; $= $ pin /*build [↑]a row anof emptypins oddto rowbe (withdisplayed. no pins)*/
do pins=1 for r%2; $= $ pin; end /*pins*/ /*build a row of pins.*/
@.r= center( strip($, 'T'), sw) /*an easy method to build a triangle. */
end /*r*/; #= 0; return /*#: is the number of balls dropped. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
drop: static= 1 /*used to indicate all balls are static*/
do c=sd-1 by -1 tofor sd-1; n= c + 1 /*D: current row; N: the next row. */
x= pos(ball, @.c); y= x - 1 /*X: position of a ball on the C line.*/
if x==0 then iterate /*No balls here? Then nothing to drop.*/
Line 3,463 ⟶ 4,104:
if z==' ' then do; @.n= overlay(ball, @.n, y) /*drop a ball straight down.*/
@.c= overlay(' ' , @.c, y) /*make current ball a ghost.*/
static=0 0 /*indicate balls are moving.*/
iterate /*go keep looking for balls.*/
end
Line 3,471 ⟶ 4,112:
@.n= overlay(ball, @.n, y+d)
@.c= overlay(' ' , @.c, y )
static=0 0 /*indicate balls are moving.*/
iterate /*go keep looking for balls.*/
end
Line 3,481 ⟶ 4,122:
return
/*──────────────────────────────────────────────────────────────────────────────────────*/
show: !cls; do LR=sd by -1 until @.LR\=='' info= right(" step" step, sw%4) /*LR: last /*titlerow forof screendata.*/
doend g=sd by/*LR*/; -1 until @.g\='' ss= 'step' step /* [↓] display /*G: last dataa row. */
do r=1 for LR; _= strip(@.r, 'T'); if r==2 then _= overlay(ss, _, sw-12); say _
end /*g*/ /* [↓] show a row.*/
doend r=1 for g/*r*/; _= strip(@.r, 'T'); if rstep==2freeze then _=do; _ left( say 'press ENTER ···',; 9) info pull; say _end
end /*r*/; if step==freeze then do; say 'press ENTER ···'; pull; end
return
/*══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════*/
run: do step=1; call drop; call show; end /*step*/ /*'til run out of balls.*/
halt: say '***warning*** REXX program' !fn "execution halted by user."; exit 1
!all: !!=!;!=space(!);upper !;call !fid;!nt=right(!var('OS'),2)=='NT';!cls=word('CLS VMFCLEAR CLRSCREEN',1+!cms+!tso*2);if arg(1)\==1 then return 0;if wordpos(!,'? ?SAMPLES ?AUTHOR ?FLOW')==0 then return 0;!call=']$H';call '$H' !fn !;!call=;return 1
!cal: if symbol('!CALL')\=="VAR" then !call=; return !call
!env: !env='ENVIRONMENT'; if !sys=='MSDOS' | !brexx | !r4 | !roo then !env= 'SYSTEM'; if !os2 then !env= 'OS2'!env; !ebcdic= 3 2=='f3f2'x; if !crx then !env= 'DOS'; return
!fid: parse upper source !sys !fun !fid . 1 . . !fn !ft !fm .; call !sys; if !dos then do; _= lastpos('\', !fn); !fm= left(!fn, _); !fn= substr(!fn, _+1); parse var !fn !fn '.' !ft; end; return word(0 !fn !ft !fm, 1 + ('0'arg(1) ) )
!rex: parse upper version !ver !vernum !verdate .; !brexx= 'BY'==!vernum; !kexx= 'KEXX'==!ver; !pcrexx= 'REXX/PERSONAL'==!ver | 'REXX/PC'==!ver; !r4= 'REXX-R4'==!ver; !regina= 'REXX-REGINA'==left(!ver, 11); !roo= 'REXX-ROO'==!ver; call !env; return
!sys: !cms= !sys=='CMS'; !os2= !sys=='OS2'; !tso= !sys=='TSO' | !sys=='MVS'; !vse= !sys=='VSE'; !dos= pos('DOS', !sys)\==0 | pos('WIN', !sys)\==0 | !sys=='CMD'; !crx= left(!sys, 6)=='DOSCRX'; call !rex; return
!var: call !fid; if !kexx then return space( dosenv( arg(1) ) ); return space( value( arg(1), , !env) )</langsyntaxhighlight>
Programming note: &nbsp; the last seven lines of this REXX program are some general purpose (boilerplate code) that, among other things, finds:
::* &nbsp; the REXX program's filename, filetype (file extension), and filemode (and/or path)
Line 3,653 ⟶ 4,292:
{{libheader|Shoes}}
[[File:galtonbox.shoes.png|thumb|Sample display of Ruby solution]]
<langsyntaxhighlight lang="ruby">$rows_of_pins = 12
$width = $rows_of_pins * 10 + ($rows_of_pins+1)*14
 
Line 3,729 ⟶ 4,368:
end
end
end</langsyntaxhighlight>
 
=={{header|Tcl}}==
{{trans|C}}
<langsyntaxhighlight lang="tcl">package require Tcl 8.6
 
oo::class create GaltonBox {
Line 3,833 ⟶ 4,472:
board show
if {[board step]} {after 60} break
}</langsyntaxhighlight>
After a sample run with input parameters <tt>10 55</tt>:
<pre>
Line 3,893 ⟶ 4,532:
</pre>
There is a much more comprehensive solution to this on the [http://wiki.tcl.tk/8825 Tcler's Wiki].<!-- Too long to reproduce here -->
 
=={{header|Wren}}==
{{trans|D}}
{{libheader|Wren-iterate}}
<syntaxhighlight lang="wren">import "random" for Random
import "./iterate" for Reversed
 
var boxW = 41 // Galton box width.
var boxH = 37 // Galton box height.
var pinsBaseW = 19 // Pins triangle base.
var nMaxBalls = 55 // Number of balls.
 
var centerH = pinsBaseW + (boxW - pinsBaseW * 2 + 1) / 2 - 1
var Rand = Random.new()
 
class Cell {
static EMPTY { " " }
static BALL { "o" }
static WALL { "|" }
static CORNER { "+" }
static FLOOR { "-" }
static PIN { "." }
}
 
/* Galton box. Will be printed upside down. */
var Box = List.filled(boxH, null)
for (i in 0...boxH) Box[i] = List.filled(boxW, Cell.EMPTY)
 
class Ball {
construct new(x, y) {
if (Box[x][y] != Cell.EMPTY) Fiber.abort("The cell at (x, y) is not empty.")
Box[y][x] = Cell.BALL
_x = x
_y = y
}
 
doStep() {
if (_y <= 0) return // Reached the bottom of the box.
var cell = Box[_y - 1][_x]
if (cell == Cell.EMPTY) {
Box[_y][_x] = Cell.EMPTY
_y = _y - 1
Box[_y][_x] = Cell.BALL
} else if (cell == Cell.PIN) {
Box[_y][_x] = Cell.EMPTY
_y = _y - 1
if (Box[_y][_x - 1] == Cell.EMPTY && Box[_y][_x + 1] == Cell.EMPTY) {
_x = _x + Rand.int(2) * 2 - 1
Box[_y][_x] = Cell.BALL
return
} else if (Box[_y][_x - 1] == Cell.EMPTY){
_x = _x + 1
} else _x = _x - 1
Box[_y][_x] = Cell.BALL
} else {
// It's frozen - it always piles on other balls.
}
}
}
 
var initializeBox = Fn.new {
// Set ceiling and floor:
Box[0][0] = Cell.CORNER
Box[0][boxW - 1] = Cell.CORNER
for (i in 1...boxW - 1) Box[0][i] = Cell.FLOOR
for (i in 0...boxW) Box[boxH - 1][i] = Box[0][i]
 
// Set walls:
for (r in 1...boxH - 1) {
Box[r][0] = Cell.WALL
Box[r][boxW - 1] = Cell.WALL
}
// Set pins:
for (nPins in 1..pinsBaseW) {
for (pin in 0...nPins) {
Box[boxH - 2 - nPins][centerH + 1 - nPins + pin * 2] = Cell.PIN
}
}
}
 
var drawBox = Fn.new() {
for (row in Reversed.new(Box, 1)) {
for (c in row) System.write(c)
System.print()
}
}
 
initializeBox.call()
var balls = []
for (i in 0...nMaxBalls + boxH) {
System.print("\nStep %(i):")
if (i < nMaxBalls) balls.add(Ball.new(centerH, boxH - 2)) // Add ball.
drawBox.call()
 
// Next step for the simulation.
// Frozen balls are kept in balls list for simplicity
for (b in balls) b.doStep()
}</syntaxhighlight>
 
{{out}}
Sample output, showing the last step only:
<pre>
Step 91:
+---------------------------------------+
| |
| . |
| . . |
| . . . |
| . . . . |
| . . . . . |
| . . . . . . |
| . . . . . . . |
| . . . . . . . . |
| . . . . . . . . . |
| . . . . . . . . . . |
| . . . . . . . . . . . |
| . . . . . . . . . . . . |
| . . . . . . . . . . . . . |
| . . . . . . . . . . . . . . |
| . . . . . . . . . . . . . . . |
| . . . . . . . . . . . . . . . . |
| . . . . . . . . . . . . . . . . . |
| . . . . . . . . . . . . . . . . . . |
| . . . . . . . . . . . . . . . . . . . |
| |
| |
| o |
| o |
| o |
| o o |
| o o |
| o o |
| o o o o |
| o o o o |
| o o o o |
| o o o o o |
| o o o o o o o o |
| o o o o o o o o o |
| o o o o o o o o o o o o |
+---------------------------------------+
</pre>
 
=={{header|XPL0}}==
Line 3,898 ⟶ 4,679:
This ''Peeks'' into some IBM-PC specific locations and hence is not entirely portable.
 
<langsyntaxhighlight XPL0lang="xpl0">include c:\cxpl\codes; \intrinsic code declarations
define Balls = 80; \maximum number of balls
int Bx(Balls), By(Balls), \character cell coordinates of each ball
Line 3,930 ⟶ 4,711:
Sound(0, 3, 1); \delay about 1/6 second
until KeyHit; \continue until a key is struck
]</langsyntaxhighlight>
 
{{Out}}
Line 3,961 ⟶ 4,742:
 
=={{header|Yabasic}}==
<langsyntaxhighlight Yabasiclang="yabasic">bola$ = "0000ff"
obst$ = "000000"
 
Line 4,020 ⟶ 4,801:
next n
loop
</syntaxhighlight>
</lang>
 
=={{header|zig}}==
 
=={{header|Zig}}==
<lang zig>const std = @import("std");
<syntaxhighlight lang="zig">const std = @import("std");
const rand = std.rand;
const time = std.os.time;
 
const PEG_LINES = 20;
const BALLS = 10;
 
fn boardSize(comptime peg_lines: u16) u16 {
var i: u16 = 0;
var size: u16 = 0;
inline while (i <= PEG_LINESpeg_lines) : (i += 1) {
size += i + 1;
}
return size;
Line 4,041 ⟶ 4,822:
const BOARD_SIZE = boardSize(PEG_LINES);
 
fn stepBoard(board: *[BOARD_SIZE]u1, count: *[PEG_LINES + 1]u8) void {
var prng = rand.DefaultPrng.init(@bitCast(time.timestamp()));
 
var p: u8 = 0;
var sum: u16 = 0;
while (p <= PEG_LINES) : (p += 1) {
const pegs = PEG_LINES - p;
var i: u16 = 0;
while (i < pegs + 1) : (i += 1) {
if (pegs != PEG_LINES and board[BOARD_SIZE - 1 - sum - i] == 1) {
if (prng.random().boolean()) {
board.*[BOARD_SIZE - 1 - sum - i + pegs + 1] = 1;
} else {
board.*[BOARD_SIZE - 1 - sum - i + pegs + 2] = 1;
}
} else if (pegs == PEG_LINES and board[BOARD_SIZE - 1 - sum - i] == 1) {
count.*[pegs - i] += 1;
}
board.*[BOARD_SIZE - 1 - sum - i] = 0;
}
sum += pegs + 1;
}
}
 
fn printBoard(board: *[BOARD_SIZE]u1, count: *[PEG_LINES + 1]u8) !void {
varconst stdout = try std.io.getStdOut();
_ = try stdout.write("\x1B[2J\x1B[1;1H");
var pegs: u16 = 0;
var sum: u16 = 0;
while (pegs <= PEG_LINES) : (pegs += 1) {
var i: u16 = 0;
while (i < (PEG_LINES - pegs)) : (i += 1) _ = try stdout.write(" ");
i = 0;
while (i < pegs + 1) : (i += 1) {
const spot = if (board[i + sum] == 1) "o" else " ";
_ = try stdout.write(spot);
if (i != pegs) _ = try stdout.write("*");
}
sum += pegs + 1;
_ = try stdout.write("\n");
}
for (count) |n| {
const num_char = [2]u8{'0' + n, ' '};
_ = try stdout.write(&num_char);
}
_ = try stdout.write("\n");
}
 
pub fn main() !void {
var board: [BOARD_SIZE]u1 = [_]u1{0} ** BOARD_SIZE;
var bottom_count: [PEG_LINES+1]u8 = [_]u8{0} ** (PEG_LINES + 1);
 
var i: u16 = 0;
while (i < 35PEG_LINES + BALLS + 1) : (i += 1) {
if (i < 10BALLS) board[0] = 1;
 
try printBoard(&board, &bottom_count);
Line 4,101 ⟶ 4,882:
time.sleep(150000000);
}
}</langsyntaxhighlight>
1,995

edits