# Approximate a Bell Curve

Create a program to display some approximation of a bell curve. You are free to use whatever method you wish for generating the data, but the data must be displayed vertically, as in oriented like so:

Other restrictions:

• Your code must create the approximation, that is, don't hardcode or take data from the internet.
• The shape must actually look like a bell.

This is a , so be creative.

• Sorry for not remembering to ask this when it was in the sandbox, but is ASCII-art ok? – Victor Stafusa Mar 2 '14 at 2:08
• @Victor Of course. (as long as you orient vertically) – Justin Mar 2 '14 at 2:08
• What is etc? That rule needs clarification. What about getInternetBellCurve+0? What does "hard-coding" imply? This rule is currently highly opinion based. – Doorknob Mar 2 '14 at 2:22
• @Doorknob The "etc" means "any other cheating method to avoid actually generating the curve by getting it already done from somewhere else". – Victor Stafusa Mar 2 '14 at 3:06
• – dmckee --- ex-moderator kitten Mar 3 '14 at 3:34

# Java

The method of generation is based off of the game Sugar, Sugar. In that game, sugar particles fall, traveling randomly left and right. In my program, Dust objects fall until they hit the ground. I collect data based on where they land; this is the bell curve:

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Random;
import java.util.Stack;
import javax.imageio.ImageIO;

/**
*
* @author Quincunx
*/
public class ApproxBellCurve {

public static final int NUM_DUST = 10_000_000;
public static final int NUM_THREADS = Runtime.getRuntime().availableProcessors() - 1;
public static final int LOOP_LIMIT = NUM_DUST / (NUM_THREADS + 1);

public static void main(String[] args) {
BufferedImage output = new BufferedImage(2049, 2049, BufferedImage.TYPE_INT_RGB);

for (int i = 0; i < NUM_THREADS; i++) {
}

Dust d;
Random r = new Random();
for (int i = 0; i < LOOP_LIMIT + NUM_DUST - (LOOP_LIMIT * (NUM_THREADS + 1)); i++) {
d = new Dust(r);
while (!d.end) {
d.step();
}
if ((i & 1024) == 0) {
r = new Random();
}
}
try {
} catch (InterruptedException ex) {

}
}
int maxy = 0;
for (int x = 0; x < Dust.data.length; x++) {
maxy = Dust.data[x] > maxy ? Dust.data[x] : maxy;
}

for (int x = 0; x < Dust.data.length; x++) {
for (int y = 0; y < output.getHeight(); y++) {
output.setRGB(x, y, (y >= output.getHeight() - (Dust.data[x] * output.getHeight() / maxy)) ? 6591981 : 16777215);
}
}
try {
ImageIO.write(output, "png", new File("Filepath"));
} catch (IOException ex) {
ex.printStackTrace();
}
}

private static class Duster implements Runnable {

@Override
public void run() {
Dust d;
Random r = new Random();
for (int i = 0; i < LOOP_LIMIT; i++) {
d = new Dust(r);
while (!d.end) {
d.step();
}
if ((i & 1024) == 0) {
r = new Random();
}
}
}

}

private static class Dust {

public static int[] data = new int[2049];

static {
for (int i = 0; i < data.length; i++) {
data[i] = 0;
}
}

private int[] location;
private Random r;
public boolean end;

public Dust(Random rand) {
location = new int[]{1024, 0};
r = rand;
end = false;
}

public void step() {
if (end) {
return;
}
if (location[1] >= 1024) {
end = true;
synchronized (data) {
data[location[0]] += 1;
}
return;
}
location[1] += 1;
location[0] += r.nextInt(21) - 10;
}
}
}


Sample output (took 1 minute to create):

Because of the nature of the random number generation, it is possible to get an ArrayIndexOutOfBoundsException.

I used multithreading to speed up the process. The program determines the number of processors available and creates that many threads to run the simulations.

To obtain a finer image, NUM_DUST can be increased, but that would also lead to an increased risk of an ArrayIndexOutOfBoundsException.

Each thread creates a new Random after every 1024 Dust objects are simulated. When that code was removed, the image was more coarse.

rand.nextInt(21) - 10 is to widen the distribution. A change to rand.nextInt(3) - 1 would remove all chance of an ArrayIndexOutOfBoundsException.

## Mathematica

I decided it should not only look like a bell curve, it should look like a bell. So hey, let's spin it around the Z-axis and make it 3D.

And hey, while we're at it, it should sound like a bell as well.

