Primer commit. Este codigo fue escrito en septiembre de 2021

This commit is contained in:
2025-12-09 09:06:03 -05:00
commit 580736bc88
54 changed files with 15176 additions and 0 deletions

1
.gitignore vendored Executable file
View File

@@ -0,0 +1 @@
/out

171
Documentacion/Punto.html Executable file
View File

@@ -0,0 +1,171 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Class: Punto</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Class: Punto</h1>
<section>
<header>
<h2><span class="attribs"><span class="type-signature"></span></span>Punto<span class="signature">()</span><span class="type-signature"></span></h2>
<div class="class-description"><h1>Punto</h1>
<p>Esta clase almacena temporalmente las coordenadas X,Y como un objeto</p></div>
</header>
<article>
<div class="container-overview">
<h2>Constructor</h2>
<h4 class="name" id="Punto"><span class="type-signature"></span>new Punto<span class="signature">()</span><span class="type-signature"></span></h4>
<dl class="details">
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="index.js.html">index.js</a>, <a href="index.js.html#line17">line 17</a>
</li></ul></dd>
</dl>
</div>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="graficos.html">graficos</a></li><li><a href="Punto.html">Punto</a></li></ul><h3>Global</h3><ul><li><a href="global.html#_contarvecinos">_contarvecinos</a></li><li><a href="global.html#getPuntoBajoMouse">getPuntoBajoMouse</a></li><li><a href="global.html#iniciar">iniciar</a></li><li><a href="global.html#init">init</a></li><li><a href="global.html#limpiar">limpiar</a></li><li><a href="global.html#parar">parar</a></li><li><a href="global.html#procesarCelula">procesarCelula</a></li><li><a href="global.html#siguiente_generacion">siguiente_generacion</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.7</a> on Fri Sep 10 2021 08:16:05 GMT-0500 (GMT-05:00)
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>

Binary file not shown.

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

1084
Documentacion/global.html Executable file

File diff suppressed because it is too large Load Diff

448
Documentacion/graficos.html Executable file
View File

@@ -0,0 +1,448 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Class: graficos</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Class: graficos</h1>
<section>
<header>
<h2><span class="attribs"><span class="type-signature"></span></span>graficos<span class="signature">()</span><span class="type-signature"></span></h2>
<div class="class-description"><h1>Graficos</h1>
<p>Esta clase permite el control y la creacion del lienzo y las funciones que alteran el estado del lienzo</p></div>
</header>
<article>
<div class="container-overview">
<h2>Constructor</h2>
<h4 class="name" id="graficos"><span class="type-signature"></span>new graficos<span class="signature">()</span><span class="type-signature"></span></h4>
<dl class="details">
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="index.js.html">index.js</a>, <a href="index.js.html#line28">line 28</a>
</li></ul></dd>
</dl>
</div>
<h3 class="subsection-title">Methods</h3>
<h4 class="name" id="dibujarCelula"><span class="type-signature"></span>dibujarCelula<span class="signature">(x, y, estado)</span><span class="type-signature"></span></h4>
<div class="description">
<h1>Dibujar Celula</h1>
<p>Permite dibujar una celula en un estado encendido o apagado en un lugar determinado del lienzo</p>
</div>
<h5>Parameters:</h5>
<table class="params">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th class="last">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="name"><code>x</code></td>
<td class="type">
<span class="param-type">int</span>
</td>
<td class="description last"></td>
</tr>
<tr>
<td class="name"><code>y</code></td>
<td class="type">
<span class="param-type">int</span>
</td>
<td class="description last"></td>
</tr>
<tr>
<td class="name"><code>estado</code></td>
<td class="type">
<span class="param-type">bool</span>
</td>
<td class="description last"></td>
</tr>
</tbody>
</table>
<dl class="details">
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="index.js.html">index.js</a>, <a href="index.js.html#line55">line 55</a>
</li></ul></dd>
</dl>
<h4 class="name" id="pintar"><span class="type-signature"></span>pintar<span class="signature">()</span><span class="type-signature"></span></h4>
<div class="description">
<h1>Pintar</h1>
<p>Esta funcion cambia el estado de todas las celulas de acuerdo al que esta almacenado en la matriz original</p>
</div>
<dl class="details">
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="index.js.html">index.js</a>, <a href="index.js.html#line69">line 69</a>
</li></ul></dd>
</dl>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="graficos.html">graficos</a></li><li><a href="Punto.html">Punto</a></li></ul><h3>Global</h3><ul><li><a href="global.html#_contarvecinos">_contarvecinos</a></li><li><a href="global.html#getPuntoBajoMouse">getPuntoBajoMouse</a></li><li><a href="global.html#iniciar">iniciar</a></li><li><a href="global.html#init">init</a></li><li><a href="global.html#limpiar">limpiar</a></li><li><a href="global.html#parar">parar</a></li><li><a href="global.html#procesarCelula">procesarCelula</a></li><li><a href="global.html#siguiente_generacion">siguiente_generacion</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.7</a> on Fri Sep 10 2021 08:16:05 GMT-0500 (GMT-05:00)
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>

BIN
Documentacion/images/favicon.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

207
Documentacion/index.html Executable file
View File

