def n_card_strength(self, n: int):
        deck = Deck()
        for _ in range(100):
            deck.shuffle()
            cards = []
            for _ in range(n):
                cards += [deck.next()]

            correct_result = max(
                HandStrength.strength(*c)
                for c in combinations(cards, 5)).strength
            self.assertEqual(HoldemPoker.fast_max_strength(cards),
                             correct_result)
    def test_fast_hand_strength(self):

        cards = [Card('AS'), Card('8C'), Card('9D'), Card('2S'), Card('KD')]
        self.assertEqual(HoldemPoker.fast_hand_strength(cards),
                         Strength.Nothing)

        cards = [Card('AS'), Card('AC'), Card('9D'), Card('2S'), Card('KD')]
        self.assertEqual(HoldemPoker.fast_hand_strength(cards), Strength.Pair)

        cards = [Card('AS'), Card('AC'), Card('9D'), Card('9S'), Card('KD')]
        self.assertEqual(HoldemPoker.fast_hand_strength(cards), Strength.Pairs)

        cards = [Card('AS'), Card('KC'), Card('9D'), Card('9S'), Card('9H')]
        self.assertEqual(HoldemPoker.fast_hand_strength(cards), Strength.Set)

        cards = [Card('JS'), Card('QC'), Card('KD'), Card('9S'), Card('TH')]
        self.assertEqual(HoldemPoker.fast_hand_strength(cards),
                         Strength.Straight)

        cards = [Card('AS'), Card('8S'), Card('9S'), Card('2S'), Card('KS')]
        self.assertEqual(HoldemPoker.fast_hand_strength(cards), Strength.Flush)

        cards = [Card('AS'), Card('AC'), Card('9D'), Card('9S'), Card('9H')]
        self.assertEqual(HoldemPoker.fast_hand_strength(cards),
                         Strength.FullHouse)

        cards = [Card('AS'), Card('AH'), Card('9S'), Card('AC'), Card('AD')]
        self.assertEqual(HoldemPoker.fast_hand_strength(cards), Strength.Quad)

        cards = [Card('QS'), Card('8S'), Card('9S'), Card('JS'), Card('TS')]
        self.assertEqual(HoldemPoker.fast_hand_strength(cards),
                         Strength.StraightFlush)

        cards = [Card('QS'), Card('AS'), Card('KS'), Card('JS'), Card('TS')]
        self.assertEqual(HoldemPoker.fast_hand_strength(cards),
                         Strength.RoyalFlush)

        deck = Deck()
        for _ in range(100):
            deck.shuffle()
            cards = [
                deck.next(),
                deck.next(),
                deck.next(),
                deck.next(),
                deck.next()
            ]
            self.assertEqual(HoldemPoker.fast_hand_strength(cards),
                             HandStrength.strength(*cards).strength)
Example #3
0
    def create(res: BasePokerDecisionAnswer, money: int, pot: int, call: int,
               bb: int, step: Step, cards: CardsPair, board: Cards,
               players_on_table: int, players_active: int,
               players_not_moved: int) -> PokerDecision6:

        if money < 0:
            raise ValueError(f'Money must be > 0, gived {money}')

        if pot < 0:
            raise ValueError(f'Pot must be > 0, gived {pot}')

        if call < 0:
            raise ValueError(f'Call must be > 0, gived {call}')

        if bb < 0:
            raise ValueError(f'Big blinds must be > 0, gived {bb}')

        if pot <= call and step != Step.Preflop:
            raise ValueError(
                f'Pot must be > call, gived call {call} pot {pot}')

        if type(res) is not PokerDecisionAnswer3:
            raise ValueError(
                f'Result must ne instance of PokerDecisionAnswer, gived {res}')

        pr = HoldemPoker.probability(cards, board)
        strength = HandStrength.get_strength(cards, board)
        outs: float = HoldemPoker.calculate_outs(
            cards, board)[0] / HoldemPoker.MAX_OUTS

        des = PokerDecision6()
        des.set_answer(res)
        des.probability_to_win = pr
        des.my_money = money
        des.money_in_pot = pot
        des.money_to_call = call
        des.big_blind = bb

        if step == Step.Preflop:
            des.is_preflop = 1
        elif step == Step.Flop:
            des.is_flop = 1
        elif step == Step.Turn:
            des.is_turn = 1
        elif step == Step.River:
            des.is_river = 1
        else:
            raise ValueError('bad step', step)

        int_strength: int = strength.value
        if int_strength < 0:
            raise ValueError('strength is < 0', int_strength, strength)
        des.strength[int_strength] = 1

        rank: int = cards.first.rank.value - 2
        if rank < 0:
            raise ValueError('rank is < 0', rank, cards.first.rank)
        des.first[rank] = 1

        rank: int = cards.second.rank.value - 2
        if rank < 0:
            raise ValueError('rank is < 0', rank, cards.second.rank)
        des.second[rank] = 1

        if cards.suitability == Suitability.Suited:
            des.have_suited_cards = 1

        if players_on_table < 2 or players_on_table > 10:
            raise ValueError('bad players on table:', players_active)

        if players_active < 2 or players_active > 10:
            raise ValueError('bad players active:', players_active)

        if players_active > players_on_table:
            raise ValueError('bad players active:', players_active,
                             'with players on table:', players_on_table)

        if players_not_moved < 0 or players_not_moved >= players_active:
            raise ValueError('bad players not moved:', players_not_moved,
                             'with players active:', players_active)

        des.players_on_table[players_on_table - 2] = 1
        des.players_playing[players_on_table - 2] = 1
        des.players_not_moved[players_not_moved] = 1

        des.outs = outs

        return des
