質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
canvas

HTML5の<canvas>要素用のタグです。CanvasはHTML5から導入された、二次元の図形描写が可能な要素です。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

Q&A

解決済

2回答

5772閲覧

15パズルのクリア判定について

KyoheiTsuno

総合スコア17

canvas

HTML5の<canvas>要素用のタグです。CanvasはHTML5から導入された、二次元の図形描写が可能な要素です。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

0グッド

0クリップ

投稿2016/08/16 03:22

編集2016/08/16 08:41

###前提・実現したいこと

参考書でjavascriptを学習中です。サンプルとして、15パズルがあったので作ってみました。クリア処理を追加で実装しようと考えたのですが、どういった風に判定させればいいか、調べて考えても思いつかなかったので、質問させて頂きます。
###発生している問題・エラーメッセージ
・15パズルを完成させた時の判定処理が分からない
・サンプルは数字がランダムで入れ替わるが、何回やってもクリアできない状態(14と15の位置が正解と入れ替わっている)となる
・正解のみのパターンとなるようなコードにできないか...

エラーメッセージ

###該当のソースコード

ここにご自身が実行したソースコードを書いてください
<!DOCTYPE html> <html> <head> <title>15puzzle</title> <meta charset="UTF-8"> <style> .tile{ width:70px; height:70px; border: 1px solid blue; border-radius: 10px; text-align: center; font-size:36px; background-color:white; box-shadow:rgb(128,128,128) 5px 5px; } </style> <script> "use strict"; // 広域変数 var tiles = []; // 初期化関数 function init() { var table = document.getElementById("table"); for (var i = 0; i < 4; i++) { var tr = document.createElement("tr"); // 各行の作成 for (var j = 0; j < 4; j++) { var td = document.createElement("td"); // 4×4作成 var index = i*4 + j; td.className = "tile"; td.index = index; td.value = index; td.textContext = index == 0? "":index; td.onclick = click; tr.appendChild(td); // 子要素(td要素)を追加 tiles.push(td); } table.appendChild(tr); // tableにtr要素を追加 } for (var i = 0; i<1000; i++) { click({ srcElement: {index: Math.floor(Math.random()*16)}}) } } function click(e) { // タイルをクリックした時に空であれば入れ替える var i = e.srcElement.index; // タイルの数字を入れ替える時のロジック if(i - 4>=0 && tiles[i - 4].value == 0) { // タイル上と入れ替え swap(i,i-4); } else if(i + 4< 16 && tiles[i + 4].value == 0) { // タイル下と入れ替え swap(i,i + 4); } else if (i % 4!= 0 && tiles[i - 1].value == 0) { // タイル左隣と入れ替え swap(i,i - 1); } else if (i % 4!= 3 && tiles[i + 1].value == 0) { // タイル右隣と入れ替え swap(i,i + 1); } } function swap(i,j) { var tmp = tiles[i].value; tiles[i].textContent = tiles[j].textContent; tiles[i].value = tiles[j].value; tiles[j].textContent = tmp; tiles[j].value = tmp; } </script> </head> <body onload="init()"> <table id="table"></table> </body> </html>

###試したこと

・他のサイトから、プログラミングで作った15パズルをひたすら確認したが、あまり理解できませんでした。

・for文やif文を織り交ぜて、タイルの数字と位置情報(indexとvalue)を正しいかどうかtrue,falseで判定するというのは想像がつくのですが、実際にどう書いたらいいか分からず、詰まっています...
###補足情報(言語/FW/ツール等のバージョンなど)
より詳細な情報

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

flied_onion

2016/08/16 03:27

自分で書いてみた判定処理が見当たらなかったのですがどれでしょうか。 もしないなら書いてみてください(うまく行かない状態のもので問題ありません)
kei344

2016/08/16 04:18

質問文は適切に編集してください。質問のテンプレート分がそのまま入っています。(例:「●●なシステムを作っています。」)
KyoheiTsuno

2016/08/16 08:45

flied__onion様 ご投稿頂きありがとうございます アドバイス頂いた内容を参考に試してみます。
KyoheiTsuno

2016/08/16 08:46

kei344様 いつも大変お世話になっております。テンプレート分は修正致しました。
guest

回答2

0

ベストアンサー

ちょっとヒントだけ書いておきます。
まずは、一番左上とその右横のタイルの並びが正しいかの判定を考えてみてください。
一旦それ以外のタイルは無視してかまいません。言ってみればタイルが2枚しかなくて、並びが正解かだと思う時、その2枚にはどういう関係があるか考えてみてください。

ちなみにそれ以外のタイルを無視するのが気にかかる様であれば、他を無視してもいいのは、もしその2枚の並びが間違っていたらその後がどうあろうが関係なくその時点でアウトだから、と考えてください。

