Planeta PythonBrasil

December 04, 2008

Inno::Blog

Prospecções


Talvez um teco influenciado pelo documento “Prospectiva Estratégica, Metodologia de Descrição de Cenários” temperada a puro palpite visionário, outro dia quando na piclistbr o Mak lançou esta:

1996 - um supercomputador usava 10 mil processadores Pentium Pro clocados a
200 MHz pra atingir 1 teraflops (um trilhão de operações matemáticas por
segundo). ocupava um andar inteiro de um laboratório no Novo México. Ele
consumia absurdos 500 kW e, pasme, mais 500 kW só de cooler, ar-condicionado
e tudo o mais para manter a sala geladinha e não pifar a bagaça.

2008 - uma Radeon HD 4870, placa de video das mais rápidas atualmente,
atinge esse mesmo número de flops com apenas um chip. A placa de vídeo da
AMD, assim como as outras dessa categoria, cabe num slotzinho PCI Express e
gasta 110 watts, o que já é uma cavalice.

2015 - tentem fazer uma projeção…

http://info.abril.com.br/blog/papodemicreiro/20081104_listar.shtml?125707

E lancei o seguinte cenário:

2050: Life, the Universe and Everything: q-bits e processamento de
chuckflops por segundo serão triviais. Seth Lloyd e Miguel Nicolelis
serão mais populares que Von Newman e Alan Turing. Haverá dispositivos
computacionais com processamento de chuckflops do tamanho de um
alfinente usados como implantes com baterias recarregáveis via
wireless. Todo boteco terá um recarregador wireless. Estes implantes
computacionais usarão o protocolo 802.11xyz para se conectar com a
spacenet, seja da Terra ou de Marte e a segunda língua mundial será o
chinês. Via 802.11xyz q-telepatia será algo muito comum; porém isto
será coisas para os jovens, a galerinha de 80 e 90 anos ainda usará
menssegers baseado nos protocolos XMPP em seus handhelds.

A plebe ainda usará estes dispositivos de 2015, com PCs digitais com
placas de vídeo com meros 100 teraflops consumindo os exagerados 70
Watts, utilizando toda a arcaica tecnologia digital binária. Ainda
existirão analfabetos digitais e ONGs lutando contra a fome mundial,
isto em 2050.

2100: Em 2100 os Estados Unidos elegerá o primeiro presidente
marciano, descendente de terráqueos chineses e brasileiros, que foram
para a colônia marciana em 2060, que se promoveu a base de q-telepatia.

(…)

OK: Para justificar este minha prospecção eu teria que escrever um relatório de mais de 100 páginas, mas está aí um cenário factível, não exatamente nestas datas e com esta terminologia, mas num futuro não muito distante.

      

por techberto em 04 de December de 2008 às 16:29

Luciano Ramalho

Ganhamos do MySpace

E perdemos do Google, como já imaginávamos. Estive ontem no coquetel do Prêmio Info 2008 e o resultado na categoria “Personalidade do Ano” ficou assim: 61% para Bruno Diniz do Google, 23% para Luciano Ramalho do Python Brasil e 16% para Edson Calegaretti do MySpace.

Quero agradeçer muito a todos os que votaram no meu nome e fizeram campanha. Não levamos o troféu mas fizemos bonito, porque o Google é realmente uma marca quase imbatível hoje.

Nenhuma marca foi nomeada em tantas categorias, e o Google levou 10 das 13 que disputou. O poder da marca fez até o Picasa ganhar do Flickr. Só o IPhone e o Firefox bateram concorrentes do Google (o Firefox em duas categorias).

O Django, produto da comunidade Python, ficou em terceiro na categoria “Desenvolvimento”, atrás do Rails e do Adobe AIR. [resultados completos]

O mais importante é que a gente teve as nomeações, então estamos de novo na revista (pags. 90 e 92 da edição de dezembro), e vamos entrando no radar de mais leitores. E a nomeação me deu a oportunidade de estar lá ontem à noite, em nome da Associação Python Brasil, trocando cartões de visita com empresas que podem patrocinar ou ajudar de outra forma em nossas ações. Tentamos aproveitar ao máximo a oportunidade, porque tava claro que ganhar seria muito difícil.

Para a nossa comunidade, a melhor notícia da noite foi que a Sandra Carvalho, publisher da Info, quer abrir um fórum permanente sobre Python no site da revista.

Valeu pessoal, muito muito grato pela força!

por luciano em 04 de December de 2008 às 13:09

December 03, 2008

Eduardo Willians

Há Não Muito Tempo...

C é uma linguagem muito poderosa; dizem que um holandês a decifrou para os humanos.
(rumores sobre Python)

por Eduardo Willians (noreply@blogger.com) em 03 de December de 2008 às 08:35

November 30, 2008

Juracy Filho

Desenho de árvore binária em Python


Como comentei no post anterior estou fazendo faculdade, o que sugou bastante o meu tempo. Na faculdade desenvolvi alguns pequenos projetos (sozinho ou em equipe), e realizei alguns trabalhos, vou tentar publica-los aqui aos poucos.

Na matéria de Estrutura de Dados o professor aceitou que os exercícios fossem feitos na linguagem que o aluno quisesse, a limitação era apenas a capacidade dele de entender a lógica (talvez ele não tivesse aceito em linguagens funcionais por exemplo). E é claro, já que eu podia escolher, escolhi Python :D

Recentemente desenvolvemos uma árvore binária e apesar de não solicitado desenvolvi também uma representação gráfica da mesma, assim ficaria mais fácil depura-la. Achei o resultado suficiente interessante para compartilhar com vocês, espero que gostem.

O código é um pouco extenso para publicar no corpo do post então coloco aqui os links para download, porém o wordpress não suporta arquivos .py, então converti-os para PDF (se alguém tiver sugestões de como melhorar este processo aceito dicas). Até a próxima.

Posted in Python   Tagged: Python   

por juracy em 30 de November de 2008 às 22:42

November 29, 2008

Fazer Jogos

Introdução à pyglet

Se você já tentou ou foi atrás de módulos para programar jogos em python, provavelmente já se deparou com a conhecida pygame. O projeto começou a ser desenvolvido em 2000 e já tem um nome muito forte e associado ao desenvolvimento de jogos em Python. No entanto, existe uma alternativa bem menos conhecida que eu acho muito interessante. Essa alternativa é a pyglet.

Nesse post vou mostrar a pyglet através de um tutorial simples. Para acompanhar melhor o tutorial, sugiro a familiarização com o conceito de programação orientada a eventos. Também é importante saber python e orientação a objetos em python.

Uma Visão Geral

A pyglet é uma biblioteca multimídia multiplataforma. Ela consegue carregar e exibir imagens, abrir e tocar sons e até mesmo passar vídeos. Ela também tem uma série de classes e funções úteis para criação de jogos, como sprites e funções de gerenciamento de tempo, uma série de módulos de renderização de texto bastante avançados e um sistema de eventos elegante e fácil de extender.

Se você não tem problemas com inglês eu recomendo fortemente a leitura do guia de programação e uma olhada pela documentação da API da pyglet para ter uma idéia melhor do que ela é capaz.

Sua Primeira Aplicação Pyglet

A menor aplicação possível escrita com a pyglet tem apenas 3 linhas.

import pyglet
window = pyglet.window.Window()
pyglet.app.run()

Bem simples, não? Primeiro importamos o módulo da pyglet, depois criamos uma janela. Essa janela exibirá as coisas que iremos desenhar e também responderá a eventos de mouse e teclado quando estiver em foco. A última chamada, inicia um laço de processamento de eventos. 

Bom, essas 3 linhas são simples, mas não fazem lá muitas coisas úteis. O máximo que você vai conseguir é fechar sua janela apertando <Esc> ou clicando no botão de fechar, caso seu gerenciador de janelas mostre um. Além disso, dependendo de onde você estiver executando esse script, pode ser que a sua janela exiba um padrão meio aleatório de pixels. Isso acontece porque ela está despejando o conteúdo de sua memória de vídeo diretamente (não é exatamente isso que acontece, mas não convém entrar em detalhes aqui).

Para mudar um pouco esse cenário e fazer com que nossa aplicação faça algo útil, vamos entender como os eventos da pyglet funcionam.

Eventos na Pyglet

Como eu mencionei, a chamada a pyglet.app.run inicia um laço de tratamento de eventos. Na pyglet existe uma classe para a geração de eventos chamada EventDispatcher. Todas as classes que geram eventos derivam da EventDispatcher. Por convenção, os eventos gerados por um dispatcher se chamam on_<alguma coisa>, por exemplo on_draw ou on_key_release.

Para tratar eventos gerados por um dispatcher precisamos de event handlers. Não existe uma classe específica para handlers, eles podem ser qualquer objeto ou função python desde que sejam conectados ao dispatcher da maneira adequada. Existem várias maneiras de conectar um handler a um dispatcher. É mais fácil mostrar através de um exemplo:

# A classe window da pyglet é um EventDispatcher
window = pyglet.window.Window()
 
# Cada vez que o conteúdo da janela precisa ser redesenhado, um evento
# on_draw é gerado. Podemos tratá-lo usando o evento como uma
# propriedade do objeto
def my_draw():
    print "desenhando a janela"
window.on_draw = my_draw
 
# Instâncias de EventDispatcher possuem um decorador event para
# conectar eventos a eles
@window.event('on_draw')
def my_draw():
    print "desenhando a janela"
 
# Se a função python tem o mesmo nome do evento tratado, basta usar
@window.event
def on_draw():
    print "desenhando a janela"
 
# O método push_handlers de um dispatcher também pode ser usado
# passando uma função...
window.push_handlers(on_draw=my_draw)
 
# ... ou um objeto com métodos com o mesmo nome dos eventos a
# serem tratados
class MyClass(object):
    def on_draw(self):
        print "desenhando a janela a partir do objeto ", self
 
obj = MyClass()
window.push_handlers(obj)

Uma outra forma ainda, não mostrada no exemplo acima, é fazer uma classe herdando de um EventDispatcher e sobrescrevendo os métodos correspondente aos eventos. Bom, existem muitos jeitos de fazer e cada um deles vai ser mais adequado dependendo da arquitetura da sua aplicação e de como você acha mais intuitivo. Agora seguindo em frente com a pyglet…

