THE PUZZLET PAGE

PUZZLET 026 - THE SOLUTION
' Puzzlet #026
' 3 odometers happen to be recording
' numerical palindromes simultaneously:
' 662266, 74646, and 1001.  They all
' continue to increment at the same rate.
' When any odometer reaches a maximum
' value, it rolls over to zero and starts
' to increment from there. Note that they
' are all different types:  a 4-digit, a
' 5-digit, and a 6-digit version.
' What will each device display when next
' they are all simultaneously palindromic?
' By Dave Ellis.

declare ReverseString(str1$: string)
declare IsPalindrome(p: int, s: int)
def done, od1, od2, od3: int
def lastMiles, newMiles, mileage: int
def od1Front$, od1Rear$: string
openconsole
print
"Working ...": print

od1 = 662: od2 = 74647: od3 = 1001
'od1 is acutally 662266, but only digits 1-3 are needed
done = 0

do
    'work out current mileage for od1
    od1Front$ = ltrim$(str$(od1))
    od1Rear$ = ReverseString(od1Front$)
    lastMiles = val(od1Front$ + od1Rear$)
    'increment current mileage to next palindrome
    od1 = od1 + 1
    'work out new mileage for od1
    od1Front$ = ltrim$(str$(od1))
    od1Rear$ = ReverseString(od1Front$)
    newMiles = val(od1Front$ + od1Rear$)
    'work out distance travelled as mileage
    mileage = newMiles - lastMiles
    'add mileage on to od2 and od3
    od2 = (od2 + mileage) % 100000
    od3 = (od3 + mileage) % 10000
    'are they all palindromes?
    if IsPalindrome(od2)
        if IsPalindrome(od3)
            done = -1
            print newMiles, od2, od3
        endif
    endif
until
done

print: print "Done!"
print: print "Press any key to exit ..."
do: until inkey$ <> ""
closeconsole
end

sub
ReverseString(str1$)
' returns the reverse of string str1$
' example: str1$ = "knob" returns "bonk"

def i, L: int
def rev$: string
L = len(str1$)
rev$ = ""
for i = L to 1 #-1
    rev$ = rev$ + mid$(str1$, i, 1)
next i
return rev$

sub IsPalindrome(p, s)
'p is buffered with leading zeroes to
'make it s digits long.  If the result
'is a palindrome, returns 0, otherwise
'returns -1.

def flag, i, j, L: int
def p1$, p2$, p3$: string
p1$ = ltrim$(str$(p))
L = len(p1$)
'buffer p1$ with leading zeroes
p1$ = string$(s - L, "0") + p1$
L = len(p1$)
j = int(L/2)
i = 1
flag = 1
do
    p2$ = mid$(p1$, i, 1)
    p3$ = mid$(p1$, L + 1 - i, 1)
    if p2$ <> p3$
        flag = 0: 'it cannot be a palindrome
    endif
    i = i + 1
until flag = 0 | i > j
return flag   
   


       
PROGRAM NOTES

I originally published this as a QBasic program.  In this IBasic version, I am using a faster algorithm proposed by Denis Borris. This relies on taking only the first three digits of odometer 1, generating a reversed version of it, and tacking it onto the end of the first three digits to obtain the current mileage.  Incrementing those first three digits and repeating the process will give the next mileage at which odometer 1 is a palindrome, skipping over all the non-palindromic mileages along the way.

The values of the odometers are held in variables od1, od2, and od3. od1's current mileage is held in variable lastMiles. The new mileage after incrementing to the next palindromic value is held in variable newMiles.  The actual distance travelled between
lastMiles and newMiles  is held in mileage.

All the action takes place within the main DO loop. The REMs give a fairly clear description of what's going on.

First, the current mileage for od1 is worked out by the method described above.  String slicing is deployed here.  od1 is converted to a string and held in variable od1Front$.  This is passed as the parameter to the function ReverseString(), which returns a string which is an exact reverse of its argument.  The reversed string is stored in od2Rear$.  Finally the current mileage is obtained by concatenating od1Front$ and od1Rear$ in that order then finding their arithmetic value by use of the function val and storing it in variable lastMiles.

We're ready to get the next palindromic mileage now for od1.  Its 3-digit version is incremented by 1 to obtain this.  The process for obtaining the new mileage is exactly the same as that used for the current mileages, even using the same variables.  The result is stored in newMiles.

The distance travelled is easily worked out from newMiles - lastMiles, with the result stored in mileage.  Since all three odometers are incrementing at exactly the same rate, they must all be incremented by the value stored in mileage.  However, each odo must always roll over to zero when full.  To facilitate this the addition is carried out using modular arithmetic.

For od2 we have to say
od2 = (od2 + mileage) % 100000
For od3 we have to say od3 = (od3 + mileage) % 10000

Now we can actually look for our main objectives: palindromic values in all three odomoters simultaneously.  This is slightly complicated by the fact that you can't store leading zeroes in integers, but the palindromes must be based on any leading zeroes which would be present in a real odometer.  To make matters worse, some of the values to be checked will be five digits long and some only four digits long.

To overcome this problem two parameters are passed to the function IsPalindrome: the integer to be checked for palindromicity (local variable p), and the size it would be if any leading zeroes were needed (local variable s).  The function converts p to a string then, if necessary, stuffs enough leading zeroes in front of it to make it equal in size, or length, to s.  Now a normal palindrome check can be made, and a TRUE (-1) or FALSE (0) returned to the calling routine.

Once a combination of odometers which are all numerical palindromes is found, their values are printed out and variable flag set to permit the program to stop.


When you run the code,  it will produce the inset screen.  

This is the first solution.  There are two more occasions when all the odometers are palindromic, so you may like to find them if you're still hungry for more ...


Working ...

773377  85758  2112

Done!

Press any key to exit ...

        




MAIN MENU
DOWNLOAD CODE
ARCHIVES

Site design/maintenance: Dave Ellis E-mail me!
Last Updated: February 22nd, 2004.