This project uses Python 3.6 and Django 2.0
Clone the repo, install requirements, python manage.py makemigrations
and python manage.py migrate
, then python manage.py loaddata puzzle_data.json
to add the existing puzzles to the database. (Warning: The puzzle_data.json
file includes spoilers for some puzzles.)
This project uses python-decouple
to hide secret data from version control, so make sure you've created a .env
file at root level with at the very least a secret key. (You can find more examples in the .env-example
file). You may also need to comment out some of the OAuth values from settings.py
(pretty much everything that starts with SOCIAL_AUTH_
), at least at first.
The most important model is Puzzle
. Hopefully, most of the fields are self-explanatory, but some of the more obscure ones:
short_name
is specifically the file name for the template to render to show that puzzle, minus the.html
.meta_order
is used to set the order that all of the puzzles in a given meta will be displayed when using theas_ul
template tag. If blank, the puzzles will be sorted alphabetically by title, ignoring articles.metapuzzles
is a many-to-many, non-symmetric self-join. Note that this allows a puzzle to belong to multiple metapuzzles (as in the Emotions round of the 2018 MIT Mystery Hunt) and for multiple metas to be part of a supermeta.
The PuzzleSet
model controls what's shown on the main page (index.html
, the puzzles:index
route). Every puzzle set (regardless of how many puzzles, metas, or layers of nested metas there are) should have its own directory in templates
and static
, with a style.css
in the latter.
Some possible ideas for improvements:
- Changing answer submission to AJAX seems straightforward enough.
- As of now, correct answers are stored in the database in plain text. I'd rather they be encrypted, just to make hypothetical cheating that much harder; however, I also wanted to include a user's history of answer submissions in the clear (so they could be shown back to them), so the vulnerability's there regardless. It would avoid the spoilers in
puzzle_data.json
, at least. - Also in terms of hypothetical cheating: It would be neat to do some sort of rate limiting, so that a person can't submit every 20,000 answers a second and brute force "guess" the answer.
- In the spirit of DRY, whether an answer is correct or not isn't saved directly in the database; rather, it's a method (technically a Python
@property
) that compares the submitted answer to the puzzle's saved answer. It might be more efficient to store that on the answer itself (or have a separate table tracking which users have solved which puzzles), but I haven't tested that yet. - It would be neat to add an unlock mechanism, where only some puzzles are available at first and solving those opens up new puzzles to solve, but I haven't made any sets large enough for that to be necessary.
This project is licensed under the MIT License - see the LICENSE.md file for details
- You can see version 1 here, although the code in this project was a from-scratch rewrite.
- I found two guides by Vitor Freitas, How to Use Django's Built-in Login System and How to Add Social Login to Django, very helpful when trying to get started with Django's
auth
system. The account settings and password change pages in particular come nearly directly from his examples. - I'd be remiss if I didn't point to some other fantastic puzzle sites that inspired me to build this project in the first place:
- The MIT Mystery Hunt
- The works of Foggy Brume, including P&A Magazine and his various Puzzle Boats (1, 2, 3, 4)
- Galactic Puzzle Hunt
- Mark Halpin's Labor Day Extravaganzas
- Similarly, many thanks to team Duck Soup for their help in testing these puzzles.