GNU/Linux xterm bash 105 views

📌 Demostración: Juego de piedra, papel o tijeras con la computadora en ARM64 Assembly

💻 Lenguajes de Interfaz en TECNM Campus ITT
👨‍💻 Autor: Alejandro Suarez Sandoval
📅 Fecha: 2025/04/10

🎯 Descripción

Este programa es un juego de piedra, papel o tijeras contra con la computadora.
La implementación se realiza en:

Assembly ARM64 para RaspbianOS en Raspberry Pi

🔧 Compilación en Raspberry Pi (ARM64)

as jankenpon.s -o jankenpon.o  
ld jankenpon.o -o jankenpon

▶️ Ejecución

./jankenpon

👀 Código fuente

🔗 Código fuente en Gist: Programa 40 Juego de piedra, papel o tijeras con la computadora mostrando resultado del juego en terminal Código Assembly ARM64 para RaspbianOS

/*
 ______  ____               ____  __ __
/\  _  \/\  _`\   /'\_/`\  /'___\/\ \\ \
\ \ \L\ \ \ \L\ \/\      \/\ \__/\ \ \\ \
 \ \  __ \ \ ,  /\ \ \__\ \ \  _``\ \ \\ \_
  \ \ \/\ \ \ \\ \\ \ \_/\ \ \ \L\ \ \__ ,__\
   \ \_\ \_\ \_\ \_\ \_\\ \_\ \____/\/_/\_\_/
    \/_/\/_/\/_/\/ /\/_/ \/_/\/___/    \/_/

♡ ∩_∩
(„• ֊ •„)♡
| ̄U U ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄|
| • Lenguajes de Interfaz en TECNM Campus ITT                                 |
| • Autor: Alejandro Suarez Sandoval                                          |
| • Fecha: 2025/04/10                                                         |
| • Descripción: Programa Juego de piedra, papel o tijeras contra la          |
|   computadora  en Rust y Assembly ARM64 para RaspbianOS.                    |
| • Demostración:                                                             |
|   https://asciinema.org/a/714719                                            |
| • Compilación (Raspberry Pi ARM64):                                         |
|     as jankenpon.s -o jankenpon.o                                           |
|     ld jankenpon.o -o jankenpon                                             |
| • Ejecución: ./jankenpon                                                    |
 ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄

⠂⠄⠄⠂⠁⠁⠂⠄⠄⠂⠁⠁⠂⠄⠄⠂ ⠂⠄⠄⠂☆
═════════•°• Demostración Código en lenguaje Rust •°•═══════

use std::io::{self, Write};
use rand::Rng;

#[derive(Debug, Clone, Copy, PartialEq)]
enum Opcion {
    Piedra = 1,
    Papel = 2,
    Tijeras = 3,
}

#[derive(Debug)]
enum Resultado {
    Ganas,
    Pierdes,
    Empate,
}

fn numero_a_opcion(num: u8) -> Option<Opcion> {
    match num {
        1 => Some(Opcion::Piedra),
        2 => Some(Opcion::Papel),
        3 => Some(Opcion::Tijeras),
        _ => None,
    }
}

fn opcion_a_texto(opcion: Opcion) -> &'static str {
    match opcion {
        Opcion::Piedra => "Piedra",
        Opcion::Papel => "Papel",
        Opcion::Tijeras => "Tijeras",
    }
}

fn determinar_ganador(usuario: Opcion, computadora: Opcion) -> Resultado {
    if usuario == computadora {
        return Resultado::Empate;
    }

    match (usuario, computadora) {
        (Opcion::Piedra, Opcion::Tijeras) => Resultado::Ganas,
        (Opcion::Papel, Opcion::Piedra) => Resultado::Ganas,
        (Opcion::Tijeras, Opcion::Papel) => Resultado::Ganas,
        _ => Resultado::Pierdes,
    }
}

fn obtener_eleccion_usuario() -> Option<Opcion> {
    print!("Elige: 1-Piedra, 2-Papel, 3-Tijeras, 0-Salir: ");
    io::stdout().flush().unwrap();

    let mut entrada = String::new();
    io::stdin().read_line(&mut entrada).expect("Error al leer la entrada");

    let num = entrada.trim().parse::<u8>().ok()?;
    
    if num == 0 {
        return None;
    }
    
    numero_a_opcion(num)
}

fn eleccion_computadora() -> Opcion {
    let mut rng = rand::thread_rng();
    let num = rng.gen_range(1..=3);
    numero_a_opcion(num).unwrap()
}

fn main() {
    println!("¡Bienvenido a Piedra, Papel o Tijeras!");

    loop {
        let opcion_usuario = match obtener_eleccion_usuario() {
            Some(opcion) => opcion,
            None => {
                println!("¡Gracias por jugar! Adiós.");
                break;
            }
        };

        println!("Tu elección: {}", opcion_a_texto(opcion_usuario));

        let opcion_computadora = eleccion_computadora();
        println!("PC eligió: {}", opcion_a_texto(opcion_computadora));

        match determinar_ganador(opcion_usuario, opcion_computadora) {
            Resultado::Ganas => println!("¡Ganaste!"),
            Resultado::Pierdes => println!("¡Perdiste!"),
            Resultado::Empate => println!("¡Empate!"),
        }
        
        println!();
    }
}

════════════════════•°• ☆ •°•══════════════════════════════
/*

/* ⠂⠄⠄⠂⠁⠁⠂⠄⠄⠂⠁⠁⠂⠄⠄⠂ ⠂⠄⠄⠂☆
═════════════•°• Código en ARM64 Assembly •°•═════════════ */

