Setting a variable to an operation? (+ - * /)

Is there any way to do this? If you can’t, is there any way to do a random operation that has not been done yet? I am trying make a script that can find every possible equation that can be made from a set of numbers and operations.

Hello.

This should work:

set nmbrs to {1, 2, 3, 4, 5, 5, 6, 6}
set ops to {"-", "+", "/", "*"}

on calc(num1, op, num2)
	if op = "/" and num2 ≠ 0 then
		log num1 & "/" & num2 & " = " & (num1 / num2)
	else if op = "*" then
		log num1 & "*" & num2 & " = " & (num1 * num2)
	else if op = "-" then
		log num1 & "-" & num2 & " = " & (num1 - num2)
	else if op = "+" then
		log num1 & "+" & num2 & " = " & (num1 + num2)
	else
		log "Div/0"
	end if
end calc

repeat 5 times
	
	set num1 to some item of nmbrs
	set num2 to some item of nmbrs
	set op to some item of ops
	calc(num1, op, num2)
	
end repeat

I added what kind of operation performed in the log statements, to make it more interresting. :slight_smile:

Hi.

You’d have to be a bit more precise about what you meant by “every possible equation that can be made from a set of numbers and operations.” eg. A fixed number of numbers and/or operators per equation? Operators only used once each per equation?

To answer the question about non-repeating random choices, you can either keep making random choices until you hit on one which hasn’t been made before (not recommended, though perhaps not too disastrous with a limited number of choices) or do something like this:

-- A list of operators, each represented textually to make this possible.
set ops to {"-", "+", "/", "*"} -- Thanks to McUsr II. ;)

set c to (count ops)

-- Set up a list of consecutive integers from 1 to the number of operators.
set ints to {}
repeat with i from 1 to c
	set end of ints to i
end repeat

-- Pick the operators randomly, one at a time and once only.
repeat c times
	-- Choose an integer at random from the integer list.
	set n to some integer of ints -- 'some number' also works, should you have more than 2 ^ 29 - 1 operators.  ;)
	-- Get the operator (ie. text) indexed by the integer in the operator list.
	set thisOp to item n of ops
	log thisOp -- Or take an appropriate action associated with the operator the text represents.
	
	-- Eliminate the chosen integer from the integer list (index = the integer itself) with a non-integer.
	set item n of ints to missing value
end repeat

what i meant by this would be something like you give the script a couple of numbers and operations and it makes all possible equations

example 1, 5, 2, 3 and +, -,*

15-2+3 = (answer here)
1-2+3
5 = (answer here)
etc.

in a dialog or something

Hello.

The solution is kind of cheating, but then again, I don’t have to invent a whole machinery in AppleScript, hopefully this solution works for you. if you need to raise something to a power, then [b][/b] is the operator (2**14 = 16384), and % is the modulus operator (4%3=1).:slight_smile:

on main()
	set paper to {}
	set oldClip to the clipboard as record
	set equation to " 2+14*7-12*8 "
	set the clipboard to equation
	repeat
		tell application (path to frontmost application as text)
			try
				set equation to text returned of (display dialog "Enter a computation: " default answer equation with title "Simple Calc")
				-- Command "." cancels.
			on error
				exit repeat
			end try
		end tell
		try
			-- use the line below if you want to calculate solely on integers.
			--			set answer to do shell script "/bin/bash -c \"echo $(( " & equation & ")) \""
			-- Use the line below if you want to perform calculations on decimal numbers
			-- "." is then the Decimal separator you must use!
			set answer to do shell script " echo '" & equation & "' | bc"
			set the clipboard to answer
		on error
			set answer to ""
		end try
		if answer = "" then
			set displayText to "The equation: " & equation & " isn't wellformed."
		else
			set displayText to equation & " = " & answer
			set end of paper to displayText
			set the clipboard to answer
		end if
		
		
		tell application (path to frontmost application as text)
			display alert displayText
		end tell
	end repeat
	if length of paper > 0 then
		try
			set answ to button returned of (display dialog "Do you want to paste your computations to the clipboard?" buttons {"No", "Yes"} cancel button 1 default button 2 with title "Simple Calc")
		on error
			set answ to "No"
		end try
		if answ = "Yes" then
			set {tids, AppleScript's text item delimiters} to {AppleScript's text item delimiters, return}
			set paper to paper as text
			set AppleScript's text item delimiters to tids
			set the clipboard to paper
		else
			set the clipboard to oldClip
		end if
	else
		set the clipboard to oldClip
	end if
