ハノイの塔
上級
これはEngineering, Multimodal AI分野の自動化ワークフローで、21個のノードを含みます。主にIf, Set, Code, ManualTrigger, ExecuteWorkflowなどのノードを使用。 サブワークフローによる再帰アルゴリズムの実装:ハノイの塔デモ
前提条件
- •特別な前提条件なし、インポートしてすぐに使用可能
ワークフロープレビュー
ノード接続関係を可視化、ズームとパンをサポート
ワークフローをエクスポート
以下のJSON設定をn8nにインポートして、このワークフローを使用できます
{
"id": "VPnclcR3gHg85eOV",
"meta": {
"instanceId": "1ee7910f98ee64be6f03d5c49b072eda83992583a161149dc94314ed0b0a2fe0"
},
"name": "Towers of Hanoi",
"tags": [],
"nodes": [
{
"id": "d0112e92-b3e0-4d97-b06d-382470864364",
"name": "円盤の数を設定",
"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": "最大1枚の円盤",
"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 to 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 to 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": "更新",
"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": "更新",
"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": "スタックを作成",
"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": "解法",
"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": "ユーザー入力",
"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": "セットアップ",
"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": "結果",
"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": "解法",
"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": "交換",
"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": "移動",
"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": "更新",
"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": "開始",
"type": "n8n-nodes-base.manualTrigger",
"position": [
640,
1664
],
"parameters": {},
"typeVersion": 1
},
{
"id": "9baa2d1d-6d3b-4d8f-9d95-db479479a4e2",
"name": "ハノイの塔",
"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
}
]
]
}
}
}よくある質問
このワークフローの使い方は?
上記のJSON設定コードをコピーし、n8nインスタンスで新しいワークフローを作成して「JSONからインポート」を選択、設定を貼り付けて認証情報を必要に応じて変更してください。
このワークフローはどんな場面に適していますか?
上級 - エンジニアリング, マルチモーダルAI
有料ですか?
このワークフローは完全無料です。ただし、ワークフローで使用するサードパーティサービス(OpenAI APIなど)は別途料金が発生する場合があります。
関連ワークフロー
並列処理で速度を最適化した重要なワークフロー(ファンアウト-ファンイン)
並列処理(ファンアウト/ファンイン)を活用した速度クリティカルなワークフローを最適化
If
Set
Code
+
If
Set
Code
34 ノードLucas Peyrin
エンジニアリング
Cloudflare Turnstileを回避してn8nでウェブスクレイピング
Cloudflare Turnstileのブロックを2captchaを使って突破してウェブスクレイピング
Set
Code
Wait
+
Set
Code
Wait
18 ノードLudwig
エンジニアリング
LLM トレーサー
完全なLLM使用追跡・コスト監視ツール、ノード単位での分析付き
If
N8n
Set
+
If
N8n
Set
18 ノードAmir Safavi-Naini
エンジニアリング
APIアーキテクチャ抽出ツール
APIアーキテクチャ抽出器
If
Set
Code
+
If
Set
Code
88 ノードPolina Medvedieva
エンジニアリング
Google Sheets、Forms、Gmailを使った多段階入社フローの自動化
Google Sheets、Forms、Gmailを使って多段階の入社プロセスを自動化
If
Set
Code
+
If
Set
Code
31 ノードPollupAI
人事
待機ノード付きの長時間実行ワークフロー状態管理システム
待機ノード付きの長時間実行ワークフロー状態管理システム
If
Set
Code
+
If
Set
Code
42 ノードLucas Peyrin
エンジニアリング
ワークフロー情報
難易度
上級
ノード数21
カテゴリー2
ノードタイプ7
作成者
Adrian
@adrianAI Software & Platform Engineer. Senior Technical Consultant, Associate Researcher (Data Science & Computer Science Education), Project Engineer, Master of Computer Science (M.Sc.)
外部リンク
n8n.ioで表示 →
このワークフローを共有