= Papo Advanced em Python = O trecho abaixo é parte de um bate-papo que rolou no canal dos [[http://www.d00dz.org|d00dz]] enquanto discutia-se a criação de um jogo de tabuleiro em Python (o jogo se chama Quadro e acho que logo logo estará aqui no site para todo mundo ver). O jogo está sendo desenvolvido em Python. Só para esclarecimentos: * bruder - Sérgio Devojno Bruder - Sócio da [[http://www.haxent.com.br|Haxent]] e dono do site [[http://www.pontobr.org|PontoBR]] * gwm - Guilherme Wünsch Manika - Sócio da [[http://www.haxent.com.br|Haxent]] * ruda - RudaMoura - Sócio da [[http://www.haxent.com.br|Haxent]] * mrbrocoli - Alfredo Kenji Kojima - Sócio da [[http://www.haxent.com.br|Haxent]] e autor do [[http://www.windowmaker.org|WindowMaker]] * niemeyer - GustavoNiemeyer - Desenvolvedor da [[http://www.conectiva.com.br|Conectiva]] e um dos maiores 'ativistas' Python do Brasil. Quem estiver afim de entender algumas funcionalidades interessantes de Python é só acompanhar o 'chat' abaixo: ''A explicação do problema está no fim da conversa abaixo. Deixa eu explicar aqui para ser mais fácil de acompanhar. O problema é detectar a condição de vitória de um jogo que é jogado em um tabuleiro 4x4 com 16 peças, cada uma com quatro propriedades (alta/baixa, azul/amarela, furada/normal, redonda/triangular) [[http://www.zorked.net/woodbox-bruder-rad.jpg|[peças]]] [[http://www.zorked.net/quadro-working.jpg|[tabuleiro]]]. O jogo acaba quando um jogador monta uma quadra com pelo menos uma característica igual: todas altas, todas baixas, todas azuis, etc. As peças são representadas por tuplas com quatro valores 0/1: (0, 0, 0, 0), (0, 0, 0, 1), etc. A idéia é detectar se uma linha do jogo (portanto, uma tupla de peças) preencheu a condição de fim de jogo. Isso deve ser feito em uma unica expressão com estilo funcional, e de forma genérica - ou seja, que valesse para um jogo com NxN casas e peças com N propriedades. -- Guilherme'' {{{ for i in range(4): self.img[i].move(coords) ? map(lambda x: x.move(coords), self.img) ;) for i in self.img: i.move(coords) ruda: pegar a coluna col: map(lambda x: x[col], board) gwm_: e a diagonal? :D as (board[0][0], board[1][1], board[2][2], board[3][3]) (board[0][3], board[1][2], board[2][1], board[3][0]) >>> map(lambda x,i,j: x[i][j] and i == j, b.board) algo assim, nao é isso ruda: map(lambda x: 2*x, lista) duplica todos os elementos de uma lista por exemplo pra cada elemento da lista rodar lambda(elemento) e monta outra lista como resultado map(lambda board=board,i: board[i][i],range(4)) nossa existe isso? er.. map(lambda i,board=board: board[i][i],range(4)) >>> board=[[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]] >>> map(lambda i,board=board: board[i][i],range(4)) [1, 6, 11, 16] ah, legal lambda x, foo=foo é feio pra caramba mas legal [board[i][i] for i in range(4)] é menos feim muito melhor esse é melhor e a diagonal secundária? * ruda lembra de fórmula [board[i][0] for i in range(4)] colunas [board[0][i] for i in range(4)] linhas deve dar pra fazer um [foo [bla]] pra gerar todas combinacoes board[i][3-i] thanks como é feio esse map aka não entendo sim :) o lambda i,board=board precisa mesmo bdo board=board? map(lambda i: board[i][i],range(4)) se funciona sem, nao precisa parece que funciona sempre me confundo de qdo precisa por que será que ele aceita passar board=board se não precisa? for i in range(4): blah.append(board[i][i]) pra mudar nome? bruder: declara o blah numa linha! board=[1,2,3] valores default etc hm http://www.zorked.net/quadro-working.jpg ta usando pygame? sim o que falta agora: jogo em rede firulas (menu, perguntar quem sao os jogadores, etc) tempo de carga das imgs iniciais (está lentaum) é só cortar aqueles arquivões tou te falando o bruder carrega 50 imagens 1024x768 24 bits com canal alfa 68 e corta os 16x16 que ele usa heh pelo menos nao é um system("povray") putz :) tá funfando kra, já dá p/ jogar no esquema os-dois-no-mesmo-micro-trocando-teclado faça usar mouse e teclado de forma que não dê pro cara escolher peça pro outro por engano o bruder pegou o exemplo canônico de uso do mouse, arrastar peças numa mesa, para fazer um jogo teclado-only ficou massa com teclado, besta. setas e enter, mais nada. lambada x,y: x+y eu vou boicotar esse jogo sem mouse meu typo favorito agora já sabemos o que o ruda fazia na juventude ia na lambateria porca = reduce(lambda x,y: (x[0]+y[0], x[1]+y[1], x[2]+y[2], x[3]+y[3], line) if 4 in porca: return vitoria faltou um ) tem que ter uma maneira mais legal de fazer isso, claro mas essa usa reduce kra!#!#! usa map dentro do reduce é o que deu nó no cérebro * bruder escreveu board2screen() e screen2board(), agora o codigo ficou 30% melhor bruder: quantos reduce, map, filter ou lambda você usou? nenhum? palha! nenhum, nenhum, nenhum e nenhum o bruder deve ter escrito em phpython for i in range(4): lista[i] <-- tipo isso > reduce(lambda x,y: x & y, map(lambda x: x[0],l)) eu queria tirar o x[0] pra fazer um range disso [(1, 0, 0, 0), (1, 0, 1, 0), (1, 1, 0, 0), (1, 0, 1, 1)] >>> reduce(lambda x,y: x & y, map(lambda x: x[0],l)) 1 é mais ou menos o que quero blah, vou usar assim com for mesmo reduce(lambda x,y: map(lambda z: x[z] + y[z], range(len(x))), line) bah, trivial se você faz código críptico em perl você é um script kiddie mané se você gera código críptico em python você é um programador com tendências funcionais elevadas código ilegível perl = mané código ilegível python = acadêmico reduce(lambda x,y: [x[z]+y[z] for z in range(len(x))], line) agora eu uso filter para achar os 0 e 4 filter(lambda x: x == 4 or x == 0, reduce(lambda x,y: [x[z]+y[z] for z in range(len(x))], line)) and game_over() elegantérrimo é só juntar isso agora com os maps e reduces acima que acham linhas e colunas e diagonais... filter(lambda x: x in (0, 4), reduce(lambda x,y: [x[z]+y[z] for z in range(len(x))], line)) and game_over() 1337 daqui a 1 semana ninguem mais sabe o que isso faz :P isso troquei dez linhas de código sem comentário por 9 linhas de comentário para explicar uma linha de código ou, na visão bruderiana... performance(1 linha) > performance(10 linhas) filter(lambda x: x in (0, len(line)), reduce(lambda x,y: [x[z]+y[z] for z in range(len(x))], line)) and game_over() assim fica mais genérico greetz to ruda que achou o bug gwm_: Use list comprehensions e remova os comentários e as 10 linhas de código. :) Ou pelo menos reduza os comentários.. já que a linha parece realmente complexa. [vai, reescreve aquilo ;) * niemeyer tenta.. [ ... if 0 <= x <= line], isso remove o filter.. Deixa eu ver o resto.. Obrigado.. vai ser mais fácil.. :) a partir de uma lista como [[0,1,0,0],[1,1,1,1],[0,1,0,0],[0,1,1,0]] você tem que achar se os valores correspondentes são iguais Humm.. vamos chamar isso de ll se ll[0][0] == ll[1][0] == ll[2][0]... ou se ll[0][1] == ll[1][1] == ll[2][1]... Ok.. * niemeyer tenta. na lista que eu botei o segundo valor das listas (1) faria a linha ser vencedora no jogo Ah.. ok. Qualquer um pode determinar verdadeiro então.. sim são quatro atributos de uma peça, se tiver uma linha com algum atributo igual em todas as peças, o jogo acabou seja 1 ou 0 esse atributo seria mais facil se os atributos fossem representados por um bitmap o ponto não é ser mais fácil ;) mas sim reduce de & (ou não?) não, por causa do caso 0 0 0 0 [x[0] for x in zip(l) if sum(x[0]) == len(x[0])] Tadá! :) nossa que é zip? zip? >>> zip([1,2,3], [4,5,6]) [(1, 4), (2, 5), (3, 6)] AHHHHH ;) bah :) map(None, [1,2,3],[4,5,6]) Opa.. melhor: [x for x in zip(*l) if sum(x) == len(x)] nossa, None o que é esse pointer l? :P zip(*l) == apply(zip, l) em pythons > 2, iirc. :) * mrbrocoli tem que reaprender python * gwm_ tem que aprender python }}} Pena eu ter perdido esse bate-papo :) Certamente eu iria palpitar (errado, mas iria) :) ''Faltou apenas verificar o caso dos atributos serem todos zero: [x for x in zip(*line) if sum(x) == len(x) or sum(x) == 0]. Problema menor, certamente porque eu não expliquei com clareza. sum() só existe em Python 2.3, mas sum(x) é equivalente a reduce(lambda a,b: a+b, x) -- Guilherme'' ''Ok, eu resolvi aprender direito isso tudo e escrevi o artigo PythonFuncional. -- Rudá'' ''O problema de performance a que me referi no texto acima era realmente causado pela excessiva alocação de memória para inúmeras imagens 800x600 32 bits (24 bits de cor e 8bits de alpha channel). Mudando tudo p/ imagens pequenas consegui um bom ganho de performance. Vou anunciar/publicar o jogo aqui como exemplo de uso da pygame assim que matar uns bugs óbvios -- Bruder'' ---- OsvaldoSantanaNeto