refactor model and skill constants
This commit is contained in:
51
mhapi/db.py
51
mhapi/db.py
@@ -2,48 +2,9 @@
|
|||||||
Module for accessing the sqlite monster hunter db from
|
Module for accessing the sqlite monster hunter db from
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import string
|
|
||||||
|
|
||||||
import sqlite3
|
import sqlite3
|
||||||
|
|
||||||
class Quest(object):
|
from mhapi import model
|
||||||
def __init__(self, quest_row, quest_rewards=None):
|
|
||||||
self._row = quest_row
|
|
||||||
self.rewards = quest_rewards
|
|
||||||
|
|
||||||
self._full_template = string.Template(
|
|
||||||
"$name ($hub $stars* $rank)"
|
|
||||||
"\n Goal: $goal"
|
|
||||||
"\n Sub : $sub_goal"
|
|
||||||
)
|
|
||||||
|
|
||||||
self._one_line_template = string.Template(
|
|
||||||
"$name ($hub $stars* $rank)"
|
|
||||||
)
|
|
||||||
|
|
||||||
self.id = quest_row["_id"]
|
|
||||||
self.name = quest_row["name"]
|
|
||||||
self.stars = quest_row["stars"]
|
|
||||||
self.hub = quest_row["hub"]
|
|
||||||
self.goal = quest_row["goal"]
|
|
||||||
self.sub_goal = quest_row["sub_goal"]
|
|
||||||
self.rank = quest_row["rank"]
|
|
||||||
self.location_id = quest_row["location_id"]
|
|
||||||
|
|
||||||
def is_multi_monster(self):
|
|
||||||
return (" and " in self.goal
|
|
||||||
or "," in self.goal
|
|
||||||
or " all " in self.goal)
|
|
||||||
|
|
||||||
def one_line_u(self):
|
|
||||||
return self._one_line_template.substitute(self.__dict__)
|
|
||||||
|
|
||||||
def full_u(self):
|
|
||||||
return self._full_template.substitute(self.__dict__)
|
|
||||||
|
|
||||||
def __unicode__(self):
|
|
||||||
return self.full_u()
|
|
||||||
|
|
||||||
|
|
||||||
class MHDB(object):
|
class MHDB(object):
|
||||||
def __init__(self, path, use_cache=True):
|
def __init__(self, path, use_cache=True):
|
||||||
@@ -204,7 +165,7 @@ class MHDB(object):
|
|||||||
for r in rows:
|
for r in rows:
|
||||||
quest_row = self.get_quest(r["quest_id"])
|
quest_row = self.get_quest(r["quest_id"])
|
||||||
rewards_rows = self.get_quest_rewards(r["quest_id"])
|
rewards_rows = self.get_quest_rewards(r["quest_id"])
|
||||||
quests.append(Quest(quest_row, rewards_rows))
|
quests.append(model.Quest(quest_row, rewards_rows))
|
||||||
|
|
||||||
return quests
|
return quests
|
||||||
|
|
||||||
@@ -238,3 +199,11 @@ class MHDB(object):
|
|||||||
""")
|
""")
|
||||||
|
|
||||||
return v
|
return v
|
||||||
|
|
||||||
|
def get_weapons(self):
|
||||||
|
v = self._get_memoized("weapons", """
|
||||||
|
SELECT * FROM weapons
|
||||||
|
LEFT JOIN items ON weapons._id = items._id
|
||||||
|
""")
|
||||||
|
|
||||||
|
return v
|
||||||
|
|||||||
57
mhapi/model.py
Normal file
57
mhapi/model.py
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
import string
|
||||||
|
import json
|
||||||
|
|
||||||
|
|
||||||
|
class RowModel(object):
|
||||||
|
def __init__(self, row):
|
||||||
|
self._row = row
|
||||||
|
self.id = row["_id"]
|
||||||
|
|
||||||
|
def __getattr__(self, name):
|
||||||
|
try:
|
||||||
|
return self._row[name]
|
||||||
|
except IndexError:
|
||||||
|
raise AttributeError("'%s' object has no attribute '%s'"
|
||||||
|
% (self.__class__.__name__, name))
|
||||||
|
|
||||||
|
def as_dict(self):
|
||||||
|
d = dict(self._row)
|
||||||
|
d["id"] = d["_id"]
|
||||||
|
del d["_id"]
|
||||||
|
return d
|
||||||
|
|
||||||
|
def as_json(self):
|
||||||
|
data = self.as_dict()
|
||||||
|
return json.dumps(data)
|
||||||
|
|
||||||
|
|
||||||
|
class Quest(RowModel):
|
||||||
|
_full_template = string.Template(
|
||||||
|
"$name ($hub $stars* $rank)"
|
||||||
|
"\n Goal: $goal"
|
||||||
|
"\n Sub : $sub_goal"
|
||||||
|
)
|
||||||
|
|
||||||
|
_one_line_template = string.Template(
|
||||||
|
"$name ($hub $stars* $rank)"
|
||||||
|
)
|
||||||
|
|
||||||
|
def __init__(self, quest_row, quest_rewards=None):
|
||||||
|
super(Quest, self).__init__(quest_row)
|
||||||
|
|
||||||
|
self.rewards = quest_rewards
|
||||||
|
|
||||||
|
def is_multi_monster(self):
|
||||||
|
return (" and " in self.goal
|
||||||
|
or "," in self.goal
|
||||||
|
or " all " in self.goal)
|
||||||
|
|
||||||
|
def one_line_u(self):
|
||||||
|
return self._one_line_template.substitute(self.as_dict())
|
||||||
|
|
||||||
|
def full_u(self):
|
||||||
|
return self._full_template.substitute(self.as_dict())
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
return self.full_u()
|
||||||
|
|
||||||
@@ -7,7 +7,8 @@ from __future__ import print_function
|
|||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
from mhapi import stats
|
from mhapi import stats
|
||||||
from mhapi.db import Quest
|
from mhapi.model import Quest
|
||||||
|
from mhapi.skills import LuckSkill, CapSkill, CarvingSkill
|
||||||
|
|
||||||
SKILL_CARVING = "carving"
|
SKILL_CARVING = "carving"
|
||||||
SKILL_CAP = "cap"
|
SKILL_CAP = "cap"
|
||||||
@@ -125,7 +126,7 @@ class QuestReward(object):
|
|||||||
self.skill_delta = 0
|
self.skill_delta = 0
|
||||||
self.evs = self._calculate_ev()
|
self.evs = self._calculate_ev()
|
||||||
|
|
||||||
def expected_value(self, luck_skill=stats.LUCK_SKILL_NONE,
|
def expected_value(self, luck_skill=LuckSkill.NONE,
|
||||||
cap_skill=None, carving_skill=None):
|
cap_skill=None, carving_skill=None):
|
||||||
return self.evs[luck_skill]
|
return self.evs[luck_skill]
|
||||||
|
|
||||||
@@ -140,8 +141,8 @@ class QuestReward(object):
|
|||||||
else:
|
else:
|
||||||
# variable reward, expected number of draws depends on luck skill
|
# variable reward, expected number of draws depends on luck skill
|
||||||
counts = [stats.quest_reward_expected_c(self.slot, skill)
|
counts = [stats.quest_reward_expected_c(self.slot, skill)
|
||||||
for skill in xrange(stats.LUCK_SKILL_NONE,
|
for skill in xrange(LuckSkill.NONE,
|
||||||
stats.LUCK_SKILL_AMAZING+1)]
|
LuckSkill.AMAZING+1)]
|
||||||
|
|
||||||
|
|
||||||
evs = [((count - self.fixed_rewards)
|
evs = [((count - self.fixed_rewards)
|
||||||
@@ -193,7 +194,7 @@ class QuestItemExpectedValue(object):
|
|||||||
return (len(self.slot_rewards["A"]) > 0
|
return (len(self.slot_rewards["A"]) > 0
|
||||||
or len(self.slot_rewards["B"]) > 0)
|
or len(self.slot_rewards["B"]) > 0)
|
||||||
|
|
||||||
def expected_value(self, luck_skill=stats.LUCK_SKILL_NONE,
|
def expected_value(self, luck_skill=LuckSkill.NONE,
|
||||||
cap_skill=None, carving_skill=None):
|
cap_skill=None, carving_skill=None):
|
||||||
return self.total_expected_values[luck_skill]
|
return self.total_expected_values[luck_skill]
|
||||||
|
|
||||||
@@ -262,8 +263,8 @@ class HuntReward(object):
|
|||||||
self.evs = self._calculate_evs()
|
self.evs = self._calculate_evs()
|
||||||
|
|
||||||
def expected_value(self, strategy, luck_skill=None,
|
def expected_value(self, strategy, luck_skill=None,
|
||||||
cap_skill=stats.CAP_SKILL_NONE,
|
cap_skill=CapSkill.NONE,
|
||||||
carving_skill=stats.CARVING_SKILL_NONE):
|
carving_skill=CarvingSkill.NONE):
|
||||||
if strategy == STRAT_CAP:
|
if strategy == STRAT_CAP:
|
||||||
if not self.cap:
|
if not self.cap:
|
||||||
return 0
|
return 0
|
||||||
@@ -292,6 +293,27 @@ class HuntReward(object):
|
|||||||
out.write(" " + " ".join("%0.2f" % i for i in self.evs[1:]))
|
out.write(" " + " ".join("%0.2f" % i for i in self.evs[1:]))
|
||||||
out.write("\n")
|
out.write("\n")
|
||||||
|
|
||||||
|
def as_data(self):
|
||||||
|
d = dict(condition=self.condition,
|
||||||
|
stack_size=self.stack_size,
|
||||||
|
percentage=self.percentage,
|
||||||
|
item_id=self.item_id,
|
||||||
|
cap=self.cap,
|
||||||
|
kill=self.kill,
|
||||||
|
shiny=self.shiny)
|
||||||
|
kill_ev = dict()
|
||||||
|
cap_ev = dict()
|
||||||
|
for skill in xrange(CarvingSkill.NONE, CarvingSkill.GOD+1):
|
||||||
|
kill_ev[CarvingSkill.name(skill)] = \
|
||||||
|
self.expected_value(STRAT_CAP, carving_skill=skill)
|
||||||
|
for skill in xrange(CapSkill.NONE, CapSkill.GOD+1):
|
||||||
|
cap_ev[CapSkill.name(skill)] = self.expected_value(STRAT_CAP,
|
||||||
|
cap_skill=skill)
|
||||||
|
|
||||||
|
d["kill_expected_value"] = kill_ev
|
||||||
|
d["cap_expected_value"] = cap_ev
|
||||||
|
return d
|
||||||
|
|
||||||
def _calculate_evs(self):
|
def _calculate_evs(self):
|
||||||
if self.condition == "Tail Carve":
|
if self.condition == "Tail Carve":
|
||||||
self.skill = SKILL_CARVING
|
self.skill = SKILL_CARVING
|
||||||
@@ -299,8 +321,8 @@ class HuntReward(object):
|
|||||||
self.kill = True
|
self.kill = True
|
||||||
counts = [
|
counts = [
|
||||||
1 + stats.carve_delta_expected_c(skill)
|
1 + stats.carve_delta_expected_c(skill)
|
||||||
for skill in xrange(stats.CARVING_SKILL_PRO,
|
for skill in xrange(CarvingSkill.PRO,
|
||||||
stats.CARVING_SKILL_GOD+1)
|
CarvingSkill.GOD+1)
|
||||||
]
|
]
|
||||||
elif self.condition == "Body Carve (Apparent Death)":
|
elif self.condition == "Body Carve (Apparent Death)":
|
||||||
# Gypceros fake death. Assume one carve, it's dangerous to try
|
# Gypceros fake death. Assume one carve, it's dangerous to try
|
||||||
@@ -315,8 +337,8 @@ class HuntReward(object):
|
|||||||
self.kill = True
|
self.kill = True
|
||||||
counts = [
|
counts = [
|
||||||
3 + stats.carve_delta_expected_c(skill)
|
3 + stats.carve_delta_expected_c(skill)
|
||||||
for skill in xrange(stats.CARVING_SKILL_PRO,
|
for skill in xrange(CarvingSkill.PRO,
|
||||||
stats.CARVING_SKILL_GOD+1)
|
CarvingSkill.GOD+1)
|
||||||
]
|
]
|
||||||
elif self.condition.startswith("Body Carve (KO"):
|
elif self.condition.startswith("Body Carve (KO"):
|
||||||
# Kelbi
|
# Kelbi
|
||||||
@@ -325,8 +347,8 @@ class HuntReward(object):
|
|||||||
self.kill = True
|
self.kill = True
|
||||||
counts = [
|
counts = [
|
||||||
1 + stats.carve_delta_expected_c(skill)
|
1 + stats.carve_delta_expected_c(skill)
|
||||||
for skill in xrange(stats.CARVING_SKILL_PRO,
|
for skill in xrange(CarvingSkill.PRO,
|
||||||
stats.CARVING_SKILL_GOD+1)
|
CarvingSkill.GOD+1)
|
||||||
]
|
]
|
||||||
elif "Carve" in self.condition:
|
elif "Carve" in self.condition:
|
||||||
# Mouth Carve: Dah'ren Mohran
|
# Mouth Carve: Dah'ren Mohran
|
||||||
@@ -340,8 +362,8 @@ class HuntReward(object):
|
|||||||
self.kill = True
|
self.kill = True
|
||||||
counts = [
|
counts = [
|
||||||
3 + stats.carve_delta_expected_c(skill)
|
3 + stats.carve_delta_expected_c(skill)
|
||||||
for skill in xrange(stats.CARVING_SKILL_PRO,
|
for skill in xrange(CarvingSkill.PRO,
|
||||||
stats.CARVING_SKILL_GOD+1)
|
CarvingSkill.GOD+1)
|
||||||
]
|
]
|
||||||
elif self.condition == "Capture":
|
elif self.condition == "Capture":
|
||||||
self.skill = SKILL_CAP
|
self.skill = SKILL_CAP
|
||||||
@@ -349,8 +371,8 @@ class HuntReward(object):
|
|||||||
self.kill = False
|
self.kill = False
|
||||||
counts = [
|
counts = [
|
||||||
stats.capture_reward_expected_c(skill)
|
stats.capture_reward_expected_c(skill)
|
||||||
for skill in xrange(stats.CAP_SKILL_NONE,
|
for skill in xrange(CapSkill.NONE,
|
||||||
stats.CAP_SKILL_GOD+1)
|
CapSkill.GOD+1)
|
||||||
]
|
]
|
||||||
elif self.condition == "Virus Reward":
|
elif self.condition == "Virus Reward":
|
||||||
# TODO: not sure how these work
|
# TODO: not sure how these work
|
||||||
@@ -394,9 +416,9 @@ class RankAndSkills(object):
|
|||||||
rank.
|
rank.
|
||||||
"""
|
"""
|
||||||
def __init__(self, rank="G",
|
def __init__(self, rank="G",
|
||||||
luck_skill=stats.LUCK_SKILL_NONE,
|
luck_skill=LuckSkill.NONE,
|
||||||
cap_skill=stats.CAP_SKILL_NONE,
|
cap_skill=CapSkill.NONE,
|
||||||
carving_skill=stats.CARVING_SKILL_NONE,
|
carving_skill=CarvingSkill.NONE,
|
||||||
explorer=False):
|
explorer=False):
|
||||||
self.rank = rank
|
self.rank = rank
|
||||||
self.luck_skill = luck_skill
|
self.luck_skill = luck_skill
|
||||||
@@ -600,8 +622,8 @@ class HuntItemExpectedValue(object):
|
|||||||
self._set_rewards(hunt_rewards)
|
self._set_rewards(hunt_rewards)
|
||||||
|
|
||||||
def expected_value(self, strategy, luck_skill=None,
|
def expected_value(self, strategy, luck_skill=None,
|
||||||
cap_skill=stats.CAP_SKILL_NONE,
|
cap_skill=CapSkill.NONE,
|
||||||
carving_skill=stats.CARVING_SKILL_NONE):
|
carving_skill=CarvingSkill.NONE):
|
||||||
ev = 0
|
ev = 0
|
||||||
for reward in self.matching_rewards:
|
for reward in self.matching_rewards:
|
||||||
ev += reward.expected_value(strategy,
|
ev += reward.expected_value(strategy,
|
||||||
@@ -620,6 +642,23 @@ class HuntItemExpectedValue(object):
|
|||||||
for hr in self.matching_rewards:
|
for hr in self.matching_rewards:
|
||||||
hr.print(out, indent)
|
hr.print(out, indent)
|
||||||
|
|
||||||
|
def as_data(self):
|
||||||
|
d = dict(monster_name=self.monster_name,
|
||||||
|
monster_rank=self.monster_rank,
|
||||||
|
rewards=[r.as_data() for r in self.matching_rewards])
|
||||||
|
kill_ev = dict()
|
||||||
|
cap_ev = dict()
|
||||||
|
for skill in xrange(CarvingSkill.NONE, CarvingSkill.GOD+1):
|
||||||
|
kill_ev[CarvingSkill.name(skill)] = \
|
||||||
|
self.expected_value(STRAT_CAP, carving_skill=skill)
|
||||||
|
for skill in xrange(CapSkill.NONE, CapSkill.GOD+1):
|
||||||
|
cap_ev[CapSkill.name(skill)] = self.expected_value(STRAT_CAP,
|
||||||
|
cap_skill=skill)
|
||||||
|
|
||||||
|
d["kill_expected_value"] = kill_ev
|
||||||
|
d["cap_expected_value"] = cap_ev
|
||||||
|
return d
|
||||||
|
|
||||||
def _set_rewards(self, rewards):
|
def _set_rewards(self, rewards):
|
||||||
for reward in rewards:
|
for reward in rewards:
|
||||||
if reward["item_id"] != self.item_id:
|
if reward["item_id"] != self.item_id:
|
||||||
@@ -658,13 +697,13 @@ class ItemRewards(object):
|
|||||||
RankAndSkills(rank)),
|
RankAndSkills(rank)),
|
||||||
|
|
||||||
("Capture God",
|
("Capture God",
|
||||||
RankAndSkills(rank, cap_skill=stats.CAP_SKILL_GOD)),
|
RankAndSkills(rank, cap_skill=CapSkill.GOD)),
|
||||||
|
|
||||||
("Carving God",
|
("Carving God",
|
||||||
RankAndSkills(rank, carving_skill=stats.CARVING_SKILL_GOD)),
|
RankAndSkills(rank, carving_skill=CarvingSkill.GOD)),
|
||||||
|
|
||||||
("Amazing Luck",
|
("Magnificent Luck",
|
||||||
RankAndSkills(rank, luck_skill=stats.LUCK_SKILL_AMAZING)),
|
RankAndSkills(rank, luck_skill=LuckSkill.AMAZING)),
|
||||||
])
|
])
|
||||||
if rank != "LR":
|
if rank != "LR":
|
||||||
self.rank_skill_sets[rank]["Explorer"] = \
|
self.rank_skill_sets[rank]["Explorer"] = \
|
||||||
@@ -776,11 +815,11 @@ class ItemRewards(object):
|
|||||||
kill_ev = [0, 0]
|
kill_ev = [0, 0]
|
||||||
kill_ev[0] = hunt_item.expected_value(STRAT_KILL)
|
kill_ev[0] = hunt_item.expected_value(STRAT_KILL)
|
||||||
kill_ev[1] = hunt_item.expected_value(STRAT_KILL,
|
kill_ev[1] = hunt_item.expected_value(STRAT_KILL,
|
||||||
carving_skill=stats.CARVING_SKILL_GOD)
|
carving_skill=CarvingSkill.GOD)
|
||||||
cap_ev = [0, 0]
|
cap_ev = [0, 0]
|
||||||
cap_ev[0] = hunt_item.expected_value(STRAT_CAP)
|
cap_ev[0] = hunt_item.expected_value(STRAT_CAP)
|
||||||
cap_ev[1] = hunt_item.expected_value(STRAT_CAP,
|
cap_ev[1] = hunt_item.expected_value(STRAT_CAP,
|
||||||
cap_skill=stats.CAP_SKILL_GOD)
|
cap_skill=CapSkill.GOD)
|
||||||
shiny_ev = hunt_item.expected_value(STRAT_SHINY)
|
shiny_ev = hunt_item.expected_value(STRAT_SHINY)
|
||||||
out.write(" %20s\n" % "= Totals")
|
out.write(" %20s\n" % "= Totals")
|
||||||
out.write(" %20s %s / 100\n"
|
out.write(" %20s %s / 100\n"
|
||||||
@@ -843,10 +882,10 @@ class ItemRewards(object):
|
|||||||
|
|
||||||
kill_ev[0] += hunt_item.expected_value(STRAT_KILL)
|
kill_ev[0] += hunt_item.expected_value(STRAT_KILL)
|
||||||
kill_ev[1] += hunt_item.expected_value(STRAT_KILL,
|
kill_ev[1] += hunt_item.expected_value(STRAT_KILL,
|
||||||
carving_skill=stats.CARVING_SKILL_GOD)
|
carving_skill=CarvingSkill.GOD)
|
||||||
cap_ev[0] += hunt_item.expected_value(STRAT_CAP)
|
cap_ev[0] += hunt_item.expected_value(STRAT_CAP)
|
||||||
cap_ev[1] += hunt_item.expected_value(STRAT_CAP,
|
cap_ev[1] += hunt_item.expected_value(STRAT_CAP,
|
||||||
cap_skill=stats.CAP_SKILL_GOD)
|
cap_skill=CapSkill.GOD)
|
||||||
shiny_ev = hunt_item.expected_value(STRAT_SHINY)
|
shiny_ev = hunt_item.expected_value(STRAT_SHINY)
|
||||||
|
|
||||||
if kill_ev[0] == 0 and cap_ev[0] == 0 and shiny_ev == 0:
|
if kill_ev[0] == 0 and cap_ev[0] == 0 and shiny_ev == 0:
|
||||||
|
|||||||
53
mhapi/skills.py
Normal file
53
mhapi/skills.py
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
|
||||||
|
|
||||||
|
class SkillEnum(object):
|
||||||
|
_names = dict()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def name(cls, skill_id):
|
||||||
|
return cls._names[skill_id]
|
||||||
|
|
||||||
|
|
||||||
|
class CapSkill(SkillEnum):
|
||||||
|
NONE = 0
|
||||||
|
EXPERT = 1
|
||||||
|
MASTER = 2
|
||||||
|
GOD = 3
|
||||||
|
|
||||||
|
_names = { NONE: "No skills",
|
||||||
|
EXPERT: "Capture Expert",
|
||||||
|
MASTER: "Capture Master",
|
||||||
|
GOD: "Capture God" }
|
||||||
|
|
||||||
|
|
||||||
|
class LuckSkill(SkillEnum):
|
||||||
|
NONE = 0
|
||||||
|
GOOD = 1
|
||||||
|
GREAT = 2
|
||||||
|
AMAZING = 3
|
||||||
|
|
||||||
|
_names = { NONE: "No skills",
|
||||||
|
GOOD: "Good Luck",
|
||||||
|
GREAT: "Great Luck",
|
||||||
|
AMAZING: "Magnificent Luck" }
|
||||||
|
|
||||||
|
|
||||||
|
class CarvingSkill(SkillEnum):
|
||||||
|
NONE = 0
|
||||||
|
PRO = 0 # prevent knockbacks but no extra carves
|
||||||
|
FELYNE_LOW = 1
|
||||||
|
FELYNE_HI = 2
|
||||||
|
CELEBRITY = 3
|
||||||
|
GOD = 4
|
||||||
|
|
||||||
|
_names = { NONE: "No skills",
|
||||||
|
FELYNE_LOW: "Felyne Carver Lo",
|
||||||
|
FELYNE_HI: "Felyne Carver Hi",
|
||||||
|
CELEBRITY: "Carving Celebrity",
|
||||||
|
GOD: "Carving God" }
|
||||||
|
|
||||||
|
|
||||||
|
QUEST_A = "A"
|
||||||
|
QUEST_B = "B"
|
||||||
|
QUEST_SUB = "Sub"
|
||||||
|
|
||||||
Reference in New Issue
Block a user