• ベストアンサー

16面パズルを作ったのですが、シャッフルすると解けないパターンが出てしまいます

■□□□ □□□□ □□□□ □□□□ ■=空きマス プログラミング初心者です。javascriptの練習にと思い、↑のような16面のパズルを作りました。(正式名称はよくわかりません。マスをずらして絵柄を完成させるアレです) パズルを始める際にマスの並びをシャッフルする、まではできたのですが、一つ問題があり、シャッフルされたマスの並びで絶対に解けないパターンが発生してしまいます。 16面のパズルの解けないパターンというのは、↓の状態から(2)と(1)を入れ替える事が不可能、というものです。 ■(2)(1)(3) (4)(5)(6)(7) (8)(9)(10)(11) (12)(13)(14)(15) 現段階でのシャッフルの方法は、単純に、マス(画像)が正しい順番で並んでいる状態を シャッフル前 ⇒ 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 とし、これをシャッフルして シャッフル後 ⇒ 14,8,1,7,12,9,3,5,15,2,10,6,4,11,13 のようにランダムな並び順となった配列を作り、それを元に画像を並べていく、というものです。 このシャッフル後の配列をチェックして解けないパターンであればエラーとしたいのですが、どのようなチェックをすれば良いのかがわかりません。数学のカテゴリに質問すべきかとも思いましたが、もしどなたかわかる方いらっしゃいましたら教えて頂けると幸いです。

質問者が選んだベストアンサー

  • ベストアンサー
  • buriburi3
  • ベストアンサー率44% (353/792)
回答No.2

解けないパターンの識別方法は数学的に証明されています。 「15パスル パリティ」で検索してください。 ただ、方法論としてはシャッフルするよりスワップする方が簡単だと思います。

blue_monday_88
質問者

お礼

回答ありがとうございます。 パリティっていうんですね… すっきりしました!ありがとうございます!

その他の回答 (1)

  • yambejp
  • ベストアンサー率51% (3827/7415)
回答No.1

単純なはなし・・・シャッフルしなければいいのでは? このゲームの主旨は空マスと最多4つの隣接するマスとを 入れ替えるという処理ですね よって隣接するマスをランダムに選び、入れ替えをおこなえば すむはずです。(端のマスは例外処理をいれる) どのくらいでバラバラになるかは微妙ですが、1万回も入れ替えを 行えばよいのでは?

blue_monday_88
質問者

補足

回答ありがとうございます。 その方法は最初に考えたのですが、数学的な考え方で配列をチェックできないものか、という点がどうしても気になってしまい、質問させて頂きました。やはり数学のカテゴリが専門でしょうか…

関連するQ&A

  • 携帯用パズルのシャッフルについて

    こんにちは。 携帯用のパズルゲームを作っているのですが、シャッフルがうまくできません。 私の持っている本(フラッシュ8用)を読むと、ランダムな数字を先に作ってからピースに置き換えて ステージに配置すると書いてあります。 携帯用に書き換えなければいけないのですがさっぱり見当もつきません。。 ランダムは for(i = 0; i < 16; i++){ while(1){ eval("p" add i) = random(16); flag = 0; for(j = 0; j < i; j++){ if(eval("p" add i) == eval("p" add j)) flag = 1; } if(flag == 0) break; } } このように書きました。 パズルのピースにはそれぞれMC0~MC15というインスタンス名がつけてあります。 ステージには各マスにp0~p15とつけてあります。 パズルピースは縦40ピクセル横40ピクセルの正方形で 縦に4枚横に4枚ならんでいるようなステージです。 全くの初心者なので、参考になるサイトなどもあれば 教えていただけると助かります。 よろしくお願いします。

  • 入れ替える処理

    プログラム初心者です。AS3.0で書いています 簡単な15面パズルを作りたいです。 15面パズルは解けない配置があるらしいので、ランダムではなく数字の入れ替えを100回くらい行いたいです。この入れ替えの処理をどう書けばいいのか教えてください スタートボタンを押したときに4つの隣接するマスをランダムに選び、入れ替えを行うようにすればいいらしいのですがどうやって書けばいいのかわかりません(端のマスは例外処理をいれる) できれば重複もなくしたいです よろしくお願いします メインタイムラインには mc1~mc16のムービークリップ mcのなかに入れ子で数字が入っています no1~no16のテキスト スタートボタン内のasです var i:int; var parentObject:Object=Object(parent); parentObject.sbtn.addEventListener(MouseEvent.CLICK,Mouse_Down); function Mouse_Down(event:MouseEvent):void { for( i = 1 ; i <= 16 ; i++ ) //カード番号の初期化、左上に1右下に16の規則的な配置 { Object(root)[ "mc" + i ]["no" + i].text = ""; } for( i = 1 ; i <= 16 ; i++) //配列の初期化クリア { //配列の初期化をクリアできる処理 } //ここにスタートボタンを押したときに4つの隣接するマスをランダムに選び、100回くらい入れ替えができる処理を入れたいです if( Object(root)[ "mc" + i ]["no" + i].text == 16 ) { Object(root)[ "mc" + i ]["no" + i].text = ""; //「no16」の表示をクリアして空のマスを作る Object(root).soeji = i; //数値をクリアした配列の「添え字」を保存 } }

    • ベストアンサー
    • Flash
  • ランダムで表示されるアイコン→画像+リンク

    複数のアイコンがランダムで配列されるようになっていて(並びが変わるだけで全てが画面上に表示されている)、各アイコンにonマウスで、アイコン毎に応じた大きめの画像が表示される。 そしてその画像をクリックすると外部にリンクされると言うものを作りたいと思っています。画像毎にリンク先は変わります。 また、放置した場合は順に大きめの画像が表示されていくと言った形にしたいと思っています。 こちらの質問などは近いと思うのですが、 http://oshiete1.goo.ne.jp/qa2267673.html ランダムに表示される複数の画像を同時に表示させるというのと、それを連動させる方法などがわかりません。 ご教授戴けると幸いです。どうかよろしくおねがいします。

    • ベストアンサー
    • Flash
  • エクセルでトランプ

    エクセルで、トランプの「山」のような状態を作りたい・・・と思っています。 例えば、1番目~52番目までに、1~52までの数値をランダムで重複なくセットし、更新するごとにその山がランダムでシャッフルされる、といった感じのものです。 いろいろ調べてみたのですが、マクロはちょっと自信がありません。また、画像なども必要ありません。 何か通常の関数などでいい方法はないでしょうか?

  • C言語で三目並べをするプログラムの作成

    C言語で三目並べ(いわゆる○×)をするプログラムを作成したいのですがうまくいきません;; どなたか教えてください。よろしくお願いします。 条件 ・コンピュータの手はランダムに決定するものとする(空いているところに打つ) ・盤面を表現する配列は3×3の二次元配列とし、グローバルに宣言する ・以下のような関数を作成すること:盤の表示、○×を打つ、3つ並んだかチェック ・他にも必要に応じて関数を宣言すること ヒント集 ・マスの状態は空:0 ○:1 ×:2など数値で定義するとよい。 ・char stone[3][3]={"-","○","×"};などと宣言しておくと便利? ・9マスしかないので、9マス打ち切ったら終了→このとき勝敗が決まっていなければ引き分け ・ループの考え方は2通りできる  1.先手後手がセットで1ループ、9マス目に先手が打ったらbreak 2.先手、後手それぞれ1ループ,nマス目は、n%2=0なら先手、n%2=1な  ら後手 ・三目並んだかのチェックは工夫のしどころ  ・手盤の人の石だけチェックする  ・打ったところの縦横は必ずチェック、斜めはどうする? ・作っていく順  ・石の入力+盤面表示、コンピュータの手番、3つ並んだかチェック、勝敗表示  ・石の入力+盤面表示、3つ並んだかチェック、勝敗表示、コンピュータの手番

  • TS8030での印刷パターンがおかしいです

    使用プリンタ 機種・型番:TS8030 使用端末:PC 使用アプリケーション:印刷全般 先日から黄色のインクの出方がおかしく、クリーニング、強力クリーニングでも状態が改善しません。 パターンチェックをしてみると、長方形の左側、1センチほどはきれいに印刷されるのに、右の方は【<】のように途切れます。(添付画像参照) 横一直線に色が抜けていたらノズルが詰まっているのかと思うのですが、このような状態は初めてで調べてもわかりませんでした。 とても困っていますので、お知恵をお借りしたいです。宜しくお願い致します。 ※OKWAVEより補足:「キヤノン製品」についての質問です。

  • [PHP]負荷の少ない方法は?

    PHPでテキスト広告をランダム表示するプログラムを作ろうと思います。 方法が幾つかあるとは思うのですができるだけ負荷を少ないしたいです。 以下の様な方法を思いついたのですが どれが処理が早いでしょうか? ■配列に広告を入れてシャッフル表示 $ad[] = ("広告名","URL"); といった感じで広告の数の文だけ作る。 ■広告の数の文だけファイルをつくりinclude $n;<ランダムな数字 include ("ad".$n.".html"); 広告ファイルの管理が面倒ですが・・ ■MYSQL+PHPでランダム表示 広告データの数はせいぜい50~100件程度かとは思いますが 1000件、1万件クラスになった場合のパターンも合わせて 教えてほしいです。

    • ベストアンサー
    • PHP
  • [JAVA]配列のカウントに関して

    はじめまして。 JAVAで配列を使ってプログラミングしています。 TEST[a][b][c] という配列の「a」に何パターンのデータが格納されているかを取得するにはどうすればいいですか? データベースでいう、レコードカウントみないなコマンドはないですか?? TEST[0][0][0] = い TEST[0][0][1] = ろ TEST[1][0][0] = は という状態であれば、「2」を返して欲しいんです。 宜しくお願い致します。

    • ベストアンサー
    • Java
  • 15パズルの作り方が分かりません!

    ご閲覧ありがとうございます。 実は大学で、「15パズル」のプログラムを作れという課題が出たのですが、上手く動きません。プログラミングに関してはほぼ初心者で、どこがどうまちがっているのか、どのように直したらきちんと動くのかが全く分かりません・・・。!il||li(っω-`。)il||li 助けて下さい!お願いします(´;ω;`) 以下が私がいじっていたプログラムです <html> <head> <title>15パズル</title> <script type="text/javascript"> // 初期盤面を生成するプロシージャ function gstart() { var checked=new Array(15); // 「使用済み」のチェック用 var i, j; // カウンタ var n; // パネル番号 var p; // パリティ計算用 var parity = false; // 奇順列の状態 var flag; // その数が使用済みかどうか while(parity==false){ // 奇順列の間は繰り返す for(i=0;i<16;i++) checked[i]=false; // すべて未使用状態化 for(i=0;i<16;i++){ // パネル番号を順に決める flag = false; // 最初はパネル番号未決定とする while(flag==false){ // 未使用状態の間は繰り返す n = Math.floor(Math.random()*16); // nに0~8の乱数を設定 if(checked[n]==false){ // nが未使用なら pnum[i] = n; // i番目のパネルのパネル番号をn checked[n] = true; // nを使用済みにする flag = true; // パネル番号決定 } } } p = 0; // 偶順列か奇順列かの計算 for(i=0;i<15;i++){ for(j=i+1;j<16;j++){ if(pnum[i]!=0 && pnum[j]!=0){ if(pnum[i]>pnum[j]) p++; // 互換の数を勘定 } } } if((p%2)==0) parity=true; // 互換の数が偶数なら偶順列 } for(i=0;i<16;i++){ if(pnum[i]==0) document.forms[0].elements[i].value= ""; else document.forms[0].elements[i].value= pnum[i]; } } function move(obj) { var i,j,k; for(j=0;j<16;j++) if(obj.value==pnum[j]) i=j; // objのパネル位置を調べる for(j=-4;j<2;j=j+3){ // 上下左右の隣接パネルの調査 k = i+j; if((k>=0&&k<16) && ((Math.floor(i/2)==Math.floor(k/2))||(i%2==k%2))){ if(pnum[k]==0){ // 隣が空なら入れ替え pnum[k] = pnum[i]; document.forms[0].elements[k].value= pnum[k]; pnum[i] = 0; document.forms[0].elements[i].value= ""; } } } } </script> </head> <body> <h1>15パズル</h1> [開始]ボタンクリックでスタート。 <form id="Form1"> <script type="text/javascript"> var i; var s; var pnum=new Array(16); // パネル番号記憶用 for(i=0;i<16;i++){ document.write("<input style='width:30px; height:30px;' type='button' value='"+(i+1)+"' onClick='move(this)'>"); if((i+1)%4==0) document.write("<br />"); } document.forms[0].elements[15].value= ""; </script> <br /> <input style="width:60px; height:30px;" type="button" value="開始" onClick="gstart()"><br /> </form> </body> </html>

  • 15パズルでできないパターンがあるのですか?

    16升目に1~15の数字をばらばらに入れて横に1~15まで並べるゲームで1~12まで並んであと13・14・15を13・15・14(又は14・13・15)と入れなをし13・14・15にすることができるのですか、それともできないのですか。自分で考えてもできないので回答よろしくお願いします。

専門家に質問してみよう