// Constantes
.equ SYS_READ, 63       // Syscall para leer
.equ SYS_WRITE, 64      // Syscall para escribir
.equ SYS_EXIT, 93       // Syscall para salir
.equ STDIN, 0           // Descriptor de archivo para entrada estándar
.equ STDOUT, 1          // Descriptor de archivo para salida estándar
.equ STDERR, 2          // Descriptor de archivo para error estándar
.equ PIEDRA, 1          // Valor para piedra
.equ PAPEL, 2           // Valor para papel
.equ TIJERAS, 3         // Valor para tijeras
.equ MAX_RAND, 3        // Valor máximo para generación aleatoria

.section .data
// Constantes para el generador congruencial lineal
lcg_a:
    .quad 6364136223846793005
lcg_c:
    .quad 1442695040888963407

bienvenida:
    .ascii "¡Bienvenido al juego de Piedra, Papel o Tijeras!\n\n"
bienvenida_len = . - bienvenida

menu:
    .ascii "Escoge una opción:\n"
    .ascii "1. Piedra\n"
    .ascii "2. Papel\n"
    .ascii "3. Tijeras\n"
    .ascii "0. Salir\n"
    .ascii "Tu elección: "
menu_len = . - menu

eleccion_pc:
    .ascii "La computadora eligió: "
eleccion_pc_len = . - eleccion_pc

piedra_str:
    .ascii "Piedra\n"
piedra_len = . - piedra_str

papel_str:
    .ascii "Papel\n"
papel_len = . - papel_str

tijeras_str:
    .ascii "Tijeras\n"
tijeras_len = . - tijeras_str

ganaste:
    .ascii "¡Has ganado!\n\n"
ganaste_len = . - ganaste

perdiste:
    .ascii "¡Has perdido!\n\n"
perdiste_len = . - perdiste

empate:
    .ascii "¡Empate!\n\n"
empate_len = . - empate

opcion_invalida:
    .ascii "Opción inválida. Intenta de nuevo.\n\n"
opcion_invalida_len = . - opcion_invalida

adios:
    .ascii "¡Gracias por jugar! ¡Hasta pronto!\n"
adios_len = . - adios

.section .bss
    .lcomm buffer, 8           // Buffer para la entrada del usuario
    .lcomm seed, 8             // Semilla para el generador de números aleatorios

.section .text
.global _start

_start:
    // Inicializar la semilla con el tiempo actual (contador de ciclos)
    mrs x0, CNTVCT_EL0         // Leer el contador de ciclos virtual
    adr x20, seed              // Obtener la dirección de seed
    str x0, [x20]              // Guardar como semilla

    // Mostrar mensaje de bienvenida
    mov x0, STDOUT
    adr x1, bienvenida
    mov x2, bienvenida_len
    mov x8, SYS_WRITE
    svc 0