Uma aplicação mais interessante

Agora que já sabemos como começar uma aplicação pyglet e como tratar eventos, vamos começar a botar isso para algum uso construindo uma aplicação um pouco mais interessante. A pyglet pode ser usada pra vários tipos de aplicação, mas como esse é um blog sobre fazer jogos a nossa aplicação de exemplo será uma base para um pequeno jogo. Para seguir em frente, você pode adicionar os trechos de código aqui descritos logo após a criação do objeto window (ou logo antes da chamada pyglet.app.run()) na nossa aplicação minimalista.

A idéia é bem simples: carregar uma imagem para ser nosso personagem e movê-lo pela tela usando o teclado. A imagem que eu vou usar é realmente simples. Você pode usar outra se quiser. Aqui está ela:

Na pyglet carregamos arquivos de mídia através do módulo pyglet.resource. Esse módulo tem funções para carregar vários tipos de arquivo. Além disso também é possível adicionar diretórios onde os arquivos serão procurados para serem carregados. Por padrão, os caminhos são relativos ao diretório onde o script python se encontra. Para carregar a imagem do nosso personagem, fazemos o seguinte:

image = pyglet.resource.image('char.png')

Essa imagem carregada possui um ponto de âncora definido pelas propriedades anchor_x e anchor_y do objeto image. Quando vamos desenhar uma imagem em uma posição x, y é esse ponto de âncora que é posicionado na posição indicada. Por padrão o ponto de âncora é o canto inferior esquerdo da imagem. No caso do nosso personagem, parece mais interessante posicioná-lo a partir do seu centro, então mudaremos o ponto de âncora para o centro da imagem:

image.anchor_x = image.width // 2
image.anchor_y = image.height // 2

Apesar de nós podermos desenhar diretamente nossa imagem na tela com o método blit(x, y), iremos criar um objeto Sprite com a nossa imagem, que já encapsula uma série de propriedades muito úteis para um objeto de jogo como posição, rotação e escala.

sprite = pyglet.sprite.Sprite(image, x=320, y=240)

Os parâmetros x e y são opcionais e são apenas os valores iniciais x e y da posição do sprite. Depois de criar o nosso objeto sprite vamos tratar o evento on_draw da nossa janela para desenhá-lo. Além de desenhar o sprite, também chamamos o método window.clear() para limpar o conteúdo da nossa janela a cada frame.

@window.event
def on_draw():
    window.clear()
    sprite.draw()

Como você pode ver, é muito fácil desenhar um sprite. Agora vamos aprender como tratar eventos de teclado para movê-lo pela tela conforme apertamos as teclas de seta.

Eventos de Teclado

A classe window gera eventos on_key_press e on_key_release cada vez que uma tecla do teclado é pressionada ou solta. Um pouco diferente do evento on_draw, esses eventos também enviam parâmetros para seus handlers. Nesse caso, os parâmetros enviados são um valor correspondente à tecla pressionada que gerou o evento e os modificadores ativos naquele momento. Os modificadores são referentes às teclas Shift, Alt ou Ctrl estarem pressionadas ou não.

@window.event
def on_key_release(symbol, modifiers):
    print symbol, modifiers

Com o handler acima você pode ver quais valores estão sendo recebidos cada vez que você solta uma tecla do teclado. Se você colocar executar o código com esse handler vai perceber que são valores numéricos inteiros. Felizmente, você não precisa decorar o valor de cada tecla. A pyglet tem constantes com nomes intuitivos para os valores recebidos. Elas estão no módulo pyglet.window.key. Como esse módulo é bastante usado no tratamento de eventos de teclado, é conveniente importá-lo no início do seu programa com um

from pyglet.window import key

Agora, supondo que você colocou o import acima no seu código, vamos escrever um handler de teclado mais interessante:

@window.event
def on_key_release(symbol, modifiers):
    if symbol == key.UP:
        print "Mover o sprite para cima"

Imagino que não seja difícil prever o que vai acontecer aqui. Quando você pressionar a tecla da seta para cima no teclado a mensagem ‘Mover o sprite para cima’ será exibida. Como esse era para ser apenas um exemplo bobo de como usar as constantes do módulo key eu lhe poupei de mensagens semelhantes para as constantes das outras setas.

Movendo o Sprite

Mover o sprite efetivamente não tem nenhum mistério também. Como eu disse antes um Sprite encapsula uma série de propriedades úteis como posição, rotação e escala. Um jeito de mudar a posição de um sprite é acessando seus atributos x e y. Vamos ver como fica isso no contexto do nosso handler de teclado:

@window.event
def on_key_release(symbol, modifiers):
    if symbol == key.UP:
        sprite.y += 32

Agora a nossa mensagem boba foi substituída por um código que faz o que a mensagem dizia anteriormente: move o sprite para cima. Esse é um bom momento para mencionar que a pyglet convenciona que o eixo x positivo fica à direita da origem, o y positivo fica acima da origem e a origem fica no canto inferior esquerdo da tela. Essa convenção de x é bem comum, mas frequentemente vemos uma convenção y trocada. Na pygame, por exemplo, o y cresce para baixo e a origem fica no canto superior esquerdo da tela.

Completar o código acima com movimentos para as outras direções é bastante simples, mas você pode também baixar o código completo do exemplo, junto com a imagem utilizada e ver como fazer.

Conclusão

Nesse post criamos uma aplicação muito simples usando a pyglet, mas que poderia servir como base para algo mais sofisticado. Várias melhorias e alterações poderiam ser feitas, por exemplo, no código acima nosso personagem se move apenas cada vez que uma tecla é solta e sempre faz um movimento de 32 pixels por vez. Esse tipo de movimento pode ser apropriado para alguns tipos de jogos, já outros exigiriam um movimento mais suave e contínuo e que fosse realizada durante todo o tempo em que as setas estão pressionadas.

Como esse post já ficou muito longo vou ficando por aqui, mas esse tutorial foi pensado como parte de uma série, então em breve essas melhorias serão descritas aqui conforme outros tópicos são abordados.

por Kao Félix em 29 de November de 2008 às 04:45

November 26, 2008

Luciano Ramalho

O mistério do teclado sem “?”

Outro dia eu li na Info que um modelo de notebook Vaio lançado no Brasil não tem o ponto de interrogação no teclado. Achei bizarro e fui conferir na Fnac. Fiquei abismado ao constatar que os notebooks novos da Sony, STI e outros fabricantes estão saindo com teclados supostamente “padrão ABNT-2″ que têm o “Ç” mas não têm a tecla com os caracteres “?” e “/”. Curiosamente, a tecla do “\” e do “|” foi mantida. Veja a foto de um teclado deste tipo.

Nesses notebooks, para digitar um ponto de interrogação ou uma barra normal é preciso usar uma combinação com a tecla AltGr. Por exemplo, “?” é AltGr+W. Mas a contrabarra está lá, com sua própria tecla, e basta um Shift para produzir o pipe, símbolo que só interessa para programadores. Pena que como programador eu faço mais divisões que disjunções de bits.

Este teclado não é para mim. Pensando bem, acho que minha mãe também usa mais a barra e a interrogação que a contrabarra e o pipe. Para quem será que este padrão de teclado foi feito?

Fiquei muito interessado em descobrir como é que vários fabricantes de notebooks foram levados a tomar esta decisão. Será que foi uma norma técnica publicada no primeiro de abril?

Se você sabe alguma coisa sobre os bastidores desta história, por gentileza, deixe o seu comentário contando. Ou, se você acha muito mais útil a tecla “\|” do que a “/?”, então me conte o que você faz com o seu computador.

Vou continuar investigando e quando tiver novidades, colocarei aqui. Conto com você para esclarecer este mistério!

por luciano em 26 de November de 2008 às 22:04

Devlog

Atualizações no Mundo Python

Os últimos dias foram cheios de atualizações para os pythonistas :) . Devido a um problema no empacotamento, 3 dias após o lançamento do Django 1.0.1, foi lançado o 1.0.2. Para quem usa o Google AppEngine, problema semelhante aconteceu: 3 dias após o lançamento do 1.1.6, saiu o 1.1.7 para corrigir bugs de última hora.

O Pylons se aproxima da versão 0.97 final, no última dia 24 saiu o Release Candidate 4, que eles esperam ser o último. A documentação atualizada você pode ver em http://docs.pylonshq.com/ ou baixar em PDF.

O Michael Bayer (SQLAlchemy, Mako), após usar o Beaker (middleware WSGI de Cache e Sessão) em produção, corrigiu muitos bugs nos caches em arquivo e memcached. Eu enviei um patch minúsculo que fez com que ele voltasse a funcionar com o Google AppEngine e tudo isso já está disponível na versão 1.1.2. Outro projeto que agora funciona melhor com o Google AppEngine é o FormEncode. A versão 1.1 tinha introduzido um pequeno problema com o Google AppEngine, que foi corrigido no FormEncode 1.2

Ao colaborar com a tradução da documentação do Django para português, descobri um problema com o CSS, que depois acabou se revelando um problema com a dupla docutils + Sphinx. Enquanto o bug era testado, saiu uma nova versão, o Sphinx 0.5. O Sphinx se tornou muito popular na geração de documentação para projetos Python (a documentação do Pylons que eu citei agora a pouco é gerada com Sphinx).

É isso, hora de atualizar os virtualenvs da vida :)

por Walter Cruz em 26 de November de 2008 às 13:54

November 25, 2008

Elcio Luiz Ferreira

Eu vou ao 1º Encontro de TI da Arteccom

A Editora Arteccom está organizando o I ETI. Eu vou estar lá, e recomendo, parece que vai ser muito interessante. Recebi deles o seguinte release:

É tempo de interatividade e o 1º Encontro de TI faz tudo o que o público deseja!
A editora Arteccom promove novo evento que promete agitar o mercado dos desenvolvedores web.

Sabe aquele evento que você sempre sonhou? Com as palestras que você sempre quis assistir? Virou realidade! A Arteccom fez uma pesquisa com desenvolvedores web para que fossem sugeridos temas e palestrantes para o evento. 512 profissionais da área de TI responderam a pesquisa e, mais tarde, com expressiva participação do público no site www.encontrodeti.com.br, foi desenhado o 1º Encontro de Tecnologia da Informação.

