diff --git a/AlphaBetaPruning/Explaination.md b/AlphaBetaPruning/Explaination.md index 2c42c68..8542e61 100644 --- a/AlphaBetaPruning/Explaination.md +++ b/AlphaBetaPruning/Explaination.md @@ -39,13 +39,38 @@ Here's how the code would execute these moves: # Initial total is 0 total = 0 +# Define the minimax function +def minimax(total, is_maximizing, alpha, beta): + # Base case: If total reaches or exceeds 20, return a high value for winning, low for losing + if total >= 20: + return 1 if is_maximizing else -1 + + if is_maximizing: + max_eval = -float('inf') + for i in range(1, 4): # AI can add 1, 2, or 3 + eval = minimax(total + i, False, alpha, beta) + max_eval = max(max_eval, eval) + alpha = max(alpha, eval) + if beta <= alpha: + break + return max_eval + else: + min_eval = float('inf') + for i in range(1, 4): # Human can add 1, 2, or 3 + eval = minimax(total + i, True, alpha, beta) + min_eval = min(min_eval, eval) + beta = min(beta, eval) + if beta <= alpha: + break + return min_eval + # Game loop while True: # Human's turn - human_move = int(input("Enter your move (1, 2, or 3): ")) # Let's say the human enters 1 - total += human_move # total becomes 1 - print(f"After your move, total is {total}") # Prints "After your move, total is 1" - if total >= 20: # The total is not 20 or more, so the game continues + human_move = int(input("Enter your move (1, 2, or 3): ")) + total += human_move + print(f"After your move, total is {total}") + if total >= 20: print("You win!") break @@ -53,18 +78,17 @@ while True: print("AI is making its move...") ai_move = 1 max_eval = -float('inf') - for i in range(1, 4): # For each possible move (1, 2, or 3) - eval = minimax(total + i, False, -float('inf'), float('inf')) # Call minimax to get the evaluation of the move - if eval > max_eval: # If the evaluation is greater than max_eval, update max_eval and ai_move + for i in range(1, 4): + eval = minimax(total + i, False, -float('inf'), float('inf')) + if eval > max_eval: max_eval = eval ai_move = i - total += ai_move # Add the AI's move to the total. Let's say the AI adds 3, so total becomes 4 - print(f"AI adds {ai_move}. Total is {total}") # Prints "AI adds 3. Total is 4" - if total >= 20: # The total is not 20 or more, so the game continues + total += ai_move + print(f"AI adds {ai_move}. Total is {total}") + if total >= 20: print("AI wins!") break -# The game continues in this way until the total reaches or exceeds 20 ``` In this example, the AI wins because the total reaches 20 after the AI's move. The AI uses the Minimax algorithm with Alpha-Beta pruning to decide its moves, always choosing the move that maximizes its score assuming that the human player is also playing optimally. diff --git a/AlphaBetaPruning/GameOf20.py b/AlphaBetaPruning/GameOf20.py index 0b26caf..94d5218 100644 --- a/AlphaBetaPruning/GameOf20.py +++ b/AlphaBetaPruning/GameOf20.py @@ -1,66 +1,52 @@ -# The minimax function is the heart of the AI. It recursively calculates the optimal move for the AI. -def minimax(total, turn, alpha, beta): - # Base case: if total is 20, it's a draw, so return 0 - if total == 20: - return 0 - # Base case: if total is more than 20, the last player to move loses - elif total > 20: - if turn: # If it's the AI's turn, AI loses, so return -1 - return -1 - else: # If it's the human's turn, human loses, so return 1 - return 1 +def minimax(total, is_ai_turn, alpha, beta): + # Base case: If total is 20 or more, the game is over + if total >= 20: + return -1 if is_ai_turn else 1 if total > 20 else 0 # -1 if AI loses, 1 if AI wins, 0 if draw + + # Set initial evaluation depending on whose turn it is + best_eval = -float('inf') if is_ai_turn else float('inf') + + # Explore each possible move (1, 2, or 3) + for i in range(1, 4): + eval = minimax(total + i, not is_ai_turn, alpha, beta) # Recursive call for the next move + + # Maximize if it's AI's turn, else minimize + if is_ai_turn: + best_eval = max(best_eval, eval) + alpha = max(alpha, eval) + else: + best_eval = min(best_eval, eval) + beta = min(beta, eval) + + # Alpha-beta pruning to cut off unnecessary branches + if beta <= alpha: + break + return best_eval - # If it's the AI's turn, we want to maximize the score - if turn: - max_eval = -float('inf') # Initialize max_eval to negative infinity - for i in range(1, 4): # For each possible move (1, 2, or 3) - # Recursively call minimax for the next state of the game - eval = minimax(total + i, False, alpha, beta) - max_eval = max(max_eval, eval) # Update max_eval if necessary - alpha = max(alpha, eval) # Update alpha if necessary - if beta <= alpha: # If beta is less than or equal to alpha, break the loop (alpha-beta pruning) - break - return max_eval # Return the maximum evaluation - # If it's the human's turn, we want to minimize the score - else: - min_eval = float('inf') # Initialize min_eval to positive infinity - for i in range(1, 4): # For each possible move (1, 2, or 3) - # Recursively call minimax for the next state of the game - eval = minimax(total + i, True, alpha, beta) - min_eval = min(min_eval, eval) # Update min_eval if necessary - beta = min(beta, eval) # Update beta if necessary - if beta <= alpha: # If beta is less than or equal to alpha, break the loop (alpha-beta pruning) - break - return min_eval # Return the minimum evaluation - -# The total score of the game is initially 0 -total = 0 +total = 0 # Initialize total score # Game loop -while True: - # Get the human player's move from input and add it to the total +while total < 20: + # Human player's move human_move = int(input("Enter your move (1, 2, or 3): ")) - while human_move not in [1, 2, 3]: # If the move is not valid, ask for input again - print("Invalid move. Please enter 1, 2, or 3.") - human_move = int(input("Enter your move (1, 2, or 3): ")) + while human_move not in [1, 2, 3]: # Validate input + human_move = int(input("Invalid move. Enter 1, 2, or 3: ")) total += human_move - print(f"After your move, total is {total}") - if total >= 20: # If the total is 20 or more after the human's move, the human wins + print(f"Total after your move: {total}") + + # Check if human wins + if total >= 20: print("You win!") break - # If the game is not over, it's the AI's turn + # AI's turn print("AI is making its move...") - ai_move = 1 - max_eval = -float('inf') - for i in range(1, 4): # For each possible move (1, 2, or 3) - # Call minimax to get the evaluation of the move - eval = minimax(total + i, False, -float('inf'), float('inf')) - if eval > max_eval: # If the evaluation is greater than max_eval, update max_eval and ai_move - max_eval = eval - ai_move = i - total += ai_move # Add the AI's move to the total - print(f"AI adds {ai_move}. Total is {total}") - if total >= 20: # If the total is 20 or more after the AI's move, the AI wins + # Select the best move by calling minimax on each possible option + best_move = max((minimax(total + i, False, -float('inf'), float('inf')), i) for i in range(1, 4))[1] + total += best_move + print(f"AI adds {best_move}. Total is {total}") + + # Check if AI wins + if total >= 20: print("AI wins!") break diff --git a/HillClimbSearch/HillClimbSearchEval.py b/HillClimbSearch/HillClimbSearchEval.py index e60d299..f97be36 100644 --- a/HillClimbSearch/HillClimbSearchEval.py +++ b/HillClimbSearch/HillClimbSearchEval.py @@ -1,50 +1,35 @@ -import numpy as np +def hill_climbing(func, start, step=0.01, max_iter=1000): + x = start + for _ in range(max_iter): + fx = func(x) + fx_positive = func(x + step) + fx_negative = func(x - step) -def hill_climbing(func, start, step_size=0.01, max_iterations=1000): - current_position = start - current_value = func(current_position) - - for i in range(max_iterations): - next_position_positive = current_position + step_size - next_value_positive = func(next_position_positive) - - next_position_negative = current_position - step_size - next_value_negative = func(next_position_negative) - - if next_value_positive > current_value and next_value_positive >= next_value_negative: - current_position = next_position_positive - current_value = next_value_positive - elif next_value_negative > current_value and next_value_negative > next_value_positive: - current_position = next_position_negative - current_value = next_value_negative + if fx_positive > fx and fx_positive >= fx_negative: + x += step + elif fx_negative > fx and fx_negative > fx_positive: + x -= step else: break - - return current_position, current_value + return x, func(x) -# Get the function from the user -while True: - func_str = input("\nEnter a function of x: ") - try: - # Test the function with a dummy value - x = 0 - eval(func_str) - break - except Exception as e: - print(f"Invalid function. Please try again. Error: {e}") - -# Convert the string into a function -func = lambda x: eval(func_str) +if __name__ == "__main__": + while True: + try: + func_str = input("Enter a function of x (e.g., -(x-2)**2 + 4): ") + func = eval(f"lambda x: {func_str}") # Convert string to function + func(0) # Test the function with x = 0 + break + except Exception as e: + print(f"Invalid function. Please try again. Error: {e}") -# Get the starting point from the user -while True: - start_str = input("\nEnter the starting value to begin the search: ") - try: - start = float(start_str) - break - except ValueError: - print("Invalid input. Please enter a number.") + while True: + try: + start = float(input("Enter the starting value (e.g., 0): ")) + break + except ValueError: + print("Invalid input. Please enter a valid number.") -maxima, max_value = hill_climbing(func, start) -print(f"The maxima is at x = {maxima}") -print(f"The maximum value obtained is {max_value}") + max_x, max_val = hill_climbing(func, start) + print(f"Maxima found at x = {max_x}") + print(f"Maximum value = {max_val}") diff --git a/Logistic_Regression/LogisticReg.py b/Logistic_Regression/LogisticReg.py index 66bc58b..1d744cc 100644 --- a/Logistic_Regression/LogisticReg.py +++ b/Logistic_Regression/LogisticReg.py @@ -1,5 +1,5 @@ -import matplotlib.pyplot as plt import numpy as np +import matplotlib.pyplot as plt from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler @@ -7,22 +7,28 @@ def sigmoid(z): return 1.0 / (1.0 + np.exp(-z)) -def logistic_regression(X, y, num_iterations=200, learning_rate=0.001): +def cost_function(h, y): + return (-y * np.log(h) - (1 - y) * np.log(1 - h)).mean() + +def gradient(X, h, y): + return np.dot(X.T, (h - y)) / y.shape[0] + +def logistic_regression(X, y, num_iterations=5000, learning_rate=0.1): weights = np.zeros(X.shape[1]) for _ in range(num_iterations): z = np.dot(X, weights) h = sigmoid(z) - gradient_val = np.dot(X.T, (h - y)) / y.shape[0] + gradient_val = gradient(X, h, y) weights -= learning_rate * gradient_val return weights # Load Iris dataset iris = load_iris() -X = iris.data[:, :2] # Use only the first two features (sepal length and width) +X = iris.data[:, :2] # Use only the first two features y = (iris.target != 0) * 1 # Convert to binary classification # Split the dataset -X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.4, random_state=9) +X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) # Standardize features sc = StandardScaler() @@ -38,7 +44,6 @@ def logistic_regression(X, y, num_iterations=200, learning_rate=0.001): # Print accuracy print(f'Accuracy: {np.mean(y_pred == y_test):.4f}') - # Plot decision boundary x_min, x_max = X_train_std[:, 0].min() - 1, X_train_std[:, 0].max() + 1 y_min, y_max = X_train_std[:, 1].min() - 1, X_train_std[:, 1].max() + 1 @@ -53,7 +58,4 @@ def logistic_regression(X, y, num_iterations=200, learning_rate=0.001): plt.title('Logistic Regression Decision Boundaries') plt.xlabel('Sepal length') plt.ylabel('Sepal width') - plt.savefig('plot.png') - - diff --git a/NaiveBayesClassifeir/Explaination.md b/NaiveBayesClassifeir/Explainationudinggaussian.md similarity index 99% rename from NaiveBayesClassifeir/Explaination.md rename to NaiveBayesClassifeir/Explainationudinggaussian.md index 6d542b5..8178f24 100644 --- a/NaiveBayesClassifeir/Explaination.md +++ b/NaiveBayesClassifeir/Explainationudinggaussian.md @@ -1,5 +1,5 @@ -## Naive Bayes Classifier +## Naive Bayes Classifier using Gaussian method The Naive Bayes classifier is a simple and effective classification algorithm that uses probabilities and Bayes' theorem to predict the class of an instance. The 'naive' part comes from the assumption that all features are independent of each other, which is not always the case in real-world data, but it simplifies the calculations and often works well in practice. diff --git a/NaiveBayesClassifeir/naiveBayes.py b/NaiveBayesClassifeir/naiveBayes_Gaussian_method.py similarity index 99% rename from NaiveBayesClassifeir/naiveBayes.py rename to NaiveBayesClassifeir/naiveBayes_Gaussian_method.py index 496c93d..5e76b27 100644 --- a/NaiveBayesClassifeir/naiveBayes.py +++ b/NaiveBayesClassifeir/naiveBayes_Gaussian_method.py @@ -7,6 +7,7 @@ X, y = iris.data, iris.target class_names = iris.target_names + class NaiveBayes: def fit(self, X, y): self._classes = np.unique(y) @@ -54,4 +55,4 @@ def _pdf(self, class_idx, x): # Print classification report print("\nClassification Report:") -print(classification_report(y_test, y_pred, target_names=class_names)) \ No newline at end of file +print(classification_report(y_test, y_pred, target_names=class_names)) diff --git a/ReadMe.md b/ReadMe.md index 8a8f40d..eb9870c 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -27,7 +27,7 @@ pip install -r requirements.txt ## Usage -1. Can be used for the AI_ML Lab for the course 21AI52 at RVCE +1. Can be used for the AI_ML Lab for the course 21AI52 and IS353IA ## Contributing diff --git a/TicTacToe/TicTacToe_DFS.py b/TicTacToe/TicTacToe_DFS.py index da6aea9..991b005 100644 --- a/TicTacToe/TicTacToe_DFS.py +++ b/TicTacToe/TicTacToe_DFS.py @@ -17,27 +17,27 @@ def is_draw(self): return False return True - def is_game_over(self): - # Step 3: Check if the game is over + def is_game_over(self, board=None): + if board is None: + board = self.board # Default to the current board state # Check rows - for row in self.board: + for row in board: if row.count(row[0]) == len(row) and row[0] != ' ': return row[0] # Check columns - for col in zip(*self.board): + for col in zip(*board): if col.count(col[0]) == len(col) and col[0] != ' ': return col[0] - # Check diagonals - if self.board[0][0] == self.board[1][1] == self.board[2][2] != ' ': - return self.board[0][0] - if self.board[0][2] == self.board[1][1] == self.board[2][0] != ' ': - return self.board[0][2] + if board[0][0] == board[1][1] == board[2][2] != ' ': + return board[0][0] + if board[0][2] == board[1][1] == board[2][0] != ' ': + return board[0][2] return False def dfs(self, board, depth, player): # Step 5: DFS logic to choose the best move - winner = self.is_game_over() + winner = self.is_game_over(board) if winner: if winner == 'X': # AI wins return {'score': 1} @@ -46,12 +46,8 @@ def dfs(self, board, depth, player): elif self.is_draw(): return {'score': 0} # Draw - if player == 'X': - best = {'score': -float('inf')} - symbol = 'X' - else: - best = {'score': float('inf')} - symbol = 'O' + best = {'score': -float('inf')} if player == 'X' else {'score': float('inf')} + symbol = 'X' if player == 'X' else 'O' for i in range(3): for j in range(3): @@ -62,10 +58,10 @@ def dfs(self, board, depth, player): score['row'] = i score['col'] = j - if player == 'X': + if player == 'X': # Maximize for AI if score['score'] > best['score']: best = score - else: + else: # Minimize for opponent if score['score'] < best['score']: best = score return best @@ -84,6 +80,7 @@ def play(self): break if self.player == 'X': + print("AI is making a move...") best_move = self.dfs(self.board, 0, 'X') self.board[best_move['row']][best_move['col']] = 'X' else: @@ -102,5 +99,6 @@ def play(self): self.player = 'O' if self.player == 'X' else 'X' + game = TicTacToe() game.play()