見出し画像

「わかるけどできない」を解決したい!

こんにちは「つけらっとゲームス」プログラム担当のとちです。

ゲームを作る他に、専門学校のシステム系学科で非常勤講師もやってまして、今回は学生と接して感じた「わかるけどできない」を、マジでなんとかして…いやね、本当にどうにかして解決したいというお話なんです。

そして「こうしたら解決できるんじゃね?」というお話でもあります。

高校等で情報関連の勉強をしていて「わかるけどできない」という方や、これからプログラムを勉強しようという方にオススメです!

基本情報技術者[科目B]で出題されるアルゴリズムが「わかるけどできない」も一緒に予習復習していきましょう!



わかるけどできない状態とは?

多分なんですけど、誰にでも経験があると思うんですよ。

わたしにとっても日常的な「状態異常」でして…解説書や動画を見ると、書いている(喋ってる)意味はわかるんですが、実際に手を動かそうとすると「できない」んですよね。

んで、自分が教える立場になると最悪なことに、わたしが状態異常攻撃をまき散らします。教えてる時間は学生たちも意味を理解しているんですが、じゃぁ練習問題を解いてみましょうの時間になると、急に「できない」学生が出てきます。

これを解決したいですね…
というわけで記事の中で「わかるけどできない」状態になって貰います!


今回のデータ

以前「UnityでCSVファイルを読んでみる!」という記事で使用したデータを再利用します。以下の表はドラゴンクエスト2の武器データです。

ドラクエ2の武器データ

武器No、名前、攻撃力、買値、売値、装備可否、備考といった項目が並んでいます。これらは配列となっており添字で対応しているとします。

添字が10だった場合、bName[10] は「ロトのつるぎ」を指します。今回の記事ではこのデータを使用して幾つかのアルゴリズムを考えてみます。


「どうのつるぎ」の攻撃力を知りたい!

「どうのつるぎの攻撃力を画面表示するフローチャートを書きましょう」という問題だった場合は、これまで何度か記事にしてきた線形探索という方法が良いでしょう。

線形探索ではデータの先頭(または末尾)から必要なデータか確認していきます。上記の例ですと「どうのつるぎ」と配列 bName を比較して同じ名前のデータを探します。

添字をカウントアップすることで探しているデータが何番目なのかが判明します。配列 bkouka の 添字番目を画面表示すればいいんです。

探しているのは「どうのつるぎ」です。

bNameの0番目は「ひのきのぼう」なので違う。次のデータを見る。
bNameの1番目は「はやぶさのけん」なので違う。次のデータを見る。
bNameの2番目は「こんぼう」なので違う。次のデータを見る。
bNameの3番目は「どうのつるぎ」なので見つけた!

「どうのつるぎ」は3番目なので、bKoukaの3番目「10」を画面表示する。

線形探索で「どうのつるぎ」の攻撃力を表示する考え方

では、これをフローチャートで、またはプログラムコードで表現しましょう。と言われると難しい…「わかるけどできない」状態です。説明を聞いているときは理解できます。理解できるけど書けない。

とりあえず解答例を先に貼るとこんな感じになります。

Dim i As Integer                                        '【変数定義】探索用添字
                                                        '
For i = 0 To 15                                         '■ 配列 bName を探索するループ
                                                        '│
    If "どうのつるぎ" = bName(i) Then                    '├◆ bName が どうのつるぎ だった場合
       Label1.Caption = Str(bKouka(i))                  '│├ 画面に攻撃力(武器効果)を表示
       Exit For                                         '│└ ループを抜ける
    End If                                              ''│
Next i                                                  '└ ループ終端

なぜ書けないのか、原因は恐らくですが「いきなり正解を求めている」からではないでしょうか?

確かに線形探索は基本的なアルゴリズムだと何度か述べていますが、やったことない方からすれば未知の内容です。

これね、もっと分解できるんですよ。最初はもっと単純に考えていいのです。だってアルゴリズムはこれなんですよ(再掲)

探しているのは「どうのつるぎ」です。

bNameの0番目は「ひのきのぼう」なので違う。次のデータを見る。
bNameの1番目は「はやぶさのけん」なので違う。次のデータを見る。
bNameの2番目は「こんぼう」なので違う。次のデータを見る。
bNameの3番目は「どうのつるぎ」なので見つけた!

