0% found this document useful (0 votes)
42 views20 pages

Ai Lab - R22

The document outlines six experiments in Python, covering algorithms such as Breadth-First Search (BFS), Depth-First Search (DFS), and applications like Tic-Tac-Toe, the 8-Puzzle problem, the Water Jug problem, and the Travelling Salesman Problem (TSP). Each experiment includes an aim, description, key properties, procedures, and sample code demonstrating the implementation of the respective algorithms. The document serves as a comprehensive guide for understanding and applying these fundamental algorithms and problem-solving techniques in programming.

Uploaded by

Hasi P
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
42 views20 pages

Ai Lab - R22

The document outlines six experiments in Python, covering algorithms such as Breadth-First Search (BFS), Depth-First Search (DFS), and applications like Tic-Tac-Toe, the 8-Puzzle problem, the Water Jug problem, and the Travelling Salesman Problem (TSP). Each experiment includes an aim, description, key properties, procedures, and sample code demonstrating the implementation of the respective algorithms. The document serves as a comprehensive guide for understanding and applying these fundamental algorithms and problem-solving techniques in programming.

Uploaded by

Hasi P
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 20

EXPERIMENT-1: BREADTH FIRST SEARCH(BFS)

AIM:
To implement the Breadth-First Search (BFS) algorithm in Python to explore or traverse a graph,
ensuring that nodes are visited in the order of their depth levels.

Description:
Breadth-First Search (BFS) is a fundamental graph traversal algorithm commonly used in AI for
pathfinding and problem-solving. It explores all neighbors of a node before moving to the next level,
ensuring the shortest path in unweighted graphs.

Key Properties:
 Queue (FIFO) structure is used.
 Traverses level by level.
 Guarantees shortest path in an unweighted graph.
 Prevents revisiting nodes using a visited list.

Procedure:
1. Initialize a queue and insert the starting node.
2. Mark the starting node as visited.
3. While the queue is not empty:
o Dequeue the front node.
o Print the node (processing).
o Enqueue all its unvisited neighbors and mark them as visited.
4. Continue until all reachable nodes are visited.

Program:
# Input Graph
graph = {
'A' : ['B','C'],
'B' : ['A','C','D'],
'C' : ['A','B','E'],
'D' : ['B','E'],
'E' : ['C','D']
}
# To store visited nodes.
visitedNodes = []
# To store nodes in queue
queueNodes = []
# function
def bfs(visitedNodes, graph, snode):
visitedNodes.append(snode)
queueNodes.append(snode)
print()
print("RESULT :")
while queueNodes:
s = queueNodes.pop(0)
print (s, end = " ")
for neighbour in graph[s]:
if neighbour not in visitedNodes:
visitedNodes.append(neighbour)
queueNodes.append(neighbour)

# Main Code
snode = input("Enter Starting Node(A, B, C, D, or E) :").upper()
# calling bfs function
bfs(visitedNodes, graph, snode)
input("\n\nPress Enter to close...")

Sample Output (if input is A):


Enter Starting Node(A, B, C, D, or E) : A

RESULT :
ABCDE
Press Enter to close...

Sample Output (if input is C):


Enter Starting Node(A, B, C, D, or E) : C
RESULT :
CABED
Press Enter to close...

EXPERIMENT-2: DEPTH FIRST SEARCH (DFS)


AIM:
To implement the Depth-First Search (DFS) using a Python program to explore nodes and edges in a
graph.

Description:
Depth-First Search (DFS) is a graph traversal algorithm that explores nodes and edges by going as
deep as possible along a branch before backtracking. It is especially useful in scenarios where we
want to explore all possible paths, detect cycles, or traverse in a depth-wise manner.

Key Properties:
 Uses Stack (explicitly or through recursion).
 Works on both Directed and Undirected graphs.
 Traversal order is not unique (depends on neighbor order).
 Can be used to detect cycles, connected components, etc.
Procedure:
DFS Working Principle – Step by Step:
1. Start at a Given Node
Choose a starting node (root or any node).
2. Mark the Node as Visited
Use a list or set to avoid revisiting nodes.
3. Explore Each Unvisited Neighbor One by One
Recursively go deeper into each unvisited neighbor.
4. Backtrack if No More Neighbors Exist
If dead-end reached, return to previous node.
5. Repeat Until All Nodes Are Visited
Continue exploring unvisited paths until completion.

