Option Explicit
'************************************************************************
'
'This code was developed by Andrew Fergus on 18 October 2006
'and finally modified on December 11th 2006 after much procrastination
'in response to this question on MrExcel:
'http://www.mrexcel.com/board2/viewtopic.php?t=238026
'
'************************************************************************
Public Sub SolvePuzzle()
Dim Answers(8) As Integer, _
Values(9, 2) As Integer, _
Finished(4) As Boolean, _
Outcome(4) As Integer, _
OuterLoop As Integer, _
InnerLoop As Integer, _
Loop1 As Integer, _
Loop2 As Integer, _
Loop3 As Integer, _
Loop4 As Integer, _
LoopLimit As Integer, _
RowCounter As Integer, _
TempVar1 As Integer, _
TempVar2 As Double
'Values variable:
' holds the values 0 through 9
' dimension 0 is used to hold the value
' dimension 1 is used to hold the used value (where 1 = used, 0 = unused)
' dimension 2 holds how many times this value is used as a factor
'Initialise variables
'Get the 5 starting values
Outcome(0) = Range("C3").Value
Outcome(1) = Range("C2").Value
Outcome(2) = Range("D3").Value
Outcome(3) = Range("C4").Value
Outcome(4) = Range("B3").Value
'Clear the target area
Range("G1:J15").ClearContents
'Set the headings
Range("G1") = "BDFH Possibles"
'Set the array starting values
For Loop1 = 0 To 9
Values(Loop1, 0) = Loop1 'the value
Values(Loop1, 1) = 0 'not used
Values(Loop1, 2) = 0 'no factors (yet)
Next
'Set initial answers to zero
For Loop1 = 0 To 8
Answers(Loop1) = 0
Next
If Outcome(0) = 0 Then
'There is not a unique answer
MsgBox "The middle value cannot be zero. Please try other numbers", vbCritical, "Error"
Exit Sub
ElseIf Outcome(0) = 6 Then
'BDFH is the minima (0,1,2,3)
Range("G2") = 0
Range("H2") = 1
Range("I2") = 2
Range("J2") = 3
LoopLimit = 2
ElseIf Outcome(0) = 30 Then
'BDFH is the maxima (6,7,8,9)
Range("G2") = 6
Range("H2") = 7
Range("I2") = 8
Range("J2") = 9
LoopLimit = 2
Else
'Find the possible combinations of values for positions BDFH
LoopLimit = GetBDFH(Outcome(0))
End If
'Get all possible factors for the other 4 outcomes
For OuterLoop = 1 To 4
If Outcome(OuterLoop) = 0 Then
For Loop1 = 0 To 9
Values(Loop1, 2) = Values(Loop1, 2) + 1
Next
Else
For Loop1 = 1 To 9
If Outcome(OuterLoop) Mod Loop1 = 0 Then
Values(Loop1, 2) = Values(Loop1, 2) + 1
End If
Next
End If
Next
'Remove the BDFH combinations that include non-existent factors
'and seek instances where there are two products that equal zero
For Loop1 = 0 To 9
If Values(Loop1, 2) = 0 Then
'This digit is not used
For Loop2 = 2 To LoopLimit
If Range("G" & Loop2).Value = Loop1 _
Or Range("H" & Loop2).Value = Loop1 _
Or Range("I" & Loop2).Value = Loop1 _
Or Range("J" & Loop2).Value = Loop1 Then
'Delete this row of BDFH possibles - it cannot be used
Range("G" & Loop2 & ":J" & Loop2).Delete Shift:=xlShiftUp
'But we need to retest the row that now occupies the row deleted
LoopLimit = LoopLimit - 1
Loop2 = Loop2 - 1
End If
Next
Else
If Loop1 = 0 Then
If Values(0, 2) > 1 Then
MsgBox "There is more than one result. Try other numbers", vbCritical, "Error"
Exit Sub
End If
End If
End If
Next
For OuterLoop = 2 To LoopLimit
'Loop through all combinations of BDFH
'Get the starting values around Outcome(0)
Answers(2) = Range("G" & OuterLoop).Value
Answers(4) = Range("H" & OuterLoop).Value
Answers(6) = Range("I" & OuterLoop).Value
Answers(8) = Range("J" & OuterLoop).Value
For Loop2 = 1 To 4
'Loop through the 4 corner values (around BDFH)
If Loop2 > 1 Then
'Rotate the values around Outcome(0)
Answers(0) = Answers(8)
For Loop1 = 8 To 2 Step -2
Answers(Loop1) = Answers(Loop1 - 2)
Next
End If
For Loop3 = 1 To 6
If Loop3 > 1 Then
'Rotate the last 3 values around Outcome(0), but fix the lowest value
Select Case Loop2
Case 1
If Loop3 Mod 2 = 0 Then
'Mod and case used to decide which pair of digits to swap
Answers(0) = Answers(8)
Answers(8) = Answers(6)
Answers(6) = Answers(0)
Else
Answers(0) = Answers(6)
Answers(6) = Answers(4)
Answers(4) = Answers(0)
End If
Case 2
If Loop3 Mod 2 = 0 Then
Answers(0) = Answers(8)
Answers(8) = Answers(6)
Answers(6) = Answers(0)
Else
Answers(0) = Answers(6)
Answers(6) = Answers(2)
Answers(2) = Answers(0)
End If
Case 3
If Loop3 Mod 2 = 0 Then
Answers(0) = Answers(8)
Answers(8) = Answers(4)
Answers(4) = Answers(0)
Else
Answers(0) = Answers(4)
Answers(4) = Answers(2)
Answers(2) = Answers(0)
End If
Case Else
If Loop3 Mod 2 = 0 Then
Answers(0) = Answers(6)
Answers(6) = Answers(4)
Answers(4) = Answers(0)
Else
Answers(0) = Answers(4)
Answers(4) = Answers(2)
Answers(2) = Answers(0)
End If
End Select
End If
'Reset variables
For Loop1 = 0 To 9
Values(Loop1, 1) = 0
Next
For Loop1 = 1 To 4
Values(Answers(Loop1 * 2), 1) = 1
Next
Answers(1) = 0
Answers(3) = 0
Answers(5) = 0
Answers(7) = 0
For Loop1 = 1 To 4
Finished(Loop1) = False
Next
'Set the 4 product values
'Check the first outcome
If Outcome(1) = 0 Then
TempVar2 = 0
Else
'Calculate the factor
TempVar2 = Outcome(1) / (Answers(2) * Answers(8))
End If
If TempVar2 < 10 And Int(TempVar2) = TempVar2 Then
'This is a possible factor (integer < 9)
If Values(TempVar2, 1) = 0 Then
'This value has not been used yet
Values(TempVar2, 1) = 1
Answers(1) = TempVar2
Finished(1) = True
Else
'This value has already been used
Finished(1) = False
'No point testing the other 3 products
GoTo Skip_To_Here
End If
Else
'This is not a valid factor
Finished(1) = False
'No point testing the other 3 products
GoTo Skip_To_Here
End If
'Check 2nd outcome
If Outcome(2) = 0 Then
TempVar2 = 0
Else
TempVar2 = Outcome(2) / (Answers(2) * Answers(4))
End If
If TempVar2 < 10 And Int(TempVar2) = TempVar2 Then
If Values(TempVar2, 1) = 0 Then
Values(TempVar2, 1) = 1
Answers(3) = TempVar2
Finished(2) = True
Else
Finished(2) = False
GoTo Skip_To_Here
End If
Else
Finished(2) = False
GoTo Skip_To_Here
End If
'Check 3rd outcome
If Outcome(3) = 0 Then
TempVar2 = 0
Else
TempVar2 = Outcome(3) / (Answers(4) * Answers(6))
End If
If TempVar2 < 10 And Int(TempVar2) = TempVar2 Then
If Values(TempVar2, 1) = 0 Then
Values(TempVar2, 1) = 1
Answers(5) = TempVar2
Finished(3) = True
Else
Finished(3) = False
GoTo Skip_To_Here
End If
Else
Finished(3) = False
GoTo Skip_To_Here
End If
'Check 4th outcome
If Outcome(4) = 0 Then
TempVar2 = 0
Else
TempVar2 = Outcome(4) / (Answers(6) * Answers(8))
End If
If TempVar2 < 10 And Int(TempVar2) = TempVar2 Then
If Values(TempVar2, 1) = 0 Then
Values(TempVar2, 1) = 1
Answers(7) = TempVar2
Finished(4) = True
Else
Finished(4) = False
End If
Else
Finished(4) = False
End If
Skip_To_Here:
If Finished(1) = True And Finished(2) = True And Finished(3) = True And Finished(4) = True Then
GoTo JumpOut 'Yes I know this is sloppy but hey it works!
End If
Next
Next
Next
'If the code has ended up here it has looped through every combination
MsgBox "Answer not found"
Range("C1").Value = "?"
Range("D2").Value = "?"
Range("E3").Value = "?"
Range("D4").Value = "?"
Range("C5").Value = "?"
Range("B4").Value = "?"
Range("A3").Value = "?"
Range("B2").Value = "?"
Exit Sub
'If a combination is found then the loop jumps out to here
JumpOut:
'Display the answers
Range("C1").Value = Answers(1)
Range("D2").Value = Answers(2)
Range("E3").Value = Answers(3)
Range("D4").Value = Answers(4)
Range("C5").Value = Answers(5)
Range("B4").Value = Answers(6)
Range("A3").Value = Answers(7)
Range("B2").Value = Answers(8)
MsgBox "Finished", vbInformation, "Done"
End Sub
Private Function GetBDFH(Outcome As Integer) As Integer
Dim RowCounter As Integer, _
Loop1 As Integer, _
Loop2 As Integer, _
Loop3 As Integer, _
Loop4 As Integer
RowCounter = 2
For Loop1 = 1 To 5
For Loop2 = (Loop1 + 1) To 6
For Loop3 = (Loop2 + 1) To 7
For Loop4 = (Loop3 + 1) To 9
If Loop1 + Loop2 + Loop3 + Loop4 = Outcome Then
Range("G" & RowCounter) = Loop1
Range("H" & RowCounter) = Loop2
Range("I" & RowCounter) = Loop3
Range("J" & RowCounter) = Loop4
RowCounter = RowCounter + 1
End If
Next
Next
Next
Next
GetBDFH = RowCounter - 1
End Function