teaching machines

Madeup

December 13, 2013 by . Filed under madeup, public.

Madeup is a language for making things up. Using commands for moving around, its speakers walk interesting paths through 3-D space and generate geometric models tracing the paths. The models may be viewed in any standard 3-D model viewer or sent to a 3-D printer.

The language was designed for several reasons:

  1. To enable the creation of 3-D models through code. Some models are best sculpted with a mouse in a full-blown 3-D modeler. Others can be expressed more simply using a program.
  2. To teach math and computational thinking from a tangible, “first person” perspective. Madeup programmers build something out of nothing, giving them a high degree of creative involvement and responsibility in the construction process.
  3. To feed the diverse cravings of its designer, who loves programming languages and anything visual.

This document briefly describes the language.

Language

Madeup is a programming language—a language for instructing a machine to perform some action on its user’s behalf. Like most programming languages, Madeup lets its speakers

The language supports recursion, higher order functions, and partial function application.

Geometric Commands

Programmers traverse 3-D space using Cartesian or turtle geometry.

moveto <x> <y> <z>
move <distance>
yaw <degrees>
pitch <degrees>
roll <degrees>

Once a satisfactory path has been traversed, that path can be turned into a geometric model in several ways:

tube
revolve <degrees>
dots
surface <nrows> <ncolumns>
extrude <direction> <height>
forget

Let’s explain these through examples. Consider the following Madeup program, which walks from (3, 0, 0) in the Cartesian coordinate system in a roundabout way to (3, 2, 0):

moveto 3 0 0
moveto 7 0 0
moveto 7 2 0
moveto 3 2 0
tube

Using tube to generate the geometry, we produce a model that surrounds the path with a hose-like structure:

A model generated using the tube command.

If instead of tube we use the revolve command, we spin the path around an axis to produce a surface of revolution:

A model generated using the revolve command.

If we use the dots command, we mark each stopping point along the path with a sphere:

A model generated using the dot command.

If we use all three of tube, dot, and revolve, we get a medley:

A model generated using tube, dots, and revolve—really, three models.

If we use the forget command, we throw away the path without generating any geometry. This is like lifting the pen in Logo:

A (non-)model generated using the forget command.

The surface command doesn’t produce anything meaningful for the above program. Let’s switch to a new program, which visits a 3×3 grid of positions, the center of which is peaked upward:

-- Closest row
moveto 0 0 0
moveto 1 0.5 0
moveto 2 0 0

-- Middle row
moveto 0 0.5 1
moveto 1 1 1
moveto 2 0.5 1

-- Farthest row
moveto 0 0 2
moveto 1 0.5 2
moveto 2 0 2

surface 3 3

Unlike the other commands, the resulting model is not a solid object:

A model generated using the surface command.

The last command, extrude, treats the path as the perimeter of a solid object’s base. It pulls the perimeter up some specified height and fills in walls, floor, and ceiling. In the following example, we trace the path of a star and then extrude it 5 units along the negative Z axis:

moveto 0 0 0
repeat 5
  move 10
  yaw -144
  move 10
  yaw 72
end
extrude 0 0 -1 5
A star built through extrusion.

A star built through extrusion.

Flow Commands

Besides commands to move and orient in 3-D space, Madeup has commands for controlling which commands are executed and how often:

if <condition> <then-block> else <else-block> end
repeat <n> <block> end
while <condition> <block> end
for <identifier> to <upper-bound> <block> end
for <identifier> through <upper-bound> <block> end
for <identifier> in <lower-bound>..<upper-bound> <block> end

Let’s start with a simple repeat loop. We surround a block of commands with a repeat loop and quantify how many times we’d like that block to execute. In the following program, we move 5 units forward and turn right 30 degrees—and then we do this four more times:

moveto 0 0 0
repeat 5
  move 5
  yaw 30
end
tube

We get a curved tube:

A model generated using a simple loop.

Loops can nest inside of each other. In the following program: we walk along a 5×5 grid using two for loops and generate a sphere at each location:

for r to 5
  for c to 5
    moveto c 0 r
  end
end

dot

A model generated using nested loops.

Conditional statements let us choose between commands based on some criteria. We can perturb a walk along a straight line, for example, by having one step zig and the next step zag. If we’re on an even step, let’s perturb right. Otherwise, let’s perturb left:

for i to 10
  if i % 2 == 0
    moveto 0.5 i 0
  else
    moveto -0.5 i 0
  end
end

tube

A zigzag created through conditional logic.

New Commands

If we have a sequence of code that represents a meaningful action, we can give it a meaningful name. This name becomes a new command, which we can use to execute the sequence. In the following program, for example, the code to draw a square is given the name square. We invoke the square command whenever we want a square to be drawn:

to square =
  repeat 4
    move 10
    yaw 90
  end
  tube
end

moveto 0 0 0
square
moveto 5 -5 0
square

Adding a new command to Madeup to draw a square.

Variables

Numbers in Madeup programs can also be given names. The benefits are twofold. Mathematical expressions that use variables are easier to make sense of, and it’s easier to try out different values if the number isn’t sprinkled throughout the code. To draw a regular, n-sided polygon, we might use the following program:

n = 5
angle = 360.0 / n

moveto 0 0 0
repeat n
  move 5
  yaw angle
end

tube

An n-sided polygon, where n is 5—a pentagon.

The value of n can be changed freely to generate hexagons, heptagons, octagons, nonagons, and so on.

Special Variables

Madeup relies on a few special variables when generating geometry:

nsides -- Defines the smoothness of the geometry (tube, dot, revolve)
radius -- Defines the girth of the geometry (tube, dot)
axis -- Defines the direction of motion (revolve, extrude)

By assigning different values to these variables, we can generate a snowman with varying levels of facetedness and body segment size using the dot command:

nsides = 6
radius = 1
moveto 0 6.5 0
dot

nsides = 15
radius = 2
moveto 0 4 0
dot

nsides = 50
radius = 3
moveto 0 0 0
dot

A snowman with changing radius and nsides.

 

Recursion

Madeup supports recursion, where functions call themselves. The following program, for example, recursively generates a Hilbert curve:

size = 10

to hilbert level degrees =
  if level > 0
    yaw degrees * -1
    hilbert level - 1 degrees * -1
    move size
    yaw degrees
    hilbert level - 1 degrees
    move size
    hilbert level - 1 degrees
    yaw degrees
    move size
    hilbert level - 1 degrees * -1
    yaw degrees * -1
  end
end

moveto 0 0 0
hilbert level:4 degrees:90
tube
Hilbert's space-filling curve, generated with recursion.

Hilbert’s space-filling curve, generated with recursion.

Where Can I Find It?

The language and its execution environment are under active development. You can try it out at http://madeup.club:9013.