Program:
# Input Graph
graph = {
'A' : ['B','C'],
'B' : ['A','C','D'],
'C' : ['A','B','E'],
'D' : ['B','E'],
'E' : ['C','D']
}
# Set used to store visited nodes.
visitedNodes = list()
# function
def dfs(visitedNodes, graph, node):
if node not in visitedNodes:
print (node,end=" ")
visitedNodes.append(node)
for neighbour in graph[node]:
dfs(visitedNodes, graph, neighbour)

# Driver Code
snode = input("Enter Starting Node(A, B, C, D, or E) :").upper()
# calling dfs function
print("RESULT :")
print("-"*20)
dfs(visitedNodes, graph, snode)
input("\n\nPress Enter to close...")

Sample Output 1 (if input is A):


Enter Starting Node(A, B, C, D, or E) : A
RESULT :
--------------------
ABCED
Press Enter to close...
Sample Output 2 (if input is C):
Enter Starting Node(A, B, C, D, or E) : C
RESULT :
--------------------
CABDE
Press Enter to close...

EXPERIMENT-3: TIC-TAC-TOE GAME


AIM:
Write a program to implement Tic-Tac-Toe game using Python.

Description:
Tic-Tac-Toe is a simple two-player game played on a 3x3 grid. Players alternate turns placing their
symbols ("X" or "O") in empty cells. The objective is to be the first player to form a line of three
symbols horizontally, vertically, or diagonally. If all cells are filled without a winner, the game ends in
a draw.

Procedure:
1. Set Up the Game:
Prepare a 3×3 grid. In this program, the grid is simulated with a list of numbers from 1 to 9.
2. Choose Symbols:
One player will use "X", the other will use "O".
3. Decide Who Goes First:
Usually, Player 1 ("X") starts. Players take turns thereafter.
4. Take Turns:
During a turn, a player selects an empty cell by entering its number (1–9). The program
updates the grid with that player's symbol.
5. Check for a Winner:
After each move, the program checks for any winning combinations (three same symbols in a
line).
6. Declare the Outcome:
o If a player forms a winning line, that player is declared the winner.
o If all cells are filled without any winner, the game ends in a draw.
7. Restart or End the Game:
Once the result is declared, players may restart manually or end the session.

Program:
# Tuple to store winning positions.
win_positions = (
(0, 1, 2), (3, 4, 5), (6, 7, 8),
(0, 3, 6), (1, 4, 7), (2, 5, 8),
(0, 4, 8), (2, 4, 6)
)
def game(player):
# display current mesh
print("\n", " | ".join(mesh[:3]))
print("---+---+---")
print("", " | ".join(mesh[3:6]))
print("---+---+---")
print("", " | ".join(mesh[6:]))

# Loop until player valid input cell number.


while True:
try:
ch = int(input(f"Enter player {player}'s choice : "))
if str(ch) not in mesh:
raise ValueError
mesh[ch-1] = player
break
except ValueError:
print("Invalid position number.")

# Return winning positions if player wins, else None.


for wp in win_positions:
if all(mesh[pos] == player for pos in wp):
return wp
return None

player1 = "X"
player2 = "O"
player = player1
mesh = list("123456789")

for i in range(9):
won = game(player)
if won:
print("\n", " | ".join(mesh[:3]))
print("---+---+---")
print("", " | ".join(mesh[3:6]))
print("---+---+---")
print("", " | ".join(mesh[6:]))
print(f"*** Player {player} won! ***")
break
player = player1 if player == player2 else player2
else:
# 9 moves without a win is a draw.
print("Game ends in a draw.")
input("\n\nPress Enter to close...")
Output:
1|2|3
---+---+---
4|5|6
---+---+---
7|8|9
Enter player X's choice : 1

X|2|3
---+---+---
4|5|6
---+---+---
7|8|9
Enter player O's choice : 5

X|2|3
---+---+---
4|O|6
---+---+---
7|8|9
...
*** Player X won! ***

EXPERIMENT-4: 8-PUZZLE PROBLEM


AIM:
To implement the 8-Puzzle problem using Python.

