#!/usr/bin/python import json data = json.load(open("data.json")) calculated = {} def calcRatio(child, parent): if child in calculated and parent in calculated[child]: return calculated[child][parent] elif child == parent: return 500 r = 0 for s in xrange(5): r += 2 - abs(data[child]['stats'][s] - data[parent]['stats'][s]) r += 5 * len(set(data[child]['attributes']).intersection(set(data[parent]['attributes']))) diff = data[child]['tier'] - data[parent]['tier'] if diff > 1: r -= 2 * diff elif diff < -3: r += diff if r < 0: r = 0 if not child in calculated: calculated[child] = {} calculated[child][parent] = r return r def cross(parents): weight = {} for c in data.iterkeys(): weight[c] = 0 for p in parents: weight[c] += calcRatio(c, p) total = sum(weight.itervalues()) result = [] for c, v in weight.iteritems(): if v > 0: result.append((float(v) / total, c, v, total)) return result def target(child): weight = {} for p in data.iterkeys(): weight[p] = {} for c in data.iterkeys(): weight[p][c] = calcRatio(c, p) result = [] for p in data.iterkeys(): total = sum(weight[p].itervalues()) v = weight[p][child] if v > 0: result.append((float(v) / total, p, v, total)) return result def reachability(start): reachable = {start: (1, 'start', 1, 1)} remaining = {start} while remaining: test = remaining.pop() new = cross([test]) for c in new: if not c[1] in reachable: reachable[c[1]] = (c[0], test, c[2], c[3]) remaining.add(c[1]) elif c[0] > reachable[c[1]][0] and test != c[1]: reachable[c[1]] = (c[0], test, c[2], c[3]) #reachprint(reachable, set(data.iterkeys()).difference(set(reachable.iterkeys())), remaining) unreachable = set(data.iterkeys()).difference(set(reachable.iterkeys())) return (reachable, unreachable) def reachprint(r, u, rem): print 'Reachable:' for c, v in r.iteritems(): print '%s: %.3f%% (%d/%d)' % (' <- '.join([c] + v[1]), v[0] * 100., v[2], v[3]) print print 'Unreachable: ' + ', '.join(u) print 'Remaining: ' + ', '.join(rem) print def list(): for c in data.iterkeys(): print c def output(result): result.sort() for r in result: print '%s: %.3f%% (%d/%d)' % (r[1], r[0] * 100., r[2], r[3]) def usage(name): print 'Usage: ' + name + ' crop...' print ' ' + name + ' [-t | --target] crop' print ' ' + name + ' [-r | --reachability] startcrop' print ' ' + name + ' [-l | --list]' raise SystemExit() def unknown(crops): print 'Unknown crops: ' + ', '.join(crops) raise SystemExit() if __name__ == '__main__': import getopt import sys try: options, args = getopt.getopt(sys.argv[1:], 'lt:r:', ['list', 'target=', 'reachability=']) except getopt.GetoptError as e: print e.msg usage(sys.argv[0]) if not options: if not args: print 'No crops specified' usage(sys.argv[0]) elif len(args) > 4: print 'At most 4 crops can be crossbred' usage(sys.argv[0]) else: u = [c for c in args if not c in data] if u: unknown(u) output(cross(args)) else: if any(o[0] in {'-l', '--list'} for o in options): list() elif len(options) != 1: print 'Only one mode may be specified' usage(sys.argv[0]) elif not options[0][1]: print 'No crop specified' usage(sys.argv[0]) elif options[0][1] not in data: unknown([options[0][1]]) elif options[0][0] in {'-t', '--target'}: output(target(options[0][1])) else: r, u = reachability(options[0][1]) print 'Reachable:' for c, v in r.iteritems(): print '%s <- %s: %.3f%% (%d/%d)' % (c, v[1], v[0] * 100., v[2], v[3]) print print 'Unreachable: ' + ', '.join(u)