CodeIQ MAGAZINECodeIQ MAGAZINE

【謎解きプログラム】弾幕の軌跡を作ってみよう【描画】解答と解説

2017.02.24 Category:CodeIQ問題解説・リーダーボード Tag:

  • 2
  • このエントリーをはてなブックマークに追加
entry

言語不問で、プログラムにちなんだ謎を解く「謎解きプログラム」。

あなたは見事、謎を解けましたか? というわけで、出題者の柳井さんによる解答と解説をどうぞ!
by CodeIQ運営事務局

【謎解きプログラム】弾幕の軌跡を作ってみよう【描画】

本問題は、表題のテーマで、プログラムにちなんだ謎を解くというものでした。

それでは以下、各問題とその解答を見ていきましょう。

問題のオープニング

ある日、出社すると、あなたのPCのログイン画面に、謎の挑戦状が表示されていた。

「24時間以内にが解けない場合は、このPCのデータは消失する。

 は、あなたが真のプログラマーなら解けるものだ」

これは挑戦状ではなく脅迫状だ!

そこには、見たことのない謎が掲載されていた。

あなたは歴戦のプログラマーとして、データを救うために、この謎に挑むことになった。

前提条件

以下に簡易なJavaScriptのコードを示します。bullets関数は、中心座標を元に、弾幕の軌跡を描く関数です。また、draw関数は、一つの点(弾)を描画する関数です。座標は、左上が0,0になります。

// bullets 関数の引数
cx …… 中心X座標
cy …… 中心Y座標
w …… 横幅
h …… 高さ
tmRate …… 時間比率(0~1.0)軌跡を描くのに使用
// draw 関数の引数
x …… X座標
y …… Y座標
tmRate …… 時間比率(0~1.0)色の変化に使用

問題1

引数w, h, cx, cyは固定。cxはw/2、cyはh/4。tmRateは0~1.0で変化します。

プログラムで描画される点の座標を考え、下の図1~図3のどの図になるかを選んでください。

var bullets = function(cx, cy, w, h, tmRate) {
    var x = cx;
    var y = cy + h * tmRate;
    draw(x, y, tmRate);
};

図1

図2

図3

// 選択肢
図1
図2
図3

問題のプログラムを見てみましょう。

var bullets = function(cx, cy, w, h, tmRate) {
    var x = cx;
    var y = cy + h * tmRate;
    draw(x, y, tmRate);
};

xの値が固定で、yの値が、「h(高さ) * tmRate(時間比率)」で変化しています。

この条件に当てはまる図は2となり、2番目の選択肢の「図2」が答えになります。

また、各図はプログラムで生成したものなので、それぞれのコードを掲載しておきます。

// 図1
var bullets = function(cx, cy, w, h, tmRate) {
    var x = cx + w * tmRate;    // xが変化
    var y = cy;
    draw(x, y, tmRate);
};
// 図2
var bullets = function(cx, cy, w, h, tmRate) {
    var x = cx;
    var y = cy + h * tmRate;    // yが変化
    draw(x, y, tmRate);
};
// 図3
var bullets = function(cx, cy, w, h, tmRate) {
    var x = cx + w * tmRate;    // xが変化
    var y = cy + h * tmRate;    // yが変化
    draw(x, y, tmRate);
};

問題2

引数w, h, cx, cyは固定。cxはw/2、cyはh/4。tmRateは0~1.0で変化します。

プログラムで描画される点の座標を考え、下の図1~図3のどの図になるかを選んでください。

var bullets = function(cx, cy, w, h, tmRate) {
    var sz = Math.sqrt(w * w + h * h) * tmRate;
    for (var r = 0; r < Math.PI * 2; r += Math.PI / 16) {
        var x = cx + sz * Math.cos(r);
        var y = cy + sz * Math.sin(r);
        draw(x, y, tmRate);
    }
};

図1

図2

図3

// 選択肢
図1
図2
図3

問題のプログラムを見てみましょう。

var bullets = function(cx, cy, w, h, tmRate) {
    var sz = Math.sqrt(w * w + h * h) * tmRate;
    for (var r = 0; r < Math.PI * 2; r += Math.PI / 16) {
        var x = cx + sz * Math.cos(r);
        var y = cy + sz * Math.sin(r);
        draw(x, y, tmRate);
    }
};

