From 94bc9472b78e75d18a4ec73c0d50ac6a9665faaf Mon Sep 17 00:00:00 2001
From: Neale Pickett
Date: Fri, 11 Sep 2020 17:33:43 -0600
Subject: [PATCH] Port some example puzzles
---
.gitignore | 1 +
.../example/1/{puzzle.moth => puzzle.md} | 42 ++++++----
example-puzzles/example/2/puzzle.md | 36 +++++++++
example-puzzles/example/2/puzzle.moth | 39 ---------
example-puzzles/example/3/mkpuzzle | 81 ++++++++++++-------
example-puzzles/example/3/puzzle.py | 27 -------
example-puzzles/example/4/puzzle.moth | 20 -----
example-puzzles/example/5/helpers.js | 56 ++++++++++---
.../example/5/{puzzle.moth => puzzle.md} | 40 ++++++---
example-puzzles/example/6/puzzle.md | 18 +++++
example-puzzles/example/6/puzzle.moth | 17 ----
pkg/transpile/puzzle.go | 19 ++---
theme/puzzle.js | 31 +++----
13 files changed, 222 insertions(+), 205 deletions(-)
rename example-puzzles/example/1/{puzzle.moth => puzzle.md} (58%)
create mode 100644 example-puzzles/example/2/puzzle.md
delete mode 100644 example-puzzles/example/2/puzzle.moth
delete mode 100644 example-puzzles/example/3/puzzle.py
delete mode 100644 example-puzzles/example/4/puzzle.moth
rename example-puzzles/example/5/{puzzle.moth => puzzle.md} (69%)
create mode 100644 example-puzzles/example/6/puzzle.md
delete mode 100644 example-puzzles/example/6/puzzle.moth
diff --git a/.gitignore b/.gitignore
index a22d658..4e8c7d1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,3 +8,4 @@ build/
cache/
target/
puzzles
+__debug_bin
diff --git a/example-puzzles/example/1/puzzle.moth b/example-puzzles/example/1/puzzle.md
similarity index 58%
rename from example-puzzles/example/1/puzzle.moth
rename to example-puzzles/example/1/puzzle.md
index 3b9fc1b..928e312 100644
--- a/example-puzzles/example/1/puzzle.moth
+++ b/example-puzzles/example/1/puzzle.md
@@ -1,21 +1,26 @@
-Author: neale
-Summary: static puzzles
-Answer: puzzle.moth
-
+---
+pre:
+ authors:
+ - neale
+debug:
+ summary: static puzzles
+answers:
+ - puzzle.md
+---
Puzzle categories are laid out on the filesystem:
example/
├─1
- │ └─puzzle.moth
+ │ └─puzzle.md
├─2
- │ ├─puzzle.moth
+ │ ├─puzzle.md
│ └─salad.jpg
├─3
- │ └─puzzle.py
+ │ └─mkpuzzle
├─10
- │ └─puzzle.moth
+ │ └─puzzle.md
└─100
- └─puzzle.py
+ └─mkpuzzle
In this example,
there are puzzles with point values 1, 2, 3, 10, and 100.
@@ -24,17 +29,22 @@ Puzzles 1, 2, and 10 are "static" puzzles:
their content was written by hand.
Puzzles 3 and 100 are "dynamic" puzzles:
-they are generated from a Python module.
+their content is generated by `mkpuzzle`.
To create a static puzzle, all you must have is a
-`puzzle.moth` file in the puzzle's directory.
+`puzzle.md` 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]
-
+ ---
+ pre:
+ authors:
+ - name of the person who wrote this puzzle
+ debug:
+ summary: brief description of the puzzle
+ answers:
+ - answer to this puzzle
+ - second acceptable answer to this puzzle
+ ---
This is the puzzle body.
It is Markdown formatted:
you can read more about Markdown on the Internet.
diff --git a/example-puzzles/example/2/puzzle.md b/example-puzzles/example/2/puzzle.md
new file mode 100644
index 0000000..4836b3d
--- /dev/null
+++ b/example-puzzles/example/2/puzzle.md
@@ -0,0 +1,36 @@
+---
+pre:
+ authors:
+ - neale
+ attachments:
+ - filename: salad.jpg
+ - filename: s2.jpg
+ filesystempath: salad2.jpg
+debug:
+ summary: Static puzzle resource files
+answers:
+ - salad
+---
+
+You can include additional resources in a static puzzle,
+by dropping them in the directory and listing them under `attachments`.
+
+If the puzzle compiler sees both `filename` and `filesystempath`,
+it changes the filename when the puzzle category is built.
+You can use this to give good filenames while building,
+but obscure them during build.
+On this page, we obscure
+`salad2.jpg` to `s2.jpg`,
+so that people can't guess the answer based on filename.
+
+Check the source to this puzzle to see how this is done!
+
+You can refer to resources 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.
+Check the source for this puzzle to see how it was created.
+
+![Leafy Green Deliciousness](salad.jpg)
+![Mmm so good](s2.jpg)
+
+The answer for this page is what is featured in the photograph.
diff --git a/example-puzzles/example/2/puzzle.moth b/example-puzzles/example/2/puzzle.moth
deleted file mode 100644
index 50d7918..0000000
--- a/example-puzzles/example/2/puzzle.moth
+++ /dev/null
@@ -1,39 +0,0 @@
-Author: neale
-Summary: Static puzzle resource files
-File: salad.jpg s.jpg
-File: salad2.jpg s2.jpg hidden
-Answer: salad
-X-Answer-Pattern: *pong
-
-You can include additional resources in a static puzzle,
-by dropping them in the directory and listing them in a `File:` header field.
-
-The format is:
-
- File: filename [translatedname] [hidden]
-
-If `translatedname` is provided,
-the filename is changed to it when the puzzle category is built.
-You can use this to give good filenames while building,
-but obscure them during build.
-On this page, we obscure `salad.jpg` to `s.jpg`,
-and `salad2.jpg` to `s2.jpg`,
-so that people can't guess the answer based on filename.
-
-The word `hidden`, if present,
-prevents a file from being listed at the bottom of the page.
-
-Here are the `File:` fields in this page:
-
- File: salad.jpg s.jpg
- File: salad2.jpg s2.jpg hidden
-
-You can refer to resources 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.
-Check the source for this puzzle to see how it was created.
-
-![Leafy Green Deliciousness](s.jpg)
-![Mmm so good](s2.jpg)
-
-The answer for this page is what is featured in the photograph.
diff --git a/example-puzzles/example/3/mkpuzzle b/example-puzzles/example/3/mkpuzzle
index b23b47f..92df1da 100755
--- a/example-puzzles/example/3/mkpuzzle
+++ b/example-puzzles/example/3/mkpuzzle
@@ -1,34 +1,55 @@
-#! /bin/sh
+#! /usr/bin/python3
-number=$(seq 20 500 | shuf -n 1)
-answer=$(echo $(grep -v "['A-Z]" /usr/share/dict/words | shuf -n 4))
+import argparse
+import json
+import os
+import random
+import shutil
+import sys
-case "$1:$2" in
- :)
- cat <Dynamic puzzles are provided with a JSON-generating mkpuzzles program in the puzzle directory.
Dynamic puzzles are provided with a JSON-generating mkpuzzles program in the puzzle directory.
"
+ "
You can write mkpuzzles in any language you like. This puzzle was written in Python 3.
"
+ "
Here is some salad:
"
+ ),
+ "Attachments": ["salad.jpg"],
+ },
+ "Answers": [
+ answer,
],
- "Errors": [],
- "Log": [
- "$number is a positive integer"
- ]
+ "Debug": {
+ "Summary": "Dynamic puzzles",
+ "Hints": [
+ "Check the debug output to get the answer." ,
+ ],
+ "Errors": [],
+ "Log": [
+ "%d is a positive integer" % number,
+ ],
+ }
}
-}
-EOT
- ;;
- -file:salad.jpg)
- cat salad.jpg
- ;;
-esac
+ json.dump(obj, sys.stdout)
diff --git a/example-puzzles/example/3/puzzle.py b/example-puzzles/example/3/puzzle.py
deleted file mode 100644
index a5e93df..0000000
--- a/example-puzzles/example/3/puzzle.py
+++ /dev/null
@@ -1,27 +0,0 @@
-#!/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")
-
- puzzle.add_file('salad.jpg')
- puzzle.body.write("Here are some more pictures of salad:\n")
- puzzle.body.write("")
- puzzle.body.write("![salad](salad.jpg)")
- puzzle.body.write("\n\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))
-
diff --git a/example-puzzles/example/4/puzzle.moth b/example-puzzles/example/4/puzzle.moth
deleted file mode 100644
index c06a653..0000000
--- a/example-puzzles/example/4/puzzle.moth
+++ /dev/null
@@ -1,20 +0,0 @@
-Summary: Answer patterns
-Answer: command.com
-Answer: COMMAND.COM
-X-Answer-Pattern: PINBALL.*
-X-Answer-Pattern: pinball.*
-Author: neale
-Pattern: [0-9A-Za-z]{1,8}\.[A-Za-z]{1,3}
-
-This puzzle features answer input pattern checking.
-
-Sometimes you need to provide a hint about whether the user has entered the answer in the right format.
-By providing a `Pattern` value (a regular expression),
-the browser will (hopefully) provide a visual hint when an answer is incorrectly formatted.
-It will also (hopefully) prevent the user from submitting,
-which will (hopefully) inform the participant that they may have the right solution technique,
-but there's a problem with the format of the answer.
-This will (hopefully) keep people from getting overly-frustrated with difficult-to-enter answers.
-
-This answer field will validate only FAT 8+3 filenames.
-Try it!
diff --git a/example-puzzles/example/5/helpers.js b/example-puzzles/example/5/helpers.js
index f8cf28a..9c2b65f 100644
--- a/example-puzzles/example/5/helpers.js
+++ b/example-puzzles/example/5/helpers.js
@@ -1,6 +1,6 @@
// jshint asi:true
-function helperUpdateAnswer(event) {
+async function helperUpdateAnswer(event) {
let e = event.currentTarget
let value = e.value
let inputs = e.querySelectorAll("input")
@@ -24,7 +24,11 @@ function helperUpdateAnswer(event) {
if (join === undefined) {
join = ","
}
- value = values.join(join)
+ if (values.length == 0) {
+ value = "None"
+ } else {
+ value = values.join(join)
+ }
}
// First make any adjustments to the value
@@ -35,6 +39,35 @@ function helperUpdateAnswer(event) {
value = value.toUpperCase()
}
+ // "substrings" answers try all substrings. If any are the answer, they're filled in.
+ if (e.classList.contains("substring")) {
+ let validated = null
+ let anchorEnd = e.classList.contains("anchor-end")
+ let anchorBeg = e.classList.contains("anchor-beg")
+
+ for (let end = 0; end <= value.length; end += 1) {
+ for (let beg = 0; beg < value.length; beg += 1) {
+ if (anchorEnd && (end != value.length)) {
+ continue
+ }
+ if (anchorBeg && (beg != 0)) {
+ continue
+ }
+ let sub = value.substring(beg, end)
+ if (await checkAnswer(sub)) {
+ validated = sub
+ }
+ }
+ }
+
+ value = validated
+ }
+
+ // If anything zeroed out value, don't update the answer field
+ if (!value) {
+ return
+ }
+
let answer = document.querySelector("#answer")
answer.value = value
answer.dispatchEvent(new InputEvent("input"))
@@ -78,15 +111,16 @@ function helperActivate(e) {
}
}
+{
+ let init = function(event) {
+ for (let e of document.querySelectorAll(".answer")) {
+ helperActivate(e)
+ }
+ }
-function helperInit(event) {
- for (let e of document.querySelectorAll(".answer")) {
- helperActivate(e)
+ if (document.readyState === "loading") {
+ document.addEventListener("DOMContentLoaded", init)
+ } else {
+ init()
}
}
-
-if (document.readyState === "loading") {
- document.addEventListener("DOMContentLoaded", helperInit);
-} else {
- helperInit();
-}
diff --git a/example-puzzles/example/5/puzzle.moth b/example-puzzles/example/5/puzzle.md
similarity index 69%
rename from example-puzzles/example/5/puzzle.moth
rename to example-puzzles/example/5/puzzle.md
index 1cbdffb..211ef51 100644
--- a/example-puzzles/example/5/puzzle.moth
+++ b/example-puzzles/example/5/puzzle.md
@@ -1,9 +1,15 @@
-Summary: Using JavaScript Input Helpers
-Author: neale
-Script: helpers.js
-Script: draggable.js
-Answer: helper
-
+---
+pre:
+ authors:
+ - neale
+ scripts:
+ - filename: helpers.js
+ - filename: draggable.js
+answers:
+ - helper
+debug:
+ summary: Using JavaScript Input Helpers
+---
MOTH only takes static answers:
you can't, for instance, write code to check answer correctness.
But you can provide as many correct answers as you like in a single puzzle.
@@ -18,7 +24,7 @@ This is just a demonstration page.
You will probably only want one of these in a page,
to avoid confusing people.
-RFC3339 Timestamp
+### RFC3339 Timestamp