Fluxograma de estratégiaDurante o desenvolvimento do LikeFriends, fui fortemente coagido a desenvolver um passatempo pela beta-tester, que, incidentalmente, é também minha esposa. A escolha recaiu sobre o jogo do galo, e o código foi colocado no GitHub. Este post é uma tradução do README que acompanha o meu repositório TicTacToeJS, no GitHub.

Existem três maneiras de fazer uma AI de jogo imbatível:

  1. Processar cada jogada possível adiantadamente e jogar pela linha de maior sucesso a cada passo – isto é um método de força bruta;
  2. Implementar uma rede neuronal – isto vai começar bastante palerma, mas depois de alguns milhares de jogos deverá ser imbatível;
  3. Implementar uma solução heurística, fazendo-a jogar como um especialista humano.

O jogo do galo é um fortíssimo candidato a uma solução de força bruta: o número total de jogadas é de apenas 9!, ou 362.880; de facto, seriam muito menos, visto que a maioria das jogadas poderia ser obtida por rotação do tabuleiro de jogo. No entanto, não existe grande "I" nesta AI...

A solução por rede neuronal é bastante divertida, e é usada frequentemente em cenários complexos, desde que alguém tenha o tempo (ou os jogos automatizados) para treinar a rede. Aparte o código da rede neuronal em si (que poderia ser usada para paletes de outros problemas), esta solução seria a mais pequena ao nível do código.

A solução heurística é a mais difícil de implementar para a maioria dos jogos. Implica criar um conjunto de regras a seguir, para cada situação possível, da forma mais compacta possível. De novo, o jogo do galo é propício a este tipo de solução, porquanto apenas três jogadas, no máximo, podem ser problemáticas; a quarta e a eventual quinta jogada são feitas para ganhar ou para empatar.

Esta foi a solução que implementei.

LikeFriendsLancei (finalmente) esta semana o LikeFriends, o meu pequeno projecto de Verão. É um brinquedo social, engraçado como conceito, que apresenta dois rankings baseados nos likes e amigos do Facebook, um de amigos, outro de likes.

Eu podia dar motivações perfeitamente válidas como uma melhoria do ranking de amigos que o próprio Facebook faz (e mesmo esse está absurdamente escondido aqui, à direita – para se chegar lá, é preciso ir aos nossos likes e depois clicar em Sugestões, no topo) ou até como negócio; mas não: só encontrei o ranking (errado) do Facebook quando estava na fase de investigação deste projecto e o site do projecto não está, nem vai estar, monetizado.

Na verdade, fi-lo porque podia. Só isso. Há muito que queria experimentar umas coisas com métricas sociais, mas que fosse algo útil; ao mesmo tempo, andava a brincar com a API do Facebook e resolvi juntar as duas coisas. Ora, a única coisa que contém um espaço métrico no Facebook é a relação entre os likes e os utilizadores.

Afinal, que raio de ranking é aquele?

Versão TL;DR

Um ranking feito unicamente a partir dos likes que dois utilizadores partilham não é preciso.

Se eu tenho 50 likes e tenho 10 em comum com dois dos meus amigos, qual deles é o mais parecido comigo, o que tem 100 likes ou o que têm 500? Com um amigo que tem uma quantidade enorme de likes até seria de estranhar se não tivesse alguns em comum; por outro lado, se outro amigo tem tão poucos likes e mesmo assim tem alguns em comum comigo, quer dizer que, efectivamente, temos gostos muito mais semelhantes.

Aviso: a próxima secção inclui matemática!

Hoje em dia há hipsters para todos os gostos: há os culturais (cinema independente, fotografia lomo e tilt-shifting), há os tecnológicos e há os dos costumes (movimentos LGBT, vegetarianismo, ambientalistas).

Mas como distinguir o hipster dos não-hipsters? Os que adoptam o perfil clássico do hipster (se um hipster é clássico, ainda é hipster?) são fáceis: os óculos com armações de massa, a roupa estilo vintage, a atitude geral de laissez-faire, laissez-passer, excepto no tocante à sua causa. Os outros, são mais difíceis, e é preciso discutir com eles para o descobrir – nesse caso, já é tarde demais.

