滝の音

滝の音

名こそ流れてなお聞こえけれ

VBAでパフォーマンスの良いライフゲームをつくろう その6 マシンの性能

  • はじめに

前回終わりを宣言したこのコーナーですが
ちょっと試してみたいことがあったのでもう一回だけ。

  • マシンを変えてみる

今まで使っていたのはMyノートパソコン
スペックはどうやって表現するのだろう
メモリは2Gです。

それに対して今回使ってみたのが
メモリが8Gのネカフェのパソコン。

Ver7とVer8_1を扱います。 F_sizeを100で計測。

ちなみにMyノートパソコンでの結果は前回の通り。

ノートパソコン ネカフェのパソコン
Ver7 Ver8_1 Ver7 Ver8_1
調査終了0.046875 調査終了 0.1411133 調査終了0.03125 調査終了 0.046875
更新終了0.328125 更新終了 0.21875 更新終了0.046875 更新終了 0.03125

ちょっとみにくいですかね。。
ネカフェのパソコンのほうが段違いのスピードを出しています。
Ver7もVer8_1も等しく高速になりました。

このマシンではf_sizeが100では速いってことしかわからないですね。 Ver7とVer8.1それぞれの強みがどのf_sizeまで通用するのか。
もうちょっとf_sizeを上げて測りますか。

Ver7 Ver8_1
100 0.03125 0.046875
0.078125 0.03125
140 0.03125 0.078125
0.109375 0.03125
180 0.046875 0.078125
0.125 0.054688
450 0.140625 0.390015
0.6875 0.218018
700 0.3125 0.935974
1.695313 0.218994

各f_sizeの1段目が調査時間で
2段目が更新時間です。

F_sizeを700くらいまでもっていくと
ひとつひとつのセルに書き込むことには無理があるみたいですね。
ただ1マスに700の文字列を入れることにも無理があるみたい。

んー。
これが次への布石になるだろうか。

ちなみにf_size700だと小さすぎてセルの動きがよくわからないです。
なんかざわざわしてる
くらいな見え方。

  • まとめ

今回一番理解できたことは
マシンの性能が上がるとパフォーマンスも上がるということ。

まぁ。
現状でMyノートパソコンの性能を使いこなせているかは謎ですが。
たぶん使いこなせていないんだろうなぁ。

というわけで。
このコーナーは終了。
次回のコーナーもこうご期待。

VBAでパフォーマンスの良いライフゲームをつくろう その5 Ver7と8.1

  • はじめに

このコーナーも第5回。
飽きたか飽きてないかでいうと
飽きてきました笑

  • Ver7は配列

Ver7はめちゃ速くなります。
このアイディアは思い浮かんではいたものの
実装するとすごいめんどくさくなりそうだなー
と思って放置していたのですが
いいやり方を思いついたのでようやく実装できます。

シートへのアクセスを減らして速度を上げることが一番簡単な手法。
今回はまずシートの情報を配列に書いて
配列の中身を書き換えて
最後に配列をシートに貼り付けます。

今まではシートの情報を取得して
計算の結果を配列に書いて
最後に配列を貼り付ける
というやり方でした。

ちょっと中途半端なやり方でしたが
シート情報を配列に入れてしまうと配列のサイズを決められてしまいます。
ふつうはそれは便利な特徴なのですが
そうなってしまうと配列の中に「隅」や「端」ができてしまいます。
それらの周囲は8マスではなくなってしまうので
計算するのに特別なやり方が必要になってしまいます。

これはまぁ書けばいいのですがちょっと大変そうだなぁ
と思って書いていませんでした。

ただ今回思いつきました。
読み込むシート情報を本来必要なものより一回り大きく読み込めばいいんです。

たとえばRange(cells(2,2),cells(9,9))の88マスを扱いたい場合は
Range(cells(1,1),cells(10,10))の10
10マスを読み込んで
実際に処理するのは8*8マス分にすれば解決します。

配列で説明すると
10*10のシート情報をStockに書き込むと
Stock(1 to 10, 1 to 10)として書き込まれます。

そしてcell_jdgでは

For i = 2 to 9
    For j = 2 to 9
        ‘処理をする
    Next
Next

みたいにすれば大丈夫です。

ただ処理の仕方も今までとは少し違うのでcell_jdgのちゃんとしたコードを載せますね。

Function cell_jdg(f_size, stock, q) As Variant()
 Dim p1 As Variant
 Dim trgt  As Range
 Dim cnt As Integer
 Dim ans() As Variant
 
 ReDim ans(1 To f_size + 2, 1 To f_size + 2)
 
'------------------------------------------------
'field内の各セルに対して
'自身と周囲の計9マスの生きているセルを数えて
'それによって生死を判定します
'生きている場合はそのセルに対応するans()に1を入れる
'------------------------------------------------
 For i = 2 To f_size + 1
    For j = 2 To f_size + 1
    
        cnt = stock(i - 1, j - 1) + stock(i - 1, j) + stock(i - 1, j + 1) + _
            stock(i, j - 1) + stock(i, j) + stock(i, j + 1) + _
            stock(i + 1, j - 1) + stock(i + 1, j) + stock(i + 1, j + 1)
            
        Select Case stock(i, j)
            Case 1
                If cnt = 3 Or cnt = 4 Then
                    ans(i, j) = 1
                End If
            Case Else
                If cnt = 3 Then
                    ans(i, j) = 1
                End If
        End Select
    
    Next j
 Next i

 cell_jdg = ans
 
End Function

これで速度がどうなるかというと。

f_size\Version Ver6_1 Ver7
30 調査終了 0.078125 調査終了0.0078125
更新終了 0.0625 更新終了0.0546875
50 調査終了 0.21875 調査終了0.0078125
更新終了 0.109375 更新終了0.109375
70 調査終了0.4208984 調査終了0.015625
更新終了0.21875 更新終了0.15625

調査時間が30倍くらい?に上がりました。
更新時間はCell_dscをいじっていないので特に変わらず。

このコーナーの初めのほうで決めた目標が100*100のセルに対して1秒間隔で画面を更新していくことでした

なんだか行けそうなので試してみますか。

調査終了0.046875
更新終了0.328125

余裕ですね笑

これにてチャレンジクリア!

。。。

というのもあっけないですね。
Ver7にケチをつけるなら
更新速度の遅さ。

7070 つまり4900マスで0.15秒
100
100 10000マスで0.32秒

これは遠からず壁が来ますね。
更新速度にこだわったVer8を作ってみましょう。

  • 更新速度を上げよう

これはシンプルなやり方がありますよね。

書き込むセル数が肝なら
それを減らせばよい。

1行の内容を1つのセルに入れてみましょう。

ただしこれを行うと欠点もあります。

セルの条件付き書式が使えなくなることと
数値以外のものを扱わねばならいことと
1つのセルに対するデータ量が増えてしまうこと。

ちなみに初期画面はこんな感じです。

“■”が生きているセル
”□”が死んでいるセル

という風に表します。

速度を測るぞ~
いまさら100*100に耐えられない仕様は論外なので
F_sizeは100で計測します。