Os temas mais votados e escolhidos para as palestras foram “Linguagens – quais são as mais requisitadas pelas grandes empresas e o valor das formações/certificações”, “CMS livres: Drupal x Joomla! x WordPress”, “Ferramenta Google Analytics: como analisar acessos e gerar melhores resultados” e “Padrões W3C – Como tornar seu site mais leve e mais acessível”. E ocorrerão ainda, simultaneamente, algumas oficinas que vão discutir os assuntos mais atuais da área, como Ruby On Rails, SEO, Interoperabilidade e Scrum.

Mas a interação não pára por aí. Depois de escolhidos os temas, os mediadores das palestrantes e oficinas propõem um debate no site do ETI para decidir qual especialidade dentro do assunto principal será abordada para as palestras (http://www.encontrodeti.com.br/site/?p=558). Ou seja, todas as decisões são feitas através de pesquisas com o público.

Vai ter até café da manhã, espaço imprensa digital, e, para completar, eu te faço mais uma perguntinha: Já pensou em um evento com as palestras e oficinas que você sempre sonhou, e no final ainda curtir um Happy Hour? Não está acreditando não é? É isso aí! Você não pode perder! No final deste mês, dia 27/11, quinta-feira, na Amcham Brasil, em São Paulo, e dia 29/11, sábado, no Centro de Convenções SulAmérica, no Rio de Janeiro.

Para ter um gostinho do que vai rolar no evento, confira os quatro chats sobre os temas das palestras, que tiveram ótima repercussão com cerca de 50 participantes em cada sala: http://www.encontrodeti.com.br/site/?page_id=319.

O Encontro de Tecnologia da Informação é uma realização da Arteccom, com os patrocínios de PagSeguro UOL, UOL Host, Tecla e Hostnet.

Veja a programação do evento:

08:30 – Credenciamento
09:00 – Café da manhã (networking e visita aos estandes)
10:00 – Abertura
10:15Palestra: “Linguagens: quais são as mais requisitadas pelas grandes empresas e o valor das formações/certificações”
Palestrante SP e RJ: Guilherme Chapiewski (Globo.com)
11:15Debate CMS livres:
- WordPress: SP: José Murilo (Minc) | RJ: Guilherme Aguiar (Minc)
- Joomla!: Ricardo Accioly (Noix)
- Drupal: Paulino Michelazzo (Fábrica Livre)
13:00 – Intervalo para almoço
14:30Palestra: “Google Analytics: como analisar acessos e gerar melhores resultados”
Palestrante SP: Ruy Carneiro (WA Consulting)
Palestrante RJ: Gustavo Loureiro (Infnet)
15:30 – Intervalo para visita aos estandes
16:00Palestra: “Padrões W3C: torne seu site mais leve e mais acessível”
Palestrante SP: Vagner Diniz (W3C)
Palestrante RJ: Everaldo Bechara (iLearn)
17:00 – Happy hour
18:00 – Encerramento

Oficinas (vagas limitadas):

10:15 às 11:15h (palestra principal: Linguagens e certificações)
Ruby on Rails – SP Fábio Akita (Locaweb)
Ruby on Rails – RJ Sylvestre Mergulhão (Hostnet)

11:15 às 12:15 (palestra principal: CMS livres)
SEO – SP Fábio Ricotta (MestreSEO)
SEO – RJ Paulo Teixeira (Marketing de Busca)

14:30 às 15:30 (palestra principal: Google Analytics)
Interoperabilidade – SP Fábio Hara (Microsoft)
Interoperabilidade – RJ Gilson Banin (Microsoft)

16:00 às 17:00 (palestra principal: Padrões W3C)
Scrum – SP Guilherme Chapiewski (Globo.com)
Scrum – RJ Guilherme Chapiewski (Globo.com)

Locais:

São Paulo
Data: 27 de novembro de 2008
Local: Amcham Brasil
Rua da Paz, 1.431 – Chácara Santo Antônio – São Paulo – SP
Telefone: (11) 5180-3728

Rio de Janeiro
Data: 29 de novembro de 2008
Local: Centro de Convenções SulAmérica
Av. Paulo de Frontin, 1 – Cidade Nova – RJ
Telefone: (21) 3293-6700

Inscrições: www.encontrodeti.com.br
Mais informações: (21) 2253.0596

Texto de Flávia Freire
Flavia.freire@arteccom.com.br

Recomendo. Vejo você lá.

por Elcio em 25 de November de 2008 às 19:54

Elton Luís Minetto

Lock em arquivos usando SVN e Subclipse

Outra novidade para mim ao usar o Subversion foi o controle de Locks. 

Eu sempre usei o CVS integrado ao Eclipse para gerenciar os projetos que eu trabalhava e com essa duplinha é bem fácil configurar para evitar que dois programadores alterem o mesmo arquivo.

Com o Subversion e o Eclipse (usando o plugin Subclipse) eu não encontrei essa opção. A solução que encontrei foi configurar o cliente do subversion para quando criar novos arquivos marcá-los com um flag. Este flag indica que, para editar o arquivo é preciso que seja feito o “lock” antes. No momento de criar o lock o Subclipse também verifica a versão do arquivo e avisa caso a versão local seja inferior a que consta no repositório. Desta forma eu garanto que o programador sempre tenha a última versão do arquivo e evito que duas pessoas alterem o mesmo arquivo ao mesmo tempo. Existem formas de corrigir isso usando práticas de merge, mas eu acho mais fácil evitar o problema do que resolvê-lo :-)

O que eu fiz foi alterar o arquivo config no diretório do usuário:

mate ~/.subversion/config

Eu estou usando o Textmate no MacOSX. Mas o mesmo passo vai funcionar no Linux. No Windows XP o arquivo encontra-se no diretório

c:\Documents and Settings\usuario\Dados de Aplicativos\Subversion\config

Neste arquivo eu alterei 

# enable-auto-props = yes

para

enable-auto-props = yes

E adicionei alinha abaixo na seção  [auto-props]

* = svn:needs-lock

Desta forma, assim que o programador criar um novo arquivo e realizar o primeiro commit é adicionada esta flag ao arquivo. Todos que forem alterá-lo vão passar pela fase “lock-edit-commit”, com um “update” caso seja necessário.

por elm em 25 de November de 2008 às 17:09

Deploy automático do SVN

Estou iniciando um novo projeto e aproveitei para mudar do CVS para o Subversion. 

Uma das coisas que achei interessante é o esquema de “hooks“. É um conceito parecido com “triggers” de bancos de dados. Você pode programar alguns scripts para serem executados em momentos específicos do ciclo gerenciado pelo SVN. As opções são:

post-commit.tmpl
post-lock.tmpl
post-revprop-change.tmpl
post-unlock.tmpl
pre-commit.tmpl
pre-lock.tmpl
pre-revprop-change.tmpl
pre-unlock.tmpl
start-commit.tmpl

Os nomes são auto-explicativos. Por exemplo, o script post-lock vai ser executado sempre após algum usuário ter feito o lock de um arquivo.

Estes arquivos estão armazenados no diretório hooks do repositório do projeto.

O que eu fiz foi alterar o post-commit.tmpl

É preciso remover a extensão do nome e dar permissão de execução no arquivo, então:

cp post-commit.tmpl post-commit
chmod +x post-commit

O conteúdo do arquivo ficou assim:

REPOS="$1"
REV="$2"
PROD="/var/www/html"
#pega todas as alteracoes
svnlook changed $REPOS --revision $REV >> /tmp/lixo_$REV
#pega cada alteracao e salva
for i in `cat /tmp/lixo_$REV|cut -c 5-1024` ; do
  svnlook cat $REPOS $i > $PROD/$i
done
#apagar arquivo
rm /tmp/lixo_$REV
Desta forma cada vez que um programador faz o commit do fonte ele é automaticamente salvo no htdocs, onde fica acessível para a equipe de testes. 
Lógico que esse script pode ser melhorado e isso está sendo executado em um servidor de desenvolvimento e não o de produção. Além disso eu comecei a usar o SVN somente agora, por isso, se alguém encontrar um problema ou erro na lógica me avisem :-)

por elm em 25 de November de 2008 às 16:17

Stiods Palace

Gerenciamento de usuários Trac com Django

No Gravatar

Uma das minhas maiores broncas com o Trac é na hora de gerenciar usuários.

Até poucos meses atrás eu costumava gerenciar os usuários com o famoso aplicativo htpasswd que utiliza um arquivo de texto simples pra gerenciar os usuários. O primeiro problema que eu tive com ele veio quando eu pensei:

Holly shit...se eu precisar definir permissões de acesso a diferentes Tracs eu to fucked

Foi então que eu resolvi procurar uma alternativa, e o primeiro (e mais obvio) lugar que eu procurei foi no Django, felizmente encontrei a documentação que ensina passo-a-passo como configurar o Apache para autenticar com o Django, é tão ridiculamente simples configurar que recomendo acessar o link por você mesmo e configurar.

Agora eu estava feliz, tinha 3 tracs pra administrar, felizmente, todos com as mesmas permissões de acesso e tudo sobre controle, gerenciamento de usuários centralizado e tudo mais. E eis que finalmente surge a oportunidade de por a prova o gerenciamento de permissões de acesso com o Trac do projeto Djapian (ainda não publicado), dessa forma fiz o seguinte:

  • Os 3 Tracs já existentes estão configurados para permitir apenas acesso de pessoas com o atributo is_staff habilidado
  • O novo Trac foi configurado para permitir acesso de qualquer pessoa que tenha a permissão djapian

Após configurar o Apache apropriadamente eu criei um usuário de teste pelo Admin do Django, feito isso, testei o usuário no Trac do Djapian e no Trac interno, resultado: Perfeito, conseguindo logar-se e negando autenticação respectivamente.

Agora estava tudo perfeito, até eu perceber um detalhe: O projeto Djapian é OpenSource, e eu gostaria que o wiki também fosse, porém, não gostaria de deixar habilitado a edição do mesmo por usuários anonimos, até por questões de rastreamento no caso de alguem apagar ou estragar uma página.