Description:
The 8-Puzzle is a classic sliding puzzle consisting of a 3x3 grid with 8 numbered tiles and one empty
space (represented by 0). The goal is to reach a predefined target configuration by sliding tiles into
the empty space. It’s often solved using search algorithms like Breadth-First Search (BFS), Depth-
First Search (DFS), or A* Search.
This implementation uses a queue-based BFS approach to find the shortest path from the initial
state to the goal.

Procedure:
1. Define the Puzzle:
Represent the puzzle state as a 3x3 grid (flattened into a list) with numbers 1–8 and 0
representing the blank.
2. Create State Tracking:
Use a dictionary to store each visited state along with its parent (for path reconstruction).
3. Use a Queue (BFS):
Use a queue (deque) as a frontier to hold the current states to explore next.
4. Generate Moves:
Identify the valid directions the empty space can move and generate new states by swapping
tiles.
5. Search for Goal:
Continue exploring until the current state matches the goal configuration.
6. Trace and Print Path:
Once the goal is reached, backtrack using the parent dictionary to reconstruct and display
the solution steps.

Program:
from collections import deque

def bfs(start_state):
target = [1, 2, 3, 4, 5, 6, 7, 8 , 0]
dq = deque([start_state])
visited = {tuple(start_state): None}

while dq:
state = dq.popleft()
if state == target:
path = []
while state:
path.append(state)
state = visited[tuple(state)]
return path[::-1]

zero = state.index(0)
row, col = divmod(zero, 3)
for move in (-3, 3, -1, 1):
new_row, new_col = divmod(zero + move, 3)
if 0 <= new_row < 3 and 0 <= new_col < 3 and abs(row - new_row) + abs(col - new_col) == 1:
neighbor = state[:]
neighbor[zero], neighbor[zero + move] = neighbor[zero + move], neighbor[zero]
if tuple(neighbor) not in visited:
visited[tuple(neighbor)] = state
dq.append(neighbor)

def printSolution(path):
for state in path:
print("\n".join(' '.join(map(str, state[i:i+3])) for i in range(0, 9, 3)), end="\n-----\n")

# Example Usage
startState = [1, 3, 0 , 6, 8, 4, 7, 5, 2]
solution = bfs(startState)
if solution:
printSolution(solution)
print(f"Solved in {len(solution) - 1} moves.")
else:
print("No solution found.")
input("\n\nPress Enter to close...")
Sample Output:
130
684
752
-----
103
684
752
-----
013
684
752
...
123
456
780
-----
Solved in 22 moves.

EXPERIMENT-5: WATER-JUG PROBLEM


AIM:
To implement the Water Jug Problem using Python and solve it using the BFS (Breadth-First Search)
algorithm.

Description:
The Water Jug Problem is a fundamental AI problem involving two jugs with given capacities and a
goal to measure a specific amount of water using only those jugs. This classic example demonstrates
state space search, and here, it is solved using a Breadth-First Search strategy to explore all valid
states without revisiting previously seen configurations.

Problem Statement:
 You are given two jugs of capacities X liters and Y liters.
 The objective is to measure exactly Z liters using only these two jugs.
 You can perform the following operations:
o Fill either jug completely.
o Empty either jug completely.
o Pour water from one jug to the other until the first is empty or the second is full.

Procedure:
1. Define the Problem:
Set values for jug1, jug2, and the target goal.
2. Breadth-First Search (BFS) Approach:
o Use a queue or recursion to explore all valid states.
o Maintain a visited matrix to track explored states to avoid infinite loops.
o For each state, apply all six valid operations (fill, empty, transfer).
o Stop the search when the goal condition is met in either jug.
3. Output:
o Print each valid state explored.
o Indicate when the goal amount is reached.
o

Program:
# jug1 and jug2 contain the value
jug1, jug2, goal = 4, 3, 2

# Initialize a 2D list for visited states


# The list will have dimensions (jug1+1) x (jug2+1) to cover all possible states
visited = [[False for _ in range(jug2 + 1)] for _ in range(jug1 + 1)]

def waterJug(vol1, vol2):


# Check if we reached the goal state
if (vol1 == goal and vol2 == 0) or (vol2 == goal and vol1 == 0):
print(vol1,"\t", vol2)
print("Solution Found")
return True