「Math.sqrt(w * w + h * h)」は、描画領域の対角線の長さを求めています。求めた長さにtmRate(時間比率)を掛けた値を、変数szに格納しています。

「for (var r = 0; r < Math.PI * 2; r += Math.PI / 16)」のループでは、円を32分割した角度を順に処理しています。

最後に、「var x = cx + sz * Math.cos(r);」と、「var y = cy + sz * Math.sin(r);」で、それぞれの角度に座標を回転させて描画を行なっています。

コードがどの図かを見分けるポイントは、「弾の間隔」と「弾が広がる円の縦横の比率」です。コードでは、弾の間隔は一定で、縦横も同じです。

そのため図1は、弾の間隔が徐々に開いているので除外されます。図2は、縦横の比率が違うので除外されます。

この条件に当てはまる図は3となり、3番目の選択肢の「図3」が答えになります。

また、各図はプログラムで生成したものなので、それぞれのコードを掲載しておきます。

// 図1
var bullets = function(cx, cy, w, h, tmRate) {
    var sz = Math.sqrt(w * w + h * h) * tmRate;
    for (var r = 0; r < Math.PI * 2; r += Math.PI / 16) {
        // 「sz * sz」で、徐々に間隔が大きくなっている。
        var x = cx + sz * sz * 0.05 * Math.cos(r);
        var y = cy + sz * sz * 0.05 * Math.sin(r);
        draw(x, y, tmRate);
    }
};
// 図2
var bullets = function(cx, cy, w, h, tmRate) {
    for (var r = 0; r < Math.PI * 2; r += Math.PI / 16) {
        // xはw(横の長さ)に比例。yはh(縦の長さ)に比例。
        var x = cx + w * tmRate * Math.cos(r);
        var y = cy + h * tmRate * Math.sin(r);
        draw(x, y, tmRate);
    }
};
// 図3
var bullets = function(cx, cy, w, h, tmRate) {
    var sz = Math.sqrt(w * w + h * h) * tmRate;
    for (var r = 0; r < Math.PI * 2; r += Math.PI / 16) {
        // 対角線の長さszに、縦も横も比例。
        var x = cx + sz * Math.cos(r);
        var y = cy + sz * Math.sin(r);
        draw(x, y, tmRate);
    }
};

問題3

引数w, h, cx, cyは固定。cxはw/2、cyはh/4。tmRateは0~1.0で変化します。

プログラムで描画される点の座標を考え、下の図1~図3のどの図になるかを選んでください。

var bullets = function(cx, cy, w, h, tmRate) {
    var sz = Math.sqrt(w * w + h * h) * tmRate;
    for (var r = 0; r < Math.PI * 2; r += Math.PI / 8) {
        var x = cx + sz * Math.cos(r + Math.PI * tmRate);
        var y = cy + sz * Math.sin(r + Math.PI * tmRate);
        draw(x, y, tmRate);
    }
};

図1

図2

図3

// 選択肢
図1
図2
図3

問題のプログラムを見てみましょう。

var bullets = function(cx, cy, w, h, tmRate) {
    var sz = Math.sqrt(w * w + h * h) * tmRate;
    for (var r = 0; r < Math.PI * 2; r += Math.PI / 8) {
        var x = cx + sz * Math.cos(r + Math.PI * tmRate);
        var y = cy + sz * Math.sin(r + Math.PI * tmRate);
        draw(x, y, tmRate);
    }
};

「Math.sqrt(w * w + h * h)」は、描画領域の対角線の長さを求めています。求めた長さにtmRate(時間比率)を掛けた値を、変数szに格納しています。

「for (var r = 0; r < Math.PI * 2; r += Math.PI / 8)」のループでは、円を16分割した角度を順に処理しています。

最後に、「var x = cx + sz * Math.cos(r + Math.PI * tmRate);」と、「var y = cy + sz * Math.sin(r + Math.PI * tmRate);」で、時間の推移とともに、徐々に回転するようにしています。

「Math.PI * tmRate」となっていることで、時間とともに回転しています。

この動きをする図は3となり、3番目の選択肢の「図3」が答えになります。

また、各図はプログラムで生成したものなので、それぞれのコードを掲載しておきます。

