用PDDL实现骑士之旅
注意:本节内容参考《An Introduction to the Planning
Domain Definition Language》
骑士之旅是一个经典的国际象棋难题。在国际象棋中,骑士棋子沿任何基本方向(水平或垂直)移动两个空格,然后沿垂直方向移动一个空格。
与其他棋子不同,骑士“跳”到目标位置而不踩中间方块。骑士之旅是骑士的一系列动作,使棋子可以访问棋盘的每一个方块,而不必两次踩在任何方块上。(因此,它是哈密顿路径问题的一个特例。)下图显示了骑士从棋盘左上角开始的巡游示例。
问题状态可以表示为一组事实(骑士棋子所在的位置,以及它已经访问过的方块),计划由一系列动作(骑士的动作)组成,这些动作将起始状态(棋子处于起始位置,没有访问过其他方块)转换为满足目标条件的最终状态(参观过每个方块)。必须制定行动,以便它们捕获问题的所有约束:特别是,每个行动不仅必须对应于有效的骑士移动,而且还必须强制要求移动的目标方块尚未访问。
在域文件中我们定义了动作move以及三个谓词at、visited、valid_move,对于8*8的方格,棋盘上有336个有效骑士移动。因此,我们可以通过编写336个像这样的动作来模拟这个谜题,使用64个谓词表示骑士可能的当前位置,使用64个谓词跟踪访问的方块。这336个动作我们利用python程序生成:
# 这里代码感觉有点繁琐,大家有好的建议可以联系我修改
lists = [[0] * 8 for i in range(8)]
for i in range(1, 9):
for j in range(1, 9):
lists[i - 1][j - 1] = chr((ord('A') + i - 1)) + str(j)
# print("(visited " + lists[i-1][j-1] + ")")
actions = []
for i in range(8):
for j in range(8):
if i + 2 < 8 and j + 1 < 8:
actions.append("(valid_move " + lists[i][j] + " " + lists[i + 2][j + 1] + ")")
for i in range(8):
for j in range(8):
if i + 2 < 8 and -1 < j - 1 < 8:
actions.append("(valid_move " + lists[i][j] + " " + lists[i + 2][j - 1] + ")")
for i in range(8):
for j in range(8):
if i + 1 < 8 and j + 2 < 8:
actions.append("(valid_move " + lists[i][j] + " " + lists[i + 1][j + 2] + ")")
for i in range(8):
for j in range(8):
if i + 1 < 8 and -1 < j - 2 < 8:
actions.append("(valid_move " + lists[i][j] + " " + lists[i + 1][j - 2] + ")")
for i in range(8):
for j in range(8):
if -1 < i - 2 < 8 and -1 < j - 1 < 8:
actions.append("(valid_move " + lists[i][j] + " " + lists[i - 2][j - 1] + ")")
for i in range(8):
for j in range(8):
if -1 < i - 2 < 8 and j + 1 < 8:
actions.append("(valid_move " + lists[i][j] + " " + lists[i - 2][j + 1] + ")")
for i in range(8):
for j in range(8):
if -1 < i - 1 < 8 and -1 < j - 2 < 8:
actions.append("(valid_move " + lists[i][j] + " " + lists[i - 1][j - 2] + ")")
for i in range(8):
for j in range(8):
if -1 < i - 1 < 8 and j + 2 < 8:
actions.append("(valid_move " + lists[i][j] + " " + lists[i - 1][j + 2] + ")")
# for i in actions:
# print(i)
然后,下面是我们用PDDL语言实现的域文件和问题文件:
;这里是域文件
(define (domain knights-tour)
(:requirements :negative-preconditions)
(:predicates
(at ?square)
(visited ?square)
(valid_move ?square_from ?square_to)
)
(:action move
:parameters (?from ?to)
:precondition (and (at ?from)
(valid_move ?from ?to)
(not (visited ?to))
)
:effect (and (not(at ?from))
(at ?to)
(visited ?to)
)
)
)
;这里是我们的问题文件
(define (problem knights-tour-problem-8x8)
(:domain knights-tour)
(:objects
A1 A2 A3 A4 A5 A6 A7 A8
B1 B2 B3 B4 B5 B6 B7 B8
C1 C2 C3 C4 C5 C6 C7 C8
D1 D2 D3 D4 D5 D6 D7 D8
E1 E2 E3 E4 E5 E6 E7 E8
F1 F2 F3 F4 F5 F6 F7 F8
G1 G2 G3 G4 G5 G6 G7 G8
H1 H2 H3 H4 H5 H6 H7 H8
)
(:init
; 我们假设骑士在右上角
(at A8)
(visited A8)
;我们罗列出所有的有效动作
(valid_move A1 C2)
(valid_move A2 C3)
(valid_move A3 C4)
(valid_move A4 C5)
(valid_move A5 C6)
(valid_move A6 C7)
(valid_move A7 C8)
(valid_move B1 D2)
(valid_move B2 D3)
(valid_move B3 D4)
(valid_move B4 D5)
(valid_move B5 D6)
(valid_move B6 D7)
(valid_move B7 D8)
(valid_move C1 E2)
(valid_move C2 E3)
(valid_move C3 E4)
(valid_move C4 E5)
(valid_move C5 E6)
(valid_move C6 E7)
(valid_move C7 E8)
(valid_move D1 F2)
(valid_move D2 F3)
(valid_move D3 F4)
(valid_move D4 F5)
(valid_move D5 F6)
(valid_move D6 F7)
(valid_move D7 F8)
(valid_move E1 G2)
(valid_move E2 G3)
(valid_move E3 G4)
(valid_move E4 G5)
(valid_move E5 G6)
(valid_move E6 G7)
(valid_move E7 G8)
(valid_move F1 H2)
(valid_move F2 H3)
(valid_move F3 H4)
(valid_move F4 H5)
(valid_move F5 H6)
(valid_move F6 H7)
(valid_move F7 H8)
(valid_move A2 C1)
(valid_move A3 C2)
(valid_move A4 C3)
(valid_move A5 C4)
(valid_move A6 C5)
(valid_move A7 C6)
(valid_move A8 C7)
(valid_move B2 D1)
(valid_move B3 D2)
(valid_move B4 D3)
(valid_move B5 D4)
(valid_move B6 D5)
(valid_move B7 D6)
(valid_move B8 D7)
(valid_move C2 E1)
(valid_move C3 E2)
(valid_move C4 E3)
(valid_move C5 E4)
(valid_move C6 E5)
(valid_move C7 E6)
(valid_move C8 E7)
(valid_move D2 F1)
(valid_move D3 F2)
(valid_move D4 F3)
(valid_move D5 F4)
(valid_move D6 F5)
(valid_move D7 F6)
(valid_move D8 F7)
(valid_move E2 G1)
(valid_move E3 G2)
(valid_move E4 G3)
(valid_move E5 G4)
(valid_move E6 G5)
(valid_move E7 G6)
(valid_move E8 G7)
(valid_move F2 H1)
(valid_move F3 H2)
(valid_move F4 H3)
(valid_move F5 H4)
(valid_move F6 H5)
(valid_move F7 H6)
(valid_move F8 H7)
(valid_move A1 B3)
(valid_move A2 B4)
(valid_move A3 B5)
(valid_move A4 B6)
(valid_move A5 B7)
(valid_move A6 B8)
(valid_move B1 C3)
(valid_move B2 C4)
(valid_move B3 C5)
(valid_move B4 C6)
(valid_move B5 C7)
(valid_move B6 C8)
(valid_move C1 D3)
(valid_move C2 D4)
(valid_move C3 D5)
(valid_move C4 D6)
(valid_move C5 D7)
(valid_move C6 D8)
(valid_move D1 E3)
(valid_move D2 E4)
(valid_move D3 E5)
(valid_move D4 E6)
(valid_move D5 E7)
(valid_move D6 E8)
(valid_move E1 F3)
(valid_move E2 F4)
(valid_move E3 F5)
(valid_move E4 F6)
(valid_move E5 F7)
(valid_move E6 F8)
(valid_move F1 G3)
(valid_move F2 G4)
(valid_move F3 G5)
(valid_move F4 G6)
(valid_move F5 G7)
(valid_move F6 G8)
(valid_move G1 H3)
(valid_move G2 H4)
(valid_move G3 H5)
(valid_move G4 H6)
(valid_move G5 H7)
(valid_move G6 H8)
(valid_move A3 B1)
(valid_move A4 B2)
(valid_move A5 B3)
(valid_move A6 B4)
(valid_move A7 B5)
(valid_move A8 B6)
(valid_move B3 C1)
(valid_move B4 C2)
(valid_move B5 C3)
(valid_move B6 C4)
(valid_move B7 C5)
(valid_move B8 C6)
(valid_move C3 D1)
(valid_move C4 D2)
(valid_move C5 D3)
(valid_move C6 D4)
(valid_move C7 D5)
(valid_move C8 D6)
(valid_move D3 E1)
(valid_move D4 E2)
(valid_move D5 E3)
(valid_move D6 E4)
(valid_move D7 E5)
(valid_move D8 E6)
(valid_move E3 F1)
(valid_move E4 F2)
(valid_move E5 F3)
(valid_move E6 F4)
(valid_move E7 F5)
(valid_move E8 F6)
(valid_move F3 G1)
(valid_move F4 G2)
(valid_move F5 G3)
(valid_move F6 G4)
(valid_move F7 G5)
(valid_move F8 G6)
(valid_move G3 H1)
(valid_move G4 H2)
(valid_move G5 H3)
(valid_move G6 H4)
(valid_move G7 H5)
(valid_move G8 H6)
(valid_move C2 A1)
(valid_move C3 A2)
(valid_move C4 A3)
(valid_move C5 A4)
(valid_move C6 A5)
(valid_move C7 A6)
(valid_move C8 A7)
(valid_move D2 B1)
(valid_move D3 B2)
(valid_move D4 B3)
(valid_move D5 B4)
(valid_move D6 B5)
(valid_move D7 B6)
(valid_move D8 B7)
(valid_move E2 C1)
(valid_move E3 C2)
(valid_move E4 C3)
(valid_move E5 C4)
(valid_move E6 C5)
(valid_move E7 C6)
(valid_move E8 C7)
(valid_move F2 D1)
(valid_move F3 D2)
(valid_move F4 D3)
(valid_move F5 D4)
(valid_move F6 D5)
(valid_move F7 D6)
(valid_move F8 D7)
(valid_move G2 E1)
(valid_move G3 E2)
(valid_move G4 E3)
(valid_move G5 E4)
(valid_move G6 E5)
(valid_move G7 E6)
(valid_move G8 E7)
(valid_move H2 F1)
(valid_move H3 F2)
(valid_move H4 F3)
(valid_move H5 F4)
(valid_move H6 F5)
(valid_move H7 F6)
(valid_move H8 F7)
(valid_move C1 A2)
(valid_move C2 A3)
(valid_move C3 A4)
(valid_move C4 A5)
(valid_move C5 A6)
(valid_move C6 A7)
(valid_move C7 A8)
(valid_move D1 B2)
(valid_move D2 B3)
(valid_move D3 B4)
(valid_move D4 B5)
(valid_move D5 B6)
(valid_move D6 B7)
(valid_move D7 B8)
(valid_move E1 C2)
(valid_move E2 C3)
(valid_move E3 C4)
(valid_move E4 C5)
(valid_move E5 C6)
(valid_move E6 C7)
(valid_move E7 C8)
(valid_move F1 D2)
(valid_move F2 D3)
(valid_move F3 D4)
(valid_move F4 D5)
(valid_move F5 D6)
(valid_move F6 D7)
(valid_move F7 D8)
(valid_move G1 E2)
(valid_move G2 E3)
(valid_move G3 E4)
(valid_move G4 E5)
(valid_move G5 E6)
(valid_move G6 E7)
(valid_move G7 E8)
(valid_move H1 F2)
(valid_move H2 F3)
(valid_move H3 F4)
(valid_move H4 F5)
(valid_move H5 F6)
(valid_move H6 F7)
(valid_move H7 F8)
(valid_move B3 A1)
(valid_move B4 A2)
(valid_move B5 A3)
(valid_move B6 A4)
(valid_move B7 A5)
(valid_move B8 A6)
(valid_move C3 B1)
(valid_move C4 B2)
(valid_move C5 B3)
(valid_move C6 B4)
(valid_move C7 B5)
(valid_move C8 B6)
(valid_move D3 C1)
(valid_move D4 C2)
(valid_move D5 C3)
(valid_move D6 C4)
(valid_move D7 C5)
(valid_move D8 C6)
(valid_move E3 D1)
(valid_move E4 D2)
(valid_move E5 D3)
(valid_move E6 D4)
(valid_move E7 D5)
(valid_move E8 D6)
(valid_move F3 E1)
(valid_move F4 E2)
(valid_move F5 E3)
(valid_move F6 E4)
(valid_move F7 E5)
(valid_move F8 E6)
(valid_move G3 F1)
(valid_move G4 F2)
(valid_move G5 F3)
(valid_move G6 F4)
(valid_move G7 F5)
(valid_move G8 F6)
(valid_move H3 G1)
(valid_move H4 G2)
(valid_move H5 G3)
(valid_move H6 G4)
(valid_move H7 G5)
(valid_move H8 G6)
(valid_move B1 A3)
(valid_move B2 A4)
(valid_move B3 A5)
(valid_move B4 A6)
(valid_move B5 A7)
(valid_move B6 A8)
(valid_move C1 B3)
(valid_move C2 B4)
(valid_move C3 B5)
(valid_move C4 B6)
(valid_move C5 B7)
(valid_move C6 B8)
(valid_move D1 C3)
(valid_move D2 C4)
(valid_move D3 C5)
(valid_move D4 C6)
(valid_move D5 C7)
(valid_move D6 C8)
(valid_move E1 D3)
(valid_move E2 D4)
(valid_move E3 D5)
(valid_move E4 D6)
(valid_move E5 D7)
(valid_move E6 D8)
(valid_move F1 E3)
(valid_move F2 E4)
(valid_move F3 E5)
(valid_move F4 E6)
(valid_move F5 E7)
(valid_move F6 E8)
(valid_move G1 F3)
(valid_move G2 F4)
(valid_move G3 F5)
(valid_move G4 F6)
(valid_move G5 F7)
(valid_move G6 F8)
(valid_move H1 G3)
(valid_move H2 G4)
(valid_move H3 G5)
(valid_move H4 G6)
(valid_move H5 G7)
(valid_move H6 G8)
)
(:goal
(and
(visited A1)
(visited A2)
(visited A3)
(visited A4)
(visited A5)
(visited A6)
(visited A7)
(visited A8)
(visited B1)
(visited B2)
(visited B3)
(visited B4)
(visited B5)
(visited B6)
(visited B7)
(visited B8)
(visited C1)
(visited C2)
(visited C3)
(visited C4)
(visited C5)
(visited C6)
(visited C7)
(visited C8)
(visited D1)
(visited D2)
(visited D3)
(visited D4)
(visited D5)
(visited D6)
(visited D7)
(visited D8)
(visited E1)
(visited E2)
(visited E3)
(visited E4)
(visited E5)
(visited E6)
(visited E7)
(visited E8)
(visited F1)
(visited F2)
(visited F3)
(visited F4)
(visited F5)
(visited F6)
(visited F7)
(visited F8)
(visited G1)
(visited G2)
(visited G3)
(visited G4)
(visited G5)
(visited G6)
(visited G7)
(visited G8)
(visited H1)
(visited H2)
(visited H3)
(visited H4)
(visited H5)
(visited H6)
(visited H7)
(visited H8)
)
)
)
最后,我们来看下实现效果,这里我们依赖vscode中的PDDL插件:
Planning service: http://solver.planning.domains/solve
Domain: knights-tour, Problem: knights-tour-problem-8x8
--- OK.
Match tree built with 334 nodes.
PDDL problem description loaded:
Domain: KNIGHTS-TOUR
Problem: KNIGHTS-TOUR-PROBLEM-8X8
#Actions: 334
#Fluents: 190
Landmarks found: 63
Starting search with IW (time budget is 60 secs)...
rel_plan size: 63
#RP_fluents 126
Caption
{#goals, #UNnachieved, #Achieved} -> IW(max_w)
{63/63/0}:IW(1) -> [2]rel_plan size: 62
#RP_fluents 124
{63/62/1}:IW(1) -> [2]rel_plan size: 61
#RP_fluents 122
{63/61/2}:IW(1) -> [2]rel_plan size: 60
#RP_fluents 120
{63/60/3}:IW(1) -> [2]rel_plan size: 59
#RP_fluents 118
{63/59/4}:IW(1) -> [2]rel_plan size: 58
#RP_fluents 116
{63/58/5}:IW(1) -> [2]rel_plan size: 57
#RP_fluents 114
{63/57/6}:IW(1) -> [2]rel_plan size: 56
#RP_fluents 112
{63/56/7}:IW(1) -> [2]rel_plan size: 55
#RP_fluents 110
{63/55/8}:IW(1) -> [2]rel_plan size: 54
#RP_fluents 108
{63/54/9}:IW(1) -> [2]rel_plan size: 53
#RP_fluents 106
{63/53/10}:IW(1) -> [2]rel_plan size: 52
#RP_fluents 104
{63/52/11}:IW(1) -> [2]rel_plan size: 51
#RP_fluents 102
{63/51/12}:IW(1) -> [2]rel_plan size: 50
#RP_fluents 100
{63/50/13}:IW(1) -> [2]rel_plan size: 49
#RP_fluents 98
{63/49/14}:IW(1) -> [2]rel_plan size: 48
#RP_fluents 96
{63/48/15}:IW(1) -> [2]rel_plan size: 47
#RP_fluents 94
{63/47/16}:IW(1) -> [2]rel_plan size: 46
#RP_fluents 92
{63/46/17}:IW(1) -> [2]rel_plan size: 45
#RP_fluents 90
{63/45/18}:IW(1) -> [2]rel_plan size: 44
#RP_fluents 88
{63/44/19}:IW(1) -> [2]rel_plan size: 43
#RP_fluents 86
{63/43/20}:IW(1) -> [2]rel_plan size: 42
#RP_fluents 84
{63/42/21}:IW(1) -> [2][3][4][5][6][7][8][9][10][11][12][13][14][15][16][17][18][19][20][21][22][23][24][25][26];; NOT I-REACHABLE ;;
Total time: 0.104
Nodes generated during search: 383
Nodes expanded during search: 362
IW search completed
Starting search with BFS(novel,land,h_add)...
--[4294967295 / 220]--
--[42 / 220]--
--[42 / 175]--
--[42 / 149]--
--[42 / 143]--
--[42 / 136]--
--[42 / 133]--
--[42 / 127]--
--[41 / 127]--
--[40 / 127]--
--[39 / 127]--
--[38 / 127]--
--[37 / 127]--
--[36 / 127]--
--[35 / 127]--
--[35 / 123]--
--[34 / 123]--
--[34 / 117]--
--[33 / 117]--
--[32 / 117]--
--[31 / 117]--
--[30 / 117]--
--[29 / 117]--
--[28 / 117]--
--[28 / 109]--
--[28 / 108]--
--[28 / 102]--
--[27 / 102]--
--[26 / 102]--
--[26 / 101]--
--[25 / 101]--
--[25 / 97]--
--[25 / 96]--
--[25 / 95]--
--[24 / 95]--
--[23 / 95]--
--[22 / 95]--
--[21 / 95]--
--[21 / 92]--
--[20 / 92]--
--[20 / 72]--
--[19 / 72]--
--[19 / 70]--
--[19 / 59]--
--[18 / 59]--
--[18 / 53]--
--[17 / 53]--
--[16 / 53]--
--[15 / 53]--
--[14 / 53]--
--[14 / 45]--
--[14 / 43]--
--[13 / 43]--
--[13 / 30]--
--[12 / 30]--
--[12 / 26]--
--[11 / 26]--
--[11 / 21]--
--[10 / 21]--
--[9 / 21]--
--[9 / 20]--
--[8 / 20]--
--[8 / 14]--
--[7 / 14]--
--[6 / 14]--
--[6 / 11]--
--[5 / 11]--
--[5 / 9]--
--[4 / 9]--
--[4 / 6]--
--[3 / 6]--
--[3 / 3]--
--[2 / 3]--
--[2 / 1]--
--[1 / 1]--
--[1 / 0]--
--[0 / 0]--
Total time: 3.276
Nodes generated during search: 36860
Nodes expanded during search: 11061
Plan found with cost: 63
BFS search completed
0.00100: (move a8 b6)
0.00200: (move b6 d5)
0.00300: (move d5 f4)
0.00400: (move f4 d3)
0.00500: (move d3 e5)
0.00600: (move e5 f3)
0.00700: (move f3 e1)
0.00800: (move e1 g2)
0.00900: (move g2 h4)
0.01000: (move h4 g6)
0.01100: (move g6 h8)
0.01200: (move h8 f7)
0.01300: (move f7 g5)
0.01400: (move g5 h3)
0.01500: (move h3 g1)
0.01600: (move g1 e2)
0.01700: (move e2 c1)
0.01800: (move c1 a2)
0.01900: (move a2 b4)
0.02000: (move b4 a6)
0.02100: (move a6 c7)
0.02200: (move c7 e8)
0.02300: (move e8 g7)
0.02400: (move g7 h5)
0.02500: (move h5 g3)
0.02600: (move g3 h1)
0.02700: (move h1 f2)
0.02800: (move f2 e4)
0.02900: (move e4 d2)
0.03000: (move d2 b1)
0.03100: (move b1 a3)
0.03200: (move a3 c4)
0.03300: (move c4 a5)
0.03400: (move a5 b3)
0.03500: (move b3 a1)
0.03600: (move a1 c2)
0.03700: (move c2 d4)
0.03800: (move d4 e6)
0.03900: (move e6 c5)
0.04000: (move c5 b7)
0.04100: (move b7 d6)
0.04200: (move d6 f5)
0.04300: (move f5 h6)
0.04400: (move h6 g8)
0.04500: (move g8 e7)
0.04600: (move e7 c8)
0.04700: (move c8 a7)
0.04800: (move a7 b5)
0.04900: (move b5 c3)
0.05000: (move c3 a4)
0.05100: (move a4 b2)
0.05200: (move b2 d1)
0.05300: (move d1 e3)
0.05400: (move e3 f1)
0.05500: (move f1 h2)
0.05600: (move h2 g4)
0.05700: (move g4 f6)
0.05800: (move f6 h7)
0.05900: (move h7 f8)
0.06000: (move f8 d7)
0.06100: (move d7 b8)
0.06200: (move b8 c6)
0.06300: (move c6 d8)
Planner found 1 plan(s) in 4.882secs.
附带vscode中生成的效果图: