教えて下さい。

 投稿者:GAI  投稿日:2012年 8月16日(木)14時18分12秒
  先日カードマジックの原理を掴むため教えてもらったプログラムを使って
今度は3山に配っていき、客が覚えたカードを最後に残すことを調べようと下記のプログラムを作ってみました。
ただし戦略"0"を行う時には、余った2つの山は左にある方のパケットを上段になるように
2つを重ねて、そのパケットで再び3山に配っていきます。

これで全パターンの一覧表を作成しようとしましたが、
プログラムの7行目の

LET P(j)=N+1-j

において、添え字が範囲外です。
の警告が出て上手く動作しません。
やむなく、個別にN,Kを指定していき調査しましたが、このどこに問題があるのか未だわかりません。
どうぞ解析のほどをお願いします。



FOR N=1 TO 52 !N枚のカード
   PRINT STR$(N);"枚"
   FOR K=1 TO N !残すカードの位置(下からK枚目)
      PRINT USING "   ##枚目: ":K;

     DIM P(52) !N枚のカードによるパケット ※P(1):上
      FOR j=1 TO N  !初期化
         LET P(j)=N+1-j
      NEXT j

      LET C=0 !回数

      LET NN=N
      DO WHILE NN>1 !1枚になるまで
         LET C=C+1
         !PRINT "パケットのカード"
         !MAT PRINT P; !debug

         DIM L(N),R(N),M(N) !3つに分ける
         MAT L=ZER      !左パケット
         MAT R=ZER      !真ん中のパケット
         MAT M=ZER      !右パケット
         LET LL=0       !枚数
         LET RR=0
         LET MM=0
         FOR i=1 TO NN
            IF P(i)=K THEN LET KK=i !残すカードを確認する
            IF MOD(i,3)=1 THEN !左の山へ
               LET LL=LL+1
               LET L(LL)=P(i)
            ELSEIF  MOD(i,3)=2 THEN !真中の山へ
               LET RR=RR+1
               LET R(RR)=P(i)
            ELSEIF MOD(i,3)=0 THEN !右の山へ
               LET MM=MM+1
               LET M(MM)=P(i)
            END IF
         NEXT i

         CALL Reverse(L,LL) !実際の並び(上から)に合わせる
         CALL Reverse(R,RR)
         CALL reverse(M,MM)
         !PRINT "左の山";
         !MAT PRINT L;
         !PRINT "真中の山";
         !MAT PRINT R;
         !PRINT "右の山";
         !MAT PRINT M;

         !PRINT "カードの総数と残すカードのトップからの位置:";NN;KK
         IF MOD(NN,3)=MOD(KK,3) THEN !最後のカードと同じ山にある場合
            PRINT "1";     !!!STR$(C);"回目の戦略=1" !残す!
            IF MOD(NN,3)=1 THEN !左の山なら
               LET NN=LL
               MAT P=L
            ELSEIF MOD(NN,3)=2 THEN !真中の山なら
               LET NN=RR
               MAT P=R
            ELSEIF MOD(NN,3)=0 THEN !右の山なら
               LET NN=MM
               MAT P=M
            END IF

         ELSE

            PRINT "0";     !!!STR$(C);"回目の戦略=0" !捨てる
            IF MOD(NN,3)=1 THEN
               LET NN=RR+MM
               DIM P1(NN)
               FOR i=1 TO RR
                  LET  P1(i)=R(i)
                  MAT P=P1
               NEXT i
               FOR i=1 TO MM
            LET  P1(RR+i)=M(i)!残ったパケットは左方が上方になるように2つを重ねる。
                  MAT P=P1
               NEXT i


            ELSEIF MOD(NN,3)=2  THEN
               LET NN=LL+MM
               DIM P2(NN)
               FOR i=1 TO LL
                  LET  P2(i)=L(i)
                  MAT P=P2
               NEXT i
               FOR i=1 TO MM
            LET  P2(LL+i)=M(i)!残ったパケットは左方が上方になるように2つを重ねる。
                  MAT P=P2
               NEXT i


            ELSEIF  MOD(NN,3)=0 THEN
               LET NN=RR+LL
               DIM P3(NN)
               FOR i=1 TO LL
                  LET  P3(i)=L(i)
                  MAT P=P3
               NEXT i
               FOR i=1 TO RR
            LET  P3(LL+i)=R(i)!残ったパケットは左方が上方になるように2つを重ねる。
                  MAT P=P3
               NEXT i

            END IF
         END IF
      LOOP
      PRINT

   NEXT k
