sábado, 24 de março de 2018

Tratamento de Choque para jogo em javaScript



Tratamento de Choque para jogo em javaScript
São duas imagens onde as dimensões de cada quadrado possuem w e h de 17 pixeis.


O fonte e as duas imagens:


<html>
<body onload="startGame()">
<script>

//=================================================================================================
// Autor: Luiz Augusto S. Prado - 2018
// javaScript: Game 
//=================================================================================================
    window.requestAnimationFrame = function() 
    {
        return window.requestAnimationFrame ||
        window.webkitRequestAnimationFrame ||window.mozRequestAnimationFrame ||
        window.msRequestAnimationFrame ||window.oRequestAnimationFrame ||
        function(f) 
        {
            window.setTimeout(f,1e3/60);
        }
    }();
    
    getNumber = function(str)
    {
        var r = Number( str.charCodeAt(0) )
        if(r>47 && r<58) r-=48
        if(r>64 && r<91) r-=55
        if(r>96 && r<123)r-=87
        return r;
    }

    paintImagem = function(ctx, ctx2, pos_x_0, pos_y_0, tamanhox, tamanhoy, pos_x_f, pos_y_f, escala, ang)
    {
        ctx.translate( pos_x_f, pos_y_f );
        ctx.rotate(-ang * Math.PI / 180);
        ctx.drawImage(ctx2, pos_x_0, pos_y_0, tamanhox, tamanhoy, escala, escala, escala, escala);
        ctx.rotate(ang * Math.PI / 180);
        ctx.translate( -pos_x_f, -pos_y_f);
    }
    
    Hero = function()
    {        
        this.onde_estou    = "no_mapa"
        this.speedX    = 0;
        this.speedY    = 0;
        this.color    = "red";
        this.width    = 16;
        this.height    = 16;
    }

    paintHero = function(mapa)
    {
        mapa.ctx.fillStyle = mapa.hero.color;
        mapa.ctx.fillRect(mapa.canvas.width/2, mapa.canvas.height/2, 16, 16)
    }

    Ground = function(x0, y0, xf, yf)
    {
        this.x = xf/2*17
        this.y = yf*17
        this.onde_estou    = "no_mapa"
        this.width    = 17;
        this.height    = 17;
        this.px        = x0*this.width;
        this.py        = y0*this.height;        
    }

    Item = function(x0, y0, xf, yf)
    {
        this.x = xf/2*17
        this.y = yf*17
        this.onde_estou    = "no_mapa"
        this.width    = 17;
        this.height    = 17;
        this.px        = x0*this.width;
        this.py        = y0*this.height;        
    }

    paintMap= function(mapa)
    {
        var ctx = mapa.ctx;
        var arq = mapa.arquivo_mapas;    
        var w=mapa.canvas.width/2
        var h=mapa.canvas.height/2;    
        for(var py=0; mapa.mapa!=null && py<mapa.mapa.length; py++ )
        {
            for(var px=0; px<mapa.mapa[py].length; px++ )
            {
                if( mapa.mapa[py][px]!=null )
                {
                    var m = mapa.mapa[py][px];    
                    var tm=m.width;    
                    paintImagem(ctx, arq, m.px, m.py, tm, tm, m.x-mapa.hero.x+w-4, m.y-mapa.hero.y+h-4, tm+2, 0)
                }
            }
           }
    }

    paintItens = function(mapa)
    {
        var ctx = mapa.ctx;
        var arq = mapa.arquivo_itens;
        var w=mapa.canvas.width/2
        var h=mapa.canvas.height/2;        
        for(var py=0; mapa.itens!=null && py<mapa.itens.length; py++ )
        {
            for(var px=0; px<mapa.itens[py].length; px++ )
            {
                if( mapa.itens[py][px]!=null )
                {
                    var m = mapa.itens[py][px];    
                    var tm=m.width;                
                     paintImagem(ctx, arq, m.px+mapa.time*tm, m.py+1, tm,  tm-1, m.x-mapa.hero.x+w-4, m.y-mapa.hero.y+h-4, tm+2, 0)
                }
            }
           }
    }
    
    function createItens()
    {
        var str = document.getElementById("itens").value
        str = str.replace(new RegExp(/ /, 'gi'), "");
        var res = str.split("|\n");
        var array_final = new Array();
        for(var py=0; py<res.length-1; py++)
        {
            array_final[py]=[]
            for(var px=0; px<res[py].length; px+=2)
            {
                if( res[py].charAt(px)!='3' && res[py].charAt(px+1)!='z' )
                {
                     array_final[py][px/2] = new Item(getNumber(  res[py].charAt(px)) ,  getNumber( res[py].charAt(px+1) ), px, py ); 
                }
            }
        }
        return array_final;
    }
    
    function createMapa()
    {
        var str = document.getElementById("mapa").value    
        str = str.replace(new RegExp(/ /, 'gi'), "");
        var res = str.split("|\n");
        var array_final = new Array();
        for(var py=0; py<res.length-1; py++)
        {
            array_final[py]=[]
            for(var px=0; px<res[py].length; px+=2)
            {
                if( res[py].charAt(px)!='3' && res[py].charAt(px+1)!='z' )
                {
                     array_final[py][px/2] = new Ground(getNumber(  res[py].charAt(px)) ,  getNumber( res[py].charAt(px+1) ) , px, py ); 
                }
            }
        }
        return array_final;
    }

    /*===========================================
    O mapa anda ao contrário. Ele é a referência. 
                                       
      e1 d1       e2 d2           
    n1_|_|_n1   n2_|_|_n2    a. .b y1
    s1_|_|_s1   s2_|_|_s2    c. .d y2  
       | |         | |       x1 x2
      e1 d1       e2 d2      

    */

    function isHitting(obj1, obj2, tm)
    {
        var e1 = obj1.x - obj1.speedX -tm
        var d1 = obj1.x - obj1.speedX 
        var n1 = obj1.y - obj1.speedY -tm
        var s1 = obj1.y - obj1.speedY

        var e2 = obj2.x         
        var d2 = obj2.x + tm
        var n2 = obj2.y         
        var s2 = obj2.y + tm
        
        var x1 = e1<=d2 && d2<=d1            
        var x2 = e1<=e2 && e2<=d1
        var y1 = n1<=s2 && s2<=s1                
        var y2 = n1<=n2 && n2<=s1

        var a = x1 && y1
        var b = x2 && y1
        var c = x1 && y2
        var d = x2 && y2

        if( a || c || b || d )
        {
            if( (x1 || x2) && obj1.speedY!=0 ) obj1.speedY =0
            if( (y1 || y2) && obj1.speedX!=0 ) obj1.speedX =0
            return true
        }
        return false
    }


    function Mapa()
    {
        this.start = function() 
        {
            this.arquivo_mapas = new Image()
            this.arquivo_mapas.src = "mapa.png"
            this.arquivo_itens = new Image()
            this.arquivo_itens.src = "itens.png"

            this.canvas = document.createElement("canvas")

            this.count = 0;
            this.time=0;

            this.ctx = this.canvas.getContext("2d");
            document.body.insertBefore(this.canvas, document.body.childNodes[0]);
            this.canvas.width = (window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth )-70;
            this.canvas.height= (window.innerHeight|| document.documentElement.clientHeight|| document.body.clientHeight)-70;

            window.addEventListener('keydown', function (e) 
            {
               window.keys = (window.keys || []);
               window.keys[e.keyCode] = (e.type == "keydown")  ;
            })

            window.addEventListener('keyup', function (e) 
            {
               window.keys[e.keyCode] = (e.type == "keydown") ;            
            })
            
            this.itens = createItens();
            this.mapa  = createMapa ();
            this.hero  = new Hero ();
            
            this.hero.x = 0;
            this.hero.y = 0;
        }

        this.clear = function()
        {
            this.canvas.width = (window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth )-70;
            this.canvas.height= (window.innerHeight|| document.documentElement.clientHeight|| document.body.clientHeight)-70;

            this.ctx.fillStyle="#99ccff";
            this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height); 
        }

        this.calcs = function()
        {
            this.hero.speedX = 0;
            this.hero.speedY = 0;
            this.hero.w = this.canvas.width/2;
            this.hero.h = this.canvas.height/2;
            
            this.count++
            
            if(this.count%10==0)
            {
                this.time++
                if(this.time==4){this.time=0; this.count=0}
            }
            
            if (window.keys && window.keys[37]) {this.hero.speedX = 2; }
            if (window.keys && window.keys[39]) {this.hero.speedX =-2; }
            if (window.keys && window.keys[38]) {this.hero.speedY = 2; }
            if (window.keys && window.keys[40]) {this.hero.speedY =-2; }
            
            var saida=false;

            for(var py=0; py<this.mapa.length; py++)
            {
                for(var px=0; px<this.mapa[py].length; px++)
                {
                    if(this.mapa[py][px]!=null)
                    {
                        saida = isHitting(this.hero, this.mapa[py][px], 17)
                    }
                    if( saida ) break
                }
                if( saida ) break
            }
            this.hero.x -= this.hero.speedX;
            this.hero.y -= this.hero.speedY;
        }

        this.paint = function()
        {
            paintMap  (this)
            paintItens(this)
            paintHero (this)
        }
    }

    var mapa;
    animloop = function()
    {
        mapa.calcs();
        mapa.clear();
        mapa.paint();
        requestAnimationFrame(animloop);
    }

    function startGame() 
    {
        mapa = new Mapa();
        mapa.start();
        animloop();
    }

