Mais um blog inútil.

Useless

Maio 5, 2009

Oldies

Arquivado em: coding, fail, useless — dcoder @ 21:14

Em conversa há dias com o falso, mostrei-lhe uma calculadora de bitrate que tinha feito há (N) anos, toda em Win32 assembly. Escusado será dizer o desperdício de tempo que foi. Fiquei, no entanto, triste por ter perdido o código original da mesma; aquilo era até bastante complexo, para o efeito que era.

Para não perder mais lixo que fiz no passado, sempre que o encontrar por aqui vou postando. Neste post coloco o CryptoFrame, uma aplicação modular que fiz para servir de workbench para as várias experiências que ia fazendo. Como sempre, nunca foi acabado nem passou da primeira versão, 0.1. Mesmo assim, há quem tenha achado isto útil por alguma razão que me ultrapassa.

A versão inicial continha um plugin para brincar com curvas elípticas e assinaturas digitais com as mesmas, um plugin para calcular hashes de strings ou ficheiros e uma calculadora de precisão arbitrária com base na biblioteca GNU MP.

Download.

Maio 4, 2009

Malbolge desmistificado

Arquivado em: arvorezinha, coding, lulz, useless — mirage @ 21:42

Bem-vindos. Espicaçado pelas inutilidades que o falso e o Dcoder fizeram em malbolge, e ainda mais depois de o falso ter afirmado peremptoriamente que era impossível fazer uma arvorezinha à mão nesta linguagem diabólica, decidi, fatalmente, jogar mãos à obra.

O segredo do falso em relação ao malbolge é que todo o código dele é gerado por bruteforce. As optimizações do Dcoder limitaram-se a correr o bruteforce durante mais tempo para procurar soluções mais curtas. Neste post proponho um método real, analítico e bastante simples para criar um programa de malbolge que imprima qualquer sequência de caracteres, com a limitação de ser curta. E sim, a arvorezinha é suficientemente curta. ;-) Para facilitar a programação, criei vários utilitários, baseados no malbolge.c original, que constituem o malbolge SDK disponível aqui. Eis uma curta explicação de cada programa:

  • malbolgec: Compila uma source não obfuscada de malbolge (extensão .mbs), transformando-a na versão obfuscada executável (extensão .mb). São admitidos comentários na source, começando com “;”.
  • malbolged: Uma variação do malbolge.c standard que imprime o estado da VM à medida que executa o código. Muito útil para debugging.
  • malbolgedis: O inverso do malbolgec. Dado um programa executável de malbolge, mostra o seu código desobfuscado.
  • malbolgeconstant: Descobre a sequência mais curta para calcular o valor desejado. Mais abaixo será mostrado como o utilizar, já que é uma peça fulcral no método apresentado.
  • malbolgevalid: Mostra os valores válidos num programa de malbolge no intervalo de memória especificado. Útil para procurar valores directos para usar em jumps.
  • malbolgestring: Um proof-of-concept que gera um programa de malbolge que imprima a string especificada. Apenas aceita strings muito curtas (uma arvorezinha completa não cabe, por exemplo, mas “lol jews” sim).

Um dos problemas da programação em malbolge é que que o code pointer e o data pointer começam ambos a 0 no início do programa, ou seja, estão sobrepostos. Por isso, o meu plano começa por separar claramente a zona de código da zona de dados. Assim sendo, a primeira coisa que faço é avançar o D para qualquer sítio mais à frente, com a instrução “j”. Devido à obfuscação que a o malbolge obriga no input, esta instrução na posição 0 de memória corresponde a um salto do D para o valor 41. Temos agora 40 bytes de código disponíveis pela frente, sem mais complicações, antes de voltar a tropeçar nos dados.

Outro dos problemas é a alteração sofrida nas instruções depois de serem executadas, e também dos dados depois de serem usados pelos operadores. Para minimizar estes problemas optei por uma abordagem naïve mas suficientemente eficaz para o problema em questão, que consiste em ter todo o código e dados a correr linearmente, excepto a configuração inicial da área de dados descrita anteriormente.

