Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Assignment 1 #1

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 39 additions & 3 deletions Q6/Readme.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,43 @@
# Assignment 1 : Question 6
|Std ID|Name|
|------|-|
|K211234|Amjad Amjad|
|K214321|Sajjid Sajjid|
|i222132|Mursil Hassan|

Add code files for question 6 here. Explain code here. Add screenshots of your programs output.
![image](https://github.com/NUCES-Khi/assign1-7questions-mursil/assets/85949538/fe32debb-209f-4b37-bdc4-fe650bcb2346)

#Explaination
The code uses functions ,and each function is an algorithm, the goal of the program is to fine the most effective algorithm,
in order to reach a specific place
## BFS UCS GBFS IDDFS

These are the algorithms used within the program, they all work differently.

**(BFS)** explores neighboring nodes at the current depth before progressing to deeper levels, using a queue to track the next nodes to visit.

**(UCS)** prioritizes nodes based on their path cost from the source in a weighted graph, maintaining a priority queue.

**(GBFS)** selects nodes closest to the goal using a heuristic function, employing a priority queue based on heuristic values.

**(IDDFS)** combines BFS and DFS, gradually increasing the depth limit until finding the target node.







## MAIN
The main part of the code takes input for the source and destination nodes, checks if they exist in the graph, and then runs each of the
search algorithms. After finding paths, it computes their costs and prints the results, including the shortest path algorithms in ascending
order of their costs.


## Result

The Screen shot shows that that BFS had the least cost as compared to all other algos used.






174 changes: 174 additions & 0 deletions Q6/Task 6.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
from collections import deque
from queue import PriorityQueue

heuristic_table = {
"Arad": 366,
"Bucharest": 0,
"Craiova": 160,
"Drobeta": 242,
"Eforie": 161,
"Fagaras": 176,
"Giurgiu": 77,
"Hirsova": 151,
"Iasi": 226,
"Lugoj": 244,
"Mehadia": 241,
"Neamt": 234,
"Oradea": 380,
"Pitesti": 100,
"Rimnicu Vilcea": 193,
"Sibiu": 253,
"Timisoara": 329,
"Urziceni": 80,
"Vaslui": 199,
"Zerind": 374
}

graph = {
'Arad': {'Zerind': 75, 'Sibiu': 140, 'Timisoara': 118},
'Zerind': {'Arad': 75, 'Oradea': 71},
'Oradea': {'Zerind': 71, 'Sibiu': 151},
'Sibiu': {'Arad': 140, 'Oradea': 151, 'Fagaras': 99, 'Rimnicu Vilcea': 80},
'Timisoara': {'Arad': 118, 'Lugoj': 111},
'Lugoj': {'Timisoara': 111, 'Mehadia': 70},
'Mehadia': {'Lugoj': 70, 'Drobeta': 75},
'Drobeta': {'Mehadia': 75, 'Craiova': 120},
'Craiova': {'Drobeta': 120, 'Rimnicu Vilcea': 146, 'Pitesti': 138},
'Rimnicu Vilcea': {'Sibiu': 80, 'Craiova': 146, 'Pitesti': 97},
'Fagaras': {'Sibiu': 99, 'Bucharest': 211},
'Bucharest': {'Fagaras': 211, 'Pitesti': 101, 'Giurgiu': 90, 'Urziceni': 85},
'Giurgiu': {'Bucharest': 90},
'Urziceni': {'Bucharest': 85, 'Hirsova': 98, 'Vaslui': 142},
'Hirsova': {'Urziceni': 98, 'Eforie': 86},
'Eforie': {'Hirsova': 86},
'Vaslui': {'Urziceni': 142, 'Iasi': 92},
'Iasi': {'Vaslui': 92, 'Neamt': 87},
'Neamt': {'Iasi': 87},
'Pitesti': {'Rimnicu Vilcea': 97, 'Craiova': 138, 'Bucharest': 101}
}


def breadth_first_search(graph, source, target):
visited = set()
queue = deque([[source]])
if source == target:
return [source]
while queue:
vertex = queue.popleft()
node = vertex[-1]
if node not in visited:
neighbors = graph[node]
for neighbor in neighbors:
new_vertex = list(vertex)
new_vertex.append(neighbor)
queue.append(new_vertex)
if neighbor == target:
return new_vertex
visited.add(node)
return None


def uniform_cost_search(graph, source, target):
visited = set()
queue = PriorityQueue()
queue.put((0, [source]))
while not queue.empty():
cost, vertex = queue.get()
node = vertex[-1]
if node not in visited:
if node == target:
return vertex
visited.add(node)
neighbors = graph[node]
for neighbor, weight in neighbors.items():
if neighbor not in visited:
total_cost = cost + weight
new_vertex = list(vertex)
new_vertex.append(neighbor)
queue.put((total_cost, new_vertex))
return None


def greedy_best_first_search(graph, source, target, heuristic):
visited = set()
queue = PriorityQueue()
queue.put((heuristic[source], [source]))
while not queue.empty():
_, path = queue.get()
node = path[-1]
if node not in visited:
visited.add(node)
if node == target:
return path
for neighbor, _ in graph[node].items():
if neighbor not in visited:
queue.put((heuristic[neighbor], path + [neighbor]))
return None


def iterative_deepening_depth_first_search(graph, source, target):
depth_limit = 0
while True:
stack = [(source, [source])]
visited = set()
while stack:
node, path = stack.pop()
if node == target:
return path
if len(path) <= depth_limit:
if node not in visited:
visited.add(node)
for neighbor in graph[node]:
if neighbor not in visited:
stack.append((neighbor, path + [neighbor]))
depth_limit += 1


def compute_path_cost(path, graph):
total_cost = 0
for i in range(len(path) - 1):
total_cost += graph[path[i]][path[i + 1]]
return total_cost

source = input("Enter Starting Point: ")
destination = input("Enter Destination: ")
if source not in graph or destination not in graph:
print("Invalid Input")
else:
bfs = breadth_first_search(graph, source, destination)
if bfs:
bfs_cost = compute_path_cost(bfs, graph)
print("Shortest Path By Breadth First Search: ",bfs)
print("Cost By Breadth First Search: ",bfs_cost)
else:
print("No Path Found")
ucs = uniform_cost_search(graph, source, destination)
if ucs:
ucs_cost = compute_path_cost(ucs,graph)
print("Shortest Path By Uniform Cost Search: ",ucs)
print("Cost By Uniform Cost Search: ",ucs_cost)
else:
print("No Path Found")
gbfs = greedy_best_first_search(graph, source, destination, heuristic_table)
if gbfs:
gbfs_cost = compute_path_cost(gbfs,graph)
print("Shortest Path By Greedy Best First Search: ",gbfs)
print("Cost By Greedy Best First Search: ",gbfs_cost)
else:
print("No Path Found")
iddfs = iterative_deepening_depth_first_search(graph, source, destination)
if iddfs:
iddfs_cost = compute_path_cost(iddfs,graph)
print("Shortest Path By Iterative Depth First Search: ",iddfs)
print("Cost By Iterative Depth First Search: ",iddfs_cost)
else:
print("No Path Found")
sorted_algorithms = sorted([
("Breadth-First Search", bfs_cost),
("Uniform Cost Search", ucs_cost),
("Greedy Best-First Search", gbfs_cost),
("Iterative Deepening Depth-First Search", iddfs_cost)
], key=lambda x: x[1])
print("\nShortest Path Algorithms (Ascending Order):")
for algorithm, cost in sorted_algorithms:
print(f"{algorithm}: Cost {cost}")
31 changes: 27 additions & 4 deletions Q7/Readme.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,29 @@
# Assignment 1 : Question 7
|Std ID|Name|
|------|-|
|K211234|Amjad Amjad|
|K214321|Sajjid Sajjid|
You must add code for Q7 in this folder. Update this readme file to explain your code and paste screenshots of your programs output.
|I222132|Mursil Hassan|

# Screen Shot

![image](https://github.com/NUCES-Khi/assign1-7questions-mursil/assets/85949538/2b529faf-2950-49db-8317-9043951e39fa)


# Code

### Explaination

These are the two main functions.

**isSafe(arr, row, col, n):**
This function checks whether placing a queen at position (row, col) on the chessboard (arr) is safe or not.
It ensures that no other queen in the same column or diagonal can attack it. It iterates over the rows above the current row to check
for queens in the same column and diagonals.

**nQueen(arr, row, n):**
This is the main recursive function to solve the N-Queens problem. It tries to place queens row by row.
If it successfully places a queen in the current row, it recursively calls itself for the next row. If all queens are successfully placed,
it returns True. If no solution is found, it backtracks by resetting the cell and tries the next column. If all columns are tried and no
solution is found, it returns False.

# Result
The result is seen in the screen shot, where N Queen Probelm has been solved

32 changes: 32 additions & 0 deletions Q7/Task 7.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
def isSafe(arr, row, col, n):
for i in range(row):
if arr[i][col] == 1:
return False
for i, j in zip(range(row, -1, -1), range(col, -1, -1)):
if arr[i][j] == 1:
return False
for i, j in zip(range(row, -1, -1), range(col, n)):
if arr[i][j] == 1:
return False
return True


def nQueen(arr, row, n):
if row >= n:
return True
for col in range(n):
if isSafe(arr, row, col, n):
arr[row][col] = 1
if nQueen(arr, row + 1, n):
return True
arr[row][col] = 0
return False


n = int(input("Enter Value Of N: "))
arr = [[0] * n for _ in range(n)]
if nQueen(arr, 0, n):
for i in range(n):
for j in range(n):
print(arr[i][j], end=" ")
print()
Loading