feat(ib002,ib111): add backtracking exercise

Signed-off-by: Matej Focko <mfocko@redhat.com>
This commit is contained in:
Matej Focko 2022-11-29 15:21:48 +01:00
parent 117f865ee8
commit e71fcfdf4f
Signed by: mfocko
GPG key ID: 7C47D46246790496
48 changed files with 2361 additions and 0 deletions

View file

@ -0,0 +1,164 @@
---
title: Recursion and backtracking with Robot Karel
description: |
A problem with too many restrictions.
tags:
- python
- karel
- recursion
- backtracking
---
- [Sources](pathname://files/ib002/karel_1)
## Introduction
In this exercise we will be working with a Robot Karel and with a »very« limited
resources. The point of this exercise is to show how powerful recursion and
backtracking can be even without anything else at your hand.
## Your environment and problem description
### Environment
You are given a robot that is present in a maze and is looking for an exit. Maze
consists of different walls and exit is marked with a single so-called „beeper“.
Walking into a wall results in a permanent damage of the robot.
### Interface
You can control the robot using the following interface:
- actions ​­— you can use them to change the current state of the robot and its
surroundings
- `robot.step()` — moves robot one step further
- `robot.turn_left()` — turns robot 90-degrees counter-clockwise
- notice that you are not given `turn_right` or `turn_around`, but feel free
to implement them yourself
- `robot.pick_beeper()` and opposite operation `robot.put_beeper()` — that
allows you to either pick or put „beeper“ from or onto the current position
- queries — you can use them to check the current state of the robot and its
surroundings
- `robot.beepers_present()` — to check if there are any beepers at the robot's
current location
- `robot.left_is_clear()` — to check if you can step to the left
- analogically for `front` and `right`
:::caution
Helper functions / procedures are allowed. Return values are allowed.
**Variables are prohibited!**
:::
### Problem
Your task is to decide whether there is an exit from the maze or not. You can see
an example of a maze here:
![Image of the maze](/img/ib002/karel_1/maze.png)
## Simple problem to get familiar with the robot
If you feel completely lost after the previous description, let me start you off
with a simpler problem.
You are standing in front of the stairs, your task is to walk up the stairs.
You can see an example of such map here:
![Image of the stairs](/img/ib002/karel_1/stairs.png)
## Brainstorm the idea
As a first step write down any ideas and things that you have noticed or came to
your mind. Ideally:
- Write down a nested list of the problems, e.g.
:::info Example
Problem: I want to find out whether the display on smartphone should rotate.
- Check if display has been rotated
- Read data from some sensor
- From what sensor
- In what format are the data I have read?
- How do I communicate with the sensor?
- What is the meaning of the data that I got?
- How can I process it?
:::
- Write down list of problems that can happen, e.g.
:::info Example continued
Following the same problem.
- What if the sensor doesn't work?
- What if the data doesn't conform to the specification?
- What if my formulas are wrong?
:::
- Write down **anything** you consider important to solving the problem, e.g.
:::info Example continued once again
- I could probably use gyroscope.
- I should probably look up the datasheet for that module.
- I could write some tests to verify that my computations are correct.
:::
## »Rough« pseudocode
As a next step write a **mock up** of a pseudocode solving the problem, you are
allowed to use comments as placeholders for bigger chunks of code.
Those comments are also a very good hints for decomposition and short, but
descriptive, commnets (if they are short enough and you decide not to factor them
out to separate functions).
:::tip
The smaller the function is, the easier it is to test it and argue about its
correctness.
:::
## »Proper« pseudocode
If you are satisfied with the _»rough« pseudocode_, it's time to convert it into
a proper one. Get rid of the uncertain pieces of functionality and replace them
with proper pseudocode, i.e. list of the things that should happen in its place.
## Library
If you got here, and you **actually** wrote down the pseudocode, you can try your
solution after downloading the sources linked at the beginning. If you download
the ZIP-file, you can there:
- `generate_mazes.py` - that was used to generate the same maze with beepers in
different locations
- `karel_tk.py` - library which can run Karel given the his world
- documentation can be found [here](https://www.fi.muni.cz/~xfocko/ib111/10/docs/)
- also requires Tk Python library to be installed (it should be included in
majority of Python installations)
- `*.kw` - which represent multiple worlds for Karel I have prepared
- `skeleton.py` - skeleton for your solution, needs to be put in the same directory
as `karel_tk.py` and takes path to the world as a first argument, example usage:
$ python3 skeleton.py stairs.kw
- of course, this file can be renamed ;)
## Solution
Solution to this problem will be released as a second part, so that you can try
it out by yourself without any influence of „example solution“.
If you want to get any feedback, feel free to mail me your solution (including
all the steps that lead to your final solution, if you wish to get feedback on
those too).

View file

View file

@ -0,0 +1,21 @@
#!/usr/bin/env python3
from itertools import product
def generate_map(template: str, st: int, ave: int) -> str:
return template.format(st=st, ave=ave)
def main():
template = None
with open("maze_skel.kw", "r") as f:
template = f.read()
for st, ave in product(range(1, 7), range(1, 7)):
with open("maze{:03d}.kw".format(st * 6 + ave), "w") as out:
print(generate_map(template, st, ave), file=out)
if __name__ == "__main__":
main()

View file

@ -0,0 +1,791 @@
from dataclasses import dataclass
from enum import Enum, IntEnum
from functools import wraps
from itertools import product
from math import radians, sin, cos
from sys import stderr
import tkinter as tk
from typing import Tuple, Union
def check_before(precondition):
"""
Decorator for running methods before executing a method.
Args:
call_before: Function to be called before executing a method.
Returns:
Parametrized decorator that can be used to wrap method with the
`call_before`.
"""
def parametrized(f):
@wraps(f)
def wrapper(self, *args, **kwargs):
if not precondition(self, *args, **kwargs, fn=f):
return
return f(self, *args, **kwargs)
return wrapper
return parametrized
def after(call_after):
"""
Decorator for running methods after executing a method.
Args:
call_after: Function to be called after executing a method.
Returns:
Parametrized decorator that can be used to wrap method with the
`call_after`.
"""
def parametrized(f):
@wraps(f)
def wrapper(self, *args, **kwargs):
result = f(self, *args, **kwargs)
call_after(self, *args, **kwargs, fn=f)
return result
return wrapper
return parametrized
def skip_for_summary(f):
"""
Decorator used for skipping a function call if the Karel is running
in a summary mode.
"""
@wraps(f)
def wrapper(self, *args, **kwargs):
if self.summary_mode:
return
return f(self, *args, **kwargs)
return wrapper
class Block(IntEnum):
"""
Represents a field in the world of the Robot Karel.
It can be either clear or a wall.
"""
Clear = 0
Wall = -1
# Constants for major angles
EAST, NORTH, WEST, SOUTH = 0, 90, 180, 270
# @dataclass(frozen=True, slots=True)
@dataclass(frozen=True)
class _Direction:
"""
angle: Represents heading of the Robot Karel
"""
angle: int
@property
def vector(self) -> Tuple[int, int]:
"""
Get a direction vector in the current direction the robot is heading.
Returns:
Pair of ints, representing a vector of (dx, dy).
"""
angle, x, y = radians(self.angle), 1, 0
return (
x * round(cos(angle)) - y * round(sin(angle)),
x * round(sin(angle)) + y * round(cos(angle)),
)
@property
def in_world(self) -> str:
"""
Get a character that is being put in the graphical representation of
the Robot Karel.
Returns:
Character to be put in the world.
"""
return {
Direction.East.value: ">",
Direction.North.value: "^",
Direction.West.value: "<",
Direction.South.value: "v",
# Direction.East.value: "⮞",
# Direction.North.value: "⮝",
# Direction.West.value: "⮜",
# Direction.South.value: "⮟",
}[self]
@property
def as_string(self) -> str:
"""
Returns a string with a direction for Tk label.
Returns:
Label of the direction
"""
return {
Direction.East.value: "east",
Direction.North.value: "north",
Direction.West.value: "west",
Direction.South.value: "south",
}[self]
def __add__(self, angle: int) -> "_Direction":
return _Direction((360 + self.angle + angle) % 360)
class Direction(Enum):
"""
Provides constants of directions Karel can face.
"""
East = _Direction(EAST)
North = _Direction(NORTH)
West = _Direction(WEST)
South = _Direction(SOUTH)
class KarelWindow:
def __init__(self, karel: "Karel", scale: int, font: str):
self.size = 32 * scale
self.steps = tk.Label(text=karel.steps, anchor="e")
self.steps.grid(row=0, column=0, sticky="e")
self.last_cmd = tk.Label(text=karel.last_command, anchor="w")
self.last_cmd.grid(row=0, column=1, columnspan=3, sticky="w")
tk.Label(text="CORNER").grid(row=1, column=0)
tk.Label(text="FACING").grid(row=1, column=1)
tk.Label(text="BEEP-BAG").grid(row=1, column=2)
tk.Label(text="BEEP-CORNER").grid(row=1, column=3)
self.corner = tk.Label()
self.corner.grid(row=2, column=0)
self.facing = tk.Label()
self.facing.grid(row=2, column=1)
self.beep_bag = tk.Label()
self.beep_bag.grid(row=2, column=2)
self.beep_corner = tk.Label()
self.beep_corner.grid(row=2, column=3)
self.canvas = tk.Canvas(
width=((karel.world.width + 1) // 2 + 2) * self.size,
height=((karel.world.height + 1) // 2 + 2) * self.size,
background="black",
)
self.canvas.grid(column=0, row=3, columnspan=4)
self.font = f"{font} {int(12 * scale)}"
self.__draw_world(karel.world)
self.render(karel)
def __draw_world(self, world: "World"):
m, n = (world.height + 1) // 2, (world.width + 1) // 2
# NUMBERS
self.canvas.create_text(
self.size // 2,
self.size,
text="ST.",
fill="white",
anchor="s",
font=self.font,
)
for i in range(m):
self.canvas.create_text(
self.size - 8,
(i + 2) * self.size - self.size // 2,
text=(m - i),
anchor="e",
fill="white",
font=self.font,
)
y = ((m + 1) * self.size) + 8
self.canvas.create_text(
(n + 1) * self.size + self.size // 2,
y,
text="AVE.",
fill="white",
anchor="n",
font=self.font,
)
for i in range(n):
self.canvas.create_text(
(i + 2) * self.size - self.size // 2,
y,
text=(i + 1),
anchor="n",
fill="white",
font=self.font,
)
# BORDER
self.canvas.create_rectangle(
self.size,
self.size,
self.size * (n + 1),
self.size * (m + 1),
fill="",
outline="white",
)
for row, col in product(range(world.height), range(world.width)):
block = world.data[row][col]
if row % 2 == 0 and col % 2 == 0:
self.__print_beeper(world, block or ".", row // 2, col // 2)
elif block == Block.Wall:
size = self.size
x = size + col // 2 * size
y = (world.width + 1) // 2 * size - row // 2 * size
if row % 2 == 1 and col % 2 == 0:
self.canvas.create_line(x, y, x + size, y, fill="white")
elif row % 2 == 0:
x += size
self.canvas.create_line(x, y, x, y + size, fill="white")
self.canvas.update()
def __print_beeper(
self, world: "World", beeper: Union[str, int], row: int, column: int
):
self.canvas.create_text(
(column + 1) * self.size + self.size // 2,
((world.height + 1) // 2 - row) * self.size + self.size // 2,
text=str(beeper),
anchor="center",
fill="white",
font=self.font,
)
def render(self, karel: "Karel"):
self.facing["text"] = karel.direction.as_string
self.steps["text"] = karel.steps
self.last_cmd["text"] = karel.last_command
self.corner["text"] = f"({(karel.x + 2) // 2}, {(karel.y + 2) // 2})"
self.beep_bag["text"] = karel.beepers
self.beep_corner["text"] = karel.world.data[karel.y][karel.x]
i, j = (karel.y + 2) // 2, (karel.x + 2) // 2
size = self.size
x, y = j * size, ((karel.world.height + 1) // 2 - i + 1) * size
self.canvas.create_rectangle(
x + 1, y + 1, x + size - 1, y + size - 1, fill="black"
)
karel_on_map = karel.direction.in_world
self.canvas.create_text(
x + size // 2,
y + size // 2,
text=karel_on_map,
font=self.font + " bold",
fill="yellow",
anchor="center",
)
self.canvas.update()
self.canvas.after(karel.step_delay)
def update(self, karel: "Karel", dx: int, dy: int):
block = karel.world.data[karel.y - 2 * dy][karel.x - 2 * dx]
i, j = (karel.y - 2 * dy) // 2, (karel.x - 2 * dx) // 2
x, y = (j + 1) * self.size, (
(karel.world.height + 1) // 2 - i
) * self.size
self.canvas.create_rectangle(
x + 1, y + 1, x + self.size - 1, y + self.size - 1, fill="black"
)
self.__print_beeper(karel.world, block or ".", i, j)
def error(self, karel: "Karel", message: str):
self.render(karel)
self.last_cmd["foreground"] = "red"
self.last_cmd["text"] = f"Error Shutoff! ({message})"
class World:
def __init__(self, width, height, data):
self.width = width * 2 - 1
self.height = height * 2 - 1
self.data = [
[0 for _ in range(self.width)] for _ in range(self.height)
]
if self.width > 30 or self.height > 30:
raise ValueError(
"The given world is greater than the max values of [{}x{}]".format(
30, 30
)
)
self._parse_world(data)
def __parse_wall(self, column, row, orientation, line):
column = column * 2 - 2
row = row * 2 - 2
if column % 2 == 1 or row % 2 == 1:
raise ValueError("Wrong position of the wall")
if orientation == "E":
column += 1
elif orientation == "W":
column -= 1
elif orientation == "N":
row += 1
elif orientation == "S":
row -= 1
else:
raise ValueError(
"Unknown wall orientation '{}' on line {} in world file".format(
orientation, line
)
)
self.data[row][column] = Block.Wall
if column % 2 == 1 and row % 2 == 0:
if row + 1 < self.height:
self.data[row + 1][column] = Block.Wall
if row - 1 >= 0:
self.data[row - 1][column] = Block.Wall
else:
if column + 1 < self.width:
self.data[row][column + 1] = Block.Wall
if column - 1 >= 0:
self.data[row][column - 1] = Block.Wall
def __parse_beepers(self, column, row, count):
column = column * 2 - 2
row = row * 2 - 2
self.data[row][column] = count
def _parse_world(self, world_content):
for i, line in enumerate(world_content, 1):
if not line:
continue
block, column, row, arg = [part.upper() for part in line.split()]
if block == "W":
self.__parse_wall(int(column), int(row), arg, i)
elif block == "B":
self.__parse_beepers(int(column), int(row), int(arg))
else:
raise ValueError(
"Unknown block character '{}' on line {} in world file".format(
block, i
)
)
class Karel:
def __init__(
self, filename, summary_mode=False, scale=1, font="monospace"
):
"""
Turn Karel on.
Args:
filename: Path to the file containing Karel's world and initial
settings.
summary_mode: Disable rendering of the Karel's world in the window.
Defaults to `False`.
scale: Change the scaling factor of the font used to render Karel's
world.
Defaults to `1`.
font: Change the default monospace font that is used to render the
world.
Defaults to `"monospace"`.
"""
self.summary_mode = summary_mode
world_content = None
with open(filename) as world_file:
world_content = world_file.read()
first_line, world = world_content.split("\n", maxsplit=1)
width, height, x, y, direction, beepers = first_line.split()
direction = direction.upper()
self.world = World(int(width), int(height), world.split("\n"))
self.x, self.y = int(x) * 2 - 2, int(y) * 2 - 2
if direction == "S":
self.direction = Direction.South.value
elif direction == "W":
self.direction = Direction.West.value
elif direction == "E":
self.direction = Direction.East.value
elif direction == "N":
self.direction = Direction.North.value
else:
raise ValueError("Unknown Karel's direction")
self.beepers = int(beepers)
self.steps = 0
self.step_delay = 1000
self.is_running = True
self.last_command = "turn_on"
self._initialize_window(scale, font)
@skip_for_summary
def _initialize_window(self, scale, font):
"""
Initializes a window where the Karel is drawn.
"""
self._window = KarelWindow(self, scale, font)
@skip_for_summary
def __update(self, dx, dy):
"""
Updates Karel's position in the window.
Args:
dx: Change along the horizontal axis.
dy: Change along the vertical axis.
"""
self._window.update(self, dx, dy)
def __render(self, fn, *args, **kwargs):
"""
Updates step counter and last command for Karel.
If the robot is not running in a summary mode, then the window
is rendered once again.
"""
if not self.is_running:
return
self.steps += 1
self.last_command = fn.__name__
if not self.summary_mode:
self._window.render(self)
def __error(self, message):
"""
Provides error handling.
Args:
message: Error message to be shown.
"""
if not self.summary_mode:
self._window.error(self, message)
self.is_running = False
else:
print(f"Error Shutoff! ({message})", file=stderr)
@skip_for_summary
def __deinit(self):
tk.mainloop()
def __check_state(self, *args, **kwargs):
"""
Assures that commands are not run while the robot is not running.
Robot is not running when error has occurred.
"""
return self.is_running
@check_before(__check_state)
def beepers_in_bag(self):
"""
Check if there are any beepers in the Karel's bag.
Returns:
`True` if there is at least one beeper in Karel's beeper bag,
`False` otherwise.
"""
return self.beepers > 0
def no_beepers_in_bag(self):
"""
Check if there are no beepers in the Karel's bag.
Returns:
`True` if there is no beeper in Karel's beeper bag, `False` otherwise.
"""
return not self.beepers_in_bag()
@check_before(__check_state)
def front_is_clear(self):
"""
Check if there is no wall in front of Karel.
Returns:
`True` if there is no obstacle in front of Karel, `False` otherwise.
"""
dx, dy = self.direction.vector
if not (
0 <= self.x + dx < self.world.width
and 0 <= self.y + dy < self.world.height
):
return False
if self.world.data[self.y + dy][self.x + dx] == Block.Wall:
return False
return True
def front_is_blocked(self):
"""
Check if there is a wall in front of Karel.
Returns:
`True` if there is an obstacle in front of Karel, `False` otherwise.
"""
return not self.front_is_clear()
@check_before(__check_state)
def __side_is_clear(self, d):
"""
Helper function for determining whether the sides of Karel are clear.
Args:
d: Counterclockwise change in angle of Karel's heading.
Returns:
`True` if the side after applying the `d` counterclokwise turn
is clear, `False` otherwise.
"""
original_direction = self.direction
self.direction = self.direction + d
is_clear = self.front_is_clear()
self.direction = original_direction
return is_clear
def left_is_clear(self):
"""
Check if there is no wall to the left side of Karel.
Returns:
`True` if there is no obstacle to the left side of Karel,
`False` otherwise.
"""
return self.__side_is_clear(90)
def left_is_blocked(self):
"""
Check if there is a wall to the left side of Karel.
Returns:
`True` if there is an obstacle to the left side of Karel,
`False` otherwise.
"""
return not self.left_is_clear()
def right_is_clear(self):
"""
Check if there is no wall to the right side of Karel.
Returns:
`True` if there is no obstacle to the right side of Karel,
`False` otherwise.
"""
return self.__side_is_clear(-90)
def right_is_blocked(self):
"""
Check if there is a wall to the right side of Karel.
Returns:
`True` if there is an obstacle to the right side of Karel,
`False` otherwise.
"""
return not self.right_is_clear()
@check_before(__check_state)
def facing_north(self):
"""
Check if Karel is facing north.
Returns:
`True` if Karel is facing north, `False` otherwise.
"""
return self.direction == Direction.North
def not_facing_north(self):
"""
Check if Karel is »not« facing north.
Returns:
`True` if Karel is »not« facing north, `False` otherwise.
"""
return not self.facing_north()
@check_before(__check_state)
def facing_south(self):
"""
Check if Karel is facing south.
Returns:
`True` if Karel is facing south, `False` otherwise.
"""
return self.direction == Direction.South
def not_facing_south(self):
"""
Check if Karel is »not« facing south.
Returns:
`True` if Karel is »not« facing south, `False` otherwise.
"""
return not self.facing_south()
@check_before(__check_state)
def facing_east(self):
"""
Check if Karel is facing east.
Returns:
`True` if Karel is facing east, `False` otherwise.
"""
return self.direction == Direction.East
def not_facing_east(self):
"""
Check if Karel is »not« facing east.
Returns:
`True` if Karel is »not« facing east, `False` otherwise.
"""
return not self.facing_east()
@check_before(__check_state)
def facing_west(self):
"""
Check if Karel is facing west.
Returns:
`True` if Karel is facing west, `False` otherwise.
"""
return self.direction == Direction.West
def not_facing_west(self):
"""
Check if Karel is »not« facing west.
Returns:
`True` if Karel is »not« facing west, `False` otherwise.
"""
return not self.facing_west()
@check_before(__check_state)
def beepers_present(self):
"""
Check whether Karel stands on a position that has any beepers present.
Returns:
`True` if there is at least one beeper present on the current
position, `False` otherwise.
"""
return self.world.data[self.y][self.x] > 0
def no_beepers_present(self):
"""
Check whether Karel stands on a position that has no beepers present.
Returns:
`True` if there is no beeper present on the current position,
`False` otherwise.
"""
return not self.beepers_present()
@check_before(__check_state)
@after(__render)
def step(self):
"""
Move Karel one position in the direction he's facing.
"""
if not self.front_is_clear():
return self.__error("Can't move this way")
dx, dy = self.direction.vector
self.x += 2 * dx
self.y += 2 * dy
self.__update(dx, dy)
@check_before(__check_state)
@after(__render)
def turn_left(self):
"""
Turn Karel counterclockwise, i.e. left, by 90 degrees.
"""
self.direction = self.direction + 90
@after(__render)
def turn_off(self):
"""
Turn Karel off.
"""
self.is_running = False
self.__deinit()
@check_before(__check_state)
@after(__render)
def put_beeper(self):
"""
Take a beeper from Karel's beeper bag and put on the current position.
"""
if self.beepers <= 0:
return self.__error("Karel has no beeper to put at the corner")
self.world.data[self.y][self.x] += 1
self.beepers -= 1
@check_before(__check_state)
@after(__render)
def pick_beeper(self):
"""
Pick a beeper from the current position and put it into Karel's
beeper bag.
"""
if self.world.data[self.y][self.x] <= 0:
return self.__error("There is no beeper at the corner")
self.world.data[self.y][self.x] -= 1
self.beepers += 1
def set_step_delay(self, delay):
"""
Set delay of a Karel's step.
Args:
delay: Delay of one step in milliseconds.
"""
self.step_delay = delay
def get_step_delay(self):
"""
Get current delay of a Karel's step.
Returns:
Current delay in milliseconds.
"""
return self.step_delay

View file

@ -0,0 +1,34 @@
6 6 1 1 E 72
B 1 1 1
W 1 1 E
W 1 3 E
W 1 4 E
W 1 5 N
W 2 1 N
W 2 2 E
W 2 2 N
W 2 4 N
W 2 5 E
W 3 2 N
W 3 3 N
W 3 4 E
W 3 5 E
W 4 1 E
W 4 1 N
W 4 3 E
W 4 3 N
W 4 4 E
W 4 5 E
W 5 2 E
W 5 2 N
W 5 4 E
W 5 5 N
W 5 6 E
W 6 4 N

View file

@ -0,0 +1,34 @@
6 6 1 1 E 72
B 1 2 1
W 1 1 E
W 1 3 E
W 1 4 E
W 1 5 N
W 2 1 N
W 2 2 E
W 2 2 N
W 2 4 N
W 2 5 E
W 3 2 N
W 3 3 N
W 3 4 E
W 3 5 E
W 4 1 E
W 4 1 N
W 4 3 E
W 4 3 N
W 4 4 E
W 4 5 E
W 5 2 E
W 5 2 N
W 5 4 E
W 5 5 N
W 5 6 E
W 6 4 N

View file

@ -0,0 +1,34 @@
6 6 1 1 E 72
B 1 3 1
W 1 1 E
W 1 3 E
W 1 4 E
W 1 5 N
W 2 1 N
W 2 2 E
W 2 2 N
W 2 4 N
W 2 5 E
W 3 2 N
W 3 3 N
W 3 4 E
W 3 5 E
W 4 1 E
W 4 1 N
W 4 3 E
W 4 3 N
W 4 4 E
W 4 5 E
W 5 2 E
W 5 2 N
W 5 4 E
W 5 5 N
W 5 6 E
W 6 4 N

View file

@ -0,0 +1,34 @@
6 6 1 1 E 72
B 1 4 1
W 1 1 E
W 1 3 E
W 1 4 E
W 1 5 N
W 2 1 N
W 2 2 E
W 2 2 N
W 2 4 N
W 2 5 E
W 3 2 N
W 3 3 N
W 3 4 E
W 3 5 E
W 4 1 E
W 4 1 N
W 4 3 E
W 4 3 N
W 4 4 E
W 4 5 E
W 5 2 E
W 5 2 N
W 5 4 E
W 5 5 N
W 5 6 E
W 6 4 N

View file

@ -0,0 +1,34 @@
6 6 1 1 E 72
B 1 5 1
W 1 1 E
W 1 3 E
W 1 4 E
W 1 5 N
W 2 1 N
W 2 2 E
W 2 2 N
W 2 4 N
W 2 5 E
W 3 2 N
W 3 3 N
W 3 4 E
W 3 5 E
W 4 1 E
W 4 1 N
W 4 3 E
W 4 3 N
W 4 4 E
W 4 5 E
W 5 2 E
W 5 2 N
W 5 4 E
W 5 5 N
W 5 6 E
W 6 4 N

View file

@ -0,0 +1,34 @@
6 6 1 1 E 72
B 1 6 1
W 1 1 E
W 1 3 E
W 1 4 E
W 1 5 N
W 2 1 N
W 2 2 E
W 2 2 N
W 2 4 N
W 2 5 E
W 3 2 N
W 3 3 N
W 3 4 E
W 3 5 E
W 4 1 E
W 4 1 N
W 4 3 E
W 4 3 N
W 4 4 E
W 4 5 E
W 5 2 E
W 5 2 N
W 5 4 E
W 5 5 N
W 5 6 E
W 6 4 N

View file

@ -0,0 +1,34 @@
6 6 1 1 E 72
B 2 1 1
W 1 1 E
W 1 3 E
W 1 4 E
W 1 5 N
W 2 1 N
W 2 2 E
W 2 2 N
W 2 4 N
W 2 5 E
W 3 2 N
W 3 3 N
W 3 4 E
W 3 5 E
W 4 1 E
W 4 1 N
W 4 3 E
W 4 3 N
W 4 4 E
W 4 5 E
W 5 2 E
W 5 2 N
W 5 4 E
W 5 5 N
W 5 6 E
W 6 4 N

View file

@ -0,0 +1,34 @@
6 6 1 1 E 72
B 2 2 1
W 1 1 E
W 1 3 E
W 1 4 E
W 1 5 N
W 2 1 N
W 2 2 E
W 2 2 N
W 2 4 N
W 2 5 E
W 3 2 N
W 3 3 N
W 3 4 E
W 3 5 E
W 4 1 E
W 4 1 N
W 4 3 E
W 4 3 N
W 4 4 E
W 4 5 E
W 5 2 E
W 5 2 N
W 5 4 E
W 5 5 N
W 5 6 E
W 6 4 N

View file

@ -0,0 +1,34 @@
6 6 1 1 E 72
B 2 3 1
W 1 1 E
W 1 3 E
W 1 4 E
W 1 5 N
W 2 1 N
W 2 2 E
W 2 2 N
W 2 4 N
W 2 5 E
W 3 2 N
W 3 3 N
W 3 4 E
W 3 5 E
W 4 1 E
W 4 1 N
W 4 3 E
W 4 3 N
W 4 4 E
W 4 5 E
W 5 2 E
W 5 2 N
W 5 4 E
W 5 5 N
W 5 6 E
W 6 4 N

View file

@ -0,0 +1,34 @@
6 6 1 1 E 72
B 2 4 1
W 1 1 E
W 1 3 E
W 1 4 E
W 1 5 N
W 2 1 N
W 2 2 E
W 2 2 N
W 2 4 N
W 2 5 E
W 3 2 N
W 3 3 N
W 3 4 E
W 3 5 E
W 4 1 E
W 4 1 N
W 4 3 E
W 4 3 N
W 4 4 E
W 4 5 E
W 5 2 E
W 5 2 N
W 5 4 E
W 5 5 N
W 5 6 E
W 6 4 N

View file

@ -0,0 +1,34 @@
6 6 1 1 E 72
B 2 5 1
W 1 1 E
W 1 3 E
W 1 4 E
W 1 5 N
W 2 1 N
W 2 2 E
W 2 2 N
W 2 4 N
W 2 5 E
W 3 2 N
W 3 3 N
W 3 4 E
W 3 5 E
W 4 1 E
W 4 1 N
W 4 3 E
W 4 3 N
W 4 4 E
W 4 5 E
W 5 2 E
W 5 2 N
W 5 4 E
W 5 5 N
W 5 6 E
W 6 4 N

View file

@ -0,0 +1,34 @@
6 6 1 1 E 72
B 2 6 1
W 1 1 E
W 1 3 E
W 1 4 E
W 1 5 N
W 2 1 N
W 2 2 E
W 2 2 N
W 2 4 N
W 2 5 E
W 3 2 N
W 3 3 N
W 3 4 E
W 3 5 E
W 4 1 E
W 4 1 N
W 4 3 E
W 4 3 N
W 4 4 E
W 4 5 E
W 5 2 E
W 5 2 N
W 5 4 E
W 5 5 N
W 5 6 E
W 6 4 N

View file

@ -0,0 +1,34 @@
6 6 1 1 E 72
B 3 1 1
W 1 1 E
W 1 3 E
W 1 4 E
W 1 5 N
W 2 1 N
W 2 2 E
W 2 2 N
W 2 4 N
W 2 5 E
W 3 2 N
W 3 3 N
W 3 4 E
W 3 5 E
W 4 1 E
W 4 1 N
W 4 3 E
W 4 3 N
W 4 4 E
W 4 5 E
W 5 2 E
W 5 2 N
W 5 4 E
W 5 5 N
W 5 6 E
W 6 4 N

View file

@ -0,0 +1,34 @@
6 6 1 1 E 72
B 3 2 1
W 1 1 E
W 1 3 E
W 1 4 E
W 1 5 N
W 2 1 N
W 2 2 E
W 2 2 N
W 2 4 N
W 2 5 E
W 3 2 N
W 3 3 N
W 3 4 E
W 3 5 E
W 4 1 E
W 4 1 N
W 4 3 E
W 4 3 N
W 4 4 E
W 4 5 E
W 5 2 E
W 5 2 N
W 5 4 E
W 5 5 N
W 5 6 E
W 6 4 N

View file

@ -0,0 +1,34 @@
6 6 1 1 E 72
B 3 3 1
W 1 1 E
W 1 3 E
W 1 4 E
W 1 5 N
W 2 1 N
W 2 2 E
W 2 2 N
W 2 4 N
W 2 5 E
W 3 2 N
W 3 3 N
W 3 4 E
W 3 5 E
W 4 1 E
W 4 1 N
W 4 3 E
W 4 3 N
W 4 4 E
W 4 5 E
W 5 2 E
W 5 2 N
W 5 4 E
W 5 5 N
W 5 6 E
W 6 4 N

View file

@ -0,0 +1,34 @@
6 6 1 1 E 72
B 3 4 1
W 1 1 E
W 1 3 E
W 1 4 E
W 1 5 N
W 2 1 N
W 2 2 E
W 2 2 N
W 2 4 N
W 2 5 E
W 3 2 N
W 3 3 N
W 3 4 E
W 3 5 E
W 4 1 E
W 4 1 N
W 4 3 E
W 4 3 N
W 4 4 E
W 4 5 E
W 5 2 E
W 5 2 N
W 5 4 E
W 5 5 N
W 5 6 E
W 6 4 N

View file

@ -0,0 +1,34 @@
6 6 1 1 E 72
B 3 5 1
W 1 1 E
W 1 3 E
W 1 4 E
W 1 5 N
W 2 1 N
W 2 2 E
W 2 2 N
W 2 4 N
W 2 5 E
W 3 2 N
W 3 3 N
W 3 4 E
W 3 5 E
W 4 1 E
W 4 1 N
W 4 3 E
W 4 3 N
W 4 4 E
W 4 5 E
W 5 2 E
W 5 2 N
W 5 4 E
W 5 5 N
W 5 6 E
W 6 4 N

View file

@ -0,0 +1,34 @@
6 6 1 1 E 72
B 3 6 1
W 1 1 E
W 1 3 E
W 1 4 E
W 1 5 N
W 2 1 N
W 2 2 E
W 2 2 N
W 2 4 N
W 2 5 E
W 3 2 N
W 3 3 N
W 3 4 E
W 3 5 E
W 4 1 E
W 4 1 N
W 4 3 E
W 4 3 N
W 4 4 E
W 4 5 E
W 5 2 E
W 5 2 N
W 5 4 E
W 5 5 N
W 5 6 E
W 6 4 N

View file

@ -0,0 +1,34 @@
6 6 1 1 E 72
B 4 1 1
W 1 1 E
W 1 3 E
W 1 4 E
W 1 5 N
W 2 1 N
W 2 2 E
W 2 2 N
W 2 4 N
W 2 5 E
W 3 2 N
W 3 3 N
W 3 4 E
W 3 5 E
W 4 1 E
W 4 1 N
W 4 3 E
W 4 3 N
W 4 4 E
W 4 5 E
W 5 2 E
W 5 2 N
W 5 4 E
W 5 5 N
W 5 6 E
W 6 4 N

View file

@ -0,0 +1,34 @@
6 6 1 1 E 72
B 4 2 1
W 1 1 E
W 1 3 E
W 1 4 E
W 1 5 N
W 2 1 N
W 2 2 E
W 2 2 N
W 2 4 N
W 2 5 E
W 3 2 N
W 3 3 N
W 3 4 E
W 3 5 E
W 4 1 E
W 4 1 N
W 4 3 E
W 4 3 N
W 4 4 E
W 4 5 E
W 5 2 E
W 5 2 N
W 5 4 E
W 5 5 N
W 5 6 E
W 6 4 N

View file

@ -0,0 +1,34 @@
6 6 1 1 E 72
B 4 3 1
W 1 1 E
W 1 3 E
W 1 4 E
W 1 5 N
W 2 1 N
W 2 2 E
W 2 2 N
W 2 4 N
W 2 5 E
W 3 2 N
W 3 3 N
W 3 4 E
W 3 5 E
W 4 1 E
W 4 1 N
W 4 3 E
W 4 3 N
W 4 4 E
W 4 5 E
W 5 2 E
W 5 2 N
W 5 4 E
W 5 5 N
W 5 6 E
W 6 4 N

View file

@ -0,0 +1,34 @@
6 6 1 1 E 72
B 4 4 1
W 1 1 E
W 1 3 E
W 1 4 E
W 1 5 N
W 2 1 N
W 2 2 E
W 2 2 N
W 2 4 N
W 2 5 E
W 3 2 N
W 3 3 N
W 3 4 E
W 3 5 E
W 4 1 E
W 4 1 N
W 4 3 E
W 4 3 N
W 4 4 E
W 4 5 E
W 5 2 E
W 5 2 N
W 5 4 E
W 5 5 N
W 5 6 E
W 6 4 N

View file

@ -0,0 +1,34 @@
6 6 1 1 E 72
B 4 5 1
W 1 1 E
W 1 3 E
W 1 4 E
W 1 5 N
W 2 1 N
W 2 2 E
W 2 2 N
W 2 4 N
W 2 5 E
W 3 2 N
W 3 3 N
W 3 4 E
W 3 5 E
W 4 1 E
W 4 1 N
W 4 3 E
W 4 3 N
W 4 4 E
W 4 5 E
W 5 2 E
W 5 2 N
W 5 4 E
W 5 5 N
W 5 6 E
W 6 4 N

View file

@ -0,0 +1,34 @@
6 6 1 1 E 72
B 4 6 1
W 1 1 E
W 1 3 E
W 1 4 E
W 1 5 N
W 2 1 N
W 2 2 E
W 2 2 N
W 2 4 N
W 2 5 E
W 3 2 N
W 3 3 N
W 3 4 E
W 3 5 E
W 4 1 E
W 4 1 N
W 4 3 E
W 4 3 N
W 4 4 E
W 4 5 E
W 5 2 E
W 5 2 N
W 5 4 E
W 5 5 N
W 5 6 E
W 6 4 N

View file

@ -0,0 +1,34 @@
6 6 1 1 E 72
B 5 1 1
W 1 1 E
W 1 3 E
W 1 4 E
W 1 5 N
W 2 1 N
W 2 2 E
W 2 2 N
W 2 4 N
W 2 5 E
W 3 2 N
W 3 3 N
W 3 4 E
W 3 5 E
W 4 1 E
W 4 1 N
W 4 3 E
W 4 3 N
W 4 4 E
W 4 5 E
W 5 2 E
W 5 2 N
W 5 4 E
W 5 5 N
W 5 6 E
W 6 4 N

View file

@ -0,0 +1,34 @@
6 6 1 1 E 72
B 5 2 1
W 1 1 E
W 1 3 E
W 1 4 E
W 1 5 N
W 2 1 N
W 2 2 E
W 2 2 N
W 2 4 N
W 2 5 E
W 3 2 N
W 3 3 N
W 3 4 E
W 3 5 E
W 4 1 E
W 4 1 N
W 4 3 E
W 4 3 N
W 4 4 E
W 4 5 E
W 5 2 E
W 5 2 N
W 5 4 E
W 5 5 N
W 5 6 E
W 6 4 N

View file

@ -0,0 +1,34 @@
6 6 1 1 E 72
B 5 3 1
W 1 1 E
W 1 3 E
W 1 4 E
W 1 5 N
W 2 1 N
W 2 2 E
W 2 2 N
W 2 4 N
W 2 5 E
W 3 2 N
W 3 3 N
W 3 4 E
W 3 5 E
W 4 1 E
W 4 1 N
W 4 3 E
W 4 3 N
W 4 4 E
W 4 5 E
W 5 2 E
W 5 2 N
W 5 4 E
W 5 5 N
W 5 6 E
W 6 4 N

View file

@ -0,0 +1,34 @@
6 6 1 1 E 72
B 5 4 1
W 1 1 E
W 1 3 E
W 1 4 E
W 1 5 N
W 2 1 N
W 2 2 E
W 2 2 N
W 2 4 N
W 2 5 E
W 3 2 N
W 3 3 N
W 3 4 E
W 3 5 E
W 4 1 E
W 4 1 N
W 4 3 E
W 4 3 N
W 4 4 E
W 4 5 E
W 5 2 E
W 5 2 N
W 5 4 E
W 5 5 N
W 5 6 E
W 6 4 N

View file

@ -0,0 +1,34 @@
6 6 1 1 E 72
B 5 5 1
W 1 1 E
W 1 3 E
W 1 4 E
W 1 5 N
W 2 1 N
W 2 2 E
W 2 2 N
W 2 4 N
W 2 5 E
W 3 2 N
W 3 3 N
W 3 4 E
W 3 5 E
W 4 1 E
W 4 1 N
W 4 3 E
W 4 3 N
W 4 4 E
W 4 5 E
W 5 2 E
W 5 2 N
W 5 4 E
W 5 5 N
W 5 6 E
W 6 4 N

View file

@ -0,0 +1,34 @@
6 6 1 1 E 72
B 5 6 1
W 1 1 E
W 1 3 E
W 1 4 E
W 1 5 N
W 2 1 N
W 2 2 E
W 2 2 N
W 2 4 N
W 2 5 E
W 3 2 N
W 3 3 N
W 3 4 E
W 3 5 E
W 4 1 E
W 4 1 N
W 4 3 E
W 4 3 N
W 4 4 E
W 4 5 E
W 5 2 E
W 5 2 N
W 5 4 E
W 5 5 N
W 5 6 E
W 6 4 N

View file

@ -0,0 +1,34 @@
6 6 1 1 E 72
B 6 1 1
W 1 1 E
W 1 3 E
W 1 4 E
W 1 5 N
W 2 1 N
W 2 2 E
W 2 2 N
W 2 4 N
W 2 5 E
W 3 2 N
W 3 3 N
W 3 4 E
W 3 5 E
W 4 1 E
W 4 1 N
W 4 3 E
W 4 3 N
W 4 4 E
W 4 5 E
W 5 2 E
W 5 2 N
W 5 4 E
W 5 5 N
W 5 6 E
W 6 4 N

View file

@ -0,0 +1,34 @@
6 6 1 1 E 72
B 6 2 1
W 1 1 E
W 1 3 E
W 1 4 E
W 1 5 N
W 2 1 N
W 2 2 E
W 2 2 N
W 2 4 N
W 2 5 E
W 3 2 N
W 3 3 N
W 3 4 E
W 3 5 E
W 4 1 E
W 4 1 N
W 4 3 E
W 4 3 N
W 4 4 E
W 4 5 E
W 5 2 E
W 5 2 N
W 5 4 E
W 5 5 N
W 5 6 E
W 6 4 N

View file

@ -0,0 +1,34 @@
6 6 1 1 E 72
B 6 3 1
W 1 1 E
W 1 3 E
W 1 4 E
W 1 5 N
W 2 1 N
W 2 2 E
W 2 2 N
W 2 4 N
W 2 5 E
W 3 2 N
W 3 3 N
W 3 4 E
W 3 5 E
W 4 1 E
W 4 1 N
W 4 3 E
W 4 3 N
W 4 4 E
W 4 5 E
W 5 2 E
W 5 2 N
W 5 4 E
W 5 5 N
W 5 6 E
W 6 4 N

View file

@ -0,0 +1,34 @@
6 6 1 1 E 72
B 6 4 1
W 1 1 E
W 1 3 E
W 1 4 E
W 1 5 N
W 2 1 N
W 2 2 E
W 2 2 N
W 2 4 N
W 2 5 E
W 3 2 N
W 3 3 N
W 3 4 E
W 3 5 E
W 4 1 E
W 4 1 N
W 4 3 E
W 4 3 N
W 4 4 E
W 4 5 E
W 5 2 E
W 5 2 N
W 5 4 E
W 5 5 N
W 5 6 E
W 6 4 N

View file

@ -0,0 +1,34 @@
6 6 1 1 E 72
B 6 5 1
W 1 1 E
W 1 3 E
W 1 4 E
W 1 5 N
W 2 1 N
W 2 2 E
W 2 2 N
W 2 4 N
W 2 5 E
W 3 2 N
W 3 3 N
W 3 4 E
W 3 5 E
W 4 1 E
W 4 1 N
W 4 3 E
W 4 3 N
W 4 4 E
W 4 5 E
W 5 2 E
W 5 2 N
W 5 4 E
W 5 5 N
W 5 6 E
W 6 4 N

View file

@ -0,0 +1,34 @@
6 6 1 1 E 72
B 6 6 1
W 1 1 E
W 1 3 E
W 1 4 E
W 1 5 N
W 2 1 N
W 2 2 E
W 2 2 N
W 2 4 N
W 2 5 E
W 3 2 N
W 3 3 N
W 3 4 E
W 3 5 E
W 4 1 E
W 4 1 N
W 4 3 E
W 4 3 N
W 4 4 E
W 4 5 E
W 5 2 E
W 5 2 N
W 5 4 E
W 5 5 N
W 5 6 E
W 6 4 N

View file

@ -0,0 +1,32 @@
6 6 1 1 E 72
W 1 1 E
W 1 3 E
W 1 4 E
W 1 5 N
W 2 1 N
W 2 2 E
W 2 2 N
W 2 4 N
W 2 5 E
W 3 2 N
W 3 3 N
W 3 4 E
W 3 5 E
W 4 1 E
W 4 1 N
W 4 3 E
W 4 3 N
W 4 4 E
W 4 5 E
W 5 2 E
W 5 2 N
W 5 4 E
W 5 5 N
W 5 6 E
W 6 4 N

View file

@ -0,0 +1,30 @@
6 6 2 1 E 72
B 6 3 1
W 2 1 N
W 3 1 N
W 4 1 N
W 2 5 N
W 3 5 N
W 4 5 N
W 1 2 E
W 1 3 E
W 1 4 E
W 1 5 E
W 4 2 E
W 2 3 E
W 2 4 E
W 4 5 E
W 5 1 E
W 5 2 E
W 5 4 E
W 5 5 E
W 5 6 E
W 6 3 N
W 6 3 S

View file

@ -0,0 +1,34 @@
6 6 1 1 E 72
B {st} {ave} 1
W 1 1 E
W 1 3 E
W 1 4 E
W 1 5 N
W 2 1 N
W 2 2 E
W 2 2 N
W 2 4 N
W 2 5 E
W 3 2 N
W 3 3 N
W 3 4 E
W 3 5 E
W 4 1 E
W 4 1 N
W 4 3 E
W 4 3 N
W 4 4 E
W 4 5 E
W 5 2 E
W 5 2 N
W 5 4 E
W 5 5 N
W 5 6 E
W 6 4 N

View file

@ -0,0 +1,28 @@
from karel_tk import Karel
import sys
class SuperKarel(Karel):
# you can define your own helper functions on Karel here, if you wish to
def run(self):
# TODO
pass
def main():
if len(sys.argv) != 2:
print("Please provide a path to the world as an argument.")
return
k = SuperKarel(sys.argv[1], scale=3, font="Iosevka\\ Term")
k.set_step_delay(500)
k.run()
k.turn_off()
if __name__ == "__main__":
main()

View file

@ -0,0 +1,17 @@
9 9 1 1 E 0
W 2 1 E
W 3 2 S
W 3 2 E
W 4 3 S
W 4 3 E
W 5 4 S
W 5 4 E
W 6 5 S
W 7 4 W
W 7 3 W
W 7 2 W
W 7 1 W
B 3 2 1
B 4 3 1
B 5 4 1

View file

@ -0,0 +1,20 @@
9 9 1 1 E 0
W 1 1 E
W 2 1 N
W 3 2 S
W 3 2 E
W 4 3 S
W 4 3 E
W 5 4 S
W 5 4 E
W 6 5 S
W 7 4 W
W 7 3 W
W 7 2 W
W 7 1 W
B 3 2 1
B 4 3 1
B 5 4 1

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB