狭い場所でカード揃え

 投稿者:GAI  投稿日:2013年 1月 5日(土)17時59分16秒
  1~nの番号のカードを十分シャッフルしてから
表向きにしてテーブルの左の位置に重ねて置いておく。
そして、
テーブルの3カ所(左,中,右)にカードを動かしていく。
ただし、下のルールだけを頼りに操作する。
つまり、下にあるカードの数字は見えなく、また何枚が下にあるのかも
わからない。
以前の状態は一切関係なく、今見えているカードの数のみに依存して
操作を進めるものとする。


_は空枠であることを示す。

<ルール>
①(2,1,_)→1を2の上にのせる。
②2枚のカードが見えていたら、空き枠の左隣のカードで空きを埋める。
(右と左は繋がっていると考える。)
③j<kとし、(k,j,k-1)の配置が見えたら、k-1をkの上にのせる。
(両端が連続する数で左端の方が大きいものであり、中の数がより小さい場合)
④1枚しかカードが見えてないなら、そのカードを左隣へ動かす。
(右と左は繋がっていると考える。)
⑤3枚のカードが見えていたら、その3枚のうち最大の数の右隣に
 あるカードを右隣へ移動する。
(右と左は繋がっていると考える。)

*(左,中,右)にあるカード(重なっている場合は左端の数字が見える。)
 を示す。
<例1>
番号1~4の4枚のカードをシャッフルして
上から[2,1,3,4]であった場合の推移の様子

([2,1,3,4],_,_)
↓④
([1,3,4],_,2)
↓②
([3,4],1,2)
↓③
([2,3,4],1,_)
↓①
([1,2,3,4],_,_)

<例2>
同じく[4,3,2,1]であった場合の推移の様子

([4,3,2,1],_,_)
↓④
([3,2,1],_,4)
↓②
([2,1],3,4)
↓⑤
(1,[2,3],4)
↓⑤
(_,[1,2,3],4)
↓②
(4,[1,2,3],_)
↓②
(4,[2,3],1)
↓⑤
(4,3,[2,1])
↓⑤
(4,_,[3,2,1])
↓②
(_,4,[3,2,1])
↓②
(3,4,[2,1])
↓⑤
([2,3],4,1)
↓⑤
([1,2,3],4,_)
↓②
([1,2,3],_,4)
↓②
([2,3],1,4)
↓⑤
(3,[2,1],4)
↓⑤
(_,[3,2,1],4)
↓②
(4,[3,2,1],_)
↓②
(4,[2,1],3)
↓③
([3,4],[2,1],_)
↓②
([3,4],1,2)
↓③
([2,3,4],1,_)
↓①
([1,2,3,4],_,_)

このルールを守って操作する限り、必ず左の位置に上から1~nの順番に揃ったカードが
重なって終わる。

これが本当に52枚あるトランプでも達成できるのか確かめたいので
この操作をプログラム化して頂きたいです。


 

Re: 狭い場所でカード揃え

 投稿者:山中和義  投稿日:2013年 1月 6日(日)12時13分9秒
  > No.2949[元記事へ]

GAIさんへのお返事です。

> 1~nの番号のカードを十分シャッフルしてから

> <ルール>
> ①(2,1,_)→1を2の上にのせる。
> ②2枚のカードが見えていたら、空き枠の左隣のカードで空きを埋める。
> (右と左は繋がっていると考える。)
> ③j<kとし、(k,j,k-1)の配置が見えたら、k-1をkの上にのせる。
> (両端が連続する数で左端の方が大きいものであり、中の数がより小さい場合)
> ④1枚しかカードが見えてないなら、そのカードを左隣へ動かす。
> (右と左は繋がっていると考える。)
> ⑤3枚のカードが見えていたら、その3枚のうち最大の数の右隣に
>  あるカードを右隣へ移動する。
> (右と左は繋がっていると考える。)

52枚の場合、かなりの作業となります。


LET N=4 !カードの枚数

DIM m1(N),m2(N),m3(N) !カードの並び

SUB card_initialize(c(),N) !カードを整列する
   FOR i=1 TO N
      LET c(i)=i
   NEXT i