Example #4
0
    def end_game(self) -> None:

        Debug.table(
            f'Table {self.id} hand {self.board.hand}: cards - {self.board}')

        if self.players.count_in_game_players() == 1:

            if self.online:
                self.network.hand_results(self.board, [])
                sleep(Delay.HandResults)

            winner = max(p for p in self.players.in_game_players())
            winner.wins += winner.in_pot

            for player in self.players.all_players():
                if player != winner:
                    if winner.in_pot >= player.in_pot:
                        winner.wins += player.in_pot
                        player.in_pot = 0
                    else:
                        Debug.error('THERE IS SOME ERROR')

            self.give_money(winner)

        else:

            self.collect_pot()

            hand_results = []

            for player in self.players.in_game_players():

                player.hand = HandStrength.max_strength(player.cards.get() +
                                                        self.board.get())

                hand_results += [(player.hand, player, str(player.hand))]

                Debug.table(
                    f'Table {self.id} hand {self.board.hand}: '
                    f'{player.get_cards()}, {player.name} has {player.hand}')

            hand_results.sort(reverse=True, key=lambda x: x[0])

            if self.online:
                self.network.hand_results(self.board, hand_results)
                sleep(Delay.HandResults)

            while self.players.count_in_game_players() > 0:

                wins_hand = max(player.hand
                                for player in self.players.in_game_players())
                players_wins = [
                    p for p in self.players.in_game_players()
                    if p.hand == wins_hand
                ]
                count_winners = len(players_wins)

                Debug.table(
                    f"Table {self.id} hand {self.board.hand}: "
                    f"{', '.join(p.name for p in players_wins)} wins with {wins_hand}"
                )

                all_inners = [p for p in self.players.all_in_players()]
                undivided_money = 0

                if all_inners:
                    all_inners_wins = sorted(
                        [p for p in all_inners if p in players_wins],
                        key=lambda x: x.in_pot)

                    for player in all_inners_wins:

                        side_pot = player.in_pot
                        Debug.table(
                            f'Table {self.id} hand {self.board.hand}: '
                            f'{player.name} opened pot with {player.in_pot}')

                        for opponent in self.players.all_players():
                            if opponent != player:
                                give_away = min(player.in_pot, opponent.in_pot)
                                Debug.table(
                                    f'Table {self.id} hand {self.board.hand}: '
                                    f'{opponent.name} moved to pot {give_away}'
                                )
                                side_pot += give_away
                                opponent.in_pot -= give_away

                        win_for_everyone = side_pot / count_winners
                        if win_for_everyone % 1 != 0:
                            undivided_money = round(
                                (win_for_everyone % 1) * count_winners)

                        win_for_everyone = int(win_for_everyone)

                        if undivided_money > 0:

                            for lucky_man in self.players.sort_by_nearest_to_button(
                                    players_wins):
                                lucky_man.wins += 1
                                undivided_money -= 1

                                if undivided_money == 0:
                                    break

                        for winner in players_wins:
                            winner.wins += win_for_everyone
                            Debug.table(
                                f'Table {self.id} hand {self.board.hand}: '
                                f'{winner.name} took {winner.wins} money from pot'
                            )

                        self.give_money(player)

                        del players_wins[players_wins.index(player)]
                        count_winners -= 1

                if count_winners > 0:

                    main_pot = sum(p.in_pot for p in players_wins)
                    Debug.table(
                        f'Table {self.id} hand {self.board.hand}: '
                        f'{" ".join(p.name for p in players_wins)} opened main pot with '
                        f'{main_pot // len(players_wins)} each and sum {main_pot}'
                    )

                    for player in self.players.all_players():
                        if player not in players_wins:
                            Debug.table(
                                f'Table {self.id} hand {self.board.hand}: '
                                f'{player.name} move {player.in_pot} in main pot'
                            )
                            main_pot += player.in_pot
                            player.in_pot = 0
                            player.in_game = False

                    win_for_everyone = main_pot / count_winners
                    if win_for_everyone % 1 != 0:
                        undivided_money = round(
                            (win_for_everyone % 1) * count_winners)

                    win_for_everyone = int(win_for_everyone)

                    if undivided_money > 0:

                        for lucky_man in self.players.sort_by_nearest_to_button(
                                players_wins):
                            lucky_man.wins += 1
                            undivided_money -= 1

                            if undivided_money == 0:
                                break

                    for winner in players_wins:
                        Debug.table(
                            f'Table {self.id} hand {self.board.hand}: '
                            f'{winner.name} took {win_for_everyone} money from main pot'
                        )
                        winner.wins += win_for_everyone
                        self.give_money(winner)

                for player in self.players.in_game_players():
                    if player.in_pot == 0:
                        player.in_game = False

        self.print_result()

        if self.pot.money != 0:
            Debug.error('ERROR IN POT')
            raise ValueError(f"POT != 0 pot = {self.pot.money}")

        self.players.remove_losers(self.game)
        self.take_cards()

        for player in self.players.all_players():
            if player.in_pot != 0:
                raise ValueError(
                    f"POT != 0 on {player.name} POT = {player.in_pot}")

            if player.in_game:
                raise ValueError(f"{player.name} IN GAME AFTER ALL")

            if player.gived != 0:
                raise ValueError(
                    f"GIVED != 0 on {player.name} gived = {player.gived}")

            if player.wins != 0:
                raise ValueError(
                    f"WINS != 0 on {player.name} wins = {player.wins}")

        self.in_game = False
    def create(res: BasePokerDecisionAnswer,
               money: int,
               pot: int,
               call: int,
               bb: int,
               step: Step,
               cards: CardsPair,
               board: Cards) -> PokerDecision5:

        if money < 0:
            raise ValueError(f'Money must be > 0, gived {money}')

        if pot < 0:
            raise ValueError(f'Pot must be > 0, gived {pot}')

        if call < 0:
            raise ValueError(f'Call must be > 0, gived {call}')

        if bb < 0:
            raise ValueError(f'Big blinds must be > 0, gived {bb}')

        if pot <= call and step != Step.Preflop:
            raise ValueError(f'Pot must be > call, gived call {call} pot {pot}')

        if type(res) is not PokerDecisionAnswer3:
            raise ValueError(f'Result must ne instance of PokerDecisionAnswer, gived {res}')

        pr = HoldemPoker.probability(cards, board)
        strength = HandStrength.get_strength(cards, board)

        des = PokerDecision5()
        des.set_answer(res)
        des.probability_to_win = pr
        des.my_money = money
        des.money_in_pot = pot
        des.money_to_call = call
        des.big_blind = bb

        if step == Step.Preflop:
            des.is_preflop = 1
        elif step == Step.Flop:
            des.is_flop = 1
        elif step == Step.Turn:
            des.is_turn = 1
        elif step == Step.River:
            des.is_river = 1
        else:
            raise ValueError('bad step', step)

        int_strength: int = strength.value
        if int_strength < 0:
            raise ValueError('strength is < 0', int_strength, strength)
        des.strength[int_strength] = 1

        rank: int = cards.first.rank.value - 2
        if rank < 0:
            raise ValueError('rank is < 0', rank, cards.first.rank)
        des.first[rank] = 1

        rank: int = cards.second.rank.value - 2
        if rank < 0:
            raise ValueError('rank is < 0', rank, cards.second.rank)
        des.second[rank] = 1

        if cards.suitability == Suitability.Suited:
            des.have_suited_cards = 1

        return des
    def create(res: BasePokerDecisionAnswer,
               money: int,
               pot: int,
               call: int,
               bb: int,
               step: Step,
               cards: CardsPair,
               board: Cards) -> PokerDecision4:

        if money < 0:
            raise ValueError(f'Money must be > 0, gived {money}')

        if pot < 0:
            raise ValueError(f'Pot must be > 0, gived {pot}')

        if call < 0:
            raise ValueError(f'Call must be > 0, gived {call}')

        if bb < 0:
            raise ValueError(f'Big blinds must be > 0, gived {bb}')

        if pot <= call and step != Step.Preflop:
            raise ValueError(f'Pot must be > call, gived call {call} pot {pot}')

        if type(res) is not PokerDecisionAnswer3:
            raise ValueError(f'Result must ne instance of PokerDecisionAnswer, gived {res}')

        pr = HoldemPoker.probability(cards, board)
        strength = HandStrength.get_strength(cards, board)

        des = PokerDecision4()
        des.set_answer(res)
        des.probability_to_win = pr
        des.my_money = money
        des.money_in_pot = pot
        des.money_to_call = call
        des.big_blind = bb

        if step == Step.Preflop:
            des.is_preflop = 1
        elif step == Step.Flop:
            des.is_flop = 1
        elif step == Step.Turn:
            des.is_turn = 1
        elif step == Step.River:
            des.is_river = 1
        else:
            raise ValueError('bad step', step)

        if strength == Strength.RoyalFlush:
            des.have_royal_flush = 1
        elif strength == Strength.StraightFlush:
            des.have_straight_flush = 1
        elif strength == Strength.Quad:
            des.have_quad = 1
        elif strength == Strength.FullHouse:
            des.have_full_house = 1
        elif strength == Strength.Flush:
            des.have_flush = 1
        elif strength == Strength.Straight:
            des.have_straight = 1
        elif strength == Strength.Set:
            des.have_set = 1
        elif strength == Strength.Pairs:
            des.have_two_pairs = 1
        elif strength == Strength.Pair:
            des.have_pair = 1
        elif strength == Strength.Nothing:
            des.have_nothing = 1
        else:
            raise ValueError('bad hand strength', strength)

        return des
