Bricklayer provides a function, called *generateRandomBrickFn*, that can be used to generate random bricks. Before describing the details of the *generateRandomBrickFn* it is important to understand what generating a random brick means (what it should mean).

Slides covering this material can be found here.

## Generating Random Values

In this discussion we will ignore the idiosyncrasies surrounding how computers represent real numbers and issues surrounding equality comparisons.

Virtually all programming languages provide a variety of ways to generate a random (real) number that, mathematically speaking, is in the range 0.0 ≤ n < 1.0. Note that, in this range, n can never equal 1.0, but can equal 0.0. To get a random number, one typically calls a special function. The basic random number function is a nullary function. Its name can vary from language to language, but the function is typically called *random* or *rand*.

Let *random* denote a function that when called generates a random number in the range 0.0 ≤ n < 1.0. Let us assume that *random* is a nullary function which can therefore be called as follows:

*random *()

### Simulating the Flip of a Coin

The following algorithm shows how the *random* function can be used to simulate a coin flip. In the algorithm below, H stands for “heads” and T stands for “tails”.

- Let n = random ()
- if n < 0.5 then print (“H”) else print (“T”)

This algorithm can be easily implemented in SML. An important question is: What kind of output could one expect from a program that flipped a coin, say, 10 times?

- Would you expect 5 heads and 5 tails?
- Would you expect 10 heads and 0 tails?

I conducted an experiment where I flipped an actual coin 10 times and got the following sequence of heads (H) and tails (T).

H T T T T T H H H H

One important thing to note about the sequence is that random does not mean “evenly distributed”. For example, after seeing a sequence of 3 tails, it is incorrect to assume that the next coin flip must yield heads.

What would happen if I ran the experiment again? What would be the chances (i.e., the odds) that same sequence of heads and tails would occur? Now let us consider writing a program that conducts the coin-flipping experiment on our behalf. What would you want to have happen if you ran such a program twice?

- Would you want the program to produce the same output every time it is executed?
- Would you want the program to produce the same output if it is executed on a different computer?
- Would you want the program to produce a (possibly) different output everytime it is executed? In this case, how might this impact your ability to test the program?

### Simulating the Roll of a Die

The following algorithm shows how the *random* function can be used to simulate the roll of a six-sided die. The basic idea here is to partition the range 0.0 ≤ n < 1.0 into six equal sections and associate each section with (aka, map each section to) a side of the die.

- Let n = random ()
- if 0.0/6.0 ≤ n < 1.0/6.0 then print (“1”)
- else if 1.0/6.0 ≤ n < 2.0/6.0 then print (“2”)
- else if 2.0/6.0 ≤ n < 3.0/6.0 then print (“3”)
- else if 3.0/6.0 ≤ n < 4.0/6.0 then print (“4”)
- else if 4.0/6.0 ≤ n < 5.0/6.0 then print (“5”)
- else if 5.0/6.0 ≤ n < 6.0/6.0 then print (“6”)

This algorithm can also be easily implemented in SML.

I conducted an experiment where I rolled an actual die 10 times and got the following sequence of numbers.

3 5 1 2 1 5 2 2 5 2

Note that the numbers 4 and 6 never appeared. Does this imply that the die is “loaded”? No. If I roll the die five more times, will I be guaranteed that 4 and/or 6 will appear? No. It is important to appreciate that random number sequences have such properties.

## Bricklayer’s Random Brick Function

Bricklayer provides a function, called *generateRandomBrickFn*, that can be used to generate random bricks. This function implements an algorithm similar to the coin-flipping and die-rolling algorithms described previously.

Let *brickList* denote a list of bricks. The evaluation of the expression

generateRandomBrickFn brickList

will produce a nullary function value as its result. A val-declaration can be used to bind a variable (i.e., our desired function name) to this nullary function value as follows.

val myName = generateRandomBrickFn brickList;

The evaluation of the function call “myName ()” will return a brick, randomly selected from *brickList*.

## Predefined Brick Lists

Bricklayer provides a set of predefined brick lists that can be used to generate random brick functions. This set includes the following brick lists.

- grayScale
- greenScale
- blueScale
- purpleScale
- redScale
- warmScale
- brownScale
- clearScale
- allOneBitBricks

