1votos

Poker Kata en Haskell

por josejuan hace 6 años

Si nuestro programa correrá en un dispositivo con poco almacenamiento deben usarse algoritmos de cálculo directo, pero en general, es mucho más sencillo y fácil generar todas las combinaciones de interés y precalcularlas en alguna base de datos (ej. unos archivos). Las funciones resultantes son muy sencillas. Se generan todas las combinaciones posibles, con y sin comodines.

Conviértete en un jugador de poker profesional y averigua la combinación ganadora que tienes entre tus manos.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
{-# LANGUAGE BangPatterns #-} 
import Data.List (nub, sort) 
import Control.Parallel 
import Control.Parallel.Strategies 
import System.Environment (getArgs) 
import Data.Char (toUpper) 
 
data Palo = O | C | E | B deriving (Eq, Enum, Show, Read, Ord) 
data Olap = N1 | N2 | N3 | N4 | N5 | N6 | N7 | N8 | N9 | N0 | NJ | NQ | NK deriving (Eq, Enum, Show, Read, Ord) 
data Carta = Mono | Carta { palo :: Palo, olap :: Olap } deriving (Eq, Show, Read, Ord) 
 
palos = enumFromTo O B 
olaps = enumFromTo N1 NK 
 
baraja = [Carta p o | p <- palos, o <- olaps] 
baraja' = Mono: Mono: baraja 
 
-- Obtiene una baraja completa excepto las cartas indicadas 
recortarBaraja cartas = filter (not.flip elem cartas) baraja' 
 
-- Si tenemos una jugada en 'n' cartas, es obvio que cambiando cartas por monos 
-- tendremos como mínimo la misma jugada. La siguiente función toma una jugada y 
-- genera las versiones con monos: 
conMonos' n !jugada = map (Mono:) (comb (n - 1) jugada) ++ map ((Mono:).(Mono:)) (comb (n - 2) jugada) 
conMonos n !jugada = jugada: conMonos' n jugada 
 
-- Dada una jugada, todas las manos que la contienen es (como mínimo) esa misma jugada. 
-- Esta función genera todas las manos que contienen una jugada: 
jugadasJugada' n !jugada = map (jugada++) $ comb (5 - n) $ recortarBaraja jugada 
jugadasJugada n = concat . (parMap rseq) (jugadasJugada' n) . conMonos n 
jugadasJugadas n = concat . (parMap rseq) (jugadasJugada n) 
 
-- Devuelve todas las n-tuplas de mismo olap y diferentes palos 
tuplaOlap n = concatMap (t n) olaps 
  where t n o = [map (flip Carta o) c | c <- comb n palos] 
 
-- Representar todas las manos ahora es muy sencillo:   
manos_ER = jugadasJugadas 5 $ [map (Carta p) es| p <- palos] where es = N1:enumFromTo N0 NK 
manos_EC = jugadasJugadas 5 $ concatMap (\es -> [map (Carta p) es| p <- palos]) [take 5 $ enumFrom w | w <- enumFromTo N1 N9] 
manos_PO = jugadasJugadas 4 $ tuplaOlap 4 
manos_FU = jugadasJugadas 5 $ filter ((5==).length) [ nub (t ++ p) | t <- tuplaOlap 3, p <- tuplaOlap 2] 
manos_CO = jugadasJugadas 5 $ concatMap (\es -> [map (Carta p) es| p <- palos]) $ comb 5 olaps 
manos_ES = jugadasJugadas 5 $ concatMap s [take 5 $ enumFrom w | w <- enumFromTo N1 N9] 
  where v x = [[Carta p x]| p <- palos] 
        s (x:[]) = v x 
        s (x:xs) = [c++ys | c <- v x, ys <- s xs] 
manos_TR = jugadasJugadas 3 $ tuplaOlap 3 
manos_DP = jugadasJugadas 4 $ filter ((4==).length) [nub (p1 ++ p2) | p1 <- tuplaOlap 2, p2 <- tuplaOlap 2] 
manos_PA = jugadasJugadas 2 $ tuplaOlap 2 
 
-- Generamos el archivo de jugadas solicitado: 
main = do 
  tipo <- getArgs >>= return . map toUpper . head 
  let f = case tipo of 
          "ER" -> manos_ER 
          "EC" -> manos_EC 
          "PO" -> manos_PO 
          "FU" -> manos_FU 
          "CO" -> manos_CO 
          "ES" -> manos_ES 
          "TR" -> manos_TR 
          "DP" -> manos_DP 
          "PA" -> manos_PA 
          otherwise -> [] 
      s !m = (concatMap showCard . sort) m 
  mapM_ (putStrLn.s) f 
   
  where showCard Mono = "<>" 
        showCard (Carta p o) = show p ++ tail (show o) 
 
-- Combinaciones sin repetición 
comb :: Int -> [a] -> [[a]] 
comb n xs = c 0 [] xs 
  where c d w p | d == n    = [w] 
                | null p    = [] 
                | otherwise = c d w xs ++ c (d + 1) (x:w) xs where (x:xs) = p 
 
{- 
 
Por ejemplo, un script para generar los archivos de la base de datos podría ser: 
 
for i in ER EC PO FU CO ES TR DP PA 
do 
  echo "==== Generando base de datos de jugadas $i..." 
  ./dbpoker "$i" +RTS -N4 | sort | uniq > "$i.jugadas.txt" 
  echo "   "`cat "$i.jugadas.txt" | wc -l`" combinaciones." 
done 
 
 
Cuyo resultado sería (en mi humilde ATOM): 
 
==== Generando base de datos de jugadas ER... 
   64 combinaciones. 
==== Generando base de datos de jugadas EC... 
   416 combinaciones. 
==== Generando base de datos de jugadas PO... 
   6929 combinaciones. 
==== Generando base de datos de jugadas FU... 
   12844 combinaciones. 
==== Generando base de datos de jugadas CO... 
   9152 combinaciones. 
==== Generando base de datos de jugadas ES... 
   22400 combinaciones. 
==== Generando base de datos de jugadas TR... 
   169065 combinaciones. 
==== Generando base de datos de jugadas DP... 
   237705 combinaciones. 
==== Generando base de datos de jugadas PA... 
   1573897 combinaciones. 
 
 
-} 

Comenta la solución

Tienes que identificarte para poder publicar tu comentario.