# If this state has been visited, return False


if visited[vol1][vol2]:
return False
# Mark this state as visited
visited[vol1][vol2] = True
# Print the current state
print(vol1,"\t", vol2)
# Try all possible moves:
return (
waterJug(0, vol2) or # Empty jug1
waterJug(vol1, 0) or # Empty jug2
waterJug(jug1, vol2) or # Fill jug1
waterJug(vol1, jug2) or # Fill jug2
waterJug(vol1 + min(vol2, (jug1 - vol1)), vol2 - min(vol2, (jug1 - vol1))) or # Pour water from jug2
to jug1
waterJug(vol1 - min(vol1, (jug2 - vol2)), vol2 + min(vol1, (jug2 - vol2))) # Pour water from jug1 to
jug2
)

print("Steps: ")
print("Jug1 \t Jug2 ")
print("----- \t ------")
waterJug(0, 0)
input("\n\nPress Enter to close...")

Sample Output:
Steps:
Jug1 Jug2
----- ------
0 0
0 3
3 0
3 3
4 2
2 0
0 2
Solution Found

EXPERIMENT-6: TRAVELLING SALESPERSON PROBLEM


AIM:
To implement the Travelling Salesman Problem (TSP) using Dynamic Programming (Held-Karp
Algorithm) or the Branch and Bound approach in Python.

Description:
The Travelling Salesman Problem (TSP) is a classical NP-hard combinatorial optimization problem
where a salesman must visit each city exactly once and return to the origin city while minimizing the
total travel cost or distance. TSP has significant applications in fields such as logistics, route planning,
and supply chain optimization.

Approaches to Solve TSP:


1. Brute Force – Try all possible permutations of cities (Complexity: O(n!))
2. Dynamic Programming (Held-Karp Algorithm) – Efficient method (Complexity: O(2ⁿ × n))
3. Branch and Bound – Optimizes brute-force using bounds and pruning
4. Approximation Techniques – e.g., Nearest Neighbour, Genetic Algorithm (for large n)

Procedure:
Step 1: Define the Problem
 Represent cities as nodes
 Represent paths as weighted edges
Step 2: Input the Adjacency Matrix
 A 2D matrix where graph[i][j] represents the cost of traveling from city i to city j
Step 3: Implement the Algorithm
 Use Breadth-First Search (BFS) for TSP (similar to Branch and Bound)
 Keep track of paths and costs using a queue
 Prune invalid or repeated paths
Step 4: Compute the Optimal Tour
 Visit all cities once
 Return to the starting city
 Track minimum cost
Step 5: Display the Result
 Output the optimal path and the minimum cost
Program:
from collections import deque

def tsp_bfs(graph):
n = len(graph) # Number of cities
startCity = 0 # Starting city
min_cost = float('inf') # Initialize minimum cost as infinity
opt_path = [] # To store the optimal path

# Queue for BFS: Each element is (current path, current cost)


dq = deque([([startCity], 0)])

print("Path Traversal:")

while dq:
cur_path, cur_cost = dq.popleft()
cur_city = cur_path[-1]

# Print the current path and cost


print(f"Current Path: {cur_path}, Current Cost: {cur_cost}")

# If all cities visited and path returned to start


if len(cur_path) == len(graph) and cur_path[0] == startCity:
total_cost = cur_cost + graph[cur_city][startCity]
if total_cost < min_cost:
min_cost = total_cost
opt_path = cur_path + [startCity]
continue

# Explore unvisited neighboring cities


for next_city in range(n):
if next_city not in cur_path:
new_path = cur_path + [next_city]
new_cost = cur_cost + graph[cur_city][next_city]
dq.append((new_path, new_cost))

return min_cost, opt_path

# Example graph as a 2D adjacency matrix


graph = [
[0, 10, 15, 20],
[10, 0, 35, 25],
[15, 35, 0, 30],
[20, 25, 30, 0]
]
# Solve TSP using BFS-based approach
min_cost, opt_path = tsp_bfs(graph)

print("\nOptimal Solution:")
print(f"Minimum cost: {min_cost}")
print(f"Optimal path: {opt_path}")
input("\n\nPress Enter to close...")

