OSDN Git Service

2a312f36f4a85af39d23122337963aed06b205c4
[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 import singleton
18
19 class AlchemySimulator(object):
20     u""" 特定Seed1,2から生じる錬金結果を模擬するクラス """
21     __metaclass__ = singleton.Singleton
22     def __init__(self, db_cursor):
23         u""" 錬金結果の模擬クラス """
24         self._cursor = db_cursor
25         acc_minmax = SkillMinMaxTableAccessor(db_cursor)
26         acc_skill = SkillTableAccessor(db_cursor)
27         acc_amulet = AmuletTableAccessor(db_cursor)
28         self._acc_suff = SufficientTableAccessor(db_cursor)
29         self._skill_id2name, self._skill_name2id = acc_skill.get_dict()
30         self._amu_id2name, self._amu_name2id = acc_amulet.get_dict()
31         self._minmax_dict = acc_minmax.get_minmax_by_id()
32
33     def _get_skill_value(self, rand1, rand2, skill_max, skill_min):
34         u""" 与えられた2つの乱数値とスキルの最大、最小値からスキル値を計算する """
35         value = (rand1 ^ rand2) % (skill_max - skill_min + 1) + skill_min   # XOR
36         return value
37
38     def alchemy_nazo_id(self, seed1, seed2):
39         u""" なぞの錬金
40         return (skill1_id, skill1_val, skill2_id, skill2_val, slot_num, type_name)
41         """
42         gen_c = RandomGenerator(seed1) # generator C
43         gen_d = RandomGenerator(seed2) # generator D
44         return self._judge(gen_c, gen_d, mh4constnumbers.NAME_AMULET0)    # nazo
45
46     def alchemy_nazo_name(self, seed1, seed2):
47         u""" なぞの錬金
48         return (skill1_name, skill1_val, skill2_name, skill2_val, slot_num, type_name)
49         """
50         val = self.alchemy_nazo_id(seed1, seed2)
51         skill1_id, skill1_val, skill2_id, skill2_val, slot_num, type_name = val
52         if skill2_id in self._skill_id2name:
53             return (self._skill_id2name[skill1_id], skill1_val, 
54                     self._skill_id2name[skill2_id], skill2_val, slot_num, type_name)
55         else:
56             return (self._skill_id2name[skill1_id], skill1_val, u"", 0, slot_num, type_name)
57
58     def alchemy_komyou_id(self, seed1, seed2):
59         u""" 光明の錬金
60         return (skill1_id, skill1_val, skill2_id, skill2_val, slot_num, type_name)
61         """
62         gen_c = RandomGenerator(seed1) # generator C
63         gen_d = RandomGenerator(seed2) # generator D
64         return self._judge(gen_c, gen_d, mh4constnumbers.NAME_AMULET1)    # komyou
65
66     def alchemy_komyou_name(self, seed1, seed2):
67         u""" 光明の錬金
68         return (skill1_name, skill1_val, skill2_name, skill2_val, slot_num, type_name)
69         """
70         val = self.alchemy_komyou_id(seed1, seed2)
71         skill1_id, skill1_val, skill2_id, skill2_val, slot_num, type_name = val
72         if skill2_id in self._skill_id2name:
73             return (self._skill_id2name[skill1_id], skill1_val, 
74                     self._skill_id2name[skill2_id], skill2_val, slot_num, type_name)
75         else:
76             return (self._skill_id2name[skill1_id], skill1_val, u"", 0, slot_num, type_name)
77
78     def alchemy_inishie_id(self, seed1, seed2):
79         u""" いにしえの錬金
80         return (skill1_id, skill1_val, skill2_id, skill2_val, slot_num, type_name)
81         """
82         gen_c = RandomGenerator(seed1) # generator C
83         gen_d = RandomGenerator(seed2) # generator D
84         return self._judge(gen_c, gen_d, mh4constnumbers.NAME_AMULET2)    # inishie
85
86     def alchemy_inishie_name(self, seed1, seed2):
87         u""" いにしえの錬金
88         return (skill1_name, skill1_val, skill2_name, skill2_val, slot_num, type_name)
89         """
90         val = self.alchemy_inishie_id(seed1, seed2)
91         skill1_id, skill1_val, skill2_id, skill2_val, slot_num, type_name = val
92         if skill2_id in self._skill_id2name:
93             return (self._skill_id2name[skill1_id], skill1_val, 
94                     self._skill_id2name[skill2_id], skill2_val, slot_num, type_name)
95         else:
96             return (self._skill_id2name[skill1_id], skill1_val, u"", 0, slot_num, type_name)
97
98     def alchemy_tenun_id(self, seed1, seed2, alchemy_type):
99         u""" 天運の錬金 (古*3または歪*3限定。)
100         return list of (skill1_id, skill1_val, skill2_id, skill2_val, slot_num, type_name)
101         """
102         if alchemy_type == mh4constnumbers.KEY_TENUN555:
103             result_num_max = mh4constnumbers.TENUN555_MAX
104             result_num_min = mh4constnumbers.TENUN555_MIN
105             yuga_divisor = mh4constnumbers.TENUN555_DIVISOR
106         elif alchemy_type == mh4constnumbers.KEY_TENUN888:
107             result_num_max = mh4constnumbers.TENUN888_MAX
108             result_num_min = mh4constnumbers.TENUN888_MIN
109             yuga_divisor = mh4constnumbers.TENUN888_DIVISOR
110         else:
111             raise NotImplementedError(u"Irregular Alchemy Type!")
112
113         gen_a = RandomGenerator(seed1)  # generator A
114         gen_b = RandomGenerator(seed2)  # generator B
115
116         result_num = gen_a.get_next() % (result_num_max - result_num_min + 1) + result_num_min
117         result_list = []
118
119         for i in range(result_num):
120             s1 = gen_a.get_next()
121             s2 = gen_b.get_next()
122             amulet_type = s1 % yuga_divisor
123             if 0 <= amulet_type < 10:
124                 u""" 謎のお守り """
125                 amulet_name = mh4constnumbers.NAME_AMULET0
126             elif 10 <= amulet_type < 55:
127                 u""" 光るお守り """
128                 amulet_name = mh4constnumbers.NAME_AMULET1
129             elif 55 <= amulet_type < 85:
130                 u""" 古びたお守り """
131                 amulet_name = mh4constnumbers.NAME_AMULET2
132             elif 85 <= amulet_type < 100:
133                 u""" 歪んだお守り """
134                 amulet_name = mh4constnumbers.NAME_AMULET3
135             else:
136                 raise NotImplementedError(u"Divisor must be incorrect")
137
138             gen_c = RandomGenerator(s1) # generator C
139             gen_d = RandomGenerator(s2) # generator D
140
141             result_list.append(self._judge(gen_c, gen_d, amulet_name))
142         return result_list
143
144     def alchemy_tenun_name(self, seed1, seed2, alchemy_type):
145         u""" 天運の錬金(古*3または歪*3限定。)
146         return list of (skill1_name, skill1_val, skill2_name, skill2_val, slot_num, type_name)
147         """
148         result_list = []
149         result = self.alchemy_tenun_id(seed1, seed2, alchemy_type)
150         for skill1_id, skill1_val, skill2_id, skill2_val, slot_num, type_name in result:
151             if skill2_id in self._skill_id2name:
152                 result_list.append(
153                     (self._skill_id2name[skill1_id], skill1_val,
154                     self._skill_id2name[skill2_id], skill2_val, slot_num, type_name))
155             else:
156                 result_list.append((self._skill_id2name[skill1_id], skill1_val, u"", 0, slot_num, type_name))
157
158         return result_list
159
160     def _judge(self, gen_c, gen_d, amulet_name):
161         u""" 乱数生成器C,Dおよびお守りの種類から鑑定を行う
162         return (skill1_id, skill1_val, skill2_id, skill2_val, slot_num, type_name)
163         """
164         amulet_id = self._amu_name2id[amulet_name]
165         skill1_minmax, skill2_minmax = self._minmax_dict[amulet_id]
166         s1 = gen_c.get_next()    # for skill1 dicision
167         s1 %= len(skill1_minmax)    # skill1_pos
168         skill1_id = [x for i,x in enumerate(sorted(skill1_minmax.keys())) if i == s1][0]
169         min1, max1 = skill1_minmax[skill1_id]
170
171         x1 = gen_c.get_next()
172         x2 = gen_d.get_next()
173         skill1_val = (x1 ^ x2) % (max1 - min1 + 1) + min1 # XOR
174
175         y1 = gen_c.get_next()
176         y2 = gen_d.get_next()
177         border = mh4constnumbers.SKILL2_BORDER_DICT[amulet_name]
178
179         if (y1 ^ y2) % 100 >= border:   # decide skill2 to exist
180             s2 = gen_d.get_next()    # for skill2 dicision
181             s2 %= len(skill2_minmax)    # skill2_pos
182             skill2_id = [x for i,x in enumerate(sorted(skill2_minmax.keys())) if i == s2][0]
183             min2, max2 = skill2_minmax[skill2_id]
184
185             if min2 < 0:
186                 z0 = gen_c.get_next()
187             else:
188                 z0 = None
189
190             z1 = gen_c.get_next()
191             z2 = gen_d.get_next()
192             if min2 < 0 and z0 % 2 == 0:    # skill2 val is minus
193                 skill2_val = (z1 ^ z2) % (1 - min2) + min2
194             else:   # skill2 val is plus
195                 skill2_val = (z1 ^ z2) % max2 + 1
196
197             if skill2_id == skill1_id or skill2_val == 0:
198                 skill2_id = None
199                 skill2_val = 0
200         else:
201             skill2_id = None
202             skill2_val = 0
203
204         # slot number
205         if skill2_val <= 0:
206             suff_val = (skill1_val * 10) // max1
207         else:
208             suff_val = (skill1_val * 10) // max1 + (skill2_val * 10) // max2
209
210         w = gen_c.get_next()
211         if (w & mh4constnumbers.SEED_DECIDE_FLAG) != 0: # falg = 128, 50%
212             w2 = gen_c.get_next()
213         else:
214             w2 = gen_d.get_next()
215         _slot = w2 % 100
216
217         th1_slot, th2_slot, th3_slot = self._acc_suff.select_thresholds_by_id(amulet_id, suff_val)
218         if _slot < th1_slot:
219             slot_num = 0
220             slot_point = mh4constnumbers.SLOT_POINT0
221         elif th1_slot <= _slot < th2_slot:
222             slot_num = 1
223             slot_point = mh4constnumbers.SLOT_POINT1
224         elif th2_slot <= _slot < th3_slot:
225             slot_num = 2
226             slot_point = mh4constnumbers.SLOT_POINT2
227         elif th3_slot <= _slot:
228             slot_num = 3
229             slot_point = mh4constnumbers.SLOT_POINT3
230
231         type_name = self._decide_amulet_type(suff_val, slot_point, amulet_name)
232
233         return (skill1_id, skill1_val, skill2_id, skill2_val, slot_num, type_name)
234
235
236     def _decide_amulet_type(self, suff_val, slot_point, amulet_name):
237         u""" 鑑定結果の護石名を充足値、スロットポイント、お守り名から決定する """
238         type_val = suff_val + slot_point
239
240         border1, border2, border3 = mh4constnumbers.TYPE_BORDER_DICT[amulet_name]
241         if type_val >= border3[0]:
242             return border3[1]
243         elif type_val >= border2[0]:
244             return border2[1]
245         elif type_val >= border1[0]:    # 0
246             return border1[1]
247         else:
248             return None