Talvez a limitação mais severa seja a dos caracteres que podemos usar como input inicial no malbolge, o que dificulta tremendamente o uso de valores pré-definidos, como sejam os caracteres da nossa string. Isto obriga-nos a calcular praticamente todos os valores desejados e imprimi-los, um por um. O malbolge apenas oferece duas instruções de cálculo, o trinary rotate e a trinary op a.k.a. crazy operation. Felizmente para nós, qualquer valor ASCII é calculável usando estas operações com um máximo 3 operações seguidas com valores específicos nos dados (por vezes antecedidas de nops, é certo, para aceder aos dados necessários que, como é sabido, variam consoante a sua posição em memória). Para ajudar, não precisamos de ter o valor exacto no A, basta um A tal que A & 0xFF seja o caracter que queremos (os registos são unsigned short e o print só usa os primeiros 8 bits). Para descobrir a menor sequência de operações necessárias e respectivos valores nos dados fiz o malbolgeconstant (tal como referi acima, pertence ao SDK).

Para exemplificar, vamos criar um programa que imprima “Oi”. Usaremos os símbolos reais para as instruções e não a versão executável, que depois compilaremos com o malbolgec. Primeiro avançamos o D para a posição 41:

jv

Agora calculamos o caracter “O” (ASCII 79) com o malbolgeconstant (tem como input o valor do D, o valor que procuramos e o valor actual do A, que no início do programa é zero):

./malbolgeconstant 41 79 0
EUREKA! code=p pos=42 data=p (r)
EUREKA! code=* pos=41 data=p (s)

OK, esta efusão de felicidade conta-nos que devemos usar as operações “*” e “p”, com o input “p” e “p” respectivamente (que correspondem a “r” e “s” em código obfuscado, mas vamos aqui trabalhar com código normal). De notar que o pos (a posição de memória onde devem estar os dados) começa a 41, que foi a posição inicial que especificámos. Poderia ser 42 ou mais, o que significaria que precisávamos de inserir nops no código (e nos dados, mas aqui não é obrigatório serem nops) antes de executar as instruções especificadas. Por vezes os valores necessários às operações só estão disponíveis mais à frente na memória, devido à forma como o malbolge obriga a codificar as sores. Adiante, o nosso programa tem agora este aspecto:

j*p<voooooooooooooooooooooooooooooooooooopp

Recapitulando: avançamos o D, calculamos “O” (o seu valor fica no registo A) e imprimimo-lo com “< “, terminando o programa com o “v”. A sequência de “o” (nops) no meio é apenas para encher choriços, já que não chegam a ser executados. Estão cá apenas para chegar à posição 41 e 42, onde temos o input necessário às nossas instruções. Vamos compilar este programa e corre-lo no malbolged para ver a evolução dos registos:

