···
end = builtins.fromJSON (builtins.elemAt parts 1); };
in map parseRange rangeStrings;
14
-
# Convert number to string digits
15
-
numToStr = n: builtins.toString n;
17
-
# Check if string has even length and halves are equal
18
-
hasEqualHalves = str:
19
-
let len = builtins.stringLength str;
21
-
in if len == 0 || (len / 2 * 2) != len then false
22
-
else (builtins.substring 0 half str) == (builtins.substring half half str);
24
-
# Check if string is repeating pattern of given chunk size
25
-
isRepeating = str: chunkSize:
27
-
len = builtins.stringLength str;
28
-
chunk = builtins.substring 0 chunkSize str;
30
-
if pos >= len then true
31
-
else if (builtins.substring pos chunkSize str) != chunk then false
32
-
else checkPos (pos + chunkSize);
33
-
in if len == 0 || (len / chunkSize * chunkSize) != len then false
36
-
# Find smallest repeating chunk size for a string
37
-
hasRepeatingPattern = str:
39
-
len = builtins.stringLength str;
41
-
if size > len / 2 then false
42
-
else if isRepeating str size then true
43
-
else checkSize (size + 1);
44
-
in if len == 0 then false else checkSize 1;
14
+
# Generate all numbers with equal halves in a range
15
+
generateEqualHalves = start: end:
17
+
startLen = builtins.stringLength (builtins.toString start);
18
+
endLen = builtins.stringLength (builtins.toString end);
20
+
# For even digit counts, generate patterns directly
21
+
generateForDigits = numDigits:
23
+
halfDigits = numDigits / 2;
24
+
isEven = (numDigits - halfDigits * 2) == 0;
26
+
if !isEven || numDigits < 2 then []
29
+
# Calculate 10^halfDigits for multiplier
30
+
multiplier = builtins.foldl' (a: _: a * 10) 1 (builtins.genList (x: x) halfDigits);
31
+
halfMin = multiplier / 10;
32
+
halfMax = multiplier - 1;
34
+
# Generate number from half: n = half * (10^half + 1)
35
+
makeNum = half: half * (multiplier + 1);
37
+
minVal = makeNum halfMin;
38
+
maxVal = makeNum halfMax;
40
+
# Only generate if range overlaps
41
+
actualMin = if minVal < start then
42
+
let h = (start + multiplier) / (multiplier + 1); in if makeNum h >= start then h else h + 1
44
+
actualMax = if maxVal > end then
45
+
end / (multiplier + 1)
48
+
count = if actualMax >= actualMin then actualMax - actualMin + 1 else 0;
50
+
if count > 0 then builtins.genList (i: makeNum (actualMin + i)) count else [];
52
+
allDigits = builtins.genList (d: startLen + d) (endLen - startLen + 1);
53
+
allNums = builtins.concatMap generateForDigits allDigits;
46
-
# Process range in batches to avoid stack overflow
47
-
sumRangeIf = predicate: start: end:
56
+
# Generate all repeating pattern numbers in a range
57
+
generateRepeating = start: end:
50
-
numBatches = ((end - start + 1) + batchSize - 1) / batchSize;
59
+
startLen = builtins.stringLength (builtins.toString start);
60
+
endLen = builtins.stringLength (builtins.toString end);
62
+
# Calculate 10^n efficiently
63
+
pow10 = n: builtins.foldl' (a: _: a * 10) 1 (builtins.genList (x: x) n);
65
+
# Generate numbers with specific total length and chunk size
66
+
generateForPattern = totalDigits: chunkSize:
54
-
batchStart = start + i * batchSize;
55
-
batchEnd = if batchStart + batchSize - 1 < end then batchStart + batchSize - 1 else end;
56
-
nums = builtins.genList (n: batchStart + n) (batchEnd - batchStart + 1);
57
-
validNums = builtins.filter predicate nums;
58
-
in builtins.foldl' (a: n: a + n) 0 validNums;
60
-
in builtins.foldl' (acc: i: acc + processBatch i) 0 (builtins.genList (i: i) numBatches);
68
+
reps = totalDigits / chunkSize;
69
+
isValid = (totalDigits - reps * chunkSize) == 0 && chunkSize * 2 <= totalDigits;
74
+
# Calculate multiplier for repeating: e.g., for 3 reps of 2 digits: 10^4 + 10^2 + 1
76
+
let terms = builtins.genList (i: pow10 (i * chunkSize)) reps;
77
+
in builtins.foldl' builtins.add 0 terms;
79
+
multiplier = calcMultiplier;
80
+
chunkMin = pow10 (chunkSize - 1);
81
+
chunkMax = pow10 chunkSize - 1;
83
+
makeNum = chunk: chunk * multiplier;
85
+
minVal = makeNum chunkMin;
86
+
maxVal = makeNum chunkMax;
88
+
# Calculate actual range
89
+
actualMin = if minVal < start then
90
+
let c = (start + multiplier - 1) / multiplier;
91
+
in if c > chunkMax then chunkMax + 1 else if c < chunkMin then chunkMin else c
93
+
actualMax = if maxVal > end then
97
+
count = if actualMax >= actualMin then actualMax - actualMin + 1 else 0;
98
+
nums = if count > 0 then builtins.genList (i: makeNum (actualMin + i)) count else [];
99
+
filtered = builtins.filter (n: n >= start && n <= end) nums;
102
+
# For each digit count, try all valid chunk sizes
103
+
generateForDigits = numDigits:
105
+
maxChunk = numDigits / 2;
106
+
validChunks = builtins.filter
107
+
(c: (numDigits - numDigits / c * c) == 0)
108
+
(builtins.genList (i: i + 1) maxChunk);
109
+
in builtins.concatMap (c: generateForPattern numDigits c) validChunks;
111
+
allDigits = builtins.genList (d: startLen + d) (endLen - startLen + 1);
112
+
allNums = builtins.concatLists (map generateForDigits allDigits);
114
+
# Remove duplicates efficiently using sort
115
+
sorted = builtins.sort (a: b: a < b) allNums;
116
+
dedupe = builtins.foldl'
117
+
(acc: n: if acc.prev == n then acc else { prev = n; list = acc.list ++ [n]; })
118
+
{ prev = -1; list = []; }
65
-
acc + sumRangeIf (n: hasEqualHalves (numToStr n)) r.start r.end;
125
+
let nums = generateEqualHalves r.start r.end;
126
+
in acc + builtins.foldl' builtins.add 0 nums;
in builtins.foldl' processRange 0 ranges;
71
-
acc + sumRangeIf (n: hasRepeatingPattern (numToStr n)) r.start r.end;
132
+
let nums = generateRepeating r.start r.end;
133
+
in acc + builtins.foldl' builtins.add 0 nums;
in builtins.foldl' processRange 0 ranges;