Introduction

Welcome to the Dancing Robots project! This is a game realized as a theme for Project OutFox, a Stepmania fork1.

The game is intended to be played in two stages. In the first stage you program a robot using a simple programming language. In the second stage you need to dance in order to successfully execute the instructions in your program!

Using this documentation

You can use the arrows on your keyboard to move between subsequent pages (as dictated by the menu on the left of this page). You may also quickly search for information by using the search icon on top of each page.

Screenshots

Selection screen
Selection screen

OutFox gameplay
OutFox gameplay

Evaluation screen success
Evaluation screen - success

Evaluation screen failure
Evaluation screen - failure

Command-line interface
Command-line interface

1 .

Setup

The process of setting up this game involves three crucial steps:

  1. cloning the Dancing Robots repository
  2. downloading and installing the engine
  3. adjusting a couple of preferences and linking the environment

Cloning the repository

git clone git@gitea.ks.matfyz.cz:auburn/dancing-robots.git

Installing the engine

This project is targeted at Project OutFox. You may download it for your OS at the bottom of this Project Outfox page. There should be a binary/installer ready to get you quickly started with the game.

You can find detailed information on how to set the engine up at the Project Outfox Wiki guide. The binary itself should be functioning on its own, but if you run into issues, you may find relevant troubleshooting tips there.

Environment configuration

  1. First off, run the engine binary. This should create a game directory somewhere in your $HOME. Let's assume it's ~/.project-outfox.
  2. Fire up your favourite shell. Make sure the shell is in the root of the working tree of this repository.
mkdir -p ~/.project-outfox/Themes/
ln -sr eralk ~/.project-outfox/Themes/eralk
  1. Now running the engine, adjust your preferences in its GUI:
  • you may also change these preferences in ~/.project-outfox/Save/Preferences.ini
  • Resolution:
    • Options -> Display & Graphics -> Display and Resolution (set the correct resolution of your display here)
  • Select this theme:
    • Options -> User experience -> Appearance options -> Theme (select ERALK)
  • Fail at end:
    • Options -> System settings -> Gameplay settings -> Default fail type -> End of song
Fail at end setting
Fail at end setting

File reloading

If you want for the engine to notice any new input/output files, return to the Main menu.

Adding new songs

Check out this guide on getting started with OutFox for more information.

The directory structure is the same as with Stepmania:

  • song packs are to be placed at ~/.project-outfox/Songs/
  • individual songs should be placed at ~/.project-outfox/Songs/<name-of-the-song-pack>/

Here's an example of such a directory structure:

% ~/.project-outfox/Songs tree -d -L 2
.
├── OutFox Serenity Volume 1
│   ├── Aspid Cat - Abandoned Doll
│   ├── Aspid Cat - Conflicting Revenge
│   ├── DJ Megas - Plasma
│   ├── spirai project -drazil- - synthborn lovebirds
├── OutFox Serenity Volume 2
│   ├── Ace of Beat - B-Happy
│   ├── Thomas Dingwall a.k.a. td - CRUSH THE DEVIL (IN MY BRAIN)
│   └── Zenth - Relaxation Piece of Conclusion
└── Undertale Pack
    ├── Chill (MarioNintendo)
    ├── Ghouliday (MarioNintendo)
    ├── Long Elevator (MarioNintendo)
    ├── Oh My (MarioNintendo)
    ├── Ooo (MarioNintendo)
    ├── Pathetic House (MarioNintendo)

If your packs are already located elsewhere and you don't feel like linking/copying them, you can tell the engine to look for them at the specified folder via a preference (as per this page). Just do AdditionalSongsFolders=/path/to/other/song-pack-dir in your Preferences.ini.

Obtaining new songs

How to play

Make sure you've got your environment set up before continuing.

Programming gameplay

There are multiple problems that you may wish to solve in the game.

Each problem involves writing a sequence of commands to be executed by a robot named Eralk1. Following these commands, Eralk should always traverse from a starting point to an end point while additionally interacting with the game field (maze) as per the problem statement.

For each problem, you are provided a handful of static inputs that you may choose to solve. You may also design a solver to tackle any valid input from the given problem class for extra points (this is to be tested in the "classic KSP" way: with time-constrained inputs).

Dance gameplay

Once your command sequences (outputs) are ready, it's time to dance!

Just fire up an already-configured engine and select the problem instance code from a list before the chosen song start. The commands from your output file will get mapped uniformly on the song notes.

If you hit any note associated with an instruction, the instruction gets executed. There may be multiple notes associated with a single instructions and vice-versa. You are guaranteed for each instruction to be associated with at least 3 notes. If you fail to hit all notes associated with an instruction, a random instruction will be executed instead.

You may choose to play on any difficulty, single-player or multiplayer.

main.lua

This script allows both for generating and testing problems. If the script mentions inputs and outputs, by that it means the files located in the Inputs and Output folders respectively (relative to the project repository root).

See main.lua -h for more information on its usage.

Example usage

# generate a problem instance 'spiral_n4' while passing n=4 to the underlying generator
> ./main.lua generate spiral spiral_n4 n 4
# test a problem instance 'comb_n2' while both showing progress and showing warnings
> ./main.lua test comb_n2 -p -w

Inputs

This is the folder used to store problem instance files. It's also where the main.lua generate command stores the generated inputs. There is currently no naming convention other than that the files must end with an .in extension (the generate command adds them automatically).

Outputs

This is the folder used to store user data - outputs (command sequences). There is currently no naming convention other than that the files must end with an .out extension.

Important note: a file named Outputs/problem-instance.out is expected to be solving a Inputs/problem-instance.in.

Examples

Here you can find example inputs and outputs. You may copy them over to Inputs/Outputs in order to test them.

1 descendant of the Great Hrochobot

How to program

This guide covers input and output type format, as well as available commands. If you wish to solve a problem instance named Inputs/<problem-instance>.in, you are expected to put your solution in a file named Outputs/<problem-instance>.out.

