Acciones

Relación 25

De Informática de 1º de Matemáticas [Curso 2021-22, Grupo 3]

Revisión del 20:49 4 abr 2022 de Alvgalber (discusión | contribs.)
(difs.) ← Revisión anterior | Revisión actual (difs.) | Revisión siguiente → (difs.)
-- I1M 2021-22: Relación 25
-- Funciones de entrada/salida: El dilema de Monty Hall
-- Departamento de Ciencias de la Computación e Inteligencia Artificial
-- Universidad de Sevilla
-- ============================================================================

-- ============================================================================
-- Librerías auxiliares
-- ============================================================================

import System.Random
import Data.List
import Data.Char

-- ============================================================================
-- Monty Hall es el nombre de un conocido presentador de televisión en
-- Estados Unidos. En uno de sus concursos, se presenta el siguiente dilema:
--
-- El concursante debe elegir una de entre tres puertas cerradas y el premio
-- consiste en llevarse lo que se encuentra detrás de la puerta elegida.
-- Se sabe con certeza que una de las puertas encierra un coche y que las otras
-- dos tienen sendas cabras (se entiende que el concursante prefiere llevarse
-- el coche antes que una cabra).
--
-- Una vez que el concursante haya elegido una puerta, el presentador, que sabe
-- lo que encierra cada puerta, abrirá una de las otras dos, mostrando siempre
-- una cabra.
--
-- A continuación, le da la opción al concursante de cambiar, si lo desea, de
-- puerta o quedarse con su elección original.
--
-- Vamos a plantear un programa interactivo que permita recrear la
-- participación del concursante en el dilema de Monty Hall
-- ============================================================================

-- ----------------------------------------------------------------------------
-- Representación
-- ----------------------------------------------------------------------------

-- Denominaremos a las puertas por los enteros 1, 2 y 3.

-- ----------------------------------------------------------------------------
-- Ejercicio 1. Definir la acción de E/S
--   escojaPuerta :: IO Int
-- que interactúe con el jugador para que decida qué puerta escoger, dando los
-- correspondientes mensajes (se debe devolver un entero entre 1 y 3),
-- por ejemplo:
--   escojaPuerta     =>
--     Que puerta elige? c
--     ERROR: Entrada incorrecta
--     Que puerta elige? 4
--     ERROR: Entrada incorrecta
--     Que puerta elige? 2
--     2
-- ----------------------------------------------------------------------------

-- Álvaro Galisteo: 

escojaPuerta :: IO Int
escojaPuerta = do putStrLn "Que puerta elige? "
                  x <- getLine
                  if x == "1" || x == "2" || x == "3"
                     then return (read x :: Int) 
                     else do putStrLn "ERROR: Entrada incorrecta"
                             escojaPuerta

-- ----------------------------------------------------------------------------
-- Ejercicio 2. Definir la acción
--   ponPremio :: IO Int
-- tal que devuelva la puerta que contiene el premio del concurso.
-- Para ello se debe seleccionar de forma aleatoria un valor entero entre 1 y 3:
--   ponPremio        =>
--   3
-- ----------------------------------------------------------------------------

-- Álvaro Galisteo: 

ponPremio :: IO Int
ponPremio = randomRIO (1::Int,3)

-- ----------------------------------------------------------------------------
-- Ejercicio 3. Definir la función
--   abrePuerta :: Int -> Int -> IO Int
-- tal que (abrePuerta concursante premio) devuelve el número de una puerta que
-- abre el presentador. La puerta devuelta nunca puede ser la que contiene el
-- premio ni la que ha escogido el concursante, y, en caso de que el jugador
-- haya elegido la puerta con premio, se debe escoger aleatoriamente entre las
-- otras dos.
--    abrePuerta 1 1 =>
--    2 (pero podía haber sido la 3)
--    abrePuerta 1 1 =>
--    3 (pero podía haber sido la 2)
--    abrePuerta 1 2 =>
--    3 (obligada)
--    abrePuerta 1 3 =>
--    2 (obligada)
-- ----------------------------------------------------------------------------