END SUB
RANDOMIZE
CALL card_initialize(m1,N)


SUB shuffle_randomize(c(),N) !ランダムにシャッフルする
   FOR i=N TO 2 STEP -1
      LET j=INT(RND*(i-1))+1 !1~i-1
      swap c(i),c(j)
   NEXT i
END SUB
CALL shuffle_randomize(m1,N)
!DATA 1,2,3,4
!!DATA 4,3,1,2
!MAT READ m1
!!!MAT PRINT m1; !debug

MAT m2=ZER
MAT m3=ZER

LET c1=N
LET c2=0
LET c3=0


SUB card_display(c(),N)
   PRINT "{";
   IF N>0 THEN
      PRINT STR$(c(N));
      FOR i=N-1 TO 1 STEP -1
         PRINT ",";STR$(c(i));
      NEXT i
   END IF
   PRINT "}"
END SUB
CALL card_display(m1,c1)
CALL card_display(m2,c2)
CALL card_display(m3,c3)
PRINT


SUB move(x(),a,y(),b) !XからYへ移動させる
   LET t=x(a)
   LET a=a-1
   LET b=b+1
   LET y(b)=t
END SUB

LET S=0 !ステップ
DO

   IF c1=N THEN !整列しているかどうか
      FOR i=c1 TO 1 STEP -1
         IF m1(i)<>N-i+1 THEN EXIT FOR
      NEXT i
      IF i<1 THEN EXIT DO !OK!
   END IF

   LET S=S+1
   PRINT S;": ";

   !ルール1
   IF (c1>0 AND m1(c1)=2) AND (c2>0 AND m2(c2)=1) AND (c3=0) THEN !(2,1,_)なら
      CALL move(m2,c2,m1,c1) !1を2の上にのせる
      PRINT "ルール1"
   ELSE

   !ルール2
      IF c1>0 AND c2>0 AND c3=0 THEN !3が空きなら
         CALL move(m2,c2,m3,c3) !左隣のカードで空きを埋める
         PRINT "ルール2"
      ELSEIF c2>0 AND c3>0 AND c1=0 THEN !1が空きなら
         CALL move(m3,c3,m1,c1)
         PRINT "ルール2"
      ELSEIF c3>0 AND c1>0 AND c2=0 THEN !2が空きなら
         CALL move(m1,c1,m2,c2)
         PRINT "ルール2"
      ELSE

      !ルール3
         IF (c1>0 AND c2>0 AND c3>0) AND (m1(c1)-1=m3(c3) AND m2(c2)<m1(c1)) THEN !(k,j,k-1)
            CALL move(m3,c3,m1,c1) !(k-1)のカードをkのカードの上にのせる
            PRINT "ルール3"
         ELSE

         !ルール4
            IF c1=N AND c2=0 AND c3=0 THEN !2,3が空きなら
               CALL move(m1,c1,m3,c3) !左隣へ移動する
               PRINT "ルール4"
            ELSEIF c2=N AND c3=0 AND c1=0  THEN !3,1が空きなら
               CALL move(m2,c2,m1,c1)
               PRINT "ルール4"
            ELSEIF c3=N AND c1=0 AND c3=0 THEN !1,2が空きなら
               CALL move(m3,c3,m2,c2)
               PRINT "ルール4"
            ELSE

            !ルール5
               IF (c1>0 AND c2>0 AND c3>0) THEN !3枚のカードが見えるなら
                  LET t1=m1(c1)
                  LET t2=m2(c2)
                  LET t3=m3(c3)
                  LET t=MAX(MAX(t1,t2),t3)
                  IF t1=t THEN !1が最大なら
                     CALL move(m2,c2,m3,c3) !右隣のカードを右隣へ移動させる
                  ELSEIF t2=t THEN !2が最大なら
                     CALL move(m3,c3,m1,c1)
                  ELSE !3が最大なら
                     CALL move(m1,c1,m2,c2)
                  END IF
                  PRINT "ルール5"

               END IF
            END IF
         END IF
      END IF
   END IF

   CALL card_display(m1,c1) !結果を表示する
   CALL card_display(m2,c2)
   CALL card_display(m3,c3)
   PRINT

LOOP

END

 

戻る