O hipster é um supra defensor da sua causa, que não admite ser comparado com os defensores normais. Não vale de nada eu ter amigos gay desde muito novo, e até me ter "atravessado", socialmente e não só, por um ou outro ao longo dos anos: se não vou ao Pride, sou um homofóbico como os outros; não vale de nada eu gastar muito mais na manutenção do meu carro por o ter escolhido por ter filtro de partículas: se não tenho um Prius, sou um assassino da natureza; não vale de nada eu ter um computador em casa com 8 núcleos e 12 GB de RAM: se não é um Apple, sou um info-excluído. Não vale de nada a entrada do meu apartamento parecer uma sucursal da Arca de Noé (agora já não, que os hamsters e os peixes foram-se – resta a tartaruga): se não tenho três gatos e dois cães (todos resgatados, claro), não tenho nenhum respeito pelos animais.

Hipster Conundrum
Hipster Conundrum @ DogHouseDiaries - Creative Commons BY-NC

Depois de alguns anos a ter tido o desprazer de entrar em discussões com estes hipsters camuflados, aqui ficam três dicas a usar assim que se apercebam que estão a (tentar) discutir com um:

Em casa, sozinho com as duas filhas, a mais velha de 7 anos, a mais nova de 10 meses. A esposa tem uma reunião até às tantas da noite. Depois de dar a sopa à mais nova e de mandar a mais velha tomar banho antes de jantarmos, sentei-me no sofá, com um olho no José Gomes Ferreira a zurzir nas PPP como se não houvesse amanhã, outro no parque, onde a mais nova balbuciava e batia com os peluches.

É nesta altura que a mais velha, tentando tirar partido da minha atenção já dividida, vem lançar a sua negociação.

— Sabes, pai, no Sábado vai haver um piquenique no parque... tem cavalos onde podemos andar, e barcos...

— Hmmm...

("...isto foi de tal maneira um conluio, que levou a que se favorecessem estes interesses todos...", dizia Gomes Ferreira).

— Podemos ir? – incentivada pela minha aparente distracção, faz a pergunta de chofre, pode ser que eu responda afirmativamente, só para abreviar a discussão.

— Tenho que falar com a mãe.

— Mas tu deixas?

— Sabes que eu e a mãe tomamos essas decisões em conjunto; depois dizemos-te.

— Mas se fosses tu a decidir, deixávas? – afinal, não tinha sido tão simples como parecia à primeira vista.

— Nunca seria eu a decidir uma coisa dessas sozinho, filha.

("...e a Procuradoria já vem tarde, porque já todos percebemos, há muito tempo...")

— E se a mãe não estivesse cá? Se tivesse ido para o Codebits, por exemplo... – e ri-se, nervosamente. A única pessoa que desaparece de casa sou eu, uma vez por ano, precisamente para ir ao Codebits. Eu estava a ver onde ela queria chegar: "afinal, quando não estás cá, a mãe tem de tomar as decisões sem ti". Falha: isso não é minimamente verdade.

— A mãe não me telefona, se tiver algum problema, quando não estou cá? Não falamos no Skype à noite, todos os dias que eu estou lá em baixo? Se fosse preciso tomar uma decisão a correr, que não é, eu também telefonava à mãe. – a mais nova agarra no sapato e interroga-se "ai é?", que é maneira dela perguntar "o que é?", e presta-se a responder com afinco, "atato", franze o sobrolho, "tapato", ainda não é isto, "tatato"; desiste e grita "ah ah ah ah ah", enquanto bate com as mãos nas pernas. Está-se a tornar difícil seguir os raciocínios de tanta gente e manter o meu coerente.

("...chama-se enriquecimento ilícito, que os nossos políticos não quiseram legislar.")

Sente-se encurralada, e tenta a última cartada: o cenário impiedosamente lógico, plausível e tétrico.

— Então imagina que a mãe não existia; tinhas mesmo que decidir: íamos?

Não digo nada por momentos. Um, dois, três, a maximizar o desconforto dela. A mais nova, sentindo a tensão, cala-se e olha para mim: tem um olhar misto, meio receoso, meio vitorioso, como quem sabe que vem aí uma resposta que tem tanto de sarcástico como de contundente, que vai arrumar a discussão, e que não é ela que está na berlinda. Até Gomes Ferreira faz uma pausa dramática, como se, lá em Lisboa, sentisse que precisava de ajudar este pai, cá em cima, em Vila Real.

