Torres de Hanói
Este es unEngineering, Multimodal AIflujo de automatización del dominio deautomatización que contiene 21 nodos.Utiliza principalmente nodos como If, Set, Code, ManualTrigger, ExecuteWorkflow. Implementación de algoritmos recursivos usando sub-flujos de trabajo: Demostración de la Torre de Hanoi
- •No hay requisitos previos especiales, puede importar y usarlo directamente
Nodos utilizados (21)
Categoría
{
"id": "VPnclcR3gHg85eOV",
"meta": {
"instanceId": "1ee7910f98ee64be6f03d5c49b072eda83992583a161149dc94314ed0b0a2fe0"
},
"name": "Towers of Hanoi",
"tags": [],
"nodes": [
{
"id": "d0112e92-b3e0-4d97-b06d-382470864364",
"name": "Establecer número de discos",
"type": "n8n-nodes-base.set",
"position": [
912,
1664
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "c775d359-9599-494b-918c-3e46aae9274c",
"name": "numberOfDiscs",
"type": "number",
"value": 4
}
]
}
},
"notesInFlow": true,
"typeVersion": 3.4
},
{
"id": "b76775a3-9cf4-4cb5-9945-4cb7d2df7436",
"name": "Máximo 1 disco",
"type": "n8n-nodes-base.if",
"position": [
752,
1984
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "26c868df-4677-4ded-9ba5-7a69fc3cfd06",
"operator": {
"type": "number",
"operation": "lte"
},
"leftValue": "={{ $json.numberOfDiscs }}",
"rightValue": 1
}
]
}
},
"typeVersion": 2.2
},
{
"id": "a4ce4e6c-cc21-43f3-b1ae-04768a1abee3",
"name": "A B C",
"type": "n8n-nodes-base.executeWorkflow",
"position": [
1328,
1664
],
"parameters": {
"options": {
"waitForSubWorkflow": true
},
"workflowId": {
"__rl": true,
"mode": "list",
"value": "VPnclcR3gHg85eOV",
"cachedResultName": "Towers of Hanoi"
},
"workflowInputs": {
"value": {
"logs": "={{ $json.logs }}",
"stackX": "={{ $json.stackA }}",
"stackY": "={{ $json.stackB }}",
"stackZ": "={{ $json.stackC }}",
"numberOfDiscs": "={{ $json.numberOfDiscs }}"
},
"schema": [
{
"id": "numberOfDiscs",
"type": "number",
"display": true,
"required": false,
"displayName": "numberOfDiscs",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "stackX",
"type": "object",
"display": true,
"required": false,
"displayName": "stackX",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "stackY",
"type": "object",
"display": true,
"required": false,
"displayName": "stackY",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "stackZ",
"type": "object",
"display": true,
"required": false,
"displayName": "stackZ",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "logs",
"type": "array",
"display": true,
"required": false,
"displayName": "logs",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": true
}
},
"notesInFlow": true,
"typeVersion": 1.2
},
{
"id": "5ef7690f-7554-47f5-8124-562edbba5a86",
"name": "X Y Z",
"type": "n8n-nodes-base.executeWorkflowTrigger",
"position": [
640,
1984
],
"parameters": {
"workflowInputs": {
"values": [
{
"name": "numberOfDiscs",
"type": "number"
},
{
"name": "stackX",
"type": "object"
},
{
"name": "stackY",
"type": "object"
},
{
"name": "stackZ",
"type": "object"
},
{
"name": "logs",
"type": "array"
}
]
}
},
"typeVersion": 1.1
},
{
"id": "be89d88c-9814-440b-8d49-99fe49e65a4b",
"name": "X a Z",
"type": "n8n-nodes-base.code",
"position": [
1232,
1968
],
"parameters": {
"mode": "runOnceForEachItem",
"jsCode": "// Move disc\nconst disc = $json.stackX.items.pop();\n$json.stackZ.items.push(disc);\n\n// Log\n$json.logs.push($json.stackX.name + \" \" + $json.stackZ.name + \" \" + disc);\n\nreturn $input.item;"
},
"typeVersion": 2
},
{
"id": "81ad6f90-0689-43e9-b67b-911c91dade6a",
"name": "X a Z",
"type": "n8n-nodes-base.code",
"position": [
1232,
2112
],
"parameters": {
"mode": "runOnceForEachItem",
"jsCode": "// Move disc\nconst disc = $json.stackX.items.pop();\n$json.stackZ.items.push(disc);\n\n// Log\n$json.logs.push($json.stackX.name + \" \" + $json.stackZ.name + \" \" + disc);\n\nreturn $input.item;"
},
"typeVersion": 2
},
{
"id": "e9430884-2810-475f-90d2-9cffcfbaf9c8",
"name": "Actualizar",
"type": "n8n-nodes-base.code",
"position": [
1072,
2112
],
"parameters": {
"mode": "runOnceForEachItem",
"jsCode": "// Reset number of discs\n$json.numberOfDiscs += 1;\n\n// Reset stacks (XZY to XYZ)\nconst stack = $json.stackY;\n$json.stackY = $json.stackZ;\n$json.stackZ = stack;\n\nreturn $input.item;"
},
"typeVersion": 2
},
{
"id": "ef117924-272e-4eb6-b098-f1a909ae0334",
"name": "Actualizar",
"type": "n8n-nodes-base.code",
"position": [
1520,
2112
],
"parameters": {
"mode": "runOnceForEachItem",
"jsCode": "// Reset number of discs\n$json.numberOfDiscs += 1;\n\n// Reset stacks (YXZ to XYZ)\nconst stack = $json.stackY;\n$json.stackY = $json.stackX;\n$json.stackX = stack;\n\nreturn $input.item;"
},
"typeVersion": 2
},
{
"id": "a3f48f91-44f9-41c2-963d-51c4d2f4e21d",
"name": "Crear pilas",
"type": "n8n-nodes-base.code",
"position": [
1120,
1664
],
"parameters": {
"mode": "runOnceForEachItem",
"jsCode": "// Really check, if you want to waste computing energy. Recursion errors are hard enough. Best regards, Adrian\nconst min = 1;\nconst max = 5;\nif ($json.numberOfDiscs < min) {\n $json.numberOfDiscs = min;\n}\nif ($json.numberOfDiscs > max) {\n $json.numberOfDiscs = max;\n}\n\n// Create stack items\nlet items = [];\nfor (let i=$json.numberOfDiscs; i>0; i--) {\n items.push(i);\n}\n\n// Set data\n$json.stackA = {};\n$json.stackA.name = \"A\";\n$json.stackA.items = items;\n$json.stackB = {};\n$json.stackB.name = \"B\";\n$json.stackB.items = [];\n$json.stackC = {};\n$json.stackC.name = \"C\";\n$json.stackC.items = [];\n$json.logs = [];\n\n// Return this n8n item\nreturn $input.item;"
},
"typeVersion": 2
},
{
"id": "ade72738-15aa-4bcf-b98c-d4804eeb949e",
"name": "X Z Y",
"type": "n8n-nodes-base.executeWorkflow",
"position": [
944,
2112
],
"parameters": {
"options": {},
"workflowId": {
"__rl": true,
"mode": "list",
"value": "VPnclcR3gHg85eOV",
"cachedResultName": "Towers of Hanoi"
},
"workflowInputs": {
"value": {
"logs": "={{ $json.logs }}",
"stackX": "={{ $json.stackX }}",
"stackY": "={{ $json.stackZ }}",
"stackZ": "={{ $json.stackY }}",
"numberOfDiscs": "={{ $json.numberOfDiscs - 1 }}"
},
"schema": [
{
"id": "numberOfDiscs",
"type": "number",
"display": true,
"removed": false,
"required": false,
"displayName": "numberOfDiscs",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "stackX",
"type": "object",
"display": true,
"removed": false,
"required": false,
"displayName": "stackX",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "stackY",
"type": "object",
"display": true,
"removed": false,
"required": false,
"displayName": "stackY",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "stackZ",
"type": "object",
"display": true,
"removed": false,
"required": false,
"displayName": "stackZ",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "logs",
"type": "array",
"display": true,
"removed": false,
"required": false,
"displayName": "logs",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": true
}
},
"notesInFlow": true,
"typeVersion": 1.2
},
{
"id": "69fe66b5-2244-4ba8-a22f-507613f53f0b",
"name": "Y X Z",
"type": "n8n-nodes-base.executeWorkflow",
"position": [
1392,
2112
],
"parameters": {
"options": {
"waitForSubWorkflow": true
},
"workflowId": {
"__rl": true,
"mode": "list",
"value": "VPnclcR3gHg85eOV",
"cachedResultName": "Towers of Hanoi"
},
"workflowInputs": {
"value": {
"logs": "={{ $json.logs }}",
"stackX": "={{ $json.stackY }}",
"stackY": "={{ $json.stackX }}",
"stackZ": "={{ $json.stackZ }}",
"numberOfDiscs": "={{ $json.numberOfDiscs - 1 }}"
},
"schema": [
{
"id": "numberOfDiscs",
"type": "number",
"display": true,
"removed": false,
"required": false,
"displayName": "numberOfDiscs",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "stackX",
"type": "object",
"display": true,
"removed": false,
"required": false,
"displayName": "stackX",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "stackY",
"type": "object",
"display": true,
"removed": false,
"required": false,
"displayName": "stackY",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "stackZ",
"type": "object",
"display": true,
"removed": false,
"required": false,
"displayName": "stackZ",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "logs",
"type": "array",
"display": true,
"removed": false,
"required": false,
"displayName": "logs",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": true
}
},
"notesInFlow": true,
"typeVersion": 1.2
},
{
"id": "01a8c211-6e7f-4ef2-a651-84ed77de8390",
"name": "Solución",
"type": "n8n-nodes-base.code",
"position": [
1536,
1664
],
"parameters": {
"jsCode": "function logsToSentence(logs) {\n return logs.map((entry, index) => {\n const [from, to, disc] = entry.split(\" \");\n let text;\n\n if (index === 0) {\n text = `Move disc ${disc} from ${from} to ${to}`;\n } else if (index === 1) {\n text = `then ${from} ${disc}→ ${to}`;\n } else {\n text = `${from} ${disc}→ ${to}`;\n }\n\n text += \",\";\n\n if (index === 0 || index % 2 === 1) {\n text += \"\\n\";\n } else {\n text += \" \";\n }\n\n return text;\n }).join(\"\").slice(0, -2) + \".\";\n}\n\nreturn { \"solution\" : logsToSentence($input.first().json.logs) };"
},
"typeVersion": 2
},
{
"id": "4f5aeb9a-37e0-4a02-9c0d-35dfe57cf70b",
"name": "Entrada del usuario",
"type": "n8n-nodes-base.stickyNote",
"position": [
864,
1360
],
"parameters": {
"color": 7,
"width": 192,
"height": 448,
"content": "### Input\n- **numberOfDiscs:** 4 "
},
"typeVersion": 1
},
{
"id": "1633c56d-628c-4976-b00a-f2322bffc46f",
"name": "Configuración",
"type": "n8n-nodes-base.stickyNote",
"position": [
1072,
1360
],
"parameters": {
"color": 7,
"width": 192,
"height": 448,
"content": "### Setup\n- **numberOfDiscs:** 4 \n- **stackA**\n - **name:** A \n - **items:** 4, 3, 2, 1 \n- **stackB**\n - **name:** B \n - **items:** - \n- **stackC**\n - **name:** C \n - **items:** - \n"
},
"typeVersion": 1
},
{
"id": "187388ec-ec1c-4ee9-acf2-cad916f301b6",
"name": "Resultado",
"type": "n8n-nodes-base.stickyNote",
"position": [
1280,
1360
],
"parameters": {
"color": 7,
"width": 192,
"height": 448,
"content": "### Result\n- **numberOfDiscs:** 4 \n- **stackX**\n - **name:** A \n - **items:** - \n- **stackY**\n - **name:** B \n - **items:** - \n- **stackZ**\n - **name:** C \n - **items:** 4, 3, 2, 1"
},
"typeVersion": 1
},
{
"id": "3a038abe-5ee2-4875-898a-d92910fc343a",
"name": "Solución",
"type": "n8n-nodes-base.stickyNote",
"position": [
1488,
1360
],
"parameters": {
"color": 7,
"width": 208,
"height": 448,
"content": "### Solution\nMove disc 1 from A to B,\nthen A 2→ C,\nB 1→ C, A 3→ B,\nC 1→ A, C 2→ B,\nA 1→ B, A 4→ C,\nB 1→ C, B 2→ A,\nC 1→ A, B 3→ C,\nA 1→ B, A 2→ C,\nB 1→ C."
},
"typeVersion": 1
},
{
"id": "2cdfe45e-3284-46b9-933c-c399ed0abfdc",
"name": "Intercambiar",
"type": "n8n-nodes-base.stickyNote",
"position": [
864,
1840
],
"parameters": {
"color": 7,
"width": 198,
"height": 416,
"content": "### Node input\n- **numberOfDiscs** -1 \n- stackX = **stackX** \n- stackY = **stackZ** \n- stackZ = **stackY** "
},
"typeVersion": 1
},
{
"id": "f4cef2e4-e803-4b61-b197-56b8ef90685a",
"name": "Mover",
"type": "n8n-nodes-base.stickyNote",
"position": [
1184,
1840
],
"parameters": {
"color": 7,
"width": 192,
"height": 416,
"content": "### Node steps\n- disc = **stackX**.pop()\n- **stackZ**.push(disc)"
},
"typeVersion": 1
},
{
"id": "b4ad8c17-ff19-4cd6-a848-207ec67918e1",
"name": "Actualizar",
"type": "n8n-nodes-base.stickyNote",
"position": [
1504,
1840
],
"parameters": {
"color": 7,
"width": 192,
"height": 416,
"content": "### Node steps\n- **numberOfDiscs** += 1\n- YXZ to XYZ\n - stack = **stackY**\n - **stackY** = **stackX**\n - **stackX** = stack"
},
"typeVersion": 1
},
{
"id": "89a9c41f-42c4-48c1-a187-a90a795f7bdd",
"name": "Inicio",
"type": "n8n-nodes-base.manualTrigger",
"position": [
640,
1664
],
"parameters": {},
"typeVersion": 1
},
{
"id": "9baa2d1d-6d3b-4d8f-9d95-db479479a4e2",
"name": "Torres de Hanói",
"type": "n8n-nodes-base.stickyNote",
"position": [
0,
1360
],
"parameters": {
"color": 5,
"width": 576,
"height": 1024,
"content": "## Towers of Hanoi\nThis is an **example of using sub-workflow nodes** and a proof of concept showing that it’s possible to **solve and explain recursive problems with n8n**.\n\n### Task\nMove a stack of n disks from rod A to rod C, using rod B as auxiliary. Only one disk can be moved at a time, and no disk may be placed on a smaller disk.\n\n### Example\n```\nn=4\n | | |\n = | |\n === | |\n ===== | |\n ======= | |\n --------- --------- ---------\n A B C\n```\n### Algorithm\n```\nprocedure Hanoi(n, X, Y, Z):\n if n == 1:\n move disk from X to Z\n else:\n Hanoi(n-1, X, Z, Y)\n move disk from X to Z\n Hanoi(n-1, Y, X, Z)\n```\nAnother variant, with better readability and no redundant code, but it includes empty n8n executions (when n is 0):\n```\nprocedure Hanoi(n, X, Y, Z):\n if n > 0:\n Hanoi(n-1, X, Z, Y)\n move disk from X to Z\n Hanoi(n-1, Y, X, Z)\n```\n### Notes\n- This is a learning example. In a real scenario, you would probably use an iterative approach with only a single code node.\n- The workflow variables X, Y, and Z represent the positions of the rods. E.g., if rods A and B are swapped, A is at position Y and B is at position X.\n- As the modified number of discs and positions are returned when a sub-workflow finishes, the \"Update\" nodes reset these values.\n- When experimenting with recursion, make sure to define a termination condition first. Also, be aware of the \"Restart workspace\" link in the [n8n Dashboard](https://app.n8n.cloud/manage).\n- Check Towers of Hanoi on [GitHub](https://github.com/adibaba/n8n.workflows)\n- Learn more about [Recursion on Wikipedia](https://en.wikipedia.org/w/index.php?title=Recursion_(computer_science)&oldid=1301600240#Towers_of_Hanoi)."
},
"typeVersion": 1
}
],
"active": false,
"pinData": {},
"settings": {
"executionOrder": "v1"
},
"versionId": "50e00ac4-9c41-4e49-9390-4f196d97ad1a",
"connections": {
"a4ce4e6c-cc21-43f3-b1ae-04768a1abee3": {
"main": [
[
{
"node": "3a038abe-5ee2-4875-898a-d92910fc343a",
"type": "main",
"index": 0
}
]
]
},
"89a9c41f-42c4-48c1-a187-a90a795f7bdd": {
"main": [
[
{
"node": "d0112e92-b3e0-4d97-b06d-382470864364",
"type": "main",
"index": 0
}
]
]
},
"5ef7690f-7554-47f5-8124-562edbba5a86": {
"main": [
[
{
"node": "b76775a3-9cf4-4cb5-9945-4cb7d2df7436",
"type": "main",
"index": 0
}
]
]
},
"ade72738-15aa-4bcf-b98c-d4804eeb949e": {
"main": [
[
{
"node": "b4ad8c17-ff19-4cd6-a848-207ec67918e1",
"type": "main",
"index": 0
}
]
]
},
"69fe66b5-2244-4ba8-a22f-507613f53f0b": {
"main": [
[
{
"node": "b4ad8c17-ff19-4cd6-a848-207ec67918e1",
"type": "main",
"index": 0
}
]
]
},
"b4ad8c17-ff19-4cd6-a848-207ec67918e1": {
"main": [
[
{
"node": "81ad6f90-0689-43e9-b67b-911c91dade6a",
"type": "main",
"index": 0
}
]
]
},
"81ad6f90-0689-43e9-b67b-911c91dade6a": {
"main": [
[
{
"node": "69fe66b5-2244-4ba8-a22f-507613f53f0b",
"type": "main",
"index": 0
}
]
]
},
"b76775a3-9cf4-4cb5-9945-4cb7d2df7436": {
"main": [
[
{
"node": "81ad6f90-0689-43e9-b67b-911c91dade6a",
"type": "main",
"index": 0
}
],
[
{
"node": "ade72738-15aa-4bcf-b98c-d4804eeb949e",
"type": "main",
"index": 0
}
]
]
},
"a3f48f91-44f9-41c2-963d-51c4d2f4e21d": {
"main": [
[
{
"node": "a4ce4e6c-cc21-43f3-b1ae-04768a1abee3",
"type": "main",
"index": 0
}
]
]
},
"d0112e92-b3e0-4d97-b06d-382470864364": {
"main": [
[
{
"node": "a3f48f91-44f9-41c2-963d-51c4d2f4e21d",
"type": "main",
"index": 0
}
]
]
}
}
}¿Cómo usar este flujo de trabajo?
Copie el código de configuración JSON de arriba, cree un nuevo flujo de trabajo en su instancia de n8n y seleccione "Importar desde JSON", pegue la configuración y luego modifique la configuración de credenciales según sea necesario.
¿En qué escenarios es adecuado este flujo de trabajo?
Avanzado - Ingeniería, IA Multimodal
¿Es de pago?
Este flujo de trabajo es completamente gratuito, puede importarlo y usarlo directamente. Sin embargo, tenga en cuenta que los servicios de terceros utilizados en el flujo de trabajo (como la API de OpenAI) pueden requerir un pago por su cuenta.
Flujos de trabajo relacionados recomendados
Adrian
@adrianAI Software & Platform Engineer. Senior Technical Consultant, Associate Researcher (Data Science & Computer Science Education), Project Engineer, Master of Computer Science (M.Sc.)
Compartir este flujo de trabajo