1 # -*- coding: utf-8 -*-
5 2013/12/19 written by kei9
11 import mh4constnumbers
12 from randomgenerator import RandomGenerator
13 from skillminmaxtable import SkillMinMaxTableAccessor
14 from skilltable import SkillTableAccessor
15 from amulettable import AmuletTableAccessor
16 from sufficienttable import SufficientTableAccessor
18 class AlchemySimulator(object):
19 u""" 特定Seed1,2から生じる錬金結果を模擬するクラス """
20 def __init__(self, db_cursor):
22 self._cursor = db_cursor
23 acc_minmax = SkillMinMaxTableAccessor(db_cursor)
24 acc_skill = SkillTableAccessor(db_cursor)
25 acc_amulet = AmuletTableAccessor(db_cursor)
26 self._acc_suff = SufficientTableAccessor(db_cursor)
27 self._skill_id2name, self._skill_name2id = acc_skill.get_dict()
28 self._amu_id2name, self._amu_name2id = acc_amulet.get_dict()
29 self._minmax_dict = acc_minmax.get_minmax_by_id()
31 def _get_skill_value(self, rand1, rand2, skill_max, skill_min):
32 u""" 与えられた2つの乱数値とスキルの最大、最小値からスキル値を計算する """
33 value = (rand1 ^ rand2) % (skill_max - skill_min + 1) + skill_min # XOR
36 def alchemy_nazo_id(self, seed1, seed2):
38 return (skill1_id, skill1_val, skill2_id, skill2_val, slot_num, type_name)
40 gen_c = RandomGenerator(seed1) # generator C
41 gen_d = RandomGenerator(seed2) # generator D
42 return self._judge(gen_c, gen_d, mh4constnumbers.NAME_AMULET0) # nazo
44 def alchemy_nazo_name(self, seed1, seed2):
46 return (skill1_name, skill1_val, skill2_name, skill2_val, slot_num, type_name)
48 val = self.alchemy_nazo_id(seed1, seed2)
49 skill1_id, skill1_val, skill2_id, skill2_val, slot_num, type_name = val
50 if skill2_id in self._skill_id2name:
51 return (self._skill_id2name[skill1_id], skill1_val,
52 self._skill_id2name[skill2_id], skill2_val, slot_num, type_name)
54 return (self._skill_id2name[skill1_id], skill1_val, u"", 0, slot_num, type_name)
56 def alchemy_komyou_id(self, seed1, seed2):
58 return (skill1_id, skill1_val, skill2_id, skill2_val, slot_num, type_name)
60 gen_c = RandomGenerator(seed1) # generator C
61 gen_d = RandomGenerator(seed2) # generator D
62 return self._judge(gen_c, gen_d, mh4constnumbers.NAME_AMULET1) # komyou
64 def alchemy_komyou_name(self, seed1, seed2):
66 return (skill1_name, skill1_val, skill2_name, skill2_val, slot_num, type_name)
68 val = self.alchemy_komyou_id(seed1, seed2)
69 skill1_id, skill1_val, skill2_id, skill2_val, slot_num, type_name = val
70 if skill2_id in self._skill_id2name:
71 return (self._skill_id2name[skill1_id], skill1_val,
72 self._skill_id2name[skill2_id], skill2_val, slot_num, type_name)
74 return (self._skill_id2name[skill1_id], skill1_val, u"", 0, slot_num, type_name)
76 def alchemy_inishie_id(self, seed1, seed2):
78 return (skill1_id, skill1_val, skill2_id, skill2_val, slot_num, type_name)
80 gen_c = RandomGenerator(seed1) # generator C
81 gen_d = RandomGenerator(seed2) # generator D
82 return self._judge(gen_c, gen_d, mh4constnumbers.NAME_AMULET2) # inishie
84 def alchemy_inishie_name(self, seed1, seed2):
86 return (skill1_name, skill1_val, skill2_name, skill2_val, slot_num, type_name)
88 val = self.alchemy_inishie_id(seed1, seed2)
89 skill1_id, skill1_val, skill2_id, skill2_val, slot_num, type_name = val
90 if skill2_id in self._skill_id2name:
91 return (self._skill_id2name[skill1_id], skill1_val,
92 self._skill_id2name[skill2_id], skill2_val, slot_num, type_name)
94 return (self._skill_id2name[skill1_id], skill1_val, u"", 0, slot_num, type_name)
96 def alchemy_tenun_id(self, seed1, seed2, alchemy_type):
97 u""" 天運の錬金 (古*3または歪*3限定。)
98 return list of (skill1_id, skill1_val, skill2_id, skill2_val, slot_num, type_name)
100 if alchemy_type == mh4constnumbers.KEY_TENUN555:
101 result_num_max = mh4constnumbers.TENUN555_MAX
102 result_num_min = mh4constnumbers.TENUN555_MIN
103 yuga_divisor = mh4constnumbers.TENUN555_DIVISOR
104 elif alchemy_type == mh4constnumbers.KEY_TENUN888:
105 result_num_max = mh4constnumbers.TENUN888_MAX
106 result_num_min = mh4constnumbers.TENUN888_MIN
107 yuga_divisor = mh4constnumbers.TENUN888_DIVISOR
109 raise NotImplementedError(u"Irregular Alchemy Type!")
111 gen_a = RandomGenerator(seed1) # generator A
112 gen_b = RandomGenerator(seed2) # generator B
114 result_num = gen_a.get_next() % (result_num_max - result_num_min + 1) + result_num_min
117 for i in range(result_num):
118 s1 = gen_a.get_next()
119 s2 = gen_b.get_next()
120 amulet_type = s1 % yuga_divisor
121 if 0 <= amulet_type < 10:
123 amulet_name = mh4constnumbers.NAME_AMULET0
124 elif 10 <= amulet_type < 55:
126 amulet_name = mh4constnumbers.NAME_AMULET1
127 elif 55 <= amulet_type < 85:
129 amulet_name = mh4constnumbers.NAME_AMULET2
130 elif 85 <= amulet_type < 100:
132 amulet_name = mh4constnumbers.NAME_AMULET3
134 raise NotImplementedError(u"Divisor must be incorrect")
136 gen_c = RandomGenerator(s1) # generator C
137 gen_d = RandomGenerator(s2) # generator D
139 result_list.append(self._judge(gen_c, gen_d, amulet_name))
142 def alchemy_tenun_name(self, seed1, seed2, alchemy_type):
143 u""" 天運の錬金(古*3または歪*3限定。)
144 return list of (skill1_name, skill1_val, skill2_name, skill2_val, slot_num, type_name)
147 result = self.alchemy_tenun_id(seed1, seed2, alchemy_type)
148 for skill1_id, skill1_val, skill2_id, skill2_val, slot_num, type_name in result:
149 if skill2_id in self._skill_id2name:
151 (self._skill_id2name[skill1_id], skill1_val,
152 self._skill_id2name[skill2_id], skill2_val, slot_num, type_name))
154 result_list.append((self._skill_id2name[skill1_id], skill1_val, u"", 0, slot_num, type_name))
158 def _judge(self, gen_c, gen_d, amulet_name):
159 u""" 乱数生成器C,Dおよびお守りの種類から鑑定を行う
160 return (skill1_id, skill1_val, skill2_id, skill2_val, slot_num, type_name)
162 amulet_id = self._amu_name2id[amulet_name]
163 skill1_minmax, skill2_minmax = self._minmax_dict[amulet_id]
164 s1 = gen_c.get_next() # for skill1 dicision
165 s1 %= len(skill1_minmax) # skill1_pos
166 skill1_id = [x for i,x in enumerate(sorted(skill1_minmax.keys())) if i == s1][0]
167 min1, max1 = skill1_minmax[skill1_id]
169 x1 = gen_c.get_next()
170 x2 = gen_d.get_next()
171 skill1_val = (x1 ^ x2) % (max1 - min1 + 1) + min1 # XOR
173 y1 = gen_c.get_next()
174 y2 = gen_d.get_next()
175 border = mh4constnumbers.SKILL2_BORDER_DICT[amulet_name]
177 if (y1 ^ y2) % 100 >= border: # decide skill2 to exist
178 s2 = gen_d.get_next() # for skill2 dicision
179 s2 %= len(skill2_minmax) # skill2_pos
180 skill2_id = [x for i,x in enumerate(sorted(skill2_minmax.keys())) if i == s2][0]
181 min2, max2 = skill2_minmax[skill2_id]
184 z0 = gen_c.get_next()
188 z1 = gen_c.get_next()
189 z2 = gen_d.get_next()
190 if min2 < 0 and z0 % 2 == 0: # skill2 val is minus
191 skill2_val = (z1 ^ z2) % (1 - min2) + min2
192 else: # skill2 val is plus
193 skill2_val = (z1 ^ z2) % max2 + 1
195 if skill2_id == skill1_id or skill2_val == 0:
204 suff_val = (skill1_val * 10) // max1
206 suff_val = (skill1_val * 10) // max1 + (skill2_val * 10) // max2
209 if (w & mh4constnumbers.SEED_DECIDE_FLAG) != 0: # falg = 128, 50%
210 w2 = gen_c.get_next()
212 w2 = gen_d.get_next()
215 th1_slot, th2_slot, th3_slot = self._acc_suff.select_thresholds_by_id(amulet_id, suff_val)
218 slot_point = mh4constnumbers.SLOT_POINT0
219 elif th1_slot <= _slot < th2_slot:
221 slot_point = mh4constnumbers.SLOT_POINT1
222 elif th2_slot <= _slot < th3_slot:
224 slot_point = mh4constnumbers.SLOT_POINT2
225 elif th3_slot <= _slot:
227 slot_point = mh4constnumbers.SLOT_POINT3
229 type_name = self._decide_amulet_type(suff_val, slot_point, amulet_name)
231 return (skill1_id, skill1_val, skill2_id, skill2_val, slot_num, type_name)
234 def _decide_amulet_type(self, suff_val, slot_point, amulet_name):
235 u""" 鑑定結果の護石名を充足値、スロットポイント、お守り名から決定する """
236 type_val = suff_val + slot_point
238 border1, border2, border3 = mh4constnumbers.TYPE_BORDER_DICT[amulet_name]
239 if type_val >= border3[0]:
241 elif type_val >= border2[0]:
243 elif type_val >= border1[0]: # 0