— Se a mãe não existisse, tu estavas no colégio interno, e esta discussão nem sequer se colocava. – digo-o muito claramente, quase soletrando as palavras, com uma cara de pau inabalável. Fito-a durante um segundo, e volto a prestar atenção à televisão.

("Isto é dum cinismo e duma frieza atroz.")

A minha filha mais velha passa por várias emoções em menos de um segundo. Pelo canto do olho, vejo-a passar da confusão à incredulidade, depois ao receio, de seguida à sobranceria de quem sabe que isso seria impossível e finalmente ao desalento, ao aperceber-se que, por improvável que fosse esse o cenário, é hipotéticamente tão provável como o cenário colocado por ela. A discussão tinha acabado, e ela sabia que tinha perdido.

— Quando a mãe chegar, não te esqueças de discutir o assunto com ela, está bem?

Criança sensata.

— Não me esqueço, não te preocupes. E se fôssemos jantar?

Comentários Nenhum comentário Continuar a ler Continuar a ler »

SASSPara finalizar esta série sobre o mjamado.com, falta falar sobre o que é, para mim, a tecnologia mais útil que aprendi no último ano: SASS, um superset da linguagem CSS, juntamente com Compass, uma biblioteca de mixins para usar com SASS (mixins é o termo convencionado para referir o que não são mais que pequenas funções).

Não vou alongar-me sobre todas as vantagens do SASS (estão aí os links, é dar uma voltinha), mas vou focar quatro pontos que me são caros.

Antes de mais nada, um pedido de desculpas às 10 pessoas que visitaram o mjamado.com com o Internet Explorer 8 até sexta-feira: como estou a usar as novas tags semânticas do HTML5, devem ter ficado a olhar para um grande espaço de... nada. Acontece que os IE abaixo do 9 não reconhecem as novas tags e, pior do que isso, não lhe dão sequer um estilo básico (podiam definir todas as tags desconhecidas como block, por exemplo); para adicionar insulto à injúria, definir um estilo na CSS também não chega, porque as tags nem são inseridas na DOM.

Quando publiquei esqueci-me desse problema, mas já está controlado, através do HTML5 Shiv (um excelente pedaço de história sobre a evolução desta solução pode ser encontrada aqui).

Com isso fora do caminho, existiam dois grandes problemas, que eu tinha debaixo de olho desde o início.

O primeiro era relacionado com as CSS Transitions, das quais já falei aqui. Desde o início do projecto que assumi a opção da degradação graciosa, que o transforma num não-problema. Quem usa o IE não vê a transição entre os dois estados, mas não perde nenhuma de experiência intrínseca, tendo acesso a ambos; só que a transição é abrupta. Como já disse nesse post, é relativamente fácil forçar o comportamente consistente com meia dúzia de linhas JS, mas não compensa o esforço; sobretudo, à luz do lançamento próximo do IE10.

O outro era muito mais bicudo e está relacionado com a conjugação de gradientes CSS e cantos redondos. Aliás, nem sequer é a primeira vez que os cantos redondos me vêm morder no rabo. Desde essa altura, o IE9 passou a suportar cantos redondos e até o Chrome, culpado por esse post, melhorou bastante o cálculo do corte do background.

Apesar de não suportar gradientes CSS, o IE (para aí desde o 6) suporta gradientes lineares definidos através de filtros DirectX. É uma questão de incluir esses filtros, e o IE, não reconhecendo a sintaxe CSS3 dos gradientes, irá usá-los. Porreiro, certo? O problema é quando se atiram os cantos redondos para cima.

Continuando com coisas-que-ainda-não-tinha-experimentado-a-sério, usei no mjamado.com duas web fonts do directório da Google (Cantata One para os títulos e Imprima para corpo). Já tinha usado uma ou outra nalguns projectos comerciais (e por "usado" entenda-se que a empresa tinha usado – o design não é exactamente a minha praia), mas queria ver "ao perto" o que se podia fazer com isto.

O processo é trivial e croquetes, mais ainda se aceitarmos os métodos mais simples que a própria Google recomenda. Só embati numa pequena irritação, que ainda por cima não tem solução – ironicamente, afecta outro produto da Google, o Chrome, mas apenas em Windows.

