def number2digits(long n) {
    def result = []
    for(/**/; n > 0; n /= 10) {
        result.add(0, n % 10)
    }
    return (result) ? result : [0]
}
assert number2digits(123) == [1, 2, 3]

def digits2number(digits) {
    return digits.inject(0l) { a, b -> a*10 + b }
}
assert digits2number([1, 2, 3]) == 123

def createPalindrome(long palindromeBeginning, boolean doubleDigitInMiddle) {
    def palindromeBeginningDigits = number2digits(palindromeBeginning)
    def palindromeEndingDigits = palindromeBeginningDigits.reverse()
    if (!doubleDigitInMiddle) {
        palindromeEndingDigits = palindromeEndingDigits.tail()
    }
    return digits2number(palindromeBeginningDigits + palindromeEndingDigits)
}
assert createPalindrome(123, false) == 12321
assert createPalindrome(123, true) == 123321

COUNTER = 0

def findNDigitsDivisorPair(long x, int N) {
    int MAX_DIVISOR = 10**N - 1
    int MIN_DIVISOR = 10**(N-1)
    int squareRoot = Math.sqrt(x)
    if (MIN_DIVISOR <= squareRoot && squareRoot <= MAX_DIVISOR) {
        int lowerDivisorBound = Math.max(x / MAX_DIVISOR as int, MIN_DIVISOR);
        for (int i = lowerDivisorBound; i <= squareRoot; ++i) {
            double quotient = (x as double) / i
            ++COUNTER
            //println "$x / $i = $quotient"
            if (quotient % 1 == 0) return [i, quotient as int]
        }
    }
    return null
}
assert findNDigitsDivisorPair(143, 2) == [11, 13]

def findBiggestDivisiblePalindrome(digitsCount) {
    for (int begin = 10**digitsCount - 1; begin >= 10**(digitsCount-1); --begin) {
        long palindrome = createPalindrome(begin, true)
        def solution = findNDigitsDivisorPair(palindrome, digitsCount)
        if (solution) {
            println "Number of checks = " + COUNTER
            println "$palindrome = ${solution[0]} * ${solution[1]}"
            return palindrome
        }
    }    
}
//assert findBiggestDivisiblePalindrome(9) = 999996100001699999

def start = new Date().getTime()
findBiggestDivisiblePalindrome(3)
println "Execution time: ${new Date().getTime() - start} ms"
