Function par(ByVal scores As Range, Optional ByVal delta As Integer = 10)
' scores is the range of cells containing the scores
' delta is the smallest difference between scores
On Error GoTo par_error
If scores.Count = 1 Then ' dispose of trivial case
par = scores.Value
Exit Function
End If
Dim data
data = scores ' read range into array, for efficiency
Debug.Assert IsArray(data)
Dim par1 As Integer, par2 As Integer
Dim sum1 As Integer, sum2 As Integer
' set initial values to bracket the par value
par2 = 8000
par1 = -par2
sum2 = scores.Count
sum1 = -sum2
While par2 - par1 > delta
par = delta * Fix((par1 + par2) / (2 * delta))
Dim sum As Integer, i As Integer, j As Integer
sum = 0
' calculate the net sum of imp scores against par
' imp_() is a function to calculate the IMP scale
For i = LBound(data, 1) To UBound(data, 1)
For j = LBound(data, 2) To UBound(data, 2)
sum = sum + imp_(par - data(i, j))
Next j
Next i
If sum = 0 Then Exit Function
' if we haven't found par, adjust the bracket
If sum < 0 Then
par1 = par
sum1 = sum
Else
par2 = par
sum2 = sum
End If
' check we haven't lost the plot!
Debug.Assert par1 < par2 And sum1 < 0 And 0 < sum2
Wend
' if we can't find a par value giving sum = 0
' take the par will the smallest sum ...
If (-sum1) < sum2 Then
par = par1
ElseIf sum2 < (-sum1) Then
par = par2
' ... splitting ties choosing par nearer zero
ElseIf par2 > 0 Then
par = par1
Else
par = par2
End If
Exit Function
par_error:
MsgBox "Error in par: " & Err.Description
par = CVErr(xlErrValue)
End Function
31 May 2009
VBA code to calculate par for zero-sum butler
21 May 2009
Butler scoring and other abuses of the IMP scale
I posted some random thoughts on butler scoring on a thread IBLF and earlier I promised something here on butlering so here it is.
IMP scale
I think that when you compare a pairs score with par, the difference should be doubled before converting to IMPs. The par score should not be thought of as the result in the other room but as the average of the two results at the two tables of a match. To recover the "teams result", the diffence between one real score and the average/par score needs to be multiplied by two before converting to IMPs. If you like, the IMP score can then be divided by two to represent the actual contribution of each of the pairs in a team. (Obviously this won't affect the relative scores of different pairs.)
Calculating par
Someone else on IBLF said it was obvious that the scores for all the NS pairs should sum to zero, since this determines the par score it should be used to calculate par. Other ways of calculating par approximate to this but you might was well use this desired property as the definition. Implementation is easy, some sort of binary chop will work. You need some rule for deciding what to do when there is no zero-sum par. I suggest minimizing the absolute value of the sum of the NS scores, splitting any tie by picking closest par to zero.
Barking alternative to butler for teams of eight
Another abuse of the IMP scale is to score teams-of-eight by aggregating the four scores and converting to IMPs. This is done in the Eastern Counties League and the Berks and Bucks league. You can use forms of butlering to compare the performance of the pairs in such teams-of-eight matches, or you could use cross IMPs. I think the right form of cross IMPs is
IMP(A+B+C+D) + IMP(A-B+C-D) + IMP(A-B-C+D)
to calculate the score for pair A, with pair B sat the same way, and other pairs of the team (C, D) sat the other way. This formula can be extended if there are multiple matches (in different divisions) played at the same time with the same boards. A pair is compared with all other pairs sat the same way against all possible pairs of pairs sat the other way; with all scores from four different tables. If there are two matches (8 tables) then the three terms above become 105, and if there are three matches (12 tables) there are 495 terms. When I implemented this, I described the scoring option as "barking" (a pun on my name and anticipation of other people's reaction).