Solution Exercises Project Day 2
Solution Exercises Project Day 2
Solution
1. In contrast to subroutines, variables declared outside a function cannot be used. After a function has been
successfully executed, it automatically jumps back to the line of the program in which it was executed. With
a subroutine, on the other hand, you would always have to save the return destination in a variable and use
checks to find out exactly where to continue.
2. The call command saves the point where the call should return to, unlike jump.
3. You use functions when, for example, you want to use a part of the code several times in different locations
and, after each use, continue execution at the respective point from which you called the function, thus
avoiding the need to manually store multiple return labels.
In today’s lecture we discussed the Pledge algorithm and how it improves upon the right-hand rule algorithm. Take
a look at the given pseudocode for the pledge algorithm:
While you did not arrive at the goal location:
Set the turn counter to 0.
While you don’t have a wall in front of you:
Move forward.
If you encountered a wall in front of you:
Turn right.
Increment the turn counter by 1.
While the turn counter is ≠ 0:
Use the left-hand-rule.
For each right turn, increment the turn counter by 1.
For each left turn, decrement the turn counter by 1.
Move forward until you reach the next wall.
1. Explain again why the right hand rule does not always work and how the pledge algorithm fixes this problem.
2. Implement the pledge algorithm.
1
Solution
1. The right-hand rule will not work when you start within the labyrinth and if you encounter an obstacle which
is not connected to the border of the labyrinth. In this case, you will be trapped in a circle.
The pledge algorithm solves this through counting the turns and checking, if you walked a full circle. Then,
you just move forward until you hit a wall instead of following the wall.
In this exercise, you will write a program that solves a maze in spiral form.
1. Write a function that, given a number 𝑛 of steps, makes the owl walk 𝑛 steps forward.
2. Modify your function by adding a second argument 𝑟. Your function should now make the owl turn 𝑟 steps
to the right before walking 𝑛 steps forward.
3. Use this function to solve the maze in spiral form. The spiral has only right turns, and you start on the outside,
having to walk inwards. Assume that the maze is the same as illustrated below. Hint: Use recursion, and the
function written in subtask 2.
2
0 1 2 3 4 5 6 7
■ ■ ■ ■ ■ ■ ■ 8
■ ■ 22 23 24 25 ■ 9
■ ■ 21 ■ ■ 26 ■ 10
■ ■ 20 ■ 38 27 ■ 11
■ ■ 19 ■ ■ ■ ■ 12
■ ■ 18 17 16 15 14 13
The image above illustrates the spirals that your algorithm should be able to solve. (The blocks are hedges, and
the numbers show the order in which the tiles of the maze should be stepped on.)
Solution
set_arg 0 7
call spiral
end
#subtask 3
spiral:
var int num
get_arg num 0
branch num spiralcall # if number remaining != 0
jump spiralend
spiralcall:
set_arg 0 num # number of moves forward = number of turns remaining
set_arg 1 1 # turn right every call
call movesteps
sub num num 1
set_arg 0 num # next spiral call
call spiral
spiralend:
end
movesteps:
# subtask 2
var int turns
get_arg turns 1
branch turns loop1
jump loop1end
loop1:
turn right
sub turns turns 1
branch turns loop1
loop1end:
# subtask 1
var int steps
get_arg steps 0
branch steps loop2
jump loop2end
loop2:
move
sub steps steps 1 # steps <- steps - 1
branch steps loop2 # when steps != 0 jump to loop2
loop2end:
end
3
Task 2.3: Lists
This task is about lists (arrays). In the given code, a sequence of directions is written to an array. This sequence
will guide your owl to the goal. Your task is now to write a program that reads the directions one-by-one and then
takes a step in that direction.
For help, the length of the array has been written to the variable length.
arr_set 0 left
arr_set 1 left
arr_set 2 front
arr_set 3 left
arr_set 4 front
arr_set 5 front
arr_set 6 front
arr_set 7 left
arr_set 8 front
arr_set 9 front
arr_set 10 right
arr_set 11 left
arr_set 12 front
Solution
arr_set 0 left
arr_set 1 left
arr_set 2 front
arr_set 3 left
arr_set 4 front
arr_set 5 front
arr_set 6 front
arr_set 7 left
arr_set 8 front
arr_set 9 front
arr_set 10 right
arr_set 11 left
arr_set 12 front
loop:
arr_get tempdir counter
test equal temptest tempdir front
branch temptest go_front
test equal temptest tempdir left
branch temptest go_left
jump go_right
loop_end:
add counter counter 1
test less temptest counter length
branch temptest loop
end
go_front:
4
move
jump loop_end
go_left:
turn left
move
jump loop_end
go_right:
turn right
move
jump loop_end
This task is about implementing a simple stack for direction. You have already learned how a stack works in the
lecture. In our project, we use the global array to store the memory in which we store the stack. The “address”
of the stack is therefore a position in the array, in the following called stack_base. At this position we store the
stack_pointer. This contains the position where the topmost element on the stack is located. Each operation is
passed the stack_base as argument 0. The following operations shall be supported by the stack:
Now you should test your implementation of the stack. You are given the same sequence of directions as in Task
3.3. Your task is now to push the directions onto the stack and write a program that follows the operations by using
your implementation of the stack operations.
Hint:
Return values can be set with set_arg position value and read by the caller with get_arg variable position.
Solution
# Initialize the stack
var int sb
set sb 0
set_arg 0 sb
call StackInit
set_arg 0 sb
set_arg 1 left
call StackPush
5
set_arg 0 sb
set_arg 1 right
call StackPush
set_arg 0 sb
set_arg 1 front
call StackPush
set_arg 0 sb
set_arg 1 front
call StackPush
set_arg 0 sb
set_arg 1 left
call StackPush
set_arg 0 sb
set_arg 1 front
call StackPush
set_arg 0 sb
set_arg 1 front
call StackPush
set_arg 0 sb
set_arg 1 front
call StackPush
set_arg 0 sb
set_arg 1 left
call StackPush
set_arg 0 sb
set_arg 1 front
call StackPush
set_arg 0 sb
set_arg 1 left
call StackPush
set_arg 0 sb
set_arg 1 left
call StackPush
loop:
# Test if stack is empty and if true then go to loop_end
set_arg 0 sb
call StackEmpty
get_arg temptest 0
branch temptest loop_end
# Pop the top element from the stack and store it in tempdir
set_arg 0 sb
call StackPop
get_arg tempdir 0
# Move into the direction that the value stored in tempdir denotes
6
test equal temptest tempdir front
branch temptest go_front
test equal temptest tempdir left
branch temptest go_left
jump go_right
go_front:
move
jump loop
go_left:
turn left
move
jump loop
go_right:
turn right
move
jump loop
loop_end:
end
# StackInit
# Initializes the stack.
# Argument 0: Position of the stack’s base
# Return: -
StackInit:
var int stack_base
var int stack_pointer
get_arg stack_base 0
# Sets the value at the stack_base position to stack_base.
arr_set stack_base stack_base
end
# StackPush
# Pushes an element onto the stack.
# Argument 0: Position of the stack’s base
# Argument 1: Element to be pushed onto the stack
# Return: -
StackPush:
var int stack_base
var int stack_pointer
get_arg stack_base 0
arr_get stack_pointer stack_base
# Increments the stack_pointer
# At this point the new element should be stored.
add stack_pointer stack_pointer 1
# Gets the element to be pushed.
var direction dir
get_arg dir 1
# Writes the element into the array.
arr_set stack_pointer dir
# Writes the new stack_pointer.
arr_set stack_base stack_pointer
end
# StackPop
# Pops an element from the stack.
# Argument 0: Position of the stack’s base
# Return: The top element on the stack
StackPop:
var int stack_base
7
var int stack_pointer
get_arg stack_base 0
arr_get stack_pointer stack_base
# Reads the topmost element on the stack.
var direction dir
arr_get dir stack_pointer
# Sets the return value.
set_arg 0 dir
# Decrements and stores the new stack_pointer.
sub stack_pointer stack_pointer 1
arr_set stack_base stack_pointer
end
# StackEmpty
# Checks if the stack is empty.
# Argument 0: Position of the stack’s base
# Return: 1 if the stack is empty, 0 otherwise
StackEmpty:
var int stack_base
var int stack_pointer
get_arg stack_base 0
arr_get stack_pointer stack_base
# Subtracts the stack_base from the stack_pointer,
# to get the number of elements on the stack.
var int size
sub size stack_pointer stack_base
branch size NotEmpty
# Stack is empty.
set_arg 0 1
end
NotEmpty:
# Stack is not empty.
set_arg 0 0
end
# StackPeek
# Returns the top element from the stack without removing it.
# Argument 0: Position of the stack’s base
# Return: The top element on the stack
StackPeek:
var int stack_base
get_arg stack_base 0
# Pops the top element.
var direction dir
set_arg 0 stack_base
call StackPop
get_arg dir 0
# Pushes the element back.
set_arg 0 stack_base
set_arg 1 dir
call StackPush
set_arg 0 dir
end
StackPeek2:
var int stack_base
var int stack_pointer
get_arg stack_base 0
arr_get stack_pointer stack_base
# Reads the topmost element on the stack.
var direction dir
arr_get dir stack_pointer
8
# Sets the return value.
set_arg 0 dir
end
This labyrinth has already been explored by your friend No Hau. She has observed that its structure is comparable
to that of a binary tree1 :
• At each intersection, you can either turn left or right.
• The labyrinth contains no loops.
Indeed, any labyrinth without loops is equivalent to a graph, which in turn can be represented as a tree. In order
to help you quickly catch up to her, No Hau has left clues which direction to follow at each intersection in the
global array, starting at index 0. Here, the levels of the tree are stored one after another, and on each level, the node
ordering goes from left to right:
arr_set 0 left
arr_set 1 right
arr_set 2 left
arr_set 3 left
arr_set 4 right
arr_set 5 right
arr_set 6 right
arr_set 7 left
arr_set 8 right
arr_set 9 left
arr_set 10 right
arr_set 11 left
arr_set 12 left
arr_set 13 left
arr_set 14 right
9
Solution
1. We obtain the following binary tree, where L means left and R means right.
L
R L
L R R R
L R L R L L L R
⌊ ⌋
𝑖−1
2. For the node represented by index 𝑖, the left child is 2𝑖 + 1, the right child is 2𝑖 + 2, the parent is 2
.
3. get_child:
var int index
var int offset
var direction dir
get_arg index 0
get_arg dir 1
set_arg 0 index
end
4. walk:
var int flag
explore flag front
jump walk_loop_condition
walk_loop_body:
move
explore flag front
walk_loop_condition:
branch flag walk_loop_body
end
5. main:
var direction dir
var int node
set node 0
main_loop_body:
call walk
set_arg 0 node
set_arg 1 dir
call get_child
get_arg node 0
10
jump main_loop_body
end
turn_intersection:
var direction dir
var int flag
get_arg dir 0
test equal flag dir left
branch flag turn_left
turn right
jump turn_end
turn_left:
turn left
turn_end:
end
11