├── LICENSE ├── README.md ├── TicTacToeMaster.py ├── test.py └── unbeatableBot.py /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Navdeesh Ahuja 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Python TicTacToe Best Move Generator 2 | 3 | A Python script to generate the best move for the TicTacToe Game. 4 | Uses the Backtracking technique to make unbeatable moves. 5 | Feel free to make changes :) 6 | 7 | ## Demo 8 | ``` python 9 | >>> import TicTacToeMaster as ttt 10 | 11 | >>> board, nextMove = ttt.getRandomBoard() 12 | >>> ttt.printBoard(board) 13 | >>> 14 | _ _ _ 15 | O X _ 16 | O O X 17 | 18 | >>> bestMove = ttt.getAIMove(board, nextMove, nextMove) 19 | >>> print(nextMove+" should play at: " + str(bestMove[0]) + " index") 20 | >>> 21 | X should play at: 0 index 22 | 23 | >>> board = [" ", " ", "X", " ", "O", " ", "X", " ", " "] 24 | >>> bestMovePosition = ttt.getAIMove(board, "O", "O")[0] 25 | >>> print("O should play at: " + str(bestMovePosition) + " index") 26 | >>> 27 | O should play at: 1 index 28 | 29 | ``` 30 | 31 | ## Installation 32 | 33 | Just Copy the TicTacToeMaster.py in your project and you are good to go 34 | 35 | ## Dependencies 36 | 37 | None, pure python code. 38 | 39 | ## Usage 40 | ``` python 41 | import TicTacToeMaster as ttt 42 | 43 | board = [" ", " ", "X", " ", "O", " ", "X", " ", " "] 44 | ttt.printBoard(board) 45 | aiPlayer = "O" 46 | bestMove = ttt.getAIMove(board, aiPlayer, aiPlayer) 47 | bestPosition = str(bestMove[0]) 48 | print(aiPlayer + " should play at " + bestPosition + " index") 49 | ``` 50 | 51 | ## Unbeatable Bot 52 | ``` python 53 | 54 | >>> 55 | Where do you want to play X: 7 56 | 57 | 58 | _ _ _ 59 | _ O _ 60 | X _ _ 61 | 62 | Where do you want to play X: 3 63 | 64 | 65 | _ O X 66 | _ O _ 67 | X _ _ 68 | 69 | Where do you want to play X: 8 70 | 71 | 72 | _ O X 73 | _ O _ 74 | X X O 75 | 76 | Where do you want to play X: 1 77 | 78 | 79 | X O X 80 | O O _ 81 | X X O 82 | 83 | Where do you want to play X: 6 84 | 85 | 86 | X O X 87 | O O X 88 | X X O 89 | 90 | ``` 91 | 92 | ## License 93 | MIT License 94 | 95 | Copyright (c) 2017 Navdeesh Ahuja 96 | 97 | Permission is hereby granted, free of charge, to any person obtaining a copy 98 | of this software and associated documentation files (the "Software"), to deal 99 | in the Software without restriction, including without limitation the rights 100 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 101 | copies of the Software, and to permit persons to whom the Software is 102 | furnished to do so, subject to the following conditions: 103 | 104 | The above copyright notice and this permission notice shall be included in all 105 | copies or substantial portions of the Software. 106 | 107 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 108 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 109 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 110 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 111 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 112 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 113 | SOFTWARE. -------------------------------------------------------------------------------- /TicTacToeMaster.py: -------------------------------------------------------------------------------- 1 | from random import randint 2 | 3 | def checkWin(board, player): 4 | for i in range(0, 7, 3): 5 | if(board[i] == player and board[i+1] == player and board[i+2] == player): 6 | return True 7 | for i in range(0, 3): 8 | if(board[i] == player and board[i+3] == player and board[i+6] == player): 9 | return True 10 | if(board[0] == player and board[4] == player and board[8] == player): 11 | return True 12 | if(board[2] == player and board[4] == player and board[6] == player): 13 | return True 14 | return False 15 | 16 | def checkLose(board, player): 17 | if(player == "X"): 18 | opponent = "O" 19 | else: 20 | opponent = "X" 21 | if(checkWin(board, opponent)): 22 | return True 23 | return False 24 | 25 | def checkTie(board): 26 | for x in board: 27 | if(x == " "): 28 | return False 29 | return True 30 | 31 | 32 | def getAIMove(board, nextMove, aiPlayer): 33 | if(checkWin(board, aiPlayer)): 34 | return (-1, 10) 35 | elif(checkLose(board, aiPlayer)): 36 | return (-1, -10) 37 | elif(checkTie(board)): 38 | return (-1, 0) 39 | 40 | moves = [] 41 | 42 | for i in range(len(board)): 43 | if(board[i] == " "): 44 | board[i] = nextMove 45 | 46 | score = getAIMove(board, ("X" if nextMove == "O" else "O"), aiPlayer)[1] 47 | moves.append((i, score)) 48 | board[i] = " " 49 | 50 | 51 | if(nextMove == aiPlayer): 52 | maxScore = moves[0][1] 53 | bestMove = moves[0] 54 | for move in moves: 55 | if(move[1] > maxScore): 56 | bestMove = move 57 | maxScore = move[1] 58 | return bestMove 59 | else: 60 | minScore = moves[0][1] 61 | worstMove = moves[0] 62 | for move in moves: 63 | if(move[1] < minScore): 64 | worstMove = move 65 | minScore = move[1] 66 | return worstMove 67 | 68 | 69 | 70 | def getRandomBoard(): 71 | filledPositions = randint(2, 8) 72 | board = [" " for _ in range(9)] 73 | r = randint(0, 1) 74 | moves = ["X", "O"] 75 | nextMove = moves[r] 76 | for i in range(filledPositions): 77 | pos = randint(0, 8) 78 | while(board[pos] != " "): 79 | pos = randint(0, 8) 80 | board[pos] = nextMove 81 | if(nextMove == "X"): 82 | nextMove = "O" 83 | else: 84 | nextMove = "X" 85 | return (board, nextMove) 86 | 87 | def printBoard(board): 88 | print("\n") 89 | for i in range(9): 90 | if(not board[i] == " "): 91 | print(board[i], end=" ") 92 | else: 93 | print("_", end=" ") 94 | if(i==2 or i==5): 95 | print("") 96 | print("\n") 97 | 98 | -------------------------------------------------------------------------------- /test.py: -------------------------------------------------------------------------------- 1 | import TicTacToeMaster as ttt 2 | 3 | board, nextMove = ttt.getRandomBoard() 4 | print(board) 5 | ttt.printBoard(board) 6 | bestMove = ttt.getAIMove(board, nextMove, nextMove) 7 | print(nextMove+" should play at: " + str(bestMove[0]) + " index") 8 | -------------------------------------------------------------------------------- /unbeatableBot.py: -------------------------------------------------------------------------------- 1 | import TicTacToeMaster as ttt 2 | 3 | board = [" ", " ", " ", " ", " ", " ", " ", " ", " "] 4 | 5 | while(not (ttt.checkWin(board, "O") or ttt.checkLose(board, "O") or ttt.checkTie(board))): 6 | playerPosition = int(input("Where do you want to play X: ")) - 1 7 | board[playerPosition] = "X" 8 | aiMovePosition = int(ttt.getAIMove(board, "O", "O")[0]) 9 | board[aiMovePosition] = "O" 10 | ttt.printBoard(board) 11 | --------------------------------------------------------------------------------