じゃん。

調査終了 0.1411133
更新終了 0.21875

ってこれだけじゃよくわからないですね。

先ほどのVer7と比較してみると

Ver7 Ver8
調査終了0.046875 調査終了 0.1411133
更新終了0.328125 更新終了 0.21875

んー。これは。。
更新速度は速くなりましたが
調査速度が遅くなりました。
トータルではいい勝負?
ちなみにf_sizeを150にしてみると。

Ver7 Ver8_1
調査終了0.078125 調査終了0.3276367
更新終了0.722168 更新終了0.4853516

んー。

両者のいいところ悪いところがはっきり出ていますね。
これは正式にはバージョンアップできないなぁ。

  • まとめ

Ver7はVer6の意思を引き継がない形となってしまいました。
sheetの中身を配列に移すにはVariant型でないといけないらしいんですよね。

Ver8はうまいこといかなかったー
かといって悪いこともない。

Ver8_1としておきますか。

Ver7もVer8_1もいいところと悪いところがそれぞれあり
これらのいい点を統合出来たらバージョンアップということにしましょう。
ただちょっとやり方が思いつかないので
今回のライフゲームのコーナーはここまでにしましょうか。

当初の100*100はクリアしたしねっ

VBAでパフォーマンスの良いライフゲームをつくろう その4 迷走しながらもVer6まで更新

  • はじめに

さて~!!

今回はライフゲームの第4回ですね。
前回は配列をシートに模してそこにセル状態を書き込み
最後にシートに貼り付ける
という手法を取りました。

今回はVer5でできるだけforを使わない。
Ver6でデータサイズを小さくする。
を実現したいと思います。

先に言っておくと
今回はだいぶ迷走の回です。

  • ちゃちゃっとVer5

Cell_jdgをいじります。
具体的にはForを一つ外します。 現状はこう。

 For Each p1 In field
    
    Set trgt = Range(p1.Offset(-1, -1), p1.Offset(1, 1))
    cnt = 0
    
    For Each p2 In trgt
        If p2 = kigou Then
            cnt = cnt + 1
        End If
    Next p2
    
    Select Case p1.Value
        Case kigou
            If cnt = 3 Or cnt = 4 Then
                stock(p1.Row - 1, p1.Column - 1) = kigou
            End If
        Case Else
            If cnt = 3 Then
                stock(p1.Row - 1, p1.Column - 1) = kigou
            End If
    End Select
 Next p1

この中のFor Each p2 in target
の部分を書き換えます。

For Each p1 In field
    Set trgt = Range(p1.Offset(-1, -1), p1.Offset(1, 1))
    cnt = WorksheetFunction.CountIf(trgt, kigou)

    Select Case p1.Value
        Case kigou
            If cnt = 3 Or cnt = 4 Then
                stock(p1.Row - 1, p1.Column - 1) = kigou
            End If
        Case Else
            If cnt = 3 Then
                stock(p1.Row - 1, p1.Column - 1) = kigou
            End If
    End Select
    
 Next p1

ForではなくConntIfを使って調べています。
こんなちょっとした変更でも。。

f_size\Version Ver4 Ver5
30 調査終了0.1557617 調査終了0.1088867
更新終了0.078125 更新終了0.078125
50 調査終了0.3911133 調査終了0.25
更新終了0.2661133 更新終了0.28125
70 調査終了0.828125 調査終了0.53125
更新終了0.5629883 更新終了0.5170898

調査フェイズが約1.5倍になっています。
Forの回数が1/9になった恩恵ですね。
できることならFieldのForも外したいのですが。。。
まだちょっと無理そうです。

  • 本質を理解せずにつくったVer6_1

最初はstock配列やkigouをString型からInteger型にすれば速くなるでしょ!
っていう軽いノリで書きました。

今は生きているセルに"■"を打ち込んでいますが
生きているセルに1、死んでいるセルに0を打ち込むタイプ。
それがVer6_1です。

f_size\Version Ver5 ver6_1
30 調査終了0.109375 調査終了0.078125
更新終了0.125 更新終了0.0625
50 調査終了0.2646484 調査終了0.21875
更新終了0.2822266 更新終了0.109375
70 調査終了0.546875 調査終了0.4208984
更新終了0.53125 更新終了0.21875

調査時間は約1.25倍
更新時間が2倍になりました。

ただ。
もうちょっと調べているうちに
Byte型というもっと小さいものある?
とか
メモリというものを使ってあれこれしている?
ということに興味を持ったので
これを機に調べてみました。

  • 記事にしようと思ったのですが

一応調べたことをまとめたのですが
ちょっとあまりにもお粗末すぎるので
概要だけ載せますね。

仕事をするとき。
メモリは作業机の大きさ。
一度に乗りきらない場合はHDDを使うが
めちゃ速度が落ちる。
なのでメモリを大きくするか
メモリが耐えられるコードを書くことが肝?

1Byteが8bitなのはただの決め事。

VBAにはVarPtrという関数があり
自分がプロシージャ中に定義したデータが格納されているメモリ番地を教えてくれる。
ただそれの活用法はよくわからず。

VBAではDimで変数の型を決めているが
それぞれの型で確保されるメモリのサイズは違う
ので必要な分だけ定義していくのがメモリにやさしそう?

んー。
なんか言葉だけ覚えたって感じです。
これをつかってVer6_2をつくる。
などの工夫はできませんでした。

んー。
何のための章だこれは?

  • 仕方ないのでVer6_1を正式にVer6に

あ。
言い忘れていました。
Ver6ではセルへのアクセスを0と1を打ち込むことにして
配列のサイズと記述の負荷を下げているのですが
それでは視覚的によろしくないですよね。

なので条件付き書式を使いました。
1と記入されたセルを黒く塗りつぶす仕様にしました。
そしてセルに記述される文字の色を白にしました。

f:id:nozomi-hayashi:20180715190656g:plain

上の表で書いた6_1の速度はたしか1,0で回しただけなので
実際はもうちょっと遅くなるかも。。

  • まとめ

んー。。。
今回は迷走の回でした。

やろうとおもったけどできなかったーということばかり。。。

でもメモリのことをちょっぴり学んだり
データ型について考えたりする機会にはなりました。

とりあえず覚えておけば何かの役に立つかな?
最後にVer6の正式バージョンのコードを載せます。

まずはlife_game_Ver6です。

Sub life_game_Ver6(f_size, return_time, q)

 Dim field As Range
 Dim gene As Integer
 Dim time_watch As Single
 Dim stock() As Integer
'---------------------------------
'fieldの設定
'---------------------------------
 Set field = Range(Cells(2, 2), Cells(2, 2).Offset(f_size - 1, f_size - 1))
'---------------------------------
'geneは世代数を記録するためのセル
'---------------------------------
 gene = Cells(1, q + 2).Value
'-------------------------------------
'調査フェイズの計測
'-------------------------------------
 time_watch = Timer
 
    stock = cell_jdg(f_size, field, q)
 
 Debug.Print "調査終了" & Timer - time_watch