@@ -0,0 +1,207 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Home</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Home</h1>
<h3> </h3>
<section>
<article><h1>El juego de la vida. Una reescritura en vainilla javascript.</h1>
<h1>Tabla de contenidos</h1>
<ul>
<li><a href="#el-juego-de-la-vida-una-reescritura-en-vainilla-javascript">El juego de la vida. Una reescritura en vainilla javascript.</a></li>
<li><a href="#tabla-de-contenidos">Tabla de contenidos</a></li>
<li><a href="#introducci%C3%B3n">Introducción</a>
<ul>
<li><a href="#justificaci%C3%B3n-del-trabajo">Justificación del trabajo</a></li>
<li><a href="#contexto-y-estado-del-arte">Contexto y estado del arte</a>
<ul>
<li><a href="#pulgarinco">Pulgarin.co</a></li>
<li><a href="#pmaveu">pmav.eu</a></li>
<li><a href="#javascriptplainenglishio">javascript.plainenglish.io</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#desarrollo">Desarrollo</a>
<ul>
<li><a href="#an%C3%A1lisis-de-la-situaci%C3%B3n">Análisis de la situación</a></li>
<li><a href="#inicializaci%C3%B3n-de-un-proyecto-con-npm-init">Inicialización de un proyecto con npm init</a></li>
<li><a href="#uso-de-clases-en-javascript">Uso de clases en JavaScript</a></li>
<li><a href="#implementaci%C3%B3n-de-un-sistema-de-inicializaci%C3%B3n">Implementación de un sistema de inicialización</a></li>
<li><a href="#implementaci%C3%B3n-de-un-sistema-de-dibujado">Implementación de un sistema de dibujado</a></li>
<li><a href="#implantaci%C3%B3n-de-un-sistema-de-funciones-publicas">Implantación de un sistema de funciones publicas</a></li>
<li><a href="#uso-de-comentarios-para-jsdoc">Uso de comentarios para jsdoc</a></li>
<li><a href="#compilando-en-jsdoc">Compilando en JSDoc</a></li>
<li><a href="#service-workers-y-pwa">Service workers y PWA</a>
<ul>
<li><a href="#usos-de-pwa-y-app-cache-para-trabajo-offline">usos de pwa y app cache para trabajo offline</a></li>
</ul>
</li>
<li><a href="#web-responsiva">Web responsiva</a></li>
<li><a href="#hosting-http-y-https">hosting http y https</a></li>
<li><a href="#readmemd-y-otros-archivos-de-documentaci%C3%B3n">Readme.md y otros archivos de documentación</a></li>
</ul>
</li>
<li><a href="#conclusiones-y-trabajos-futuros">Conclusiones y trabajos futuros</a></li>
<li><a href="#bibliograf%C3%ADawebgraf%C3%ADa">Bibliografía/webgrafía</a></li>
</ul>
<h1>Introducción</h1>
<p>Hace mucho tiempo, antes de intentar tomarme en serio la programación, publique <a href="https://interlan.ec/2020/05/23/el-juego-de-la-vida-en-javascript/">un post en mi blog sobre el juego de la vida</a>. Habiendo mejorado mucho mis capacidades para leer código y hacer muchas cosas mas, decidí retomar mi blog para llenarlo con nuevos contenidos que ayuden a otras personas a las que les interesen las mismas cosas que a mi.</p>
<p>Mientras exploraba mis escasos aportes a la red, me topé con el post original que hice sobre el juego de la vida. Estaba completamente en ruinas en cuanto a estar lleno de links rotos, imágenes faltantes y contenidos desactualizados.</p>
<p>Desempolvando un poco, elimine los links rotos puesto que no llevaban a ningún lado. Las imágenes las tuve que eliminar porque los hostings que las contenían habían muerto o las habían removido y ni siquiera recuerdo de que iban (aprendí la lección, debo controlar que las imágenes que copio se alojen en mi propio servidor para evitar estas cosas, pero tampoco olvidare citar las fuentes originales).</p>
<p>Es bastante increíble que la primera vez que revise este algoritmo no haya validado si funcionaba o no, que tecnologías usaba o siquiera si el sitio continuaba vivo. Para ser un post del 2020, todos los links eran del año 2011 por lo que no es raro encontrar problemas como cosas desaparecidas.</p>
<blockquote>
<p>Titulo: El sitio de Pulgarín esta muerto desde quien sabe cuando
<img src="images/sitio_pulgarin.png" alt="El sitio de Pulgarín esta muerto desde quien sabe cuando"></p>
<p><strong>Fuente:</strong> Elaboración propia</p>
</blockquote>
<h2>Justificación del trabajo</h2>
<p>Realmente este trabajo es mas para pulir mis habilidades leyendo código ajeno, entendiendo como funciona y reescribiéndolo en una forma mejorada y funcional, pero también es un pequeño aporte en español para internet, puesto que es justo allí donde aprendí a programar.</p>
<p>Quien desee explorar mi código, puede hacerlo libremente. También publicaré en enlace de GitHub donde pueden descargar el proyecto completo y si lo desean, pueden citarme cuando realicen sus practicas.</p>
<p>Conforme he avanzado en el estudio de este código, también he aprovechado para aprender nuevas cosas. Por ejemplo, en este articulo también se explicará el uso de JSDoc, comentarios para JSDoc, aplicaciones web progresivas, deducción de herramientas de trabajo mediante la lectura de código incompleto y mas. Espero que este trabajo sea de ayuda para aquellos que estén comenzando en el mundo de la programación.</p>
<h2>Contexto y estado del arte</h2>
<blockquote>
<p>El Juego de la vida es un autómata celular diseñado por el matemático británico John Horton Conway en 1970.
Hizo su primera aparición pública en el número de octubre de 1970 de la revista Scientific American, en la columna de juegos matemáticos de Martin Gardner. Desde un punto de vista teórico, es interesante porque es equivalente a una máquina universal de Turing, es decir, todo lo que se puede computar algorítmicamente se puede computar en el juego de la vida.</p>
<p>Desde su publicación, ha atraído mucho interés debido a la gran variabilidad de la evolución de los patrones. Se considera que el Juego de la vida es un buen ejemplo de emergencia y autoorganización. Es interesante para científicos, matemáticos, economistas y otros observar cómo patrones complejos pueden provenir de la implementación de reglas muy sencillas. <a href="https://es.wikipedia.org/wiki/Juego_de_la_vida">(Wikipedia,2021)</a></p>
</blockquote>
<p>Las reglas del juego de la vida son sencillas:</p>
<ul>
<li>Una célula viva con menos de dos vecinos vivos se muere (de soledad)</li>
<li>Una con dos o tres vecinos vivos sobrevive</li>
<li>Una con más de tres vecinos vivos se muere (por sobrepoblación)</li>
<li>Una célula muerta con exactamente tres vecinos vivos, nace (por reproducción)</li>
</ul>
<p>Estas simplicidades de las reglas hacen que básicamente sea el juego mas fácil de programar que se me ocurre.</p>
<p>A pesar de que es algo que se conoce desde mas de medio siglo, me propuse buscar la implementación mas simple posible para poder aprender y entender como funciona este juego a nivel de programación. para esto, he localizado las siguientes implementaciones:</p>
<h3>Pulgarin.co</h3>
<p>La implementación mas sencilla que he encontrado. Pero debido a que es algo ya muy viejo, se ha perdido el código html y las dependencias jquery de las que depende.</p>
<h3>pmav.eu</h3>
<p><a href="https://pmav.eu/stuff/javascript-game-of-life-v3.1.1/">javascript game of life</a></p>
<p>Es tal vez una de las implementaciones mas extensas que he encontrado, pero muy compleja para entender como principiante. También es una implementación muy antigua, de alrededor del año 2008 o 2010. Al menos la pagina sigue viva.</p>
<h3>javascript.plainenglish.io</h3>
<p><a href="https://javascript.plainenglish.io/the-game-of-life-using-javascript-fc1aaec8274f?gi=ca6f1846eddf">the game of life using javascript</a></p>
<p>Tal vez la mejor documentada de todas las implementaciones que he visto. Una lastima no haberla visto antes de comenzar este proyecto, pero al menos aprendí a hacerlo por mi cuenta.</p>
<h1>Desarrollo</h1>
<p>Es raro que un código de 329 líneas de código requiera tanta atención, pero he de abarcar todas estas cosas en artículos distintos que enlazo a continuación.</p>
<h2>Análisis de la situación</h2>
<p><a href="analisis_situacion.md">Análisis de situación</a></p>
<p>Como deducir la tecnología utilizada en el código original</p>
<h2>Inicialización de un proyecto con npm init</h2>
<p>uso del comando npm init y configuración de las opciones del proyecto</p>
<h2>Uso de clases en JavaScript</h2>
<p>razones para utilizar clases en javascript, como se crean, inicializan y razón para usarlas al reescribir este código</p>
<h2>Implementación de un sistema de inicialización</h2>
<p>forma en la que se inicializan las clases, variables dentro de las clases y funciones que llaman métodos en clases</p>
<h2>Implementación de un sistema de dibujado</h2>
<p>Estudio de la clase gráficos, como funciona en lienzo canvas y la variable de contexto (ctx)</p>
<p>funciones de dibujado y como se reciclan</p>
<h2>Implantación de un sistema de funciones publicas</h2>
<p>Funciones publicas que realizan tareas adicionales</p>
<h2>Uso de comentarios para jsdoc</h2>
<p>Comentarios en jsdoc, como pueden ayudar a la documentación de un código y como se ven en Visual Studio Code.</p>
<h2>Compilando en JSDoc</h2>
<p>Modificación del código de package.json para agregar comandos de jsdoc</p>
<p>opciones de configuración, y parámetros adicionales</p>
<h2>Service workers y PWA</h2>
<h3>usos de pwa y app cache para trabajo offline</h3>
<p>https://www.pwabuilder.com</p>
<h2>Web responsiva</h2>
<h2>hosting http y https</h2>
<p>Etiquetas que permiten a la pagina web adaptarse a los tamaños de pantalla</p>
<h2>Readme.md y otros archivos de documentación</h2>
<h1>Conclusiones y trabajos futuros</h1>
<p>Estoy bastante sorprendido de todo lo que se puede hacer con algo tan simple que se puede resumir en cuatro reglas. pero parece que queda mucho mas.</p>
<p>al juego le hacen falta muchas cosas, pero las que he visto hasta el momento son las siguientes:</p>
<ul>
<li><strong>Debería poder modificar el tamaño del lienzo</strong></li>
</ul>
<p>Al leer el código se pueden encontrar algunos comentarios que he dejado, que demuestran que al menos lo he intentado.</p>
<p>Me gustaría que el código permita crear un lienzo del ancho de la pantalla, pero eso tal vez haga el código muy extenso para mi propósito original.</p>
<p>He intentado utilizando algo de CSS, pero el resultado es que, si bien el lienzo se adapta al ancho de la pantalla, se pierde precisión del click, haciendo que solo un cuarto de la pantalla sea preciso y el resto no detecte el click en las partes que corresponde.</p>
<ul>
<li><strong>Debería permitir arrastrar y soltar para dibujar en el lienzo</strong></li>
</ul>
<p>Curiosamente es una función que se encuentra en el código original. El problema es que no logre implementarla sin que se rompa todo. Tengo que estudiar mas para saber como hacerlo.</p>
<ul>
<li><strong>Hay bugs extraños, muy extraños</strong></li>
</ul>
<p>Aunque he creado una función para iniciar y otra para parar la ejecución del temporizador para procesar las nuevas generaciones, en algunos casos y por alguna razón, es imposible detener el temporizador después de funcionar correctamente antes. Es un problema extraño que pensé que se solucionaría si controlaba las veces que se puede usar la función iniciar. Tal vez deba agregar un changelog y un control de versiones, quien sabe.</p>
<ul>
<li><strong>Funciones adicionales</strong></li>
</ul>
<p>Una vez terminado el proyecto me di cuenta de que seria genial que haya mas funciones, pero tal vez dejaría de ser didáctico si hago eso. Aun así destaco lo siguiente:</p>
<ol>
<li>Seria genial si se pudiera generar un arreglo aleatorio para iniciar</li>
<li>Me gustaría agregar una lista de arreglos prediseñados para poder ver como funcionan los diferentes patrones ya descubiertos.</li>
<li>Me gustaría que se puedan configurar los colores</li>
<li>¡Agregar publicidad! Bueno, es algo que siempre quise aprender a hacer y muchos de los códigos que he encontrado la agregan.</li>
<li>¿Comentarios y sugerencias? Tal vez es muy optimista agregar un elemento así en una aplicación super simple, mas aun sabiendo que no creo que reciba algún comentario en mi propio blog.</li>
</ol>
<h1>Bibliografía/webgrafía</h1>
<p><a href="https://www.codeandbeyond.org/2011/01/code-katas-la-practica-hace-al-maestro.html">Code katas, la practica hace al maestro(2011).Obtenido de www.codeandbeyond.org</a></p>
<p><a href="https://julianpulgarin.com/canvaslife/">El juego de la vida(2011), obtenido de www.pulgarin.co</a> (enlace roto)</p>
<p><a href="https://es.wikipedia.org/wiki/Juego_de_la_vida">El juego de la vida(2021), obtenido de es.wikipedia.org</a></p>
<p><a href="https://pmav.eu/stuff/javascript-game-of-life-v3.1.1/">El juego de la vida (2008-2010), obtenido de pmav</a></p>
<p><a href="https://javascript.plainenglish.io/the-game-of-life-using-javascript-fc1aaec8274f?gi=ca6f1846eddf">the game of life using javascript (2020), javascript.plainenglish.io</a></p></article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="graficos.html">graficos</a></li><li><a href="Punto.html">Punto</a></li></ul><h3>Global</h3><ul><li><a href="global.html#_contarvecinos">_contarvecinos</a></li><li><a href="global.html#getPuntoBajoMouse">getPuntoBajoMouse</a></li><li><a href="global.html#iniciar">iniciar</a></li><li><a href="global.html#init">init</a></li><li><a href="global.html#limpiar">limpiar</a></li><li><a href="global.html#parar">parar</a></li><li><a href="global.html#procesarCelula">procesarCelula</a></li><li><a href="global.html#siguiente_generacion">siguiente_generacion</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.7</a> on Fri Sep 10 2021 08:16:05 GMT-0500 (GMT-05:00)
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>

409
Documentacion/index.js.html Executable file
View File

