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

Dequeue Python

poeratin in dequeue python

Uploaded by

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

Dequeue Python

poeratin in dequeue python

Uploaded by

arasanvee
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
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