NEXT n

END


EXTERNAL SUB Reverse(P(),N) !カードの位置を反転させる
FOR i=1 TO INT(N/2)  !半分を対象とする
   LET t=P(i) !交換する
   LET P(i)=P(N+1-i)
   LET P(N+1-i)=t
NEXT i
END SUB


 

Re: 教えて下さい。

 投稿者:白石和夫  投稿日:2012年 8月16日(木)16時08分10秒
  > No.1941[元記事へ]

                MAT P=R
を実行した時点でPの上限がRの上限と同じになります。(P,Rの下限が同じ場合)

ついでに指摘しておくと,
FOR N=2 TO 52
   DIM R(N)
NEXT N
のように最初に確保した大きさから拡大するような使い方はできません。
配列の大きさを変えたいときは,
DIM R(52)
FOR N=2 TO 52
   MAT R=ZER(N)
NEXT N
のように,初めに最大の大きさで宣言しておいてください。
 

Re: 教えて下さい。

 投稿者:山中和義  投稿日:2012年 8月17日(金)09時32分13秒
  > No.1941[元記事へ]

GAIさんへのお返事です。

> 先日カードマジックの原理を掴むため教えてもらったプログラムを使って
> 今度は3山に配っていき、客が覚えたカードを最後に残すことを調べようと下記のプログラムを作ってみました。
> ただし戦略"0"を行う時には、余った2つの山は左にある方のパケットを上段になるように
> 2つを重ねて、そのパケットで再び3山に配っていきます。

山の個数は、変更できるようにしました。
山への分配は、左、中、右、左、中、右、… の順です。


LET D=3 !山の数 ※D≧2

DIM P(52) !N枚のカードによるパケット ※P(1):上

FOR N=1 TO 52 !N枚のカード
   PRINT STR$(N);"枚"
   FOR K=1 TO N !残すカードの位置(下からK枚目)
      PRINT USING "   ##枚目: ":K;

      FOR i=1 TO N !初期化
         LET P(i)=N+1-i
      NEXT i
      !!!MAT PRINT P; !debug

      LET NN=N
      DO WHILE NN>1 !1枚になるまで

         DIM Q(52) !次のパケット
         MAT Q=ZER
         LET C=0 !その枚数

         FOR KK=1 TO NN !(上から)残すカードの位置を確認する
            IF P(KK)=K THEN EXIT FOR
         NEXT KK
         IF KK>NN THEN !存在しない場合
            PRINT "論理エラー"; NN
            MAT PRINT P;
            STOP
         END IF

         LET T=MOD(NN,D) !最後のカードが入る山の番号(左からT番目)
         IF T=0 THEN LET T=D !T=[1,D]

         IF MOD(KK,D)=MOD(NN,D) THEN !最後のカードと同じ山にある場合
            PRINT "1"; !残す!

            FOR J=T TO NN STEP D !山に分ける
               LET C=C+1
               LET Q(C)=P(J)
            NEXT J

         ELSE
            PRINT "0"; !捨てる!

            FOR i=D TO 1 STEP -1 !左にある方を上に重ねる
               IF i<>T THEN !同じ山を除く
                  FOR J=i TO NN STEP D !山に分ける
                     LET C=C+1
                     LET Q(C)=P(J)
                  NEXT J
               END IF
            NEXT i

         END IF
         CALL Reverse(Q,C) !実際の並び(上から)に合わせる
         !!!PRINT C !debug
         !!!MAT PRINT Q; !debug

         MAT P=Q !次へ
         LET NN=C
      LOOP

      PRINT
   NEXT K
NEXT N

END


EXTERNAL SUB Reverse(P(),N) !カードの位置を反転させる
!!MAT PRINT P; !debug
FOR i=1 TO INT(N/2) !半分を対象とする
   LET t=P(i) !交換する
   LET P(i)=P(N+1-i)
   LET P(N+1-i)=t
NEXT i
!!MAT PRINT P; !debug
END SUB

 

戻る