CodeIQ MAGAZINECodeIQ MAGAZINE

【謎解きプログラム】どう防ぐ?【無限ループ】解答と解説

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

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

簡単なプログラムにちなんだ謎を解く「謎解きプログラム」。

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

【謎解きプログラム】どう防ぐ?【無限ループ】

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

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

問題のオープニング

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

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

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

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

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

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

問題1

あなたは、無限ループしてしまうプログラムを修正することになりました。

(厳密に言うと、変数の上限まで来て負数になると停まったりするので、10000回以上繰り返される部分を、無限ループとします)

示されるコードは、C、Java、JavaScriptなどのプログラミング言語で見られるような、一般的な書き方のコードです。

無限ループを防げるコードを、選択肢から1つ選んで下さい。

● コードと選択肢

// コード
i = 0;
while(true) {
    i ++;

    if (i == 0)  {break;}    // 選択肢1
    if (i > 100) {break;}    // 選択肢2
    if (i < 0)   {break;}    // 選択肢3
}
println("ESCAPE!");

● 答え

変数iは0から始まります。また、選択肢の前に「i ++;」という処理が入ります。そのため選択肢の時点で、iは1から始まり、1ずつ大きくなっていきます。

// コード
i = 0;
while(true) {
    i ++;    // ←最初にここを通過したあと、変数iは、1加算されて1になる。

    // 選択肢の時点で変数iは、1, 2, 3, ……と変化する

上記から、選択肢1の「i == 0」がtrueになることはありません。そのため選択肢1は答えではありません。

次に、選択肢3の「i < 0」もtrueになることはありません。変数iが0より小さくなることがないためです。そのため選択肢3も答えではありません。

最後に、選択肢2の「i > 100」は、変数iが1から1ずつ大きくなっていった結果、101になった時にtrueになります。

というわけで選択肢2の「if (i > 100) {break;}」が答えになります。

以下、コードを、JavaScriptで処理したものを掲載します。

● 確認コード

// 共通
var i, j;
var println = console.log;

//----------------------------------------
// 選択肢1
console.log('選択肢1');
(function() {
    var cnt = 0;

    i = 0;
    while(true) {
        i ++;
        if (i == 0) {break;}

        if (++cnt >= 10000) {break;}    // デバッグ用
    }
    println("ESCAPE!");
    println("cnt", cnt, (cnt >= 10000) ? '×' : '○');
})();
console.log('-'.repeat(20));

// 選択肢2
console.log('選択肢2');
(function() {
    var cnt = 0;

    i = 0;
    while(true) {
        i ++;
        if (i > 100) {break;}

        if (++cnt >= 10000) {break;}    // デバッグ用
    }
    println("ESCAPE!");
    println("cnt", cnt, (cnt >= 10000) ? '×' : '○');
})();
console.log('-'.repeat(20));

// 選択肢3
console.log('選択肢3');
(function() {
    var cnt = 0;

    i = 0;
    while(true) {
        i ++;
        if (i < 0) {break;}

        if (++cnt >= 10000) {break;}    // デバッグ用
    }
    println("ESCAPE!");
    println("cnt", cnt, (cnt >= 10000) ? '×' : '○');
})();
console.log('-'.repeat(20));

● 出力結果

選択肢1
ESCAPE!
cnt 10000 "×"
--------------------
選択肢2
ESCAPE!
cnt 100 "○"
--------------------
選択肢3
ESCAPE!
cnt 10000 "×"
--------------------

問題2

あなたは、無限ループしてしまうプログラムを修正することになりました。

(厳密に言うと、変数の上限まで来て負数になると停まったりするので、10000回以上繰り返される部分を、無限ループとします)

示されるコードは、C、Java、JavaScriptなどのプログラミング言語で見られるような、一般的な書き方のコードです。

無限ループを防げるコードを、選択肢から1つ選んで下さい。

● コードと選択肢

// コード
i = 0;
while(true) {
    i ++;
    i ++;

    if (i == 5)      {break;}    // 選択肢1
    if (i * 2 == 10) {break;}    // 選択肢2
    if (i -- == 5)   {break;}    // 選択肢3
}
println("ESCAPE!");

● 答え

変数iは0から始まります。また、選択肢の前に「i ++;」という処理が2回入ります。そのため選択肢の時点で、iは2から始まり、2ずつ大きくなっていきます。

// コード
i = 0;
while(true) {
    i ++;    // ←最初にここを通過したあと、変数iは、1加算されて1になる。
    i ++;    // ←最初にここを通過したあと、変数iは、1加算されて2になる。

    // 選択肢の時点で変数iは、2, 4, 6, ……と変化する

上記から、選択肢1の「i == 5」がtrueになることはありません。そのため選択肢1は答えではありません。

次に、選択肢2の「i * 2 == 10」の両辺を2で割ってみます。「i == 5」になり、選択肢1と同じになります。そのため、こちらもtrueになることはありません。そのため選択肢2も答えではありません。

最後に、選択肢3の「i — == 5」は、判定を行なったあと、変数iから1を減算しています。2増え、1減っているわけです。

その結果、判定に用いられる変数iの値は、2, 3, 4, 5, 6, 7, ……となります。そのため「== 5」が成立します。

というわけで選択肢3の「if (i — == 5) {break;}」が答えになります。

以下、コードを、JavaScriptで処理したものを掲載します。

● 確認コード

// 共通
var i, j;
var println = console.log;

//----------------------------------------
// 選択肢1
console.log('選択肢1');
(function() {
    var cnt = 0;

    i = 0;
    while(true) {
        i ++;
        i ++;

        if (i == 5) {break;}

        if (++cnt >= 10000) {break;}    // デバッグ用
    }
    println("ESCAPE!");
    println("cnt", cnt, (cnt >= 10000) ? '×' : '○');
})();
console.log('-'.repeat(20));

// 選択肢2
console.log('選択肢2');
(function() {
    var cnt = 0;

    i = 0;
    while(true) {
        i ++;
        i ++;

        if (i * 2 == 10) {break;}

        if (++cnt >= 10000) {break;}    // デバッグ用
    }
    println("ESCAPE!");
    println("cnt", cnt, (cnt >= 10000) ? '×' : '○');
})();
console.log('-'.repeat(20));

// 選択肢3
console.log('選択肢3');
(function() {
    var cnt = 0;

    i = 0;
    while(true) {
        i ++;
        i ++;

        if (i -- == 5) {break;}

        if (++cnt >= 10000) {break;}    // デバッグ用
    }
    println("ESCAPE!");
    println("cnt", cnt, (cnt >= 10000) ? '×' : '○');
})();
console.log('-'.repeat(20));

● 出力結果

選択肢1
ESCAPE!
cnt 10000 "×"
--------------------
選択肢2
ESCAPE!
cnt 10000 "×"
--------------------
選択肢3
ESCAPE!
cnt 3 "○"
--------------------

問題3

あなたは、無限ループしてしまうプログラムを修正することになりました。

(厳密に言うと、変数の上限まで来て負数になると停まったりするので、10000回以上繰り返される部分を、無限ループとします)

示されるコードは、C、Java、JavaScriptなどのプログラミング言語で見られるような、一般的な書き方のコードです。

無限ループを防げるコードを、選択肢から1つ選んで下さい。

● コードと選択肢

// コード
i = 0;
j = 1000;
while(true) {
    i ++;
    j --;

    if (i == j)     {break;}    // 選択肢1
    if (i - j == 1) {break;}    // 選択肢2
    if (i + j == 0) {break;}    // 選択肢3
}
println("ESCAPE!");

● 答え

変数iは0から始まります。変数jは1000から始まります。また、選択肢の前に「i ++;」「j –;」という処理が入ります。そのため選択肢の時点で、iは1から始まり1ずつ大きくなり、jは999から始まり1ずつ小さくなっていきます。

// コード
i = 0;
j = 1000;
while(true) {
    i ++;    // ←最初にここを通過したあと、変数iは、1加算されて1になる。
    j --;    // ←最初にここを通過したあと、変数jは、1減算されて999になる。

    // 選択肢の時点で変数iは、1, 2, 3, ……と変化する
    // 選択肢の時点で変数iは、999, 998, 997, ……と変化する

まず、選択肢3を見てみましょう。

変数iの初期値は1、変数jの初期値は999、0から始まり1ずつ大きくなる数値をnとすると、変数iの値は「1+n」、変数jの値は「999-n」と書けます。

「i + j == 0」にこの値を代入すると、「(1+n) + (999-n) == 0」となり、丸括弧を除くと「1 + n + 999 – n == 0」になります。この際「+n」と「-n」が相殺されて「1 + 999 == 0」になります。

これは成立しません。そのため、選択肢3は答えではありません。

次に、選択肢1、2を見てみましょう。

選択肢1の「i == j」は、変形すると「i – j == 0」になります。

// 選択肢1と2
    if (i - j == 0) {break;}    // 選択肢1を変形したもの
    if (i - j == 1) {break;}    // 選択肢2

先程と同じように、変数iの初期値を1、変数jの初期値を999、0から始まり1ずつ大きくなる数値をnとします。そうすると、変数iの値は「1+n」、変数jの値は「999-n」と書けます。この値を「i – j」の部分に代入してみましょう。

「(1+n) – (999-n)」となり、丸括弧を除くと「1 + n – 999 + n」となります。この式を整理すると「-998 + 2 * n」となります。

-998は2の倍数なので「2 * (-499 + n)」と書けます

そしてnが499の場合、「2 * (-499 + 499) == 0」となり、ループから抜けられます。

左辺は2の倍数であるため「2 * (-499 + n) == 1」となることはありません。

そのため選択肢1の「if (i == j) {break;}」が答えになります。選択肢2は答えではありません。

以下、コードを、JavaScriptで処理したものを掲載します。

● 確認コード

// 共通
var i, j;
var println = console.log;

//----------------------------------------
// 選択肢1
console.log('選択肢1');
(function() {
    var cnt = 0;

    i = 0;
    j = 1000;
    while(true) {
        i ++;
        j --;

        if (i == j) {break;}

        if (++cnt >= 10000) {break;}    // デバッグ用
    }
    println("ESCAPE!");
    println("cnt", cnt, (cnt > 10000) ? '×' : '○');
})();
console.log('-'.repeat(20));

// 選択肢2
console.log('選択肢2');
(function() {
    var cnt = 0;

    i = 0;
    j = 1000;
    while(true) {
        i ++;
        j --;

        if (i - j == 1) {break;}

        if (++cnt >= 10000) {break;}    // デバッグ用
    }
    println("ESCAPE!");
    println("cnt", cnt, (cnt >= 10000) ? '×' : '○');
})();
console.log('-'.repeat(20));

// 選択肢3
console.log('選択肢3');
(function() {
    var cnt = 0;

    i = 0;
    j = 1000;
    while(true) {
        i ++;
        j --;

        if (i + j == 0) {break;}

        if (++cnt >= 10000) {break;}    // デバッグ用
    }
    println("ESCAPE!");
    println("cnt", cnt, (cnt >= 10000) ? '×' : '○');
})();
console.log('-'.repeat(20));

● 出力結果

選択肢1
ESCAPE!
cnt 499 "○"
--------------------
選択肢2
ESCAPE!
cnt 10000 "×"
--------------------
選択肢3
ESCAPE!
cnt 10000 "×"
--------------------

CodeIQ運営事務局より

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

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

■関連記事

数学の問題をプログラミングで解こう!「タワー・ビルディング」問題解説... 問題のおさらい A を一辺が 1 の立方体のブロックとし、B を縦が 1、横が 1、高さが 2 の直方体のブロックとします。 (下は横から見た図です。) 自然数 n, a, b に対し、A を最大 a 個、B を最大 b 個使って、縦が 1、横が 1、高さが n の直方体の塔を作ります。 こ...
【謎解きプログラム】正しいコードは?【一人すごろく】解答と解説... 【謎解きプログラム】正しいコードは?【一人すごろく】 本問題は、表題のテーマで、プログラムにちなんだ謎を解くというものでした。 それでは以下、各問題とその解答を見ていきましょう。 問題のオープニング ある日、出社すると、あなたのPCのログイン画面に、謎の挑戦状が表示されていた。 「24時間...
数学の問題をプログラミングで解こう!「ペア・ドロップ」問題解説... 問題のおさらい n を自然数とします。1 から n までの自然数が 1 つずつ書かれた n 枚のカードが 2 組あります。 これら 2n 枚のカードをよく混ぜ、A と B の 2 人に n 枚ずつ配ります。 A と B は、それぞれ自分の持ち札の中に番号が一致するカードがあればその 2 枚を捨...
【謎解きプログラム】中身はどうなる?【出し入れ】解答と解説... 【謎解きプログラム】中身はどうなる?【出し入れ】 本問題は、表題のテーマで、プログラムにちなんだ謎を解くというものでした。 それでは以下、各問題とその解答を見ていきましょう。 問題のオープニング ある日、出社すると、あなたのPCのログイン画面に、謎の挑戦状が表示されていた。 「24時間以内...
【謎解きプログラム】座標の移動【Matrix】解答と解説... 【謎解きプログラム】座標の移動【Matrix】 本問題は、表題のテーマで、プログラムにちなんだ謎を解くというものでした。 それでは以下、各問題とその解答を見ていきましょう。 問題のオープニング ある日、出社すると、あなたのPCのログイン画面に、謎の挑戦状が表示されていた。 「24時間以内に...
数学の問題をプログラミングで解こう!「ストレート・ラインズ」問題解説... 問題のおさらい 2 以上の自然数 n に対し、n×n の格子状に並んだ点を考えます。 これらの点のうちちょうど 2 個の点を通る直線の数を F(n) と定義します。 例えば F(2)=6 です。題意を満たす直線は以下の 6 通りです。 また、F(3)=12 です。題意を満たす直線は以下の...

今週のPickUPレポート

新着記事

週間ランキング

CodeIQとは

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

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

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