🎮 Juegos de Competición Real

Estos problemas están inspirados en competiciones reales de HP CodeWars (Barcelona, Valencia, León). Son el tipo de ejercicios que te encontrarás el día de la competición.

📋
Recursos oficiales: Puedes descargar problemas de años anteriores en codewarsbcn.hpcloud.hp.com
🎯
Recuerda: En la competición real tienes 3 horas para ~30 problemas. Practica cronometrándote: intenta resolver estos 5 en menos de 1 hora.

🎮 Juego 1: La Escalera Mágica (3 pts)

📜
Enunciado: La bruja Maléfica está subiendo una escalera mágica. En cada escalón, el número de estrellas sigue un patrón: 1, 3, 5, 7, 9...

Dado el número de escalón N, ¿cuántas estrellas hay en ese escalón?
Entrada: 1
Salida: 1

Entrada: 4
Salida: 7

Entrada: 10
Salida: 19
💡 Pista 1: Observa el patrón

Mira la secuencia:

  • Escalón 1 → 1 estrella
  • Escalón 2 → 3 estrellas
  • Escalón 3 → 5 estrellas
  • Escalón 4 → 7 estrellas

¿Ves algo? Son los números impares: 1, 3, 5, 7...

💡 Pista 2: Fórmula de números impares

El n-ésimo número impar es: 2*n - 1

  • n=1 → 2*1-1 = 1 ✓
  • n=4 → 2*4-1 = 7 ✓
  • n=10 → 2*10-1 = 19 ✓
🍌 Ver solución Minion (paso a paso)
# Leer el número de escalón
n = int(input())

# Observamos el patrón:
# Escalón 1 → 1 estrella
# Escalón 2 → 3 estrellas
# Escalón 3 → 5 estrellas
# Son números impares: 1, 3, 5, 7...

# El n-ésimo número impar es 2*n - 1
estrellas = 2 * n - 1

print(estrellas)
😎 Ver solución Gru (compacta)
n = int(input())
print(2 * n - 1)
🎓
Truco Gru: Muchos problemas de secuencias tienen una fórmula directa. Antes de hacer bucles, busca el patrón matemático.

🎮 Juego 2: El Detector de Espías (5 pts)

📜
Enunciado: En una agencia secreta, los espías se comunican con mensajes codificados. Un mensaje es sospechoso si contiene la palabra "SECRETO" (sin importar mayúsculas/minúsculas) escondida en cualquier parte del texto.

Dado un mensaje, responde "ALERTA" si es sospechoso o "SEGURO" si no lo es.
Entrada: Hola, esto es un mensaje normal
Salida: SEGURO

Entrada: El SeCrEtO está en la caja
Salida: ALERTA

Entrada: Nos vemos en secretolandia mañana
Salida: ALERTA
💡 Pista 1: Ignora mayúsculas

Convierte todo a minúsculas (o mayúsculas) antes de buscar.

mensaje = input().lower()
💡 Pista 2: Buscar substring

El operador in busca si una cadena está dentro de otra:

if "secreto" in mensaje:
    # está!
🍌 Ver solución Minion (paso a paso)
# Leer el mensaje
mensaje = input()

# Convertir todo a minúsculas para comparar sin importar mayúsculas
mensaje_minusculas = mensaje.lower()

# Buscar si contiene la palabra "secreto"
if "secreto" in mensaje_minusculas:
    print("ALERTA")
else:
    print("SEGURO")
😎 Ver solución Gru (compacta)
mensaje = input().lower()
print("ALERTA" if "secreto" in mensaje else "SEGURO")
🎓
Truco Gru: lower() + in + ternario en una línea. Combo perfecta.

🎮 Juego 3: La Calculadora Romana (8 pts)

📜
Enunciado: Tu abuelo colecciona monedas antiguas y quiere sumar sus valores. Cada moneda tiene un número romano. Dados N números romanos, calcula la suma total.

Números romanos: I=1, V=5, X=10, L=50, C=100, D=500, M=1000
Regla especial: IV=4, IX=9, XL=40, XC=90, CD=400, CM=900
Entrada:
3
X
V
III

Salida: 18

(X=10, V=5, III=3 → 10+5+3=18)
💡 Pista 1: Convierte cada número romano

Crea una función que convierta un número romano a decimal.

Recorre de izquierda a derecha. Si el valor actual es menor que el siguiente, resta; si no, suma.

