Primer Parcial 1er Cuat 2010 (Paradigmas)

De Cuba-Wiki

Plantilla:Back

Ejercicio 1 - Programacion funcional (40 puntos)

a) (11 puntos) Dadas las siguientes deniciones basicas para crear un juego de cartas:

data Carta = C Palo Int deriving Eq

data Palo = Oro | Basto | Espada | Copa deriving Eq type Jugador = String

Escribir la funcion repartir :: Int -> [Jugador] -> [Carta] -> [(Jugador, [Carta])] que dado un entero n, una lista de jugadores js, y un mazo (lista) de cartas cs devuelve los pares (Jugador, [Carta]) que representan la asignacion de n cartas de cs para cada uno de los jugadores de js.

Las cartas se deben repartir alternadamente entre todos los jugadores respetando el orden del mazo cs y de los jugadores js. Si el mazo no alcanza se debe asignar por igual la maxima cantidad de cartas posible por jugador. Si es necesario, puede asumirse que no hay cartas repetidas.

Ejemplos: sean js = [j1; j2; j3] y cs = [c1, c2, c3, c4, . . . ,c19, c20]

repartir 3 js cs = [ (j1, [c1, c4, c7]), (j2, [c2, c5, c8]), (j3, [c3, c6, c9]) ]

repartir 10 js cs = [ (j1, [c1, c4, c7, c10, c13, c16]), (j2, [c2, c5, c8, c11, c14, c17]), (j3, [c3, c6, c9, c12, c15, c18]) ]

Sugerencia: usar la funcion cycle del Prelude, que dada una lista devuelve la concatenacion infinita de esa lista consigo misma.

RESPUESTA

data Carta = C Palo Int deriving (Eq,Show)

data Palo = Oro | Basto | Espada | Copa deriving (Eq,Show)

--data Palo = Pique | Corazon | Trebol | Diamante deriving (Eq,Show)

type Jugador = String

j1 = ["Cochi", "Diego", "Eric", "Martin C"]

c1 = [C Pique 1 , C Corazon 3, C Diamante 5, C Trebol 7, C Pique 2, C Corazon 4, C Diamante 6, C Trebol 8, C Pique 9]

jc = zip j1 c1

--Devuelve una lista de funciones donde la funcion i devuelve true si se le pasa como parámetro el jugador i.
listaFuncionEsJugadorX:: [Jugador] -> [(Jugador, Carta) -> Bool]
listaFuncionEsJugadorX js = map (\j -> \jc -> (fst jc) == j) js
--Reparte las mayor cantidad de cartas a cada jugador a todos la misma cantidad
listaJugadorCarta:: [Jugador] -> [Carta] -> [(Jugador,Carta)]
listaJugadorCarta js cs = reverse (zip (cycle js) (drop ((length cs) `mod` (length js)) (reverse cs)))
--Dada una lista de tuplas (Jugador Carta) une todas las cartas en una lista para devolver una lista de (Jugador, [Carta]), (el jugador deberia ser el mismo)
juntar:: Int -> [(Jugador, Carta)] -> [(Jugador, [Carta])]
juntar i jcs = [(fst (head jcs), foldr (\jc jcs -> [snd jc] ++ jcs ) [] (take i jcs))]
--Reparte las cartas a todos los jugadores i cartas a cada uno
repartir::Int -> [Jugador] -> [Carta] -> [(Jugador, [Carta])]
repartir i js cs = foldr (\f jc -> jc ++ (juntar i (filter f (listaJugadorCarta js cs)))) [] (listaFuncionEsJugadorX js)

nota: hay puestos algunos reverse en el codigo, esto de debe a que al resolver terminos la recursion termina devolviendolos de atras para adelante por lo que para mantener el orden del mazo primero lo invertimos asi la recursion comienza por devolver el primero.