Minesweeper board labels (beginner level) - list

We were given a homework, where we get a sample minesweeper-like board, with blank spaces instead of numbers (board is in [String] form) and already placed mines. What we need is to create a function, that replaces all blank spaces with numbers, which are equal to number of adjecent mines.
I was unable of making any real progress, except for removing all spaces with zeroes, which is probably not even useful in any way. I also had a problem with zeroes being of Char type, which made me unable to add for example +1 to it. It would be great if this could be solved without advanced functions, so I can understand it, but any solution or at least idea of solution will do.
This is what the beginning of the code should look like.
import Data.Char
type Result = [String]
pp :: Result -> IO ()
pp x = putStr (concat (map (++"\n") x)) --prints strings in a column.
sampleInput = [" ",
" * ",
" * ",
" * ",
" *",
"*** ",
"* * ",
"*** "]
minesweeper :: Result -> Result
And result should be this
Prelude>pp(minesweeper sampleInput)
1110000
1*11110
1122*10
001*221
233211*
***2011
*8*3000
***2000
I'm incredibly glad for any guidance as I'm unable of any real progress.
Update: Did a bit different yet similar solution. You can check related question here

What you need here is called "stencil convolution". Look at this picture:
111
1x1
111
This is your stencil. Pick a tile on the playing board and place the stencil on top of that tile.
How many 1s overlay mines, that number we should display in this tile. For example:
..... .....
111 .*... .....
1x1 + ..x*. = ..3..
111 ...*. .....
..... .....
Once we apply this operation to the whole board, we are basically done.
There are advanced devices for this, such as comonads and arrays, but for the purpose of this post
I will keep things simple, so we are going to draft everything by hand, in the simplest types. I
am also going to leave some blanks in the code, so that it is less boring for the reader. If you
enable -fdefer-typed-holes, you can put things like _wut in place of ... and ghc
will tell you what it thinks the type of the hole should be.
I should like to deal with numbers, rather than characters: as you point out, characters
are ill-suited for algorithmic work. Conversion should be two way, so that we can display our
result as well.
charsToInts :: [[Char]] -> [[Int]]
charsToInts = (fmap . fmap) charToInt
where
charToInt '*' = ...
charToInt ... = ...
intsToChars :: [[Int]] -> [[Char]]
intsToChars = ...
A nested list is not a very comfortable type to work with. We will define some helper functions
to make it easier. The operation that we will surely need is "indexing", that is, accessing an
element by its index — if it is there in the first place.
lookup2DMaybe :: [[a]] -> (Int, Int) -> Maybe a
lookup2DMaybe u (i, j) = do
xs' <- lookupMaybe xs i
x <- ...
return x
where
lookupMaybe :: [a] -> Int -> Maybe a
lookupMaybe xs i
| 0 <= i && i < length xs = ...
| ... = ...
Now, to interesting stuff — stencil application.
applyStencil :: [[Int]] -> (Int, Int) -> Int
applyStencil u = sum . Data.Maybe.catMaybes . fmap (... u) . stencil
where
stencil :: (Int, Int) -> [(Int, Int)]
stencil (i, j) = [ (i + di, ...) | di <- ..., dj <- ..., (di, dj) /= ... ]
Does this work?
λ applyStencil (charsToInts sampleInput) (3, 5)
2
λ applyStencil (charsToInts sampleInput) (6, 1)
8
All that is left to do is to "map" the stencil all around the minefield. To this end, we are
going to generate a board where at every point its coordinates are written. I hope somewhere along
the way you will see why.
indices :: [[a]] -> [[(Int, Int)]]
indices u = [ [ ... | ... ] | ... ]
The idea here is that we give it a board of anything, and it creates a board of coordinates of
the same size.
Consider the type we have so far:
λ :type applyStencil (charsToInts sampleInput)
applyStencil (charsToInts sampleInput) :: (Int, Int) -> Int
So, this is a function that converts coordinates to the number of mines around these
coordinates. What happens if we map it over a board of coordinates?
fill :: [[Int]] -> [[Int]]
fill u = (fmap.fmap) (... u) (... u)
λ intsToChars (fill (charsToInts sampleInput))
["1110000","1011110","1122110","0011221","2332110","2422011","4843000","2422000"]
Looks about right, does it not?
Only small things left to do: given two boards of characters, overlay them. This is outlined in
an answer to another question about lists of lists. (We get a lot of of questions of this
kind of late. Say hi to your professor from the Stack Overflow Haskell Teacher's Assistants
Team!)
Final solution!
minesweeper x = overlay x (intsToChars . fill . charsToInts $ x)
Not hard at all!
There are some ways to improve this code:
Create a specialized type for the board, such that only correct boards can be constructed.
Define a comonad for that type.
Scratch the type altogether and generalize the code to the Store comonad.
Use efficient array processing.
But the ideas we explored are there to last.
Some further reading:
The basics of stencil convolution.
The use of standard comonad types.
Advanced optimization of stencil convolution.
Let me know how it goes!

