Beispiel #1
0
    async def post_game(self, args: typing.Dict):
        logger.debug(f'post_game {args}')
        request = valid_request_from_dict(AddGameRequest, args)

        players = []
        for nick in request.nicks_won + request.nicks_lost:
            player = await self._search.load_player_by_nick(nick)
            if player is None:
                raise RuntimeError(f'Player not found: {nick}')
            if player.get_rating() is None:
                raise RuntimeError(f'Player rating is not set')
            players.append(player)

        game = Game(nicks_won=request.nicks_won, nicks_lost=request.nicks_lost,
                    score_won=request.score_won, score_lost=request.score_lost, date=datetime.now())
        for player in players:
            game.set_rating_before(player.nick, player.get_rating())

        self.ranking.calculate(game)
        await self._manage.save_game(game)

        for player in players:
            player.set_rating(game.rating_after(player.nick))
            await self._manage.save_player(player)

        return game.as_dict()
Beispiel #2
0
    async def load_game_by_id(game_id):
        g = Game(game_id=game_id)
        res = await db.execute(Search.sql_load_game_by_id(game_id))
        if len(res) == 0:
            raise RuntimeError(f'Could not find game game_id({g.id})')

        res = res[0]
        g.date = datetime.datetime.strptime(res[0], '%Y-%m-%d %H:%M:%S')
        g.score_won = res[1]
        g.score_lost = res[2]

        res = await db.execute(Search.sql_load_game_players_by_id(game_id))

        for record in res:
            won = record[1]
            p = await Search.load_player_by_id(player_id=record[0])
            if won:
                g.nicks_won.append(p.nick)
            else:
                g.nicks_lost.append(p.nick)

            res = await db.execute(
                Search.sql_rating_change(g.id, p.id, ratingSystem))
            if len(res) == 0:
                raise RuntimeError(
                    f'Could not find rating change for game_id({g.id}), player_id({p.id})'
                )

            g.set_rating_before(p.nick,
                                Rating(value=res[0][0], accuracy=res[0][2]))
            g.set_rating_after(p.nick,
                               Rating(value=res[0][1], accuracy=res[0][3]))

        logger.debug(f'load_game_by_id {g}')
        return g
Beispiel #3
0
async def test_all():
    g = None
    team_won = []
    team_lost = []
    try:
        # create players
        for i in range(0, 4):
            p = Player(nick=f'NewPlayer{i}')
            p.set_rating(Rating(value=1200, accuracy=0))
            await Manage.delete_player(p)
            await Manage.save_player(p)
            if i < 2:
                team_won.append(p)
            else:
                team_lost.append(p)

        g = Game(date=datetime.now(),
                 nicks_won=[p.nick for p in team_won],
                 nicks_lost=[p.nick for p in team_lost],
                 score_won=23,
                 score_lost=21)
        for p in team_won:
            g.set_rating_before(p.nick, p.get_rating())
            p.set_rating(Rating(value=1300, accuracy=0))
            g.set_rating_after(p.nick, p.get_rating())

        for p in team_lost:
            g.set_rating_before(p.nick, p.get_rating())
            p.set_rating(Rating(value=1100, accuracy=0))
            g.set_rating_after(p.nick, p.get_rating())

        await Manage.save_game(g)

        test_g = await Search.load_game_by_id(g.id)

        assert test_g.nicks_won == ['NewPlayer0', 'NewPlayer1']
        assert test_g.nicks_lost == ['NewPlayer2', 'NewPlayer3']

        for nick in test_g.nicks_won:
            assert test_g.rating_before(nick) == Rating(value=1200, accuracy=0)
            assert test_g.rating_after(nick) == Rating(value=1300, accuracy=0)

        for nick in test_g.nicks_lost:
            assert test_g.rating_before(nick) == Rating(value=1200, accuracy=0)
            assert test_g.rating_after(nick) == Rating(value=1100, accuracy=0)

        assert test_g.score_won == 23
        assert test_g.score_lost == 21

    finally:
        # clear
        await Manage.delete_game(g)
        for p in team_won + team_lost:
            await Manage.delete_player(p)
