Today is a great day: we will learn the buggles to play Dance Revolution, this game beloved of some students where the player has to move its feet on the carpet according to the instructions presented on the screen, and following the music. But before that, we have some details to study first.
[!java|scala]There is one detail we omitted about the conditional syntax: if a branch contains only one instruction, then the curly braces become optional. So, the two chunk of code are equivalent:
if (condition) { whatToDoIfTheConditionIsTrue(); } else { whatToDoElse(); }
if (condition) whatToDoIfTheConditionIsTrue(); else whatToDoElse();
Actually, you can do the same for loops body that are reduced to one instruction only. But beware, this becomes dangerous if you chain the if instructions like this:
if (isOverBaggle()) if (x == 5) left(); else right(); forward();
In fact, it does not turn right when there is no baggle on the ground AND x equals 5, but when the buggle found a baggle on the ground and x equals anything but 5. Putting this otherwise, the buggle understands the previous code as if it were written the following way (note that the else were moved to the right):
if (isOverBaggle()) if (x == 5) left(); else right(); forward();
The first lesson of this is that the indentation is very important to help humans understanding, even if it does not change the actual meaning of the code. We could have written the following code and obtain the same result. But if you want a human to read and review your code, you really want to indent it correctly. That's for example the case if you want a professor to read it (to grade it or to answer a question about it), or if you want to reuse your code later, or even if you need to debug your code yourself.
if (isOverBaggle()) if (x == 5) left(); else right(); forward();
The second lesson is that a else branch always connects to the closest if. This may be a bit troublesome in some case, and it may be easier to add more braces than strictly needed to remove any ambiguity.
[/!]You sometimes want to ask the buggle something similar to:
if it's raining, take an umbrella; if not, and if it's a hot day, take a bottle of water; if not and if it's July 4th, take an American flag
The trap is that we want at most one of these actions to be taken. That is to say, if it's raining a very hot July 4th, we don't want the buggle to get outside with an umbrella, some water and a flag, but simply with an umbrella. The following code is thus WRONG.
[!java|scala]if (rainy()) takeUmbrella(); if (hot()) takeWater(); if (todayIsJuly4th()) takeFlag();[/!][!python]if rainy(): takeUmbrella() if hot(): takeWater() if todayIsJuly4th(): takeFlag()[/!]
Indeed, since the conditions are evaluated one after the other, there is a risk that you go to the July 4th march on a rainy day. Instead, we should use something like this to ensure that once we found a true condition, we won't evaluate the next ones.
[!java|scala]if (rainy()) { takeUmbrella(); } else { if (hotDay()) { takeWater(); } else { if (todayIsJuly4th()) { takeFlag(); } } }[/!][!python]if rainy(): takeUmbrella() else: if hotDay(): takeWater() else: if todayIsJuly4th(): takeFlag()[/!]
Unfortunately, such a cascade of conditionals is quite difficult to read. It is better to
[!java|scala]omit the curly braces for the else statements. Some languages
even introduce a specific construct for these else if, but not [!thelang].[/!]
[!python]change the sub-blocks using the elif
keyword to mark
explicitly these "else if" branches.[/!]
[!java|scala]if (rainy()) { takeUmbrella(); } else if (hotDay()) { takeWater(); } else if (todayIsJuly4th()) { takeFlag(); }[/!][!python]if rainy(): takeUmbrella() elif hotDay(): takeWater() elif todayIsJuly4th(): takeFlag()[/!]
Buggles can tag graffitis on the ground of their world. For that, they use the four following methods:
[!java]boolean[/!] isOverMessage()[!scala]:Boolean[/!]
:
returns [!java|scala]true[/!][!python]True[/!]
if and only if there is a
message on the ground.[!java]String[/!] readMessage()[!scala]: String[/!]
:
returns the message written on the ground (or an empty string if nothing is written).[!java]void[/!] writeMessage([!java]String [/!]msg[!scala]: String[/!])
:
writes the specified message down on the ground. If there is already a message on the
ground, the new content is added at the end of the existing message.[!java]void [/!]clearMessage()
: clears what is written on the ground.Message | What to do | Mnemonic |
[!java]'R'[/!][!scala|python]"R"[/!] | Turn right and move one step forward | Right |
[!java]'L'[/!][!scala|python]"L"[/!] | Turn left and move one step forward | Left |
[!java]'I'[/!][!scala|python]"I"[/!] | Turn back (U-turn) and move one step forward | Inverse |
[!java]'A'[/!][!scala|python]"A"[/!] | Move one step forward | First letter of the alphabet |
[!java]'B'[/!][!scala|python]"B"[/!] | Move two steps forward | Second letter of the alphabet |
[!java]'C'[/!][!scala|python]"C"[/!] | Move three steps forward | Third letter of the alphabet |
[!java]'Z'[/!][!scala|python]"Z"[/!] | Move one step backward | One letter before the end of the alphabet |
[!java]'Y'[/!][!scala|python]"Y"[/!] | Move two steps backward | Two letters before the end of the alphabet |
[!java]'X'[/!][!scala|python]"X"[/!] | Move three steps backward | Three letters before the end of the alphabet |
(anything else) | Stop dancing. |
You have to keep dancing as long as there is some dancing steps to do,
i.e., as long as we are not in cell which content is not described in the table.
The easier for that is to use a boolean variable (finished
)
as termination condition to a while
loop.
It should be initialized to [!java|scala]false[/!][!python]False[/!]
, and
switched to [!java|scala]true[/!][!python]True[/!]
as soon as the buggle find a cell with a value not described in the table.
Thus the loop, will stop and the program will terminate.
Another subtlety is that detecting if strings are equals is a bit annoying in Java.
So, we use the char getIndication()
instead of String readMessage()
.
This method, only known by the buggles of this exercise, returns the first char of the message written on the ground
(or ' ' -- the space char -- if nothing is written down). It enables to work with chars instead of strings, that is
much simpler in Java.
brushDown()
in your method. This asks the
buggle to put down a brush leaving a trail when it moves. It should help you
understanding its trajectory, but do not forget to remove this call when you
want to test whether your code is a valid solution to the exercise: you are
asked to let the buggle dance, not to vandalize the dance floor.
When your program finally works, move on to the next exercise.