RosettaCodeData/Task/Josephus-problem/AppleScript/josephus-problem-3.applescript

143 lines
3.3 KiB
AppleScript

-- josephusSurvivor :: Int -> Int -> Int
on josephusSurvivor(n, k)
script go
on |λ|(x, a)
(k + x) mod a
end |λ|
end script
foldl(go, 0, enumFromTo(1, n))
end josephusSurvivor
-- josephusSequence :: Int -> Int -> [Int]
on josephusSequence(n, k)
script josephus
on |λ|(m, xs)
if 0 m then
set {l, r} to splitAt((k - 1) mod m, xs)
{item 1 of r} & |λ|(m - 1, rest of r & l)
else
{}
end if
end |λ|
end script
|λ|(n, enumFromTo(0, n - 1)) of josephus
end josephusSequence
--------------------------- TEST ---------------------------
on run
unlines({"Josephus survivor -> " & str(josephusSurvivor(41, 3)), ¬
"Josephus sequence ->" & linefeed & tab & ¬
showList(josephusSequence(41, 3))})
end run
---------------- REUSABLE GENERIC FUNCTIONS ----------------
-- enumFromTo :: Int -> Int -> [Int]
on enumFromTo(m, n)
if m n then
set lst to {}
repeat with i from m to n
set end of lst to i
end repeat
lst
else
{}
end if
end enumFromTo
-- foldl :: (a -> b -> a) -> a -> [b] -> a
on foldl(f, startValue, xs)
tell mReturn(f)
set v to startValue
set lng to length of xs
repeat with i from 1 to lng
set v to |λ|(v, item i of xs, i, xs)
end repeat
return v
end tell
end foldl
-- map :: (a -> b) -> [a] -> [b]
on map(f, xs)
-- The list obtained by applying f
-- to each element of xs.
tell mReturn(f)
set lng to length of xs
set lst to {}
repeat with i from 1 to lng
set end of lst to |λ|(item i of xs, i, xs)
end repeat
return lst
end tell
end map
-- mReturn :: First-class m => (a -> b) -> m (a -> b)
on mReturn(f)
-- 2nd class handler function lifted into 1st class script wrapper.
if script is class of f then
f
else
script
property |λ| : f
end script
end if
end mReturn
-- intercalate :: String -> [String] -> String
on intercalate(delim, xs)
set {dlm, my text item delimiters} to ¬
{my text item delimiters, delim}
set str to xs as text
set my text item delimiters to dlm
str
end intercalate
-- showList :: [a] -> String
on showList(xs)
script show
on |λ|(x)
x as text
end |λ|
end script
"[" & intercalate(",", map(show, xs)) & "]"
end showList
-- splitAt :: Int -> [a] -> ([a], [a])
on splitAt(n, xs)
if n > 0 and n < length of xs then
if class of xs is text then
{items 1 thru n of xs as text, ¬
items (n + 1) thru -1 of xs as text}
else
{items 1 thru n of xs, items (n + 1) thru -1 of xs}
end if
else
if n < 1 then
{{}, xs}
else
{xs, {}}
end if
end if
end splitAt
-- str :: a -> String
on str(x)
x as string
end str
-- unlines :: [String] -> String
on unlines(xs)
-- A single string formed by the intercalation
-- of a list of strings with the newline character.
set {dlm, my text item delimiters} to ¬
{my text item delimiters, linefeed}
set str to xs as text
set my text item delimiters to dlm
str
end unlines