O problema é este:

Ao construir o mjamado.com, evitei ao máximo usar animações por Javascript, preferindo usar CSS Transitions. O motivo óbvio é o desempenho: uma animação ser controlada pelo renderer interno dos browsers será sempre mais rápida e leve do que pelo motor de JS.

Um motivo menos claro é a separação de responsabilidades: cabe ao HTML mostrar os dados, ao JS controlar as acções sobre esses dados (acções apresentacionais - qualquer acção que altere os dados deve ser server side) e às CSS controlar como são apresentados os dados. Uma transição entre visualizações de dados é, claramente, uma responsabilidade apresentacional – logo, uma responsabilidade de CSS.

As CSS Transitions são novinhas em folha; pertencem à especificação CSS3, ainda estão em estado de working draft na W3C, mas o suporte já é sólido: segundo o caniuse.com, e corroborado pelos meus testes, apenas o Opera Mini, usado nalguns telemóveis menos potentes, e o (sem surpresa) Internet Explorer (até à versão actual, a 9) não as suportam. Todos os outros browsers tem suporte, pelo menos, há 5 gerações.

As transições funcionam de um estilo para outro, seja como for que esse estilo varie (por estados, mudança de classe ou id, directo ou indirecto), e podem animar qualquer valor passível de ser interpretado como numérico – cores, por exemplo, podem ser declaradas como nomes, mas têm um valor intrínseco numérico. São parametrizadas por quatro valores: a propriedade a animar, a duração, o nome de uma função de animação e o tempo de atraso de início de animação.

Tal como tinha dito aqui, está na altura do mjamado.com passar à iteracção seguinte. Já passou tempo que chegue, espero que todos os parceiros de negócios do Sr. Messias tenham actualizado os seus contactos e até o site das Páginas Amarelas já retirou o link.

Nesta iteracção, contém um misto de currículo e portfólio e, provavelmente, manter-se-á neste formato a médio prazo.

Aproveitei que era um projecto relativamente simples (meia dúzia de canais, autenticação de utilizadores de back-office básica) para usar um conjunto de tecnologias com que tenho andado a brincar (Yii, SASS e Compass), assim como várias técnicas que ainda não tinha usado em projectos ao vivo (media queries, CSS transitions).

Nos próximos dias farei mais alguns posts sobre algumas das técnicas que usei e os percalços que encontrei.

Comentários Nenhum comentário Continuar a ler Continuar a ler »

R2D2O Montepio tem uma nova campanha publicitária baseada no universo Star Wars. Porreiro. Um dos spots de rádio conta com a "participação" do astro-dróide R2D2. Ora oiçam:

Uma conversa muito agradável, a senhora até consegue algo só ao alcance do C3PO e de alguns Jedi, que é entender os trinados do R2D2. Ou então tem um monitor de tradução como os que equipam os T-65 X-Wing Starfighter ou os Eta-2 Actis-class Interceptor.

Mas a parte que realmente me interessa é esta:

- Não, senhor R2D2, não são 4 anos-luz; são 4 anos terrestres.

Ora, ou o R2D2, à força de andar sempre metido em sarilhos, perdeu de vez o juízo, ou a senhora, realmente, não percebe patavina dos trinados, e, na volta, este desgraçado astro dróide só queria mesmo alguém que lhe trocasse o óleo, e está a ser impingido com um depósito a prazo.

É que a unidade anos-luz é uma medida de distância e não de tempo, como anos terrestres. Um ano-luz é a distância percorrida pela luz num ano. Como a velocidade da luz no vácuo é uma constante (um cheirinho menos que 300.000 quilómetros por segundo), um ano-luz é qualquer coisa como 9,46 x 1015 metros, ou quase 9,5 biliões de quilómetros (biliões dos nossos, não dos americanos).

Criativos de todo o mundo, se vão fazer referências científicas nos vossos anúncios, façam um favor à humanidade: arranjem um assessor científico. Da maneira que andam as coisas, estão baratos e impedem que pareçam uns perfeitos anormais.

Comentários Nenhum comentário Continuar a ler Continuar a ler »
 Categorias
 Arquivo
 Projectos em Destaque
 Últimas Postas no Blog
 Últimos Comentários do Blog