mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2026-05-28 18:26:54 +00:00
feat(curriculum): added the Tower of Hanoi Python project (#51347)
Co-authored-by: Naomi Carrigan <nhcarrigan@gmail.com> Co-authored-by: Krzysztof G. <60067306+gikf@users.noreply.github.com> Co-authored-by: Shaun Hamilton <shauhami020@gmail.com> Co-authored-by: Estefania Cassingena Navone <85124911+estefaniacn@users.noreply.github.com>
This commit is contained in:
@@ -1191,6 +1191,13 @@
|
||||
"title": "Upcoming Python Project",
|
||||
"intro": ["placeholder"]
|
||||
},
|
||||
"learn-recursion-by-solving-the-tower-of-hanoi-puzzle": {
|
||||
"title": "Learn Recursion by Solving the Tower of Hanoi Puzzle",
|
||||
"intro": [
|
||||
"Recursion allows you to write concise and elegant code to solve complex computational problems.",
|
||||
"In this project, you'll start with an iterative approach to solve the tower of Hanoi mathematical puzzle and then you'll learn how to implement a recursive solution."
|
||||
]
|
||||
},
|
||||
"learn-string-manipulation-by-building-a-cipher": {
|
||||
"title": "Learn String Manipulation by Building a Cipher",
|
||||
"intro": [
|
||||
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
---
|
||||
title: Introduction to the Learn Recursion by Solving the Tower of Hanoi Puzzle
|
||||
block: learn-recursion-by-solving-the-tower-of-hanoi-puzzle
|
||||
superBlock: upcoming-python
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Introduction to the Learn Recursion by Solving the Tower of Hanoi Puzzle
|
||||
|
||||
This is a test for the new project-based curriculum.
|
||||
+237
@@ -0,0 +1,237 @@
|
||||
{
|
||||
"name": "Learn Recursion by Solving the Tower of Hanoi Puzzle",
|
||||
"isUpcomingChange": true,
|
||||
"usesMultifileEditor": true,
|
||||
"hasEditableBoundaries": true,
|
||||
"dashedName": "learn-recursion-by-solving-the-tower-of-hanoi-puzzle",
|
||||
"order": 3,
|
||||
"time": "5 hours",
|
||||
"template": "",
|
||||
"required": [],
|
||||
"superBlock": "upcoming-python",
|
||||
"superOrder": 20,
|
||||
"isBeta": true,
|
||||
"challengeOrder": [
|
||||
{
|
||||
"id": "64dc8b1faf9c60304ca8a9b6",
|
||||
"title": "Step 1"
|
||||
},
|
||||
{
|
||||
"id": "64de1469fccce61940f498c4",
|
||||
"title": "Step 2"
|
||||
},
|
||||
{
|
||||
"id": "64dc8ea01436383a88256d7f",
|
||||
"title": "Step 3"
|
||||
},
|
||||
{
|
||||
"id": "64dc9004f658183afa85f4f1",
|
||||
"title": "Step 4"
|
||||
},
|
||||
{
|
||||
"id": "64dc90949ff85e3b37be40d0",
|
||||
"title": "Step 5"
|
||||
},
|
||||
{
|
||||
"id": "64dc90e837670a3ba26a1e61",
|
||||
"title": "Step 6"
|
||||
},
|
||||
{
|
||||
"id": "64dc916138dbe03bdfe6cec6",
|
||||
"title": "Step 7"
|
||||
},
|
||||
{
|
||||
"id": "64dc922df2919e3c38cead61",
|
||||
"title": "Step 8"
|
||||
},
|
||||
{
|
||||
"id": "64dc92a9718fb53ca3d1bad7",
|
||||
"title": "Step 9"
|
||||
},
|
||||
{
|
||||
"id": "64dc963d866fff3dd0329993",
|
||||
"title": "Step 10"
|
||||
},
|
||||
{
|
||||
"id": "64dc97005bc7943e2978df0a",
|
||||
"title": "Step 11"
|
||||
},
|
||||
{
|
||||
"id": "64dc976bf864693e668d67e8",
|
||||
"title": "Step 12"
|
||||
},
|
||||
{
|
||||
"id": "64de4bccf5becb208a48ca97",
|
||||
"title": "Step 13"
|
||||
},
|
||||
{
|
||||
"id": "64df72c6e0183a191fcd72dc",
|
||||
"title": "Step 14"
|
||||
},
|
||||
{
|
||||
"id": "64e33a488b4a2717fa22ebf3",
|
||||
"title": "Step 15"
|
||||
},
|
||||
{
|
||||
"id": "64dc97ab25730b3e9de86ea5",
|
||||
"title": "Step 16"
|
||||
},
|
||||
{
|
||||
"id": "64dc985e6720a23edac63b51",
|
||||
"title": "Step 17"
|
||||
},
|
||||
{
|
||||
"id": "65782342850feb3b8d62f936",
|
||||
"title": "Step 18"
|
||||
},
|
||||
{
|
||||
"id": "6578273de26b6e5965a9107d",
|
||||
"title": "Step 19"
|
||||
},
|
||||
{
|
||||
"id": "64dcd3d61c448e2676501f43",
|
||||
"title": "Step 20"
|
||||
},
|
||||
{
|
||||
"id": "64dcd9bbc2268127e7898d77",
|
||||
"title": "Step 21"
|
||||
},
|
||||
{
|
||||
"id": "64dcdee07a14f0299ec30559",
|
||||
"title": "Step 22"
|
||||
},
|
||||
{
|
||||
"id": "64dce5f6ff907c2b2c47bb05",
|
||||
"title": "Step 23"
|
||||
},
|
||||
{
|
||||
"id": "64dce7ee2494e82bf4205a3f",
|
||||
"title": "Step 24"
|
||||
},
|
||||
{
|
||||
"id": "64dceadec3c9cf2ca7b56de6",
|
||||
"title": "Step 25"
|
||||
},
|
||||
{
|
||||
"id": "64ddcc2ee182e0164c3539f8",
|
||||
"title": "Step 26"
|
||||
},
|
||||
{
|
||||
"id": "64ddce6f6e8066173208235b",
|
||||
"title": "Step 27"
|
||||
},
|
||||
{
|
||||
"id": "64ddd02838f36117cd9738eb",
|
||||
"title": "Step 28"
|
||||
},
|
||||
{
|
||||
"id": "64ddd280d69fa818ca782d50",
|
||||
"title": "Step 29"
|
||||
},
|
||||
{
|
||||
"id": "64ddd4fbb4b598199acf5ec5",
|
||||
"title": "Step 30"
|
||||
},
|
||||
{
|
||||
"id": "64ddd65848a12919d7e1c7d0",
|
||||
"title": "Step 31"
|
||||
},
|
||||
{
|
||||
"id": "64de6c8a5305d8173a3a9e09",
|
||||
"title": "Step 32"
|
||||
},
|
||||
{
|
||||
"id": "64de7357cc75bd18bdced920",
|
||||
"title": "Step 33"
|
||||
},
|
||||
{
|
||||
"id": "64de73f6c2486518e3064fec",
|
||||
"title": "Step 34"
|
||||
},
|
||||
{
|
||||
"id": "64de7662244db513d7b673ec",
|
||||
"title": "Step 35"
|
||||
},
|
||||
{
|
||||
"id": "64de773f81facd14653f49c8",
|
||||
"title": "Step 36"
|
||||
},
|
||||
{
|
||||
"id": "64de79de2fac6b1536ebcfdd",
|
||||
"title": "Step 37"
|
||||
},
|
||||
{
|
||||
"id": "64de7be06eb689161dd63cf0",
|
||||
"title": "Step 38"
|
||||
},
|
||||
{
|
||||
"id": "64df202aa1342114cd077920",
|
||||
"title": "Step 39"
|
||||
},
|
||||
{
|
||||
"id": "64df332162988b13c35b7f7d",
|
||||
"title": "Step 40"
|
||||
},
|
||||
{
|
||||
"id": "64df346f4c86461419974c1e",
|
||||
"title": "Step 41"
|
||||
},
|
||||
{
|
||||
"id": "64df353d7ae6dc148fd64f53",
|
||||
"title": "Step 42"
|
||||
},
|
||||
{
|
||||
"id": "64df3e2fac34d813d048f3f9",
|
||||
"title": "Step 43"
|
||||
},
|
||||
{
|
||||
"id": "64df3f1011888113fbd3d81b",
|
||||
"title": "Step 44"
|
||||
},
|
||||
{
|
||||
"id": "64e337e3096b7c1739d934e6",
|
||||
"title": "Step 45"
|
||||
},
|
||||
{
|
||||
"id": "64df45a3ad4f8719e5355244",
|
||||
"title": "Step 46"
|
||||
},
|
||||
{
|
||||
"id": "64e3392996b41d17a1375643",
|
||||
"title": "Step 47"
|
||||
},
|
||||
{
|
||||
"id": "64e340302bd28513f3e73740",
|
||||
"title": "Step 48"
|
||||
},
|
||||
{
|
||||
"id": "64df47b32b92301a815d5ef8",
|
||||
"title": "Step 49"
|
||||
},
|
||||
{
|
||||
"id": "64df496c6a8ddf1b38db1ed6",
|
||||
"title": "Step 50"
|
||||
},
|
||||
{
|
||||
"id": "64e340ecee18af1430939018",
|
||||
"title": "Step 51"
|
||||
},
|
||||
{
|
||||
"id": "650c6082e5586f9e3acfcd3b",
|
||||
"title": "Step 52"
|
||||
},
|
||||
{
|
||||
"id": "64e34146860065146733883b",
|
||||
"title": "Step 53"
|
||||
},
|
||||
{
|
||||
"id": "657b667a772ed53e82962c81",
|
||||
"title": "Step 54"
|
||||
},
|
||||
{
|
||||
"id": "657b6a4a49faec5c600287ba",
|
||||
"title": "Step 55"
|
||||
}
|
||||
],
|
||||
"helpCategory": "Python"
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
---
|
||||
id: 64dc8b1faf9c60304ca8a9b6
|
||||
title: Step 1
|
||||
challengeType: 20
|
||||
dashedName: step-1
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
In this project, you will solve the mathematical puzzle known as the Tower of Hanoi. The puzzle consists of three rods and a number of disks of different diameters.
|
||||
|
||||
The goal of this puzzle is moving the disks from the first rod to the third rod, following specific rules that restrict placing a larger disk on top of a smaller one.
|
||||
|
||||
Start by creating an empty dictionary named `rods` to represent the rods.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should have a variable named `rods`.
|
||||
|
||||
```js
|
||||
({ test: () => assert(__userGlobals.has('rods')) })
|
||||
```
|
||||
|
||||
Your `rods` variable should be an empty dictionary.
|
||||
|
||||
```js
|
||||
({ test: () => assert(__pyodide.runPython(`
|
||||
rods = __locals.get("rods")
|
||||
rods == {}
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
---
|
||||
id: 64dc8ea01436383a88256d7f
|
||||
title: Step 3
|
||||
challengeType: 20
|
||||
dashedName: step-3
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
The puzzle starts with the disks piled up on the first rod, in decreasing size. You need to populate your first list with numbers representing the various disk sizes.
|
||||
|
||||
Instead of adding the items manually to the first list, generate a sequence of numbers from `3` to `1` by using the `range()` function and assign it to `rods['A']`.
|
||||
|
||||
The syntax is `range(x, y, h)`, where `x` is the starting integer (inclusive), `y` is the last integer (not inclusive), and `h` is the difference between a number and the next one in the sequence.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should use the `range()` function to assign a sequence of numbers to `rods['A']`. The syntax for calling the `range()` function is `range(x, y, h)`.
|
||||
|
||||
```js
|
||||
({ test: () => assert(__pyodide.runPython(`
|
||||
a = __locals.get('rods')
|
||||
type(a['A']) is range
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
You should use the `range()` function to assign the sequence of numbers from `3` to `1` to `rods['A']`.
|
||||
|
||||
```js
|
||||
({ test: () => assert(__pyodide.runPython(`
|
||||
a = __locals.get('rods')
|
||||
a['A'] == range(3, 0, -1)
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
--fcc-editable-region--
|
||||
rods = {
|
||||
'A': [],
|
||||
'B': [],
|
||||
'C': []
|
||||
}
|
||||
--fcc-editable-region--
|
||||
```
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
---
|
||||
id: 64dc9004f658183afa85f4f1
|
||||
title: Step 4
|
||||
challengeType: 20
|
||||
dashedName: step-4
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Now check the data type of your `'A'` key by passing it to the `type()` function and print the result on the terminal.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should pass your `'A'` key to the `type()` function.
|
||||
|
||||
```js
|
||||
({ test: () => assert.match(code, /type\s*\(\s*rods\s*\[\s*('|")\s*A\s*\1\s*\]\)/) })
|
||||
```
|
||||
|
||||
You should print the type of `rods['A']` using the `print()` function.
|
||||
|
||||
```js
|
||||
({ test: () => assert.match(code, /print\s*\(\s*type\s*\(\s*rods\s*\[\s*('|")\s*A\s*\1\s*\]\)\s*\)/) })
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
--fcc-editable-region--
|
||||
rods = {
|
||||
'A': range(3, 0, -1),
|
||||
'B': [],
|
||||
'C': []
|
||||
}
|
||||
--fcc-editable-region--
|
||||
```
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
---
|
||||
id: 64dc90949ff85e3b37be40d0
|
||||
title: Step 5
|
||||
challengeType: 20
|
||||
dashedName: step-5
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
The `range()` function returns an immutable sequence of numbers. As you can see, the data type of `rods['A']` is `range`, but you want it to be a list.
|
||||
|
||||
Pass your `range()` call to the `list()` function to do that.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should pass your `range()` call to the `list()` function.
|
||||
|
||||
```js
|
||||
({ test: () => assert(__pyodide.runPython(`
|
||||
a = __locals.get('rods')
|
||||
a['A'] == list(range(3, 0, -1))
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
--fcc-editable-region--
|
||||
rods = {
|
||||
'A': range(3, 0, -1),
|
||||
'B': [],
|
||||
'C': []
|
||||
}
|
||||
print(type(rods['A']))
|
||||
--fcc-editable-region--
|
||||
```
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
---
|
||||
id: 64dc90e837670a3ba26a1e61
|
||||
title: Step 6
|
||||
challengeType: 20
|
||||
dashedName: step-6
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Now that the type is `list` as required, you can remove the `print()` call.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should remove `print(type(rods['A']))` from your code.
|
||||
|
||||
```js
|
||||
({ test: () => assert.match(code, /\}(?!\s+print\s*\(\s*type\s*\(\s*rods\[\s*('|")A\1\s*\]\s*\)\s*\))/) })
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
--fcc-editable-region--
|
||||
rods = {
|
||||
'A': list(range(3, 0, -1)),
|
||||
'B': [],
|
||||
'C': []
|
||||
}
|
||||
print(type(rods['A']))
|
||||
--fcc-editable-region--
|
||||
```
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
---
|
||||
id: 64dc916138dbe03bdfe6cec6
|
||||
title: Step 7
|
||||
challengeType: 20
|
||||
dashedName: step-7
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
The goal of the Tower of Hanoi is moving all the disks to the last rod. To do that, you must follow three simple rules:
|
||||
|
||||
1. You can move only top-most disks
|
||||
2. You can move only one disk at a time
|
||||
3. You cannot place larger disks on top of smaller ones
|
||||
|
||||
Below your existing code, declare an empty function named `move`. Later on, you will use that function to move the disks between the rods. For now, to avoid errors, use the `pass` keyword inside the function body.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should declare an empty function named `move`. Remember to use the `pass` keyword inside the function body with the correct indentation.
|
||||
|
||||
```js
|
||||
({ test: () => {
|
||||
assert(__pyodide.runPython(`
|
||||
import inspect
|
||||
inspect.isfunction(__locals.get('move'))
|
||||
`))
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
rods = {
|
||||
'A': list(range(3, 0, -1)),
|
||||
'B': [],
|
||||
'C': []
|
||||
}
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
---
|
||||
id: 64dc922df2919e3c38cead61
|
||||
title: Step 8
|
||||
challengeType: 20
|
||||
dashedName: step-8
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
At the top of your code, declare a variable named `NUMBER_OF_DISKS` to store the number of disks and give it the value of `3`. Then, replace the first argument passed in to the `range()` function with your new variable.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should declare a variable named `NUMBER_OF_DISKS`.
|
||||
|
||||
```js
|
||||
({test: () => assert(__userGlobals.has('NUMBER_OF_DISKS')) })
|
||||
```
|
||||
|
||||
The `NUMBER_OF_DISKS` variable should have the value `3`.
|
||||
|
||||
```js
|
||||
({test: () => assert.equal(__userGlobals.get('NUMBER_OF_DISKS'), 3) })
|
||||
```
|
||||
|
||||
You should change the value of the `range()` function's first argument into the `NUMBER_OF_DISKS` variable.
|
||||
|
||||
```js
|
||||
({test: () => assert.match(code, /('|")A\1\s*:\s*list\s*\(\s*range\s*\(\s*NUMBER_OF_DISKS\s*,\s*0\s*,\s*-\s*1\s*\)\s*\)/) })
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
--fcc-editable-region--
|
||||
|
||||
rods = {
|
||||
'A': list(range(3, 0, -1)),
|
||||
'B': [],
|
||||
'C': []
|
||||
}
|
||||
--fcc-editable-region--
|
||||
|
||||
def move():
|
||||
pass
|
||||
```
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
---
|
||||
id: 64dc92a9718fb53ca3d1bad7
|
||||
title: Step 9
|
||||
challengeType: 20
|
||||
dashedName: step-9
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
The Tower of Hanoi puzzle can be solved in 2<sup>n</sup> - 1 moves, where n is the number of disks. Declare a variable named `number_of_moves` and assign the total number of moves to this variable.
|
||||
|
||||
The power operator in Python is `**`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should declare a variable named `number_of_moves`.
|
||||
|
||||
```js
|
||||
({ test: () => assert(__userGlobals.has('number_of_moves')) })
|
||||
```
|
||||
|
||||
The value of `number_of_moves` should be the expression to calculate the number of moves.
|
||||
|
||||
```js
|
||||
({ test: () => {
|
||||
assert(__pyodide.runPython(`
|
||||
a = __locals.get('NUMBER_OF_DISKS')
|
||||
__locals.get('number_of_moves') == 2**a -1
|
||||
`))
|
||||
} })
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
--fcc-editable-region--
|
||||
NUMBER_OF_DISKS = 3
|
||||
|
||||
--fcc-editable-region--
|
||||
rods = {
|
||||
'A': list(range(NUMBER_OF_DISKS, 0, -1)),
|
||||
'B': [],
|
||||
'C': []
|
||||
}
|
||||
def move():
|
||||
pass
|
||||
```
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
---
|
||||
id: 64dc963d866fff3dd0329993
|
||||
title: Step 10
|
||||
challengeType: 20
|
||||
dashedName: step-10
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Print the variable you declared in the previous step and feel free to change the number of disks to see how fast the required minimum number of moves increases.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should print the `number_of_moves` variable.
|
||||
|
||||
```js
|
||||
({ test: () => assert.match(code, /print\s*\(\s*number_of_moves\s*\)/) })
|
||||
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
--fcc-editable-region--
|
||||
NUMBER_OF_DISKS = 3
|
||||
number_of_moves = 2**NUMBER_OF_DISKS - 1
|
||||
|
||||
--fcc-editable-region--
|
||||
rods = {
|
||||
'A': list(range(NUMBER_OF_DISKS, 0, -1)),
|
||||
'B': [],
|
||||
'C': []
|
||||
}
|
||||
|
||||
def move():
|
||||
pass
|
||||
```
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
---
|
||||
id: 64dc97005bc7943e2978df0a
|
||||
title: Step 11
|
||||
challengeType: 20
|
||||
dashedName: step-11
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Now you can remove your `print()` call. Then, inside the `move()` function, remove the `pass` keyword and print the content of your `rods` dictionary.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should not have `print(number_of_moves)` in your code.
|
||||
|
||||
```js
|
||||
({ test: () => assert.isFalse(/print\s*\(\s*number_of_moves\s*\)/.test(code)) })
|
||||
```
|
||||
|
||||
You should remove the `pass` keyword and print the `rods` dictionary.
|
||||
|
||||
```js
|
||||
({ test: () => assert.match(code, /def\s+move\s*\(\s*\)\s*:\s+print\s*\(\s*rods\s*\)(?!\s*pass)/) })
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
--fcc-editable-region--
|
||||
NUMBER_OF_DISKS = 3
|
||||
number_of_moves = 2**NUMBER_OF_DISKS - 1
|
||||
print(number_of_moves)
|
||||
rods = {
|
||||
'A': list(range(NUMBER_OF_DISKS, 0, -1)),
|
||||
'B': [],
|
||||
'C': []
|
||||
}
|
||||
def move():
|
||||
pass
|
||||
--fcc-editable-region--
|
||||
```
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
---
|
||||
id: 64dc976bf864693e668d67e8
|
||||
title: Step 12
|
||||
challengeType: 20
|
||||
dashedName: step-12
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Now call your function and see the output on the terminal.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should call your `move()` function.
|
||||
|
||||
```js
|
||||
({test: () => assert.match(code, /(?<!def\s+)move\(\s*\)/) })
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
NUMBER_OF_DISKS = 3
|
||||
number_of_moves = 2**NUMBER_OF_DISKS - 1
|
||||
rods = {
|
||||
'A': list(range(NUMBER_OF_DISKS, 0, -1)),
|
||||
'B': [],
|
||||
'C': []
|
||||
}
|
||||
def move():
|
||||
print(rods)
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
```
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
---
|
||||
id: 64dc97ab25730b3e9de86ea5
|
||||
title: Step 16
|
||||
challengeType: 20
|
||||
dashedName: step-16
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
At the end of this project, you will create a recursive solution to the Tower of Hanoi puzzle, but now you are going to explore an iterative approach to this problem.
|
||||
|
||||
Start by adding a `for` loop to your function that iterates through the number of moves and prints the current iteration number.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should write a `for` loop to iterate through the number of moves. Use the `range()` function for that.
|
||||
|
||||
```js
|
||||
({ test: () => {
|
||||
const rgs = [
|
||||
/for\s+\w+\s+in\s+range\s*\(\s*number_of_moves\s*\)\s*:/,
|
||||
/for\s+\w+\s+in\s+range\s*\(\s*0\s*,\s*number_of_moves\s*\)\s*:/,
|
||||
/for\s+\w+\s+in\s+range\s*\(\s*0\s*,\s*number_of_moves\s*,\s*1\s*\)\s*:/
|
||||
]
|
||||
const loop = rgs.some(r => code.match(r));
|
||||
assert.isTrue(loop);
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
You should print the current move number at each iteration.
|
||||
|
||||
```js
|
||||
({ test: () => {
|
||||
const rgs = [
|
||||
/for\s+(\w+)\s+in\s+range\s*\(\s*number_of_moves\s*\)\s*:\s+print\s*\(\s*\1\s*\)/,
|
||||
/for\s+(\w+)\s+in\s+range\s*\(\s*0\s*,\s*number_of_moves\s*\)\s*:\s+print\s*\(\s*\1\s*\)/,
|
||||
/for\s+(\w+)\s+in\s+range\s*\(\s*0\s*,\s*number_of_moves\s*,\s*1\s*\)\s*:\s+print\s*\(\s*\1\s*\)/
|
||||
]
|
||||
const loop = rgs.some(r => code.match(r));
|
||||
assert.isTrue(loop);
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
NUMBER_OF_DISKS = 3
|
||||
number_of_moves = 2**NUMBER_OF_DISKS - 1
|
||||
rods = {
|
||||
'A': list(range(NUMBER_OF_DISKS, 0, -1)),
|
||||
'B': [],
|
||||
'C': []
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
def move(n, source, auxiliary, target):
|
||||
# display starting configuration
|
||||
print(rods)
|
||||
--fcc-editable-region--
|
||||
|
||||
# initiate call from source A to target C with auxiliary B
|
||||
move(NUMBER_OF_DISKS, 'A', 'B', 'C')
|
||||
```
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
---
|
||||
id: 64dc985e6720a23edac63b51
|
||||
title: Step 17
|
||||
challengeType: 20
|
||||
dashedName: step-17
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
The allowed disk movements between the rods exhibit a repetitive pattern occurring every three moves. For example, movements between rod `A` and rod `C` are allowed on the first, the fourth and the seventh move, where the remainder of the division between the move number and 3 is equal to 1.
|
||||
|
||||
Inside the previously created `for` loop, replace the existing `print()` call with an `if` statement that is triggered when `(i + 1) % 3 == 1`. Within this `if` statement, print `f'Move {i + 1} allowed between {source} and {target}'` using an f-string. Please, note that `i + 1` is the move number since `i` is zero during the first iteration.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should have an `if` statement that should be executed when `(i + 1) % 3 == 1`.
|
||||
|
||||
```js
|
||||
({test: () => assert.match(code, /if\s+\(\s*i\s*\+\s*1\s*\)\s*%\s*3\s*==\s*1\s*:/)})
|
||||
```
|
||||
|
||||
You should print the string `f'Move {i + 1} allowed between {source} and {target}'` using an f-string.
|
||||
|
||||
```js
|
||||
({test: () => assert.match(code, /print\s*\(\s*f('|")Move\s\{\s*i\s*\+\s*1\s*\}\sallowed\sbetween\s\{\s*source\s*\}\sand\s\{\s*target\s*\s*\}\1\s*\)/)})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
NUMBER_OF_DISKS = 3
|
||||
number_of_moves = 2**NUMBER_OF_DISKS - 1
|
||||
rods = {
|
||||
'A': list(range(NUMBER_OF_DISKS, 0, -1)),
|
||||
'B': [],
|
||||
'C': []
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
def move(n, source, auxiliary, target):
|
||||
# display starting configuration
|
||||
print(rods)
|
||||
for i in range(number_of_moves):
|
||||
print(i)
|
||||
--fcc-editable-region--
|
||||
|
||||
# initiate call from source A to target C with auxiliary B
|
||||
move(NUMBER_OF_DISKS, 'A', 'B', 'C')
|
||||
```
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
---
|
||||
id: 64dcd3d61c448e2676501f43
|
||||
title: Step 20
|
||||
challengeType: 20
|
||||
dashedName: step-20
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
When the remainder of the move number divided by 3 is equal to 2, the movement is allowed between `A` and `B` (the source and the auxiliary rods).
|
||||
|
||||
Add an `elif` statement for that. Then, print the appropriate string if the condition is met.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should have an `elif` statement to execute when `remainder == 2`.
|
||||
|
||||
```js
|
||||
({test: () => assert.match(code, /elif\s+remainder\s*==\s*2:/)})
|
||||
```
|
||||
|
||||
You should print the string `f'Move {i + 1} allowed between {source} and {auxiliary}'`.
|
||||
|
||||
```js
|
||||
({test: () => assert.match(code, /print\s*\(\s*f('|")Move\s\{\s*i\s*\+\s*1\s*\}\sallowed\sbetween\s\{\s*source\s*\}\sand\s\{\s*auxiliary\s*\s*\}\1\s*\)/)})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
NUMBER_OF_DISKS = 3
|
||||
number_of_moves = 2**NUMBER_OF_DISKS - 1
|
||||
rods = {
|
||||
'A': list(range(NUMBER_OF_DISKS, 0, -1)),
|
||||
'B': [],
|
||||
'C': []
|
||||
}
|
||||
--fcc-editable-region--
|
||||
def move(n, source, auxiliary, target):
|
||||
# display starting configuration
|
||||
print(rods)
|
||||
for i in range(number_of_moves):
|
||||
remainder = (i + 1) % 3
|
||||
if remainder == 1:
|
||||
print(f'Move {i + 1} allowed between {source} and {target}')
|
||||
--fcc-editable-region--
|
||||
|
||||
# initiate call from source A to target C with auxiliary B
|
||||
move(NUMBER_OF_DISKS, 'A', 'B', 'C')
|
||||
```
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
---
|
||||
id: 64dcd9bbc2268127e7898d77
|
||||
title: Step 21
|
||||
challengeType: 20
|
||||
dashedName: step-21
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Finally, when the move number divided by 3 has no remainder, the movement is allowed between `B` and `C`.
|
||||
|
||||
Add an `elif` statement for that. Then, print the appropriate string if the condition is met.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should have an `elif` statement to execute when `remainder == 0`.
|
||||
|
||||
```js
|
||||
({test: () => assert.match(code, /elif\s+remainder\s*==\s*0\s*:/)})
|
||||
```
|
||||
|
||||
You should print the string `f'Move {i + 1} allowed between {auxiliary} and {target}'`.
|
||||
|
||||
```js
|
||||
({test: () => assert.match(code, /print\s*\(\s*f('|")Move\s\{\s*i\s*\+\s*1\s*\}\sallowed\sbetween\s\{\s*auxiliary\s*\}\sand\s\{\s*target\s*\s*\}\1\s*\)/)})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
NUMBER_OF_DISKS = 3
|
||||
number_of_moves = 2**NUMBER_OF_DISKS - 1
|
||||
rods = {
|
||||
'A': list(range(NUMBER_OF_DISKS, 0, -1)),
|
||||
'B': [],
|
||||
'C': []
|
||||
}
|
||||
--fcc-editable-region--
|
||||
def move(n, source, auxiliary, target):
|
||||
# display starting configuration
|
||||
print(rods)
|
||||
for i in range(number_of_moves):
|
||||
remainder = (i + 1) % 3
|
||||
if remainder == 1:
|
||||
print(f'Move {i + 1} allowed between {source} and {target}')
|
||||
elif remainder == 2:
|
||||
print(f'Move {i + 1} allowed between {source} and {auxiliary}')
|
||||
--fcc-editable-region--
|
||||
|
||||
# initiate call from source A to target C with auxiliary B
|
||||
move(NUMBER_OF_DISKS, 'A', 'B', 'C')
|
||||
```
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
---
|
||||
id: 64dcdee07a14f0299ec30559
|
||||
title: Step 22
|
||||
challengeType: 20
|
||||
dashedName: step-22
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
You wrote the code to find the allowed movement between the rods, but the actual move could be in both directions.
|
||||
After the `print()` call, declare a variable named `forward` and set it to `False`. You will use that variable to check in which direction you need to move the disk between the rods.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should declare a variable named `forward`.
|
||||
|
||||
```js
|
||||
({ test: () => assert.match(code, /forward\s*=\s*./) })
|
||||
```
|
||||
|
||||
Your `forward` variable should be set to `False`.
|
||||
|
||||
```js
|
||||
({ test: () => assert.match(code, /forward\s*=\s*False/) })
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
NUMBER_OF_DISKS = 3
|
||||
number_of_moves = 2**NUMBER_OF_DISKS - 1
|
||||
rods = {
|
||||
'A': list(range(NUMBER_OF_DISKS, 0, -1)),
|
||||
'B': [],
|
||||
'C': []
|
||||
}
|
||||
|
||||
def move(n, source, auxiliary, target):
|
||||
# display starting configuration
|
||||
print(rods)
|
||||
for i in range(number_of_moves):
|
||||
remainder = (i + 1) % 3
|
||||
--fcc-editable-region--
|
||||
if remainder == 1:
|
||||
print(f'Move {i + 1} allowed between {source} and {target}')
|
||||
--fcc-editable-region--
|
||||
elif remainder == 2:
|
||||
print(f'Move {i + 1} allowed between {source} and {auxiliary}')
|
||||
elif remainder == 0:
|
||||
print(f'Move {i + 1} allowed between {auxiliary} and {target}')
|
||||
|
||||
# initiate call from source A to target C with auxiliary B
|
||||
move(NUMBER_OF_DISKS, 'A', 'B', 'C')
|
||||
```
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
---
|
||||
id: 64dce5f6ff907c2b2c47bb05
|
||||
title: Step 23
|
||||
challengeType: 20
|
||||
dashedName: step-23
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
When `target` is empty, the disk should be moved necessarily from `source` to `target`.
|
||||
|
||||
After the declaration of `forward`, add an `if` statement to check if `rods[target]` is empty. If it is, change `forward` to `True`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should have an `if` statement to check if `rods[target]` is empty, and assign `True` to `forward`.
|
||||
|
||||
```js
|
||||
({
|
||||
test: () => {
|
||||
const tCode = code.replace(/\r/g, '');
|
||||
const ifBlock = __helpers.python.getBlock(tCode, "if remainder == 1");
|
||||
const { block_body } = ifBlock
|
||||
const if2 = __helpers.python.getBlock(block_body, /if [^:]+/);
|
||||
const if2Indent = if2.block_body.match(/ +/)[0];
|
||||
const ifLoc = tCode.indexOf(block_body.slice(0,20));
|
||||
const ifLen = block_body.length;
|
||||
const newIf = block_body + `\n${if2Indent}__spy(forward)`
|
||||
const newCode = `
|
||||
__counter = 0
|
||||
def __spy(x):
|
||||
global __counter
|
||||
if x:
|
||||
__counter += 1
|
||||
|
||||
${tCode.slice(0,ifLoc)}
|
||||
${newIf}
|
||||
${tCode.slice(ifLoc + ifLen)}
|
||||
|
||||
__counter
|
||||
`;
|
||||
const out = __pyodide.runPython(newCode);
|
||||
assert.equal(out, 3);
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
NUMBER_OF_DISKS = 3
|
||||
number_of_moves = 2**NUMBER_OF_DISKS - 1
|
||||
rods = {
|
||||
'A': list(range(NUMBER_OF_DISKS, 0, -1)),
|
||||
'B': [],
|
||||
'C': []
|
||||
}
|
||||
|
||||
def move(n, source, auxiliary, target):
|
||||
# display starting configuration
|
||||
print(rods)
|
||||
for i in range(number_of_moves):
|
||||
remainder = (i + 1) % 3
|
||||
--fcc-editable-region--
|
||||
if remainder == 1:
|
||||
print(f'Move {i + 1} allowed between {source} and {target}')
|
||||
forward = False
|
||||
--fcc-editable-region--
|
||||
elif remainder == 2:
|
||||
print(f'Move {i + 1} allowed between {source} and {auxiliary}')
|
||||
elif remainder == 0:
|
||||
print(f'Move {i + 1} allowed between {auxiliary} and {target}')
|
||||
|
||||
# initiate call from source A to target C with auxiliary B
|
||||
move(NUMBER_OF_DISKS, 'A', 'B', 'C')
|
||||
```
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
---
|
||||
id: 64dce7ee2494e82bf4205a3f
|
||||
title: Step 24
|
||||
challengeType: 20
|
||||
dashedName: step-24
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
The other case in which you have to move the disk necessarily from `source` to `target` is when the source list is **not** empty **and** the last disk in `source` is lower than the last disk in `target`.
|
||||
|
||||
Add an `elif` statement to check this condition. Then, set the `forward` variable to `True` if the condition is met.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should have an `elif` statement to check if `rods[source]` is not empty and `rods[source][-1] < rods[target][-1]`.
|
||||
|
||||
```js
|
||||
const allowedRes = [
|
||||
"rods\\s*\\[\\s*source\\s*\\]",
|
||||
"len\\(rods\\s*\\[\\s*source\\s*\\]\\)\\s*>\\s*0",
|
||||
"len\\(rods\\s*\\[\\s*source\\s*\\]\\)\\s*>=\\s*1",
|
||||
];
|
||||
const re = new RegExp(`elif\\s+((${allowedRes.join(")|(")}))\\s+and\\s+(rods\\s*\\[\\s*source\\s*\\]\\[\\s*-\\s*1\\s*\\]\\s*<\\s*rods\\s*\\[\\s*target\\s*\\]\\[\\s*-\\s*1\\s*\\]|rods\\s*\\[\\s*target\\s*\\]\\[\\s*-\\s*1\\s*\\]\\s*>\\s*rods\\s*\\[\\s*source\\s*\\]\\[\\s*-\\s*1\\s*\\])\\s*:`);
|
||||
assert.match(code, re);
|
||||
```
|
||||
|
||||
You should set `forward` to `True` inside your new `elif` statement. You should not change the previous assignments of `forward`.
|
||||
|
||||
```js
|
||||
const allowedRes = [
|
||||
"rods\\s*\\[\\s*source\\s*\\]",
|
||||
"len\\(rods\\s*\\[\\s*source\\s*\\]\\)\\s*>\\s*0",
|
||||
"len\\(rods\\s*\\[\\s*source\\s*\\]\\)\\s*>=\\s*1",
|
||||
];
|
||||
const re = new RegExp(`elif\\s+((${allowedRes.join(")|(")}))\\s+and\\s+(rods\\s*\\[\\s*source\\s*\\]\\[\\s*-\\s*1\\s*\\]\\s*<\\s*rods\\s*\\[\\s*target\\s*\\]\\[\\s*-\\s*1\\s*\\]|rods\\s*\\[\\s*target\\s*\\]\\[\\s*-\\s*1\\s*\\]\\s*>\\s*rods\\s*\\[\\s*source\\s*\\]\\[\\s*-\\s*1\\s*\\])\\s*:\\s+forward\\s*=\\s*True`);
|
||||
assert.match(code, re);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
NUMBER_OF_DISKS = 3
|
||||
number_of_moves = 2**NUMBER_OF_DISKS - 1
|
||||
rods = {
|
||||
'A': list(range(NUMBER_OF_DISKS, 0, -1)),
|
||||
'B': [],
|
||||
'C': []
|
||||
}
|
||||
|
||||
def move(n, source, auxiliary, target):
|
||||
# display starting configuration
|
||||
print(rods)
|
||||
for i in range(number_of_moves):
|
||||
remainder = (i + 1) % 3
|
||||
if remainder == 1:
|
||||
print(f'Move {i + 1} allowed between {source} and {target}')
|
||||
forward = False
|
||||
--fcc-editable-region--
|
||||
if not rods[target]:
|
||||
forward = True
|
||||
--fcc-editable-region--
|
||||
elif remainder == 2:
|
||||
print(f'Move {i + 1} allowed between {source} and {auxiliary}')
|
||||
elif remainder == 0:
|
||||
print(f'Move {i + 1} allowed between {auxiliary} and {target}')
|
||||
|
||||
# initiate call from source A to target C with auxiliary B
|
||||
move(NUMBER_OF_DISKS, 'A', 'B', 'C')
|
||||
```
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
---
|
||||
id: 64dceadec3c9cf2ca7b56de6
|
||||
title: Step 25
|
||||
challengeType: 20
|
||||
dashedName: step-25
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Next, below the nested `elif` statement, add another `if` statement that should be executed when `forward` is `True`. Inside this conditional, print the following f-string: `f'Moving disk {rods[source][-1]} from {source} to {target}'`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should add an `if` statement to execute when `forward` is `True` after the `elif` block.
|
||||
|
||||
```js
|
||||
({ test: () => assert.match(code, /^\s{12}if\s+forward(\s*==\s*True)?\s*:/m) })
|
||||
```
|
||||
|
||||
You should print the provide string inside your new `if` statement.
|
||||
|
||||
```js
|
||||
({ test: () => assert.match(code, /if\s+forward(\s*==\s*True)?\s*:\s+print\s*\(\s*f('|")Moving\sdisk\s\{\s*rods\[\s*source\s*\]\[\s*-\s*1\s*\]\s*\}\sfrom\s\{\s*source\s*\}\sto\s\{\s*target\s*\}\2\s*\)/) })
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
NUMBER_OF_DISKS = 3
|
||||
number_of_moves = 2**NUMBER_OF_DISKS - 1
|
||||
rods = {
|
||||
'A': list(range(NUMBER_OF_DISKS, 0, -1)),
|
||||
'B': [],
|
||||
'C': []
|
||||
}
|
||||
|
||||
def move(n, source, auxiliary, target):
|
||||
# display starting configuration
|
||||
print(rods)
|
||||
for i in range(number_of_moves):
|
||||
remainder = (i + 1) % 3
|
||||
--fcc-editable-region--
|
||||
if remainder == 1:
|
||||
print(f'Move {i + 1} allowed between {source} and {target}')
|
||||
forward = False
|
||||
if not rods[target]:
|
||||
forward = True
|
||||
elif rods[source] and rods[source][-1] < rods[target][-1]:
|
||||
forward = True
|
||||
--fcc-editable-region--
|
||||
elif remainder == 2:
|
||||
print(f'Move {i + 1} allowed between {source} and {auxiliary}')
|
||||
elif remainder == 0:
|
||||
print(f'Move {i + 1} allowed between {auxiliary} and {target}')
|
||||
|
||||
# initiate call from source A to target C with auxiliary B
|
||||
move(NUMBER_OF_DISKS, 'A', 'B', 'C')
|
||||
```
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
---
|
||||
id: 64ddcc2ee182e0164c3539f8
|
||||
title: Step 26
|
||||
challengeType: 20
|
||||
dashedName: step-26
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
After printing the move, you need to remove the last element from the source rod and append it to target rod. Use the `.pop()` method and the `.append()` method for that.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should remove the last element from `rods[source]`.
|
||||
|
||||
```js
|
||||
({ test: () => assert.match(code, /rods\[\s*source\s*\]\.pop\s*\(\s*\)/) })
|
||||
```
|
||||
|
||||
You should have `rods[target].append(rods[source].pop())` in your code.
|
||||
|
||||
```js
|
||||
({ test: () => assert.match(code, /rods\[\s*target\s*\]\.append\s*\(\s*rods\[\s*source\s*\]\.pop\s*\(\s*\)\s*\)/) })
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
NUMBER_OF_DISKS = 3
|
||||
number_of_moves = 2**NUMBER_OF_DISKS - 1
|
||||
rods = {
|
||||
'A': list(range(NUMBER_OF_DISKS, 0, -1)),
|
||||
'B': [],
|
||||
'C': []
|
||||
}
|
||||
|
||||
def move(n, source, auxiliary, target):
|
||||
# display starting configuration
|
||||
print(rods)
|
||||
for i in range(number_of_moves):
|
||||
remainder = (i + 1) % 3
|
||||
--fcc-editable-region--
|
||||
if remainder == 1:
|
||||
print(f'Move {i + 1} allowed between {source} and {target}')
|
||||
forward = False
|
||||
if not rods[target]:
|
||||
forward = True
|
||||
elif rods[source] and rods[source][-1] < rods[target][-1]:
|
||||
forward = True
|
||||
if forward:
|
||||
print(f'Moving disk {rods[source][-1]} from {source} to {target}')
|
||||
--fcc-editable-region--
|
||||
elif remainder == 2:
|
||||
print(f'Move {i + 1} allowed between {source} and {auxiliary}')
|
||||
elif remainder == 0:
|
||||
print(f'Move {i + 1} allowed between {auxiliary} and {target}')
|
||||
|
||||
# initiate call from source A to target C with auxiliary B
|
||||
move(NUMBER_OF_DISKS, 'A', 'B', 'C')
|
||||
```
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
---
|
||||
id: 64ddce6f6e8066173208235b
|
||||
title: Step 27
|
||||
challengeType: 20
|
||||
dashedName: step-27
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
When `forward` is `False`, the disk has to be moved in the opposite direction. Write an `else` clause for that. Print the move and change the content of the lists accordingly.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should have an `else` clause to move the disks in the opposite direction.
|
||||
|
||||
```js
|
||||
({ test: () => assert.match(code, /rods\[\s*target\s*\]\.append\s*\(\s*rods\[\s*source\s*\]\.pop\s*\(\s*\)\s*\)\s+else\s*:/) })
|
||||
```
|
||||
|
||||
You should have `print(f'Moving disk {rods[target][-1]} from {target} to {source}')` inside your `else` clause.
|
||||
|
||||
```js
|
||||
({ test: () => assert.match(code, /else\s*:\s+print\s*\(\s*f('|")Moving\sdisk\s\{\s*rods\[\s*target\s*\]\[\s*-\s*1\s*\]\s*\}\sfrom\s\{\s*target\s*\}\sto\s\{\s*source\s*\}\1\s*\)/) })
|
||||
```
|
||||
|
||||
You should remove the last element from `rods[target]`.
|
||||
|
||||
```js
|
||||
({ test: () => assert.match(code, /rods\[\s*target\s*\]\.pop\s*\(\s*\)/) })
|
||||
```
|
||||
|
||||
You should have `rods[source].append(rods[target].pop())` in your code.
|
||||
|
||||
```js
|
||||
({ test: () => assert.match(code, /rods\[\s*source\s*\]\.append\s*\(\s*rods\[\s*target\s*\]\.pop\s*\(\s*\)\s*\)/) })
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
NUMBER_OF_DISKS = 3
|
||||
number_of_moves = 2**NUMBER_OF_DISKS - 1
|
||||
rods = {
|
||||
'A': list(range(NUMBER_OF_DISKS, 0, -1)),
|
||||
'B': [],
|
||||
'C': []
|
||||
}
|
||||
|
||||
def move(n, source, auxiliary, target):
|
||||
# display starting configuration
|
||||
print(rods)
|
||||
for i in range(number_of_moves):
|
||||
remainder = (i + 1) % 3
|
||||
if remainder == 1:
|
||||
print(f'Move {i + 1} allowed between {source} and {target}')
|
||||
forward = False
|
||||
if not rods[target]:
|
||||
forward = True
|
||||
elif rods[source] and rods[source][-1] < rods[target][-1]:
|
||||
forward = True
|
||||
--fcc-editable-region--
|
||||
if forward:
|
||||
print(f'Moving disk {rods[source][-1]} from {source} to {target}')
|
||||
rods[target].append(rods[source].pop())
|
||||
--fcc-editable-region--
|
||||
elif remainder == 2:
|
||||
print(f'Move {i + 1} allowed between {source} and {auxiliary}')
|
||||
elif remainder == 0:
|
||||
print(f'Move {i + 1} allowed between {auxiliary} and {target}')
|
||||
|
||||
# initiate call from source A to target C with auxiliary B
|
||||
move(NUMBER_OF_DISKS, 'A', 'B', 'C')
|
||||
```
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
---
|
||||
id: 64ddd02838f36117cd9738eb
|
||||
title: Step 28
|
||||
challengeType: 20
|
||||
dashedName: step-28
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Outside the `else` block, add a comment saying `display our progress` and print the content of the lists to check that everything is working.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should use the provided text to add a comment outside the `else` block.
|
||||
|
||||
```js
|
||||
({ test: () => assert.match(code, /rods\[\s*source\s*\]\.append\s*\(\s*rods\[\s*target\s*\]\.pop\s*\(\s*\)\s*\)\s+#\s*display\sour\sprogress/) })
|
||||
```
|
||||
|
||||
You should print the `rods` object outside the `else` block, after the comment.
|
||||
|
||||
```js
|
||||
({ test: () => assert.match(code, /rods\[\s*source\s*\]\.append\s*\(\s*rods\[\s*target\s*\]\.pop\s*\(\s*\)\s*\)\s+#\s*display\sour\sprogress\s+print\s*\(\s*rods\s*\)/) })
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
NUMBER_OF_DISKS = 3
|
||||
number_of_moves = 2**NUMBER_OF_DISKS - 1
|
||||
rods = {
|
||||
'A': list(range(NUMBER_OF_DISKS, 0, -1)),
|
||||
'B': [],
|
||||
'C': []
|
||||
}
|
||||
|
||||
def move(n, source, auxiliary, target):
|
||||
# display starting configuration
|
||||
print(rods)
|
||||
for i in range(number_of_moves):
|
||||
remainder = (i + 1) % 3
|
||||
if remainder == 1:
|
||||
print(f'Move {i + 1} allowed between {source} and {target}')
|
||||
forward = False
|
||||
if not rods[target]:
|
||||
forward = True
|
||||
elif rods[source] and rods[source][-1] < rods[target][-1]:
|
||||
forward = True
|
||||
--fcc-editable-region--
|
||||
if forward:
|
||||
print(f'Moving disk {rods[source][-1]} from {source} to {target}')
|
||||
rods[target].append(rods[source].pop())
|
||||
else:
|
||||
print(f'Moving disk {rods[target][-1]} from {target} to {source}')
|
||||
rods[source].append(rods[target].pop())
|
||||
--fcc-editable-region--
|
||||
elif remainder == 2:
|
||||
print(f'Move {i + 1} allowed between {source} and {auxiliary}')
|
||||
elif remainder == 0:
|
||||
print(f'Move {i + 1} allowed between {auxiliary} and {target}')
|
||||
|
||||
# initiate call from source A to target C with auxiliary B
|
||||
move(NUMBER_OF_DISKS, 'A', 'B', 'C')
|
||||
```
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
---
|
||||
id: 64ddd280d69fa818ca782d50
|
||||
title: Step 29
|
||||
challengeType: 20
|
||||
dashedName: step-29
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
As you can see, disk 1 is going back and forth every three moves. This happens because you still need to take care of movements between the other rods.
|
||||
Instead of repeating the same code you wrote during the previous few steps and changing the rods, it would be better to move that code inside a function to call in each conditional statement. Declare an empty function named `make_allowed_move()` and don't forget the `pass` keyword.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should declare an empty function named `make_allowed_move`. Remember to use the `pass` keyword inside the function body with the correct indentation.
|
||||
|
||||
```js
|
||||
({ test: () => assert(__pyodide.runPython(`
|
||||
import inspect
|
||||
inspect.isfunction(__locals.get('make_allowed_move'))
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
NUMBER_OF_DISKS = 3
|
||||
number_of_moves = 2**NUMBER_OF_DISKS - 1
|
||||
rods = {
|
||||
'A': list(range(NUMBER_OF_DISKS, 0, -1)),
|
||||
'B': [],
|
||||
'C': []
|
||||
}
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
def move(n, source, auxiliary, target):
|
||||
# display starting configuration
|
||||
print(rods)
|
||||
for i in range(number_of_moves):
|
||||
remainder = (i + 1) % 3
|
||||
if remainder == 1:
|
||||
print(f'Move {i + 1} allowed between {source} and {target}')
|
||||
forward = False
|
||||
if not rods[target]:
|
||||
forward = True
|
||||
elif rods[source] and rods[source][-1] < rods[target][-1]:
|
||||
forward = True
|
||||
if forward:
|
||||
print(f'Moving disk {rods[source][-1]} from {source} to {target}')
|
||||
rods[target].append(rods[source].pop())
|
||||
else:
|
||||
print(f'Moving disk {rods[target][-1]} from {target} to {source}')
|
||||
rods[source].append(rods[target].pop())
|
||||
|
||||
# display our progress
|
||||
print(rods)
|
||||
elif remainder == 2:
|
||||
print(f'Move {i + 1} allowed between {source} and {auxiliary}')
|
||||
elif remainder == 0:
|
||||
print(f'Move {i + 1} allowed between {auxiliary} and {target}')
|
||||
|
||||
# initiate call from source A to target C with auxiliary B
|
||||
move(NUMBER_OF_DISKS, 'A', 'B', 'C')
|
||||
```
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
---
|
||||
id: 64ddd4fbb4b598199acf5ec5
|
||||
title: Step 30
|
||||
challengeType: 20
|
||||
dashedName: step-30
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Add two parameters called `rod1` and `rod2` to your new function.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your `make_allowed_move()` function should have two parameters named `rod1` and `rod2`.
|
||||
|
||||
```js
|
||||
({ test: () => assert(__pyodide.runPython(`
|
||||
import inspect
|
||||
str(inspect.signature(__locals.get('make_allowed_move'))) == '(rod1, rod2)'
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
NUMBER_OF_DISKS = 3
|
||||
number_of_moves = 2**NUMBER_OF_DISKS - 1
|
||||
rods = {
|
||||
'A': list(range(NUMBER_OF_DISKS, 0, -1)),
|
||||
'B': [],
|
||||
'C': []
|
||||
}
|
||||
--fcc-editable-region--
|
||||
def make_allowed_move():
|
||||
pass
|
||||
--fcc-editable-region--
|
||||
|
||||
def move(n, source, auxiliary, target):
|
||||
# display starting configuration
|
||||
print(rods)
|
||||
for i in range(number_of_moves):
|
||||
remainder = (i + 1) % 3
|
||||
if remainder == 1:
|
||||
print(f'Move {i + 1} allowed between {source} and {target}')
|
||||
forward = False
|
||||
if not rods[target]:
|
||||
forward = True
|
||||
elif rods[source] and rods[source][-1] < rods[target][-1]:
|
||||
forward = True
|
||||
if forward:
|
||||
print(f'Moving disk {rods[source][-1]} from {source} to {target}')
|
||||
rods[target].append(rods[source].pop())
|
||||
else:
|
||||
print(f'Moving disk {rods[target][-1]} from {target} to {source}')
|
||||
rods[source].append(rods[target].pop())
|
||||
|
||||
# display our progress
|
||||
print(rods)
|
||||
elif remainder == 2:
|
||||
print(f'Move {i + 1} allowed between {source} and {auxiliary}')
|
||||
elif remainder == 0:
|
||||
print(f'Move {i + 1} allowed between {auxiliary} and {target}')
|
||||
|
||||
# initiate call from source A to target C with auxiliary B
|
||||
move(NUMBER_OF_DISKS, 'A', 'B', 'C')
|
||||
```
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
---
|
||||
id: 64ddd65848a12919d7e1c7d0
|
||||
title: Step 31
|
||||
challengeType: 20
|
||||
dashedName: step-31
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
It's time to move some code from the `move()` function to the `make_allowed_move()` function. Move the code nested inside the first `if` statement (except the first `print()` call) to your new function. Pay close attention to the indentation.
|
||||
Don't forget to remove the `pass` keyword.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should move the code nested inside the first `if` statement (except the first `print()` call) to your new function.
|
||||
|
||||
```js
|
||||
({ test: () => {
|
||||
assert.match(code, /def\s+make_allowed_move\(rod1, rod2\):\s+forward\s+=\s+False\s+if\s+not\s+rods\[\s*target\s*\]\s*:\s+forward\s*=\s*True\s+elif\s+rods\[\s*source\s*\]\s+and\s+rods\[\s*source\s*\]\[-1\]\s<\srods\[\s*target\s*\]\[\s*-\s*1\s*\]:\s+forward\s*=\s*True\s+if\s+forward\s*:\s+print\(\s*f'Moving\sdisk\s\{\s*rods\[\s*source\s*\]\[\s*-\s*1\s*\]\s*\}\sfrom\s\{\s*source\s*\}\sto\s\{\s*target\s*\}'\s*\)\s+rods\[\s*target\s*\]\.append\(\s*rods\[\s*source\s*\]\.pop\(\s*\)\s*\)\s+else\s*:\s+print\(\s*f'Moving\sdisk\s\{\s*rods\[\s*target\s*\]\[\s*-\s*1\s*\]\}\sfrom\s\{\s*target\s*\}\sto\s\{\s*source\s*\}'\s*\)\s+rods\[\s*source\s*\].append\(\s*rods\[\s*target\s*\].pop\(\s*\)\s*\)\s+#\sdisplay\sour\sprogress\s+\print\(\s*rods\s*\)/);
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
NUMBER_OF_DISKS = 3
|
||||
number_of_moves = 2**NUMBER_OF_DISKS - 1
|
||||
rods = {
|
||||
'A': list(range(NUMBER_OF_DISKS, 0, -1)),
|
||||
'B': [],
|
||||
'C': []
|
||||
}
|
||||
--fcc-editable-region--
|
||||
def make_allowed_move(rod1, rod2):
|
||||
pass
|
||||
|
||||
def move(n, source, auxiliary, target):
|
||||
# display starting configuration
|
||||
print(rods)
|
||||
for i in range(number_of_moves):
|
||||
remainder = (i + 1) % 3
|
||||
if remainder == 1:
|
||||
print(f'Move {i + 1} allowed between {source} and {target}')
|
||||
forward = False
|
||||
if not rods[target]:
|
||||
forward = True
|
||||
elif rods[source] and rods[source][-1] < rods[target][-1]:
|
||||
forward = True
|
||||
if forward:
|
||||
print(f'Moving disk {rods[source][-1]} from {source} to {target}')
|
||||
rods[target].append(rods[source].pop())
|
||||
else:
|
||||
print(f'Moving disk {rods[target][-1]} from {target} to {source}')
|
||||
rods[source].append(rods[target].pop())
|
||||
|
||||
# display our progress
|
||||
print(rods)
|
||||
--fcc-editable-region--
|
||||
elif remainder == 2:
|
||||
print(f'Move {i + 1} allowed between {source} and {auxiliary}')
|
||||
elif remainder == 0:
|
||||
print(f'Move {i + 1} allowed between {auxiliary} and {target}')
|
||||
|
||||
# initiate call from source A to target C with auxiliary B
|
||||
move(NUMBER_OF_DISKS, 'A', 'B', 'C')
|
||||
```
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
---
|
||||
id: 64de1469fccce61940f498c4
|
||||
title: Step 2
|
||||
challengeType: 20
|
||||
dashedName: step-2
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
The `rods` dictionary will represent the three rods with their disks. Give it the strings `'A'`, `'B'`, and `'C'` as keys and set each of them to an empty list.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your `rods` dictionary should have an `'A'` key.
|
||||
|
||||
```js
|
||||
({ test: () => assert(__pyodide.runPython(`'A' in __locals.get("rods")`)) })
|
||||
|
||||
```
|
||||
|
||||
`rods['A']` should be an empty list.
|
||||
|
||||
```js
|
||||
({ test: () => assert(__pyodide.runPython(`
|
||||
a = __locals.get("rods")
|
||||
a['A'] == []
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
Your `rods` dictionary should have a `'B'` key.
|
||||
|
||||
```js
|
||||
({ test: () => assert(__pyodide.runPython(`'B' in __locals.get("rods")`)) })
|
||||
|
||||
```
|
||||
|
||||
`rods['B']` should be an empty list.
|
||||
|
||||
```js
|
||||
({ test: () => assert(__pyodide.runPython(`
|
||||
a = __locals.get("rods")
|
||||
a['B'] == []
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
Your `rods` dictionary should have a `'C'` key.
|
||||
|
||||
```js
|
||||
({ test: () => assert(__pyodide.runPython(`'C' in __locals.get("rods")`)) })
|
||||
|
||||
```
|
||||
|
||||
`rods['C']` should be an empty list.
|
||||
|
||||
```js
|
||||
({ test: () => assert(__pyodide.runPython(`
|
||||
a = __locals.get("rods")
|
||||
a['C'] == []
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
--fcc-editable-region--
|
||||
rods = {}
|
||||
--fcc-editable-region--
|
||||
```
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
---
|
||||
id: 64de4bccf5becb208a48ca97
|
||||
title: Step 13
|
||||
challengeType: 20
|
||||
dashedName: step-13
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
In the Tower of Hanoi puzzle, you can identify the three rods according to their purpose:
|
||||
|
||||
- The first rod is the source, where all the disks are stacked on top of each other at the beginning of the game.
|
||||
- The second rod is an auxiliary rod, and it helps in moving the disks to the target rod.
|
||||
- The third rod is the target, where all the disks should be placed in order at the end of the game.
|
||||
|
||||
Currently, the `move()` function does not take any parameters. Change the function declaration to take 4 parameters: `n`, `source`, `auxiliary`, and `target`. Then, pass `NUMBER_OF_DISKS` and the strings `'A'`, `'B'`, and `'C'` as arguments to your function call. The order matters.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your `move()` function should have `n`, `source`, `auxiliary`, and `target` as the parameters. The order matters.
|
||||
|
||||
```js
|
||||
({ test: () => assert(__pyodide.runPython(`
|
||||
import inspect
|
||||
str(inspect.signature(__locals.get('move'))) == '(n, source, auxiliary, target)'
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
You should pass `NUMBER_OF_DISKS` and the strings `'A'`, `'B'`, and `'C'` to `move()`. The order matters.
|
||||
|
||||
```js
|
||||
({test: () => assert.match(code, /^move\(\s*NUMBER_OF_DISKS\s*,\s*('|")A\1\s*,\s*('|")B\2\s*,\s*('|")C\3\s*\)/m)
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
NUMBER_OF_DISKS = 3
|
||||
number_of_moves = 2**NUMBER_OF_DISKS - 1
|
||||
rods = {
|
||||
'A': list(range(NUMBER_OF_DISKS, 0, -1)),
|
||||
'B': [],
|
||||
'C': []
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
def move():
|
||||
print(rods)
|
||||
|
||||
move()
|
||||
--fcc-editable-region--
|
||||
```
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
---
|
||||
id: 64de6c8a5305d8173a3a9e09
|
||||
title: Step 32
|
||||
challengeType: 20
|
||||
dashedName: step-32
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
`make_allowed_move()` takes in `rod1` and `rod2` as parameters. You need a little refactoring here. Change every occurrence of `source` into `rod1`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should change each occurrence of `source` inside the `make_allowed_move()` function into `rod1`.
|
||||
|
||||
```js
|
||||
({ test: () => {
|
||||
assert.match(code, /elif\s+rods\s*\[\s*rod1\s*\]\s+and\s+rods\s*\[\s*rod1\s*\]\[\s*-\s*1\s*\]\s*<\s*rods\s*\[\s*target\s*\]\[\s*-\s*1\s*\]\s*:/);
|
||||
assert.match(code, /if\s+forward(\s*==\s*True)?\s*:\s+print\s*\(\s*f('|")Moving\sdisk\s\{\s*rods\[\s*rod1\s*\]\[\s*-\s*1\s*\]\s*\}\sfrom\s\{\s*rod1\s*\}\sto\s\{\s*target\s*\}\2\s*\)\s+rods\[\s*target\s*\]\.append\s*\(\s*rods\[\s*rod1\s*\]\.pop\s*\(\s*\)\s*\)/);
|
||||
assert.match(code, /else\s*:\s+print\s*\(\s*f('|")Moving\sdisk\s\{\s*rods\[\s*target\s*\]\[\s*-\s*1\s*\]\s*\}\sfrom\s\{\s*target\s*\}\sto\s\{\s*rod1\s*\}\1\s*\)/);
|
||||
assert.match(code, /rods\[\s*rod1\s*\]\.append\s*\(\s*rods\[\s*target\s*\]\.pop\s*\(\s*\)\s*\)/);
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
NUMBER_OF_DISKS = 3
|
||||
number_of_moves = 2**NUMBER_OF_DISKS - 1
|
||||
rods = {
|
||||
'A': list(range(NUMBER_OF_DISKS, 0, -1)),
|
||||
'B': [],
|
||||
'C': []
|
||||
}
|
||||
--fcc-editable-region--
|
||||
def make_allowed_move(rod1, rod2):
|
||||
forward = False
|
||||
if not rods[target]:
|
||||
forward = True
|
||||
elif rods[source] and rods[source][-1] < rods[target][-1]:
|
||||
forward = True
|
||||
if forward:
|
||||
print(f'Moving disk {rods[source][-1]} from {source} to {target}')
|
||||
rods[target].append(rods[source].pop())
|
||||
else:
|
||||
print(f'Moving disk {rods[target][-1]} from {target} to {source}')
|
||||
rods[source].append(rods[target].pop())
|
||||
|
||||
# display our progress
|
||||
print(rods)
|
||||
--fcc-editable-region--
|
||||
|
||||
def move(n, source, auxiliary, target):
|
||||
# display starting configuration
|
||||
print(rods)
|
||||
for i in range(number_of_moves):
|
||||
remainder = (i + 1) % 3
|
||||
if remainder == 1:
|
||||
print(f'Move {i + 1} allowed between {source} and {target}')
|
||||
elif remainder == 2:
|
||||
print(f'Move {i + 1} allowed between {source} and {auxiliary}')
|
||||
elif remainder == 0:
|
||||
print(f'Move {i + 1} allowed between {auxiliary} and {target}')
|
||||
|
||||
# initiate call from source A to target C with auxiliary B
|
||||
move(NUMBER_OF_DISKS, 'A', 'B', 'C')
|
||||
```
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
---
|
||||
id: 64de7357cc75bd18bdced920
|
||||
title: Step 33
|
||||
challengeType: 20
|
||||
dashedName: step-33
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Now change each occurrence of `target` into `rod2`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should change each occurrence of `target` inside `make_allowed_move` into `rod2`.
|
||||
|
||||
```js
|
||||
({ test: () => {
|
||||
assert.match(code, /if\s+not\s+rods\s*\[\s*rod2\s*\]\s*:/);
|
||||
assert.match(code, /elif\s+rods\s*\[\s*rod1\s*\]\s+and\s+rods\s*\[\s*rod1\s*\]\[\s*-\s*1\s*\]\s*<\s*rods\s*\[\s*rod2\s*\]\[\s*-\s*1\s*\]\s*:/);
|
||||
assert.match(code, /if\s+forward(\s*==\s*True)?\s*:\s+print\s*\(\s*f('|")Moving\sdisk\s\{\s*rods\[\s*rod1\s*\]\[\s*-\s*1\s*\]\s*\}\sfrom\s\{\s*rod1\s*\}\sto\s\{\s*rod2\s*\}\2\s*\)\s+rods\[\s*rod2\s*\]\.append\s*\(\s*rods\[\s*rod1\s*\]\.pop\s*\(\s*\)\s*\)/);
|
||||
assert.match(code, /else\s*:\s+print\s*\(\s*f('|")Moving\sdisk\s\{\s*rods\[\s*rod2\s*\]\[\s*-\s*1\s*\]\s*\}\sfrom\s\{\s*rod2\s*\}\sto\s\{\s*rod1\s*\}\1\s*\)/);
|
||||
assert.match(code, /rods\[\s*rod1\s*\]\.append\s*\(\s*rods\[\s*rod2\s*\]\.pop\s*\(\s*\)\s*\)/);
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
NUMBER_OF_DISKS = 3
|
||||
number_of_moves = 2**NUMBER_OF_DISKS - 1
|
||||
rods = {
|
||||
'A': list(range(NUMBER_OF_DISKS, 0, -1)),
|
||||
'B': [],
|
||||
'C': []
|
||||
}
|
||||
--fcc-editable-region--
|
||||
def make_allowed_move(rod1, rod2):
|
||||
forward = False
|
||||
if not rods[target]:
|
||||
forward = True
|
||||
elif rods[rod1] and rods[rod1][-1] < rods[target][-1]:
|
||||
forward = True
|
||||
if forward:
|
||||
print(f'Moving disk {rods[rod1][-1]} from {rod1} to {target}')
|
||||
rods[target].append(rods[rod1].pop())
|
||||
else:
|
||||
print(f'Moving disk {rods[target][-1]} from {target} to {rod1}')
|
||||
rods[rod1].append(rods[target].pop())
|
||||
|
||||
# display our progress
|
||||
print(rods)
|
||||
--fcc-editable-region--
|
||||
|
||||
def move(n, source, auxiliary, target):
|
||||
# display starting configuration
|
||||
print(rods)
|
||||
for i in range(number_of_moves):
|
||||
remainder = (i + 1) % 3
|
||||
if remainder == 1:
|
||||
print(f'Move {i + 1} allowed between {source} and {target}')
|
||||
elif remainder == 2:
|
||||
print(f'Move {i + 1} allowed between {source} and {auxiliary}')
|
||||
elif remainder == 0:
|
||||
print(f'Move {i + 1} allowed between {auxiliary} and {target}')
|
||||
|
||||
# initiate call from source A to target C with auxiliary B
|
||||
move(NUMBER_OF_DISKS, 'A', 'B', 'C')
|
||||
```
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
---
|
||||
id: 64de73f6c2486518e3064fec
|
||||
title: Step 34
|
||||
challengeType: 20
|
||||
dashedName: step-34
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Now call `make_allowed_move()` and pass in `source` and `target` as the arguments.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should call `make_allowed_move()` passing `source` and `target` as the arguments.
|
||||
|
||||
```js
|
||||
({ test: () => assert.match(code, /make_allowed_move\s*\(\s*source\s*,\s*target\s*\)(?=\s+elif\s+remainder\s*==\s*2\s*:)/) })
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
NUMBER_OF_DISKS = 3
|
||||
number_of_moves = 2**NUMBER_OF_DISKS - 1
|
||||
rods = {
|
||||
'A': list(range(NUMBER_OF_DISKS, 0, -1)),
|
||||
'B': [],
|
||||
'C': []
|
||||
}
|
||||
|
||||
def make_allowed_move(rod1, rod2):
|
||||
forward = False
|
||||
if not rods[rod2]:
|
||||
forward = True
|
||||
elif rods[rod1] and rods[rod1][-1] < rods[rod2][-1]:
|
||||
forward = True
|
||||
if forward:
|
||||
print(f'Moving disk {rods[rod1][-1]} from {rod1} to {rod2}')
|
||||
rods[rod2].append(rods[rod1].pop())
|
||||
else:
|
||||
print(f'Moving disk {rods[rod2][-1]} from {rod2} to {rod1}')
|
||||
rods[rod1].append(rods[rod2].pop())
|
||||
|
||||
# display our progress
|
||||
print(rods)
|
||||
|
||||
def move(n, source, auxiliary, target):
|
||||
# display starting configuration
|
||||
print(rods)
|
||||
for i in range(number_of_moves):
|
||||
remainder = (i + 1) % 3
|
||||
--fcc-editable-region--
|
||||
if remainder == 1:
|
||||
print(f'Move {i + 1} allowed between {source} and {target}')
|
||||
|
||||
--fcc-editable-region--
|
||||
elif remainder == 2:
|
||||
print(f'Move {i + 1} allowed between {source} and {auxiliary}')
|
||||
elif remainder == 0:
|
||||
print(f'Move {i + 1} allowed between {auxiliary} and {target}')
|
||||
|
||||
# initiate call from source A to target C with auxiliary B
|
||||
move(NUMBER_OF_DISKS, 'A', 'B', 'C')
|
||||
```
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
---
|
||||
id: 64de7662244db513d7b673ec
|
||||
title: Step 35
|
||||
challengeType: 20
|
||||
dashedName: step-35
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Call the `make_allowed_move()` function again inside the two `elif` clauses, and pass in the correct arguments.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should call `make_allowed_move(source, auxiliary)` inside the first `elif` clause.
|
||||
|
||||
```js
|
||||
({ test: () => {
|
||||
assert.match(code, /make_allowed_move\s*\(\s*source\s*,\s*auxiliary\s*\)(?=\s+elif\s+remainder\s*==\s*0\s*:)/);
|
||||
}})
|
||||
```
|
||||
|
||||
You should call `make_allowed_move(auxiliary, target)` inside the second `elif` clause.
|
||||
|
||||
```js
|
||||
assert.match(code, /make_allowed_move\s*\(\s*auxiliary\s*,\s*target\s*\)(?=\s+#\s*initiate\scall)/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
NUMBER_OF_DISKS = 3
|
||||
number_of_moves = 2**NUMBER_OF_DISKS - 1
|
||||
rods = {
|
||||
'A': list(range(NUMBER_OF_DISKS, 0, -1)),
|
||||
'B': [],
|
||||
'C': []
|
||||
}
|
||||
|
||||
def make_allowed_move(rod1, rod2):
|
||||
forward = False
|
||||
if not rods[rod2]:
|
||||
forward = True
|
||||
elif rods[rod1] and rods[rod1][-1] < rods[rod2][-1]:
|
||||
forward = True
|
||||
if forward:
|
||||
print(f'Moving disk {rods[rod1][-1]} from {rod1} to {rod2}')
|
||||
rods[rod2].append(rods[rod1].pop())
|
||||
else:
|
||||
print(f'Moving disk {rods[rod2][-1]} from {rod2} to {rod1}')
|
||||
rods[rod1].append(rods[rod2].pop())
|
||||
|
||||
# display our progress
|
||||
print(rods)
|
||||
|
||||
def move(n, source, auxiliary, target):
|
||||
# display starting configuration
|
||||
print(rods)
|
||||
for i in range(number_of_moves):
|
||||
remainder = (i + 1) % 3
|
||||
--fcc-editable-region--
|
||||
if remainder == 1:
|
||||
print(f'Move {i + 1} allowed between {source} and {target}')
|
||||
make_allowed_move(source, target)
|
||||
elif remainder == 2:
|
||||
print(f'Move {i + 1} allowed between {source} and {auxiliary}')
|
||||
|
||||
elif remainder == 0:
|
||||
print(f'Move {i + 1} allowed between {auxiliary} and {target}')
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
# initiate call from source A to target C with auxiliary B
|
||||
move(NUMBER_OF_DISKS, 'A', 'B', 'C')
|
||||
```
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
---
|
||||
id: 64de773f81facd14653f49c8
|
||||
title: Step 36
|
||||
challengeType: 20
|
||||
dashedName: step-36
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
It looks like it's working! But the output is not very readable. Print a new line character after printing the rods to fix that.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should pass a string with a new line character (`\n`) as the second argument for your two `print(rods)` calls.
|
||||
|
||||
```js
|
||||
({ test: () => assert.match(code, /print\(\s*rods\s*,\s*('|")\\n\1\s*\)(?=.*print\(\s*rods\s*,\s*('|")\\n\2\s*\))/s) })
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
NUMBER_OF_DISKS = 3
|
||||
number_of_moves = 2**NUMBER_OF_DISKS - 1
|
||||
rods = {
|
||||
'A': list(range(NUMBER_OF_DISKS, 0, -1)),
|
||||
'B': [],
|
||||
'C': []
|
||||
}
|
||||
|
||||
def make_allowed_move(rod1, rod2):
|
||||
forward = False
|
||||
if not rods[rod2]:
|
||||
forward = True
|
||||
elif rods[rod1] and rods[rod1][-1] < rods[rod2][-1]:
|
||||
forward = True
|
||||
|
||||
if forward:
|
||||
print(f'Moving disk {rods[rod1][-1]} from {rod1} to {rod2}')
|
||||
rods[rod2].append(rods[rod1].pop())
|
||||
else:
|
||||
print(f'Moving disk {rods[rod2][-1]} from {rod2} to {rod1}')
|
||||
rods[rod1].append(rods[rod2].pop())
|
||||
--fcc-editable-region--
|
||||
# display our progress
|
||||
print(rods)
|
||||
|
||||
def move(n, source, auxiliary, target):
|
||||
# display starting configuration
|
||||
print(rods)
|
||||
--fcc-editable-region--
|
||||
for i in range(number_of_moves):
|
||||
remainder = (i + 1) % 3
|
||||
if remainder == 1:
|
||||
print(f'Move {i + 1} allowed between {source} and {target}')
|
||||
make_allowed_move(source, target)
|
||||
elif remainder == 2:
|
||||
print(f'Move {i + 1} allowed between {source} and {auxiliary}')
|
||||
make_allowed_move(source, auxiliary)
|
||||
elif remainder == 0:
|
||||
print(f'Move {i + 1} allowed between {auxiliary} and {target}')
|
||||
make_allowed_move(auxiliary, target)
|
||||
|
||||
# initiate call from source A to target C with auxiliary B
|
||||
move(NUMBER_OF_DISKS, 'A', 'B', 'C')
|
||||
```
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
---
|
||||
id: 64de79de2fac6b1536ebcfdd
|
||||
title: Step 37
|
||||
challengeType: 20
|
||||
dashedName: step-37
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
The iterative solution of Tower of Hanoi might seem complete, but change the number of disks to `4` and look at the output.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should set `NUMBER_OF_DISKS` to 4.
|
||||
|
||||
```js
|
||||
({ test: () => assert.equal(__userGlobals.get('NUMBER_OF_DISKS'), 4) })
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
--fcc-editable-region--
|
||||
NUMBER_OF_DISKS = 3
|
||||
--fcc-editable-region--
|
||||
number_of_moves = 2**NUMBER_OF_DISKS - 1
|
||||
rods = {
|
||||
'A': list(range(NUMBER_OF_DISKS, 0, -1)),
|
||||
'B': [],
|
||||
'C': []
|
||||
}
|
||||
|
||||
def make_allowed_move(rod1, rod2):
|
||||
forward = False
|
||||
if not rods[rod2]:
|
||||
forward = True
|
||||
elif rods[rod1] and rods[rod1][-1] < rods[rod2][-1]:
|
||||
forward = True
|
||||
|
||||
if forward:
|
||||
print(f'Moving disk {rods[rod1][-1]} from {rod1} to {rod2}')
|
||||
rods[rod2].append(rods[rod1].pop())
|
||||
else:
|
||||
print(f'Moving disk {rods[rod2][-1]} from {rod2} to {rod1}')
|
||||
rods[rod1].append(rods[rod2].pop())
|
||||
|
||||
# display our progress
|
||||
print(rods, '\n')
|
||||
|
||||
def move(n, source, auxiliary, target):
|
||||
# display starting configuration
|
||||
print(rods, '\n')
|
||||
for i in range(number_of_moves):
|
||||
remainder = (i + 1) % 3
|
||||
if remainder == 1:
|
||||
print(f'Move {i + 1} allowed between {source} and {target}')
|
||||
make_allowed_move(source, target)
|
||||
elif remainder == 2:
|
||||
print(f'Move {i + 1} allowed between {source} and {auxiliary}')
|
||||
make_allowed_move(source, auxiliary)
|
||||
elif remainder == 0:
|
||||
print(f'Move {i + 1} allowed between {auxiliary} and {target}')
|
||||
make_allowed_move(auxiliary, target)
|
||||
|
||||
# initiate call from source A to target C with auxiliary B
|
||||
move(NUMBER_OF_DISKS, 'A', 'B', 'C')
|
||||
```
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
---
|
||||
id: 64de7be06eb689161dd63cf0
|
||||
title: Step 38
|
||||
challengeType: 20
|
||||
dashedName: step-38
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
The conditionals you wrote previously are only valid for odd numbers of disks.
|
||||
|
||||
Add a nested `if` to execute when `n` is odd, and add one indent level to your `print()` and `make_allowed_move()` calls.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should nest an `if` statement to execute when `n` is odd. Don't forget to indent your `print()` and `make_allowed_move()` calls.
|
||||
|
||||
```js
|
||||
({ test: () => assert.match(code, /if\s+n\s*%\s*2\s*(!=\s*0|==\s*1)\s*:\s+print.*\s+make_allowed_move\(.*\)/) })
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
NUMBER_OF_DISKS = 4
|
||||
number_of_moves = 2**NUMBER_OF_DISKS - 1
|
||||
rods = {
|
||||
'A': list(range(NUMBER_OF_DISKS, 0, -1)),
|
||||
'B': [],
|
||||
'C': []
|
||||
}
|
||||
|
||||
def make_allowed_move(rod1, rod2):
|
||||
forward = False
|
||||
if not rods[rod2]:
|
||||
forward = True
|
||||
elif rods[rod1] and rods[rod1][-1] < rods[rod2][-1]:
|
||||
forward = True
|
||||
|
||||
if forward:
|
||||
print(f'Moving disk {rods[rod1][-1]} from {rod1} to {rod2}')
|
||||
rods[rod2].append(rods[rod1].pop())
|
||||
else:
|
||||
print(f'Moving disk {rods[rod2][-1]} from {rod2} to {rod1}')
|
||||
rods[rod1].append(rods[rod2].pop())
|
||||
|
||||
# display our progress
|
||||
print(rods, '\n')
|
||||
|
||||
def move(n, source, auxiliary, target):
|
||||
# display starting configuration
|
||||
print(rods, '\n')
|
||||
for i in range(number_of_moves):
|
||||
remainder = (i + 1) % 3
|
||||
--fcc-editable-region--
|
||||
if remainder == 1:
|
||||
|
||||
print(f'Move {i + 1} allowed between {source} and {target}')
|
||||
make_allowed_move(source, target)
|
||||
--fcc-editable-region--
|
||||
elif remainder == 2:
|
||||
print(f'Move {i + 1} allowed between {source} and {auxiliary}')
|
||||
make_allowed_move(source, auxiliary)
|
||||
elif remainder == 0:
|
||||
print(f'Move {i + 1} allowed between {auxiliary} and {target}')
|
||||
make_allowed_move(auxiliary, target)
|
||||
|
||||
# initiate call from source A to target C with auxiliary B
|
||||
move(NUMBER_OF_DISKS, 'A', 'B', 'C')
|
||||
```
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
---
|
||||
id: 64df202aa1342114cd077920
|
||||
title: Step 39
|
||||
challengeType: 20
|
||||
dashedName: step-39
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
If the number of disks is even and the remainder equals `1`, the move is allowed between the source rod and the auxiliary rod. Add an `else` clause to print the allowed movement and call `make_allowed_move()` with the correct arguments.
|
||||
|
||||
If you look at the output, you can see that the execution stops at the third move because of an `IndexError`. This happens because the code is still incomplete and needs an `else` clause that you will be writing soon. To make it work, turn your `make_allowed_move()` call into a comment.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should add an `else` clause.
|
||||
|
||||
```js
|
||||
const tCode = code.replace(/\r/g, '');
|
||||
const ifBlock = __helpers.python.getBlock(tCode, "if remainder == 1");
|
||||
assert.match(ifBlock.block_body, /else:/);
|
||||
```
|
||||
|
||||
You should have `print(f'Move {i + 1} allowed between {source} and {auxiliary}')` within the `else` clause.
|
||||
|
||||
```js
|
||||
const tCode = code.replace(/\r/g, '');
|
||||
const ifBlock = __helpers.python.getBlock(tCode, "if remainder == 1");
|
||||
const elseBlock = __helpers.python.getBlock(ifBlock.block_body, "else");
|
||||
assert.match(elseBlock.block_body, /print\(\s*f('|")Move\s\{\s*i\s*\+\s*1\s*\}\sallowed\sbetween\s\{\s*source\s*\}\sand\s\{\s*auxiliary\s*\}\1\s*\)/);
|
||||
```
|
||||
|
||||
You should have `# make_allowed_move(source, auxiliary)` within the `else` clause.
|
||||
|
||||
```js
|
||||
const tCode = code.replace(/\r/g, '');
|
||||
const ifBlock = __helpers.python.getBlock(tCode, "if remainder == 1");
|
||||
const elseBlock = __helpers.python.getBlock(ifBlock.block_body, "else");
|
||||
assert.match(elseBlock.block_body, /# *make_allowed_move\(\s*source\s*,\s*auxiliary\s*\)/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
NUMBER_OF_DISKS = 4
|
||||
number_of_moves = 2**NUMBER_OF_DISKS - 1
|
||||
rods = {
|
||||
'A': list(range(NUMBER_OF_DISKS, 0, -1)),
|
||||
'B': [],
|
||||
'C': []
|
||||
}
|
||||
|
||||
def make_allowed_move(rod1, rod2):
|
||||
forward = False
|
||||
if not rods[rod2]:
|
||||
forward = True
|
||||
elif rods[rod1] and rods[rod1][-1] < rods[rod2][-1]:
|
||||
forward = True
|
||||
if forward:
|
||||
print(f'Moving disk {rods[rod1][-1]} from {rod1} to {rod2}')
|
||||
rods[rod2].append(rods[rod1].pop())
|
||||
else:
|
||||
print(f'Moving disk {rods[rod2][-1]} from {rod2} to {rod1}')
|
||||
rods[rod1].append(rods[rod2].pop())
|
||||
|
||||
# display our progress
|
||||
print(rods, '\n')
|
||||
|
||||
def move(n, source, auxiliary, target):
|
||||
# display starting configuration
|
||||
print(rods, '\n')
|
||||
for i in range(number_of_moves):
|
||||
remainder = (i + 1) % 3
|
||||
--fcc-editable-region--
|
||||
if remainder == 1:
|
||||
if n % 2 != 0:
|
||||
print(f'Move {i + 1} allowed between {source} and {target}')
|
||||
make_allowed_move(source, target)
|
||||
|
||||
--fcc-editable-region--
|
||||
elif remainder == 2:
|
||||
print(f'Move {i + 1} allowed between {source} and {auxiliary}')
|
||||
make_allowed_move(source, auxiliary)
|
||||
elif remainder == 0:
|
||||
print(f'Move {i + 1} allowed between {auxiliary} and {target}')
|
||||
make_allowed_move(auxiliary, target)
|
||||
|
||||
# initiate call from source A to target C with auxiliary B
|
||||
move(NUMBER_OF_DISKS, 'A', 'B', 'C')
|
||||
```
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
---
|
||||
id: 64df332162988b13c35b7f7d
|
||||
title: Step 40
|
||||
challengeType: 20
|
||||
dashedName: step-40
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Now you need to do the same with your `elif` statement: put the `print()` and `make_allowed_move()` calls inside an `if` statement to execute when `n` is odd.
|
||||
|
||||
Also, turn the `# make_allowed_move(source, auxiliary)` comment into code.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should nest your `print()` and `make_allowed_move()` calls inside an `if` statement to execute when `n` is odd.
|
||||
|
||||
```js
|
||||
({ test: () => assert.match(code, /if\s+n\s*%\s*2\s*(!=\s*0|==\s*1)\s*:\s+print\(\s*f('|")Move\s\{\s*i\s*\+\s*1\s*\}\sallowed\sbetween\s{\s*source\s*\}\sand\s\{\s*auxiliary\s*\}\2\s*\)\s+make_allowed_move\(\s*source\s*,\s*auxiliary\s*\)/) })
|
||||
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
NUMBER_OF_DISKS = 4
|
||||
number_of_moves = 2**NUMBER_OF_DISKS - 1
|
||||
rods = {
|
||||
'A': list(range(NUMBER_OF_DISKS, 0, -1)),
|
||||
'B': [],
|
||||
'C': []
|
||||
}
|
||||
|
||||
def make_allowed_move(rod1, rod2):
|
||||
forward = False
|
||||
if not rods[rod2]:
|
||||
forward = True
|
||||
elif rods[rod1] and rods[rod1][-1] < rods[rod2][-1]:
|
||||
forward = True
|
||||
|
||||
if forward:
|
||||
print(f'Moving disk {rods[rod1][-1]} from {rod1} to {rod2}')
|
||||
rods[rod2].append(rods[rod1].pop())
|
||||
else:
|
||||
print(f'Moving disk {rods[rod2][-1]} from {rod2} to {rod1}')
|
||||
rods[rod1].append(rods[rod2].pop())
|
||||
|
||||
# display our progress
|
||||
print(rods, '\n')
|
||||
|
||||
def move(n, source, auxiliary, target):
|
||||
# display starting configuration
|
||||
print(rods, '\n')
|
||||
for i in range(number_of_moves):
|
||||
remainder = (i + 1) % 3
|
||||
if remainder == 1:
|
||||
if n % 2 != 0:
|
||||
print(f'Move {i + 1} allowed between {source} and {target}')
|
||||
make_allowed_move(source, target)
|
||||
--fcc-editable-region--
|
||||
else:
|
||||
print(f'Move {i + 1} allowed between {source} and {auxiliary}')
|
||||
# make_allowed_move(source, auxiliary)
|
||||
|
||||
elif remainder == 2:
|
||||
print(f'Move {i + 1} allowed between {source} and {auxiliary}')
|
||||
make_allowed_move(source, auxiliary)
|
||||
--fcc-editable-region--
|
||||
elif remainder == 0:
|
||||
print(f'Move {i + 1} allowed between {auxiliary} and {target}')
|
||||
make_allowed_move(auxiliary, target)
|
||||
|
||||
# initiate call from source A to target C with auxiliary B
|
||||
move(NUMBER_OF_DISKS, 'A', 'B', 'C')
|
||||
```
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
---
|
||||
id: 64df346f4c86461419974c1e
|
||||
title: Step 41
|
||||
challengeType: 20
|
||||
dashedName: step-41
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Finally, add an `else` clause that prints the allowed move and call `make_allowed_move`. Try to figure out the correct arguments.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should add an `else` clause.
|
||||
|
||||
```js
|
||||
const tCode = code.replace(/\r/g, '');
|
||||
const elifBlock = __helpers.python.getBlock(tCode, "elif remainder == 2");
|
||||
assert.match(elifBlock.block_body, /else:/);
|
||||
```
|
||||
|
||||
You should have `print(f'Move {i + 1} allowed between {source} and {target}')` within the `else` block.
|
||||
|
||||
```js
|
||||
const tCode = code.replace(/\r/g, '');
|
||||
const elifBlock = __helpers.python.getBlock(tCode, "elif remainder == 2");
|
||||
assert.match(elifBlock.block_body, /print\(\s*f('|")Move\s\{\s*i\s*\+\s*1\s*\}\sallowed\sbetween\s{\s*source\s*\}\sand\s\{\s*target\s*\}\1\s*\)/);
|
||||
```
|
||||
|
||||
You should have `make_allowed_move(source, target)` within the `else` block.
|
||||
|
||||
```js
|
||||
const tCode = code.replace(/\r/g, '');
|
||||
const elifBlock = __helpers.python.getBlock(tCode, "elif remainder == 2");
|
||||
assert.match(elifBlock.block_body, /make_allowed_move\(\s*source\s*,\s*target\s*\)/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
NUMBER_OF_DISKS = 4
|
||||
number_of_moves = 2 ** NUMBER_OF_DISKS - 1
|
||||
rods = {
|
||||
'A': list(range(NUMBER_OF_DISKS, 0, -1)),
|
||||
'B': [],
|
||||
'C': []
|
||||
}
|
||||
|
||||
def make_allowed_move(rod1, rod2):
|
||||
forward = False
|
||||
if not rods[rod2]:
|
||||
forward = True
|
||||
elif rods[rod1] and rods[rod1][-1] < rods[rod2][-1]:
|
||||
forward = True
|
||||
if forward:
|
||||
print(f'Moving disk {rods[rod1][-1]} from {rod1} to {rod2}')
|
||||
rods[rod2].append(rods[rod1].pop())
|
||||
else:
|
||||
print(f'Moving disk {rods[rod2][-1]} from {rod2} to {rod1}')
|
||||
rods[rod1].append(rods[rod2].pop())
|
||||
|
||||
# display our progress
|
||||
print(rods, '\n')
|
||||
|
||||
def move(n, source, auxiliary, target):
|
||||
# display starting configuration
|
||||
print(rods, '\n')
|
||||
for i in range(number_of_moves):
|
||||
remainder = (i + 1) % 3
|
||||
if remainder == 1:
|
||||
if n % 2 != 0:
|
||||
print(f'Move {i + 1} allowed between {source} and {target}')
|
||||
make_allowed_move(source, target)
|
||||
else:
|
||||
print(f'Move {i + 1} allowed between {source} and {auxiliary}')
|
||||
make_allowed_move(source, auxiliary)
|
||||
--fcc-editable-region--
|
||||
elif remainder == 2:
|
||||
if n % 2 != 0:
|
||||
print(f'Move {i + 1} allowed between {source} and {auxiliary}')
|
||||
make_allowed_move(source, auxiliary)
|
||||
--fcc-editable-region--
|
||||
elif remainder == 0:
|
||||
print(f'Move {i + 1} allowed between {auxiliary} and {target}')
|
||||
make_allowed_move(auxiliary, target)
|
||||
|
||||
# initiate call from source A to target C with auxiliary B
|
||||
move(NUMBER_OF_DISKS, 'A', 'B', 'C')
|
||||
```
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
---
|
||||
id: 64df353d7ae6dc148fd64f53
|
||||
title: Step 42
|
||||
challengeType: 20
|
||||
dashedName: step-42
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
That's all for the iterative solution. From now on you are going to build a function that makes use of a recursive approach. Recursion is when a function calls itself.
|
||||
In this case, you are going to use recursion to calculate smaller versions of the same problem.
|
||||
|
||||
Delete the whole body of the `move` function except for the comment and the first `print` call. Leave the function declaration as is.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should delete the whole body of the `move` function except for the comment and the first `print` call.
|
||||
|
||||
```js
|
||||
({ test: () => assert.match(code, /print\(\s*rods\s*,\s*('|")\\n\1\s*\)\s+(?=#\sinitiate)/) })
|
||||
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
NUMBER_OF_DISKS = 4
|
||||
number_of_moves = 2 ** NUMBER_OF_DISKS - 1
|
||||
rods = {
|
||||
'A': list(range(NUMBER_OF_DISKS, 0, -1)),
|
||||
'B': [],
|
||||
'C': []
|
||||
}
|
||||
|
||||
def make_allowed_move(rod1, rod2):
|
||||
forward = False
|
||||
if not rods[rod2]:
|
||||
forward = True
|
||||
elif rods[rod1] and rods[rod1][-1] < rods[rod2][-1]:
|
||||
forward = True
|
||||
if forward:
|
||||
print(f'Moving disk {rods[rod1][-1]} from {rod1} to {rod2}')
|
||||
rods[rod2].append(rods[rod1].pop())
|
||||
else:
|
||||
print(f'Moving disk {rods[rod2][-1]} from {rod2} to {rod1}')
|
||||
rods[rod1].append(rods[rod2].pop())
|
||||
|
||||
# display our progress
|
||||
print(rods, '\n')
|
||||
|
||||
--fcc-editable-region--
|
||||
def move(n, source, auxiliary, target):
|
||||
# display starting configuration
|
||||
print(rods, '\n')
|
||||
for i in range(number_of_moves):
|
||||
remainder = (i + 1) % 3
|
||||
if remainder == 1:
|
||||
if n % 2 != 0:
|
||||
print(f'Move {i + 1} allowed between {source} and {target}')
|
||||
make_allowed_move(source, target)
|
||||
else:
|
||||
print(f'Move {i + 1} allowed between {source} and {auxiliary}')
|
||||
make_allowed_move(source, auxiliary)
|
||||
elif remainder == 2:
|
||||
if n % 2 != 0:
|
||||
print(f'Move {i + 1} allowed between {source} and {auxiliary}')
|
||||
make_allowed_move(source, auxiliary)
|
||||
else:
|
||||
print(f'Move {i + 1} allowed between {source} and {target}')
|
||||
make_allowed_move(source, target)
|
||||
elif remainder == 0:
|
||||
print(f'Move {i + 1} allowed between {auxiliary} and {target}')
|
||||
make_allowed_move(auxiliary, target)
|
||||
--fcc-editable-region--
|
||||
|
||||
# initiate call from source A to target C with auxiliary B
|
||||
move(NUMBER_OF_DISKS, 'A', 'B', 'C')
|
||||
```
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
---
|
||||
id: 64df3e2fac34d813d048f3f9
|
||||
title: Step 43
|
||||
challengeType: 20
|
||||
dashedName: step-43
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
You won't need `make_allowed_move` and `number_of_moves`, either. Delete the whole function and the variable.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should delete the `number_of_moves` variable and its content.
|
||||
|
||||
```js
|
||||
({ test: () => assert.match(code, /NUMBER_OF_DISKS\s*=\s*4\s+(?=rods\s*=\s*\{)/) })
|
||||
```
|
||||
|
||||
You should delete the whole `make_allowed_move` function.
|
||||
|
||||
```js
|
||||
({ test: () => assert.match(code, /\}\s+(?=def\s+move\(\s*n\s*,\s*source\s*,\s*auxiliary\s*,\s*target\s*\)\s*:)/) })
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
--fcc-editable-region--
|
||||
NUMBER_OF_DISKS = 4
|
||||
number_of_moves = 2 ** NUMBER_OF_DISKS - 1
|
||||
rods = {
|
||||
'A': list(range(NUMBER_OF_DISKS, 0, -1)),
|
||||
'B': [],
|
||||
'C': []
|
||||
}
|
||||
|
||||
def make_allowed_move(rod1, rod2):
|
||||
forward = False
|
||||
if not rods[rod2]:
|
||||
forward = True
|
||||
elif rods[rod1] and rods[rod1][-1] < rods[rod2][-1]:
|
||||
forward = True
|
||||
if forward:
|
||||
print(f'Moving disk {rods[rod1][-1]} from {rod1} to {rod2}')
|
||||
rods[rod2].append(rods[rod1].pop())
|
||||
else:
|
||||
print(f'Moving disk {rods[rod2][-1]} from {rod2} to {rod1}')
|
||||
rods[rod1].append(rods[rod2].pop())
|
||||
|
||||
# display our progress
|
||||
print(rods, '\n')
|
||||
|
||||
def move(n, source, auxiliary, target):
|
||||
# display starting configuration
|
||||
print(rods, '\n')
|
||||
|
||||
--fcc-editable-region--
|
||||
# initiate call from source A to target C with auxiliary B
|
||||
move(NUMBER_OF_DISKS, 'A', 'B', 'C')
|
||||
```
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
---
|
||||
id: 64df3f1011888113fbd3d81b
|
||||
title: Step 44
|
||||
challengeType: 20
|
||||
dashedName: step-44
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
To solve the puzzle with recursion, the first thing to do is break the original problem down into smaller sub-problems.
|
||||
|
||||
The final configuration with `n` disks piled up to the third rod in decreasing order can be obtained by moving:
|
||||
|
||||
- `n - 1` disks from the source to the auxiliary rod
|
||||
- the largest disk from the source to the target
|
||||
- and then the `n - 1` disks from the auxiliary rod to the target.
|
||||
|
||||
So, the first thing the `move` function should do is calling itself with `n - 1` as the first parameter. But if you try to do so without defining a base case, you will get a `RecursionError`. This happens because the function keeps calling itself indefinitely.
|
||||
|
||||
Before your comment and your `print()` call, add the recursive function call with `n - 1` as the first parameter and make sure the function body executes only when `n` is greater than zero. For now, leave the others parameters in the same order.
|
||||
|
||||
# --hints--
|
||||
|
||||
The `move` function body should start with an `if` statement that is triggered when `n` is greater than zero.
|
||||
|
||||
```js
|
||||
({ test: () => assert.match(code, /def\s+move\(\s*n\s*,\s*source\s*,\s*auxiliary\s*,\s*target\s*\)\s*:\s+if\s+n\s*>\s*0\s*:/) })
|
||||
```
|
||||
|
||||
You should call `move(n - 1, source, auxiliary, target)` inside the `if` statement. Remember to indent your `print()` call.
|
||||
|
||||
```js
|
||||
const transformedCode = "\n" + code.replace(/\r/g, '');
|
||||
const move = __helpers.python.getDef(transformedCode, "move");
|
||||
const { function_parameters, function_body } = move;
|
||||
|
||||
assert.match(function_parameters, /n\s*,\s*source\s*,\s*auxiliary\s*,\s*target/);
|
||||
const functionBodyIndent = function_body.match(/ +/)[0];
|
||||
const re = new RegExp(`${functionBodyIndent}if\\s+n\\s*>\\s*0\\s*:\\s+^${functionBodyIndent}( +)move\\(\\s*n\\s*-\\s*1\\s*,\\s*source\\s*,\\s*auxiliary\\s*,\\s*target\\s*\\).+?^${functionBodyIndent}\\1print\\s*\\(\\s*rods\\s*,\\s*("|')\\\\n\\2\\s*\\)`, "ms");
|
||||
assert.match(function_body, re);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
NUMBER_OF_DISKS = 4
|
||||
rods = {
|
||||
'A': list(range(NUMBER_OF_DISKS, 0, -1)),
|
||||
'B': [],
|
||||
'C': []
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
def move(n, source, auxiliary, target):
|
||||
# display starting configuration
|
||||
print(rods, '\n')
|
||||
|
||||
--fcc-editable-region--
|
||||
# initiate call from source A to target C with auxiliary B
|
||||
move(NUMBER_OF_DISKS, 'A', 'B', 'C')
|
||||
```
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
---
|
||||
id: 64df45a3ad4f8719e5355244
|
||||
title: Step 46
|
||||
challengeType: 20
|
||||
dashedName: step-46
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
The steps of moving `n - 1` disks can be broken down further until only a single disk is considered. This will be the first move occurring. After the first move occurs, the following moves are generated by the unwinding of the recursive calls. Keep in mind that in each recursive step the role played by the rods changes between source, target, and auxiliary.
|
||||
|
||||
For now, each recursive call prints the `rods` dictionary without performing any changes to the lists. Before the `print()` call, remove the last element from the `rods[source]` list and append it to the `rods[target]` list.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should remove the last element from the `rods[source]` list and append it to the `rods[target]` list before the `print` call.
|
||||
|
||||
```js
|
||||
({ test: () => assert.match(code, /move\(\s*n\s*-\s*1\s*,\s*source\s*,\s*auxiliary\s*,\s*target\s*\)\s+rods\[\s*target\s*\].append\(\s*rods\[\s*source\s*\].pop\(\s*\)\s*\)/) })
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
NUMBER_OF_DISKS = 4
|
||||
rods = {
|
||||
'A': list(range(NUMBER_OF_DISKS, 0, -1)),
|
||||
'B': [],
|
||||
'C': []
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
def move(n, source, auxiliary, target):
|
||||
if n > 0:
|
||||
# move n - 1 disks from source to auxiliary, so they are out of the way
|
||||
move(n - 1, source, auxiliary, target)
|
||||
|
||||
# display starting configuration
|
||||
print(rods, '\n')
|
||||
|
||||
--fcc-editable-region--
|
||||
# initiate call from source A to target C with auxiliary B
|
||||
move(NUMBER_OF_DISKS, 'A', 'B', 'C')
|
||||
```
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
---
|
||||
id: 64df47b32b92301a815d5ef8
|
||||
title: Step 49
|
||||
challengeType: 20
|
||||
dashedName: step-49
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
At first, the recursive call you have just added deals with the sub-problem of moving `n - 1` disks to the second rod.
|
||||
|
||||
For that reason, the `target` parameter corresponds to your second rod, while the `auxiliary` parameter is the third rod. Keep in mind that those will keep swapping as the recursion proceeds.
|
||||
|
||||
Fix the parameters order exchanging `target` and `auxiliary` in your recursive call.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should modify the order of the parameters in your `move(n - 1, source, auxiliary, target)` call.
|
||||
|
||||
```js
|
||||
({ test: () => assert.match(code, /move\(\s*n\s*-\s*1\s*,\s*source\s*,\s*target\s*,\s*auxiliary\s*\)/) })
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
NUMBER_OF_DISKS = 4
|
||||
rods = {
|
||||
'A': list(range(NUMBER_OF_DISKS, 0, -1)),
|
||||
'B': [],
|
||||
'C': []
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
def move(n, source, auxiliary, target):
|
||||
if n > 0:
|
||||
# move n - 1 disks from source to auxiliary, so they are out of the way
|
||||
move(n - 1, source, auxiliary, target)
|
||||
|
||||
# move the nth disk from source to target
|
||||
rods[target].append(rods[source].pop())
|
||||
|
||||
# display our progress
|
||||
print(rods, '\n')
|
||||
|
||||
--fcc-editable-region--
|
||||
# initiate call from source A to target C with auxiliary B
|
||||
move(NUMBER_OF_DISKS, 'A', 'B', 'C')
|
||||
```
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
---
|
||||
id: 64df496c6a8ddf1b38db1ed6
|
||||
title: Step 50
|
||||
challengeType: 20
|
||||
dashedName: step-50
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
In a previous step, you wrote the code to move the largest disk of the sub-problem to the target rod.
|
||||
|
||||
Now, all you need to do is add another recursive call to move the `n - 1` disks you have already displaced. Copy the first recursive call and paste it at the end of the `if` block.
|
||||
|
||||
Note that the function parameters are not in the right order. Try to figure out the correct order.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should call `move(n - 1, auxiliary, source, target)` at the end of your `move` function.
|
||||
|
||||
```js
|
||||
({ test: () => assert.match(code, /^\s{8}move\(\s*n\s*-\s*1\s*,\s*auxiliary\s*,\s*source\s*,\s*target\s*\)/m) })
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
NUMBER_OF_DISKS = 4
|
||||
rods = {
|
||||
'A': list(range(NUMBER_OF_DISKS, 0, -1)),
|
||||
'B': [],
|
||||
'C': []
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
def move(n, source, auxiliary, target):
|
||||
if n > 0:
|
||||
# move n - 1 disks from source to auxiliary, so they are out of the way
|
||||
move(n - 1, source, target, auxiliary)
|
||||
|
||||
# move the nth disk from source to target
|
||||
rods[target].append(rods[source].pop())
|
||||
|
||||
# display our progress
|
||||
print(rods, '\n')
|
||||
|
||||
--fcc-editable-region--
|
||||
# initiate call from source A to target C with auxiliary B
|
||||
move(NUMBER_OF_DISKS, 'A', 'B', 'C')
|
||||
```
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
---
|
||||
id: 64df72c6e0183a191fcd72dc
|
||||
title: Step 14
|
||||
challengeType: 20
|
||||
dashedName: step-14
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Before your function call, write a comment saying `initiate call from source A to target C with auxiliary B`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should write the given comment before your function call.
|
||||
|
||||
```js
|
||||
({test: () => assert.match(code, /#\s*initiate\scall\sfrom\ssource\sA\sto\starget\sC\swith\sauxiliary\sB/) })
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
NUMBER_OF_DISKS = 3
|
||||
number_of_moves = 2**NUMBER_OF_DISKS - 1
|
||||
rods = {
|
||||
'A': list(range(NUMBER_OF_DISKS, 0, -1)),
|
||||
'B': [],
|
||||
'C': []
|
||||
}
|
||||
|
||||
def move(n, source, auxiliary, target):
|
||||
print(rods)
|
||||
--fcc-editable-region--
|
||||
|
||||
move(NUMBER_OF_DISKS, 'A', 'B', 'C')
|
||||
--fcc-editable-region--
|
||||
```
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
---
|
||||
id: 64e337e3096b7c1739d934e6
|
||||
title: Step 45
|
||||
challengeType: 20
|
||||
dashedName: step-45
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Before your recursive call, add a comment saying `move n - 1 disks from source to auxiliary, so they are out of the way`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should add a comment with the provided text before your recursive call.
|
||||
|
||||
```js
|
||||
({ test: () => assert.match(code, /if\s+n\s*>\s*0\s*:\s+#\s*move\sn\s-\s1\sdisks\sfrom\ssource\sto\sauxiliary,\sso\sthey\sare\sout\sof\sthe\sway\s+(?=move\(\s*n\s*-\s*1\s*,\s*source\s*,\s*auxiliary\s*,\s*target\s*\))/) })
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
NUMBER_OF_DISKS = 4
|
||||
rods = {
|
||||
'A': list(range(NUMBER_OF_DISKS, 0, -1)),
|
||||
'B': [],
|
||||
'C': []
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
def move(n, source, auxiliary, target):
|
||||
if n > 0:
|
||||
|
||||
move(n - 1, source, auxiliary, target)
|
||||
|
||||
# display starting configuration
|
||||
print(rods, '\n')
|
||||
|
||||
--fcc-editable-region--
|
||||
# initiate call from source A to target C with auxiliary B
|
||||
move(NUMBER_OF_DISKS, 'A', 'B', 'C')
|
||||
```
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
---
|
||||
id: 64e3392996b41d17a1375643
|
||||
title: Step 47
|
||||
challengeType: 20
|
||||
dashedName: step-47
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Before appending the last element to the target, add a comment saying `move the nth disk from source to target`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should add a comment with the provided text before `rods[target].append(rods[source].pop())`.
|
||||
|
||||
```js
|
||||
({ test: () => assert.match(code, /move\(\s*n\s*-\s*1\s*,\s*source\s*,\s*auxiliary\s*,\s*target\s*\)\s+#\s*move\sthe\snth\sdisk\sfrom\ssource\sto\starget\s+(?=rods\[\s*target\s*\].append\(\s*rods\[\s*source\s*\].pop\(\s*\)\s*\))/) })
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
NUMBER_OF_DISKS = 4
|
||||
rods = {
|
||||
'A': list(range(NUMBER_OF_DISKS, 0, -1)),
|
||||
'B': [],
|
||||
'C': []
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
def move(n, source, auxiliary, target):
|
||||
if n > 0:
|
||||
# move n - 1 disks from source to auxiliary, so they are out of the way
|
||||
move(n - 1, source, auxiliary, target)
|
||||
|
||||
rods[target].append(rods[source].pop())
|
||||
|
||||
# display starting configuration
|
||||
print(rods, '\n')
|
||||
|
||||
--fcc-editable-region--
|
||||
# initiate call from source A to target C with auxiliary B
|
||||
move(NUMBER_OF_DISKS, 'A', 'B', 'C')
|
||||
```
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
---
|
||||
id: 64e33a488b4a2717fa22ebf3
|
||||
title: Step 15
|
||||
challengeType: 20
|
||||
dashedName: step-15
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Add another comment before your `print()` call saying `display starting configuration`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should use the provided text to add a comment before your `print()` call.
|
||||
|
||||
```js
|
||||
({ test: () => assert.match(code, /#\s*display\sstarting\sconfiguration\s+print\s*\(\s*rods\s*\)/) })
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
NUMBER_OF_DISKS = 3
|
||||
number_of_moves = 2**NUMBER_OF_DISKS - 1
|
||||
rods = {
|
||||
'A': list(range(NUMBER_OF_DISKS, 0, -1)),
|
||||
'B': [],
|
||||
'C': []
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
def move(n, source, auxiliary, target):
|
||||
|
||||
print(rods)
|
||||
--fcc-editable-region--
|
||||
|
||||
# initiate call from source A to target C with auxiliary B
|
||||
move(NUMBER_OF_DISKS, 'A', 'B', 'C')
|
||||
```
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
---
|
||||
id: 64e340302bd28513f3e73740
|
||||
title: Step 48
|
||||
challengeType: 20
|
||||
dashedName: step-48
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Now, change the comment above the `print()` call into `display our progress`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should change `# display starting configuration` into `# display our progress`.
|
||||
|
||||
```js
|
||||
({ test: () => assert.match(code, /\)\s+#\s*display\sour\sprogress\s+(?=print\()/) })
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
NUMBER_OF_DISKS = 4
|
||||
rods = {
|
||||
'A': list(range(NUMBER_OF_DISKS, 0, -1)),
|
||||
'B': [],
|
||||
'C': []
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
def move(n, source, auxiliary, target):
|
||||
if n > 0:
|
||||
# move n - 1 disks from source to auxiliary, so they are out of the way
|
||||
move(n - 1, source, auxiliary, target)
|
||||
|
||||
# move the nth disk from source to target
|
||||
rods[target].append(rods[source].pop())
|
||||
|
||||
# display starting configuration
|
||||
print(rods, '\n')
|
||||
|
||||
--fcc-editable-region--
|
||||
# initiate call from source A to target C with auxiliary B
|
||||
move(NUMBER_OF_DISKS, 'A', 'B', 'C')
|
||||
```
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
---
|
||||
id: 64e340ecee18af1430939018
|
||||
title: Step 51
|
||||
challengeType: 20
|
||||
dashedName: step-51
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Above the second `move` call, add one last comment saying `move the n - 1 disks that we left on auxiliary onto target`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should add a comment using the provided text.
|
||||
|
||||
```js
|
||||
({ test: () => assert.match(code, /#\s*move\sthe\sn\s-\s1\sdisks\sthat\swe\sleft\son\sauxiliary\sonto\starget\s+(?=move\(\s*n\s*-\s*1\s*,\s*auxiliary\s*,\s*source\s*,\s*target\s*\))/) })
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
NUMBER_OF_DISKS = 4
|
||||
rods = {
|
||||
'A': list(range(NUMBER_OF_DISKS, 0, -1)),
|
||||
'B': [],
|
||||
'C': []
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
def move(n, source, auxiliary, target):
|
||||
if n > 0:
|
||||
# move n - 1 disks from source to auxiliary, so they are out of the way
|
||||
move(n - 1, source, target, auxiliary)
|
||||
|
||||
# move the nth disk from source to target
|
||||
rods[target].append(rods[source].pop())
|
||||
|
||||
# display our progress
|
||||
print(rods, '\n')
|
||||
|
||||
move(n - 1, auxiliary, source, target)
|
||||
|
||||
--fcc-editable-region--
|
||||
# initiate call from source A to target C with auxiliary B
|
||||
move(NUMBER_OF_DISKS, 'A', 'B', 'C')
|
||||
```
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
---
|
||||
id: 64e34146860065146733883b
|
||||
title: Step 53
|
||||
challengeType: 20
|
||||
dashedName: step-53
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Although recursion could sometimes be less easy to understand, it gives you the power to create more concise code. In this case, you don't even need to differentiate between even and odd numbers of disks.
|
||||
|
||||
Set `NUMBER_OF_DISKS` to `5` and check the output.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should set the `NUMBER_OF_DISKS` variable to 5.
|
||||
|
||||
```js
|
||||
({test: () => assert.equal(__userGlobals.get('NUMBER_OF_DISKS'), 5) })
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
--fcc-editable-region--
|
||||
NUMBER_OF_DISKS = 4
|
||||
A = list(range(NUMBER_OF_DISKS, 0, -1))
|
||||
B = []
|
||||
C = []
|
||||
|
||||
def move(n, source, auxiliary, target):
|
||||
if n > 0:
|
||||
# move n - 1 disks from source to auxiliary, so they are out of the way
|
||||
move(n - 1, source, target, auxiliary)
|
||||
|
||||
# move the nth disk from source to target
|
||||
target.append(source.pop())
|
||||
|
||||
# display our progress
|
||||
print(A, B, C, '\n')
|
||||
|
||||
# move the n - 1 disks that we left on auxiliary onto target
|
||||
move(n - 1, auxiliary, source, target)
|
||||
|
||||
# initiate call from source A to target C with auxiliary B
|
||||
move(NUMBER_OF_DISKS, A, B, C)
|
||||
--fcc-editable-region--
|
||||
```
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
---
|
||||
id: 650c6082e5586f9e3acfcd3b
|
||||
title: Step 52
|
||||
challengeType: 20
|
||||
dashedName: step-52
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Now, delete the `rods` dictionary and turn its keys into the variables `A`, `B`, and `C`, respectively, keeping their values. Refactor your code to reflect these changes. If you see the output on the terminal, you correctly did this step.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should turn `rods['A']` into a variable named `A` keeping its value.
|
||||
|
||||
```js
|
||||
assert.match(code, /A\s*=\s*list\s*\(\s*range\s*\(\s*NUMBER_OF_DISKS\s*,\s*0\s*,\s*-\s*1\s*\)\s*\)/);
|
||||
```
|
||||
|
||||
You should turn `rods['B']` into a variable named `B` keeping its value.
|
||||
|
||||
```js
|
||||
assert.match(code, /B\s*=\s*\[\s*\]/);
|
||||
```
|
||||
|
||||
You should turn `rods['C']` into a variable named `C` keeping its value.
|
||||
|
||||
```js
|
||||
assert.match(code, /C\s*=\s*\[\s*\]/);
|
||||
```
|
||||
|
||||
You should modify your `print()` call to print `A`, `B`, `C`, instead of the `rods` object. Keep the newline character in the `print()` call.
|
||||
|
||||
```js
|
||||
assert.match(code, /print\s*\(\s*A\s*,\s*B\s*,\s*C\s*,\s*('|")\\n\1\s*\)/);
|
||||
```
|
||||
|
||||
You should have `target.append(source.pop())` in your code.
|
||||
|
||||
```js
|
||||
assert.match(code, /target\.append\s*\(\s*source\.pop\s*\(\s*\)\s*\)/);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
--fcc-editable-region--
|
||||
NUMBER_OF_DISKS = 4
|
||||
rods = {
|
||||
'A': list(range(NUMBER_OF_DISKS, 0, -1)),
|
||||
'B': [],
|
||||
'C': []
|
||||
}
|
||||
|
||||
def move(n, source, auxiliary, target):
|
||||
if n > 0:
|
||||
# move n - 1 disks from source to auxiliary, so they are out of the way
|
||||
move(n - 1, source, target, auxiliary)
|
||||
|
||||
# move the nth disk from source to target
|
||||
rods[target].append(rods[source].pop())
|
||||
|
||||
# display our progress
|
||||
print(rods, '\n')
|
||||
|
||||
# move the n - 1 disks that we left on auxiliary onto target
|
||||
move(n - 1, auxiliary, source, target)
|
||||
|
||||
# initiate call from source A to target C with auxiliary B
|
||||
move(NUMBER_OF_DISKS, 'A', 'B', 'C')
|
||||
--fcc-editable-region--
|
||||
```
|
||||
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
---
|
||||
id: 65782342850feb3b8d62f936
|
||||
title: Step 18
|
||||
challengeType: 20
|
||||
dashedName: step-18
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Since you are going to use the expression `(i + 1) % 3` multiple times, it is convenient to store it in a variable.
|
||||
|
||||
Just above your `if` statement, declare a `remainder` variable and assign the value `(i + 1) % 3` to this variable.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should declare a `remainder` variable just above the `if` block.
|
||||
|
||||
```js
|
||||
({ test: () => assert.match(code, /^\s{8}remainder\s*=/m) })
|
||||
```
|
||||
|
||||
The value of your `remainder` variable should be the expression `(i + 1) % 3`.
|
||||
|
||||
```js
|
||||
({ test: () => assert.match(code, /^\s{8}remainder\s*=\s*\(\s*i\s*\+\s*1\s*\)\s*%\s*3/m) })
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
NUMBER_OF_DISKS = 3
|
||||
number_of_moves = 2**NUMBER_OF_DISKS - 1
|
||||
rods = {
|
||||
'A': list(range(NUMBER_OF_DISKS, 0, -1)),
|
||||
'B': [],
|
||||
'C': []
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
def move(n, source, auxiliary, target):
|
||||
# display starting configuration
|
||||
print(rods)
|
||||
for i in range(number_of_moves):
|
||||
|
||||
if (i + 1) % 3 == 1:
|
||||
print(f'Move {i + 1} allowed between {source} and {target}')
|
||||
--fcc-editable-region--
|
||||
|
||||
# initiate call from source A to target C with auxiliary B
|
||||
move(NUMBER_OF_DISKS, 'A', 'B', 'C')
|
||||
```
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
---
|
||||
id: 6578273de26b6e5965a9107d
|
||||
title: Step 19
|
||||
challengeType: 20
|
||||
dashedName: step-19
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Now, replace the expression in the `if` condition with the `remainder` variable.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should replace `(i+ 1) % 3` with the `remainder` variable.
|
||||
|
||||
```js
|
||||
({ test: () => assert.match(code, /^\s{8}if\s+remainder\s*==\s*1\s*:/m) })
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
NUMBER_OF_DISKS = 3
|
||||
number_of_moves = 2**NUMBER_OF_DISKS - 1
|
||||
rods = {
|
||||
'A': list(range(NUMBER_OF_DISKS, 0, -1)),
|
||||
'B': [],
|
||||
'C': []
|
||||
}
|
||||
|
||||
--fcc-editable-region--
|
||||
def move(n, source, auxiliary, target):
|
||||
# display starting configuration
|
||||
print(rods)
|
||||
for i in range(number_of_moves):
|
||||
remainder = (i + 1) % 3
|
||||
if (i + 1) % 3 == 1:
|
||||
print(f'Move {i + 1} allowed between {source} and {target}')
|
||||
--fcc-editable-region--
|
||||
|
||||
# initiate call from source A to target C with auxiliary B
|
||||
move(NUMBER_OF_DISKS, 'A', 'B', 'C')
|
||||
```
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
---
|
||||
id: 657b667a772ed53e82962c81
|
||||
title: Step 54
|
||||
challengeType: 20
|
||||
dashedName: step-54
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
There's still one thing you can do to improve the readability of your code.
|
||||
|
||||
Modify your `if` to execute when `n` is less than or equal to zero and add a `return` statement to stop the function execution.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should modify your existing `if` to check if `n` is less than or equal to `0`.
|
||||
|
||||
```js
|
||||
({ test: () =>
|
||||
{
|
||||
const hanoi = __helpers.python.getDef(code, "move");
|
||||
const {function_body} = hanoi;
|
||||
assert(function_body.match(/^\s{4}if\s+n\s*<=\s*0\s*:/m));
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
You should add a `return` statement to the first line of your `if` block.
|
||||
|
||||
```js
|
||||
({ test: () =>
|
||||
{
|
||||
const hanoi = __helpers.python.getDef(code, "move");
|
||||
const {function_body} = hanoi;
|
||||
assert(function_body.match(/^(\s{4})if\s+n\s*<=\s*0\s*:\s*\1\1return/m));
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
NUMBER_OF_DISKS = 5
|
||||
A = list(range(NUMBER_OF_DISKS, 0, -1))
|
||||
B = []
|
||||
C = []
|
||||
--fcc-editable-region--
|
||||
def move(n, source, auxiliary, target):
|
||||
if n > 0:
|
||||
|
||||
--fcc-editable-region--
|
||||
# move n - 1 disks from source to auxiliary, so they are out of the way
|
||||
move(n - 1, source, target, auxiliary)
|
||||
|
||||
# move the nth disk from source to target
|
||||
target.append(source.pop())
|
||||
|
||||
# display our progress
|
||||
print(A, B, C, '\n')
|
||||
|
||||
# move the n - 1 disks that we left on auxiliary onto target
|
||||
move(n - 1, auxiliary, source, target)
|
||||
|
||||
# initiate call from source A to target C with auxiliary B
|
||||
move(NUMBER_OF_DISKS, A, B, C)
|
||||
|
||||
```
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
---
|
||||
id: 657b6a4a49faec5c600287ba
|
||||
title: Step 55
|
||||
challengeType: 20
|
||||
dashedName: step-55
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
As a final step, reduce the indentation level of all the code after the `return` statement.
|
||||
|
||||
Well done. You have completed the Tower of Hanoi practice project.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should reduce the indentation level of all the code after the `return` statement.
|
||||
|
||||
```js
|
||||
({ test: () => assert(__pyodide.runPython(`
|
||||
hanoi = __locals.get("move")
|
||||
a, b, c = [3, 2, 1], [], []
|
||||
hanoi(3, a, b, c)
|
||||
a == [] and b == [] and c == [3, 2, 1]
|
||||
`))
|
||||
})
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
--fcc-editable-region--
|
||||
NUMBER_OF_DISKS = 5
|
||||
A = list(range(NUMBER_OF_DISKS, 0, -1))
|
||||
B = []
|
||||
C = []
|
||||
|
||||
def move(n, source, auxiliary, target):
|
||||
if n <= 0:
|
||||
return
|
||||
# move n - 1 disks from source to auxiliary, so they are out of the way
|
||||
move(n - 1, source, target, auxiliary)
|
||||
|
||||
# move the nth disk from source to target
|
||||
target.append(source.pop())
|
||||
|
||||
# display our progress
|
||||
print(A, B, C, '\n')
|
||||
|
||||
# move the n - 1 disks that we left on auxiliary onto target
|
||||
move(n - 1, auxiliary, source, target)
|
||||
|
||||
# initiate call from source A to target C with auxiliary B
|
||||
move(NUMBER_OF_DISKS, A, B, C)
|
||||
--fcc-editable-region--
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```py
|
||||
NUMBER_OF_DISKS = 5
|
||||
A = list(range(NUMBER_OF_DISKS, 0, -1))
|
||||
B = []
|
||||
C = []
|
||||
|
||||
def move(n, source, auxiliary, target):
|
||||
if n <= 0:
|
||||
return
|
||||
# move n - 1 disks from source to auxiliary, so they are out of the way
|
||||
move(n - 1, source, target, auxiliary)
|
||||
|
||||
# move the nth disk from source to target
|
||||
target.append(source.pop())
|
||||
|
||||
# display our progress
|
||||
print(A, B, C, '\n')
|
||||
|
||||
# move the n - 1 disks that we left on auxiliary onto target
|
||||
move(n - 1, auxiliary, source, target)
|
||||
|
||||
# initiate call from source A to target C with auxiliary B
|
||||
move(NUMBER_OF_DISKS, A, B, C)
|
||||
```
|
||||
Reference in New Issue
Block a user