;------------------------------------------------------------------------------ ; ; Programação em Baixo Nível (PBN) ;------------------------------------------------------------------------------ ; Projeto final de curso: advinha.asm ; Data: 23/08/2025 ; Autor: Daniel Ramos Gonçalves ; E-mail: daniel@drginfo.com.br ; Professor/Instrutor/Mentor: Blau Araujo (MUITO FERA) ; ; Proposta: Criar um programa em Assembly, jogo de advinhação. ; O programa deve gerar um número aleatório, e você deve advinhar. ; Entrar com um número inteiro entre 1 e 100. Deve ter críticas ; de Maior / Menor / Igual. Deve aceitar somente números, e qualquer ; entrada diferente deve ser decartada e encerrar o programa com ; uma mensagem de erro. ; ;------------------------------------------------------------------------------ ;------------------------------------------------------------------------------ ; difinições de pré-processamento padronizadas ;------------------------------------------------------------------------------ %define SYS_READ 0 %define SYS_STDIN 0 %define SYS_WRITE 1 %define SYS_STDOUT 1 %define SYS_TIME 201 %define SYS_EXIT 60 %define SYS_OK 0 %define SYS_ERR 1 %define BUF_SIZE 2048 %define BUF_COUNT 5 ;------------------------------------------------------------------------------ section .rodata ;------------------------------------------------------------------------------ ; mensagens que serão exibidas na tela... msg_ini db "Digite um número entre 1 e 100: ", 0 len_msg_ini equ $-msg_ini ; com a mensagem entre crases, ela aceita caracteres de controle como '\n' msg_maior db `Muito acima! Tente novamente...\n`, 0 len_msg_maior equ $-msg_maior msg_menor db `Muito abaixo! Tente novamente...\n`, 0 len_msg_menor equ $-msg_menor msg_ok_ini db "Você acertou com: ", 0 len_msg_ok_ini equ $-msg_ok_ini msg_ok_end db " Tentativas!", 10, 0 len_msg_ok_end equ $-msg_ok_end ; mensagem de uso...caso não digite nada ou digitação inválida... msg_uso db "Você deve digitar um numero inteiro entre 1 e 100.", 10, 0 len_msg_uso equ $-msg_uso ;------------------------------------------------------------------------------ section .bss buffer resb BUF_SIZE tentativas resb BUF_COUNT ;------------------------------------------------------------------------------ ; seção do codigo em si... ;------------------------------------------------------------------------------ section .text global _start _start: ;------------------------------------------------------------------------------ ; gera um número inteiro randômico de 0..100 e salva resultado em r9 ; registradores: eax, edx, ebx, r9 ; resultado: r9 ;------------------------------------------------------------------------------ _num_rand: mov eax, SYS_TIME mov edx, 0 syscall mov ebx, 100 div ebx add edx, 1 mov r9d, edx ;-------------------------------------------------------- ; rdi rsi rdx ; | | | ; syscall: i64 read(int fd, void *buf[.count], u64 size) ; | ; rax -> quantidade de bytes lidos (-1 = erro) ;-------------------------------------------------------- _msg_ini: mov rax, SYS_WRITE ; sys_write = 1 mov rdi, SYS_STDOUT ; fd=1 (stdout) mov rsi, msg_ini ; Mensagem Inicial mov rdx, len_msg_ini ; Tamanho da mensagem syscall mov rax, SYS_READ ; sys_read = 0 mov rdi, SYS_STDIN ; fd=0 (stdin) mov rsi, buffer ; buffer da leitura (armazenamento) mov rdx, BUF_SIZE ; máximo caracteres a ler syscall ; retorna quantidade de bytes lidos em rax ;-------------------------------------------------------- ; conversão de string para inteiro... ; registradores: rax, rbx, rcx, r8 ;-------------------------------------------------------- _convert_strtoint: dec rax mov byte [buffer + rax], 0 ; garante terminador nulo '\0' mov rbx, 10 ; multiplicador (x10) xor rcx, rcx ; contador = 0 xor rax, rax ; resultados da conversão .digit_loop: mov r8b, byte [buffer + rcx] ; caractere em buf[rcx] cmp r8b, '0' ; caractere < 0x30? jl _done ; se menor, termina cmp r8b, '9' ; caractere > 0x39? jg _done ; se maior, termina sub r8b, 0x30 ; converte de ASCII para numero mul rbx ; rdx:rax = rax * 10 (rbx = 10) add rax, r8 ; armazena dígito em rax inc rcx ; incrementa para receber o próximo byte jmp .digit_loop ;-------------------------------------------------------- ; conversão de inteiro para string... ; registradores: rax(int), rbx, rcx, r12, r15 ;-------------------------------------------------------- _convert_inttostr: mov rcx, tentativas ; buffer para receber o inteiro mov rbx, 10 ; divisor mov r12, 0 ; contador de dígitos .proximo_digito: xor rdx, rdx ; limpa rdx para divisão div rbx ; divide rdx:rax/rbx = rax / 10, resto em rdx add rdx, '0' ; converte o resto(digito) para seu caracter ASCII push rdx ; salva rdx na pilha inc r12 ; incrementa contador de dígitos cmp rax, 0 ; verifica se o quociente é zero jnz .proximo_digito ; se não, continua o loop .print_str: cmp r12, 0 ; verifica se ainda há digitos para desempilhar jz _str_final ; se não, pula para o final pop rax ; desempilha o caractere do dígito em rax mov [rcx], al inc rcx dec r12 jmp .print_str _str_final: mov rsi, tentativas ; Endereço do buffer com a string mov rdx, rcx ; Endereço do final da string sub rdx, rsi ; Calcula o tamanho da string (final - início) ret ;-------------------------------------------------------------------- ; compara o numero digitado que está em 'rax' com o numero gerado ; pelo systema 'random' 'r9' ( rax < r9 ?) ;-------------------------------------------------------------------- _compara: cmp rax, 0 ; se rax == 0, erro je _exit_err ; pula para saida de erro cmp rax, 0x64 ; se maior que 100, erro ja _exit_err ; pula para saida de erro cmp rax, r9 ; compara os numeros je .igual ; se for igual, pula para '.igual' jb .menor ; se for menor pula para '.menor' ja .maior ; se for mais alto pula para '.maior' .menor: mov rsi, msg_menor mov rdx, len_msg_menor call _print call _msg_ini .maior: mov rsi, msg_maior mov rdx, len_msg_maior call _print call _msg_ini .igual: ; primeira parte da mensagem... mov rsi, msg_ok_ini mov rdx, len_msg_ok_ini call _print ; quantidade de tentativas... mov rax, r15 ; copia qtd tentativas para rax mov rsi, tentativas ; buffer de tentativas call _convert_inttostr call _print ; final da mensagem... mov rsi, msg_ok_end mov rdx, len_msg_ok_end call _print call _exit_ok _done: inc r15 ; incrementa contador jmp _compara ;---------------------------------------------------- ; Imprime a mensagem na saída padrão STD_OUT FD = 1 ;---------------------------------------------------- _print: mov rax, SYS_WRITE mov rdi, SYS_STDOUT syscall ret ;---------------------------------------------------- ; Imprime a mensagem na saída padrão se acertou ;---------------------------------------------------- ;_print_ok: ; mov rax, SYS_WRITE ; mov rdi, r15 ; syscall ;jmp _exit_ok ;-------------------------------------------------------- ; saída em caso de erro... ;-------------------------------------------------------- _exit_err: mov rsi, msg_uso mov rdx, len_msg_uso call _print mov rax, SYS_EXIT mov rdi, SYS_ERR syscall ;-------------------------------------------------------- ; saída em caso de sucesso... ;-------------------------------------------------------- _exit_ok: mov rax, SYS_EXIT mov rdi, SYS_OK syscall