diff --git a/minesweeper.py b/minesweeper.py index b307996..7b1d315 100644 --- a/minesweeper.py +++ b/minesweeper.py @@ -1,7 +1,8 @@ import collections import itertools import operator -from util import * +from .util import * +from functools import reduce set_ = frozenset @@ -176,9 +177,9 @@ def condense_supercells(rules): cell_rules_map = map_reduce(rules, lambda rule: [(cell, rule) for cell in rule.cells], set_) # for each 'list of rules appearing in', list of cells that share that ruleset (these cells # thus only ever appear together in the same rules) - rules_supercell_map = map_reduce(cell_rules_map.iteritems(), lambda (cell, rules): [(rules, cell)], set_) + rules_supercell_map = map_reduce(cell_rules_map.items(), lambda x: [(x[1], x[0])], set_) # for each original rule, list of 'supercells' appearing in that rule - rule_supercells_map = map_reduce(rules_supercell_map.iteritems(), lambda (rules, cell_): [(rule, cell_) for rule in rules], set_) + rule_supercells_map = map_reduce(rules_supercell_map.items(), lambda x: [(rule, x[1]) for rule in x[0]], set_) return ([rule.condensed(rule_supercells_map) for rule in rules], rules_supercell_map.values()) @@ -374,7 +375,7 @@ def combine(self, permu): """return a new permutation by combining this permutation with 'permu' the permutations must be compatible!""" - assert all(permu.mapping[k] == v for k, v in self.mapping.iteritems() if k in permu.mapping) + assert all(permu.mapping[k] == v for k, v in self.mapping.items() if k in permu.mapping) mapping = dict(self.mapping) mapping.update(permu.mapping) return Permutation(mapping) @@ -394,13 +395,13 @@ def multiplicity(self): e.g., N mines in a supercell of M cells has (M choose N) actual configurations """ - return product(choose(len(cell_), k) for cell_, k in self.mapping.iteritems()) + return product(choose(len(cell_), k) for cell_, k in self.mapping.items()) def _canonical(self): - return tuple(sorted(self.mapping.iteritems(), key=lambda (k, v): hash(k))) + return tuple(sorted(self.mapping.items(), key=lambda x: hash(x[0]))) def __repr__(self): - cell_counts = sorted([(sorted(list(cell)), count) for cell, count in self.mapping.iteritems()]) + cell_counts = sorted([(sorted(list(cell)), count) for cell, count in self.mapping.items()]) cell_frags = ['%s:%d' % (','.join(str(c) for c in cell), count) for cell, count in cell_counts] return '{%s}' % ' '.join(cell_frags) @@ -629,7 +630,7 @@ def rereduce(self): superseded_rules = set() decompositions = {} - for rule, permu_set in self.permu_map.iteritems(): + for rule, permu_set in self.permu_map.items(): decomp = permu_set.decompose() if len(decomp) > 1: superseded_rules.add(rule) @@ -709,7 +710,7 @@ def __init__(self, ruleset=None): # the current configuration-in-progress self.fixed = set() # subset of ruleset whose permutations are still 'open' - self.free = dict((rule, set(permu_set)) for rule, permu_set in ruleset.permu_map.iteritems()) + self.free = dict((rule, set(permu_set)) for rule, permu_set in ruleset.permu_map.items()) # helper function (closure) self.overlapping_rules = lambda rule: ruleset.cell_rules_map.overlapping_rules(rule) @@ -721,7 +722,7 @@ def clone(self): """clone this state""" state = EnumerationState() state.fixed = set(self.fixed) - state.free = dict((rule, set(permu_set)) for rule, permu_set in self.free.iteritems()) + state.free = dict((rule, set(permu_set)) for rule, permu_set in self.free.items()) state.overlapping_rules = self.overlapping_rules state.compatible_rule_index = self.compatible_rule_index return state @@ -729,7 +730,7 @@ def clone(self): def build_compatibility_index(self, rspm): """build the constraint index""" index = {} - for rule, permu_set in rspm.iteritems(): + for rule, permu_set in rspm.items(): for permu in permu_set: for rule_ov in self.overlapping_rules(rule): index[(permu, rule_ov)] = rspm[rule_ov].compatible(permu) @@ -845,7 +846,7 @@ def is_static(self): return len(self.subtallies) == 1 def __iter__(self): - return self.subtallies.iteritems() + return iter(self.subtallies.items()) def normalize(self): """normalize sub-tally totals into relative weights such that @@ -860,7 +861,7 @@ def collapse(self): all sub-tallies""" self.normalize() collapsed = map_reduce(self.subtallies.values(), lambda subtally: subtally.collapse(), sum) - for entry in collapsed.iteritems(): + for entry in collapsed.items(): yield entry def scale_weights(self, scalefunc): @@ -895,7 +896,7 @@ def for_other(num_uncharted_cells, mine_totals): """ metacell = UnchartedCell(num_uncharted_cells) - return FrontTally(dict((num_mines, FrontSubtally.mk(k, {metacell: num_mines})) for num_mines, k in mine_totals.iteritems())) + return FrontTally(dict((num_mines, FrontSubtally.mk(k, {metacell: num_mines})) for num_mines, k in mine_totals.items())) def __repr__(self): return str(dict(self.subtallies)) @@ -917,18 +918,18 @@ def add(self, config): """add a configuration to the tally""" mult = config.multiplicity() # weight by multiplicity self.total += mult - for cell_, n in config.mapping.iteritems(): + for cell_, n in config.mapping.items(): self.tally[cell_] += n * mult def finalize(self): """after all configurations have been summed, compute relative prevalence from totals""" - self.tally = dict((cell_, n / float(self.total)) for cell_, n in self.tally.iteritems()) + self.tally = dict((cell_, n / float(self.total)) for cell_, n in self.tally.items()) def collapse(self): """helper function for FrontTally.collapse(); emit all cell expected mine values weighted by this sub-tally's weight""" - for cell_, expected_mines in self.tally.iteritems(): + for cell_, expected_mines in self.tally.items(): yield (cell_, self.total * expected_mines) @staticmethod @@ -1064,7 +1065,8 @@ def new_front_total(): tallies = list(tallies) # we need guaranteed iteration order # iterate over the cartesian product of sub-tallies from each tally - for combination in (combo(e) for e in itertools.product(*tallies)): + for e in itertools.product(*tallies): + combination = combo(e) num_tallied_mines = sum(s.num_mines for s in combination) # number of mines lying in the 'other' cells num_free_mines = at_large_mines - num_tallied_mines diff --git a/util.py b/util.py index 0a2d955..4476e1e 100644 --- a/util.py +++ b/util.py @@ -1,10 +1,11 @@ import math import operator import collections +from functools import reduce def fact_div(a, b): """return a! / b!""" - return product(xrange(b + 1, a + 1)) if a >= b else 1. / fact_div(b, a) + return product(range(b + 1, a + 1)) if a >= b else 1. / fact_div(b, a) def choose(n, k): """return n choose k @@ -21,7 +22,7 @@ def peek(iterable): useful for extracting singletons, or when you're managing iteration yourself""" - return iter(iterable).next() + return next(iter(iterable)) def product(n): """return the product of a set of numbers @@ -62,7 +63,7 @@ def map_reduce(data, emitfunc=lambda rec: [(rec,)], reducefunc=lambda v: v): except ValueError: k, v = emission[0], None mapped[k].append(v) - return dict((k, reducefunc(v)) for k, v in mapped.iteritems()) + return dict((k, reducefunc(v)) for k, v in mapped.items()) class ImmutableMixin(object): """mixin for immutable, hashable objects""" diff --git a/web_demo/manage.py b/web_demo/manage.py index 5e78ea9..27014c5 100755 --- a/web_demo/manage.py +++ b/web_demo/manage.py @@ -1,11 +1,15 @@ #!/usr/bin/env python -from django.core.management import execute_manager -try: - import settings # Assumed to be in the same directory. -except ImportError: - import sys - sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__) - sys.exit(1) +import os +import sys -if __name__ == "__main__": - execute_manager(settings) +if __name__ == '__main__': + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'web_demo.settings') + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) diff --git a/web_demo/minesweepr/static/script/minesweeper.js b/web_demo/minesweepr/static/script/minesweeper.js index f73aa97..76f0729 100644 --- a/web_demo/minesweepr/static/script/minesweeper.js +++ b/web_demo/minesweepr/static/script/minesweeper.js @@ -9,7 +9,7 @@ COUNT_FILL = ['blue', 'green', 'red', 'purple', 'brown', 'cyan', 'orange', 'blac MARGIN = 1; MINE_RADIUS = .5; FONT_SIZE = .5; -FONT_OFFSET = ($.browser.mozilla ? .15 : .07); +FONT_OFFSET = .07; FONT_SCALE_LONG = .8; HIGHLIGHT_CUR_CELL = 'rgba(0, 0, 0, 0)'; //'rgba(255, 180, 0, .2)'; HIGHLIGHT_NEIGHBOR = 'rgba(255, 220, 255, .2)'; diff --git a/web_demo/minesweepr/taskexec.py b/web_demo/minesweepr/taskexec.py index 040463a..d0d7100 100644 --- a/web_demo/minesweepr/taskexec.py +++ b/web_demo/minesweepr/taskexec.py @@ -26,7 +26,7 @@ def __init__(self, task, *args, **kwargs): self.kwargs = kwargs def start(self): - project_root = filter(lambda p: p, sys.path)[0] # sketchy + project_root = next(filter(lambda p: p, sys.path)) # sketchy self.p = Popen(['python', os.path.join(os.getcwd(), __file__)], cwd=project_root, stdin=PIPE, stdout=PIPE, stderr=PIPE) threading.Thread.start(self) @@ -34,7 +34,7 @@ def start(self): def run(self): payload = {'task': self.taskname, 'args': self.args, 'kwargs': self.kwargs} try: - out, err = self.p.communicate(ser.dumps(payload)) + out, err = self.p.communicate(ser.dumps(payload).encode()) self.result = ((False, err) if err else (True, ser.loads(out))) except: # various errors if process is terminated @@ -57,7 +57,7 @@ def resolve(self): if success: return result else: - raise Exception('error in task> ' + result) + raise Exception('error in task> ' + result.decode()) def _exec(payload): taskname = payload['task'] @@ -70,4 +70,4 @@ def _exec(payload): if __name__ == "__main__": sys.path.insert(0, os.getcwd()) # cwd set to django project root dir - print ser.dumps(_exec(ser.load(sys.stdin))) + print(ser.dumps(_exec(ser.load(sys.stdin)))) diff --git a/web_demo/minesweepr/templates/_player.html b/web_demo/minesweepr/templates/_player.html index b69ae53..74cb7af 100644 --- a/web_demo/minesweepr/templates/_player.html +++ b/web_demo/minesweepr/templates/_player.html @@ -5,13 +5,14 @@ {% block content_script %} {% endblock %} - - - - + +{% load static %} + + + @@ -213,7 +214,7 @@
| # mines left: | — |
| total accumulated risk: | — |
| solving… | ![]() |
| solving… | ![]() |
| solved in: | |
|
WIN
diff --git a/web_demo/minesweepr/templates/_query.html b/web_demo/minesweepr/templates/_query.html
deleted file mode 100644
index 93bb765..0000000
--- a/web_demo/minesweepr/templates/_query.html
+++ /dev/null
@@ -1,35 +0,0 @@
-
-
- | |