Reputation: 165
I'm new to Haskell and I am trying to generate an random weighted number for an arbitrary cell in a Sudoku
90% of the time, it should generate Nothing
10% of the time, it should generate a random value between 1 and 9
This is what I have came up with so far (it does not compile)
-- cell generates an arbitrary cell in a Sudoku
-- cell :: Gen (Maybe Int)
cell = case x of 1 -> return (Just y); _ -> return Nothing
where std = mkStdGen(100)
(x, a) = randomR(1, 10) std
(y, a')= randomR(1, 9) std
Any help in getting it to compile, or by pointing me towards a better approach is much appreciated
Using Quickcheck this is how I did it:
-- cell generates an arbitrary cell in a Sudoku
cell :: Gen (Maybe Int)
cell = frequency [(9, return Nothing),
(1, do r <- choose (1,9); return (Just r))]
-- an instance for generating Arbitrary Sudokus
instance Arbitrary Sudoku where
arbitrary =
do rows <- sequence [ sequence [ cell | j <- [1..9] ] | i <- [1..9] ]
return (Sudoku rows)
Upvotes: 1
Views: 369
Reputation: 14598
If you are using QuickCheck, you certainly don't want a cell
to a pure value - randomR (0,100) (mkStdGen 43434343)
is not random whatsoever, so it will be useless to you for testing.
Since you are using QuickCheck, you need to use QuickCheck functions. You cannot easily use System.Random
nor should you. Simply use the (quite powerful) QuickCheck API, which has a function choose :: Random a => (a,a) -> Gen a
, which picks a random number in the range, and a function frequency :: [(Int, Gen a)] -> Gen a
which selects a random generator, based on its weight, ie the likelihood, and returns that generator. You can write cell
as:
cell :: Gen (Maybe Int)
cell = frequency
[ (1, Just `fmap` choose (1,9))
, (9, return Nothing)
]
Then, for example, if you define your Sudoku board as data Sudoku = Sudoku [[Maybe Int]]
, you can easily write an Arbitrary
instance for it using cell
:
import Control.Monad (replicateM)
instance Arbitrary Sudoku where
arbitrary = Sudoku `fmap` replicateM 9 (replicateM 9 cell)
Upvotes: 2