modelduelInforme de duelo1 oct 2026 · 00:25 UTCv0.3.0

alfa vs beta

3 tareas · 1 ejecución por tarea · límite de 20 s por ejecución de tests

Areplay:alfa
31/32
Breplay:beta
30/32

tests superados

gana A por tests superados (31 frente a 30, con las mismas tareas resueltas)

2/3
Tareas resueltas
Tareas resueltas: A 2/3, B 2/3
todos los tests en todas las ejecuciones
2/3
31/32(mejor)
Tests superados
Tests superados: A 31/32, B 30/32
(peor)30/32
10,1 s(mejor)tests: 1,3 s
Tiempo del modelo
Tiempo del modelo: A 10,1 s, B 28,1 s
menos es mejor
(peor)28,1 stests: 1,3 s
2.104(mejor)entrada 1.401 · salida 703
Tokens
Tokens: A 2.104, B 3.505
menos es mejor
(peor)3.505entrada 1.373 · salida 2.132
0,0017 USD(mejor)
Coste estimado
Coste estimado: A 0,0017 USD, B 0,0248 USD
precios ficticios de demostración
(peor)0,0248 USD

Tests superados por tarea

Convertir un texto en slugfácil
A: 8 de 8 tests superados8/8
B: 6 de 8 tests superados6/8
Fusionar intervalosmedia
A: 8 de 8 tests superados8/8
B: 8 de 8 tests superados8/8
Convertir una duración a segundosdifícil
A: 15 de 16 tests superados15/16
B: 16 de 16 tests superados16/16

Tabla por tarea

Totales por tarea. El tiempo es el que tarda el modelo en responder.
TareaTestsTiempo del modeloTokens entrada / salidaCoste
ABABABAB
Convertir un texto en slugfácil8/86/82,8 s7,6 s412 / 188405 / 5960,0005 USD0,0070 USD
Fusionar intervalosmedia8/88/83,4 s8,9 s468 / 241459 / 7020,0006 USD0,0082 USD
Convertir una duración a segundosdifícil15/1616/163,9 s11,5 s521 / 274509 / 8340,0006 USD0,0096 USD

Código y salida de los tests

Convertir un texto en slugslugifyA 8/8 B 6/8
# Convertir un texto en slug Escribe una función de Python con esta firma exacta: ```python def slugify(text: str, separator: str = "-") -> str: ``` Debe convertir cualquier texto en un *slug* apto para una URL siguiendo estas reglas: 1. El resultado va en minúsculas. 2. Las letras con tilde, diéresis u otros diacríticos se convierten en su letra base (`á` → `a`, `ñ` → `n`, `ü` → `u`, `ç` → `c`). 3. Solo se conservan letras ASCII (`a`-`z`) y dígitos (`0`-`9`). 4. Cualquier secuencia de uno o más caracteres no conservados (espacios, signos de puntuación, barras, guiones, puntos…) se sustituye por **un único** `separator`. 5. El resultado nunca empieza ni termina con el separador. 6. Si no queda ningún carácter conservado, devuelve la cadena vacía `""`. Ejemplos: - `slugify("Canción de Añoranza")` → `"cancion-de-anoranza"` - `slugify("Python 3.12 en 2026")` → `"python-3-12-en-2026"` - `slugify("Árbol Genealógico", separator="_")` → `"arbol_genealogico"`
A · replay:alfa
8/8 tests · resuelta · 2,8 s
import re
import unicodedata


def slugify(text: str, separator: str = "-") -> str:
    normalized = unicodedata.normalize("NFKD", text)
    ascii_text = normalized.encode("ascii", "ignore").decode("ascii").lower()
    parts = re.split(r"[^a-z0-9]+", ascii_text)
    return separator.join(part for part in parts if part)
Salida de pytest
........                                                                 [100%]
8 passed in 0.06s
B · replay:beta
6/8 tests · 2 fallan · 7,6 s
import re
import unicodedata


