前回の記事
の補足
上下左右ループ
前々回
前々回ではループさせていなかったので端に行くと消えたり詰まったりしていた
前回
赤枠が全体マップ
黒枠が11番のセルの周囲を探索するときの範囲
セルa,b,cはマップ外なので探査しても無意味になる
左右をつなげるには、それぞれ10,15,20が入るようになっていればいい
こうなっていればいいので
右側を左側の外にコピペで
左側が右側に繋がったことになる
上下左右コピペ
後の四隅は対角
例えば表示用がこんな状態のとき探査用のシートは
右のようになっているので
次の世代には
1番に誕生して5番が生存維持になる
ループなしだと全滅
こんな感じでループするようにしたんだけど
1ターンに9回もコピペを繰り返しているのが遅くなっている原因かなあ
探査用のシートを使わないで配列変数を使えば少し早くなるはずなんだけど
ほとんど書き直すことになっちゃうなあ
コード全部
Function NextGeneration() As Long
Application.ScreenUpdating = False
Call CopyAtoB
Dim mA As Range
Set mA = Range("mapA")
Dim cc As Long, rc As Long, lifeCount As Long
rc = mA.Rows.Count
cc = mA.Columns.Count
Dim lifeLower As Long, lifeUpper As Long, lifeBirth As Long
lifeLower = Range("下限").Value
lifeUpper = Range("上限").Value
lifeBirth = Range("誕生").Value
Dim ci As Long
Dim sr As Long
For x = 1 To rc
For y = 1 To cc
Dim rA As Range, rB As Range
Set rA = Range("mapA").Cells(x, y)
Set rB = Range("mapB").Cells(x, y)
ci = rB.Interior.ColorIndex
sr = SearchCell(rB)
If ci = xlColorIndexNone Then
If sr = lifeBirth Then
lifeCount = lifeCount + 1
rA.Interior.ColorIndex = 1
End If
Else
If (sr >= lifeLower And sr <= lifeUpper) Then
lifeCount = lifeCount + 1
Call Nuri2(rA, rB)
Else
rA.Interior.ColorIndex = xlColorIndexNone
rB.Value = 0
End If
End If
Next y
Next
NextGeneration = lifeCount
Application.ScreenUpdating = True
End Function
Sub NuriBlack(r As Range)
r.Interior.ColorIndex = 1
End Sub
Sub Nuri2(rA As Range, rB As Range)
rB.Value = rB.Value + 64
If rB.Value > 255 Then rB.Value = 255
rA.Interior.Color = rB.Value
End Sub
Function SearchCell(r As Range) As Long
Dim c As Long
For y = -1 To 1
For x = -1 To 1
If r.Offset(x, y).Interior.ColorIndex <> xlColorIndexNone Then
If Not (x = 0 And y = 0) Then
c = c + 1
End If
End If
Next
Next
SearchCell = c
End Function
Sub initial初期配置()
Dim r As Range
Set r = Range("mapA")
r.Interior.ColorIndex = xlColorIndexNone
Dim rr As Range
For Each rr In r
Randomize
If Rnd < Range("liferacio").Value Then
rr.Interior.ColorIndex = 1
End If
Next
Range("lifecount").Value = GetLifeCount生存数カウント
Range("mapB").ClearContents
End Sub
Function GetLifeCount生存数カウント() As Long
Dim r As Range
Dim life As Long
For Each r In Range("mapA")
If r.Interior.ColorIndex <> xlColorIndexNone Then
life = life + 1
End If
Next
GetLifeCount生存数カウント = life
End Function
Sub ClearColor()
Worksheets("lifegameA").Activate
Range("mapA").Interior.ColorIndex = xlColorIndexNone
Range("mapB").ClearContents
End Sub
Sub CopyAtoB()
Range("mapA").Copy
Range("mapB").PasteSpecial xlPasteFormats
Dim r As Range, rr As Range
Set r = Range("mapB")
Dim rc As Long, cc As Long
rc = r.Rows.Count
cc = r.Columns.Count
r.Rows(1).Copy r.Rows(rc + 1)
r.Rows(rc).Copy r.Rows(0)
r.Columns(1).Copy r.Columns(cc + 1)
r.Columns(cc).Copy r.Columns(0)
r.Cells(1, 1).Copy r.Cells(rc + 1, cc + 1)
Set rr = r.Cells(1, 1).Offset(-1, -1)
r.Cells(rc, cc).Copy rr
Set rr = r.Cells(rc, 1).Offset(1, -1)
r.Cells(1, cc).Copy rr
Set rr = r.Cells(1, cc).Offset(-1, 1)
r.Cells(rc, 1).Copy rr
End Sub
Sub ChangeMapRangeマップの範囲変更()
If TypeName(Selection) <> "Range" Then Exit Sub
If Selection.Areas.Count > 1 Then
MsgBox "複数の選択範囲は選べない"
Exit Sub
End If
If MsgBox("選択範囲をライフゲームの範囲に変更します", vbYesNo) = vbYes Then
Dim rA As Range, rB As Range
Set rA = Range("mapA")
rA.ClearFormats
Set rA = Selection
rA.Name = "mapA"
rA.Borders.Color = RGB(200, 200, 200)
rA.BorderAround , xlThin, 3
Worksheets("lifegameA").Calculate
Set rB = Range("mapB")
Set rB = rB.Offset(-1, -1)
Set rB = rB.Resize(rB.Rows.Count + 2, rB.Columns.Count + 2)
rB.Clear
Worksheets("lifegameB").Range(rA.Address).Name = "mapB"
Set rB = Range("mapB")
rB.BorderAround , xlThin
End If
End Sub
Sub AutoNext()
Dim t As Long
t = Range("ターン数").Value
Dim lifeArray() As Long
ReDim lifeArray(t)
lifeArray(0) = GetLifeCount生存数カウント
Dim ti As String
ti = Range("ターン間隔").Value
Dim lifeC As Long
For i = 0 To t - 1
lifeC = NextGeneration
Range("nowtrun").Value = i + 1
Range("lifecount").Value = lifeC
lifeArray(i + 1) = lifeC
If lifeC = 0 Then Exit For
If ti = "最速" Then
Application.Wait [now() + "0:00:00.01"]
ElseIf ti = "0.1秒" Then
Application.Wait [now() + "0:00:00.1"]
ElseIf ti = "0.5秒" Then
Application.Wait [now() + "0:00:00.5"]
ElseIf ti = "1秒" Then
Application.Wait [now() + "0:00:01"]
Else
Application.Wait [now() + "0:00:00.5"]
End If
DoEvents
Next
Call ChangeChart(lifeArray)
End Sub
Sub ChangeChart(Lifes() As Long)
Range("lifelog").Offset(1, 0).ClearContents
Dim lc As Long
lc = UBound(Lifes)
Dim cc As Long
cc = Range("mapA").Cells.Count
Dim Density() As Single, Density2 As Variant
ReDim Density(lc)
For j = 0 To UBound(Density)
Density(j) = Lifes(j) / cc
Next
Dim Lifes2 As Variant
Lifes2 = Application.WorksheetFunction.Transpose(Lifes)
Dim r As Range
Set r = Range("lifelog").Resize(lc + 1, 1).Offset(1, 1)
r.Value = Lifes2
Dim rr As Range
Set rr = r.Offset(0, -1)
Density2 = Application.WorksheetFunction.Transpose(Density)
rr.Value = Density2
ActiveSheet.Calculate
End Sub
ボタンとマクロの対応
名前を付けたセル範囲
こういう一覧を作るマクロが
↓
Sub rangeName()
Dim n As Names
Set n = ActiveWorkbook.Names
Dim v() As Variant
ReDim v(n.Count, 1)
v(0, 1) = "参照範囲"
v(0, 0) = "名前"
Dim str As String
For i = 1 To n.Count
str = n.Item(i).Value
str = Right(str, Len(str) - 1)
v(i, 1) = str
v(i, 0) = n.Item(i).Name
Next
ActiveCell.Resize(UBound(v) + 1, 2).Select
If MsgBox("選択範囲に書き込んでもいい?", vbYesNo) = vbNo Then Exit Sub
Selection.Value = v
End Sub
続きは2日後