'--------------------------------------
'更新フェイズの計測
'--------------------------------------
 time_watch = Timer
    Call continue_jdg(stock, q)
    Call cell_dsc(field, stock)
 Debug.Print "更新終了" & Timer - time_watch
 '-------------------------
 '世代数を更新する
 '-------------------------
 Cells(1, q + 2).Value = gene + 1
 '---------------------------------
 'このプロシージャを頭から繰り返す
 '---------------------------------
 Application.OnTime Now() + TimeValue(return_time), _
  "'life_game_Ver6 " & f_size & ", """ & return_time & """," & q & "'"

End Sub

次にそれぞれの関数。
cell_jdg

Function cell_jdg(f_size, field, q) As Integer()
 Dim p1 As Variant
 Dim trgt  As Range
 Dim cnt As Integer
 Dim stock() As Integer
 
 ReDim stock(1 To f_size, 1 To f_size)
 
'------------------------------------------------
'field内の各セルに対して
'自身と周囲の計9マスの生きているセルを数えて
'それによって生死を判定します
'生きている場合はそのセルに対応するstockに1を入れる
'------------------------------------------------
 For Each p1 In field
    Set trgt = Range(p1.Offset(-1, -1), p1.Offset(1, 1))
    cnt = WorksheetFunction.Sum(trgt)

    Select Case p1.Value
        Case 1
            If cnt = 3 Or cnt = 4 Then
                stock(p1.Row - 1, p1.Column - 1) = 1
            End If
        Case Else
            If cnt = 3 Then
                stock(p1.Row - 1, p1.Column - 1) = 1
            End If
    End Select
    
 Next p1
 
 cell_jdg = stock
End Function

つぎはcontinue_jdg

Function continue_jdg(stock, q)
'-------------------------------
'stockがない場合
'全滅なのでstop
'-------------------------------
 'ここは今までとだいぶ違うアルゴリズムを考えているので
 '次のバージョンアップで書きます
'-------------------------------
'ループを終わらせたい場合
'cells(1,q)に何かを書き込めばstop
'-------------------------------
 If Cells(1, q) <> "" Then
    Stop
 End If
End Function

ここの処理の一部が放置しっぱなしになっていますね。。

最後がcell_dsc

Function cell_dsc(field, stock)
'-------------------------
'生存セルに1を書き込む
'-------------------------
 field = stock
End Function

基本的にバージョンアップは上位互換だと思っているので番号の低いバージョンのコードは全部消しています。
唯一Ver4_1だけは毛並みが違ったので残していますが。
でもこのブログのように低いバージョンのものも記事として残しておくと
また更新するたびにVerNの数字を上げていくと
自分の成長がはっきりと感じられていいですね。

コードを書くぐらいで成長していく今だけの楽しみかもしれませんが笑

VBAでパフォーマンスの良いライフゲームをつくろう その3 測定にてVer4を決めよう

  • はじめにの前に

見たまま編集で書いたものをMarkdownに移植させたので
もしかしたら一部変なところがあるかもです

  • はじめに

さて~!!!!
今回からようやく機能面をいじります!!

今回は特に。
次世代に生き残るセルの記録とそれを記述する箇所をいじります。
現状がVer3なのですが今回はVer4まで更新します。

  • バージョンアップについて

今までは根幹的なところをいじらなかったため一本道の更新でしたが
ここからは「考え方」が入ってくるためなかなかまっすぐは進まないです。
いくつか候補を出してそれぞれの性能を測ってそれで正式な更新版を決めていきます。
その過程は省いてもいいのかもしれませんが
せっかくなのでその試行錯誤ものせてみようと思います。

  • RangeとUnionでVer4_1

次世代に生き残るセルの記録とそれの記述。
Ver3ではどうやっているのかというと。
生き残るセルのアドレスをいったん保存して
Fieldをいったんまっさらにして
保存したアドレスのセルにひとつずつ■を書き込む。
というやり方です。

とりあえず見た目的には「ひとつずつ」というところを何とかしたいですね。
処理速度的にもおそらくですが「一気に」できたほうが速い気がしますよね。

ということでVer4_1を考えました。
生き残るセルのアドレスを保存するのではなく
生き残るセルを直接まとめて
それらに一気に書き込むというやり方。

具体的にはstockをRangeとして定義して
生き残るセルをUnionを使ってまとめていきます。
コード全体を書くのは重いのでcell_jdgとcell_dscを載せますね。
まずはcell_jdg

Function cell_jdg2(field, kigou, q) As Range
 Dim trgt As Range
 Dim p1 As Variant
 Dim p2 As Variant
 Dim cnt As Integer
 Dim stock As Range
 Dim num As Integer
 Set stock = Cells(1, q + 4)
'------------------------------------------------
'field内の各セルに対して
'自身と周囲の計9マスの生きているセルを数えて
'それによって生死を判定します
'生きている場合はそのセルをstockにunion
'------------------------------------------------
  For Each p1 In field
    Set trgt = Range(p1.Offset(-1, -1), p1.Offset(1, 1))
    cnt = 0
    For Each p2 In trgt
        If p2 = kigou Then
            cnt = cnt + 1
        End If
    Next p2
    Select Case p1.Value
        Case kigou
            If cnt = 3 Or cnt = 4 Then
                Set stock = Union(Range(p1.Address), stock)
            End If
        Case Else
            If cnt = 3 Then
                Set stock = Union(Range(p1.Address), stock)
            End If
    End Select
 Next p1
 Set cell_jdg2 = stock
End Function

つづいてcell_dsc

Function cell_dsc2(stock, kigou)
'------------------------------
'いったんシートをまっさらに
'------------------------------
 Cells.ClearContents
'-------------------------
'生存セルに■を書き込む
'-------------------------
 stock = kigou
End Function

さて。ここからがパフォーマンスの肝。
測定です。

F_size=50で計測を。

ver3 50 ver4_1 50
調査終了0.390625 調査終了0.703125
更新終了0.6259766 更新終了0.1416016
調査終了0.390625 調査終了0.6562
更新終了0.53125 更新終了0.140625

おお!
更新速度がだいぶ上がりましたね!
4倍くらい?
しかし調査速度がやけに遅い??

ver3 70 ver4_1 70
調査終了0.703125 調査終了2.391602
更新終了1.016602 更新終了0.5458984
調査終了0.75 調査終了2.25
更新終了1.052734 更新終了0.546875
Ver3 100 Ver4_1 100
調査終了1.484375 調査終了16.25
更新終了2.867188 更新終了0.34375
調査終了1.5 調査終了14.625
更新終了2.84375 更新終了0.8125

んー。F_sizeを上げてみると調査にかかる時間がネックになりますね。
ただ更新速度は比較的すばらしいのですが。。

おそらくUnionがおいしくないみたいなのでちょっとした実験を。
F_sizeを50にして
調査フェイズでUnionをする箇所をコメント化してみました。
これによってUnionの部分のみが無効になります。

その時の調査にかかった時間が0.4060059です。
これはVer3の調査時間と同程度です。

つまりUnionは時間がかかることがわかりますね。

ついでに。
配列の操作(Ver3では生存セルのアドレスを配列に記録しています)は速いこともわかります。
Ver4_1の調査フェイズでUnion部分をコメント化したものは
つまりはForの処理を回しただけのものです。
Ver3はForの処理を回してさらに配列の処理も行っています。
それにもかかわらずそれらふたつの処理速度がほとんど同じということは
配列の処理は速い。ということですよね。

あとは現在の調査フェイズのForの処理をf_size=50で回すと0.4秒はかかってしまうこともわかります。

  • 配列を貼り付けるVer4_2

Unionは遅い。
配列は速い。
その二つがわかりました。
今回できればクリアしたいことは。
生存セルの記述を「一気に」行うこと。

ということは。
配列で処理しつつ記述は一気に行う。

ができればいいのですよね。
ということでVer4_2です。
Ver3とだいたい同じなのですが。
生存セルのアドレスを保存するのではなく
Fieldとおなじサイズの配列を定義して
生存セルのアドレスと対応する箇所の配列に■を入れることにします。

。。。
説明が難しい。
Fieldの(1,1)のセルが生存する場合は
Stock(1,1)=”■”
とするということです!!

そして生存セルを記述する際にはfield = stock と書くだけでstockの状態を貼り付けることができます。

すると。。。

ver3 30 ver4_1 30 ver4_2 30
調査終了0.171875 調査終了0.15625 調査終了0.15625
更新終了0.1083984 更新終了0.046875 更新終了0.21875
調査終了0.15625 調査終了0.171875 調査終了0.1572266
更新終了0.1083984 更新終了0.0625 更新終了0.2333984
ver3 50 ver4_1 50 ver4_2 50
調査終了0.390625 調査終了0.703125 調査終了0.3916016
更新終了0.6259766 更新終了0.1416016 更新終了0.2958984
調査終了0.390625 調査終了0.6562 調査終了0.375
更新終了0.53125 更新終了0.140625 更新終了0.296875
ver3 70 ver4_1 70 ver4_2 70
調査終了0.703125 調査終了2.391602 調査終了0.7041016
更新終了1.016602 更新終了0.5458984 更新終了0.609375
調査終了0.75 調査終了2.25 調査終了0.703125
更新終了1.052734 更新終了0.546875 更新終了0.53125
Ver3 100 Ver4_1 100 Ver4_2 100
調査終了1.484375 調査終了16.25 調査終了1.469
更新終了2.867188 更新終了0.34375 更新終了0.8920002
調査終了1.5 調査終了14.625 調査終了1.452999
更新終了2.84375 更新終了0.8125 更新終了0.8610001

あらまぁびっくり!
Ver3と調査速度はほとんど変わらず更新速度を3倍にひきあげました!

それにf_sizeが70以上ではVer4_1と同程度の更新時間!
これはめちゃ強いですよ!

ただf_sizeが50以下の場合ではVer4_1の処理は優秀ですね。
これは捨てがたい魅力です。

  • まとめ

とりあえずVer4_2を正式のバージョンアップVer4としますが。
Ver4_1も捨てずに残しておきます。
何かを改善すれば最強のアルゴリズムになるかもですので。。

あ。そういえばしれっと更新した部分があります。
「initialization」のコードもVer4_2式に変更しました。
あとは「mother」にqという変数を増やしました。
世代を表示するセルなどを固定しないための変数です。
これをつけないと大事なセルがfieldに飲み込まれてしまう場合があるのです。

最後に「mother」「initialization」「life_game_ver4」のコードを載せますね。

Private Sub CmdB1_Click()
 Dim f_size As Integer
 Dim kigou As String
 Dim return_time As String
 Dim field As Range
 Dim q As Integer
'-----------------------------
'フォームの数値の読み込み
'-----------------------------
 f_size = Val(TB1)
 return_time = TB2
 kigou = TB3
'----------------------------
'fieldの設定
'----------------------------
 Set field = Range(Cells(2, 2), Cells(2, 2).Offset(f_size - 1, f_size - 1))
'---------------------------------
'qは大事なセルを指定するための数値
'---------------------------------
 q = q_jdg(f_size)
'----------------------------
'実行コードの決定
'----------------------------
 Select Case True
    Case OB1
        Call initialization(f_size, kigou, field)
    Case OB2
        Debug.Print "Ver4_1 " & f_size
        Call life_game_Ver4_1(f_size, return_time, kigou, q)
 End Select
 Unload Me
End Sub
Function q_jdg(f_size) As Integer
 Dim ans As Integer
 Do While ans < f_size
    ans = ans + 26
 Loop
 q_jdg = ans
End Function
Sub initialization(f_size, kigou, field)
 Dim p1 As Variant
 Dim stock() As String
 Cells.ClearContents
 ReDim stock(1 To f_size, 1 To f_size)
 '-----------------------------------------------------
 'fieldのセルひとつひとつに
 '一定の確率で■を入れます
 '-----------------------------------------------------
 For Each p1 In field
    If Rnd() < 0.5 Then
        stock(p1.Row - 1, p1.Column - 1) = kigou
    End If
 Next p1
 field = stock
End Sub
Sub life_game_Ver4(f_size, return_time, kigou, q)
 Dim field As Range
 Dim gene As Integer
 Dim time_watch As Single
 Dim stock() As String
'---------------------------------
'fieldの設定
'---------------------------------
 Set field = Range(Cells(2, 2), Cells(2, 2).Offset(f_size - 1, f_size - 1))
'---------------------------------
'geneは世代数を記録するためのセル
'---------------------------------
 gene = Cells(1, q + 2).Value
'-------------------------------------
'調査フェイズの計測
'-------------------------------------
 time_watch = Timer
    stock = cell_jdg(f_size, field, kigou, q)
 Debug.Print "調査終了" & Timer - time_watch
'--------------------------------------
'更新フェイズの計測
'--------------------------------------
 time_watch = Timer
    Call continue_jdg(stock, q)
    Call cell_dsc(field, stock)
 Debug.Print "更新終了" & Timer - time_watch
 '-------------------------
 '世代数を更新する
 '-------------------------
 Cells(1, q + 2).Value = gene + 1
 '---------------------------------
 'このプロシージャを頭から繰り返す
 '---------------------------------
 Application.OnTime Now() + TimeValue(return_time), _
  "'life_game_Ver4 " & f_size & ", """ & return_time & """ , """ & kigou & """," & q & "'"
End Sub
Function cell_jdg(f_size, field, kigou, q) As String()
 Dim p1 As Variant
 Dim p2 As Variant
 Dim trgt As Range
 Dim cnt As Integer
 Dim stock() As String
 ReDim stock(1 To f_size, 1 To f_size)
'------------------------------------------------
'field内の各セルに対して
'自身と周囲の計9マスの生きているセルを数えて
'それによって生死を判定します
'生きている場合はそのセルに対応するstockに■を入れる
'------------------------------------------------
 For Each p1 In field
    Set trgt = Range(p1.Offset(-1, -1), p1.Offset(1, 1))
    cnt = 0
    For Each p2 In trgt
        If p2 = kigou Then
            cnt = cnt + 1
        End If
    Next p2
    Select Case p1.Value
        Case kigou
            If cnt = 3 Or cnt = 4 Then
                stock(p1.Row - 1, p1.Column - 1) = kigou
            End If
        Case Else
            If cnt = 3 Then
                stock(p1.Row - 1, p1.Column - 1) = kigou
            End If
    End Select
 Next p1
 cell_jdg = stock
End Function
Function continue_jdg(stock, q)
'-------------------------------
'stockがない場合
'全滅なのでstop
'-------------------------------
 'ここは今までとだいぶ違うアルゴリズムを考えているので
 '次のバージョンアップで書きます
'-------------------------------
'ループを終わらせたい場合
'cells(1,q)に何かを書き込めばstop
'-------------------------------
 If Cells(1, q) <> "" Then
    Stop
 End If
End Function
 
Function cell_dsc(field, stock)
'-------------------------
'生存セルに■を書き込む
'-------------------------
 field = stock
End Function

今回は以上です。
ブログにあげるために整理している段階で気づくこともやはりいくつかありますね。

一番感じたのは速度の結果がめちゃわかりにくこと。
これは次回までに改善したいですが。。
この書式でVerまで書いてしまっていることがつらい。。。

こういう意味でも根幹の機能面ではない
いうなれば「デザイン面」は初めに整えておかないとひたすら面倒なことになります。。

ただ元の素養がないのでこうして面倒な思いをしてあげていくしかないのか。。。
よく言えば「不器用」なやりかた。
不器用に「」がつくと良いイメージがあります笑

今回はここでおわり。

VBAでパフォーマンスの良いライフゲームをつくろう その2 関数への分割とユーザーフォーム

  • はじめにの前に

この記事は以前に「見たまま」編集であげたものを「Markdown」に変更したものです。
載せているコードの見易さのために移しました。

  • はじめに  

この記事はとっくにあげていたつもりが  

あげわすれていました。  

 

あんまり本稿とは関係のない、リアルタイムとのずれの話を。  

 

ノートパソコンを買ってからは記事をワードに書いておいて時期を見計らって投稿しているのですが  

記事をストックしておくと当然ながら「今の自分」とのずれが生じますよね。  

特に今回のようなバージョンを更新していくコーナーではめちゃくちゃ違和感があります。  

明らかな「過去の自分」を発表しているような変な感覚。  

 

現在の自分はこの投稿のコードを書いた時よりは進化しているのでほんとに変な感じです。  

この投稿ではバージョンを1から3にあげるのですが  

リアルタイムではもっと更新されています。  

フリーザじゃないけどこのコードはあと5段階強くなります。。。  

 

違和感。  

 

でもそれって何かを発信するときには少なからず感じることなのかもしれませんね。  

起きてから発信するまでには時差があるので。  

 

今まではブログをその場で書いたらその場で投稿していたのであまりその違和感は感じませんでしたが  

今後はそういった感覚にも慣れないとなぁ。  

 

例えば集団で何かをしようとか、人に何かをさせようと思ったらこの違和感をより感じるでしょうしね。  

(実はさいきん、プログラミング初心者にjavaを教えて、自分の書いてほしいコードを書いてくれるマンを育てようとしているのですが、それはまた別のコーナーで。たぶん次のコーナーで書きます)  

 

  • 関数への分割  

可読性をあげるためにlife_game_Ver2の各フェイズを関数に書き換えました。  

些細なことですが、何度もコードを書き換えていく場合は細かく関数に分けておくことが吉だと思います。  

Sub life_game_Ver3()

 Dim kigou As String

 Dim f_size As Integer

 Dim field As Range

 Dim gene As Integer

 Dim time_watch As Single

 Dim stock() As String

'---------------------------------

'geneは世代数を記録するためのセル

'---------------------------------

 gene = Cells(1, 26 * 3 + 2).Value

'------------------------------

'生きているセルには■を入れます

'------------------------------

 kigou = "■"

'-----------------------------------------------------

'fieldはセルの生死判定をする領域

'f_size * f_size のセルを扱います

'-----------------------------------------------------

 f_size = 70

 Set field = Range(Cells(2, 2), Cells(2, 2).Offset(f_size - 1, f_size - 1))

'-------------------------------------

'調査フェイズの計測

'-------------------------------------

 time_watch = Timer

    stock() = cell_jdg(field, kigou)

 Debug.Print "調査終了" & Timer - time_watch

'--------------------------------------

'更新フェイズの計測

'--------------------------------------

 time_watch = Timer

    Call continue_jdg(stock)

    Call cell_dsc(stock, kigou)

 Debug.Print "更新終了" & Timer - time_watch

'-------------------------

'世代数を更新する

'-------------------------

 Cells(1, 26 * 3 + 2).Value = gene + 1

'---------------------------------

'このプロシージャを頭から繰り返す

'---------------------------------

 Application.OnTime Now() + TimeValue("0:00:02"), "life_game_Ver3"

End Sub

続いてそれぞれの関数です。  

まずはcell_jdg。  

これは各セルの次世代の状態を判定する関数です。  

内容はVer2と同じです。  

Function cell_jdg(field, kigou) As String()

 Dim trgt As Range

 Dim p1 As Variant

 Dim p2 As Variant

 Dim cnt As Integer

 Dim stock() As String

 Dim num As Integer

 num = 0

 ReDim stock(num)

'------------------------------------------------

'field内の各セルに対して

'自身と周囲の計9マスの生きているセルを数えて

'それによって生死を判定します

'生きている場合はそのセルのアドレスをstockに保存

'------------------------------------------------

 For Each p1 In field

    Set trgt = Range(p1.Offset(-1, -1), p1.Offset(1, 1))

    cnt = 0

    For Each p2 In trgt

        If p2 = kigou Then

            cnt = cnt + 1

        End If

    Next p2

    Select Case p1.Value

        Case kigou

            If cnt = 3 Or cnt = 4 Then

                ReDim Preserve stock(num)

                stock(num) = p1.Address

                num = num + 1

            End If

        Case Else

            If cnt = 3 Then

                ReDim Preserve stock(num)

                stock(num) = p1.Address

                num = num + 1

            End If

    End Select

 Next p1

 cell_jdg = stock

End Function

次はcontinue_jdg。  

繰り返し処理を行うかを決めます。  

 

Function continue_jdg(stock)

'-------------------------------

'stockがない場合

'全滅なのでstop

'-------------------------------

 If stock(0) = "" Then

    Stop

 End If

'-------------------------------

'ループを終わらせたい場合

'cells(1,52)に何かを書き込めばstop

'-------------------------------

 If Cells(1, 26 * 3) <> "" Then

    Stop

 End If

End Function

最後がcell_dsc。  

次世代に生存するセルを記述します。  

Function cell_dsc(stock, kigou)

 Dim p1 As Variant

'------------------------------

'いったんシートをまっさらに

'------------------------------

 Cells.ClearContents

'-------------------------

'生存セルに■を書き込む

'-------------------------

 For Each p1 In stock

    Range(p1) = kigou

 Next p1

End Function

はい。  

これで関数への分割が終わりました。  

ただこれだけでVer3に更新というのも味気がないので  

もう一つ追加というか整理をします。  

  • ユーザーフォームによる変数の指定  

今使っているコードは「initialization」と「life_game_verN」のふたつです。  

現状ではf_sizeを変更するためにはそれぞれのコード内のf_sizeを書き換えないといけないので面倒くさいです。  

ほかにも何かの変数の中身を変えたい場合に二度手間になってしまうのは情けない。  

なのでそれらをまとめて管理するコードを書きます。  

見やすさを重視したいのでユーザーフォームを作りましょう。  

ユーザーフォームは「中学数学」のコーナーでだいぶ慣れた気がします。  

 

ユーザーフォームの名前は「mother」にします。  

自分なりのコードネーム?をいろいろ使うのにあこがれています笑  

ユーザーフォームの見た目はこんな感じ。  

 

f:id:nozomi-hayashi:20180711200613g:plain

 

今回は水色系にしてみました。  

 

せっかくなのでf_sizeだけでなく  

kigouとreturn_timeもここで指定します。  

return_timeはOnTimeに入れる値です。  

ここで何秒おきに繰り返すかも指定します。  

 

続いてユーザーフォームのコードを。  

Private Sub CmdB1_Click()

 Dim f_size As Integer

 Dim kigou As String

 Dim return_time As String

 Dim field As Range

'-----------------------------

'フォームの数値の読み込み

'-----------------------------

 f_size = Val(TB1)

 return_time = TB2

 kigou = TB3

'----------------------------

'fieldの設定

'----------------------------

 Set field = Range(Cells(2, 2), Cells(2, 2).Offset(f_size - 1, f_size - 1))

'----------------------------

'実行コードの決定

'----------------------------

 Select Case True

    Case OB1

        Call initialization(f_size, kigou, field)

    Case OB2

        Call life_game_Ver3(f_size, return_time, kigou)

 End Select

End Sub

当然ですがこれによって「initialization」と「life_gae_VerN」の中身も少し変わります。  

 

Sub initialization(f_size, kigou, field)

 Dim p1 As Variant

 Cells.ClearContents

 '-----------------------------------------------------

 'fieldのセルひとつひとつに

 '一定の確率で■を入れます

 '-----------------------------------------------------

 For Each p1 In field

    If Rnd() < 0.5 Then

        Range(p1.Address) = kigou

    End If

 Next p1

End Sub

life_game_VerNのほうは。。。  

Sub life_game_Ver3(f_size, return_time, kigou)

 Dim field As Range

 Dim gene As Integer

 Dim time_watch As Single

 Dim stock() As String

'---------------------------------

'fieldの設定

'---------------------------------

 Set field = Range(Cells(2, 2), Cells(2, 2).Offset(f_size - 1, f_size - 1))

'---------------------------------

'geneは世代数を記録するためのセル

'---------------------------------

 gene = Cells(1, 26 * 3 + 2).Value

'-------------------------------------

'調査フェイズの計測

'-------------------------------------

 time_watch = Timer

    stock() = cell_jdg(field, kigou)

 Debug.Print "調査終了" & Timer - time_watch

'--------------------------------------

'更新フェイズの計測

'--------------------------------------

 time_watch = Timer

    Call continue_jdg(stock)

    Call cell_dsc(stock, kigou)

 Debug.Print "更新終了" & Timer - time_watch

'-------------------------

'世代数を更新する

'-------------------------

 Cells(1, 26 * 3 + 2).Value = gene + 1

'---------------------------------

'このプロシージャを頭から繰り返す

'---------------------------------

 Application.OnTime Now() + TimeValue(return_time), _

  "'life_game_Ver3 """ & f_size & """, """ & return_time & """ , """ & kigou & """'"

End Sub

こんな感じです。  

 

これでユーザーフォームでいくつかの変数を扱えます。  

各プロシージャで定義する必要がなくなったのでコードの見た目もすっきりしました。  

Ver3はここまで。  

 

本当はVer1でこのくらいのレベルまで行ってもいいはずなのですが。  

二度もバージョンアップしたのにまだ体裁の面しかいじれていない。。  

まだまだ修行不足ですね。  

 

  • まとめ  

実はこの記事を書く前にVer2の機能面を変更したVer3とVer4を書いたのですが  

速度を測る際にあちこちのコード内の数字をいじって走らせることにストレスを感じたのでこのVer3をはさむことにしました。  

 

なので実はVer4とVer5もすでにできているのですが  

記事に書くのは次回になりそうです。。  

もうVer6とVer7での変更点も決めているのに。。  

 

これはプログラミングうんぬんよりは計画性の問題な気がします。  

もう少しまともになろう。  

 

VBAでパフォーマンスの良いライフゲームをつくろう! その1 概要とver2まで

  • はじめにの前に
    この記事は以前に「見たまま」編集であげたものを「Markdown」に変更したものです。
    コードのみやすさのために移しました。

  • はじめに  

こんにちはー。  

じつは。。。。  

 

ノートパソコン買いました!!!  

 

いえい。  

これからはパソコンでブログの記事が書けます。  

今までは基本ケータイで書いていて  

プログラミングのコードを載せたりしたいときはネカフェでやっていました。  

そのせいで投稿のスパンがぶれぶれでしたが。。  

 

これからは定期的に更新していこうと思います。  

 

あと自前のpcを入手したことでjavaやcにも触れられるようになりました。  

どちらも勉強中です!  

もうちょっとしたらjavaでのプログラミングもブログに書きたいなと思います。  

 

とりあえず今回は慣れ親しんでいるVBAで。  

 

今回はだいぶ古典的ですがライフゲームのプログラミングについて。  

今回は特にパフォーマンスを上げることをテーマにやります。  

 

とりあえずどういうプログラムをかけばよいのかを確認。  

 

各セルについて次世代に  

生存するか  

死滅するか  

誕生するか  

 

を調べてそれを可視化すればいいのですよね。  

 

やり方はいろいろあるでしょうがとりあえず直感的にコードを書きました。  

 

Sub life_game_Ver1()

 Dim field As Range

 Dim f_size As Integer

 Dim trgt As Range

 Dim p1 As Variant

 Dim p2 As Variant

 Dim cnt As Integer

 Dim stock() As String

 Dim num As Integer

 Dim kigou As String

 '------------------------------

 '生きているセルには■を入れます

 '------------------------------

 kigou = "■"

 '-----------------------------------------------------

 'fieldはセルの生死判定をする領域

 'f_size * f_size のセルを扱います

 '-----------------------------------------------------

 f_size = 30

 Set field = Range(Cells(2, 2), Cells(2, 2).Offset(f_size - 1, f_size - 1))

 '-----------------------------------------------------

 'numはstockをredimするための数字

 'stockには次世代に生存しているセルのアドレスを入れます

 'その生死判定がこの先

 '-----------------------------------------------------

 num = 0

 ReDim stock(num)

 '-----------------------------------------------------

 '生死判定の概要を書きます

 'fieldのセルをひとつずつ取り出す

 'その周囲8マスと自身をtrgtとして指定

 'trgtに■がいくつ入っているか調べる

 '■のサイズで現段階での自身の生死で次世代の生死を判定

 '生存する場合はそのセルのアドレスをstockに保存

 '以上です!

 '-----------------------------------------------------

 For Each p1 In field

    Set trgt = Range(p1.Offset(-1, -1), p1.Offset(1, 1))

    cnt = 0

    For Each p2 In trgt

        If p2 = kigou Then

            cnt = cnt + 1

        End If

    Next p2

    Select Case p1.Value

        Case kigou

            If cnt = 3 Or cnt = 4 Then

                ReDim Preserve stock(num)

                stock(num) = p1.Address

                num = num + 1

            End If

        Case Else

            If cnt = 3 Then

                ReDim Preserve stock(num)

                stock(num) = p1.Address

                num = num + 1

            End If

    End Select

 Next p1

'-------------------------------

'stockがない場合

'全滅なので終了

'-------------------------------

 If stock(0) = "" Then

    Exit Sub

 End If

'-------------------------------

'ループを終わらせたい場合

'cells(1,52)に何かを書き込めばstop

'-------------------------------

 If Cells(1, 52) <> "" Then

    Stop

 End If

 '------------------------------

 'いったんシートをまっさらに

 '------------------------------

 Cells.ClearContents

 '-------------------------

 '生存セルに■を書き込む

 '-------------------------

 For Each p1 In stock

    Range(p1) = kigou

 Next p1

 '---------------------------------

 'このプロシージャを頭から繰り返す

 '時間はこのコードが読まれた2秒後

 '---------------------------------

  Application.OnTime Now() + TimeValue("0:00:02"), "life_game_Ver1"

End Sub

 

とりあえず動作は確認できました。  

このコードの概要は。。。  

 

Fieldのセルひとつひとつについて  

周囲8マスと自身の合計9マスの■の数を数える  

それによって次世代の状態を調べる  

次世代に生きている場合はそのセルのアドレスをstockに保存  

Fieldの全セルについて調べ終わったら  

いったんシートをまっさらにしてから  

Stockに入っているアドレスに■を書き込む  

もしも書き込む先がない場合は全滅なので終了  

 

という感じです。  

このVer1をどうにかしてパフォーマンスを上げていくのが今回やることです。  

  • その前に・・・  

ライフゲームはある状態のfieldに対して処理をするものです。  

そのために「ある状態」というものをつくるコードもつくらねば。  

Sub initialization()

 Dim field As Range

 Dim f_size As Integer

 Dim p1 As Variant

 Dim kigou As String

 Cells.ClearContents

 kigou = "■"

 f_size = 30

 Set field = Range(Cells(2, 2), Cells(2, 2).Offset(f_size - 1, f_size - 1))

 '-----------------------------------------------------

 'fieldのセルひとつひとつに

 '一定の確率で■を入れます

 '-----------------------------------------------------

 For Each p1 In field

    If Rnd() < 0.5 Then

        Range(p1.Address) = kigou

    End If

 Next p1

End Sub

これでfieldの各セルに対して50%の確率で■が書き込まれます。  

life_game_ver1を一部書き換えてつくりました。  

今後はこれで形成された初期状態に対してlife_game_verNのパフォーマンスを調べていきます。  

 

  • パフォーマンスとは? 数値で評価するための更新Ver2  

本題に戻ります。  

Ver1をちょっと評価してみますか。。  

 

とりあえず感覚としては。。  

毎回セルがまっさらになるせいで、そのセルが生存したのか誕生したのか死滅したのかがわからない。  

世代が更新されるまでの時間が一定にならない(おそらく処理が重いせい)。

という感じです。  

 

んー。  

感覚的です。  

 

感覚も大事なのですが  

もう少し数値を使ってパフォーマンスを評価したいですね。  

 

そのためのいくつかの機能を加えましょう。  

 

Sub life_game_Ver2()

 Dim field As Range

 Dim f_size As Integer

 Dim trgt As Range

 Dim p1 As Variant

 Dim p2 As Variant

 Dim cnt As Integer

 Dim stock() As String

 Dim num As Integer

 Dim kigou As String

 Dim gene As Integer

 gene = Cells(1, 26 * 3 + 2).Value

 Dim time_watch As Single

 time_watch = Timer

 '------------------------------

 '生きているセルには■を入れます

 '------------------------------

 kigou = "■"

 '-----------------------------------------------------

 'fieldはセルの生死判定をする領域

 'f_size * f_size のセルを扱います

 '-----------------------------------------------------

 f_size = 70

 Set field = Range(Cells(2, 2), Cells(2, 2).Offset(f_size - 1, f_size - 1))

 'Debug.Print "ver2 " & f_size

 '-----------------------------------------------------

 'numはstockをredimするための数字

 'stockには次世代に生存しているセルのアドレスを入れます

 '-----------------------------------------------------

 num = 0

 ReDim stock(num)

 '-----------------------------------------------------

 '生死判定の概要を書きます

 'fieldのセルをひとつずつ取り出す

 'その周囲8マスと自身をtrgtとして指定

 'trgtに■がいくつ入っているか調べる

 '■のサイズで現段階での自身の生死で次世代の生死を判定

 '生存する場合はそのセルのアドレスをstockに保存

 '以上です!

 '-----------------------------------------------------

 For Each p1 In field

    Set trgt = Range(p1.Offset(-1, -1), p1.Offset(1, 1))

    cnt = 0

    For Each p2 In trgt

        If p2 = kigou Then

            cnt = cnt + 1

        End If

    Next p2

    Select Case p1.Value

        Case kigou

            If cnt = 3 Or cnt = 4 Then

                ReDim Preserve stock(num)

                stock(num) = p1.Address

                num = num + 1

            End If

        Case Else

            If cnt = 3 Then

                ReDim Preserve stock(num)

                stock(num) = p1.Address

                num = num + 1

            End If

    End Select

 Next p1

 Debug.Print "調査終了" & Timer - time_watch

 time_watch = Timer

'-------------------------------

'stockがない場合

'全滅なので終了

'-------------------------------

 If stock(0) = "" Then

    Exit Sub

 End If

'-------------------------------

'ループを終わらせたい場合

'cells(1,52)に何かを書き込めばstop

'-------------------------------

 If Cells(1, 26 * 3) <> "" Then

    Stop

 End If

 '------------------------------

 'いったんシートをまっさらに

 '------------------------------

 Cells.ClearContents

 '-------------------------

 '生存セルに■を書き込む

 '-------------------------

 For Each p1 In stock

    Range(p1) = kigou

 Next p1

 Debug.Print "更新終了" & Timer - time_watch

 '-------------------------

 '世代数を更新する

 '-------------------------

 Cells(1, 26 * 3 + 2).Value = gene + 1

 '---------------------------------

 'このプロシージャを頭から繰り返す

 '時間はこのコードが読まれた1秒後

 '---------------------------------

  Application.OnTime Now() + TimeValue("0:00:3"), "life_game_Ver2"

End Sub

さきほど言ったようにVer2はVer1にいくつかの機能を足したものです。  

以下詳細。  

 

世代数のカウンターと処理時間の計測機能を足しました。  

すべてのセルについて生死確認する段階を調査フェイズ。  

そこから指定のセルの生存を表現する段階を更新フェイズ。  

としました。

 

調査終了0.15625  

更新終了0.046875  

調査終了0.15625  

更新終了0.046875  

調査終了0.15625  

更新終了0.0625  

 

蓄積したデータの一部です。  

ちなみに今回は320世代で停滞しました。  

停滞とは世代を経てもセルの生死が変わらない状態です。  

もう一回試してみたら今度は90世代で停滞したので  

あるフィールドサイズに対する停滞するまでの世代数はかなりばらつきがあるみたい。  

 

とりあえずこれで。  

フィールドサイズ  

プログラムを繰り返す秒数  

世代数  

各フェイズにかかる時間  

が分かるようになったのでパフォーマンスをはかれるようになりました。  

 

現状は30*30のフィールドで1秒おきに繰り返す仕様にすら耐えられていません。  

これを何とかしていくのがこれからやるべきことです。  

 

更新フェイズと調査フェイズを合わせても0.2秒かからないのに  

OnTimeの値を1秒にするとカクカクしてしまうのはなぜなのだろう。。。  

 

  • まとめ  

今回はここまでです。  

次回はVer3とVer4について書くつもりです。  

じつはそれらはもう作っています。  

ただ記事にできていないので少々お待ちを。。  

更新は際限がなさそうなので  

100*100のフィールドで1秒おきにカクカクせずに各セルの状態がどう変わったのが見てわかる仕様をつくること。   

を目標にしますか。  

 

ではではー。  

(番外編)Markdown方式で書いてみる プログラミングのコードをいい感じに見せたい

最近デザインに悩むことが多いです。 デザインというかもっと大きなものかな。

そう。伝え方に。

中身がどうあるかとそれをどう表現するかの二軸があると思います。 その中でも特に表現方法。

自分は今までそれを怠ってきたのでそのツケが回ってきている段階です。

自分のブログの記事ってみにくいなぁ。

そう思うことが多くて
またそう思うとやる気をなくすんですよね。。

これは一生付きまとう問題だと思うので
苦しみ続けていないでなんとかしないとなぁ。

というのが今回の記事のテーマ。

実はちょっと前に「ブログをカスタマイズしよう!」のチャレンジ企画に挑戦したのですが
そのときにできたのはブログテーマとスタイルシートをちょびっといじるだけでした。

今回はもうちょっと踏み込みます。

今まではスマホで記事を書いていたのでこういったことに億劫になっていましたが
ノートパソコン買ったし!の熱が冷める前に蒸気で上昇します笑

自分は今まで特になにも考えることもなく
選ぶまでもなく「見たまま」モードで記事を書いていました。
でもはてなブログにはもうふたつモードがあるんですよね。
はてなブログ方式」と「Markdown」がね。

なんーとなく直感で今回はMarkdownを使ってみることにしました。

Markdownマークアップ言語の一種らしいです。
マークアップ言語は文章の見た目と構造を記述する言語みたいです。

なんか。
デザインにあからさまに向いていますね笑

デザインに悩んでる~とかいってもそんなのどこの階層にいっても同じなので
今回は課題をひとつこなしましょう。
最近よくプログラミングのコードを載せているのですが
めちゃ見にくいのでそれを何とかしますか。

じゃあ適当にコードを載せますね。
いつものやり方で。

Sub initialization_old(f_size, kigou, field)
Dim p1 As Variant
Dim stock() As String
Cells.ClearContents
ReDim stock(1 To f_size, 1 To f_size)
'-----------------------------------------------------
'fieldのセルひとつひとつに
'一定の確率で■を入れます
'-----------------------------------------------------
For Each p1 In field
If Rnd() < 0.5 Then
stock(p1.Row - 1, p1.Column - 1) = kigou
End If
Next p1
field = stock
End Sub

わぁ。
Markdownだと編集の見た目も変わるんですね~
みたまま編集ってそういうことだったのか。。

ちょっと編集者にしかわからないこと言っちゃいました笑

<span style="color: #F5A2A2"><span style="font-size: 80%">

文字のサイズと色を変えていたのですが
Markdownでは上のような呪文が現れました。

上のような呪文を呪文として書くためにも
また別の呪文を使いました。

あれ
というか
いい感じに四角に囲まれていますね。

ちょっと使ってみよ。

Sub initialization_old(f_size, kigou, field)  
 Dim p1 As Variant  
 Dim stock() As String  
 Cells.ClearContents  
 ReDim stock(1 To f_size, 1 To f_size)  
 '-----------------------------------------------------  
 'fieldのセルひとつひとつに  
 '一定の確率で■を入れます  
 '-----------------------------------------------------  
 For Each p1 In field  
    If Rnd() < 0.5 Then  
        stock(p1.Row - 1, p1.Column - 1) = kigou  
    End If  
 Next p1  
 field = stock  
End Sub  

およよ
これでもうよくない?笑

いきなりクリアしてまったか?

これはpre記法というもので
囲うことが目的ではないみたいなので
もうちょっと勉強しましょう

ほいさっ

おぉ。強調も楽~

ほいさっさっ

ふむ。
アスタリスクでもストロングタグでも強調ができるらしい。

Sub initialization_old(f_size, kigou, field)
 Dim p1 As Variant
 Dim stock() As String
 Cells.ClearContents
 ReDim stock(1 To f_size, 1 To f_size)
 '-----------------------------------------------------
 'fieldのセルひとつひとつに
 '一定の確率で■を入れます
 '-----------------------------------------------------
 For Each p1 In field
    If Rnd() < 0.5 Then
        stock(p1.Row - 1, p1.Column - 1) = kigou
    End If
 Next p1
 field = stock
End Sub

お!
とうとつにできてまった笑
なるほどね。
VBAに限らずJavaでもCでも
きれいにコードを載せている人ってめちゃ色を変えまくっているのかと思っていたけど
シンタックス・ハイライトなるものを使っていたようです!

public class main(){
    public static void test001(args[]){
        System.out.println("Hello");
    }
}
#include<stdio.h>
  int main() {
    printf("hello\n");
  }

javaとcで適当に書いてみたけどあっているかな?笑
そうかー
超かんたんじゃん

うん。
なんとなくつかみました。

さんきゅー

今まで見出しってほぼ一回も使ってこなかったのですが
これからはもうちょっと使います。。

そうかー
ここでまたCSSへと進んでいくのか
前にCSSを調べたときは

見出し?

んなもんいつつかうんねん!

そんなのいいからリストだけいじるで!

とスルーしましたが
これだけ簡単に使えるなら使う価値ありですね

うん。
こんかいはここまで
ありがとう
Markdownマジ神!