INITIAL COMMIT
This commit is contained in:
commit
28c83baa29
6 changed files with 383 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
__pycache__
|
||||||
|
*.pyc
|
19
setup.py
Normal file
19
setup.py
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
try:
|
||||||
|
from setuptools import setup
|
||||||
|
except ImportError:
|
||||||
|
from distutils.core import setup
|
||||||
|
|
||||||
|
config = {
|
||||||
|
'description': 'Super awesome Tic Tac Toe game',
|
||||||
|
'author': 'Magnus Walbeck',
|
||||||
|
'url': '',
|
||||||
|
'download_url': '',
|
||||||
|
'author_email': 'mw@mwalbeck.org',
|
||||||
|
'version': '0.1',
|
||||||
|
'install_requires': [''],
|
||||||
|
'packages': ['tictactoe'],
|
||||||
|
'scripts': [],
|
||||||
|
'name': 'tictactoe'
|
||||||
|
}
|
||||||
|
|
||||||
|
setup(**config)
|
5
tictactoe/__init__.py
Normal file
5
tictactoe/__init__.py
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import menu
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
menu.mainMenu()
|
142
tictactoe/ai.py
Normal file
142
tictactoe/ai.py
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
import random
|
||||||
|
import game
|
||||||
|
|
||||||
|
|
||||||
|
def chooseRandomMove(board, moves):
|
||||||
|
possible_move = []
|
||||||
|
for move in moves:
|
||||||
|
if game.validMove(board, move):
|
||||||
|
possible_move.append(move)
|
||||||
|
|
||||||
|
if possible_move:
|
||||||
|
return random.choice(possible_move)
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def cornerMove(board):
|
||||||
|
return chooseRandomMove(board, [1, 3, 7, 9])
|
||||||
|
|
||||||
|
|
||||||
|
def edgeMove(board):
|
||||||
|
return chooseRandomMove(board, [2, 4, 6, 8])
|
||||||
|
|
||||||
|
|
||||||
|
def randomFirstMove(board):
|
||||||
|
move = random.randint(1, 3)
|
||||||
|
|
||||||
|
if move == 1:
|
||||||
|
return edgeMove(board)
|
||||||
|
|
||||||
|
if move == 2:
|
||||||
|
return cornerMove(board)
|
||||||
|
|
||||||
|
if move == 3:
|
||||||
|
return 5
|
||||||
|
|
||||||
|
|
||||||
|
def getBoardCopy(board):
|
||||||
|
return board[:]
|
||||||
|
|
||||||
|
|
||||||
|
def whichTurn(board):
|
||||||
|
turn_count = 0
|
||||||
|
for space in board:
|
||||||
|
if space == "X" or space == "O":
|
||||||
|
turn_count += 1
|
||||||
|
|
||||||
|
return turn_count + 1
|
||||||
|
|
||||||
|
|
||||||
|
def wentFirst(board):
|
||||||
|
x_count = 0
|
||||||
|
o_count = 0
|
||||||
|
|
||||||
|
for space in board:
|
||||||
|
if space == "X":
|
||||||
|
x_count += 1
|
||||||
|
if space == "O":
|
||||||
|
o_count += 1
|
||||||
|
|
||||||
|
if x_count == o_count:
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def testCanWin(board, player, move):
|
||||||
|
board_copy = getBoardCopy(board)
|
||||||
|
game.makeMove(board_copy, player, move)
|
||||||
|
if game.hasWon(board_copy, player):
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def testCanFork(board, player, move):
|
||||||
|
board_copy = getBoardCopy(board)
|
||||||
|
board_copy[move - 1] = player
|
||||||
|
winning_moves = 0
|
||||||
|
for i in range(1, 10):
|
||||||
|
if game.validMove(board_copy, i) and testCanWin(board_copy, player, i):
|
||||||
|
winning_moves += 1
|
||||||
|
|
||||||
|
return winning_moves >= 2
|
||||||
|
|
||||||
|
|
||||||
|
def getComputerMove(board, player):
|
||||||
|
if player == "X":
|
||||||
|
opponent = "O"
|
||||||
|
else:
|
||||||
|
opponent = "X"
|
||||||
|
# If Ai goes first, play certain moves
|
||||||
|
if whichTurn(board) == 1:
|
||||||
|
return randomFirstMove(board)
|
||||||
|
|
||||||
|
# Check if AI can win with the next move
|
||||||
|
for i in range(1, 10):
|
||||||
|
if game.validMove(board, i) and testCanWin(board, player, i):
|
||||||
|
return i
|
||||||
|
|
||||||
|
# Check if Player can win with next move, so we can block them
|
||||||
|
for i in range(1, 10):
|
||||||
|
if game.validMove(board, i) and testCanWin(board, opponent, i):
|
||||||
|
return i
|
||||||
|
|
||||||
|
# Check AI fork moves
|
||||||
|
for i in range(1, 10):
|
||||||
|
if game.validMove(board, i) and testCanFork(board, player, i):
|
||||||
|
return i
|
||||||
|
|
||||||
|
# Check Player fork moves
|
||||||
|
opponent_forks = 0
|
||||||
|
for i in range(1, 10):
|
||||||
|
if game.validMove(board, i) and testCanFork(board, opponent, i):
|
||||||
|
opponent_forks += 1
|
||||||
|
temp_move = i
|
||||||
|
|
||||||
|
if opponent_forks == 1:
|
||||||
|
return temp_move
|
||||||
|
|
||||||
|
if opponent_forks == 2 and wentFirst(board):
|
||||||
|
|
||||||
|
if board[2 - 1] == player or board[8 - 1] == player:
|
||||||
|
return chooseRandomMove(board, [4, 6])
|
||||||
|
|
||||||
|
if board[4 - 1] == player or board[6 - 1] == player:
|
||||||
|
return chooseRandomMove(board, [2, 8])
|
||||||
|
|
||||||
|
if opponent_forks == 2:
|
||||||
|
return edgeMove(board)
|
||||||
|
|
||||||
|
# Take the center if free
|
||||||
|
if game.validMove(board, 5):
|
||||||
|
return 5
|
||||||
|
|
||||||
|
# Take a corner if free
|
||||||
|
move = cornerMove(board)
|
||||||
|
if move is not False:
|
||||||
|
return move
|
||||||
|
|
||||||
|
# Take a side
|
||||||
|
return edgeMove(board)
|
149
tictactoe/game.py
Normal file
149
tictactoe/game.py
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
import os
|
||||||
|
import menu
|
||||||
|
import ai
|
||||||
|
import random
|
||||||
|
|
||||||
|
|
||||||
|
def hasWon(board, player):
|
||||||
|
win_cons = [
|
||||||
|
(0, 1, 2),
|
||||||
|
(3, 4, 5),
|
||||||
|
(6, 7, 8),
|
||||||
|
(0, 3, 6),
|
||||||
|
(1, 4, 7),
|
||||||
|
(2, 5, 8),
|
||||||
|
(0, 4, 8),
|
||||||
|
(2, 4, 6),
|
||||||
|
]
|
||||||
|
|
||||||
|
for win_con in win_cons:
|
||||||
|
if (
|
||||||
|
board[win_con[0]] == player
|
||||||
|
and board[win_con[1]] == player
|
||||||
|
and board[win_con[2]] == player
|
||||||
|
):
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def isDraw(board):
|
||||||
|
for space in board:
|
||||||
|
if space != "X" and space != "O":
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def printBoard(board):
|
||||||
|
os.system("clear")
|
||||||
|
print("\n" * 9)
|
||||||
|
print(f"{board[0]}|{board[1]}|{board[2]}".center(80, " "))
|
||||||
|
print("-+-+-".center(80, " "))
|
||||||
|
print(f"{board[3]}|{board[4]}|{board[5]}".center(80, " "))
|
||||||
|
print("-+-+-".center(80, " "))
|
||||||
|
print(f"{board[6]}|{board[7]}|{board[8]}\n".center(80, " "))
|
||||||
|
print("\n" * 8)
|
||||||
|
|
||||||
|
|
||||||
|
def validInput(player_input):
|
||||||
|
if not player_input.isnumeric():
|
||||||
|
return False
|
||||||
|
|
||||||
|
if not int(player_input) > 0 or not int(player_input) < 10:
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def validMove(board, player_input):
|
||||||
|
if board[player_input - 1] != "X" and board[player_input - 1] != "O":
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def makeMove(board, player, player_input):
|
||||||
|
board[player_input - 1] = player
|
||||||
|
|
||||||
|
|
||||||
|
def playAgain():
|
||||||
|
print("Do you want to play again? (Y/N)")
|
||||||
|
user_input = input("> ")
|
||||||
|
|
||||||
|
if user_input == "y" or user_input == "Y":
|
||||||
|
return True
|
||||||
|
|
||||||
|
menu.mainMenu()
|
||||||
|
|
||||||
|
|
||||||
|
def getPlayerMove(player, board):
|
||||||
|
while True:
|
||||||
|
print(f"Player {player}'s turn:")
|
||||||
|
player_input = input("> ")
|
||||||
|
|
||||||
|
if not validInput(player_input):
|
||||||
|
print("Please type in a number between 1 and 9.")
|
||||||
|
continue
|
||||||
|
|
||||||
|
clean_input = int(player_input)
|
||||||
|
|
||||||
|
if validMove(board, clean_input):
|
||||||
|
return clean_input
|
||||||
|
|
||||||
|
print("This spot is already taken, please pick another.")
|
||||||
|
|
||||||
|
|
||||||
|
def playGame(with_ai):
|
||||||
|
player = random.choice(["X", "O"])
|
||||||
|
board = list(range(1, 10))
|
||||||
|
|
||||||
|
while True:
|
||||||
|
printBoard(board)
|
||||||
|
|
||||||
|
if player == "X":
|
||||||
|
makeMove(board, player, getPlayerMove(player, board))
|
||||||
|
|
||||||
|
if player == "O" and with_ai:
|
||||||
|
makeMove(board, player, ai.getComputerMove(board, player))
|
||||||
|
elif player == "O":
|
||||||
|
makeMove(board, player, getPlayerMove(player, board))
|
||||||
|
|
||||||
|
if hasWon(board, player):
|
||||||
|
printBoard(board)
|
||||||
|
print(f"Player {player} has won!!!!!!!!!!!!!!!!!!!!!")
|
||||||
|
if playAgain():
|
||||||
|
playGame(with_ai)
|
||||||
|
break
|
||||||
|
|
||||||
|
if isDraw(board):
|
||||||
|
printBoard(board)
|
||||||
|
print("It's a draw!")
|
||||||
|
if playAgain():
|
||||||
|
playGame(with_ai)
|
||||||
|
break
|
||||||
|
|
||||||
|
if player == "X":
|
||||||
|
player = "O"
|
||||||
|
else:
|
||||||
|
player = "X"
|
||||||
|
|
||||||
|
|
||||||
|
def playTestAi(start_player):
|
||||||
|
player = start_player
|
||||||
|
board = list(range(1, 10))
|
||||||
|
|
||||||
|
while True:
|
||||||
|
if player == "X":
|
||||||
|
makeMove(board, player, ai.getComputerMove(board, player))
|
||||||
|
|
||||||
|
if player == "O":
|
||||||
|
makeMove(board, player, ai.getComputerMove(board, player))
|
||||||
|
|
||||||
|
if hasWon(board, player):
|
||||||
|
return player
|
||||||
|
|
||||||
|
if isDraw(board):
|
||||||
|
return "draw"
|
||||||
|
|
||||||
|
if player == "X":
|
||||||
|
player = "O"
|
||||||
|
else:
|
||||||
|
player = "X"
|
66
tictactoe/menu.py
Normal file
66
tictactoe/menu.py
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
import os
|
||||||
|
import game
|
||||||
|
|
||||||
|
|
||||||
|
def mainMenu():
|
||||||
|
os.system("clear")
|
||||||
|
print("\n" * 9)
|
||||||
|
print("Welcome to the Tic Tackity Toe".center(80, " "))
|
||||||
|
print("[1] Player vs AI ".center(80, " "))
|
||||||
|
print("[2] Player vs Player".center(80, " "))
|
||||||
|
print("[3] Play test AI ".center(80, " "))
|
||||||
|
print("[4] Exit game ".center(80, " "))
|
||||||
|
print("\n" * 9)
|
||||||
|
|
||||||
|
while True:
|
||||||
|
player_input = input("> ")
|
||||||
|
|
||||||
|
if player_input == "1":
|
||||||
|
with_ai = True
|
||||||
|
game.playGame(with_ai)
|
||||||
|
|
||||||
|
if player_input == "2":
|
||||||
|
with_ai = False
|
||||||
|
game.playGame(with_ai)
|
||||||
|
|
||||||
|
if player_input == "3":
|
||||||
|
print(playTest())
|
||||||
|
|
||||||
|
if player_input == "4":
|
||||||
|
exit()
|
||||||
|
|
||||||
|
|
||||||
|
def playTest():
|
||||||
|
# Player first
|
||||||
|
player_win = 0
|
||||||
|
player_lose = 0
|
||||||
|
player_draw = 0
|
||||||
|
for i in range(1, 10001):
|
||||||
|
result = game.playTestAi("X")
|
||||||
|
|
||||||
|
if result == "draw":
|
||||||
|
player_draw += 1
|
||||||
|
|
||||||
|
if result == "O":
|
||||||
|
player_win += 1
|
||||||
|
|
||||||
|
if result == "X":
|
||||||
|
player_lose += 1
|
||||||
|
|
||||||
|
# Ai first
|
||||||
|
ai_win = 0
|
||||||
|
ai_lose = 0
|
||||||
|
ai_draw = 0
|
||||||
|
for i in range(1, 10001):
|
||||||
|
result = game.playTestAi("O")
|
||||||
|
|
||||||
|
if result == "draw":
|
||||||
|
ai_draw += 1
|
||||||
|
|
||||||
|
if result == "O":
|
||||||
|
ai_win += 1
|
||||||
|
|
||||||
|
if result == "X":
|
||||||
|
ai_lose += 1
|
||||||
|
|
||||||
|
return f"Player first - Wins: {player_win}, Draw: {player_draw}, Loss {player_lose}\nAi first - Wins: {ai_win}, Draw: {ai_draw}, Loss {ai_lose}"
|
Loading…
Add table
Reference in a new issue