Solução para a provinha do Google Developer Day 2011 em Python
Esse ano, resolvi tratar com um pouco mais de respeito a prova do GDD. Ano passado, eu resolvi com o prompt do Python aberto, olhando o browser em uma janela e o prompt na outra. Esse ano, as perguntas eram um pouco mais trabalhosas e as strings maiores e isso me fez, em vez disso, escrever um programa. Mais tarde eu coloco o programa no github, mas, por hora, eu transcrevo e comento aqui a minha solução.
A prova apresenta dois textos escritos no idioma Googlon, com os quais vamos trabalhar, e quatro perguntas. Para ajudar (eles são realmente bonzinhos), eles dão as soluções para o primeiro texto, o que ajuda a testar se o código está correto.
Letras foo, bar e preposições
A primeira pergunta explica que algumas letras são chamadas de "letras foo" e todas as demais, "letras bar" e que preposições são palavras de cinco letras que começam com uma letra bar e não contém a letra "q" (é muito provável que a sua prova seja diferente da minha e que elas sejam geradas aleatoriamente - é como eu faria). Para ajudar a resolver, eu escrevi algumas funções
def foo(l): return l in "snrbg" def bar(l): return not foo(l) def preposicao(p): return len(p) == 5 and bar(p[-1]) and 'q' not in p
Aí, testar a resposta dada no enunciado é fácil:
>>> palavras_a = texto_a.split(' ') >>> len(filter(preposicao, palavras_a)) 63
Assim como responder a pergunta:
>>> palavras_b= texto_b.split(' ') >>> len(filter(preposicao, palavras_b)) 57
Verbos e verbos em primeira pessoa
A segunda pergunta ensina que verbos são palavras de 6 letras que terminam em uma letra bar. Se ele também começar com uma letra bar, estará em primeira pessoa.
def verbo(p): return len(p) >= 6 and bar(p[-1]) def verbo_primeira_pessoa(p): return verbo(p) and bar(p[0])
Agora podemos testar nosso código com o dado do enunciado:
>>> len(filter(verbo, palavras_a)) == 216 True >>> len(filter(verbo_primeira_pessoa, palavras_a)) == 160 True
E descobrir a nossa própria resposta:
>>> len(filter(verbo, palavras_b)) 224 >>> len(filter(verbo_primeira_pessoa, palavras_b)) 154
No meu caso, eu tinha 224 verbos, dos quais 154 em primeira pessoa.
Vocabulário
Agora o problema pede para criar uma lista com o vocabulário, ordenado segundo o alfabeto googlon. Para isso, eu vou usar o ordenador que já vem embutido nas listas do Python e vou produzir uma função de comparação. Essa função pode ser facilmente plugada em seu próprio sort, se você quiser muito:
def cmp_googlon(p1, p2): v = 'jgptzmqskbclrhdfnvwx' for l1, l2 in zip(p1, p2): if v.index(l1) != v.index(l2): return v.index(l1) - v.index(l2) return len(p1) - len(p2)
E podemos testar com os dados do enunciado:
>>> vocabulario_a_unsorted = list(set(palavras_a)) >>> ' '.join(sorted(vocabulario_a_unsorted, ... cmp = cmp_googlon)) == vocabulario_a True
Nota: ao construir um set com as palavras do texto A, eu eliminei as repetições. Como objetos do tipo set não são ordenáveis, eu transformei o conjunto em uma lista.
Agora podemos encontrar nossa resposta:
>>> vocabulario_b_unsorted = list(set(palavras_b)) >>> vocabulario_b = ' '.join(sorted(vocabulario_b_unsorted, cmp = cmp_googlon)) >>> vocabulario_b 'jgspd jgv jpgzkx jzvjw jmrmlq jmdxx jmntpzq jqw jspk jkc jbb jcphbk jch jcv jlkm...
Números
Agora a prova nos explica que todas as palavras em googlon tem um valor numérico. Em googlon, os números são escritos do dígito menos significativo para o mais significativo e em base 20. Pra isso, precisamos de mais uma função:
def valor_numerico(p): v = 'jgptzmqskbclrhdfnvwx' vn = 0 i = 0 for c in p: vn += v.index(c) * (20 ** i) i += 1 return vn
que, podemos testar contra o enunciado:
>>> valor_numerico('blsmgpz') == 262603029 True
Essa parte está certa. Mas a pergunta pede para contarmos os números bonitos. Para eles, números bonitos são divisíveis por 5 e maiores que 492528.
def numero_bonito(p): return valor_numerico(p) > 492528 and (valor_numerico(p) % 5 == 0)
Agora podemos testar:
>>> len(filter(numero_bonito, vocabulario_a.split(' '))) == 75 True
E chegar na nossa resposta:
>>> len(filter(numero_bonito, vocabulario_b.split(' '))) 71
Conclusão
Foi difícil? Nem um pouco. Se você não conseguiu responder por conta própria, precisa estudar mais. Foi mais trabalhosa do que a do ano passado? Um pouco. Por outro lado, ela tinha informações suficientes para você poder testar suas próprias soluções - e isso ajudou quem teve mais problemas para resolver a prova a aprender alguma coisa. Prova boa é assim - você aprende enquanto faz.
Uma última observação: eu gosto de list comprehensions, mas também gosto de map, filter e reduce. O código fica mais limpo quando eles são bem empregados.
Sobre a provinha do Google Developer Day 2011
Ano passado, quando a Google abriu as inscrições para o GDD, eu escrevi o primeiro de uma série de três artigos sobre a tal provinha. Esperei até o final das inscrições (e o sinal verde de um amigo que trabalha lá) para publicá-lo.
Não vou fazer diferente esse ano. Se você veio aqui querendo ver a solução dos problemas do ano passado, eles estão relacionados abaixo. Se, por outro lado, chegou aqui procurando um jeito fácil de entrar no evento, devia ter vergonha. Eu respeito a decisão da Google de usar a prova como uma forma de garantir que a platéia tenha melhores chances de entender o que o palestrante vai falar e não vou ajudar a estragar o processo de seleção de convidados deles. Quando as inscrições estiverem encerradas, eu volto aqui e publico a minha solução e aí você pode comparar com a sua.
De resto, boa sorte. A prova não é difícil e eu tenho certeza que você consegue. Você já chegou até aqui, afinal.
Um abraço e até lá.
Nota: Se você colocar aqui um comentário mostrando uma solução antes que sejam fechadas as inscrições, eu vou apagar pela mesma razão que me fez não publicar a minha ainda. Se você tem uma solução, volte depois.
Outra nota: Agora, que as inscrições estão encerradas, você pode achar soluções procurando no Google. Uma delas (em Java) foi postada em um comentário aqui. A mihha em Python está aqui. Há outras, algumas com escolhas de linguagem ainda mais estranhas do que a minha versão para computadores de 8-bits do ano passado. Acho uma pena que tantos tenham praticado GDD (Google-Driven Development, pun intended) e tenham googlado por respostas em vez de aprender a programar.
Emacs perfection - selecting fonts according to screen size
Most of the time, I work at my desk, where my netbook is hooked up to a reasonably sized monitor (the largest its feeble GPU can handle with acceleration). Since screen real-estate in that situation is abundant, I opted to use a larger font (one I made from the x3270 bitmap font, but that's another, much longer story). Unfortunately, when I am not at my desk, the 1024x600 LCD is quite limiting and the default options don't work for me. When I am away from the big screen monitor, screen real-estate is limited and a small font should be selected by default.
I started from the options the Custom menu gave me. Removing comments, it's a very simple snippet:
(custom-set-faces '(default ((t (:inherit nil :stipple nil :inverse-video nil :box nil :strike-through nil :overline nil :underline nil :slant normal :weight normal :height 140 :width normal :family "IBM 3270")))) '(linum ((t (:inherit default :foreground "#777" :height 110)))))
Translating that to English, I have a font called "IBM 3270" at a 14-point height, with line numbers with 11 points. Very readable.
But that doesn't solve the problem when I am on the road.
The friendly guys at Stack Overflow pointed out one way to do it: x-display-pixel-width and x-display-pixel-height.
With that in hand, I can do:
(if (> (x-display-pixel-width) 1280) ; screen is big (custom-set-faces '(default ((t (:inherit nil :stipple nil :inverse-video nil :box nil :strike-through nil :overline nil :underline nil :slant normal :weight normal :height 140 :width normal :family "IBM 3270")))) '(linum ((t (:inherit default :foreground "#777" :height 110))))) ; screen is small (custom-set-faces '(default ((t (:inherit nil :stipple nil :inverse-video nil :box nil :strike-through nil :overline nil :underline nil :slant normal :weight normal :height 110 :width normal :family "IBM 3270")))) '(linum ((t (:inherit default :foreground "#777" :height 80))))) )
and I can be happy.
But can I?
When I start Emacs without X (as in from a remote terminal), these functions issue an ugly warning telling me that X is not available and that I should --debug-init and fix the problem. That's safely ignorable (as these adjustments are being done when everything non-cosmetic is already in place, at least in my init.el), but, still, annoying.
There is a variable, window-system, that can help - it holds "x" if we are under the X windowing system and nil if we are using a character terminal. With it, I can do:
(if (and (eq 'x window-system) (> (x-display-pixel-width) 1280)) ; screen is big (custom-set-faces '(default ((t (:inherit nil :stipple nil :inverse-video nil :box nil :strike-through nil :overline nil :underline nil :slant normal :weight normal :height 140 :width normal :family "IBM 3270")))) '(linum ((t (:inherit default :foreground "#777" :height 110))))) ; screen is small (custom-set-faces '(default ((t (:inherit nil :stipple nil :inverse-video nil :box nil :strike-through nil :overline nil :underline nil :slant normal :weight normal :height 110 :width normal :family "IBM 3270")))) '(linum ((t (:inherit default :foreground "#777" :height 80))))) )
short-circuiting the x-display-pixel-width and allowing Emacs starts cleanly from a remote terminal session. Since window-system also can tell you if you are on a Mac (or NeXT, if you are into retrocomputing) or under Windows (you can't argue taste), you can take appropriate actions according to your environment.
I am happy for today.
The Manga Guide to Relativity
Physics is an intimidating subject this (comic-)book manages to tackle in a way most teenagers will find easy to understand. More to the point, they will, hopefully, find it fun and compelling too. Its structure is a good fit for high-school teenagers (don't traumatize your 10-year-old kid with it) with an interest for science and/or Japanese comic-books.