Check user-supplied answers for possible correctness

This commit is contained in:
Neale Pickett 2019-02-24 11:53:22 -07:00
parent c726847cb9
commit 15503cb45b
4 changed files with 47 additions and 7 deletions

View File

@ -40,8 +40,6 @@ def get_puzzle(request, data=None):
puzzle = cat.puzzle(points) puzzle = cat.puzzle(points)
return puzzle return puzzle
# OMG what is this I hate Python now
@asyncio.coroutine
async def handle_answer(request): async def handle_answer(request):
data = await request.post() data = await request.post()
puzzle = get_puzzle(request, data) puzzle = get_puzzle(request, data)

View File

@ -15,9 +15,9 @@ import tempfile
messageChars = b'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' messageChars = b'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
def djb2hash(buf): def djb2hash(str):
h = 5381 h = 5381
for c in buf: for c in str.encode("utf-8"):
h = ((h * 33) + c) & 0xffffffff h = ((h * 33) + c) & 0xffffffff
return h return h
@ -277,7 +277,7 @@ class Puzzle:
def hashes(self): def hashes(self):
"Return a list of answer hashes" "Return a list of answer hashes"
return [djb2hash(a.encode('utf-8')) for a in self.answers] return [djb2hash(a) for a in self.answers]
class Category: class Category:

View File

@ -22,7 +22,7 @@
<input type="hidden" name="cat"> <input type="hidden" name="cat">
<input type="hidden" name="points"> <input type="hidden" name="points">
Team ID: <input type="text" name="id"> <br> Team ID: <input type="text" name="id"> <br>
Answer: <input type="text" name="answer" id="answer"> <br> Answer: <input type="text" name="answer" id="answer"> <span id="answer_ok"></span><br>
<input type="submit" value="Submit"> <input type="submit" value="Submit">
</form> </form>
<div id="devel"></div> <div id="devel"></div>

View File

@ -44,7 +44,17 @@ function devel_addin(obj, e) {
} }
} }
// The routine used to hash answers in compiled puzzle packages
function djb2hash(buf) {
let h = 5381
for (let c of (new TextEncoder).encode(buf)) { // JavaScript is weird.
h = ((h * 33) + c) & 0xffffffff
}
return h
}
// Pop up a message
function toast(message, timeout=5000) { function toast(message, timeout=5000) {
let p = document.createElement("p") let p = document.createElement("p")
@ -56,7 +66,7 @@ function toast(message, timeout=5000) {
) )
} }
// When the user submits an answer
function submit(e) { function submit(e) {
e.preventDefault() e.preventDefault()
fetch("answer", { fetch("answer", {
@ -92,6 +102,9 @@ function loadPuzzle(categoryName, points, puzzleId) {
// Populate authors // Populate authors
document.getElementById("authors").textContent = obj.authors.join(", ") document.getElementById("authors").textContent = obj.authors.join(", ")
// Make the whole puzzle available
window.puzzle = obj
// If answers are provided, this is the devel server // If answers are provided, this is the devel server
if (obj.answers) { if (obj.answers) {
devel_addin(obj, document.getElementById("devel")) devel_addin(obj, document.getElementById("devel"))
@ -139,6 +152,32 @@ function loadPuzzle(categoryName, points, puzzleId) {
document.querySelector("input[name=points]").value = points document.querySelector("input[name=points]").value = points
} }
function answerCheck(e) {
let answer = e.target.value
let ok = document.querySelector("#answer_ok")
// You have to provide someplace to put the check
if (! ok) {
return
}
let possiblyCorrect = false
let answerHash = djb2hash(answer)
for (let correctHash of window.puzzle.hashes) {
if (correctHash == answerHash) {
possiblyCorrect = true
}
}
if (possiblyCorrect) {
ok.textContent = "🙆"
ok.title = "Possibly correct"
} else {
ok.textContent = "🙅"
ok.title = "Definitely not correct"
}
}
function init() { function init() {
let params = new URLSearchParams(window.location.search) let params = new URLSearchParams(window.location.search)
let categoryName = params.get("cat") let categoryName = params.get("cat")
@ -154,6 +193,9 @@ function init() {
document.querySelector("input[name=id]").value = teamId document.querySelector("input[name=id]").value = teamId
} }
if (document.querySelector("#answer")) {
document.querySelector("#answer").addEventListener("input", answerCheck)
}
document.querySelector("form").addEventListener("submit", submit) document.querySelector("form").addEventListener("submit", submit)
} }