SUB dec(C(),p, w) !パケット内上からp位置のカードを削除する
LET w=C(p)
FOR i=p TO C(0)-1 !前に詰める
LET C(i)=C(i+1)
NEXT i
LET C(0)=C(0)-1
END SUB
SUB inc(C(),p,w) !パケット内上からp位置にカードを追加する
IF p<=C(0) THEN
FOR i=C(0) TO p STEP -1 !後ろにずらす
LET C(i+1)=C(i)
NEXT i
ELSE
LET p=C(0)+1 !最後
END IF
LET C(p)=w
LET C(0)=C(0)+1
END SUB
DIM TT(0 TO 13*4+1)
SUB add(C1(),C2(), C()) !C1を上、C2を下にパケットを重ねる
FOR i=1 TO C1(0)
LET TT(i)=C1(i)
NEXT i
FOR i=1 TO C2(0) !続けて
LET TT(C1(0)+i)=C2(i)
NEXT i
LET C(0)=C1(0)+C2(0)
FOR i=1 TO C(0)
LET C(i)=TT(i)
NEXT i
END SUB
SUB clr(C()) !パケットをクリアする
LET C(0)=0
END SUB
SUB rev(C()) !パケットを裏返す
FOR i=1 TO INT(C(0)/2)
swap C(i),C(C(0)-i+1)
NEXT i
END SUB
SUB disp(C(),m$) !パケットを上から順に表示する
PRINT m$;"(";C(0);"枚)";
FOR i=1 TO C(0)
PRINT C(i);
NEXT i
PRINT
END SUB
!-------------------- ここまでがサブルーチン
LET N=12 !枚数
DIM S(0 TO N),H(0 TO N) !スペード、ハートパケットの初期化
FOR i=1 TO N !整列
LET S(i)=i !スペード 1~13
LET H(i)=i+13*2 !ハート 27~39
NEXT i
LET H(0)=N !枚数
LET S(0)=N
!テーブルの初期化
DIM Y1(0 TO N),Y2(0 TO N),Y3(0 TO N) !山1、山2、捨て場
CALL clr(Y1) !山のクリア
CALL clr(Y2)
CALL clr(Y3)
CALL dump !内容を確認する
SUB dump
CALL disp(S,"スペード") !トレース
CALL disp(H,"ハート")
CALL disp(Y1,"山1")
CALL disp(Y2,"山2")
CALL disp(Y3,"捨て場")
PRINT
END SUB
!1回目
INPUT PROMPT "好きな数字(2~N)?": K !好きな数字 1~N
CALL routine
SUB routine !作業の定義
FOR x=1 TO N !手持ちのカードがなくなるまで
PRINT x;"枚目をテーブルへ"
CALL dec(S,1,w) !削除する
IF x=K THEN !一致する枚数目なら捨て場へ
!IF MOD(x,K)=0 THEN !一致する枚数目なら捨て場へ
CALL inc(Y3,1,w)
CALL dec(H,1,w) !代替として場から
END IF
IF MOD(x,2)=0 THEN !左右交互で山に置く
CALL inc(Y2,1,w)
ELSE
CALL inc(Y1,1,w)
END IF
INPUT PROMPT "カードのマーク?": c$
INPUT PROMPT "数字(1~N)?": K
IF UCASE$(c$)="H" THEN
LET w=H(K) !スペードの列になっている
LET w=S(w)
ELSE
LET w=MOD(S(K),13) !ハートの列になっている
LET w=H(w)
END IF
PRINT mid$(mk$,INT(w/13)+1,1); MOD(w,13)
PRINT "----- 最初の状態 -----"
CALL ready
CALL printa(s) ! スペード
CALL printa(h) ! ハート
PRINT
!
FOR R=1 TO 12
PRINT "----- Request";R;"の場合-----"
CALL ready
LET k=1
DO WHILE k< 13
FOR i=1 TO 12
LET j=MOD(i,2)*7+INT(i/2) ! 分けた2つを重ねた時の位置。
IF i=R THEN
LET t(j)=h(k) ! ハートをテーブルへ
LET w(k)=s(i) ! 手元(最初スペード)を「捨て」へ
LET k=k+1
ELSE
LET t(j)=s(i) ! 手元(最初スペード)をテーブルへ
END IF
NEXT i
MAT s=t ! テーブルを手元(最初スペード)へ
LOOP
CALL printa(s) ! 比較・・・手元(最初スペード)
CALL printa(w) ! 比較・・・「捨て」の重なり
PRINT
NEXT R
SUB printa(a())
FOR n=1 TO 12
PRINT USING "## ":a(n);
NEXT n
PRINT " …互いに Index."
END SUB
SUB ready
FOR i=1 TO 12
LET s(i)=i
LET h(i)=i
NEXT i
END SUB
!補助ルーチン
SUB PermPrintOut(A()) !表示する ※標準形(2行n列の行列表記する)
!PRINT "┌";
!FOR i=1 TO UBOUND(A)
! PRINT USING "###": i;
!NEXT i
!PRINT " ┐"
!PRINT "└";
FOR i=1 TO UBOUND(A)
PRINT USING "###": A(i);
NEXT i
!PRINT " ┘";
PRINT
END SUB
!置換
SUB PermIdentity(A()) !恒等置換
FOR i=1 TO UBOUND(A)
LET A(i)=i
NEXT i
END SUB
SUB PermMultiply(A(),B(), AB()) !積AB ※AB≠BA、A(BC)=(AB)C
LET ua=UBOUND(A)
LET ub=UBOUND(B)
IF ua=ub THEN
FOR i=1 TO ua
LET AB(i)=A(B(i)) !※合成写像(AB)(i)=A(B(i))
NEXT i
ELSE
PRINT "次元が違います。A=";ua;" B=";ub
STOP
END IF
END SUB
!-------------------- ここまでがサブルーチン
!main
LET N=12 !※2,4,10,12
!A=┌ 1 2 3 4 ┐=(1 2 4 3) ※1行目の順番は固定とする
! └ 2 4 1 3 ┘
DATA 2,4,6,8,10,12,1,3,5,7,9,11 !配列変数の「添え字と値」に対応させる
!DATA 2,4,6,8,10,1,3,5,7,9 !N=10
!DATA 2,4,1,3 !N=4
!DATA 2,1 !N=2
DIM A(N)
MAT READ A
FOR i=1 TO N
PRINT USING "###": i;
NEXT i
PRINT
DIM B(N)
CALL PermIdentity(B) !初期値
DIM c(N)
FOR k=1 TO N !回数
CALL PermMultiply(B,A,c) !シャッフル
PRINT "K=";k
CALL PermPrintOut(c) !何回か実行すると元に戻る
MAT B=c
NEXT k
カードマジックで出会った現象
投稿日:2008年11月 4日(火)22時52分56秒Cのスピードは魅力的ですが、どうも約束事が多くて馴染み難いのです。
その点BASICの記述では何をしたいのかがCに較べると読み取り易い気がします。
C言語でプログラムを書いていただいた方には後ほど質問をしておきます。
話は変わりますが・・・
この場を借りて日頃疑問に感じていることを解析してほしいんですが実は自分はカードマジックが大好きでそれに関連した本を読んでいて出会った記述でして、次のような事が起きます。
ぜひ、トランプで確認を!
ハートとスペードを順にA、2、3・・・Qと重ねる。
ハートパケットはテーブルに裏向き(Aが上)で置く。
観客に1~12までの好きな数字を決め手もらう。
スペードパケットを手に裏向き(Aが上)に持ち、上から表向きにしながらテーブルへ左、右、左、・・・と2つの山を作りながらカードを重ねていく。
客が決めた数字の枚数目の時、このカードはテーブルの別の場所に捨てられた札として、表向きのまま除く。その代わりとして、ハートパケットの一番上のカードをこのカードの置くべきだった山へ表向きにのせる。後続けていき手持ちのカードが無くなるまで進む。
左の山を持ち上げ、右の山へ重ね、一つになったパケットを手にとり、裏向きで持つ。
同じことをくり返し、最終的に手にはハート、捨て場にはスペードが集まる。
この二つの山をテーブルに並べて置く。
観客にハートまたはスペードから好きなカード(A~Qまでの中から)の名前を言ってもらう。(例ハートの8を観客が選んだとして説明します。)
客がハートを選択したのなら、まずスペードの山から、上より8枚目のカードを引き出す。
(もし客がスペードの選択をしたのならハートの山からカードを引き出すことになる。)
引き出したカードの数字に従い、今度はハートパケットの上からその数字の枚数目のカードを表向きにする。
ここから客が指定しておいたハートの8が出現する。
<わかり難いでしょうか?>
この客に任意で選択させている事(1~12を選ばせたり、好きなカードを指定させたり)をやっておきながら、的確に客のカードを当ててしまう仕組みはとっても数学的に巧く計算されていると思われます。
12という数字が何かキーになる性質を有しているからだろうと予感されます。
このことをプログラムで解明して欲しいんですが・・・