💡 Pista 2: Diccionario de valores
valores = {'I':1, 'V':5, 'X':10, 'L':50,
           'C':100, 'D':500, 'M':1000}
🍌 Ver solución Minion (paso a paso)
# Diccionario con los valores de cada letra
valores = {
    'I': 1,
    'V': 5,
    'X': 10,
    'L': 50,
    'C': 100,
    'D': 500,
    'M': 1000
}

# Leer cuántas monedas hay
n = int(input())
suma_total = 0

# Procesar cada moneda
for moneda in range(n):
    romano = input()
    valor_moneda = 0

    # Recorrer cada letra del número romano
    i = 0
    while i < len(romano):
        letra_actual = romano[i]
        valor_actual = valores[letra_actual]

        # ¿Hay una letra después?
        if i + 1 < len(romano):
            letra_siguiente = romano[i + 1]
            valor_siguiente = valores[letra_siguiente]

            # Si la siguiente es mayor, hay que restar
            if valor_siguiente > valor_actual:
                valor_moneda = valor_moneda + (valor_siguiente - valor_actual)
                i = i + 2  # Saltamos 2 letras
            else:
                valor_moneda = valor_moneda + valor_actual
                i = i + 1
        else:
            valor_moneda = valor_moneda + valor_actual
            i = i + 1

    suma_total = suma_total + valor_moneda

print(suma_total)
😎 Ver solución Gru (compacta)
def romano_a_decimal(romano):
    valores = {'I':1, 'V':5, 'X':10, 'L':50, 'C':100, 'D':500, 'M':1000}
    total = 0
    for i in range(len(romano)):
        if i + 1 < len(romano) and valores[romano[i]] < valores[romano[i+1]]:
            total -= valores[romano[i]]
        else:
            total += valores[romano[i]]
    return total

n = int(input())
print(sum(romano_a_decimal(input()) for _ in range(n)))
🎓
Truco Gru: El truco de restar cuando el actual es menor que el siguiente simplifica mucho. Y usar sum() con generador ahorra líneas.

🎮 Juego 4: El Torneo de Ajedrez (10 pts)

📜
Enunciado: En un torneo de ajedrez, cada jugador tiene puntos. Ganar = 3 pts, Empatar = 1 pt, Perder = 0 pts.

Dados los resultados de N partidas (jugador1, jugador2, resultado), muestra la clasificación final ordenada por:
  1. Más puntos (descendente)
  2. Más victorias (descendente)
  3. Nombre alfabético (ascendente)
Entrada:
4
Ana Luis G
Luis Eva E
Eva Ana G
Ana Eva G

Salida:
Ana 6
Eva 4
Luis 1

(Ana: 2 victorias = 6pts, Eva: 1 victoria + 1 empate = 4pts, Luis: 1 empate = 1pt)
💡 Pista 1: Estructura de datos

Usa un diccionario donde guardes para cada jugador sus puntos y victorias:

jugadores = {}
# jugadores["Ana"] = {"puntos": 6, "victorias": 2}
💡 Pista 2: Procesar cada partida
if resultado == "G":  # Gana jugador1
    jugadores[j1]["puntos"] += 3
    jugadores[j1]["victorias"] += 1
elif resultado == "P":  # Pierde jugador1 (gana j2)
    jugadores[j2]["puntos"] += 3
    jugadores[j2]["victorias"] += 1
else:  # Empate
    jugadores[j1]["puntos"] += 1
    jugadores[j2]["puntos"] += 1
💡 Pista 3: Ordenar con múltiples criterios

Convierte el diccionario a lista y ordena con lambda:

clasificacion = sorted(jugadores.items(),
    key=lambda x: (-x[1]["puntos"], -x[1]["victorias"], x[0]))
🍌 Ver solución Minion (paso a paso)
# Leer número de partidas
n = int(input())

# Diccionario para guardar puntos y victorias de cada jugador
puntos = {}
victorias = {}

# Procesar cada partida
for i in range(n):
    linea = input()
    partes = linea.split()
    jugador1 = partes[0]
    jugador2 = partes[1]
    resultado = partes[2]

    # Asegurarnos que los jugadores existen en los diccionarios
    if jugador1 not in puntos:
        puntos[jugador1] = 0
        victorias[jugador1] = 0
    if jugador2 not in puntos:
        puntos[jugador2] = 0
        victorias[jugador2] = 0

    # Asignar puntos según resultado
    if resultado == "G":
        # Gana jugador1
        puntos[jugador1] = puntos[jugador1] + 3
        victorias[jugador1] = victorias[jugador1] + 1
    elif resultado == "P":
        # Gana jugador2
        puntos[jugador2] = puntos[jugador2] + 3
        victorias[jugador2] = victorias[jugador2] + 1
    else:
        # Empate
        puntos[jugador1] = puntos[jugador1] + 1
        puntos[jugador2] = puntos[jugador2] + 1

