Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add some tests and Travis integration #2

Merged
merged 4 commits into from
Mar 23, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.pytest_cache/
__pycache__/
10 changes: 10 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
language: python

python:
- 3.6

install:
- pip install pytest pytest-pep8

script:
- pytest --pep8
49 changes: 47 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,61 @@ A set of micromouse maze files in text format. They have been collected over som

These files are a companion to the maze tool https://github.com/micromouseonline/micromouse_maze_tool.

The format used here has three characters per horizontal wall to make them easier to read when displayed on the screen or printed out.
The format used here is as follows:

- All posts are represented with the character `o`.
- All posts must be present in the grid even if there is no wall attached to
them.
- Horizontal walls are represented with three `---`.
- Vertical walls are represented with a single `|`.
- The goal cell in half-size mazes has a `G` in the certer of the cell.
- Starting cells might have an `S` in the certer of the cell.

Here is an example of a 4x4 maze:

```
o---o---o---o---o
| G | |
o o o o---o
| | |
o---o---o---o o
| |
o o---o---o o
| | |
o---o---o---o---o
```

**classic** mazes are all 16x16. Some of these have smaller active areaswhere the event in which they were used only had a smaller maze available. That may have been 7x8, 8x8, 11x11 or some other size. All these mazes have a legal goal cell in cell 7,7.

**halfsize** mazes are all 32x32. The goal is not fixed in the same way as it might be in the classic contest. Goal cells are marked with an asterisk in the centre of the cell. The goal may be a single cell or a rectangular block of cells.
**halfsize** mazes are all 32x32. The goal is not fixed in the same way as it might be in the classic contest. The goal for halfsize mazes is a single cell, marked with a "G" in the center of the cell, which may be part of a larger area.

**training** mazes are all 16x16 but may not have legal goal areas as the useable area might be only 5x5, 8x8, 10x5 or some other size representing small mazes used for testing a mouse where there is not room for a full sized maze. The filename should indicate the active area.

The files may, or may not, represent actual contest mazes. If there are errors in contest mazes, please let me know. Preferably with a photo of the original maze so that I can make changes.


## FAQ

### How can I contribute to the repository?

Thanks for your interest! Start by reading GitHub's guide on [how to propose
changes to someone else's project][0], then feel free to create a pull request
with your changes or new maze files.

### Why text files?

- They are easy to understand by humans.
- They get along with version control systems (Git).
- They are easy to read/write with any programming language.
- They are easy to visualize (just use your browser or favorite text editor).
- No need for special tools if you want to edit them or create your own. Just
a bit of patience is required.

### Are there any tools to help me create maze files?

- If you happen to have an image of a micromouse maze setup you might want to
try the [Optical Micromouse Maze Recognition software][1].


