Created
March 30, 2015 15:46
-
-
Save xvedejas/2ed29712779b09addf63 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python3 | |
class TicTacToeGame(): | |
def __init__(self): | |
# Our game state is defined by a list of 3 lists, each containing 3 | |
# characters, which can be either ' ' (blank), an 'X', or an 'O'. | |
self.state = [[' ', ' ', ' '], [' ', ' ', ' '], [' ', ' ', ' ']] | |
self.next_turn_player = 'X' | |
def do_move(self, index): | |
""" | |
Plays a move at the given index (beginning with 1 in the top-left). | |
""" | |
# Correct to zero-indexing | |
index -= 1 | |
# Make sure the move index is not out of bounds | |
if index >= 9 or index < 0: | |
raise IndexError | |
# Find the row/column | |
row = index // 3 | |
col = index % 3 | |
# Make sure the position hasn't been played yet | |
if self.state[row][col] != ' ': | |
raise ValueError | |
# Make the move | |
self.state[row][col] = self.next_turn_player | |
# Update the player expected for next turn | |
self.next_turn_player = ('O' if self.next_turn_player == 'X' else 'X') | |
def __repr__(self): | |
""" | |
Returns the representation of the game state as a string, which looks | |
like this: | |
1 |2 |3 | |
| | | |
-------- | |
4 |\/|6 | |
|/\| | |
-------- | |
7 |/\|9 | |
|\/| | |
""" | |
representation = [] | |
i = 0 | |
for row in self.state: | |
upper_halves = [] | |
lower_halves = [] | |
for item in row: | |
i += 1 | |
if item == 'X': | |
upper_halves.append('\\/') | |
lower_halves.append('/\\') | |
elif item == 'O': | |
upper_halves.append('/\\') | |
lower_halves.append('\\/') | |
else: | |
upper_halves.append('%i ' % i) | |
lower_halves.append(' ') | |
representation += ['|'.join(upper_halves) + '\n' + | |
'|'.join(lower_halves) + '\n'] | |
return '--------\n'.join(representation) | |
def check_game_end(self): | |
"""Checks the game state to see if the game is over, either by virtue of | |
someone winning or because all spaces are filled.""" | |
# Assume the board is filled until contrary evidence | |
filled = True | |
for row in self.state: | |
if ' ' in row: | |
filled = False | |
break | |
# If there is a winner, then one of the following sets of indices in | |
# our game state will all be the same value: | |
wins = (# Horizontal wins: | |
(0, 1, 2), | |
(3, 4, 5), | |
(6, 7, 8), | |
# Vertical wins: | |
(0, 3, 6), | |
(1, 4, 7), | |
(2, 5, 8), | |
# Diagonal wins: | |
(0, 4, 8), | |
(2, 4, 6)) | |
for win in wins: | |
i, j, k = win | |
a, b, c = (self.state[i // 3][i % 3], | |
self.state[j // 3][j % 3], | |
self.state[k // 3][k % 3]) | |
if a == b and b == c and a != ' ': | |
return a | |
return filled | |
def play_2p_game(self): | |
""" | |
Two-Player Interactive Game | |
This method creates a loop which waits for input from the command line. | |
After each move is played, it shows the new state of the game. This | |
continues until the game is over. | |
""" | |
print(self) | |
while True: | |
index = input('Player %s move: ' % self.next_turn_player) | |
try: | |
self.do_move(int(index)) | |
except TypeError: | |
print('Expected a position number') | |
except IndexError: | |
print('Position out of range') | |
except ValueError: | |
print('Position already played') | |
else: | |
print(self) | |
end_state = self.check_game_end() | |
if end_state == True: | |
print('Tied game.') | |
break | |
elif end_state: | |
print('Player %s wins!' % end_state) | |
break | |
def play_1p_game(self): | |
""" | |
One-Player Interactive Game | |
Like the two-player game, except now we play against an AI. | |
""" | |
pass | |
ttt = TicTacToeGame() | |
ttt.play_2p_game() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment