swarm-0.4: data/scenarios/Tutorials/conditionals.yaml
version: 1
name: Conditionals
description: |
Learn how to write conditional expressions.
objectives:
- goal:
- |
The 4x4 gray square contains 4 `very small rock`{=entity}s --- so
small they cannot be seen! Your goal is to collect all of
them and bring them back to your base; you win when you have
all 4. There is one rock in each row and column, but
otherwise you can't be sure where they are. Your best bet is
to sweep over the entire 4x4 square and pick up a `very small rock`{=entity}
any time you detect one.
- |
The `ishere` command, with type `text -> cmd bool`{=type}, can be used
for detecting the presence of a specific item such as a `very small rock`{=entity}.
What we need is a way to take the `bool`{=type} output from `ishere`
and use it to decide whether to `grab` a rock or not.
(Trying to execute `grab` in a cell without anything to grab will
throw an exception, causing the robot to crash.)
- |
As you might expect, `if` can be used to write
conditional expressions. However, `if` is not special syntax;
it is simply a built-in function of type
- |
```
if : bool -> {a} -> {a} -> a
```
- |
It takes a boolean expression and then returns either the first or second subsequent
argument, depending on whether the boolean expression is true or false, respectively.
- |
The type variable `a`{=type} can stand for any type; `{a}`{=type}
indicates a *delayed* expression of type `a`{=type}. Normally,
function arguments are evaluated strictly before the function
is called. Delayed expressions, on the other hand, are not
evaluated until needed. In this case, we want to make sure
that only the correct branch is evaluated. To write a value
of type, say, `{int}`{=type}, we just surround a value of type `int`{=type}
in curly braces, like `{3}`. This is why arguments to `build`
must also be in curly braces: the type of `build`
is `{cmd a} -> cmd robot`{=type}.
- |
**TIP:** Note that `if` requires a `bool`{=type}, not a `cmd bool`{=type}! So you cannot directly say
`if (ishere "very small rock") {...} {...}`{=snippet}.
Instead you can write `b <- ishere "very small rock"; if b {...} {...}`{=snippet}.
You might enjoy writing your own function of
type `cmd bool -> {cmd a} -> {cmd a} -> cmd a`{=type} to encapsulate this pattern.
- |
**TIP:** the two branches of an `if` must have the same type. In particular,
`if ... {grab} {}`{=snippet} is not
allowed, because `{grab}` has type `{cmd text}`{=type} whereas `{}` has type `{cmd unit}`{=type}.
In this case `{grab; return ()}` has the right type.
condition: |
try {
n <- as base {count "very small rock"};
return (n == 4)
} { return false}
solution: |
def tL = turn left end;
def tB = turn back end;
def x4 = \c. c;c;c;c end;
def VSR = "very small rock" end;
def ifC = \c.\t.\e. b <- c; if b t e end;
def pick = move; ifC (ishere VSR) {grab; return ()} {} end;
def pickrow = x4 pick; turn back; x4 move end;
build {
turn south; x4 (move; tL; pickrow; tL); tB; x4 move; x4 (give base VSR)
}
robots:
- name: base
heavy: true
dir: [0,1]
display:
char: Ω
attr: robot
devices:
- logger
- 3D printer
- dictionary
inventory:
- [8, compass]
- [8, solar panel]
- [8, logger]
- [8, treads]
- [8, grabber]
- [8, scanner]
- [8, lambda]
- [8, branch predictor]
- [8, 3D printer]
- [0, very small rock]
entities:
- name: very small rock
display:
invisible: true
description:
- A small rock. It is so small, it is practically invisible.
properties: [portable]
world:
palette:
'Ω': [grass, null, base]
'.': [grass]
'_': [stone]
'o': [stone, very small rock]
'┌': [stone, upper left corner]
'┐': [stone, upper right corner]
'└': [stone, lower left corner]
'┘': [stone, lower right corner]
'─': [stone, horizontal wall]
'│': [stone, vertical wall]
upperleft: [-1, 1]
map: |
┌─────┐
│Ω....│
│.o___│
│._o__│
│.___o│
│.__o_│
└─────┘