Sample Output:
Path Traversal:
Current Path: [0], Current Cost: 0
Current Path: [0, 1], Current Cost: 10
Current Path: [0, 2], Current Cost: 15
...
Optimal Solution:
Minimum cost: 80
Optimal path: [0, 1, 3, 2, 0]

EXPERIMENT-7: TOWER OF HANOI


AIM:
To implement the Tower of Hanoi problem using Python and demonstrate the concept of recursion
in solving a classic mathematical puzzle.

DESCRIPTION:
The Tower of Hanoi is a fundamental problem in computer science used to illustrate recursive
algorithms. The puzzle involves three rods and a number of disks of varying sizes. Initially, all disks
are stacked on one rod in decreasing size order, with the largest at the bottom and the smallest at
the top.
The goal is to move the entire stack to another rod following these rules:
1. Only one disk can be moved at a time.
2. Each move consists of taking the top disk from one stack and placing it on top of another
stack.
3. No disk may be placed on top of a smaller disk.
This recursive problem has an optimal solution in 2ⁿ - 1 moves, where n is the number of disks.

PROCEDURE:
1. Define a recursive function that accepts four parameters:
o num: The number of disks.
o source: The name of the source rod.
o aux: The name of the auxiliary rod.
o target: The name of the destination rod.
2. If there is only one disk, move it directly from the source to the destination.
3. Recursively move the top n-1 disks from the source to the auxiliary rod.
4. Move the largest (nth) disk directly from the source to the destination rod.
5. Recursively move the n-1 disks from the auxiliary rod to the destination rod.
PROGRAM:
def tower_of_hanoi(num, source, aux, target):
"""
Recursive function to solve Tower of Hanoi problem.

Parameters:
num (int): Number of disks.
source (str): The name of the source tower.
aux (str): The name of the auxiliary tower.
target (str): The name of the target tower.
"""
if num == 1:
print (f"Move disk 1 from {source} to {target}")
return
# Step 1: Move n-1 disks from source to auxiliary
tower_of_hanoi (num - 1, source, target, aux)

# Step 2: Move the remaining disk to target


Print (f"Move disk {num} from {source} to {target}")

# Step 3: Move the n-1 disks from auxiliary to target


tower_of_hanoi (num - 1, aux, source, target)

# Example usage
num_disks = 3 # You can change this number to test with more disks
print(f"Tower of Hanoi solution for {num_disks} disks:\n")
tower_of_hanoi(num_disks, "A", "B", "C")

input("\n\nPress Enter to close...")

OUTPUT:
Move disk 1 from A to C
Move disk 2 from A to B
Move disk 1 from C to B
Move disk 3 from A to C
Move disk 1 from B to A
Move disk 2 from B to C
Move disk 1 from A to C

EXPERIMENT-8: MONKEY BANANA PROBLEM


AIM:
To implement the Monkey-Banana Problem using Python, demonstrating how state-space search
(using Breadth-First Search) can solve classical AI planning problems.

DESCRIPTION:
The Monkey-Banana Problem is a well-known problem in Artificial Intelligence (AI) used to illustrate
state-space representation and goal-oriented planning. A monkey is placed in a room where a
banana hangs from the ceiling, out of reach. A chair is available in the room which the monkey can
use to reach the banana. The monkey must figure out how to reach the banana by executing a
sequence of valid actions such as walking to the chair, pushing it under the banana, climbing onto it,
and finally grabbing the banana.
The task is solved by modelling the environment as states, defining valid actions that transition
between states, and using a search algorithm to find a path from the initial state to the goal state.

PROCEDURE:
1. Define the initial state: Represent the monkey as being far from the chair, the chair not
under the banana, the monkey off the chair, and not holding the banana.
2. Define the goal state: The monkey is near the chair, the chair is under the banana, the
monkey is on the chair, and holding the banana.
3. List valid actions:
o Move to Chair
o Push Chair under Banana
o Climb Chair
o Grasp Banana
4. Implement transitions: Each action transforms the current state to a new state if allowed.
5. Use Breadth-First Search (BFS): Explore all possible sequences of actions from the initial
state until the goal state is reached.

