from collections import defaultdict, deque
import heapq
# Class representing the board configuration
class ChessBoard:
def __init__(self):
self.piece_positions = {}
def get_piece_at(self, row, col):
for piece, position in self.piece_positions.items():
if position == (row, col):
return piece
return ' '
def display(self):
print("-" * 33)
for i in range(8):
row_display = '| '
for j in range(8):
row_display += self.get_piece_at(i, j) + ' | '
print(row_display)
print("-" * 33)
def duplicate(self):
new_board = ChessBoard()
new_board.piece_positions = self.piece_positions.copy()
return new_board
def count_connected_pieces(board):
connected_count = 0
visited = [[False]*8 for _ in range(8)]
queue = deque()
queue.append(board.piece_positions['J'])
while queue:
row, col = queue.popleft()
if visited[row][col]:
continue
visited[row][col] = True
piece = board.get_piece_at(row, col)
if piece == ' ':
continue
connected_count += 1
for d_row, d_col in zip(knight_row_moves, knight_col_moves):
new_row, new_col = row + d_row, col + d_col
if 0 <= new_row < 8 and 0 <= new_col < 8 and not visited[new_row][new_col]:
queue.append((new_row, new_col))
return connected_count
def bfs_search(board):
print("Algorithm: Breadth-First Search:")
queue = deque([(board, [])])
visited = set()
visited.add(tuple(board.piece_positions.items()))
expanded_states = 0
while queue:
current_board, moves = queue.popleft()
expanded_states += 1
if count_connected_pieces(current_board) == 6:
print("One of the goal states:")
current_board.display()
print("Solution:")
for move in moves:
print(move)
print("Number of expanded states:", expanded_states)
return
for piece, (row, col) in current_board.piece_positions.items():
for direction_index, (d_row, d_col) in enumerate(zip(move_row_changes, move_col_changes)):
new_row, new_col = row + d_row, col + d_col
if 0 <= new_row < 8 and 0 <= new_col < 8:
new_board = current_board.duplicate()
new_board.piece_positions[piece] = (new_row, new_col)
new_moves = moves + [f"Move {piece} {directions[direction_index]}"]
if tuple(new_board.piece_positions.items()) not in visited:
visited.add(tuple(new_board.piece_positions.items()))
queue.append((new_board, new_moves))
def a_star_search(board):
print("Algorithm: A* Search:")
priority_queue = []
count = 0
expanded_states = 0
heapq.heappush(priority_queue, (5, count, board, []))
visited = set()
visited.add(tuple(board.piece_positions.items()))
while priority_queue:
estimated_cost, _, current_board, moves = heapq.heappop(priority_queue)
expanded_states += 1
if estimated_cost == 0:
print("One of the goal states:")
current_board.display()
print("Solution:")
for move in moves:
print(move)
print("Number of expanded states:", expanded_states)
return
for piece, (row, col) in current_board.piece_positions.items():
for direction_index, (d_row, d_col) in enumerate(zip(move_row_changes, move_col_changes)):
new_row, new_col = row + d_row, col + d_col
if 0 <= new_row < 8 and 0 <= new_col < 8:
count += 1
new_board = current_board.duplicate()
new_board.piece_positions[piece] = (new_row, new_col)
new_moves = moves + [f"Move {piece} {directions[direction_index]}"]
if tuple(new_board.piece_positions.items()) not in visited:
visited.add(tuple(new_board.piece_positions.items()))
h_n = 6 - count_connected_pieces(current_board)
heapq.heappush(priority_queue, (h_n, count, new_board, new_moves))
# Moves configuration
knight_row_moves = [1, 2, -1, -2, -1, 2, 1, -2]
knight_col_moves = [2, 1, 2, 1, -2, -1, -2, -1]
move_row_changes = [1, -1, 0, 0]
move_col_changes = [0, 0, 1, -1]
directions = ["Down", "Up", "Right", "Left"]
# Initialize and run
initial_board = ChessBoard()
initial_board.piece_positions['J'] = (1, 1)
initial_board.piece_positions['A'] = (2, 2)
initial_board.piece_positions['F'] = (4, 1)
initial_board.piece_positions['R'] = (2, 4)
initial_board.piece_positions['O'] = (5, 4)
initial_board.piece_positions['M'] = (6, 7)
print("Student name: Jafar Omar\n" +
"The six first unique letters are: J A F R O M\n");
bfs_search(initial_board)
a_star_search(initial_board)
ZnJvbSBjb2xsZWN0aW9ucyBpbXBvcnQgZGVmYXVsdGRpY3QsIGRlcXVlCmltcG9ydCBoZWFwcQoKIyBDbGFzcyByZXByZXNlbnRpbmcgdGhlIGJvYXJkIGNvbmZpZ3VyYXRpb24KY2xhc3MgQ2hlc3NCb2FyZDoKICAgIGRlZiBfX2luaXRfXyhzZWxmKToKICAgICAgICBzZWxmLnBpZWNlX3Bvc2l0aW9ucyA9IHt9CgogICAgZGVmIGdldF9waWVjZV9hdChzZWxmLCByb3csIGNvbCk6CiAgICAgICAgZm9yIHBpZWNlLCBwb3NpdGlvbiBpbiBzZWxmLnBpZWNlX3Bvc2l0aW9ucy5pdGVtcygpOgogICAgICAgICAgICBpZiBwb3NpdGlvbiA9PSAocm93LCBjb2wpOgogICAgICAgICAgICAgICAgcmV0dXJuIHBpZWNlCiAgICAgICAgcmV0dXJuICcgJwoKICAgIGRlZiBkaXNwbGF5KHNlbGYpOgogICAgICAgIHByaW50KCItIiAqIDMzKQogICAgICAgIGZvciBpIGluIHJhbmdlKDgpOgogICAgICAgICAgICByb3dfZGlzcGxheSA9ICd8ICcKICAgICAgICAgICAgZm9yIGogaW4gcmFuZ2UoOCk6CiAgICAgICAgICAgICAgICByb3dfZGlzcGxheSArPSBzZWxmLmdldF9waWVjZV9hdChpLCBqKSArICcgfCAnCiAgICAgICAgICAgIHByaW50KHJvd19kaXNwbGF5KQogICAgICAgICAgICBwcmludCgiLSIgKiAzMykKCiAgICBkZWYgZHVwbGljYXRlKHNlbGYpOgogICAgICAgIG5ld19ib2FyZCA9IENoZXNzQm9hcmQoKQogICAgICAgIG5ld19ib2FyZC5waWVjZV9wb3NpdGlvbnMgPSBzZWxmLnBpZWNlX3Bvc2l0aW9ucy5jb3B5KCkKICAgICAgICByZXR1cm4gbmV3X2JvYXJkCgpkZWYgY291bnRfY29ubmVjdGVkX3BpZWNlcyhib2FyZCk6CiAgICBjb25uZWN0ZWRfY291bnQgPSAwCiAgICB2aXNpdGVkID0gW1tGYWxzZV0qOCBmb3IgXyBpbiByYW5nZSg4KV0KICAgIHF1ZXVlID0gZGVxdWUoKQogICAgcXVldWUuYXBwZW5kKGJvYXJkLnBpZWNlX3Bvc2l0aW9uc1snSiddKQoKICAgIHdoaWxlIHF1ZXVlOgogICAgICAgIHJvdywgY29sID0gcXVldWUucG9wbGVmdCgpCiAgICAgICAgaWYgdmlzaXRlZFtyb3ddW2NvbF06CiAgICAgICAgICAgIGNvbnRpbnVlCiAgICAgICAgdmlzaXRlZFtyb3ddW2NvbF0gPSBUcnVlCiAgICAgICAgcGllY2UgPSBib2FyZC5nZXRfcGllY2VfYXQocm93LCBjb2wpCiAgICAgICAgaWYgcGllY2UgPT0gJyAnOgogICAgICAgICAgICBjb250aW51ZQogICAgICAgIGNvbm5lY3RlZF9jb3VudCArPSAxCiAgICAgICAgZm9yIGRfcm93LCBkX2NvbCBpbiB6aXAoa25pZ2h0X3Jvd19tb3Zlcywga25pZ2h0X2NvbF9tb3Zlcyk6CiAgICAgICAgICAgIG5ld19yb3csIG5ld19jb2wgPSByb3cgKyBkX3JvdywgY29sICsgZF9jb2wKICAgICAgICAgICAgaWYgMCA8PSBuZXdfcm93IDwgOCBhbmQgMCA8PSBuZXdfY29sIDwgOCBhbmQgbm90IHZpc2l0ZWRbbmV3X3Jvd11bbmV3X2NvbF06CiAgICAgICAgICAgICAgICBxdWV1ZS5hcHBlbmQoKG5ld19yb3csIG5ld19jb2wpKQogICAgcmV0dXJuIGNvbm5lY3RlZF9jb3VudAoKZGVmIGJmc19zZWFyY2goYm9hcmQpOgogICAgcHJpbnQoIkFsZ29yaXRobTogQnJlYWR0aC1GaXJzdCBTZWFyY2g6IikKICAgIHF1ZXVlID0gZGVxdWUoWyhib2FyZCwgW10pXSkKICAgIHZpc2l0ZWQgPSBzZXQoKQogICAgdmlzaXRlZC5hZGQodHVwbGUoYm9hcmQucGllY2VfcG9zaXRpb25zLml0ZW1zKCkpKQogICAgZXhwYW5kZWRfc3RhdGVzID0gMAoKICAgIHdoaWxlIHF1ZXVlOgogICAgICAgIGN1cnJlbnRfYm9hcmQsIG1vdmVzID0gcXVldWUucG9wbGVmdCgpCiAgICAgICAgZXhwYW5kZWRfc3RhdGVzICs9IDEKICAgICAgICBpZiBjb3VudF9jb25uZWN0ZWRfcGllY2VzKGN1cnJlbnRfYm9hcmQpID09IDY6CiAgICAgICAgICAgIHByaW50KCJPbmUgb2YgdGhlIGdvYWwgc3RhdGVzOiIpCiAgICAgICAgICAgIGN1cnJlbnRfYm9hcmQuZGlzcGxheSgpCiAgICAgICAgICAgIHByaW50KCJTb2x1dGlvbjoiKQogICAgICAgICAgICBmb3IgbW92ZSBpbiBtb3ZlczoKICAgICAgICAgICAgICAgIHByaW50KG1vdmUpCiAgICAgICAgICAgIHByaW50KCJOdW1iZXIgb2YgZXhwYW5kZWQgc3RhdGVzOiIsIGV4cGFuZGVkX3N0YXRlcykKICAgICAgICAgICAgcmV0dXJuCgogICAgICAgIGZvciBwaWVjZSwgKHJvdywgY29sKSBpbiBjdXJyZW50X2JvYXJkLnBpZWNlX3Bvc2l0aW9ucy5pdGVtcygpOgogICAgICAgICAgICBmb3IgZGlyZWN0aW9uX2luZGV4LCAoZF9yb3csIGRfY29sKSBpbiBlbnVtZXJhdGUoemlwKG1vdmVfcm93X2NoYW5nZXMsIG1vdmVfY29sX2NoYW5nZXMpKToKICAgICAgICAgICAgICAgIG5ld19yb3csIG5ld19jb2wgPSByb3cgKyBkX3JvdywgY29sICsgZF9jb2wKICAgICAgICAgICAgICAgIGlmIDAgPD0gbmV3X3JvdyA8IDggYW5kIDAgPD0gbmV3X2NvbCA8IDg6CiAgICAgICAgICAgICAgICAgICAgbmV3X2JvYXJkID0gY3VycmVudF9ib2FyZC5kdXBsaWNhdGUoKQogICAgICAgICAgICAgICAgICAgIG5ld19ib2FyZC5waWVjZV9wb3NpdGlvbnNbcGllY2VdID0gKG5ld19yb3csIG5ld19jb2wpCiAgICAgICAgICAgICAgICAgICAgbmV3X21vdmVzID0gbW92ZXMgKyBbZiJNb3ZlIHtwaWVjZX0ge2RpcmVjdGlvbnNbZGlyZWN0aW9uX2luZGV4XX0iXQogICAgICAgICAgICAgICAgICAgIGlmIHR1cGxlKG5ld19ib2FyZC5waWVjZV9wb3NpdGlvbnMuaXRlbXMoKSkgbm90IGluIHZpc2l0ZWQ6CiAgICAgICAgICAgICAgICAgICAgICAgIHZpc2l0ZWQuYWRkKHR1cGxlKG5ld19ib2FyZC5waWVjZV9wb3NpdGlvbnMuaXRlbXMoKSkpCiAgICAgICAgICAgICAgICAgICAgICAgIHF1ZXVlLmFwcGVuZCgobmV3X2JvYXJkLCBuZXdfbW92ZXMpKQoKZGVmIGFfc3Rhcl9zZWFyY2goYm9hcmQpOgogICAgcHJpbnQoIkFsZ29yaXRobTogQSogU2VhcmNoOiIpCiAgICBwcmlvcml0eV9xdWV1ZSA9IFtdCiAgICBjb3VudCA9IDAKICAgIGV4cGFuZGVkX3N0YXRlcyA9IDAKICAgIGhlYXBxLmhlYXBwdXNoKHByaW9yaXR5X3F1ZXVlLCAoNSwgY291bnQsIGJvYXJkLCBbXSkpCiAgICB2aXNpdGVkID0gc2V0KCkKICAgIHZpc2l0ZWQuYWRkKHR1cGxlKGJvYXJkLnBpZWNlX3Bvc2l0aW9ucy5pdGVtcygpKSkKCiAgICB3aGlsZSBwcmlvcml0eV9xdWV1ZToKICAgICAgICBlc3RpbWF0ZWRfY29zdCwgXywgY3VycmVudF9ib2FyZCwgbW92ZXMgPSBoZWFwcS5oZWFwcG9wKHByaW9yaXR5X3F1ZXVlKQogICAgICAgIGV4cGFuZGVkX3N0YXRlcyArPSAxCiAgICAgICAgaWYgZXN0aW1hdGVkX2Nvc3QgPT0gMDoKICAgICAgICAgICAgcHJpbnQoIk9uZSBvZiB0aGUgZ29hbCBzdGF0ZXM6IikKICAgICAgICAgICAgY3VycmVudF9ib2FyZC5kaXNwbGF5KCkKICAgICAgICAgICAgcHJpbnQoIlNvbHV0aW9uOiIpCiAgICAgICAgICAgIGZvciBtb3ZlIGluIG1vdmVzOgogICAgICAgICAgICAgICAgcHJpbnQobW92ZSkKICAgICAgICAgICAgcHJpbnQoIk51bWJlciBvZiBleHBhbmRlZCBzdGF0ZXM6IiwgZXhwYW5kZWRfc3RhdGVzKQogICAgICAgICAgICByZXR1cm4KCiAgICAgICAgZm9yIHBpZWNlLCAocm93LCBjb2wpIGluIGN1cnJlbnRfYm9hcmQucGllY2VfcG9zaXRpb25zLml0ZW1zKCk6CiAgICAgICAgICAgIGZvciBkaXJlY3Rpb25faW5kZXgsIChkX3JvdywgZF9jb2wpIGluIGVudW1lcmF0ZSh6aXAobW92ZV9yb3dfY2hhbmdlcywgbW92ZV9jb2xfY2hhbmdlcykpOgogICAgICAgICAgICAgICAgbmV3X3JvdywgbmV3X2NvbCA9IHJvdyArIGRfcm93LCBjb2wgKyBkX2NvbAogICAgICAgICAgICAgICAgaWYgMCA8PSBuZXdfcm93IDwgOCBhbmQgMCA8PSBuZXdfY29sIDwgODoKICAgICAgICAgICAgICAgICAgICBjb3VudCArPSAxCiAgICAgICAgICAgICAgICAgICAgbmV3X2JvYXJkID0gY3VycmVudF9ib2FyZC5kdXBsaWNhdGUoKQogICAgICAgICAgICAgICAgICAgIG5ld19ib2FyZC5waWVjZV9wb3NpdGlvbnNbcGllY2VdID0gKG5ld19yb3csIG5ld19jb2wpCiAgICAgICAgICAgICAgICAgICAgbmV3X21vdmVzID0gbW92ZXMgKyBbZiJNb3ZlIHtwaWVjZX0ge2RpcmVjdGlvbnNbZGlyZWN0aW9uX2luZGV4XX0iXQogICAgICAgICAgICAgICAgICAgIGlmIHR1cGxlKG5ld19ib2FyZC5waWVjZV9wb3NpdGlvbnMuaXRlbXMoKSkgbm90IGluIHZpc2l0ZWQ6CiAgICAgICAgICAgICAgICAgICAgICAgIHZpc2l0ZWQuYWRkKHR1cGxlKG5ld19ib2FyZC5waWVjZV9wb3NpdGlvbnMuaXRlbXMoKSkpCiAgICAgICAgICAgICAgICAgICAgICAgIGhfbiA9IDYgLSBjb3VudF9jb25uZWN0ZWRfcGllY2VzKGN1cnJlbnRfYm9hcmQpCiAgICAgICAgICAgICAgICAgICAgICAgIGhlYXBxLmhlYXBwdXNoKHByaW9yaXR5X3F1ZXVlLCAoaF9uLCBjb3VudCwgbmV3X2JvYXJkLCBuZXdfbW92ZXMpKQoKIyBNb3ZlcyBjb25maWd1cmF0aW9uCmtuaWdodF9yb3dfbW92ZXMgPSBbMSwgMiwgLTEsIC0yLCAtMSwgMiwgMSwgLTJdCmtuaWdodF9jb2xfbW92ZXMgPSBbMiwgMSwgMiwgMSwgLTIsIC0xLCAtMiwgLTFdCm1vdmVfcm93X2NoYW5nZXMgPSBbMSwgLTEsIDAsIDBdCm1vdmVfY29sX2NoYW5nZXMgPSBbMCwgMCwgMSwgLTFdCmRpcmVjdGlvbnMgPSBbIkRvd24iLCAiVXAiLCAiUmlnaHQiLCAiTGVmdCJdCgojIEluaXRpYWxpemUgYW5kIHJ1bgppbml0aWFsX2JvYXJkID0gQ2hlc3NCb2FyZCgpCmluaXRpYWxfYm9hcmQucGllY2VfcG9zaXRpb25zWydKJ10gPSAoMSwgMSkKaW5pdGlhbF9ib2FyZC5waWVjZV9wb3NpdGlvbnNbJ0EnXSA9ICgyLCAyKQppbml0aWFsX2JvYXJkLnBpZWNlX3Bvc2l0aW9uc1snRiddID0gKDQsIDEpCmluaXRpYWxfYm9hcmQucGllY2VfcG9zaXRpb25zWydSJ10gPSAoMiwgNCkKaW5pdGlhbF9ib2FyZC5waWVjZV9wb3NpdGlvbnNbJ08nXSA9ICg1LCA0KQppbml0aWFsX2JvYXJkLnBpZWNlX3Bvc2l0aW9uc1snTSddID0gKDYsIDcpCgpwcmludCgiU3R1ZGVudCBuYW1lOiBKYWZhciBPbWFyXG4iICsKICAgICAgICAgICAgICAgICJUaGUgc2l4IGZpcnN0IHVuaXF1ZSAgbGV0dGVycyBhcmU6IEogQSBGIFIgTyBNXG4iKTsKYmZzX3NlYXJjaChpbml0aWFsX2JvYXJkKQphX3N0YXJfc2VhcmNoKGluaXRpYWxfYm9hcmQpCg==