Example #7
0
    def convert(self) -> None:

        if not exists('games'):
            mkdir('games')

        if not exists('games/converted'):
            mkdir('games/converted')

        current_date = datetime.now()

        if self.date == '' or self.time == '':
            date = current_date.strftime('%Y/%m/%d')
            time = current_date.strftime('%H:%M:%S')
        else:
            date = self.date
            time = self.time

        year, month, day = date.split('/')

        if len(month) == 1:
            month = '0' + month
        if len(day) == 1:
            day = '0' + day

        hour, minute, second = time.split(':')

        if len(hour) == 1:
            hour = '0' + hour
        if len(minute) == 1:
            minute = '0' + minute
        if len(second) == 1:
            second = '0' + second

        folder_name = f'{year}-{month}-{day}_{hour}-{minute}-{second} 1 {self.seats} {len(self.hands)} {self.name}'
        folder_name = folder_name.strip()

        Debug.parser(f'Converting {folder_name}')

        path = PokerGame.path_to_converted_games + PokerGame.converted_games_folder + '/' + folder_name
        chat_path = PokerGame.path_to_converted_games + PokerGame.converted_chat_folder + '/' + folder_name

        if exists(path):
            rmtree(path)

        if exists(chat_path):
            rmtree(chat_path)

        table_folder = f'/0 {len(self.hands)}'

        path += table_folder

        makedirs(path)
        makedirs(chat_path)

        time = datetime(int(year), int(month), int(day), int(hour),
                        int(minute), int(second), 0)
        network = BaseNetwork()
        chat_messages: List[Tuple[datetime, str]] = []

        for num, hand in enumerate(self.hands):
            converted: List[Tuple[datetime, str]] = []
            hand.switch_to_step(Step.Preflop)
            events: Iterator[Event] = iter(hand.curr_events)

            game = Game(0, self.seats, self.seats, 0)
            table = game.final_table
            table.is_final = hand.is_final

            table.id = hand.table_id
            table.players.total_seats = self.seats
            table.board.hand = num + 1
            table.blinds.ante = hand.ante
            table.blinds.small_blind = hand.small_blind
            table.blinds.big_blind = hand.big_blind

            game.average_stack = int(
                mean(player.money for player in hand.players))
            game.players_left = hand.players_left

            players: List[Player] = []
            find: Dict[int, Player] = dict()

            for seat in range(1, self.seats + 1):

                player = sorted(player for player in hand.players
                                if player.seat == seat)
                if not player:
                    player = None
                elif len(player) == 1:
                    player = player[0]
                else:
                    raise ValueError('Two players with same seat')

                if player is not None:
                    new_player = DummyPlayer(player.seat, player.name,
                                             player.money)
                    new_player.in_game = True
                    new_player.cards = player.cards
                    players += [new_player]
                    find[player.seat] = new_player
                else:
                    players += [None]

            game.top_9 = sorted([p for p in players if p is not None],
                                key=lambda p: p.money,
                                reverse=True)
            table.players.players = players

            json_message = loads(network.init_hand(None, table, game))
            for curr in json_message['players']:
                if curr['id'] is not None:
                    pl = max(pl for pl in hand.players
                             if pl.seat == curr['id'])
                    curr['disconnected'] = not pl.is_active
                else:
                    curr['disconnected'] = False
            init_message = dumps(json_message)

            converted += [(time, init_message)]
            time = time + timedelta(seconds=Delay.InitHand)

            converted += [(time, network.deal_cards())]
            time = time + timedelta(seconds=0)

            converted += [(time, network.open_cards(table))]
            time = time + timedelta(seconds=Delay.DealCards)

            event = next(events)

            if hand.ante > 0:

                paid: List[Tuple[Player, int]] = []
                while event.event == Event.Ante:
                    try:
                        paid += [(find[event.player.seat], event.money)]
                    except KeyError:
                        pass
                    event = next(events)

                converted += [(time, network.ante(paid))]
                time = time + timedelta(seconds=Delay.Ante)

                converted += [(time, network.collect_money())]
                time = time + timedelta(seconds=Delay.CollectMoney)

            try:
                button: Player = find[hand.button_seat]
            except KeyError:
                continue

            blinds_info: List[Tuple[Player, int]] = []

            if event.event == Event.SmallBlind:
                try:
                    blinds_info += [(find[event.player.seat], event.money)]
                except KeyError:
                    pass
                event = next(events)

            if event.event == Event.BigBlind:
                try:
                    blinds_info += [(find[event.player.seat], event.money)]
                except KeyError:
                    pass
                event = next(events)

            converted += [(time, network.blinds(button, blinds_info))]
            time = time + timedelta(seconds=Delay.Blinds)

            if hand.sit_during_game:

                for player in hand.sit_during_game:
                    converted += [(time,
                                   network.add_player(
                                       DummyPlayer(player.seat, player.name,
                                                   player.money),
                                       player.seat - 1))]
                    time = time + timedelta(seconds=Delay.AddPlayer)

            avoid_in_first_iteration = True
            need_to_collect_money = True

            while True:

                if hand.curr_step == Step.River:
                    break

                elif not avoid_in_first_iteration:

                    hand.next_step()

                    need_to_continue = False

                    if hand.curr_step == Step.Flop and \
                            hand.board.flop1 is not None and \
                            hand.board.flop2 is not None and \
                            hand.board.flop3 is not None:
                        converted += [(time,
                                       network.flop(hand.board.flop1,
                                                    hand.board.flop2,
                                                    hand.board.flop3))]
                        time = time + timedelta(seconds=Delay.Flop)
                        need_to_continue = True

                    elif hand.curr_step == Step.Turn and hand.board.turn is not None:
                        converted += [(time, network.turn(hand.board.turn))]
                        time = time + timedelta(seconds=Delay.Turn)
                        need_to_continue = True

                    elif hand.curr_step == Step.River and hand.board.river is not None:
                        converted += [(time, network.river(hand.board.river))]
                        time = time + timedelta(seconds=Delay.River)
                        need_to_continue = True

                    events = iter(hand.curr_events)

                    try:
                        event: PokerEvent = next(events)
                    except StopIteration:
                        if need_to_continue:
                            continue
                        else:
                            break

                else:
                    avoid_in_first_iteration = False

                while True:

                    need_continue = True
                    while need_continue:
                        try:
                            _ = find[event.player.seat]
                        except KeyError:
                            try:
                                event = next(events)
                            except StopIteration:
                                need_continue = False
                            else:
                                continue
                        except AttributeError:
                            break
                        else:
                            break
                    else:
                        break

                    if event.event == Event.Fold or \
                            event.event == Event.Check or \
                            event.event == Event.Call or \
                            event.event == Event.Raise or \
                            event.event == Event.Allin:

                        if event.event == Event.Call or \
                                event.event == Event.Raise or \
                                event.event == Event.Allin:
                            need_to_collect_money = True

                        player = find[event.player.seat]
                        player.gived = event.money

                        converted += [(time, network.switch_decision(player))]
                        time = time + timedelta(seconds=Delay.SwitchDecision +
                                                Delay.DummyMove)

                        converted += [
                            (time,
                             network.made_decision(player,
                                                   event.event.to_result()))
                        ]
                        time = time + timedelta(seconds=Delay.MadeDecision)

                    elif event.event == Event.WinMoney:

                        if need_to_collect_money:
                            converted += [(time, network.collect_money())]
                            time = time + timedelta(seconds=Delay.CollectMoney)
                            need_to_collect_money = False

                        converted += [
                            (time,
                             network.give_money(find[event.player.seat],
                                                event.money))
                        ]
                        time = time + timedelta(seconds=Delay.GiveMoney)

                    elif event.event == Event.ReturnMoney:

                        if sum(e.event == Event.Allin or e.event == Event.Raise
                               or e.event == Event.Call or e.event ==
                               Event.SmallBlind or e.event == Event.BigBlind
                               for e in hand.curr_events) == 1:
                            need_to_collect_money = False

                        converted += [
                            (time,
                             network.back_excess_money(find[event.player.seat],
                                                       event.money))
                        ]
                        time = time + timedelta(seconds=Delay.ExcessMoney)

                    elif event.event == Event.ChatMessage:

                        chat_message = network.send({
                            'type':
                            'chat',
                            'text':
                            f'{event.player.name}: {event.message}'
                        })

                        converted += [(time, chat_message)]
                        chat_messages += [(time, chat_message)]

                        time = time + timedelta(seconds=0)

                    elif event.event == Event.ObserverChatMessage:

                        chat_message = network.send({
                            'type':
                            'chat',
                            'text':
                            f'{event.player.name} [observer]: {event.message}'
                        })

                        converted += [(time, chat_message)]
                        chat_messages += [(time, chat_message)]

                        time = time + timedelta(seconds=0)

                    elif event.event == Event.Disconnected:

                        converted += [(time,
                                       network.send({
                                           'type': 'disconnected',
                                           'id': event.player.seat
                                       }))]
                        time = time + timedelta(seconds=0)

                        chat_message = network.send({
                            'type':
                            'chat',
                            'text':
                            f'{event.player.name} disconnected'
                        })

                        converted += [(time, chat_message)]
                        chat_messages += [(time, chat_message)]

                        time = time + timedelta(seconds=0)

                    elif event.event == Event.Connected:

                        converted += [(time,
                                       network.send({
                                           'type': 'connected',
                                           'id': event.player.seat
                                       }))]
                        time = time + timedelta(seconds=0)

                        chat_message = network.send({
                            'type':
                            'chat',
                            'text':
                            f'{event.player.name} connected'
                        })

                        converted += [(time, chat_message)]
                        chat_messages += [(time, chat_message)]

                        time = time + timedelta(seconds=0)

                    elif event.event == Event.FinishGame:

                        if event.money == 0:
                            chat_message = network.send({
                                'type':
                                'chat',
                                'text':
                                f'{event.player.name} finished {event.message}'
                            })

                        else:
                            chat_message = network.send({
                                'type':
                                'chat',
                                'text':
                                f'{event.player.name} '
                                f'finished {event.message} and get '
                                f'${event.money // 100}.{event.money % 100}'
                            })

                        converted += [(time, chat_message)]
                        chat_messages += [(time, chat_message)]

                        time = time + timedelta(seconds=0)

                        if event.message != '1st':
                            converted += [(time,
                                           network.delete_player(
                                               find[event.player.seat]))]
                            time = time + timedelta(seconds=Delay.DeletePlayer)

                    else:
                        raise ValueError(f'Undefined event id {event.event}')

                    need_continue = True
                    while need_continue:
                        try:
                            event = next(events)
                            _ = find[event.player.seat]
                        except StopIteration:

                            time = time + timedelta(seconds=Delay.EndOfRound)

                            if need_to_collect_money:
                                converted += [(time, network.collect_money())]
                                time = time + timedelta(
                                    seconds=Delay.CollectMoney)
                                need_to_collect_money = False

                            need_continue = False

                        except KeyError:
                            continue

                        except AttributeError:
                            break

                        else:
                            break

                    else:
                        break

            results: List[Tuple[Hand, Player, str]] = []

            for player in hand.players:
                if player.cards is not None:
                    if hand.board.state == Step.Preflop:
                        if not player.cards.initialized():
                            curr_hand = HandStrength.strength1(
                                player.cards.first)
                        else:
                            curr_hand = HandStrength.strength2(
                                player.cards.first, player.cards.second)

                    elif hand.board.state == Step.Flop:
                        if not player.cards.initialized():
                            curr_hand = HandStrength.strength4(
                                player.cards.first, hand.board.flop1,
                                hand.board.flop2, hand.board.flop3)
                        else:
                            curr_hand = HandStrength.strength(
                                player.cards.first, player.cards.second,
                                hand.board.flop1, hand.board.flop2,
                                hand.board.flop3)

                    else:
                        cards = hand.board.get()

                        if not player.cards.initialized():
                            cards += [player.cards.first]
                        else:
                            cards += [player.cards.first, player.cards.second]

                        curr_hand = HandStrength.max_strength(cards)

                    try:
                        results += [(curr_hand, find[player.seat], '')]
                    except KeyError:
                        pass

            results.sort(reverse=True, key=lambda x: x[0].safe_value)

            converted += [(time, network.hand_results(hand.board, results))]
            time = time + timedelta(seconds=Delay.HandResults)

            converted += [(time, network.clear())]
            time = time + timedelta(seconds=Delay.Clear)

            output = ''

            for d, s in converted:
                output += '%s %s %s %s %s %s %s' % (d.year, d.month, d.day,
                                                    d.hour, d.minute, d.second,
                                                    d.microsecond)
                output += '\n'
                output += s
                output += '\n'

            open(path + '/%s' % (num, ), 'w').write(output)

        chat_output = ''

        for d, s in chat_messages:
            chat_output += '%s %s %s %s %s %s %s' % (d.year, d.month, d.day,
                                                     d.hour, d.minute,
                                                     d.second, d.microsecond)
            chat_output += '\n'
            chat_output += s
            chat_output += '\n'

        open(chat_path + table_folder, 'w').write(chat_output)
    def create(res: BasePokerDecisionAnswer, money: int, pot: int, call: int,
               bb: int, step: Step, cards: CardsPair, board: Cards,
               players_on_table: int, players_active: int,
               players_not_moved: int, max_playing_stack: int,
               average_stack_on_table: int, players: List[MockPlayer],
               folded_players: List[str],
               my_position: PokerPosition) -> PokerDecision10:

        if money < 0:
            raise ValueError(f'Money must be > 0, gived {money}')

        if pot < 0:
            raise ValueError(f'Pot must be > 0, gived {pot}')

        if call < 0:
            raise ValueError(f'Call must be > 0, gived {call}')

        if bb < 0:
            raise ValueError(f'Big blinds must be > 0, gived {bb}')

        if pot <= call and step != Step.Preflop:
            raise ValueError(
                f'Pot must be > call, gived call {call} pot {pot}')

        if type(res) is not PokerDecisionAnswer3:
            raise ValueError(
                f'Result must ne instance of PokerDecisionAnswer, gived {res}')

        pr = HoldemPoker.probability(cards, board)
        strength = HandStrength.get_strength(cards, board)
        outs: float = HoldemPoker.calculate_outs(
            cards, board)[0] / HoldemPoker.MAX_OUTS

        des = PokerDecision10()
        des.set_answer(res)
        des.probability_to_win = pr
        des.my_money = money
        des.money_in_pot = pot
        des.money_to_call = call
        des.big_blind = bb

        if step == Step.Preflop:
            des.is_preflop = 1
        elif step == Step.Flop:
            des.is_flop = 1
        elif step == Step.Turn:
            des.is_turn = 1
        elif step == Step.River:
            des.is_river = 1
        else:
            raise ValueError('bad step', step)

        int_strength: int = strength.value
        if int_strength < 0:
            raise ValueError('strength is < 0', int_strength, strength)
        des.strength[int_strength] = 1

        rank: int = cards.first.rank.value - 2
        if rank < 0:
            raise ValueError('rank is < 0', rank, cards.first.rank)
        des.first[rank] = 1

        rank: int = cards.second.rank.value - 2
        if rank < 0:
            raise ValueError('rank is < 0', rank, cards.second.rank)
        des.second[rank] = 1

        if cards.suitability == Suitability.Suited:
            des.have_suited_cards = 1

        if players_on_table < 2 or players_on_table > 10:
            raise ValueError('bad players on table:', players_active)

        if players_active < 2 or players_active > 10:
            raise ValueError('bad players active:', players_active)

        if players_active > players_on_table:
            raise ValueError('bad players active:', players_active,
                             'with players on table:', players_on_table)

        if players_not_moved < 0 or players_not_moved >= players_active:
            raise ValueError('bad players not moved:', players_not_moved,
                             'with players active:', players_active)

        des.players_on_table[players_on_table - 2] = 1
        des.players_playing[players_on_table - 2] = 1
        des.players_not_moved[players_not_moved] = 1

        des.outs = outs

        des.max_playing_stack = max_playing_stack
        des.average_stack_on_table = average_stack_on_table

        curr_raisers: Dict[Tuple[str, PokerPosition],
                           PlayerStatistics] = PokerDecision10.CurrRaisers
        curr_callers: Dict[Tuple[str, PokerPosition],
                           PlayerStatistics] = PokerDecision10.CurrCallers
        curr_folders: Dict[Tuple[str, PokerPosition],
                           PlayerStatistics] = PokerDecision10.CurrFolders
        curr_checkers: Dict[Tuple[str, PokerPosition],
                            PlayerStatistics] = PokerDecision10.CurrCheckers

        raisers = []
        callers = []
        folders = []
        checkers = []
        for player in players:
            if player.name not in folded_players:
                raisers += [
                    curr_raisers[player.name, player.position].get_stats()
                ]
                callers += [
                    curr_callers[player.name, player.position].get_stats()
                ]
                folders += [
                    curr_folders[player.name, player.position].get_stats()
                ]
                checkers += [
                    curr_checkers[player.name, player.position].get_stats()
                ]

        des.max_raiser = max(raisers)
        des.min_raiser = min(raisers)
        des.avg_raiser = mean(raisers)

        des.max_caller = max(callers)
        des.min_caller = min(callers)
        des.avg_caller = mean(callers)

        des.max_folder = max(folders)
        des.min_folder = min(folders)
        des.avg_folder = mean(folders)

        des.max_checker = max(checkers)
        des.min_checker = min(checkers)
        des.avg_checker = mean(checkers)

        des.my_position_is_early = my_position is PokerPosition.Early
        des.my_position_is_middle = my_position is PokerPosition.Middle
        des.my_position_is_late = my_position is PokerPosition.Late
        des.my_position_is_blinds = my_position is PokerPosition.Blinds

        if step.value >= Step.Flop.value:
            cards_sorted = sorted(board[0:3], reverse=True)

            des.flop1[cards_sorted[0].rank.value - 2] = 1
            des.flop2[cards_sorted[1].rank.value - 2] = 1
            des.flop3[cards_sorted[2].rank.value - 2] = 1

            suits = sorted(board[0:3], key=lambda card: card.suit.value)

            if suits[0].suit == suits[1].suit == suits[2].suit:
                des.flop_3_suited = 1
            elif suits[0].suit == suits[1].suit or suits[1].suit == suits[
                    2].suit:
                des.flop_2_suited = 1
            elif suits[0].suit != suits[1].suit != suits[2].suit != suits[
                    0].suit:
                des.flop_rainbow = 1
            else:
                raise ValueError(f'bad sorted suits {suits}')

        if step.value >= Step.Turn.value:
            des.turn[board[3].rank.value - 2] = 1

            suits = sorted(board[0:4], key=lambda card: card.suit.value)

            if suits[0].suit == suits[1].suit == suits[2].suit == suits[3].suit:
                des.turn_4_suited = 1
            elif suits[0].suit == suits[1].suit == suits[2].suit:
                des.turn_3_suited = 1
            elif suits[1].suit == suits[2].suit == suits[3].suit:
                des.turn_3_suited = 1
            elif suits[0].suit == suits[1].suit and suits[2].suit == suits[
                    3].suit:
                des.turn_2_suited_and_other_2 = 1
            elif suits[0].suit == suits[
                    1].suit and suits[2].suit != suits[3].suit:
                des.turn_2_suited_2_not = 1
            elif suits[1].suit == suits[
                    2].suit and suits[0].suit != suits[3].suit:
                des.turn_2_suited_2_not = 1
            elif suits[2].suit == suits[
                    3].suit and suits[0].suit != suits[1].suit:
                des.turn_2_suited_2_not = 1
            elif len(set([suit.suit.value for suit in suits])) == 4:
                des.turn_rainbow = 1
            else:
                raise ValueError(f'bad suits {suits}')

        if step == Step.River:
            des.river[board[4].rank.value - 2] = 1

            suits = sorted(board, key=lambda card: card.suit.value)
            diff_suits = len(set([suit.suit.value for suit in suits]))

            if diff_suits == 1:
                des.river_5_suited = 1
            elif diff_suits == 2 and suits[0].suit == suits[1].suit == suits[
                    2].suit == suits[3].suit:
                des.river_4_suited = 1
            elif diff_suits == 2 and suits[1].suit == suits[2].suit == suits[
                    3].suit == suits[4].suit:
                des.river_4_suited = 1
            elif diff_suits == 2 and suits[0].suit == suits[1].suit == suits[
                    2].suit and suits[3].suit == suits[4].suit:
                des.river_3_suited_and_other_2 = 1
            elif diff_suits == 2 and suits[2].suit == suits[3].suit == suits[
                    4].suit and suits[0].suit == suits[1].suit:
                des.river_3_suited_and_other_2 = 1
            elif diff_suits == 3 and suits[0].suit == suits[1].suit == suits[
                    2].suit and suits[3].suit != suits[4].suit:
                des.river_3_suited_2_not = 1
            elif diff_suits == 3 and suits[1].suit == suits[2].suit == suits[
                    3].suit and suits[0].suit != suits[4].suit:
                des.river_3_suited_2_not = 1
            elif diff_suits == 3 and suits[2].suit == suits[3].suit == suits[
                    4].suit and suits[0].suit != suits[1].suit:
                des.river_3_suited_2_not = 1
            elif diff_suits == 3 and suits[0].suit == suits[1].suit and suits[
                    2].suit == suits[3].suit:
                des.river_2_suited_and_2_suited = 1
            elif diff_suits == 3 and suits[0].suit == suits[1].suit and suits[
                    3].suit == suits[4].suit:
                des.river_2_suited_and_2_suited = 1
            elif diff_suits == 3 and suits[1].suit == suits[2].suit and suits[
                    3].suit == suits[4].suit:
                des.river_2_suited_and_2_suited = 1
            elif diff_suits == 4:
                des.river_only_2_suited = 1
            else:
                raise ValueError(f'bad suits {diff_suits} {suits}')

        return des
    def create(res: BasePokerDecisionAnswer, money: int, pot: int, call: int,
               bb: int, step: Step, cards: CardsPair, board: Cards,
               players_on_table: int, players_active: int,
               players_not_moved: int, max_playing_stack: int,
               average_stack_on_table: int, players: List[MockPlayer],
               folded_players: List[str],
               my_position: PokerPosition) -> PokerDecision9:

        if money < 0:
            raise ValueError(f'Money must be > 0, gived {money}')

        if pot < 0:
            raise ValueError(f'Pot must be > 0, gived {pot}')

        if call < 0:
            raise ValueError(f'Call must be > 0, gived {call}')

        if bb < 0:
            raise ValueError(f'Big blinds must be > 0, gived {bb}')

        if pot <= call and step != Step.Preflop:
            raise ValueError(
                f'Pot must be > call, gived call {call} pot {pot}')

        if type(res) is not PokerDecisionAnswer3:
            raise ValueError(
                f'Result must ne instance of PokerDecisionAnswer, gived {res}')

        pr = HoldemPoker.probability(cards, board)
        strength = HandStrength.get_strength(cards, board)
        outs: float = HoldemPoker.calculate_outs(
            cards, board)[0] / HoldemPoker.MAX_OUTS

        des = PokerDecision9()
        des.set_answer(res)
        des.probability_to_win = pr
        des.my_money = money
        des.money_in_pot = pot
        des.money_to_call = call
        des.big_blind = bb

        if step == Step.Preflop:
            des.is_preflop = 1
        elif step == Step.Flop:
            des.is_flop = 1
        elif step == Step.Turn:
            des.is_turn = 1
        elif step == Step.River:
            des.is_river = 1
        else:
            raise ValueError('bad step', step)

        int_strength: int = strength.value
        if int_strength < 0:
            raise ValueError('strength is < 0', int_strength, strength)
        des.strength[int_strength] = 1

        rank: int = cards.first.rank.value - 2
        if rank < 0:
            raise ValueError('rank is < 0', rank, cards.first.rank)
        des.first[rank] = 1

        rank: int = cards.second.rank.value - 2
        if rank < 0:
            raise ValueError('rank is < 0', rank, cards.second.rank)
        des.second[rank] = 1

        if cards.suitability == Suitability.Suited:
            des.have_suited_cards = 1

        if players_on_table < 2 or players_on_table > 10:
            raise ValueError('bad players on table:', players_active)

        if players_active < 2 or players_active > 10:
            raise ValueError('bad players active:', players_active)

        if players_active > players_on_table:
            raise ValueError('bad players active:', players_active,
                             'with players on table:', players_on_table)

        if players_not_moved < 0 or players_not_moved >= players_active:
            raise ValueError('bad players not moved:', players_not_moved,
                             'with players active:', players_active)

        des.players_on_table[players_on_table - 2] = 1
        des.players_playing[players_on_table - 2] = 1
        des.players_not_moved[players_not_moved] = 1

        des.outs = outs

        des.max_playing_stack = max_playing_stack
        des.average_stack_on_table = average_stack_on_table

        curr_raisers: Dict[Tuple[str, PokerPosition],
                           PlayerStatistics] = PokerDecision9.CurrRaisers
        curr_callers: Dict[Tuple[str, PokerPosition],
                           PlayerStatistics] = PokerDecision9.CurrCallers
        curr_folders: Dict[Tuple[str, PokerPosition],
                           PlayerStatistics] = PokerDecision9.CurrFolders
        curr_checkers: Dict[Tuple[str, PokerPosition],
                            PlayerStatistics] = PokerDecision9.CurrCheckers

        raisers = []
        callers = []
        folders = []
        checkers = []
        for player in players:
            if player.name not in folded_players:
                raisers += [
                    curr_raisers[player.name, player.position].get_stats()
                ]
                callers += [
                    curr_callers[player.name, player.position].get_stats()
                ]
                folders += [
                    curr_folders[player.name, player.position].get_stats()
                ]
                checkers += [
                    curr_checkers[player.name, player.position].get_stats()
                ]

        des.max_raiser = max(raisers)
        des.min_raiser = min(raisers)
        des.avg_raiser = mean(raisers)

        des.max_caller = max(callers)
        des.min_caller = min(callers)
        des.avg_caller = mean(callers)

        des.max_folder = max(folders)
        des.min_folder = min(folders)
        des.avg_folder = mean(folders)

        des.max_checker = max(checkers)
        des.min_checker = min(checkers)
        des.avg_checker = mean(checkers)

        des.my_position_is_early = my_position is PokerPosition.Early
        des.my_position_is_middle = my_position is PokerPosition.Middle
        des.my_position_is_late = my_position is PokerPosition.Late
        des.my_position_is_blinds = my_position is PokerPosition.Blinds

        return des