Here are some of the latest results:
Algorithm Correct Time Score Penalties Eggs
--------------- ------- ------ ------- --------- ----
Empty Economy 49.86 2.8104 472849 2378650 0
Empty Deluxe 0.05 2.8311 1944 474168000 243
Starter Economy 89.75 2.9663 851367 486060 0
Starter Deluxe 90.68 2.9764 1663118 441920 151
Dan Beast 4 99.85 3.2622 1750076 7130 151
Cedron Unrolled 100.00 3.2721 1898616 0 243
Cedron Deluxe 100.00 3.3255 1898616 0 243
Cedron Revised 100.00 3.2128 1898616 0 243
Olli Revised 99.50 3.1893 1728065 23880 0
Olli Original 99.50 3.2464 1728065 23880 0
Cedron Multiply 100.00 3.2042 1898616 0 243
Matt Multiply 100.00 3.3146 1898616 0 243
The timing for the contenders is too close and too noisy to show a clear favorite. Benchmarking on the target platform would be much more useful now.
The code has been updated. It is as it is.
import numpy as np
import timeit
# The passed arguments to a running horse.
#
# ( I1, Q1 ) First Complex Value (or Point)
# ( I2, Q2 ) Second Complex Value (or Point)
# Its return values are
#
# ( rc ) Comparison Result (Return Code)
# ( l ) Locus of the Exit
# The return value can be one of these
#
# -2 The first is for sure less than the second
# -1 The first is likely less than the second
# 0 The two are equal for sure
# 1 The first is likely greater than the second
# 2 The first is for sure greater than the second
#
# Routines that only return {-1,1} can be called Economy
# Routines that only return {-2,0,2} can be called Deluxe
#
# How Scoring works
#
# S Score
# P Penalties
# E Egg Count
# W Wrong
#
# Correct Marginal Wrong
# {-1,1} S+=2 S+=1 W+=1,P+=10
# {-2,0,2} S+=4(E+=1) S+=2,P+=10 W+=1,P+=1000
#
#
#====================================================================
#====================================================================
# W A L K O N S
#====================================================================
#====================================================================
def WalkOnOne( I1, Q1, I2, Q2 ):
return 1, 0
#====================================================================
def WalkOnTwo( I1, Q1, I2, Q2 ):
return 1, 0
#====================================================================
def WalkOnThree( I1, Q1, I2, Q2 ):
return 1, 0
#====================================================================
#====================================================================
# S T A R T E R C O D E
#====================================================================
#====================================================================
def EmptyEconomy( I1, Q1, I2, Q2 ):
return 1, 0
#====================================================================
def EmptyDeluxe( I1, Q1, I2, Q2 ):
return 0, 0
#====================================================================
def StarterEconomy( I1, Q1, I2, Q2 ):
#---- Ensure the Points are in the First Quadrant WLOG
x1 = abs( I1 )
y1 = abs( Q1 )
x2 = abs( I2 )
y2 = abs( Q2 )
#---- Ensure they are in the Lower Half (First Octant) WLOG
if y1 > x1:
x1, y1 = y1, x1
if y2 > x2:
x2, y2 = y2, x2
#---- Return Results
if x1 < x2:
return -1, 0
return 1, 0
#====================================================================
def StarterDeluxe( I1, Q1, I2, Q2 ):
#---- Ensure the Points are in the First Quadrant WLOG
x1 = abs( I1 )
y1 = abs( Q1 )
x2 = abs( I2 )
y2 = abs( Q2 )
#---- Ensure they are in the Lower Half (First Octant) WLOG
if y1 > x1:
x1, y1 = y1, x1
if y2 > x2:
x2, y2 = y2, x2
#---- Primary Determination
if x1 > x2:
if x1 + y1 >= x2 + y2:
return 2, 0
thePresumedResult = 1
elif x1 < x2:
if x1 + y1 <= x2 + y2:
return -2, 0
thePresumedResult = -1
else:
if y1 > y2:
return 2, 1
elif y1 < y2:
return -2, 1
else:
return 0, 1
#---- Return the Presumed Result
return thePresumedResult, 2
#====================================================================
#====================================================================
# C E D R O N ' S
#====================================================================
#====================================================================
def CedronRevised( I1, Q1, I2, Q2 ):
#---- Ensure the Points are in the First Quadrant WLOG
x1 = abs( I1 )
y1 = abs( Q1 )
x2 = abs( I2 )
y2 = abs( Q2 )
#---- Ensure they are in the Lower Half (First Octant) WLOG
if y1 > x1:
x1, y1 = y1, x1
if y2 > x2:
x2, y2 = y2, x2
#---- Primary Determination with X Absolute Differences
if x1 > x2:
if x1 + y1 >= x2 + y2:
return 2, 0
thePresumedResult = 2
dx = x1 - x2
elif x1 < x2:
if x1 + y1 <= x2 + y2:
return -2, 0
thePresumedResult = -2
dx = x2 - x1
else:
if y1 > y2:
return 2, 1
elif y1 < y2:
return -2, 1
else:
return 0, 1
#---- Sums and Y Absolute Differences
sx = x1 + x2
sy = y1 + y2
dy = abs( y1 - y2 )
#---- Bring Factors into 1/2 to 1 Ratio Range
while dx < sx:
dx += dx
if dy < sy:
dy += dy
else:
sy += sy
while dy < sy:
dy += dy
if dx < sx:
dx += dx
else:
sx += sx
#---- Use Double Arithmetic Mean as Proxy for Geometric Mean
cx = sx + dx
cy = sy + dy
cx16 = cx << 4
cy16 = cy << 4
if cx16 - cx > cy16:
return thePresumedResult, 2
if cy16 - cy > cx16:
return -thePresumedResult, 2
#---- X Multiplication
px = 0
while sx > 0:
if sx & 1:
px += dx
dx += dx
sx >>= 1
#---- Y Multiplication
py = 0
while sy > 0:
if sy & 1:
py += dy
dy += dy
sy >>= 1
#---- Return Results
if px > py:
return thePresumedResult, 2
if px < py:
return -thePresumedResult, 2
return 0, 2
#====================================================================
def CedronUnrolled( I1, Q1, I2, Q2 ):
#---- Ensure the Points are in the First Quadrant WLOG
x1 = abs( I1 )
y1 = abs( Q1 )
x2 = abs( I2 )
y2 = abs( Q2 )
#---- Ensure they are in the Lower Half (First Octant) WLOG
if y1 > x1:
x1, y1 = y1, x1
if y2 > x2:
x2, y2 = y2, x2
#---- Primary Determination with X Absolute Differences
if x1 > x2:
if x1 + y1 >= x2 + y2:
return 2, 0
thePresumedResult = 2
dx = x1 - x2
elif x1 < x2:
if x1 + y1 <= x2 + y2:
return -2, 0
thePresumedResult = -2
dx = x2 - x1
else:
if y1 > y2:
return 2, 1
elif y1 < y2:
return -2, 1
else:
return 0, 1
#---- Estimate First Multiplied Magnitude
if y1 < (x1>>1):
if y1 < (x1>>2):
m1 = (x1<<8) - (x1<<1) \
+ (y1<<5) + (y1<<1)
else:
m1 = (x1<<8) - (x1<<4) \
+ (y1<<6) + (y1<<5) - (y1<<2) - (y1<<1)
else:
if y1 < (x1>>1) + (x1>>2):
m1 = (x1<<8) - (x1<<5) - (x1<<2) - (x1<<1) \
+ (y1<<7) + (y1<<3) - y1
else:
m1 = (x1<<7) + (x1<<6) + (x1<<1) \
+ (y1<<7) + (y1<<5) + (y1<<3)
#---- Estimate Second Multiplied Magnitude
if y2 < (x2>>1):
if y2 < (x2>>2):
m2 = ( (x2<<7) - x2 \
+ (y2<<4) + y2 ) << 1
else:
m2 = ( (x2<<7) - (x2<<3) \
+ (y2<<5) + (y2<<4) - (y2<<1) - y2 ) << 1
else:
if y2 < (x2>>1) + (x2>>2):
m2 = ( (x2<<8) - (x2<<5) - (x2<<2) - (x2<<1) \
+ (y2<<7) + (y2<<3) - y2 )
else:
m2 = ( (x2<<6) + (x2<<5) + x2 \
+ (y2<<6) + (y2<<4) + (y2<<2) ) << 1
#---- Return Results (1000 is a temp hack value!)
if m1 > m2 + (m2>>6):
return 2, 2
if m2 > m1 + (m1>>6):
return -2, 2
#---- Sums and Y Absolute Differences
sx = x1 + x2
sy = y1 + y2
dy = abs( y1 - y2 )
#---- X Multiplication
px = 0
while dx > 0:
if dx & 1:
px += sx
sx += sx
dx >>= 1
#---- Y Multiplication
py = 0
while dy > 0:
if dy & 1:
py += sy
sy += sy
dy >>= 1
#---- Return Results
if px > py:
return thePresumedResult, 2
if px < py:
return -thePresumedResult, 2
return 0, 2
#====================================================================
def CedronDeluxe( I1, Q1, I2, Q2 ):
#---- Ensure the Points are in the First Quadrant WLOG
x1 = abs( I1 )
y1 = abs( Q1 )
x2 = abs( I2 )
y2 = abs( Q2 )
#---- Ensure they are in the Lower Half (First Octant) WLOG
if y1 > x1:
x1, y1 = y1, x1
if y2 > x2:
x2, y2 = y2, x2
#---- Primary Determination with X Absolute Differences
if x1 > x2:
if x1 + y1 >= x2 + y2:
return 2, 0
dx = x1 - x2
elif x1 < x2:
if x1 + y1 <= x2 + y2:
return -2, 0
dx = x2 - x1
else:
if y1 > y2:
return 2, 1
elif y1 < y2:
return -2, 1
else:
return 0, 1
#---- Employ a DanBeast
L1 = DanBeast_2_8_Level( x1, y1 )
L2 = DanBeast_2_8_Level( x2, y2 )
#---- Early Out Return
if L1 > L2 + (L2>>6):
return 2, 1
if L2 > L1 + (L1>>6):
return -2, 1
#---- Sums and Y Absolute Differences
sx = x1 + x2
sy = y1 + y2
dy = abs( y1 - y2 )
#---- Do the Multiplications
px = UnsignedBitMultiply( sx, dx )
py = UnsignedBitMultiply( sy, dy )
#---- Account for Swap
if x1 > x2:
thePresumedResult = 2
else:
thePresumedResult = -2
#---- Return Results
if px > py:
return thePresumedResult, 2
if px < py:
return -thePresumedResult, 2
return 0, 2
#====================================================================
def DanBeastFour( I1, Q1, I2, Q2 ):
#---- Ensure the Points are in the First Quadrant WLOG
x1 = abs( I1 )
y1 = abs( Q1 )
x2 = abs( I2 )
y2 = abs( Q2 )
#---- Ensure they are in the Lower Half (First Octant) WLOG
if y1 > x1:
x1, y1 = y1, x1
if y2 > x2:
x2, y2 = y2, x2
#---- Primary Determination with Quick Exit
if x1 > x2:
if x1 + y1 >= x2 + y2:
return 2, 0
elif x1 < x2:
if x1 + y1 <= x2 + y2:
return -2, 0
else:
if y1 > y2:
return 2, 0
elif y1 < y2:
return -2, 0
else:
return 0, 0
#---- Estimate First Multiplied Magnitude
if y1 < (x1>>1):
if y1 < (x1>>2):
m1 = (x1<<8) - (x1<<1) \
+ (y1<<5) + (y1<<1)
else:
m1 = (x1<<8) - (x1<<4) \
+ (y1<<6) + (y1<<5) - (y1<<2) - (y1<<1)
else:
if y1 < (x1>>1) + (x1>>2):
m1 = (x1<<8) - (x1<<5) - (x1<<2) - (x1<<1) \
+ (y1<<7) + (y1<<3) - y1
else:
m1 = (x1<<7) + (x1<<6) + (x1<<1) \
+ (y1<<7) + (y1<<5) + (y1<<3)
#---- Estimate Second Multiplied Magnitude
if y2 < (x2>>1):
if y2 < (x2>>2):
m2 = ( (x2<<7) - x2 \
+ (y2<<4) + y2 ) << 1
else:
m2 = ( (x2<<7) - (x2<<3) \
+ (y2<<5) + (y2<<4) - (y2<<1) - y2 ) << 1
else:
if y2 < (x2>>1) + (x2>>2):
m2 = ( (x2<<8) - (x2<<5) - (x2<<2) - (x2<<1) \
+ (y2<<7) + (y2<<3) - y2 )
else:
m2 = ( (x2<<6) + (x2<<5) + x2 \
+ (y2<<6) + (y2<<4) + (y2<<2) ) << 1
#---- Return Results
if m1 < m2:
return -1, 2
return 1, 2
#====================================================================
def CedronMultiply( I1, Q1, I2, Q2 ):
#---- Ensure the Points are in the First Quadrant WLOG
x1 = abs( I1 )
y1 = abs( Q1 )
x2 = abs( I2 )
y2 = abs( Q2 )
#---- Ensure they are in the Lower Half (First Octant) WLOG
if y1 > x1:
x1, y1 = y1, x1
if y2 > x2:
x2, y2 = y2, x2
#---- Primary Determination with X Absolute Differences
if x1 > x2:
if x1 + y1 >= x2 + y2:
return 2, 0
thePresumedResult = 2
dx = x1 - x2
elif x1 < x2:
if x1 + y1 <= x2 + y2:
return -2, 0
thePresumedResult = -2
dx = x2 - x1
else:
if y1 > y2:
return 2, 1
elif y1 < y2:
return -2, 1
else:
return 0, 1
#---- Sums and Y Absolute Differences
sx = x1 + x2
sy = y1 + y2
dy = abs( y1 - y2 )
#---- X Multiplication
px = 0
while dx > 0:
if dx & 1:
px += sx
sx += sx
dx >>= 1
#---- Y Multiplication
py = 0
while dy > 0:
if dy & 1:
py += sy
sy += sy
dy >>= 1
#---- Return Results
if px > py:
return thePresumedResult, 2
if px < py:
return -thePresumedResult, 2
return 0, 2
#====================================================================
#====================================================================
# O L L I L I K E
#====================================================================
#====================================================================
def MyVersionOfOllis( I1, Q1, I2, Q2 ):
# Returns ( c )
#
# c Comparison
#
# -1 | (I1,Q1) | < | (I2,Q2) |
# 1 | (I1,Q1) | > | (I2,Q2) |
#
# t Exit Test
#
# 1 (Partial) Primary Determination
# 2 CORDIC Loop + 1
# 6 Terminating Guess
#---- Set Extent Parameter
maxIterations = 4
#---- Ensure the Points are in the First Quadrant WLOG
I1 = abs( I1 )
Q1 = abs( Q1 )
I2 = abs( I2 )
Q2 = abs( Q2 )
#---- Ensure they are in the Lower Half (First Octant) WLOG
if Q1 > I1:
I1, Q1 = Q1, I1
if Q2 > I2:
I2, Q2 = Q2, I2
#---- (Partial) Primary Determination
if I1 < I2 and I1 + Q1 <= I2 + Q2:
return -2, 1
if I1 > I2 and I1 + Q1 >= I2 + Q2:
return 2, 1
#---- CORDIC Loop
for n in range ( 1, maxIterations+1 ):
newI1 = I1 + ( Q1 >> n )
newQ1 = Q1 - ( I1 >> n )
newI2 = I2 + ( Q2 >> n )
newQ2 = Q2 - ( I2 >> n )
I1 = newI1
Q1 = abs( newQ1 )
I2 = newI2
Q2 = abs( newQ2 )
s = n + n + 1
if I1 <= I2 - ( I2 >> s ):
return -1, 1 + n
if I2 <= I1 - ( I1 >> s ):
return 1, 1 + n
#---- Terminating Guess
if I1 < I2:
return -1, 7
return 1, 7
#====================================================================
def MyRevisionOfOllis( I1, Q1, I2, Q2 ):
# Returns ( rc, l )
#
# c Comparison
#
# -1,-2 | (I1,Q1) | < | (I2,Q2) |
# 1, 2 | (I1,Q1) | > | (I2,Q2) |
#
# t Exit Test
#
# 1 (Partial) Primary Determination
# 2 CORDIC Loop + 1
# 6 Terminating Guess
#---- Ensure the Points are in the First Quadrant WLOG
I1 = abs( I1 )
Q1 = abs( Q1 )
I2 = abs( I2 )
Q2 = abs( Q2 )
#---- Ensure they are in the Lower Half (First Octant) WLOG
if Q1 > I1:
I1, Q1 = Q1, I1
if Q2 > I2:
I2, Q2 = Q2, I2
#---- (Partial) Primary Determination
if I1 < I2 and I1 + Q1 <= I2 + Q2:
return -2, 1
if I1 > I2 and I1 + Q1 >= I2 + Q2:
return 2, 1
#---- CORDIC Loop Head
s = 3
for n in range ( 1, 5 ):
#---- Apply the Rotation
newI1 = I1 + ( Q1 >> n )
newQ1 = Q1 - ( I1 >> n )
newI2 = I2 + ( Q2 >> n )
newQ2 = Q2 - ( I2 >> n )
#---- Attempt Comparison
if newI1 <= newI2 - ( newI2 >> s ):
return -1, 1 + n
if newI2 <= newI1 - ( newI1 >> s ):
return 1, 1 + n
s += 2
#---- Advance the Values
I1 = newI1
I2 = newI2
Q1 = abs( newQ1 )
Q2 = abs( newQ2 )
#---- Terminating Guess
if I1 < I2:
return -1, 7
return 1, 7
#====================================================================
#====================================================================
# M A T T L L I K E
#====================================================================
#====================================================================
def MattMultiply( I1, Q1, I2, Q2 ):
#---- Ensure the Points are in the First Quadrant WLOG
I1 = abs( I1 )
Q1 = abs( Q1 )
I2 = abs( I2 )
Q2 = abs( Q2 )
#---- Ensure they are in the Lower Half (First Octant) WLOG
if Q1 > I1:
I1, Q1 = Q1, I1
if Q2 > I2:
I2, Q2 = Q2, I2
#---- Ensure the first value is rightmost
swap = 0;
if I2 > I1:
swap = 4
I1, I2 = I2, I1
Q1, Q2 = Q2, Q1
#---- Primary determination
if I1 + Q1 > I2 + Q2:
return 2 - swap, 2
else:
DI = I1 - I2
if DI < 0:
tmp1 = -UnsignedBitMultiply( I1 + I2, -DI )
else:
tmp1 = UnsignedBitMultiply( I1 + I2, DI )
DQ = Q2 - Q1
if DQ < 0:
tmp2 = -UnsignedBitMultiply( Q1 + Q2, -DQ )
else:
tmp2 = UnsignedBitMultiply( Q1 + Q2, DQ )
if tmp1 == tmp2:
return 0 , 2
elif tmp1 > tmp2:
return 2 - swap, 2
else:
return -2 + swap, 2
#====================================================================
#====================================================================
# U T I L I T I E S
#====================================================================
#====================================================================
def UnsignedBitMultiply( a, b ): # Smaller value second is faster.
p = 0
while b > 0:
if b & 1:
p += a
a += a
b >>= 1
return p
#====================================================================
def DanBeast_2_8_Level( x, y ):
if y+y < x: # 2 y < x
if (y<<2) < x: # 4 y < x
L = (x<<8) -x-x \
+ (y<<5) +y+y # y/x = 0.00 to 0.25
else:
L = (x<<8) - (x<<4) \
+ (y<<6) + (y<<5) - (y<<2) -y-y # y/x = 0.25 to 0.50
else:
if (y<<2) < x+x+x: # 4 y < 3 x
L = (x<<8) - (x<<5) - (x<<2) -x-x \
+ (y<<7) + (y<<3) - y # y/x = 0.50 to 0.75
else:
L = (x<<7) + (x<<6) +x+x \
+ (y<<7) + (y<<5) + (y<<3) # y/x = 0.75 to 1.00
return L
#====================================================================
#====================================================================
# T E S T I N G H A R N E S S
#====================================================================
#====================================================================
def Test( ArgLimit, ArgThreshold, ArgLane, ArgTestName ):
#---- Set the Parameters
t = ArgThreshold
#---- Initialize the Counters
theCount = 0
theWrongCount = 0
theEggs = 0
theScore = 0
thePenalties = 0
#---- Start Timing
theStartTime = timeit.default_timer()
#---- Test on a Swept Area
for i1 in range( -ArgLimit, ArgLimit, 10 ):
ii1 = i1 * i1
for q1 in range( -ArgLimit, ArgLimit, 7 ):
d1 = np.sqrt( ii1 + q1 * q1 )
for i2 in range( -ArgLimit, ArgLimit, 11 ):
ii2 = i2 * i2
for q2 in range( -ArgLimit, ArgLimit, 5 ):
d2 = np.sqrt( ii2 + q2 * q2 )
D = d1 - d2 # = |(I1,Q1)| - |(I2,Q2)|
theCount += 1
#---- The Fast Side Bench Mark Lanes
if ArgLane == 0:
rc, l = EmptyEconomy( i1, q1, i2, q2 )
if ArgLane == 1:
rc, l = EmptyDeluxe( i1, q1, i2, q2 )
if ArgLane == 2:
rc, l = StarterEconomy( i1, q1, i2, q2 )
if ArgLane == 3:
rc, l = StarterDeluxe( i1, q1, i2, q2 )
#---- The Slower Pace Horses
if ArgLane == 8:
rc, l = TwoMultiply( i1, q1, i2, q2 )
if ArgLane == 9:
rc, l = FourMultiply( i1, q1, i2, q2 )
#---- Walk Ons
if ArgLane == 11:
rc, l = WalkOnOne( i1, q1, i2, q2 )
if ArgLane == 12:
rc, l = WalkOnTwo( i1, q1, i2, q2 )
if ArgLane == 13:
rc, l = WalkOnThree( i1, q1, i2, q2 )
#---- Cedron D.'s Lanes
if ArgLane == 20:
rc, l = CedronRevised( i1, q1, i2, q2 )
if ArgLane == 21:
rc, l = CedronDeluxe( i1, q1, i2, q2 )
if ArgLane == 22:
rc, l = CedronUnrolled( i1, q1, i2, q2 )
if ArgLane == 23:
rc, l = DanBeastFour( i1, q1, i2, q2 )
if ArgLane == 24:
rc, l = CedronMultiply( i1, q1, i2, q2 )
#---- Olli N.'s Lanes
if ArgLane == 30:
rc, l = MyVersionOfOllis( i1, q1, i2, q2 )
if ArgLane == 31:
rc, l = MyRevisionOfOllis( i1, q1, i2, q2 )
#---- Dan B.'s Lanes
# if ArgLane == 41:
# rc, l = Dan1( i1, q1, i2, q2 )
#---- Matt L.'s Lanes
if ArgLane == 50:
rc, l = MattMultiply( i1, q1, i2, q2 )
#---- Assess Scores, Penalties, and Eggs
if rc == -2:
if D < -t:
theScore += 4
elif D < 0:
theScore += 2
thePenalties += 10
else:
theWrongCount += 1
thePenalties += 1000
elif rc == 2:
if D > t:
theScore += 4
elif D > 0:
theScore += 2
thePenalties += 10
else:
theWrongCount += 1
thePenalties += 1000
elif rc == -1:
if D < 0:
theScore += 2
elif D <= t:
theScore += 1
else:
theWrongCount += 1
thePenalties += 10
elif rc == 1:
if D > 0:
theScore += 2
elif D >= -t:
theScore += 1
else:
theWrongCount += 1
thePenalties += 10
elif rc == 0:
if abs( D ) <= t:
theScore += 8
if D == 0:
theEggs += 1
else:
theWrongCount += 1
thePenalties += 1000
else:
print "Disqualification -- Invalid c value:", c, "Lane", ArgLane
return
#---- Finish Timing
theDuration = timeit.default_timer() - theStartTime
#---- Calculate the Results
theCorrectCount = theCount - theWrongCount
theCorrectPct = 100.0 * float( theCorrectCount ) \
/ float( theCount )
#---- Return Results
return "%15s %7.2f %10.4f %10d %10d %4d" % \
( ArgTestName, theCorrectPct, theDuration,\
theScore, thePenalties, theEggs )
#====================================================================
def Main():
#---- Set Run Time Parameters
L = 101 # The Limit
T = 0 # Threshold
#---- Print Headers
print "Algorithm Correct Time Score Penalties Eggs"
print "--------------- ------- ------ ------- --------- ----"
#---- The Calibrators
print Test( L, T, 0, "Empty Economy" )
print Test( L, T, 1, "Empty Deluxe" )
print Test( L, T, 2, "Starter Economy" )
print Test( L, T, 3, "Starter Deluxe" )
#---- The Walk Ons
# print
# print Test( L, T, 11, "Walk On One" )
#---- The Contenders
print
print Test( L, T, 23, "Dan Beast 4" )
print Test( L, T, 22, "Cedron Unrolled" )
print Test( L, T, 21, "Cedron Deluxe" )
print Test( L, T, 20, "Cedron Revised" )
print Test( L, T, 31, "Olli Revised" )
print Test( L, T, 30, "Olli Original" )
#---- The Pace Setters
print
print Test( L, T, 24, "Cedron Multiply" )
print Test( L, T, 50, "Matt Multiply" )
#====================================================================
Main()
Earlier, I pledged a 50 point bounty to the best horse (fastest time 99%+ correct) that wasn't one of my entries. I'm sticking with that, and right now Olli is leading. (My optimized version is DQ'd)