#!/usr/bin/env python3 import os import warnings # Ignorar el aviso de AVX2 y otros avisos de ejecución warnings.filterwarnings("ignore", category=RuntimeWarning) # Silenciar el saludo de "Hello from the pygame community" os.environ['PYGAME_HIDE_SUPPORT_PROMPT'] = "hide" import pygame import sys # Inicialización pygame.init() # Configuración de ventana ANCHO, ALTO = 1000, 850 ventana = pygame.display.set_mode((ANCHO, ALTO)) pygame.display.set_caption("Codificador Morse - SoloConLinux") # Colores COLOR_FONDO = (245, 245, 245) COLOR_PUNTO = (70, 70, 160) COLOR_RAYA = (180, 50, 50) COLOR_LINEA = (210, 210, 210) COLOR_RESALTE = (0, 200, 0) COLOR_TEXTO = (20, 20, 20) COLOR_BARRA = (40, 40, 40) COLOR_LEYENDA = (220, 220, 220) COLOR_HISTORIAL = (50, 50, 100) # Fuentes fuente_nodos = pygame.font.SysFont("Arial", 20, bold=True) fuente_leyenda = pygame.font.SysFont("Monospace", 16) fuente_preview = pygame.font.SysFont("Arial", 40, bold=True) fuente_mensaje = pygame.font.SysFont("Courier New", 36, bold=True) class NodoMorse: def __init__(self, letra, x, y, es_raya=False): self.letra = letra self.x = x self.y = y self.es_raya = es_raya self.punto = None self.raya = None self.padre = None def dibujar_lineas(self, superficie, nodo_actual): es_camino_activo = self.es_parte_del_camino(nodo_actual) color = COLOR_RESALTE if es_camino_activo else COLOR_LINEA ancho = 4 if es_camino_activo else 2 if self.punto: pygame.draw.line(superficie, color, (self.x, self.y), (self.punto.x, self.punto.y), ancho) self.punto.dibujar_lineas(superficie, nodo_actual) if self.raya: pygame.draw.line(superficie, color, (self.x, self.y), (self.raya.x, self.raya.y), ancho) self.raya.dibujar_lineas(superficie, nodo_actual) def dibujar_nodo(self, superficie, nodo_actual): activo = (self == nodo_actual) color = COLOR_RESALTE if activo else (COLOR_RAYA if self.es_raya else COLOR_PUNTO) if self.es_raya: pygame.draw.rect(superficie, color, (self.x - 22, self.y - 11, 44, 22)) else: pygame.draw.circle(superficie, color, (self.x, self.y), 16) if self.letra: color_letra = (255, 255, 255) if activo else COLOR_TEXTO # Ajustar texto si no tiene fuente Arial instalada # Generamos la superficie del texto texto_surf = fuente_nodos.render(self.letra, True, color_letra) # Creamos un rectángulo con el tamaño del texto y lo centramos en (self.x, self.y) texto_rect = texto_surf.get_rect(center=(self.x, self.y)) # Dibujamos la superficie en las coordenadas del rectángulo calculado superficie.blit(texto_surf, texto_rect) def es_parte_del_camino(self, destino): temp = destino while temp is not None: if temp == self: return True temp = temp.padre return False # --- CONSTRUCCIÓN DEL ÁRBOL --- nodos_lista = [] def crear_nodo(letra, x, y, es_raya=False): nuevo = NodoMorse(letra, x, y, es_raya) nodos_lista.append(nuevo) return nuevo raiz = crear_nodo("", 500, 150) # Bajado un poco para dar espacio al texto arriba # Derecha (Puntos) e = crear_nodo("E", 700, 250); e.padre = raiz; raiz.punto = e i = crear_nodo("I", 800, 250); i.padre = e; e.punto = i s = crear_nodo("S", 900, 250); s.padre = i; i.punto = s h = crear_nodo("H", 970, 250); h.padre = s; s.punto = h v = crear_nodo("V", 900, 330, True); v.padre = s; s.raya = v u = crear_nodo("U", 800, 330, True); u.padre = i; i.raya = u f = crear_nodo("F", 800, 410); f.padre = u; u.punto = f a = crear_nodo("A", 700, 450, True); a.padre = e; e.raya = a r = crear_nodo("R", 800, 530); r.padre = a; a.punto = r l = crear_nodo("L", 900, 530); l.padre = r; r.punto = l w = crear_nodo("W", 700, 610, True); w.padre = a; a.raya = w p = crear_nodo("P", 800, 610); p.padre = w; w.punto = p j = crear_nodo("J", 700, 690, True); j.padre = w; w.raya = j # Izquierda (Rayas) t = crear_nodo("T", 300, 250, True); t.padre = raiz; raiz.raya = t m = crear_nodo("M", 200, 250, True); m.padre = t; t.raya = m o = crear_nodo("O", 100, 250, True); o.padre = m; m.raya = o g = crear_nodo("G", 200, 330); g.padre = m; m.punto = g q = crear_nodo("Q", 100, 410, True); q.padre = g; g.raya = q z = crear_nodo("Z", 200, 410); z.padre = g; g.punto = z n = crear_nodo("N", 300, 450); n.padre = t; t.punto = n k = crear_nodo("K", 200, 530, True); k.padre = n; n.raya = k y = crear_nodo("Y", 100, 530, True); y.padre = k; k.raya = y c = crear_nodo("C", 200, 610); c.padre = k; k.punto = c d = crear_nodo("D", 300, 610); d.padre = n; n.punto = d x = crear_nodo("X", 200, 690, True); x.padre = d; d.raya = x b = crear_nodo("B", 300, 690); b.padre = d; d.punto = b # --- VARIABLES DE ESTADO --- nodo_actual = raiz mensaje_completo = "" # El mensaje final que se imprimirá codigo_morse_total = "" # El código final que se imprimirá morse_actual = "" # Lo que se va pulsando para la letra actual ejecutando = True reloj = pygame.time.Clock() while ejecutando: ventana.fill(COLOR_FONDO) # 1. Dibujar Cabecera (Mensaje generado) pygame.draw.rect(ventana, (230, 230, 230), (0, 0, ANCHO, 80)) pygame.draw.line(ventana, COLOR_BARRA, (0, 80), (ANCHO, 80), 2) img_msg = fuente_mensaje.render(mensaje_completo + "_", True, COLOR_HISTORIAL) ventana.blit(img_msg, (20, 20)) # 2. Dibujar Árbol raiz.dibujar_lineas(ventana, nodo_actual) for n in nodos_lista: n.dibujar_nodo(ventana, nodo_actual) # 3. Dibujar Barra de Leyenda pygame.draw.rect(ventana, COLOR_BARRA, (0, ALTO - 60, ANCHO, 60)) texto_leyenda = ". (Punto) - (Raya) SPACE (Confirmar) BACKSPACE (Borrar) ESC (Salir)" img_leyenda = fuente_leyenda.render(texto_leyenda, True, COLOR_LEYENDA) ventana.blit(img_leyenda, (20, ALTO - 38)) # 4. Previsualización de letra actual if nodo_actual.letra: # Ajuste texto si no tiene fuente Arial pygame.draw.circle(ventana, COLOR_RESALTE, (ANCHO - 60, ALTO - 120), 35, 3) img_prev = fuente_preview.render(nodo_actual.letra, True, COLOR_TEXTO) # Centrado dinámico: rect_prev = img_prev.get_rect(center=(ANCHO - 60, ALTO - 120)) ventana.blit(img_prev, rect_prev) for evento in pygame.event.get(): if evento.type == pygame.QUIT: ejecutando = False if evento.type == pygame.KEYDOWN: if evento.key == pygame.K_PERIOD: if nodo_actual.punto: nodo_actual = nodo_actual.punto morse_actual += "." elif evento.key in [pygame.K_MINUS, pygame.K_SLASH, pygame.K_KP_MINUS]: if nodo_actual.raya: nodo_actual = nodo_actual.raya morse_actual += "-" elif evento.key == pygame.K_SPACE: if nodo_actual.letra: mensaje_completo += nodo_actual.letra codigo_morse_total += morse_actual + " " else: mensaje_completo += " " codigo_morse_total += " " # resetarar para siguiente letra nodo_actual = raiz morse_actual = "" elif evento.key == pygame.K_BACKSPACE: mensaje_completo = mensaje_completo[:-1] morse_actual = "" elif evento.key == pygame.K_ESCAPE: ejecutando = False pygame.display.flip() reloj.tick(30) # -- Al Salir imprimimos todo el texto -- print("\n" + "="*40) print("CODIFICADOR MORSE") print(f"TEXTO: {mensaje_completo}") print(f"MORSE: {codigo_morse_total.strip()}") print("="*40 + "\n") pygame.quit() sys.exit()