0% found this document useful (0 votes)
18 views11 pages

Solution Exercises Project Day 2

The document outlines a pre-course for Programming 2 at Saarland University, detailing various tasks related to programming concepts such as subroutines, functions, algorithms, and data structures. It includes explanations and sample solutions for tasks involving the Pledge algorithm, spiral maze solving, lists, stacks, and binary trees. Participation in the pre-course is optional and does not award credit points.

Uploaded by

toukeaparfait
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
18 views11 pages

Solution Exercises Project Day 2

The document outlines a pre-course for Programming 2 at Saarland University, detailing various tasks related to programming concepts such as subroutines, functions, algorithms, and data structures. It includes explanations and sample solutions for tasks involving the Pledge algorithm, spiral maze solving, lists, stacks, and binary trees. Participation in the pre-course is optional and does not award credit points.

Uploaded by

toukeaparfait
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 11

Pre-Course

Programming 2 (SS 2025)


Sample Solution 2
Pre-Course Team
Saarland University
Fakultät MI Project Day 2
The pre-course is an offer of the (partly former) programming 2 tutors. The course is not an official course. No CP will be
awarded, participation is optional, and HISPOS registration is neither possible nor required. If you have any questions about the
pre-course and Programming 2, please feel free to contact the instructors and tutors. We wish you a successful semester and
look forward to seeing you again in Programming 2.

Task 2.0: Subroutines vs Functions

In today’s lecture we have covered both subroutines and functions.

1. Explain the difference between subroutines and functions.


2. Why do we use call to execute functions instead of jump? What is the difference between the two commands?
3. Give examples when to use functions instead of subroutines.

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.

Task 2.1: Pledge

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.

2. var int isWalkableFront


var int counter
set counter 0
var int isWalkableLeft
next_move_pledge:
explore isWalkableFront front
branch isWalkableFront no_wall
jump there_is_wall
no_wall:
move
jump next_move_pledge
there_is_wall:
turn right
add counter counter 1
jump next_move
next_move:
var int comp
test equal comp counter 0
branch comp next_move_pledge
explore isWalkableLeft left
branch isWalkableLeft no_wall_to_left
jump wall_to_left
no_wall_to_left:
turn left
sub counter counter 1
move
jump next_move
wall_to_left:
explore isWalkableFront front
branch isWalkableFront no_wall_in_front
jump wall_in_front
no_wall_in_front:
move
jump next_move
wall_in_front:
turn right
add counter counter 1
jump next_move

Task 2.2: Spirals

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

var int length


set length 13

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

var int length


set length 13
var direction tempdir
var int temptest
var int counter
set counter 0

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

Task 2.4: Stack

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:

1. StackInit: Initializes the stack_pointer.


2. StackPush: Pushes the element from argument 1 onto the stack.
3. StackPop: Deletes the current element from the stack and returns it.
4. StackEmpty: Returns 1 if the stack is empty, otherwise 0.
5. StackPeek: Returns the topmost element of the stack without removing it. Implement StackPeek in two
ways:
(a) Do not access the array directly, use the other stack operations.
(b) Implement StackPeek without using the other operations.
What is the advantage and disadvantage of the first implementation over the second?

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

# Push the directions onto the stack in reverse order


set_arg 0 sb
set_arg 1 front
call StackPush

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

var direction tempdir


var int temptest

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

# While variant 2 is faster,


# variant 1 is independent of the exact implementation of the stack.

Task 2.5: Binary Trees

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

1. Draw the tree No Hau gave you in form of the array.


2. Derive a formula that, given the index 𝑖 of any node, returns you the positions of its children in the array. If
you need help, visit the link in the footnote.
3. Implement your formula by writing a function that accepts the index of a node and a direction as arguments,
and returns the index of the next child. You can assume the direction is always equal to left or right.
4. Implement a function that walks the owl straight ahead until it arrives at an intersection.
5. Using all previous parts, you can now solve the labyrinth:
• Walk until you arrive at an obstacle
• Turn into the direction stored in the node at the current index
• Update your index to the correct child
• Repeat
6. You have successfully reached No Hau, who has spent the time pondering whether the tree necessarily has
to start at index 0, or if other indices are possible as well. Can you help her?
More specifically, No Hau already needs the first few cells of the array for something else. So the root is now
not at 0, but at 𝑟. So, if for example 𝑟 = 3, the root’s left child would be at 4, while the right one would be at
5, and so on. Can you change the existing formulas so that they still work when the root is located at 𝑟?
1 https://en.wikipedia.org/wiki/Binary_tree#Arrays

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

test equal offset dir right


add offset offset 1
add index index index
add index index offset

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

arr_get dir node


set_arg 0 dir
call turn_intersection

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

6. For a tree with root ⌊at 𝑟, you


⌋ get the left child of some node at 𝑖 as 2𝑖 + 1 − 𝑟, the right child is at 2𝑖 + 2 − 𝑟,
and the parent is at 𝑖−1−𝑟2
+ 𝑟.

11

You might also like