Related

Beginner question: Problems using a function on each combination of two lists of a custom type

I'm currently studying for an exam in an entry level university course in which we use Haskell mainly to simulate combinational circuits. I have basic problems with Haskell itself, knowing next to nothing of functional programming and coming from a basic level of understanding of Java which further complicates things.
I am trying to build a function which uses and prints all combinations of two lists of my custom type in a comparator. I am working with the following (working as intended) snippets:
type Nibble = (Bool, Bool, Bool, Bool)
comparator :: Nibble -> Nibble -> Bool
comparator (a3,a2,a1,a0) (b3,b2,b1,b0) = nor [a3<+>b3, a2<+>b2, a1<+>b1, a0<+>b0]
Using list comprehension I got a list containing all 4-tuples of my custom type. I am trying to use each element of my two lists to get the output of comparator for every possible combination of my custom type.
I tried building a function that takes the head of each of two lists and uses them with the comparator function to then recursively start with the rest of the list. I struggle with basically every part of that function and I think I am going down the wrong path.
I am looking for resources that can point me in the right direction/ towards the right concepts I need to look at and maybe a suggestion on how I should approach similar problems since I struggle with the concept of functional programming and combining multiple functions. I have no idea where and how to start. I'm working with learnyouahaskell however they seem to jump from very easy to quite complex examples very quickly while skipping most topics I need.
I'd much appreciate if anyone could point me in a direction. Thanks a lot in advance!
Please excuse any shortcomings in the description of my problem. Its my first time writing anything on stackoverflow. I will clarify everything I missed in edits.
Edit:Thanks for the feedback, I'm trying to clarify but I'm struggling with both, the language, the vocabulary, my distinct lack of programming skills and the understanding of the terminology required.
The comparator function intends to simulate a comparator circuit by testing whether two 4-bit numbers, here represented by Nibbles, are the same. I intend to try this function on every possible combination of two 4-bit numbers. My idea was to take a list
nibTab = [(a,b,c,d) | a <- [False, True], b <- [False, True],c <- [False, True],d <- [False, True]], using it as input list 1 and input list 2. Both lists are supposed to look like this, which I think I already achieved:
[(True, True, True, True), (True,True,True,False),...,(False,False,False,False)]
I'm trying to print a string for each comparison and with the two answers actually got it to work.
compRow :: [String]
compRow =
[show x ++ " , " ++ show y ++ " : " ++ show (comparator x y)
| x <- nibTab, y <- nibTab]
where
nibTab = [(a,b,c,d) | a <- [False, True], b <- [False, True],c <- [False, True],d <- [False, True]]
compList :: [String] -> String
compList [] = ""
compList (x:xs) = show x ++ "\n" ++ compList xs
I had a smaller example to work with. Here we checked whether our definition of an XOR-Operator worked as intended. I got lost trying to identify how the type signatures for my task at hand had to look like and with writing appropriate functions that tried to imitate the example below:
(<+>) :: Bool -> Bool -> Bool
(<+>) a b = (a || b) && (not (a && b))
table_row :: (Bool -> Bool -> Bool) -> (Bool, Bool) -> String
table_row f (x, y) = show (x,y)++ ":" ++ show (f x y)
table :: (Bool -> Bool -> Bool) -> [(Bool, Bool)] -> String
table f [] = ""
table f (x:xs) = table_row f x ++ "\n" ++ table f xs
checkTable = do
let bool_duo [(a,b) | a <- [False,True], b <- [False,True]]
putStrLn (table (<+>) bool_duo)
You have already seen list comprehensions. You can use that to call a function with all the elements in a list you already have. E.g.
results :: [String]
results =
[ "The square of " ++ show x ++ " is " ++ show (square x)
| x <- allInputs ]
where
square y = y*y
allInputs = [0..10] -- an example
Above, square only has one argument. If you have more, add a generator to the list comprehension.
results :: [String]
results =
[ "The comparison of " ++ show x ++ " and " ++ show y
++ " is " ++ show (comparator x y)
| x <- allInputs, y <- allInputs ]
where
allInputs = .... -- your list with all the inputs to try
If you don't want a list of strings, adapt accordingly.
It's hard to figure out what you want to do, but my best guess is something like this:
bools = [True, False]
all_nibbles = [(a,b,c,d) | a <- bools, b <- bools, c <- bools, d <- bools]
all_results = [comparator x y | x <- all_nibbles, y <- all_nibbles]
This code uses list comprehensions to first build a list of all possible nibbles, then compute the results of your function when applied to all possible combinations of nibbles.
For future reference:
in Haskell, (a,b,c,d) is a tuple:
tuples are fixed-length, and
each element of a tuple can have a different type.
in Haskell, [a,b,c,d] is a list:
lists are variable-length, and
each element of a list must have the same type