def slugify(text: str, separator: str = "-") -> str:
    """Convierte ``text`` en un slug apto para URL."""
    # 1. Quitar tildes y diacríticos: "Canción" -> "Cancion".
    text = unicodedata.normalize("NFKD", text)
    text = text.encode("ascii", "ignore").decode("ascii")

    # 2. Eliminar todo lo que no sea letra, dígito, espacio o guion.
    text = re.sub(r"[^\w\s-]", "", text).strip().lower()

    # 3. Colapsar espacios, guiones y guiones bajos en un único separador.
    text = re.sub(r"[\s_-]+", separator, text)

    # 4. Nunca empezar ni terminar con el separador.
    return text.strip(separator)
Salida de pytest
....FF..                                                                 [100%]
================================== FAILURES ===================================
_______________________ test_punto_entre_digitos_separa _______________________
test_task.py:22: in test_punto_entre_digitos_separa
    assert slugify("Python 3.12 en 2026") == "python-3-12-en-2026"
E   AssertionError: assert 'python-312-en-2026' == 'python-3-12-en-2026'
E     
E     - python-3-12-en-2026
E     ?         -
E     + python-312-en-2026
_______________________ test_barra_y_guion_bajo_separan _______________________
test_task.py:26: in test_barra_y_guion_bajo_separan
    assert slugify("Entrada/Salida") == "entrada-salida"
E   AssertionError: assert 'entradasalida' == 'entrada-salida'
E     
E     - entrada-salida
E     ?        -
E     + entradasalida
=========================== short test summary info ===========================
FAILED test_task.py::test_punto_entre_digitos_separa - AssertionError: assert...
FAILED test_task.py::test_barra_y_guion_bajo_separan - AssertionError: assert...
2 failed, 6 passed in 0.15s
Fusionar intervalosmerge_intervalsA 8/8 B 8/8
# Fusionar intervalos Escribe una función de Python con esta firma exacta: ```python def merge_intervals(intervals: list[tuple[int, int]]) -> list[tuple[int, int]]: ``` Recibe una lista de intervalos **cerrados** `(inicio, fin)` de números enteros y devuelve una lista nueva con los intervalos fusionados: 1. El resultado está ordenado por `inicio` y ningún par de intervalos del resultado se solapa ni se toca. 2. Dos intervalos que se solapan o que **comparten un extremo** se fusionan: `(1, 3)` y `(3, 5)` → `(1, 5)`. 3. Dos intervalos consecutivos que no comparten ningún punto **no** se fusionan: `(1, 2)` y `(3, 4)` siguen separados. 4. La entrada puede venir desordenada y puede contener intervalos de un solo punto, como `(5, 5)`. 5. La lista de entrada no se modifica. 6. Si algún intervalo tiene `inicio > fin`, lanza `ValueError`. 7. Una lista vacía devuelve `[]`. 8. Cada intervalo del resultado es una tupla `(inicio, fin)`. Ejemplo: ```python merge_intervals([(8, 10), (1, 3), (2, 6), (15, 18)]) # [(1, 6), (8, 10), (15, 18)] ```
A · replay:alfa
8/8 tests · resuelta · 3,4 s
def merge_intervals(intervals: list[tuple[int, int]]) -> list[tuple[int, int]]:
    for start, end in intervals:
        if start > end:
            raise ValueError(f"Intervalo inválido: ({start}, {end})")

    merged: list[tuple[int, int]] = []
    for start, end in sorted(intervals):
        if merged and start <= merged[-1][1]:
            last_start, last_end = merged[-1]
            merged[-1] = (last_start, max(last_end, end))
        else:
            merged.append((start, end))
    return merged
Salida de pytest
........                                                                 [100%]
8 passed in 0.06s
B · replay:beta
8/8 tests · resuelta · 8,9 s
def merge_intervals(intervals: list[tuple[int, int]]) -> list[tuple[int, int]]:
    """Fusiona intervalos cerrados que se solapan o comparten un extremo."""
    if not intervals:
        return []

    # Validamos antes de hacer nada para no devolver resultados parciales.
    for interval in intervals:
        start, end = interval
        if start > end:
            raise ValueError(f"El intervalo {interval!r} tiene inicio > fin")

    # sorted() crea una lista nueva, así que la entrada no se modifica.
    ordered = sorted(intervals, key=lambda item: item[0])

    result: list[tuple[int, int]] = [tuple(ordered[0])]
    for start, end in ordered[1:]:
        current_start, current_end = result[-1]
        if start <= current_end:  # se solapan o se tocan
            result[-1] = (current_start, max(current_end, end))
        else:
            result.append((start, end))
    return result