end main
main()

I am not sure if you are aware of it, so I’ll just mention, that you can perform calculations like that in the Spotlight search bar, it knows about powers (^), logarithms, (ln), and e (Exp), if it gets out of hand, then you can open the calculation in Calculator, which has “paper”, nifty!

Edit
I added a dialog, so it is easier to enter calculations. Hit Cmd -“.” to cancel the “data entry” dialog to quit.

I now store any wellformed calculation onto the clipboard, so you can use the previous result in the next calculation, by pasting it into the “data-entry” dialog.
I also added an opportunity to save the calculations to the clipboard upon quit, so that you can paste the equations with the results somewhere else, otherwise, I restore the clipboard to the contents it had before we started to compute equations.

You may note that I have wrapped it all into a main() handler, I have done that, to be pretty much sure, that the “paper” list is clear when we start, because variable that are declared at the top level, in a script, gets stored with the script, in this particular case, I have to start afresh, for the list to have the correct contents, and I chose this approach out of several other alternatives.

I still only works with integers, and that is a big constraint.

Edit++

I changed it to work with floating point numbers, NB the decimal separator is you must use is “.”, and the exponentiation operator has changed from ** to ^, now you should also be able to use parenthesis to signify the order in which operations are performed, it is still a very coarse thing, but it is now at least usable for practical purposes other than integers.

This page with ‘bc’ examples shows how and what kind of operations it can perform. :slight_smile:

OK. So what’s really needed is an “all permutations” process rather than an “random choice” one, although random choice could then be used to determine the order in which the permutations were presented to the user.

The script below just lists the equations in permutation order. Each permutation is unique, but there are many which are mathematically identical, such as:

1+3-52 = (answer here)
1+3-2
5 = (answer here)
3+1-25 = (answer here)
3+1-5
2 = (answer here)

I can’t think of a convenient way to weed out such duplicates at the moment.


-- The numbers and operators (in text form) to use this time.
set nums to {1, 5, 2, 3}
set ops to {"+", "-", "*"}

-- Generate all possible permutations of the numbers.
set allNumPerms to allPermutations(nums)

-- Assuming there's one fewer operators than numbers, arrange the number permutations round the operators to create a text containing all the equations.
set allEquations to ""
set c to (count nums)
repeat with thisPerm in allNumPerms
	set equation to ""
	repeat with i from 1 to c - 1
		set equation to equation & item i of thisPerm & item i of ops
	end repeat
	set allEquations to allEquations & (equation & item c of thisPerm & " = (answer here)" & return)
end repeat
set allEquations to text 1 thru -2 of allEquations

-- Display the results in a form where the user can enter the answers.
display dialog "Do these sums:" default answer allEquations

