
Warehouse is built of squares, and every square is one of a few things: a wall, a bit of floor, a goal, a crate. You could number them - 0 for a wall, 1 for floor - and remember which is which. Or you could tell Pascal what the things are called, and have it remember for you, and refuse to let a square be anything else. That is what your own types are for.
type
Tile = (Wall, Floor, Goal, Crate);
var
T: Tile;
This declares a new type, Tile, whose values are exactly the four names in brackets - in that order. A Tile variable can hold Wall, Floor, Goal or Crate, and nothing else:
T := Floor;
if T = Wall then ...
The names are new words in your program, as good as True and False.
Because the values have an order, several things you know from numbers work:
Ord(T) gives its position, counting from 0: Ord(Wall) is 0, Ord(Crate) is 3.Succ and Pred give the next and previous values: Succ(Wall) is Floor.Wall < Crate is true.for runs through them: for T := Wall to Crate do, or downto.case chooses on them.Tile(3) is Crate.Turbo will not print an enumerated value: Writeln(T) is
Error 66: I/O are not allowed. Press <ESC>
The names are for you and the compiler; to show one, print its Ord, or - much better - write a procedure that shows each value as it should appear. That is this section's program, and in Warehouse it draws the board.
A subrange is a type limited to part of another:
type
Col = 1..20;
Mark = 0..100;
A Col is an integer from 1 to 20. Subranges say what a variable is for - a column on a board of 20, a mark out of 100 - and, with range checking on, Turbo holds you to it.
Byte is a subrange Turbo already has, from 0 to 255, and it wraps like an integer: 255 plus 1 is 0.
A number that means something should have a name:
const
Width = 20;
Height = 16;
type
Col = 1..Width;
The const section comes before type. A constant can be used anywhere its value could - in sums, in a subrange - and it cannot be changed: Width := 30 is Error 41. When the board grows to 24 wide, you change one line.
Here is a trap. With Turbo as it starts, nothing checks the limits. A Col variable will happily hold 50; C := 25 is not even an error when compiled; and Succ(Crate) gives a fifth, nameless tile with Ord 4. The limits you declared are documentation and nothing more.
Put this at the top of the program:
{$R+}
and Turbo checks assignments to subrange variables as the program runs. The first value out of range stops it:
Run-time error 91, PC=004E
Program aborted
and ESC shows you the assignment that did it. Borland's manual recommends {$R+} while a program is being developed, and taking it out once the program works, because the checking slows the program down.
program Tiles;
type
Tile = (Wall, Floor, Goal, Crate);
var
T: Tile;
procedure Show(What: Tile);
begin
case What of
Wall: Write('#');
Floor: Write(' ');
Goal: Write('.');
Crate: Write('$');
end;
end;
begin
for T := Wall to Crate do
begin
Show(T);
Writeln(' is tile ', Ord(T));
end;
end.
These are the characters Warehouse will draw its board with: # for a wall, a space for floor, . for a goal and $ for a crate.
Starting from
Turbo freshly started, Y, a new work file called TILES.
What you should see
# is tile 0
is tile 1
. is tile 2
$ is tile 3
The floor's line begins with its own character - a space.
Show(T); to Writeln(T);. What does Turbo say?Worker, to the end of the type, and change the loop to run to Worker. What is printed for it, and why?Crate downto Wall instead. What happens to the order?17.1 Declare Direction = (North, East, South, West) and write a function TurnRight that gives the next direction clockwise - with West turning back to North. Starting from North, turn right six times, printing Ord of each direction.
17.2 Declare Mark = 0..100, switch on range checking, set a Mark to 99 and add 2 to it. What happens?
17.3 Declare constants Width = 20 and Height = 16, and print how many squares a board that size has.
Worked solutions are in Appendix II.
| Symptom | Cause |
|---|---|
Error 66: I/O are not allowed | Writing an enumerated value. Print its Ord, or show it through a case. |
| A variable holds a value outside its declared range | {$R+} is not on; nothing checks. |
Run-time error 91 | A value out of range with {$R+} on. ESC shows where. |
Error 41 assigning to a constant | Constants cannot change. Use a variable. |
A case on your type does nothing | The value has no label - perhaps a value you added to the type later. |
type Tile = (Wall, Floor, Goal, Crate); makes a type whose values are those names, in order; Ord, Succ, Pred, comparisons, for and case all work on it, but it cannot be printed. Subranges such as 1..20 limit a type; const names a value that never changes. Nothing is range-checked unless {$R+} is on, and then an out-of-range value is Run-time error 91.
S18, Sets - "is this one of those?" in one test: the question Warehouse asks every time the worker moves.