投稿2016/08/16 03:35

flied_onion

総合スコア2604

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

KyoheiTsuno

2016/08/16 08:50

flied__onion様 とても分かりやすいヒントを頂きまして、ありがとうございます。少しイメージができてきましたので、色々試行錯誤してトライアンドエラーで試してみます。
KyoheiTsuno

2016/08/17 13:21

flied__onion様 お世話になっております。 考えた式をノートに書き出してみたり、他のサイトをみて調べ、 以下のような判定処理を実装してみました。 var counter = 0; if(td.index == td.value + 1) { counter++; } if (counter === 14) { this.gameComplete.show(); } 上記のコードを、table.appendChild(tr); の下に入れました。 参考書によると、 ・index がタイルの並び順 ・value がタイルに描画されている数値 となっており、左上からindexが0ではじまります。 なので、index+1がvalue(タイルの数値)になれば、正しい位置と判断しました。 counterをつけて、15まで正しい位置にできればクリア画面に遷移するように しました。 consoleはエラーがなかったですが、画面が遷移しなかったので このコードで問題ないのか、遷移させるプログラムに問題があるのか、確認中です。
flied_onion

2016/08/17 13:57

基本的な判定の方向性あってます。実現方法に、いくつか問題があります。 まず単純なミスからですが、indexが0から始まっていて、valueは1から始まっているので、 index+1とvalueが等しい時、そのvalueは正しいindexに収まっていると考えられます。 なので、 if(td.index+1 == td.value) ですね。 判定の場所なのですが、ループをしているからその場所と考えたのだと思いますが、2つ問題があります。 一つは、tdは jのループ(for文)で定義されていて、table.appendChildの段階では範囲外です。 もう一つは、initは初期化の時(つまりパズルを作るときに)に呼ばれるもので、ユーザーが操作するのはinitを抜けた後なので、そこで判断するのはふさわしくないという点ですね。 クリックすると、click()が呼ばれるのでそこで判断する方がいいでしょう。 ではclickの中でどうやってマスにアクセスするかですが、initを見てみてください。 tiles.push(td) という文があります。pushは配列の最後に要素を追加する命令です。つまりすべてのtdはtilesの中で管理されているということになります。 clickではこのtilesを使って、tdを取り出してみましょう。
flied_onion

2016/08/17 14:00

ということで、 click関数の最後で if(tiles[0].index+1 == tiles[0].value) { console.log( tiles[0].value + ' は OK!'); }else{ console.log( tiles[0].value + ' は NG!'); } というのを追加してみてください。 tilesの使い方のヒントと、あとは KyoheiTsuno さんの考えた条件が正しいかを確認できると思います。
KyoheiTsuno

2016/08/17 14:55

非常に分かりやすい解説をして頂き、感謝しています! 参考書にはpushの解説などがなかった為、勉強になりました。 GoogleChromeにて確認しました結果、しっかりと判定されていました。 if文で各々タイルの判定を行わせていけばOKだと思いますが、 現時点では15回分のif文をつくる方法しか思いついていません。 もう少しコードが短くできるスマートな方法がないかも考えてみます。 ご回答頂き、誠にありがとうございました。
flied_onion

2016/08/17 16:09

コメントに書いていた、counter を使うというやり方はありだと思いますよ。 あとは15回分の似たような処理をどう短くするかですね。頑張ってください。
KyoheiTsuno

2016/08/18 13:15