@@ -0,0 +1,409 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Source: index.js</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Source: index.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>/**
* Hace mucho tiempo, antes de intentar tomarme en serio la programacion, publique [un post en mi blog sobre el juego de la vida](https://interlan.ec/2020/05/23/el-juego-de-la-vida-en-javascript/). Habiendo mejorado mucho mis capacidades para leer codigo y hacer muchas cosas mas, decidi retomar mi blog para llenarlo con nuevos contenidos que ayuden a otras personas a las que les interesen las mismas cosas que a mi.
*
* @projectname El juego de la vida. Una reescritura en vainilla javascript
* @version 1.0
* @author drk0027
* @copyright 2021
*
*/
/**
* # Punto
*
* Esta clase almacena temporalmente las coordenadas X,Y como un objeto
*/
class Punto {
constructor(x, y) {
this.x = x
this.y = y
}
}
/**
* # Graficos
*
* Esta clase permite el control y la creacion del lienzo y las funciones que alteran el estado del lienzo
*/
class graficos {
constructor() {
//contexto
this.ctx = lienzo.getContext("2d")
//colores
this.color_encendido = 'rgb(0, 0, 0)'
this.color_apagado = 'rgb(255, 255, 255)'
this.color_rejilla = 'rgb(50, 50, 50)'
//tamaños
this.tamaño_celula = 10
//celdas
this.yCelula
this.xCelula
this.prev = []
this.sig = []
//temporizador
this.intervalo
}
/**
* # Dibujar Celula
*
* Permite dibujar una celula en un estado encendido o apagado en un lugar determinado del lienzo
* @param {int} x
* @param {int} y
* @param {bool} estado
*/
dibujarCelula(x, y, estado) {
if (estado == 1) {
this.ctx.fillStyle = this.color_encendido
} else {
this.ctx.fillStyle = this.color_apagado
}
this.ctx.fillRect(x * this.tamaño_celula + 1, y * this.tamaño_celula + 1, this.tamaño_celula - 1, this.tamaño_celula - 1)
}
/**
* # Pintar
*
* Esta funcion cambia el estado de todas las celulas de acuerdo al que esta almacenado en la matriz original
*/
pintar() {
for (var x = 0; x &lt; this.xCelula; x++) {
for (var y = 0; y &lt; this.yCelula; y++) {
this.dibujarCelula(x, y, this.prev[x][y]);
}
}
}
}
//inicializar clase graficos
const gx = new graficos()
//variables globales
var celula = ""
var estado = ""
/**
* # Procesar Celula
*
* Esta funcion permite calcular la posicion de la celula y determinar su estado
* @param {Object} celula Objeto de puntos en X,Y definido en la clase Puntos
*/
function procesarCelula(celula) {
var x = celula.x
var y = celula.y
var estado = 1
if (x > gx.xCelula - 1 || y > gx.yCelula - 1) {
return;
}
if (typeof estado == 'undefined') {
estado = !gx.prev[x][y];
}
gx.prev[x][y] = estado;
gx.dibujarCelula(x, y, estado);
}
/**
* # Celda seleccionada (getPuntoBajoMouse)
*
* Esta funcion permite al programa determinar en sobre que celda se encuentra posicionado el mouse a partir de las coordenadas devueltas por el evento mousedown.
*
* Para calcular este valor, se realizan las siguientes operaciones
*
* X=
*
* Donde:
*
* e.pageX: posicion del cursor en x
* e.pageY: posicion del cursor en y
*
* gx.ctx.canvas.offsetLeft: pixeles desde el lienzo hasta el borde de la pantalla a la izquierda
* gx.ctx.canvas.offsetright: pixeles desde el lienzo hasta el borde de la pantalla arriba
* gx.tamaño_celula: tamaño de la celula en pixeles
*
* @param {Object} e eventos devueltos por el listener de mousedown
*/
function getPuntoBajoMouse(e) {
//esta funcion permite optener un nuevo punto por medio de restar pageX (eje x devuelto por el evento del mouse) menos el offset izquierdo del lienzo, dividirlo para el tamaño de la celula (definido en la clase grafico) o establecer el punto como cero para el punto x de la clase Punto
/*
esta funcion devuelve un nuevo arreglo de puntos x,y para la clase Punto
Punto X: resta pageX (eje x devuelto por el evento del mouse) menos el offset izquierdo del lienzo, dividirlo para el tamaño de la celula (definido en la clase grafico) o establecer el punto como cero para el punto x de la clase Punto.
Punto Y: resta pagey (eje x devuelto por el evento del mouse) menos el offset superior del lienzo, dividirlo para el tamaño de la celula (definido en la clase grafico) o establecer el punto como cero para el punto y de la clase Punto.
*/
return new Punto((e.pageX - gx.ctx.canvas.offsetLeft) / gx.tamaño_celula | 0, ((e.pageY - gx.ctx.canvas.offsetTop) / gx.tamaño_celula) | 0);
}
/**
* # Init
*
* Esta funcion permite inicializar todas las variables necesarias para el funcionamiento de este programa
*/
function init() {
gx.xCelula = ((gx.ctx.canvas.width - 1) / gx.tamaño_celula) | 0
gx.yCelula = ((gx.ctx.canvas.height - 1) / gx.tamaño_celula) | 0
//inicializa el panel en color encendido
gx.ctx.fillStyle = gx.color_apagado
//Pintar el fondo
gx.ctx.fillRect(0, 0, gx.xCelula * gx.tamaño_celula, gx.yCelula * gx.tamaño_celula)
//Definir color de la rejilla
gx.ctx.fillStyle = gx.color_rejilla
//Dibujar lineas verticales
for (var x = 0; x &lt; gx.xCelula; x++) {
//se inicializa la matriz
gx.prev[x] = []
gx.sig[x] = []
//se dibuja cada celula
gx.ctx.fillRect(x * gx.tamaño_celula, 0, 1, gx.yCelula * gx.tamaño_celula)
for (var y = 0; y &lt; gx.yCelula; y++) {
gx.prev[x][y] = false;
}
}
gx.ctx.fillRect(gx.xCelula * gx.tamaño_celula, 0, 1, gx.yCelula * gx.tamaño_celula)
//Dibujar lineas horizontales
for (var y = 0; y &lt; gx.yCelula; y++) {
gx.ctx.fillRect(0, y * gx.tamaño_celula, gx.xCelula * gx.tamaño_celula, 1)
}
gx.ctx.fillRect(0, gx.yCelula * gx.tamaño_celula, gx.xCelula * gx.tamaño_celula, 1)
}
/**
* # Contar Vecinos
*
* Esta funcion permite contar los vecinos de una celula, sea que esta viva como si esta muerta y devuelve la cantidad de vecinos vivos que esta tenga.
*
* Esquema:
*
* **Esquema:**
*
* 3 4 5
* | | |
* v v v
* __ ___ ___
* | | | | &lt;-3
* +---|---|---|
* | 1 | 1 | 1 | &lt;-4
* +---|---|---|
* | | | | &lt;-5
* +---|---|---|
*
* **calcular el vecino de 4,4**
*
* xCelula la cantidad de filas de celulas
* yCelula es la cantidad de columnas de celulas
*
* |variable|estado|
* |--------|------|
* |prev[4][3]|verdadero|
* |prev[5][3]|falso|
* |prev[5][4]|falso|
* |prev[5][5]|falso|
* |prev[4][5]|verdadero|
* |prev[3][5]|falso|
* |prev[3][4]|falso|
* |prev[3][3]|falso|
*
* @param {int} x filas
* @param {int} y columnas
*/
function _contarvecinos(x, y) {
var cantidad = 0
var vecinos = [
gx.prev[x][(y - 1 + gx.yCelula) % gx.yCelula],
gx.prev[(x + 1 + gx.xCelula) % gx.xCelula][(y - 1 + gx.yCelula) % gx.yCelula],
gx.prev[(x + 1 + gx.xCelula) % gx.xCelula][y],
gx.prev[(x + 1 + gx.xCelula) % gx.xCelula][(y + 1 + gx.yCelula) % gx.yCelula],
gx.prev[x][(y + 1 + gx.yCelula) % gx.yCelula],
gx.prev[(x - 1 + gx.xCelula) % gx.xCelula][(y + 1 + gx.yCelula) % gx.yCelula],
gx.prev[(x - 1 + gx.xCelula) % gx.xCelula][y],
gx.prev[(x - 1 + gx.xCelula) % gx.xCelula][(y - 1 + gx.yCelula) % gx.yCelula],
]
for (var i = 0; i &lt; vecinos.length; i++) {
if (vecinos[i]) {//si hay valor o no
cantidad++;
}
}
return cantidad
}
/**
* # Siguiente Generacion
*
* Esta funcion se encarga de calcular la siguiente generacion de la partida, para esto, crea un nuevo arreglo con la matriz aun vigente, luego hace un barrido por cada una de las celdas buscando cuantas celulas tienen vecinos y evalua su situacion actual segun las reglas del juego de la vida. Una vez hecho esto, se copia la nueva matriz sobre la anterior, sobreescribiendola y mostrandola en pantalla.
*
* ## Reglas del juego de la vida
*
* - Cualquier celula viva con dos o tres compañeros vivos, sobrevive
* - Cualquier celula muerta con tres compañeros vivos, revive
* - Todas las demas celulas mueren en la siguiente generacion. De la misma forma, las celulas muertas, permanecen muertas
*
* (Conway's game of Life, Wikipedia)
*
*/
function siguiente_generacion() {
//Copiar el arreglo de la pantalla anterior en uno nuevo, que sera modificado mas adelante
for (var x = 0; x &lt; gx.xCelula; x++) {//numero de filas
for (var y = 0; y &lt; gx.yCelula; y++) {//numero de columnas
gx.sig[x][y] = gx.prev[x][y];
}
}
for (var x = 0; x &lt; gx.xCelula; x++) {//numero de filas
for (var y = 0; y &lt; gx.yCelula; y++) {//numero de columnas
var cantidad = _contarvecinos(x, y);
// Reglas del juego de la vida
if (gx.prev[x][y]) { //si la celula esta encendida
if (cantidad &lt; 2 || cantidad > 3) {//si la celula tiene menos de dos vecinos vivos o mas de tres muere
gx.sig[x][y] = false;
}
} else if (cantidad == 3) { //sino, esta viva
gx.sig[x][y] = true;
}
}
}
//copiar arreglo modificado en el anterior
for (var x = 0; x &lt; gx.xCelula; x++) {
for (var y = 0; y &lt; gx.yCelula; y++) {
gx.prev[x][y] = gx.sig[x][y];
}
}
gx.pintar()
}
/**
* # Limpiar
*
* Cambia el estado de cada celula a apagado
*/
function limpiar() {
for (var x = 0; x &lt; gx.xCelula; x++) {
for (var y = 0; y &lt; gx.yCelula; y++) {
gx.prev[x][y] = false
}
}
gx.pintar()
}
/**
* #Init
*
* Inicializa la plataforma
*/
init()
//eventos
/**
* # Listener: mousedown
*
* Agrega un gestor de eventos que detecte cuando se hace click en una celda correspondiente a una celula
*/
lienzo.addEventListener("mousedown", e => {
celula = getPuntoBajoMouse(e)
procesarCelula(celula)
})
/**
* # Iniciar
*
* Inicia el temporizador que avanza cada generacion
*/
function iniciar(){
gx.intervalo=setInterval(siguiente_generacion,500)
}
/**
* # Parar
*
* Limpia el temporizador que ejecuta la funcion de siguiente_generacion
*/
function parar(){
clearInterval(gx.intervalo)
}
//Service-Worker
window.addEventListener('beforeinstallprompt', (event) => {
console.log('👍', 'beforeinstallprompt', event);
// Stash the event so it can be triggered later.
window.deferredPrompt = event;
// Remove the 'hidden' class from the install button container
//divInstall.classList.toggle('hidden', false);
});
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('service-worker.js');
}
if (window.location.protocol === 'http:') {
console.log("cuidado, no pùedes instalar apps desde un sitio inseguro")
//determina si estoy en una pagina insegura
/* const requireHTTPS = document.getElementById('requireHTTPS');
const link = requireHTTPS.querySelector('a');
link.href = window.location.href.replace('http://', 'https://');
requireHTTPS.classList.remove('hidden'); */
}
window.addEventListener('appinstalled', (event) => {
console.log('👍', 'appinstalled', event);
// Clear the deferredPrompt so it can be garbage collected
window.deferredPrompt = null;
});</code></pre>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="graficos.html">graficos</a></li><li><a href="Punto.html">Punto</a></li></ul><h3>Global</h3><ul><li><a href="global.html#_contarvecinos">_contarvecinos</a></li><li><a href="global.html#getPuntoBajoMouse">getPuntoBajoMouse</a></li><li><a href="global.html#iniciar">iniciar</a></li><li><a href="global.html#init">init</a></li><li><a href="global.html#limpiar">limpiar</a></li><li><a href="global.html#parar">parar</a></li><li><a href="global.html#procesarCelula">procesarCelula</a></li><li><a href="global.html#siguiente_generacion">siguiente_generacion</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.7</a> on Fri Sep 10 2021 08:16:05 GMT-0500 (GMT-05:00)
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>

View File

@@ -0,0 +1,25 @@
/*global document */
(() => {
const source = document.getElementsByClassName('prettyprint source linenums');
let i = 0;
let lineNumber = 0;
let lineId;
let lines;
let totalLines;
let anchorHash;
if (source && source[0]) {
anchorHash = document.location.hash.substring(1);
lines = source[0].getElementsByTagName('li');
totalLines = lines.length;
for (; i < totalLines; i++) {
lineNumber++;
lineId = `line${lineNumber}`;
lines[i].id = lineId;
if (lineId === anchorHash) {
lines[i].className += ' selected';
}
}
}
})();

View File