-- Álvaro Galisteo: 

abrePuerta :: Int -> Int -> IO Int
abrePuerta c p = if c == p
                    then do r <- randomRIO (0::Int,1)
                            return ((filter f [1,2,3])!!r)   
                    else return (head (filter f [1,2,3]))
                where f x = x /= c && x /= p

-- ----------------------------------------------------------------------------
-- Ejercicio 4. Definir la acción
--   otraPuerta :: Int -> Int -> Int
-- tal que (otraPuerta concursante abierta) devuelve el número de la puerta que
-- no es igual a la del concursante ni a la que ya está abierta (se supone
-- que "concursante" es distinto de "abierta").
--    otraPuerta 1 2 =>
--    3
--    otraPuerta 2 1 =>
--    3
--    otraPuerta 3 1 =>
--    2
-- ----------------------------------------------------------------------------

-- Álvaro Galisteo: 

otraPuerta :: Int -> Int -> Int
otraPuerta c a = head (filter f [1,2,3])
                where f x = x /= c && x /= a

-- ----------------------------------------------------------------------------
-- Ejercicio 5. Definir la acción
--   cambiaPuerta :: Int -> Int -> IO Int
-- tal que (cambiaPuerta concursante cerrada) devuelve el número de la puerta
-- que el concursante al final termina escogiendo después de haberle dado a
-- elegir entre "mantener" la elección original "concursante" o "cambiar" a
-- la "cerrada".
--   cambiaPuerta 1 3    =>
-- Concursante, digame, prefiere mantener su decision original, la puerta 1 [mantener]
-- o quiere cambiar a la puerta 3 [cambiar]? mantener
-- 1
-- Concursante, digame, prefiere mantener su decision original, la puerta 1 [mantener]
-- o quiere cambiar a la puerta 3 [cambiar]? cambiar
-- 3
-- ----------------------------------------------------------------------------

-- Álvaro Galisteo: 

cambiaPuerta :: Int -> Int -> IO Int
cambiaPuerta con cer = do putStr ("Concursante, digame, prefiere mantener su decision original, la puerta "++(show con)++" [mantener] o quiere cambiar a la puerta "++(show cer)++" [cambiar]? ")
                          x <- getLine
                          if x == "mantener"
                             then return con
                             else if x == "cambiar"
                                     then return cer
                                     else cambiaPuerta con cer 

-- ----------------------------------------------------------------------------
-- Ejercicio 6. Definir la acción
--   concurso :: IO ()
-- tal que se describa una ronda completa del concurso de Monty Hall.
--    concurso      =>
-- Muy bien, concursante, aqui tiene tres puertas, una de ellas esconde un
-- coche y las otras dos, sendas cabras.
-- Que puerta elige? 1
-- Pues ahora abramos la puerta 2:
-- Vaya, hay una CABRA!
-- Concursante, digame, prefiere mantener su decision original, la puerta 1 [mantener]
-- o quiere cambiar a la puerta 3 [cambiar]? mantener
-- Bien, pues abramos la puerta 1: Y hay un COCHE, enhorabuena!
--   ó
-- Bien, pues abramos la puerta 1: Y hay una CABRA, lo sentimos mucho!
-- Juegue varias veces. ¿Qué estrategia es mejor, mantener o cambiar?
-- ¿Con qué probabilidad nos llevamos el coche si escogemos "mantener"?
-- ¿Con qué probabilidad nos llevamos el coche si escogemos "cambiar"?
-- ----------------------------------------------------------------------------

-- Álvaro Galisteo: 