O problema: Como eu permito que usuários se cadastrem?
A solução: Construir um plugin para o Trac que faça a interface com o Django :D

Levei aproximadamente 1 dia útil de trabalho para desenvolver esse plugin que pode ser baixado aqui, o plugin é bem simples de se configurar e instalar, para isso siga os seguintes passos:

 
$ wget http://pub.stiod.com/TracDjangoAuth-0.1.tar.gz
$ tar -zxvf TracDjangoAuth-0.1.tar.gz
$ cd TracDjangoAuth-0.1
$ python setup.py bdist_egg
$ cp dist/TracDjangoAuth-0.1-*.egg /path/para/o/seu/trac/plugins/
 

Agora é preciso apenas editar o arquivo trac.ini e acrescentar no final dele as seguintes linhas:

 
[djangoauth]
# Adicione aqui sua permissao
django_permission_name = can_do_something
# Permissoes padroes para cada usuario que se cadastras
default_trac_permissions = WIKI_CREATE,WIKI_MODIFY,WIKI_VIEW
# Settings que deve ser usado
django_settings_module = some_project.settings
 

Apenas note que a opção django_permission_name requer apenas o atributo codename da permissão, diferentemente de seu equivalente no Apache, que precisa do nome da aplicação também como myapp.some_perm.

Feito isso apenas reinicie o Apache e divirta-se, o novo plugin irá criar um novo link chamado "Signup" para que seus usuários possam se cadastrar e se logar :)

Qualquer dúvida, bug, sugestão, correção ou patch, é só comentar ai em baixo ;)

Em tempo: Fiz esse plugin para o Trac 0.10.x, se você estiver disposto a migrar para o 0.11, saiba que a unica mudança é no sistema de templates, de ClearSilver para Genshi.

por Rafael SDM Sierra em 25 de November de 2008 às 16:13

November 23, 2008

Inno::Blog

Notas sobre o Seminário C & C++ para Sistemas Embarcados


Numa conversa de boteco a uns 6 anos atrás com alguns colegas, falávamos de bits, bytes, C, programação, redes e clusters; eis que surge uma idéia  (talvez inovadora) de distribuição de carga em clusters utilizando pirometro óptico, termômetro digital, amperímetros criando uma grande rede de sensoriamento visando não apenas o balanceamento computacional mas também a economia de energia através do equilíbrio térmico e de consumo de energia no datacenter. Foi neste contexto que foi inserido o assunto microcontroladores na conversa e a maioria dos colegas que estavam na mesa ficaram fascinados. Curiosamente, lendo o blog Arquitetura em Pauta o Otávio comentou que no PDC houve uma apresentação que demonstrou solução similar e vejo agora que a viagem não era tão grande.

Mas voltando às conversas de boteco, já naqueles tempos conversávamos sobre a idéia de encontros e eventos específicos para programadores de C & C++, sendo-se que dentre estes ao menos um deveria ser exclusivo de embedded systems voltados para microcontroladores e como já comentado anteriormente que iria ocorrer, foi realizado no dia 08/11 o seminário C & C++ para Sistemas Embarcados, onde o foco foi adivinha o quê? Sobre o que lá ocorreu, é possível ficar sabendo pelos blogs do DQ , P. e do Diego, assim como por threads na ccppbrasil, programa embedded software e sis_embarcados.

Em paralelo, num outro evento que estava ocorrendo no mesmo dia em São Paulo, o Lameiro e uma galera do Grupy-SP  fez uma implementação pitoresca de sensor networks utilizando AVR numa placa Arduino Diecimila que pela idéia inovadora recebeu um prêmio especial.

Portanto vemos que o assunto microcontroladores está ficando cada vez mais pop, assim como sensor networks que tem sido o campo onde microcontroladores tem sido largamente utilizados, seja para segurança da informação, segurança privada ou telemetria; tornando telematics algo cada vez mais presente em nosso dia-a-dia.

E os feedbacks do seminário foram excepcionais, muito acima do normal, mais críticos do que recebemos dos outros eventos, superando expectativas e nos mostrando que este público de embedded systems quer eventos diferentes do que eles estão acostumados a presenciar, quase nos intimando a repetir a dose e experimentar outros formatos mais ousados; o que na medida do possível tentaremos realizar. Portanto, pedido anotado!

      

por techberto em 23 de November de 2008 às 17:49

November 22, 2008

Fazer Jogos

Pontos e Vetores

Aos que receberam a versão incompleta desse post pelo leitor de RSS, peço desculpas pelo inconveniente. Eu acidentalmente apertei o botão de publicar no Wordpress.

A razão de eu escrever esse post é que muita gente que gostaria de fazer jogos não tem um background muito matemático ou técnico e alguns conceitos são muito importantes de se entender para fazer pelo menos as coisas mais básicas em um jogo. Duas entidades matemáticas que eu acho particularmente importantes são pontos e vetores. Já vi muitas pessoas com dificuldade de entender as diferenças entre esses dois e eu mesmo só compreendi completamente após ver vários exemplos de uso dos dois.

Antes de falar do assunto do post em si, gostaria de dizer que a visão que eu quero dar aqui é bem pragmática, sem entrar em detalhes teóricos da matemática por trás das coisas. Minha intenção é focar nos conceitos representados e como eles são aplicados de maneiras úteis na hora de fazer um jogo.

Também vale mencionar que eu tentei começar do mais básico possível. Eu imagino que pessoas com um background em exatas vão passar o post inteiro bocejando com a trivialidade do que é coberto aqui, mas esse post se destina justamente às pessoas cuja última lembrança desses conceitos são aulas traumatizantes ou há muito esquecidas.

Uma última observação: para o propósito desse post todos os exemplos serão em 2D.

Pontos

Para colocar elementos gráficos na tela de um jogo precisamos atribuir posições para esses elementos. Posições normalmente são representadas por pontos. Pontos 2D são representados por 2 números. Dependendo do que você está fazendo você pode usar números inteiros ou números reais. Esses números são números absolutamente normais. Eles não tem nada de especial. Você pode somá-los, pode subtraí-los, multiplicá-los, dividí-los e até usar qualquer outro tipo de operação matemática que atue sobre um ou mais números. Pode parecer bobagem explicar uma coisa dessas, mas eu vejo muitas pessoas que querem começar a fazer jogos e empacam na matemática às vezes dizendo coisas como “Não sou bom com números” ou “Não sei fazer contas”. Eu entendo isso. No colégio eu ia muito mal em matemática simplesmente porque não fazia o menor sentido para mim ficar fazendo operações com números de novo e de novo sem chegar a lugar algum. Na faculdade as coisas começaram a ficar realmente interessantes porque elas ganharam significado.

Pois então, pontos 2D são pares de números e você pode fazer com esse número qualquer coisa que você já sabe fazer com um número normal. Mas a questão é: pra que fazer isso? Não tem sentido nenhum fazer qualquer coisa com esses números se não acabar dando um resultado interessante. Para enxergar isso é preciso enxergar além dos números: é preciso ver o significado. O que significam esses dois números que compõe um ponto 2D? Para dar uma interpretação para eles a gente precisa de algumas coisas a mais. Lembre-se do colégio agora e do bom e velho plano cartesiano. Temos dois eixos normalmente chamados de x e y e os números que compõem um ponto representam deslocamentos através desses eixos.

Plano Cartesiano 2D

Plano Cartesiano 2D

O ponto onde nossos eixos se cruzam é especial e chamamos ele de origem do sistema de coordenadas. A razão dele ser especial é justamente porque é nosso ponto de referência a partir do qual contamos o quanto nos deslocamos através dos eixos. O deslocamento nos eixos pode ser positivo ou negativo e isso diz para que sentido estamos nos movendo em relação à origem. Normalmente a parte à direita da origem é o lado do x positivo e a parte acima da origem é o y positivo, mas isso não está escrito em pedra. Diferente convenções podem ser adotadas e é importante saber qual você está usando para não se perder.

Ok, pontos são simples de entender. No final das contas é um conceito bastante intuitivo. Agora que sabemos que nossos números significam deslocamentos através de eixos, podemos também atribuir significado a operações matemáticas em cima desses números.

Primeiro, vamos ganhar um pouco mais de intimidade com essa entidade abstrata criando um ponto chamado P. Quando damos nomes para as coisas é muito mais fácil de pensar sobre elas. Esse nosso ponto P é composto por dois números que nós chamamos de coordenadas. Como temos uma dessas coordenadas associadas a x e outra a y, vamos chamar cada uma de coordenada x de P e coordenada y de P respectivamente. Para representar de forma mais compacta vamos escrever P = (x, y).

Ok, agora que temos nosso ponto P vamos começar tentando dar um significado para a operação de soma e subtração em cima das suas coordenadas x e y. Como o valor da coordenada representa deslocamento em um eixo, somar ou subtrair um número a esse valor faz com que esse deslocamento aumente ou diminua. Se fizermos isso repetidas vezes ao longo do tempo, podemos interpretar que estamos movendo o ponto P pelo espaço 2D.

Movimento de 10 unidades no eixo X

Movimento de 10 unidades no eixo X

Esse já é o tipo de coisa que começa a ficar fácil de relacionar com jogos. Pense em um jogo 2D com um personagem. Zelda, por exemplo. Apesar de nunca ter visto o código de Zelda na minha vida, posso apostar como o Link tem uma posição associada representada por um parente do nosso ponto P. A cada vez que a tela é desenhada o link é desenhado nessa posição. Conforme apertamos o direcional do nosso controle as coordenadas x e y são incrementadas ou decrementadas fazendo com que o personagem seja desenhado em posições diferentes a cada vez dando a impressão de que ele está se movimentando.

Jogo Zelda: O personagem se move em x e y

Jogo Zelda: O personagem se move em x e y de acordo com a entrada do jogador.

Vetores

Agora que já você já sabe mais sobre pontos no espaço 2D, podemos seguir em frente e começar a falar sobre uma outra entidade conhecida como vetor. Uma coisa engraçada é que a representação de vetores é exatamente igual à representação de pontos: um par de números. No entanto eles são duas entidades bem diferentes. Isso é uma situação ideal para eu aproveitar e reforçar: o que realmente conta aqui é o significado. Sem uma interpretação, um conceito em cima desse par de números, eles não servem para absolutamente nada.

Então, em que exatamente vetores são diferentes de pontos? Eles se diferenciam pelos conceitos que eles representam. Enquanto um ponto representa a posição de algo num espaço, um vetor representa um sentido e um tamanho. Para compreender melhor as diferenças, nós desenhamos os vetores de maneira diferente dos pontos também. Além disso costumamos chamar os números que compõem um vetor de componentes ao invés de coordenadas, mas isso não é obrigatório.

Um ponto e um vetor

Um ponto e um vetor

Vamos um pouco além com essa história de sentido e tamanho. A representação gráfica de seta sintetiza isso da forma ideal para criar uma intuição sobre o assunto. O sentido em que a seta aponta é justamente o sentido representado pelo vetor, enquanto o tamanho, chamado mais formalmente de magnitude ou norma do vetor, corresponde ao comprimento dessa seta.

Tamanho de um Vetor

Tamanho de um Vetor

Outra coisa que é interessante observar é que vetores não tem um conceito de posição associado. Então não precisamos nos limitar a desenhar as setas dos vetores a partir da origem, mas podemos desenhá-las onde for mais cômodo e facilitar nosso entendimento. Note que isso não quer dizer que estejamos mudando os componentes do vetor.

Só o fato de dar uma interpretação diferente para um par de pontos já torna eles apropriados para representarem um monte de coisas novas. Um exemplo ótimo e intuitivo de uso de vetores é como representação de uma velocidade. Um vetor de velocidade representa de maneira muito compacta o sentido em que um objeto se move e também, através da magnitude do vetor, a rapidez com que ele se move nesse sentido. Esse é um dos usos mais universais de vetores em jogos. Entender isso faz com que o nível do pensamento suba um tanto e fique muito mais fácil raciocinar sobre uma série de coisas.

Vamos dar um exemplo prático para mostrar o quanto ajuda ter o conceito de vetores. Quando estávamos falando sobre pontos vimos um exemplo de como movimentar nosso ponto P através dos eixos x e y somando ou subtraindo valores em suas coordenadas. Agora vamos pensar que nossa intenção não é mover nosso ponto P através do eixo x ou do eixo y separadamente. Queremos movê-lo através dos dois eixos ao mesmo tempo. Obviamente temos que mudar as duas coordenadas ao mesmo tempo.

Vamos supor que somamos um valor u à nossa coordenada x e um valor v à nossa coordenada y. Se construirmos um vetor V a partir desses dois valores, teremos um vetor que nos dá o sentido em que nosso ponto se movimentará e o quando esse ponto se movimentará nesse sentido. Isso quer dizer que, supondo que saibamos construir um vetor V com componentes u e v no sentido que quisermos e saibamos dar a ele o tamanho que quisermos, podemos movimentar nosso ponto P tantas unidades quanto quisermos no sentido apontado pelo vetor. E para isso é só somar nossas coordenada x e y do ponto P com nossas componentes u e v do vetor V respectivamente.

Operações

Agora que os dois conceitos envolvidos nesse post já devem estar mais claros, vamos começar a fazer coisas mais úteis e interessantes com eles. Pra começar vamos pegar dois pares de números A = (ax, ay) e B = (bx, by), fazer uma operação de soma componente a componente resultando em outro par de números C = (ax + bx, ay + by) e ver como os resultados podem variar conforme mudamos a interpretação de cada um.

Primeiro vamos imaginar que A e B são pontos e vamos somá-los.

Soma de dois pontos A e B. C é o resultado.

Soma de dois pontos A e B. C é o resultado.

Acima temos o resultado C interpretado como um ponto. Existe alguma relação visível e intuitiva entre A e B e o resultado C para esse caso? Bom, eu não consigo ver muita relação. Mas conforme mudamos a interpretação de A e B a interpretação do resultado muda também. Por exemplo, vamos supor agora que A representa um ponto, B representa um vetor e o resultado C é um ponto também.

Soma de um vetor B com um ponto A. C é A deslocado por B.

Soma de um vetor B com um ponto A. C é A deslocado por B.

Esse caso tem uma interpretação muito mais interessante, que por sinal é a mesma do nosso exemplo lá mais pra cima de como usar um vetor para mover nosso ponto P pelo espaço 2D. Na segunda parte da figura dá pra ver como podemos usar o fato de que vetores não têm posição para desenhá-los num lugar que fica mais intuitivo para enxergar o que está acontecendo.

Outra interpretação útil é ver A, B e C como vetores. Essa interpretação é especialmente útil quando os vetores representam forças. Quando duas forças agem sobre um objeto ao mesmo tempo a soma dos vetores de força resulta em um vetor que é equivalente às duas forças combinadas.

Soma de vetores

Soma de vetores

Como eu disse mais para cima, se soubermos construir vetores com o sentido e tamanho que quisermos fica muito mais fácil e intuitivo de mover um ponto pelo espaço 2D. Agora vamos ver algumas ferramentas que nos ajudarão a construir vetores para mover nossos objetos pela tela.

Manipulando o Tamanho do Vetor

Manipular o tamanho de um vetor é algo muito, muito fácil. Vamos supor que temos nosso vetor V = (u, v) e o tamanho dele é um número t. Agora queremos obter um vetor que aponta para o mesmo sentido mas que tem o dobro do tamanho. O que fazemos? Basta multiplicar cada uma das coordenadas u e v por 2. Se o objetivo é dividir t pela metade, basta dividir u e v por 2. Essa operação é chamada muitas vezes de multiplicação por escalar. Podemos escrever V*2 e isso quer dizer (u*2, v*2).

Tamanhos do vetor

Tamanhos do vetor

Existem momentos em que nós podemos querer saber qual o tamanho do nosso vetor V. Apesar de ser um pouquinho mais complicado de fazer do que uma multiplicação, não envolve nenhuma matemática super avançada. Além do mais, calcular o resultado final normalmente é a tarefa do computador: a sua é apenas escrever a fórmula certa no momento certo e saber interpretar o resultado da maneira certa. Extrair o tamanho de um vetor tem uma notação própria também. Normalmente escrevemos ||V|| para dizero tamanho do vetor V. A fórmula para isso é a seguinte:

Agora digamos que nosso vetor V tem um tamanho t e um sentido e nós queremos um outro vetor W com exatamente o mesmo sentido mas com um tamanho x que não tem uma relação óbvia com t. Como obtemos esse vetor? Um jeito muito fácil seria se tivéssemos um vetor N de tamanho 1 que apontasse no mesmo sentido que V. Daí bastaríamos usar a multiplicação por escalar para fazer x*N. O tamanho resultante seria ||N|| = 1 que multiplicado por x ficaria x. Mas como obtemos esse vetor N? Nós dividimos V pelo seu próprio tamanho.

Dividir um vetor pelo seu próprio tamanho é uma operação tão importante e comum que tem um nome próprio. É chamada normalização do vetor. De maneira similar, um vetor que tem um tamanho 1 é chamado de vetor normalizado ou vetor normal em alguns casos. Não foi por acaso que eu escolhi a letra N para representar o tal vetor ;-).

Uma coisa legal sobre um vetor normal é que ele representa um sentido de uma maneira mais “pura”. Para obter um vetor de qualquer tamanho naquele sentido basta multiplicar o vetor normal pelo tamanho desejado. Dentro de um jogo isso é legal porque podemos querer que um personagem se mova num dado sentido mas com uma rapidez diferente em diferentes instantes de tempo (pode ser que ele esteja caminhando em um momento e correndo em outro). Nesse caso podemos guardar sempre um vetor normalizado para sua direção e um valor correspondente à sua rapidez. Cada vez que movermos o personagem multiplicamos o vetor de direção pela rapidez e somamos à posição dele. Outra coisa legal é que podemos fazer com que ele pare de se mover apenas tornando a rapidez igual a zero.

Escolhendo o Sentido dos Vetores

Agora que já sabemos mudar o tamanho dos nossos vetores vamos começar a pensar em como criar vetores com o sentido que quisermos. Um jeito intuitivo de pensar em um sentido é pensando em um ângulo.

Sentido de um vetor a partir de um ângulo

Sentido de um vetor a partir de um ângulo

Digamos que tenhamos um determinado ângulo. Como obter um sentido a partir dele? Usamos o seno e o cosseno. Antes que você saia correndo lembrando da sua professora de matemática lhe obrigando a decorar uma tabelinha de resultados para funções trigonométricas, me deixe lembrar um pequeno detalhe: você não vai calcular um seno e um cosseno. O computador vai. Existem funções na biblioteca padrão de praticamente toda linguagem de programação, então não tema. Você vai apenas usar uma interpretação particular do resultado dessas funções.

Se pensarmos no nosso ângulo como sendo em referência ao eixo x, como mostrado na figura mais acima, é muito fácil obter as coordenadas que determinam o sentido do nosso vetor. Vamos chamar nosso ângulo de a (alpha). Se pegarmos as coordenas (cos(a), sen(a)) temos um vetor normalizado que corresponde ao ângulo que gostaríamos.

Sentido a partir de seno e cosseno

Sentido a partir de seno e cosseno

Outra forma intuitiva de pensar sobre o sentido de um vetor é pensando a partir de 2 pontos. Esse é o caso em que pensamos “eu quero um vetor que aponte do ponto A para o ponto B”. Obter esse vetor é extremamente simples. Basta subtrair as coordenadas de A das coordenadas de B de forma a obter um vetor com componentes (bx - ax, by - ay). Esse vetor aponta do ponto A para o ponto B. Além disso temos um bônus: o tamanho do vetor obtido é a distância entre os pontos A e B.

Vetor de A para B

Vetor de A para B

Um uso típico para um vetor obtido dessa forma é para fazer com que um inimigo persiga o personagem do jogo. Digamos que a posição do personagem seja um ponto chamado P e a do inimigo um ponto chamado I. O vetor P - I aponta na direção do inimigo para o jogador. Então pegamos esse vetor, normalizamos ele e depois multiplicamos pela rapidez com que queremos que nosso inimigo se aproxime do personagem. Depois basta somar o vetor resultante na posição do inimigo. A figura abaixo exemplifica essa situação:

