Después del clásico FizzBuzz, el siguiente reto sube ligeramente el nivel: trabajar con cadenas de texto y diseñar una función que determine si dos palabras son anagramas.
Este ejercicio es especialmente interesante en PLC porque obliga a trabajar con:
- Manipulación de strings
- Gestión de arrays
- Contadores
- Comparaciones estructuradas
- Diseño de funciones reutilizables
Y todo esto en Structured Text (ST) dentro de TwinCAT 3.
El reto
Debemos crear una función que:
- Reciba dos palabras (
STRING) - Devuelva
TRUEsi son anagramas - Devuelva
FALSEsi no lo son
Condiciones:
- Un anagrama consiste en reordenar todas las letras de otra palabra.
- No es necesario comprobar si la palabra existe en el diccionario.
- Dos palabras exactamente iguales no se consideran anagrama.
Ejemplo:
'cosa' → 'saco' → TRUE 'cosa' → 'cosa' → FALSE
Programa principal
PROGRAM R002_Es_un_Anagrama
VAR
result : BOOL;
END_VAR
result := IsAnagram('cosa', 'saco');
Aquí simplemente llamamos a la función IsAnagram y almacenamos el resultado.
Diseño de la función
FUNCTION IsAnagram : BOOL VAR_INPUT sWordA : STRING(20); sWordB : STRING(20); END_VAR
La función recibe dos palabras y devuelve un booleano.
Estrategia utilizada
En lugar de ordenar cadenas (lo cual implicaría más complejidad), utilizamos un enfoque más robusto y eficiente:
Contar la frecuencia de cada carácter
La idea es simple:
- Contar cuántas veces aparece cada carácter en la palabra A.
- Contar cuántas veces aparece cada carácter en la palabra B.
- Comparar los contadores.
Si todos coinciden → son anagramas.
Inicialización de contadores
FOR i:= 0 TO 256 DO CountA[i] := 0; CountB[i] := 0; END_FOR
Se crean dos arrays de tamaño 256 (rango ASCII) para almacenar la frecuencia de cada carácter.
Este enfoque evita depender de ordenamientos y reduce el problema a comparación de frecuencias.
Conteo de caracteres
Para la primera palabra:
lengthA := LEN(sWordA); FOR i := 0 TO lengthA DO bCode := sWordA[i]; CountA[BYTE_TO_INT(bCode)] := CountA[BYTE_TO_INT(bCode)] + 1; END_FOR
Cada carácter se convierte en su código ASCII y se incrementa el contador correspondiente.
Para la segunda palabra:
lengthB := LEN(sWordB); FOR i := 0 TO lengthB DO bCode := sWordB[i]; CountB[BYTE_TO_INT(bCode)] := CountB[BYTE_TO_INT(bCode)] + 1; END_FOR
Validaciones previas importantes
IF lengthA <> lengthB THEN IsAnagram := FALSE; RETURN; END_IF; IF sWordA = sWordB THEN IsAnagram := FALSE; RETURN; END_IF;
Primero descartamos casos evidentes:
- Si no tienen la misma longitud → imposible que sean anagramas.
- Si son exactamente iguales → no cumplen la definición del reto.
Esto evita cálculos innecesarios.
Comparación final
FOR i:= 0 TO 256 DO IF CountA[i] <> CountB[i] THEN IsAnagram := FALSE; RETURN; END_IF END_FOR IsAnagram := TRUE;
Si algún contador difiere, las palabras no son anagramas.
Si todos coinciden, entonces sí lo son.
Reflexión
Este ejercicio introduce conceptos muy relevantes para programación industrial:
- Manipulación avanzada de datos
- Uso eficiente de memoria
- Comparaciones estructuradas
- Early return para optimización
- Diseño de funciones puras (sin efectos colaterales)
Además, el enfoque basado en frecuencia de caracteres es:
- Más eficiente que ordenar
- Más escalable
- Independiente del idioma
- Fácil de testear
En un entorno industrial real, este patrón podría utilizarse en:
- Validación de comandos
- Procesamiento de recetas
- Sistemas de trazabilidad
- Normalización de datos recibidos por comunicación
Posibles mejoras
Algunas mejoras arquitectónicas interesantes serían:
- Normalizar mayúsculas/minúsculas (
TO_LOWER) - Ignorar espacios
- Convertir la función en un método de una librería de utilidades
- Implementar testing automático con TcUnit
- Optimizar rango ASCII si solo usamos letras
Conclusión
Aunque “¿Es un Anagrama?” parece un reto simple, es una excelente excusa para practicar:
- Diseño estructurado
- Pensamiento algorítmico
- Manipulación de strings en PLC
- Funciones reutilizables

No responses yet