「どうのつるぎ」は3番目なので、bKoukaの3番目「10」を画面表示する。

この文章をそのままフローチャート化すると、本当は次の画像のフローチャートになりますよね。

線と矢印がごちゃごちゃしてます。理由は表示記号が何個もあるから、だったら表示を1回で済ませばいいんですよ。表示を1回にするために添字を利用します。すると次の画像になります。

表示の部分はスッキリしましたが判断(分岐)記号のあたりがごちゃごちゃしました。似たような処理を繰り返しています。なのでこれをまとめます。
すると…解答例になるんですね(再掲)

プログラムコードも同じです。
いきなりFor文を書くのが難しいと思ったら、もっと単純に考えましょう。
配列を1つずつチェックするならこんな感じのコードになります。

If "どうのつるぎ" = bName(0) Then                   '◆ bName 0番目が どうのつるぎ だった場合
   Label1.Caption = Str(bKouka(0))                 '└ 画面に攻撃力(武器効果)を表示
End If                                             '
                                                   '
If "どうのつるぎ" = bName(1) Then                   '◆ bName 1番目が どうのつるぎ だった場合
   Label1.Caption = Str(bKouka(1))                 '└ 画面に攻撃力(武器効果)を表示
End If                                             '
                                                   '
If "どうのつるぎ" = bName(2) Then                   '◆ bName 2番目が どうのつるぎ だった場合
   Label1.Caption = Str(bKouka(2))                 '└ 画面に攻撃力(武器効果)を表示
End If                                             '
                                                   '
If "どうのつるぎ" = bName(3) Then                   '◆ bName 3番目が どうのつるぎ だった場合
   Label1.Caption = Str(bKouka(3))                 '└ 画面に攻撃力(武器効果)を表示
End If                                             '

これを配列の最後まで書けば、どうのつるぎの攻撃力はわかるんですけど、見た感じ似ている行が並んでいるのがわかります。

似ている行があったらまとめよう。まとめる方法は何がいいかな?
まとめる方法はFor文で繰り返そう!

すると、こんな感じのコードになりますよね?(再掲)

Dim i As Integer                                        '【変数定義】探索用添字
                                                        '
For i = 0 To 15                                         '■ 配列 bName を探索するループ
                                                        '│
    If "どうのつるぎ" = bName(i) Then                    '├◆ bName が どうのつるぎ だった場合
       Label1.Caption = Str(bKouka(i))                  '│├ 画面に攻撃力(武器効果)を表示
       Exit For                                         '│└ ループを抜ける
    End If                                              ''│
Next i                                                  '└ ループ終端

「わかるけどできない」を解決する方法、それは「いきなり難しいことをやらない」です。

デジタル化だ、プログラミング的思考だと言われると効率よく作らないといけないような気がしますが、プログラムを作るのは人間です。人間はミスする動物です。

ですが、プログラムを組めば作業そのものは機械がやってくれます。そのプログラムは人間が作ってるからミス(バグ)が発生します。

ミスはあるんです。だからこそ、これが大事。
問題を複雑化しない。単純な部分から書く。ミスしたら修正する。
もちろん、書ける人は最初から答えを書いていいんですよ!


もっと条件のある問題

引き続き、以下のデータ「ドラゴンクエスト2の武器データ」(再掲)で応用問題に挑戦してみましょう。

ドラクエ2の武器データ(再掲)

【応用問題】
登場キャラ全員が装備可能(つまりローレシアの王子、サマルトリアの王子、ムーンブルクの王女の全員が装備可能)な武器の中で最も攻撃力の大きい武器の名前を画面表示するフローチャート(及びVBAのプログラムコード)を書きましょう!

はい、かなり複雑な感じがする問題です。でも大丈夫です。
まずはアルゴリズムを考えてみましょう。

0件目のbSoubi1 と bSoubi2 と bSoubi3 の全てが1かチェックする。
もし全て1だったら攻撃力を確認し、攻撃力が一番大きいか確認する。

1件目のbSoubi1 と bSoubi2 と bSoubi3 の全てが1かチェックする。
もし全て1だったら攻撃力を確認し、攻撃力が一番大きいか確認する。