How do I combine consectuive numbers in a list into a range in Haskell?

I'm trying to grapple my head around Haskell and I'm having a hard time pinning down the general procedure/algorithm for this specific task. What I want to do is basically give Haskell a list [1,2,3,5,6,9,16,17,18,19] and have it give me back [1-3, 5, 6, 9, 16-19] so essentially turning three or more consecutive numbers into a range in the style of lowestnumber - highestnumber. What I have issue with it I suppose is the all too common difficulty grappling with with the functional paradigm of Haskell. So I would really appreciate a general algorithm or an insight into how to view this from an "Haskellian" point of view.
Thanks in advance.
If I understand the question correctly, the idea is to break up the input lists in chunks, where a chunk is either a single input element or a range of at least three consecutive elements.
So, let's start by defining a datatype for representing such chunks:
data Chunk a = Single a | Range a a
As you can see, the type is parametric in the type of input elements.
Next, we define a function chunks to actually construct a list of chunks from a list of input elements. For this, we require the ability to compare input elements and to obtain the immediate consecutive for a given input element (that is, its successor). Hence, the type of the function reads
chunks :: (Eq a, Enum a) => [a] -> [Chunk a]
Implementation is relatively straightforward:
chunks = foldr go []
where
go x (Single y : Single z : cs) | y == succ x && z == succ y = Range x z : cs
go x (Range y z : cs) | y == succ x = Range x z : cs
go x cs = Single x : cs
We traverse the list from right to left, generating chunks as we go. We generate a range if an input element precedes its two immediate consecutive elements (the first case of the helper function go) or if it precedes a range that starts with its immediate consecutive (the second case). Otherwise, we generate a single element (the final case).
To arrange for pretty output, we declare applications of the type constructor Chunk to be instances of the class Show (given that the type of input elements is in Show):
instance Show a => Show (Chunk a) where
show (Single x ) = show x
show (Range x y) = show x ++ "-" ++ show y
Returning to the example from the question, we then have:
> chunks [1,2,3,5,6,9,16,17,18,19]
[1-3,5,6,9,16-19]
Unfortunately, things are slightly more complicated if we need to account for bounded element types; such types have a largest element for which succ is undefined:
> chunks [maxBound, 1, 2, 3] :: [Chunk Int]
*** Exception: Prelude.Enum.succ{Int}: tried to take `succ' of maxBound
This suggests that we should abstract from the specific approach for determining whether one elements succeeds another:
chunksBy :: (a -> a -> Bool) -> [a] -> [Chunk a]
chunksBy succeeds = foldr go []
where
go x (Single y : Single z : cs) | y `succeeds` x && z `succeeds` y =
Range x z : cs
go x (Range y z : cs) | y `succeeds` x = Range x z : cs
go x cs = Single x : cs
Now, the version of chunks that was given above, can be expressed in terms of chunksBy simply by writing
chunks :: (Eq a, Enum a) => [a] -> [Chunk a]
chunks = chunksBy (\y x -> y == succ x)
Moreover, we can now also implement a version for bounded input types as well:
chunks' :: (Eq a, Enum a, Bounded a) => [a] -> [Chunk a]
chunks' = chunksBy (\y x -> x /= maxBound && y == succ x)
That merrily gives us:
> chunks' [maxBound, 1, 2, 3] :: [Chunk Int]
[9223372036854775807,1-3]
First, all elements of a list must be of the same type. Your resulting list has two different types. Ranges (for what ever that means) and Ints. We should convert one single digit into a range with lowest and highest been the same.
Been said so, You should define the Range data type and fold your list of Int into a list of Range
data Range = Range {from :: Int , to :: Int}
intsToRange :: [Int] -> [Range]
intsToRange [] = []
intsToRange [x] = [Range x x]
intsToRange (x:y:xs) = ... -- hint: you can use and auxiliar acc which holds the lowest value and keep recursion till find a y - x differece greater than 1.
You can also use fold, etc... to get a very haskelly point of view
Use recursion. Recursion is a leap of faith. It is imagining you've already written your definition and so can ("recursively") call it on a sub-problem of your full problem, and combine the (recursively calculated) sub-result with the left-over part to get the full solution -- easy:
ranges xs = let (leftovers, subproblem) = split xs
subresult = ranges subproblem
result = combine leftovers subresult
in
result
where
split xs = ....
combine as rs = ....
Now, we know the type of rs in combine (i.e. subresult in ranges) -- it is what ranges returns:
ranges :: [a] -> rngs
So, how do we split our input list xs? The type-oriented design philosophy says, follow the type.
xs is a list [a] of as. This type has two cases: [] or x:ys with x :: a and ys :: [a]. So the easiest way to split a list into a smaller list and some leftover part is
split (x:xs) = (x, ys)
split [] = *error* "no way to do this" -- intentionally invalid code
Taking note of the last case, we'll have to tweak the overall design to take that into account. But first things first, what's the rngs type could be? Going by your example data, it's a list of rngs, naturally, rngs ~ [rng].
A rng type though, we have a considerable degree of freedom to make it to be whatever we want. The cases we have to account for are pairs and singletons:
data Rng a = Single a
| Pair a a
.... and now we need to fit the jagged pieces together into one picture.
Combining a number with a range which starts from consecutive number is obvious.
Combining a number with a single number will have two obvious cases, for whether those numbers are consecutive or not.
I think / hope you can proceed from here.

Haskell list length alternative

Hi I've got a list on Haskell with close to 10^15 Int's in it and I'm trying print the length of the list.
let list1 = [1..1000000000000000] -- this is just a dummy list I dont
print list1 length -- know the actual number of elements
printing this takes a very long time to do, is there another way to get the number of elements in the list and print that number?
I've occasionally gotten some value out of lists that carry their length. The poor man's version goes like this:
import Data.Monoid
type ListLength a = (Sum Integer, [a])
singletonLL :: a -> ListLength a
singletonLL x = (1, [x])
lengthLL :: ListLength a -> Integer
lengthLL (Sum len, _) = len
The Monoid instance that comes for free gives you empty lists, concatenation, and a fromList-alike. Other standard Prelude functions that operate on lists like map, take, drop aren't too hard to mimic, though you'll need to skip the ones like cycle and repeat that produce infinite lists, and filter and the like are a bit expensive. For your question, you would also want analogs of the Enum methods; e.g. perhaps something like:
enumFromToLL :: Integral a => a -> a -> ListLength a
enumFromToLL lo hi = (fromIntegral hi-fromIntegral lo+1, [lo..hi])
Then, in ghci, your example is instant:
> lengthLL (enumFromToLL 1 1000000000000000)
1000000000000000

To leave in the list items whose values coincide with the numbers of their positions in the list

I need to change list for example:
[1,2,4,6,5,10]
To this one
[1,2,5] (the list of elements that are on correct position).
1st element value is 1 - ok,
element value is 2 - ok,
3rd element value is 4 but expected 3 (due to the index)- remove
and etc. How can I solve the error which is attached below?
My code:
module Count where
import Control.Monad.State
nthel n xs = last xsxs
where xsxs = take n xs
deleteNth i items = take i items ++ drop (1 + i) items
repeatNTimes 0 _ = return ()
repeatNTimes n xs =
do
if (n == nthel n xs) then return()
else deleteNth (n-1) xs
repeatNTimes (n-1) xs
list = [1,2,3,4,5]
main = repeatNTimes (length list) list
I have the following error:
* Couldn't match type `Int' with `()'
Expected type: [()]
Actual type: [Int]
* In the expression: deleteNth (n - 2) xs
In a stmt of a 'do' block:
if (n == nthel n xs) then return () else deleteNth (n - 2) xs
In the expression:
do { if (n == nthel n xs) then return () else deleteNth (n - 2) xs;
repeatNTimes (n - 1) xs }
A really nice way to work with this is to stitch functions together. First one might need to get to know the functions in the Data.List module, which you can find with hoogle: http://hoogle.haskell.org
Data.List Module functions
I'll give you a little bit of a boost here. The functions I would pick out are the zip function: https://hackage.haskell.org/package/base-4.9.1.0/docs/Data-List.html#v:zip whose type is [a] -> [b] -> [(a, b)] and then the filter function https://hackage.haskell.org/package/base-4.9.1.0/docs/Prelude.html#v:filter whose type is (a -> Bool) -> [a] -> [a] and then the map function whose type is (a -> b) -> [a] -> [b] along with the fst :: (a, b) -> a
Function Composition
These functions can be stitched together using the function composition operator: (.) :: (b -> c) -> (a -> b) -> a -> c it takes two functions that share a common input/output point (in the type signature they are the second and first parameters, respectively; a -> b and b -> c) and it will then join them into one single function.
Stacking it up - required knowledge
In order to do what you want to do, you really need to know about simple types, parameterised types, ranges (including lazy infinite ranges would help), functions and possibly recursion as well some higher order functions and how Haskell functions are curried, and to understand function composition. It wouldn't hurt to add a basic understanding of what typeclasses do and are into the mix.
I helped author a tutorial which can really help with understanding how this stuff works from a usage point of view by following a series of interesting examples. It's not too long, and you might find it much easier to approach your problem once you have understood some of the more foundational stuff: http://happylearnhaskelltutorial.com — note that it's not tuned to teaching you how to construct stuff, that'll be coming in a later volume, but it should give you enough understanding to be able to at least guess at an answer, or understand the one below.
The Answer - spoilers
If you want to work this out yourself, you should stop here and come back later on when you're feeling more confident. However, I'm going to put one possible answer just below, so don't look if you don't want to know yet!
positionals :: (Enum a, Eq a, Num a) => [a] -> [a]
positionals = map fst . filter (\(x, y) -> x == y) . zip [1..]
Keep in mind this is only one way of doing this. There are simpler more explanatory ways to do it, and while it might possibly seem inefficient, Haskell has list/stream fusion which compiles that function into something that will do a single pass across your data.

