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

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

ただいまの
回答率

89.65%

グリッド マス目表 ランダムの位置に画像を配置

解決済

回答 2

投稿

  • 評価
  • クリップ 2
  • VIEW 684

williamsArk

score 32

Javascript初心者の練習として、今ゲーム(マインスイーパー)を作っています。
縦横の線を引いて、クリックしたら「スタンプ」がつくところまでは行きました。
しかし、10*10のグリッドの中に、ランダムで爆弾を配置したいのですが、詰まってます。
一番下にbombCreationの関数を作って、とりあえずrowの配列にcolの配列を詰め込んだ状態にはして、
tiles[row][col]で何番目のタイルをクリックしたか(左上が0番目、右下が99番目)を得られるかなと思ったのですが、
仮にそれがうまくいったとしても、爆弾をどのようにランダムに表の中に混ぜ込むかに苦戦しています。
引数で(row,col)として、後々tiles[Math.random()][Math.random()]みたいにできるかなとも思ってますが。。。
アドバイスいただければ幸いです。

<!DOCTYPE html>
<html lang="ja">
<head>
 <meta charset="utf-8">
 <title>Game</title>
 <link rel="css/styles.css">
</head>
<body>
  <button onclick ="init();">クリアする</button>
  <br>
  <br>
  <canvas id="MyCanvas" style="padding:0;"></canvas>
  <div id="location"></div>
<script>
var canvas;
var ctx;

var canvas_magnification = 50; //表示倍率
var canvas_width = 10; //横マスの数
var canvas_height = 10; //縦マスの数
var canvas_pushed = false; //キャンバスのマスが押されているかどうか
var bomNumber = 10;

// 初期の見た目の設定
function init() {
  ctx.fillStyle = "rgb(255, 255, 255)";
  ctx.fillRect(0, 0, canvas.width, canvas.height);

  drawLines();
}

function place(x, y) {
  var col = (Math.floor(x / canvas_magnification) + 1) + '番目';
  var row = (Math.floor(y / canvas_magnification) + 1) + '番目';

  document.getElementById('location').textContent = '上から ' + row + ' 左から ' + col;
}

// 線を引く関数
function drawLines() {
  // 色
  ctx.strokeStyle = "#FF82B2";

 // 太さ
  ctx.lineWidth = 2;

ctx.beginPath();
//縦の線
for (var i = 0; i < canvas_width + 1; i++){
  ctx.moveTo((i * canvas_magnification), 0);
  ctx.lineTo((i * canvas_magnification), canvas.height);
}

//横の線
for (var i = 0; i < canvas.height + 1; i++){
  ctx.moveTo(0, (i * canvas_magnification));
  ctx.lineTo(canvas.height, (i * canvas_magnification))
 }
 ctx.stroke();
}

//座標の位置を把握
document.addEventListener("click", function(e) {
  var rect = e.target.getBoundingClientRect();
  mouseX = e.clientX - rect.left;
  mouseY = e.clientY - rect.top;

  var col = Math.floor(mouseX / canvas_magnification);
  var row = Math.floor(mouseY / canvas_magnification);
  var img = new Image();
  img.src ="img/clear.jpg";
  ctx.drawImage(img, col * canvas_magnification, row * canvas_magnification,
       canvas_magnification, canvas_magnification) ;
  // ctx.fillStyle = "rgb(150, 0, 0)";
  // ctx.fillRect(col * canvas_magnification, row * canvas_magnification,
  //      canvas_magnification, canvas_magnification);
  // ctx

  drawLines();
});

window.onload = function() {
  canvas = document.getElementById('MyCanvas');

  canvas.width = canvas_width * canvas_magnification;
  canvas.height = canvas_height * canvas_magnification;

  ctx = canvas.getContext('2d');

  init();
}

function bombCreation(row, col){
  var row, col;
  var tiles;
  for(row = 0; row < canvas_height; row++) {
    tiles[row] = [];
    for(col = 0; col < canvas_width; col++) {
      tiles[row][col] = row * canvas_width + col;
    }
  }
}

</script>
</body>
</html>
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

質問への追記・修正、ベストアンサー選択の依頼

  • 退会済みユーザー

    退会済みユーザー

    2019/03/05 01:52

    クリックされたとき、まず canvas 要素なのか?で弾かないとまずそう。
    そのクリック処理の最後の drawLines(); はいらないよね。
    もしよければ図が表示されるように以下のようにしてみる。
    そうすれば、コピペだけで検証しやすくなるよ。
    img.src=[
    "data:image/gif;base64,",
    "R0lGODlhHgAeAIEAANwAAAD/AP/78AAAACH5BAEAAAEALAAAAAAeAB4AAAimAAMIHEgwAICDCA8WXMjQ",
    "4EEBECNCRNiQIYCICRNirDjwoYCMIC9+BFBRZMiTJi1ORHly4sKLLFl+LAgzpkySAk3aROnS4MidPHHW",
    "BNqS5FCiRY8iBTmyqcSnUKE+nCoyqtWnVJ1e3do0K9etWZcGVSoW4UyyYmf6LJtRrU62PdeyhUnz51K1",
    "BN8SjZt3JVC+NPW2HMkxJ8aQGwt39ChVoeKXIQsHBAA7"
    ].join ('\n')

    キャンセル

  • williamsArk

    2019/03/05 02:08

    アドバイスいただきましてありがとうございました。
    初心者なのでいただいた情報が難しいですね。これはどういった処理になるのでしょうか?

    キャンセル

