# -*- encoding: utf-8 -*- """ 局面をなるべく小さい範囲の整数へマッピングする関数のジェネレータ """ from copy import deepcopy import logging logging.basicConfig( # level=logging.DEBUG, format="%(message)s") import utils import en_decoder class Node(object): def get_node_name(self, context={}): return self.node_name + context.get("suffix", "") class Choice(Node): """ >>> c = Choice(5, "") >>> c.size({}) 5 >>> Choice.count = 0 >>> Choice(6, "dice").encoder() ['# Choice(6)', 'choice0 = dice'] >>> Choice(6, "dice").decoder() ['# Choice(6)', 'dice = choice1'] """ count = 0 def __init__(self, n, arg_name): self.n = n self.arg_name = arg_name utils.set_node_name(self) #assert n > 1 self.vars = [(utils.INT_TYPE, self.node_name)] self.args = [(utils.INT_TYPE, arg_name, "[0, %d)" % n)] def size(self, context={}): return self.n def __repr__(self): return "Choice(%r)" % self.n def is_repeatable(self): return True encoder = en_decoder.Choice.encoder decoder = en_decoder.Choice.decoder class Resource(object): def __init__(self, n, name=None): self.n = n self.name = name def take(self, arg_name): return Take(self, arg_name) def __repr__(self): return "Resource(%s)" % (self.name, ) class Take(Node): count = 0 def __init__(self, res, arg_name): self.res = res self.arg_name = arg_name utils.set_node_name(self) self.vars = [(utils.INT_TYPE, self.node_name)] self.args = [(utils.INT_TYPE, arg_name, "[0, %d)" % res.n)] def size(self, context={}): result = self.res.n - len(context[self.res.name]) context[self.res.name].append(self.arg_name) return result def __repr__(self): return "Take(%r)" % self.res def is_repeatable(self): return False encoder = en_decoder.Take.encoder decoder = en_decoder.Take.decoder class BinaryOperator(Node): def __init__(self, rule1, rule2, arg_name=""): self.r1 = rule1 self.r2 = rule2 self.arg_name = arg_name utils.set_node_name(self) self.vars = rule1.vars + rule2.vars + [(utils.INT_TYPE, self.node_name)] self.args = rule1.args + rule2.args self.initialize() def initialize(self): pass def is_repeatable(self): return self.r1.is_repeatable() and self.r2.is_repeatable() def And(rule1, rule2): """ >>> a = And(Choice(3, ""), Choice(5, "")) >>> a.size() 15 >>> a = And(Or(Choice(3, ""), Choice(5, "")), Or(Choice(2, ""), Choice(5, ""))) >>> a.size() 56 """ # Orがルールに含まれているなら展開する if isinstance(rule1, Or): return Or( And(rule1.r1, rule2), And(rule1.r2, rule2), rule1.arg_name).set_unorder_info(rule1.unorder_info) if isinstance(rule2, Or): return Or( And(rule1, rule2.r1), And(rule1, rule2.r2), rule2.arg_name).set_unorder_info(rule2.unorder_info) return And_(rule1, rule2) class And_(BinaryOperator): count = 0 unorder_info = None def size(self, context={}): return self.r1.size(context) * self.r2.size(context) def __repr__(self): return "And(%r, %r)" % (self.r1, self.r2) def set_unorder_info(self, oname): self.unorder_info = oname self.original_args = self.args self.vars += [(typ, v) for (typ, v, com) in self.args] self.args = [] return self encoder = en_decoder.And.encoder decoder = en_decoder.And.decoder class Or(BinaryOperator): """ Or(x, y, var_name) xまたはy。var_nameはyであるときにTrueになる変数の名前 >>> t = Or(Choice(3, ""), Choice(5, "")) >>> t.size() 8 """ count = 0 unorder_info = None def initialize(self): if not self.arg_name: self.arg_name = "is_" + self.r2.node_name self.args.append((utils.BOOL_TYPE, self.arg_name, "true if second rule selected")) def set_unorder_info(self, oname): self.unorder_info = oname return self def size(self, context={}): copy = deepcopy(context) return self.r1.size(copy) + self.r2.size(context) def __repr__(self): return "Or(%r, %r)" % (self.r1, self.r2) encoder = en_decoder.Or.encoder decoder = en_decoder.Or.decoder def Unordered(rule): """ >>> Unordered(Choice(3, "")).size({}) 6 >>> Unordered(And(Choice(3, ""), Choice(2, ""))).size({}) 21 >>> Unordered(Or(Choice(3, ""), Choice(2, ""))).size({}) 15 """ # Orがルールに含まれているなら展開する if isinstance(rule, Or): oname = rule.arg_name xy = And(rule.r1, rule.r2).set_unorder_info(oname) or_ = Or( xy, Or(Unordered(rule.r1), Unordered(rule.r2), oname + "_0"), oname + "_1") or_.unorder_info = oname return or_ return Unordered_(rule) class Unordered_(Node): count = 0 def __init__(self, rule): self.rule = rule utils.set_node_name(self) self.vars = [(typ, name + suffix) for (typ, name) in rule.vars for suffix in ["_0", "_1"]] self.vars.append((utils.INT_TYPE, self.node_name)) self.vars.append((utils.INT_TYPE, "n")) self.args = [(typ, name + suffix, comment) for (typ, name, comment) in rule.args for suffix in ["_0", "_1"]] def size(self, context={}): if self.is_repeatable(): n = self.rule.size(context) # 重複を許すn個から2個選ぶ組み合わせ return n * (n + 1) / 2 else: # 重複を許さないn個から2個選ぶ組み合わせ result = self.rule.size(context) * self.rule.size(context) / 2 return result raise NotImplementedError def __repr__(self): return "Unordered(%r)" % self.rule def is_repeatable(self): return self.rule.is_repeatable() encoder = en_decoder.Unordered.encoder decoder = en_decoder.Unordered.decoder def _main(): "make doubutu shougi's minimum complete hash" r = Resource(12, "X") Lion0 = r.take("lion0") Lion1 = r.take("lion1") Mochigoma = Choice(1, "dummy1") Player = Choice(2, "kirin_player") Kirin = Unordered( And( Or(r.take("kirin"), Mochigoma, "is_kirin_mochigoma"), Player)) Mochigoma = Choice(1, "dummy2") Player = Choice(2, "zou_player") Zou = Unordered( And( Or(r.take("zou"), Mochigoma, "is_zou_mochigoma"), Player)) Mochigoma = Choice(1, "dummy3") Player = Choice(2, "hiyoko_player") IsNiwa = Choice(2, "is_niwatori") Hiyoko = Unordered( And( Or( And( r.take("hiyoko"), IsNiwa), Mochigoma, "is_hiyoko_mochigoma"), Player)) All = And(Lion0, And(Lion1, And(Kirin, And(Zou, Hiyoko)))) s = en_decoder.CppRenderer.get_test(All, {"X": []}) file("tmp.cpp", "w").write(s) def _test(): import doctest doctest.testmod() print "test ok." if __name__ == "__main__": _test() _main()