GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Pull Request — develop (#307)
by
unknown
42s
created

PlayerDivisionInfo   A

Complexity

Total Complexity 4

Size/Duplication

Total Lines 14
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
dl 0
loc 14
rs 10
c 0
b 0
f 0
wmc 4

4 Methods

Rating   Name   Duplication   Size   Complexity  
A __init__() 0 4 1
A __str__() 0 2 1
A is_in_superior_league() 0 2 1
A is_in_inferior_league() 0 2 1
1
# coding=utf-8
2
import logging
3
from abc import ABCMeta, abstractmethod
4
from typing import List, Dict
0 ignored issues
show
Configuration introduced by
The import typing could not be resolved.

This can be caused by one of the following:

1. Missing Dependencies

This error could indicate a configuration issue of Pylint. Make sure that your libraries are available by adding the necessary commands.

# .scrutinizer.yml
before_commands:
    - sudo pip install abc # Python2
    - sudo pip3 install abc # Python3
Tip: We are currently not using virtualenv to run pylint, when installing your modules make sure to use the command for the correct version.

2. Missing __init__.py files

This error could also result from missing __init__.py files in your module folders. Make sure that you place one file in each sub-folder.

Loading history...
Unused Code introduced by
Unused Dict imported from typing
Loading history...
5
6
logger = logging.getLogger(__name__)
7
8
9
class Division:
10
    def __init__(self, id: int, name: str, league: int, threshold: float):
0 ignored issues
show
Bug Best Practice introduced by
This seems to re-define the built-in id.

It is generally discouraged to redefine built-ins as this makes code very hard to read.

Loading history...
11
        self.id = id
12
        self.name = name
13
        self.league = league
14
        self.threshold = threshold
15
16
17
class PlayerDivisionInfo:
18
    def __init__(self, user_id: int, current_league: int, current_score: float):
19
        self.user_id = user_id
20
        self.league = current_league
21
        self.score = current_score
22
23
    def is_in_inferior_league(self, compared_to: 'PlayerDivisionInfo') -> bool:
24
        return self.league < compared_to.league
25
26
    def is_in_superior_league(self, compared_to: 'PlayerDivisionInfo') -> bool:
27
        return self.league > compared_to.league
28
29
    def __str__(self):
30
        return "PlayerDivisionInfo(user_id=%s, league=%s, score=%s)" % (self.user_id, self.league, self.score)
31
32
33
class DivisionPersistor(ABCMeta):
0 ignored issues
show
Unused Code introduced by
This abstract class does not seem to be used anywhere.
Loading history...
34
    """
35
    Interface for the persistance layer
36
    """
37
38
    @abstractmethod
39
    def add_player(self, player: 'PlayerDivisionInfo') -> None:
0 ignored issues
show
Coding Style Best Practice introduced by
The first argument of the metaclass method add_player should be named cls.
Loading history...
40
        """
41
        Add a new player to the persistance layer
42
        :param player: new player with zero score and initial league
43
        """
44
        pass
45
46
    @abstractmethod
47
    def update_player(self, player: 'PlayerDivisionInfo') -> None:
0 ignored issues
show
Coding Style Best Practice introduced by
The first argument of the metaclass method update_player should be named cls.
Loading history...
48
        """
49
        Update a player after a game (league, score, games)
50
        :param player: updated player
51
        """
52
        pass
53
54
55
class DivisionService:
56
    """
57
    Division service calculates changes to the ladder leagues & divisions after each game
58
    """
59
60
    def __init__(self, divisions: List['Division'], player_division_infos: List['PlayerDivisionInfo'],
61
                 persistor: 'DivisionPersistor'):
62
        self.divisions = divisions
63
        self.players = dict()  # type: Dict[int, 'PlayerDivisionInfo']
64
        self.persistor = persistor
65
66
        for info in player_division_infos:
67
            self.players[info.user_id] = info
68
69
    def add_player(self, player_id: int) -> None:
70
        logger.info("Added new player %s to divisions", player_id)
71
        self.players[player_id] = PlayerDivisionInfo(player_id, 1, 0.0)
72
        self.persistor.add_player(self.players[player_id])
73
74
    def update_player_stats(self, player: PlayerDivisionInfo, new_score: float) -> None:
75
        logger.debug("Update score for %s to %s", player)
0 ignored issues
show
Bug introduced by
Not enough arguments for logging format string
Loading history...
76
        player.score = new_score
77
        self.persistor.update_player(player)
78
79
    def promote_player(self, player):
80
        logger.info("%s got promoted to league %s", player, player.league + 1)
81
        player.score = 0.0
82
        player.league += 1
83
        self.persistor.update_player(player)
84
85
    def post_result(self, player_one: int, player_two: int, winning_slot: int) -> None:
86
        """
87
        Post a ladder game result to the division system
88
        :param player_one: FAF User ID of 1st player
89
        :param player_two: FAF User ID of 2nd player
90
        :param winning_slot: 0 for draw, 1 for 1st player, 2 for 2nd player
91
        """
92
        if player_one not in self.players:
93
            self.add_player(player_one)
94
95
        if player_two not in self.players:
96
            self.add_player(player_two)
97
98
        if winning_slot == 0:
99
            logger.info("Game ended in a draw - no changes in score")
100
            self.update_player_stats(self.players[player_one], self.players[player_one].score)
101
            self.update_player_stats(self.players[player_two], self.players[player_two].score)
102
            return
103
104
        winner = self.players[player_one] if winning_slot == 1 else self.players[player_two]
105
        loser = self.players[player_two] if winning_slot == 1 else self.players[player_one]
106
107
        if winner.is_in_inferior_league(loser):
108
            gain = 1.5
109
            loss = 1.0
110
        elif winner.is_in_superior_league(loser):
111
            gain = 0.5
112
            loss = 0.5
113
        else:
114
            gain = 1.0
115
            loss = 0.5
116
117
        logger.info("%s won against %s - gain: %s - loss: %s", winner, loser, gain, loss)
118
119
        if winner.score + gain > self.max_league_threshold(winner.league):
120
            self.promote_player(winner)
121
        else:
122
            self.update_player_stats(winner, winner.score + gain)
123
124
        self.update_player_stats(loser, max(0.0, loser.score - loss))
125
126
    def get_player_division(self, player_id: int) -> 'Division':
127
        player = self.players[player_id]
128
        return self.get_division(player.league, player.score)
129
130
    def max_league_threshold(self, league: int) -> float:
131
        return max([x.threshold for x in self.divisions if x.league == league])
132
133
    def get_division(self, league: int, score: float) -> Division:
134
        divisions_of_league = [x for x in self.divisions if x.league == league]
135
136
        for division in sorted(divisions_of_league, key=lambda d: d.threshold):
137
            if division.threshold > score:
138
                return division
139
140
        logger.error("league %s has no division for score %s", league, score)
141
        return None
142