A: P-I é o vetor que aponta de I para P, B:

Passo a passo da situação descrita acima

Vetores e Pontos na Programação

Procurando na internet é possível encontrar diversas implementações das operações descritas acima. A versão mais comum é uma classe de vetor que sobrecarrega operadores de soma, subtração, multiplicação, divisão, etc. e também tem métodos para outras operações como a normalização, por exemplo. Algumas bibliotecas diferenciam pontos de vetores na implementação, mas nem todas. Nesse caso o que fazer?

Como eu disse algumas vezes durante esse texto, a principal diferença entre pontos e vetores é conceitual, então se a biblioteca de programação que você usa apenas lhe dá uma classe de vetor e não uma de ponto, não se preocupe. Você pode usar a classe de vetor para representar pontos também, o importante é interpretar os dois valores numéricos da maneira mais conveniente para o que você estiver fazendo.

Conclusão

Minha esperança é que esse post atinja pelo menos dois tipos de pessoa: pessoas que estão iniciando na programação de jogos e ainda não chegaram a aprender esses conceitos matemáticos de uma forma mais aplicada a isso (esse era eu quando estava no Ensino Médio :-)) e pessoas que têm interesse em fazer jogos, mas não são da área técnica (conheço algumas pessoas assim também). Mais ainda, espero que as pessoas que têm medo de matemática aproveitem para perceber que não é fazer um monte de contas, as coisas tem um significado e é quando entendemos ele que tudo começa a fazer sentido. Olhando desse ponto de vista a matemática fica muito mais atraente. Deixe o trabalho duro de calcular as coisas para o computador e comece a se focar no conceito que cada fórmula representa.

Bom, chega de recomendações, fico por aqui.

[]’s

por Kao Félix em 22 de November de 2008 às 23:08

November 21, 2008

Ricardo Banffy

Fazer Jogos

Saiu a Panda 3D 1.5.4

Saiu hoje a versão 1.5.4 da biblioteca Panda 3D. Esse release é apenas um bugfix na série 1.5, sem maiores novidades.

Para quem ainda não conhece, a Panda 3D é uma engine 3D para Python bastante completa e cheia de funcionalidades. O release 1.5 trouxe recursos muito legais como a geração automática de shaders para algumas das técnicas de renderização mais comuns. Com isso é possível se beneficiar da qualidade gráfica providenciada pelas placas 3D programáveis sem precisar escrever seu próprio shader no braço. A partir da versão 1.5.3 a biblioteca de física Ode passou a fazer parte da distribuição e a Panda 3D agora incluí seus próprios bindings para ela.

Além das novidades a Panda 3D já contava com vários recursos legais:

  • Implementada em C++, mas usada através de Python
  • Fácil de usar
  • Exportadores de modelos para vários programas 3D, inclusive um para Blender
  • Classes para auxiliar na implementação da lógica do jogo (agendamento de tarefas, eventos, máquinas de estado)
  • Personagens animados
  • Outras mais

Apesar de ser uma biblioteca muito legal ela também possui seus problemas, principalmente para quem já está acostumado com o jeito que as coisas normalmente funcionam em Python. Os exemplos e tutoriais da documentação da Panda usam o módulo DirectBase que cria um monte de objetos “mágicos” no namespace global do seu programa. Além disso ela não tem uma hierarquia de módulos bem organizada e sua API ainda guarda muitas semelhanças com C++, sem tirar total proveito dos recursos da linguagem Python.

por Kao Félix em 21 de November de 2008 às 00:17

November 20, 2008

Fazer Jogos

Game Loop

Faz um tempo eu consegui autorização do Koen Witters para traduzir um excelente artigo dele sobre Game Loops. Além de traduzir o texto também traduzi os exemplos de C para Python. Vale dizer que minha tradução de código não foi muito idiomática e o código ainda parece um pouco C-like, mas isso também ajuda a não distrair do propósito da explicação e entrar em detalhes de Python.

Eu publiquei a tradução já no wiki da Python Brasil e agora estou publicando ela aqui também. Espero que ajude vocês como já me ajudou também :-)

Introdução

O “game loop” é o batimento cardíaco de todo jogo, nenhum jogo pode ser executado sem ele. Mas, infelizmente para novos programadores de jogo, não há bons artigos na Internet que fornecem a informação adequada sobre este tema. Mas não tema, porque você acabou de esbarrar no único artigo que dá ao “game loop” a atenção que merece.

Graças ao meu trabalho como programador de jogos, entrei em contato com um monte de código de pequenos jogos para dispositivos móveis. E sempre me impressiona quantos implementações de “game loop” que existem por aí. Você pode estar se perguntando como algo simples assim pode ser escrito de formas diferentes. Pois bem, pode, e eu vou discutir os prós e os contras das mais populares implementações, e dar-lhe a (na minha opinião) melhor solução de implementação de um “game loop”.

O “Game Loop”

Cada jogo consiste de uma seqüência de pegar a entrada do usuário, atualizar o estado do jogo, lidar com a IA, tocar música e efeitos sonoros, e mostrar o jogo. Esta seqüência é tratada através do “game loop”. Assim como eu disse na introdução, o “game loop” é o batimento cardíaco de cada jogo. Neste artigo, não irei entrar em detalhes sobre qualquer uma das tarefas acima mencionadas, mas que irei me concentrar no “game loop” em si. Por isso também reduzi as tarefas a apenas duas funções: Atualizar o jogo e exibi-lo.

Eis alguns exemplos código do “game loop” em sua forma mais simples:

jogo_rodando = True
 
while jogo_rodando:
    atualizar_jogo()
    desenhar_jogo()

O problema com este “loop” simples é que ele não controla o tempo, o jogo só é executado. Em um hardware mais lento o jogo vai rodar mais devagar e mais rápido com hardware mais rápido. De volta aos velhos tempos, quando a velocidade do hardware era conhecida, isso não era um problema, mas atualmente existem tantas plataformas de hardware por aí, que temos que implementar algum tipo de gerenciamento de tempo. Há muitas maneiras de fazer isso, e eu vou discuti-las nas seções seguintes.

Em primeiro lugar, deixe-me explicar 2 termos que são usados em todo este artigo:

FPS

FPS é uma abreviatura de frames por segundo. No contexto da execução acima referido, é o número de vezes desenhar_jogo() é chamada por segundo.

Velocidade de Jogo

Velocidade de Jogo é o número de vezes que o estado do jogo é atualizado por segundo, ou, em outras palavras, o número de vezes que atualizar_jogo() é chamada por segundo.

FPS dependente de Velocidade de Jogo Constante

Implementação

Uma solução fácil para a questão do tempo é apenas deixar o jogo correr em uma velocidade fixa de 25 frames por segundo. O código então tem esta aparência:

import time
import pygame
 
FRAMES_PER_SECOND = 25
SKIP_TICKS = 1000 / FRAMES_PER_SECOND
 
pygame.init()
next_game_tick = pygame.time.get_ticks()
# pygame.time.get_ticks() retorna o número atual de milisegundos
# decorridos desde que o sistema foi iniciado
 
sleep_time = 0
game_is_running = True
 
while game_is_running:
    atualizar_jogo()
    desenhar_jogo()
 
    next_game_tick + = SKIP_TICKS
    sleep_time = next_game_tick - pygame.time.get_ticks()
    if sleep_time >= 0:
        time.sleep(sleep_time)
    senão:
        # Droga, estamos ficando para trás!

Esta solução tem uma enorme vantagem: é simples! Uma vez que você sabe que atualizar_jogo() é chamada 25 vezes por segundo, escrever o código do seu jogo é bastante simples. Por exemplo, a implementação de uma função de “replay” neste tipo de “game loop” é fácil. Se valores aleatórios não forem utilizados no jogo, você pode apenas registrar a entrada do usuário e repicá-la posteriormente.

No seu hardware de teste você pode adaptar FRAMES_PER_SECOND a um valor ideal, mas o que irá acontecer em um hardware que for mais rápido ou mais lento? Bem, vamos descobrir.

Hardware Lento

Se o hardware agüenta o FPS definido, não há problema. Mas os problemas vão começar quando o hardware não puder lidar com ele. O jogo vai rodar mais devagar. No pior dos casos o jogo tem algumas partes mais pesadas onde ele vai rodar muito lenta e outras onde ele vai rodar normal. O tempo se torna variável, o que pode fazer seu jogo ficar injogável.

Hadware rápido

O jogo não terá problemas com hardware rápido, mas você está desperdiçando muitos ciclos de “clock” preciosos. Rodar um jogo em 25 ou 30 FPS quando ele poderia facilmente rodar a 300 FPS… que vergonha! Você vai perder uma grande quantidade de apelo visual nessa situação, especialmente com objetos que se movimentam rapidamente.

Por outro lado, com dispositivos móveis, isso pode ser visto como uma vantagem. Não deixando o jogo rodar constantemente em seu extremo poderia poupar algum tempo de bateria.

Conclusão

Tornar o FPS dependente de uma velocidade de jogo constante é uma solução que é implementada rapidamente e mantém o código do jogo simples. Mas existem alguns problemas: Definir um FPS alto vai causar problemas com hardware mais lento, e definição de um FPS baixo irá desperdiçar apelo visual em hardware rápido.

Velocidade de Jogo dependente de FPS Variável

Implementação

Outra forma de implementar um “game loop” é deixá-lo correr o mais rápido possível, e deixar o FPS ditar a velocidade do jogo. O jogo é atualizado com a diferença de tempo do quadro anterior.

# imports e incialização omitidos
 
prev_frame_tick
curr_frame_tick = pygame.time.get_ticks()
 
game_is_running = True
while game_is_running:
    prev_frame_tick = curr_frame_tick
    curr_frame_tick = pygame.time.get_ticks()
 
    atualizar_jogo(curr_frame_tick - prev_frame_tick)
    desenhar_jogo()

O código do jogo torna-se um pouco mais complicado, pois temos agora que considerar a diferença de tempo na função atualizar_jogo(). Mas ainda assim, não é tão difícil.