Salida de pytest
........                                                                 [100%]
8 passed in 0.06s
Convertir una duración a segundosparse_durationA 15/16 B 16/16
# Convertir una duración a segundos Escribe una función de Python con esta firma exacta: ```python def parse_duration(text: str) -> int: ``` Recibe una duración escrita por una persona, como `"1h 30m 15s"`, y devuelve el total en segundos (`5415` en ese ejemplo). Formato válido: 1. La duración está formada por uno o más **componentes** `<entero><unidad>`, sin espacio entre el número y la unidad. 2. Las unidades son `d` (días), `h` (horas), `m` (minutos) y `s` (segundos), en minúsculas o mayúsculas. 3. Los componentes pueden ir juntos (`"1h30m"`) o separados por espacios, y se admiten espacios al principio y al final. 4. Cada unidad aparece **como mucho una vez** y siempre en orden descendente: `d`, luego `h`, luego `m`, luego `s`. Se pueden omitir unidades (`"2d 5s"` es válido). 5. El número es un entero sin signo; `"0s"` es válido y vale `0`. Cualquier otra cosa debe lanzar `ValueError`, por ejemplo: cadena vacía o solo espacios, un número sin unidad (`"10"`), una unidad desconocida (`"5x"`), una unidad repetida (`"1h 2h"`), unidades fuera de orden (`"30m 1h"`), signos (`"-5m"`), decimales (`"1.5h"`) o texto sobrante (`"1h y 5m"`).
A · replay:alfa
15/16 tests · 1 falla · 3,9 s
import re

_SECONDS = {"d": 86_400, "h": 3_600, "m": 60, "s": 1}
_FORMAT = re.compile(r"(?:\s*\d+[dhms])+\s*", re.IGNORECASE)
_COMPONENT = re.compile(r"(\d+)([dhms])", re.IGNORECASE)


def parse_duration(text: str) -> int:
    if not _FORMAT.fullmatch(text):
        raise ValueError(f"Duración no válida: {text!r}")

    total = 0
    seen: set[str] = set()
    for number, unit in _COMPONENT.findall(text):
        unit = unit.lower()
        if unit in seen:
            raise ValueError(f"Unidad repetida: {unit!r}")
        seen.add(unit)
        total += int(number) * _SECONDS[unit]
    return total
Salida de pytest
...............F                                                         [100%]
================================== FAILURES ===================================
_______________ test_unidades_fuera_de_orden_lanzan_valueerror ________________
test_task.py:41: in test_unidades_fuera_de_orden_lanzan_valueerror
    with pytest.raises(ValueError):
         ^^^^^^^^^^^^^^^^^^^^^^^^^
E   Failed: DID NOT RAISE ValueError
=========================== short test summary info ===========================
FAILED test_task.py::test_unidades_fuera_de_orden_lanzan_valueerror - Failed:...
1 failed, 15 passed in 0.15s
B · replay:beta
16/16 tests · resuelta · 11,5 s
import re

_UNITS = (("d", 86_400), ("h", 3_600), ("m", 60), ("s", 1))
_PATTERN = re.compile(
    r"\s*"
    r"(?:(?P<d>\d+)d)?\s*"
    r"(?:(?P<h>\d+)h)?\s*"
    r"(?:(?P<m>\d+)m)?\s*"
    r"(?:(?P<s>\d+)s)?\s*",
    re.IGNORECASE,
)


def parse_duration(text: str) -> int:
    """Convierte una duración como "1h 30m 15s" en segundos."""
    match = _PATTERN.fullmatch(text)
    if match is None:
        raise ValueError(f"Duración no válida: {text!r}")

    values = match.groupdict()
    if all(value is None for value in values.values()):
        raise ValueError("La duración está vacía")

    return sum(int(values[unit]) * factor for unit, factor in _UNITS if values[unit] is not None)
Salida de pytest
................                                                         [100%]
16 passed in 0.06s