Advertisement
Guest User

Untitled

a guest
Jan 16th, 2025
72
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 3.04 KB | None | 0 0
  1. import queue
  2. #green marble is a 1 bit
  3. #5 bits empty coordinate, 25 bits bitmap of marbles
  4. #                12   |bitmap
  5. start_state =  0b011001000011000110001110011110
  6. target_state = 0b011000111100111000110001100001
  7. target_board = 0b0111100111000110001100001
  8.  
  9. def decompose_state_int(state):
  10.     empty = (state >> 25)%25
  11.     board = (state & 0x1ffffff)
  12.     return (empty, board)
  13.  
  14. def compose_state_int(empty, board):
  15.     return (empty << 25) | board
  16.  
  17. def decompose_pos_int(empty):
  18.     return (4-empty//5,4-empty%5)
  19.  
  20. def compose_pos_int(x,y):
  21.     return (4-y)*5+(4-x)
  22.  
  23. def metric(state):
  24.     empty, board = decompose_state_int(state)
  25.     empty_adjust = 1 if empty!=12 else 0
  26.     board_score = (board ^ target_board).bit_count() #this wrongly prefers blue over green, but should be irrelevant since the problem is symmetric
  27.     return board_score+empty_adjust
  28.  
  29. def get_possible_next_states(state):
  30.     offsets = [(1,2),(2,1),(2,-1),(1,-2),(-1,-2),(-2,-1),(-2,1),(-1,2)]
  31.     empty, board = decompose_state_int(state)
  32.     empty_pos = decompose_pos_int(empty)
  33.     results = []
  34.     for offset in offsets:
  35.         ny = empty_pos[0]+offset[0]
  36.         nx = empty_pos[1]+offset[1]
  37.         if nx<0 or nx>4 or ny<0 or ny>4:
  38.             continue
  39.         new_empty = compose_pos_int(nx,ny)
  40.         new_mask = 1<<new_empty
  41.         target_bit = 1 if (new_mask&board) != 0 else 0
  42.         new_board = (board & ~new_mask) | target_bit<<empty #unset bit at new coordinate, set that bit in old empty coordinate
  43.         results.append(compose_state_int(new_empty,new_board))
  44.     return results
  45.  
  46. def debug_print(state):
  47.     empty, board = decompose_state_int(state)
  48.     y,x = decompose_pos_int(empty)
  49.     print(x,y,hex(board))
  50.     for py in range(5):
  51.         row_num = (board >> (20-5*py))&0x1f
  52.         row = "".join(["X" if py==y and px==x else str((row_num>>(4-px)&1)) for px in range(5)])
  53.         print(row)
  54.  
  55. def search():
  56.     todo = queue.PriorityQueue()
  57.     todo.put((metric(start_state),start_state))
  58.     done = {}
  59.     parent = {start_state:None}
  60.  
  61.     while not todo.empty():
  62.         val, curr = todo.get()
  63.         real_dist = val - metric(curr) #remove metric from final value
  64.         if curr == target_state:
  65.             print("found")
  66.             s=curr
  67.             counter = 0
  68.             while s:
  69.                 debug_print(s)
  70.                 print(counter)
  71.                 counter += 1
  72.                 s=parent[s]
  73.             return counter
  74.         done[curr] = real_dist
  75.         next_states = get_possible_next_states(curr)
  76.         for state in next_states:
  77.             if state in done:
  78.                 continue
  79.             estimate = real_dist+metric(state)+1
  80.             #print(metric(state))
  81.             #debug_print(state)
  82.             todo.put((estimate, state)) #append next state if we haven't seen it before
  83.             done[state] = estimate #add to done dictionary to avoid repeatedly adding states we've already reached
  84.             parent[state] = curr
  85.     return -1
  86.        
  87.  
  88.  
  89. print(metric(start_state))
  90. print(search())
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement