Árvorezinha 2.0
Ora viva amigos!
Há uns tempos no trabalho um colega meu começou a fazer pouco das minhas árvorezinhas, a dizer que só eram meia árvore, e que eu devia era de fazer uma árvore completa. Eu fiquei SENTIDO com tal AFRONTA, e fiquei a MATUTAR sobre isso, até que decidi por mãos à obra, e criar a Árvorezinha 2.0.
Primeiro decidi faze-la em C porque é a linguagem STANDARD!
[sourcecode language="c"]
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int altura;
int i,x;
int lul;
if (argc < 2)
{
return(0);
}
altura = atoi(argv[1]);
/* Ciclo da altura da Arvore */
for(i = 1; i <= altura; i++)
{
/*
Numero de Espaços
Começa em 0 porque existem linhas com 0 espaços
Algoritmo: altura - linha
*/
for(x = 0 ; x < (altura-i); x++)
{
putchar(' ');
}
/*
Numero de Asteriscos
Começa em 1 porque não existem linhas sem *
Algoritmo: (2 * linha) - 1
*/
for (x = 1; x <= (2*i)-1; x++)
{
putchar('*');
}
putchar('\n');
}
/* Largura ultima linha */
lul = (altura * 2) - 1;
/*
Ciclo da altura do tronco
Algoritmo: altura / 2
*/
for(i = 1; i <= (altura/2); i++)
{
/*
Por causa do ASCII nao permitir meio char
tive de fazer duas implementacoes diferentes,
uma para quando o valor da altura do tronco
e' par, e outra para quando e' impar.
*/
if (altura % 2)
{
/* Impar */
/*
Numero de Espaços
Algoritmo: (lul / 4) - 1
*/
for(x = 0; x <= (lul/4)-1; x++)
{
putchar(' ');
}
/*
Numero de # (tronco)
Algoritmo: lul / 2
*/
for(x = 0; x <= (lul/2); x++)
{
putchar('#');
}
putchar('\n');
}
else
{
/* Par */
/*
Numero de Espaços
Algoritmo: lul / 4
*/
for(x = 0; x <= (lul/4); x++)
{
putchar(' ');
}
/*
Numero de # (tronco)
Algoritmo: (lul / 2) - 1
*/
for(x = 0; x <= (lul/2)-1; x++)
{
putchar('#');
}
putchar('\n');
}
}
}
[/sourcecode]
A pedido de muitas famílias, foi me imposta a tarefa de fazer um RFC da nova árvorezinha, mas não tenho muito jeito para escrever algoritmos em pseudo-código. Então tal obra heróica fica para o caro leitor, façam me um baseado no código em C e enviem-me!
Segundo as próprias leis já pré-estabelecidas da Árvorezinha, tem de existir uma implementação em Assembly! Então não podia cá faltar a minha versão em x86 Assembly.
[sourcecode language="plain"]
;
; Arvorezinha 2.0
; x86 Assembly
; Copyright (C) 2010 Pedro de Oliveira
; //blol.org
;
; this assembly can never fail
;
BITS 32
GLOBAL main
; Vou usar duas funcoes da libc para o codigo nao crescer gigantescamente
; com rotinas que nao interessam nada para aqui.
EXTERN atoi
EXTERN printf
; Definicao das Variaveis
SECTION .data
argc dd 0
argv dd 0
erro db "ERRO! Executar: %s <altura da arvore>",10,0
card db '#'
newl db 0xa
aste db '*'
espa db ' '
altura dd 0
i dd 1
x dd 0
lul dd 0
; He cometh!
SECTION .text
main:
pop eax ; Ignorar...
pop eax ; Saca o argc da Stack
mov dword [argc], eax ; Guarda o valor na variavel argc
pop ebx ; Saca a posicao de memoria do
; argv[0] da Stack
mov eax, dword [ebx] ; Mete a posicao em EAX
mov [argv], eax ; Guarda-a em argv
add ebx,0x4 ; Salta 4 bytes para a frente
; para o argv[1] ficar em EBX
mov eax, [argc] ; Mete o argc em EAX
cmp eax, 0x2 ; Verifica se e' diferente de 2
jne jafoste ; Se for sai com erro
push dword [ebx] ; Mete o valor de argv[1] na Stack
call atoi ; Corre o atoi com esse valor
mov [altura], eax ; O resultado fica em EAX, guarda
; na variavel altura
ciclo_linhas:
; INICIO - CICLO DAS LINHAS DA ARVORE
mov eax, [i] ; i em EAX
mov ebx, [altura] ; altura em EBX
cmp ebx, eax ; Compara
jb prepara_tronco ; i > altura ? proximo passo
mov dword [x], 0 ; Mete x a 0
ciclo_espacos:
; INICIO - CICLO DE ESPAÇOS ANTES DOS ASTERISCOS
mov eax, [x] ; x em EAX
; pretende-se (altura - i) em EBX
mov ebx, [altura] ; altura em EBX
mov ecx, [i] ; i em ECX
sub ebx, ecx ; EBX - ECX
cmp ebx, eax ; Compara
jbe prepara_asteriscos ; x >= (altura - i) ? proximo passo
push espa ; Espaço
call print ; write()
call incrementa_x
jmp ciclo_espacos ; Volta para o inicio do ciclo
; FIM - CICLO DE ESPAÇOS ANTES DOS ASTERISCOS
prepara_asteriscos:
mov dword [x], 1 ; Mete x a 1
ciclo_asteriscos:
; INICIO - CICLO DE ASTERISCOS (ARVORE)
mov ebx, [x] ; x em EBX
; pretende-se (2 * i) - 1 em EAX
mov eax, 2 ; 2 em EAX
mov ecx, [i] ; i em ECX
mul ecx ; Multiplica EAX por ECX
dec eax ; Subtrai 1 a EAX
cmp eax, ebx ; Compara
jb fim_ciclo_linhas ; x > (2*i)-1 ? proximo passo
push aste ; Asterisco
call print ; write()
call incrementa_x
jmp ciclo_asteriscos ; Volta para o inicio do ciclo
; FIM - CICLO DE ASTERISCOS (ARVORE)
fim_ciclo_linhas:
push newl ; Newline
call print ; write()
call incrementa_i
jmp ciclo_linhas ; Volta para o inicio
; FIM - CICLO DAS LINHAS DA ARVORE
prepara_tronco:
; pretende-se (altura * 2) - 1 em EAX
mov eax, [altura] ; altura em EAX
mov ecx, 2 ; 2 em ECX
mul ecx ; Multiplica EAX por ECX
dec eax ; Subtrai 1 a EAX
mov dword [lul], eax ; Guarda a largura da ultima linha
; em lul
mov dword [i], 1 ; Mete o i a 1
ciclo_linhas_tronco:
; BEGIN - CICLO DAS LINHAS DO TRONCO
mov ecx, [i] ; i em ECX
; pretende-se (altura / 2)
mov eax, [altura] ; altura em EAX
shr eax, 1 ; divide por 2
cmp ecx, eax ; Compara ECX com EAX
jg sair ; i > (altura / 2) ? Adeus!
mov eax, [altura] ; altura em EAX
test eax, 1
je pc_tronco_par_espacos ; e' par?
; --------------------------- IMPAR -------------------------------
pc_tronco_impar_espacos:
mov dword [x], 0 ; Mete-se x a 0
c_tronco_impar_espacos:
; INICIO - CICLO DOS ESPAÇOS ANTES DO TRONCO (IMPAR)
mov ecx, [x] ; x em EAX
; pretende-se (lul / 4) - 1 em EAX
mov eax, [lul] ; lul em EAX
shr eax, 2 ; Divide por 4
dec eax ; Subtrai 1
cmp eax, ecx ; Compara
jb pc_tronco_impar_cardinal; x > (lul/4)-1 ? Next!
push espa ; Espaço
call print ; write()
call incrementa_x
jmp c_tronco_impar_espacos ; Volta para o inicio
; FIM - CICLO DOS ESPAÇOS ANTES DO TRONCO (IMPAR)
pc_tronco_impar_cardinal:
mov dword [x], 0 ; Mete x a 0
c_tronco_impar_cardinal:
; INICIO - CICLO DOS CARDINAIS DO TRONCO (IMPAR)
mov ecx, [x] ; x em ECX
; pretende-se (lul / 2) em EAX
mov eax, [lul] ; lul em EAX
shr eax, 1 ; Divide por 2
cmp eax, ecx ; Compara
jb fim_ciclo_linhas_tronco ; x > (lul/2) ? Next!
push card ; Cardinal
call print ; write()
call incrementa_x
jmp c_tronco_impar_cardinal ; Volta para o inico
; FIM - CICLO DOS CARDINAIS DO TRONCO (IMPAR)
; --------------------- FIM IMPAR --------------------------------
; ----------------------------- PAR ------------------------------
pc_tronco_par_espacos:
mov dword [x], 0 ; Mete x a 0
c_tronco_par_espacos:
; INICIO - CICLO DOS ESPAÇOS ANTES DO TRONCO (PAR)
mov ecx, [x] ; x em ECX
; pretende-se (lul / 4) em EAX
mov eax, [lul] ; lul em EAX
shr eax, 2 ; divide por 4
cmp eax, ecx ; Compara
jb pc_tronco_par_cardinal ; x > (lul / 4) ? Next!
push espa ; Espaço
call print ; write()
call incrementa_x
jmp c_tronco_par_espacos ; Volto para o inico do ciclo
; FIM - CICLO DOS ESPAÇOS ANTES DO TRONCO (PAR)
pc_tronco_par_cardinal:
mov dword [x], 0 ; Mete x a 0
c_tronco_par_cardinal:
; INICIO - CICLO DOS CARDINAIS DO TRONCO (PAR)
mov ecx, [x] ; x em ECX
; pretende-se (lul / 2) - 1 em EAX
mov eax, [lul] ; lul em EAX
shr eax, 1 ; Divide por 2
dec eax ; Subtrai 1
cmp eax, ecx ; Compara
jb fim_ciclo_linhas_tronco ; x > (lul / 2) - 1 ? uhuhuh
push card ; Cardinal
call print ; write()
call incrementa_x
jmp c_tronco_par_cardinal ; Volta para o inicio do ciclo
; FIM - CICLO DOS CARDINAIS DO TRONCO (PAR)
; ----------------------- FIM PAR ----------------------------------
fim_ciclo_linhas_tronco:
push newl
call print
call incrementa_i
jmp ciclo_linhas_tronco ; Volta para o inico do ciclo
; FIM - CICLO DAS LINHAS DO TRONCO
jafoste:
mov eax, [argv] ; Mete o apontador de argv em EAX
push dword eax ; Mete o endereço de argv na Stack
push dword erro ; Mete o endereço da String na Stack
call printf ; Escreve no ecra!
sair:
mov ebx,0x0 ; valor de saida
mov eax,0x1 ; sys_exit
int 0x80
print:
mov ecx,[esp+4] ; Mete o argumento em ECX
mov edx,1 ; Length
mov ebx,1 ; stdout
mov eax,4 ; sys_write
int 0x80
ret
incrementa_x:
mov eax, [x]
inc eax
mov dword [x], eax
ret
incrementa_i:
mov eax, [i]
inc eax
mov dword [i], eax
ret
[/sourcecode]
E aqui vai a prova dos nove:
[sourcecode language="plain"]
falso@lemonparty:~/src/zbr$ make
rm -f arvore2 arvore.o
nasm -f elf arvore.asm -o arvore.o
gcc -g -o arvore2 arvore.o
falso@lemonparty:~/src/zbr$ ./arvore2 4
*
***
*****
*******
###
###
falso@lemonparty:~/src/zbr$ ./arvore2 5
*
***
*****
*******
*********
#####
#####
falso@lemonparty:~/src/zbr$
[/sourcecode]
Espero lançar futuramente um género de Unit Tests, para testar as varias implementações da Arvorezinha 2.0 que possam surgir, para ver se cumprem o standard ou não.
Espero que tenham gostado do post, até à proxima, fiquem bem e joguem muito! Chuuuuuuack!
