{"id":3960,"date":"2013-12-27T04:30:04","date_gmt":"2013-12-27T03:30:04","guid":{"rendered":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/?p=3960"},"modified":"2016-01-09T18:36:35","modified_gmt":"2016-01-09T17:36:35","slug":"el-juego-de-tres-en-raya-en-haskell","status":"publish","type":"post","link":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/el-juego-de-tres-en-raya-en-haskell\/","title":{"rendered":"El juego de &#8220;tres en raya&#8221; en Haskell"},"content":{"rendered":"<p>El <a href=\"http:\/\/es.wikipedia.org\/wiki\/Tres_en_l\u00ednea\">tres en raya<\/a> es un juego entre dos jugadores que marcan los espacios de un tablero de 3&#215;3 alternadamente. Un jugador gana si consigue tener una l\u00ednea de tres de sus s\u00edmbolos: la l\u00ednea puede ser horizontal, vertical o diagonal.<\/p>\n<p>El objetivo de esta relaci\u00f3n de ejercicos es realizar un programa para que la m\u00e1quina juegue contra el humano el tres en raya usando la <a href=\"http:\/\/es.wikipedia.org\/wiki\/Minimax#Algoritmo_Minimax_con_movimientos_alternativos\">estrategia minimax<\/a>.<br \/>\n<!--more--><\/p>\n<p>Un ejemplo de juego es<\/p>\n<pre lang=\"shell\">\nghci> main\nTres en raya\n1|2|3\n-+-+-\n4|5|6\n-+-+-\n7|8|9\nComienza el juego? (s\/n) s\n\nIndica el lugar donde colocar la ficha: 5\n1|2|3\n-+-+-\n4|X|6\n-+-+-\n7|8|9\n\nMi jugada:\nO|2|3\n-+-+-\n4|X|6\n-+-+-\n7|8|9\n\nIndica el lugar donde colocar la ficha: 8\nO|2|3\n-+-+-\n4|X|6\n-+-+-\n7|X|9\n\nMi jugada:\nO|O|3\n-+-+-\n4|X|6\n-+-+-\n7|X|9\n\nIndica el lugar donde colocar la ficha: 3\nO|O|X\n-+-+-\n4|X|6\n-+-+-\n7|X|9\n\nMi jugada:\nO|O|X\n-+-+-\n4|X|6\n-+-+-\nO|X|9\n\nIndica el lugar donde colocar la ficha: 4\nO|O|X\n-+-+-\nX|X|6\n-+-+-\nO|X|9\n\nMi jugada:\nO|O|X\n-+-+-\nX|X|O\n-+-+-\nO|X|9\n\nIndica el lugar donde colocar la ficha: 9\nO|O|X  \n-+-+-\nX|X|O\n-+-+-\nO|X|X\nEmpate.\n<\/pre>\n<p><lp>La relaci\u00f3n de ejercicios (elaborada para la asignatura de <a href=\"http:\/\/www.cs.us.es\/~jalonso\/cursos\/i1m\">Inform\u00e1tica de 1\u00ba del Grado en Matem\u00e1ticas<\/a> y para la siguiente versi\u00f3n del libro <a href=\"http:\/\/www.cs.us.es\/~jalonso\/publicaciones\/Piensa_en_Haskell.pdf\">Piensa en Haskell<\/a>) es la siguiente<br \/>\n<!--more--><\/p>\n<pre lang=\"haskell\">\n-- ---------------------------------------------------------------------\n-- \u00a7 Librer\u00edas auxiliares                                             --\n-- ---------------------------------------------------------------------\n\nimport Data.List \nimport System.IO\n\n-- ---------------------------------------------------------------------\n-- \u00a7 Implementaci\u00f3n del juego                                         --\n-- ---------------------------------------------------------------------\n\n-- ---------------------------------------------------------------------\n-- Ejercicio 1. Definir la constante\n--    profundidadDeBusqueda :: Int\n-- tal que profundidadDeBusqueda es el m\u00e1ximo nivel de profundidad del\n-- \u00e1rbol de an\u00e1lisis del juego. Por defecto es 6. \n-- \n-- Nota: Cuanto mayor sea la profundidadDeBusqueda, mejor juega el\n-- computador pero su velocidad es menor. \n-- ---------------------------------------------------------------------\n\nprofundidadDeBusqueda :: Int\nprofundidadDeBusqueda = 6\n\n-- ---------------------------------------------------------------------\n-- Ejercicio 2. Las posiciones del tablero se numeran como se indica a\n-- continuaci\u00f3n: \n--    1|2|3\n--    -+-+-\n--    4|5|6\n--    -+-+-\n--    7|8|9\n-- \n-- Definir el tipo de dato Posicion para representar una posici\u00f3n del\n-- tablero. Cada posici\u00f3n es un entero del 1 a 9.\n-- ---------------------------------------------------------------------\n\ntype Posicion = Int\n\n-- ---------------------------------------------------------------------\n-- Ejercicio 3. Definir el tipo de datos Posiciones para representar\n-- listas de posiciones.  \n-- ---------------------------------------------------------------------\n\ntype Posiciones = [Posicion]\n\n-- ---------------------------------------------------------------------\n-- Ejercicio 4. En el juego participan dos jugadores. El jugador X es el\n-- que comienza el juego y el otro jugador es el O.\n-- \n-- Definir el tipo de datos Tablero para representar los tableros. El\n-- tablero de la forma (Tab xs os) representa un tablero donde xs es\n-- la lista de las posiciones donde est\u00e1n colocadas las fichas del\n-- primer jugador y os la del segundo jugador. \n-- ---------------------------------------------------------------------\n\ndata Tablero = Tab Posiciones Posiciones \n               deriving Show\n\n-- ---------------------------------------------------------------------\n-- Ejercicio 5. Definir la constante\n--    tableroInicial :: Tablero\n-- para representar el tablero inicial en el no hay colocada ninguna\n-- ficha. \n-- ---------------------------------------------------------------------\n\ntableroInicial :: Tablero\ntableroInicial = Tab [] []\n\n-- ---------------------------------------------------------------------\n-- Ejercicio 6. Definir la funci\u00f3n\n--    turnoDeX :: Tablero -> Bool\n-- tal que (turnoDeX t) se verifica si en el tablero t le toca mover al\n-- jugador X. Como X es el que inicia el juego, su turno es cuando son\n-- iguales el n\u00famero de X y de O colocadas. Por ejemplo, \n--    turnoDeX (Tab []  [])   ==  True\n--    turnoDeX (Tab [3] [])   ==  False\n--    turnoDeX (Tab [3] [7])  ==  True\n-- ---------------------------------------------------------------------\n\nturnoDeX :: Tablero -> Bool\nturnoDeX (Tab xs os) = \n    length xs == length os\n\n-- ---------------------------------------------------------------------\n-- Ejercicio 7. Definir la funci\u00f3n\n--    pone :: Tablero -> Posicion -> Tablero\n-- tal que (pone t p) es el tablero obtenido poniendo en la posici\u00f3n\n-- p del tablero t una ficha del jugador al que le corresponde\n-- colocar. Por ejemplo,\n--    pone (Tab []    [])  3  ==  Tab [3] []\n--    pone (Tab [3]   [])  5  ==  Tab [3] [5]\n--    pone (Tab [3]   [5]) 8  ==  Tab [8,3] [5]\n--    pone (Tab [8,3] [5]) 4  ==  Tab [8,3] [4,5]\n-- ---------------------------------------------------------------------\n\npone :: Tablero -> Posicion -> Tablero\npone (Tab xs os) p | turnoDeX (Tab xs os) = Tab (p:xs) os\n                   | otherwise            = Tab xs (p:os)\n\n-- ---------------------------------------------------------------------\n-- Ejercicio 8. Definir la funci\u00f3n\n--    completo :: Tablero -> Bool\n-- tal que (completo t) se verifica si el tablero t est\u00e1 completo; es\n-- decir, se han colocado las 9 fichas. Por ejemplo,\n--    completo (Tab [3,9,5,8,4] [1,7,6,2])  ==  True\n--    completo (Tab [3,9,5,8,4] [1,7,6])    ==  False\n-- ---------------------------------------------------------------------\n\ncompleto :: Tablero -> Bool\ncompleto (Tab xs os) = length xs + length os == 9\n\n-- ---------------------------------------------------------------------\n-- Ejercicio 9. Definir la funci\u00f3n\n--    subconjunto :: Posiciones -> Posiciones -> Bool\n-- tal que (subconjunto s1 s2) se verifica si s1 es un subconjunto de\n-- s2. Por ejemplo,\n--    subconjunto [3,2,5] [6,2,4,5,3]  ==  True\n--    subconjunto [3,2,5] [6,2,4,3]    ==  False\n-- ---------------------------------------------------------------------\n\nsubconjunto :: Posiciones -> Posiciones -> Bool\nsubconjunto s1 s2 = all (`elem` s2) s1\n\n-- ---------------------------------------------------------------------\n-- Ejercicio 10. Definir la funci\u00f3n\n--    tieneLinea :: Posiciones -> Bool\n-- tal que (tieneLinea ps) se verifica si la lista de posiciones ps \n-- contiene una l\u00ednea horizontal, vertical o diagonal. Por ejemplo,\n--    tieneLinea [2,5,3,6,4]  ==  True\n--    tieneLinea [2,5,3,6]  ==  False\n-- ---------------------------------------------------------------------\n\ntieneLinea :: Posiciones -> Bool\ntieneLinea ps = \n    subconjunto [1,2,3] ps ||subconjunto [4,5,6] ps ||subconjunto [7,8,9] ps ||\n    subconjunto [1,4,7] ps ||subconjunto [2,5,8] ps ||subconjunto [3,6,9] ps ||\n    subconjunto [1,5,9] ps ||subconjunto [3,5,7] ps\n\n-- ---------------------------------------------------------------------\n-- Ejercicio 11. Definir la funci\u00f3n\n--    tieneGanador :: Tablero -> Bool\n-- tal que (tieneGanador t) se verifica si el tablero t tiene un\n-- ganador; es decir, alguno de los dos jugadores ha conseguido una\n-- l\u00ednea. Por ejemplo,\n--    tieneGanador (Tab [2,5,3,6] [1,7,8,9])  ==  True\n--    tieneGanador (Tab [2,5,3,9] [1,6,8,7])  ==  False\n-- ---------------------------------------------------------------------\n\ntieneGanador :: Tablero -> Bool\ntieneGanador (Tab xs os) = tieneLinea xs || tieneLinea os\n\n-- ---------------------------------------------------------------------\n-- \u00a7 Construcci\u00f3n del \u00e1rbol de juego                                  --\n-- ---------------------------------------------------------------------\n\n-- ---------------------------------------------------------------------\n-- Ejercicio 12. Definir el tipo de datos Arbol para representa los\n-- \u00e1rboles compuestos por nodos con una lista de hijos. Por ejemplo,\n--    ghci> :type Nodo 1 [Nodo 2 [Nodo 4 []], Nodo 3 []]\n--    Nodo 1 [Nodo 2 [Nodo 4 []], Nodo 3 []] :: Num a => Arbol a\n-- ---------------------------------------------------------------------\n\ndata Arbol a = Nodo a [Arbol a]\n\n-- ---------------------------------------------------------------------\n-- Ejercicio 13. Definir la funci\u00f3n\n--    muestraArbol :: Show t => Arbol t -> String\n-- tal que (muestraArbol t) es una cadena que representa el \u00e1rbol\n-- t para una mejor visualizaci\u00f3n. Hacer la clase Arbol una\n-- instancia de Show definiendo show como muestraArbol. Por\n-- ejemplo,\n--    ghci> muestraArbol (Nodo 1 [Nodo 2 [Nodo 4 []], Nodo 3 []])\n--    \"1\\n  2\\n    4\\n  3\\n\"\n--    ghci> Nodo 1 [Nodo 2 [Nodo 4 []], Nodo 3 []]\n--    1\n--      2\n--        4\n--      3\n-- ---------------------------------------------------------------------\n\nmuestraArbol (Nodo x xs) = \n    show x ++ '\\n' : (unlines . map (\"  \"++) . concatMap (lines . show)) xs\n\ninstance Show a => Show (Arbol a) where\n  show = muestraArbol\n\n\n-- En la siguiente sesi\u00f3n se muestra el comportamiento de muestraArbol.\n--    ghci> show 1\n--    \"1\"\n--    ghci> concatMap (lines . show) [Nodo 2 [Nodo 4 []], Nodo 3 []]\n--    [\"2\",\"  4\",\"3\"]\n--    ghci> map (\"  \"++) [\"2\",\"  4\",\"3\"]\n--    [\"  2\",\"    4\",\"  3\"]\n--    ghci> unlines [\"  2\",\"    4\",\"  3\"]\n--    \"  2\\n    4\\n  3\\n\"\n--    ghci> \"1\" ++ '\\n' : \"  2\\n    4\\n  3\\n\"\n--    \"1\\n  2\\n    4\\n  3\\n\"\n\n-- ---------------------------------------------------------------------\n-- Ejercicio 14. Definir la funci\u00f3n\n--    posicionesLibres :: Tablero -> Posiciones\n-- tal que (posicionesLibres t) es la lista de las posiciones libres del\n-- tablero t. Por ejemplo,\n--    posicionesLibres (Tab [3,2] [1,7])  ==  [4,5,6,8,9]\n-- ---------------------------------------------------------------------\n\nposicionesLibres :: Tablero -> Posiciones\nposicionesLibres (Tab xs os) = [1..9] \\\\ (xs++os)\n\n-- ---------------------------------------------------------------------\n-- Ejercicio 15. Definir la funci\u00f3n\n--    siguientesTableros :: Tablero -> [Tablero]\n-- tal que (siguientesTableros t) es la lista de tableros obtenidos\n-- colocando una pieza en cada una de las posiciones libres de t. Por\n-- ejemplo,\n--    ghci> tableroInicial\n--    Tab [] []\n--    ghci> siguientesTableros tableroInicial\n--    [Tab [1] [], Tab [2] [], Tab [3] [], Tab [4] [], Tab [5] [],\n--     Tab [6] [], Tab [7] [], Tab [8] [], Tab [9] []]\n--    ghci> siguientesTableros (Tab [1] [])\n--    [Tab [1] [2], Tab [1] [3], Tab [1] [4], Tab [1] [5],\n--     Tab [1] [6], Tab [1] [7], Tab [1] [8], Tab [1] [9]]\n--    ghci> siguientesTableros (Tab [1] [2])\n--    [Tab [3,1] [2], Tab [4,1] [2], Tab [5,1] [2], Tab [6,1] [2],\n--     Tab [7,1] [2], Tab [8,1] [2], Tab [9,1] [2]]\n-- ---------------------------------------------------------------------\n\nsiguientesTableros :: Tablero -> [Tablero]\nsiguientesTableros t \n    | tieneGanador t = [] \n    | otherwise      = map (pone t) (posicionesLibres t)\n\n-- ---------------------------------------------------------------------\n-- Ejercicio 16. Definir la funci\u00f3n\n--    construyeArbol :: Tablero -> Arbol Tablero\n-- tal que (construyeArbol t) es el \u00e1rbol de juego correspondiente al\n-- tablero t. Por ejemplo,\n--    ghci> construyeArbol (Tab [7,1,6,2] [5,4,3])\n--     Tab [7,1,6,2] [5,4,3]\n--       Tab [7,1,6,2] [8,5,4,3]\n--         Tab [9,7,1,6,2] [8,5,4,3]\n--       Tab [7,1,6,2] [9,5,4,3]\n--         Tab [8,7,1,6,2] [9,5,4,3]\n-- ---------------------------------------------------------------------\n\nconstruyeArbol :: Tablero -> Arbol Tablero\nconstruyeArbol t = \n    Nodo t (map construyeArbol (siguientesTableros t)) \n\n-- ---------------------------------------------------------------------\n-- Ejercicio 17. Definir el tipo Valor para representa el valor de los\n-- tableros. Los valores son n\u00fameros enteros.\n-- ---------------------------------------------------------------------\n\ntype Valor = Int\n\n-- ---------------------------------------------------------------------\n-- Ejercicio 18. Un tablero valorado es un par de la forma (v,t) donde t\n-- es un tablero y v es el valor del tablero.\n-- \n-- Definir la funci\u00f3n\n--    valores :: [Arbol (Valor,Tablero)] -> [Valor]\n-- tal que (valores vts) es la lista de valores de la lista de \u00e1rboles de\n-- tableros valorados vts. Por ejemplo, \n--    ghci> valores [Nodo (2,Tab[][])[], Nodo (5,Tab[3][])[]] \n--    [2,5]\n-- ---------------------------------------------------------------------\n\nvalores :: [Arbol (Valor,Tablero)] -> [Valor]\nvalores vts = [v | Nodo (v,_) _ <- vts]\n\n-- ---------------------------------------------------------------------\n-- Ejercicio 19. Definir la funci\u00f3n\n--    maximiza :: Arbol Tablero -> Arbol (Valor,Tablero)\n-- tal que (maximiza at) es el \u00e1rbol de tableros m\u00e1ximamente valorados\n-- correspondiente al \u00e1rbol de tableros at mediante el algoritmo\n-- minimax; es decir, \n-- * si at es un \u00e1rbol con ra\u00edz t y sin sub\u00e1rboles, entonces\n--   * si t tiene ganador, devuelve (Nodo (-1,t) [])\n--   * en caso contrario,  devuelve (Nodo ( 0,t) [])\n-- * si at es un \u00e1rbol con ra\u00edz t y sub\u00e1rboles ts, entonces minimiza los\n--   \u00e1rboles de ts (construyendo una lista vts de \u00e1rboles valorados) y\n--   devuelve (Nodo (m,t) vts), donde m es el m\u00e1ximo de los valores de\n--   vts.    \n-- ---------------------------------------------------------------------\n\nmaximiza :: Arbol Tablero -> Arbol (Valor,Tablero)\nmaximiza (Nodo t []) | tieneGanador t = Nodo (-1,t) []\n                     | otherwise      = Nodo (0,t) []                                        \nmaximiza (Nodo t ts) = Nodo (maximum (valores vts),t) vts\n    where vts = map minimiza ts\n\n-- ---------------------------------------------------------------------\n-- Ejercicio 20. Definir la funci\u00f3n\n--    minimiza :: Arbol Tablero -> Arbol (Valor,Tablero)\n-- tal que (minimiza at) es el \u00e1rbol de tableros m\u00ednimamente valorados\n-- correspondiente al \u00e1rbol de tableros at mediante el algoritmo\n-- minimax; es decir, \n-- * si at es un \u00e1rbol con ra\u00edz t y sin sub\u00e1rboles, entonces\n--   * si t tiene ganador, devuelve (Nodo (1,t) [])\n--   * en caso contrario,  devuelve (Nodo (0,t) [])\n-- * si at es un \u00e1rbol con ra\u00edz t y sub\u00e1rboles ts, entonces maximiza los\n--   \u00e1rboles de ts (construyendo una lista vts de \u00e1rboles valorados) y\n--   devuelve (Nodo (m,t) vts), donde m es el m\u00ednimo de los valores de\n--   vts.    \n-- ---------------------------------------------------------------------\n\nminimiza :: Arbol Tablero -> Arbol (Valor,Tablero)\nminimiza (Nodo t []) | tieneGanador t = Nodo (1,t) []\n                     | otherwise      = Nodo (0,t) []\nminimiza (Nodo t ts) = Nodo (minimum (valores vts),t) vts\n    where vts = map maximiza ts\n\n-- ---------------------------------------------------------------------\n-- Ejercicio 21. Definir la funci\u00f3n\n--    poda :: Int -> Arbol a -> Arbol a\n-- tal que (poda n a) es el \u00e1rbol obtenido podando el \u00e1rbol a a\n-- partir de la profundidad n. Por ejemplo,\n--    ghci> Nodo 4 [Nodo 3 [], Nodo 7 [Nodo 9 [Nodo 2 []]]]\n--    4\n--      3\n--      7\n--        9\n--          2\n--    \n--    ghci> poda 2 (Nodo 4 [Nodo 3 [], Nodo 7 [Nodo 9 [Nodo 2 []]]])\n--    4\n--      3\n--      7\n--        9\n--    \n--    ghci> poda 1 (Nodo 4 [Nodo 3 [], Nodo 7 [Nodo 9 [Nodo 2 []]]])\n--    4\n--      3\n--      7\n-- ---------------------------------------------------------------------\n\npoda :: Int -> Arbol a -> Arbol a\npoda n (Nodo x as) | n == 0    = Nodo x []\n                   | otherwise = Nodo x (map (poda (n-1)) as)\n\n-- ---------------------------------------------------------------------\n-- Ejercicio 22. Definir la funci\u00f3n\n--    selecciona :: Arbol (Valor,Tablero) -> Tablero\n-- tal que (selecciona avts) es el tablero del primer hijo de la ra\u00edz del\n-- \u00e1rbol de tableros valorados avts cuyo valor es igual que la ra\u00edz.\n-- ---------------------------------------------------------------------\n\nselecciona :: Arbol (Valor,Tablero) -> Tablero\nselecciona (Nodo (v,_) ts) = \n    head [t | Nodo (v',t) _ <- ts, v'==v]\n\n-- ---------------------------------------------------------------------\n-- Ejercicio 23. Definir la funci\u00f3n\n--    mejorMovimiento :: Tablero -> Tablero\n-- tal que (mejorMovimiento t) es el tablero correspondiente al mejor\n-- movimiento a partir del tablero t. Por ejemplo,\n--    mejorMovimiento (Tab [3] [])     ==  Tab [3] [5]\n--    mejorMovimiento (Tab [4,3] [5])  ==  Tab [4,3] [1,5]\n-- ---------------------------------------------------------------------\n\nmejorMovimiento :: Tablero -> Tablero\nmejorMovimiento = \n    selecciona . maximiza . poda profundidadDeBusqueda . construyeArbol\n\n-- ---------------------------------------------------------------------\n-- \u00a7 Dibujo del tablero                                               --\n-- ---------------------------------------------------------------------\n\n-- ---------------------------------------------------------------------\n-- Ejercicio 24. Definir la funci\u00f3n\n--    muestraPosicion :: Tablero -> Posicion -> String\n-- tal que (muestraPosicion t p) es el contenido de la posici\u00f3n p del\n-- tablero t; es decir, X si p est\u00e1 en la lista de las xs; O si p est\u00e1\n-- en la lista de las os y la cadena de p, en otro caso. Por ejemplo,\n--    ghci> muestraPosicion (Tab [1] [3]) 1\n--    \"X\"\n--    ghci> muestraPosicion (Tab [1] [3]) 3\n--    \"O\"\n--    ghci> muestraPosicion (Tab [1] [3]) 2\n--    \"2\"\n-- ---------------------------------------------------------------------\n\nmuestraPosicion :: Tablero -> Posicion -> String\nmuestraPosicion (Tab xs os) p \n    | p `elem` xs = \"X\"\n    | p `elem` os = \"O\"\n    | otherwise   = show p\n\n-- ---------------------------------------------------------------------\n-- Ejercicio 25. Definir la funci\u00f3n\n--    muestraLinea :: Tablero -> [Posicion] -> String\n-- tal que (muestraLinea t ps) es la cadena correspondiente al contenido\n-- de las posiciones ps en el tablero t separadas por la barra\n-- vertical. Por ejemplo,\n--    ghci> muestraLinea (Tab [7,1,6,2] [8,4,3]) [4..6]\n--    \"O|5|X\"\n-- ---------------------------------------------------------------------\n\nmuestraLinea :: Tablero -> [Posicion] -> String\nmuestraLinea t = \n    concat . intersperse \"|\" . map (muestraPosicion t)\n\n-- ---------------------------------------------------------------------\n-- Ejercicio 26. Definir la funci\u00f3n\n--    muestraTablero :: Tablero -> String\n-- tal que (muestraTablero t) es la cadena correspondiente al tablero\n-- t. Por ejemplo, \n--    ghci> muestraTablero (Tab [7,1,6,2] [8,4,3])\n--    \"X|X|O\\n-+-+-\\nO|5|X\\n-+-+-\\nX|O|9\"\n--    ghci> putStrLn (muestraTablero (Tab [7,1,6,2] [8,4,3]))\n--    X|X|O\n--    -+-+-\n--    O|5|X\n--    -+-+-\n--    X|O|9\n-- ---------------------------------------------------------------------\n\nmuestraTablero :: Tablero -> String\nmuestraTablero t = \n    muestraLinea t [1..3] ++ \"\\n-+-+-\\n\" ++\n    muestraLinea t [4..6] ++ \"\\n-+-+-\\n\" ++\n    muestraLinea t [7..9]\n\n-- ---------------------------------------------------------------------\n-- \u00a7 Control del juego                                                --\n-- ---------------------------------------------------------------------\n\n-- ---------------------------------------------------------------------\n-- Ejercicio 27. Definir la funci\u00f3n\n--    main :: IO ()\n-- que controle el juego siguiendo los siguientes pasos:\n--    1. Activa la escritura inmediata en la pantalla.\n--    2. Escribe el nombre del juego.\n--    3. Escribe el tablero inicial.\n--    4. Pregunta al humano si desea comenzar el juego.\n--    5. Para y lee la respuesta.\n--    6. Comprueba si la respuesta es afirmativa.\n--    7. En el caso que la respuesta sea afirmativa, realiza un\n--       movimiento del jugador humano.  \n--    8. En el caso que la respuesta sea negativa, realiza un movimiento\n--       de la computadora. \n-- ---------------------------------------------------------------------\n\nmain :: IO ()\nmain = do\n  hSetBuffering stdout NoBuffering           -- 1\n  putStrLn \"Tres en raya\"                    -- 2\n  putStrLn (muestraTablero tableroInicial)   -- 3\n  putStr \"Comienza el juego? (s\/n) \"         -- 4\n  l <- getLine                               -- 5\n  if head l `elem` \"sS\"                      -- 6\n     then humano tableroInicial              -- 7\n     else computadora tableroInicial         -- 8\n\n-- ---------------------------------------------------------------------\n-- Ejercicio 28. Definir la funci\u00f3n\n--    humano :: Tablero -> IO ()\n-- tal que (humano t) realiza el movimiento del jugador humano a partir\n-- del tablero t. Consta de los siguientes pasos:\n--    1. Pregunta la posici\u00f3n en donde desea colocar la ficha.\n--    2. Lee la posici\u00f3n en donde desea colocar la ficha.\n--    3. Calcula el tablero t' correspondiente a colocar la ficha en la\n--       posici\u00f3n elegida.\n--    4. Muestra el tablero t'.\n--    5. Decide si t' tiene ganador.\n--       5.a. En caso afirmativo, escribe que el jugador humano ha ganado.\n--       5.b. En caso negativo, decide si el tablero est\u00e1 completo\n--            5.b.1. En caso afirmativo, escribe que hay empate.\n--            5.b.2. En caso negativo, pasa el turno a la computadora\n--                   con tablero t'. \n-- \n-- Nota: No se comprueba la correcci\u00f3n de la posici\u00f3n elegida (es decir, \n-- si es un n\u00famero entre 1 y 9 y no hay ficha en esa posici\u00f3n).\n-- ---------------------------------------------------------------------\n\nhumano :: Tablero -> IO ()\nhumano t = do \n  putStr \"\\nIndica el lugar donde colocar la ficha: \" -- 1\n  l <- getLine                                        -- 2 \n  let t' = pone t (read l :: Posicion)                -- 3\n  putStrLn (muestraTablero t')                        -- 4\n  if tieneGanador t'                                  -- 5\n     then putStrLn \"Has ganado.\"                      -- 5.a\n     else if completo t'                              -- 5.b\n             then putStrLn \"Empate.\"                  -- 5.b.1\n             else computadora t'                      -- 5.b.2\n\n-- ---------------------------------------------------------------------\n-- Ejercicio 29. Definir la funci\u00f3n\n--    computadora :: Tablero -> IO ()\n-- tal que (computadora t) realiza el movimiento de la computadora a\n-- partir del tablero t. Consta de los siguientes pasos:\n--    1. Escribe la jugada de la computadora \n--    2. Calcula el tablero t' correspondiente al mejor movimiento en\n--       t. \n--    3. Escribe t'.\n--    4. Decide si t' tiene ganador.\n--       4.a. En caso afirmativo, escribe que la computadora ha ganado.\n--       4.b. En caso negativo, decide si el tablero est\u00e1 completo.\n--            4.b.1. En caso afirmativo, escribe que hay empate.\n--            4.b.2. En caso negativo, pasa el turno al humano con\n--                   tablero t'. \n-- ---------------------------------------------------------------------\n\ncomputadora :: Tablero -> IO ()\ncomputadora t = do\n  putStrLn \"\\nMi jugada:\"            -- 1\n  let t' = mejorMovimiento t         -- 2\n  putStrLn (muestraTablero t')       -- 3\n  if tieneGanador t'                 -- 4\n     then putStrLn \"He ganado.\"      -- 4.a\n     else if completo t'             -- 4.b\n             then putStrLn \"Empate.\" -- 4.b.1\n             else humano t'          -- 4.b.2\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>El tres en raya es un juego entre dos jugadores que marcan los espacios de un tablero de 3&#215;3 alternadamente. Un jugador gana si consigue tener una l\u00ednea de tres de sus s\u00edmbolos: la l\u00ednea puede ser horizontal, vertical o diagonal. El objetivo de esta relaci\u00f3n de ejercicos es realizar un programa para que la&#8230;<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_kad_post_transparent":"","_kad_post_title":"","_kad_post_layout":"","_kad_post_sidebar_id":"","_kad_post_content_style":"","_kad_post_vertical_padding":"","_kad_post_feature":"","_kad_post_feature_position":"","_kad_post_header":false,"_kad_post_footer":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"footnotes":"","_jetpack_memberships_contains_paid_content":false},"categories":[5,221],"tags":[270,299],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_likes_enabled":false,"_links":{"self":[{"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/posts\/3960"}],"collection":[{"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/comments?post=3960"}],"version-history":[{"count":3,"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/posts\/3960\/revisions"}],"predecessor-version":[{"id":5273,"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/posts\/3960\/revisions\/5273"}],"wp:attachment":[{"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/media?parent=3960"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/categories?post=3960"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/tags?post=3960"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}