Internal coordinate representation

  • when seeing certain messages, you will encounter the coordinates in this format unless stated otherwise (e.g. the game reports an error specifying a graph edge)
  • the game uses the (y,x) (also referred to as (row,col)) coordinate system with its origin being at the top-left corner of the grid
    • the x-coordinate increases by going right (east), the y-coordinate increases by going down (south)
    • beware, the top-left corner is actually at (1,1) (that's because lua arrays are designed as 1-indexed 😎) Example (padded with extra spaces for clarity)
row/col 1  2  3 4 5 6   7   8
   1    #  #  # # # #   #   #
   2    #  .  . # . .   E   #
   3    #  .  . I . .   #   #
   4    #  #  . . . .   .   #
   5    #  .  . I # I (5,7) #
   6    #  .  . . . #   .   #
   7    #  IS # I . I   #   #
   8    #  #  # # # #   #   #

Orientation

  • there are 4 directions, one of which the robot will be facing: North, East, South, West
  • moving North decreases the y (row) coordinate of the robot
  • moving East increases the x (col) coordinate of the robot
  • moving South increases the y (row) coordinate of the robot
  • moving West decreases the x (col) coordinate of the robot
  • Eralk's default orientation is to North

Robot commands

  • in the following examples, Eralk is marked as one of nesw denoting his orientation in the maze
  • start and end cells are omitted for better alignment and readability
  • TURN_LEFT
    • formally, this command changes the robot's orientation like this (the format is Old orientation -> New orientation): North -> West, West -> South, South -> East, East -> North
# # # #                # # # #                # # # #                # # # #                # # # #
# n . #                # w . #                # s . #                # e . #                # n . #
# . . # -> TURNLEFT -> # . . # -> TURNLEFT -> # . . # -> TURNLEFT -> # . . # -> TURNLEFT -> # . . #
# . . #                # . . #                # . . #                # . . #                # . . #
# # # #                # # # #                # # # #                # # # #                # # # #
  • TURN_RIGHT
    • inverse operation to the TURN_LEFT command
  • COLLECT
    • this command makes Eralk collect ONE item at the current position and adds it to Eralk's inventory
    • if there's no item to be collected, this command functions as a NOP except that you get a warning in stderr (which you can safely ignore if you don't care)
  • DROP
    • Eralk drops ONE item at the current position from his inventory
    • if Eralk's inventory is empty, this command functions as a NOP except that you get a warning in stderr (which you can safely ignore if you don't care)
  • MOVE_TO_ITEM
  • if there's a wall somewhere between Eralk and the closest item in his direction, this command functions as MOVE_TO_WALL
  • otherwise Eralk makes at least one step in the direction of his current orientation and stops at the closest item detected underneath him
# #  # # # # #                  # # #  # # # #
# .  I . . . #                  # . I  . . . #
# # Ie I I # # -> MOVETOITEM -> # # I Ie I # #
# .  . . . . #                  # . .  . . . #
# #  # # # # #                  # # #  # # # #
# # # # #                  # # # # #
# . # . #                  # . # . #
# . . . #                  # . n . #
# . . . # -> MOVETOITEM -> # . . . # (acts as MOVETOWALL)
# . . . #                  # . . . #
# . n . #                  # . . . #
# # # # #                  # # # # #
# # # # #                  # # # # #
# . I . #                  # . I . #
# . I . #                  # . I . #
# . # . # -> MOVETOITEM -> # . # . # (acts as MOVETOWALL)
# . . . #                  # . n . #
# . n . #                  # . . . #
# # # # #                  # # # # #
  • MOVE_TO_WALL
    • move in the current direction until there's a wall one step away from Eralk
    • in this command Eralk makes ZERO or more steps (that is, he may not need to move at all if standing in front of a wall already)
  • MOVE_TO_START
    • makes Eralk move in the current direction until he's standing at a cell marked as start S
    • if there's no start in the current direction, this command functions as MOVE_TO_WALL
    • in this command Eralk makes ZERO or more steps (that is, he may not need to move at all if standing on start already)
  • MOVE_TO_END
    • makes Eralk move in the current direction until he's standing at a cell marked as end E
    • if there's no start in the current direction, this command functions as MOVE_TO_WALL
    • in this command Eralk makes ZERO or more steps (that is, he may not need to move at all if standing on end already)
  • NOP
    • it does absolutely nothing lol

Input file (problem instance) description

  • the first line in the file contains a lowercase single-word string determining the game type (=problem class)
  • on the next line follow two space-separated positive integers h w denoting the height and the width of the grid, respectively, measured in cells
  • next follow h lines, each containing precisely w space-separated cell type descriptions
sortp
10 10
# # # # # # # # # #
# . . . . # . . E #
# . . . . I . . # #
# . . # . . . . . #
# . . I . I # . . #
# # . . . . . # . #
# . . I # I . I # #
# . . . . # . . . #
# IS # I . I # I . #
# # # # # # # # # #