on allPermutations(theList)
	(*
	allPermutations() by Nigel Garvey, 2004.
	Returns a list containing all possible permutations of a given list.
	Not recommended for lists of more than about 8 items, owing to the number of permutations generated!
	Based on Sedgewick's "Improved version of Heap's method (recursive)" algorithm.
	*)
	script o
		property workList : missing value
		property permutations : {}
		property r : count theList -- index of the rightmost item
		property m : r - 1 -- index of the middle item of the last three
		
		on prmt(l)
			-- l is the index of the leftmost item affected by this iteration
			set n to r - l + 1 -- n is the number of list items affected by this iteration (l thru r)
			
			if n = 3 then
				-- These six permutations are hard-coded to reduce low-level recursion
				copy my workList to the end of my permutations
				
				set {v1, v2, v3} to items l thru r of my workList
				
				set item m of my workList to v3
				set item r of my workList to v2
				copy my workList to the end of my permutations
				
				set item l of my workList to v2
				set item r of my workList to v1
				copy my workList to the end of my permutations
				
				set item m of my workList to v1
				set item r of my workList to v3
				copy my workList to the end of my permutations
				
				set item l of my workList to v3
				set item r of my workList to v2
				copy my workList to the end of my permutations
				
				set item m of my workList to v2
				set item r of my workList to v1
				copy my workList to the end of my permutations
			else
				-- Precalculate some values for the repeat
				set lPlus1 to l + 1 -- parameter for next-level recursions
				set nIsEven to (n mod 2 = 0) -- true if n is even
				set x to r -- the default index with which to swap if n is odd
				
				-- Get all permutations of items (l +1) thru r with the current item l
				prmt(lPlus1)
				-- Repeat with successive values of item l
				repeat with i from r to lPlus1 by -1
					-- If n is even, swap items l and i, otherwise default to swapping items l and r
					if nIsEven then set x to i
					tell item x of my workList
						set item x of my workList to item l of my workList
						set item l of my workList to it
					end tell
					prmt(lPlus1)
				end repeat
			end if
		end prmt
		
	end script
	
	if o's r < 3 then
		-- Special-case lists of less than three items
		copy theList to the beginning of o's permutations
		if o's r is 2 then set the end of o's permutations to the reverse of the beginning of o's permutations
	else
		-- Otherwise use the recursive handler
		copy theList to o's workList
		o's prmt(1)
	end if
	
	return o's permutations
	
end allPermutations

Hello Nigel.

Amazing, both your script, and also the difference in perceiving the problem.

What if you used this:

set answer to do shell script "/bin/bash -c \"echo $(( " & equation & ")) \""

, and built up a list with the answers during the course as you created the permutations. Then afterwards you could check the corresponding operations for having the same operators and the same numbers.

I just sense, that it should work out correctly, since pieces that contains the same numbers, and the same operators must necessarily be perceived as the “same” equation. :slight_smile: -At least there are two expressions, that contains the same bits, and gives the same result, so at least the “commutatively equal” expressions, can be eliiminated.

Here’s another version of the script in post #6, based on the fact that nightfury2986’s example also has the operators in different permutions. (Depending on the operators and whether or not they’re unique, this could have mathematical implications.) The order of the resulting set of equations is randomised using the method from post #3. [Edit: now changed to the use of ‘random number’ and an in-place shuffle.] The hope is that this will produce a more “interesting” random result and that any mathematic duplicates will be less noticeable. The number of possible permutations with four numbers and three operators is 144, so the text is simply returned here instead of being displayed.

Further edit: the equations now include their results instead of “(answer here)”.


-- The numbers and operators (in text form) to use this time.
set nums to {1, 5, 2, 3}
set ops to {"+", "-", "*"}

-- Generate all possible permutations of the numbers and of the operators.
set allNumPerms to allPermutations(nums)
set allOpPerms to allPermutations(ops)

-- Assuming there's one fewer operators than numbers, arrange the number permutations round the operator permutations to create a list containing all the possible equations.
set allEquations to {}
set c to (count nums)
repeat with thisOpPerm in allOpPerms
	repeat with thisPerm in allNumPerms
		set equation to ""
		repeat with i from 1 to c - 1
			set equation to equation & item i of thisPerm & item i of thisOpPerm
		end repeat
		set equation to equation & item c of thisPerm
		set end of allEquations to equation & " = " & (run script equation)
	end repeat
end repeat

-- Randomise the list of equations.
repeat with i from (count allEquations) to 1 by -1
	set n to (random number from 1 to i)
	tell item i of allEquations
		set item i of allEquations to item n of allEquations
		set item n of allEquations to it
	end tell
end repeat

-- Coerce the randomised list to a return-delimited text.
set astid to AppleScript's text item delimiters
set AppleScript's text item delimiters to return
set allEquations to allEquations as text
set AppleScript's text item delimiters to astid

return allEquations