So, each time you evaluate the code, it makes a nice pleasing church-bell BWONNGGG!

Manipulate[
RevolutionPlot3D[PDF[NormalDistribution[mu, sigma], x], {x, -4, 4},
PlotRange -> {Automatic, Automatic, Automatic},
BoxRatios -> {1, 1, 1}, PlotStyle -> {Orange, Yellow},
ImageSize -> {500, 500}], {{mu, 0, "mean"}, -3, 3,
Appearance -> "Labeled"}, {{sigma, 1.47, "standard deviation"}, .5,
2, Appearance -> "Labeled"}]
EmitSound[Sound[SoundNote[0, 3, "TubularBells", SoundVolume -> 1]]]


Here's what it looks like:

And here's a brief video of the bell ringing.

Everyone's code is so ... huge, and their approximations are ... less than deterministic. Just to remind everyone of the simplicity of the actual task, here's a nine-liner in Haskell:

import Data.List; import Data.Ratio
main = do
putStrLn "please choose the width and the maximum height:"
[w, mh] <- (map read.words) fmap getLine
let dist = map length $group$ sort $map length$ subsequences [2..w]
scale = ceiling $maximum dist % mh maxD = scale * ceiling (maximum dist % scale) putStrLn$ unlines $map (row dist) [maxD, maxD - scale .. 0] where row dist y = map (\x -> if x >= y then '*' else ' ') dist  OK... that wasn't exactly fast. Here's another go. Does it still count as not hard-coded? import Data.List; import Data.Ratio main = do putStrLn "please choose the width and the maximum height:" [w, mh] <- (map read.words) fmap getLine let dist = map ((w-1) choose) [0..(w-1)] scale = ceiling$ maximum dist % mh
maxD = scale * ceiling (maximum dist % scale)
putStrLn $unlines$ map (row dist) [maxD, maxD - scale .. 0]
where row dist y = map (\x -> if x >= y then '*' else ' ') dist

factorial x = product [1..x]
n choose k = factorial n div factorial k div factorial (n-k)


• You mean, "Them Java users' code is so huge." The other people's codes are rather small. Also, is there anything wrong with long code? I personally enjoy popularity-contests because I am free to make my code as long as I want to. – Justin Mar 2 '14 at 8:39
• @Quincunx Hmm... true. But I'm still shorter than the non-Java solutions :-) as for whether long code or short code should be preferred in this challenge, that's up to voters. I offer consciseness. – John Dvorak Mar 2 '14 at 8:45
• Yours is huge compared to mine. :P – Tim Seguine Mar 6 '14 at 22:26

# Ruby

Simulates the classic example of bell curves, dropping a ball down a grid full of pole thingies.

a = [0]*30
1000.times do
x = 15
49.times do
x += (rand(3) - 1)
end
a[[[x.to_i, 29].min, 0].max] += 1
end
until a.all?{|x| x == 0}
a.each_with_index{|x,i|
if x == 0
print ' '
else
print 'x'
a[i] -= 1
end
}
puts
end


Sample output:

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxx
x xxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxx
xxxxxxxxxxxxxxx
xxxxxxxxxxxxxxx
xxxxxxxxxxxxxxx
xxxxxxxxxxxxxxx
xxxxxxxxxxxxxxx
xxxxxxxxxxxxxxx
xxxxxxxxxxxxxxx
xxxxxxxxxxxxxx
xxxxxxxxxxxxxx
xxxxxxxxxxxxx
xxxxxxxxxxxxx
xxxxxxxxxxxxx
xxxxxxxxxxxxx
xxxxxxxxxxxxx
xxxxxxxxxxxxx
xxxxxxxxxxxx
xxxxxxxxxxx
xxxxxxxxxxx
xxxxxxxxxxx
xxxxxxxxxxx
xxxxxxxxxx
xxxxxxxxxx
xxxxxxxxxx
xxxxxxx xx
xxxxxxx xx
xxxxxxx xx
xxxxxx xx
xxxxxx xx
xxxxxx x
xxxxx  x
xxxxx  x
xxx  x
xxx  x
xxx  x
xxx  x
xxx  x
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
xxx
x x
x x
x x
x x
x
x
x


Oh, did I forget to mention it's upside down?

• +1 for hiding the most abnormal part of the curve below the fold. Genius! :) – Jonathan Van Matre Mar 3 '14 at 15:39

# Mathematica

Generating the sums of 5 random integers, each between 0 and 100, 20000 times.

