''' mbinary ######################################################################### # File : Astar.py # Author: mbinary # Mail: zhuheqin1@gmail.com # Blog: https://mbinary.xyz # Github: https://github.com/mbinary # Created Time: 2018-05-19 23:06 # Description: ######################################################################### ''' from random import shuffle isVisited = [0]*362880 # 0 for not visited,1 for occured,2 for visited fac = [1, 1, 2, 6, 24, 120, 720, 5040, 40320] lf = len(fac) h = [[0, 1, 2, 1, 2, 3, 2, 3, 4], [1, 0, 1, 2, 1, 2, 3, 2, 3], [2, 1, 0, 3, 2, 1, 4, 3, 2], [1, 2, 3, 0, 1, 2, 1, 2, 3], [2, 1, 2, 1, 0, 1, 2, 1, 2], [3, 2, 1, 2, 1, 0, 3, 2, 1], [2, 3, 4, 1, 2, 3, 0, 1, 2], [3, 2, 3, 2, 1, 2, 1, 0, 1], [4, 3, 2, 3, 2, 1, 2, 1, 0]] def cantor(s): sum = 0 ls = len(s) for i in range(ls): count = 0 for j in range(i+1, ls): if s[i] > s[j]: count += 1 sum += count*fac[lf-i-1] return sum que = [] dir = {-3: 'u', 1: 'r', 3: 'd', -1: 'l'} class state: flag = True def __init__(self, s, x, f, step=0, last=0): self.x = x self.s = list(s) self.step = step self.path = [] self.last = last self.f = f def can(self): cans = [-1, 1, 3, -3] if self.last in cans: cans.remove(-self.last) if self.x < 3: cans.remove(-3) if self.x > 5: cans.remove(3) if self.x % 3 is 0: cans.remove(-1) if self.x % 3 is 2: cans.remove(1) return cans def move(self): cans = self.can() for i in cans: s = list(self.s) tmp = self.x + i s[self.x] = s[tmp] s[tmp] = '9' ct = cantor(s) if isVisited[ct] != 2: val = int(s[self.x]) f = h[8][tmp] + h[val-1][self.x] - \ h[8][self.x]-h[val-1][tmp]+self.step+1 new = state(s, tmp, f, self.step + 1, i) new.path = self.path + [dir[i]] if isVisited[ct] == 1: for i, node in enumerate(que): if mew.s == node.s: del que[i] break else: isVisited[ct] = 1 if que == []: que.append(new) continue for i, node in enumerate(que): if new.f <= node.f: que.insert(i, new) def solvable(s): reverse = 0 for i in range(8): if s[i] is '9': continue for j in range(i+1, 9): if s[i] > s[j]: reverse += 1 if reverse % 2 is 0: return True else: return False def getPath(s, index): f = 0 for i, j in enumerate(s): f += h[int(j)-1][i] que.append(state(s, index, f, 0, 0)) while que != []: cur = que.pop(0) ct = cantor(cur.s) isVisited[ct] = 2 if ct is 0: return cur.path cur.move() def info(): print('input a 3x3 matrix in one line') print('from left to right,from up to down') print('such as 56831247x represent matrix as follow') print('5 6 8\n3 1 2\n4 7 x') print('then, if it has, I will print the path of moving x to reach state as follows') print('1 2 3\n4 5 6\n7 8 x') print('print q to quit') case = list('12345678x') def genCase(): tmp = case.copy() shuffle(tmp) print(f'Using random data: {tmp}') index = -1 for i, j in enumerate(tmp): if j == 'x': index = i break tmp[index] = '9' return tmp, index def isValid(li): for i in '123456789': if not i in li: print('Invalid Input') return False return True def run(): while 1: print('\n\n'+'-'*10+'Game Begins' + '-'*10) info() s = input('input: ') if s == 'q' or s == 'Q' or s == 'quit': break index = s.find('x') li = list(s) if index != -1: li[index] = '9' if not isValid(li): li, index = genCase() if solvable(li): print(''.join(getPath(li, index))) else: print('unsolvable') if __name__ == '__main__': run()