{"id":6928,"date":"2020-01-10T08:59:31","date_gmt":"2020-01-10T07:59:31","guid":{"rendered":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/?p=6928"},"modified":"2020-01-11T09:03:58","modified_gmt":"2020-01-11T08:03:58","slug":"i1m2019-el-juego-de-la-vida-en-haskell","status":"publish","type":"post","link":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/i1m2019-el-juego-de-la-vida-en-haskell\/","title":{"rendered":"I1M2019: El juego de la vida en Haskell"},"content":{"rendered":"<p>En la clase de hoy de <a href=\"http:\/\/www.cs.us.es\/~jalonso\/cursos\/i1m-19\">Inform\u00e1tica de 1\u00ba del Grado en Matem\u00e1ticas<\/a> se ha estudiado el juego de la vida como caso de estudio de programaci\u00f3n interactiva.<\/p>\n<p>Los apuntes correspondientes son<br \/>\n\n<!-- iframe plugin v.5.0 wordpress.org\/plugins\/iframe\/ -->\n<iframe loading=\"lazy\" src=\"https:\/\/www.cs.us.es\/~jalonso\/cursos\/i1m-19\/temas\/tema-13.html#el-juego-de-la-vida\" width=\"100%\" frameborder=\"1\" height=\"500\" scrolling=\"yes\" class=\"iframe-class\"><\/iframe>\n<\/p>\n<p>En la implementaci\u00f3n anterior, las funciones de interacci\u00f3n con la terminal son dependientes del sistema operativo. A continuaci\u00f3n se muestra otra que no lo es basada en el uso de la librer\u00eda <a href=\"https:\/\/hackage.haskell.org\/package\/ansi-terminal\">ansi-terminal<\/a>.<\/p>\n<p><!--more--><\/p>\n<pre lang=\"haskell\">\nimport Data.List (nub)\nimport System.Console.ANSI\n\n-- Una posici\u00f3n es un par de enteros (x,y) donde es el n\u00famero de fila e\n-- y es el n\u00famero de columna empezando en 0. \ntype Pos = (Int,Int)\n\n-- (irA p) mueve el cursor a la posici\u00f3n p.\nirA :: Pos -> IO ()\nirA (x,y) = setCursorPosition x y\n\n-- (escribeEn p xs) escribe en la posici\u00f3n p la cadena xs.\nescribeEn :: Pos -> String -> IO ()\nescribeEn p xs = do\n  irA p\n  putStr xs\n\n-- limpiaPantalla limpia la pantalla.\nlimpiaPantalla :: IO ()\nlimpiaPantalla = clearScreen\n\n-- Un tablero es una lista de posiciones que indican donde se encuentran\n-- las c\u00e9lulas vivas.\ntype Tablero = [Pos]\n\n-- ejTablero es el tablero que usaremos en los ejemplos. Gr\u00e1ficamente,\n--      0 1 2 3 4\n--    0\n--    1       X \n--    2   X   X\n--    3     X X\n--    4\nejTablero :: Tablero\nejTablero = [(1,3),(2,1),(2,3),(3,2),(3,3)]\n\n-- ancho es la anchura del tablero (por defecto, 5).\nancho :: Int\nancho = 5\n\n-- alto es la altura del tablero (por defecto, 5).\nalto :: Int\nalto = 5\n\n-- (vida n t) simula el juego de la vida empezando en el tablero t y una\n-- pausa de n entre cada generaci\u00f3n. Por ejemplo,\n--    vida (10^6) ejTablero\nvida :: Int -> Tablero -> IO ()\nvida = vida' 0 \n  where\n    vida' 21 _ _ = do\n      escribeEn (4+alto,0) \"Finalizado\\n\\n\"\n      return ()\n    vida' g n t = do\n      limpiaPantalla\n      escribeTablero t\n      escribeGeneracion g\n      espera n\n      vida' (g+1) n (siguienteGeneracion t)\n\n-- (escribeTablero t) escribe el tablero t.\nescribeTablero :: Tablero -> IO ()\nescribeTablero t = sequence_ [escribeEn p \"O\" | p <- t]\n\n-- (escribeGeneracion g) escribe el n\u00famero dela generaci\u00f3n.\nescribeGeneracion :: Int -> IO ()\nescribeGeneracion g = escribeEn (2+alto,0) (\"Generacion \" ++ show g)\n\n-- (espera n) espera un tiempo proporcional a n.\nespera :: Int -> IO ()\nespera n = sequence_ [return () | _ <- [1..n]]\n\n-- (siguienteGeneracion t) es la generaci\u00f3n siguiente a la\n-- correspondiente al tablero t. Por ejemplo,\n--    \u03bb> siguienteGeneracion ejTablero\n--    [(2,3),(3,2),(3,3),(1,2),(2,4)]\n--    \u03bb> siguienteGeneracion it\n--    [(3,2),(3,3),(2,4),(1,3),(3,4)]\nsiguienteGeneracion :: Tablero -> Tablero\nsiguienteGeneracion t = supervivientes t ++ nacimientos t\n\n-- (supervivientes t) es la listas de posiciciones de t que sobreviven;\n-- i.e. posiciciones con 2 \u00f3 3 vecinos vivos. Por ejemplo,\n--    \u03bb> supervivientes ejTablero\n--    [(2,3),(3,2),(3,3)]\nsupervivientes :: Tablero -> [Pos]\nsupervivientes t = [p | p <- t, elem (nVecinosVivos t p) [2,3]]\n\n-- (nVecinosVivos t p) es el n\u00famero de vecinos vivos de la posici\u00f3n p en\n-- el tablero t. Por ejemplo,\n--    nVecinosVivos ejTablero (2,2)  ==  5\n--    nVecinosVivos ejTablero (3,2)  ==  3\nnVecinosVivos :: Tablero -> Pos -> Int\nnVecinosVivos t = length . filter (tieneVida t) . vecinos\n\n-- (vecinos p) es la lista de los vecinos de p. Por ejemplo, \n--    vecinos (2,1)  ==  [(1,0),(1,1),(1,2),(2,0),(2,2),(3,0),(3,1),(3,2)]\n--    vecinos (1,0)  ==  [(0,0),(0,1),(1,1),(2,0),(2,1)]\n--    vecinos (1,4)  ==  [(0,3),(0,4),(1,3),(2,3),(2,4)]\n--    vecinos (0,0)  ==  [(0,1),(1,0),(1,1)]\nvecinos :: Pos -> [Pos]\nvecinos (x,y) = [(x+a,y+b) | a <- [-1,0,1]\n                           , b <- [-1,0,1]\n                           , (a,b) \/= (0,0)\n                           , 0 <= x+a &#038;&#038; x+a < ancho\n                           , 0 <= y+b &#038;&#038; y+b < alto]\n\n-- (tieneVida t p) se verifica si en la posici\u00f3n p del tablero t hay una\n-- c\u00e9lula viva. Por ejemplo,\n--    tieneVida ejTablero (2,1)  ==  True\n--    tieneVida ejTablero (0,0)  ==  False\ntieneVida :: Tablero -> Pos -> Bool\ntieneVida t p = elem p t\n\n-- (nacimientos t) es la lista de los nacimientos de tablero t; i.e. las\n-- posiciones sin vida con 3 vecinos vivos. Por ejemplo, \n--    nacimientos ejTablero   ==  [(1,2),(2,4)]\n-- Una definici\u00f3n ineficente es\nnacimientos' :: Tablero -> [Pos]\nnacimientos' t = [(x,y) | x <- [1..ancho],\n                          y <- [1..alto],\n                          noTieneVida t (x,y),\n                          nVecinosVivos t (x,y) == 3]\n\n-- (noTieneVida t p) se verifica si en la posici\u00f3n p del tablero t no\n-- hay una c\u00e9lula viva. Por ejemplo,\n--    tieneVida ejTablero (2,1)  ==  False\n--    tieneVida ejTablero (0,0)  ==  True\nnoTieneVida :: Tablero -> Pos -> Bool\nnoTieneVida t p = not (tieneVida t p)\n\n-- Una definici\u00f3n eficiente es\nnacimientos :: Tablero -> [Pos]\nnacimientos t = [p | p <- nub (concatMap vecinos t),\n                     noTieneVida t p,\n                     nVecinosVivos t p == 3]\n\n-- Funci\u00f3n principal para la ejecuci\u00f3n . Por ejemplo,\n--    stack exec -- runhaskell Juego_de_la_vida_v4.hs \nmain :: IO ()\nmain = do\n  setTitle \"El juego de la vida\"\n  vida (10^6) ejTablero\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>En la clase de hoy de Inform\u00e1tica de 1\u00ba del Grado en Matem\u00e1ticas se ha estudiado el juego de la vida como caso de estudio de programaci\u00f3n interactiva. Los apuntes correspondientes son En la implementaci\u00f3n anterior, las funciones de interacci\u00f3n con la terminal son dependientes del sistema operativo. A continuaci\u00f3n se muestra otra que no&#8230;<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","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":[331],"tags":[],"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\/6928"}],"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=6928"}],"version-history":[{"count":4,"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/posts\/6928\/revisions"}],"predecessor-version":[{"id":6932,"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/posts\/6928\/revisions\/6932"}],"wp:attachment":[{"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/media?parent=6928"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/categories?post=6928"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/tags?post=6928"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}