 |
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
|
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 |
| 4 | 5 | 6 | <-- row 2 |
| 7 | 8 | 9 | <-- 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.
- Tree blocks all come before non-tree peripheral outlets.
- 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.
- 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.
- 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".