Examen: 2025_06_24:Robótica - myTeachingURJC/2019-20-LAB-AO GitHub Wiki

Examen convocatoria extraordinaria: 2025-06-24. Ingeniería en Robótica Software

  • Tiempo: 2h
  • Descripción: Examen del Laboratorio del grado de Ingeniería en Robótica Software. Convocatoria extraordinaria
  • Fecha: 2025/Junio/24

Contenido

Enunciado

Partiendo de la solución al examen del parcial 3 de la convocatoria de mayo, que se proporciona en la plantilla, se pide la realización de una serie de modificaciones. El programa tiene una subrutina intermedia cambio_contrasena que se utiliza para solicitar un cambio de contraseña. Dicha subrutina ha de:

  • pedir contraseña al usuario
  • comprobar que tiene entre 6 y 12 caracteres
  • comprobar que no es igual que la almacenada (se recibe como argumento)
  • comprobar que aplica la política de caracteres garantizando que la contraseña contiene un dígito, una mayúscula, una minúscula y un carácter especial.

El examen consta de varios ejercicios, aunque entre todos suman 12 puntos, se valorará sobre 10 puntos, dejando la opción de no implementar alguno de los mismos.

Ejercicio 1 (2,5 puntos)

Confirmación de nueva contraseña. En una aplicación real, la nueva contraseña no suele ser visible para el usuario cuando la introduce, por lo que antes de establecer la nueva contraseña conviene pedirle al usuario de nuevo la contraseña que quiere establecer por si acaso tuvo un error al introducir la contraseña deseada en el primer intento. En la subrutina cambia_contrasena, utilizando la misma subrutina que pide la contraseña, se ha de pedir de nuevo la contraseña, con el mensaje al usuario: “Reintroduzca la contraseña deseada: y comprobar que es igual que la introducida anteriormente. En caso de que no sean iguales, se ha de mostrar el siguiente mensaje: “Las contraseñas introducidas no son iguales” (que ha de definirse en el module inputoutput) y retornar error al cambiar la contraseña.

Ejercicio 2 (2,5 puntos)

Refactorización (cambiar estructura de código sin cambiar la funcionalidad) de la subrutina cambia_contrasena extrayendo a otra subrutina intermedia toda la lógica que se encarga de comprobar que la contraseña contiene los diferentes tipos de caracteres (una mayúscula, una minúscula, un dígito y un carácter especial). La nueva subrutina ha de recibir como argumento la contraseña a analizar y ha de retornar si cumple las políticas (1) o si no las cumple (0).

Consejo: La subrutina original guarda en pila varias variables temporales. Por simplicidad, se recomienda no actualizar los índices de los elementos que se guardan en la pila en la nueva subrutina, aunque eso suponga dejar algún hueco en la pila.

Ejercicio 3 (1,5 punto)

Modificar el programa para permitir que el usuario pueda introducir contraseñas de al menos 20 caracteres (aunque no se modifica la política del tamaño de las contraseñas). También añadir mensajes específicos por cada tipo de error, a modo de ejemplo se pueden utilizar los siguientes:

  • “Longitud de contraseña incorrecta”
  • “Incumplimiento de políticas de caracteres”
  • “Contraseña introducida es igual a la almacenada”
  • “Fallo en confirmación de contraseña” Se ha de respetar arquitectura de programa e incluir en modulo inputoutput.asm todas las funciones relacionadas con la entrada/salida de la aplicación.

Ejercicio 4 (1,5 puntos)

Establecimiento de contraseña. En el caso de que en la llamada a cambio contraseña no se reciba la contraseña antigua, se considera como el caso de establecimiento de contraseña. En la subrutina cambia_contrasena, se ha de asegurar que se cumplen todas las políticas que aplican a las contraseñas salvo que sea igual que la anteriormente almacenada.

Ejercicio 5 (4 puntos)