on allPermutations(theList)
	(*
	allPermutations() by Nigel Garvey, 2004.
	Returns a list containing all possible permutations of a given list.
	Not recommended for lists of more than about 8 items, owing to the number of permutations generated!
	Based on Sedgewick's "Improved version of Heap's method (recursive)" algorithm.
	*)
	script o
		property workList : missing value
		property permutations : {}
		property r : count theList -- index of the rightmost item
		property m : r - 1 -- index of the middle item of the last three
		
		on prmt(l)
			-- l is the index of the leftmost item affected by this iteration
			set n to r - l + 1 -- n is the number of list items affected by this iteration (l thru r)
			
			if n = 3 then
				-- These six permutations are hard-coded to reduce low-level recursion
				copy my workList to the end of my permutations
				
				set {v1, v2, v3} to items l thru r of my workList
				
				set item m of my workList to v3
				set item r of my workList to v2
				copy my workList to the end of my permutations
				
				set item l of my workList to v2
				set item r of my workList to v1
				copy my workList to the end of my permutations
				
				set item m of my workList to v1
				set item r of my workList to v3
				copy my workList to the end of my permutations
				
				set item l of my workList to v3
				set item r of my workList to v2
				copy my workList to the end of my permutations
				
				set item m of my workList to v2
				set item r of my workList to v1
				copy my workList to the end of my permutations
			else
				-- Precalculate some values for the repeat
				set lPlus1 to l + 1 -- parameter for next-level recursions
				set nIsEven to (n mod 2 = 0) -- true if n is even
				set x to r -- the default index with which to swap if n is odd
				
				-- Get all permutations of items (l +1) thru r with the current item l
				prmt(lPlus1)
				-- Repeat with successive values of item l
				repeat with i from r to lPlus1 by -1
					-- If n is even, swap items l and i, otherwise default to swapping items l and r
					if nIsEven then set x to i
					tell item x of my workList
						set item x of my workList to item l of my workList
						set item l of my workList to it
					end tell
					prmt(lPlus1)
				end repeat
			end if
		end prmt
		
	end script
	
	if o's r < 3 then
		-- Special-case lists of less than three items
		copy theList to the beginning of o's permutations
		if o's r is 2 then set the end of o's permutations to the reverse of the beginning of o's permutations
	else
		-- Otherwise use the recursive handler
		copy theList to o's workList
		o's prmt(1)
	end if
	
	return o's permutations
	
end allPermutations

Hello Nigel.

I didn’t see the randomizing at first. The unordering provides a good variety.

Yeah. I hope it gives nightfury2986 something with which to work.

I’ve been thinking about the randomisation process though. I used the integer-list method because AppleScript’s ‘some’ reference is so much faster than the StandardAdditions’s ‘random number’ ” even without referencing the list variable ”that you can add in the times taken to build the integer list and then replace its integers with missing values and still finish ahead of ‘random number’! With the 144-item lists here though, the difference is only .005 seconds on my machine, so I’ve decided to simplify things by dispensing with both the integer list and the additional list for the rearranged equations. Instead there’s an in-place rearrangement of the original equation list, using ‘random number’ to decide the swaps. Edited in post #8 above.

ok thanks! but, i actually wanted the (answer here) to be an answer, and it was 2 AM so i really didn’t want to do math
so i just put an (answer here) >.< sorry for the confusion

Hello. I actually read the code in a hurry, and just sort of ran it, sort of without thinking.

So I ran back, and wrote what a good idea it was to permute from left to right, for us that read from left to right, then the left side changes the most often, and maybe that camouflages the ordering that is there?

I also had fun with counting the number of combinations, since the permuted list is really combinations of permutatins, 4*3^2 (Cartesian product).

It was an interesting thread. :slight_smile:

I think the algorithm in Sedgewick’s booklet changed from the left. But after I transcribed it for AppleScript, I did a from-the-right version too, which I much preferred precisely because of the more ordered look of the results! I couldn’t immediately lay my hands on either script today, but eventually tracked down the from-the-right version in an old post to the MACSCRPT mailing list. That’s the version used above.

Luckily, the day’s work wasn’t wasted. The change only required a small adjustment in the code populating the equation list. That’s now done in the script in post #8. :slight_smile:

Thanks!