Skip to content

Instantly share code, notes, and snippets.

@h2rashee
Last active May 21, 2020 07:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save h2rashee/623e67f6ebab8674bab538f616da9193 to your computer and use it in GitHub Desktop.
Save h2rashee/623e67f6ebab8674bab538f616da9193 to your computer and use it in GitHub Desktop.
Tic Tac Toe
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])
print
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