./malbolgec example.mbs example.mb && ./malbolged example.mb
	CODE: j	MEM: 040 (() 	A: 00000	C: 00000	D: 00000
	CODE: *	MEM: 115 (s) 	A: 00000	C: 00001	D: 00041
	CODE: p	MEM: 114 (r) 	A: 19721	C: 00002	D: 00042
	CODE: < MEM: 29416 (è) 	A: 09807	C: 00003	D: 00043
O	CODE: v	MEM: 114 (r) 	A: 09807	C: 00004	D: 00044

Como podem ver, quando o programa termina, o registo A tem o valor 9807 e o D tem 44. Vamos usar estes valores como base para calcular a próxima constante de que necessitamos, que é a letra “i” (ASCII 105):

./malbolgeconstant 44 105 9807
EUREKA! code=p pos=45 data=j (Y)
EUREKA! code=* pos=44 data=/ (I)

Mais uma vez só precisamos de duas operações. Temos assim o seguinte:

j*p<*p<voooooooooooooooooooooooooooooooooppo/j

Notem o “o” entre os dois grupos de dados: é para compensar o avanço do D gerado pela instrução que imprime o caracter. Poderia ser qualquer outro símbolo, já que não está a ser usado.

Vamos terminar com um \n, para ficar com um output decente:

./malbolgec example.mbs example.mb && ./malbolged example.mb
	CODE: j	MEM: 040 (() 	A: 00000	C: 00000	D: 00000
	CODE: *	MEM: 115 (s) 	A: 00000	C: 00001	D: 00041
	CODE: p	MEM: 114 (r) 	A: 19721	C: 00002	D: 00042
	CODE: < MEM: 119 (w) 	A: 09807	C: 00003	D: 00043
O	CODE: *	MEM: 073 (I) 	A: 09807	C: 00004	D: 00044
	CODE: p	MEM: 089 (Y) 	A: 19707	C: 00005	D: 00045
	CODE: <	MEM: 29477 (%) 	A: 09833	C: 00006	D: 00046
i	CODE: v	MEM: 088 (X) 	A: 09833	C: 00007	D: 00047

./malbolgeconstant 47 10 9833
EUREKA! code=p pos=49 data=* (T)
EUREKA! code=p pos=48 data=v (!)
EUREKA! code=* pos=47 data=i (3)

Chegamos por fim ao programa desejado:

mirage@arda ~/malbolge-sdk-1.0 $ cat example.mbs
j*p<*p<*pp<voooooooooooooooooooooooooooooppo/joiv*
mirage@arda ~/malbolge-sdk-1.0 $ ./malbolgec example.mbs example.mb
mirage@arda ~/malbolge-sdk-1.0 $ cat example.mb
(&<`#9]~65YF876543210/.-,+*)('&%$#"!~}|{zsrwIYt3!T
mirage@arda ~/malbolge-sdk-1.0 $ ./malbolge example.mb
Oi

Vamos agora à prova dos nove: a arvorezinha! Note-se que esta arvorezinha tem \n na última linha, como manda o RFC. Tal como as arvorezinhas anteriores em malbolge, não usa ciclos. Ocupa 99 caracteres (incluí no SDK uma versão sem a última newline com apenas 95 caracteres). Como verão, usei dois incrementos ao D, porque a arvorezinha não coube em 40 caracteres de código. Ainda assim, foi necessário usar o próprio valor em 44, que é um < , para imprimir um caracter da árvore, e simultaneamente servir de input para o segundo “j”. Reparem:

./malbolgevalid 44 44
44:	037 (v)	054 (i)	055 (<)	073 (/)	089 (*)	090 (j)	112 (p)	118 (o)

O “< “, por coincidência a instrução de print, resulta no valor 55, bastante simpático para o novo início dos dados. Atenção que, na listagem que se segue, o nº de linha N corresponde à posição de memória N-1. Sem mais paleio, aqui vai:

j ; avançar dados para o 41
o ; estes nops são para diminuir o resultado do próximo j
o
o
j ; avançar ainda mais, para o 56
p ; calcular "*" com "pp" com os dados 56 e 57
p
< ; imprime-o
* ; agora calcula o "\n" com dados do 59 ao 61
p
p
< ; imprime-o
* ; calcula novamente "*"
p
p
< ; desta vez imprime dois
<
p ; calcula "\n" de novo e assim sucessivamente até completar a arvorezinha
p
<
p
p
<
<
<
p
p
<
*
p
p
<
<
<
<
p
p
<
p
p
< ; print dos últimos 5 asteriscos
< ; posição de dados usado no D=56, e simultaneamente faz um print ;-)
<
<
<
*
p
p
< ; printa "\n" no fim, como manda o RFC, seus batoteiros
v ; fim do código
o ; nops a encher choriço até começarem os dados úteis
o
o
o
o
o
j ; dados do cálculo do primeiro "*"
*
o ; nop para compensar o "<" desse "*"
i ; dados do cálculo do primeiro "\n"
p
i
o ; nop idem
i ; etc, dados dos cálculos até ao final
<
*
o
o
o
p
o
*
<
o
o
o
o
i
o
/
p
j
o
o
o
o
*
o
o
p
j
o
o
o
o
o
p
/
j

Rapidamente, a versão prêt-à-porter:

(CBA$98}54Xy10TS-,P*)MLK%$Hi!~DCBAyx>vu;:987Xnm3~ponmlkNLh'`%d##D`_^W>yYXWVsT&L5PONM/KJC,GFEDC<r$

E assim chegamos ao fim do post. Espero que tenham perdido tanto tempo a lê-lo como eu perdi a escrevê-lo. ;-) Feliz programação em malbolge!

Este post é dedicado à memória do fravia, o Deus do cracking, e do Vasco Granja, o Rei do lulz importado da antiga checoslováquia.

Abril 29, 2009

Byte Swap com SSE4.1

Arquivado em: assembly, coding, useless — dcoder @ 17:03

Para finalizar esta série de optimizações inúteis, trago-vos a versão final desta função:

BITS 32

%define UNROLL_COUNT (4)

section .data
align 16
shuffle: dd 0x04050607, 0x00010203, 0x0c0d0e0f, 0x08090a0b

section .text
global sse41_bswap64
sse41_bswap64:
  push ebp
  mov edx, [esp+8] ; buffer -- assumed aligned 16
  mov ecx, [esp+12] ; length in #words
  test   ecx, ecx
  jz  near   _end

  and    ecx, -(UNROLL_COUNT*2) ; make ecx even
  jz     _finalize

  movdqu xmm7, [shuffle]
align 16
_loop:
  sub ecx, UNROLL_COUNT*2
  ; use movntdqa with sse 4.1   
  movntdqa xmm0, [edx + 00]
  movntdqa xmm1, [edx + 16]
  movntdqa xmm2, [edx + 32]
  movntdqa xmm3, [edx + 48]

  pshufb xmm0, xmm7 ; p5, 1l 1t
  pshufb xmm1, xmm7 ; p5, 1l 1t
  pshufb xmm2, xmm7 ; p5, 1l 1t
  pshufb xmm3, xmm7 ; p5, 1l 1t

  ; use movntdq --- the data won't be accessed again 
  ; until the end of the function
  movntdq [edx + 00], xmm0
  movntdq [edx + 16], xmm1
  movntdq [edx + 32], xmm2
  movntdq [edx + 48], xmm3

  lea edx, [edx+ 16*UNROLL_COUNT];
  jnz _loop ; no dependency, all flags were 
             ; computed in the beginning of the loop
_finalize:
  sfence
  mov  ebp, [esp+8]
  and  ebp, (UNROLL_COUNT*2)-1 ; ebp = count mod UNROLL
  jz _end

_endloop:
  mov eax, [edx]
  bswap eax ; p0+p5
  mov ecx, [edx+4]
  bswap ecx
  mov [edx], ecx
  mov [edx+4], eax
  sub ebp, 1
  lea edx, [edx+8]
  jnz _endloop
_end:
  pop ebp
  ret

A única diferença nesta é que agora não apenas os stores, mas também os loads são não temporais, evitando a poluição da cache com dados que sabemos que nao vão ser usados. A performance desta última versão é a melhor do grupo, como demonstrado:

[dcoder@localhost bswap]$ ./bswap 
ref done
sse2 done
ssse3 done
SSE4.1 done
Ref  : 1804875336 cycles
SSE2 : 1822536180 cycles
SSSE3: 1012685742 cycles
SSE41: 998087949 cycles
Speedup: 44.700449%

Byte Swap com SSSE3

Arquivado em: assembly, coding, serious-business, useless — dcoder @ 04:26

Lembrei-me há pouco, durante as minhas insónias, que podemos aproveitar uma nova instrução introduzida nos Core 2 para acelerar consideravelmente esta operação: PSHUFB.

Essencialmente, o PSHUFB permite-nos criar uma permutação à escolha dentro de um registo XMM. É fácil ver como isto se aplica no nosso caso a inversão de bytes.

Para aumentar o débito, nas escritas utilizo a instrução MOVNTDQ, que dá a dica ao processador que a memória em causa já não vai ser acedida em breve. SFENCE serve para serializar todos estes armazenamentos. Mais uma vez leio/escrevo uma cache line por iteração (podia abusar e fazer isto para uma página inteira – valerá a pena?).

Código:

BITS 32

%define UNROLL_COUNT (4)

section .data

shuffle: dd 0x04050607, 0x00010203, 0x0c0d0e0f, 0x08090a0b

section .text
global _ssse3_bswap64
_ssse3_bswap64:
  push ebp
  mov edx, [esp+8] ; buffer -- assumed aligned 16
  mov ecx, [esp+12] ; length in #words
  test   ecx, ecx
  jz     _end

  and    ecx, -(UNROLL_COUNT*2) ; make ecx even
  jz     _finalize
  
  movdqa xmm7, [shuffle]

align 16
_loop:
  sub ecx, UNROLL_COUNT*2

  ; use movntdqa with sse 4.1   

  movdqa xmm0, [edx + 00]
  movdqa xmm1, [edx + 16]
  movdqa xmm2, [edx + 32]
  movdqa xmm3, [edx + 48]
  
  pshufb xmm0, xmm7 ; p5, 1l 1t
  pshufb xmm1, xmm7 ; p5, 1l 1t
  pshufb xmm2, xmm7 ; p5, 1l 1t
  pshufb xmm3, xmm7 ; p5, 1l 1t
  
  ; use movntdq --- the data won't be accessed again 
  ; until the end of the function
  movntdq [edx + 00], xmm0
  movntdq [edx + 16], xmm1
  movntdq [edx + 32], xmm2
  movntdq [edx + 48], xmm3

  lea edx, [edx+ 16*UNROLL_COUNT];
  jnz _loop ; no dependency, all flags were 
            ; computed in the beginning of the loop

_finalize:
  sfence ; serialize stores
  mov  ebp, [esp+8]
  and  ebp, (UNROLL_COUNT*2)-1 ; ebp = count mod UNROLL
  jz _end
  
_endloop:
  mov eax, [edx]
  bswap eax ; p0+p5
  mov ecx, [edx+4]
  bswap ecx
  mov [edx], ecx
  mov [edx+4], eax
  sub ebp, 1
  lea edx, [edx+8]
  jnz _endloop
  
_end:
  pop ebp
  ret

A performance agora é claramente superior em cerca de 10% — 1500 MB/s neste Core 2 a 2.0 GHz.

Adeus.

Abril 28, 2009

Byte Swap com SSE2

Arquivado em: assembly, coding, useless — dcoder @ 23:32

Encontrava-me hoje na Internet descansado quando o raxx7 começou a falar de optimizar uma função simples, mas engraçada – inverter a ordem dos bytes de um inteiro de 64 bits. Vou desde já assumir x86, visto que em amd64 existe uma instrução nativa que faz isto em apenas 4 ciclos (latência no core2) e é provavelmente rápido o suficiente. Mas em x86 precisamos de 2 instruções destas e 2+2 acessos à memória. Assim, peguei na identidade simples:

    BSWAP64(x) = BSWAP32(x>>32)|BSWAP32(x&0xFFFFFFFF)
    BSWAP32(x) = ((ROTL32((x), 8) & 0x00FF00FF) | (ROTL32((x), 24) & 0xFF00FF00))

,onde ROTL32 significa uma rotação de n bits à esquerda. Infelizmente, as extensões SSE2 da arquitectura x86 não possuem instruções específicas de rotação, forçando-nos a utilizar outra identidade bastante útil:

    ROTL32(x, n) = ((x< < n) | (x >> (32-n))) 

Neste momento, já temos tudo o que precisamos para efectuar a operação desejada em SSE2. No entanto, parece haver aqui um excesso de computação que torna este método demasiado ineficiente: 10 operações lógicas – 5 booleanas, 4 shifts e 1 shuffle. Mas a pipeline do Core 2 é extremamente boa: conseguimos efectuar 3 operações booleanas por ciclo, 1 shift por ciclo e 1 shuffle por ciclo. Se conseguirmos esconder a latência dos shifts com as operações booleanas, vamos obter uma contagem de ciclos não muito superior à dos 2 bswap de 32 bits. Além do mais, efectuamos 2 inversões simultâneas, dado que os registos XMM têm 128 bits; seria um desperdício não o fazer. Os acessos à memória também são mais eficientes, com acessos contíguos de 16 bytes (com o unrolling correcto processamos uma cache line (64 bytes) inteira de uma só vez).

Fiz então uma função para completar o exercício:

BITS 32

%define UNROLL_COUNT (4)

section .data
mask1: dd 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff
mask2: dd 0xff00ff00, 0xff00ff00, 0xff00ff00, 0xff00ff00

section .text
global _sse2_bswap64
_sse2_bswap64:
  push ebp
  mov edx, [esp+8] ; buffer -- assumed aligned 16
  mov ecx, [esp+12] ; length in #words
  test   ecx, ecx
  jz     _end

  and    ecx, -(UNROLL_COUNT*2) ; make ecx even
  jz     _finalize
  
  movdqa xmm6, [mask1]
  movdqa xmm7, [mask2]

align 16
_loop:
  sub ecx, UNROLL_COUNT*2
  
%assign i 0  
%rep  UNROLL_COUNT
  
  movdqa xmm0, [edx] ; p2
  movdqa xmm1, xmm0  ; p0/p1/p5
  pslld  xmm0, 8     ; p0
  movdqa xmm2, xmm1  ; p0/p1/p5
  psrld  xmm1, 24;   ; p0
  movdqa xmm3, xmm2  ; p0/p1/p5
  pslld  xmm2, 24    ; p0
  por    xmm0, xmm1  ; p0/p1/p5
  psrld  xmm3, 8     ; p0
  por    xmm2, xmm3  ; p0/p1/p5
  pand   xmm0, xmm6  ; p0/p1/p5
  pand   xmm2, xmm7  ; p0/p1/p5
  por    xmm0, xmm2  ; p0/p1/p5
  pshufd xmm0, xmm0, 10110001b ; p5 + p0/p1
  movdqa [edx], xmm0 ; p2  
  lea    edx,  [edx+16] ; p0   
  
%assign i i + 1
%endrep

  jnz _loop ; no dependency, all flags were 
               ; computed in the beginning of the loop

_finalize:
  mov  ebp, [esp+8]
  and  ebp, (UNROLL_COUNT*2)-1 ; ebp = count mod UNROLL
  jz _end
  
_endloop:
  mov eax, [edx]
  bswap eax ; p0+p5
  mov ecx, [edx+4]
  bswap ecx
  mov [edx], ecx
  mov [edx+4], eax
  sub ebp, 1
  lea edx, [edx+8]
  jnz _endloop
  
_end:
  pop ebp
  ret

Este código pode ser usado com o yasm ou nasm (o yasm em win32 não acertava com os endereços das masks, não sei se era bug no exportador para COFF ou AIDS). Esta função, junto com código para testá-la encontra-se aqui.

A performance obtida não foi tão boa como esperado, mas mantém-se competitiva com a alternativa: no Core 2 (65 nm) onde testei, a versão SSE2 era ~2% mais rápida. A utilidade de todo este exercício é, assim, discutível.

Bem-haja.

Hipocrisia no Planet Geek

Arquivado em: drama, serious-business, useless — falso @ 10:24

Ora viva amigalhaços!

Venho deste modo falar de um drama que aconteceu, que me deixou um bocado triste.
No sábado passado fiz um pedido para ser adicionado ao agregador português de blogs, o Planet Geek, disseram-me que iam fazer uma votação com os membros actuais para saber se o nosso blog poderia entrar ou não.
Fiz este pedido, por desde já uns tempos o blog está a ter vários posts diariamente e muitos deles com conteúdo, pode se dizer, MUITO geek, e gostava que tivesse mais um pouco de exposição do que tem actualmente.

Hoje depois de mandar um email a perguntar pela resposta, pois ainda não tinham dito nada, recebi isto:

Como acho que já estão recolhidas opiniões suficientes, tenho de te informar que a resposta é negativa, muito em parte pelo conteúdo anterior do blog no que respeita ao Mário Gamito.

Isto parece me um bocado hipócrita, porque enquanto o Gamito cá estava ninguém gostava dele, e montes deles gozavam com o homem… Agora que se passou o que se passou, são todos amiguinhos e defendem-no. Deviam ter feito isso enquanto ele cá estava e não agora, não acham amiguinhos?

Fiquei um bocado triste pois, um pedido sem malícia foi acusado de troll e tal, é cagar e andar! Como o cantor Fausto diz numa musica de 1977 “E assim se faz Portugal, uns vão bem e outros mal”.

Fiquem bem e joguem muito!

Abril 27, 2009

Arvorezinha - MOOsaico

Arquivado em: arvorezinha, useless — spico @ 17:25

Seguindo a linha do “One Liner”, segue a arvorezinha feita no MOOsaico.

;eval("s=\"*\";for x in [1..5] player:tell(s); s=s+\"*\";endfor;")

Resultado:
*
**




Abril 26, 2009

Arvorezinha - Perl

Arquivado em: arvorezinha, coding, useless — devnull @ 16:07

Já que avançámos para linguagens mais normais e para demonstrar que o python suga, segue o meu one liner em perl.


david@tokyo ~ $ perl -l arvorezinha.pl
*
**
***
****
*****
david@tokyo ~ $ cat arvorezinha.pl
for (1..5){print "*"x$_;}
david@tokyo ~ $ wc -c arvorezinha.pl

O “-l” põe automaticamente o carriage return no fim de cada linha.

Bem-haja!

Abril 25, 2009

Arvorezinha em Brainfuck 2.0 - Com loops

Arquivado em: arvorezinha, coding, fail, useless — dcoder @ 21:42

Viva amigos.  Numa noite lenta como esta, decidi ceder aos pedidos de uma arvorezinha em brainfuck segundo as regras, isto é, sem ser hardcoded. E aqui está. Aviso desde já que podia ser reduzida pelo menos uns 20% com alguns melhoramentos mais ou menos óbvios, mas não tenho paciência para essas coisas. Podem alterar o número de iterações na quarta sequência de ‘+’.

++++++++++>++++++[>+++++++<-]>>++++++[>+>+<<-]>>[<<+>>-]+
[>+>+<<-]>>[<<+>>-]<[<<->>-]<[>+>+<<-]>>[<<+>>-]<<<[>>[<<
<<.>>>>-]<<<<<<.>>>>>><+[>+>+<<-]>>[<<+>>-]<[-]<<[-]<[>+>
>+<<<-]>>>[<<<+>>>-]<[>+>+<<-]>>[<<<->>>-]<[>+<-]>[<+<+>>
-]<<<]

Um grande bem-haja!

Abril 23, 2009

Arvorezinha .NET

Arquivado em: arvorezinha, coding, useless — spico @ 15:22

Não é ASP.NET .. Mas sim PAINT.NET

Dcoder e falso, fica ai o desafio para optimizarem esta arvorezinha em Paint.NET

arvorezinha