Last active
May 21, 2020 07:13
-
-
Save h2rashee/623e67f6ebab8674bab538f616da9193 to your computer and use it in GitHub Desktop.
Tic Tac Toe
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
import random | |
ROWS = 3 | |
COLS = 3 | |
EMPTY = '-' | |
USER_MOVE = 'X' | |
AI_MOVE = 'O' | |
# TODO Make turns versatile to change | |
class TicTacToe: | |
def __init__(self, is_human_start=True): | |
self.board = [] | |
for i in xrange(ROWS): | |
row = [] | |
for j in xrange(COLS): | |
row.append(EMPTY) | |
self.board.append(row) | |
self.is_human_turn = is_human_start | |
def _add_token(self, x, y, token): | |
if self.is_taken(x, y): | |
raise Exception('Place already taken') | |
self.board[x][y] = token | |
def _has_anyone_won(self): | |
return self._has_won(USER_MOVE) or self._has_won(AI_MOVE) | |
def _has_won(self, token): | |
opposing_token = USER_MOVE | |
if token == USER_MOVE: | |
opposing_token = AI_MOVE | |
# Check for a horizontal match | |
for row in self.board: | |
if EMPTY in row or opposing_token in row: | |
continue | |
return True | |
# Check for a vertical match | |
for j in xrange(COLS): | |
is_winning_column = True | |
for i in xrange(ROWS): | |
if self.board[i][j] in [EMPTY, opposing_token]: | |
is_winning_column = False | |
break | |
if is_winning_column: | |
return True | |
# If we're not working with an nxn grid, | |
# there's no need to check diagonals | |
if ROWS != COLS: | |
return False | |
is_winning_diagonal = True | |
for i in xrange(ROWS): | |
if self.board[i][i] in [EMPTY, opposing_token]: | |
is_winning_diagonal = False | |
break | |
if is_winning_diagonal: | |
return True | |
is_winning_diagonal = True | |
for i in xrange(ROWS): | |
if self.board[i][COLS-i-1] in [EMPTY, opposing_token]: | |
is_winning_diagonal = False | |
break | |
if is_winning_diagonal: | |
return True | |
return False | |
def _is_full(self): | |
for i in xrange(ROWS): | |
if EMPTY in self.board[i]: | |
return False | |
return True | |
def play_turn(self, x, y): | |
self._add_token(x, y, USER_MOVE if self.is_human_turn else AI_MOVE) | |
self.is_human_turn = not self.is_human_turn | |
def display(self): | |
for i in xrange(ROWS): | |
print "|".join(self.board[i]) | |
def is_taken(self, row, column): | |
return self.board[row][column] != EMPTY | |
def make_ai_move(self): | |
assert not self._is_full() | |
while True: | |
try: | |
r = random.randint(0, ROWS-1) | |
c = random.randint(0, COLS-1) | |
self.play_turn(r, c) | |
except Exception: | |
continue | |
break | |
def has_ended(self): | |
return self._is_full() or self._has_anyone_won() | |
def find_winner(self): | |
if not self._has_anyone_won() and self._is_full(): | |
return 0 | |
if self._has_won(USER_MOVE): | |
return 1 | |
if self._has_won(AI_MOVE): | |
return -1 | |
def play_move(): | |
if ttt.is_human_turn: | |
try: | |
user_move_row = int(raw_input('Enter row (0-2): ')) | |
user_move_col = int(raw_input('Enter col (0-2): ')) | |
except ValueError: | |
print "Error: Grid location co-ordinates invalid" | |
return | |
if (user_move_row < 0 or user_move_row >= ROWS or | |
user_move_col < 0 or user_move_col >= COLS): | |
print "Error: Grid location co-ordinates out of range" | |
return | |
if ttt.is_taken(user_move_row, user_move_col): | |
print "Error: Space already taken" | |
return | |
ttt.play_turn(user_move_row, user_move_col) | |
else: | |
ttt.make_ai_move() | |
ttt.display() | |
if __name__ == "__main__": | |
ttt = TicTacToe(is_human_start=True) | |
while not ttt.has_ended(): | |
play_move() | |
result = ttt.find_winner() | |
if result == 1: | |
print "Congratulations. You won!" | |
elif result == 0: | |
print "This game was a draw" | |
else: | |
print "You lost. Please try again" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment