├── README.md ├── Nodes.py ├── main.py ├── Algorithm.py ├── DotsNBoxes.py └── Board.py /README.md: -------------------------------------------------------------------------------- 1 | # Dots-Boxes 2 | Playing Dots and Boxes in Python with AI. You play the game against artificial intelligence with the option to choose the board size. You can also choose different plys (how deep the search algorithm goes into the search tree). AI uses two methods of Min-Max and Alpha-Beta Pruning to defeat you. 3 | -------------------------------------------------------------------------------- /Nodes.py: -------------------------------------------------------------------------------- 1 | class Thing: # A class for Node related operations 2 | def __init__(self, currentState): 3 | self.Current = currentState 4 | self.CurrentScore = 0 5 | self.children = {} 6 | 7 | def Make(self, i, j, player): # Function for generating a child node 8 | self.children[(i, j)] = Thing(self.Current.Get_currentState()) 9 | mul = 1 10 | if player: 11 | mul *= -1 12 | self.children[(i, j)].CurrentScore = (self.children[(i, j)].Current.action(i, j) * mul) + self.CurrentScore 13 | 14 | def Populate(self, i, j, Child): # Function for adding a node 15 | self.children[(i,j)] = Child 16 | 17 | def Draw(self): # function for drawing the board 18 | self.Current.Draw_mat() 19 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | from Algorithm import * 2 | from DotsNBoxes import * 3 | from Board import * 4 | from Nodes import * 5 | 6 | def main(): 7 | while True: 8 | 9 | print("\t\t!! Welcome to the game of Dots and Boxes !!\n\n Be prepared to be crushed by the power of Artificial Intelligence ... !!\n\n\ 10 | Kidding! You totally can beat it!\n\n\n") 11 | 12 | x = input("Press 1 to start the game or press 2 to escape from the inevitable doom!!\n\n") 13 | if x == "1": 14 | 15 | Board_Xdim = int(input("\nPlease enter the number of rows for the board: \n")) * 2 + 1 16 | 17 | if Board_Xdim < 5: 18 | print("\nthe number of rows should atleast be 2\n") 19 | exit() 20 | 21 | Board_Ydim = int(input("\nPlease enter the number of columns for the board: \n")) * 2 + 1 22 | 23 | if Board_Ydim < 5: 24 | print("\nthe number of columns should atleast be 2\n") 25 | exit() 26 | 27 | Ply_num = int(input("\nPlease enter the number of plies used by the AI: \n")) 28 | 29 | if Ply_num < 2: 30 | print("\nThe number of plies should be higher than 1\n") 31 | exit() 32 | 33 | Match = DotsNBoxes(Board_Xdim, Board_Ydim, Ply_num) 34 | Match.start() 35 | else: 36 | print ("\n\nEscape it is!") 37 | exit() 38 | 39 | if __name__ == "__main__": 40 | main() 41 | -------------------------------------------------------------------------------- /Algorithm.py: -------------------------------------------------------------------------------- 1 | 2 | class Algo: # A class for defining algorithms used (minimax and alpha-beta pruning) 3 | 4 | def miniMax(State, Ply_num): # Function for the minimax algorithm 5 | 6 | for i in range(State.Current.dimY): 7 | for j in range(State.Current.dimX): 8 | if State.Current.Mat[i][j] == ' ' and (j, i) not in State.children: 9 | State.Make(j, i, True) 10 | if Ply_num < 2: 11 | return (i, j) 12 | 13 | Minimum_Score = 1000 14 | i = 0 15 | j = 0 16 | for k, z in State.children.items(): 17 | Result = Algo.Maximum(z, Ply_num - 1, Minimum_Score) 18 | if Minimum_Score > Result: 19 | Minimum_Score = Result 20 | i = k[0] 21 | j = k[1] 22 | 23 | return (i, j) 24 | 25 | 26 | def Maximum(State, Ply_num, Alpha): # Alpha-beta pruning function for taking care of Alpha values 27 | if Ply_num == 0: 28 | return State.CurrentScore 29 | 30 | for i in range(State.Current.dimY): 31 | for j in range(State.Current.dimX): 32 | if State.Current.Mat[i][j] == ' ' and (j, i) not in State.children: 33 | State.Make(j, i, False) 34 | 35 | Maximum_Score = -1000 36 | i = 0 37 | j = 0 38 | for k, z in State.children.items(): 39 | Result = Algo.Minimum(z, Ply_num - 1, Maximum_Score) 40 | if Maximum_Score < Result: 41 | Maximum_Score = Result 42 | if Result > Alpha: 43 | return Result 44 | 45 | return Maximum_Score 46 | 47 | 48 | def Minimum(State, Ply_num, Beta): # Alpha-beta pruning function for taking care of Beta values 49 | if Ply_num == 0: 50 | return State.CurrentScore 51 | 52 | for i in range(State.Current.dimY): 53 | for j in range(State.Current.dimX): 54 | if State.Current.Mat[i][j] == ' ' and (j, i) not in State.children: 55 | State.Make(j, i, True) 56 | 57 | Minimum_Score = 1000 58 | i = 0 59 | j = 0 60 | for k, z in State.children.items(): 61 | Result = Algo.Maximum(z, Ply_num - 1, Minimum_Score) 62 | if Minimum_Score > Result: 63 | Minimum_Score = Result 64 | if Result < Beta: 65 | return Result 66 | 67 | return Minimum_Score 68 | -------------------------------------------------------------------------------- /DotsNBoxes.py: -------------------------------------------------------------------------------- 1 | from random import * 2 | import collections 3 | from Algorithm import * 4 | from Board import * 5 | from Nodes import * 6 | 7 | 8 | class DotsNBoxes: # A class for managing the moves made by the human and the computer 9 | def __init__(self, Board_Xdim, Board_Ydim, Ply_num): 10 | currentState = Game([], Board_Xdim, Board_Ydim) 11 | currentState.Initiate() 12 | self.State = Thing(currentState) 13 | self.Ply_num = Ply_num 14 | self.Score = 0 15 | 16 | def Human(self): # Defining the Human player and his actions/Choices 17 | self.State.Draw() 18 | 19 | HumanX = int(input("Please enter the 'X' coordinate of your choice (an integer such as 4): ")) 20 | HumanY = int(input("Please enter the 'Y' coordinate of your choice (an integer such as 4): ")) 21 | if (HumanX, HumanY) not in self.State.children: 22 | self.State.Make(HumanX, HumanY, False) 23 | self.State = self.State.children[(HumanX, HumanY)] 24 | else: 25 | self.State = self.State.children[(HumanX, HumanY)] 26 | 27 | print("Current Score =====>> Your Score - AI Score = " + str(self.State.CurrentScore),end ="\n\n\n") 28 | 29 | self.Computer() 30 | 31 | 32 | def Computer(self): # Defining the Computer player and its actions/Choices 33 | self.State.Draw() 34 | 35 | move = Algo.miniMax(self.State, self.Ply_num) 36 | 37 | self.State = self.State.children[(move[0], move[1])] 38 | 39 | print("AI selected the following coordinates to play:\n" + "(" ,str(move[0]), ", " + str(move[1]), ")", end = "\n\n") 40 | 41 | print("Current Score =====>> Your Score - AI Score = " + str(self.State.CurrentScore), end = "\n\n\n") 42 | 43 | if len(self.State.children) == 0: 44 | self.State.Draw() 45 | self.Evaluation() 46 | return 47 | 48 | self.Human() 49 | 50 | def Evaluation(self): # Evaluation function for taking care of the final scores 51 | print("Stop this Madness!!!\n") 52 | if self.State.CurrentScore > 0: 53 | print("You won you crazy little unicorn!! You are the new hope for the mankind!") 54 | exit() 55 | elif self.State.CurrentScore < 0: 56 | print("!!! Inevitable Doom!!! You were crushed by the AI!! ") 57 | exit() 58 | else: 59 | print("Draw! Well Congratulations! you are as smart as the AI!") 60 | exit() 61 | 62 | def start(self): 63 | self.Human() 64 | -------------------------------------------------------------------------------- /Board.py: -------------------------------------------------------------------------------- 1 | from random import * 2 | 3 | 4 | class Game: #A class for managing different situations and states happening in the game and on the board 5 | def __init__(self, Mat, dimX, dimY): 6 | self.Mat = Mat 7 | self.dimX = dimX 8 | self.dimY = dimY 9 | 10 | def Initiate(self): #initiating the game board with X and Y dimensions 11 | for i in range(0, self.dimY): 12 | R = [] 13 | for j in range (0, self.dimX): 14 | if i % 2 == 1 and j % 2 == 1: 15 | R.append(randint(1, 9)) # Assigning a random number from 1 to 9 to the spots in the board as the points 16 | elif i % 2 == 0 and j % 2 == 0: 17 | R.append('*') # printing asterisks as the dots in the board 18 | else: 19 | R.append(' ') # adding extra space for actions in the game 20 | self.Mat.append(R) 21 | 22 | def Get_matrix(self): # Board matrix 23 | ans = [] 24 | for i in range(0, self.dimY): 25 | R = [] 26 | for j in range(0, self.dimX): 27 | R.append(self.Mat[i][j]) 28 | ans.append(R) 29 | return ans 30 | 31 | def Draw_mat(self): # Drawing the board marix as dots and lines 32 | 33 | if self.dimX > 9: 34 | print(" ", end='') 35 | print(" ", end='') 36 | for i in range(0, self.dimX): 37 | print(str(i), end=' ') 38 | print() 39 | 40 | if self.dimX > 9: 41 | print(" ", end='') 42 | print(" ", end='') 43 | for i in range(0, self.dimX + 1): 44 | print("___", end='') 45 | print() 46 | for j in range(self.dimY): 47 | if self.dimX > 9 and j < 10: 48 | print(" ", end='') 49 | print(str(j) + "| ", end='') 50 | for z in range(self.dimX): 51 | print(str(self.Mat[j][z]), end=' ') 52 | print() 53 | print(" _________________________\n") 54 | 55 | def Get_currentState(self): 56 | return Game(self.Get_matrix(), self.dimX, self.dimY) 57 | 58 | def action(self, i, j): # Applying the actions made by the human or the computer 59 | Sum = 0 60 | 61 | if j % 2 == 0 and i % 2 == 1: 62 | self.Mat[j][i] = '-' 63 | if j < self.dimY - 1: 64 | if self.Mat[j+2][i] == '-' and self.Mat[j+1][i+1] == '|' and self.Mat[j+1][i-1] == '|': 65 | Sum += self.Mat[j+1][i] 66 | if j > 0: 67 | if self.Mat[j-2][i] == '-' and self.Mat[j-1][i+1] == '|' and self.Mat[j-1][i-1] == '|': 68 | Sum += self.Mat[j-1][i] 69 | 70 | else: 71 | self.Mat[j][i] = '|' 72 | if i < self.dimX - 1: 73 | if self.Mat[j][i+2] == '|' and self.Mat[j+1][i+1] == '-' and self.Mat[j-1][i+1] == '-': 74 | Sum += self.Mat[j][i+1] 75 | if i > 0: 76 | if self.Mat[j][i-2] == '|' and self.Mat[j+1][i-1] == '-' and self.Mat[j-1][i-1] == '-': 77 | Sum += self.Mat[j][i-1] 78 | return Sum 79 | --------------------------------------------------------------------------------