Cell types

  • a cell can be one or more of:
    • empty (denoted by the char .)
    • non-empty:
      • item (denoted by the char I)
        • items don't have any internal identifiers, they are indistinguishable from one another
      • start (S)
      • end (E)
      • wall (#)
  • cell types may be combined (e.g. you may encounter SEI meaning there's start, end and a single item on this cell), however you will never encounter a cell that is described nboth as empty and non-empty at the same time (e.g. .I is a forbidden cell description)
  • there may be multiple items at a single cell (e.g. EIIIIS), but there will never be more than one start, end, wall or empty
  • there is always precisely one start and one end
  • each cell either is a wall or has wall neighbours in all 4 directions
  • cell type order is arbitrary

Output file format

  • sequence of commands that the robot shall execute in the order given in this file
  • there is no size limit (yet)
  • the parser is pretty chill about the user input
  • commands are read in a case-insensitive way, you can even put dashes or underscores inside them if you feel like it
    • e.g. all MOVETOWALL, movetowall, move-to-wall or moveToWall are recognized as the same command
  • other non-letter characters (that is, besides - and _) are treated as command separators

How to dance

Here's a link to familiarize yourself with the basic patterns in dance games.

Once you have your output files ready in the Outputs directory, you may choose to start Outfox. Select the dance mode if prompted. Upon selecting the difficulty, pick either Easy or Normal.

Game difficulty selection menu
Game difficulty selection menu

You may choose to play either in a singleplayer or a multiplayer in any difficulty you'd like. If you decide to do multiplayer, then determining whether or not a group of instructions should be executed correctly depends on if any of the players succeeds in hitting any of the notes associated with the instruction group.

Select a song and choose a desired problem instance to solve.

Song selection screen
Song selection screen

Problem selection screen
Problem selection screen

Keep playing as good as you can! There are at least 3 notes associated with each instruction. Hold and roll notes each count as two notes - one is for the note's head, the other for its tail.

Gameplay screen
Gameplay screen

Aaaand here's the evaluation screen. If you fail, you will see what exactly ended up being wrong with your run (from the judge's output). The error list is limited to 3 errors only.

Failed gameplay evaluation screen
Failed gameplay evaluation screen

Problemset

There's currently 5 classes of problems, each with a slightly different goal.

They all have a couple of things in common:

  • input and output format
  • accepted set of commands
  • Eralk must be standing at the end cell after interpreting all instructions
    • the direction he's facing doesn't matter unless stated otherwise in a specific problem class

Problem classes

comb gameplay
comb gameplay
matrix
matrix gameplay
sortp
sortp gameplay
spiral
spiral gameplay
wave
wave gameplay

comb

Your goal here is to traverse a "comb"-shaped maze while collecting every item along the way.

The items are sometimes randomly placed on the tips of the comb, but nowhere else.

Problem statement

Maze format

  • let n,m be positive integers
  • you are given a (m+3)x(4n+3) grid
    • there are solid walls on all of its 4 borders (so there is a solid left,right,bottom,top wall line)
  • the origin (1,1) is located at the top left corner of the maze (the intersection of the top and left border)
  • for each valid integer k, the (4k+3)rd column is filled with wall except for a single cell at the very bottom of this column (just before the border)
    • this cell may or may not contain an item
  • for each valid integer k, the (4k+1)st column is filled with wall except for a single cell at the very top of this column (just before the border)
    • this cell may or may not contain an item
  • there are no other walls or items elsewhere other that at the just mentioned positions
  • you start off at the top-left-most empty cell (the position (2,2)) and end at the bottom-right-most empty cell (the position (m+2,4n+2)).

Objective

  • you must drop all items at the ending cell before your program finishes

Examples

You may find all of the inputs and outputs in the Examples/comb directory. See the robot's progress while solving these problems by e.g. running

./main.lua test -p Examples/comb/comb_n2.in Examples/comb/comb_n2.out

or just

./main.lua test -p Examples/comb/comb_n2.{in,out}

if your shell supports it.

Example 1

Example input (n=2, m=10) (Examples/comb/comb_n2.in)

comb
13 11
# # # # # # # # # # #
# S # . . . # . I . #
# . # . # . # . # . #
# . # . # . # . # . #
# . # . # . # . # . #
# . # . # . # . # . #
# . # . # . # . # . #
# . # . # . # . # . #
# . # . # . # . # . #
# . # . # . # . # . #
# . # . # . # . # . #
# . I . # . I . # E #
# # # # # # # # # # #

Example final form

  • note: the robot orientation doesn't matter
  • also note that the robot's inventory MUST be empty after finishing the program
# # # # # # # # # # #
# S # . . . # . . . #
# . # . # . # . # . #
# . # . # . # . # . #
# . # . # . # . # . #
# . # . # . # . # . #
# . # . # . # . # . #
# . # . # . # . # . #
# . # . # . # . # . #
# . # . # . # . # . #
# . # . # . # . # . #
# . . . # . . . # nEIII #
# # # # # # # # # # #

Example output (Examples/comb/comb_n2.out)

turnright
turnright
movetowall
turnleft
movetoitem
collect
movetowall
turnleft
movetowall
turnright
movetowall
turnright
movetowall
turnleft
movetoitem
collect
movetowall
turnleft
movetowall
turnright
movetoitem
collect
movetowall
turnright
movetowall
turnleft
movetowall
turnleft
drop
drop
drop

Example 2

Example input (n=10, m=1) (Examples/comb/comb_n10.in)

comb
4 43
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# S # . . . # . I . # . . . # . I . # . . . # . . . # . . . # . . . # . I . # . . . #
# . I . # . I . # . I . # . I . # . . . # . . . # . . . # . I . # . I . # . I . # E #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

Example final form

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# S # . . . # . . . # . . . # . . . # . . . # . . . # . . . # . . . # . . . # . . . #
# . . . # . . . # . . . # . . . # . . . # . . . # . . . # . . . # . . . # . . . # n #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

matrix

You are given an undirected graph with self-loops on each node in the form of an adjacency matrix. Find and report the shortest path in this graph.

Problem statement

Maze format

  • let n >= 3 be a positive integer
  • let there be an undirected unweighted graph G=({1..n},E)
    • every vertex of the graph contains a self-loop
  • the problem is encoded in the grid as follows:
    • the grid has a square shape of (n+2)x(n+2) cells
    • there are solid walls on all of its 4 borders (so there is a solid left,right,bottom,top wall line)
    • the top-left-most non-wall cell is at row 1, column 1
    • column number increases by moving east, row number increases by moving south
    • there is an edge e=(u,v) in E if and only if there is an item at row u, column v
      • since the graph is undirected, there also exists an edge e'=(v,u) opposite to the edge e
  • both start and end are placed in the same position (row, column): (r,s)

Objective

  • your task is to find the shortest path from node r to node s
    • the length of the shortest path is guaranteed to be at least 2 edges
    • if there's multiple shortest paths, you may choose to output any one of them
  • if the shortest path has length of k edges and is consisted of oriented edges (v1,v2),(v2,v3),...,(v{k}, v{k+1}), then the robot shall collect items at positions (v1,v2),...,(v{k},v{k+1}) and drop them all at position (r, s)
  • in the end, the only collected or moved items shall be the ones representing the shortest path

Examples

You may find all of the inputs and outputs in the Examples/matrix directory. See the robot's progress while solving these problems by e.g. running

./main.lua test -p Examples/matrix/matrix_n4.in Examples/matrix/matrix_n4.out

Example 1

Explanation

We need to find a shortest path from node 1 to node 4. One such path consists of edges (1,2) and (2,4). Thus we pick up these two items at corresponding positions and bring them to the endpoint with us.

Example input (n=4) (Examples/matrix/matrix_n4.in)

matrix
6 6
# # # # # #
# I I . SE #
# I I I I #
# . I I I #
# . I I I #
# # # # # #

Example final form (added node numbering for clarity)

    1 2 3 4
  # # # # # #
1 # I . . nESII #
2 # I I I . #
3 # . I I I #
4 # . I I I #
  # # # # # #

Example output

turnleft
movetoitem
collect
turnright
turnright
movetowall
turnright
movetoitem
collect
turnright
turnright
movetoend
drop
drop

sortp

(as in "sort a permutation")

Oh no, our beautiful identity permutation had just been shuffled! Can you help us put it back to its original form?

Problem statement

Maze format

  • let n be a positive integer greater than one
  • let p: {1..n} -> {1..n} != id be a permutation (bijective function with the same domain and range - {1..n})
  • the permutation p is encoded on the grid as follows:
    • the grid has a square shape of size (2n+2)x(2n+2) with walls on its borders (so there is a solid left,right,bottom,top wall line)
    • in the (2i)-th column you will find p(i) items placed from the bottom wall to top
    • let's denote the bottom wall a row no. 1
    • the first item is placed right above the bottom-most wall block (row 2)
    • each consecutive item is placed two blocks above the previous item (rows 2,4,6,8,...2i)
    • there is a wall at column 2i, row 2i+3
    • there is also a partially filled diagonal of walls starting right to the position of column 2i, row 2i
      • this diagonal continues in the bottom-right direction all the way until it hits a border wall
    • the start is placed at position column 2, row 2 (the bottom-left-most non-wall position)
    • the start is placed at position column 2n+1, row 2n+1 (the top-right-most non-wall position)

Objective

  • Eralk's task is to rearrange the items so that the grid represents a sequence 1,2,...,n

Examples

You may find all of the inputs and outputs in the Examples/sortp directory. See the robot's progress while solving these problems by e.g. running

./main.lua test -p Examples/sortp/sortp_n4.in Examples/sortp/sortp_n4.out

Example 1

Example input (n=4,p=(1,3,4,2)) (Examples/sortp/sortp_n4.in)

sortp
10 10
# # # # # # # # # #
# . . . . # . . E #
# . . . . I . . # #
# . . # . . . . . #
# . . I . I # . . #
# # . . . . . # . #
# . . I # I . I # #
# . . . . # . . . #
# IS # I . I # I . #
# # # # # # # # # #

Example final form

# # # # # # # # # #
# . . . . # . . eE #
# . . . . . . I # #
# . . # . . . . . #
# . . . . I # I . #
# # . . . . . # . #
# . . I # I . I # #
# . . . . # . . . #
# IS # I . I # I . #
# # # # # # # # # #

Example output

movetowall
turnright
movetoitem
turnleft
movetoitem
collect
turnright
movetowall
turnleft
movetoitem
collect
turnright
movetowall
drop
turnright
movetowall
drop
turnleft
turnleft
movetowall
turnright
movetoend

Example 2

Example input (n=5,p=(1,3,5,4,2)) (Examples/sortp/sortp_n5.in)

sortp
12 12
# # # # # # # # # # # #
# . . . . . . # . . E #
# . . . . I . . . . # #
# . . . . # . . . . . #
# . . . . I . I # . . #
# . . # . . . . . # . #
# . . I . I # I . . # #
# # . . . . . # . . . #
# . . I # I . I # I . #
# . . . . # . . . # . #
# IS # I . I # I . I # #
# # # # # # # # # # # #

Example final form

# # # # # # # # # # # #
# . . . . . . # . . e #
# . . . . . . . . I # #
# . . . . # . . . . . #
# . . . . . . I # I . #
# . . # . . . . . # . #
# . . . . I # I . I # #
# # . . . . . # . . . #
# . . I # I . I # I . #
# . . . . # . . . # . #
# IS # I . I # I . I # #
# # # # # # # # # # # #

Example 3

Example input (n=10,p=(8,5,3,1,9,7,10,4,2,6)) (Examples/sortp/sortp_n10.in)

sortp
22 22
# # # # # # # # # # # # # # # # # # # # # #
# . . . . . . . . . . . . . . . . # . . E #
# . . . . . . . . . . . . I . . . . . . # #
# . . . . . . . . . . . . . . # . . . . . #
# . . . . . . . . I . . . I . . . . # . . #
# . . . . . . . . . . . . # . . . . . # . #
# I . . . . . . . I . . . I . . # . . . # #
# . . . . . . . . . . # . . . . . # . . . #
# I . . . . . . . I . I . I # . . . # . . #
# . . . . . . . . # . . . . . # . . . # . #
# I . . . . . . . I . I # I . . # . . I # #
# . . . . . . # . . . . . # . . . # . . . #
# I . I . . . . . I # I . I # . . . # I . #
# . . . . # . . . . . # . . . # . . . # . #
# I . I . . . . # I . I # I . I # . . I # #
# . . # . . . . . # . . . # . . . # . . . #
# I . I . I # . . I # I . I # I . . # I . #
# # . . . . . # . . . # . . . # . . . # . #
# I . I # I . . # I . I # I . I # I . I # #
# . . . . # . . . # . . . # . . . # . . . #
# IS # I . I # I . I # I . I # I . I # I . #
# # # # # # # # # # # # # # # # # # # # # #

Example final form

# # # # # # # # # # # # # # # # # # # # # #
# . . . . . . . . . . . . . . . . # . . e #
# . . . . . . . . . . . . . . . . . . I # #
# . . . . . . . . . . . . . . # . . . . . #
# . . . . . . . . . . . . . . . . I # I . #
# . . . . . . . . . . . . # . . . . . # . #
# . . . . . . . . . . . . . . I # I . I # #
# . . . . . . . . . . # . . . . . # . . . #
# . . . . . . . . . . . . I # I . I # I . #
# . . . . . . . . # . . . . . # . . . # . #
# . . . . . . . . . . I # I . I # I . I # #
# . . . . . . # . . . . . # . . . # . . . #
# . . . . . . . . I # I . I # I . I # I . #
# . . . . # . . . . . # . . . # . . . # . #
# . . . . . . I # I . I # I . I # I . I # #
# . . # . . . . . # . . . # . . . # . . . #
# . . . . I # I . I # I . I # I . I # I . #
# # . . . . . # . . . # . . . # . . . # . #
# . . I # I . I # I . I # I . I # I . I # #
# . . . . # . . . # . . . # . . . # . . . #
# IS # I . I # I . I # I . I # I . I # I . #
# # # # # # # # # # # # # # # # # # # # # #

spiral

Your goal is to traverse a spiral from one of the maze corners to its center. There are no items to collect this time.

Problem statement

Maze format

  • let n be a positive integer
  • you are given a (4n+2)x(4n+1) grid
    • there are solid walls on all of its 4 borders (so there is a solid left,right,bottom,top wall line)
  • the origin (1,1) is located at the top left corner of the maze (the intersection of the top and left border)
  • the robot starts at the top-right-most empty cell (position (2,4n))
  • right underneath the robot, there starts a spiral that whirls towards the center and makes a left turn two blocks before a wall

Objective

  • just get to the end by any means

Examples

You may find all of the inputs and outputs in the Examples/spiral directory. See the robot's progress while solving these problems by e.g. running

./main.lua test -p Examples/spiral/spiral_n1.in Examples/spiral/spiral_n1.out

or just

./main.lua test -p Examples/spiral/spiral_n2.{in,out}

if your shell supports it.

Example 1

Example input (n=1) (Examples/spiral/spiral_n1.in)

spiral
6 5
# # # # #
# . . S #
# . # # #
# . # E #
# . . . #
# # # # #

Example final form

# # # # #
# . . S #
# . # # #
# . # n #
# . . . #
# # # # #

Example output (Examples/spiral/spiral_n1.out)

turnleft
movetowall
turnleft
movetowall
turnleft
movetowall
turnleft
movetowall

Example 2

Example input (n=4) (Examples/spiral/spiral_n4.in)

spiral
18 17
# # # # # # # # # # # # # # # # #
# . . . . . . . . . . . . . . S #
# . # # # # # # # # # # # # # # #
# . # . . . . . . . . . . . . . #
# . # . # # # # # # # # # # # . #
# . # . # . . . . . . . . . # . #
# . # . # . # # # # # # # . # . #
# . # . # . # . . . . . # . # . #
# . # . # . # . # # # . # . # . #
# . # . # . # . # E # . # . # . #
# . # . # . # . . . # . # . # . #
# . # . # . # # # # # . # . # . #
# . # . # . . . . . . . # . # . #
# . # . # # # # # # # # # . # . #
# . # . . . . . . . . . . . # . #
# . # # # # # # # # # # # # # . #
# . . . . . . . . . . . . . . . #
# # # # # # # # # # # # # # # # #

Example final form

# # # # # # # # # # # # # # # # #
# . . . . . . . . . . . . . . S #
# . # # # # # # # # # # # # # # #
# . # . . . . . . . . . . . . . #
# . # . # # # # # # # # # # # . #
# . # . # . . . . . . . . . # . #
# . # . # . # # # # # # # . # . #
# . # . # . # . . . . . # . # . #
# . # . # . # . # # # . # . # . #
# . # . # . # . # nE # . # . # . #
# . # . # . # . . . # . # . # . #
# . # . # . # # # # # . # . # . #
# . # . # . . . . . . . # . # . #
# . # . # # # # # # # # # . # . #
# . # . . . . . . . . . . . # . #
# . # # # # # # # # # # # # # . #
# . . . . . . . . . . . . . . . #
# # # # # # # # # # # # # # # # #

wave

Eralk is stuck at the epicenter of a wave. Help him to get out while collecting all items along the way!

Problem statement

Maze format

  • let n be a positive integer
  • you are given a (4n+7)x(4n+7) grid
    • there are solid walls on all of its 4 borders (so there is a solid left,right,bottom,top wall line)
  • the origin (1,1) is located at the top left corner of the maze (the intersection of the top and left border)
  • there are n+1 concentric octagon-shaped borders ("waves"), each with a single hole in it
    • we can refer to the octagon's sides by their orientation (north,...,west,norteast,...,southwest)
    • before each hole there is always a single item to hold on to
    • k-th octagon has each side composed of 2k-1 walls
    • the hole is always in the middle of a (north,east,south,west) side
    • there's a hole on the north side of the first octagon, for each subsequent octagon a hole's position shifts 90 degrees clockwise
      • more formally:
      • for each valid l, there's a hole on the north side of the (4l-3)rd octagon
      • for each valid l, there's a hole on the east side of the (4l-2)nd octagon
      • for each valid l, there's a hole on the south side of the (4l-1)st octagon
      • for each valid l, there's a hole on the west side of the (4l)th octagon
  • start is at the center of the maze (the position (2n+4,2n+4))
  • end is located at the hole of the last ((n+1)st) octagon

Objective

  • your goal is to collect all items and drop them off at the end

Examples

You may find all of the inputs and outputs in the Examples/wave directory. See the robot's progress while solving these problems by e.g. running

./main.lua test -p Examples/wave/wave_n2.in Examples/wave/wave_n2.out

or just

./main.lua test -p Examples/wave/wave_n2.{in,out}

if your shell supports it.

Example 1

Example input (n=2) (Examples/wave/wave_n2.in)

wave
15 15
# # # # # # # # # # # # # # #
# . . . . # # # # # . . . . #
# . . . # . . . . . # . . . #
# . . # . . # # # . . # . . #
# . # . . # . . . # . . # . #
# # . . # . . . . . # . . # #
# # . # . . # I # . . # . # #
# # . # . # . S . # I . . # #
# # . # . . # . # . . # . # #
# # . . # . . # . . # . . # #
# . # . . # . . . # . . # . #
# . . # . . # # # . . # . . #
# . . . # . . I . . # . . . #
# . . . . # # E # # . . . . #
# # # # # # # # # # # # # # #

Example final form

# # # # # # # # # # # # # # #
# . . . . # # # # # . . . . #
# . . . # . . . . . # . . . #
# . . # . . # # # . . # . . #
# . # . . # . . . # . . # . #
# # . . # . . . . . # . . # #
# # . # . . # . # . . # . # #
# # . # . # . S . # . . . # #
# # . # . . # . # . . # . # #
# # . . # . . # . . # . . # #
# . # . . # . . . # . . # . #
# . . # . . # # # . . # . . #
# . . . # . . . . . # . . . #
# . . . . # # sEIII # # . . . . #
# # # # # # # # # # # # # # #

Example 2

Example input (n=6) (Examples/wave/wave_n6.in)

wave
31 31
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# . . . . . . . . # # # # # # # # # # # # # . . . . . . . . #
# . . . . . . . # . . . . . . . . . . . . . # . . . . . . . #
# . . . . . . # . . # # # # # # # # # # # . . # . . . . . . #
# . . . . . # . . # . . . . . . . . . . . # . . # . . . . . #
# . . . . # . . # . . # # # # . # # # # . . # . . # . . . . #
# . . . # . . # . . # . . . . I . . . . # . . # . . # . . . #
# . . # . . # . . # . . # # # # # # # . . # . . # . . # . . #
# . # . . # . . # . . # . . . . . . . # . . # . . # . . # . #
# # . . # . . # . . # . . # # # # # . . # . . # . . # . . # #
# # . # . . # . . # . . # . . . . . # . . # . . # . . # . # #
# # . # . # . . # . . # . . # # # . . # . . # . . # . # . # #
# # . # . # . # . . # . . # . . . # . . # . . # . # . # . # #
# # . # . # . # . # . . # . . . . . # . . # . # . # . # . # #
# # . # . # . # . # . # . . # I # . . # . # . # . # . # . # #
# # . # . # . . I # . # . # . S . # I . . # . # . # I . . # #
# # . # . # . # . # . # . . # . # . . # . # . # . # . # . # #
# # . # . # . # . # . . # . . # . . # . . # . # . # . # . # #
# # . # . # . # . . # . . # . . . # . . # . . # . # . # . # #
# # . # . # . . # . . # . . # # # . . # . . # . . # . # . # #
# # . # . . # . . # . . # . . I . . # . . # . . # . . # . # #
# # . . # . . # . . # . . # # . # # . . # . . # . . # . . # #
# . # . . # . . # . . # . . . . . . . # . . # . . # . . # . #
# . . # . . # . . # . . # # # # # # # . . # . . # . . # . . #
# . . . # . . # . . # . . . . . . . . . # . . # . . # . . . #
# . . . . # . . # . . # # # # # # # # # . . # . . # . . . . #
# . . . . . # . . # . . . . . . . . . . . # . . # . . . . . #
# . . . . . . # . . # # # # # # # # # # # . . # . . . . . . #
# . . . . . . . # . . . . . . I . . . . . . # . . . . . . . #
# . . . . . . . . # # # # # # E # # # # # # . . . . . . . . #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

Example final form

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# . . . . . . . . # # # # # # # # # # # # # . . . . . . . . #
# . . . . . . . # . . . . . . . . . . . . . # . . . . . . . #
# . . . . . . # . . # # # # # # # # # # # . . # . . . . . . #
# . . . . . # . . # . . . . . . . . . . . # . . # . . . . . #
# . . . . # . . # . . # # # # . # # # # . . # . . # . . . . #
# . . . # . . # . . # . . . . . . . . . # . . # . . # . . . #
# . . # . . # . . # . . # # # # # # # . . # . . # . . # . . #
# . # . . # . . # . . # . . . . . . . # . . # . . # . . # . #
# # . . # . . # . . # . . # # # # # . . # . . # . . # . . # #
# # . # . . # . . # . . # . . . . . # . . # . . # . . # . # #
# # . # . # . . # . . # . . # # # . . # . . # . . # . # . # #
# # . # . # . # . . # . . # . . . # . . # . . # . # . # . # #
# # . # . # . # . # . . # . . . . . # . . # . # . # . # . # #
# # . # . # . # . # . # . . # . # . . # . # . # . # . # . # #
# # . # . # . . . # . # . # . S . # . . . # . # . # . . . # #
# # . # . # . # . # . # . . # . # . . # . # . # . # . # . # #
# # . # . # . # . # . . # . . # . . # . . # . # . # . # . # #
# # . # . # . # . . # . . # . . . # . . # . . # . # . # . # #
# # . # . # . . # . . # . . # # # . . # . . # . . # . # . # #
# # . # . . # . . # . . # . . . . . # . . # . . # . . # . # #
# # . . # . . # . . # . . # # . # # . . # . . # . . # . . # #
# . # . . # . . # . . # . . . . . . . # . . # . . # . . # . #
# . . # . . # . . # . . # # # # # # # . . # . . # . . # . . #
# . . . # . . # . . # . . . . . . . . . # . . # . . # . . . #
# . . . . # . . # . . # # # # # # # # # . . # . . # . . . . #
# . . . . . # . . # . . . . . . . . . . . # . . # . . . . . #
# . . . . . . # . . # # # # # # # # # # # . . # . . . . . . #
# . . . . . . . # . . . . . . . . . . . . . # . . . . . . . #
# . . . . . . . . # # # # # # sEIIIIIII # # # # # # . . . . . . . . #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

Introduction

This part is targeted at whoever decides to extend this project by adding new playable/solvable content into it.

You can read about additional debug options for the engine, creating your own generator/solver/judge and also generating new inputs.

Debug options

Engine gameplay debugging

  • to show FPS and other information about your audio/video status press F3+6 while anywhere in OutFox (you're looking for Rendering stats)
  • to show errors onscreen press F3+F6+8 (Toggle screen errors)

Accessing logs

  • you may find all the logs in the ~/.project-outfox/Logs
    • the most useful log is probably gonna be ~/.project-outfox/Logs/ProjectOutfox-eralk.ThemeLua.<timestamp>.log which also serves as stderr for custom lua scripts

Generating inputs

You can generate new inputs via the ./main.lua generate command.

Generator arguments

  • If a generator requires N named arguments (with names <arg1>,...,<argN> and respective values <val1>,...,<valN>), specify them space-separated like this: <arg1> <val1> <arg2> <val2> ... <argN> <valN>
  • you can pass whatever arguments you want to the generators, but they may choose to ignore them or replace them if you provide an unfit value
  • there is a common argument seed which you can pass to the generator via the option -s or --seed <num>
    • this value defaults to 42 if not provided
    • again, some generators are not required to use randomness (and for example they expect the caller to tell them the exact problem size)

comb

  • recognized arguments/options: -s, --seed, seed, n, m
  • this generator uses randomness to determine item placement
  • n,m are used as defined in the problem statement
    • if you dont provide a valid value for either of these numbers, they default to n=10 and m=8
  • example generation:
./main.lua generate comb comb_n30 n 30 m 1

matrix

  • recognized arguments/options: -s, --seed, seed, n, m
  • this generator uses randomness to place the edges
  • n,m define number of vertices and edges respectively
  • default values:
    • n=10
    • m=math.random(2*n-1,math.min(4*n, n*(n-1)//2-1))

sortp

  • recognized arguments/options: -s, --seed, seed, n
  • this generator uses randomness to create a random permutation
  • default value:
    • n=10

spiral

  • recognized arguments/options: n
  • default: n=10

wave

  • recognized arguments/options: n
  • default: n=10

Defining new problems

  • defining a new problem consists of (writing the problem statement), creating a generator and a judge
  • in the following text we're going to assume the new problem class you want to create is called <problem-class>

Implementing a generator

  • first off, create a new directory <problem-class> in generators/
  • in there, you may create and link as many files as you have, but you need to have a main.lua file that ties them all together
  • all generators should inherit from the common Generator class which provides a few methods for modifying and printing the maze

Basic outline for a generator

-- assuming we're in generators/<problem-class>/main.lua
-- let's instantiate the Generator class first
local ProblemClassGenerator = = require("generators.common"):new()
function ProblemClassGenerator.generate(params)
  -- fetch the arguments from the params table here ...
  local gen = ProblemClassGenerator:new()
  gen:init("<problem-class", height, width)
  gen:add_borders()
  -- more logic to follow here ...
  -- Example usage:
  gen.grid[start_row][start_col]:add_start()
  gen.grid[end_row][end_col]:add_end()
  if i % 5 == 0 then
    gen.grid[5][5]:add_item()
  end
  -- always call this method at the end of the generate function
  -- to get a textual representation of your just-generated maze
  return tostring(gen)
end

return ProblemClassGenerator

Testing a generator

  • once ready, you may test your generator via the ./main.lua program
    • this little router allows for arbitrary string passing to a generator's params via the command-line arguments

Example

  • the following command passes the arguments "n"="10","m"="50","hello"="world" to your generator's params
  • it then stores the generated output to Inputs/problem-class-instance_n10.in
./main.lua generate <problem-class> problem-class-instance_n10 n 10 m 50 hello world

Creating a judge

  • your judge code should reside in the judges/<problem-class> directory
  • same case as with generators, put your "main" code in judges/<problem-class>/main.lua
  • all judges should inherit from the common Judge class

Basic outline for a judge

local ProblemClassJudge = require("judges.common"):new()
-- you may choose to overload the base class methods make_judgment or judge_next_command
-- this method is for evaluating the grid once all instructions have been executed
-- see judges/common.lua for a list of available methods (mainly the tests)
function ProblemClassJudge:make_judgment()
  self:add_judgment(self:test_if_robot_is_at_end())
  self:add_judgment(self:test_if_everything_collected())
  self.judgment_received = true
end

-- this other method is for continuous tracking of robot behaviour (you may use it to collect stats as well)
function ProblemClassJudge:judge_next_command(randomize)
  collect_stats()
  return Judge.judge_next_command(self, randomize) -- fallback to base class method
end

return ProblemClassJudge
  • a solver is meant to be implemented for just a single problem type
  • just write any program that reads a valid input file from stdin and outputs a valid and acceptable output file to stdout
  • see the solvers directory for more examples
  • once finished, add your solvers to the appropriate folder
  • a quick-and-dirty script may be enough (think about the maintainability though), no objects necessarily needed
  • here's a snippet of parsing the input and storing the maze data in lua:
local type_str = io.read("*line")
assert(type_str == "<problem-class>", string.format("wrong game type (expected '<problem-class>', got '%s')", type_str))
local h, w = io.read("*n", "*n", "*l") -- eat the newline by requesting to read a line

local row = 1
local maze = {}
for line in (io.read("*all") .. "\n"):gmatch('(.-)\r?\n') do
  maze[row] = maze[row] or {}
  local col = 1
  for cell in line:gmatch("[#ISE%.]+") do
    maze[row][col] = maze[row][col] or {}
    for obj_type in cell:gmatch(".") do
      -- this stores the literal representation of a cell type, you might want to consider processing it in a different way
      maze[row][col][#maze[row][col]+1] = obj_type
    end
    col = col+1
  end
  row = row+1
end

Current usage of solvers

  • the players aren't meant to see the solvers folder
  • for generating example outputs call this command
lua solvers/<problem-class>/main.lua < Inputs/<instance>.in > Outputs/<instance>.out

Overview of directory structure

Let's go through the project directory structure from the root up:

> tree -L 1
.
├── data_structures -> eralk/BGAnimations/_modules/data_structures
├── doc
├── eralk
├── Examples
├── generators
├── Inputs -> eralk/BGAnimations/_gamedata/Inputs
├── interpreter -> eralk/BGAnimations/_modules/interpreter
├── judges -> eralk/BGAnimations/_modules/judges
├── main.lua
├── Outputs -> eralk/BGAnimations/_gamedata/Outputs
├── README.md
└── solvers
> tree eralk -L 2
eralk
├── BGAnimations
│  ├── _gamedata
│  ├── _images
│  ├── _modules
│  ├── ScreenEvaluationEralk overlay
│  └── ScreenGameplay overlay
├── Languages
│   └── en.ini
├── metrics.ini
├── Scripts
│   ├── ListAllConfigurations.lua
│   └── loader.lua
└── ThemeInfo.ini

Right off the beginning, you will notice that I've symlinked a bunch of directories. This is because Project OutFox only runs scripts contained in the theme directory. Since I need interpreter and judges (and their dependence data_structures) modules to be both functioning in the CLI and the engine, I chose to move them to the OutFox theme directory and symlink them from there. Similar thing with Inputs and Outputs. I'm not symlinking what doesn't need to be linked.

Data structures

There's currently three data structures being defined: FenwickTree, Graph and Queue.

FenwickTree

This data structure is utilized for quickly answering queries of type "tell me a position of the closest item from this position" while allowing to add and remove items during runtime.

Graph

Used in the matrix problem (both in generator and judge). Is capable of generating (pseudo)random trees/graphs and reporting shortest paths.

Queue

Used by the game engine to queue instructions in case the interpreter is busy at the moment. Implemented using linked lists.

Interpreter

Let's start with the interpreter module. It contains a bunch of inter-dependent submodules that are utilized by THE interpreter (interpreter.intepreter)

List of structures/classes

Cell

The module cell.lua defines a structure for a single maze cell. Used in a Maze.

Maze

A container in maze.lua which stores a 2d array of cells while keeping track of its size, start and end cells and current items. Most notably depends on data_structures.fenwick-tree.

Enums

Various enums related to the interpreter are stored in enums.lua. There's enums defining tokens, cell types, directions and recognized game types.

Utils

Various helper methods for writing debug information and asserting conditions are stored in utils.lua.

RobotState

A simple structure containing robot's current row, column, orientation and inventory status. Used in a Game.

Game

Combines a Maze with a RobotState. Issues in-game warnings if turned on. It's possible to create one from an input file.

Interpreter

Contains a Game and a list of Tokens to parse. Takes care of interpreting instructions, maintaining the instruction pointer and letting others know when it's processed all instructions. Reports parsing-related warnings (if preference set).

Engine controller

Main code for the engine controller resides in eralk/BGAnimations/_modules/engine/.

constants

A bunch of named magic values that you can tweak to your liking is stored in constants.lua.

dancefloor

The main drawing class (also called Actor). Implemented as a polygon (ActorMultiVertex) of Quads with vertices referencing texture coordinates. Owns a direct reference to the current game state (data stored in the Game structure - the Maze and RobotState) to save bandwidth. Communicates with a judge-wrapper.

judge-wrapper

The wrapper around the current judge. Updates the game state (represented by an array of Drawables in this case) while telling dancefloor what part of the maze should be (re)drawn.

debug

A bunch of debugging utilities. Can be turned off via a flag.

enums

Enums relevant to the engine function are defined here. Contains a list of sprites, extended direction and utilities to manipulate them.

Drawable

An enum representing either a cell type or a shadow, sometimes also describing the object's orientation or count (in case of items). Examples: Drawable.robot_south, Drawable.item2, Drawable.start, Drawable.wall.

instruction-dispatcher

This module is in charge of processing hit and missed notes. It then decides whether the next group of instructions should be executed correctly or nah.

judgment-emitter

The sole purpose of this module is to parse hit and missed notes from a Judgment Message and then tell instruction-dispatcher how many hits and misses had each player just scored.

recognized-types

Helper module for abstracting work with notes and judgments. Used by judgment-emitter.

More about the theme

While we have covered the main engine controller code, there is still a couple of important files and concepts we should be aware of.

Screens

This theme (partially) defines three additional screens. For more information about screens and their layers, see the OutFox wiki.

ScreenSelectConfig

ScreenSelectConfig
ScreenSelectConfig

Because of the available resources (and my limited knowledge), this screen is defined in eralk/metrics.ini and eralk/Scripts/ListAllConfigurations.lua. It contains the logic for filtering files from Inputs and Outputs while passing the selected problem instance to the engine module via an environment variable.

Scripts

Be aware that the directory eralk/Scripts is meant to be used for quick-and-dirty scripts that are globally available from everywhere in the game environment. However, the alternative option to this was defining the lua function directly in eralk/metrics.ini which in my opinion felt slightly more messy than this.

ScreenGameplay overlay

ScreenGameplay overlay
ScreenGameplay overlay with notefield and judgment proxies

This is where the engine.dancefloor gets drawn at. The dancefloor actually gets to be drawn over the whole screen. The rest of the drawing logic ensures that the notefield and judgment messages get rendered as well. This is done by creating actor proxies and drawing them over dancefloor.

The current implementation of my drawing actors isn't "resistant" to some of the songs that you may find out in the wild (or even in the Serenity pack). It's those songs that define a #FGCHANGES in their configuration which lets them draw over, manipulate or straight up discard whatever this theme provides. Also, this theme doesn't really disable anything else but the original notefield, so things like background animations in the song might slow down the rendering.

Code for this screen resides at eralk/BGAnimations/ScreenGameplay overlay.

ScreenEvaluationEralk

ScreenEvaluationEralk
ScreenEvaluationEralk

This is the evaluation screen for the Eralk gameplay. It simply reports whether the game was succesful and provides at most 3 remarks / errors for the player. Code for this screen resides at eralk/BGAnimations/ScreenEvaluationEralk overlay.

Languages

You can find localization files for my custom screen's titles an list descriptions in eralk/Languages.

There is currently only an English file. Why not Czech? Because not even the original Stepmania was localized for Czech, just for Slovak (and I don't speak Slovak).

Stepmania/OutFox/NotITG documentation

Here's a list of resources I used while working on this project. Not mentioning the source code nor the discord servers.

  • Lua for SM5
    • very useful, explains the basic principles
    • has an objectively better render of the SM5 API (the OutFox API docs have the same format but have additional features documented; see below)
  • OutFox API documentation
    • one big XML file, useful for when you want to see the methods provided for a specific class
    • not useful for when you want to learn about the basic principles
  • OutFox Wiki
    • occasionally has key principles explained
    • also has a somewhat functioning search engine
  • HeySora's introduction to modding
    • this was written for a different fork but there's still a lot of (like 95%) common ground one can adapt (ignore the XML code though)
  • Craftedcart's unofficial documentation
    • again, it's documentation for a different fork1 but the basic concepts are the same and most of the methods also behave the same

1 .

Building this doc

This site uses mdbook to create a searchable user-friendly structure from a bunch of markdowns.

Running a local instance (on port 3000)

cd doc
mdbook serve --open

Building

cd doc
mdbook build

TODO / would be nice to have

  • pisnicky
    • figure out deployment
      • submission system
        • parsovani nazevtymu + nazevproblemku
          • zatim alfa bravo charlie delta echo
        • skore: http request
          • success? pocet kroku
          • v pripade failu sehnat orga
      • kam se budou nahravat vystupy?
        • na webovou stranku :3
        • vypisovat log behu programu
        • omezit velikost vystupu na par mega pls
        • sshfs?
          • kouknout jak funguje reloading
        • (zde se pripadne budou generovat nove vstupy, casove omezene)
      • na cem se bude hrat?
        • poskytneme 6 notebooku, kazdy s jednou podlozkou
      • (jak zaridit testovani ucastnickych solveru?) -jine staticke vstupy pro kazdy tym
  • Czech docs
    • scoring system
      • https://sourceforge.net/p/stepmania/mailman/message/30413274/
  • resolve and handle ALL unresolved edge cases
  • figure out why the framerate sometimes drops significantly
  • find out the cause of those occasional in-game segfaults
  • figure out why the matrix generator only generates shortest paths of 2-3 edges long (observed from a couple of inputs)
  • provide templates for different programming languages taking care of input parsing and maze data storage
    • maybe just hint with function definitions with the maze data manipulation?