I wrote a simple TicTacToe console game in Python3. I would like to make my program more pythonic than it is now. For example, instead of if a == 5 and b == 5 and c == 5:
you can write if a == b == c == 5:
. So I expect hints of how can I rewrite my code to take adventage of Python language.
I don't ask for algorithm optimization (it contains some bugs, I know). The code should be rather understood for you except computer_turn()
method which simulates computer's move. But since I don't ask for optimization I don't see a need to explain what exacly happens inside this method.
You may find my code on Github.
from random import randint, choice
import time, sys, os
class TicTacToe:
board = [None for i in range(9)] # list representing game's board
turn = 1 # counter of computer's turns
def print_board(self, board = None): # printing game board
board = self.board if board == None else board
os.system("clear") # use "cls" for windows
print("|---|---|---|")
for i, cell in enumerate(board, 1):
print("| {} ".format(" " if cell == None else cell), end = "")
if i % 3 == 0:
print("|")
print("|---|---|---|")
def get_game_winner(self, board = None):
board = self.board if board == None else board
for i in range(0, 9, 3):
if board[i] == board[i + 1] == board[i + 2]:
if board[i] != None: return board[i]
for i in range(0, 3):
if board[i] == board[i + 3] == board[i + 6]:
if board[i] != None: return board[i]
if board[0] == board[4] == board[8] or board[2] == board[4] == board[6]:
if board[4] != None: return board[4]
return None
def computer_turn(self):
position = None
def get_line(cell):
if cell <= 3: return 1
if cell <= 6: return 2
return 3
if self.turn == 1:
self.turn = 2
oponent_choice = self.board.index("X")
if oponent_choice + 1 in [1, 3, 7, 9]:
position = 5 - 1
else:
position = choice([1, 3, 7, 9]) - 1
elif self.turn == 2:
self.turn = 3
for i in [1, 3, 7, 9]:
if self.board[i - 1] == "X":
if self.board[5 - 1] == "X":
position = 10 - i - 1
if self.board[position] == "O":
position = choice([item - 1 for item in [1, 3, 7, 9] if item not in [position + 1, i]])
break
for j in [1, 3, 7, 9]:
if i != j and self.board[j - 1] == "X":
position = i + (j - i) // 2 - 1
if self.board[position] == "O":
position = choice([2, 4, 6, 8]) - 1
break
for j in [2, 4, 6, 8]:
if self.board[j - 1] == "X":
diff = abs(j - i)
if get_line(i) != get_line(j) and diff == 1:
position = 5 - 1
else:
position = max(i, j) + diff
if position > 9: position = min(i, j) - diff
if self.board[position - 1] == "O": position = 5
position -= 1
if position == None:
for i in [2, 4, 6, 8]:
if self.board[i - 1] == "X":
if self.board[5 - 1] == "X":
position = 10 - i - 1
else:
position = 5 - 1
if self.turn > 2:
tmp_board = self.board[:]
candidates = [i for i in range(9) if self.board[i] == None]
for candidate in candidates:
tmp_board[candidate] = "O"
if self.get_game_winner(tmp_board) == "O":
position = candidate
break
tmp_board[candidate] = None
if position == None:
for candidate in candidates:
tmp_board[candidate] = "X"
if self.get_game_winner(tmp_board) == "X":
position = candidate
break
tmp_board[candidate] = None
if position == None: position = candidates[0]
self.board[position] = "O"
def ask_for_choice(self):
while True:
try:
print("Your choice: ", end = "")
position = int(input())
except ValueError:
print("That's not an integer!")
continue
if 1 <= position <= 9:
return position - 1
else:
print("Number must be in range 1 to 9!")
def user_turn(self):
position = self.ask_for_choice()
while self.board[position] != None:
print("This position is filled")
position = self.ask_for_choice()
self.board[position] = "X"
def is_game_finished(self):
if None not in self.board:
print("The game ended with a draw")
sys.exit()
winner = self.get_game_winner()
if winner == None: return
if winner == "X": print("You won the game!")
else: print("Computer won the game")
sys.exit()
def start(self):
self.print_board([i for i in range(1, 10)])
print()
print("Hello, the game just started!")
while True:
self.user_turn()
self.print_board()
self.is_game_finished()
time.sleep(0.5)
self.computer_turn()
self.print_board()
self.is_game_finished()
game = TicTacToe()
game.start()