簡単なGUIのパズルゲームプログラミングです。
プログラムの中断は、「中断」ボタン(メニュー)で行います。
!●問題
!8個のさいころが、3×3の盤に1の目を上にして他の目も同じ向きで配置されています。
!空いているマスに転がして、すべての目が6になるようにしてください。
!置換(Permutation)の計算
SUB PermPrintOut(A()) !表示する
MAT PRINT USING(REPEAT$(" ##",UBOUND(A))): A;
PRINT
END SUB
SUB PermIdentity(A()) !恒等置換
FOR i=1 TO UBOUND(A)
LET A(i)=i
NEXT i
END SUB
SUB PermInverse(A(), iA()) !逆置換 ※iAはA以外の配列を指定すること
FOR i=1 TO UBOUND(A)
LET iA(A(i))=i
NEXT i
END SUB
SUB PermMultiply(A(),B(), AB()) !積AB ※ABはAかつB以外の配列を指定すること
FOR i=1 TO UBOUND(A)
LET AB(i)=A(B(i)) !※合成写像(AB)(i)=A(B(i))
NEXT i
END SUB
!-------------------- ここまでがサブルーチン
DIM U(6),D(6),L(6),R(6) !置換
! 1,2,3,4,5,6
DATA 3,2,6,4,1,5 !上 ※正面を上面にするの(図での水平軸)回転
!!!DATA 5,2,1,4,6,3 !下
DATA 1,3,4,5,2,6 !左
!!!DATA 1,5,2,3,4,6 !右
MAT READ U
CALL PermInverse(U,D)
!!!MAT READ D
MAT READ L
CALL PermInverse(L,R)
!!!MAT READ R
!---------- ↑↑↑↑↑ ----------
!展開図の配置と面番号(配列の添え字)との関係
! □ 後 1
!□□□□ 左上右下 2345
! □ 正 6
DIM T1(6),T2(6),T3(6),T4(6),T5(6),T6(6),T7(6),T8(6) !8個のさいころ
DATA 5,4,1,3,6,2 !目の配置 ※展開図参照
MAT READ T1
MAT T2=T1 !同じ向き
MAT T3=T1
MAT T4=T1
MAT T5=T1
MAT T6=T1
MAT T7=T1
MAT T8=T1
PICTURE dice(T()) !さいころを表示する ※原点基準
SET TEXT JUSTIFY "CENTER","HALF"
PLOT TEXT ,AT 0,-0.4: STR$(T(1)) !側面の目の数
PLOT TEXT ,AT -0.4,0: STR$(T(2))
PLOT TEXT ,AT 0.4,0: STR$(T(4))
PLOT TEXT ,AT 0,0.4: STR$(T(6))
LET nm=T(3) !上面の目の数
IF nm=1 THEN DRAW eye(4) !中央
IF nm=3 OR nm=5 THEN DRAW eye(1)
IF nm=2 OR nm=4 OR nm=5 OR nm=6 THEN !左斜め
DRAW eye(1) WITH SHIFT(0.25,0.25)
DRAW eye(1) WITH SHIFT(-0.25,-0.25)
END IF
IF nm=3 OR nm=4 OR nm=5 OR nm=6 THEN !右斜め
DRAW eye(1) WITH SHIFT(0.25,-0.25)
DRAW eye(1) WITH SHIFT(-0.25,0.25)
END IF
IF nm=6 THEN !中段
DRAW eye(1) WITH SHIFT(0.25,0)
DRAW eye(1) WITH SHIFT(-0.25,0)
END IF
END PICTURE
PICTURE eye(c) !1つの目を表示する
SET AREA COLOR c
DRAW disk WITH SCALE(0.1) !※要調整
END PICTURE
!---------- ↑↑↑↑↑ ----------
LET MY=3 !マップの大きさ
LET MX=3
DIM M(MY,MX) !さいころの配置 ※数字は番号、0は空き
DATA 1,2,3
DATA 4,0,5
DATA 6,7,8
MAT READ M
SUB dispMap !マップ上のさいころを表示する
FOR y=1 TO 3 !左上から順に
LET yy=y-0.5 !位置を算出する
FOR x=1 TO 3
LET xx=x-0.5
SELECT CASE M(y,x) !配置されたさいころに応じて
CASE 1
DRAW dice(T1) WITH SHIFT(xx,yy) !上面
CASE 2
DRAW dice(T2) WITH SHIFT(xx,yy)
CASE 3
DRAW dice(T3) WITH SHIFT(xx,yy)
CASE 4
DRAW dice(T4) WITH SHIFT(xx,yy)
CASE 5
DRAW dice(T5) WITH SHIFT(xx,yy)
CASE 6
DRAW dice(T6) WITH SHIFT(xx,yy)
CASE 7
DRAW dice(T7) WITH SHIFT(xx,yy)
CASE 8
DRAW dice(T8) WITH SHIFT(xx,yy)
CASE ELSE
END SELECT
NEXT x
NEXT y
END SUB
!---------- ↑↑↑↑↑ ----------
SUB move(T(),OP(),x,y,dx,dy) !さいころを回転移動させる
LET ANSWER_COUNT=ANSWER_COUNT+1
PRINT ANSWER_COUNT;"手"
DIM TT(6) !作業配列
CALL PermMultiply(T,OP,TT) !回転
MAT T=TT
LET w=M(y,x) !移動
LET M(y,x)=M(y+dy,x+dx)
LET M(y+dy,x+dx)=w
END SUB
SUB CalcDirection(x,y, T()) !移動可能な方向へ回転移動させる
IF y>=2 THEN !上に移動可能で
IF M(y-1,x)=0 THEN !空きマスなら
CALL move(T,U,x,y,0,-1) !回転移動させる
PRINT "UP";y;x
END IF
END IF
IF y<=2 THEN !下
IF M(y+1,x)=0 THEN
CALL move(T,D,x,y,0,1)
PRINT "DOWN";y;x
END IF
END IF
IF x>=2 THEN !左
IF M(y,x-1)=0 THEN
CALL move(T,L,x,y,-1,0)
PRINT "LEFT";y;x
END IF
END IF
IF x<=2 THEN !右
IF M(y,x+1)=0 THEN
CALL move(T,R,x,y,1,0)
PRINT "RIGHT";y;x
END IF
END IF
MAT PRINT M; !debug
END SUB
LET ANSWER_COUNT=0 !手数
SET WINDOW -1,MX+1,MY+1,-1 !表示領域
LET cx=1 !ポインタを左上に位置付ける
LET cy=1
DO
mouse poll x,y,left,right !マウスの情報を得る
LET xx=INT(x) !位置
LET yy=INT(y)
IF xx>=0 AND xx<MX AND yy>=0 AND yy<MY THEN !マップ内なら
LET cx=xx+1 ![1,MX]
LET cy=yy+1 ![1,MY]
END IF
IF left=1 THEN !左ボタンが押されたら
SELECT CASE M(cy,cx) !さいころの番号を得る
CASE 1
CALL CalcDirection(cx,cy, T1) !回転移動させる
CASE 2
CALL CalcDirection(cx,cy, T2)
CASE 3
CALL CalcDirection(cx,cy, T3)
CASE 4
CALL CalcDirection(cx,cy, T4)
CASE 5
CALL CalcDirection(cx,cy, T5)
CASE 6
CALL CalcDirection(cx,cy, T6)
CASE 7
CALL CalcDirection(cx,cy, T7)
CASE 8
CALL CalcDirection(cx,cy, T8)
CASE ELSE
END SELECT
WAIT DELAY 0.2 !※要調整
END IF
SET DRAW mode hidden !ちらつき防止開始
CLEAR
DRAW grid !目盛り
SET LINE width 2 !ポインタを表示する
PLOT LINES: cx-1,cy-1; cx,cy-1; cx,cy; cx-1,cy; cx-1,cy-1
SET LINE width 1
CALL dispMap !さいころを表示する
SET TEXT JUSTIFY "LEFT","BOTTOM" !文字位置の調整
PLOT TEXT ,AT -0.5,-0.5: "移動するさいころを左クリックしてください。"
SET DRAW mode explicit !ちらつき防止終了
LOOP
END
!答え 38手
! URDL,DRUL,LDRR,UULD,RUL;LDR,ULDD,RRUL,LDRU,LURD