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

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

ただいまの
回答率

90.74%

  • JavaScript

    15234questions

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

  • canvas

    237questions

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

JavaScript 二次元配列の要素比較

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 114

 前提・実現したいこと

あみだくじ
上記のようなあみだくじをランダムに生成し、クリックで横棒を消したり出したりするのが目標です。現在クリックで横棒を出せるところまでできていて、今は横棒を消す処理と横棒同士で繋がらないようにする処理をするための配列検索で詰まっています。

 発生している問題・エラーメッセージ

今回横棒の情報を二次元配列で[左の棒(0~11),右の棒(0~11),y座標]という感じで以下のように配列に保管しています。

コンソールログ
0:(3) [0, 1, 90]
1:(3) [0, 1, 110]
2:(3) [0, 1, 190]
3:(3) [0, 1, 210]
4:(3) [0, 1, 230]
5:(3) [0, 1, 250]
6:(3) [0, 1, 290]
7:(3) [0, 1, 350]
8:(3) [0, 1, 370]
9:(3) [0, 1, 410]
10:(3) [1, 2, 150]
以下略


クリックで新しい横棒を生成するときに左右に横棒があると繋がってしまうので、左右に横棒がないときにだけ新しく生成したいのですが
indexOf([0, 1, 230])のように要素を検索しようとしても上手くいかず調べたところ配列で検索できないとのことで困っています。
後々横棒を消したり生成したりするたびに配列の最後にpushで入れたりするので↑のように綺麗に並んでるわけではないので、完全一致で検索できる方法がないとだめなんじゃないかなと思っています。
[a,b,y]のように配列で検索できる方法があるのか、もしくはまた違うアプローチがあるのかどうかお助け願いたいです
以下長いですがJSとhtmlのソース

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<title>あみだ</title>
<link rel="stylesheet" href="test.css" type="text/css" />
<script type="text/javascript" src="test.js"></script>
</head>
<body>
<canvas id="stage" width="500" height="500"></canvas>
</body>
</html>
window.addEventListener( "load", loadFunc, false );

function loadFunc() {
    var canvas = document.getElementById( "stage" );
    var ctx = canvas.getContext( "2d" ); 

    ctx.strokeStyle = "#339933"; 
    ctx.lineWidth = 2; 

    for( var i = 0; i < 11; i++ ) {  //縦棒描画
        ctx.beginPath();
        ctx.moveTo( 50 + i * 40, 50 );
        ctx.lineTo( 50 + i * 40, 450 );
        ctx.closePath();
        ctx.stroke();
    }

    var ran = new Array();  //横棒が重ならないようにするための二元配列
    for(i=0;i<11;i++) {
        ran[i] = new Array();
    }

    var cross = new Array();  //横棒情報を保管するための二元配列
    for(var j = 0; j<10;j++){    //横棒描画
        for(var i = 0; i<19; i++) {
            ran[j][i] = Math.floor( Math.random() * 2 );
            if (j == 0) {
                if(ran[j][i]==0) {
                    draw(i, j);;
                }
            } else {
                if(ran[j-1][i]==0) {     
                } else {
                    if(ran[j][i]==0) {
                        draw(i, j);;
                    }
                }
            }
        }
    }
    var x = 0;
    var y = 0;
    var tate = 0;
    var yoko = 0;
    function onClick(e) {
        var rect = e.target.getBoundingClientRect();
        x = e.clientX - rect.left;
        y = e.clientY - rect.top;
        for(var i=0;; i++) {
            var leftLine = 50 + i*40;   //i+1本目の縦棒
            var rightLine = 90 + i*40;  //i+2本目の縦棒

            if(x<leftLine || x>450) {   //枠外をクリックしたら無効に
                x = -1;
                break;
            }
            if(x>=leftLine && x<rightLine) {    //i+1とi+2の間にいたらx座標をi+1本目の縦棒と一緒にする
                x = leftLine;
                tate = i;
                break;
            }
        }

        for(var j=0;; j++) {
            var topLine = 60 + j*20;       //70に横線があるとして上下10ずつの空間にいれば70とみなす処理
            var bottomLine = 80 + j*20;

            if(y<topLine || y>440) {
                y = -1;
                break;
            }
            if(y>=topLine && y<bottomLine) {
                y = topLine+10;
                yoko = j;
                break;
            }
        }

        if(x>0 && y>0) {
            draw(yoko, tate);
        } 
    }

    function draw(i, j) {         // 描画処理
        /***↓以下のような検索ではちゃんと検索できない***/ 
        var left = cross.indexOf([j-1, j, 70 + i * 20]);
        var right = cross.indexOf([j+1, j+2, 70 + i * 20]);

        console.log(left,right)
        if(left == -1 && right == -1) {
            ctx.beginPath();
            ctx.moveTo( 50 +j * 40 , 70 + i * 20 );
            ctx.lineTo( 90 +j * 40,  70 + i * 20 );
            ctx.closePath();
            ctx.stroke();
            cross.push([j, j+1, 70 + i * 20])   //配列に横棒情報保存
        } 
    }
    canvas.addEventListener('click', onClick, false);
}
  • 気になる質問をクリップする

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+1

