-- | -- Module : Mastermind -- Description : Puntuación del mastermind. -- Copyright : Exercitium (25-04-14) -- License : GPL-3 -- Maintainer : JoseA.Alonso@gmail.com -- -- El Mastermind es un juego que consiste en deducir un código -- numérico formado por una lista de números distintos. Cada vez que se -- empieza un partido, el programa debe elegir un código, que será lo -- que el jugador debe adivinar en la menor cantidad de intentos -- posibles. Cada intento consiste en una propuesta de un código posible -- que propone el jugador, y una respuesta del programa. Las respuestas -- le darán pistas al jugador para que pueda deducir el código. -- -- Estas pistas indican cuán cerca estuvo el número propuesto de la -- solución a través de dos valores: la cantidad de aciertos es la -- cantidad de dígitos que propuso el jugador que también están en el -- código en la misma posición. La cantidad de coincidencias es la -- cantidad de digitos que propuso el jugador que también están en el -- código pero en una posición distinta. -- -- Por ejemplo, si el código que eligió el programa es el [2,6,0,7], y -- el jugador propone el [1,4,0,6], el programa le debe responder un -- acierto (el 0, que está en el código original en el mismo lugar, el -- tercero), y una coincidencia (el 6, que también está en el código -- original, pero en la segunda posición, no en el cuarto como fue -- propuesto). Si el jugador hubiera propuesto el [3,5,9,1], habría -- obtenido como respuesta ningún acierto y ninguna coincidencia, ya que -- no hay números en común con el código original, y si se obtienen -- cuatro aciertos es porque el jugador adivinó el código y ganó el -- juego. -- -- Definir la función -- -- > mastermind :: [Int] -> [Int] -> (Int,Int) -- -- tal que __(mastermind xs ys)__ es el par formado por los números de -- aciertos y de coincidencias entre xs e ys. Por ejemplo, -- -- >>> mastermind [2,6,0,7] [1,4,0,6] -- (1,1) -- >>> mastermind [2,6,0,7] [3,5,9,1] -- (0,0) -- >>> mastermind [2,6,0,7] [1,6,0,4] -- (2,0) -- >>> mastermind [2,6,0,7] [2,6,0,7] -- (4,0) module Mastermind where import Data.List (nub) import Test.QuickCheck -- | 1ª definición mastermind :: [Int] -> [Int] -> (Int,Int) mastermind xs ys = ( length (aciertos xs ys) , length (coincidencias xs ys)) -- | (aciertos xs ys) es la lista de aciertos entre xs e ys. Por -- ejemplo, -- -- >>> aciertos [2,6,0,7] [1,4,0,6] -- [0] aciertos :: Eq a => [a] -> [a] -> [a] aciertos xs ys = [x | (x,y) <- zip xs ys , x == y] -- | (coincidencia xs ys) es la lista de coincidencias entre xs e ys. Por -- ejemplo, -- -- >>> coincidencias [2,6,0,7] [1,4,0,6] -- [6] coincidencias :: Eq a => [a] -> [a] -> [a] coincidencias xs ys = [x | x <- xs , x `elem` ys , x `notElem` zs] where zs = aciertos xs ys -- | 2ª definición (por recursión): mastermind2 :: [Int] -> [Int] -> (Int,Int) mastermind2 xs ys = aux xs ys where aux (u:us) (z:zs) | u == z = (a+1,b) | u `elem` ys = (a,b+1) | otherwise = (a,b) where (a,b) = aux us zs aux _ _ = (0,0) -- | 3ª definición: mastermind3 :: [Int] -> [Int] -> (Int,Int) mastermind3 xs ys = (nAciertos,nCoincidencias) where nAciertos = length [(x,y) | (x,y) <- zip xs ys, x == y] nCoincidencias = length (xs++ys) - length (nub (xs++ys)) - nAciertos -- | (prop_mastermind xs) se verifica si todas las definiciones -- de mastermind son equivalentes para xs. Por ejemplo, -- -- >>> prop_mastermind [2,6,0,7] [1,4,0,6] -- True -- >>> prop_mastermind [2,6,0,7] [3,5,9,1] -- True -- >>> prop_mastermind [2,6,0,7] [1,6,0,4] -- True -- >>> prop_mastermind [2,6,0,7] [2,6,0,7] -- True prop_mastermind :: [Int] -> [Int] -> Bool prop_mastermind xs ys = all (== mastermind cs ds) [f cs ds | f <- [ mastermind2 , mastermind3]] where as = nub xs bs = nub ys n = min (length as) (length bs) cs = take n as ds = take n bs -- | Comprueba la equivalencia de las definiciones -- -- >>> verifica_mastermind -- +++ OK, passed 100 tests. verifica_mastermind :: IO () verifica_mastermind = quickCheck prop_mastermind