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 TRUE si son anagramas
  • Devuelva FALSE si 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:

  1. Contar cuántas veces aparece cada carácter en la palabra A.
  2. Contar cuántas veces aparece cada carácter en la palabra B.
  3. 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

Tags:

No responses yet

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *