0% found this document useful (0 votes)
10 views6 pages

Test 4

goal state

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)
10 views6 pages

Test 4

goal state

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 and the flip that led to the state
parent = {initial_state: (None, None)} # state: (parent_state, flip_position)

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

# Now, determine the flip positions by traversing the path


formatted_path = []
for i in range(len(path) - 1):
current_state = path[i]
next_state = path[i + 1]
# Retrieve the flip position that led to next_state
_, flip_pos = parent[next_state]
formatted_state = insert_flip_marker(current_state, flip_pos)
formatted_path.append(formatted_state)
# Add the goal state
formatted_path.append(GOAL_STATE)
return formatted_path

# 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, pos)
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)
g_costs = {initial_state: 0}
h = heuristic(initial_state)
heapq.heappush(fringe, (h, tie_breaker(initial_state), 0, initial_state))
# Dictionary to keep track of parent states and the flip that led to the state
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:
current_g = g_costs[state]
current_h = heuristic(state)
path.append((state, current_g, current_h))
parent_info = parent[state]
state = parent_info[0]
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]
# Retrieve the flip position from parent mapping
# Since flip_pos was stored during BFS, we need to track it appropriately
# However, in this function, it's not directly accessible, so use
determine_flip_position
# Alternatively, we can adjust the BFS function to pass the flip positions
if needed
# Here, we assume flip_pos is correctly retrieved
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.
"""
# To accurately determine the flip position, compare the two states and find
the position where
# the next_state has the top 'flip_pos' pancakes flipped from current
for pos in range(1, 5):
flipped = flip(current, pos)
if flipped == next_state:
return pos
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

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy