我差不多完成了一个程序,但在我完成它之前,我需要找到一个bug的原因。虽然我的本能是提供我认为可能导致问题的部分,但我已经复制了下面的整个程序。毕竟,如果我对问题所在的地方是对的,我现在可能已经能够找到它,而且我已经知道人们希望尽可能多地继续下去。事实上,经过几个小时,我能做的最好的事情是更严密地定义错误!
预期成果: 一个贯穿整个计划涉及到:
Merc01-Merc04
按此顺序,然后调用
Merc05-Merc09
或只是
Merc10
(在特殊任务的情况下)。
最后,在每种情况下,
Merc11
应该叫。问题在于,在30个大约1个案例中,这个预期的序列正在破裂。在正确执行Merc09和Merc11之后,控制将返回到Merc07,而不是停止,然后Merc08-Merc09和Merc11正常运行。我没有找到为什么会这样。一个(其他)特性是,如果程序在第一次传递时执行了Merc10,则不会出现此错误。关于在哪里寻找我难以捉摸的bug的任何建议都将不胜感激。
Option Explicit
Dim ArmOfService As Byte
Dim Bottom
Dim CharacterNumber As Long
Dim CurrentTerm As Byte
Dim DecorationRollMade As Byte
Dim DecorationRollNeeded As Byte
Dim DiceSize As Byte
Dim GenAssignment
Dim GenAssignmentSwitchInt As Byte
Dim GenAssignmentSwitchOff As Byte
Dim iLoopControl
Dim jLoopControl
Dim kLoopControl
Dim LeftCol
Dim LineIncrement As Integer
Dim lLoopControl
Dim Merc(100)
Dim NoOfDice As Byte
Dim OfficerPromotion(63 To 78) As Byte
Dim PromotionRollMade As Byte
Dim PromotionRollNeeded As Byte
Dim Rank
Dim Roll As Byte
Dim SkillColumn
Dim SkillRollMade As Integer
Dim SkillRollNeeded As Integer
Dim SpecAssignmentSwitchEnd As Byte
Dim SurvivalRollMade As Byte
Dim SurvivalRollNeeded As Byte
Dim TechLevel As Byte
Dim Temp, Temp2, Temp3, Temp4, Temp5
Dim Term As Byte
Dim TestCount
Dim Top
Dim UnitAssignment
Dim WhichTable
Dim XTrainedArm
Dim Year As Byte
'UDF to roll a number of Dice of specified size and total them
Function Dice(NoOfDice, DiceSize)
For iLoopControl = 1 To NoOfDice
Dice = Dice + WorksheetFunction.RandBetween(1, DiceSize)
Next
End Function
'UDF to generate a skill from the MOS Table
Function MOSSkill(ArmOfService, TechLevel)
Roll = Dice(1, 6)
If TechLevel = 2 Then Roll = Roll + 1 'TL-11 or less = 1; TL-12+ = 2
MOSSkill = WorksheetFunction.VLookup((WorksheetFunction.VLookup(Roll, (Range(Cells(4, 2), Cells(10, 8))), ArmOfService, False)), (Range(Cells(9, 32), Cells(39, 33))), 2, False)
End Function
'UDF to generate a skill from the Skill Tables
Function SixTables(SkillColumn, Rank)
Roll = Dice(1, 6)
SixTables = WorksheetFunction.VLookup((WorksheetFunction.VLookup(Roll + RankDMs(WhichTable, Rank), (Range("SKILL_TABLES")), SkillColumn, False)), (Range("Skills_Lookup")), 2, False)
End Function
'UDF to lookup DMs on Skills_Tables_DMs table
Function RankDMs(WhichTable, Rank)
Debug.Print "Which Table "; WhichTable, ""
RankDMs = WorksheetFunction.HLookup(WhichTable, (Range(Cells(11, 38), Cells(31, 41))), (Rank + 1), False)
End Function
'UDF to read skills from the six 't' tables (marked in pale blue and less pale blue on worksheet)
Function tSpecTables(Top, Bottom, LeftCol, lLoopControl)
Temp3 = Cells(lLoopControl, LeftCol + 1)
tSpecTables = WorksheetFunction.VLookup(Temp3, Range("Skills_Lookup"), 2, False)
End Function
Sub MainOne()
'This is the 'main' Sub, providing the flow control and decision making structure for the rest,
'which are organised as other subs
Randomize
'Loop back to this point to begin generation of a new character
'NOTE: Replace this with a proper loop structure
CharacterNumber = CharacterNumber + 1
Call Merc01
'Clear and initialise arrays and variables
Call Merc02
'Handles the roll up of UPP, enlistment and first year of service
'There is NO Merc03()!!
Debug.Print
Debug.Print "Char No "; Merc(100)
Debug.Print "<Call04"
Call Merc04
'Generate General Assignment
If GenAssignment <> "Special" Then
Debug.Print "<Call05"
Call Merc05
'Determine Unit Assignment
Debug.Print "<Call06"
Call Merc06
'Resolve Unit Assignment - Survival
Debug.Print "<Call07"
Call Merc07
'Resolve Unit Assignment - Decoration
Debug.Print "<Call08"
Call Merc08
'Resolve Unit Assignment - Promotion
Debug.Print "<Call09"
Call Merc09
'Resolve Unit Assignment - Skills
Else 'If Special Assignment
Debug.Print "<Call10"
Call Merc10
'Generate Special Assignment
If Year = 4 Then 'End of term procedure
' To be replaced by a proper control structure
End If
End If
'Year = Year + 1
Debug.Print "<Call11"
Call Merc11
'DISPLAY BLOCK'
End Sub
Sub Merc01()
'Clear and initialise arrays and variables
For iLoopControl = 1 To 100
Merc(iLoopControl) = 0
Next
For iLoopControl = 63 To 78
OfficerPromotion(iLoopControl) = 0
Next
'NOTE: Check that only those variablea that need to be initialised are, and that THEY all are
ArmOfService = 0
GenAssignment = 0
Merc(98) = 1
SpecAssignmentSwitchEnd = 0
TechLevel = 0
Term = 1
Year = 1
End Sub
Sub Merc02()
'Handles the roll up of UPP, enlistment and first year of service
'Generate a character's UPP and allocate it as both current and original scores
For jLoopControl = 1 To 6
Merc(jLoopControl) = Dice(2, 6)
Merc(jLoopControl + 56) = Merc(jLoopControl)
TestCount = TestCount + 1 'Test
Next
'Insert Character No. in array
Merc(100) = CharacterNumber
'Generate Tech Level 12+ and insert in array?
TechLevel = Dice(1, 2) '1-Tech Level 11 or less, 2-Tech Level 12+
Merc(80) = TechLevel
'Roll to enlist in the Army
Roll = Dice(2, 6)
If Merc(2) >= 6 Then Roll = Roll + 1
If Merc(3) >= 5 Then Roll = Roll + 2
If Roll < 5 Then Call MainOne
'Basic Training - Gun Cmbt
Merc(22) = 1
'Generate Arm of Service
ArmOfService = Dice(1, 4) '2-Art, 3-Cav, 4-Inf, 6-Spt, [7-Com]
If ArmOfService = 4 Then
ArmOfService = ArmOfService + 2
Else: ArmOfService = ArmOfService + 1
End If
Merc(63) = ArmOfService 'Record ArmOfService for first term
'Advanced Training
Temp = MOSSkill(ArmOfService, TechLevel)
Merc(Temp) = Merc(Temp) + 1
End Sub
Sub Merc04()
'Generate General Assignment
Roll = Dice(1, 6)
If Merc(4) >= 8 And GenAssignmentSwitchInt = 1 Then Roll = Roll + 1
If Merc(98) >= 11 And GenAssignmentSwitchOff = 1 Then Roll = Roll - 1
GenAssignment = WorksheetFunction.VLookup(Roll, (Range(Cells(14, 2), Cells(21, 8))), ArmOfService, True)
Merc(79) = GenAssignment
'Arrange this on the GUI so that either Int or Off are selectable, not both
End Sub
Sub Merc05()
'Determine Unit Assignment
Roll = Dice(2, 6)
UnitAssignment = WorksheetFunction.VLookup(Roll, (Range(Cells(26, 2), Cells(36, 8))), ArmOfService, False)
Merc(81) = UnitAssignment
End Sub
Sub Merc06()
'Resolve Unit Assignment - Survival
' Find roll needed for survival
Roll = Dice(2, 6)
LineIncrement = ArmOfService - 5
If LineIncrement < 0 Then LineIncrement = 0
SurvivalRollNeeded = WorksheetFunction.HLookup(UnitAssignment, Range(Cells(23 + (LineIncrement * 7), 10), Cells(24 + (LineIncrement * 7), 16)), 2, False)
' Make survival roll
SurvivalRollMade = Dice(2, 6)
If ArmOfService = 2 And (Merc(14) > 1 Or Merc(16) > 1 Or Merc(18) > 1 Or Merc(20) > 1 Or Merc(28) > 1 Or Merc(36) > 1) Then SurvivalRollMade = SurvivalRollMade + 1
If ArmOfService = 3 And (Merc(14) > 1 Or Merc(24) > 1 Or Merc(28) > 1 Or Merc(36) > 1) Then SurvivalRollMade = SurvivalRollMade + 1
If ArmOfService = 4 And (Merc(22) > 1 Or Merc(24) > 1 Or Merc(30) > 1 Or Merc(35) > 1 Or Merc(36) > 1) Then SurvivalRollMade = SurvivalRollMade + 1
If ArmOfService = 6 And (Merc(12) > 1 Or Merc(14) > 1 Or Merc(16) > 1 Or Merc(28) > 1 Or Merc(29) > 1 Or Merc(36) > 1) Then SurvivalRollMade = SurvivalRollMade + 1
If ArmOfService = 7 And (Merc(8) > 1 Or Merc(15) > 1 Or Merc(22) > 1 Or Merc(24) > 1 Or Merc(30) > 1 Or Merc(33) > 1) Then SurvivalRollMade = SurvivalRollMade + 1
If Cells(85, 28) <> Cells(84, 28) Then Cells(86, 28) = 999 'Test that a MOS 2+ DM has been made
'Award Purple Heart if wounded
If SurvivalRollMade = SurvivalRollNeeded Then Merc(84) = Merc(84) + 1
'Check for KIA
If SurvivalRollMade < SurvivalRollNeeded Then Call MainOne 'Replace GoTo with something more elegant (probably a Do While on ALIVE=YES AND RETIRED=NO)
End Sub
Sub Merc07()
'Resolve Unit Assignment - Decoration
DecorationRollMade = Dice(2, 6)
LineIncrement = ArmOfService - 5
If LineIncrement < 0 Then LineIncrement = 0
DecorationRollNeeded = WorksheetFunction.HLookup(UnitAssignment, Range(Cells(23 + (LineIncrement * 7), 10), Cells(25 + (LineIncrement * 7), 16)), 3, False)
If (DecorationRollMade >= (DecorationRollNeeded + 6)) Then Merc(87) = Merc(87) + 1 'Check for award of SEH
If (DecorationRollMade >= (DecorationRollNeeded + 3)) And (DecorationRollMade < (DecorationRollNeeded + 6)) Then Merc(86) = Merc(86) + 1 'Check for award of MCG
If (DecorationRollMade >= DecorationRollNeeded) And (DecorationRollMade < (DecorationRollNeeded + 3)) Then Merc(85) = Merc(85) + 1 'Check for award of MCUF
End Sub
Sub Merc08()
'Resolve Unit Assignment - Promotion
PromotionRollMade = Dice(2, 6)
PromotionRollNeeded = WorksheetFunction.HLookup(UnitAssignment, Range(Cells(23 + (LineIncrement * 7), 10), Cells(26 + (LineIncrement * 7), 16)), 4, False)
If (ArmOfService < 5 And Merc(5) >= 7) Then PromotionRollMade = PromotionRollMade + 1 '+1 DM for Inf, Cav, Art
If (ArmOfService = 6 And Merc(4) >= 8) Then PromotionRollMade = PromotionRollMade + 1 '+1 DM for Support
If (ArmOfService = 7 And Merc(3) >= 8) Then PromotionRollMade = PromotionRollMade + 1 '+1 DM for Commandos
If PromotionRollMade >= PromotionRollNeeded Then
If Merc(98) < 9 Then Merc(98) = Merc(98) + 1
If (Merc(98) > 10 And OfficerPromotion(Term + 62) = 0) And (UnitAssignment <> "Training" And UnitAssignment <> "Int Sec" And UnitAssignment <> "Garrison") Then
Merc(98) = Merc(98) + 1
OfficerPromotion(Term + 62) = 1 'Set Officer Promotion Flag
End If
End If
'Merc(98) = 2 'Test
End Sub
Sub Merc09()
'Resolve Unit Assignment - Skills
'SKILL CHECK
SkillRollMade = Dice(2, 6)
LineIncrement = ArmOfService - 5
If LineIncrement < 0 Then LineIncrement = 0
SkillRollNeeded = WorksheetFunction.HLookup(UnitAssignment, Range(Cells(23 + (LineIncrement * 7), 10), Cells(27 + (LineIncrement * 7), 16)), 5, False)
Debug.Print "Made"; SkillRollMade, "Needed"; SkillRollNeeded, "AoS"; ArmOfService, "Mission "; UnitAssignment, "*"; GenAssignment 'Test
If SkillRollMade >= SkillRollNeeded Then
'Which skill table
WhichTable = WorksheetFunction.VLookup(Merc(98), Range(Cells(5, 39), Cells(8, 45)), Dice(1, 6) + 1, True)
Select Case WhichTable
Case "MOS Skills"
Temp = MOSSkill(ArmOfService, TechLevel)
Merc(Temp) = Merc(Temp) + 1
Debug.Print "Temp(MOS): "; Temp,
Debug.Print
Case "Army Life"
SkillColumn = 2
Rank = Merc(98)
Temp = SixTables(SkillColumn, Rank)
Merc(Temp) = Merc(Temp) + 1
Debug.Print "Temp(Army): "; Temp,
Debug.Print
Case "NCO Skills"
SkillColumn = 4
Rank = Merc(98)
Temp = SixTables(SkillColumn, Rank)
Merc(Temp) = Merc(Temp) + 1
Debug.Print "Temp(NCO): "; Temp,
Debug.Print
Case "Officer Skills"
If GenAssignment = "Command" Then SkillColumn = 5 Else SkillColumn = 6
Rank = Merc(98)
Temp = SixTables(SkillColumn, Rank)
Merc(Temp) = Merc(Temp) + 1
Debug.Print "Temp(Officer): "; Temp,
Debug.Print
Case Else
End Select
End If 'completed skill check and continue onto next part of the year's resolution
End Sub
Sub Merc10()
'Generate Special Assignment
Merc(98) = 1 'Test
' Special Assignment - Enlisted men and NCOs
If Merc(98) < 10 Then
Roll = Dice(1, 6)
'If Merc(3) >= 7 And SpecAssignmentSwitchEnd = 1 Then Roll = Roll + 1
Select Case Roll
Case 1: Call CrossTraining
Case 2: Call SpecSchool
Case 3: Call CommandoSchool
Case 4: Call ProtForces
Case 5: Call Recruiting
Case 6 To 7: Call OCS
End Select
Else
'Special Assignment - Officers
Roll = Dice(1, 6)
Select Case Roll
Case 1: Call IntSchool
Case 2: Call CommandCollege
Case 3: Call StaffCollege
Case 4: Call CommandoSchool
Case 5: Call Recruiting
Case 6: Call AttacheAide
End Select
End If
End Sub
Sub Merc11()
'DISPLAY BLOCK'
'Display all of Merc array in the worksheet
For kLoopControl = 1 To 100
Cells(kLoopControl + 2, 34) = Merc(kLoopControl)
Next
End Sub
Sub AttacheAide()
Debug.Print "AttacheAide"
Merc(6) = Merc(6) + 1 '+1 Social
Roll = Dice(1, 6)
If Roll <= 4 Then
'Military Attache
Merc(45) = Merc(45) + 1 'Count Special Assignment
Merc(84) = Merc(84) + 1 'Automatic Promotion
Else
'General's Aide - [TO DO] WORK OUT Benefit of choosing next appointment
Merc(42) = Merc(42) + 1 'Count Special Assignment
End If
'xx
End Sub
Sub CommandCollege()
Debug.Print "CommandCollege"
'Check for Instructor assignment
'Merc(38) = 1 'Test
'Merc(27) = 2 'Test
If Merc(38) > 0 And (Merc(34) >= 2 Or Merc(27) >= 2 Or Merc(30) >= 2) Then
Merc(39) = Merc(39) + 1
Merc(25) = Merc(25) + 1
Else
If Dice(1, 6) >= 4 Then Merc(27) = Merc(27) + 1
If Dice(1, 6) >= 4 Then Merc(30) = Merc(30) + 1
If Dice(1, 6) >= 4 Then Merc(34) = Merc(34) + 1
Merc(38) = Merc(38) + 1 'Count Special Assignment
End If
End Sub
Sub CommandoSchool()
Debug.Print "CommandoSchool"
'Check for Instructor assignment
'Merc(9) = 2 'Test
'Merc(40) = 1 'Test
If Merc(40) > 0 And (Merc(9) > 1 Or Merc(10) > 1 Or Merc(15) > 1 Or Merc(22) > 1 Or Merc(25) > 1 Or Merc(30) > 1 Or Merc(33) > 1 Or Merc(35) > 1) Then
Merc(41) = Merc(41) + 1
Merc(25) = Merc(25) + 1
Else
If Dice(1, 6) >= 5 Then Merc(9) = Merc(9) + 1
If Dice(1, 6) >= 5 Then Merc(10) = Merc(10) + 1
If Dice(1, 6) >= 5 Then Merc(15) = Merc(15) + 1
If Dice(1, 6) >= 5 Then Merc(22) = Merc(22) + 1
If Dice(1, 6) >= 5 Then Merc(25) = Merc(25) + 1
If Dice(1, 6) >= 5 Then Merc(30) = Merc(30) + 1
If Dice(1, 6) >= 5 Then Merc(33) = Merc(33) + 1
If Dice(1, 6) >= 5 Then Merc(35) = Merc(35) + 1
Merc(40) = Merc(40) + 1 'Count Special Assignment
End If
End Sub
Sub CrossTraining()
Debug.Print "CrossTraining"
'Select Arm of Service for X-training
Do
XTrainedArm = Dice(1, 4)
If XTrainedArm = 4 Then XTrainedArm = 6 Else XTrainedArm = XTrainedArm + 1 '2-Art, 3-Cav, 4-Inf, 6-Spt
Loop Until XTrainedArm <> ArmOfService
'Generate skill gained from X-Training
Temp = MOSSkill(XTrainedArm, TechLevel)
Merc(Temp) = Merc(Temp) + 1
'Increment attendance
If XTrainedArm = 6 Then XTrainedArm = 4 Else XTrainedArm = XTrainedArm - 1
Merc(52 + XTrainedArm) = Merc(52 + XTrainedArm) + 1
End Sub
Sub IntSchool()
Debug.Print "IntSchool"
'Check for Instructor assignment
If Merc(43) > 0 And (Merc(11) > 1 Or Merc(19) > 1 Or Merc(26) > 1 Or Merc(32) > 1) Then
Merc(44) = Merc(44) + 1
Merc(25) = Merc(25) + 1
Else
'Generate skills
If Dice(1, 6) >= 4 Then Merc(11) = Merc(11) + 1
If Dice(1, 6) >= 4 Then Merc(19) = Merc(19) + 1
If Dice(1, 6) >= 4 Then Merc(26) = Merc(26) + 1
If Dice(1, 6) >= 4 Then Merc(32) = Merc(32) + 1
Merc(43) = Merc(43) + 1 'Count Special Assignment
End If
End Sub
Sub OCS()
''Commission as 2nd Lt
Debug.Print "OCS"
Merc(98) = 11
''Generate one MOS skill
Temp = MOSSkill(ArmOfService, TechLevel)
Merc(Temp) = Merc(Temp) + 1
''Generate one Staff Skill
Select Case Dice(1, 6)
Case 1: Merc(13) = Merc(13) + 1
Case 2: Merc(16) = Merc(16) + 1
Case 3: Merc(20) = Merc(20) + 1
Case 4: Merc(25) = Merc(25) + 1
Case 5: Merc(28) = Merc(28) + 1
Case 6: Merc(29) = Merc(29) + 1
End Select
''Generate one Command Skill
Select Case Dice(1, 6)
Case 1: Merc(3) = Merc(3) + 1
Case 2: Merc(22) = Merc(22) + 1
Case 3: Merc(24) = Merc(24) + 1
Case 4: Merc(27) = Merc(27) + 1
Case 5: Merc(34) = Merc(34) + 1
Case 6: Merc(36) = Merc(36) + 1
End Select
End Sub
Sub ProtForces()
Debug.Print "ProtForces"
'Check for Instructor assignment
If Merc(46) > 0 And (Merc(35) > 1 Or Merc(37) > 1) Then
Merc(47) = Merc(47) + 1
Merc(25) = Merc(25) + 1
Else
'Generate skills
If Dice(1, 6) >= 3 Then Merc(35) = Merc(35) + 1
If Dice(1, 6) >= 3 Then Merc(37) = Merc(37) + 1
Merc(46) = Merc(46) + 1 'Count Special Assignment
End If
End Sub
'
Sub Recruiting()
Debug.Print "Recruiting"
Merc(31) = Merc(31) + 1
Merc(48) = Merc(48) + 1 'Count Special Assignment
End Sub
Sub SpecSchool()
Debug.Print "SpecSchool"
'Check for Instructor assignment
If Merc(49) > 0 And (Merc(7) > 1 Or Merc(13) > 1 Or Merc(14) > 1 Or Merc(16) > 1 Or Merc(28) > 1 Or Merc(29) > 1) Then
Merc(50) = Merc(50) + 1 'Increment Spec School*
Merc(25) = Merc(25) + 1 'Instructor skill
Else
'Generate skills
Select Case Dice(1, 6)
Case 1: Merc(7) = Merc(7) + 1
Case 2: Merc(13) = Merc(13) + 1
Case 3: Merc(14) = Merc(14) + 1
Case 4: Merc(16) = Merc(16) + 1
Case 5: Merc(28) = Merc(28) + 1
Case 6: Merc(29) = Merc(29) + 1
End Select
Merc(49) = Merc(49) + 1 'Count Special Assignment
End If
End Sub
Sub StaffCollege()
Debug.Print "StaffCollege"
'Check for Instructor assignment
If Merc(51) > 0 And (Merc(7) > 1 Or Merc(12) > 1 Or Merc(14) > 1) Then
Merc(52) = Merc(52) + 1
Merc(25) = Merc(25) + 1
Else
'Generate skills
If Dice(1, 6) >= 4 Then Merc(7) = Merc(7) + 1
If Dice(1, 6) >= 4 Then Merc(12) = Merc(12) + 1
If Dice(1, 6) >= 4 Then Merc(14) = Merc(14) + 1
Merc(51) = Merc(51) + 1 'Count Special Assignment
End If
End Sub
答案 0 :(得分:1)
Merc02
和Merc06
在某些情况下都会调用MainOne
。我不认为这会产生你想要的行为
如果我们从调用MainOne
的{{1}}开始(调用此#1),而Merc02
又调用MainOne
(称之为#2),我们现在有两个单独版本的{ {1}}。当MainOne
#2完成后,控件会返回MainOne
(从Merc02
行开始),然后最终返回Merc(22) = 1
#1(在MainOne
#1后面的行呼叫Merc02
,在调试之后,调用Merc04
)
由于大多数控制是通过模块级变量完成的,MainOne
#1最终使用MainOne
#2完成时留下的值。具体来说,我们不会调用Merc01
将变量重置回其初始状态
不要从MainOne
和Merc02
内部调用Merc06
,而是考虑将这两者都变成函数。如果我们需要重置内容,请从函数返回False
并让MainOne
自行排序。
MainOne
:
Dim goodToContinue As Boolean
CharacterNumber = CharacterNumber + 1
goodToContinue = False
Do
'Clear and initialise arrays and variables
Merc01
'Handles the roll up of UPP, enlistment and first year of service
goodToContinue = Merc02
Loop Until (goodToContinue)
(您可以直接测试Merc02
的返回值,但我使用了一个单独的变量来使事情更清晰。不需要Call
)
在Merc02
中,我们会改变:
Sub Merc02()
' other stuff
If Roll < 5 Then Call MainOne
' more stuff
End Sub
为:
Function Merc02() As Boolean
' other stuff
If Roll < 5 Then
Merc02 = False
Exit Function
End If
' more stuff
Merc02 = True
End Function
Merc06
的逻辑更复杂(正如您在代码中的注释中所指出的那样)但使用Function的想法,返回True或False以及MainOne
中的控件结构来处理事情仍然是一样的