斜めはないんですね?
重複条件を整理しましょう。

まず、3・4本目間にy座標100の線を引きます[3, 4, 100]
そうすると、何・何本目にy座標100の線が引けなくなりますか?
答えは[2, 3, 100][4, 5, 100]の2種類です。

ポイントはy座標の値が一致するのが必須条件、
更に何本目かの情報が一つでも被っている事が追加条件です。

描画可能ってことで、isDroableという関数でも実装してみましょうかね。
戻り値はBoolean型でtrueが返ってきたら描画しても良い、falseは駄目。

var isDrowable = function (lines, line) {
  for (var i = 0; i < lines.length; i++) {
    var it = lines[i];
    // y座標が一致していなければスキップ
    if (it[2] !== line[2]) continue;
    // n本目の組み合わせが一つでも被っていればアウト
    if (it[0] === line[0]) return false;
    if (it[0] === line[1]) return false;
    if (it[1] === line[0]) return false;
    if (it[1] === line[1]) return false;
  }
  // 描画駄目な条件を満たして居ないのでこの線は引いても良いと認定されました。
  return true;
}

var lines = [
  [2, 3, 100],
  [4, 5, 120]
];
console.log(isDrowable(lines, [1, 2, 100])); // false
console.log(isDrowable(lines, [2, 3, 100])); // false
console.log(isDrowable(lines, [3, 4, 100])); // false
console.log(isDrowable(lines, [4, 5, 100])); // true
console.log(isDrowable(lines, [1, 2, 120])); // true
console.log(isDrowable(lines, [2, 3, 120])); // true
console.log(isDrowable(lines, [3, 4, 120])); // false
console.log(isDrowable(lines, [4, 5, 120])); // false
console.log(isDrowable(lines, [5, 6, 120])); // false
console.log(isDrowable(lines, [6, 7, 120])); // true

動いているようですね。
このように確認してBoolean値を返す関数を作成して置いておくとテストも楽で捗りますね。

なお、この関数はif (it[0] === line[0]) return false;の辺りが重複してダサいので色々と改良しがいがありそうですね。
色んな手段がありますので色々と改良してみてくださいね。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/05/08 00:04

    回答ありがとうございます!
    いろいろと改良して組み込んでみた結果無事動いてほしいように動きました。
    [4,5,110]を引くときは[3,4,110]と[5,6,110]があるかどうか調べなきゃいけない!
    と思い込んでしまっていて、こうやって分解して調べるというのに頭が回っていませんでした。
    聞けばなるほどのコロンブスの卵的なものですが、自分でしっかり考えてこういう解決方法を導き出せるように精進したいと思います。ありがとうございました!

    キャンセル

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

  • ただいまの回答率 90.74%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • JavaScript

    15234questions

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

  • canvas

    237questions

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