RosettaCodeData/Task/Eban-numbers/AppleScript/eban-numbers-1.applescript

117 lines
5.4 KiB
AppleScript

(*
Quickly generate all the (positive) eban numbers up to and including the
specified end number, then lose those before the start number.
0 is taken as "zero" rather than as "nought" or "nil".
WARNING: The getEbans() handler returns a potentially very long list of numbers.
Don't let such a list get assigned to a persistent variable or be the end result displayed in an editor!
*)
on getEbans(startNumber, endNumber)
script o
property output : {}
property listCollector : missing value
property temp : missing value
end script
if (startNumber > endNumber) then set {startNumber, endNumber} to {endNumber, startNumber}
-- The range is limited to between 0 and 10^15 to keep within AppleScript's current number precision.
-- Even so, some of the numbers may not /look/ right when displayed in a editor.
set limit to 10 ^ 15 - 1
if (endNumber > limit) then set endNumber to limit
if (startNumber > limit) then set startNumber to limit
-- Initialise the output list with 0 and the sub-1000 ebans, stopping if the end number's reached.
-- The 0's needed for rest of the process, but is removed at the end.
repeat with tens in {0, 30, 40, 50, 60}
repeat with units in {0, 2, 4, 6}
set thisEban to tens + units
if (thisEban endNumber) then set end of o's output to thisEban
end repeat
end repeat
-- Repeatedly sweep the output list, adding new ebans formed from the addition of those found previously
-- to a suitable power of 1000 times each one. Stop when the end number's reached or exceeded.
-- The output list may become very long and appending items to it individually take forever, so results are
-- collected in short, 1000-item lists, which are concatenated to the output at the end of each sweep.
set sweepLength to (count o's output)
set multiplier to 1000
repeat while (thisEban < endNumber) -- Per sweep.
set o's temp to {}
set o's listCollector to {o's temp}
repeat with i from 2 to sweepLength -- Per eban found already. (Not the 0.)
set baseAmount to (item i of o's output) * multiplier
repeat with j from 1 to sweepLength by 1000 -- Per 1000-item list.
set z to j + 999
if (z > sweepLength) then set z to sweepLength
repeat with k from j to z -- Per new eban.
set thisEban to baseAmount + (item k of o's output)
if (thisEban endNumber) then set end of o's temp to thisEban
if (thisEban endNumber) then exit repeat
end repeat
if (thisEban endNumber) then exit repeat
set o's temp to {}
set end of o's listCollector to o's temp
end repeat
if (thisEban endNumber) then exit repeat
end repeat
-- Concatentate this sweep's new lists together
set listCount to (count o's listCollector)
repeat until (listCount is 1)
set o's temp to {}
repeat with i from 2 to listCount by 2
set end of o's temp to (item (i - 1) of o's listCollector) & (item i of o's listCollector)
end repeat
if (listCount mod 2 is 1) then set item -1 of o's temp to (end of o's temp) & (end of o's listCollector)
set o's listCollector to o's temp
set o's temp to {}
set listCount to (count o's listCollector)
end repeat
-- Concatenate the result to the output list and prepare to go round again.
set o's output to o's output & (beginning of o's listCollector)
set sweepLength to sweepLength * sweepLength
set multiplier to multiplier * multiplier
end repeat
-- Lose the initial 0 and any ebans before the specified start number.
set resultCount to (count o's output)
if (resultCount is 1) then
set o's output to {}
else
repeat with i from 2 to resultCount
if (item i of o's output startNumber) then exit repeat
end repeat
set o's output to items i thru resultCount of o's output
end if
if (endNumber = limit) then set end of o's output to "(Limit of AppleScript's number precision.)"
return o's output
end getEbans
-- Task code:
on runTask()
set output to {}
set astid to AppleScript's text item delimiters
set AppleScript's text item delimiters to ", "
set ebans to getEbans(0, 1000)
set end of output to ((count ebans) as text) & " eban numbers between 0 and 1,000:" & (linefeed & " " & ebans)
set ebans to getEbans(1000, 4000)
set end of output to ((count ebans) as text) & " between 1,000 and 4,000:" & (linefeed & " " & ebans)
set end of output to ((count getEbans(0, 10000)) as text) & " up to and including 10,000"
set end of output to ((count getEbans(0, 100000)) as text) & " up to and including 100,000"
set end of output to ((count getEbans(0, 1000000)) as text) & " up to and including 1,000,000"
set end of output to ((count getEbans(0, 10000000)) as text) & " up to and including 10,000,000"
set ebans to getEbans(6.606606602E+10, 1.0E+12)
set end of output to ((count ebans) as text) & " between 66,066,066,020 and 1,000,000,000,000:" & (linefeed & " " & ebans)
set AppleScript's text item delimiters to linefeed
set output to output as text
set AppleScript's text item delimiters to astid
return output
end runTask
runTask()