180501154 IMPLEMENTATION OF TIC-TAC-TOC GAME USING EXHAUSTIVE SEARCH EX.NO. : 1 DATE : AIM: To implement the Tic-Tac-Toc game using python. ALGORITHM : 1. Start. 2. Initialize required variables and display the rules. 3. Display the board after each player’s turn. 4. Get player’s input and update the board. 5. Check for winning condition of that player (i) If a player wins, the game ends and display the result (ii) Else, continue reading player input 6. Repeat from step 4 until all places are filled or a player wins. 7. If no player wins and all places are filled, then display “Draw” 8. Stop. SOURCE CODE : from random import choice combo_indices = [ [0, 1, 2], [3, 4, 5], [6, 7, 8], [0, 3, 6], [1, 4, 7], [2, 5, 8], [0, 4, 8], [2, 4, 6] ] EMPTY_SIGN = '.' AI_SIGN = 'X' OPPONENT_SIGN = 'O' def print_board(board): print(" ") print(' '.join(board[:3])) print(' '.join(board[3:6])) print(' '.join(board[6:])) print(" ") def opponent_move(board, row, column): index = 3 * (row - 1) + (column - 1) if board[index] == EMPTY_SIGN: return board[:index] + OPPONENT_SIGN + board[index+1:] return board 1 180501154 def all_moves_from_board_list(board, sign): move_list = [] for i, v in enumerate(board): if v == EMPTY_SIGN: move_list.append(board[:i] + sign + board[i+1:]) return move_list def ai_move(board): return choice(all_moves_from_board_list(board, AI_SIGN)) def game_won_by(board): for index in combo_indices: if board[index[0]] == board[index[1]] == board[index[2]] != EMPTY_SIGN: return board[index[0]] return EMPTY_SIGN def game_loop(): board = EMPTY_SIGN * 9 empty_cell_count = 9 is_game_ended = False while empty_cell_count > 0 and not is_game_ended: if empty_cell_count % 2 == 1: board = ai_move(board) else: row = int(input('Enter row: ')) col = int(input('Enter column: ')) board = opponent_move(board, row, col) print_board(board) is_game_ended = game_won_by(board) != EMPTY_SIGN empty_cell_count = sum( 1 for cell in board if cell == EMPTY_SIGN ) print('Game has been ended.') print('Game won by {}'.format(game_won_by(board))) if __name__ == "__main__": game_loop() OUTPUT : . . . . . X . . . Enter row: 1 Enter column: 1 O . . 2 180501154 . . X . . . O . X . . X . . . Enter row: 3 Enter column: 3 O . X . . X . . O O . X . X X . . O Enter row: 3 Enter column: 1 O . X . X X O . O O X X . X X O . O Enter row: 2 Enter column: 1 O X X O X X O . O Game has been ended. Game has been won by O RESULT : Thus the program was executed successfully and the Tic-Tac-Toc game was implemented. 3 180501154 IMPLEMENTATION OF WATER JUG PROBLEM EX.NO. : 2 DATE : AIM: To implement the Water Jug problem using C++. ALGORITHM : 1. Start. 2. Initialize required variables and get the goal state from the user. 3. Repeat until the goal state is reached (i) If the jug is empty, fill the jug to its capacity. (ii) Else if its full, empty the jug. (iii) Else when the jug is not filled to its entirety, find the minimum of remaining capacity of the corresponding jug with the other jug; Increment and decrement the corresponding jugs with the minimum value. (iv) Display the current values 4. Stop. SOURCE CODE : #include <bits/stdc++.h> #define pii pair<int, int> #define mp make_pair using namespace std; void BFS(int a, int b, int target) { map<pii, int> m; bool isSolvable = false; vector<pii> path; queue<pii> q; q.push({ 0, 0 }); while (!q.empty()) { pii u = q.front(); // current state q.pop(); // pop off used state // if this state is already visited if (m[{ u.first, u.second }] == 1) continue; // doesn't met jug constraints 4 180501154 if ((u.first > a || u.second > b || u.first < 0 || u.second < 0)) continue; // filling the vector for constructing // the solution path path.push_back({ u.first, u.second }); // marking current state as visited m[{ u.first, u.second }] = 1; // if we reach solution state, put ans=1 if (u.first == target || u.second == target) { isSolvable = true; if (u.first == target) { if (u.second != 0) // fill final state path.push_back({ u.first, 0 }); } else { if (u.first != 0) // fill final state path.push_back({ 0, u.second }); } // print the solution path int sz = path.size(); for (int i = 0; i < sz; i++) cout <<"\n"<< "(" << path[i].first << ", " << path[i].second << ")"<<"\n"; break; } // if we have not reached final state // then, start developing intermediate // states to reach solution state q.push({ u.first, b }); // fill Jug2 q.push({ a, u.second }); // fill Jug1 for (int ap = 0; ap <= max(a, b); ap++) { // pour amount ap from Jug2 to Jug1 int c = u.first + ap; int d = u.second - ap; // check if this state is possible or not 5 180501154 if (c == a || (d == 0 && d >= 0)) q.push({ c, d }); // Pour amount ap from Jug 1 to Jug2 c = u.first - ap; d = u.second + ap; // check if this state is possible or not if ((c == 0 && c >= 0) || d == b) q.push({ c, d }); } q.push({ a, 0 }); // Empty Jug2 q.push({ 0, b }); // Empty Jug1 } // No, solution exists if ans=0 if (!isSolvable) cout << "No solution"; } // Driver code int main() { int Jug1,Jug2,target; cout<<"Enter Jug1 volume\t"; cin>>Jug1; cout<<"Enter Jug2 volume\t"; cin>>Jug2; cout<<"Enter Target volume in Jug1\t"; cin>>target; cout << "Path from initial state " "to solution state :"; BFS(Jug1, Jug2, target); return 0; } OUTPUT : Enter Jug1 volume 4 Enter Jug2 volume 3 Enter Target volume in Jug2 2 6 180501154 Path from initial state to solution state : (0, 0) (0, 3) (4, 0) (4, 3) (3, 0) (1, 3) (3, 3) (4, 2) (0, 2) RESULT : Thus the program was executed successfully and the Water Jug problem was implemented. 7 180501154 IMPLEMENTATION OF A* AND BEST FIRST SEARCH ALGORITHM EX NO : 3 DATE : AIM: To implement the A* algorithm using Python and Best First Search algorithm using C++ program. ALGORITHM : A* ALGORITHM: 1. S tart 2. Define a Heuristic function to assign values to each nodes 3. In the A* algorithm we define two lists an open list which contains nodes that have been visited but its neighbours are not inspected 4. The node inspection starts with the first node 5. We define a closed list which have been visited and all neighbors also visited. 6. We define an adjacency list of all nodes and its cost to all nodes 7. Then we declare an adjacency mapping of all nodes 8. If the current node is not present in both open and closed list then add it to open list 9. Otherwise check if its quicker to visit a node and then another node 10. Update the values in the suitable variables 11. If a node is in the closed list add it to the open list 12. Remove it from the open list and add it to closed list 13. Stop BEST FIRST SEARCH ALGORITHM: 1. Start 2. Define a function to add edges to a graph 3. Create a min heap priority queue 4. Sort the priority queue with the fist value 5. As we visit the nodes add then to the visited list 6. As we visit the nodes display the path for the nodes 7. Stop 8 180501154 SOURCE CODE : A* ALGORITHM: from collections import deque class Graph: def __init__(self, adjac_lis): self.adjac_lis = adjac_lis def get_neighbors(self, v): return self.adjac_lis[v] def h(self, n): H = { 'A': 1, 'B': 1, 'C': 1, 'D': 1 } return H[n] def a_star_algorithm(self, start, stop): open_lst = set([start]) closed_lst = set([]) poo = {} poo[start] = 0 par = {} par[start] = start while len(open_lst) > 0: n = None for v in open_lst: if n == None or poo[v] + self.h(v) < poo[n] + self.h(n): n = v; if n == None: print('Path does not exist!') 9 180501154 return None if n == stop: reconst_path = [] while par[n] != n: reconst_path.append(n) n = par[n] reconst_path.append(start) reconst_path.reverse() print('Path found: {}'.format(reconst_path)) print("Weight is: {}".format(poo[m])) return reconst_path for (m, weight) in self.get_neighbors(n): if m not in open_lst and m not in closed_lst: open_lst.add(m) par[m] = n poo[m] = poo[n] + weight else: if poo[m] > poo[n] + weight: poo[m] = poo[n] + weight par[m] = n if m in closed_lst: closed_lst.remove(m) open_lst.add(m) open_lst.remove(n) closed_lst.add(n) print('Path does not exist!') return None adjac_lis = { 'A': [('B', 1), ('C', 3), ('D', 7)], 'B': [('D', 5)], 'C': [('D', 12)] } graph1 = Graph(adjac_lis) 10 180501154 graph1.a_star_algorithm('A', 'D') OUTPUT : Path found: ['A', 'B', 'D'] Weight is:6 SOURCE CODE : BEST FIRST SEARCH ALGORITHM: #include <bits/stdc++.h> using namespace std; typedef pair<int, int> pi; vector<vector<pi> > graph; void addedge(int x, int y, int cost) { graph[x].push_back(make_pair(cost, y)); graph[y].push_back(make_pair(cost, x)); } void best_first_search(int source, int target, int n) { vector<bool> visited(n, false); priority_queue<pi, vector<pi>, greater<pi> > pq; pq.push(make_pair(0, source)); int s = source; visited[s] = true; while (!pq.empty()) { int x = pq.top().second; cout << x << " → "; pq.pop(); if (x == target) break; for (int i = 0; i < graph[x].size(); i++) { if (!visited[graph[x][i].second]) { visited[graph[x][i].second] = true; pq.push(make_pair(graph[x][i].first,graph[x][i].second)); } } 11 180501154 } } int main() { int v = 14; graph.resize(v); addedge(0, 1, 3); addedge(0, 2, 6); addedge(0, 3, 5); addedge(1, 4, 9); addedge(1, 5, 8); addedge(2, 6, 12); addedge(2, 7, 14); addedge(3, 8, 7); addedge(8, 9, 5); addedge(8, 10, 6); addedge(9, 11, 1); addedge(9, 12, 10); addedge(9, 13, 2); int source = 0; int target = 9; best_first_search(source, target, v); return 0; } OUTPUT: 0 -> 1 -> 3 -> 2 -> 8 -> 9 -> RESULT : Thus the program was executed successfully and the A* Algorithm and Best First Search was implemented. 12 180501154 IMPLEMENTATION OF MINIMAX AND ALPHA BETA PRUNING FOR TIC-TAC-TOE EX NO : 4 DATE : AIM: To implement the Min-Max algorithm and alpha beta pruning algorithm using Python ALGORITHM : MINI MAX ALGORITHM: 1. Start 2. Initialize the game board 3. Define a function to detect an invalid move 4. Define Constraints for horizontal,vertical and diagonal win 5. Check the condition for tie also 6. Define a max function providing the possible values for x,y 7. Depending on the values assign values to the max 8. Repeat the same steps for min also 9. Define the minimax function that calculates the estimated time and the recommended move 10. Stop ALPHA BETA PRUNING: 1. Start 2. Initialize the game board 3. Define a function to detect an invalid move 4. Define Constraints for horizontal,vertical and diagonal win 5. Check the condition for tie also 6. Use Alpha beta pruning to maximize and minimize the player’s 7. Make the pruning og the search tree to minimize the search space 8. Calculate the estimated time and the recommended move 9. We observe that after pruning the estimated time for each move is less than that of minimax 10.Stop SOURCE CODE : MINI MAX ALGORITHM: import time class TicTacToe: def __init__(self): self.initialize_game() 13 180501154 def initialize_game(self): self.current_state = [['.','.','.'], ['.','.','.'], ['.','.','.']] self.player_turn = 'X' def draw_board(self): for i in range(0, 3): for j in range(0, 3): print('{}|'.format(self.current_state[i][j]), end=" ") print() print() def is_valid(self, px, py): if px < 0 or px > 2 or py < 0 or py > 2: return False elif self.current_state[px][py] != '.': return False else: return True def is_end(self): # Vertical win for i in range(0, 3): if (self.current_state[0][i] != '.' and self.current_state[0][i] == self.current_state[1][i] and self.current_state[1][i] == self.current_state[2][i]): return self.current_state[0][i] # Horizontal win for i in range(0, 3): if (self.current_state[i] == ['X', 'X', 'X']): return 'X' elif (self.current_state[i] == ['O', 'O', 'O']): return 'O' # Main diagonal win if (self.current_state[0][0] != '.' and 14 180501154 self.current_state[0][0] == self.current_state[1][1] and self.current_state[0][0] == self.current_state[2][2]): return self.current_state[0][0] # Second diagonal win if (self.current_state[0][2] != '.' and self.current_state[0][2] == self.current_state[1][1] and self.current_state[0][2] == self.current_state[2][0]): return self.current_state[0][2] # Is whole board full? for i in range(0, 3): for j in range(0, 3): # There's an empty field, we continue the game if (self.current_state[i][j] == '.'): return None # It's a tie! return '.' # Player 'O' is max, in this case AI def max(self): # Possible values for maxv are: # -1 - loss # 0 - a tie # 1 - win # We're initially setting it to -2 as worse than the worst case: maxv = -2 px = None py = None result = self.is_end() # If the game came to an end, the function needs to return # the evaluation function of the end. That can be: # -1 - loss # 0 - a tie # 1 - win if result == 'X': return (-1, 0, 0) elif result == 'O': return (1, 0, 0) elif result == '.': 15 180501154 return (0, 0, 0) for i in range(0, 3): for j in range(0, 3): if self.current_state[i][j] == '.': # On the empty field player 'O' makes a move and calls Min # That's one branch of the game tree. self.current_state[i][j] = 'O' (m, min_i, min_j) = self.min() # Fixing the maxv value if needed if m > maxv: maxv = m px = i py = j # Setting back the field to empty self.current_state[i][j] = '.' return (maxv, px, py) # Player 'X' is min, in this case human # Player 'X' is min, in this case human def min(self): # Possible values for minv are: # -1 - win # 0 - a tie # 1 - loss # We're initially setting it to 2 as worse than the worst case: minv = 2 qx = None qy = None result = self.is_end() if result == 'X': return (-1, 0, 0) elif result == 'O': return (1, 0, 0) elif result == '.': return (0, 0, 0) for i in range(0, 3): for j in range(0, 3): if self.current_state[i][j] == '.': self.current_state[i][j] = 'X' 16 180501154 (m, max_i, max_j) = self.max() if m < minv: minv = m qx = i qy = j self.current_state[i][j] = '.' return (minv, qx, qy) # Game loop def play_minimax(self): while True: self.draw_board() self.result = self.is_end() if self.result != None: if self.result == 'X': print('The winner is X!') elif self.result == 'O': print('The winner is O!') elif self.result == '.': print("It's a tie!") self.initialize_game() return if self.player_turn == 'X': while True: start = time.time() (m, qx, qy) = self.min() end = time.time() print('Evaluation time: {}s'.format(round(end - start, 7))) print('Recommended move: X = {}, Y = {}'.format(qx, qy)) px = int(input('Insert the X coordinate: ')) py = int(input('Insert the Y coordinate: ')) qx = px qy = py if self.is_valid(px, py): self.current_state[px][py] = 'X' self.player_turn = 'O' break else: 17 180501154 print('The move is not valid! Try again.') else: (m, px, py) = self.max() self.current_state[px][py] = 'O' self.player_turn = 'X' if __name__ == "__main__": g = TicTacToe() g.play_minimax() OUTPUT : .| .| .| .| .| .| .| .| .| Evaluation time: 1.5625052s Recommended move: X = 0, Y = 0 Insert the X coordinate: 0 Insert the Y coordinate: 0 X| .| .| .| .| .| .| .| .| X| .| .| .| O| .| .| .| .| Evaluation time: 0.0205414s Recommended move: X = 0, Y = 1 Insert the X coordinate: 0 Insert the Y coordinate: 1 X| X| .| .| O| .| .| .| .| X| X| O| .| O| .| .| .| .| Evaluation time: 0.0008574s Recommended move: X = 2, Y = 0 Insert the X coordinate: 2 Insert the Y coordinate: 0 X| X| O| 18 180501154 .| O| .| X| .| .| X| X| O| O| O| .| X| .| .| Evaluation time: 0.0002093s Recommended move: X = 1, Y = 2 Insert the X coordinate: 1 Insert the Y coordinate: 2 X| X| O| O| O| X| X| .| .| X| X| O| O| O| X| X| O| .| Evaluation time: 5.51e-05s Recommended move: X = 2, Y = 2 Insert the X coordinate: 2 Insert the Y coordinate: 2 X| X| O| O| O| X| X| O| X| It's a tie! SOURCE CODE: ALPHA BETA PRUNING: import time class TicTacToe: def __init__(self): self.initialize_game() def initialize_game(self): self.current_state = [['.','.','.'], ['.','.','.'], ['.','.','.']] # Player X always plays first self.player_turn = 'X' 19 180501154 def draw_board(self): for i in range(0, 3): for j in range(0, 3): print('{}|'.format(self.current_state[i][j]), end=" ") print() print() # Determines if the made move is a legal move def is_valid(self, px, py): if px < 0 or px > 2 or py < 0 or py > 2: return False elif self.current_state[px][py] != '.': return False else: return True # Checks if the game has ended and returns the winner in each case def is_end(self): # Vertical win for i in range(0, 3): if (self.current_state[0][i] != '.' and self.current_state[0][i] == self.current_state[1][i] and self.current_state[1][i] == self.current_state[2][i]): return self.current_state[0][i] # Horizontal win for i in range(0, 3): if (self.current_state[i] == ['X', 'X', 'X']): return 'X' elif (self.current_state[i] == ['O', 'O', 'O']): return 'O' # Main diagonal win if (self.current_state[0][0] != '.' and self.current_state[0][0] == self.current_state[1][1] and self.current_state[0][0] == self.current_state[2][2]): return self.current_state[0][0] # Second diagonal win if (self.current_state[0][2] != '.' and self.current_state[0][2] == self.current_state[1][1] and self.current_state[0][2] == self.current_state[2][0]): return self.current_state[0][2] 20