// 図1
var bullets = function(cx, cy, w, h, tmRate) {
    var sz = Math.sqrt(w * w + h * h) * tmRate;
    var rRate = (tmRate * 4 | 0) % 2 == 0 ? tmRate : -tmRate;  // 向きの切り替え
    for (var r = 0; r < Math.PI * 2; r += Math.PI / 16) {
        var x = cx + sz * Math.cos(r + Math.PI * rRate);
        var y = cy + sz * Math.sin(r + Math.PI * rRate);
        draw(x, y, tmRate);
    }
};
// 図2
var bullets = function(cx, cy, w, h, tmRate) {
    var sz = Math.sqrt(w * w + h * h) * tmRate;
    var rRate = tmRate * Math.cos(Math.PI * 8 * tmRate) / Math.sqrt(sz);  // 揺れる
    for (var r = 0; r < Math.PI * 2; r += Math.PI / 16) {
        var x = cx + sz * Math.cos(r + Math.PI * rRate);
        var y = cy + sz * Math.sin(r + Math.PI * rRate);
        draw(x, y, tmRate);
    }
};
// 図3
var bullets = function(cx, cy, w, h, tmRate) {
    var sz = Math.sqrt(w * w + h * h) * tmRate;
    for (var r = 0; r < Math.PI * 2; r += Math.PI / 8) {
        var x = cx + sz * Math.cos(r + Math.PI * tmRate);
        var y = cy + sz * Math.sin(r + Math.PI * tmRate);
        draw(x, y, tmRate);
    }
};

CodeIQ運営事務局より

柳井さん、ありがとうございました!
現在、柳井さんの最新問題が出題中です。
ぜひ挑戦してみてくださいね!

  • 2
  • このエントリーをはてなブックマークに追加

■関連記事

【息抜き】平均値と中央値【言語不問】解答と解説... 【息抜き】平均値と中央値【言語不問】 本問題は、表題のテーマで、簡単なプログラムを書くものです。 それでは以下、問題とその解答を見ていきましょう。 問題 改行区切りの文字列の各行(最大行数30)は、半角数字のみの整数(最大桁数8)になっています。 この各行の平均値と中央値を求めて下さい。小...
【息抜き】右位置揃え【言語不問】解答と解説... 【息抜き】右位置揃え【言語不問】 本問題は、表題のテーマで、簡単なプログラムを書くものです。 それでは以下、問題とその解答を見ていきましょう。 問題 改行区切りの文字列の各行は、半角数字のみの整数(最大桁数32)になっています。 この各行の先頭に任意の数の半角のアンダーバー(_)を挿入して...
【謎解きプログラム】どんな配列が得られる?【フィルター,マップ】解答と解説... 【謎解きプログラム】どんな配列が得られる?【フィルター,マップ】 本問題は、表題のテーマで、プログラムにちなんだ謎を解くというものでした。 それでは以下、各問題とその解答を見ていきましょう。 問題のオープニング ある日、出社すると、あなたのPCのログイン画面に、謎の挑戦状が表示されていた。 ...
数学の問題をプログラミングで解こう!「タンジェント・フラクション」問題解説... 問題のおさらい α と β を、0 < α < β < π/2 を満たす実数とします。 α, β の組のうち、tan(α), tan(β), tan(α+β) がすべて単位分数(分母が自然数、分子が 1 の分数として書き表せる数)となるものを考えましょう。(α, β の単位はラジアンと見なします...
【謎解きプログラム】どう比較する?【ソート】解答と解説... 【謎解きプログラム】どう比較する?【ソート】 本問題は、表題のテーマで、プログラムにちなんだ謎を解くというものでした。 それでは以下、各問題とその解答を見ていきましょう。 問題のオープニング ある日、出社すると、あなたのPCのログイン画面に、謎の挑戦状が表示されていた。 「24時間以内に謎...
数学の問題をプログラミングで解こう!「ロンリー・ルーク」問題解説... 問題のおさらい 自然数 n, k に対し、縦横 n×n のマス目にチェスのルークの駒を k 個配置することを考えます。 このとき、自身から見て上下方向・左右方向のいずれにも他の駒が存在しないような駒を「はぐれルーク」と呼びます。 例えば以下は、(n, k)=(4, 5) のときの駒の配置例を示...

今週のPickUPレポート

新着記事

週間ランキング

CodeIQとは

CodeIQ(コードアイキュー)とは、自分の実力を知りたいITエンジニア向けの、実務スキル評価サービスです。

CodeIQご利用にあたって
関連サイト
codeiq

リクルートグループサイトへ