À primeira vista, esta parece a solução ideal para o nosso problema. Eu tenho visto muitos programadores espertos implementar este tipo de “game loop”. Alguns deles teriam provavelmente desejariam ter lido este artigo antes de implementar o seu “loop”. Vou mostrar-lhe em um minuto que este “loop” pode ter sérios problemas em hardware lento e também em hardware rápido (sim, RÁPIDO!).

Hardware Lento

Hardware lento pode causar alguns atrasos, às vezes, em alguns pontos onde o jogo fica “pesado”. Isto pode definitivamente acontecer com um jogo 3D onde, em um determinado período de tempo, polígonos demais são exibidos. Esta queda na taxa de frames irá afetar o tempo de resposta da entrada e, por conseguinte, o tempo de reação do jogador também. A atualização do jogo também irá sentir o atraso e o estado do jogo será atualizado em grandes fatias de tempo. Como resultado o tempo de reação do jogador, e também o da IA, vai ficar mais devagar e pode fazer uma simples manobra falhar, ou até mesmo ficar impossível. Por exemplo, um obstáculo que poderia ser evitado com um FPS normal, pode se tornar impossível de evitar com um FPS baixo. Um problema mais grave com o hardware lento é que quando se utiliza física, sua simulação pode até mesmo [http://www.gaffer.org/game-physics/fix-your-timestep explodir]!

Hardware Rápido

Você provavelmente está se perguntando como o “game loop” acima pode dar errado em hardware rápido. Infelizmente pode e para lhe mostrar como, deixe-me primeiro explicar algumas coisas sobre como funciona a matemática em computadores.

O espaço de memória de um valor float ou double é limitado, então alguns valores não podem ser representados. Por exemplo, 0.1 não pode ser representado em binário e, por conseguinte, é arredondado quando armazenados em um double. Permita mostrar-lhe utilizando um shell interativo de python:

>>> 0.1
0.10000000000000001

Isso por si só não é dramático, mas as consequências são. Digamos que você tem um carro de corrida que tem uma velocidade de 0.001 unidades por milisegundo. Após 10 segundos o seu carro de corrida terá viajado uma distância de 10.0. Se você dividir este cálculo como um jogo iria fazer, você tem as seguintes funções utilizando frames por segundo como entrada:

>>> def get_distance( fps ):
...     skip_ticks = 1000 / fps
...     total_ticks = 0
...     distance = 0.0
...     speed_per_tick = 0.001
...     while total_ticks < 10000:
...         distance += speed_per_tick * skip_ticks
...         total_ticks += skip_ticks
...     return distance

Agora podemos calcular a distância em 40 frames por segundo:

>>> get_distance(40)
10,000000000000075

Espere um pouco… não é 10.0??? O que aconteceu? Pois bem, porque dividimos o cálculo em 400 adições, o erro de arredondamento cresceu. Fico pensando o que irá acontecer a 100 quadros por segundo …

>>> get_distance(100)
9,9999999999998312

O que??? O erro é ainda maior!! Pois bem, por termos mais adições em 100 fps, o erro de arredondamento tem mais chances de aumentar. Portanto, o jogo será diferente quando rodando em 40 ou 100 frames por segundo:

>>> get_distance(40) - get_distance(100)
2.4336088699783431e-13

Você pode pensar que essa diferença é pequena demais para ser vista no jogo em si. Mas o problema real vai começar quando você usar esse valor incorreto para fazer mais alguns cálculos. Dessa forma um pequeno erro pode tornar-se grande, e ferrar o seu jogo quando ele rodar em altas taxas de frame. As chances disso acontecer? Suficientemente grandes para considerá-lo! Eu vi um jogo que utilizou este tipo de “game loop”, e que de fato deu problemas em taxas de frame altas. Quando o programador descobriu que o problema estava escondido no núcleo do jogo, apenas um monte de reescrita de código poderia corrigi-lo.

Conclusão

Este tipo de “game loop” pode parecer à primeira vista muito bom, mas não se deixe enganar. Tanto máquinas lentas quanto máquinas rápidas podem causar problemas sérios para o seu jogo. E, além disso, implementar a função de atualização do jogo mais difícil do que quando você usa um FPS fixo, então porque que usá-lo?

Velocidade de Jogo Constante com FPS Máximo

Implementação

A nossa primeira solução, FPS dependente de Velocidade de Jogo Constante, tem um problema quando roda em hardware lento. Tanto a velocidade do jogo quanto o framerate irá cair nesse caso. Uma possível solução para esse problema poderia ser a de manter a atualização do jogo na mesma taxa, mas reduzir o framerate da renderização. Isto pode ser feito usando o seguinte “game loop”:

# imports e incialização omitidos
 
TICKS_PER_SECOND = 50
SKIP_TICKS = 1000 / TICKS_PER_SECOND
MAX_FRAMESKIP = 10
 
next_game_tick = pygame.time.get_ticks()
 
game_is_running = True
while game_is_running:
    loops = 0
    while pygame.time.get_ticks() > next_game_tick \
            and loops < MAX_FRAMESKIP:
        atualizar_jogo()
 
        next_game_tick + = SKIP_TICKS
        loops += 1
 
    desenhar_jogo ()

O jogo vai ser actualizado exatas 50 vezes por segundo e a renderização é feita o mais rápido possível. Repare que, quando a renderização é feita mais de 50 vezes por segundo, alguns quadros subsequentes serão iguais, então frames visuais de verdade serão exibidos num máximo de 50 frames por segundo. Ao rodar em um hardware lento, o framerate pode cair até que o laço de atualização alcance MAX_FRAMESKIP. Na prática, isso significa que quando o nosso FPS cai abaixo de 5 (= FRAMES_PER_SECOND / MAX_FRAMESKIP), o jogo em si vai ficar mais lento.

Hardware Lento

Em hardware lento o FPS irá cair, mas o jogo em si se espera que vá rodar na velocidade normal. Se ainda assim o hardware não conseguir lidar com isso, o jogo em si irá correr mais lento e o framerate não vai ser suave de maneira alguma.

Hardware Rápido

O jogo não terá problemas com hardware rápido, mas, tal como a primeira solução, você vai desperdiçar tantos ciclos de clock preciosos que poderiam ser usados para um framerate maior. Encontrar o equilíbrio entre uma taxa de atualização rápida e capaz de rodar em hardware lento é crucial.

Conclusão

Utilizando uma velocidade de jogo constante com FPS Máximo é uma solução que é fácil de implementar e mantém o código do jogo simples. Mas ainda existem alguns problemas: Definir um FPS alto ainda pode causar problemas com hardware lento (mas não tão graves como na primeira solução), e a definição de um FPS baixo irá desperdiçar apelo visual em hardware rápido.

Velocidade de Jogo Constante independente do FPS Variável

Implementação

Seria possível melhorar ainda mais a solução acima para rodar mais rápido em hardware lento, e ser visualmente mais atrativa em hardware mais rápido? Bom, felizmente para nós, isso é possível. O estado do jogo em si próprio não precisa ser atualizado 60 vezes por segundo. A entrada do jogador, a IA, e a atualização do estado do jogo têm o bastante com 25 quadros por segundo. Portanto, vamos tentar chamar atualizar_jogo() 25 vezes por segundo, nem mais, nem menos. A renderização, por outro lado, precisa ser tão rápida quanto o hardware conseguir fazer. Mas um framerate baixo não deve interferir com a atualização do jogo. A maneira de conseguir isso é através da utilização do seguinte “game loop”:

# imports e incialização omitidos
 
TICKS_PER_SECOND = 25
SKIP_TICKS = 1000 / TICKS_PER_SECOND
MAX_FRAMESKIP = 5
 
next_game_tick = pygame.time.get_ticks()
 
game_is_running = True
while game_is_running:
 
    loops = 0
    while pygame.time.get_ticks() > next_game_tick and \
               loops < MAX_FRAMESKIP:
        atualizar_jogo ()
 
        next_game_tick += SKIP_TICKS
        loops += 1
 
    interpolacao = float(pygame.time.get_ticks() +
               SKIP_TICKS - next_game_tick) / float (SKIP_TICKS)
 
    desenhar_jogo(interpolacao)

Com este tipo de “game loop”, a execução do atualizar_jogo() irá permanecer fácil. Mas, infelizmente, a função desenhar_jogo() ficará mais complexa. Você terá que executar uma função preditiva que recebe a interpolação como argumento. Mas não se preocupe, isso não é difícil, apenas exige um pouco mais de trabalho. Vou explicar abaixo como a interpolação e a predição funcionam, mas primeiro deixe-me mostrar por que elas são necessárias.

A Necessidade de Interpolação

O gamestate é atualizado 25 vezes por segundo, por isso, se você não usar interpolação em sua renderização, seus quadros também serão exibidos nesta velocidade. Observe que 25 fps não é tão lento quanto algumas pessoas pensam: filmes rodam a 24 quadros por segundo, por exemplo. Então, 25 fps devem ser suficientes para uma experiência visualmente agradável, mas para objetos que se movem rápido, podemos ainda ver uma melhoria ao fazer mais FPS. Então o que podemos fazer é tornar movimentos mais rápidos suaves entre os frames. E é aí que interpolação e uma função preditiva podem fornecer uma solução.

Interpolação e Previsão

Tal como eu já disse o código do jogo é roda na sua própria taxa de frames por segundo, de modo que quando você desenhar/renderizar seus frames, é possível que ele esteja no meio de 2 gameticks. Digamos que você acabou de atualizar o seu estado de jogo pela 10ª vez, e agora você está indo renderizar a cena. Esta renderização estará entre a 10ª e a 11ª atualização do jogo. Portanto, é possível que a renderização aconteça próxima do frame 10.3. O valor de “interpolacao” então é 0.3. Pegue esse exemplo: Eu tenho um carro que se move a cada ciclo do jogo desta forma:

  posicao = posição + velocidade

Se, no 10º ciclo a posição é de 500 e a velocidade é de 100, então no 11º ciclo a posição será 600. Agora onde você irá colocar o seu carro quando você redenrizá-lo? Você só poderia apenas assumir a posição do último ciclo (neste caso, 500). Mas uma maneira melhor é predizer aonde o carro estaria em exatamente 10.3, e isso é feito desta forma:

posicao_desenho = posicao + (velocidade * interpolacao)

O carro, então, será deenhado na posição 530.

Assim, basicamente a variável interpolacao contém o valor que está entreentre o ciclo anterior e o próximo (anterior = 0,0, próximo = 1,0). O que você tem que fazer então, é criar uma função “preditiva” para prever onde o carro/câmera/etc seriam colocados na hora de renderizar. Você pode basear essa previsão na velocidade do objeto, direção ou velocidade de rotação. Ela não precisa ser complicada porque nós só usamos ela para suavizar as coisas entre frames. De fato, é possível que um objeto acabe sendo renderizado em cima de outro objeto logo antes de uma colisão ser detectada. Mas, como já vimos antes, o jogo é atualizado 25 frames por segundo, e assim, quando isso acontece, o erro é mostrado apenas por uma fração de segundo, dificilmente perceptível ao olho humano.

Hardware Lento

Na maioria dos casos, atualizar_jogo() vai levar muito menos tempo do que desenhar_jogo(). Na verdade, podemos supor que, mesmo com a com hardware lento, a função atualizar_jogo() consegue rodar 25 vezes por segundo. Portanto, nosso jogo vai lidar com a entrada entrada do jogadore atualizar o estado do jogo sem grandes dificuldades, mesmo que o jogo vá ser exibido apenas 15 quadros por segundo.

Hardware Rápido

Em hardware rápido, o jogo ainda será executado em um ritmo constante de 25 vezes por segundo, mas a atualização da tela será bem mais rápida do que isso. O método da interpolação/predição vai criar um apelo visual como se o jogo realmente estivesse rodando a uma taxa de frame alta. O melhor é que você faz um tipo de “trapaça” com seu FPS. Como você não atualizar o seu estado de jogo a cada frame, apenas a visualização, o jogo irá ter um FPS maior do que com o segundo método que eu descrevi.

Conclusão

Fazer o estado do jogo ser independente do FPS parece ser a melhor implementação para um “game loop”. No entanto, você terá que implementar uma função preditiva em desenhar_jogo(), mas isso não é difícil de fazer.

Conclusão geral

Tem mais em um “game loop” do que você imagina. Comentamos 4 possíveis implementações, e parece que há uma delas que você deve definitivamente evitar e é o caso onde um FPS variável dita a velocidade do jogo.

Um framerate constante pode ser uma boa solução simples para dispositivos móveis, mas quando você quiser aproveitar tudo que o hardware pode oferecer, é melhor usar um game loop onde o FPS é completamente independente da velocidade do jogo, utilizando uma função preditiva para framerates altos.

Se você não quiser se preocupar com uma função preditiva, você pode trabalhar com um framerate máximo, mas encontrar a melhor taxa de atualização do jogo para hardware lento e rápido pode ser complicado.

Agora comece a programar aquele jogo fantástico em que você está pensando!

Koen Witters

por Kao Félix em 20 de November de 2008 às 19:07

Leandro Severino

Curso de ORM (Object Relational Mappers) - Capitulo 01

Antes de começarmos a colocar a mão na massa e criar nossos códigos em Python, precisamos entender o conceito de ORM - Object Relational Mappers, ou Mapeamento Objeto-Relacional.

Segue a definição da Wikipedia:

Fonte: http://pt.wikipedia.org/wiki/Mapeamento_objeto-relacional


Mapeamento objecto-relacional (ou ORM) é uma técnica de desenvolvimento utilizada para reduzir a impedância da programação orientada aos objetos utilizando bancos de dados relacionais. As tabelas do banco de dados são representadas através de classes e os registos de cada tabela são representados como instâncias das classes correspondentes.

Com esta técnica, o programador não precisa de se preocupar com os comandos em linguagem SQL; irá usar uma interface de programação simples que faz todo o trabalho de persistência.

Não é necessária uma correspondência direta entre as tabelas de dados e as classes do programa. A relação entre as tabelas onde originam os dados e o objecto que os disponibiliza é configurada pelo programador, isolando o código do programa das alterações à organização dos dados nas tabelas do banco de dados.

A forma como este mapeamento é configurado depende da ferramenta que estamos a usar. Como exemplo, o programador que use Hibernate na linguagem Java pode usar ficheiros XML ou o sistema de anotações que a linguagem providencia.

No nosso caso, usaremos as excelentes ferramentas(frameworks) para Python: SQLObject, SQLAlchemy e o Storm.

De forma bem prática e objetiva teremos em ambos os frameworks o seguinte cenário:

- Precisamos que cada tabela seja tratada como uma classe e cada registro/linha da tabela seja tratado como uma instância.

Então o trabalho “sujo” que estes poderosos frameworks fazem é abstrair toda essa complexidade para nós: de transformar os registros de nossas tabelas em instâncias de classes previamente definidas através de um mapeamento pré-estabelecido, gerênciando a conexão com o banco de dados e nos fornecendo recursos preciosos como vamos conhecer nos próximos capitulos deste curso.

Ob: Uma informação importante para quem está chegando agora: Para seguir este curso tudo que você precisa é ter o Python instalado e um editor de textos, pois abordaremos passo-à-passo a instalação dos respectivos frameworks de ORM,

Na semana que vem: O poder do SQLObject !, então, até a próxima semana.

por Leandro em 20 de November de 2008 às 12:44

Kodumaro

Base64

De vez enquando, não tem como não, nós programadores sempre esbarramos na Base64.

Base64 é um protocolo de codificação que usa apenas seis bits, o que significa um conjunto de sessenta e quatro (64) elementos – daí Base64.

A conversão de oito (byte) para seis bits é feita da seguinte forma:
xxxxxx.xx xxxx.xxxx xx.xxxxxx


Ou ainda:
aaaaaabb bbbbcccc ccdddddd


Os elementos usados são caracteres simples, começando com as letras maiúsculas, A (0) a Z (25), então as letras minúsculas, a (26) a z (51), os números, 0 (52) a 9 (61), e os caracteres + (62) e / (63).

Na conversão de bytes (8b) para Base64 (6b), cada três bytes é convertido em quatro dígitos, então um código Base64 é sempre pensado em grupos de quatro. Se o tamanho de um código Base64 não for múltiplo de quatro, caracteres = são acrescentados ao final até que o tamanho seja múltiplo de quatro.

Python


Em Python, Base64 é tão simples que nem tem graça:
>>> print "Kodumaro".encode("base64")
S29kdW1hcm8=
>>> print "S29kdW1hcm8=".decode("base64")
Kodumaro


Lua


Em Lua, é preciso baixar o módulo Mime do LuaSocket:
> require "mime"
> print(mime.b64 "Kodumaro")
S29kdW1hcm8=
> print(mime.unb64 "S29kdW1hcm8=")
Kodumaro


Smalltalk


Sendo muito sincero sobre o assunto, não sei como fazer conversão de Base64 em Smalltalk. =(

Mas sei que os módulos do Seaside providenciam isso!

Se alguém souber, por favor informe!

C


Aha! Aqui começa de verdade a brincadeira!

É claro que você pode usar as funcionalidades de Base64 da gLibC, mas descobri que nem todas as versões dela apresentam tais funcionalidades:
#include <glib/gbase64.h>


Vamos precisar usar os cabeçalhos stdlib.h, string.h e sys/types.h. Como também vamos criar um cabeçalho para «compartilhar» algumas funções, ele também será incluído no início de nosso arquivo base64.c:
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include "base64.h"


Agora vamos criar um array com todos os possíveis caracteres Base64 em sua ordem natural:
static const char b64all[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef"
"ghijklmnopqrstuvwxyz0123456789+/";


Também vamos precisar de três funções locais: uma para obter o índice de um elemento (_getindex), outra para codificar para Base64 um grupo de três bytes (_encode) e mais uma para decodificar um grupo de quatro elementos Base64 (_decode):
int _decode(u_int8_t *, const u_int8_t *);
void _encode(u_int8_t *, const u_int8_t *, int);


Não é preciso uma função para _getindex:
#define _getindex(c) (int) (index(b64all, c) - b64all)


Repara que, em vez de char, estamos usando u_int8_t, que é mais conveniente quando queremos lidar com bytes enquanto bytes, não caracteres.

A partir daqui, se preferir, organize as funções em ordem alfabética – ou na ordem que quiser.

A primeira função que implementaremos será para codificar uma string C (const char *) para Base64. Como a string pode não ser bem formada, a função deverá receber também seu tamanho:
const char *b64encode(const char *original, int length) {
// Se o tamanho não for informado, consideramos uma string bem
// formada
if (length == 0)
length = strlen(original);

// Inteiro com o tamanho do código a ser gerado
int b64length = ((length + 2) / 3) * 4;

// Contadores para percorrer as strings
int i=0, j=0;

// Alocando memória para o código
char *b64 = (char *) malloc(sizeof(char) * (b64length + 1));
memset(b64, 0, b64length + 1);

while (i < length) {
// Codifica um grupo de três bytes...
_encode(
(u_int8_t *) b64 + j,
(const u_int8_t *) original + i,
(length - i)
);

// E segue para o próximo grupo
i += 3;
j += 4;
}

// Retorna o código
return (const char *) b64;
}


A próxima função deve fazer o contrário, converter um código Base64 para uma string. Como a string resultante pode não ser bem formada – pode não ser terminada em carácter nulo ou possuir caracteres nulos no meio –, é preciso uma forma de informar seu tamanho, então ela receberá um ponteiro para um inteiro:
const char *b64decode(const char *b64, int *length) {
// Inteiro com o tamanho do código
int b64length = strlen(b64);

// Se não for múltiplo de quatro, há algo errado
if (b64length % 4 != 0)
return NULL;

// Tamanho máximo da string decifrada
int prob = (b64length / 4) * 3;

// Contadores para percorrer as strings
int i=0, j=0;

// Alocando memória para o resultado
char *s = (char *) malloc(sizeof(char) * (prob + 1));

while (j < b64length) {
// Decifra um grupo de quatro elementos
// e conta o resultado
i += _decode(
(u_int8_t *) s + i,
(const u_int8_t *) b64 + j
)