PROGRAM:
def monkey_banana_problem():
# Initial state format: (Monkey's Location, Chair Position, Monkey's Position, Banana Holding
Status)
initial_state = ('Far-Chair', 'Chair-Not-Under-Banana', 'Off-Chair', 'Empty')
goal_state = ('Near-Chair', 'Chair-Under-Banana', 'On-Chair', 'Holding')
print (f"\nInitial state: {initial_state}")
# Define all possible actions and their effect on state
actions = {
"Move to Chair": lambda s: ('Near-Chair', s[1], s[2], s[3]) if s[0] != 'Near-Chair' else None,
"Push Chair under Banana": lambda s: ('Near-Chair', 'Chair-Under-Banana', s[2], s[3]) if s[0] ==
'Near-Chair' and s[1] != 'Chair-Under-Banana' else None,
"Climb Chair": lambda s: ('Near-Chair', 'Chair-Under-Banana', 'On-Chair', s[3]) if s[0] == 'Near-
Chair' and s[1] == 'Chair-Under-Banana' and s[2] != 'On-Chair' else None,
"Grasp Banana": lambda s: ('Near-Chair', 'Chair-Under-Banana', 'On-Chair', 'Holding') if s[0] ==
'Near-Chair' and s[1] == 'Chair-Under-Banana' and s[2] == 'On-Chair' and s[3] != 'Holding' else None
}
from collections import deque
dq = deque([(initial_state, [])]) # (current_state, actions_so_far)
visited = set()
while dq:
current_state, actions_taken = dq.popleft()
if current_state == goal_state:
print("\n✅ Solution Found!")
print("Steps to achieve the goal:")
for action in actions_taken:
print(action)
print(f"\nFinal State: {current_state}")
return
if current_state in visited:
continue
visited.add(current_state)
for action_name, transition in actions.items():
next_state = transition(current_state)
if next_state and next_state not in visited:
dq.append((next_state, actions_taken + [f"{action_name} → {next_state}"]))
print("❌ No solution found.")
# Run the program
monkey_banana_problem()
input("\n\nPress Enter to close...")

OUTPUT:
Initial state: ('Far-Chair', 'Chair-Not-Under-Banana', 'Off-Chair', 'Empty')
✅ Solution Found!
Steps to achieve the goal:
Move to Chair → ('Near-Chair', 'Chair-Not-Under-Banana', 'Off-Chair', 'Empty')
Push Chair under Banana → ('Near-Chair', 'Chair-Under-Banana', 'Off-Chair', 'Empty')
Climb Chair → ('Near-Chair', 'Chair-Under-Banana', 'On-Chair', 'Empty')
Grasp Banana → ('Near-Chair', 'Chair-Under-Banana', 'On-Chair', 'Holding')
Final State: ('Near-Chair', 'Chair-Under-Banana', 'On-Chair', 'Holding')

EXPERIMENT – 9: ALPHA-BETA PRUNING


AIM:
To implement Alpha-Beta Pruning using a Python program.

DESCRIPTION:
Alpha-Beta Pruning is an optimization technique for the Minimax algorithm, widely used in AI for
two-player turn-based games like Chess, Tic-Tac-Toe, and Checkers. This technique reduces the
number of nodes evaluated in the search tree, without changing the result.
It improves the performance by eliminating branches that will not affect the final decision.

KEY COMPONENTS:
 Alpha (α): The best value that the maximizing player (Player 1) can guarantee at any point.
 Beta (β): The best value that the minimizing player (Player 2) can guarantee at any point.
 Pruning: If at any point β ≤ α, that branch is cut off, as it will not be selected by a rational
player.
PROCEDURE:
1. Define the recursive function alpha_beta_pruning() which takes:
o Current depth of the tree
o Node index in the array
o Whether it's maximizing or minimizing player
o The list of leaf values
o Alpha and Beta values
2. If it's a leaf node (depth 0), return its value.
3. For a maximizing player:
o Recursively evaluate both children
o Update alpha
o Prune if beta <= alpha
4. For a minimizing player:
o Recursively evaluate both children
o Update beta
o Prune if beta <= alpha
5. Start from the root and return the optimal value.

PROGRAM:
"""
Alpha Beta Pruning :
-------------------
depth (int): Current depth in the game tree.
node_index (int): Index of the current node in the values array.
maximizing_player (bool): True if the current player is maximizing, False otherwise.
values (list): List of leaf node values.
alpha (float): Best value for the maximizing player.
beta (float): Best value for the minimizing player.

Returns:
int: The optimal value for the current player.
"""
import math

