Pregunta

Estoy intentando escribir un puntal que cambia un Sudoku y luego comprueba si es aún válida.

Sin embargo, no estoy seguro de cómo utilizar la función * "oneof" correctamente. ¿Me puede dar algunas pistas, por favor?

prop_candidates :: Sudoku -> Bool
prop_candidates su = isSudoku newSu && isOkay newSu
    where
        newSu       = update su aBlank aCandidate
        aCandidate  = oneof [return x | x <- candidates su aBlank]
        aBlank      = oneof [return x | x <- (blanks su)]

Éstos son algunos más información ...

type Pos = (Int, Int)
update :: Sudoku -> Pos -> Maybe Int -> Sudoku
blanks :: Sudoku -> [Pos]
candidates :: Sudoku -> Pos -> [Int]
[return x | x <- (blanks example)] :: (Monad m) => [m Pos]

He struggeled con este apoyo durante 3 horas ahora, por lo que todas las ideas son bienvenidas!

¿Fue útil?

Solución

Lo que yo quería ir a parar es que tiene un tipo de confusión. Es decir, no es un aBlank Pos, sino una Gen Pos, por lo update su aBlank aCandidate no tiene sentido! De hecho, lo que quiere es una manera de generar un nuevo sudoku dado una sudoku inicial; en otras palabras, una función

similarSudoku :: Sudoku -> Gen Sudoku

Ahora podemos escribir:

similarSudoku su = do aBlank <- elements (blanks su) 
                      -- simpler than oneOf [return x | x <- blanks su]
                      aCandidate <- elements (candidates su aBlank)
                      return (update su aBlank aCandidate)

o incluso más simple:

similarSudoku su = liftM2 (update su) (elements (blanks su)) (elements (candidates su aBlank))

Y la propiedad parece

prop_similar :: Sudoku -> Gen Bool
prop_similar su = do newSu <- similarSudoku su
                     return (isSudoku newSu && isOkay newSu)

Puesto que hay casos

Testable Bool
Testable prop => Testable (Gen prop)
(Arbitrary a, Show a, Testable prop) => Testable (a -> prop)

Sudoku -> Gen Bool es Testable así (suponiendo instance Arbitrary Sudoku).

Otros consejos

En mi blog, escribí una sencilla los dados con el simulador pruebas QuickCheck que utilizan oneof para generar rollos interesantes.

Supongamos que tenemos un super-sencilla Sudoku de una sola fila:

module Main where
import Control.Monad
import Data.List
import Test.QuickCheck
import Debug.Trace

type Pos = Int
data Sudoku = Sudoku [Char] deriving (Show)

Sin súper sencilla Sudoku debería haber repetido valores:

prop_noRepeats :: Sudoku -> Bool
prop_noRepeats s@(Sudoku xs) =
  trace (show s) $ all ((==1) . length) $
                   filter ((/='.') . head) $
                   group $ sort xs

Es posible generar un Sudoku súper sencillo con

instance Arbitrary Sudoku where
  arbitrary = sized board :: Gen Sudoku
    where board :: Int -> Gen Sudoku
          board 0 = Sudoku `liftM` shuffle values
          board n | n > 6 = resize 6 arbitrary
                  | otherwise =
                      do xs <- shuffle values
                         let removed = take n xs
                             dots = take n $ repeat '.'
                             remain = values \\ removed
                         ys <- shuffle $ dots ++ remain
                         return $ Sudoku ys

          values = ['1' .. '9']

          shuffle :: (Eq a) => [a] -> Gen [a]
          shuffle [] = return []
          shuffle xs = do x  <- oneof $ map return xs
                          ys <- shuffle $ delete x xs
                          return (x:ys)

El trace está ahí para mostrar las tablas generadas aleatoriamente:

*Main> quickCheck prop_noRepeats 
Sudoku "629387451"
Sudoku "91.235786"
Sudoku "1423.6.95"
Sudoku "613.4..87"
Sudoku "6..5..894"
Sudoku "7.2..49.."
Sudoku "24....1.."
[...]
+++ OK, passed 100 tests.

parece que aBlank :: Gen Pos que no coincide con la forma en que se utiliza como un argumento de candidates :: Sudoku -> Pos -> [Int].

He estado buscando a través de aquí encontrar una manera de convertir a Gen a a lo que permitiría su uso con los candidatos. Lo mejor que pude ver es la función generate.

Dime si me falta algo ...

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top