Establecimiento de una nueva política respecto a la nueva contraseña: La nueva contraseña no debe parecerse a la anterior, la nueva contraseña ha de variar en al menos dos caracteres respecto a la almacenada Esta nueva política ha de implementarse en una subrutina intermedia nueva que reciba las dos contraseñas como argumento y retorne el número de diferencias entre las dos cadenas. Dicha subrutina ha de ser invocada por cambia_contrasena, la cual en el caso de que no se cumpla la misma ha de dar un mensaje de error especifico.

Ejemplos:

  1. “Amanecer" comparado con “AmanecerXYZ" tiene 3 diferencias, por lo que ha de retornar 3
  2. “Sal34/gas” comparado con “Sal23/gas” tiene 2 diferencias, por lo que ha de retornar 0
  3. “Sal34/gas” comparado con “sAl34/gas” tiene 3 diferencias, por lo que ha de retornar 3.

Entrega

Se ha de entregar un fichero comprimido conteniendo todos los ficheros del programa, sin crear ningún fichero nuevo y sin cambiar el nombre de los ficheros provistos. El nombre del fichero comprimido ha de seguir la siguiente norma: entrega_x_y_z_v_w.zip

A modo de ejemplo: Si solo se entregasen los ejercicios 1, 3 y 4, el nombre debería ser entrega_1_3_4.zip Adicionalmente, si se deja algún ejercicio incompleto se puede indicar con el sufijo "in" tras el número. Es decir, si se ha implementado 1, 3 y 4; y además el 5 está incompleto, el nombre del fichero ha de ser entrega_1_3_4_5in.zip.

Aunque el ejercicio esté incompleto, ha de ensamblar. Considere la posibilidad de comentar el código que no ensambla o no funciona correctamente indicando lo realizado y los problemas vigentes.

Solución

#--------------------------------------------------------
#-- cambia_contrasena
#--------------------------------------------------------
#-- Subrutina que pide al usuario una nueva contraseña
#-- La contraseña debe cumplir la siguiente especificación:
#--   - Su longitud debe estar entre 6 y 12 caracteres
#-    - Contiene al menos un digito
#-    - Contiene al menos una letra mayúscula
#-    - Contiene al menos una letra miníscula
#-    - Contiene al menos un carácter especial:  !"#$%&'()*+,-.
#-    - La nueva contraseña no puede ser igual a la anterior
#---------------------------------------------------------------
# ENTRADAS:
# * a0: (string) Contraseña antigua
# SALIDAS:
# * a0: (int) 1 - Nueva contraseña disponible, 0 - Error 
# * a1: (string) Contraseña nueva
#----------------------------------------------------------------
	
# Implementa la subrutina en pequeños pasos asegurando
# que cada uno de ellos funciona
#
# Posibles pasos:
#
# 1. Petición de contraseña a usuario y retorno de 
#    la misma en la subrutina 
# 2. Comparación para comprobar que no es la misma contraseña almacenada
# 3. Obtención de la longitud de la cadena, comprobación de que está
#    en el intervalo esperado. Gestión de error en el caso de que 
#    no cumpla las condiciones
# 4. Comprobación de la primera restricción respecto a
#    los caracteres: existencia de un carácter especial en la nueva contraseña
#    -Definición de un contador para los caracteres especiales
#    -Iteración, carácter a carácter, sobre la cadena que contiene 
#     la contraseña y comprobación si se trata de un carácter especial. 
#     En cuyo caso, el contador se incrementaría
#    - Si el contador se ha incrementado, la contraseña es válida. 
#      En caso contrario, gestión el error.
# 5. Se continúa con el resto de restricciones
# 
# Otras consideraciones:
#  - Es necesario respetar ABI de RISC-V, especialmente con el manejo de los registros
	
	.globl cambia_contrasena

#==========================================================				
# SEGMENTO DE DATOS
	.data	
# TODO: Variables necesarias para la implementación de
#  la subrutina cambia_contrasena