</script>

<div id="msg">mova com o teclado.</div>

<textarea id="itens" rows="30" cols="60"  style="display:none;">
3z 3z 3z 3z 3z 3z 3z 3z|
00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 0g 0h 0i 0j 0k 0l 0m 0n 0o|
</textarea>

<textarea id="mapa"  rows="30" cols="60"  style="display:none;">
3z 3z 3z 3z 3z 3z 3z 3z|
3z 3z 3z 3z 3z 3z 3z 3z|
3z 3z 3z 3z 3z 3z 3z 3z|
3z 3z 3z 3z 3z 60 10 10|
00 10 10 10 10 61 11 11|
11 11 11 11 11 11 11 11|
11 11 11 11 11 11 11 11|
11 11 11 11 11 11 11 11|
11 11 11 11 11 11 11 11|
11 11 11 11 11 11 11 11|

</textarea>
</body>
</html>

segunda-feira, 12 de março de 2018

No máximo 4 cores em um mapa

Um probleminha matemático que li e estava pensando:
https://www1.folha.uol.com.br/colunas/marceloviana/2018/03/quatro-cores-bastam-para-colorir-qualquer-mapa.shtml

A quantidade mínima de cores para colorir qualquer mapa é 4?
A resposta é questionar qual é o máximo de países que fazem fronteira entre eles mesmos.