2件目のbSoubi1 と bSoubi2 と bSoubi3 の全てが1かチェックする。
もし全て1だったら攻撃力を確認し、攻撃力が一番大きいか確認する。

を最後まで繰り返す。

処理の流れを想像すると、そこまで難しくはないような気がします。それに、この時点で似ている処理を繰り返しているのがわかりますね。

そこで、アルゴリズムの時点でもうちょっとフロチャートやコードに寄せて考えてみます。

添字 i の初期値を 0 にする。
攻撃力の最大値 bMax の初期値を 0 にする。最大値の添字を覚えておくための変数 bIxの初期値を -1 にする。

bSoubi1[i] と bSoubi2[i] と bSoubi3[i] が全て1以上だったら攻撃力の最大値 bMax と bKouka[i] と比較する。bKouka[i]が大きい場合は bMax に bKouka[i]を代入し、bIndex にiの値を代入する。

添字iを1つ加算して繰り返す。

これをフローチャート化(VBAのプログラムコード化)してみます。

思ったよりシンプルなフローチャートになりました。
しかし、これが難しいと思ったら例題を分解して考えたように、応用問題も分解して考えるといいのです。

まず「登場キャラ全員が装備可能」という条件と「最も攻撃力が大きい」という条件がありました。難しいなら片方の条件を満たすフローチャートをそれぞれ考えてみるといいでしょう。

最も攻撃力が大きい武器の名前を表示するフローチャート

VBAのプログラムコードはこんな感じになりました。

    Dim i    As Integer                                     '【変数定義】探索用添字
    Dim bMax As Integer                                     '【変数定義】攻撃力(武器効果)の最大値を保持する変数
    Dim bIx  As Integer                                     '【変数定義】攻撃力(武器効果)の最大値を見つけた時の添字
                                                            '
    For i = 0 To 15                                         '■ 配列を探索するループ
                                                            '│
        If bSoubi1(i) = 1 Then                              '├◆ ローレシアの王子は装備できるか?
            If bSoubi2(i) = 1 Then                          '│└◆ サマルトリアの王子は装備できるか?
                If bSoubi3(i) = 1 Then                      '│ └◆ ムーンブルクの王子は装備できるか?
                    If bKouka(i) > bMax Then                '│    └▼ 攻撃力の最大値を新たに見つけた場合
                        bMax = bKouka(i)                    '│      ├ 攻撃力の最大値を保持する
                        bIx = i                             '│      └ 攻撃力の最大値を見つけた時の添字を覚えておく
                    End If                                  '│
                End If                                      '│
            End If                                          '│
        End If                                              ''│
    Next i                                                  '└ ループ終端
                                                            '
    Label1.Caption = bName(bIx)                             ' 画面に攻撃力(武器効果)を表示

if文は以下のように「And」で並べてもいいですね。

If bSoubi1(i) = 1 And bSoubi2(i) = 1 And bSoubi3(i) = 1 Then
   If bKouka(i) > bMax Then
      bMax = bKouka(i)
      bIx = i
   End If
End If

おわりに

いかがでしたでしょうか?
今回は「わかるけどできない」を少しでも解決したいというお話と、解決する為には問題を複雑化しない。単純な部分から書く。ミスしたら修正する。のが大事だというお話をしました。

これまでも、こういったお話は何度かしてきましたが、効率化を急ぐあまり自分の作業も効率化のため工程をすっ飛ばしたくなります。慣れてきたら多少の省略は可能になりますが、まずはしっかり考え方を持つといいです。

ただ、今回の例題と応用問題、実はまだまだ単純な部類です。次回以降はもっと複雑な場合どうしたらいいのかをお話したいと思います。


もうちょっと勉強したいなーって方にはコチラがオススメです。
これらの勉強に使えそうな関連記事は以下にまとめてます!(↓)

「VBAって結構ちゃんとしたプログラム作れるんだ~」と思った方はコチラがオススメです(↓)

もう少し見た目がかわいいゲームを作りたい方はコチラがオススメ(↓)

Unityで作りたい方はコチラをご覧ください(↓)


弊サークルの活動を応援してもいいなと感じていただけたら嬉しいです。 いただいたサポートは「地域/若者向けの展示会費用」「ゲーム開発費」として使わせていただきます! サポートよろしくお願い致します~🐱🐭