new_password_1:
	.space 30 #J25: modificado
new_password_2:   #J20: nuevo
	.space 30


#==========================================================				
# SEGMENTO DE CÓDIGO		
	.text

cambia_contrasena:
# TODO: Implementación de la subrutina aquí

#-- En esta implementacion se utilizan variables locales
#-- que se guardan en la pila
#-- Esta es la organizacion:

# Organizacion de la pila
#-------------
# 12: RA
#----
# 8: Direccion Contraseña antigua
#----
# 4: Direccion contraseña nueva
#-----
	addi sp, sp, -16
	sw ra, 12(sp) 
	sw a0, 8(sp) #-- Contraseña antigua
	
	# Pedir nueva contraseña
	la a0, pwd1_msg
	la a1, new_password_1
	jal pide_contrasena
	
	# Guardar contraseña introducida en la pila
	la a0, new_password_1
	sw a0, 4(sp) 
	
	#------- Comprobar condiciones
	 
	#---- La longitud debe estar entre 6 y 12 caracteres
	#-- Obtener longitud de la contraseña del usuario	
	jal longitudString
	
	#-- Comprobar la longitud minima
	li t0, 6 
	blt a0, t0, cc_no_cumple_longitud
	
	#-- Comprobar la longitud maxima
	li t1, 12 
	bgt a0, t1, cc_no_cumple_longitud

	#J25 comprueba pol�ticas de caracteres
	la a0, new_password_1
	jal comprobar_politicas_caracteres
	beqz a0, cc_no_cumple

	#J25 nueva pol�tica: diferencias en strings
	la a0, new_password_1
	lw a1, 8(sp)
	jal numeroDiferenciasStrings
	li t6, 2 #carga numero de diferencias permitidas
	ble a0, t6, cc_no_cumple_diferencias

	
	#-- Si llega hasta aqui es que la contraseña cumple las
	#-- condiciones

	# J25: Pide de nuevo la contrase�a para comprobar que es igual a la introducida por primera vez	
	
	la a0, pwd2_msg
	la a1, new_password_2
	jal pide_contrasena
	
	la a0, new_password_1
	la a1, new_password_2
	jal comparaStrings
	bnez a0, cc_segunda_contrasena_diferente


	#-- Ahora se comprueba que es diferente a la almacenada
	lw a0, 8(sp)
	# J25 -> Comprobacion si es establecimiento contrase�a
	lb t0, 0(a0)                       
	beqz t0, cc_establecimiento_contrasena
	# J25 -> Comprobacion si es establecimiento contrase�a
	lw a1, 4(sp)
	jal comparaStrings
	beqz a0, cc_misma_contrasena

cc_establecimiento_contrasena: #J25

	#-- Todo ok
	#-- Indicar que contraseña cambiada
	li a0, 1			
	
	#-- Devolver direccion de la contraseña
	lw a1,4(sp)	
	b cc_fin

cc_no_cumple_diferencias:
	jal contrasena_similar_anterior
	li a0, 0
	b cc_fin

#J25
cc_no_cumple_longitud:
	jal contrasena_no_cumple_longitud
	li a0, 0
	b cc_fin

cc_no_cumple:
	jal contrasena_no_cumple_caracteres
	li a0, 0
	b cc_fin		

cc_misma_contrasena:
	# Imprimir mensaje indicando que nueva contraseña 
	# NO es valida por ser igual que la anterior
	jal error_misma_contrasena
		
	#-- Indicar que contraseña NO cambiada
	li a0, 0
	b cc_fin

	#J25: nuevo	
cc_segunda_contrasena_diferente:
	# Imprimir mensaje indicando que contrase�a introducida por segunda vez es diferente
	jal error_segunda_contrasena_diferente
		
	#-- Indicar que contraseña NO cambiada
	li a0, 0
	b cc_fin

		
cc_fin:				
	lw ra,12(sp)      #restaura RA
	addi sp, sp, 16										

	ret
	
	
