RosettaCodeData/Task/Balanced-ternary/AppleScript/balanced-ternary-1.applescript

169 lines
6.0 KiB
AppleScript

-- Build a balanced ternary, as text, from an integer value or acceptable AppleScript substitute.
on BTFromInteger(n)
try
if (n mod 1 is not 0) then error (n as text) & " isn't an integer value"
set n to n as integer
on error errMsg
display alert "BTFromInteger handler: parameter error" message errMsg buttons {"OK"} default button 1 as critical
error number -128
end try
if (n is 0) then return "0"
-- Positive numbers' digits will be indexed from the beginning of a list containing them, negatives' from the end.
-- AppleScript indices are 1-based, so get the appropriate 1 or -1 add-in.
set one to 1
if (n < 0) then set one to -1
set digits to {"0", "+", "-", "0"}
-- Build the text digit by digit.
set bt to ""
repeat until (n = 0)
set nMod3 to n mod 3
set bt to (item (nMod3 + one) of digits) & bt
set n to n div 3 + nMod3 div 2 -- + nMod3 div 2 adds in a carry when nMod3 is either 2 or -2.
end repeat
return bt
end BTFromInteger
-- Calculate a balanced ternary's integer value from its characters' Unicode numbers.
on integerFromBT(bt)
checkInput(bt, "integerFromBT")
set n to 0
repeat with thisID in (get bt's id)
set n to n * 3
-- Unicode 48 is "0", 43 is "+", 45 is "-".
if (thisID < 48) then set n to n + (44 - thisID)
end repeat
return n
end integerFromBT
-- Add two balanced ternaries together.
on addBTs(bt1, bt2)
checkInput({bt1, bt2}, "addBTs")
set {longerLength, shorterLength} to {(count bt1), (count bt2)}
if (longerLength < shorterLength) then set {bt1, bt2, longerLength, shorterLength} to {bt2, bt1, shorterLength, longerLength}
-- Add the shorter number's digits into a list of the longer number's digits, adding in carries too where appropriate.
set resultList to bt1's characters
repeat with i from -1 to -shorterLength by -1
set {carry, item i of resultList} to sumDigits(item i of resultList, character i of bt2)
repeat with j from (i - 1) to -longerLength by -1
if (carry is "0") then exit repeat
set {carry, item j of resultList} to sumDigits(carry, item j of resultList)
end repeat
if (carry is not "0") then set beginning of bt1 to carry
end repeat
-- Zap any leading zeros resulting from the cancelling out of the longer number's MSD(s).
set j to -(count resultList)
repeat while ((item j of resultList is "0") and (j < -1))
set item j of resultList to ""
set j to j + 1
end repeat
return join(resultList, "")
end addBTs
-- Multiply one balanced ternary by another.
on multiplyBTs(bt1, bt2)
checkInput({bt1, bt2}, "multiplyBTs")
-- Longer and shorter aren't critical here, but it's more efficient to loop through the lesser number of digits.
set {longerLength, shorterLength} to {(count bt1), (count bt2)}
if (longerLength < shorterLength) then set {bt1, bt2, shorterLength} to {bt2, bt1, longerLength}
set multiplicationResult to "0"
repeat with i from -1 to -shorterLength by -1
set d2 to character i of bt2
if (d2 is not "0") then
set subresult to ""
-- With each non-"0" subresult, begin with the appropriate number of trailing zeros.
repeat (-1 - i) times
set subresult to "0" & subresult
end repeat
-- Prepend the longer ternary as is.
set subresult to bt1 & subresult
-- Negate the result if the current multiplier from the shorter ternary is "-".
if (d2 is "-") then set subresult to negateBT(subresult)
-- Add the subresult to the total so far.
set multiplicationResult to addBTs(multiplicationResult, subresult)
end if
end repeat
return multiplicationResult
end multiplyBTs
-- Negate a balanced ternary by substituting the characters obtained through subtracting its sign characters' Unicode numbers from 88.
on negateBT(bt)
checkInput(bt, "negateBT")
set characterIDs to bt's id
repeat with thisID in characterIDs
if (thisID < 48) then set thisID's contents to 88 - thisID
end repeat
return string id characterIDs
end negateBT
(* Private handlers. *)
on checkInput(params as list, handlerName)
try
repeat with thisParam in params
if (thisParam's class is text) then
if (join(split(thisParam, {"-", "+", "0"}), "") > "") then error "\"" & thisParam & "\" isn't a balanced ternary number."
else
error "The parameter isn't text."
end if
end repeat
on error errMsg
display alert handlerName & " handler: parameter error" message errMsg buttons {"OK"} default button 1 as critical
error number -128
end try
end checkInput
-- "Add" two balanced ternaries and return both the carry and the result for the column.
on sumDigits(d1, d2)
if (d1 is "0") then
return {"0", d2}
else if (d2 is "0") then
return {"0", d1}
else if (d1 = d2) then
if (d1 = "+") then
return {"+", "-"}
else
return {"-", "+"}
end if
else
return {"0", "0"}
end if
end sumDigits
on join(lst, delimiter)
set astid to AppleScript's text item delimiters
set AppleScript's text item delimiters to delimiter
set txt to lst as text
set AppleScript's text item delimiters to astid
return txt
end join
on split(txt, delimiter)
set astid to AppleScript's text item delimiters
set AppleScript's text item delimiters to delimiter
set lst to txt's text items
set AppleScript's text item delimiters to astid
return lst
end split
-- Test code:
set a to "+-0++0+"
set b to BTFromInteger(-436) --> "-++-0--"
set c to "+-++-"
set line1 to "a = " & integerFromBT(a)
set line2 to "b = " & integerFromBT(b)
set line3 to "c = " & integerFromBT(c)
tell multiplyBTs(a, addBTs(b, negateBT(c))) to ¬
set line4 to "a * (b - c) = " & it & " or " & my integerFromBT(it)
return line1 & linefeed & line2 & linefeed & line3 & linefeed & line4