This is an attempt at a reference for the programming language Design by Numbers. I welcome comments and additions. I am writing this in the context of the Computer Science for Smart People course; for an example of Design by Numbers in action, look under Learning to Program.

Generalities

In Design by Numbers (henceforth DBN) the only data type is the signed integer number (signed 32 bits to be precise). The language operates on a rectangular drawing area.
In the DBN drawing model, "color" 100 means full black and 0 means white; think of it as an amount of ink, not as an amount of light.
Notice that the drawing model is not additive; in other words, if you place light grey ink on top of black ink, the result is light grey ink, not black. this observation is mostly for graphic arts people.
There is also a rather hackish way to specify color. In some place where you can specify a grayscale color you can put an RGB triple instead of an ink quantity. For example, paper 100 100 40 sets the paper yellow (and clears it). The RGB components are scaled from 0 (nothing) to 100 (full intensity). This is particularly confusing for HTML junkies.
It is important to recognize that this is a source of confusion: paper 100 gives you black paper, and paper 100 100 100 gives you white paper.

From now on, colorspec means either a grayscale value, or an RGB triplet.

A parameter between square brackets is an optional one; it can be omitted without generating an error.

Wherever a number appears (normally indicated like this: x y x1 a w ) you can insert a numerical expression between parentheses.

Drawing Statements

size x y j
modifies the size of the drawing area. By default the drawing are is 100 x 100.
If given a third parameter j, DBN draws in "fatbit" mode, where each pixel is rendered as a j x j square (.undocumented).
WEIRDNESS WARNING: x and y have to be plain numbers. No numerical expressions or variable references are allowed. This is very bizarre.
paper colorspec
clears the drawing area and paints it in colorspec color.
pen colorspec
sets the drawing color to be colorspec.
ex: pen 30 40 100 gives you a light blue pen
line x1 y1 x2 y2
draws a 1 pixel wide line in the drawing color from the pixel whose coordinates are (x1,y1) to the point (x2,y2).
field x1 y1 x2 y2 n
draws a filled rectangle from the pixel (x1,y1) to (x2,y2) in n% ink.
ex: field 20 10 90 70 50 gives you an off-center middle gray rectangle.
set x y n
set x y red n
set x y green n
set x y blue n
the first form of the command sets the (x,y) pixel to be of n% grey. The other forms of the command set the correspondent color component of the (x,y) pixel to be n.
This is a rather ugly way of setting a pixel color.
ex: set 50 50 80 sets the pixel at coordinates 50,50 to be dark gray
ex: set 50 50 100
set 50 50 red 100
sets the pixel at (50,50) to be bright red (or at least the reddest it can)

Variables

set variablename x
sets the variable named variablename to have the value x.
ex: set a 5 sets the variable named a to the value 5
ex: set a (b*2) sets the variable named a to double the value of the variable b
ex: set a (a+1) sets a to its own value plus one - in other words, it increments a by 1.

Numerical Operators

DBN understands the four operations: + - / *. Notice that division is integer division. Thus 8/3 equals 2 and 5/9 equals 0.
DBN also has the very useful modulus operator, written %. For example, 4/2 is zero, and 9%7 is 2.

Not so obviously, DBN also has the unary minus. Thus

set a (-b)
is valid and does what you expect.

Control Structures

Design by Numbers has no booleans and no if construct. What it has is a simple repeat operation, similar to for ... next in BASIC, and specialized constructs that incorporate a comparison operation. All the control structures must be followed by exactly one block. Blocks are delimited by curly brackets, that's to say { and }. The brackets must be on their own line.

same? a b
if a and b have the same value, execute the following block.
ex:

same? a (b+10)
 {
 field 10 10 90 90 50
 }
if the value of a is equal to the value of b + 10 then draw a medium grey square.
notsame? a b
if a has a different value from b, execute the following block.
smaller? a b
if a is smaller than b, execute the following block.
notsmaller? a b
if a is not smaller than b, execute the following block.
forever
executes the following block for ever
Notice that any code you write after a forever will never be executed.
ex:

forever
 {
  set <mouse 1> <mouse 2> 100
 }