Changing the value in a tuple of tuples conditionally in Haskell

I'm working on 3-tuples of 3-tuples ((a,b,c),(d,e,f),(g,h,i)). Now I want to take this tuple as input and as output generate a list of tuples in which an element is changed to a value if it had a certain value.
Example:
changefromtovalue :: a -> a -> ((a,a,a),(a,a,a),(a,a,a)) -> [((a,a,a),(a,a,a),(a,a,a))]
changefromtovalue 1 5 ((0,1,2),(1,2,3),(2,3,4)) results in [((0,5,2),(1,2,3),(2,3,4)),((0,1,2)(5,2,3)(2,3,4))]
Now i'm not using integers, but the idea stays the same i think.
First I thought I wanted some kind of map, but that would change all values at once, instead of making a list with 1 element changed each.
Then I thought, I can just make all variations (in the example [((5,x,x)..),((x,5,x)..),((x,x,5)..)] and somehow drop the ones that don't meet the requirements, but I can't figure out a clean way to drop the unwanted ones.
I've tried searching and found some information about making a data specification for the tuple, but I fail to see how that would really simplify this particular problem.
Converting to a list and working with the list and then converting back seemed easier, but it still requires a weird kind of selection. If possible I'd like to avoid using a lot of conversions.
What I'm looking for is a suggestion that leads to a clean way, not a full cut-out line of code.
With the additional information you provided in a comment, we can solve this using Richard Bird's approach:
We instead represent the grid as a list of lists. We then replace each element in the grid with a list of the choices we can make for it. In your example, 1 becomes [1,5] (we either choose a 1 or a 5) and n becomes [n] (for everything else, there are no alternative choices).
choice :: Int -> [Int]
choice 1 = [1,5]
choice n = [n]
Then we make this choice for each element:
choices :: [[Int]] -> [[[Int]]]
choices = map (map choice)
Now comes the tricky part. We reduce a grid of choices to a choice of grids, which can be done using the general cartesian product of a list:
cp :: [[a]] -> [[a]]
cp [] = [[]]
cp (xs:xss) = [y:ys | y <- xs, ys <- cp xss]
We collapse a grid of choices like so:
collapse :: [[[a]]] -> [[[a]]]
collapse = cp . map cp
This works by first collapsing a list of rows of choices (a.k.a a grid of choices) into list of choices of rows and then collapsing the list of choices of rows into a choice of lists of rows, a.k.a, a choice of grids.
Finally, we specify a solver by first making the choices and then collapsing them:
solve :: [[Int]] -> [[[Int]]]
solve = collapse . choices
For example:
> mapM_ print (solve [[0,1,2],[1,2,3],[2,3,4]])
[[0,1,2],[1,2,3],[2,3,4]]
[[0,1,2],[5,2,3],[2,3,4]]
[[0,5,2],[1,2,3],[2,3,4]]
[[0,5,2],[5,2,3],[2,3,4]]
Hopefully this also demonstrates how converting the tuples to a list of lists makes this task easier.
Note: Some of you may have noticed that cp is sequence for the list applicative. This means we can also equivalently write:
solve' = sequence . map sequence . choices
With tuples you have to write:
change x y ((a,b,c),(d,e,f),(g,h,i))
= ((z a, z b, z c), (z d, z e, z f), (z g, z h, z i))
where z w = if w == x then y else w
Life would be easier if you used a list (or an array) to represent your 3x3 grid.