# A0: password
# Salida:
# A0: Cumple
comprobar_politicas_caracteres:
	addi sp, sp, -32
	sw ra, 28(sp) 
	sw a0, 20(sp)


	# Recorrer la cadena comprobando si hay al menos 
	# un carácter de cada tipo

	# Variables temporales en la pila
	sw zero, 12(sp) # cuenta dígitos
	sw zero, 8(sp)  # cuenta mayúsculas
	sw zero, 4(sp)  # cuenta minúsculas
	sw zero, 0(sp)  # cuenta caracteres especiales
	
	lw t4, 20(sp) #-- t4: Puntero a contraseña
	sw t4, 16(sp)
	
cpc_comprueba_condiciones_contrasena:
	
	#-- Recorrer la cadena
	
	#-- Comprobar si se ha llegado al final de la cadena	
	lw t5, 16(sp)
	lb t6, 0(t5)  #-- t6: Caracter actual
	beqz t6, cpc_fin_agregacion
	
	#-- Si se encuentra \n se termina 
	li t0, '\n'
	beq t6,t0,cpc_fin_agregacion
	
	#-- Comprobar si el caracter actual es un digito
	mv a0, t6
	jal esDigito
	
	#-- Incrementar contador de digitos en la pila
	lb t0, 12(sp)
	add t0, t0, a0
	sw t0, 12(sp)

    #-- Obtener caracter actual de la pila
	lw t5, 16(sp)
	lb t6, 0(t5)
	
	#-- Comprobar si el caracter actual es mayusculas
	mv a0, t6
	jal esMayuscula

	#-- Incrementar contador de digitos en mayusculas
	lb t0, 8(sp)
	add t0, t0, a0
	sw t0, 8(sp)

	#-- Obtener el caracter actual de la pila
	lw t5, 16(sp)
	lb t6, 0(t5)
	
	#-- Comprobar si el caracter actual esta en minusculas
	mv a0, t6
	jal esMinuscula
	
	#-- Incrementar el contador de minusculas
	lb t0, 4(sp)
	add t0, t0, a0
	sw t0, 4(sp)
	
	#-- Leer caracter actual
	lw t5, 16(sp)
	lb t6, 0(t5)
	
	#-- Comprobar si es un caracter especial
	mv a0, t6
	jal esCaracterEspecial
	
	#-- Incrementar contador de caracteres especiales
	lb t0, 0(sp)
	add t0, t0, a0
	sw t0, 0(sp)
	
	#-- Incrementar el puntero de cadena
	#-- para apuntar al siguiente caracter
	lw t5,16(sp)
	addi t5,t5,1
	sw t5,16(sp)
	
	#-- Repetir
	b cpc_comprueba_condiciones_contrasena	
		
		
	#-- Se ha terminado de analizar la cadena	
cpc_fin_agregacion:

	#-- Ahora se comprueba si se cumplen los criterios
	

	# comprueba numero de digitos, mayusculas, minusculas y caracteres especiales
	
	#-- Comprueba que el numero de digitos sea > 0
	lw t0, 12(sp)
	beqz t0, no_cumple_politica
	
	#-- Comprueba que el numero de mayusculas sea > 0
	lw t0, 8(sp)
	beqz t0, no_cumple_politica
	
	#-- Comprueba que el numero de minusculas sea > 0
	lw t0, 4(sp)
	beqz t0, no_cumple_politica
	
	#-- Comprueba que el numero de caracteres especiales sea > 0
	lw t0, 0(sp)
	beqz t0, no_cumple_politica

	li a0, 1
	b cpc_fin

no_cumple_politica:	

	li a0, 0	

cpc_fin:
												
	lw ra,28(sp)      #restaura RA
	addi sp, sp, 32										
	ret	
  • Fichero: Inputoutput.asm:
