# Lines with a line number in front refer to your code, everything else is my comment.
5 self.gamestate = 0 #0=in play;1=win;2=tie
8 self.current_player_turn = 0 #0=player1;1=player2
# Define some names for the game state.
IN_PLAY = 0
WIN = 1
TIE = 2
PLAYER1 = "player 1"
PLAYER2 = "player 2"
self.gamestate = IN_PLAY
self.current_player_turn = PLAYER1 # Nothing wrong with using strings as value of a constant.
9 print 'init'
# In Python 3 this will fail, add parentheses to prepare yourself for the
# transition.
print('init')
11 def validatemove(self, move):
# Add a doc-string describing the function interfaces, eg
def validatemove(self, move):
"""
Verify that the move is valid.
@param move: Move to verify.
@type move: C{int}
@return: Whether the move was valid.
@rtype: C{bool}
"""
# There are several different styles of documenting, I used EpyDoc. Note that
# Python 3 will support typed parameters and return values, making the @type and
# @rtype entries mostly obsolete.
# I know this may seem totally useless to you, and for this function I arguably
# agree with you. The point is however, in a year, you don't know what each
# function is doing, nor do you remember the types of the arguments or the
# special edge-cases that apply in calling a function.
# That means you will have to reverse-engineer that information from the code,
# when you open this file again. Reverse engineering information is always
# slower and more error-prone than just reading exactly what you want to know.
#
# Documentation as such is thus an investment for the future that makes you work
# faster and more accurately tomorrow.
12 print 'validating move', move
# Python 3 will want something like
print('validating move {}'.format(move))
13 #is the 'move' in range?
14 if not self.gamestate == 0:
15 print 'game is not in play'
16 return False
17 if move > 8 or move < 0:
18 print 'move is not in range'
19 return False
20 if move in self.player1_moves | self.player2_moves:
21 print 'play already made'
22 return False
23 print 'move', move, 'evaluated as legal'
24 return True
# If you insert empty lines between the different checks, it's easier to see
# the steps you're making.
#
# The problem you'll have here is that an empty line between functions and an
# empty line between statements looks very similar. This is also where function
# documentation helps. It adds a big different looking piece of text with each
# function, making it easier to see where a function starts in the code.
26 def getgamestate(self):
27 if self.gamestate == 0:
28 return "in play"
29 elif self.gamestate == 1:
30 return "win"
31 else:
32 return "tie"
# I tend to be more paranoid, and pretty much always check for completeness, ie
if self.gamestate == 0:
return "in play"
elif self.gamestate == 1:
return "win"
else:
assert self.gamestate == 2
return "tie"
# It's surprising how often these checks trigger, because you forgot some case somewhere.
#
# A simpler way to do the above is
GAMESTATE_DESCRIPTIONS = {
0: 'in play',
1: 'win',
2: 'tie',
}
def getgamestate(self):
"""
Get a human-readable description of the game state.
@return: Description of the current state of the game.
@rtype: C{str}
"""
return GAMESTATE_DESCRIPTIONS[self.gamestate]
# I just document all functions to avoid the problem of deciding what is
# trivial enough not to document, ymmv.
34 def getcurrentplayerturn(self):
35 if self.current_player_turn == 0:
36 return "player 1"
37 elif self.current_player_turn == 1:
38 return "player 2"
# With the string constants, this would be just
def getcurrentplayerturn(self):
"""
Get the name of the current player.
@return: Name of the current player.
@rtype: C{str}
"""
return self.current_player_turn
# And yes, it's normal that the documentation is longer than the code in
# Python, the language is very efficient in number of lines needed to express
# something.
54
55 def evaluateWinState(self,movesetToEval):
56 #012
57 #345
58 #678
59 winStateList = [{0,1,2},{3,4,5},{6,7,8},{0,3,6},{1,4,7},{2,5,8},{0,4,8},{2,4,6}]
winStateList = [
{0, 1, 2}, {3, 4, 5}, {6, 7, 8}, # Horizontal
{0, 3, 6}, {1, 4, 7}, {2, 5, 8}, # Vertical
{0, 4, 8}, # Main diagonal
{2, 4, 6}, # Other diagonal
]
# Exploit the multi-line capabilities of Python to make it easier to understand
# what the data contains. The comments also point you directly to what the entries mean,
# while in your version you have to actually parse the entries to find the
# right one.
# Addedsomemorewhitespacetomakeiteasiertoread (here it's quite ok, but if you
# use floating point numbers, 0.0,0.0 versus 0,0,0,0 becomes hard to read. The
# comma behind the last entry makes it simpler to extend the list at a later
# time, though this list will never get extended, most likely.
85 else:
86 raise AssertionError("unexpected ui state")
87 #ai's second turn (human has made two moves)
88 elif player1move_count == 2:
# I would also insert empty lines between the various elif clauses, as I
# consider them separate cases.