我喜欢的“游戏”旨意问题,因为你宣布自己“超级新VBA”,我认为它可以帮助你的你的初始代码如下重构
Option Explicit
Sub clue()
Dim can As Long, dag As Long, lead As Long, rev As Long, rop As Long, wre As Long, row As Long
Dim weapon As String
Dim roomsRng As Range, areaRng As Range, roomsReportRng As Range, finalStatsRng As Range, leastStatsRng As Range ' these are useful range variable. you'll set them and use to avoid loosing control over what you're actually handling
' here follows a section dedicated to setting relevant "ranges". this helps a lot in avoiding loosing control over what you're actually handling
With ActiveSheet 'always explicitly qualify which worksheet do you want to work with. "ActiveSheet" is the currently active one, but you may want to qualify 'Worksheets("MySheetName")'
Set roomsRng = .Range("A1:A" & .cells(.Rows.Count, 1).End(xlUp).row) 'set roomsRng range as the one collecting activesheet cells in column "A" down to the last non empty one
Set roomsRng = roomsRng.SpecialCells(xlCellTypeConstants, xlTextValues) 'select only non blank cells of "roomsRng" range (skip blanks)
Set roomsReportRng = .cells(1, 3) ' set the range you start writing rooms report from
Set finalStatsRng = .Range("F2") ' set the range you'll start writing final stats from
Set leastStatsRng = .Range("E10") ' set the range you'll write the least found weapon number in
End With
For Each areaRng In roomsRng.Areas 'loop through all "Areas" of "roomsRng" range cells: an "Area" is a group of contiguous cells
Call WriteRoomsReport(areaRng.cells, roomsReportRng, row, weapon) 'write room report
Call UpdateWeaponsStats(weapon, can, dag, lead, rev, rop, wre) ' update weapons statistics
Next areaRng
Call WriteFinalStats(can, dag, lead, rev, rop, wre, finalStatsRng, leastStatsRng) ' write final statistics
End Sub
Sub WriteRoomsReport(roomCells As Range, reportCell As Range, row As Long, weapon As String)
Dim arr As Variant 'it'll be used as an array, see below
arr = Application.Transpose(roomCells) 'initialize the Variant as an array, filling it up with "roomCells" range content
reportCell.Offset(row).Value = arr(1) & " in the " & arr(2) & " with the " & arr(3) & "." 'write the report line
weapon = arr(3) ' store the weapon value to pass back to calling sub
row = row + 1 'update the row for subsequent use
End Sub
Sub UpdateWeaponsStats(weapon As String, can As Long, dag As Long, lead As Long, rev As Long, rop As Long, wre As Long)
' use "Select Case" pattern to avoid multiple and unuesful If-then repetition
' once a "case" is hit, its correspondant statements will be processed and then control passes to the statement following the "End Select" one
Select Case weapon
Case "Candlestick"
can = can + 1
Case Is = "Dagger"
dag = dag + 1
Case "Lead Pipe"
lead = lead + 1
Case Is = "Revolver"
rev = rev + 1
Case "Rope"
rop = rop + 1
Case Is = "Wrench"
wre = wre + 1
End Select
End Sub
Sub WriteFinalStats(can As Long, dag As Long, lead As Long, rev As Long, rop As Long, wre As Long, finalStatsRng As Range, leastStatsRng As Range)
Dim total As Long, least As Long
Dim weaponArr As Variant
total = can + dag + lead + rev + rop + wre
weaponArr = Array(can, dag, lead, rev, rop, wre)
With finalStatsRng.Resize(6) ' select a range of 6 cells in one clolumn, starting from the passed "finalStatsRng" range and resizing it up to enclose the subsequent 5 cells below it
.Value = Application.Transpose(weaponArr) ' fill the selected range (using ".Value" property of the "Range" object) with the "array" technique
With .Offset(, 1) ' shift one column to the right of selected range
.FormulaR1C1 = "=RC[-1]/" & total ' write in all cells a formula that takes the value form the adjacent cell and divide it by the "total" variable value
.Value = .Value ' have formulas replaced with values. you can comment this and cells will remain with formulas (they show the resulting values, but if you select one of them you'll see a formula in the formula ribbon of Excel UI
End With
End With
leastStatsRng.Value = Application.WorksheetFunction.Min(weaponArr) 'get the minimum value of all passed values calling the "MIN" function (which belongs to "WorksheetFuncion" object of the "Application" object -Excel) over the array filled with weapon countings
End Sub
上面的代码图案具有以下目标:
断点代码到特定功能或潜艇
让您更好地控制代码的流动,通过“main”子(这应该是一个像“Call DoThis()”,“Call DoThat()”等语句的序列)并专注于特定的潜艇/函数来处理特定的工作
从而导致更容易维护和“可调试”代码
只使用一些(出许多)有关VBA和Excel VBA技术,如使用Range
对象(参见Resize()
,Offset()
,End()
,SpecialCells()
方法),数组(通过Variant
类型变量),WorksheetFunction
对象。
当然你需要研究所有这些技术(和其他许多技术!)利用这些资源为SO本身,MSDN网站(https://msdn.microsoft.com/en-us/library/office/ee861528.aspx)和许多其他你轻松搞定在网页只是谷歌上搜索一个显著问题
为最终(和悲伤)的说明,我必须提醒你:建设游戏是最终导致“真正的”OOP的东西,就像VBA不是。
应该“建设游戏”是你的真正目的,那么你最好立即切换到一些真正的面向对象的语言,如C#和记者IDE,如Visual Studio(其社区版的版本目前是免费的)
定义行作为长数据类型'Dim row As Long'将解决它。 – newguy
在模块的最顶端添加'Option Explicit' - 你已经声明'can'可以作为一个变体并且为'cam'设置一个值。 –