HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonMinor

Bulls and Cows in Python

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
andpythonbullscows

Problem

I have recently written this little Bulls and Cows game in Python:

```
"""Play Bulls and Cows."""
import random
NUM_DIGITS = 5

class IllegalNumber(Exception):
"""An exception to raise when the class Num has an instance of an
illegal number."""
pass

class Num(object):
"""Represent a number that consists of different NUM_DIGITS digits.
n -- a representation of the number (int, str or a
sequence of digits)."""
def __init__(self, n):
self.num = tuple(int(d) for d in str(n)) if isinstance(n, (int, str)) \
else tuple(int(d) for d in n) # convert n into a tuple of digits
if not self._is_legal():
raise IllegalNumber

def _is_legal(self):
if len(self.num) != NUM_DIGITS:
return False
if len(set(self.num)) >> Num(1234).compare(Num(5243)) ==> 1, 2
"""
bulls, cows = 0, 0
for i in xrange(NUM_DIGITS):
if self.num[i] == other.num[i]:
bulls += 1
elif self.num[i] in other.num:
cows += 1
return bulls, cows

class ComputerPlayer(object):
"""An average computer player."""
def __init__(self):
self.possible_nums = []
for num in xrange(10(NUM_DIGITS-1), 10NUM_DIGITS):
# Iterate over the numbers that has NUM_DIGITS digits.
try:
self.possible_nums.append(Num(num))
except IllegalNumber:
pass
self._secret_num = random.choice(self.possible_nums)

def guess(self, check_func):
"""Guess a number and check it with the given function.
The function gets a guess and returns the bulls and cows.
Return True if the player won, and False otherwise.
"""
try:
guess_num = random.choice(self.possible_nums)
except IndexError:
# If self.possible_nums is empty, the opponent cheated or
# mistaked
return True # If one play

Solution

-
It look like a common behaviour you want a Player to have is the ability of def check(self, num): and def guess(self, check_func):. Consider adding an ABC to this code class Player with the 2 @abstractmethods and have HumanPlayer and ComputerPlayer inherit from this.

-
Move all the try and expect logic into a separate method (consider moving it in the class Player from the comment above if you decide to go that way), and wrap all you raw_input calls with this method. The idea being keep looking until you get a valid input from the user (youre' skipping this logic in bulls, cows = int(raw_input('\tBulls: ')), int(raw_input('\tCows: ')) .. which will just crash with invalid input)

Larger Note
: I've been thinking the code in 5 sections (maybe reflecting hte code in these sections might make it more readable?):

  • NumberValidation: the class solely responsible for running all the raw_input and validating the input until we get one (no one outside of this should be calling raw_input or running validation on the input values .. the game is "stuck" at this until a valid input is recognized)



  • GameValidation: the class responsible for checking the state of the game and calling it complete once we have all bulls (a lot of the compare and some of the guess functionality can go in here)



  • Player: the ABC class that represents what a player should look like with the proper default behavior



  • The HumanPlayer and the ComputePlayer class implementations



  • The main method for game play between HumanPlayer and the ComputerPlayer.

Context

StackExchange Code Review Q#75572, answer score: 4

Revisions (0)

No revisions yet.