Beispiel #4
0
async def test_all():
    # create players
    team_won = []
    team_lost = []
    g = None
    try:
        for i in range(0, 4):
            p = Player(nick=f'NewPlayer{i}', phone=f'7916123456{i}')
            p.set_rating(Rating(value=1200 + i, accuracy=1))
            if i < 2:
                team_won.append(p)
            else:
                team_lost.append(p)

            await Manage.delete_player(p)
            await Manage.save_player(p)

        # find players LIKE
        players = await Search.load_players_nick_like('New')
        assert len(players) == 4

        players = await Search.load_players_nick_like('NewNotExists')
        assert len(players) == 0

        # game
        g = Game(date=datetime.now(), nicks_won=[p.nick for p in team_won], nicks_lost=[p.nick for p in team_lost],
                 score_won=15, score_lost=10)
        for p in team_won:
            g.set_rating_before(p.nick, p.get_rating())
            p.set_rating(Rating(value=p.get_rating().value + 100, accuracy=p.get_rating().accuracy))
            g.set_rating_after(p.nick, p.get_rating())
            await Manage.save_player(p)

        for p in team_lost:
            g.set_rating_before(p.nick, p.get_rating())
            p.set_rating(Rating(value=p.get_rating().value - 100, accuracy=p.get_rating().accuracy))
            g.set_rating_after(p.nick, p.get_rating())
            await Manage.save_player(p)

        await Manage.save_game(g)

        # find game
        res = await Search.games(player=team_lost[0])
        assert res[0].id == g.id

        # find games vs
        res = await Search.games(player=team_won[0], vs_players=[team_lost[0]])
        assert len(res) == 1
        assert res[0].id == g.id

        # not find games vs
        res = await Search.games(player=team_lost[0], vs_players=[team_lost[1]])
        assert len(res) == 0

        # find games with
        res = await Search.games(player=team_lost[1], with_players=[team_lost[0]])
        assert len(res) == 1
        assert res[0].id == g.id

        # not find games with
        res = await Search.games(player=team_lost[0], with_players=[team_won[1]])
        assert len(res) == 0

        # find games vs and with
        res = await Search.games(player=team_lost[0], vs_players=[team_won[0]], with_players=[team_lost[1]])
        assert len(res) == 1
        assert res[0].id == g.id

        # not find games vs
        res = await Search.games(player=team_lost[1], vs_players=[team_won[1]], with_players=[team_won[0]])
        assert len(res) == 0

        res = await Search.games(player=team_lost[0], vs_players=[team_lost[1]], with_players=[team_lost[1]])
        assert len(res) == 0

    finally:
        # clear
        await Manage.delete_game(g)
        for player in team_lost + team_won:
            await Manage.delete_player(player)