ありがとうございます!無事、counterでクリア処理が回りました! ですが、最終的にやりたい画面遷移ができず詰まっています... このコード以外にjs単独のコードも使っており(他のサンプルを参考にした為)、 そちらではjQueryを用いてUIの操作をしています。 クリアしたらjs側でhideにしていたボタンをshowにして出現させたかったのですが、 上手くできませんでした... js側でhideにしたものは、js側でshowで出現させない限り出せないのか、 htmlの、js部分の書き方が悪かったのか、確認中です。 以下がjs単独(jQuery)のコード一部になります $(document).ready(function() { var ui = $("#gameUI"); var uiIntro = $("#gameIntro"); var uiStats = $("#gamestats"); var uiComplete = $("#gameComplete"); var uiPlay = $("#gamePlay"); var uiReset = $(".gameReset"); var uiScore = $(".gameScore"); var uiTable = $("#table"); var uiTime = $("#showtime"); var uiBack = $("#gameBack"); var uiStart = $("#start"); var uiClear = $("#clearmain"); var example = $("#example"); // ゲーム環境を初期化する function init() { uiStats.hide(); uiTable.hide(); uiTime.hide(); uiBack.hide(); uiStart.hide(); uiClear.hide(); example.hide(); uiComplete.hide(); uiPlay.click(function(e) { e.preventDefault(); uiIntro.hide(); example.show(); uiBack.show(); uiStart.show(); //uiComplete.show(); }); uiStart.click(function(e) { example.hide(); uiTable.show(); uiTime.show(); }); uiBack.click(function(e) { location.reload(); }); uiComplete.click(function(e) { uiBack.hide(); uiStart.hide(); uiTable.hide(); uiTime.hide(); uiClear.show(); }); }; });
KyoheiTsuno

2016/08/18 13:22

htmlのスクリプト部分はこんな感じに作りました。 if(tiles[0].index+1 == tiles[0].value) { counter++; console.log(tiles[0].value + 'は OK!'); }else{ console.log(tiles[0].value + 'は NG!'); } if(tiles[1].index+1 == tiles[1].value) { counter++; console.log(tiles[1].value + 'は OK!'); }else{ console.log(tiles[1].value + 'は NG!'); } if(tiles[2].index+1 == tiles[2].value) {  counter++; console.log(tiles[2].value + 'は OK!'); }else{ console.log(tiles[2].value + 'は NG!'); } if(tiles[3].index+1 == tiles[3].value) { counter++; console.log(tiles[3].value + 'は OK!'); }else{ console.log(tiles[3].value + 'は NG!'); } if(tiles[4].index+1 == tiles[4].value) { counter++; console.log(tiles[4].value + 'は OK!'); }else{ console.log(tiles[4].value + 'は NG!'); } if(tiles[5].index+1 == tiles[5].value) { counter++; console.log(tiles[5].value + 'は OK!'); }else{ console.log(tiles[5].value + 'は NG!'); } if(tiles[6].index+1 == tiles[6].value) { counter++; console.log(tiles[6].value + 'は OK!'); }else{ console.log(tiles[6].value + 'は NG!'); } if(tiles[7].index+1 == tiles[7].value) { counter++; console.log(tiles[7].value + 'は OK!'); }else{ console.log(tiles[7].value + 'は NG!'); } if(tiles[8].index+1 == tiles[8].value) { counter++; console.log(tiles[8].value + 'は OK!'); }else{ console.log(tiles[8].value + 'は NG!'); } if(tiles[9].index+1 == tiles[9].value) { counter++; console.log(tiles[9].value + 'は OK!'); }else{ console.log(tiles[9].value + 'は NG!'); } if(tiles[10].index+1 == tiles[10].value) { counter++; console.log(tiles[10].value + 'は OK!'); }else{ console.log(tiles[10].value + 'は NG!'); } if(tiles[11].index+1 == tiles[11].value) { counter++; console.log(tiles[11].value + 'は OK!'); }else{ console.log(tiles[11].value + 'は NG!'); } if(tiles[12].index+1 == tiles[12].value) { counter++; console.log(tiles[12].value + 'は OK!'); }else{ console.log(tiles[12].value + 'は NG!'); } if(tiles[13].index+1 == tiles[13].value) { counter++; console.log(tiles[13].value + 'は OK!'); }else{ console.log(tiles[13].value + 'は NG!'); } if(tiles[14].index+1 == tiles[14].value) { counter++; console.log(tiles[14].value + 'は OK!'); }else{ console.log(tiles[14].value + 'は NG!'); } if(tiles[15].index+1 == tiles[15].value) { counter++; console.log(tiles[15].value + 'は OK!'); }else{ console.log(tiles[15].value + 'は NG!'); } if (counter > 12) { //document.getElementById("gameComplete"); //this.gameComplete.show(); clearInterval(timerID); console.log("クリア処理OK"); } } document.getElementById("gameComplete"); this.gameComplete.show(); この2つの書き方でコンソールエラーが出ていたので、正しい記述にすれば 行けるのではないか?と考えて、調査中です。 ちなみにボタンですが、 <list id="gameComplete" class="button" href="">Complete</list> ulで作ったボタンとなっております。 大変恐縮ですが、何かアドバイスを頂けましたら幸いです。 勿論、自力で解決できるのがベストですので、頑張って調べます。
KyoheiTsuno

2016/08/21 06:44

無事、解決しました! jQueryでの制御を辞めて、document.getElementByIdの後に .style.display="none";で普段は隠していて、 クリア処理がONになったら.style.display="block";で表示という方法で うまくいきました!
guest

0

15パズルの初期配置、解けるかどうかの判断などは、以下のページが判りやすいと思います。

Javaで書かれたサンプルプログラムも載っていますから、Javascriptでプログラムを作る際の参考になることと思います。

スライドパズルの配置の判定方法

投稿2016/08/16 06:41

coco_bauer

総合スコア6915

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

KyoheiTsuno

2016/08/16 08:47

coco_bauer様 分かりやすいサイトをご紹介頂き、ありがとうございます。こちらの内容を確認し、再度着手します。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問