調査して解ったこと
・最後のN手は決まっている。
・最少手数M(解ったとして)に対して、各数字の移動回数が決まる。
j回とする。j回で後半分の数字(N=5なら、4,5)を揃える。
続いて、前半分の数字(N=5なら、1,2,3)を揃える。
例 N=5の場合
0: 0012345
↓j*N 回 最後N手は決まる j*N-(M-INT((N+1)/2))手から
j*N: xx54xxx ↑
↓INT((N+1)/2) 回 │
M: 0054321 ───────┘
予想式 M=j*N + INT((N+1)/2) !?
N M j INT((N+1)/2)
2 3 1 1
3 5 1 2
4 6 1 2
5 13 2 3
6 21 3 3
7 25 3 4
8 28 3 4
9 41 4 5
10 55 5 5
11 61 5 6
12 78 6 6 !?
・最初のN手をきれいな形で固定できる!?
最初のN手を固定して、必勝パターンがあるかないか?
LET t0=TIME
PUBLIC NUMERIC N !数字1~N
PUBLIC NUMERIC cMAX !見つかった最少手数
PUBLIC NUMERIC B(100) !最初のN手、最後のN手
!LET N=2
!LET cMAX=3
!DATA 2,3 !最初の2手 ※数字を移動させる空白位置。1を2、2を3を意味する。
!DATA 3,4 !最後の2手 ※数字を移動させる空白位置。2を3、1を4を意味する。
!LET N=3
!LET cMAX=5
!DATA 1,2, 3 !最初の3手
!DATA 3, 5,4 !最後の3手
!LET N=4
!LET cMAX=6
!DATA 1,2, 4,3 !最初の4手
!DATA 4,3, 6,5 !最後の4手
!LET N=5
!LET cMAX=13
!DATA 1,2, 4,3, 6 !最初の5手 ※数字を移動させる空白位置。1を2、2を1、3を4、4を3、5を6を意味する。
!DATA 4,3, 7,6,5 !最後の5手 ※数字を移動させる空白位置。4を4、5を3、1を7、2を6、3を5を意味する。
!LET N=6
!LET cMAX=21
!DATA 1,2, 4,3, 6,7 !最初の6手
!DATA 5,4,3, 8,7,6 !最後の6手
!LET N=7
!LET cMAX=25
!DATA 1,2, 4,5,3, 7,8 !最初の7手
!DATA 5,4,3, 9,8,7,6 !最後の7手
!LET N=8
!LET cMAX=28
!DATA 1,2, 4,5,3, 7,8,9 !最初の8手
!DATA 6,5,4,3, 10,9,8,7 !最後の8手
!LET N=9
!LET cMAX=41
!DATA 1,2, 4,5,6,3, 8,9,10 !最初の9手
!DATA 6,5,4,3, 11,10,9,8,7 !最後の9手
!LET N=10
!LET cMAX=55
!DATA 1,2, 4,5,6,3, 8,9,10,11 !最初の10手
!DATA 7,6,5,4,3, 12,11,10,9,8 !最後の10手
LET N=11
LET cMAX=61
DATA 1,2, 4,5,6,7,3, 9,10,11,12 !最初の11手
DATA 7,6,5,4,3, 13,12,11,10,9,8 !最後の11手
!LET N=12
!LET cMAX=78
!DATA 1,2, 4,5,6,7,3, 9,10,11,12,13 !最初の12手
!DATA 8,7,6,5,4,3, 14,13,12,11,10,9 !最後の12手
PRINT "N=";N; "cMAX=";cMAX !debug
MAT B=ZER
FOR i=1 TO N
READ B(i)
NEXT i
FOR i=cMax-N+1 TO cMax
READ B(i)
NEXT i
MAT PRINT B; !debug
PUBLIC NUMERIC SPC !空きの数
LET SPC=2
PUBLIC STRING S$ !開始パターン
LET S$=REPEAT$("0",SPC)
FOR i=1 TO N
LET S$=S$&fnSTR1$(i)
NEXT i
!!!PRINT S$ !debug
PUBLIC STRING G$ !終了パターン
LET G$=REPEAT$("0",SPC)
FOR i=N TO 1 STEP -1
LET G$=G$&fnSTR1$(i)
NEXT i
!!!PRINT G$ !debug
PUBLIC NUMERIC C !解答数
LET C=0
DIM A(cMAX) !手数
CALL try(0,S$,A)
IF C=0 THEN PRINT "解なし"
PRINT "計算時間=";TIME-t0
END
EXTERNAL SUB try(p,M$,A()) !深さ優先探索
IF M$=G$ THEN !完成なら
LET C=C+1
PRINT "No.";C
MAT PRINT A; !debug
LET T$=S$ !盤面を表示する
FOR i=0 TO p-1 !手を再現する
LET w$=fnSTR1$(MOD(i,N)+1) !移動させる数字
PRINT USING "## ": i; !盤面
PRINT T$; " ";w$
LET x=POS(T$,w$) !移動元
LET y=A(i+1) !移動先
LET T$(x:x)="0" !move it
LET T$(y:y)=w$
NEXT i
PRINT USING "## ": p; !盤面
PRINT T$
PRINT
LET cMAX=p !最少手数を更新する
ELSE
IF p+1>cMAX THEN EXIT SUB !高々
LET w$=fnSTR1$(MOD(p,N)+1) !移動させる数字
LET y=0
FOR z=1 TO SPC !2つの空きへ
LET y=POS(M$,"0",y+1) !移動先
IF B(p+1)=0 OR y=B(p+1) THEN
LET x=POS(M$,w$) !移動元
LET T$=M$ !move it
LET T$(x:x)="0"
LET T$(y:y)=w$
!PRINT p;T$ !debug
IF N>8 AND p+1=INT((cMAX-2*N)/N)*N THEN !チェックポイント! ※N=9,10,11
LET v=N-INT((N+1)/2)-2
IF T$(3:3+v)=G$(5:5+v) THEN
LET A(p+1)=y !手を記録する
CALL try(p+1,T$,A) !次へ
END IF
ELSEIF N>8 AND p+1=INT((cMAX-N)/N)*N THEN !チェックポイント! ※N=7はNG
LET v=N-INT((N+1)/2)-1
IF T$(3:3+v)=G$(4:4+v) THEN
LET A(p+1)=y !手を記録する
CALL try(p+1,T$,A) !次へ
END IF
ELSE
LET A(p+1)=y !手を記録する
CALL try(p+1,T$,A) !次へ
END IF
END IF
NEXT z
END IF
END SUB
!N進法表記
EXTERNAL FUNCTION fnVAL1(x$) !1文字の数字を数値に変換する
LET fnVAL1=POS("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ",x$)-1
END FUNCTION
EXTERNAL FUNCTION fnSTR1$(x) !1桁の数値を数字に変換する
LET fnSTR1$=MID$("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ",x+1,1)
END FUNCTION