Em um universo plano, de bordas indo ao infinito ou uma plano conexo (Esfera) a resposta parece funcionar. Mas em um toroide, a quantidade de números pode ser maior que 4.

Confrontar todas as cores nos mostra que não é nem possível forçarmos que 5 estados se toquem entre si.


No mesmo esquema entra a tentativa de ligarmos agua, luz e telefone a 3 casas sem cruzar os tipos.
Para conseguirmos conectar os três as 3 casas, é necessário um toroide.



segunda-feira, 5 de março de 2018

Editando Livros com HTML

Percebi que no novo Windows muitos dos antigos softwares bons não estão mais vindo com ele. Como o Office. Para contornar a exigência de ter um bom editor para um livro ou carta, decidi fazer um pequeno algoritmo para facilitar a edição e impressão em PDF.

ver resultado no PDF desse link:
http://tivideotutoriais.blogspot.com.br/2018/01/eletron.html

Para demonstração dois arquivos. O Texto e o arquivo que controlará o posicionamento, criação de índices, paginas e formatação. Para adicionar imagens e índices, estude o fonte exemplo.

Editor.js

    /*
    Março de 2018
    Autor: Luiz Augusto da Silva Prado
    Site: www.codigorapido.com.br
    */

    var altura_pagina=760;
    var largur_coluna=460;
    var cor_borda="#dddddd";
    var pagina_bordas="border:8px;margin:8px;padding:8px;";

    //======================================
    // EXCLUIR QUEBRAS DE LINHA REPETIDOS
    //======================================
    function replaceAllBreak(str)
    {
        str = str.replace(new RegExp("\<\/tr\>\n", 'gi'), "\<\/tr\>");
        str = str.replace(new RegExp("\n\<tr\>", 'gi'), "\<tr\>");
        str = str.replace(new RegExp("\<\/td\>\n", 'gi'), "\<\/td\>");
        str = str.replace(new RegExp("\n\<td\>", 'gi'), "\<td\>");
        str = str.replace(new RegExp("\<\/table\>\n", 'gi'), "\<\/table\>");
        str = str.replace(new RegExp("\n\<table", 'gi'), "\<table");
        str = str.replace(new RegExp("\n\n", 'gi'), "\n");
        //espaçamento dos parágrafos
        str = str.replace(new RegExp("\n", 'gi'), "</br>&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp");
        return str;
    }

    //======================================
    // TÓPICO DO ÍNDICE
    //======================================
    pontos_indice = function(str)
    {
        var resp=""
        strr= str.replace(/\<span (.*?)\>/gi, '')
        strr= strr.replace(/\<\/span\>/gi, '')
        // Quantidade de caracteres maximos por linha
        for( var i=0; i<53 - strr.length; i++)
        {
            resp+=".";
        }
        return resp;
    }

    //======================================
    // ÍNDICE
    //======================================
    getIndex = function(str)
    {
        var Array_Parte = str.match( /\<div parte\>((\n|.)*?)#parte \<\/div\>/gi, '');
        var indice = new Array();
        var total_paginas=0;
        var array_romanos = ["I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X", "XI", "XII"]

        for(var n=0; n<Array_Parte.length; n++)
        {
            var t=new Object();
            t.parte="<br><br><span style='color:red;font-size:18px;'><b>Parte "+array_romanos[n]+" </b></span><br><br>";
            t.topicos=[];
            t.paginas=[];
            var Array_Paginas = Array_Parte[n].match( /\<div page\>((\n|.)*?)#page \<\/div\>/gi, '');
            for(var i=0; i<Array_Paginas.length; i++)
            {
                var Array_Topico = Array_Paginas[i].match( /\n\<b\>((\w|.)*?)\<\/b\>/gi, '');
                if(Array_Topico!=null)
                {
                    for(var j=0; j<Array_Topico.length; j++)
                    {
                        topico = Array_Topico[j].replace("<b>", "").replace("</b>", "")
                        t.topicos = t.topicos.concat( topico  )
                        t.paginas = t.paginas.concat(total_paginas+i+1);
                    }
                }
            }
            indice = indice.concat(t)
            total_paginas+=Array_Paginas.length;
        }

        paginas="";
        temp="";

        for(var n=0; n<indice.length; n++)
        {
            temp += indice[n].parte
            for(var j=0; j<indice[n].paginas.length; j++)
            {
                temp += indice[n].topicos[j] + pontos_indice(indice[n].topicos[j] + indice[n].paginas[j]) + indice[n].paginas[j]+"<br>"
                if((j+1)%22==0 || j==indice[n].paginas.length-1)
                {
                    paginas+="<div indice>"+temp+"</div>"
                    temp="";
                    total_paginas++
                }
            }
        }

        if(total_paginas%2==1)
        {
            str += "<div page>\n#page </div>";
        }
       
        str = str.replace(new RegExp(/\n\<div parte\>/, 'gi'), "");
        str = str.replace(new RegExp(/#parte \<\/div\>/, 'gi'), "");

        str = str.replace("#indice", paginas);

        return str
    }

    //======================================
    // PAGINAÇÃO
    //======================================
    getPagination = function(str)
    {
        var Array_Paginacao = str.match(/#page/g);
        if(Array_Paginacao!=null)
        for(var i=0; i<Array_Paginacao.length; i++)
        {
            str = str.replace(Array_Paginacao[i], "<div style='width:"+largur_coluna+"px;text-align:center;position:absolute;bottom:0px;'>"+(i+1)+"</div>");
        }
        return str;
    }
   
    //======================================
    // ADICIONAR IMAGEMS
    //======================================
    getImages = function(str)
    {
        var Array_Imagens = str.match(/#imagem[D-E][0-9] [0-9][0-9][0-9]\|[0-9][0-9][0-9]/g);
        //if(Array_Imagens!=null)
        for(var i=0; i<Array_Imagens.length; i++)
        {
            var DE = Array_Imagens[i].match(/[D-E][0-9]/g);
            var NN = Array_Imagens[i].match(/[0-9][0-9][0-9]/g);
            if(DE[0].charAt(0)=='D')
            str = str.replace(Array_Imagens[i] + " ", "<img style='float:right;width:"+NN[0]+"px;height:"+NN[1]+"px;margin:8px;padding:0px;border:"+DE[0].charAt(1)+"px solid #777777' src='imagens/");
            if(DE[0].charAt(0)=='E')
            str = str.replace(Array_Imagens[i] + " ", "<img style='float:left; width:"+NN[0]+"px;height:"+NN[1]+"px;margin:8px;padding:0px;border:"+DE[0].charAt(1)+"px solid #777777' src='imagens/");
            str = str.replace(" #fim", "'>");
        }
        return str;
    }

    //======================================
    // DIVISÃO DE PÁGINAS
    //======================================
    getDivPages = function(str)
    {
        var Array_DivisaoPaginas = str.match(/<div page/g);
        //if(Array_DivisaoPaginas!=null)
        for(var i=0; i<Array_DivisaoPaginas.length; i++)
        {
            str = str.replace(Array_DivisaoPaginas[i], "<div style='"+pagina_bordas+"position:relative;width:"+largur_coluna+"px;height:"+altura_pagina+"px;border:1px solid "+cor_borda+";' ");
        }
        return str;
    }

    //======================================
    // GERRAR ÍNDICE
    //======================================
    generateIndex = function(str)
    {
        var Array_Gerar_Indice = str.match(/<div indice/gi, '');
        //if(Array_Gerar_Indice!=null)
        for(var i=0; i<Array_Gerar_Indice.length; i++)
        {
            str = str.replace(Array_Gerar_Indice[i], "<div style='"+pagina_bordas+"font-size:12px; font-family:Courier New,Courier,monospace;font-weight: bolder;position:relative;width:"+largur_coluna+"px;height:"+altura_pagina+"px;border:0px solid #cccccc;' ");       
        }
        return str;
    }

    //======================================
    // START
    //======================================   
    makePages = function()
    {
        var mapa = document.getElementById("mapa");
        var str = mapa.value;

        str = str.replace(new RegExp(/\n\n\<div/, 'gi'), "<div");
        str = str.replace(new RegExp(/div\>\n\n/, 'gi'), "div>");
        str = str.replace(new RegExp(/\n\<div/, 'gi'), "<div");
        str = str.replace(new RegExp(/div\>\n/, 'gi'), "div>");
   


        str = getImages(str)   
        str = getIndex(str)
        str = getPagination(str)   
        str = getDivPages(str)       
        str = generateIndex(str)
        str = replaceAllBreak(str);



        document.getElementById("texto").innerHTML = str ;
        mapa.style.visibility = "hidden";
        mapa.style.height = "0%";
        document.getElementById("myCheck").checked = true;
    }

    //======================================
    // TESTE
    //======================================
    check = function()
    {
        var mapa = document.getElementById("mapa");
        if(document.getElementById("myCheck").checked)
        {
            mapa.style.visibility = "hidden";
            mapa.style.height = "0%";
        }
        else
        {
            mapa.style.visibility = "visible";
            mapa.style.height = "100%";
        }
    }
   
    //Ver como ficou: <input type="checkbox" id="myCheck" onclick="check()" >  <button onclick="makePages()">Atualizar</button>  <br>

Para inserir tópicos no índice,  basta iniciar nova linha entre as tags <b> e </b>
Para inserir imagens basta inserir algo equivalente a:
#imagemD2 210|210 imagem.png #fim
D significa que será posicionado a direita do texto
2 significa a espessura da borda
210|210 são as medidas w e h da imagem

Exemplo do uso do código. Crie um arquivo como mostrado abaixo:

<html>
<script type="text/javascript" src="Editor.js"></script>
<textarea id="mapa"  rows="15" cols="120" >
<div parte>
<div page>




<span style='color:red;font-size:18px;'><b>Parte I </b></span>

Algo aqui
<b>vai para o índice</b>

#page </div>
#parte </div>

<div parte>
<div page>




<span style='color:red;font-size:18px;'><b>Parte II </b></span>

Algo aqui
<b>Indice</b>
#imagemD2 210|210 imagem.png #fim

#page </div>

<div page>


Algo aqui
<b>Indice</b>


#page </div>
#parte </div>

</textarea><br>

<div id="texto" style="font-size:14px;  text-align: justify;  column-count: 2; -webkit-column-gap:0px; -moz-column-gap:0px; column-gap:0px;">Defeito</div>

<script>
makePages()
</script>
</html>