2018-07-08 23:28:29 +08:00
|
|
|
''' mbinary
|
|
|
|
#########################################################################
|
2020-04-15 12:28:20 +08:00
|
|
|
# File : Astar.py
|
2018-07-08 23:28:29 +08:00
|
|
|
# Author: mbinary
|
|
|
|
# Mail: zhuheqin1@gmail.com
|
2019-01-31 12:09:46 +08:00
|
|
|
# Blog: https://mbinary.xyz
|
2018-07-08 23:28:29 +08:00
|
|
|
# Github: https://github.com/mbinary
|
|
|
|
# Created Time: 2018-05-19 23:06
|
|
|
|
# Description:
|
|
|
|
#########################################################################
|
|
|
|
'''
|
|
|
|
|
2020-04-15 12:28:20 +08:00
|
|
|
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]
|
2018-07-08 23:28:29 +08:00
|
|
|
lf = len(fac)
|
2020-04-15 12:28:20 +08:00
|
|
|
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]]
|
|
|
|
|
2018-07-08 23:28:29 +08:00
|
|
|
|
|
|
|
def cantor(s):
|
|
|
|
sum = 0
|
|
|
|
ls = len(s)
|
|
|
|
for i in range(ls):
|
|
|
|
count = 0
|
2020-04-15 12:28:20 +08:00
|
|
|
for j in range(i+1, ls):
|
|
|
|
if s[i] > s[j]:
|
|
|
|
count += 1
|
2018-07-08 23:28:29 +08:00
|
|
|
sum += count*fac[lf-i-1]
|
|
|
|
return sum
|
|
|
|
|
2020-04-15 12:28:20 +08:00
|
|
|
|
2018-07-08 23:28:29 +08:00
|
|
|
que = []
|
2020-04-15 12:28:20 +08:00
|
|
|
dir = {-3: 'u', 1: 'r', 3: 'd', -1: 'l'}
|
|
|
|
|
|
|
|
|
2018-07-08 23:28:29 +08:00
|
|
|
class state:
|
|
|
|
flag = True
|
2020-04-15 12:28:20 +08:00
|
|
|
|
|
|
|
def __init__(self, s, x, f, step=0, last=0):
|
2018-07-08 23:28:29 +08:00
|
|
|
self.x = x
|
|
|
|
self.s = list(s)
|
|
|
|
self.step = step
|
|
|
|
self.path = []
|
|
|
|
self.last = last
|
|
|
|
self.f = f
|
2020-04-15 12:28:20 +08:00
|
|
|
|
2018-07-08 23:28:29 +08:00
|
|
|
def can(self):
|
2020-04-15 12:28:20 +08:00
|
|
|
cans = [-1, 1, 3, -3]
|
|
|
|
if self.last in cans:
|
2018-07-08 23:28:29 +08:00
|
|
|
cans.remove(-self.last)
|
2020-04-15 12:28:20 +08:00
|
|
|
if self.x < 3:
|
2018-07-08 23:28:29 +08:00
|
|
|
cans.remove(-3)
|
2020-04-15 12:28:20 +08:00
|
|
|
if self.x > 5:
|
2018-07-08 23:28:29 +08:00
|
|
|
cans.remove(3)
|
2020-04-15 12:28:20 +08:00
|
|
|
if self.x % 3 is 0:
|
2018-07-08 23:28:29 +08:00
|
|
|
cans.remove(-1)
|
2020-04-15 12:28:20 +08:00
|
|
|
if self.x % 3 is 2:
|
2018-07-08 23:28:29 +08:00
|
|
|
cans.remove(1)
|
|
|
|
return cans
|
2020-04-15 12:28:20 +08:00
|
|
|
|
2018-07-08 23:28:29 +08:00
|
|
|
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)
|
2020-04-15 12:28:20 +08:00
|
|
|
if isVisited[ct] != 2:
|
2018-07-08 23:28:29 +08:00
|
|
|
val = int(s[self.x])
|
2020-04-15 12:28:20 +08:00
|
|
|
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)
|
2018-07-08 23:28:29 +08:00
|
|
|
new.path = self.path + [dir[i]]
|
|
|
|
if isVisited[ct] == 1:
|
2020-04-15 12:28:20 +08:00
|
|
|
for i, node in enumerate(que):
|
2018-07-08 23:28:29 +08:00
|
|
|
if mew.s == node.s:
|
|
|
|
del que[i]
|
|
|
|
break
|
2020-04-15 12:28:20 +08:00
|
|
|
else:
|
|
|
|
isVisited[ct] = 1
|
2018-07-08 23:28:29 +08:00
|
|
|
if que == []:
|
|
|
|
que.append(new)
|
|
|
|
continue
|
2020-04-15 12:28:20 +08:00
|
|
|
for i, node in enumerate(que):
|
|
|
|
if new.f <= node.f:
|
|
|
|
que.insert(i, new)
|
|
|
|
|
|
|
|
|
2018-07-08 23:28:29 +08:00
|
|
|
def solvable(s):
|
|
|
|
reverse = 0
|
|
|
|
for i in range(8):
|
2020-04-15 12:28:20 +08:00
|
|
|
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):
|
2018-07-08 23:28:29 +08:00
|
|
|
f = 0
|
2020-04-15 12:28:20 +08:00
|
|
|
for i, j in enumerate(s):
|
|
|
|
f += h[int(j)-1][i]
|
|
|
|
que.append(state(s, index, f, 0, 0))
|
2018-07-08 23:28:29 +08:00
|
|
|
while que != []:
|
|
|
|
cur = que.pop(0)
|
|
|
|
ct = cantor(cur.s)
|
|
|
|
isVisited[ct] = 2
|
|
|
|
if ct is 0:
|
|
|
|
return cur.path
|
|
|
|
cur.move()
|
2020-04-15 12:28:20 +08:00
|
|
|
|
|
|
|
|
2018-07-15 11:20:52 +08:00
|
|
|
def info():
|
|
|
|
print('input a 3x3 matrix in one line')
|
2020-04-15 12:28:20 +08:00
|
|
|
print('from left to right,from up to down')
|
2018-07-15 11:20:52 +08:00
|
|
|
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')
|
|
|
|
|
2020-04-15 12:28:20 +08:00
|
|
|
|
2018-07-15 11:20:52 +08:00
|
|
|
case = list('12345678x')
|
2020-04-15 12:28:20 +08:00
|
|
|
|
|
|
|
|
2018-07-15 11:20:52 +08:00
|
|
|
def genCase():
|
|
|
|
tmp = case.copy()
|
|
|
|
shuffle(tmp)
|
|
|
|
print(f'Using random data: {tmp}')
|
|
|
|
index = -1
|
2020-04-15 12:28:20 +08:00
|
|
|
for i, j in enumerate(tmp):
|
|
|
|
if j == 'x':
|
2018-07-15 11:20:52 +08:00
|
|
|
index = i
|
|
|
|
break
|
|
|
|
tmp[index] = '9'
|
2020-04-15 12:28:20 +08:00
|
|
|
return tmp, index
|
|
|
|
|
|
|
|
|
2018-07-15 11:20:52 +08:00
|
|
|
def isValid(li):
|
|
|
|
for i in '123456789':
|
|
|
|
if not i in li:
|
|
|
|
print('Invalid Input')
|
|
|
|
return False
|
|
|
|
return True
|
|
|
|
|
2020-04-15 12:28:20 +08:00
|
|
|
|
2018-07-15 11:20:52 +08:00
|
|
|
def run():
|
|
|
|
while 1:
|
2020-04-15 12:28:20 +08:00
|
|
|
print('\n\n'+'-'*10+'Game Begins' + '-'*10)
|
2018-07-15 11:20:52 +08:00
|
|
|
info()
|
2020-04-15 12:28:20 +08:00
|
|
|
s = input('input: ')
|
|
|
|
if s == 'q' or s == 'Q' or s == 'quit':
|
2018-07-15 11:20:52 +08:00
|
|
|
break
|
|
|
|
index = s.find('x')
|
|
|
|
li = list(s)
|
|
|
|
if index != -1:
|
|
|
|
li[index] = '9'
|
|
|
|
if not isValid(li):
|
|
|
|
li, index = genCase()
|
|
|
|
if solvable(li):
|
2020-04-15 12:28:20 +08:00
|
|
|
print(''.join(getPath(li, index)))
|
|
|
|
else:
|
|
|
|
print('unsolvable')
|
2018-07-15 11:20:52 +08:00
|
|
|
|
2018-07-08 23:28:29 +08:00
|
|
|
|
|
|
|
if __name__ == '__main__':
|
2018-07-15 11:20:52 +08:00
|
|
|
run()
|