Sep-02-2020, 08:30 PM
Seeing the recent tic-tac-toe thread in general programming made me curious about writing tic-tac-toe with a computer player. Here is the result:
Number of players can be 0, 1, or 2. The computer will play all the non-players.
import random board = [] lines = ((0, 1, 2), (3, 4, 5), (6, 7, 8), (0, 3, 6), (1, 4, 7), (2, 5, 8), (0, 4, 8), (2, 4, 6)) corners = (0, 8, 2, 6) corner_pairs = ((0, 8), (2, 6), (0, 2), (2, 8), (8, 6), (0, 6)) for count in range(9): board.append(str(count + 1)) pieces = ["X", "O"] human_players = {"X": False, "O": False} def draw_board(): for row in range(0, 9, 3): print(f"{board[0 + row]}|{board[1 + row]}|{board[2+row]}") if row < 6: print("-----") def winner(): for line in lines: if board[line[0]] == board[line[1]] and board[line[0]] == board[line[2]]: return True return False def computer_turn(piece): opponent = [x for x in pieces if x != piece][0] # 2nd turn to a corner open, select center used_squares = {piece: [], opponent: []} for index, square in enumerate(board): if square in pieces: used_squares[square].append(index) num_used = len(used_squares[piece]) + len(used_squares[opponent]) if num_used == 1 and len(used_squares[opponent]) == 1: used = used_squares[opponent][0] if used in corners: board[4] = piece return # 4th turn to opposing corners, select any edge square if num_used == 3 and len(used_squares[opponent]) == 2: if used_squares[opponent][0] in corner_pairs[0] and used_squares[opponent][1] in corner_pairs[0] or used_squares[opponent][0] in corner_pairs[1] and used_squares[opponent][1] in corner_pairs[1]: board[random.choice([1, 3, 5, 7])] = piece return # for the win, then the block for player in [piece, opponent]: for line in lines: for shuffle in range(3): if board[line[0]] == player: if board[line[1]] == player and board[line[2]] not in pieces: board[line[2]] = piece return elif board[line[2]] == player and board[line[1]] not in pieces: board[line[1]] = piece return line = (line[1], line[2], line[0]) # Get a second corner opposite, then adjacent for pair in corner_pairs: if board[pair[0]] == piece and board[pair[1]] not in pieces: board[pair[1]] = piece return if board[pair[1]] == piece and board[pair[0]] not in pieces: board[pair[0]] = piece return # pick any available corner available_corners = [corner for corner in corners if board[corner] not in pieces] if len(available_corners) > 0: board[random.choice(available_corners)] = piece return # pick any remaining square choice = piece while choice in pieces: choice = random.choice(board) board[int(choice) - 1] = piece def tic_tac_toe(): for turn in range(9): piece = pieces[turn % 2] draw_board() square = -1 if not human_players[piece]: computer_turn(piece) else: while square not in board and square not in pieces: square = input(f"\n{piece}'s turn, select a square: ") board[int(square) - 1] = piece print() if winner(): print(f"{piece} is the winner") break else: if turn == 8: print("It's a draw") draw_board() def main(): num_players = int(input("Number of players: ")) if num_players == 1: print("Select a piece") print("1) X") print("2) O") human_players["X" if int(input(":")) == 1 else "O"] = True elif num_players == 2: human_players["X"] = True human_players["O"] = True tic_tac_toe() main()Try and beat the computer. Let me know what you think. Can it be improved or simplified?
Number of players can be 0, 1, or 2. The computer will play all the non-players.