個サ作 #8 演習問題:世界のなべあつ
こんにちは。
前回はカレンダーLv.3を完了しました。
それでプログラミングの基本3原則(順次処理、反復処理、分岐処理)はクリアしたよ、という話でしたね。
今回は演習問題として世界のなべあつをやります。箸休めだと思って、軽い気持ちで取り組んでください。
一応、仕様を掴んだらあなたに自分で考えて実装いただく機会という名目ですので、ググったりしながら自分なりに進めていただいてもOKです。
それではいってみましょう。
今回のゴール
下図が完成形です。今回はここまでもっていきます。
世界のなべあつ氏(の芸)
紹介とこの演習の意義
まずはこちらをご覧ください(リンク切れていたらごめんなさい。そのときはすみませんが、ご自身で検索いただけますか。YouTubeにて「世界のなべあつ 3の倍数」とかで出てくるかと思います)。
数値カウントの中で3の倍数と3がつく数字のときはアホになる、という芸です。
どうしてこれを演習問題として扱うのか?という点ですが、ただ単に都合がいいからです(すみません)。
ここまでのカレンダーLv.1,2,3を実装いただいたあなたならわかっていただけると思うのですが、この芸をプログラムでやろうとするとループ処理も分岐処理もおそらく使いますよね。今の状況にちょうどいいんです。
今までがインプットだとしたら今度はアウトプットのターンなので、できればまずはご自身で考えてみてください。どのようにして実現するのかを。
後続記事の#13から行うあみだくじに比べるとなんの実用性もないのですが、ちょっとしたお遊びだと思って取り組んでいただけると幸いです。
側だけ用意してしまいましょう。「E_カレンダー3()」の下に追記してください。
'演習問題1
Sub F_世界のなべあつ()
End Sub
ここからの説明ではまず最初に実装に必要な要素やロジック、処理仕様を整理します。
その段階で可能であればもう実装しちゃってください。最後に答え合わせをしましょう。
処理仕様を整理する
では参りましょう。実装にあたって必要な情報を整理します。
数字のカウントは1から40まで行う
出力セルはD2からD41を使用する
カウントの出力は一緒に顔文字を出す
カウントが3の倍数もしくは3のつく場合は以下を適用する
顔文字を変える
文字を赤色にする
文字を太字にする
処理の進行に合わせてセルの選択位置を進める
これらの情報があればあとはソースコードに落とし込むだけになります。この段階でゴリゴリと実装を進めていただいてもOK。
しかし、これまでの学習内容には登場しなかった要素があるんですよね。
カウントが3の倍数かどうかを調べる方法
カウントに3が含まれるかどうかを調べる方法
セルの文字を赤色にする方法
セルの文字を太字にする方法
これらです。次項からひとつずつヒントを示しましょう。
ヒント①3の倍数の調べ方
これには2つステップがあり、まず頭の中で3の倍数の判別方法が理解できること、次にそれをプログラミングで表現することです。
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,・・・という数字の羅列があったとき、3, 6, 9, 12, 15, 18・・・だけを抽出する方法が知りたいわけですね。
これはある数式に各数字を適用した結果「答えが○○かどうか。○○だったら3の倍数だ、そうでないなら3の倍数ではない」という方法で判別します。
3の倍数の数字にだけ共通する事象があるんですね。各数字に対してある数字を足すか、引くか、掛けるか、割るか・・・どんな手があるでしょう。
3の倍数を探したいので、ある数字というのは自ずと3だとわかります。というか、わからなかったとしてもこの場合3からアプローチを始めましょう。
では四則演算(+-×÷)のうちどれを適用するか。それは割り算です。
そして、注目すべきは答えの余りです。次の式をご覧ください(…はあまりを示す)。
1 ÷ 3 = 0…1
2 ÷ 3 = 0…2
3 ÷ 3 = 0…0
4 ÷ 3 = 1…1
5 ÷ 3 = 1…2
6 ÷ 3 = 2…0
7 ÷ 3 = 2…1
8 ÷ 3 = 2…2
9 ÷ 3 = 3…0
10 ÷ 3 = 3…1
11 ÷ 3 = 3…2
12 ÷ 3 = 4…0
13 ÷ 3 = 4…1
14 ÷ 3 = 4…2
はい!一目瞭然ですね。答えのあまりが0のときが3の倍数です。これは3に限らずこのようになります。5の倍数を調べたければ5で割ればいいし、7の倍数を調べたければ7で割ればよいです。
さて、これで第一段階クリア。あとはどうやってプログラミングで表現するか、です。調べ方としてはVBAで割り算の余りを出す計算方法を調べれば解にたどり着くことができます。それが0かどうか、だけですからね。
余りの求め方を調べるとキーワードが見えてきましたね。Mod演算子!
ここ↓を読んでください。赤線引いたところ。
構文と解説です。構文に倣うと(↓例)
2 = 14 Mod 3
ということになります。余りだけを返すんですね。14 ÷ 3の答えは4あまり2ですが、この除算結果の4の方は無視されます。
そしてカレンダーLv.3のIsNumeric関数でもやったように、上記の「2」と「14 mod 3」はイコールの関係なので、一度変数に入れずともMod演算子のままIf文の中で使うことができます。つまり・・・
Dim value as Integer: value = 14 Mod 3
If value = 0 Then
と
If 14 Mod 3 = 0 Then
は同じこと。と、すると実装イメージは下記のようになるでしょう。
Dim count As Integer
'TODO:変数countになにか値を入れる
If count Mod 3 = 0 Then
[countが3の倍数の時にしたい処理]
End If
上記ソースコードの場合、変数countの中身が6ならこのIf文はTrueと評価しますし、2とか7とかだったら余りが0とイコールにならないのでFalseと評価されます。
読み方「モジュロ」ってなんだよって思われた方、いると思います。そんな方はこちら↓も参照されるとよいでしょう。
3の倍数かどうか?を判定する実装に関するヒントはこれで以上です。
ヒント②3のつく数字かどうかの調べ方
今度は「まずプログラミング抜きで理解してから~」などと言わず、いきなり3がつくのかどうか、その方法を調べます。
いくつかのやり方があるのですが、最も簡単で直観的な方法での実装を想定しています。
「VBA ある文字が含まれるかどうか」で調べると、検索結果の中に「Like演算子」という言葉が見つかると思います。
「InStr関数」での実装方法を紹介したページもヒットするので、やり方としてはそちらもあるのですが、今回はLike演算子を採用します。
上記の構文によると
result = [検証対象のテキスト] Like [検証パターン]
という書き方をします。resultは結果が格納されるだけなので、気にしなくてよいです。
公式リファレンスの注釈欄にある記載の通り、検証対象の文字列がパターンにマッチすればTrueを、マッチしなければFalseを返してくれます。
このLike演算子でポイントになるのはLikeの後に設定する「パターン」と呼ばれるパラメータですね。#6の関数の説明で引数という言葉が出てきましたが、それと同じものと考えてください。
処理を行うための材料を与えてあげるような感じです。
パターンにはどんな指定方法があるかというと、
公式リファレンスにこのような表がついてますね。今回は「*」(アスタリスク)のみを説明します。
これまでもやってきていますが、初めて使う演算子や関数で使い方がよくわからない場合は、簡単な値を当てはめてその結果をDebug.Printでイミディエイトウィンドウに出してみるとよいです。
Like演算子でやってみましょう。下記のソースを使って説明します。
Debug.Print "「すき」と「すき」の完全一致検証:" & ("すき" Like "すき")
Debug.Print "「すきやき」と「すき」の完全一致検証:" & ("すきやき" Like "すき")
Debug.Print "「かみすき」と「すき」の完全一致検証:" & ("かみすき" Like "すき")
Debug.Print ""
Debug.Print "「すき」と「すき」の前方一致検証:" & ("すき" Like "すき*")
Debug.Print "「すきやき」と「すき」の前方一致検証:" & ("すきやき" Like "すき*")
Debug.Print "「かみすき」と「すき」の前方一致検証:" & ("かみすき" Like "すき*")
Debug.Print ""
Debug.Print "「すき」と「すき」の部分一致検証:" & ("すき" Like "*すき*")
Debug.Print "「すきやき」と「すき」の部分一致検証:" & ("すきやき" Like "*すき*")
Debug.Print "「かみすき」と「すき」の部分一致検証:" & ("かみすき" Like "*すき*")
Debug.Print ""
Debug.Print "「すき」と「すき」の後方一致検証:" & ("すき" Like "*すき")
Debug.Print "「すきやき」と「すき」の後方一致検証:" & ("すきやき" Like "*すき")
Debug.Print "「かみすき」と「すき」の後方一致検証:" & ("かみすき" Like "*すき")
Like演算子と「*」を使ったパターンでどのような結果を返してくるか?を見ています(括弧を付けているのはLike演算子に検証範囲を教えてあげるため)。「&」のうしろがTrueかFalseになるわけですね。
「*」(アスタリスク)は上に示した公式リファレンスの表では「0 文字以上の文字。」と説明されています。これはこのアスタリスクは0文字以上のどんな文字ともマッチするという意味です。
0文字以上ということは文字がないという状態にもマッチしたという結果、すなわちTrueを返す、と言っています。
アスタリスクを用いることで、とあるパターンに対して
完全一致
前方一致
部分一致
後方一致
の4パターンのマッチがあります。
実行すると・・・
結果がざっと出てきます。ひとつずつ見ていきましょう。
まずは完全一致。
Debug.Print "「すき」と「すき」の完全一致検証:" & ("すき" Like "すき")
Debug.Print "「すきやき」と「すき」の完全一致検証:" & ("すきやき" Like "すき")
Debug.Print "「かみすき」と「すき」の完全一致検証:" & ("かみすき" Like "すき")
この結果は上からTrue, False, Falseです。
アスタリスクはどんな文字にも化ける便利なやつですが、それがないときは純粋に一致するかどうかを検証します。「すき」をしらべたパターンだけがTrueの結果ですね。「すき」と「すき」なのでその通りです。一致!
次に前方一致。
Debug.Print "「すき」と「すき」の前方一致検証:" & ("すき" Like "すき*")
Debug.Print "「すきやき」と「すき」の前方一致検証:" & ("すきやき" Like "すき*")
Debug.Print "「かみすき」と「すき」の前方一致検証:" & ("かみすき" Like "すき*")
この3つの実行結果は順番にTrue, True, Falseです。
パターン文字列の末尾が「*」な点にご注目ください。
アスタリスクはどんな文字ともマッチできるので、パターンのところに「すき*」と指定することで「すき」から始まる言葉を探す、という処理をしています。
0文字以上、というところもポイントで先ほども申した通り、文字がなにも続かなくてもいいんです。だから1行目の「すき」もTrueを返します。
次に部分一致。
Debug.Print "「すき」と「すき」の部分一致検証:" & ("すき" Like "*すき*")
Debug.Print "「すきやき」と「すき」の部分一致検証:" & ("すきやき" Like "*すき*")
Debug.Print "「かみすき」と「すき」の部分一致検証:" & ("かみすき" Like "*すき*")
True, True, Trueの実行結果です。
パターン文字列の先頭・末尾両方に「*」がある点にご注目。
これは次に説明する後方一致と先ほどの前方一致の合わせ技で、パターンに「*すき*」と指定することで「すき」の前後に0文字以上の文字があればマッチすることになります。
言い換えると文字列中に「すき」を含むかどうかを検証しています。
最後に後方一致。
Debug.Print "「すき」と「すき」の後方一致検証:" & ("すき" Like "*すき")
Debug.Print "「すきやき」と「すき」の後方一致検証:" & ("すきやき" Like "*すき")
Debug.Print "「かみすき」と「すき」の後方一致検証:" & ("かみすき" Like "*すき")
順番にTrue, False, Trueです。
パターン文字列の先頭に「*」がついている点にご注目。
最後が「すき」で終わる言葉を探すパターンですね。「すき」の前にアスタリスクを付けると「すき」の前はなんでもありなので、「すき」と「かみすき」だけマッチします。
「すきやき」は「すき」で終わっていないからFalseなんです。でも、すきやきは好きですね。
このアスタリスクのようにどんな文字ともマッチできる記号のことをワイルドカードといいます(かっけぇ・・!)。
さて、ここまでやったLike演算子の使い方を「3のつく数字かどうか」に当てはめると次のようなIf文を書くことができます。
Dim count As Integer
If count Like "*3*" Then
[countに3がついたときに行う処理]
End If
これ、変数countはInteger型なのですが、#4でやった暗黙的型変換が働いています。Integerは変換可能です。
一の位、十の位、どちらにも「3」がつくケースがあるので、両サイドに「*」を付与する部分一致にしています。厳密には「前方一致も後方一致も確かめたい!それはつまり部分一致の検証だ!」ということです。
つぎ、いきましょう。
ヒント③セルの文字を赤色にする方法
これはもう知ってるかどうかだけの話でして、以下の書き方で実装できます。ググったら一瞬で出てきますから、その説明は省略します。
Cells(4, 4).Font.Color = RGB(255, 0, 0)
ヒントというか、答えですね。RGB(~)のところは補足が要りそうなので補足の章で扱います。お楽しみに。
ヒント④セルの文字を太字にする方法
こちらも知っているかどうかだけです。
Cells(4, 4).Font.Bold = True
このように書きます。こちらも補足の章で触れます。
いかがでしょうか。実装するための材料は揃ったかと思います。
答え合わせをしましょう!(Debug.Printのソースコードたちは削除いただいてOKです)
こたえあわせ
これが完成形のソースです(顔文字のところはお好きにしてください)。
'演習問題1
Sub F_世界のなべあつ()
Dim count As Integer: count = 1
Dim i As Integer
For i = 2 To 41
If count Mod 3 = 0 Or count Like "*3*" Then
'アホの場合
Cells(i, 4).Value = "(*''▽''){" & count
Cells(i, 4).Font.Bold = True
Cells(i, 4).Font.Color = RGB(255, 0, 0)
Else
'通常の場合
Cells(i, 4) = "( ゚Д゚){" & count
End If
Application.Wait [Now() + "0:00:00.1"]
Cells(i, 4).Select
count = count + 1
Next
End Sub
完成形の動作
いかがでしょう。
ソース解説
簡易的ではありますが、解説します。
Dim count As Integer: count = 1
Dim i As Integer
まず最初に変数を宣言します。変数countは1から40をカウントするためのものです。変数 i はループ内のカウントと書き出し位置を担います。
書き出し位置を担うということはこの変数 i がCells()の行位置に指定することになります。そして仕様の中には
出力セルはD2からD41を使用する
というものがあったので、Forループのソースは
For i = 2 To 41
この↑ようになりますね。
2から始まり41で終わるループが始まると・・・
If count Mod 3 = 0 Or count Like "*3*" Then
こちらのIf文のお出ましです。Mod演算子は「ヒント①3の倍数の調べ方」の項で学習しました。余りの数がわかるので、その式の結果が0とイコールかどうかを確認することが3の倍数かどうか?を調べる方法になります。
そして、3のつく数字かどうか?は「ヒント②3のつく数字かどうかの調べ方」の項でやりました。3の前後に「*」を付与することで部分一致としています。なので、一の位、十の位のどちらに3が来てもヒットするんですね。
この2つの条件式をOr演算子で繋いでいます。つまりどちらかの結果がTrueであれば「アホの場合」の処理に入ります。もちろん両方がTrueでもそのようになります。
次に出力部分です。
'アホの場合
Cells(i, 4).Value = "(*''▽''){" & count
Cells(i, 4).Font.Bold = True
Cells(i, 4).Font.Color = RGB(255, 0, 0)
上から順に
値の設定
フォントを太字に設定
フォントの色を設定
をしています。
Else
'通常の場合
Cells(i, 4) = "( ゚Д゚){" & count
End If
通常の場合、つまり、先ほどのIf文条件式でFalseを返してきた場合は上記にあるElseの処理に入ります。値を設定するだけですね。
その後の
Application.Wait [Now() + "0:00:00.1"]
Cells(i, 4).Select
count = count + 1
このソースはこれまでにも登場してきました。一瞬待つ処理を挟んだ後に、動的に見せるためにセルを選択状態にし、次の周回用に変数countをインクリメントしています。
以上です。
[Ctrl] + [S]で保存していただきましたら、今回の手を動かすパートは終了です。お疲れさまでした!
今回のふりかえり
今回はこれまで蓄えた知識のアウトプットの回でしたので、新しい要素は少なめでしたね。
Mod関数の使い方
Like関数の使い方
セルの文字色の変更方法
セルの文字の太さの設定方法
上記が今回新たにやったことです。これらはプログラミングの基礎知識ではなく、システムを実現させるための実装方法に関するものなので、必要になったときにその都度ググればよいようなものばかりです。
それよりも心に留めておいてほしいのは、仕様が確定しているものに対して、どのように実装をすればよいのかを考えるときの脳の使い方です。
あれこれ調べて手を動かしながらあーでもないこーでもないという過程を経る中でプログラミングの神経が磨かれていきます。その試行錯誤の味わいを体感いただけたとすれば、それが今回最も有用な成果だったといえます。
次の演習問題(あみだくじ)は#13ですので、今回はヒント・答えに頼りきりだった方はそちらで頑張っていただけたらと思います。
では、補足いきましょう。
今回の補足
Like演算子で括弧を使った理由
Like演算子の説明のところで
と、さらっと言いました。
Debug.Print "「すきやき」と「すき」の前方一致検証:" & ("すきやき" Like "すき*")
Like演算子の動作確認をするためのこのソースコードですね。上記ソースは
「すきやき」という文字列は「すき」で始まるのかどうか?
を検証しているのですが、ここに括弧がなかったら
「「すきやき」と「すき」の前方一致検証:すきやき」という文字列は「すき」で始まるのかどうか?
を検証していることになるんです。ちょっと見てみてください。
括弧がある時は、イミディエイトウィンドウに
「すきやき」と「すき」の前方一致検証:True
と出力されたのに、括弧を外すと
False
だけになってしまいました。これもまあおもしろい動きですよね。
括弧を外した場合、どうして「False」だけになったかというと、前文が出力する文字列ではなくLike演算子で検証するための文字列と解釈されてしまったためです。
ちょっとしたポイントですが、はじめのうちはこういうところではまったりするので、頭の片隅においておいてください。
RGBについて
「ヒント③セルの文字を赤色にする方法」の項で
Cells(4, 4).Font.Color = RGB(255, 0, 0)
このようなソースが登場しました。これは色を指定しているのですが、
これも組込関数のひとつなんですね。3つの引数に数値を渡してあげると、色を示す長い数字の羅列を返してくれます。
ここで抑えておいてほしいのはRBGはRed, Green, Blueの略でそれぞれ0から255の間の数値を指定できる、という点です。
つまり、なにか色を指定するにあたって、赤の成分、緑の成分、青の成分をそれぞれ数値で指定するんですね。そうすると、それらを基に混ぜ合わせた色を示す数値を戻り値として返してくれるわけです。
ちなみに今回は・・・
Cells(4, 4).Font.Color = RGB(255, 0, 0)
Redに255、Greenに0、Blueに0という指定をしたので、きれいな赤色になったのでした。
セルのFontオブジェクトについて
※ここの説明はよくわからなくてもいいです(ノД`)・゜・。
文字の太さ変更や色変更は下記のソースコードを使いましたね。
Cells(i, 4).Font.Bold = True
Cells(i, 4).Font.Color = RGB(255, 0, 0)
このソースコード中の「~.Font.~」の部分にご注目。
この「Font」の部分はオブジェクトというのですが、これを深く知ろうとすると泥沼にはまるかもしれないくらい危険なので、「そういうものがあるんだ」くらいに留めておいてください。
今の時点では「プロパティ」と同じように捉えていただいても大丈夫です。セルに所属する「フォント」というプロパティがもつ「Color」というプロパティに数値を指定できます。
と、言おうと思ったが、プロパティがプロパティをもつのは違和感があるな・・・。CellsはRangeオブジェクトを返してくれるので、Rangeオブジェクトに所属するFontオブジェクトがいろんなプロパティをもっています。
セルのフォントに対して何か加工したい場合は「Cells(4, 4).Font.」のあとにプロパティを指定すると任意の設定ができます。プロパティはたくさんいろいろあります。
公式リファレンスにプロパティ一覧の記載があるので、調べ方のひとつとして参考にしてください。
ほら、ColorもBoldもありますね。
おわりに
次回はカレンダーLv.4をやります。
自作の関数に挑戦する回で、いよいようるう年も考慮したカレンダー出力ができるようになります。
今まではVBAさんが用意してくれていた関数(=組込関数)を使ってやりくりしてきましたが、いよいよ自分で作っちゃいます。これは楽しみだ!
ではでは、今回も美味しいもの食べてゆっくり寝て、気分転換もしてまた戻ってきてください。そうしたら次に参りましょう。
ありがとうございました。
この記事が気に入ったらサポートをしてみませんか?