連載
» 2018年09月20日 10時00分 公開

バグ検出ドリル(10)“昔のバグ”は生命力が最強山浦恒央の“くみこみ”な話(110)(4/4 ページ)

[山浦恒央 東海大学 大学院 組込み技術研究科 非常勤講師(工学博士),MONOist]
前のページへ 1|2|3|4       

4.解答

 今回のバグは「フィールドの初期位置が表示されないことがある」です。

 今回の問題と前回の違いは、「配列fieldの初期値」と「プレイヤーの開始地点の設定方法」です。「今回のソースコードは前回の改造版」と書いてあることから、仕様書とソースコードを読む前に、「前回との仕様の違いを洗い出す」「ソースコードの違いも洗い出す」を実施したエンジニアは大正解です。おめでとうございます。これは、極めて正しい保守のプロセスです。「たかが練習問題なので、力まかせに解いてやる」は、エレガントではありません。常に、「最小の労力と時間で課題を解決する」ことを意識しましょう。

 今回のプログラムは、配列fieldの境界は、全て1にセットしてあるため、領域外にアクセスすることはなさそうです※2)。また、今回はプレイヤーの初期位置をランダムで決定します。実装では、rand関数を使い、filed[0〜9][0〜9]のどこかに、プレイヤーの初期位置を示す「2」を設定していますね。パッと見て、これでよさそうですが、プログラムの記述に問題があります。この方法では、fieldの初期値によっては、正しくありません。リスト2の迷路探索プログラムの冒頭にある、下記のリスト3をご覧ください。

	void SetField(int x, int y){
		if (field[y][x] != 1)
			field[y][x] = 2;
	}
リスト3 迷路探索プログラムの初期位置設定箇所

 リスト3は、プレイヤーの開始地点をセットする箇所です。2行目のif文をご覧ください。「もし、field[y][x]が1以外だったら、2をセットする」という記述があります。問題点は、以下の2つです。

  • プレイヤーの開始地点のフィールドが1だった場合は、開始地点をセット出来ない
  • プレイヤーの開始地点のフィールドが3だった場合は、ゴールを上書きして開始地点としてしまい、ゴールできなくなる

 開始地点のフィールドの値が0だったら、開始地点は正常に設定できます。このバグを回避するには「フィールドの初期値がセットできるまで、繰り返す」「0の箇所だけをランダムで選択する」などの方法があります※3)。他にも、良い方法はあるでしょう。模索してみてください。

※2)もちろん、初期値の設定を間違える可能性があります。詳しくは、前回の記事をご覧ください。

※3)なお、修正の際には、配列fieldの境界に開始地点を設定しないように注意が必要です。

 このバグは、前回から潜在的にあったバグです。前回も、配列fieldは「globaldata.hの値以外は使用しない」という制限事項はありましたが、壁を開始地点にはしたくないと、問題文を考えた結果、このバグを見逃してしまいました。昔のバグは、ものすごく生命力が強いと痛感する瞬間です。

5.自己採点シート

 今回の自己採点シートを以下に示します。

問題 内容 配点(点)
迷路探索プログラム 問題文とソースコードを一通り読んだ 20
ソースコードから、前回との違いを洗い出した 20
デバッグをした 20
プレイヤーの開始地点を設定できないことがあるバグを見つけた 20
その他のバグを見つけた 5×件数
リスト4 自己採点シート

 実は、これら以外にもう1つバグがあります。問題のある部分を抜粋します。

2.2.2 プレイヤーの移動

 現在地を(x,y)とすると、プレイヤーは以下の手順で移動する。

  • (1)キーボードから「↑」キーを入力した場合
    • (1-1)フィールド座標(y-1,x)の値を調べる
      • (1-1-1)フィールドの座標(y-1,x)が3の場合は、GOALとなり、ゲームを終了する
      • (1-1-2)フィールドの座標(y-1,x)が0の場合は、フィールドの座標(y-1,x)に2をセットする。また、もともとの座標(y,x)を0とする
      • (1-1-3)フィールドの座標(y-1,x)が1の場合は、移動不可であるため、何もしない

 上記は、2.2.2の仕様の一部を抜粋したものです。「現在地を(x,y)とすると」と書いてありますが、その下を見ると、「フィールド座標(y-1,x)の値を調べる……」のようにx,yの順番が入れ替わっています。数学的には、座標(x,y)の順番で記述しますが、実装に使用する配列field[HEGIHT][WIDTH]は、つまり(y,x)で記述します。非常に紛らわしいのですが、仕様として書く場合、「フィールド座標(x,y-1)の値を調べる……」のように、数学の慣例通り、逆順に書くのが正解です。これに気づいた方には、20点を加点します。なお、修正する場合は、2.2.2の座標を反転すればOKです。

 このバグは、前回からありました。自分が正しいと思い込むと、目の前にぶら下がっていても、見えません。後に、別の技術者が仕様書やソースコード読むと、「???」になります。昔のバグは、生命力が最強ですね。

6.終わりに

 今回は、迷路探索プログラムの修正版を出題しました。皆さんは、バグを見つけられましたか。機能追加などでプログラムを見直してみると、今回のように、見過ごしていた思わぬバグに出くわすことがあります。注意してみてください。

 本シリーズ10回目となりますが、過去の問題文にも未発見のバグが残っていると思います。お時間のある方は、あらためてバグ検出にチャレンジしてみてください。

【 筆者紹介 】
山浦 恒央(やまうら つねお)

東海大学 大学院 組込み技術研究科 非常勤講師(工学博士)


1977年、日立ソフトウェアエンジニアリングに入社、2006年より、東海大学情報理工学部ソフトウェア開発工学科助教授、2007年より、同大学大学院組込み技術研究科准教授、2016年より非常勤講師。

主な著書・訳書は、「Advances in Computers」 (Academic Press社、共著)、「ピープルウエア 第2版」「ソフトウェアテスト技法」「実践的プログラムテスト入門」「デスマーチ 第2版」「ソフトウエア開発プロフェッショナル」(以上、日経BP社、共訳)、「ソフトウエア開発 55の真実と10のウソ」「初めて学ぶソフトウエアメトリクス」(以上、日経BP社、翻訳)。


前のページへ 1|2|3|4       

Copyright © ITmedia, Inc. All Rights Reserved.