0% found this document useful (0 votes)
8 views

Dequeue Python

poeratin in dequeue python

Uploaded by

arasanvee
Copyright
© © All Rights Reserved
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
8 views

Dequeue Python

poeratin in dequeue python

Uploaded by

arasanvee
Copyright
© © All Rights Reserved
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 6

import sys

from collections import deque


import heapq

# Define the goal state


GOAL_STATE = "1w2w3w4w"

def parse_input(input_str):
"""
Parses the input string into the initial state and the search algorithm.

Parameters:
input_str (str): The input string in the format '#C#C#C#C-X'.

Returns:
tuple: A tuple containing the initial state string and the search algorithm
character.
"""
try:
state_part, algo = input_str.strip().split('-')
# Validate the algorithm choice
if algo not in ['b', 'a']:
raise ValueError("Algorithm must be 'b' for BFS or 'a' for A*.")
# Validate the state length
if len(state_part) != 8:
raise ValueError("State must be 8 characters long (e.g., '1w2b3w4b').")
# Validate each pancake part
for i in range(0, 8, 2):
if not state_part[i].isdigit() or state_part[i+1] not in ['w', 'b']:
raise ValueError("Each pancake must have an ID followed by 'w' or
'b'.")
return state_part, algo
except ValueError as ve:
print(f"Invalid input format: {ve}")
sys.exit(1)

def flip(state, position):


"""
Flips the top 'position' pancakes, reverses their order, and flips their sides.

Parameters:
state (str): The current state string.
position (int): The position to flip at (1-based index).

Returns:
str: The new state after the flip.
"""
# Extract pancakes as list of tuples (id, side)
pancakes = [state[i:i+2] for i in range(0, len(state), 2)]
# Flip the top 'position' pancakes
flipped = pancakes[:position]
flipped = flipped[::-1] # Reverse the order
# Flip the side of each pancake
flipped = [pancake[0] + ('w' if pancake[1] == 'b' else 'b') for pancake in
flipped]
new_pancakes = flipped + pancakes[position:]
return ''.join(new_pancakes)

def heuristic(state):
"""
Heuristic function for A* search: the ID of the largest pancake that is still
out of order.

Parameters:
state (str): The current state string.

Returns:
int: The heuristic value.
"""
# Extract the pancake IDs by ignoring orientation
ids = [int(state[i*2]) for i in range(4)]
# Iterate from largest to smallest pancake
for i in range(3, -1, -1):
if ids[i] != i+1:
return i+1 # ID of the largest out-of-order pancake
return 0 # All pancakes are in correct order

def tie_breaker(state):
"""
Converts the state string to an 8-digit number for tie-breaking.
'w' is replaced with '1' and 'b' with '0'.

Parameters:
state (str): The state string.

Returns:
int: The numerical representation for tie-breaking.
"""
num = ''
for i in range(4):
num += state[i*2]
num += '1' if state[i*2+1] == 'w' else '0'
return int(num)

def bfs(initial_state):
"""
Performs Breadth-First Search to find the solution.

Parameters:
initial_state (str): The initial state string.

Returns:
list: A list of states representing the solution path.
"""
# Initialize the fringe as a queue
fringe = deque()
fringe.append(initial_state)
# Initialize the closed set to keep track of visited states
closed_set = set()
# Dictionary to keep track of parent states for path reconstruction
parent = {initial_state: None}

while fringe:
current = fringe.popleft()
if current in closed_set:
continue
closed_set.add(current)
if current == GOAL_STATE:
# Reconstruct the path from goal to start
path = []
while current:
path.append(current)
current = parent[current]
return path[::-1] # Reverse to get path from start to goal

# Explore all possible flips (positions 1 to 4)


for pos in range(1, 5):
next_state = flip(current, pos)
if next_state not in closed_set and next_state not in fringe:
parent[next_state] = current
fringe.append(next_state)

return [] # No solution found

def a_star(initial_state):
"""
Performs A* Search to find the solution.

Parameters:
initial_state (str): The initial state string.

Returns:
list: A list of tuples representing the solution path with g and h values.
"""
# Initialize the fringe as a priority queue (min-heap)
fringe = []
# Heap elements are tuples: (f, tie_breaker, g, state)
initial_h = heuristic(initial_state)
heapq.heappush(fringe, (initial_h, tie_breaker(initial_state), 0,
initial_state))
# Dictionary to keep track of the lowest g cost for each state
g_costs = {initial_state: 0}
# Dictionary to keep track of parent states and the flip that led to them
parent = {initial_state: (None, None)} # state: (parent_state, flip_position)

while fringe:
f, tb, g, current = heapq.heappop(fringe)

if current == GOAL_STATE:
# Reconstruct the path with g and h values
path = []
state = current
while state:
prev, flip_pos = parent[state]
current_g = g_costs[state]
current_h = heuristic(state)
path.append((state, current_g, current_h))
state = prev
return path[::-1] # Reverse to get path from start to goal

# If this state has already been expanded with a lower g, skip


if g > g_costs.get(current, float('inf')):
continue

# Explore all possible flips (positions 1 to 4)


for pos in range(1, 5):
next_state = flip(current, pos)
flip_cost = pos # Cost is equal to the number of pancakes flipped
tentative_g = g + flip_cost

# If this path to next_state is better, or next_state not seen before


if tentative_g < g_costs.get(next_state, float('inf')):
g_costs[next_state] = tentative_g
h = heuristic(next_state)
f_new = tentative_g + h
heapq.heappush(fringe, (f_new, tie_breaker(next_state),
tentative_g, next_state))
parent[next_state] = (current, pos)

return [] # No solution found

def reconstruct_a_star_path(path):
"""
Constructs the output path with flip positions, g, and h values for A*.

Parameters:
path (list): The list of tuples containing state, g, and h.

Returns:
list: Formatted output strings showing the flip positions with g and h.
"""
output = []
for i in range(len(path)-1):
current, g, h = path[i]
next_state, _, _ = path[i+1]
flip_pos = determine_flip_position(current, next_state)
formatted_state = insert_flip_marker(current, flip_pos)
output.append(f"{formatted_state} g:{g}, h:{h}")
# Add the goal state with its g and h
goal_state, final_g, final_h = path[-1]
output.append(f"{goal_state} g:{final_g}, h:{final_h}")
return output

def reconstruct_bfs_path(path):
"""
Constructs the output path with flip positions for BFS.

Parameters:
path (list): The list of states from BFS.

Returns:
list: Formatted output strings showing the flip positions.
"""
output = []
for i in range(len(path)-1):
current = path[i]
next_state = path[i+1]
flip_pos = determine_flip_position(current, next_state)
formatted_state = insert_flip_marker(current, flip_pos)
output.append(formatted_state)
# Add the goal state
output.append(path[-1])
return output

def determine_flip_position(current, next_state):


"""
Determines the flip position between two states by finding the first differing
pancake.

Parameters:
current (str): The current state string.
next_state (str): The next state string.

Returns:
int: The flip position where the state changes.
"""
for i in range(4):
current_pancake = current[i*2:(i+1)*2]
next_pancake = next_state[i*2:(i+1)*2]
if current_pancake != next_pancake:
return i + 1 # Positions are 1-based
return 4 # Default to flipping all if no difference found

def insert_flip_marker(state, flip_position):


"""
Inserts the '|' character at the flip position in the state string.

Parameters:
state (str): The state string.
flip_position (int): The flip position (1-based index).

Returns:
str: The formatted state string with the flip marker.
"""
pos = flip_position * 2
return state[:pos] + '|' + state[pos:]

def main():
"""
The main function to execute the Burnt Pancake problem solution.
"""
# Read input from the user
input_str = input().strip()
initial_state, algo = parse_input(input_str)

if algo == 'b':
# Perform BFS
solution_path = bfs(initial_state)
if not solution_path:
print("No solution found using BFS.")
sys.exit(1)
formatted_output = reconstruct_bfs_path(solution_path)
elif algo == 'a':
# Perform A* Search
solution_path = a_star(initial_state)
if not solution_path:
print("No solution found using A* Search.")
sys.exit(1)
formatted_output = reconstruct_a_star_path(solution_path)
else:
print("Invalid algorithm choice. Use 'b' for BFS or 'a' for A*.")
sys.exit(1)

# Print the formatted solution


for line in formatted_output:
print(line)

if __name__ == "__main__":
main()

You might also like