Tour de Hanoï

Avancé

Ceci est unEngineering, Multimodal AIworkflow d'automatisation du domainecontenant 21 nœuds.Utilise principalement des nœuds comme If, Set, Code, ManualTrigger, ExecuteWorkflow. Implémentation d'un algorithme récursif avec des sous-workflows : démonstration de la tour de Hanoï

Prérequis
  • Aucun prérequis spécial, prêt à l'emploi après importation
Aperçu du workflow
Visualisation des connexions entre les nœuds, avec support du zoom et du déplacement
Exporter le workflow
Copiez la configuration JSON suivante dans n8n pour importer et utiliser ce workflow
{
  "id": "VPnclcR3gHg85eOV",
  "meta": {
    "instanceId": "1ee7910f98ee64be6f03d5c49b072eda83992583a161149dc94314ed0b0a2fe0"
  },
  "name": "Towers of Hanoi",
  "tags": [],
  "nodes": [
    {
      "id": "d0112e92-b3e0-4d97-b06d-382470864364",
      "name": "Définir le nombre de disques",
      "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": "Max 1 disque",
      "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 vers 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 vers 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": "Mettre à jour",
      "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": "Mettre à jour",
      "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": "Créer des piles",
      "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": "Solution",
      "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": "Entrée utilisateur",
      "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": "Configuration",
      "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": "Résultat",
      "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": "Solution",
      "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": "Échanger",
      "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": "Déplacer",
      "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": "Mettre à jour",
      "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": "Démarrer",
      "type": "n8n-nodes-base.manualTrigger",
      "position": [
        640,
        1664
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "9baa2d1d-6d3b-4d8f-9d95-db479479a4e2",
      "name": "Tours de Hanoï",
      "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
          }
        ]
      ]
    }
  }
}
Foire aux questions

Comment utiliser ce workflow ?

Copiez le code de configuration JSON ci-dessus, créez un nouveau workflow dans votre instance n8n et sélectionnez "Importer depuis le JSON", collez la configuration et modifiez les paramètres d'authentification selon vos besoins.

Dans quelles scénarios ce workflow est-il adapté ?

Avancé - Ingénierie, IA Multimodale

Est-ce payant ?

Ce workflow est entièrement gratuit et peut être utilisé directement. Veuillez noter que les services tiers utilisés dans le workflow (comme l'API OpenAI) peuvent nécessiter un paiement de votre part.

Informations sur le workflow
Niveau de difficulté
Avancé
Nombre de nœuds21
Catégorie2
Types de nœuds7
Description de la difficulté

Adapté aux utilisateurs avancés, avec des workflows complexes contenant 16+ nœuds

Auteur
Adrian

Adrian

@adrian

AI Software & Platform Engineer. Senior Technical Consultant, Associate Researcher (Data Science & Computer Science Education), Project Engineer, Master of Computer Science (M.Sc.)

Liens externes
Voir sur n8n.io

Partager ce workflow

Catégories

Catégories: 34