(* --- "From Theorems to Algorithms", from Section 4.10 --- *) fun commonDivisors(a, b) = let (* helper function comDiv: what are the common divisors of a and b that are less than or equal to n? *) fun comDiv(1) = [1] | comDiv(n) = if a mod n = 0 andalso b mod n = 0 then n::comDiv(n-1) else comDiv(n-1); in comDiv(if a < b then a else b) end; fun greatest([x]) = x | greatest(y::rest) = let val z = greatest(rest) in if y > z then y else z end; fun gcd(a, b) = greatest(commonDivisors(a, b)); fun gcd(a, 0) = a | gcd(a, b) = gcd(b, a mod b); (* Ex 4.10.2 --- exponentiation *) fun pow(x, y) = let fun powHelper(a, b, 0) = a | powHelper(a, b, n) = powHelper(a * b, b, n-1) in powHelper(1, x, y) end; (* For Exercise 4.10.3, make a variation on the version of pow above, not the one below without b. *) fun pow(x, y) = let fun powHelper(a, 0) = a | powHelper(a, n) = powHelper(a * x, n-1) in powHelper(1, y) end; (* Ex 4.10.5 -- quotient-remainder *) fun quotRem(n, d) = let fun qrt(q, r) = if r < d then (q, r) else qrt(q+1, r-d) in qrt(0, n) end; (* Ex 4.10.6 --- HW *) fun frlog(a, b) = (* The parameter bn means "b^n", that is, b raised to the nth power. Having that as a parameter makes this problem easier. *) let fun helper(bn, n, r) = if ?? then ?? else helper(??, ??, ??) in helper(??, ??, ??) end; (* --- "Bulls and Cows" example from Section 4.11 starts here. --- *) (* Code from section 4.11 *) fun contains(x, []) = false | contains(x, y::rest) = if x = y then true else contains(x, rest); fun count([]) = 0 | count(x::rest) = 1 + count(rest); fun makeNoRepeats([]) = [] | makeNoRepeats(x::rest) = if contains(x, rest) then makeNoRepeats(rest) else x::makeNoRepeats(rest); fun isValidGuess(a,b,c,d) = 0 < a andalso a < 10 andalso 0 <= b andalso b < 10 andalso 0 <= c andalso c < 10 andalso 0 <= d andalso d < 10 andalso count(makeNoRepeats([a, b, c, d])) = 4; val soln = ref (4, 7, 2, 1); val guesses = ref 0; fun resetGuesses() = (soln := (2, 6, 4, 9); guesses := 0); fun numTrue([]) = 0 | numTrue(false::rest) = numTrue(rest) | numTrue(true::rest) = 1 + numTrue(rest); fun bullsAndCows((a,b,c,d), (aa, bb, cc, dd)) = (numTrue([a = aa, b = bb, c = cc, d = dd]), numTrue([contains(a, [bb, cc, dd]), contains(b, [aa, cc, dd]), contains(c, [aa, bb, dd]), contains(d, [aa, bb, cc])])); fun checkGuess(a, b, c, d) = if isValidGuess(a, b, c, d) then let val (bulls, cows) = bullsAndCows((a, b, c, d), !soln); in (guesses := !guesses + 1; print("Guess # " ^ Int.toString(!guesses) ^ "\n"); print("bulls: " ^ Int.toString(bulls) ^ "\n"); print("cows: " ^ Int.toString(cows) ^ "\n"); if bulls = 4 then print ("Correct!\n") else ()) end else print("Invalid guess.\n"); val guessList = ref ([]:(int*int*int*int) list); fun listify([]) = [] | listify(a::rest) = [a] :: listify(rest); fun addToEach(x, []) = [] | addToEach(x, a::rest) = (x::a)::addToEach(x, rest); fun addEachToEach([], y) = [] | addEachToEach(a::aRest, y) = addToEach(a, y)@addEachToEach(aRest, y); fun enumerateCombinations(x, 1) = listify(x) | enumerateCombinations(x, r) = addEachToEach(x, enumerateCombinations(x, r-1)); fun makeGuessesTuples([]) = [] | makeGuessesTuples([a,b,c,d]::rest) = (a, b, c, d)::makeGuessesTuples(rest); fun removeInvalid([]) = [] | removeInvalid(a::rest) = if isValidGuess(a) then a::removeInvalid(rest) else removeInvalid(rest); fun printGuess(a, b, c, d) = print(Int.toString(a) ^ " " ^ Int.toString(b) ^ " " ^ Int.toString(c) ^ " " ^ Int.toString(d) ^ "\n"); val currentGuess = ref (0,0,0,0); fun firstGuess() = (guessList := removeInvalid(makeGuessesTuples( enumerateCombinations([0,1,2,3,4,5,6,7,8,9], 4))); currentGuess := hd(!guessList); guessList := tl(!guessList); printGuess(!currentGuess)); fun removeInfeasible(bulls, cows, []) = [] | removeInfeasible(bulls, cows, a::rest) = if bullsAndCows(!currentGuess, a) = (bulls, cows) then a::removeInfeasible(bulls, cows, rest) else removeInfeasible(bulls, cows, rest); fun guessAgain(bulls, cows) = (guessList := removeInfeasible(bulls, cows, !guessList); currentGuess := hd(!guessList); guessList := tl(!guessList); printGuess(!currentGuess));