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
49s
created

DivisionService   A

Complexity

Total Complexity 23

Size/Duplication

Total Lines 75
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 75
rs 10
wmc 23

8 Methods

Rating   Name   Duplication   Size   Complexity  
A max_league_threshold() 0 2 3
A __init__() 0 8 2
A add_player() 0 4 1
A get_player_division() 0 3 1
A promote_player() 0 5 1
B get_division() 0 9 6
D post_result() 0 28 8
A update_player_score() 0 4 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.debug("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_score(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, player_one_has_won: bool) -> None:
86
        if player_one not in self.players:
87
            self.add_player(player_one)
88
89
        if player_two not in self.players:
90
            self.add_player(player_two)
91
92
        winner = self.players[player_one] if player_one_has_won else self.players[player_two]
93
        loser = self.players[player_two] if player_one_has_won else self.players[player_one]
94
95
        if winner.is_in_inferior_league(loser):
96
            gain = 1.5
97
            loss = 1.0
98
        elif winner.is_in_superior_league(loser):
99
            gain = 0.5
100
            loss = 0.5
101
        else:
102
            gain = 1.0
103
            loss = 0.5
104
105
        logger.debug("%s won against %s - gain: %s - loss: %s", winner, loser, gain, loss)
106
107
        if winner.score + gain > self.max_league_threshold(winner.league):
108
            self.promote_player(winner)
109
        else:
110
            self.update_player_score(winner, winner.score + gain)
111
112
        self.update_player_score(loser, max(0.0, loser.score - loss))
113
114
    def get_player_division(self, player_id: int) -> 'Division':
115
        player = self.players[player_id]
116
        return self.get_division(player.league, player.score)
117
118
    def max_league_threshold(self, league: int) -> float:
119
        return max([x.threshold for x in self.divisions if x.league == league])
120
121
    def get_division(self, league: int, score: float) -> Division:
122
        divisions_of_league = [x for x in self.divisions if x.league == league]
123
124
        for division in sorted(divisions_of_league, key=lambda d: d.threshold):
125
            if division.threshold > score:
126
                return division
127
128
        logger.error("league %s has no division for score %s", league, score)
129
        return None
130