回答 2

checkベストアンサー

+3

let line = Array (canvas_width * canvas_height);//直線の配列をイメージ
line.fill (true, 0, bomNumber);//最初のn個を爆弾にする
line.fill (false, bomNumber);// それ以降は爆弾はなし
line.sort (()=>Math.random()-.5);//疑似ランダムに並び替える

//横の幅の数だけ切り取って重ねていくイメージ
//ラインは破壊される
let tiles = [...Array(canvas_height).keys()].map (_ => line.splice (0, canvas_width));

console.log (tiles);

canvas 以外を弾く

//座標の位置を把握
document.addEventListener("click", function(e) {
  if ('CANVAS' !== e.target.tagName) return;
  ...

文字列で図形を描く

  var img = new Image();
  img.src = [
  "data:image/gif;base64,",
  "R0lGODlhHgAeAIEAANwAAAD/AP/78AAAACH5BAEAAAEALAAAAAAeAB4AAAimAAMIHEgwAICDCA8WXMjQ",
  "4EEBECNCRNiQIYCICRNirDjwoYCMIC9+BFBRZMiTJi1ORHly4sKLLFl+LAgzpkySAk3aROnS4MidPHHW",
  "BNqS5FCiRY8iBTmyqcSnUKE+nCoyqtWnVJ1e3do0K9etWZcGVSoW4UyyYmf6LJtRrU62PdeyhUnz51K1",
  "BN8SjZt3JVC+NPW2HMkxJ8aQGwt39ChVoeKXIQsHBAA7"
].join ('\n');  

Array( w ).fill( 0 ).map(
できるだけ短くプログラムを書きたいときに使います
for (let i = 0; i < xxx.length) { ...
長ったらしくなるし、変数もつかう。

Array(x).map ((i)=> ...
これだと x 回どころか1度もループしない。

Array(x).fill(0).map ((i)=>
ところがこうすると x 回ループするってこと。
しかもそれ以降では i さえも使われてないでしょ?
変数 i は、儀礼的なもの。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/03/06 08:00 編集

    canvas_width と canvas_height の値は、そのタイルの幅と高さの値。
    その値未満であれば、OKですよ

    余計なことかもしれませんが、なるべくグローバル変数の使用を控える。
    変数名は理解しやすい名前を付ける
    個々の処理は、なるべく細分化し再構築しておおまかに機能するようにする
    入力部分、tilesに関する処理、出力処理を関数にわけて作るイメージです
    そうすれば、いずれSVGで処理したくなったとき変更部分が出力処理の部分だけで済みます。
    そしてなによりも、他者からの改変(いろいろなライブラリを組み合わせると動かなくなるような、脇のあまいプログラム)に強く、仕様の変更が容易いプログラムを書くように心がけてください。
    ショートコーディングするのはその後です。w

    たまにつまずいたら、出来上がっていく過程を見せてくださいね。
    いまの状態だと・・・厳しくツッコミできないっす!

    キャンセル

  • 2019/03/06 08:05

    それと<br><br>やりたいことはわかるのですが、それはダサい。

    キャンセル

  • 2019/03/08 20:17

    大変お世話になりました。ありがとうございました。

    キャンセル

+2

「爆弾がある場所」を最初に指定して置くとかどうでしょう。

const w = 3, h = 3, bomb = 3;
const grid = Array( w ).fill( 0 ).map( e => Array( h ).fill( 0 ) );
let i = 0, wx, hx;
while( i < bomb ) {
    wx = Math.floor( Math.random () * w );
    hx = Math.floor( Math.random () * h );
    if ( grid[ wx ][ hx ] === 0 ) {
        grid[ wx ][ hx ] = 1;
        i++;
    }
}
console.dir( grid );
/*
例えば if ( grid[ よこ ][ たて ] === 1 ) で爆弾かどうか判別する
*/

動くサンプル:https://jsfiddle.net/0gymw28t/


【Array.prototype.fill() - JavaScript | MDN】
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/fill

【Array.prototype.map() - JavaScript | MDN】
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/map

【Math.random() - JavaScript | MDN】
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Math/random

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/03/05 11:47

    Array( n ) は配列のサイズだけ決める物なので、その時点で中身はありません。mapなど配列関数は中身全てに対して操作する物が多いので、.fill( 0 )を使って中身に物をつめてから処理をしています。(今回は使わないので中身は入っていれば良いので、0でも1でも何でも良い)

    eはfillされた0が入っていますが、使っていないだけです。「() =>」書くより文字数が少ないのでそう書いているだけです。

    キャンセル

  • 2019/03/06 02:00

    これはJQueryってやつですか。Javascriptだけだと色々と力不足に感じてしまいますね。なんとか少しずつこういう技術を身につけていくほかはないのですね。ありがとうございました。

    キャンセル

  • 2019/03/06 02:06

    >JQuery
    違います。

    キャンセル

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

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

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