OSDN Git Service

add amulet search only by seed2
[amulettoolsmh4/main.git] / model / alchemysimulator.py
1 # -*- coding: utf-8 -*-
2
3 u"""
4 錬金のシミュレータ
5 2013/12/19 written by kei9
6 """
7
8 # import modules
9 import sqlite3
10
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
17
18 class AlchemySimulator(object):
19     u""" 特定Seed1,2から生じる錬金結果を模擬するクラス """
20     def __init__(self, db_cursor):
21         u""" 錬金結果の模擬クラス """
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()
30
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
34         return value
35
36     def alchemy_nazo_id(self, seed1, seed2):
37         u""" なぞの錬金
38         return (skill1_id, skill1_val, skill2_id, skill2_val, slot_num, type_name)
39         """
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
43
44     def alchemy_nazo_name(self, seed1, seed2):
45         u""" なぞの錬金
46         return (skill1_name, skill1_val, skill2_name, skill2_val, slot_num, type_name)
47         """
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)
53         else:
54             return (self._skill_id2name[skill1_id], skill1_val, u"", 0, slot_num, type_name)
55
56     def alchemy_komyou_id(self, seed1, seed2):
57         u""" 光明の錬金
58         return (skill1_id, skill1_val, skill2_id, skill2_val, slot_num, type_name)
59         """
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
63
64     def alchemy_komyou_name(self, seed1, seed2):
65         u""" 光明の錬金
66         return (skill1_name, skill1_val, skill2_name, skill2_val, slot_num, type_name)
67         """
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)
73         else:
74             return (self._skill_id2name[skill1_id], skill1_val, u"", 0, slot_num, type_name)
75
76     def alchemy_inishie_id(self, seed1, seed2):
77         u""" いにしえの錬金
78         return (skill1_id, skill1_val, skill2_id, skill2_val, slot_num, type_name)
79         """
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
83
84     def alchemy_inishie_name(self, seed1, seed2):
85         u""" いにしえの錬金
86         return (skill1_name, skill1_val, skill2_name, skill2_val, slot_num, type_name)
87         """
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)
93         else:
94             return (self._skill_id2name[skill1_id], skill1_val, u"", 0, slot_num, type_name)
95
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)
99         """
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
108         else:
109             raise NotImplementedError(u"Irregular Alchemy Type!")
110
111         gen_a = RandomGenerator(seed1)  # generator A
112         gen_b = RandomGenerator(seed2)  # generator B
113
114         result_num = gen_a.get_next() % (result_num_max - result_num_min + 1) + result_num_min
115         result_list = []
116
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:
122                 u""" 謎のお守り """
123                 amulet_name = mh4constnumbers.NAME_AMULET0
124             elif 10 <= amulet_type < 55:
125                 u""" 光るお守り """
126                 amulet_name = mh4constnumbers.NAME_AMULET1
127             elif 55 <= amulet_type < 85:
128                 u""" 古びたお守り """
129                 amulet_name = mh4constnumbers.NAME_AMULET2
130             elif 85 <= amulet_type < 100:
131                 u""" 歪んだお守り """
132                 amulet_name = mh4constnumbers.NAME_AMULET3
133             else:
134                 raise NotImplementedError(u"Divisor must be incorrect")
135
136             gen_c = RandomGenerator(s1) # generator C
137             gen_d = RandomGenerator(s2) # generator D
138
139             result_list.append(self._judge(gen_c, gen_d, amulet_name))
140         return result_list
141
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)
145         """
146         result_list = []
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:
150                 result_list.append(
151                     (self._skill_id2name[skill1_id], skill1_val,
152                     self._skill_id2name[skill2_id], skill2_val, slot_num, type_name))
153             else:
154                 result_list.append((self._skill_id2name[skill1_id], skill1_val, u"", 0, slot_num, type_name))
155
156         return result_list
157
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)
161         """
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]
168
169         x1 = gen_c.get_next()
170         x2 = gen_d.get_next()
171         skill1_val = (x1 ^ x2) % (max1 - min1 + 1) + min1 # XOR
172
173         y1 = gen_c.get_next()
174         y2 = gen_d.get_next()
175         border = mh4constnumbers.SKILL2_BORDER_DICT[amulet_name]
176
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]
182
183             if min2 < 0:
184                 z0 = gen_c.get_next()
185             else:
186                 z0 = None
187
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
194
195             if skill2_id == skill1_id or skill2_val == 0:
196                 skill2_id = None
197                 skill2_val = 0
198         else:
199             skill2_id = None
200             skill2_val = 0
201
202         # slot number
203         if skill2_val <= 0:
204             suff_val = (skill1_val * 10) // max1
205         else:
206             suff_val = (skill1_val * 10) // max1 + (skill2_val * 10) // max2
207
208         w = gen_c.get_next()
209         if (w & mh4constnumbers.SEED_DECIDE_FLAG) != 0: # falg = 128, 50%
210             w2 = gen_c.get_next()
211         else:
212             w2 = gen_d.get_next()
213         _slot = w2 % 100
214
215         th1_slot, th2_slot, th3_slot = self._acc_suff.select_thresholds_by_id(amulet_id, suff_val)
216         if _slot < th1_slot:
217             slot_num = 0
218             slot_point = mh4constnumbers.SLOT_POINT0
219         elif th1_slot <= _slot < th2_slot:
220             slot_num = 1
221             slot_point = mh4constnumbers.SLOT_POINT1
222         elif th2_slot <= _slot < th3_slot:
223             slot_num = 2
224             slot_point = mh4constnumbers.SLOT_POINT2
225         elif th3_slot <= _slot:
226             slot_num = 3
227             slot_point = mh4constnumbers.SLOT_POINT3
228
229         type_name = self._decide_amulet_type(suff_val, slot_point, amulet_name)
230
231         return (skill1_id, skill1_val, skill2_id, skill2_val, slot_num, type_name)
232
233
234     def _decide_amulet_type(self, suff_val, slot_point, amulet_name):
235         u""" 鑑定結果の護石名を充足値、スロットポイント、お守り名から決定する """
236         type_val = suff_val + slot_point
237
238         border1, border2, border3 = mh4constnumbers.TYPE_BORDER_DICT[amulet_name]
239         if type_val >= border3[0]:
240             return border3[1]
241         elif type_val >= border2[0]:
242             return border2[1]
243         elif type_val >= border1[0]:    # 0
244             return border1[1]
245         else:
246             return None