def alpha_beta_pruning(depth, node_index, maximizing_player, values, alpha, beta):


# Base case: leaf node
if depth == 0 or node_index >= len(values):
return values[node_index]

if maximizing_player:
max_eval = -math.inf
for i in range(2): # Each node has two children
eval = alpha_beta_pruning(depth - 1, node_index * 2 + i, False, values, alpha, beta)
max_eval = max(max_eval, eval)
alpha = max(alpha, eval)
if beta <= alpha:
break # Beta cutoff
return max_eval
else:
min_eval = math.inf
for i in range(2): # Each node has two children
eval = alpha_beta_pruning(depth - 1, node_index * 2 + i, True, values, alpha, beta)
min_eval = min(min_eval, eval)
beta = min(beta, eval)
if beta <= alpha:
break # Alpha cutoff
return min_eval

# Example usage
if __name__ == "__main__":
# Leaf node values for a complete binary tree
values = [3, 5, 6, 9, 1, 2, 0, -1]
depth = 3 # Height of the tree
optimal_value = alpha_beta_pruning(depth, 0, True, values, -math.inf, math.inf)
print(f"The optimal value is: {optimal_value}")

input("\n\nPress Enter to close...")

OUTPUT:
The optimal value is: 5

EXPERIMENT-10: 8-QUEENS PROBLEM


AIM:
To implement the 8-Queens Problem using a Python program.

DESCRIPTION:
The 8-Queens Problem is a classic puzzle where the task is to place 8 queens on a standard 8×8
chessboard such that no two queens attack each other.
That is:
 No two queens should be on the same row, same column, or same diagonal.
It is a specific instance of the N-Queens Problem, where N queens are to be placed on an N×N board.

PROCEDURE:
Step-by-Step:
1. Initialize the Chessboard:
o Create an 8×8 matrix (2D list) filled with 0s, where 0 means empty.
2. Start Placing Queens (Row by Row):
o Begin with row 0 and try to place a queen in each column.
3. Check for Safety Before Placement:
o Ensure that no other queen exists:
 In the same column.
 On the upper-left diagonal.
 On the upper-right diagonal.
4. Place the Queen:
o If the position is safe, mark it with 1.
5. Recurse to Next Row:
o Call the function recursively to solve for the next row.
6. Backtracking:
o If no valid position is found in a row, backtrack by removing the previous queen and
trying a different position.
7. Print Solutions:
o Once all queens are placed without conflict, print the board.

PROGRAM:
def printSolution(board):
"""Print the chessboard configuration."""
for row in board:
print(" ".join("Q" if col else "." for col in row))
print("\n")

def isSafe(board, row, col, n):


"""Check if placing a queen at board[row][col] is safe."""
# Check column
for i in range(row):
if board[i][col]:
return False

# Check upper-left diagonal


i, j = row, col
while i >= 0 and j >= 0:
if board[i][j]:
return False
i -= 1
j -= 1

# Check upper-right diagonal


i, j = row, col
while i >= 0 and j < n:
if board[i][j]:
return False
i -= 1
j += 1

return True

def solveNQueens(board, row, n):


"""Use backtracking to solve the N-Queens problem."""
if row == n:
printSolution(board)
return True

result = False
for col in range(n):
if isSafe(board, row, col, n):
# Place the queen
board[row][col] = 1
# Recur to place the rest of the queens
result = solveNQueens(board, row + 1, n) or result
# Backtrack
board[row][col] = 0

return result

def nQueens(n):
"""Driver function to solve the N-Queens problem."""
board = [[0] * n for _ in range(n)]
if not solveNQueens(board, 0, n):
print("No solution exists.")
else:
print("Solutions printed above.")

# Solve the 8-Queens problem


nQueens(8)
input("\n\nPress Enter to close...")

OUTPUT:
Q.......
....Q...
.......Q
.....Q..
..Q.....
......Q.
.Q......
...Q....

Q.......
.....Q..
...Q....
......Q.
.Q......
....Q...
.......Q
..Q.....
... (more solutions follow)
Solutions printed above.
Press Enter to close...

You might also like