If this were a real PR, I would highlight one of the *loose
variables and ask Should this read lose
?
I really like your second approach. While reading it, I felt like the next line of code was doing exactly what I was anticipating it would do, and I didn't have to use as much mental memory while reading it like I did your first approach, keeping track of all those variables that were set to zero. One way you might consider improving it is to remove the a_scr
and d_scr
initializations and use a sum()
to calculate them, such as:
def RiskGame(attacker, defender):
a = sorted(attacker, reverse=True)
b = sorted(defender, reverse=True)
a_scr = sum([i > j for i, j in zip(a,b)])
d_scr = sum([i < j for i, j in zip(a,b)])
if d_scr == 0:
return 'Defender loses %i armies.' %a_scr
elif a_scr == 0:
return 'Attacker loses %i armies.' %d_scr
else:
return 'Attacker loses %i army and defender loses %i army.' %(a_scr, d_scr)
RiskGame([1,2,6], [1, 5])
I have similar reservations about the Pascal casing of the functions and returning strings instead of values, but these are covered nicely in the other answers.
Edit: Demonstrate how to use tests
This part covers another way of ensuring your example battles run correctly in a systematic way using pytest. It illustrates why some other the other answers' suggestions to get the printing out of the function makes it easier to code.
Step 1.
Have your main function just return a_scr
and d_scr
, and put the printing logic in the main script:
# riskgame.py
def risk_game(attacker, defender):
a = sorted(attacker, reverse=True)
b = sorted(defender, reverse=True)
a_scr = sum([i > j for i, j in zip(a,b)])
d_scr = sum([i <= j for i, j in zip(a,b)])
return a_scr, d_scr
if __name__ == "__main__":
a_scr, d_scr = risk_game([6,2,6], [6, 6])
if d_scr == 0:
print('Defender loses %i armies.' %a_scr)
elif a_scr == 0:
print('Attacker loses %i armies.' %d_scr)
else:
print('Attacker loses %i army and defender loses %i army.' %(a_scr, d_scr))
When you execute the script, you get the same behavior as before:
$ python riskgame.py
Attacker loses 2 armies.
Step 2.
In the same directory create test_wins_and_losses.py
and create some tests:
# test_wins_and_losses.py
from riskgame import risk_game
def test_d_wins():
a_scr, d_scr = risk_game([1,2,6], [1, 5])
assert a_scr == 2
assert d_scr == 0
def test_a_wins():
a_scr, d_scr = risk_game([6,2,6], [6, 6])
assert a_scr == 0
assert d_scr == 2
def test_equal():
a_scr, d_scr = risk_game([1,4,1], [1, 2])
assert a_scr == 1
assert d_scr == 1
Notice I used the same values you put in the original post, but you could have any example games you want in there. Ideally, you would have lots, covering as many use cases as you can.
Step 3.
Install pytest if you haven't already.
$ pip install pytest
Step 4.
Run it!
$ pytest
============================= test session starts ==============================
platform linux -- Python 3.7.4, pytest-6.0.2, py-1.9.0, pluggy-0.13.1
rootdir: /tmp/risk_game
collected 3 items
test_wins_and_losses.py ... [100%]
============================== 3 passed in 0.02s ===============================
The idea is now you can change your code, and every time you do you can just type pytest
at the command line to confirm everything is still functioning the way you expect. For example, if we make the mistake I made earlier and change the line to
d_scr = sum([i < j for i, j in zip(a,b)])
and run the tests, we get:
$ pytest
==================================================================== test session starts =====================================================================
platform linux -- Python 3.7.4, pytest-6.0.2, py-1.9.0, pluggy-0.13.1
rootdir: /tmp/risk_game
collected 3 items
test_wins_and_losses.py .FF [100%]
========================================================================== FAILURES ==========================================================================
________________________________________________________________________ test_a_wins _________________________________________________________________________
def test_a_wins():
a_scr, d_scr = risk_game([6,2,6], [6, 6])
assert a_scr == 0
> assert d_scr == 2
E assert 0 == 2
test_wins_and_losses.py:11: AssertionError
_________________________________________________________________________ test_equal _________________________________________________________________________
def test_equal():
a_scr, d_scr = risk_game([1,4,1], [1, 2])
assert a_scr == 1
> assert d_scr == 1
E assert 0 == 1
test_wins_and_losses.py:16: AssertionError
================================================================== short test summary info ===================================================================
FAILED test_wins_and_losses.py::test_a_wins - assert 0 == 2
FAILED test_wins_and_losses.py::test_equal - assert 0 == 1
================================================================ 2 failed, 1 passed in 0.09s ================================================================
Happy testing!