Tree showing "structures" (light patterns)

CTCL

Structures

(Light patterns)

Rather than writing code to turn each individual string of lights on or off, we organize them by colors and patterns. The collection of non-tree outlets or "peripherals" can be organized in a similar fashion.

Tree patterns

Diagram of tree layout
Layout of tree with 16 blocks
The diagram at right shows one possible division of a "tree" into four rows and five columns. Each "block" of lights is numbered. Each block contains several colors of lights, independently switched.

The diagram shows 16 blocks, numbered starting at the top of the tree. We have found it somewhat more convenient to start numbering at the top of the tree, but the choice is arbitrary. We have worked with trees having as many as 46 blocks in five colors, numbered from bottom to top, and as few as 16 blocks in six colors, numbered from top to bottom.
The main advantage of numbering from the top is that if rows are added or removed at the bottom, very little of the code changes; in fact, in many cases there would be no changes at all
For purposes of illustration, we will work with a simplified "tree" containing three rows and three columns. We number the blocks of this tree starting at the top, thus:
 1  2  3  <-- row 1
456 <-- row 2
789 <-- row 3

As indicated, we will lay out three rows in the natural way. Here is the COBOL-like code to accomplish this:
1 tree               -- This declares the "tree" (as opposed to non-tree, later).
  2 rows             -- This declares the collection of rows at level 2.
    3 row 1          -- This declares row 1.
      8 block 1      -- Each block is declared at level 8.
      8 block 2      -- (Like "level 88" in COBOL, "level 8" is special here.)
      8 block 3      -- All blocks in row 1 are listed in order.
    3 row 2          -- Row 2 is declared here.
      8 block 4      -- All rows must be declared together in order to be part of
      8 block 5      --   the larger structure called "rows".
      8 block 6      -- Blocks are special and can be part of anything.
    3 row 3          -- Row 3 is declared here.
      8 block 7      -- Again, the blocks are listed in order.
      8 block 8
      8 block 9 
We can also define columns, as in
Small 3x3 tree
  2 columns
    3 column 1       -- Column 1 declared here.
      8 block 1      -- Same kind of structure as rows,
      8 block 4      --   just using different blocks.
      8 block 7
    3 column 2
      8 block 2
      8 block 5      -- Notice that comments use Ada-style double hyphens.
      8 block 8      -- This language was developed in 1987-88 when Ada seemed
    3 column 3       --   to be the wave of the future. (Boy, did we get fooled!)
      8 block 3
      8 block 6
      8 block 9
Now the object of this whole game is to make it possible to write code like this:
turn row 1 red          -- sort of self-explanatory
do i = 1 to 3           -- like unto a "for" statement in C, or "DO" in Fortran
  turn column i yellow  -- sort of self-explanatory, but using variable i
  call tdelay(0)        -- wait until next pulse from tick track
enddo                   -- required close of "do" loop
In "real life," of course, the top of the tree is very narrow, so that one "row" consists of a single triangular "block". (Usually this lone block is not part of any column, but that decision is up to the programmer.)

The more blocks you have, the more patterns make sense, such as diagonals, marquee (border around the edges), and so on.

See the turn statement for more details on handling patterns and colors.

Non-tree Peripherals

Non-tree peripherals are arranged more by groups than "patterns". For example,
1 non-tree
  2 whole_star
    3 star 1      -- inside
      8 outlet 1
    3 star 2      -- outside
      8 outlet 2
  2 chase_lights
    8 outlet 3
  2 swag_lights
    8 outlet 4
  2 bushes
    3 bush 1
      8 outlet 5
    3 bush 2
      8 outlet 6
    3 bush 3
      8 outlet 7
... and so on.

The keyword "outlet" serves the same purpose as "block", but an "outlet" does not have colors associated with it. It has only two ways to "turn", namely on and off.

Sometimes you want "antiphonal" groups of bushes, such as on either side of the driveway, so grouping them into "right" and "left" makes sense:
  2 bushes
    3 right_bushes
      4 bush 1
        8 outlet 5
      4 bush 2
        8 outlet 6
      4 bush 3
        8 outlet 7
    3 left_bushes
      4 bush 4
        8 outlet 8
      4 bush 5
        8 outlet 9
This allows you to write code such as
    turn bushes off
    do i = 1 to 5
      turn bush i on      -- turn bushes on and off in sequence
      call tdelay(0)      -- delay until next tick
      turn bush i off     
    enddo
    turn right_bushes on  -- right side of driveway
    call tdelay(0)
    call tdelay(0)        -- delay 2 ticks
    turn right_bushes off
    turn left_bushes on   -- left side of driveway "echo"
    call tdelay(0)
    call tdelay(0)
    turn left_bushes off
There are several rather arbitrary rules governing how the structure code is arranged. These rules are to make the compiler simpler to write.
  1. Tree blocks all come before non-tree peripheral outlets.
  2. Names must be unique; "row 1" is considered different from "row 2".
    • Names distinguished only by number must be grouped together at the same level, as in the examples above.
    • Names distinguished by numbers must occur in increasing order.
    • To be slightly redundant, names distinguished only by numbers may not have any other intervening names at the same level.
  3. The first appearance of every block must be in sequential order with the others. (This is usually easy, because we generally list rows first, and the blocks within the rows.) After the first appearance, blocks can be in any order.
  4. The same rule follows for outlets. If any outlets are skipped, they must be included in the list anyway, in order. (Why would you do this? Because the cables all have six sets of conductors and a six-plex outlet box on the end, and sometimes there are only 4 or 5 peripherals at that location, but we may want to allow for plugging in some blo-glo wise men or something.)
    I have a rather kludgy way of listing the outlets, just to get them all in order. I invent a "phony group" coded thus:
    1 non-tree
      2 phony_group
        8 outlet 1
        8 outlet 2
        ...
    
    This phony group could also be used to turn everything off, for example, as in "turn phony_group off", in which case I would probably choose a more sensible name like "all_outlets" instead of "phony_group".