[0]: https://help.github.com/articles/fork-a-repo/
[1]: https://github.com/Theseus/ommr
Empty file removed classic/.gitignore
Empty file.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Empty file removed halfsize/.gitignore
Empty file.
65 changes: 65 additions & 0 deletions halfsize/japan2014ef.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
o---o---o---o---o---o---o---o---o---o---o---o---o---o---o---o---o---o---o---o---o---o---o---o---o---o---o---o---o---o---o---o---o
| | | | | | | |
o o o---o---o---o---o---o---o---o---o---o---o---o---o o o o o o o o o o o o o o---o o o o o
| | | | | | | | | | | | | | |
o o---o---o---o---o---o---o---o---o---o---o---o---o o o---o o---o o o o o o o o o---o o---o o o o
| | | | | | | | | | | | |
o o o---o---o---o---o---o---o---o---o---o---o o o---o---o---o o o o o o o o o---o o---o o---o o o
| | | | | | | | | | | | | | | | |
o o o o o o o o o o o o o o o o---o o o---o---o---o---o o o---o o---o o---o---o o o
| | | | | | | | | | | | | | | |
o o o o o o o o o o o o o o o o o---o---o---o---o---o o---o---o o---o o o---o---o o o
| | | | | | | | | | | | | | | | | | |
o o o o o o o o o o o o o o o o o o o o o o o---o o---o---o o o o---o---o o
| | | | | | | | | | | | | | | | | | |
o o o o o o o o o o o o o o o o o o---o---o---o o---o o---o o o o o o o o o
| | | | | | | | | | | | | | | | | |
o o o o o---o---o---o---o o o o o o o o---o---o---o o o---o o---o---o o o o o o o o o
| | | | | | | | | | | | | | | | |
o o o o---o---o---o---o o o o o o o o---o---o---o o o---o o---o o o o o o o o o o o
| | | | | | | | | | | | | | | | | |
o o o---o---o---o---o o o---o---o---o---o o o o---o---o---o---o o---o o---o o o o o o---o---o---o o
| | | | | | | | | | | | |
o o o---o---o---o o o---o---o---o---o---o---o o---o---o o---o o---o o---o o o o o o---o---o---o o o
| | | | | | | | | | | |
o o o o---o---o---o---o---o---o---o---o---o---o---o o---o---o o---o---o o---o---o o---o---o---o---o---o o---o o
| | | | | | | | | |
o o o---o---o---o---o---o---o---o---o---o---o---o---o---o---o o---o o o o o o---o---o---o---o---o---o o---o o
| | | | | | | | | | | | | |
o o o---o---o o---o---o o o o o o o o o o---o o---o o---o---o---o---o---o---o---o o---o o---o o
| | | | | | | | | | |
o o o---o o---o---o o---o---o---o---o---o---o---o o---o---o---o---o---o---o o o---o---o---o---o o---o o---o o
| | | | | | | | | | | | |
o o---o o---o---o o o o o o o o o o---o---o---o---o---o---o o o o o o o---o---o---o---o o o
| | | | | | | | | |
o o o o---o o---o o o o o o o o o o---o---o---o---o---o---o o---o---o---o---o o---o---o---o---o o
| | | | | | | | | |
o o o---o o---o o---o o o o o o o o o o---o---o---o---o---o---o---o---o---o o---o---o---o o o o
| | | | | | | | | | | | |
o o o o---o o---o o---o---o---o---o---o o o o---o o---o o---o o o o o o o o---o---o---o o o
| | | | | | | | | | | | | | |
o o o o o---o o---o o---o---o---o o o o o o---o o---o o---o o o o o o o o---o o o o
| | | | | | | | | | | | | | | | | |
o o o o o o---o o---o o---o o o o o o---o---o---o---o---o o o o o o o o o o---o o o
| | | | | | | | | | | | | | | |
o o o o o o o---o o---o o---o o---o---o o o---o---o---o---o o o o o o o---o---o---o---o o o
| | | | | | | | | | | | |
o o---o---o---o---o---o---o---o o---o o---o o---o---o o o---o---o---o---o o o o o o---o---o---o---o---o o
| | | | | | | | | | |
o---o---o---o---o---o---o---o o---o o---o o---o o---o o---o---o---o---o o o o o---o---o---o---o---o---o o o
| | | | | | | | | | | | |
o o---o---o---o---o---o o o---o---o o---o o---o---o o o---o---o o o---o---o---o o o o o---o o---o o
| | | | | | | | | | | | | | | | |
o o o---o---o---o o o o o o---o o---o---o o---o o o o o o o o o o o o---o o---o o o
| | | | | | | | | | | | | | | | | G | | |
o o o o---o o o o o o---o o---o---o o---o---o---o o o o o o o o---o---o o o---o o---o o
| | | | | | | | | | | | | | | |
o o o o o o---o o o o o---o o o o---o---o---o---o---o o o o o o o---o o---o o---o o o
| | | | | | | | | | | | | | |
o o o o o---o---o---o o o---o---o---o---o---o o---o---o---o o---o---o---o---o---o---o---o---o---o---o---o---o o
| | | | | | | | |
o o o o---o---o---o---o---o---o---o---o---o---o---o---o o---o o---o---o---o---o---o---o---o---o---o---o---o---o o o
| | | | | | |
o o o---o---o---o---o---o---o---o---o---o---o---o---o---o---o o---o---o---o---o---o---o---o---o---o---o---o---o---o---o o
| S | |
o---o---o---o---o---o---o---o---o---o---o---o---o---o---o---o---o---o---o---o---o---o---o---o---o---o---o---o---o---o---o---o---o
144 changes: 144 additions & 0 deletions test_mazes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
"""
Basic tests to ensure maze files are properly formatted.
"""
from collections import Counter
from pathlib import Path
import re

import pytest


