mirror of https://github.com/dirtbags/moth.git
Merge pull request #17 from dirtbags/neale
Puzzle.randword, don't escape HTML, change mono font
This commit is contained in:
commit
d42229f3c5
|
@ -0,0 +1,45 @@
|
|||
Author: neale
|
||||
Summary: static puzzles
|
||||
Answer: puzzle.moth
|
||||
|
||||
Puzzle categories are laid out on the filesystem:
|
||||
|
||||
example/
|
||||
├─1
|
||||
│ └─puzzle.moth
|
||||
├─2
|
||||
│ ├─puzzle.moth
|
||||
│ └─salad.jpg
|
||||
├─3
|
||||
│ └─puzzle.py
|
||||
├─10
|
||||
│ └─puzzle.py
|
||||
└─100
|
||||
└─puzzle.moth
|
||||
|
||||
In this example,
|
||||
there are puzzles with point values 1, 2, 3, 10, and 100.
|
||||
|
||||
Puzzles 1, 2, and 100 are "static" puzzles:
|
||||
their content was written by hand.
|
||||
|
||||
Puzzles 3 and 10 are "dynamic" puzzles:
|
||||
they are generated from a Python module.
|
||||
|
||||
To create a static puzzle, all you must have is a
|
||||
`puzzle.moth` file in the puzzle's directory.
|
||||
This file is in the following format:
|
||||
|
||||
Author: [name of the person who wrote this puzzle]
|
||||
Summary: [brief description of the puzzle]
|
||||
Answer: [answer to this puzzle]
|
||||
Answer: [second acceptable answer to this puzzle]
|
||||
|
||||
This is the puzzle body.
|
||||
It is Markdown formatted:
|
||||
you can read more about Markdown on the Internet.
|
||||
|
||||
To move to the next puzzle in a category,
|
||||
someone on some team must provide an answer to the highest-point puzzle in that category.
|
||||
|
||||
The answer to this puzzle is the name of the file required to make a static puzzle.
|
|
@ -0,0 +1,14 @@
|
|||
Author: neale
|
||||
Summary: Static puzzle resource files
|
||||
Answer: salad
|
||||
|
||||
You can include additional resources in a static puzzle,
|
||||
by just dropping them in the directory.
|
||||
|
||||
You can refer to them directly in your Markdown,
|
||||
or use them however else you see fit.
|
||||
They will appear in the same directory on the web server once the exercise is running.
|
||||
|
||||
![Leafy Green Deliciousness](salad.jpg)
|
||||
|
||||
The answer for this page is what is featured in the photograph.
|
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
|
@ -0,0 +1,20 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
def make(puzzle):
|
||||
puzzle.author = 'neale'
|
||||
puzzle.summary = 'dynamic puzzles'
|
||||
answer = puzzle.randword()
|
||||
puzzle.answers.append(answer)
|
||||
|
||||
puzzle.body.write("To generate a dynamic puzzle, you need to write a Python module.\n")
|
||||
puzzle.body.write("\n")
|
||||
puzzle.body.write("The passed-in puzzle object provides some handy methods.\n")
|
||||
puzzle.body.write("In particular, please use the `puzzle.rand` object to guarantee that rebuilding a category\n")
|
||||
puzzle.body.write("won't change puzzles and answers.\n")
|
||||
puzzle.body.write("(Participants don't like it when puzzles and answers change.)\n")
|
||||
puzzle.body.write("\n")
|
||||
|
||||
number = puzzle.rand.randint(20, 500)
|
||||
puzzle.log("One is the loneliest number, but {} is the saddest number.".format(number))
|
||||
|
||||
puzzle.body.write("The answer for this page is {}.\n".format(answer))
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,6 +0,0 @@
|
|||
@font-face {
|
||||
font-family: 'Dosis';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Dosis Regular'), local('Dosis-Regular'), url(Dosis-Regular.ttf) format('truetype');
|
||||
}
|
Binary file not shown.
Binary file not shown.
|
@ -17,10 +17,10 @@
|
|||
src: local('Lato Italic'), local('Lato-Italic'), url(Lato-Italic.ttf) format('truetype');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Dosis';
|
||||
font-family: 'Inconsolata';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Dosis Regular'), local('Dosis-Regular'), url(Dosis-Regular.ttf) format('truetype');
|
||||
src: local('Inconsolata Regular'), local('Inconsolata-Regular'), url(Inconsolata-Regular.ttf) format('truetype');
|
||||
}
|
||||
|
||||
|
||||
|
@ -38,7 +38,7 @@ body {
|
|||
}
|
||||
|
||||
pre, tt {
|
||||
font-family: 'Dosis', monospace;
|
||||
font-family: Inconsolata, monospace;
|
||||
background-color: rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,8 @@ except ImportError:
|
|||
NOT_FOUND = 404
|
||||
INTERNAL_SERVER_ERROR = 500
|
||||
|
||||
sys.dont_write_bytecode = True
|
||||
|
||||
# XXX: This will eventually cause a problem. Do something more clever here.
|
||||
seed = 1
|
||||
|
||||
|
@ -48,7 +50,7 @@ def mdpage(body):
|
|||
title = "Result"
|
||||
title = title.lstrip("#")
|
||||
title = title.strip()
|
||||
return page(title, mistune.markdown(body))
|
||||
return page(title, mistune.markdown(body, escape=False))
|
||||
|
||||
|
||||
class ThreadingServer(socketserver.ThreadingMixIn, http.server.HTTPServer):
|
||||
|
@ -162,11 +164,12 @@ you are a fool.
|
|||
body.write("</ul>")
|
||||
body.write("<h2>Author</h2><p>{}</p>".format(puzzle.author))
|
||||
body.write("<h2>Summary</h2><p>{}</p>".format(puzzle.summary))
|
||||
body.write("<h2>Debug Log</h2>")
|
||||
body.write('<ul class="log">')
|
||||
for l in puzzle.logs:
|
||||
body.write("<li>{}</li>".format(html.escape(l)))
|
||||
body.write("</ul>")
|
||||
if puzzle.logs:
|
||||
body.write("<h2>Debug Log</h2>")
|
||||
body.write('<ul class="log">')
|
||||
for l in puzzle.logs:
|
||||
body.write("<li>{}</li>".format(html.escape(l)))
|
||||
body.write("</ul>")
|
||||
elif len(parts) == 5:
|
||||
# Serve up a puzzle file
|
||||
try:
|
||||
|
|
|
@ -146,6 +146,11 @@ class Puzzle:
|
|||
name = self.random_hash()
|
||||
self.files[name] = PuzzleFile(stream, name, visible)
|
||||
|
||||
def randword(self):
|
||||
"""Return a randomly-chosen word"""
|
||||
|
||||
return self.rand.choice(ANSWER_WORDS)
|
||||
|
||||
def make_answer(self, word_count, sep=' '):
|
||||
"""Generate and return a new answer. It's automatically added to the puzzle answer list.
|
||||
:param int word_count: The number of words to include in the answer.
|
||||
|
@ -153,7 +158,8 @@ class Puzzle:
|
|||
:returns: The answer string
|
||||
"""
|
||||
|
||||
answer = sep.join(self.rand.sample(ANSWER_WORDS, word_count))
|
||||
words = [self.randword() for i in range(word_count)]
|
||||
answer = sep.join(words)
|
||||
self.answers.append(answer)
|
||||
return answer
|
||||
|
||||
|
@ -162,7 +168,7 @@ class Puzzle:
|
|||
|
||||
def html_body(self):
|
||||
"""Format and return the markdown for the puzzle body."""
|
||||
return mistune.markdown(self.get_body())
|
||||
return mistune.markdown(self.get_body(), escape=False)
|
||||
|
||||
def hashes(self):
|
||||
"Return a list of answer hashes"
|
||||
|
|
Loading…
Reference in New Issue