draws a pixel trail after the mouse pointer.
repeat variablename a b
repeats the following block b - a times, with variable variablename changing in value from a to b.
ex:

repeat x 20 40
 {
 line 20 x 50 x
 }
draws a black rectangle from (20,20) to (50,40).

Fugliness

All these directives, IMHO, do not really have a perfect implementation. Using them increases the frequence of flaky events.

fast
DBN has a built-in pause after executing each statement. The idea is that it lets you observe the effect of each statement. If you decide that you do not need the pause, you can instruct the interpreter to omit it with the fast directive.
pause n
pauses execution for n hundreths of a second.
refresh
DBN normally tries to guess the right moment for refreshing the screen. If it is guessing wrong for your application (this can happen when doing animation), you can force a refresh with the refresh directive. Notice that this has the side effect of turning off auto refresh.

Mouse and Keyboard

<mouse 1>
gives the x (horizontal) coordinate of the mouse pointer in the DBN coordinate system.
<mouse 2>
gives the y (vertical) coordinate of the mouse pointer in the DBN coordinate system.
Nota Bene: these numbers will be 0 with the mouse pointer sitting on the bottom left of the drawing area. If the mouse pointer exits this area and stays in the light blue area around the drawing area, you are going to get negative mouse coordinates or coordinates bigger than the drawing area sizes. If the mouse pointer exits the blue area, the value of <mouse 1> <mouse 2> remains frozen at the last value inside the blue area.
I realize that this is tricky. Run this program to clarify matters:

size 100 100 2
forever
{

paper 0
   field 45 45 65 65 30
   field 50 50 60 60 50
   line 50 0 50 100
   line 0 50 100 50
   set x (/10)
   set y (/10)
   smaller? x 0
	{
	field 90 90 100 100 100
	}
   set (50+x) (50+y) 100
   set n ((n + 1) % 100)
   set 0 n 100
   set 0 (n -1) 0
   
}
<mouse 3>
returns 0 if the mouse button (the left one on Windows systems) is not clicked, and 100 if it is clicked.
<key n>
returns 0 if the key corresponding to the n-th letter in the good old English alphabet has been pressed. For example:

// generate amusing display reading from the alpha keyboard
size 104 104
fast
set n 0
repeat a 1 2
{
   set a 1
   repeat i 1 26
   {
      same?  100
      {
         field (i*4) n ((i+1)*4) (n+4) ((i*n)%100)
         set n (n+2)
         smaller? 100 n
         {
            set n 0
         }
      }
      refresh
      set rep i
   }
}

Array

DBN does not provide arrays; it has one big array, and it was added as an afterthought. The syntax is:

<array n> ex:

set <array 1> 3145
line 0 13

in other words, you access the array with an index, and you can use an array expression whenever you would use a number or a variable.

The advantage of the array over variables is that, since you access it through an index variable, you can use to store information that will be accessed in a loop; for example, to draw a mouse trail you need to remember where the mouse was.
More or less everything that you can do with the array you can do with variables, but using the array can be much more practical.

Procedures and functions

DBN allows you to define procedures and functions, that's to say blocks of code that can be called from your program. The difference between procedure and functions is that functions return a value; they can be used as a normal numerical expression (that's to say, wherever a bare number is legal, a function call also is).
Procedures are called as normal DBN statements, while functions are called enclosing the function name between angle brackets.

example:


//a function with two arguments that computes the square of a number and scales it
number square p q
{
   value ((p*p)/q)
}

//a procedure that draws a centered box of size 2*x
command box x
{
   field (1+x) (1+x) (99-x) (99-x) (2*x)
}

repeat x 1 55
{
//plot two parabolas 
   set x  100
//add a shrinking series of boxes on 
   set (100 - x)  (100 - (x*2))
   box x
}

Comments

Comments in DBN are introduced by the string //, and they end at the end of the line. There is no way to terminate a comment before the end of a line, nor can you make a multi-line comment.

Gentle Reader: if you find errors and omissions, or you have suggestions, please /msg me.

Log in or register to write something here or to contact authors.