谜题在使用曼哈顿距离的序言中有一个解决方案

8个难题将由一个3x3列表位置表示,其中空框将由值9表示,如下所示:[[9,1,3],[5,2,6],[4, 7,8]

可能性解决方案:8拼图的初始位置只有一半是可解的。 有一个公式可以从一开始就知道你是否可以解决这个难题。为了确定一个8难题是否可以解决,对于每个包含一个值的正方形,计算当前单元格之后有多少个小于N的数字。 例如,到初始状态:

  • 1没有数字小于= 0
  • 空(9) - 必须随后3,5,2,6,4,7,8 = 7
  • 3有= 1到2
  • 5随后达到2,4 = 2
  • 2下面没有数字= 0
  • 6随后是4 = 1
  • 4没有数字小于= 0
  • 7 = 0后没有次要数字
  • 8没有数字小于= 0
  • 之后,我们计算空位和位置之间的曼哈顿距离(3.3)。 对于上面的例子,空框位于(1.2)的位置,所以曼哈顿距离为:d = abs(3-1)+ abs(3-2)= 3最后,将所有计算值相加。 如果结果是偶数,则意味着这个难题是可以解决的,但这很奇怪,没有解决。 0 +7 +1 +2 +0 +1 +0 +0 +0 +3 = 14

    该解决方案旨在创建知识库,并在板上创建一个数字的所有可能状态,我们将在当前位置之后看到多少个小于N的数字。

    这是我的代码:

    %***********************Have Solution*********************************
    
    posA(9,8). posA(8,7). posA(7,6). posA(6,5). posA(5,4). posA(4,3). posA(3,2). posA(2,1). posA(1,0).
    
    posB(9,7). posB(8,7). posB(8,6). posB(7,6). posB(7,5). posB(7,4). 
    posB(6,5). posB(6,4). posB(6,3). posB(6,2). posB(5,4). posB(5,3). posB(5,2). posB(5,1).  posB(5,0). 
    posB(4,3). posB(4,2). posB(3,2). posB(3,1).  posB(2,1). posB(2,0). posB(1,0).
    
    posC(9,6). posC(8,6). posC(8,5). posC(7,6). posC(7,5). posC(7,4). posC(6,5). posC(6,4). posC(6,3).
    posC(5,4). posC(5,3). posC(5,2). posC(4,3). posC(4,2). posC(4,1). posC(4,0).
    posC(3,2). posC(3,1). posC(3,0). posC(2,1). posC(1,0).
    
    posD(9,5). posD(8,5). posD(8,4). posD(7,5). posD(7,4). posD(7,3). posD(6,5). posD(6,4). posD(6,3).
    posD(6,2). posD(5,4). posD(5,3). posD(5,2). posD(5,1). posD(4,3). posD(4,2). posD(4,1). posD(5,0).
    posD(3,2). posD(3,1). posD(3,0). posD(2,1). posD(1,0).
    
    posE(9,4). posE(8,4). posE(8,3). posE(7,4). posE(7,3). posE(7,2). posE(6,4). posE(6,3). posE(6,2). posE(6,1).
    posE(5,4). posE(5,3). posE(5,2). posE(5,1). posE(5,0). posE(4,3). posE(4,2). posE(4,1). posE(4,0).
    posE(3,2). posE(3,1). posE(3,0). posE(2,1). posE(2,0). posE(1,0).
    
    posF(9,3). posF(8,3). posF(8,2). posF(7,1). posF(7,2). posF(7,3). posF(6,0). posF(6,1). posF(6,2). 
    posF(6,3). posF(5,0). posF(5,1). posF(5,2). posF(5,3). posF(4,0). posF(4,1). posF(4,2). posF(4,3).
    posF(2,0). posF(2,1). posF(3,0). posF(3,1). posF(3,2). posF(1,0).
    
    posG(9,2). posG(8,0). posG(8,1). posG(8,2).  posG(7,0). posG(7,1). posG(7,2).
    posG(6,0). posG(6,1). posG(6,2). posG(5,0).  posG(5,1). posG(5,2). posG(4,0). posG(4,1). posG(4,2).
    posG(3,0). posG(3,1). posG(3,2). posG(2,0).  posG(2,1). posG(1,0).
    
    posH(9,1). posH(8,0). posH(8,1). posH(7,0). posH(7,1). posH(6,0). posH(6,1). posH(5,0). posH(5,1). 
    posH(4,0). posH(4,1). posH(3,0). posH(3,1). posH(2,0). posH(1,1). posH(1,0).
    
    posI(9,0). posI(8,0). posI(7,0). posI(6,0). posI(5,0). posI(4,0). posI(3,0). posI(2,0). posI(1,0).  
    
    haveSolution([[A,B,C],[D,E,F],[G,H,I]]):- distManhattan([A,B,C,D,E,F,G,H,I], Z),
                                             posA(A,Pa), posB(B,Pb), posC(C,Pc),
                                             posD(D,Pd), posE(E,Pe), posF(F,Pf),
                                             posG(G,Pg), posH(H,Ph), posI(I,Pi),
                                             P is Pa+Pb+Pc+Pd+Pe+Pf+Pg+Ph+Pg+Pi+Z, 0 is P mod 2,
                                             write('The 8-puzzle have solution').
    
    %%*************************Manhattan distance***********************
    distManhattan([A,B,C,D,E,F,G,H,I], Dist):-  A=9, Dist is abs(3-1)+abs(3-1), !;
                                                B=9, Dist is abs(3-1)+abs(3-2), !;
                                                C=9, Dist is abs(3-1)+abs(3-3), !;
                                                D=9, Dist is abs(3-2)+abs(3-1), !;
                                                E=9, Dist is abs(3-2)+abs(3-2), !;
                                                F=9, Dist is abs(3-2)+abs(3-3), !;
                                                G=9, Dist is abs(3-3)+abs(3-1), !;
                                                H=9, Dist is abs(3-3)+abs(3-2), !;
                                                I=9, Dist is abs(3-3)+abs(3-3).
    

    问题是我犯了一个错误,因为有些情况下我可以有多个选择,例如>:

    |  1 |  9 | 3  |
    |  5 |  2 | 6  |
    |  4 |  7 | 8  |    
    
    
    posA(1,0)+posB(9,7)+posC(3,1)+posD(5,2)+posE(2,0)+posF(6,1)+posG(4,0)+posH(7,0)+posI(8,0).
    

    posC(C,Pc)的正确解是posC(3,1),即1; 但还有其他一些后果,有时会导致错误的输出......我在代码中做错了什么,以及我如何改变它?


    这个答案试图从另一个角度来看待手头的问题:

  • 单板配置使用复合结构board/9
  • 等于滑动单件的配置通过关系m/2连接。
  • 我们开始吧,定义m/2

    m(board(' ',B,C,D,E,F,G,H,I), board(D, B ,C,' ',E,F,G,H,I)).
    m(board(' ',B,C,D,E,F,G,H,I), board(B,' ',C, D ,E,F,G,H,I)).
    



    m(board(A,' ',C,D,E,F,G,H,I), board(' ',A, C , D, E ,F,G,H,I)).
    m(board(A,' ',C,D,E,F,G,H,I), board( A ,C,' ', D, E ,F,G,H,I)).
    m(board(A,' ',C,D,E,F,G,H,I), board( A ,E, C , D,' ',F,G,H,I)).
    



    m(board(A,B,' ',D,E,F,G,H,I), board(A,' ',B,D,E, F ,G,H,I)).
    m(board(A,B,' ',D,E,F,G,H,I), board(A, B ,F,D,E,' ',G,H,I)).
    



    m(board(A,B,C,' ',E,F,G,H,I), board(' ',B,C,A, E ,F, G ,H,I)).
    m(board(A,B,C,' ',E,F,G,H,I), board( A ,B,C,E,' ',F, G ,H,I)).
    m(board(A,B,C,' ',E,F,G,H,I), board( A ,B,C,G, E ,F,' ',H,I)).
    



    m(board(A,B,C,D,' ',F,G,H,I), board(A, B ,C,' ',D, F ,G, H ,I)).
    m(board(A,B,C,D,' ',F,G,H,I), board(A,' ',C, D ,B, F ,G, H ,I)).
    m(board(A,B,C,D,' ',F,G,H,I), board(A, B ,C, D ,F,' ',G, H ,I)).
    m(board(A,B,C,D,' ',F,G,H,I), board(A, B ,C, D ,H, F ,G,' ',I)).
    



    m(board(A,B,C,D,E,' ',G,H,I), board(A,B,' ',D, E ,C,G,H, I )).
    m(board(A,B,C,D,E,' ',G,H,I), board(A,B, C ,D,' ',E,G,H, I )).
    m(board(A,B,C,D,E,' ',G,H,I), board(A,B, C ,D, E ,I,G,H,' ')).
    



    m(board(A,B,C,D,E,F,' ',H,I), board(A,B,C,' ',E,F,D, H ,I)).
    m(board(A,B,C,D,E,F,' ',H,I), board(A,B,C, D ,E,F,H,' ',I)).
    



    m(board(A,B,C,D,E,F,G,' ',I), board(A,B,C,D,' ',F, G ,E, I )).
    m(board(A,B,C,D,E,F,G,' ',I), board(A,B,C,D, E ,F,' ',G, I )).
    m(board(A,B,C,D,E,F,G,' ',I), board(A,B,C,D, E ,F,  G,I,' ')).
    



    m(board(A,B,C,D,E,F,G,H,' '), board(A,B,C,D,E,' ',G, H ,F)).
    m(board(A,B,C,D,E,F,G,H,' '), board(A,B,C,D,E, F ,G,' ',H)).
    



    几乎完成! 为了连接这些步骤,我们使用元谓词路径/ 4和length/2来执行迭代加深。

    以下两个问题实例来自@CapelliC的答案:

    ?- length(Path,N), path(m,Path,/* from */ board(1,' ',3,5,2,6,4,7, 8 ),
                                   /*  to  */ board(1, 2 ,3,4,5,6,7,8,' ')).
    N =  6, Path = [board(1,' ',3,5,2,6,4,7,8), board(1,2,3,5,' ',6,4,7,8),
                    board(1,2,3,' ',5,6,4,7,8), board(1,2,3,4,5,6,' ',7,8),
                    board(1,2,3,4,5,6,7,' ',8), board(1,2,3,4,5,6,7,8,' ')] ? ;
    N = 12, Path = [board(1,' ',3,5,2,6,4,7,8), board(1,2,3,5,' ',6,4,7,8),
                    board(1,2,3,5,7,6,4,' ',8), board(1,2,3,5,7,6,' ',4,8),
                    board(1,2,3,' ',7,6,5,4,8), board(1,2,3,7,' ',6,5,4,8),
                    board(1,2,3,7,4,6,5,' ',8), board(1,2,3,7,4,6,' ',5,8),
                    board(1,2,3,' ',4,6,7,5,8), board(1,2,3,4,' ',6,7,5,8),
                    board(1,2,3,4,5,6,7,' ',8), board(1,2,3,4,5,6,7,8,' ')] ? ;
    ...
    
    ?- length(Path,N), path(m,Path,/* from */ board(8,7,4,6,' ',5,3,2, 1 ),
                                   /*  to  */ board(1,2,3,4, 5 ,6,7,8,' ')).
    N = 27, Path = [board(8,7,4,6,' ',5,3,2,1), board(8,7,4,6,5,' ',3,2,1),
                    board(8,7,4,6,5,1,3,2,' '), board(8,7,4,6,5,1,3,' ',2),
                    board(8,7,4,6,5,1,' ',3,2), board(8,7,4,' ',5,1,6,3,2),
                    board(' ',7,4,8,5,1,6,3,2), board(7,' ',4,8,5,1,6,3,2),
                    board(7,4,' ',8,5,1,6,3,2), board(7,4,1,8,5,' ',6,3,2),
                    board(7,4,1,8,5,2,6,3,' '), board(7,4,1,8,5,2,6,' ',3),
                    board(7,4,1,8,5,2,' ',6,3), board(7,4,1,' ',5,2,8,6,3),
                    board(' ',4,1,7,5,2,8,6,3), board(4,' ',1,7,5,2,8,6,3),
                    board(4,1,' ',7,5,2,8,6,3), board(4,1,2,7,5,' ',8,6,3),
                    board(4,1,2,7,5,3,8,6,' '), board(4,1,2,7,5,3,8,' ',6),
                    board(4,1,2,7,5,3,' ',8,6), board(4,1,2,' ',5,3,7,8,6),
                    board(' ',1,2,4,5,3,7,8,6), board(1,' ',2,4,5,3,7,8,6),
                    board(1,2,' ',4,5,3,7,8,6), board(1,2,3,4,5,' ',7,8,6),
                    board(1,2,3,4,5,6,7,8,' ')] ? ;
    N = 29, Path = [...] ? ;
    ...
    

    我想在接下来的几天内扩大这个答案......接下来是什么?

  • 更多可视化(S)。
  • 可视化代码。
  • 不同的启发式。
  • 利用可接受启发式的path/4推广。
  • 经验运行时测量。
  • 考虑各种可能的时间/空间折衷。

  • 这是一个求解器,而不是对原始问题的回答。 Joel76已经在评论中解决了这个问题,因此当他回答时他将获得应有的声望。

    但是8-puzzle解决起来很有趣,并且造成了一些效率问题。 这是我尽最大的努力,我使用库(nb_set)试图在完整的解决方案枚举中实现合理的效率。

    注意:需要nb_set才能跟踪失败路径上的访问。 另一种方法是:- dynamic visited/1. 但结果太慢了。

    /*  File:    8-puzzle.pl
        Author:  Carlo,,,
        Created: Feb  4 2013
        Purpose: solve 8-puzzle
    */
    
    :- module(eight_puzzle,
          [eight_puzzle/3
          ]).
    
    :- use_module(library(nb_set)).
    
    % test cases from Stack Overflow thread with Joel76
    test0(R) :- eight_puzzle([1,2,3,4,5,6,7,8,0], [1,0,3, 5,2,6, 4,7,8], R).
    test1(R) :- eight_puzzle([1,2,3,4,5,6,7,8,0], [8,7,4, 6,0,5, 3,2,1], R).
    
    %%  eight_puzzle(+Target, +Start, -Moves) is ndet
    %
    %   public interface to solver
    %
    eight_puzzle(Target, Start, Moves) :-
        empty_nb_set(E),
        eight_p(E, Target, Start, Moves).
    
    %%  -- private here --
    
    eight_p(_, Target, Target, []) :-
        !.
    eight_p(S, Target, Current, [Move|Ms]) :-
        add_to_seen(S, Current),
        setof(Dist-M-Update,
              (  get_move(Current, P, M),
             apply_move(Current, P, M, Update),
             distance(Target, Update, Dist)
              ), Moves),
        member(_-Move-U, Moves),
        eight_p(S, Target, U, Ms).
    
    %%  get_move(+Board, +P, -Q) is semidet
    %
    %   based only on coords, get next empty cell
    %
    get_move(Board, P, Q) :-
        nth0(P, Board, 0),
        coord(P, R, C),
        (   R < 2, Q is P + 3
        ;   R > 0, Q is P - 3
        ;   C < 2, Q is P + 1
        ;   C > 0, Q is P - 1
        ).
    
    %%  apply_move(+Current, +P, +M, -Update)
    %
    %   swap elements at position P and M
    %
    apply_move(Current, P, M, Update) :-
        assertion(nth0(P, Current, 0)), % constrain to this application usage
        ( P > M -> (F,S) = (M,P) ; (F,S) = (P,M) ),
        nth0(S, Current, Sv, A),
        nth0(F, A, Fv, B),
        nth0(F, C, Sv, B),
        nth0(S, Update, Fv, C).
    
    %%  coord(+P, -R, -C)
    %
    %   from linear index to row, col
    %   size fixed to 3*3
    %
    coord(P, R, C) :-
        R is P // 3,
        C is P mod 3.
    
    %%  distance(+Current, +Target, -Dist)
    %
    %   compute Manatthan distance between equals values
    %
    distance(Current, Target, Dist) :-
        aggregate_all(sum(D),
                  (   nth0(P, Current, N), coord(P, Rp, Cp),
                  nth0(Q, Target, N), coord(Q, Rq, Cq),
                  D is abs(Rp - Rq) + abs(Cp - Cq)
                  ), Dist).
    
    %%  add_to_seen(+S, +Current)
    %
    %   fail if already in, else store
    %
    add_to_seen(S, [A,B,C,D,E,F,G,H,I]) :-
        Sig is
        A*100000000+
        B*10000000+
        C*1000000+
        D*100000+
        E*10000+
        F*1000+
        G*100+
        H*10+
        I,
        add_nb_set(Sig, S, true)
    

    Joel76在第一次尝试中展示了这个错误的测试用例:

    ?- time(eight_puzzle:test1(R)).
    % 25,791 inferences, 0,012 CPU in 0,012 seconds (100% CPU, 2137659 Lips)
    R = [5, 8, 7, 6, 3, 0, 1, 2, 5|...] ;
    % 108,017 inferences, 0,055 CPU in 0,055 seconds (100% CPU, 1967037 Lips)
    R = [5, 8, 7, 6, 3, 0, 1, 2, 5|...] ;
    % 187,817,057 inferences, 93,761 CPU in 93,867 seconds (100% CPU, 2003139 Lips)
    false.
    
    链接地址: http://www.djcxy.com/p/65561.html

    上一篇: puzzle has a solution in prolog using manhattan distance

    下一篇: Heuristic A* algorithm for N