PokerMasterDataProccesser.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. import datetime
  2. import json
  3. import logging
  4. from itertools import product
  5. # 所有的下注选项
  6. OPTIONS = [101, 102, 103, 301, 302, 303, 304, 305]
  7. TIMES_LIMIT = 10
  8. autoOutEnter = 0
  9. # 下注选项
  10. class BetOption:
  11. def __init__(self, option, odds, limit, total_bet=0):
  12. self.option = option
  13. if odds == 0:
  14. self.odds = 1
  15. else:
  16. self.odds = odds
  17. self.limitRed = limit
  18. self.total_bet = total_bet
  19. def to_json(self):
  20. return {'option': self.option, 'odds': self.odds, 'total_bet': self.total_bet}
  21. def __str__(self):
  22. return (f"BetOption(option={self.option}, odds={self.odds}, "
  23. f"limitRed={self.limitRed}, totalBet={self.total_bet})")
  24. class BetOptionEncoder(json.JSONEncoder):
  25. def default(self, obj):
  26. if isinstance(obj, BetOption):
  27. return obj.to_json() # Use the to_json method defined in BetOption.
  28. # Let the base class default method raise the TypeError
  29. return json.JSONEncoder.default(self, obj)
  30. # 用户信息
  31. class User:
  32. # 对应option的下注金额
  33. def __init__(self, bet_count, uid, amount):
  34. self.bet_count = bet_count
  35. self.uid = uid
  36. self.betAmount = amount
  37. self.finance = 0
  38. self.betOptionAmounts = {option: 0 for option in OPTIONS}
  39. class UserEncoder(json.JSONEncoder):
  40. def default(self, obj):
  41. if isinstance(obj, User):
  42. return {"uid": obj.uid, "bet_count": obj.bet_count, "betAmount": obj.betAmount, "finance": obj.finance}
  43. # 让基类的 default 方法抛出 TypeError
  44. return json.JSONEncoder.default(self, obj)
  45. def init_round_option_info():
  46. global round_option_info
  47. round_option_info = {option: BetOption(option, 0, 0) for option in OPTIONS}
  48. # 用于存储User对象的用户信息和次数,key为用户ID,value为User对象
  49. # round_user_betinfo = {}
  50. round_option_info = {}
  51. # 本轮选项赔率和下注金额
  52. init_round_option_info()
  53. # 庄家的钱
  54. banker_finance = 0
  55. # 虚拟一个用户,用来记录同步下来的下注数据,不然结算会异常,但是这样统计个人数据的时候,就会有点出入,
  56. # 没办法,因为会被定时踢出
  57. DATA_SYN_NOTIFY_UID = -9999
  58. async def write_message_2_log_file(log):
  59. with open("开奖记录.log", "a", encoding="utf-8") as f:
  60. time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
  61. f.write(f"{time}:{log}\n")
  62. async def deal_message(message, broadcast_func):
  63. try:
  64. msg_type, data = parse_message(message)
  65. if msg_type == "BetNotify":
  66. await betNotify(data)
  67. elif msg_type == "GameDataSynNotify":
  68. await gameDataSynNotify(data)
  69. elif msg_type == "ShowOddsNotify":
  70. await ShowOddsNotify(data)
  71. elif msg_type == "KickNotify":
  72. await kickNotify(data, broadcast_func)
  73. elif msg_type == "GameRoundEndNotify":
  74. await gameRoundEndNotify(data, broadcast_func)
  75. elif msg_type == "MergeAutoBetNotify":
  76. await MergeAutoBetNotify(data)
  77. else:
  78. logging.info(f"Received message: {message}")
  79. except Exception as e:
  80. logging.info(f"Received message: {message}")
  81. async def judge_auto_out_and_int(broadcast_func):
  82. global autoOutEnter, TIMES_LIMIT
  83. autoOutEnter += 1
  84. if autoOutEnter >= TIMES_LIMIT:
  85. autoOutEnter = 0
  86. await broadcast_func('''CMD:
  87. window.__require("PokerMasterHallSocket").PokerMasterHallSocket.getInstance().requestLeaveRoom();//立即退出
  88. setTimeout(function(){
  89. window.HMFExtension.openPokerMasterGameWithRoomId("716619","")
  90. },3000);//3秒后自动进入
  91. ''')
  92. async def gameRoundEndNotify(data, broadcast_func):
  93. global banker_finance
  94. await write_message_2_log_file(json.dumps(round_option_info, cls=BetOptionEncoder))
  95. await write_message_2_log_file(data)
  96. init_round_option_info()
  97. await judge_auto_out_and_int(broadcast_func)
  98. # 计算所有组合的可能性及其赔付金额
  99. async def win_option_combo_analysis(current_round_bet_amount, win_option):
  100. # 统计所有结果的可能性
  101. try:
  102. win_npc = {key: value for key, value in round_option_info.items() if key in [101, 102, 103]}
  103. win_card = {key: value for key, value in round_option_info.items() if key in [301, 302, 303, 304, 305]}
  104. # 计算所有组合的可能性及其赔付金额
  105. combinations = list(product(win_npc.keys(), win_card.keys()))
  106. # 计算每个组合的赔付金额
  107. combination_payouts = []
  108. for npc_key, card_key in combinations:
  109. npc_info = win_npc[npc_key]
  110. card_info = win_card[card_key]
  111. payout = (npc_info.odds * npc_info.total_bet) + (card_info.odds * card_info.total_bet)
  112. combination_payouts.append({
  113. "combo": f"{npc_key}x{card_key}",
  114. "payout": payout,
  115. "open": npc_key in win_option and card_key in win_option
  116. })
  117. # 按赔付金额排序
  118. sorted_combinations = sorted(combination_payouts, key=lambda x: x["payout"], reverse=True)
  119. # 输出排序后的组合和对应的赔付金额
  120. with open("庄家盈亏记录.txt", "a", encoding="utf-8") as f:
  121. label = f"{'标记':<4} {'组合':<10} {'赔付':<15} {'收入':<10}\n"
  122. print(label)
  123. f.write(label)
  124. for item in sorted_combinations:
  125. combo_key = item["combo"]
  126. payout = item["payout"]
  127. income = round((current_round_bet_amount - payout) / 100, 2)
  128. badge = "√" if item["open"] else "×"
  129. combos = f"{badge:<4} {combo_key:<10} {round(payout / 100, 2):<15}¥ {income:<10}¥\n"
  130. print(combos)
  131. f.write(combos)
  132. except Exception as e:
  133. print(e)
  134. # 庄家结算统计方法
  135. async def bankerSettlement(current_round_income, option_results):
  136. for open_result in option_results:
  137. # 开奖结果
  138. option = open_result["option"]
  139. result = open_result["result"]
  140. # 这个是下注的选项信息
  141. option_info_option_ = round_option_info[option]
  142. odds_rate = option_info_option_.odds
  143. if result == 1: # 证明这个选项中奖了
  144. # 庄家结算
  145. final_out = option_info_option_.total_bet * odds_rate
  146. current_round_income -= final_out
  147. print(
  148. f"选项{option}中奖了, 赔率{odds_rate}, 该选项总下注{round(option_info_option_.total_bet / 100, 2)}¥, 赔付了{round(final_out / 100, 2)}¥")
  149. return current_round_income
  150. # 玩家结算统计方法
  151. # async def playerSettlement(option_results):
  152. # # 玩家结算
  153. # try:
  154. # for user in round_user_betinfo.values():
  155. # for option in user.betOptionAmounts:
  156. # open_result = next(filter(lambda x: x["option"] == option, option_results))
  157. # odds_rate = round_option_info[option].odds
  158. # if open_result is not None and open_result["result"] == 1:
  159. # user.finance += user.betOptionAmounts[option] * odds_rate
  160. # else:
  161. # user.finance -= user.betOptionAmounts[option]
  162. # except Exception as e:
  163. # pass
  164. async def kickNotify(data, broadcast_func):
  165. print(f"被踢下线了: {data}")
  166. await broadcast_func('''CMD:
  167. setTimeout(function(){
  168. window.HMFExtension.openPokerMasterGameWithRoomId("716619","")
  169. lws.send("====>>>>被踢后3秒自动进入716619房间");
  170. },3000);//被踢后3秒后自动进入
  171. ''')
  172. async def ShowOddsNotify(data):
  173. # await write_message_2_log_file(data)
  174. option_odds = data["option_odds"]
  175. for optionInfo in option_odds:
  176. option_ = optionInfo["option"]
  177. odds_ = optionInfo["odds"] / 100
  178. limit_red_ = optionInfo["limitRed"]
  179. # 打印信息
  180. print(f"选项: {option_}, 赔率: {odds_}, 限红: {limit_red_}, 总下注: {0}")
  181. round_option_info[option_] = BetOption(option_, odds_, limit_red_, 0)
  182. async def gameDataSynNotify(data):
  183. # await write_message_2_log_file(data)
  184. # print(f"同步游戏数据: {data}")
  185. # sync_user = User(1, DATA_SYN_NOTIFY_UID, 0)
  186. for optionInfo in data["optionInfo"]:
  187. option_ = optionInfo["option"]
  188. odds_ = optionInfo["odds"] / 100
  189. limit_red_ = optionInfo["limitRed"]
  190. total_bet_ = optionInfo["totalBet"]
  191. # sync_user.betAmount += total_bet_
  192. # 打印信息
  193. print(f"同步下注选项: {option_}, 赔率: {odds_}, 限红: {limit_red_}, 总下注: {total_bet_}")
  194. round_option_info[option_] = BetOption(option_, odds_, limit_red_, total_bet_)
  195. # 虚拟用户,用来记录同步下来的下注数据,后续用于赔付
  196. # sync_user.betOptionAmounts[option_] = total_bet_
  197. # round_user_betinfo[DATA_SYN_NOTIFY_UID] = sync_user
  198. # 同步的数据应该包含了所有的下注选项,所以这里直接清空,但是这样统计个人数据的时候,就会有点出入
  199. # round_user_betinfo.clear()
  200. print(f"同步后下注信息:", list(map(lambda x: str(x), round_option_info.values())))
  201. async def MergeAutoBetNotify(data):
  202. print("收到合并通知")
  203. bet_notifys = data["notify"]
  204. for bet_notify in bet_notifys:
  205. await betNotify(bet_notify)
  206. async def betNotify(data):
  207. # {"uid":4174549,"detail":{"option":302,"betAmount":1000,"auto":false,"is_shot":false,"win_amt":0,"odds":0,"betGameCoin":0},"curCoin":767943,"selfBet":1000,"totalBet":67000,"curUsdt":0}
  208. # print(f"下注: {data}")
  209. # 获取用户ID
  210. uid = data["uid"]
  211. option = data["detail"]["option"]
  212. bet_amount = data["detail"]["betAmount"]
  213. # # # 获取用户信息
  214. # # user = round_user_betinfo.get(uid)
  215. # # if user is None:
  216. # # # 如果用户信息不存在,创建一个新的User对象
  217. # # user = User(0, "", 0)
  218. # # round_user_betinfo[uid] = user
  219. # # # 更新用户信息
  220. # # user.bet_count += 1
  221. # # user.uid = uid
  222. # # user.betAmount += bet_amount
  223. # # # 更新本轮下注选项的金额
  224. # user.betOptionAmounts[option] += bet_amount
  225. # 更新本轮全部选项的金额
  226. round_option_info[option].total_bet += bet_amount
  227. # print(f"用户{uid}下注次数: {user.bet_count}, 总金额: {user.betAmount}")
  228. # round_user_betinfo[uid] = user
  229. def parse_message(message):
  230. # 分割消息类型和JSON字符串
  231. msg_type, json_str = message.split(':', 1)
  232. # 将JSON字符串转换为字典
  233. data = json.loads(json_str)
  234. # 返回解析结果
  235. return msg_type, data