Beispiel #5
0
class Session(AbstractSession, xworkflows.WorkflowEnabled):
    state = SessionWorkflow()

    def __init__(self, backend, text):
        AbstractSession.__init__(self)
        logger.debug('start')
        self.backend = backend
        self.text = text

        self._game = None
        self._player = None

    # A list of transitions and checks performed on an user_input without command
    # check returns tuple (index of transition, parsed args)
    # (source state, check, transitions)
    raw_input_transitions = (('s_game_adding_player', 'check_adding_player',
                              ('game_player_confirm', 'game_add_new_player')),
                             ('s_game_new_player_phone',
                              'check_adding_player_phone',
                              ('game_new_player_phone')),
                             ('s_game_set_won_score', 'check_setting_score',
                              ('game_set_score_won')),
                             ('s_game_set_lost_score', 'check_setting_score',
                              ('game_set_score_lost')),
                             ('s_nick_adding_player', 'check_adding_player',
                              ('nick_already_exists', 'nick_new_player')),
                             ('s_nick_new_player_phone',
                              'check_adding_player_phone',
                              ('nick_new_player_phone')),
                             ('s_players', 'check_player_found',
                              ('players_found', 'players_not_found')),
                             ('s_games', 'check_game_found',
                              ('games_found', 'games_not_found')))

    def _check_error_is_fatal(self, err, processing_message):
        if err is not None and err['error_type'] != 'negative response':
            raise RuntimeError(json.dumps(err))

    ''' Checks '''

    # return tuple (index of transition, parsed arguments)
    def check_adding_player(self, user_input, processing_message=None):
        logger.debug('check_adding_player')
        if type(user_input) == Player:
            return (0, user_input)

        err, player = self.backend.get_player(nick=user_input)
        self._check_error_is_fatal(err, processing_message)
        if player is not None:
            return (0, player)
        else:
            return (1, Player(nick=user_input, phone=None))

    def check_player_found(self, user_input, processing_message=None):
        logger.debug('check_player_found')
        if type(user_input) == Player:
            user_input = user_input.nick

        err, player = self.backend.get_player(nick=user_input)
        self._check_error_is_fatal(err, processing_message)
        if player is not None:
            return (0, player)
        else:
            return (1, None)

    def check_game_found(self, user_input, processing_message=None):
        logger.debug('check_game_found')
        if type(user_input) == Player:
            user_input = user_input.nick

        err, games = self.backend.get_games(nick=user_input)
        self._check_error_is_fatal(err, processing_message)
        if games is not None and len(games) > 0:
            return (0, games)
        else:
            return (1, None)

    def check_adding_player_phone(self, user_input, processing_message=None):
        logger.debug('check_adding_player_phone')
        try:
            phone = int(self._normalize_phone(user_input))
            return (0, f'{phone}')
        except ValueError:
            self.show_message(message=self.text.check_phone_incorrect(),
                              processing_message=processing_message,
                              reply=True)
            return (-1, None)

    def check_setting_score(self, user_input, processing_message=None):
        logger.debug('check_setting_score')
        try:
            score = int(user_input)
            if score >= 0:
                if self.state.is_s_game_set_lost_score or score > 14:
                    if self.state.is_s_game_set_lost_score and score + 1 >= self._game.score_won:
                        self.show_message(
                            message=self.text.
                            check_score_looser_less_than_winner(),
                            processing_message=processing_message,
                            reply=True)
                        return (-1, None)
                    return (0, score)
                else:
                    self.show_message(
                        message=self.text.check_score_winner_min_value(),
                        processing_message=processing_message,
                        reply=True)
                    return (-1, None)
            else:
                self.show_message(message=self.text.check_score_min_value(),
                                  processing_message=processing_message,
                                  reply=True)
                return (-1, None)
        except ValueError:
            self.show_message(message=self.text.check_score_is_not_a_number(),
                              processing_message=processing_message,
                              reply=True)
            return (-1, None)

    ''' Transitions '''

    @xworkflows.transition()
    def goto_init(self,
                  user_input=None,
                  processing_message=None,
                  message=None):
        logger.debug('goto_init')
        self.show_message(message=message,
                          buttons=['/game', '/players', '/games', '/cancel'],
                          keyboard=True,
                          processing_message=processing_message)

    @xworkflows.transition()
    def game_add(self, user_input=None, processing_message=None):
        logger.debug('game_add')
        self._game = Game()
        self.show_message(message=self.text.game(),
                          processing_message=processing_message)

    @xworkflows.transition()
    def game_player_confirm(self, player, processing_message=None):
        logger.debug('game_player_confirm')
        self._player = player

    @xworkflows.transition()
    def game_add_new_player(self, player, processing_message=None):
        logger.debug('game_add_new_player')
        self._player = player
        self.show_message(message=self.text.game_add_new_player(),
                          processing_message=processing_message)

    @xworkflows.transition()
    def game_new_player_phone(self, phone, processing_message=None):
        logger.debug('game_new_player_phone')
        self._player.phone = self._normalize_phone(phone)
        err, self._player = self.backend.add_player(
            player=self._player, who=processing_message.ids.user_id)
        self._check_error_is_fatal(err, processing_message)

    @xworkflows.transition()
    def game_set_score_won(self, score, processing_message=None):
        logger.debug('game_set_score_won')
        self._game.score_won = score
        self.show_message(
            message=self.text.game_score_winner_set_next_looser(),
            processing_message=processing_message)

    @xworkflows.transition()
    def game_set_score_lost(self, score, processing_message=None):
        logger.debug('game_set_score_lost')
        self._game.score_lost = score
        '''self.show_message(
            message=self.text.score_set_done(),
            processing_message=processing_message
        )'''

    @xworkflows.transition()
    def game_set_scores(self, arg=None, processing_message=None):
        logger.debug('game_set_scores')
        self.show_message(message=self.text.game_score_set_winner(),
                          processing_message=processing_message)

    @xworkflows.transition()
    def game_next_player(self, arg=None, processing_message=None):
        logger.debug('game_next_player')
        pass

    @xworkflows.transition()
    def game_save(self, processing_message=None):
        logger.debug('game_save')
        err, g = self.backend.add_game(game=self._game,
                                       who=processing_message.ids.user_id)
        self._check_error_is_fatal(err, processing_message)
        self._game = g
        self.show_message(message=self.text.game_saved(),
                          processing_message=processing_message)

    @xworkflows.transition()
    def nick(self, user_input=None, processing_message=None):
        logger.debug('nick')
        self.show_message(message=self.text.nick(),
                          processing_message=processing_message)

    @xworkflows.transition()
    def nick_already_exists(self, arg=None, processing_message=None):
        logger.debug('nick_already_exists')
        self.show_message(message=self.text.nick_already_exists(),
                          processing_message=processing_message)

    @xworkflows.transition()
    def nick_new_player(self, player, processing_message=None):
        logger.debug('nick_new_player')
        self._player = player
        self.show_message(message=self.text.nick_adding_enter_phone(),
                          processing_message=processing_message)

    @xworkflows.transition()
    def nick_new_player_phone(self, phone, processing_message=None):
        logger.debug('nick_new_player_phone')
        self._player.phone = self._normalize_phone(phone)
        err, self._player = self.backend.add_player(
            player=self._player, who=processing_message.ids.user_id)
        self._check_error_is_fatal(err, processing_message)
        self.show_message(message=self.text.nick_added(self._player),
                          processing_message=processing_message)

    @xworkflows.transition()
    def players_wait(self, processing_message=None):
        logger.debug('players_wait')
        self.show_message(message=self.text.players(),
                          buttons=[
                              Button(text='search',
                                     switch_inline='/players ',
                                     callback=None)
                          ],
                          processing_message=processing_message)

    @xworkflows.transition()
    def players_found(self, player, processing_message=None):
        logger.debug('players_found')
        self.show_message(message=self.text.players_found(player),
                          processing_message=processing_message)

    @xworkflows.transition()
    def players_not_found(self, player, processing_message=None):
        logger.debug('players_not_found')
        self.show_message(message=self.text.players_not_found(),
                          processing_message=processing_message)

    @xworkflows.transition()
    def games_wait(self, processing_message=None):
        logger.debug('games_wait')

    @xworkflows.transition()
    def games_found(self, games, processing_message=None):
        logger.debug('games_found')
        self.show_message(message=self.text.games_found(games, len(games)),
                          processing_message=processing_message)

    @xworkflows.transition()
    def games_not_found(self, game, processing_message=None):
        logger.debug('games_not_found')
        self.show_message(message=self.text.games_not_found(),
                          processing_message=processing_message)

    @xworkflows.on_enter_state('s_game_player_confirmed')
    def _on_s_game_player_confirmed(self,
                                    transition_res=None,
                                    transition_arg=None,
                                    processing_message=None):
        logger.debug('_on_s_game_player_confirmed')
        self._add_player_to_game()
        self.show_message(message=self.text.game_player_added(),
                          processing_message=processing_message)
        if len(self._game.nicks_won) < 2 or len(self._game.nicks_lost) < 2:
            self.game_next_player(processing_message=processing_message)
        else:
            self.game_set_scores(processing_message=processing_message)

    @xworkflows.on_enter_state('s_game_adding_player')
    def _on_s_game_adding_player(self,
                                 transition_res=None,
                                 transition_arg=None,
                                 processing_message=None):
        logger.debug('_on_s_game_adding_player')
        self.show_message(message=self.text.game_add_next_player(self._game),
                          buttons=[
                              Button(text='search',
                                     switch_inline='/players ',
                                     callback=None)
                          ],
                          processing_message=processing_message)

    @xworkflows.on_enter_state('s_game_created')
    def _on_s_game_created(self,
                           transition_res=None,
                           transition_arg=None,
                           processing_message=None):
        logger.debug('_on_s_game_created')
        self.game_save(processing_message)

    @xworkflows.on_enter_state('s_players')
    def _on_s_players(self,
                      transition_res=None,
                      transition_arg=None,
                      processing_message=None):
        logger.debug('_on_s_players')

    @xworkflows.on_enter_state('s_games')
    def _on_s_players(self,
                      transition_res=None,
                      transition_arg=None,
                      processing_message=None):
        logger.debug('_on_s_games')
        self.show_message(message=self.text.games(),
                          buttons=[
                              Button(text='search',
                                     switch_inline='/players ',
                                     callback=None)
                          ],
                          processing_message=processing_message)

    def game(self, user_input=None, processing_message=None):
        logger.debug('players')
        if user_input is None or len(user_input) == 0 and self.state.is_init:
            return self.game_add(processing_message=processing_message)

        if user_input is not None:
            params = user_input.split(';')
            nicks_won = params[0:2]
            nicks_lost = params[2:4]
            score_won = params[4]
            score_lost = params[5]
            self._game = Game(nicks_won=nicks_won,
                              nicks_lost=nicks_lost,
                              score_won=score_won,
                              score_lost=score_lost)

            for nick in params[0:3]:
                err, p = self.backend.get_player(nick=nick)
                self._check_error_is_fatal(err, processing_message)
                if err is not None:
                    return self.goto_init(
                        message=self.text.nick_not_exists() + '\n' +
                        self.text.cancel(),
                        processing_message=processing_message)
                self._game.set_rating_before(nick=nick, rating=p.get_rating())

            err, g = self.backend.add_game(game=self._game,
                                           who=processing_message.ids.user_id)
            self._check_error_is_fatal(err, processing_message)
            if err is not None:
                return self.goto_init(message=self.text.game_save_fail(err),
                                      processing_message=processing_message)

            self._game = g
            self.show_message(message=self.text.game_saved(),
                              processing_message=processing_message)

    def players(self, user_input=None, processing_message=None):
        logger.debug('players')
        if user_input is None or len(user_input) == 0 and self.state.is_init:
            return self.players_wait(processing_message=processing_message)

        if user_input is not None:
            user_input = user_input.strip()
        if user_input is not None and len(user_input) > 2:
            err, players = self.backend.get_players(nick_like=user_input)
            self._check_error_is_fatal(err, processing_message)
            self.show_contacts(contacts=players,
                               processing_message=processing_message)

    def games(self, user_input=None, processing_message=None):
        logger.debug('games')
        if user_input is None or len(user_input) == 0 and self.state.is_init:
            return self.games_wait(processing_message=processing_message)

        if user_input is not None:
            user_input = user_input.strip()
        if user_input is not None and len(user_input) > 2:
            err, games = self.backend.get_games(nick=user_input)
            self._check_error_is_fatal(err, processing_message)
            self.show_message(message=json.dumps(games),
                              processing_message=processing_message)

    def start(self, user_input=None, processing_message=None):
        logger.debug('start')
        self.goto_init(message=self.text.start(),
                       processing_message=processing_message)

    def cancel(self, user_input=None, processing_message=None):
        logger.debug('cancel')
        self.goto_init(message=self.text.cancel(),
                       processing_message=processing_message)

    def help(self, user_input=None, processing_message=None):
        logger.debug('help')
        self.show_message(message=self.text.help(),
                          processing_message=processing_message)

    def _normalize_phone(self, args=None):
        p = ''
        for i in args:
            p = p + i
        return p.replace(' ', '')

    def _add_player_to_game(self):
        g = self._game
        if len(g.nicks_won) < 2:
            g.nicks_won.append(self._player.nick)
        else:
            if len(g.nicks_lost) < 2:
                g.nicks_lost.append(self._player.nick)