From 3c54f3f56a0a627f6e2b898e525417d6dbc32c05 Mon Sep 17 00:00:00 2001 From: slackish Date: Tue, 18 Oct 2016 09:36:24 -0600 Subject: [PATCH] starting zip capability --- package-puzzles | 145 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100755 package-puzzles diff --git a/package-puzzles b/package-puzzles new file mode 100755 index 0000000..0304ca4 --- /dev/null +++ b/package-puzzles @@ -0,0 +1,145 @@ +#!/usr/bin/env python3 + +import argparse +import base64 +import glob +import hashlib +import hmac +import io +import json +import os +import markdown +import random +import uuid +import zipfile + +messageChars = b'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' + +def djb2hash(buf): + h = 5381 + for c in buf: + h = ((h * 33) + c) & 0xffffffff + return h + +def write_kv_pairs(ziphandle, filename, kv): + filehandle = io.StringIO() + for key in sorted(kv.keys()): + if type(kv[key]) == type([]): + for val in kv[key]: + filehandle.write("%s: %s%s" % (key, val, os.linesep)) + else: + filehandle.write("%s: %s%s" % (key, kv[key], os.linesep)) + filehandle.seek(0) + ziphandle.writestr(filename, filehandle.read()) + +class Puzzle: + def __init__(self, stream): + self.message = bytes(random.choice(messageChars) for i in range(20)) + self.fields = {} + self.answers = [] + self.hashes = [] + + body = [] + header = True + for line in stream: + if header: + line = line.strip() + if not line.strip(): + header = False + continue + key, val = line.split(':', 1) + key = key.lower() + val = val.strip() + self._add_field(key, val) + else: + body.append(line) + self.body = ''.join(body) + + def _add_field(self, key, val): + if key == 'answer': + h = djb2hash(val.encode('utf8')) + self.answers.append(val) + self.hashes.append(h) + else: + self.fields[key] = val + + def publish(self): + obj = { + 'author': self.fields['author'], + 'hashes': self.hashes, + 'body': markdown.markdown(self.body), + } + return obj + + def secrets(self): + obj = { + 'answers': self.answers, + 'summary': self.fields['summary'], + } + return obj + + +parser = argparse.ArgumentParser(description='Build a puzzle category') +parser.add_argument('seed', help='contest seed') +parser.add_argument('puzzledir', nargs='+', help='Directory of puzzle source') +parser.add_argument('outdir', help='Output directory') +args = parser.parse_args() + + +for puzzledir in args.puzzledir: + puzzles = {} + secrets = {} + + + categoryname = os.path.basename(puzzledir.strip(os.sep)) + + # build puzzle seed + puzzle_seed = hashlib.new('sha1') + puzzle_seed.update(categoryname.encode('utf-8')) + puzzle_seed.update(args.seed.encode('utf-8')) + puzzle_seed = puzzle_seed.hexdigest() + + # create zipfile + zipfilename = os.path.join(args.outdir, "%s.zip" % categoryname) + if os.path.exists(zipfilename): +# assume blank state for now + pass +# # open and gather some state +# zf = zipfile.ZipFile(zipfilename, 'a') + else: + # create and read in state + zf = zipfile.ZipFile(zipfilename, 'w') + + # read in puzzle details (will be pflarr in future) + for puzzlePath in glob.glob(os.path.join(puzzledir, "*.moth")): + filename = os.path.basename(puzzlePath) + points, ext = os.path.splitext(filename) + points = int(points) + puzzle = Puzzle(open(puzzlePath)) + puzzles[points] = puzzle + + # build mapping, answers, and summary + mapping = {} + answers = {} + summary = {} + for points in sorted(puzzles): + puzzle = puzzles[points] + + mapping[points] = str(uuid.uuid4()) # random uuid + answers[points] = puzzle.answers + summary[points] = puzzle.fields['summary'] + + # write mapping, answers, and summary + write_kv_pairs(zf, os.path.join(categoryname, 'mapping.txt'), mapping) + write_kv_pairs(zf, os.path.join(categoryname, 'answers.txt'), answers) + write_kv_pairs(zf, os.path.join(categoryname, 'summary.txt'), summary) + print(mapping) + print(answers) + print(summary) + + # write out puzzles + for points in sorted(puzzles): + puzzle = puzzles[points] + + +#vim:py