patternpythonMinor
Bulls and Cows in Python
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
```
"""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
-
Move all the try and expect logic into a separate method (consider moving it in the
Larger Note
: I've been thinking the code in 5 sections (maybe reflecting hte code in these sections might make it more readable?):
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_inputand 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
compareand some of theguessfunctionality can go in here)
- Player: the ABC class that represents what a player should look like with the proper default behavior
- The
HumanPlayerand theComputePlayerclass 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.