2
\$\begingroup\$

In call of Duty warzone, there is a Duos mode (Teams of two). As the game progresses and people are eliminated some teams might have just one player left and some still with two. The game tells you the number of players left and the number of teams. For example, 5 players left, 3 teams left. In this case we can know that this will be two teams of 2, and one team of 1.

Anyway I worked out a formula for calculating the number of teams with 1 or 2 players. below is a short code and some test cases I would appreciate any review / feedback on.

source code

from typing import Tuple


def team_counts(players: int, teams: int) -> Tuple[int, int]:
    if players <= 0 or teams <= 0:
        raise ValueError(f"{players=}, {teams=} - Players and teams must be a positive value")
    if teams > players or teams < players / 2:
        raise ValueError(f"{players=}, {teams=} - Teams must be less than players and greater than or equal to half of players")
    twos = players - teams
    ones = teams - twos
    return ones, twos

Test code

from teams_of_two import team_counts
import pytest


def test_players_teams_positive():
    assert team_counts(players=1, teams=1) == (1, 0)


def test_players_negative_teams_positive():
    with pytest.raises(ValueError):
        team_counts(players=-1, teams=1)


def test_players_positive_teams_negative():
    with pytest.raises(ValueError):
        team_counts(players=1, teams=-1)


def test_players_zero_teams_positive():
    with pytest.raises(ValueError):
        team_counts(players=0, teams=1)


def test_players_positive_teams_zero():
    with pytest.raises(ValueError):
        team_counts(players=1, teams=0)


def test_to_many_teams():
    with pytest.raises(ValueError):
        team_counts(players=1, teams=2)
\$\endgroup\$
3
\$\begingroup\$

Good job overall. You're developing good habits: you're testing your code, you've used the type annotations, you're using f-strings.

If I were to be nit-picky, here's what I'd still suggest:

  • some of your lines are too long and I have to horizontally scroll to see everything. try to shorten them as specified in PEP8
  • add a docstrings to your function
  • function names are usually describing an action so you should be calling yours something like: def count_teams() - I'm really bad at naming things but you got my point

The final code would look like this:

from typing import Tuple


def count_teams(players: int, teams: int) -> Tuple[int, int]:
    """
    Calculate the number of teams with 1 or 2 players
    in call of Duty WarZone (Duos mode)
    """

    if players <= 0 or teams <= 0:
        raise ValueError(f"{players=}, {teams=} - Players and "
                         f"teams must be a positive value")

    if teams > players or teams < players / 2: 
        raise ValueError(f"{players=}, {teams=} - Teams must be "
                         f"less than players and greater than or"
                         f" equal to half of players")

    twos = players - teams
    ones = teams - twos

    return ones, twos

As far as your tests go, the only thing you could improve is to parametrize the tests that are the same but use different values. You have on the pytest's official docs some examples.

And another small nit-pick would be to first import the 3rd party libraries and then the local ones, with a blank line between each group:

import pytest

from teams_of_two import team_counts


# tests ...

LE: edited the chain comparison advice which wasn’t applicable in this case.

\$\endgroup\$
5
  • \$\begingroup\$ Thanks for an excellent and well presented answer. I will have a look at the parmeterising. If have just started with TDD so trying to write a test case then write the code and so on to build up my tests. \$\endgroup\$ – Chris Doyle Dec 26 '20 at 23:56
  • \$\begingroup\$ @KellyBundy I’m not sure what you’re trying to say. Feel free to add another answer if you still have improvements for OP’s code ^^ \$\endgroup\$ – Grajdeanu Alex Dec 27 '20 at 10:50
  • \$\begingroup\$ They are saying it should be players / 2 < teams < players, unless teams is negative, which has already been ruled out. \$\endgroup\$ – Graipher Dec 27 '20 at 13:22
  • \$\begingroup\$ Chain comparisons have an implied "and," while OP's code has "or." They're really cool and useful to know about, but not (I think) applicable in this case. \$\endgroup\$ – Gavin S. Yancey Dec 27 '20 at 16:28
  • \$\begingroup\$ Thinking about it a bit more, if you invert the condition and use De Morgan you can use a chain comparison: if not (players/2 <= teams <= players): ... . Although the text of OP's error there implies the <= players should maybe really be < players \$\endgroup\$ – Gavin S. Yancey Dec 27 '20 at 16:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.