Skip to content

Commit ffd6c79

Browse files
authored
Merge pull request #6817 from Maanghel/main
Reto #22 - Python
2 parents 1661fcb + 5cef200 commit ffd6c79

File tree

6 files changed

+351
-0
lines changed

6 files changed

+351
-0
lines changed
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
"""
2+
Crea una función que dibuje una espiral como la del ejemplo.
3+
- Únicamente se indica de forma dinámica el tamaño del lado.
4+
- Símbolos permitidos: ═ ║ ╗ ╔ ╝ ╚
5+
6+
Ejemplo espiral de lado 5 (5 filas y 5 columnas):
7+
════╗
8+
╔══╗║
9+
║╔╗║║
10+
║╚═╝║
11+
╚═══╝
12+
"""
13+
14+
def draw_spiral(size: int) -> None:
15+
"""
16+
Dibuja una espiral cerrada de tamaño N x N usando caracteres de dibujo de cajas permitidos.
17+
18+
La espiral comienza en la esquina superior izquierda y se mueve continuamente hacia adentro.
19+
20+
Args:
21+
size (int): La longitud del lado (número de filas y columnas) de la espiral cuadrada.
22+
Debe ser un entero positivo.
23+
24+
Raises:
25+
ValueError: Si 'size' no es un entero positivo.
26+
"""
27+
if not isinstance(size, int) or size < 1:
28+
raise ValueError("El tamaño debe ser un entero positivo.")
29+
30+
spiral = [[' ' for _ in range(size)] for _ in range(size)]
31+
top, bottom, left, right = 0, size - 1, 0, size - 1
32+
33+
while True:
34+
if left > right or top > bottom:
35+
break
36+
37+
for i in range(left, right + 1):
38+
spiral[top][i] = '═'
39+
if top < bottom:
40+
spiral[top][right] = '╗'
41+
top += 1
42+
if top > bottom:
43+
break
44+
45+
for i in range(top, bottom + 1):
46+
spiral[i][right] = '║'
47+
if left < right:
48+
spiral[bottom][right] = '╝'
49+
right -= 1
50+
if left > right:
51+
break
52+
53+
for i in range(right, left - 1, -1):
54+
spiral[bottom][i] = '═'
55+
if top <= bottom:
56+
spiral[bottom][left] = '╚'
57+
bottom -= 1
58+
if top > bottom:
59+
break
60+
61+
for i in range(bottom, top - 1, -1):
62+
spiral[i][left] = '║'
63+
if left <= right:
64+
spiral[top][left] = '╔'
65+
left += 1
66+
67+
for row in spiral:
68+
print(''.join(row))
69+
70+
71+
if __name__ == "__main__":
72+
draw_spiral(8)
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
"""
2+
Realiza una conexión desde el lenguaje que hayas seleccionado a la siguiente
3+
base de datos MySQL:
4+
- Host: mysql-5707.dinaserver.com
5+
- Port: 3306
6+
- User: mouredev_read
7+
- Password: mouredev_pass
8+
- Database: moure_test
9+
10+
Una vez realices la conexión, lanza la siguiente consulta e imprime el resultado:
11+
- SELECT * FROM `challenges`
12+
13+
Se pueden usar librerías para realizar la lógica de conexión a la base de datos.
14+
"""
15+
16+
import mysql.connector
17+
from mysql.connector import Error
18+
19+
def main():
20+
"""
21+
Función principal que gestiona la conexión a la base de datos MySQL,
22+
ejecuta una consulta SELECT sobre la tabla `challenges`
23+
y muestra los resultados en consola.
24+
"""
25+
connection = None
26+
cursor = None
27+
28+
try:
29+
connection = mysql.connector.connect(
30+
host='mysql-5707.dinaserver.com',
31+
port=3306,
32+
user='mouredev_read',
33+
password='mouredev_pass',
34+
database='moure_test'
35+
)
36+
37+
if connection.is_connected():
38+
print("Conexión establecida correctamente.\n")
39+
cursor = connection.cursor()
40+
cursor.execute("SELECT * FROM challenges")
41+
results = cursor.fetchall()
42+
43+
print("Resultados de la consulta:\n")
44+
for row in results:
45+
print(row)
46+
47+
except Error as e:
48+
print(f"Error al conectar o ejecutar la consulta en la base de datos: {e}")
49+
finally:
50+
if cursor is not None:
51+
cursor.close()
52+
if connection is not None and connection.is_connected():
53+
connection.close()
54+
print("\nConexión a la base de datos cerrada correctamente.")
55+
56+
57+
if __name__ == "__main__":
58+
main()
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
"""
2+
Crea un programa que realize el cifrado César de un texto y lo imprima.
3+
También debe ser capaz de descifrarlo cuando así se lo indiquemos.
4+
5+
Te recomiendo que busques información para conocer en profundidad cómo
6+
realizar el cifrado. Esto también forma parte del reto.
7+
"""
8+
9+
def cesar_cipher(
10+
text: str, shift: int, decipher: bool = False
11+
) -> str:
12+
"""
13+
Aplica el cifrado o descifrado César a un texto.
14+
15+
Parámetros:
16+
text (str): Texto a procesar.
17+
shift (int): Número de posiciones a desplazar en el alfabeto.
18+
decipher (bool): Si es True, se aplica el descifrado (desplazamiento inverso).
19+
20+
Retorna:
21+
str: Texto resultante tras aplicar el cifrado o descifrado.
22+
23+
Lanza:
24+
TypeError: Si el valor de `text` no es una cadena.
25+
"""
26+
27+
if not isinstance(text, str):
28+
raise TypeError("Error. Solo se acepta texto como valor.")
29+
30+
result = ""
31+
32+
if decipher:
33+
shift *= -1
34+
35+
for char in text:
36+
if char.isalpha():
37+
point_code = ord(char)
38+
if "A" <= char <= "Z":
39+
base = ord("A")
40+
elif "a" <= char <= "z":
41+
base = ord("a")
42+
new_point_code = ((point_code - base) + shift) % 26 + base
43+
result += chr(new_point_code)
44+
else:
45+
result += char
46+
47+
return result
48+
49+
50+
if __name__ == "__main__":
51+
print(cesar_cipher("Hola Mundo Yz XA", 2))
52+
print(cesar_cipher("Jqnc Owpfq Ab ZC", 2, decipher=True))
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
"""
2+
Crea un programa que detecte cuando el famoso "Código Konami" se ha
3+
introducido correctamente desde el teclado.
4+
Si sucede esto, debe notificarse mostrando un mensaje en la terminal.
5+
"""
6+
7+
from pynput.keyboard import Key, Listener, Controller
8+
9+
KONAMI_CODE = [
10+
Key.up, Key.up, Key.down, Key.down,
11+
Key.left, Key.right, Key.left, Key.right,
12+
"a", "b"
13+
]
14+
15+
press_keys = []
16+
17+
def on_press(key):
18+
"""
19+
Maneja cada pulsación registrada por el listener.
20+
21+
Convierte la tecla a un tipo comparable (string o Key) y la almacena
22+
en la lista de pulsaciones. Comprueba si las últimas teclas ingresadas
23+
coinciden con el código Konami; de ser así, imprime un mensaje y
24+
simula la pulsación de la tecla ESC para detener el programa.
25+
26+
Args:
27+
key: objeto Key proporcionado por pynput que representa la tecla pulsada.
28+
"""
29+
30+
global press_keys
31+
keyboard = Controller()
32+
33+
try:
34+
k = key.char
35+
except AttributeError:
36+
k = key
37+
38+
press_keys.append(k)
39+
40+
if press_keys[-len(KONAMI_CODE):] == KONAMI_CODE:
41+
print("¡Codigo KONAMI detectado!")
42+
keyboard.press(Key.esc)
43+
keyboard.release(Key.esc)
44+
45+
def on_release(key):
46+
"""
47+
Maneja el evento de liberación de tecla.
48+
49+
Si se libera la tecla ESC, imprime un mensaje y devuelve False para
50+
detener el listener.
51+
52+
Args:
53+
ke
54+
if key == Key.esc:
55+
print("\nDeteniendo...")
56+
return False
57+
"""
58+
59+
with Listener(on_press=on_press, on_release=on_release) as listener:
60+
print("Escuchando pulsaciones del teclado. Presiona 'esc' para salir.")
61+
listener.join()
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
"""
2+
Crea tres test sobre el reto 12: "Viernes 13".
3+
- Puedes copiar una solución ya creada por otro usuario en
4+
el lenguaje que estés utilizando.
5+
- Debes emplear un mecanismo de ejecución de test que posea
6+
el lenguaje de programación que hayas seleccionado.
7+
- Los tres test deben de funcionar y comprobar
8+
diferentes situaciones (a tu elección).
9+
"""
10+
11+
from datetime import date
12+
import unittest
13+
14+
def have_friday_13(year: int, month: int) -> bool:
15+
"""Check if the 13th of a given month/year falls on a Friday.
16+
17+
Args:
18+
year (int): Year to check.
19+
month (int): Month to check (1-12).
20+
21+
Returns:
22+
bool: True if the 13th is Friday, False otherwise.
23+
24+
Raises:
25+
TypeError: If arguments are not integers.
26+
ValueError: If month is not in 1-12.
27+
"""
28+
if not isinstance(year, int) or not isinstance(month, int):
29+
raise TypeError("El año y el mes deben ser enteros.")
30+
if not 1 <= month <= 12:
31+
raise ValueError("El mes debe estar entre 1 y 12.")
32+
33+
return date(year, month, 13).weekday() == 4
34+
35+
class TestHaveFriday13(unittest.TestCase):
36+
"""Unit test suite for the have_friday_13 function.
37+
38+
Tests include:
39+
- Cases where Friday the 13th exists
40+
- Cases where it does not
41+
- Type validation errors
42+
- Month range validation
43+
"""
44+
45+
def test_1(self):
46+
"""Check a month in 2023 that does have a Friday 13th."""
47+
result = have_friday_13(2023, 1)
48+
self.assertTrue(result)
49+
50+
def test_2(self):
51+
"""Check a month in 2023 that does not have a Friday 13th."""
52+
result = have_friday_13(2023, 3)
53+
self.assertFalse(result)
54+
55+
def test_3(self):
56+
"""Ensure TypeError is raised when passing non-integer values."""
57+
with self.assertRaises(TypeError):
58+
have_friday_13("s", "s")
59+
60+
def test_4(self):
61+
"""Ensure ValueError is raised when passing an out-of-range month."""
62+
with self.assertRaises(ValueError):
63+
have_friday_13(2024, 14)
64+
65+
66+
if __name__ == "__main__":
67+
unittest.main()
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
"""
2+
Crea una función que reciba dos parámetros para crear una cuenta atrás.
3+
- El primero, representa el número en el que comienza la cuenta.
4+
- El segundo, los segundos que tienen que transcurrir entre cada cuenta.
5+
- Sólo se aceptan números enteros positivos.
6+
- El programa finaliza al llegar a cero.
7+
- Debes imprimir cada número de la cuenta atrás.
8+
"""
9+
10+
import time
11+
12+
def countdown(start: int, delay: int) -> None:
13+
"""
14+
Prints a countdown from a given starting number down to zero, pausing
15+
for a specified number of seconds between each printed value.
16+
17+
Args:
18+
start (int): Positive integer that specifies where the countdown begins.
19+
delay (int): Positive integer indicating the number of seconds to wait
20+
between each printed number.
21+
22+
Raises:
23+
TypeError: If `start` or `delay` is not an integer.
24+
ValueError: If `start` or `delay` is less than or equal to zero.
25+
26+
Returns:
27+
None
28+
"""
29+
if not isinstance(start, int) or not isinstance(delay, int):
30+
raise TypeError("Error. Solo se aceptan valores enteros para el inicio o el tiempo.")
31+
32+
if start <= 0 or delay <= 0:
33+
raise ValueError("Error. El numero de inicio o espera debe ser mayor a 0.")
34+
35+
for i in range(start, -1, -1):
36+
print(i)
37+
time.sleep(delay)
38+
39+
40+
if __name__ == "__main__":
41+
countdown(10, 2)

0 commit comments

Comments
 (0)