# Módulo que incluye todas las funciones de entrada/salida de la aplicación
	
	.include "servicios.asm"
	
	#-- Funciones de interfaz
	.globl pide_contrasena         
	.globl contrasena_no_cumple_criterios 
	.globl contrasena_no_cumple_longitud #J25: new
	.globl contrasena_no_cumple_caracteres #J25: new 
	.globl pwd1_msg
	.globl pwd2_msg #J25: new
	.globl error_contrasena_no_actualizada
	.globl error_misma_contrasena
	.globl error_segunda_contrasena_diferente #J25: new
	.globl contrasena_cambiada  
	.globl contrasena_similar_anterior #J25: new          
		
	.data
pwd1_msg: 
	.string "Introduzca la nueva contraseña > "
pwd2_msg: #J25: New prompt
	.string "Reintroduzca la nueva contraseña > "

pwd_not_matching_length: #J25
	.string "Error. Longitud de contrasena es incorrecta, debe estar entre 6 y 12 caracteres"
pwd_not_matching_char_policies: #J25
	.string "Error. La contraseña debe contener al menos un digito, una minuscula, una mayuscula y un caracter especial"

pwd_not_matching_criteria:
	.ascii "Error. La contraseña no cumple los requisitos:\n"
	.ascii "* Longitud: 6-12 caracteres\n"
	.ascii "* Debe contener al menos un dígito, una letra minúscula,"
	.asciz " una letra mayúscula y un carácter especial\n"

pwd_quite_similar:
	.string "Error. La contraseña es similar a la existente"

pwd_not_matching:
	.string "Error. Las contraseñas introducidas no son iguales"

same_new_pwd:
	.string "Error. La nueva contraseña ha de ser diferente a la anterior"

second_pwd_different:  #J25: Nuevo mensaje de error
	.string "Error. La contraseña no ha sido confirmada"

pwd_not_updated:
	.string "\nError. Contraseña no actualizada\n"

pwd_updated:
	.string "Contraseña actualizada > "
  
	.text
	
#---------------------------------------------------------------------
# pide_contrasena
# Subrutina que imprime un prompt (mensaje para pedir contraseña) y 
# retorna la contraseña utiliza por el usuario
#---------------------------------------------------------------------
# ENTRADAS:
# - a0: (string) Prompt (mensaje) que invita a introducir contraseña
# - a1: (space for string -argumento de salida) Dirección de memoria
#       donde se puede alojar la contraseña.
#       Ha de tener al menos 13 bytes: 12 caracteres + fin de string)
# SALIDAS:
#  -
#----------------------------------------------------------------------
pide_contrasena:
	mv t0, a0

	# Imprime '\n'
	li a0, '\n'
	li a7, PRINT_CHAR
	ecall
	# Imprime mensaje
	mv a0, t0
	li a7, PRINT_STRING
	ecall

	# Lee nueva contraseña 
	mv a0,a1
	li a1, 13
	li a7, READ_STRING
	ecall

	# Quita el \n de la entrada
	mv t0, a0
	li t2, '\n'
pc_bucle:
	lb t1,0(t0)
	beqz t1, pc_fin
	beq t1, t2, pc_remove
	addi t0, t0, 1
	b pc_bucle
pc_remove:
	sb zero, 0(t0)
pc_fin:			
	ret

#-------------------------------------------------------------------
# contrasena_no_cumple_criterios
# Imprime por consola mensaje para indicar que la contraseña 
# no cumple los criterios
#-------------------------------------------------------------------
# Argumentos:
# -
# Salida
# -
#-------------------------------------------------------------------
contrasena_no_cumple_criterios:
	# Imprime '\n'
	li a0, '\n'
	li a7, PRINT_CHAR
	ecall

	la a0, pwd_not_matching_criteria
	li a7, PRINT_STRING
	ecall
	
	ret 

