
Each time the worker in Warehouse tries to move, the program has to ask what is in the square ahead. Floor or a goal? Walk in. A crate, on a goal or not? Try to push it. Anything else? Stay put. Written with = and or, those questions get long. Pascal has a neater way to ask "is this one of these?" - the set.
A set is written as values in square brackets:
[Floor, Goal]
and in asks whether a value is one of them:
if T in [Floor, Goal] then
Writeln('walk in');
That says exactly what (T = Floor) or (T = Goal) says, in half the space, and it goes on reading well with five values or twenty.
A set can hold ranges too: ['0'..'9'] is the ten digit characters, and [1, 3..6, 9] is 1, 3, 4, 5, 6 and 9. [] is the empty set, with nothing in it.
On the Einstein's screen the square brackets are drawn as arrows, and typed with the LEFT and RIGHT arrow keys (S3).
A set can be kept in a variable. Its type is set of the kind of value it holds:
type
Tile = (Wall, Floor, Goal, Crate,
CrateOnGoal);
TileSet = set of Tile;
var
Free, Crates: TileSet;
...
Free := [Floor, Goal];
Crates := [Crate, CrateOnGoal];
and then if Next in Free then reads like the rule of the game.
The values in a set must be of a type with no more than 256 of them, numbered from 0 to 255 - an enumerated type, Char, Byte, or a subrange such as 0..100. set of Integer is too big: Error 70: Set base type out of range.
Like enumerated values, a set cannot be printed (Error 66).
| Operator | Gives | Example |
|---|---|---|
+ | everything in either | Free + Crates holds all four |
* | only what is in both | [1..6] * [4..9] is [4, 5, 6] |
- | the first without the second | Free - [Goal] is [Floor] |
= | true if exactly the same | Free * Crates = [] is true: nothing in both |
<= | true if everything in the first is in the second | [Floor] <= Free is true |
Sets of characters are the easy way to sort out what someone typed:
if Ch in ['0'..'9'] then
Writeln('a digit');
if UpCase(Ch) in
['A', 'E', 'I', 'O', 'U'] then ...
program CanMove;
type
Tile = (Wall, Floor, Goal, Crate,
CrateOnGoal);
var
T: Tile;
begin
for T := Wall to CrateOnGoal do
begin
Write(Ord(T), ': ');
if T in [Floor, Goal] then
Writeln('walk in')
else if T in [Crate,
CrateOnGoal] then
Writeln('push')
else
Writeln('blocked');
end;
end.
Starting from
Turbo freshly started, Y, a new work file called CANMOVE.
What you should see
0: blocked
1: walk in
2: walk in
3: push
4: push
Tiles 0 to 4 are Wall, Floor, Goal, Crate and CrateOnGoal.
Goal out of [Floor, Goal]. What happens to tile 2?T in [Floor, Goal] to (T = Floor) or (T = Goal). Does anything change?Free of set of Tile, set it to [Floor, Goal], and try to Writeln(Free). What does Turbo say?18.1 Ask for a word and count its vowels, using a set.
18.2 Ask for one character and say whether it is a digit.
18.3 Print the numbers from 1 to 10 that are in both [1..6] and [4..9], using *.
Worked solutions are in Appendix II.
| Symptom | Cause |
|---|---|
Error 70: Set base type out of range | A set of something with more than 256 values, or values past 255 - such as set of Integer. |
Error 66: I/O are not allowed | Trying to print a set. Test its members with in. |
| A letter is not found in a set of letters | Capitals differ from small letters. UpCase it first, or put both in the set. |
A set is written [a, b, c..d]; in tests whether a value is in it. set of T makes a set type, for types of at most 256 values. +, * and - combine sets; = and <= compare them. A set cannot be printed.
S19, Lists Of Things - arrays: many values under one name, and arrays of arrays - which is what a Warehouse board is.