# Crear lista para ordenar
lista_jugadores = []
for nombre in puntos:
    lista_jugadores.append((nombre, puntos[nombre], victorias[nombre]))

# Ordenar: primero por puntos (mayor a menor), luego victorias, luego nombre
# Usamos bubble sort porque es fácil de entender
for i in range(len(lista_jugadores)):
    for j in range(i + 1, len(lista_jugadores)):
        a = lista_jugadores[i]
        b = lista_jugadores[j]
        # ¿Hay que intercambiar?
        intercambiar = False
        if b[1] > a[1]:  # Más puntos
            intercambiar = True
        elif b[1] == a[1] and b[2] > a[2]:  # Igual puntos, más victorias
            intercambiar = True
        elif b[1] == a[1] and b[2] == a[2] and b[0] < a[0]:  # Alfabético
            intercambiar = True
        if intercambiar:
            lista_jugadores[i] = b
            lista_jugadores[j] = a

# Imprimir resultado
for jugador in lista_jugadores:
    print(jugador[0], jugador[1])
😎 Ver solución Gru (compacta)
n = int(input())
jugadores = {}

for _ in range(n):
    j1, j2, r = input().split()
    for j in [j1, j2]:
        if j not in jugadores:
            jugadores[j] = {"p": 0, "v": 0}
    if r == "G": jugadores[j1]["p"] += 3; jugadores[j1]["v"] += 1
    elif r == "P": jugadores[j2]["p"] += 3; jugadores[j2]["v"] += 1
    else: jugadores[j1]["p"] += 1; jugadores[j2]["p"] += 1

for n, d in sorted(jugadores.items(), key=lambda x: (-x[1]["p"], -x[1]["v"], x[0])):
    print(n, d["p"])
🎓
Truco Gru: sorted() con lambda y tupla de criterios. Negativo = descendente. ¡Ahorra 30 líneas!

🎮 Juego 5: El Código del Tesoro (12 pts)

📜
Enunciado: Un pirata dejó un mapa con instrucciones codificadas. Cada instrucción tiene un número y una dirección: "3N" significa 3 pasos al Norte.

Direcciones: N (Norte, +Y), S (Sur, -Y), E (Este, +X), O (Oeste, -X)

Empezando en (0,0), ¿en qué coordenadas acabas después de seguir todas las instrucciones?
Entrada:
5
3N
2E
1S
4O
2N

Salida: -2 4

(Empiezas en (0,0). 3N→(0,3), 2E→(2,3), 1S→(2,2), 4O→(-2,2), 2N→(-2,4))
💡 Pista 1: Separa número y dirección

Cada instrucción tiene el número al principio y la letra al final:

instruccion = "3N"
pasos = int(instruccion[:-1])  # Todo menos el último = "3"
direccion = instruccion[-1]     # El último = "N"
💡 Pista 2: Diccionario de movimientos
movimientos = {
    'N': (0, 1),   # Y aumenta
    'S': (0, -1),  # Y disminuye
    'E': (1, 0),   # X aumenta
    'O': (-1, 0)   # X disminuye
}
🍌 Ver solución Minion (paso a paso)
# Leer número de instrucciones
n = int(input())

# Posición inicial
x = 0
y = 0

# Procesar cada instrucción
for i in range(n):
    instruccion = input()

    # Separar el número de pasos y la dirección
    # Ejemplo: "3N" → pasos = 3, direccion = "N"
    direccion = instruccion[-1]  # Última letra
    pasos_texto = instruccion[:-1]  # Todo menos la última
    pasos = int(pasos_texto)

    # Mover según la dirección
    if direccion == "N":
        y = y + pasos  # Norte: subir (Y aumenta)
    elif direccion == "S":
        y = y - pasos  # Sur: bajar (Y disminuye)
    elif direccion == "E":
        x = x + pasos  # Este: derecha (X aumenta)
    elif direccion == "O":
        x = x - pasos  # Oeste: izquierda (X disminuye)