concurso :: IO ()
concurso = do putStrLn "Muy bien, concursante, aqui tiene tres puertas, una de ellas esconde un coche y las otras dos, sendas cabras."
              x <- escojaPuerta
              y <- ponPremio
              w <- abrePuerta x y
              putStrLn ("Pues ahora abramos la puerta " ++ show w ++ ":")
              putStrLn "Vaya, hay una CABRA!"
              z <- cambiaPuerta x (otraPuerta x w)
              if z == y
                 then putStrLn ("Bien, pues abramos la puerta "++show z++": Y hay un COCHE, enhorabuena!")
                 else putStrLn ("Bien, pues abramos la puerta "++show z++": Y hay una CABRA, lo sentimos mucho!")


-- ----------------------------------------------------------------------------
-- Ejercicio 7. Definir la acción
--   estrategiaMantener :: IO Int
-- tal que devuelva un 1 si en una ronda del concurso, el jugador se llevó
-- el premio o 0 en caso contrario. Suponga que el jugador siempre escoge
-- mantener su decisión original.
--
-- Para ello:
-- 1. Seleccione de forma aleatoria una puerta para el premio.
-- 2. Seleccione de forma aleatoria una puerta para el concursante.
-- 3. Abra una de las puertas que contiene un cabra sin que sea la del concursante.
-- 4. Mantenga la decisión del concursante.
-- 5. Devuelva el valor adecuado dependiendo del resultado.
-- ----------------------------------------------------------------------------

-- Álvaro Galisteo: 

estrategiaMantener :: IO Int
estrategiaMantener = do p <- ponPremio
                        c <- randomRIO (1::Int,3)
                        a <- abrePuerta p c 
                        if p == c
                           then return 1 
                           else return 0
  
-- ----------------------------------------------------------------------------
-- Ejercicio 8. Definir la acción
--   estrategiaCambiar :: IO Int
-- tal que devuelva un 1 si en una ronda del concurso, el jugador se llevó
-- el premio o 0 en caso contrario. Suponga que el jugador siempre escoge
-- cambiar su decisión original.
--
-- Para ello:
-- 1. Seleccione de forma aleatoria una puerta para el premio.
-- 2. Seleccione de forma aleatoria una puerta para el concursante.
-- 3. Abra una de las puertas que contiene un cabra sin que sea la del concursante.
-- 4. Cambie la decisión del concursante a la puerta que queda sin abrir.
-- 5. Devuelva el valor adecuado dependiendo del resultado.
-- ----------------------------------------------------------------------------

-- Álvaro Galisteo: 

estrategiaCambiar :: IO Int
estrategiaCambiar = do p <- ponPremio
                       c <- randomRIO (1::Int,3)
                       a <- abrePuerta p c 
                       if p == (otraPuerta c a)
                          then return 1 
                          else return 0

-- ----------------------------------------------------------------------------
-- Ejercicio 9. Definir la acción
--   ejecutaEstrategia :: Int -> IO Int -> IO Int
-- tal que (ejecutaEstrategia n estrategia) ejecuta de forma consecutiva n veces
-- la estrategia pasada como segundo argumento. Devuelve el número de veces que
-- el concursante se llevó el premio. Por ejemplo:
--   ejecuta 100 estrategiaMantener   =>
--   30
--   ejecuta 100 estrategiaCambiar    =>
--   68
-- ----------------------------------------------------------------------------

-- Álvaro Galisteo: 

ejecutaEstrategia :: Int -> IO Int -> IO Int
ejecutaEstrategia n estrategia = ejecutaAux n estrategia 0

ejecutaAux :: Int -> IO Int -> Int -> IO Int
ejecutaAux n e xs = do y <- e
                       if n == 0
                          then return xs
                          else ejecutaAux (n-1) e (xs+y)


-- ----------------------------------------------------------------------------
-- Ejercicio 10.
-- ¿Cuál es número mínimo de personas que debe haber en una fiesta para
-- tener una probabilidad del 50% de que al menos dos de ellas tengan el mismo
-- cumpleaños?
-- ----------------------------------------------------------------------------

-- Álvaro Galisteo: 

-- 23 personas