@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -0,0 +1,2 @@
PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\f\r ]+/,null," \t\r\n "]],[["str",/^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/,null],["str",/^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/,null],["lang-css-str",/^url\(([^"')]*)\)/i],["kwd",/^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i],["com",/^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//],["com",
/^(?:<\!--|--\>)/],["lit",/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],["lit",/^#[\da-f]{3,6}/i],["pln",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i],["pun",/^[^\s\w"']+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[["kwd",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[["str",/^[^"')]+/]]),["css-str"]);

View File

@@ -0,0 +1,28 @@
var q=null;window.PR_SHOULD_USE_CONTINUATION=!0;
(function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a=
[],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c<i;++c){var j=f[c];if(/\\[bdsw]/i.test(j))a.push(j);else{var j=m(j),d;c+2<i&&"-"===f[c+1]?(d=m(f[c+2]),c+=2):d=j;b.push([j,d]);d<65||j>122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;c<b.length;++c)i=b[c],i[0]<=j[1]+1?j[1]=Math.max(j[1],i[1]):f.push(j=i);b=["["];o&&b.push("^");b.push.apply(b,a);for(c=0;c<
f.length;++c)i=f[c],b.push(e(i[0])),i[1]>i[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c<b;++c){var j=f[c];j==="("?++i:"\\"===j.charAt(0)&&(j=+j.substring(1))&&j<=i&&(d[j]=-1)}for(c=1;c<d.length;++c)-1===d[c]&&(d[c]=++t);for(i=c=0;c<b;++c)j=f[c],j==="("?(++i,d[i]===void 0&&(f[c]="(?:")):"\\"===j.charAt(0)&&
(j=+j.substring(1))&&j<=i&&(f[c]="\\"+d[i]);for(i=c=0;c<b;++c)"^"===f[c]&&"^"!==f[c+1]&&(f[c]="");if(a.ignoreCase&&s)for(c=0;c<b;++c)j=f[c],a=j.charAt(0),j.length>=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p<d;++p){var g=a[p];if(g.ignoreCase)l=!0;else if(/[a-z]/i.test(g.source.replace(/\\u[\da-f]{4}|\\x[\da-f]{2}|\\[^UXux]/gi,""))){s=!0;l=!1;break}}for(var r=
{b:8,t:9,n:10,v:11,f:12,r:13},n=[],p=0,d=a.length;p<d;++p){g=a[p];if(g.global||g.multiline)throw Error(""+g);n.push("(?:"+y(g)+")")}return RegExp(n.join("|"),l?"gi":"g")}function M(a){function m(a){switch(a.nodeType){case 1:if(e.test(a.className))break;for(var g=a.firstChild;g;g=g.nextSibling)m(g);g=a.nodeName;if("BR"===g||"LI"===g)h[s]="\n",t[s<<1]=y++,t[s++<<1|1]=a;break;case 3:case 4:g=a.nodeValue,g.length&&(g=p?g.replace(/\r\n?/g,"\n"):g.replace(/[\t\n\r ]+/g," "),h[s]=g,t[s<<1]=y,y+=g.length,
t[s++<<1|1]=a)}}var e=/(?:^|\s)nocode(?:\s|$)/,h=[],y=0,t=[],s=0,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=document.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);m(a);return{a:h.join("").replace(/\n$/,""),c:t}}function B(a,m,e,h){m&&(a={a:m,d:a},e(a),h.push.apply(h,a.e))}function x(a,m){function e(a){for(var l=a.d,p=[l,"pln"],d=0,g=a.a.match(y)||[],r={},n=0,z=g.length;n<z;++n){var f=g[n],b=r[f],o=void 0,c;if(typeof b===
"string")c=!1;else{var i=h[f.charAt(0)];if(i)o=f.match(i[1]),b=i[0];else{for(c=0;c<t;++c)if(i=m[c],o=f.match(i[1])){b=i[0];break}o||(b="pln")}if((c=b.length>=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m),
l=[],p={},d=0,g=e.length;d<g;++d){var r=e[d],n=r[3];if(n)for(var k=n.length;--k>=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/,
q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/,
q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g,
"");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a),
a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e}
for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g<d.length;++g)e(d[g]);m===(m|0)&&d[0].setAttribute("value",
m);var r=s.createElement("OL");r.className="linenums";for(var n=Math.max(0,m-1|0)||0,g=0,z=d.length;g<z;++g)l=d[g],l.className="L"+(g+n)%10,l.firstChild||l.appendChild(s.createTextNode("\xa0")),r.appendChild(l);a.appendChild(r)}function k(a,m){for(var e=m.length;--e>=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*</.test(m)?"default-markup":"default-code";return A[a]}function E(a){var m=
a.g;try{var e=M(a.h),h=e.a;a.a=h;a.c=e.c;a.d=0;C(m,h)(a);var k=/\bMSIE\b/.test(navigator.userAgent),m=/\n/g,t=a.a,s=t.length,e=0,l=a.c,p=l.length,h=0,d=a.e,g=d.length,a=0;d[g]=s;var r,n;for(n=r=0;n<g;)d[n]!==d[n+2]?(d[r++]=d[n++],d[r++]=d[n++]):n+=2;g=r;for(n=r=0;n<g;){for(var z=d[n],f=d[n+1],b=n+2;b+2<=g&&d[b+1]===f;)b+=2;d[r++]=z;d[r++]=f;n=b}for(d.length=r;h<p;){var o=l[h+2]||s,c=d[a+2]||s,b=Math.min(o,c),i=l[h+1],j;if(i.nodeType!==1&&(j=t.substring(e,b))){k&&(j=j.replace(m,"\r"));i.nodeValue=
j;var u=i.ownerDocument,v=u.createElement("SPAN");v.className=d[a+1];var x=i.parentNode;x.replaceChild(v,i);v.appendChild(i);e<o&&(l[h+1]=i=u.createTextNode(t.substring(b,o)),x.insertBefore(i,v.nextSibling))}e=b;e>=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"],
"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"],
H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"],
J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+
I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^<?]+/],["dec",/^<!\w[^>]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^<xmp\b[^>]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^<script\b[^>]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^<style\b[^>]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),
["default-markup","htm","html","mxml","xhtml","xml","xsl"]);k(x([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css",
/^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);k(x([],[["atv",/^[\S\s]+/]]),["uq.val"]);k(u({keywords:F,hashComments:!0,cStyleComments:!0,types:K}),["c","cc","cpp","cxx","cyc","m"]);k(u({keywords:"null,true,false"}),["json"]);k(u({keywords:H,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:K}),["cs"]);k(u({keywords:G,cStyleComments:!0}),["java"]);k(u({keywords:v,hashComments:!0,multiLineStrings:!0}),["bsh","csh","sh"]);k(u({keywords:I,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}),
["cv","py"]);k(u({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["perl","pl","pm"]);k(u({keywords:J,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb"]);k(u({keywords:w,cStyleComments:!0,regexLiterals:!0}),["js"]);k(u({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes",
hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);k(x([],[["str",/^[\S\s]+/]]),["regex"]);window.prettyPrintOne=function(a,m,e){var h=document.createElement("PRE");h.innerHTML=a;e&&D(h,e);E({g:m,i:e,h:h});return h.innerHTML};window.prettyPrint=function(a){function m(){for(var e=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;p<h.length&&l.now()<e;p++){var n=h[p],k=n.className;if(k.indexOf("prettyprint")>=0){var k=k.match(g),f,b;if(b=
!k){b=n;for(var o=void 0,c=b.firstChild;c;c=c.nextSibling)var i=c.nodeType,o=i===1?o?b:c:i===3?N.test(c.nodeValue)?b:o:o;b=(f=o===b?void 0:o)&&"CODE"===f.tagName}b&&(k=f.className.match(g));k&&(k=k[1]);b=!1;for(o=n.parentNode;o;o=o.parentNode)if((o.tagName==="pre"||o.tagName==="code"||o.tagName==="xmp")&&o.className&&o.className.indexOf("prettyprint")>=0){b=!0;break}b||((b=(b=n.className.match(/\blinenums\b(?::(\d+))?/))?b[1]&&b[1].length?+b[1]:!0:!1)&&D(n,b),d={g:k,h:n,i:b},E(d))}}p<h.length?setTimeout(m,
250):a&&a()}for(var e=[document.getElementsByTagName("pre"),document.getElementsByTagName("code"),document.getElementsByTagName("xmp")],h=[],k=0;k<e.length;++k)for(var t=0,s=e[k].length;t<s;++t)h.push(e[k][t]);var e=q,l=Date;l.now||(l={now:function(){return+new Date}});var p=0,d,g=/\blang(?:uage)?-([\w.]+)(?!\S)/;m()};window.PR={createSimpleLexer:x,registerLangHandler:k,sourceDecorator:u,PR_ATTRIB_NAME:"atn",PR_ATTRIB_VALUE:"atv",PR_COMMENT:"com",PR_DECLARATION:"dec",PR_KEYWORD:"kwd",PR_LITERAL:"lit",
PR_NOCODE:"nocode",PR_PLAIN:"pln",PR_PUNCTUATION:"pun",PR_SOURCE:"src",PR_STRING:"str",PR_TAG:"tag",PR_TYPE:"typ"}})();

View File

@@ -0,0 +1,358 @@
@font-face {
font-family: 'Open Sans';
font-weight: normal;
font-style: normal;
src: url('../fonts/OpenSans-Regular-webfont.eot');
src:
local('Open Sans'),
local('OpenSans'),
url('../fonts/OpenSans-Regular-webfont.eot?#iefix') format('embedded-opentype'),
url('../fonts/OpenSans-Regular-webfont.woff') format('woff'),
url('../fonts/OpenSans-Regular-webfont.svg#open_sansregular') format('svg');
}
@font-face {
font-family: 'Open Sans Light';
font-weight: normal;
font-style: normal;
src: url('../fonts/OpenSans-Light-webfont.eot');
src:
local('Open Sans Light'),
local('OpenSans Light'),
url('../fonts/OpenSans-Light-webfont.eot?#iefix') format('embedded-opentype'),
url('../fonts/OpenSans-Light-webfont.woff') format('woff'),
url('../fonts/OpenSans-Light-webfont.svg#open_sanslight') format('svg');
}
html
{
overflow: auto;
background-color: #fff;
font-size: 14px;
}
body
{
font-family: 'Open Sans', sans-serif;
line-height: 1.5;
color: #4d4e53;
background-color: white;
}
a, a:visited, a:active {
color: #0095dd;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
header
{
display: block;
padding: 0px 4px;
}
tt, code, kbd, samp {
font-family: Consolas, Monaco, 'Andale Mono', monospace;
}
.class-description {
font-size: 130%;
line-height: 140%;
margin-bottom: 1em;
margin-top: 1em;
}
.class-description:empty {
margin: 0;
}
#main {
float: left;
width: 70%;
}
article dl {
margin-bottom: 40px;
}
article img {
max-width: 100%;
}
section
{
display: block;
background-color: #fff;
padding: 12px 24px;
border-bottom: 1px solid #ccc;
margin-right: 30px;
}
.variation {
display: none;
}
.signature-attributes {
font-size: 60%;
color: #aaa;
font-style: italic;
font-weight: lighter;
}
nav
{
display: block;
float: right;
margin-top: 28px;
width: 30%;
box-sizing: border-box;
border-left: 1px solid #ccc;
padding-left: 16px;
}
nav ul {
font-family: 'Lucida Grande', 'Lucida Sans Unicode', arial, sans-serif;
font-size: 100%;
line-height: 17px;
padding: 0;
margin: 0;
list-style-type: none;
}
nav ul a, nav ul a:visited, nav ul a:active {
font-family: Consolas, Monaco, 'Andale Mono', monospace;
line-height: 18px;
color: #4D4E53;
}
nav h3 {
margin-top: 12px;
}
nav li {
margin-top: 6px;
}
footer {
display: block;
padding: 6px;
margin-top: 12px;
font-style: italic;
font-size: 90%;
}
h1, h2, h3, h4 {
font-weight: 200;
margin: 0;
}
h1
{
font-family: 'Open Sans Light', sans-serif;
font-size: 48px;
letter-spacing: -2px;
margin: 12px 24px 20px;
}
h2, h3.subsection-title
{
font-size: 30px;
font-weight: 700;
letter-spacing: -1px;
margin-bottom: 12px;
}
h3
{
font-size: 24px;
letter-spacing: -0.5px;
margin-bottom: 12px;
}
h4
{
font-size: 18px;
letter-spacing: -0.33px;
margin-bottom: 12px;
color: #4d4e53;
}
h5, .container-overview .subsection-title
{
font-size: 120%;
font-weight: bold;
letter-spacing: -0.01em;
margin: 8px 0 3px 0;
}
h6
{
font-size: 100%;
letter-spacing: -0.01em;
margin: 6px 0 3px 0;
font-style: italic;
}
table
{
border-spacing: 0;
border: 0;
border-collapse: collapse;
}
td, th
{
border: 1px solid #ddd;
margin: 0px;
text-align: left;
vertical-align: top;
padding: 4px 6px;
display: table-cell;
}
thead tr
{
background-color: #ddd;
font-weight: bold;
}
th { border-right: 1px solid #aaa; }
tr > th:last-child { border-right: 1px solid #ddd; }
.ancestors, .attribs { color: #999; }
.ancestors a, .attribs a
{
color: #999 !important;
text-decoration: none;
}
.clear
{
clear: both;
}
.important
{
font-weight: bold;
color: #950B02;
}
.yes-def {
text-indent: -1000px;
}
.type-signature {
color: #aaa;
}
.name, .signature {
font-family: Consolas, Monaco, 'Andale Mono', monospace;
}
.details { margin-top: 14px; border-left: 2px solid #DDD; }
.details dt { width: 120px; float: left; padding-left: 10px; padding-top: 6px; }
.details dd { margin-left: 70px; }
.details ul { margin: 0; }
.details ul { list-style-type: none; }
.details li { margin-left: 30px; padding-top: 6px; }
.details pre.prettyprint { margin: 0 }
.details .object-value { padding-top: 0; }
.description {
margin-bottom: 1em;
margin-top: 1em;
}
.code-caption
{
font-style: italic;
font-size: 107%;
margin: 0;
}
.source
{
border: 1px solid #ddd;
width: 80%;
overflow: auto;
}
.prettyprint.source {
width: inherit;
}
.source code
{
font-size: 100%;
line-height: 18px;
display: block;
padding: 4px 12px;
margin: 0;
background-color: #fff;
color: #4D4E53;
}
.prettyprint code span.line
{
display: inline-block;
}
.prettyprint.linenums
{
padding-left: 70px;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.prettyprint.linenums ol
{
padding-left: 0;
}
.prettyprint.linenums li
{
border-left: 3px #ddd solid;
}
.prettyprint.linenums li.selected,
.prettyprint.linenums li.selected *
{
background-color: lightyellow;
}
.prettyprint.linenums li *
{
-webkit-user-select: text;
-moz-user-select: text;
-ms-user-select: text;
user-select: text;
}
.params .name, .props .name, .name code {
color: #4D4E53;
font-family: Consolas, Monaco, 'Andale Mono', monospace;
font-size: 100%;
}
.params td.description > p:first-child,
.props td.description > p:first-child
{
margin-top: 0;
padding-top: 0;
}
.params td.description > p:last-child,
.props td.description > p:last-child
{
margin-bottom: 0;
padding-bottom: 0;
}
.disabled {
color: #454545;
}

View File

@@ -0,0 +1,111 @@
/* JSDoc prettify.js theme */
/* plain text */
.pln {
color: #000000;
font-weight: normal;
font-style: normal;
}
/* string content */
.str {
color: #006400;
font-weight: normal;
font-style: normal;
}
/* a keyword */
.kwd {
color: #000000;
font-weight: bold;
font-style: normal;
}
/* a comment */
.com {
font-weight: normal;
font-style: italic;
}
/* a type name */
.typ {
color: #000000;
font-weight: normal;
font-style: normal;
}
/* a literal value */
.lit {
color: #006400;
font-weight: normal;
font-style: normal;
}
/* punctuation */
.pun {
color: #000000;
font-weight: bold;
font-style: normal;
}
/* lisp open bracket */
.opn {
color: #000000;
font-weight: bold;
font-style: normal;
}
/* lisp close bracket */
.clo {
color: #000000;
font-weight: bold;
font-style: normal;
}
/* a markup tag name */
.tag {
color: #006400;
font-weight: normal;
font-style: normal;
}
/* a markup attribute name */
.atn {
color: #006400;
font-weight: normal;
font-style: normal;
}
/* a markup attribute value */
.atv {
color: #006400;
font-weight: normal;
font-style: normal;
}
/* a declaration */
.dec {
color: #000000;
font-weight: bold;
font-style: normal;
}
/* a variable name */
.var {
color: #000000;
font-weight: normal;
font-style: normal;
}
/* a function name */
.fun {
color: #000000;
font-weight: bold;
font-style: normal;
}
/* Specify class=linenums on a pre to get line numbering */
ol.linenums {
margin-top: 0;
margin-bottom: 0;
}

View File

@@ -0,0 +1,132 @@
/* Tomorrow Theme */
/* Original theme - https://github.com/chriskempson/tomorrow-theme */
/* Pretty printing styles. Used with prettify.js. */
/* SPAN elements with the classes below are added by prettyprint. */
/* plain text */
.pln {
color: #4d4d4c; }
@media screen {
/* string content */
.str {
color: #718c00; }
/* a keyword */
.kwd {
color: #8959a8; }
/* a comment */
.com {
color: #8e908c; }
/* a type name */
.typ {
color: #4271ae; }
/* a literal value */
.lit {
color: #f5871f; }
/* punctuation */
.pun {
color: #4d4d4c; }
/* lisp open bracket */
.opn {
color: #4d4d4c; }
/* lisp close bracket */
.clo {
color: #4d4d4c; }
/* a markup tag name */
.tag {
color: #c82829; }
/* a markup attribute name */
.atn {
color: #f5871f; }
/* a markup attribute value */
.atv {
color: #3e999f; }
/* a declaration */
.dec {
color: #f5871f; }
/* a variable name */
.var {
color: #c82829; }
/* a function name */
.fun {
color: #4271ae; } }
/* Use higher contrast and text-weight for printable form. */
@media print, projection {
.str {
color: #060; }
.kwd {
color: #006;
font-weight: bold; }
.com {
color: #600;
font-style: italic; }
.typ {
color: #404;
font-weight: bold; }
.lit {
color: #044; }
.pun, .opn, .clo {
color: #440; }
.tag {
color: #006;
font-weight: bold; }
.atn {
color: #404; }
.atv {
color: #060; } }
/* Style */
/*
pre.prettyprint {
background: white;
font-family: Consolas, Monaco, 'Andale Mono', monospace;
font-size: 12px;
line-height: 1.5;
border: 1px solid #ccc;
padding: 10px; }
*/
/* Specify class=linenums on a pre to get line numbering */
ol.linenums {
margin-top: 0;
margin-bottom: 0; }
/* IE indents via margin-left */
li.L0,
li.L1,
li.L2,
li.L3,
li.L4,
li.L5,
li.L6,
li.L7,
li.L8,
li.L9 {
/* */ }
/* Alternate shading for lines */
li.L1,
li.L3,
li.L5,
li.L7,
li.L9 {
/* */ }

233
GoL.js Executable file
View File

@@ -0,0 +1,233 @@
/*
* Copyright 2011 Julian Pulgarin
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var Point = function(x, y) {
this.x = x;
this.y = y;
};
var graphics = function() {
var canvas;
var ctx;
var canvasId;
var cellSize = 10; // pixels
var onColour = 'rgb(0, 200, 0)';
var offColour = 'rgb(200, 0, 0)';
var gridColour = 'rgb(50, 50, 50)';
var initCanvas = function(canvasId) {
this.canvas = $(canvasId).get(0);
this.ctx = this.canvas.getContext('2d');
this.canvasId = canvasId;
}
var drawCell = function(x, y, alive) {
var g = graphics;
g.ctx.fillStyle = (alive)? onColour : offColour;
g.ctx.fillRect(x * cellSize + 1, y * cellSize + 1, cellSize - 1, cellSize - 1);
}
var handleMouse = function(e) {
var l = life;
var g = graphics;
var that = this;
var cell = getCellPointUnderMouse(e);
var state;
processCell(cell);
$(g.canvasId).mousemove(function(e) {
cell = getCellPointUnderMouse(e);
processCell(cell);
});
function getCellPointUnderMouse(e) {
return new Point((e.pageX - that.offsetLeft) / g.cellSize | 0, ((e.pageY - that.offsetTop) / g.cellSize) | 0);
}
function processCell(cell) {
var x = cell.x;
var y = cell.y;
if (x > l.xCells - 1 || y > l.yCells - 1) {
return;
}
if (typeof state == 'undefined')
{
state = !l.prev[x][y];
}
l.prev[x][y] = state;
drawCell(x, y, state);
// TODO: Consider setting next as well
}
}
function paint() {
var g = graphics;
var l = life;
for (var x = 0; x < l.xCells; x++) {
for (var y = 0; y < l.yCells; y++) {
g.drawCell(x, y, l.prev[x][y]);
}
}
}
return {
canvas: canvas,
ctx: ctx,
canvasId: canvasId,
cellSize: cellSize,
onColour: onColour,
offColour: offColour,
gridColour: gridColour,
initCanvas: initCanvas,
drawCell: drawCell,
handleMouse: handleMouse,
paint: paint,
}
}();
var life = function() {
var yCells;
var xCells;
var prev = []; // previous generation
var next = []; // next generation
var _timeout;
var _alive = false;
var initUniverse = function(canvasId) {
var l = life;
var g = graphics;
g.initCanvas(canvasId);
l.xCells = ((g.canvas.width - 1) / g.cellSize) | 0;
l.yCells = ((g.canvas.height - 1) / g.cellSize) | 0;
g.ctx.fillStyle = g.offColour;
g.ctx.fillRect(0, 0, l.xCells * g.cellSize, l.yCells * g.cellSize);
g.ctx.fillStyle = g.gridColour;
for (var x = 0; x < l.xCells; x++) {
l.prev[x] = [];
l.next[x] = [];
g.ctx.fillRect(x * g.cellSize, 0, 1, l.yCells * g.cellSize);
for(var y = 0; y < l.yCells; y++)
{
l.prev[x][y] = false;
}
}
g.ctx.fillRect(l.xCells * g.cellSize, 0, 1, l.yCells * g.cellSize);
for(var y = 0; y < l.yCells; y++)
{
g.ctx.fillRect(0, y * g.cellSize, l.xCells * g.cellSize, 1);
}
g.ctx.fillRect(0, l.yCells * g.cellSize, l.xCells * g.cellSize, 1);
$(canvasId).mousedown(g.handleMouse);
$('body').mouseup(function(e)
{
$(g.canvasId).unbind('mousemove');
});
}
var nextGen = function() {
var l = life;
var g = graphics;
for (var x = 0; x < l.xCells; x++) {
for (var y = 0; y < l.yCells; y++) {
l.next[x][y] = l.prev[x][y];
}
}
for (var x = 0; x < l.xCells; x++) {
for (var y = 0; y < l.yCells; y++) {
count = _neighbourCount(x, y);
// Game of Life rules
if (prev[x][y]) {
if (count < 2 || count > 3) {
next[x][y] = false;
}
} else if (count == 3) {
next[x][y] = true;
}
}
}
for (var x = 0; x < l.xCells; x++) {
for (var y = 0; y < l.yCells; y++) {
l.prev[x][y] = l.next[x][y];
}
}
g.paint();
}
var toggleLife = function() {
var l = life;
if (!l._alive) {
l._alive = true;
l._timeout = setInterval("life.nextGen()", 100);
} else {
l._alive = false;
clearInterval(l._timeout);
}
}
var clear = function() {
var l = life;
var g = graphics;
for (var x = 0; x < l.xCells; x++) {
for (var y = 0; y < l.yCells; y++) {
l.prev[x][y] = false;
}
}
g.paint();
}
var _neighbourCount = function(x, y) {
var l = life;
var count = 0;
var neighbours = [
l.prev[x][(y - 1 + l.yCells) % l.yCells],
l.prev[(x + 1 + l.xCells) % l.xCells][(y - 1 + l.yCells) % l.yCells],
l.prev[(x + 1 + l.xCells) % l.xCells][y],
l.prev[(x + 1 + l.xCells) % l.xCells][(y + 1 + l.yCells) % l.yCells],
l.prev[x][(y + 1 + l.yCells) % l.yCells],
l.prev[(x - 1 + l.xCells) % l.xCells][(y + 1 + l.yCells) % l.yCells],
l.prev[(x - 1 + l.xCells) % l.xCells][y],
l.prev[(x - 1 + l.xCells) % l.xCells][(y - 1 + l.yCells) % l.yCells],
];
for (var i = 0; i < neighbours.length; i++) {
if (neighbours[i]) {
count++;
}
}
return count;
}
return {
yCells: yCells,
xCells: xCells,
prev: prev,
next: next,
initUniverse: initUniverse,
nextGen: nextGen,
toggleLife: toggleLife,
clear: clear,
}
}();

187
README.md Executable file
View File

@@ -0,0 +1,187 @@
# El juego de la vida. Una reescritura en vainilla javascript.
# Tabla de contenidos
- [El juego de la vida. Una reescritura en vainilla javascript.](#el-juego-de-la-vida-una-reescritura-en-vainilla-javascript)
- [Tabla de contenidos](#tabla-de-contenidos)
- [Introducción](#introducción)
- [Justificación del trabajo](#justificación-del-trabajo)
- [Contexto y estado del arte](#contexto-y-estado-del-arte)
- [Pulgarin.co](#pulgarinco)
- [pmav.eu](#pmaveu)
- [javascript.plainenglish.io](#javascriptplainenglishio)
- [Desarrollo](#desarrollo)
- [Análisis de la situación](#análisis-de-la-situación)
- [Inicialización de un proyecto con npm init](#inicialización-de-un-proyecto-con-npm-init)
- [Uso de clases en JavaScript](#uso-de-clases-en-javascript)
- [Implementación de un sistema de inicialización](#implementación-de-un-sistema-de-inicialización)
- [Implementación de un sistema de dibujado](#implementación-de-un-sistema-de-dibujado)
- [Implantación de un sistema de funciones publicas](#implantación-de-un-sistema-de-funciones-publicas)
- [Uso de comentarios para jsdoc](#uso-de-comentarios-para-jsdoc)
- [Compilando en JSDoc](#compilando-en-jsdoc)
- [Service workers y PWA](#service-workers-y-pwa)
- [usos de pwa y app cache para trabajo offline](#usos-de-pwa-y-app-cache-para-trabajo-offline)
- [Web responsiva](#web-responsiva)
- [hosting http y https](#hosting-http-y-https)
- [Readme.md y otros archivos de documentación](#readmemd-y-otros-archivos-de-documentación)
- [Conclusiones y trabajos futuros](#conclusiones-y-trabajos-futuros)
- [Bibliografía/webgrafía](#bibliografíawebgrafía)
# Introducción
Hace mucho tiempo, antes de intentar tomarme en serio la programación, publique [un post en mi blog sobre el juego de la vida](https://interlan.ec/2020/05/23/el-juego-de-la-vida-en-javascript/). Habiendo mejorado mucho mis capacidades para leer código y hacer muchas cosas mas, decidí retomar mi blog para llenarlo con nuevos contenidos que ayuden a otras personas a las que les interesen las mismas cosas que a mi.
Mientras exploraba mis escasos aportes a la red, me topé con el post original que hice sobre el juego de la vida. Estaba completamente en ruinas en cuanto a estar lleno de links rotos, imágenes faltantes y contenidos desactualizados.
Desempolvando un poco, elimine los links rotos puesto que no llevaban a ningún lado. Las imágenes las tuve que eliminar porque los hostings que las contenían habían muerto o las habían removido y ni siquiera recuerdo de que iban (aprendí la lección, debo controlar que las imágenes que copio se alojen en mi propio servidor para evitar estas cosas, pero tampoco olvidare citar las fuentes originales).
Es bastante increíble que la primera vez que revise este algoritmo no haya validado si funcionaba o no, que tecnologías usaba o siquiera si el sitio continuaba vivo. Para ser un post del 2020, todos los links eran del año 2011 por lo que no es raro encontrar problemas como cosas desaparecidas.
> Titulo: El sitio de Pulgarín esta muerto desde quien sabe cuando
![El sitio de Pulgarín esta muerto desde quien sabe cuando](images/sitio_pulgarin.png)
>
> **Fuente:** Elaboración propia
## Justificación del trabajo
Realmente este trabajo es mas para pulir mis habilidades leyendo código ajeno, entendiendo como funciona y reescribiéndolo en una forma mejorada y funcional, pero también es un pequeño aporte en español para internet, puesto que es justo allí donde aprendí a programar.
Quien desee explorar mi código, puede hacerlo libremente. También publicaré en enlace de GitHub donde pueden descargar el proyecto completo y si lo desean, pueden citarme cuando realicen sus practicas.
Conforme he avanzado en el estudio de este código, también he aprovechado para aprender nuevas cosas. Por ejemplo, en este articulo también se explicará el uso de JSDoc, comentarios para JSDoc, aplicaciones web progresivas, deducción de herramientas de trabajo mediante la lectura de código incompleto y mas. Espero que este trabajo sea de ayuda para aquellos que estén comenzando en el mundo de la programación.
## Contexto y estado del arte
> El Juego de la vida es un autómata celular diseñado por el matemático británico John Horton Conway en 1970.
> Hizo su primera aparición pública en el número de octubre de 1970 de la revista Scientific American, en la columna de juegos matemáticos de Martin Gardner. Desde un punto de vista teórico, es interesante porque es equivalente a una máquina universal de Turing, es decir, todo lo que se puede computar algorítmicamente se puede computar en el juego de la vida.
>
> Desde su publicación, ha atraído mucho interés debido a la gran variabilidad de la evolución de los patrones. Se considera que el Juego de la vida es un buen ejemplo de emergencia y autoorganización. Es interesante para científicos, matemáticos, economistas y otros observar cómo patrones complejos pueden provenir de la implementación de reglas muy sencillas. [(Wikipedia,2021)](https://es.wikipedia.org/wiki/Juego_de_la_vida)
Las reglas del juego de la vida son sencillas:
- Una célula viva con menos de dos vecinos vivos se muere (de soledad)
- Una con dos o tres vecinos vivos sobrevive
- Una con más de tres vecinos vivos se muere (por sobrepoblación)
- Una célula muerta con exactamente tres vecinos vivos, nace (por reproducción)
Estas simplicidades de las reglas hacen que básicamente sea el juego mas fácil de programar que se me ocurre.
A pesar de que es algo que se conoce desde mas de medio siglo, me propuse buscar la implementación mas simple posible para poder aprender y entender como funciona este juego a nivel de programación. para esto, he localizado las siguientes implementaciones:
### Pulgarin.co
La implementación mas sencilla que he encontrado. Pero debido a que es algo ya muy viejo, se ha perdido el código html y las dependencias jquery de las que depende.
### pmav.eu
[javascript game of life](https://pmav.eu/stuff/javascript-game-of-life-v3.1.1/)
Es tal vez una de las implementaciones mas extensas que he encontrado, pero muy compleja para entender como principiante. También es una implementación muy antigua, de alrededor del año 2008 o 2010. Al menos la pagina sigue viva.
### javascript.plainenglish.io
[the game of life using javascript](https://javascript.plainenglish.io/the-game-of-life-using-javascript-fc1aaec8274f?gi=ca6f1846eddf)
Tal vez la mejor documentada de todas las implementaciones que he visto. Una lastima no haberla visto antes de comenzar este proyecto, pero al menos aprendí a hacerlo por mi cuenta.
# Desarrollo
Es raro que un código de 329 líneas de código requiera tanta atención, pero he de abarcar todas estas cosas en artículos distintos que enlazo a continuación.
## Análisis de la situación
[Análisis de situación](analisis_situacion.md)
Como deducir la tecnología utilizada en el código original
## Inicialización de un proyecto con npm init
uso del comando npm init y configuración de las opciones del proyecto
## Uso de clases en JavaScript
razones para utilizar clases en javascript, como se crean, inicializan y razón para usarlas al reescribir este código
## Implementación de un sistema de inicialización
forma en la que se inicializan las clases, variables dentro de las clases y funciones que llaman métodos en clases
## Implementación de un sistema de dibujado
Estudio de la clase gráficos, como funciona en lienzo canvas y la variable de contexto (ctx)
funciones de dibujado y como se reciclan
## Implantación de un sistema de funciones publicas
Funciones publicas que realizan tareas adicionales
## Uso de comentarios para jsdoc
Comentarios en jsdoc, como pueden ayudar a la documentación de un código y como se ven en Visual Studio Code.
## Compilando en JSDoc
Modificación del código de package.json para agregar comandos de jsdoc
opciones de configuración, y parámetros adicionales
## Service workers y PWA
### usos de pwa y app cache para trabajo offline
https://www.pwabuilder.com
## Web responsiva
## hosting http y https
Etiquetas que permiten a la pagina web adaptarse a los tamaños de pantalla
## Readme.md y otros archivos de documentación
# Conclusiones y trabajos futuros
Estoy bastante sorprendido de todo lo que se puede hacer con algo tan simple que se puede resumir en cuatro reglas. pero parece que queda mucho mas.
al juego le hacen falta muchas cosas, pero las que he visto hasta el momento son las siguientes:
- **Debería poder modificar el tamaño del lienzo**
Al leer el código se pueden encontrar algunos comentarios que he dejado, que demuestran que al menos lo he intentado.
Me gustaría que el código permita crear un lienzo del ancho de la pantalla, pero eso tal vez haga el código muy extenso para mi propósito original.
He intentado utilizando algo de CSS, pero el resultado es que, si bien el lienzo se adapta al ancho de la pantalla, se pierde precisión del click, haciendo que solo un cuarto de la pantalla sea preciso y el resto no detecte el click en las partes que corresponde.
- **Debería permitir arrastrar y soltar para dibujar en el lienzo**
Curiosamente es una función que se encuentra en el código original. El problema es que no logre implementarla sin que se rompa todo. Tengo que estudiar mas para saber como hacerlo.
- **Hay bugs extraños, muy extraños**
Aunque he creado una función para iniciar y otra para parar la ejecución del temporizador para procesar las nuevas generaciones, en algunos casos y por alguna razón, es imposible detener el temporizador después de funcionar correctamente antes. Es un problema extraño que pensé que se solucionaría si controlaba las veces que se puede usar la función iniciar. Tal vez deba agregar un changelog y un control de versiones, quien sabe.
- **Funciones adicionales**
Una vez terminado el proyecto me di cuenta de que seria genial que haya mas funciones, pero tal vez dejaría de ser didáctico si hago eso. Aun así destaco lo siguiente:
1. Seria genial si se pudiera generar un arreglo aleatorio para iniciar
2. Me gustaría agregar una lista de arreglos prediseñados para poder ver como funcionan los diferentes patrones ya descubiertos.
3. Me gustaría que se puedan configurar los colores
4. ¡Agregar publicidad! Bueno, es algo que siempre quise aprender a hacer y muchos de los códigos que he encontrado la agregan.
5. ¿Comentarios y sugerencias? Tal vez es muy optimista agregar un elemento así en una aplicación super simple, mas aun sabiendo que no creo que reciba algún comentario en mi propio blog.
# Bibliografía/webgrafía
[Code katas, la practica hace al maestro(2011).Obtenido de www.codeandbeyond.org](https://www.codeandbeyond.org/2011/01/code-katas-la-practica-hace-al-maestro.html)
[El juego de la vida(2011), obtenido de www.pulgarin.co](https://julianpulgarin.com/canvaslife/) (enlace roto)
[El juego de la vida(2021), obtenido de es.wikipedia.org](https://es.wikipedia.org/wiki/Juego_de_la_vida)
[El juego de la vida (2008-2010), obtenido de pmav](https://pmav.eu/stuff/javascript-game-of-life-v3.1.1/)
[the game of life using javascript (2020), javascript.plainenglish.io](https://javascript.plainenglish.io/the-game-of-life-using-javascript-fc1aaec8274f?gi=ca6f1846eddf)

90
analisis_situacion.md Executable file
View File

@@ -0,0 +1,90 @@
# Analisis de la situacion
## Tabla de contenidos
- [Analisis de la situacion](#analisis-de-la-situacion)
- [Tabla de contenidos](#tabla-de-contenidos)
- [Introduccion](#introduccion)
- [Codigo Heredado/Legado](#codigo-heredadolegado)
- [Estructura básica de una pagina web.](#estructura-básica-de-una-pagina-web)
- [El archivo Index.html](#el-archivo-indexhtml)
- [Bibliografia](#bibliografia)
## Introduccion
Cuando quise este estudiar este codigo, pense que solo seria cuestion de copiar y pegar para verlo funcionando, pero me encontré que he compartido irresponsablemente algo que no le seriviria a nadie. Muy especialmente es notable que falten grandes trozos de codigo y que no haya comentarios significativos. Por eso y como practica para mi, he decidido explorarlo y reescribirlo en vainilla javascript, agregando comentarios detallados que permitan a los interesados en estudiar el codigo aprender mas facilmente como funciona.
Mientras realizaba este analisis, tambien fui descubriendo que podia agregar nuevas cosas interesantes, que describire mas adelante, pero por el momento, el primer desafio era, el codigo en el que me basé para hacer el mio.
## Codigo Heredado/Legado
Segun la wikipedia:
> Legacy code o código heredado es código fuente relacionado con un sistema operativo o una tecnología de computación sin soporte técnico. El término también puede aplicarse a código insertado en software más moderno para integrar u ofrecer soporte a una función creada en el pasado; por ejemplo dar soporte a una interfaz en serie incluso aunque muchos sistemas modernos no tienen un puerto serial. (wikipedia,2021)
Luego de investigar con mas empeño este codigo y su autor, he encontrado un repositorio de GitHub. Si bien este codigo puede encontrarse en [aqui](https://github.com/jpulgarin/canvaslife), solo está el codigo javascript, sin el archivo index.html necesario para poder ejecutar la practica. en el mismo repositorio es posible encontrar un enlace a un servidor actualmente inactivo.
> Titulo: El sitio de Pulgarín esta muerto desde quien sabe cuando
![El sitio de Pulgarín esta muerto desde quien sabe cuando](images/sitio_pulgarin.png)
>
> **Fuente:** Elaboración propia
Por esta razon, comenzaremos analizando las partes necesarias para la creacion de una pagina web con javascript.
### Estructura básica de una pagina web.
Una pagina web no es mas que un documento escrito con HTML.
HTML es un lenguaje de etiquetas con las que se define la estructura del documento. Se caracteriza por ser facil de interpretar, tanto por maquinas como por humanos y es el estandar para las paginas web hasta el momento. A pesar de que es un estandar, sufre cambios a lo largo del tiempo para poder agregar y quitar caracteristicas que le permitan funcionar mejor en diferentes dispositivos, por lo que un codigo muy antiguo podria no funcionar en navegadores muy modernos.
La version mas actual de HTML es la 5 y la que uso actualmente. Publicada en el año 2014, estandarizo muchas etiquetas nuevas que hasta ese momento podrian estar limitadas solo a ciertos navegadores que las interpretaran correctamente. En este caso, la etiqueta canvas existe desde el año 2004 de la mano de Apple en su navegador Safari, y entre el año 2005 y 2006 fue adoptado por los motores de gecko y opera, obviamente dejando a internet explorer al margen de su uso [wikipedia,2021](https://en.wikipedia.org/wiki/Canvas_element)
La estructura básica de un documento HTML es la siguiente:
<html>
<head>
</head>
<body>
</body>
<foot>
</foot>
</html>
Las etiquetas se caracterizan por estar cerradas entre [parentesis angulares](https://es.wikipedia.org/wiki/Signo_mayor_que#Par%C3%A9ntesis_angulares) "<>" donde la primera palabra dentro de ellas es el nombre de la etiqueta que los identifica. las palabras que se agreguen a la etiqueta seran considerados atributos, por ejemplo \<html lang='es'> donde el par "lang='es'" permite al navegador determinar el idioma del documento.
Las etiquetas html tienen una jerarquia, donde cada elemento puede contener otros elementos. para eso, cada etiqueta que abre, debe cerrar con otra con el mismo nombre, pero usando una barra diagonal antes de el. por ejemplo \</html>
Hay mas cosas para abarcar sobre html, especialmente sobre la [web semantica](https://es.wikipedia.org/wiki/Web_sem%C3%A1ntica), la cual es una buena practica para todo tipo de paginas web si quieren ser lo mas accesibles posible, pero por ahora nos vamos a concentrar en la reconstruccion del codigo que nos interesa.
### El archivo Index.html
El punto de inicio de todo sitio web es el archivo index.html, aunque esto puede cambiar de acuerdo al servidor. En realidad el archivo puede tener cualquier nombre siempre y cuando se comience a navegar por el, pues es quien contiene los enlaces iniciales para la primera navegacion.
Dado que carecemos de un archivo html del cual partir, construiremos uno propio, sin grandes pretenciones para ver nuestro codigo funcionar.
<html>
<head>
</head>
<body>
</body>
</html>
Hay que recordar que los documentos html se cargan en la memoria haciendo un barrido desde el principio hasta el final del mismo, por lo que cada etiqueta solo tendra disponible en la memoria del dispositivo, solo lo que haya sido cargado hasta el momento en el que ella sea cargada. por lo que, por ejemplo, si hay elementos con estilos css en la etiqueta body y los archivos CSS no han sido cargados todavia, apareceran sin formato alguno. De la misma forma, el codigo javascript no podra acceder a etiquetas que no existan hasta el momento en el que ellas sean cargadas.
Por esta razon, cualquier script que se desee ejecutar, deberia ser cargado hasta el final del documento;
<html>
...
<script src="...">
</html>
O en su defecto, utilizar un metodo onLoad en javascript que permita esperar a que se cargue todo el documento antes de intentar acceder al mismo.
## Bibliografia
[Código Heredado(2021), Obtenido de la wikipedia](https://es.wikipedia.org/wiki/C%C3%B3digo_heredado)
[Canvas Element(2021), Obtenido de la wikipedia](https://en.wikipedia.org/wiki/Canvas_element)

0
bugs_conocidos.md Executable file
View File

BIN
favicon.ico Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
images/android-chrome-192x192.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
images/android-chrome-512x512.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

BIN
images/apple-touch-icon.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
images/favicon-16x16.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 B

BIN
images/favicon-32x32.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 259 B

BIN
images/favicon.ico Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
images/screenshot1.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

1
images/site.webmanifest Executable file
View File

@@ -0,0 +1 @@
{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}

BIN
images/sitio_pulgarin.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

48
index.html Executable file
View File

@@ -0,0 +1,48 @@
<html lang="es">
<head>
<link rel="icon" href="favicon.ico" type="image/x-icon">
<meta charset="UTF-8">
<title>El juego de la vida</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<link rel="manifest" href="manifest.json">
</head>
<header>
</header>
<body>
<noscript>Necesitas activar Javascript para ejecutar este codigo</noscript>
<h3>El juego de la vida</h3>
<p>Esta es una reescritura y documentacion extensiva de un algoritmo que encontre hace muchos años en internet, aun
antes de saber programar. Se puede leer la documentación que he creado para este proyecto tanto en la <a
href="Documentacion/">pagina generada por jsdocs</a> como en mi <a
href="https://interlan.ec/2021/09/08/el-juego-de-la-vida-una-reescritura-en-vainilla-javascript/">blog en
interlan.ec</a></p>
<p>El objetivo de este codigo es aprender sobre componentes que nunca habia manejado, como canvas, pero tambien
aprender a documentar el codigo extensivamente usando jsdocs y crear una aplicacion progresiva sin depender de
<a href="https://create-react-app.dev">create_react_app</a></p>
<h3>Leer documentacion:</h3>
<ul>
<li><a href="https://juegodelavida.interlan.ec/Documentacion">Documentacion generada con JSDoc</a></li>
<li><a href="http://interlan.ec/2021/09/08/el-juego-de-la-vida-una-reescritura-en-vainilla-javascript/">Documentacion
en entrada del blog</a></li>
</ul>
<button onclick="iniciar()">iniciar</button>
<button onclick="parar()">parar</button>
<button onclick="limpiar()">limpiar</button>
<button onclick="siguiente_generacion()">avanzar un paso</button>
<hr>
<canvas id="lienzo" width="200px" height="200px" style="/* width: 100%; */">
</canvas>
</body>
<footer>
</footer>
<!-- <script src="/service-worker.js""></script> -->
<script src="/index.js""></script>
</html>

359
index.js Executable file
View File

@@ -0,0 +1,359 @@
/**
* Hace mucho tiempo, antes de intentar tomarme en serio la programacion, publique [un post en mi blog sobre el juego de la vida](https://interlan.ec/2020/05/23/el-juego-de-la-vida-en-javascript/). Habiendo mejorado mucho mis capacidades para leer codigo y hacer muchas cosas mas, decidi retomar mi blog para llenarlo con nuevos contenidos que ayuden a otras personas a las que les interesen las mismas cosas que a mi.
*
* @projectname El juego de la vida. Una reescritura en vainilla javascript
* @version 1.0
* @author drk0027
* @copyright 2021
*
*/
/**
* # Punto
*
* Esta clase almacena temporalmente las coordenadas X,Y como un objeto
*/
class Punto {
constructor(x, y) {
this.x = x
this.y = y
}
}
/**
* # Graficos
*
* Esta clase permite el control y la creacion del lienzo y las funciones que alteran el estado del lienzo
*/
class graficos {
constructor() {
//contexto
this.ctx = lienzo.getContext("2d")
//colores
this.color_encendido = 'rgb(0, 0, 0)'
this.color_apagado = 'rgb(255, 255, 255)'
this.color_rejilla = 'rgb(50, 50, 50)'
//tamaños
this.tamaño_celula = 10
//celdas
this.yCelula
this.xCelula
this.prev = []
this.sig = []
//temporizador
this.intervalo
}
/**
* # Dibujar Celula
*
* Permite dibujar una celula en un estado encendido o apagado en un lugar determinado del lienzo
* @param {int} x
* @param {int} y
* @param {bool} estado
*/
dibujarCelula(x, y, estado) {
if (estado == 1) {
this.ctx.fillStyle = this.color_encendido
} else {
this.ctx.fillStyle = this.color_apagado
}
this.ctx.fillRect(x * this.tamaño_celula + 1, y * this.tamaño_celula + 1, this.tamaño_celula - 1, this.tamaño_celula - 1)
}
/**
* # Pintar
*
* Esta funcion cambia el estado de todas las celulas de acuerdo al que esta almacenado en la matriz original
*/
pintar() {
for (var x = 0; x < this.xCelula; x++) {
for (var y = 0; y < this.yCelula; y++) {
this.dibujarCelula(x, y, this.prev[x][y]);
}
}
}
}
//inicializar clase graficos
const gx = new graficos()
//variables globales
var celula = ""
var estado = ""
/**
* # Procesar Celula
*
* Esta funcion permite calcular la posicion de la celula y determinar su estado
* @param {Object} celula Objeto de puntos en X,Y definido en la clase Puntos
*/
function procesarCelula(celula) {
var x = celula.x
var y = celula.y
var estado = 1
if (x > gx.xCelula - 1 || y > gx.yCelula - 1) {
return;
}
if (typeof estado == 'undefined') {
estado = !gx.prev[x][y];
}
gx.prev[x][y] = estado;
gx.dibujarCelula(x, y, estado);
}
/**
* # Celda seleccionada (getPuntoBajoMouse)
*
* Esta funcion permite al programa determinar en sobre que celda se encuentra posicionado el mouse a partir de las coordenadas devueltas por el evento mousedown.
*
* Para calcular este valor, se realizan las siguientes operaciones
*
* X=
*
* Donde:
*
* e.pageX: posicion del cursor en x
* e.pageY: posicion del cursor en y
*
* gx.ctx.canvas.offsetLeft: pixeles desde el lienzo hasta el borde de la pantalla a la izquierda
* gx.ctx.canvas.offsetright: pixeles desde el lienzo hasta el borde de la pantalla arriba
* gx.tamaño_celula: tamaño de la celula en pixeles
*
* @param {Object} e eventos devueltos por el listener de mousedown
*/
function getPuntoBajoMouse(e) {
//esta funcion permite optener un nuevo punto por medio de restar pageX (eje x devuelto por el evento del mouse) menos el offset izquierdo del lienzo, dividirlo para el tamaño de la celula (definido en la clase grafico) o establecer el punto como cero para el punto x de la clase Punto
/*
esta funcion devuelve un nuevo arreglo de puntos x,y para la clase Punto
Punto X: resta pageX (eje x devuelto por el evento del mouse) menos el offset izquierdo del lienzo, dividirlo para el tamaño de la celula (definido en la clase grafico) o establecer el punto como cero para el punto x de la clase Punto.
Punto Y: resta pagey (eje x devuelto por el evento del mouse) menos el offset superior del lienzo, dividirlo para el tamaño de la celula (definido en la clase grafico) o establecer el punto como cero para el punto y de la clase Punto.
*/
return new Punto((e.pageX - gx.ctx.canvas.offsetLeft) / gx.tamaño_celula | 0, ((e.pageY - gx.ctx.canvas.offsetTop) / gx.tamaño_celula) | 0);
}
/**
* # Init
*
* Esta funcion permite inicializar todas las variables necesarias para el funcionamiento de este programa
*/
function init() {
gx.xCelula = ((gx.ctx.canvas.width - 1) / gx.tamaño_celula) | 0
gx.yCelula = ((gx.ctx.canvas.height - 1) / gx.tamaño_celula) | 0
//inicializa el panel en color encendido
gx.ctx.fillStyle = gx.color_apagado
//Pintar el fondo
gx.ctx.fillRect(0, 0, gx.xCelula * gx.tamaño_celula, gx.yCelula * gx.tamaño_celula)
//Definir color de la rejilla
gx.ctx.fillStyle = gx.color_rejilla
//Dibujar lineas verticales
for (var x = 0; x < gx.xCelula; x++) {
//se inicializa la matriz
gx.prev[x] = []
gx.sig[x] = []
//se dibuja cada celula
gx.ctx.fillRect(x * gx.tamaño_celula, 0, 1, gx.yCelula * gx.tamaño_celula)
for (var y = 0; y < gx.yCelula; y++) {
gx.prev[x][y] = false;
}
}
gx.ctx.fillRect(gx.xCelula * gx.tamaño_celula, 0, 1, gx.yCelula * gx.tamaño_celula)
//Dibujar lineas horizontales
for (var y = 0; y < gx.yCelula; y++) {
gx.ctx.fillRect(0, y * gx.tamaño_celula, gx.xCelula * gx.tamaño_celula, 1)
}
gx.ctx.fillRect(0, gx.yCelula * gx.tamaño_celula, gx.xCelula * gx.tamaño_celula, 1)
}
/**
* # Contar Vecinos
*
* Esta funcion permite contar los vecinos de una celula, sea que esta viva como si esta muerta y devuelve la cantidad de vecinos vivos que esta tenga.
*
* Esquema:
*
* **Esquema:**
*
* 3 4 5
* | | |
* v v v
* __ ___ ___
* | | | | <-3
* +---|---|---|
* | 1 | 1 | 1 | <-4
* +---|---|---|
* | | | | <-5
* +---|---|---|
*
* **calcular el vecino de 4,4**
*
* xCelula la cantidad de filas de celulas
* yCelula es la cantidad de columnas de celulas
*
* |variable|estado|
* |--------|------|
* |prev[4][3]|verdadero|
* |prev[5][3]|falso|
* |prev[5][4]|falso|
* |prev[5][5]|falso|
* |prev[4][5]|verdadero|
* |prev[3][5]|falso|
* |prev[3][4]|falso|
* |prev[3][3]|falso|
*
* @param {int} x filas
* @param {int} y columnas
*/
function _contarvecinos(x, y) {
var cantidad = 0
var vecinos = [
gx.prev[x][(y - 1 + gx.yCelula) % gx.yCelula],
gx.prev[(x + 1 + gx.xCelula) % gx.xCelula][(y - 1 + gx.yCelula) % gx.yCelula],
gx.prev[(x + 1 + gx.xCelula) % gx.xCelula][y],
gx.prev[(x + 1 + gx.xCelula) % gx.xCelula][(y + 1 + gx.yCelula) % gx.yCelula],
gx.prev[x][(y + 1 + gx.yCelula) % gx.yCelula],
gx.prev[(x - 1 + gx.xCelula) % gx.xCelula][(y + 1 + gx.yCelula) % gx.yCelula],
gx.prev[(x - 1 + gx.xCelula) % gx.xCelula][y],
gx.prev[(x - 1 + gx.xCelula) % gx.xCelula][(y - 1 + gx.yCelula) % gx.yCelula],
]
for (var i = 0; i < vecinos.length; i++) {
if (vecinos[i]) {//si hay valor o no
cantidad++;
}
}
return cantidad
}
/**
* # Siguiente Generacion
*
* Esta funcion se encarga de calcular la siguiente generacion de la partida, para esto, crea un nuevo arreglo con la matriz aun vigente, luego hace un barrido por cada una de las celdas buscando cuantas celulas tienen vecinos y evalua su situacion actual segun las reglas del juego de la vida. Una vez hecho esto, se copia la nueva matriz sobre la anterior, sobreescribiendola y mostrandola en pantalla.
*
* ## Reglas del juego de la vida
*
* - Cualquier celula viva con dos o tres compañeros vivos, sobrevive
* - Cualquier celula muerta con tres compañeros vivos, revive
* - Todas las demas celulas mueren en la siguiente generacion. De la misma forma, las celulas muertas, permanecen muertas
*
* (Conway's game of Life, Wikipedia)
*
*/
function siguiente_generacion() {
//Copiar el arreglo de la pantalla anterior en uno nuevo, que sera modificado mas adelante
for (var x = 0; x < gx.xCelula; x++) {//numero de filas
for (var y = 0; y < gx.yCelula; y++) {//numero de columnas
gx.sig[x][y] = gx.prev[x][y];
}
}
for (var x = 0; x < gx.xCelula; x++) {//numero de filas
for (var y = 0; y < gx.yCelula; y++) {//numero de columnas
var cantidad = _contarvecinos(x, y);
// Reglas del juego de la vida
if (gx.prev[x][y]) { //si la celula esta encendida
if (cantidad < 2 || cantidad > 3) {//si la celula tiene menos de dos vecinos vivos o mas de tres muere
gx.sig[x][y] = false;
}
} else if (cantidad == 3) { //sino, esta viva
gx.sig[x][y] = true;
}
}
}
//copiar arreglo modificado en el anterior
for (var x = 0; x < gx.xCelula; x++) {
for (var y = 0; y < gx.yCelula; y++) {
gx.prev[x][y] = gx.sig[x][y];
}
}
gx.pintar()
}
/**
* # Limpiar
*
* Cambia el estado de cada celula a apagado
*/
function limpiar() {
for (var x = 0; x < gx.xCelula; x++) {
for (var y = 0; y < gx.yCelula; y++) {
gx.prev[x][y] = false
}
}
gx.pintar()
}
/**
* #Init
*
* Inicializa la plataforma
*/
init()
//eventos
/**
* # Listener: mousedown
*
* Agrega un gestor de eventos que detecte cuando se hace click en una celda correspondiente a una celula
*/
lienzo.addEventListener("mousedown", e => {
celula = getPuntoBajoMouse(e)
procesarCelula(celula)
})
/**
* # Iniciar
*
* Inicia el temporizador que avanza cada generacion
*/
function iniciar(){
gx.intervalo=setInterval(siguiente_generacion,500)
}
/**
* # Parar
*
* Limpia el temporizador que ejecuta la funcion de siguiente_generacion
*/
function parar(){
clearInterval(gx.intervalo)
}
//Service-Worker
window.addEventListener('beforeinstallprompt', (event) => {
console.log('👍', 'beforeinstallprompt', event);
// Stash the event so it can be triggered later.
window.deferredPrompt = event;
// Remove the 'hidden' class from the install button container
//divInstall.classList.toggle('hidden', false);
});
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('service-worker.js');
}
if (window.location.protocol === 'http:') {
console.log("cuidado, no pùedes instalar apps desde un sitio inseguro")
//determina si estoy en una pagina insegura
/* const requireHTTPS = document.getElementById('requireHTTPS');
const link = requireHTTPS.querySelector('a');
link.href = window.location.href.replace('http://', 'https://');
requireHTTPS.classList.remove('hidden'); */
}
window.addEventListener('appinstalled', (event) => {
console.log('👍', 'appinstalled', event);
// Clear the deferredPrompt so it can be garbage collected
window.deferredPrompt = null;
});

3
jsdoc.conf Executable file
View File

@@ -0,0 +1,3 @@
{
"plugins": ["plugins/markdown"]
}

38
manifest.json Executable file
View File

@@ -0,0 +1,38 @@
{
"short_name": "Juego_de_la_vida",
"name": "El juego de la vida. Una reescritura en vainilla javascript.",
"icons": [
{
"src": "/images/android-chrome-192x192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "/images/android-chrome-512x512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": "/?source=pwa",
"background_color": "#3367D6",
"display": "standalone",
"scope": "/",
"theme_color": "#3367D6",
"shortcuts": [
{
"name": "El juego de la vida. Una reescritura en vainilla javascript.",
"short_name": "Juego_de_la_vida",
"description": "Reescritura didactica del juego de la vida con javascript vainilla y canvas en html5",
"url": "/today?source=pwa",
"icons": [{ "src": "/images/android-chrome-192x192.png", "sizes": "192x192" }]
}
],
"description": "Reescritura didactica del juego de la vida con javascript vainilla y canvas en html5",
"screenshots": [
{
"src": "/images/screenshot1.png",
"type": "image/png",
"sizes": "380x320"
}
]
}

12
package.json Executable file
View File

@@ -0,0 +1,12 @@
{
"name": "juegodelavida",
"version": "1.0.0",
"description": "Practica para crear el juego de la vida en html con javascript",
"main": "index.html",
"scripts": {
"test": "serve",
"generatedocs": "jsdoc -c jsdoc.conf index.js README.md -d Documentacion"
},
"author": "drk0027",
"license": "ISC"
}

40
service-worker.js Executable file
View File

@@ -0,0 +1,40 @@
/* const CACHE_NAME = 'offline';
const OFFLINE_URL = 'index.html'; */
const nombre_cache = "JdlV"
const archivos_en_cache = [
'index.html',
'index.js',
'favicon.ico',
'manifest.json'
]
/**
* # Listener para el evento de instalacion
*
*
*/
self.addEventListener('install', (e) => {
console.log('[Service Worker] Install');
e.waitUntil((async () => {
const cache = await caches.open(nombre_cache);//revisa que archivos estan en el cache
console.log('[Service Worker] Caching all: app shell and content');
await cache.addAll(archivos_en_cache);//agrega los archivos en linea al cache
})());
});
self.addEventListener('fetch', (e) => {
e.respondWith((async () => {
const r = await caches.match(e.request);
console.log(`[Service Worker] Fetching resource: ${e.request.url}`);
if (r) { return r; }
const response = await fetch(e.request);
const cache = await caches.open(nombre_cache);
console.log(`[Service Worker] Caching new resource: ${e.request.url}`);
cache.put(e.request, response.clone());
return response;
})());
});
/* https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps/Offline_Service_workers */