#-J25------------------------------------------------------------------
# contrasena_no_cumple_longitud
# Imprime por consola mensaje para indicar que la contraseña 
# no cumple el criterio de longitud
#-------------------------------------------------------------------
# Argumentos:
# -
# Salida
# -
#-------------------------------------------------------------------
contrasena_no_cumple_longitud:
	# Imprime '\n'
	li a0, '\n'
	li a7, PRINT_CHAR
	ecall

	la a0, pwd_not_matching_length
	li a7, PRINT_STRING
	ecall
	
	ret 

#-J25------------------------------------------------------------------
# contrasena_no_cumple_caracteres
# Imprime por consola mensaje para indicar que la contrase�a 
# no cumple el criterio de un car�cter de cada tipo
#-------------------------------------------------------------------
# Argumentos:
# -
# Salida
# -
#-------------------------------------------------------------------
contrasena_no_cumple_caracteres:
	# Imprime '\n'
	li a0, '\n'
	li a7, PRINT_CHAR
	ecall

	la a0, pwd_not_matching_char_policies
	li a7, PRINT_STRING
	ecall
	
	ret 




#-------------------------------------------------------------------------
# error_misma_contrasena
# Imprime mensaje por consola indicando que nueva contraseña 
# no es valida por ser igual que la anterior
# ------------------------------------------------------------------------
# ENTRADAS:
# -
# SALIDA
# -
#--------------------------------------------------------------------------
error_misma_contrasena:
	# Imprime '\n'
	li a0, '\n'
	li a7, PRINT_CHAR
	ecall

	la a0, same_new_pwd
	li a7, PRINT_STRING
	ecall
	ret 

#-------------------------------------------------------------------------
# error_segunda_contrasena_diferente
# Imprime mensaje por consola indicando que nueva contraseña 
# no es valida por ser igual que la anterior
# ------------------------------------------------------------------------
# ENTRADAS:
# -
# SALIDA
# -
#--------------------------------------------------------------------------
error_segunda_contrasena_diferente:
	# Imprime '\n'
	li a0, '\n'
	li a7, PRINT_CHAR
	ecall

	la a0, second_pwd_different
	li a7, PRINT_STRING
	ecall
	ret 


#--------------------------------------------------------------------------
# error_contrasena_no_actualizada
# Imprime mensaje para indicar que no se ha actualizado la contraseña
#--------------------------------------------------------------------------
# ENTRADAS:
# -
# Salida
# -
#--------------------------------------------------------------------------
error_contrasena_no_actualizada:
	# Imprime '\n'
	li a0, '\n'
	li a7, PRINT_CHAR
	ecall
	
	li a7, PRINT_STRING
	la a0, pwd_not_updated 
	ecall	
	ret
	
#--------------------------------------------------------------------------
# contrasena_cambiada
# Muestra por consola mensaje indicando que la contraseña se ha cambiado
#--------------------------------------------------------------------------
# ENTRADAS:
# * a0 - (string). Nueva contraseña
# SALIDAS:
# - 	
#--------------------------------------------------------------------------
contrasena_cambiada:
	mv t0, a0

	# Imprime '\n'
	li a0, '\n'
	li a7, PRINT_CHAR
	ecall

	li a7, PRINT_STRING
	la a0, pwd_updated
	ecall
	
con_cam_bucle:
	lb t1, 0(t0)
	beqz t1, con_cam_fin
	li a7, PRINT_CHAR
	mv a0, t1
	ecall
	addi t0, t0, 1
	
	lb t1, 0(t0)
	beqz t1, con_cam_fin
	li a7, PRINT_CHAR
	li a0, '*'
	ecall
	addi t0, t0, 1

	b con_cam_bucle	
con_cam_fin:
	ret	
	
	
contrasena_similar_anterior:
	# Imprime '\n'
	li a0, '\n'
	li a7, PRINT_CHAR
	ecall

	la a0, pwd_quite_similar
	li a7, PRINT_STRING
	ecall
	
	ret

Autor

  • Juan Ignacio Pérez

Licencia

Enlaces