Skip to content
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
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ pylint~=4.1.3
flake8~=7.4.1
mypy~=2.4.0
pillow~=13.0.0
pytest~=9.1.1
pytest~=9.1.1
httpx~=0.28.1
8 changes: 5 additions & 3 deletions src/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"""
import secrets

from fastapi import FastAPI
from fastapi import FastAPI, Path
from starlette.responses import FileResponse
from fastapi.middleware.cors import CORSMiddleware

Expand All @@ -30,7 +30,7 @@ async def root():


@app.get(_GENERATE + "/{floor_id}")
async def generate_with_id(floor_id: int) -> FileResponse:
async def generate_with_id(floor_id: int = Path(ge=0)) -> FileResponse:
"""
This endpoint generates a floor with the given id
and returns it in a FileResponse as a json file.
Expand All @@ -46,7 +46,9 @@ async def generate_with_id(floor_id: int) -> FileResponse:


@app.get(_GENERATE + "/{floor_id}/{seed}")
async def generate_with_id_and_seed(floor_id: int, seed: str) -> FileResponse:
async def generate_with_id_and_seed(
floor_id: int = Path(ge=0), seed: str = Path()
) -> FileResponse:
"""
This endpoint generates a floor with the given id
and seed and returns it in a FileResponse as a json file.
Expand Down
15 changes: 7 additions & 8 deletions src/generators/generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,10 @@ def __init__(
Creates a new generator with the given arguments.
@param seed: seed for generating the floor
@param output_file_name: name for the outputfile
@param stage_id: id for the floor
@param stage_id: id for the floor (must be 0 or greater)
"""
if stage_id < 0:
raise ValueError(f"stage_id must be 0 or greater, got {stage_id}")
self._stage_id = stage_id
self._seed = seed
self._output_file_name = output_file_name
Expand Down Expand Up @@ -336,18 +338,15 @@ def place_super_secret_room(self) -> None:
def place_secret_room(self) -> None:
"""
Places a secret room on the floor.
If no valid position exists, no secret room is placed.
"""
floor = self._floor
secret_room_placed = False
neighbour_rooms = 3
while not secret_room_placed:
while neighbour_rooms > 0:
for room in reversed(floor.get_rooms()):
# Check all neighbours of the room
secret_room_placed = self._check_directions_for_secret_room(
room, neighbour_rooms
)
if secret_room_placed:
break
if self._check_directions_for_secret_room(room, neighbour_rooms):
return
neighbour_rooms -= 1

def _check_directions_for_secret_room(
Expand Down
26 changes: 26 additions & 0 deletions test/controller_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
"""Unit tests for the FastAPI controller."""

import unittest

from fastapi.testclient import TestClient

import controller


class ControllerTest(unittest.TestCase):
def setUp(self) -> None:
self._client = TestClient(controller.app)

def test_negative_floor_id_is_rejected(self):
response = self._client.get("/gen/-1")

self.assertEqual(422, response.status_code)

def test_negative_floor_id_with_seed_is_rejected(self):
response = self._client.get("/gen/-1/abc")

self.assertEqual(422, response.status_code)


if __name__ == "__main__":
unittest.main()
20 changes: 20 additions & 0 deletions test/generator_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,26 @@ def test_to_json_round_trips_through_floor_from_json(self):

self.assertEqual(self._generator._floor.get_rooms(), restored.get_rooms())

def test_negative_stage_id_is_rejected(self):
with self.assertRaises(ValueError):
Generator(seed="1", output_file_name="floor", stage_id=-1)

def test_generate_terminates_when_no_secret_room_position_exists(self):
# Seed "9" on floor 0 used to loop forever in place_secret_room.
generator = Generator(seed="9", output_file_name="floor", stage_id=0)

generator.generate()

self.assertGreater(len(generator._floor.get_rooms()), 0)

def test_generate_terminates_for_many_seeds_on_small_floors(self):
for stage_id in (0, 1):
for seed in range(200):
with self.subTest(stage_id=stage_id, seed=seed):
Generator(
seed=str(seed), output_file_name="floor", stage_id=stage_id
).generate()

def test_save_writes_the_generated_floor_to_the_given_path(self):
self._generator.generate()
with tempfile.TemporaryDirectory() as tmp_dir:
Expand Down
Loading