def game(self, debug=False): # print('Game #############') poker = Poker(1) poker.shuffle() pool = CardGroup() for player in self.players: player.clear() for _ in range(2): for player in self.players: player.append(poker.pop()) for _ in range(2): pool.append(poker.pop()) scores = {} for player in self.players: scores[player] = 0 for _ in range(3): pool.append(poker.pop()) values = {} values['min_score'] = 0 for player in self.players: score = player.step(values) if score > values['min_score']: scores[player] += score values['min_score'] = score elif score == values['min_score']: scores[player] += score win_player = None win_value = 0 for player in self.players: max_value, _ = self.max_value(player.get_cardgroup(), pool) if win_value < max_value: win_player = player win_value = max_value win_player.win(sum(scores.values()))
def main(): #create a poker object thePoker = Poker() #shuffle this poker thePoker.shuffle() for cards in thePoker.cards: cards.makeShowCase() #create a rule object #texasHoldem = Rule() #create new players players = [Player('东邪'), Player('西毒'), Player('南帝'), Player('北丐')] #for _ in range(5): for i in range(0, 5): for player in players: player.getCard(thePoker.next()) print("Cards before arrange: ") player.showCardsInHand() print("") #newArr = sorted(players,reverse=True) for player in players: #: arrange players' cardsInHand player.arrange() print("Cards after arrange: ") player.showCardsInHand() player.findType() player.ifFlushStraight() print("") newArr = sorted(players, reverse=True) for i in newArr: print(i.name + ': ' + i._cardsType, end=' ' + '\n') i.showCardsInHand() print('\n' + 'Winner is: ' + newArr[0].name + 'with ' + newArr[0]._cardsType)
class Referee(object): """游戏裁判""" def __init__(self, ret): from services import ServiceGame self.manager = ServiceGame.share() self.__flow = "" # 桌子日志 self.__tid = ret.tid self.__zid = ret.zid self.__round_id = ret.roundid self.__curr_seat_id = -1 self.__seats = [None] * TOTAL_SEAT self.__round_results = {} self.__is_dark = False # 最后一手下注的明暗状态 self.__last_bet = 0 # 最后一手下注的数量 self.__total_bet = 0 # 累积下注 self.__raise_rate = 0 # 当前的加注倍数 self.__round_count = 0 # 轮数 self.__wait_seconds = 0 # 临时等待玩家的时间秒数,用于比牌时播放动画 self.__game_wait_seconds = 0 # 等待开桌的计时 self.__button = -1 # 庄家ID self.__random_button = True # 随机庄家 self.__duel_dict = {0: set(), 1: set(), 2: set(), 3: set(), 4: set()} self.__winner = None # 最后的比牌赢家 self.__timer = None # 游戏的定时器 self.__poker = Poker() # 初始化扑克信息 self.__consume = self.manager.zone_consume_chip(self.__zid) # 消耗金币数 self.__base_chip = self.manager.zone_base_chip(self.__zid) # 基数 self.__limit_chip = self.manager.zone_limit_chip(self.__zid) # 最低筹码 self.__total_hands = self.manager.zone_total_hands(self.__zid) # 最高下注倍数 self.__status = TABLE_READY # 玩家之间的比牌详情 def duelers_init(self): for i in xrange(0, TOTAL_SEAT): self.__duel_dict[i].clear() self.__duel_dict[i].add(i) @property def status(self): return self.__status # 设置桌子状态 def set_status(self, status): self.__status = status self.play_log("set status: %d" % (status, )) @property def zid(self): return self.__zid @property def tid(self): return self.__tid @property def base_chip(self): return self.__base_chip @property def raise_rate(self): # 当前加注倍率 return self.__raise_rate # 寻找桌子内的空位 def search_empty_seat(self): for seatid in range(0, TOTAL_SEAT): if not self.__seats[seatid]: return seatid return -1 # 判断玩家是否在桌子内的流程 def in_table(self, uid): if uid <= 0: return False for seatid in range(0, TOTAL_SEAT): if self.__seats[seatid] and self.__seats[seatid].uid == uid: return True return False # 根据玩家uid来获得玩家的坐位ID def get_seatid(self, uid): for i in range(0, TOTAL_SEAT): if self.__seats[i] and self.__seats[i].uid == uid: return i return -1 # 扣除玩家税收,返回所扣到的总钱数 def tax(self, chip): if chip <= 0: return 0 tax_chip = 0 for seatid in range(0, TOTAL_SEAT): if not self.__seats[seatid] or self.__seats[seatid].status != player.IN_PLAYING: continue if 0 < self.__seats[seatid].setChipWithDB(chip, False): tax_chip += chip self.__seats[seatid].setDark(True) return tax_chip # 一局开始前下底注 def base_bet(self, chip): if chip <= 0: return 0 base_chip = 0 for seatid in range(0, TOTAL_SEAT): if not self.__seats[seatid] or self.__seats[seatid].status != player.IN_PLAYING: continue if self.__seats[seatid].bet(chip): base_chip += chip return base_chip # 通知所有的玩家开始游戏 def notify_game_start(self): for i in range(0, TOTAL_SEAT): p = self.__seats[i] if not p or p.status != player.IN_WAITING: continue p.onRoundStart() # 一位用户进入房间,收集房间信息并返回给客户端 def sit_down(self, p): if self.in_table(p.uid): seatid = self.get_seatid(p.uid) else: seatid = self.search_empty_seat() if seatid < 0: return ERR_SEAT_FULL self.__seats[seatid] = p # 玩家响应坐下,保存桌子ID,设置在线,清除手牌,保存坐位ID等操作 p.on_sit_down(self.__tid, seatid) self.manager.update_table_player_num(self.__zid, self.__tid, self.play_num) self.on_sit_down_success(p) return OK # 统计当前在房间的人数 @property def play_num(self): count = 0 for i in range(0, TOTAL_SEAT): if self.__seats[i]: count += 1 return count # 检查是否已经满足条件可以开始游戏 def check_start(self): if self.status == TABLE_READY and 3 <= self.play_num: # 可以开局 self.set_status(TABLE_START) DelayCall(1, self.game_start) else: # print 'CheckStart NOT IN START: ', self.status, self.play_num, self.GameWaitSeconds, self.__seats #Manager.debug(self.__zid, self.__tid) pass # 游戏开局 def game_start(self): self.manager.update_table_player_num(self.__zid, self.__tid, self.play_num) self.set_status(TABLE_PLAYING) self.clear_duel() self.clear_round_result() self.__winner = None self.__is_dark = True self.__last_bet = self.__base_chip self.__raise_rate = 0 self.__curr_seat_id = -1 self.__round_id += 1 self.__round_count = 0 self.__poker.shuffle() # 洗牌 self.duelers_init() # 比牌关系清除 self.notify_game_start() # 开局前通知玩家清理 self.tax(self.__consume) self.__total_bet = self.base_bet(self.__base_chip) self.__flow = '' # 清空打牌日志 self.select_button() # 选择庄家 self.play_log('Round %d start, Tax:%d, Button:%d' % (self.__round_id, self.__consume, self.__button)) self.send_cards() # 发牌 for seatid in range(0, TOTAL_SEAT): p = self.__seats[seatid] if not p or p.status != p.IN_PLAYING: continue send_data = [CONFIG.game_id, CMD_ROUND_START, self.__zid, self.__tid, self.__consume, self.__base_chip, self.__total_bet, self.__button] p.send(send_data) DelayCall(ROUND_START_SECONDS, self.turn_to_next, self.__button, True) # 选择庄家,第一轮是随机选庄 def select_button(self): if self.__random_button or 0 > self.__button or TOTAL_SEAT <= self.__button: self.__random_button = False self.__button = 0 ulist = [] # 集合 for i in xrange(0, TOTAL_SEAT): if self.__seats[i] and self.__seats[i].status == player.IN_PLAYING: ulist.append(i) if ulist and len(ulist) > 0: random.shuffle(ulist) self.__button = ulist[0] return self.__button # 发牌 def send_cards(self): for i in xrange(0, 3): for j in xrange(0, TOTAL_SEAT): if not self.__seats[j]: continue self.__seats[j].receiveCard(self.__poker.pop()) # 获得玩家可操作的动作 def get_play_actions(self, p): ret = list() ret.append(CMD_USER_LOOK) ret.append(CMD_USER_FOLD) if not p: return ret min_chip = self.calc_call_chip(p.is_dark) # 跟死自负 if p.uchip >= min_chip and p.total_bet / self.__base_chip < self.__total_hands: ret.append(CMD_USER_CALL) if self.__raise_rate < MAX_RAISE_RATE: ret.append(CMD_USER_RAISE) if self.can_duel: ret.append(CMD_USER_DUEL) return ret # 获得玩家的响应秒数 def get_user_seconds(self, seatid, is_begginer=False): seconds = FIRST_CALL_SECONDS if is_begginer else CALL_SECONDS user_seconds = self.__seats[seatid].roundSeconds seconds = user_seconds if user_seconds > 0 else seconds return seconds # 玩家开始接收动作 def turn_to_player(self, seatid, is_begginer=False): self.play_log('Turn to %d.' % (seatid, )) if not self.__seats[seatid]: self.play_log('user %d gone, turn to next next...' % (seatid, )) self.turn_to_next(seatid) return self.__seats[seatid].onTurnTo(self) seconds = self.get_user_seconds(seatid, is_begginer) actions = self.get_play_actions(self.__seats[seatid]) # 玩家可操作的动作 send_data = [CONFIG.game_id, CMD_TURN_TO_PLAYER, self.__zid, self.__tid, seatid, seconds, self.__round_count, actions] self.broad_cast(send_data) self.__timer = DelayCall(seconds, self.on_user_time_out, seatid) self.__curr_seat_id = seatid # 处理玩家超时 def on_user_time_out(self, seatid): self.__seats[seatid].incrTimeOutTimes() self.user_fold(self.__seats[seatid]) self.turn_to_next(seatid) # 检查是否合法的seatid @staticmethod def is_seatid(seat_id): return TOTAL_SEAT > seat_id >= 0 # 记录玩家比牌关系 def save_duel(self, seatid1, seatid2): if not self.is_seatid(seatid1) or not self.is_seatid(seatid2): return self.__duel_dict[seatid1].add(seatid2) self.__duel_dict[seatid1].add(seatid1) self.__duel_dict[seatid2].add(seatid1) self.__duel_dict[seatid2].add(seatid2) # 清除比牌关系列表 def clear_duel(self): for i in xrange(0, TOTAL_SEAT): self.__duel_dict[i].clear() # 随机挑选出一个比牌的玩家 def pick_enemy_random(self, uid): left_player = [] for i in xrange(0, TOTAL_SEAT): if not self.__seats[i]: continue if self.__seats[i].uid != uid and self.__seats[i].status == player.IN_PLAYING: left_player.append(i) if not left_player: return False return random.choice(left_player) # 执行玩家的动作 def do_user_action(self, p, cmd, ret): p.reset_time_out_times() # 玩家请求成功,重置超时次数 if cmd == CMD_USER_LOOK: # 看牌不算一个动作,所以返回false以防止转到下一玩家 self.user_check(p) return False elif cmd == CMD_USER_CALL: return self.user_call(p) elif cmd == CMD_USER_RAISE: if not ret or len(ret) != 3 or ret[2] < 1: self.manager.request_fail(p.uid, cmd, ERR_DATA_BROKEN) return False rate = ret[2] if rate not in RAISE_RATE_LIST: self.manager.request_fail(p.uid, cmd, ERR_DATA_BROKEN) return False if rate <= self.__raise_rate: self.manager.request_fail(p.uid, cmd, ERR_DATA_BROKEN) return False return self.user_raise(p, rate) elif cmd == CMD_USER_FOLD: return self.user_fold(p) elif cmd == CMD_USER_DUEL: if not ret or len(ret) != 3: self.manager.request_fail(p.uid, cmd, ERR_DATA_BROKEN) return False seatid = ret[2] if seatid < 0 or seatid >= TOTAL_SEAT: self.manager.request_fail(p.uid, cmd, ERR_SEAT_NOT_EXIST) return False p2 = self.__seats[seatid] if not p2: self.manager.request_fail(p.uid, cmd, ERR_USER_NOT_EXIST) return False return self.user_duel(p, p2) self.manager.request_fail(p.uid, cmd, ERR_ILLEGAL_OPERATION) return False # 处理玩家的游戏动作,包括看牌,下注/跟注,加注,弃牌,比牌,开牌 def deal_user_action(self, p, ret): cmd = ret[1] if self.status != TABLE_PLAYING: # 非游戏中不响应玩家游戏命令 return self.manager.request_fail(p.uid, cmd, ERR_NOT_IN_PLAYING) if self.__curr_seat_id != p.seatid: # 未轮到玩家 return self.manager.request_fail(p.uid, cmd, ERR_NOT_YOUR_TURN) if cmd not in self.get_play_actions(p): # 不允许进行的操作 return self.manager.request_fail(p.uid, cmd, ERR_ILLEGAL_OPERATION) if not self.do_user_action(p, cmd, ret): return self.turn_to_next(self.__curr_seat_id) # 下一个玩家继续 # 处理机器人的游戏动作 def deal_robot_action(self, robot, cmd, param1): if not self.do_user_action(robot, cmd, [CONFIG.game_id, cmd, param1]): return self.turn_to_next(self.__curr_seat_id) # 下一个玩家继续 # 玩家弃牌处理 def user_fold(self, p): if p.seatid == self.__curr_seat_id: # 只有当前玩家可以清除定时器 self.cancel() chip = p.total_bet # 玩家总下注 exp = 0 self.save_round_result(p.seatid, False, chip, exp) p.on_round_over(self, False, chip, exp, player.IN_FOLD) if p == self.__winner: self.__winner = None self.broad_cast([CONFIG.game_id, CMD_USER_FOLD, OK, p.seatid]) return True # 计算跟牌、下注所需要的筹码 def calc_call_chip(self, is_dark): if self.__is_dark == is_dark: return self.__last_bet if self.__is_dark and not is_dark: return self.__last_bet * 2 return self.__last_bet / 2 # 玩家下注/跟注 def user_call(self, p): chip = self.calc_call_chip(p.is_dark) if not p.bet(chip): self.manager.request_fail(p.uid, CMD_USER_CALL, ERR_CHIP_NOT_ENOUGH) return False self.__total_bet += chip self.save_bet(chip, p.is_dark) self.cancel() send_data = [CONFIG.game_id, CMD_USER_CALL, OK, p.seatid, int(p.is_dark), chip, self.__total_bet] self.broad_cast(send_data) return True # 玩家加注 def user_raise(self, p, rate): minchip = self.calc_call_chip(p.is_dark) chip = self.__base_chip * rate if not p.is_dark: chip *= 2 if chip < minchip: return self.user_call(p) if not p.bet(chip): self.manager.request_fail(p.uid, CMD_USER_RAISE, ERR_CHIP_NOT_ENOUGH) return False self.__raise_rate = rate self.__total_bet += chip self.save_bet(chip, p.is_dark) self.cancel() send_data = [CONFIG.game_id, CMD_USER_RAISE, OK, p.seatid, int(p.is_dark), chip, rate, self.__total_bet] self.broad_cast(send_data) return True # 返回当前可否进行比牌的操作 @property def can_duel(self): return self.__round_count >= 2 # 玩家比牌 # 第三轮及之后才可以比牌 def user_duel(self, p1, p2): if not self.can_duel or not p2: self.manager.request_fail( p1.uid, CMD_USER_DUEL, ERR_ROUND_THREE_NEEDED) return False return True # 玩家看牌动作 def user_check(self, p): p.set_dark(False) send_data = [CONFIG.game_id, CMD_USER_LOOK, OK, p.cards] p.send(send_data) # 广播玩家看牌 send_data = [CONFIG.game_id, CMD_LOOK_BC, p.seatid] self.broad_cast(send_data) return True # 获得最后剩余的玩家 def get_last_player(self): for i in xrange(0, TOTAL_SEAT): if not self.__seats[i]: continue if self.__seats[i].status == player.IN_PLAYING: return self.__seats[i] # 获得当局中没有被淘汰的玩家数量 @property def playing_num(self): count = 0 for i in xrange(0, TOTAL_SEAT): if self.__seats[i] and self.__seats[i].status == player.IN_PLAYING: count += 1 return count # 记录最后一玩家所下注以及是否暗注 def save_bet(self, chip, is_dark): self.__is_dark = is_dark self.__last_bet = chip # 保存玩家的结算结果,因为有的是弃牌,有的是比牌被K,而这些玩家可能中途就离开 def save_round_result(self, seatid, is_win, chip, exp): self.__round_results[seatid] = [seatid, int(is_win), chip, exp] def clear_round_result(self): self.__round_results.clear() # 获取玩家的手牌 def get_cards(self, seat_id): if not self.__seats[seat_id]: return [] return self.__seats[seat_id].cards # 检查是否累加游戏轮数 def check_round_count(self, seat_id): if seat_id == self.__button: DelayCall(0.1, self.incr_round_count) # 累加游戏轮数 def incr_round_count(self): self.__round_count += 1 # 获取下家的坐位ID def get_next_seatid(self, curr_seatid): for i in xrange(curr_seatid + 1, TOTAL_SEAT): self.check_round_count(i) if not self.__seats[i]: continue if self.__seats[i] and self.__seats[i].status == player.IN_PLAYING: return i for i in xrange(0, min(curr_seatid, TOTAL_SEAT)): self.check_round_count(i) if not self.__seats[i]: continue if self.__seats[i] and self.__seats[i].status == player.IN_PLAYING: return i return curr_seatid # 通知下一个玩家操作 def turn_to_next(self, curr_seatid, is_begginer=False): if self.status != TABLE_PLAYING: return if self.__wait_seconds > 0: DelayCall(self.__wait_seconds, self.turn_to_next, curr_seatid) self.__wait_seconds = 0 return if self.playing_num < 2: # 玩家数小于2,结算 self.check_out(self.get_winner()) return self.turn_to_player(self.get_next_seatid(curr_seatid), is_begginer) # 获得当前循环用户还剩余的时间,单位为秒 def left_seconds(self): return self.__timer.int_left_seconds # 取消定时器的定时操作 def cancel(self): if self.__timer: self.__timer.cancel() # 获得当前的胜者 def get_winner(self): if not self.__winner: return self.get_last_player() return self.__winner # 游戏结算 输赢加减钱 def check_out(self, winner): if self.status != TABLE_PLAYING: self.play_log("checkout error: not in playing. %d" % (self.status, )) return if not winner: self.play_log("checkout error: no winner") self.play_log("checkout") self.cancel() self.__round_count = 0 self.set_status(TABLE_CHECK_OUT) winchip = self.__total_bet if winner: self.save_round_result(winner.seatid, True, winchip, WIN_EXP) winner.on_round_over( self, True, winchip, WIN_EXP, player.IN_WAITING) self.__button = winner.seatid send_data = [CONFIG.game_id, CMD_CHECK_OUT, self.__zid, self.__tid, CHECKOUT_SECONDS] for i, data in self.__round_results.items(): send_data.append(data) self.clear_round_result() self.broad_cast(send_data) for seatid, duelers in self.__duel_dict.items(): # 通知底牌 if not duelers: continue p = self.__seats[seatid] if not p or p.isQuit or (not p.online): continue send_data = [ CONFIG.game_id, CMD_NOTIFY_CARDS, self.__zid, self.__tid] for i in duelers: ptmp = self.__seats[i] if not ptmp: continue attr_data = [i] attr_data.extend(ptmp.cards) send_data.append(attr_data) p.send(send_data) DelayCall(CHECKOUT_SECONDS, self.check_out_over) # 结算结束,修改桌子状态,清理钱不够的玩家,准备开始新一局 def check_out_over(self): if self.status != TABLE_CHECK_OUT: return self.set_status(TABLE_READY) self.quit_robot() # 退出多余的机器人 self.__winner = None for seat_id in xrange(0, TOTAL_SEAT): # 清理筹码不够的玩家出房间 p = self.__seats[seat_id] if not p: continue if p.isQuit: self.__seats[seat_id] = None continue p.setRoundSeconds(0) quit_type = 0 if p.uchip < self.__limit_chip: # 筹码不足退出 quit_type = 1 elif not p.online: # 离线则退出 quit_type = 2 elif p.timeOutTimes >= 2: # 超时两次则退出 quit_type = 3 if quit_type > 0 and seat_id == self.__button: self.__random_button = True if 0 < quit_type: self.manager.do_user_quit(p, self, quit_type) self.__seats[seat_id] = None else: p.setStatus(player.IN_WAITING) self.manager.update_table_player_num(self.__zid, self.__tid, self.play_num) self.update_game_wait_seconds() self.check_start() # 检查是否再开始游戏 # 退出房间内多余的机器人,一次只退一个 def quit_robot(self): if self.play_num <= 3: return for seatid in xrange(0, TOTAL_SEAT): # 清理多余的机器人出房间 p = self.__seats[seatid] if not p: continue if not p.isRobot: continue self.manager.deal_robot_quit(self, p) return # 发送当前房间内的已进入的玩家至某玩家 def send_players_in_table(self, to_player): for seatid in range(0, TOTAL_SEAT): if not self.__seats[seatid]: continue p = self.__seats[seatid] if p.isQuit: continue if p != to_player: data = self.manager.get_user_arrive_data(self.__zid, self.__tid, p) to_player.send(data) @property def game_wait_seconds(self): if self.status != TABLE_READY: return 0 return utils.timestamp() - self.__game_wait_seconds # 更新游戏桌子等待开始时间 def update_game_wait_seconds(self): self.__game_wait_seconds = utils.timestamp() # 玩家进入成功, 收到成功消息并收到其它玩家的数据, # 此处并不广播自己成功的消息,广播由manager来做 def on_sit_down_success(self, p): if not p or not self.in_table(p.uid): return if self.play_num <= 1 and self.status != TABLE_PLAYING: self.update_game_wait_seconds() send_data = [CONFIG.game_id, CMD_SIT_DOWN, self.__zid, self.__tid, p.uchip, p.seatid, p.status] p.send(send_data) self.__random_button = True self.send_players_in_table(p) self.user_re_connect(p) # 玩家断线重连 def user_re_connect(self, p): if self.status != TABLE_PLAYING: return cards = p.cards send_data = [CONFIG.game_id, CMD_RE_CONNECT, OK, self.__zid, self.__tid, self.__total_bet] actions = self.get_play_actions(self.__seats[self.__curr_seat_id]) send_data.extend([self.__button, self.__curr_seat_id, actions, self.left_seconds(), self.__base_chip, self.__raise_rate, self.__last_bet, self.__is_dark]) if p.is_dark: send_data.append([]) else: send_data.append(cards) for i in xrange(0, TOTAL_SEAT): ptmp = self.__seats[i] if not ptmp or ptmp.status < player.IN_PLAYING: continue send_data.append( [i, int(ptmp.isDark), ptmp.currBet, ptmp.status, p.total_bet]) p.send(send_data) p.set_online(True) # 玩家退出房间 def user_quit(self, p, reason=0): if not p or p.is_quit or not self.in_table(p.uid): return False self.play_log('user quit %d@%d when %d' % (p.uid, p.seatid, self.status)) if self.status == TABLE_PLAYING and p.status == player.IN_PLAYING: self.user_fold(p) if p.seatid == self.__curr_seat_id: self.turn_to_next(self.__curr_seat_id) self.broad_cast( [CONFIG.game_id, CMD_USER_QUIT, OK, p.uid, p.seatid, reason]) p.set_quit(True) self.__seats[p.seatid] = None return True # 桌子内广播 def broad_cast(self, data, not_to_uid=0): for x in range(0, TOTAL_SEAT): if not self.__seats[x]: continue p = self.__seats[x] if p.isQuit: continue if not p.online: # 广播时不包括已离线的玩家 continue if p.tid != self.__tid: # 不包括已进别的房间的玩家 continue if p.uid != not_to_uid: p.send(data) # 打牌日志 def play_log(self, log_data): self.__flow += log_data + "\n" utils.log(log_data, 'table_' + str(self.__tid) + '.log') # 返回当前机器人是否大过所有真人 def is_winner(self, robot): flag = True if not robot: pass for i in xrange(0, TOTAL_SEAT): p = self.__seats[i] if not p or p.status != player.IN_PLAYING or p.isRobot: continue # [c1, c2, c3] = robot.cards # [d1, d2, d3] = p.cards return flag