def parametrize_maze_files(maze_files):
return pytest.mark.parametrize('maze_file', maze_files,
ids=[str(x) for x in maze_files])


CLASSIC_SIZE = 16
HALFSIZE_SIZE = 32

classic_mazes = list(Path('classic').glob('*'))
halfsize_mazes = list(Path('halfsize').glob('*'))
training_mazes = list(Path('training').glob('*'))
competition_mazes = classic_mazes + halfsize_mazes
all_mazes = classic_mazes + halfsize_mazes + training_mazes

classic_mazes = parametrize_maze_files(classic_mazes)
halfsize_mazes = parametrize_maze_files(halfsize_mazes)
training_mazes = parametrize_maze_files(training_mazes)
competition_mazes = parametrize_maze_files(competition_mazes)
all_mazes = parametrize_maze_files(all_mazes)


def read_maze(maze_file):
rows = maze_file.read_text().split('\n')
for i, row in enumerate(rows):
if not row.startswith(('o', '|')):
break
return rows[:i]


@all_mazes
def test_file_name(maze_file):
"""
- All maze files must be text files with `.txt` extension.
- Only "a-z", "0-9" and "-" characters are allowed.
"""
assert maze_file.suffix == '.txt'
assert re.match('^[a-z0-9\-]*$', maze_file.stem)


@classic_mazes
def test_classic_size(maze_file):
"""
Classic maze size is always 16x16.
"""
rows = read_maze(maze_file)
assert len(rows) == (CLASSIC_SIZE * 2 + 1)
assert all(len(row) == (CLASSIC_SIZE * 4 + 1) for row in rows)


@halfsize_mazes
def test_halfsize_size(maze_file):
"""
Half-size maze size is always 32x32.
"""
rows = read_maze(maze_file)
assert len(rows) == (HALFSIZE_SIZE * 2 + 1)
assert all(len(row) == (HALFSIZE_SIZE * 4 + 1) for row in rows)


@training_mazes
def test_training_size(maze_file):
"""
Training maze size is the same as classic size, even if not fully used.
"""
rows = read_maze(maze_file)
assert len(rows) == (CLASSIC_SIZE * 2 + 1)
assert all(len(row) == (CLASSIC_SIZE * 4 + 1) for row in rows)


@all_mazes
def test_format(maze_file):
"""
Maze file format must be homogeneous. Vertical walls are represented with
a `|`, horizontal walls with `---` and posts with `o`.

Even rows must:

- Have a post each 4 characters.
- Have a wall `---` or nothing ` ` between posts.

Odd rows must:

- Have a wall `|` or nothing ` ` each 4 characters.
"""
rows = read_maze(maze_file)
even_rows = rows[::2]
assert all(all(x == 'o' for x in row[::4]) for row in even_rows)
assert all(all(x in ('---', ' ') for x in row.strip('o').split('o'))
for row in even_rows)
odd_rows = rows[1::2]
assert all(all(x in ('|', ' ') for x in row[::4]) for row in odd_rows)


@all_mazes
def test_boundaries(maze_file):
"""
Maze boundaries are expected to be closed.
"""
rows = read_maze(maze_file)
east_boundary = [row[-1] for row in rows[1::2]]
west_boundary = [row[0] for row in rows[1::2]]
assert all(v == '|' for v in east_boundary + west_boundary)
north_boundary = rows[0].strip('o').split('o')
south_boundary = rows[-1].strip('o').split('o')
assert all(h == '---' for h in north_boundary + south_boundary)


@all_mazes
def test_starting_cell_unique(maze_file):
"""
The starting cell, if marked, must be unique.
"""
rows = read_maze(maze_file)
assert Counter(''.join(rows))['S'] in (0, 1)


@competition_mazes
def test_starting_cell(maze_file):
"""
The starting cell is expected to be at the South-West and facing North.
"""
rows = read_maze(maze_file)
assert rows[-3][:5] == 'o o'
assert rows[-2][:5] in ('| |', '| S |')
assert rows[-1][:5] == 'o---o'


@halfsize_mazes
def test_goal_cell_is_marked(maze_file):
"""
Goal cell is expected to be marked with a "G".
"""
rows = read_maze(maze_file)
assert ' G ' in ''.join(rows)
Empty file removed training/.gitignore
Empty file.
File renamed without changes.
File renamed without changes.
File renamed without changes.