# Mostrar posición final
print(x, y)
😎 Ver solución Gru (compacta)
n = int(input())
mov = {'N': (0,1), 'S': (0,-1), 'E': (1,0), 'O': (-1,0)}
x, y = 0, 0
for _ in range(n):
    ins = input()
    dx, dy = mov[ins[-1]]
    x += dx * int(ins[:-1])
    y += dy * int(ins[:-1])
print(x, y)
🎓
Truco Gru: Diccionario con tuplas (dx, dy) elimina todos los if/elif. Una línea por dirección en vez de cuatro.

📚 Patrones que se repiten SIEMPRE

Después de ver muchos problemas de CodeWars, estos patrones aparecen una y otra vez. Memoriza estos trucos y los reconocerás al instante.

🔢 Secuencias numéricas — Busca la fórmula antes de hacer bucles

Fórmulas mágicas que aparecen mucho:

# Números impares: 1, 3, 5, 7...
impar_n = 2 * n - 1

# Suma de 1 a N: 1+2+3+...+N
suma = n * (n + 1) // 2

# Suma de impares hasta N: 1+3+5+...  
suma_impares = n * n  # ¡Es un cuadrado perfecto!

# Fibonacci (memoriza la lógica)
a, b = 0, 1
for _ in range(n):
    a, b = b, a + b
📝 Manipulación de Strings — El 50% de problemas usan esto

Los trucos más usados:

# Buscar ignorando mayúsculas
if "palabra" in texto.lower():

# Invertir un string
invertido = texto[::-1]

# ¿Es palíndromo?
es_palindromo = texto == texto[::-1]

# Quitar espacios y signos (solo letras)
limpio = "".join(c for c in texto if c.isalpha())

# Separar y volver a juntar
palabras = texto.split()        # "a b c" → ["a","b","c"]
junto = " ".join(palabras)      # ["a","b","c"] → "a b c"
🏆 Rankings y clasificaciones — Siempre el mismo patrón

Diccionario → Lista → Ordenar:

# 1. Guardar datos en diccionario
jugadores = {}
jugadores["Ana"] = {"puntos": 10, "goles": 3}

# 2. Ordenar con múltiples criterios
#    Negativo = descendente, Positivo = ascendente
ranking = sorted(jugadores.items(),
    key=lambda x: (-x[1]["puntos"], -x[1]["goles"], x[0]))

# 3. Imprimir
for nombre, datos in ranking:
    print(nombre, datos["puntos"])
🗺️ Coordenadas y movimientos — Mapas, laberintos, robots

Diccionario de direcciones:

# Definir movimientos posibles
direcciones = {
    'N': (0, 1),   'S': (0, -1),
    'E': (1, 0),   'O': (-1, 0)
}

# También para las 8 direcciones (incluye diagonales)
vecinos = [(-1,-1), (-1,0), (-1,1),
           (0,-1),          (0,1),
           (1,-1),  (1,0),  (1,1)]

# Mover
x, y = 0, 0
dx, dy = direcciones['N']
x, y = x + dx, y + dy
📊 Contar frecuencias — Letra más común, repetidos, etc.

Dos formas de hacerlo:

# Forma 1: Manual con .get()
freq = {}
for letra in texto:
    freq[letra] = freq.get(letra, 0) + 1

# Forma 2: Con Counter (más fácil)
from collections import Counter
freq = Counter(texto)

# Encontrar el más común
mas_comun = max(freq, key=freq.get)

# Los 3 más comunes
top_3 = freq.most_common(3)  # [('a', 5), ('b', 3), ('c', 2)]
🔄 Conversiones — Romano, binario, bases numéricas

Siempre usa diccionarios:

# Números romanos
romanos = {'I':1, 'V':5, 'X':10, 'L':50, 'C':100}

# Binario a decimal (sin usar int())
binario = "1011"
decimal = 0
for bit in binario:
    decimal = decimal * 2 + int(bit)

# Decimal a binario (sin usar bin())
n = 11
bits = []
while n > 0:
    bits.append(str(n % 2))
    n //= 2
binario = "".join(bits[::-1])  # "1011"
🏆
El secreto: No tienes que inventar nada nuevo. El 90% de los problemas de competición son variaciones de estos patrones. Practica hasta que los reconozcas al instante.
⚠️
Para más problemas reales: Descarga los PDFs de años anteriores en la web oficial de CodeWars. Hay problemas de Valencia 2025, Barcelona 2024/2025 y más.