Chapter 4 Discussion V
Scrabble
In the game of Scrabble you try to fit a word into spaces with some letters already in place. In this question you will write a function to determine if a word fits into a certain space.
wordFits :: String -> String -> Bool
wordFits "jerk" "_or_" == False
wordFits "work" "__r_" == True
Along the way you may want to use a helper function to determine if characters from the same place match.
letterFits :: Char -> Char -> Bool
letterFits 'j' '_' == True
letterFits 'e' 'o' == False
Assume that the strings given to wordFits are the same length.
Game of 24
In the game of 24 you are supposed to find a way to combine four whole numbers using addition, subtraction, multiplication, and division, in order to get 24 as the final answer.
-
pairPossible produces all of the numbers that you can get from a single pair of numbers. Only consider the results of division when the answer is an integer.
pairPossible 3 12 == [-9,9,15,36,4] pairPossible 3 4 == [-1,1,7,12] pairPossible 49 2 == [-47,47,51,98]Danger: 49/2 is not 24, so
pairPossible 49 2should not include 24 in the list! (Trouble? See the notes below.) -
allPairs produces a list of all of the
possibletwo number pairs given a list offournumbers.allPairs :: [Int] -> [(Int,Int)] allPairs [1,2,3] == [(1,2),(1,3),(2,3)] allPairs [1,2,3,4] == [(1,2),(1,3),(1,4),(2,3),(2,4),(3,4)] -
allPossible1 produces a list of all numbers that can be produced by using any pair of numbers from the list. Duplicates are ok.
-
Finish the 24-solver. Given a list of 4 numbers, return True if is is possible to make 24 (somehow).
Examples: $(49 - 1) / (5 - 3)$ and $((15 / 3)+1)*4$ are both 24… your method should have the ability to detect both of these possibilities.
check_solve24 = [ solve24 [1,3,5,49] == True, solve24 [1,3,4,15] == True, solve24 [2,11,17,31] == False]Note: Working with fractions is optionl because it is more complex. Thanks to Sara J for pointing out that this means we will make mistakes in some circumstances, including the example
[1,5,5,5].NOTE: There are two different groupings that could lead to 24:
(((ab)c)d)and((ab)(cd)).Advice: begin by considering the
(((ab)c)d)case - the final result is built up by doing a single operation at a time on the previous result.You can use your
allPairsfunction but as you build all of the possibilities for four numbers. (See the walkthrough suggestions if posted.)
Advanced
-
Make
choose k numsthat gives allkitem subsets ofnums. For example, whenkis 3 andnumsis[1,2,3,4,5], the result should bechoose 3 [1..5] == [[1,2,3],[1,2,4],[1,2,5],[1,3,4],[1,3,5], [1,4,5],[2,3,4],[2,3,5],[2,4,5],[3,4,5]]
Notes
Many people have problems determining when a fraction is an integer. A good way to solve this problem is to determine if division will produce a fraction before you do the division. Use the integer division (quotient) and remainder functions.
The bad way to do this is:
isInt :: Float -> Bool
isInt x =
x == round x
Oops, that does not work because round produces an Integral
output. Free that up with fromIntegral:
isInt x =
x == fromIntegral (round x)
Edits 2022
The output from a “24-solver” is actually just a “24-tester”: it gives True or False, depending on whether you can make 24 with the given numbers. If you study more advanced Haskell, there is a straightforward way to convert our tester into something that actually gives a solution. (Read about the Writer monad if you want, maybe in a tutorial.
Overview
A strategy to write a “24-solver” is:
- Produce a list of all possible permutations of
[0,1,2,3], corresponding to an ordering of the four given numbers. For example,[3,2,1,0]and[3,0,1,2]should both appear in this list. - Try all of the arithmetic operations combining the items in order.
The first step working with
[a,b,c,d]would be to combineaandbusing every possible arithmetic operation. Then similarly combine that result withc, etc. This step should produce a list of all of the possible outcomes from combining the numbers. - See the note above about
(ab)(cd). - The result is True if 24 is in the list of all possibilities.
Details for Problem Solving Class
(This is a good discussion topic for an entire class period. Without a discussion it can be difficult to follow.)
The key step in this method is to generate a list of all possible
permutations. We will call the function that creates this allOrder.
allOrder :: [Int] -> [Int]
Write out examples, beginning with an input of [a], then [a,b] and
[a,b,c]. As you write the examples, look for a pattern you can use
repeatedly. Discuss with classmates. Don’t quit until you have written
out the results from allOrder [a,b,c,d].
I won’t write out the details here. They should come out of class discussion.
Side Projects
When the starting list is [100,250,600,900], then we use 0 to
represent 100 (item 0 in the list), 1 to represent 250 (item 1
in the list), etc.
The subin function takes the original list of numbers (of length n)
and a list with the representing numbers [0..n-1] in some order. It
outputs the original numbers reordered to match the order given by the
representing numbers.
subin :: [Int] -> [Int] -> [Int]
subin original representing = [0]
subin_checks = [
subin [100,250,600,900] [2,0,3,1] == [600,100,900,250]
,subin [1000,800,600,500,400] [3,4,2,0,1] == [500,400,600,1000,800]
]
Postscript
The desperate approach would be to just type the list of all possible permutations of four elements, but that’s not educational.