Histogram[Plus @@@ RandomInteger[100, {20000, 5}]]


Here's the result for sums of 1,2, 3 numbers. As the number of integers to be summed increases, the curve approaches the bell shape.

When single random integers are generated, but not summed, the distribution should be fairly uniform, not favoring any value. The apparent anomaly for 100 may be the result of how Matheamtica bins data. (see https://mathematica.stackexchange.com/questions/43300/does-randominteger0-n-disfavor-n/43302#43302 )

Table[Histogram[Plus @@@ RandomInteger[100, {20000, k}]], {k, 1, 3}]


## Wolfram Alpha (tongue-in-cheek) 4 bytes:

Here is a practical application of the Central Limit Theorem. I even golfed it!

Type this into the input box on Wolfram Alpha:

3d20


Here is a link to the results. It interprets this input as 3 icosahedral dice, and decides you want a graph of the distribution function of the pip sums. It prints the following graph:

We can make the graph more and more bell shaped by adding more dice. I don't see this as taking my data from the internet since, if I could run the query engine for it on my home computer I would. Unfortunately, Wolfram Research doesn't provide it for download, though.

• You can get a better looking curve with more dice and die-faces: wolframalpha.com/input/?i=10d50 – Justin Mar 6 '14 at 20:33
• @Quincunx I wanted to keep it to 20 sided dice so that it could actually be done with physical dice that are fair. I think 20d20 looks pretty good though: wolframalpha.com/input/?i=20d20 – Tim Seguine Mar 6 '14 at 20:37
• @Quincunx Oh, I didn't know you could hotlink images here... I learn something new all the time – Tim Seguine Mar 6 '14 at 20:39
• @Quincunx I rolled back your edit, because the link went dead. – Tim Seguine Mar 6 '14 at 22:00

## Python

from pygame import*
t,u=640,400;init();d=display;s=d.set_mode((t,u))
s.fill(0xFFFFFF)
for x in range(t):
d.flip();event.get()
draw.line(s,u,(x,int(u-2**(-((x-t*.5)/120)**2)*u)),(x,u))

while time.wait(50):
for e in event.get():
if e.type==QUIT:exit()


This is actually a normal distribution, using 2 as the base of the exponent instead of e, and not dividing by ⎷2π, because without axes, it doesn't really matter if the area under the curve isn't exactly 1.

The last 3 lines just keep the window open until the user closes it manually.

## C#, WPF

Rough approximation with a hand-crafted Bézier curve. To make it more interesting: No use of Line, Path or similar, only Ellipse.

public MainWindow()
{
InitializeComponent();
// Requires a Canvas named Canvas in XAML file
DrawBellCurve(Canvas, 300, 300);
}

public static void DrawBellCurve(Canvas canvas, int width, int height)
{
Point p1 = new Point(0, height);
Point p2 = new Point(0.3 * width, 1 * height);
Point p3 = new Point(0.4 * width, 0.1 * height);
Point peak = new Point(width / 2, 0);
Point p3r = new Point(width - p3.X, p3.Y);
Point p2r = new Point(width - p2.X, p2.Y);
Point p1r = new Point(width, height);
List<Point> controlPoints = new List<Point> { p1, p2, p3, peak, p3r, p2r, p1r };

DrawBezierCurve(canvas, controlPoints, Color.FromRgb(50, 200, 25));
DrawPoints(canvas, controlPoints, 5, Color.FromRgb(80, 80, 220));
}

public static void DrawPoints(Canvas canvas, List<Point> points, double radius, Color color)
{
foreach (var p in points)
{
Ellipse ellipse = new Ellipse();
ellipse.SetValue(Canvas.LeftProperty, p.X - radius / 2);
ellipse.SetValue(Canvas.TopProperty, p.Y - radius / 2);
ellipse.Fill = new SolidColorBrush(color);
}
}

public static void DrawBezierCurve(Canvas canvas, List<Point> controlPoints, Color color)
{
var curvePoints = new List<Point>();
double tStep = 0.01;
for (double t = 0; t <= 1; t += tStep)
{
}

DrawPoints(canvas, curvePoints, 3, color);
}

public static Point GetBezierPoint(List<Point> controlPoints, double t)
{
// De Casteljau's algorithm
if (controlPoints.Count == 1)
{
return controlPoints[0];
}

var newControlPoints = new List<Point>();
for (int i = 0; i < controlPoints.Count - 1; i++)
{
Point p1 = controlPoints[i];
Point p2 = controlPoints[i + 1];
Point p = new Point(
t * p1.X + (1 - t) * p2.X,
t * p1.Y + (1 - t) * p2.Y);
}
return GetBezierPoint(newControlPoints, t);
}


# Java 8

It gets the height and the width from the user, chooses width random booleans and count how many are true, registering the counted frequency. Repeat this until some of the generated frequencies is enough to fill the height:

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.util.Random;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JOptionPane;

public class Bell {
public static int[] bell(int width, int height) {
// I could have used Random.nextGaussian() method, but this way is more fun.
Random r = new Random();
int max = 0;
int[] freqs = new int[width];
for (int j = 0; max < height - 1; j++) {
int count = 0;
for (int i = 0; i < width; i++) {
if (r.nextBoolean()) count++;
}
freqs[count]++;
if (freqs[count] > max) max++;
}
return freqs;
}

public static BufferedImage drawBell(int[] ps, int width, int height) {
BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
for (int i = 0; i < width; i++) {
for (int j = 0; j < ps[i]; j++) {
bi.setRGB(i, height - j - 1, 0xFF00FFFF); // Cyan
}
for (int m = i - 1; m <= i + 1; m++) {
if (m < 0 || m >= width) continue;
for (int n = ps[i] - 1; n <= ps[i] + 1; n++) {
if (n < 0 || n >= height) continue;
bi.setRGB(m, height - n - 1, 0xFF0000FF); // Blue
}
}
for (int j = ps[i] + 1; j < height; j++) {
bi.setRGB(i, height - j - 1, 0xFFFFFFFF); // White
}
}
return bi;
}

public static void main(String[] args) {
String a = JOptionPane.showInputDialog("Give the width:");
String b = JOptionPane.showInputDialog("Give the height:");

int w, h;
try {
w = Integer.parseInt(a);
} catch (NumberFormatException e) {
JOptionPane.showMessageDialog(null, "Invalid width.");
return;
}

try {
h = Integer.parseInt(b);
} catch (NumberFormatException e) {
JOptionPane.showMessageDialog(null, "Invalid height.");
return;
}

int[] freqs = bell(w, h);
BufferedImage image = drawBell(freqs, w, h);

EventQueue.invokeLater(() -> {
JFrame j = new JFrame("Bell curve");
j.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
j.setResizable(false);
j.pack();
j.setVisible(true);
});
}

public static class SimpleSprite extends JComponent {
private final BufferedImage image;
private final Dimension dim;

public SimpleSprite(BufferedImage image) {
this.image = image;
this.dim = new Dimension(image.getWidth(), image.getHeight());
}

@Override
public Dimension getMinimumSize() {
return dim;
}

@Override
public Dimension getMaximumSize() {
return dim;
}

@Override
public Dimension getPreferredSize() {
return dim;
}

@Override
public void paintComponent(Graphics g) {
g.drawImage(image, 0, 0, null);
}
}
}


Screenshot:

# Python and tkinter

I liked Doorknob's generation method and Victor's output (his generation is actually equivalent), so I decided to combine the two with tkinter!

from tkinter import *
import random

bins = [0]*201
for i in range(20000):
x = 0
for j in range(100):
if random.randint(0, 1):
x += 0.5
else:
x -= 0.5
bins[int(x)+100] += 1

master = Tk()

w = Canvas(master, width = 201, height=200)
w.pack()

for i in range(201):
w.create_line(i, 200, i, 200-bins[i]/10, fill="light blue")
w.create_line(i-1, 200-bins[i-1]/10, i, 200-bins[i]/10, fill="blue")


## GeoGebra

I don't know whether it is valid to use an application that is made to draw graphs, but if you enter this in the input, you get a Bell Curve:

f(x) = 3ℯ^(-(x - 1)²)


Or, if you want a customizable bell curve:

a = 0
b = 0
c = 0
d = 0
f(x) = a ℯ^((-(x - b)²) / 2 c²) + d


Then, make sure that you enable the sliders for the variables (if they are disabled, click on the circle next to the variable names). Then, you can set a value for them by sliding.

Image of the curve with the sliders (click to enlarge):

• Although the rules didn't technically require posting them, give us the visuals! We'd love to see the result. And is this program specifically designed to give accessibility options for disabled users? That is great! – Jonathan Van Matre Mar 3 '14 at 15:36
• @JonathanVanMatre: Done. – ProgramFOX Mar 3 '14 at 15:42
• Haha, I see now I made a parsing error when reading your text. Nice graph, though! – Jonathan Van Matre Mar 3 '14 at 16:30
• It's a cool program, fun to mess around with. – Tim Seguine Mar 6 '14 at 22:21

## Java

Throwing 6 dice in every possible combination approaches a 'normal distribution', which happens to be a bell curve.

public class Temp {
public static void main(String[] args) throws Exception {
int[] hist = new int[31];
for (int d1 = 0; d1 < 6; d1++)
for (int d2 = 0; d2 < 6; d2++)
for (int d3 = 0; d3 < 6; d3++)
for (int d4 = 0; d4 < 6; d4++)
for (int d5 = 0; d5 < 6; d5++)
for (int d6 = 0; d6 < 6; d6++)
hist[d1 + d2 + d3 + d4 + d5 + d6]++;
for (int y = 4104; y >= 0; y -= 228)
for (int x = 0; x < 32; x++)
System.out.print(x == 31? '\n' : hist[x] <= y? '\u3000' : (char)('\u2580' + Math.min(Math.ceil((hist[x] - y) / 28.5), 8)));
}
}


Some Unicode tricks make the output smoother:

　　　　　　　　　　　　　　▅█▅
▂███▂
█████
▁█████▁
███████
███████
▅███████▅
█████████
█████████
▇█████████▇
███████████
▃███████████▃
█████████████
▁█████████████▁
███████████████
▃███████████████▃
█████████████████
▁███████████████████▁
▁▁▁▂▅█████████████████████▅▂▁▁▁


# C

Based on random walks

#include <stdio.h>
#include <stdlib.h>

#define X_SIZE 40
#define Y_SIZE 15
#define SMOOTH 100

int main(void)
{
int i,j;
int T[X_SIZE*2];
int w;

for (i=0; i<X_SIZE*2; i++) T[i]=0;

// random walks
do  {
w=X_SIZE;
for (i=0;i<X_SIZE;i++)
w+=rand()%2?1:-1;
T[w]++;
}
while (T[w]<Y_SIZE*SMOOTH);

// display
for (j=Y_SIZE; j>=0; j--)
{
for (i=0; i<X_SIZE*2; i+=2)
printf("%c", (T[i]>j*SMOOTH)?'#':' ');
printf("\n");
}

}


Output :

               ###
###
#####
#####
#####
#######
#######
#########
#########
#########
###########
###########
#############
###############
#######################


# J

load 'plot'
plot (3+i.58)([:+/=)"0 1]3+([:+/?,?,?)"0]1e6#20


Not very creative, but still fun!

Throws three twenty sided dice 1000000 times, summing the result each time. Then to get it in a plot-ready format, we take the array [3..60] and replace each element by the number of times it occures in the random sums.

plot then creates a PDF:

# Octave

c=79;
x=ifft(fft([ones(1,10) zeros(1,c-10)]).^8);
y=(1:c)*0+' ';
for l=-24:-1,
for k=1:c,
if -real(x(k))<l*2e5,
y(k)='*';
end
end
printf([char(y) '\n'])
end


Try it online!

Instead of directly simulating coin flips, this just uses the observation that the pdf of a sum of random variables is the convolution of the pdfs of each of the random variables. An efficient way to do circular convolution is to take the inverse fourier transform of the element-wise product of the fourier transforms of the pdfs of each of the random variables. For the purpose of this problem (not true in general) circular convolution can stand in for linear convolution.

As an example, given the following pdf of a uniform random variable.

                           **********
**********
**********
**********
**********
**********
**********
**********
**********
**********
**********
**********


The above random variable summed with itself

                                *
***
***
*****
*******
*********
***********
***********
*************
***************
*****************
*******************


The uniform random variable summed with itself 7 times.

                                *
*******
***********
*************
***************
*****************
*******************
***********************
*************************
***************************
*******************************
*************************************


## Python (Box-Muller) - 6 lines

This short code uses the Box-Muller transform for simulating a normally distributed variable:

from math import cos, log, pi
from random import random

f = open("normDist.txt",'w')
for i in xrange(10**6):
f.write(str(cos(2*pi*random())*(-2*log(random()))**.5)+'\n')
f.close()


You can plug the values on GNUPLOT or use this script

f=open("normDist.txt",'r')

v = [0 for i in xrange(51)]
for i in f:
v[int(float(i)*10) if float(i)<5 and float(i)>-5 else 0]+=1

m=0
for i in v:
if i>m:
m=i
for i in v[3:]:
for j in xrange(int(70.*i/m)):
print '*',
print


to produce something like this:

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * *
* * * * * * * * * * * * * *
* * * * * * * * * * * *
* * * * * * * * * *
* * * * * * * *
* * * * * * *
* * * * * *
* * * * *
* * * *
* * *
* * *
* *
* *
* *
* *
* *
* *
* * *
* * *
* * * *
* * * * *
* * * * * *
* * * * * * *
* * * * * * * *
* * * * * * * * * *
* * * * * * * * * * * *
* * * * * * * * * * * * * *
* * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

• Not properly oriented according to the question. Should be rotated 90 degrees. – Tim Seguine Mar 6 '14 at 22:17

# awk

#!/ust/bin/awk -f
BEGIN {
#
# do WALKS random walks with OOPS times left or right per walk
#
WALKS=100000
OOPS=39
#
# output will be H lines
# the line width will be 2*OOPS+1
#
H=23
#
# shake awk's pseudorandom generator
#
srand()
#
# do the walks
#
for(i=0;i<WALKS;i++) {
x=0
for(j=0;j<OOPS;j++) rand()<0.5?--x:++x
X[x]++
}
#
# scan for maximum height
#
M=0
for(x=-OOPS;x<=OOPS;x++) {
if(X[x]>M) M=X[x]
}
#
# "draw" into S[x]: strings of H*X[x]/M "*"s
#
for(x=-OOPS;x<=OOPS;x++) {
s=sprintf("%*s",H*X[x]/M," ")
gsub(/./,"*",s)
S[x]=s
}
#
# print S[x] transposed
#
for(y=H;y>0;y--) {
for(x=-OOPS;x<=OOPS;x++) {
if(c=substr(S[x],y,1)) printf c
else printf " "
}
print ""
}
}


Output:

                                        *
* *
* *
* * * *
* * * *
* * * *
* * * *
* * * * * *
* * * * * *
* * * * * *
* * * * * *
* * * * * * * *
* * * * * * * *
* * * * * * * *
* * * * * * * *
* * * * * * * * * *
* * * * * * * * * *
* * * * * * * * * *
* * * * * * * * * * *
* * * * * * * * * * * *
* * * * * * * * * * * *
* * * * * * * * * * * * * *
*******************************************************************************


# Stax, 20 bytes

⌐∞¶J♠fr"▐cS╥aÆ~a╚∩┌I


Run and debug it

This isn't code-golf but I still want to give Stax a try. Calculates frequency of sum of dices rolled 6 times. Note there are no support for random numbers in Stax.

ASCII equivalent:

6R6|^{|+m{o:G{AJ/'**mMrm


Output:

               *
***
***
***
*****
*****
*****
*****
*****
*******
*******
*******
*******
*******
*******
*********
*********
*********
*********
*********
*********
***********
***********
***********
***********
***********
***********
*************
*************
*************
*************
*************
***************
***************
***************
***************
*****************
*****************
*****************
*******************
*******************
*********************
***********************


# Charcoal

≔⟦Ｘφ±⁹⟧θＦ⁹⁹≔Ｅ⊞Ｏθ⁰⁺κ§θ⊖λθ↑θ


Verbose version:

Assign([Power(1000, Negate(9))], q);
for (99) Assign(Map(PushOperator(q, 0), Plus(k, AtIndex(q, Decremented(l)))), q);
Print(:Up, q);


Try it online! Output:

             ||
||
||||
||||
||||
||||
||||||
||||||
||||||
||||||
||||||
||||||||
||||||||
||||||||
||||||||
||||||||
||||||||
||||||||||
||||||||||
||||||||||
||||||||||
||||||||||
||||||||||
||||||||||||
||||||||||||
||||||||||||
||||||||||||
||||||||||||
||||||||||||
||||||||||||||
||||||||||||||
||||||||||||||
||||||||||||||
||||||||||||||
||||||||||||||||
||||||||||||||||
||||||||||||||||
||||||||||||||||
||||||||||||||||
||||||||||||||||||
||||||||||||||||||
||||||||||||||||||
||||||||||||||||||||
||||||||||||||||||||
||||||||||||||||||||
||||||||||||||||||||||
||||||||||||||||||||||
||||||||||||||||||||||||
||||||||||||||||||||||||||
||||||||||||||||||||||||||||