Consult the Bricklayer documentation on Pieces for a complete listing of all predefined brick lists as well as the bricks they contain.

## Example 1 – A one dimensional sequence of RED and BLACK bricks.

This first example represents Bricklayer’s version of a sequence of coin flips. A brickList is defined that contains two bricks, a BLACK brick and a RED brick. We can think of one of these bricks as denoting “heads” and the other as denoting “tails”. Using this *brickList*, a random nullary funtion is declared called *randomBrick*. When called, the function *randomBrick* will return a randomly selected brick from the *brickList*. Specifically, the randomBrick function will randomly select either a BLACK brick or a RED brick and return this brick as its result.

The function *sequence0* creates a sequence, running along the x-axis, consisting of 2 bricks randomly selected from *brickList*. Val-declarations are used to bind the variables *brick1* and *brick2* to random bricks obtained by evaluating the function call *randomBrick ()*.

A geometric algorithm is used to create longer and longer sequences along the x-axis. The function *sequence1* creates an artifact consisting of two *sequence0* artifacts placed side-by-side. The remaining sequence functions construct their artifacts in a similar fashion.

open Level_3; val brickList = [BLACK,RED]; val randomBrick = generateRandomBrickFn brickList; fun sequence0 (x,z) = let val delta = 1; val brick1 = randomBrick (); val brick2 = randomBrick (); in put2D (1,1) brick1 (x + 0 * delta, z); put2D (1,1) brick2 (x + 1 * delta, z) end; fun sequence1 (x,z) = let val delta = 2*1; in sequence0 (x + 0 * delta, z ); sequence0 (x + 1 * delta, z ) end; fun sequence2 (x,z) = let val delta = 2*2*1; in sequence1 (x + 0 * delta, z ); sequence1 (x + 1 * delta, z ) end; fun sequence3 (x,z) = let val delta = 2*2*2*1; in sequence2 (x + 0 * delta, z ); sequence2 (x + 1 * delta, z ) end; fun sequence4 (x,z) = let val delta = 2*2*2*2*1; in sequence3 (x + 0 * delta, z ); sequence3 (x + 1 * delta, z ) end; build2D (32,32); sequence4 (0,0); show2D "random in 1D";

## Example 2 – A four-colored two dimensional random brick sequence.

The code in this example creates a chessboard-like artifact in which unit bricks (i.e., bit-bricks) are randomly selected from the brick list

[RED, GREEN, YELLOW, BLUE]

Note that bricks are only created in the body of the function *board0*. More specifically, the put2D function is used to create four unit bricks in a square configuration. Each brick in this configuration is randomly selected from brickList via the function call *randomBrick ()*.

A standard geometric algorithm is then used to create a 16×16 chessboard-like artifact.

It is worth mentioning that the distribtion of brick colors can be changed by creating a brickList in which desired bricks occur more frequently. For example, the following brick list

[RED, GREEN, YELLOW, BLUE, BLUE]

will randomly select BLUE bricks more frequently than other colored bricks. While this technique offers some control over brick distribution it is not meant to be used as a mechanism to create complex distributions.

open Level_3; val brickList = [RED, GREEN, YELLOW, BLUE]; val randomBrick = generateRandomBrickFn brickList; fun board0 (x,z) = let val delta = 1; val brick1 = randomBrick (); val brick2 = randomBrick (); val brick3 = randomBrick (); val brick4 = randomBrick (); in put2D (1,1) brick1 (x , z ); put2D (1,1) brick2 (x + delta, z ); put2D (1,1) brick3 (x + delta, z + delta); put2D (1,1) brick4 (x , z + delta) end; fun board1 (x,z) = let val delta = 2*1; in board0 (x , z ); board0 (x + delta, z ); board0 (x + delta, z + delta); board0 (x , z + delta) end; fun board2 (x,z) = let val delta = 2*2*1; in board1 (x , z ); board1 (x + delta, z ); board1 (x + delta, z + delta); board1 (x , z + delta) end; fun board3 (x,z) = let val delta = 2*2*2*1; in board2 (x , z ); board2 (x + delta, z ); board2 (x + delta, z + delta); board2 (x , z + delta) end; build2D (32,32); board3 (0,0); show2D "random 2D";