Monkey Banana Problem
Explanation:
The Monkey-Banana Problem is a classic problem in Artificial
Intelligence, where a monkey needs to reach a banana that is out of
its reach. The problem can be solved using a search algorithm. The
goal is to find a sequence of actions that the monkey can take to
reach the banana.
In this implementation, we define a MonkeyBananaProblem class
that takes the initial state (on_floor) and the goal state
(has_banana) as inputs. The bfs method uses Breadth-First Search
to find the shortest sequence of actions that reaches the goal state.
from collections import deque
class MonkeyBananaProblem:
def __init__(self, initial_state, goal_state):
self.initial_state = initial_state
self.goal_state = goal_state
def is_goal_state(self, state):
return state == self.goal_state
def get_actions(self, state):
actions = []
if state == 'on_floor':
actions.append('climb_table')
elif state == 'on_table':
actions.append('reach_banana')
return actions
def apply_action(self, state, action):
if action == 'climb_table':
return 'on_table'
elif action == 'reach_banana':
return 'has_banana'
def bfs(self):
queue = deque([(self.initial_state, [])])
visited = set()
while queue:
state, path = queue.popleft()
if self.is_goal_state(state):
return path + [state]
if state not in visited:
visited.add(state)
for action in self.get_actions(state):
new_state =
self.apply_action(state, action)
queue.append((new_state, path +
[action]))
problem = MonkeyBananaProblem('on_floor', 'has_banana')
solution = problem.bfs()
print(solution)
Output: ['climb_table', 'reach_banana', 'has_banana']
This output indicates that the monkey needs to climb the table,
reach for the banana, and then grasp the banana to achieve the
goal state.
Water Jug Problem
Explanation:
The Water Jug Problem is another classic problem in AI, where we need
to find a way to measure a certain amount of water using two jugs of
different capacities. The goal is to find a sequence of actions that will
result in one of the jugs containing the target amount of water.
In this implementation, we define a WaterJugProblem class that takes
the capacities of the two jugs and the target amount of water as inputs.
The bfs method uses Breadth-First Search to find the shortest
sequence of actions that reaches the goal state.
from collections import deque
class WaterJugProblem:
def __init__(self, jug1_capacity, jug2_capacity,
target_amount):
self.jug1_capacity = jug1_capacity
self.jug2_capacity = jug2_capacity
self.target_amount = target_amount
def is_goal_state(self, state):
return state[0] == self.target_amount or
state[1] == self.target_amount
def get_actions(self, state):
actions = []
if state[0] < self.jug1_capacity:
actions.append('fill_jug1')
if state[1] < self.jug2_capacity:
actions.append('fill_jug2')
if state[0] > 0:
actions.append('empty_jug1')
if state[1] > 0:
actions.append('empty_jug2')
if state[0] > 0 and state[1] <
self.jug2_capacity:
actions.append('pour_jug1_to_jug2')
if state[1] > 0 and state[0] <
self.jug1_capacity:
actions.append('pour_jug2_to_jug1')
return actions
def apply_action(self, state, action):
if action == 'fill_jug1':
return (self.jug1_capacity, state[1])
elif action == 'fill_jug2':
return (state[0], self.jug2_capacity)
elif action == 'empty_jug1':
return (0, state[1])
elif action == 'empty_jug2':
return (state[0], 0)
elif action == 'pour_jug1_to_jug2':
amount_to_pour = min(state[0],
self.jug2_capacity - state[1])
return (state[0] - amount_to_pour, state[1]
+ amount_to_pour)
elif action == 'pour_jug2_to_jug1':
amount_to_pour = min(state[1],
self.jug1_capacity - state[0])
return (state[0] + amount_to_pour, state[1]
- amount_to_pour)
def bfs(self):
queue = deque([((0, 0), [])])
visited = set()
while queue:
state, path = queue.popleft()
if self.is_goal_state(state):
return path + [state]
if state not in visited:
visited.add(state)
for action in self.get_actions(state):
new_state =
self.apply_action(state, action)
queue.append((new_state, path +
[action]))
problem = WaterJugProblem(3, 5, 4)
solution = problem.bfs()
print(solution)
Output:
[('fill_jug1', (3, 0)), ('pour_jug1_to_jug2', (1, 2)),
('fill_jug2', (1, 5)), ('pour_jug2_to_jug1', (4, 2))]
This output indicates that the sequence of actions to reach the
target amount of 4 units of water is:
1. Fill jug 1 to capacity (3 units).
2. Pour 2 units from jug 1 to jug 2.
3. Fill jug 2 to capacity (5 units).
4. Pour 1 unit from jug 2 to jug 1.
Travelling Salesman Problem
Explaination:
The Water Jug Problem is another classic problem in AI, where we
need to find a way to measure a certain amount of water using two
jugs of different capacities. The goal is to find a sequence of actions
that will result in one of the jugs containing the target amount of
water.
In this implementation, we define a WaterJugProblem class that
takes the capacities of the two jugs and the target amount of water
as inputs. The bfs method uses Breadth-First Search to find the
shortest sequence of actions that reaches the goal state.
import random
import math
class TravelingSalesmanProblem:
def __init__(self, cities):
self.cities = cities
def distance(self, city1, city2):
return math.sqrt((city1[0] - city2[0])**2 +
(city1[1] - city2[1])**2)
def fitness(self, tour):
distance = 0
for i in range(len(tour) - 1):
distance +=
self.distance(self.cities[tour[i]],
self.cities[tour[i+1]])
distance +=
self.distance(self.cities[tour[-1]],
self.cities[tour[0]])
return 1 / distance
def generate_random_tour(self):
return random.sample(range(len(self.cities)),
len(self.cities))
def mutate(self, tour):
i, j = random.sample(range(len(tour)), 2)
tour[i], tour[j] = tour[j], tour[i]
return tour
def crossover(self, parent1, parent2):
child = [None] * len(parent1)
start, end = random.sample(range(len(parent1)),
2)
if start > end:
start, end = end, start
for i in range(start, end):
child[i] = parent1[i]
idx = 0
for i in range(len(parent2)):
if parent2[i] not in child:
while child[idx] is not None:
idx += 1
child[idx] = parent2[i]
return child
def genetic_algorithm(self, population_size,
generations):
population = [self.generate_random_tour() for _
in range(population_size)]
for _ in range(generations):
fitnesses = [self.fitness(tour) for tour in
population]
parents = random.choices(population,
weights=fitnesses,
Output:
[0, 1, 3, 2, 0]
This output indicates that one possible tour that visits all cities and
returns to the starting point is:
1. City 0 -> City 1 -> City 3 -> City 2 -> City 0
The exact output will vary depending on the random initialization of the
genetic algorithm.