410 lines
13 KiB
HTML
Executable File
410 lines
13 KiB
HTML
Executable File
<!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 < 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;
|
|
});</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>
|