main_loop:
    // Mostrar menú
    mov x0, STDOUT
    adr x1, menu
    mov x2, menu_len
    mov x8, SYS_WRITE
    svc 0

    // Leer elección del usuario
    mov x0, STDIN
    adr x1, buffer
    mov x2, 8
    mov x8, SYS_READ
    svc 0

    // Procesar la elección del usuario
    ldrb w19, [x1]           // Cargar el primer byte
    sub w19, w19, '0'        // Convertir ASCII a entero

    // Comprobar si el usuario quiere salir
    cmp w19, 0
    beq salir

    // Comprobar si la elección es válida
    cmp w19, 1
    blt opcion_invalida_msg
    cmp w19, 3
    bgt opcion_invalida_msg

    // La elección es válida, generar la elección de la computadora
    bl random
    mov w20, w0              // w20 = elección de la computadora (1-3)

    // Mostrar la elección de la computadora
    mov x0, STDOUT
    adr x1, eleccion_pc
    mov x2, eleccion_pc_len
    mov x8, SYS_WRITE
    svc 0

    // Imprimir la elección de la computadora
    cmp w20, PIEDRA
    beq imprimir_piedra
    cmp w20, PAPEL
    beq imprimir_papel
    cmp w20, TIJERAS
    beq imprimir_tijeras

continuar_despues_imprimir:
    // Determinar el resultado
    cmp w19, w20
    beq es_empate

    // Comprobar si el usuario gana
    cmp w19, PIEDRA
    beq check_piedra
    cmp w19, PAPEL
    beq check_papel
    cmp w19, TIJERAS
    beq check_tijeras
    b main_loop

check_piedra:
    cmp w20, TIJERAS
    beq usuario_gana
    b usuario_pierde

check_papel:
    cmp w20, PIEDRA
    beq usuario_gana
    b usuario_pierde

check_tijeras:
    cmp w20, PAPEL
    beq usuario_gana
    b usuario_pierde

imprimir_piedra:
    mov x0, STDOUT
    adr x1, piedra_str
    mov x2, piedra_len
    mov x8, SYS_WRITE
    svc 0
    b continuar_despues_imprimir

imprimir_papel:
    mov x0, STDOUT
    adr x1, papel_str
    mov x2, papel_len
    mov x8, SYS_WRITE
    svc 0
    b continuar_despues_imprimir

imprimir_tijeras:
    mov x0, STDOUT
    adr x1, tijeras_str
    mov x2, tijeras_len
    mov x8, SYS_WRITE
    svc 0
    b continuar_despues_imprimir

es_empate:
    mov x0, STDOUT
    adr x1, empate
    mov x2, empate_len
    mov x8, SYS_WRITE
    svc 0
    b main_loop

usuario_gana:
    mov x0, STDOUT
    adr x1, ganaste
    mov x2, ganaste_len
    mov x8, SYS_WRITE
    svc 0
    b main_loop

usuario_pierde:
    mov x0, STDOUT
    adr x1, perdiste
    mov x2, perdiste_len
    mov x8, SYS_WRITE
    svc 0
    b main_loop

opcion_invalida_msg:
    mov x0, STDOUT
    adr x1, opcion_invalida
    mov x2, opcion_invalida_len
    mov x8, SYS_WRITE
    svc 0
    b main_loop

salir:
    // Mostrar mensaje de despedida
    mov x0, STDOUT
    adr x1, adios
    mov x2, adios_len
    mov x8, SYS_WRITE
    svc 0

    // Salir del programa
    mov x0, 0
    mov x8, SYS_EXIT
    svc 0

// Función para generar un número aleatorio entre 1 y 3
random:
    // Cargar la semilla actual
    adr x3, seed
    ldr x0, [x3]

    // Cargar las constantes desde la sección de datos
    adr x1, lcg_a
    ldr x1, [x1]
    adr x2, lcg_c  
    ldr x2, [x2]

    // Realizar la operación del LCG: x_next = (a * x + c) mod 2^64
    mul x0, x0, x1
    add x0, x0, x2
    str x0, [x3]               // Guardar la nueva semilla

    // Reducir al rango [1,3]
    lsr x0, x0, 32             // Usar los bits superiores que tienen mejor distribución
    mov x1, MAX_RAND
    udiv x2, x0, x1
    msub x0, x2, x1, x0        // x0 = x0 % MAX_RAND (0-2)
    add w0, w0, 1              // Convertir a rango 1-3
    
    ret