diff --git a/curriculum/challenges/_meta/learn-classes-and-objects-by-building-a-sudoku-solver/meta.json b/curriculum/challenges/_meta/learn-classes-and-objects-by-building-a-sudoku-solver/meta.json
index ae2c603985d..5827154640e 100644
--- a/curriculum/challenges/_meta/learn-classes-and-objects-by-building-a-sudoku-solver/meta.json
+++ b/curriculum/challenges/_meta/learn-classes-and-objects-by-building-a-sudoku-solver/meta.json
@@ -11,320 +11,316 @@
"superBlock": "scientific-computing-with-python",
"challengeOrder": [
{
- "id": "656873ffdc638f7e290f60de",
+ "id": "66068fb0bfddba2b7977eb60",
"title": "Step 1"
},
{
- "id": "656874efd5102b81815c8ef7",
+ "id": "66069167b3307b2f4067b22b",
"title": "Step 2"
},
{
- "id": "65688efcc78c9495e73acfc9",
+ "id": "6606927d010be4300a4e5330",
"title": "Step 3"
},
{
- "id": "65688f22703200963a85dfb7",
+ "id": "6606933d6813a8308c962dd1",
"title": "Step 4"
},
{
- "id": "65688f737b0ef396bf0c22d6",
+ "id": "660699119472f332798860ad",
"title": "Step 5"
},
{
- "id": "65688f93a1b6e9970f710f62",
+ "id": "660699aabc59c532f2d556e5",
"title": "Step 6"
},
{
- "id": "65688fc27e8dda9760c45d7d",
+ "id": "66069b0b36053733a2f012fe",
"title": "Step 7"
},
{
- "id": "65689020cfd5279803976b25",
+ "id": "66069b992c1c5e3451f3deb0",
"title": "Step 8"
},
{
- "id": "6568904b83a2f29878578146",
+ "id": "66069d65162e61357c793e0c",
"title": "Step 9"
},
{
- "id": "6568917528820d99236ad811",
+ "id": "66069e5759b800364707988e",
"title": "Step 10"
},
{
- "id": "656896ffecbf07a2d3402a93",
+ "id": "66069f86f58f85371d47123e",
"title": "Step 11"
},
{
- "id": "6568991b4d4874a4d5271337",
+ "id": "6606a219f9efbf38ad496f67",
"title": "Step 12"
},
{
- "id": "6568994faf481da5d37bfa40",
+ "id": "6606a2f8a6a36f39518e0439",
"title": "Step 13"
},
{
- "id": "6568997f94c673a68b035b60",
+ "id": "6606a3ccb1eea93a23c066bf",
"title": "Step 14"
},
{
- "id": "656899c0478950a7e5db2cc0",
+ "id": "6606a4641ec48b3a9fe8c2fc",
"title": "Step 15"
},
{
- "id": "656899f4214ee6a881bc8649",
+ "id": "6606b0d602d1e33e81bcef0d",
"title": "Step 16"
},
{
- "id": "65689a748de8fbaa00c5617e",
+ "id": "6606b224a69a293f98f8db8f",
"title": "Step 17"
},
{
- "id": "65689aa3d3f2b6aad204a59e",
+ "id": "6606b63c0fd55e4314d2ec85",
"title": "Step 18"
},
{
- "id": "65689ad61dfa81ab9ffafc86",
+ "id": "6606b6b7760d0643c3b4eb29",
"title": "Step 19"
},
{
- "id": "65689b055e6f49ac6f82d3cf",
+ "id": "6606b8d31356fe4563f0e99c",
"title": "Step 20"
},
{
- "id": "6568a242a3e1efc22b07274d",
+ "id": "6606b961ebcf04460f8af76e",
"title": "Step 21"
},
{
- "id": "6568bb1ffe8462c427c0d386",
+ "id": "6606baaf1828ff46ebcc008c",
"title": "Step 22"
},
{
- "id": "6568bb656c67e9c54cced2d7",
+ "id": "6606bbd52233b247cf0a56e4",
"title": "Step 23"
},
{
- "id": "6568bba429481cc693fc2570",
+ "id": "6606bc4e5535c0484990ccd5",
"title": "Step 24"
},
{
- "id": "6568bbc8c3bda1c773e23cf1",
+ "id": "6606bd3d02e86548d3ce1a0a",
"title": "Step 25"
},
{
- "id": "6568bc19f3418dc8a8821187",
+ "id": "6606beade9200b49aaeecd94",
"title": "Step 26"
},
{
- "id": "6568bc85c5beadca3e0f6eb1",
+ "id": "6606bf4561f8794a0d345919",
"title": "Step 27"
},
{
- "id": "6568bd3741e379ccc220af1b",
+ "id": "6606c05b5624a54ab85808fa",
"title": "Step 28"
},
{
- "id": "6568bd85482755cdd26443ae",
+ "id": "6606c0dd3293064b30d17a72",
"title": "Step 29"
},
{
- "id": "6568bdb69e05a9cee01068a8",
+ "id": "6606c14182435d4bab0de2ee",
"title": "Step 30"
},
{
- "id": "6568beebba98a3d1f26f6bf8",
+ "id": "6606c2d203a8124c83b2234b",
"title": "Step 31"
},
{
- "id": "6568bf22bb5de0d2e8260cf3",
+ "id": "6606c3fd5634684d48a7887b",
"title": "Step 32"
},
{
- "id": "6568bf5e5b2f4bd3eb7ef995",
+ "id": "6606cb019db4f74f224856f4",
"title": "Step 33"
},
{
- "id": "6568bf853bf06dd4ed25d4ca",
+ "id": "6606cc088fd3574fa9010a4f",
"title": "Step 34"
},
{
- "id": "6568bfb601a54ed5b367b44f",
+ "id": "6606cc473675e85017b0c53d",
"title": "Step 35"
},
{
- "id": "6568bfd65322add674039bde",
+ "id": "6606cc754a8834509cd0afb6",
"title": "Step 36"
},
{
- "id": "6568c0013b3b62d7617518c7",
+ "id": "6606cd69f56e27516583b0cc",
"title": "Step 37"
},
{
- "id": "6568c024933423d85d5ed93c",
+ "id": "6606cf1b2b9f65529c161098",
"title": "Step 38"
},
{
- "id": "6568c073d5f37fd99ab2ab0c",
+ "id": "6606d03ff198245383e61d90",
"title": "Step 39"
},
{
- "id": "6568c0a5edddc3daa65d20b2",
+ "id": "6606d32096165654b8e73f21",
"title": "Step 40"
},
{
- "id": "6569d83fe4dcc614c2ff971d",
+ "id": "6606d378de78d55523f08298",
"title": "Step 41"
},
{
- "id": "6569d8a4b8d85515cbb1ce72",
+ "id": "6606d589750ad655fa0df168",
"title": "Step 42"
},
{
- "id": "6569d946293d4f185e32e2da",
+ "id": "6606d6138c49e456920fa818",
"title": "Step 43"
},
{
- "id": "6569d98303af38193149b66e",
+ "id": "6606d7bb9e4c6b574235159a",
"title": "Step 44"
},
{
- "id": "6569d9dfd53db11b176d2963",
+ "id": "6606d8795bd533582425a363",
"title": "Step 45"
},
{
- "id": "6569da02e7e2641be14ff922",
+ "id": "6606d8c323d6205890fbbd54",
"title": "Step 46"
},
{
- "id": "6569de93a5340b202667deda",
+ "id": "6606d9d92fcf78598b3b5184",
"title": "Step 47"
},
{
- "id": "6569def38470282151f873ce",
+ "id": "6606db6a23a1455a402f91ae",
"title": "Step 48"
},
{
- "id": "6569df1d6fb83d22623b38c5",
+ "id": "6606dcf5a31e4e5b43737417",
"title": "Step 49"
},
{
- "id": "6569df6916294723e01f0035",
+ "id": "6606dd63109f9f5c2195e30c",
"title": "Step 50"
},
{
- "id": "6569df9e20f74a251d482c5d",
+ "id": "6606de006a82e05c9a65cebe",
"title": "Step 51"
},
{
- "id": "6569dffeee007f26d2b56d46",
+ "id": "6606e2f27f19ca5f398c6aed",
"title": "Step 52"
},
{
- "id": "6569e2a01a97b231862ba2ff",
+ "id": "6606e3e6231702600bd5860c",
"title": "Step 53"
},
{
- "id": "6569e2e1944fe7329ab21c7f",
+ "id": "660a737f0f72b51de361051c",
"title": "Step 54"
},
{
- "id": "6569e309feb5d333867a034a",
+ "id": "660a7a1cac69b7217cbae22d",
"title": "Step 55"
},
{
- "id": "6569e33a708a3834f6d4879b",
+ "id": "660a7cb75dce3d22ab562c0d",
"title": "Step 56"
},
{
- "id": "6569e37ec28e853628f18a86",
+ "id": "660a7ea6e3a21a243d6aa288",
"title": "Step 57"
},
{
- "id": "6569e3a134fea0371fa008de",
+ "id": "660a7f28d5ce6a24ef856a50",
"title": "Step 58"
},
{
- "id": "6569e3d1418b373839a0aa7b",
+ "id": "660a8b6cd8de406ae82ce910",
"title": "Step 59"
},
{
- "id": "6569e41657a9923953aa7d3c",
+ "id": "660a8c3b21100c6b83e57cb0",
"title": "Step 60"
},
{
- "id": "6569e481e67f123ad25c5d20",
+ "id": "660a8d7c5f33c16c67e58b37",
"title": "Step 61"
},
{
- "id": "6569f6b48716b5402504e216",
+ "id": "660a8ef6b7571f6dddc3553b",
"title": "Step 62"
},
{
- "id": "6569f6ebe558bd4136da96cc",
+ "id": "660a92e93854486efa68fe6f",
"title": "Step 63"
},
{
- "id": "6569f70a66ccdc42097ca051",
+ "id": "660a937220bf966fd844f1ee",
"title": "Step 64"
},
{
- "id": "6569f770fd7dc443d6293095",
+ "id": "660a940b3379fb708a83593a",
"title": "Step 65"
},
{
- "id": "6569f7c7f6954944d207775f",
+ "id": "660a94f55c3c9b71a37e1c8b",
"title": "Step 66"
},
{
- "id": "6569f7f2fa74c045e95676ac",
+ "id": "660a957f44c096728ba9c41f",
"title": "Step 67"
},
{
- "id": "6569fa5b9d507748bf4ec722",
+ "id": "660a95c3da857673124ed698",
"title": "Step 68"
},
{
- "id": "6569fa85d8f9ed49c8dfb37d",
+ "id": "660a968ca0838773c9bbfc85",
"title": "Step 69"
},
{
- "id": "6569fabbfe1c094ad838ec4c",
+ "id": "660a9819ad113774d65a1e7c",
"title": "Step 70"
},
{
- "id": "6569fbbfee025a4e850b6eaf",
+ "id": "660ac1d158923e805d3c3099",
"title": "Step 71"
},
{
- "id": "6569fc21837cab5029d82e26",
+ "id": "660ac2873b090d80d6aa6ce2",
"title": "Step 72"
},
{
- "id": "6569fc63a404c8519d918095",
+ "id": "660ac35d55a15d81afdedd76",
"title": "Step 73"
},
{
- "id": "6569fca3cd7a9f52f322a298",
+ "id": "660ac44c7eec868220318297",
"title": "Step 74"
},
{
- "id": "6569fd01dab2ea547d98f093",
+ "id": "660ac4f4f784b9829e89632a",
"title": "Step 75"
},
{
- "id": "6569fd352879475599d0ec66",
+ "id": "660ac56326c2eb831583c0de",
"title": "Step 76"
},
{
- "id": "6569fd6d3cb95856c9ed2190",
+ "id": "660ac59d7ea60083900b83df",
"title": "Step 77"
},
{
- "id": "6569fdc59fe1b658bc9e23a4",
+ "id": "660ac60e22aa218400acb4b6",
"title": "Step 78"
- },
- {
- "id": "6569fe0fe5b5425a1bb1f534",
- "title": "Step 79"
}
],
"helpCategory": "Python"
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/656874efd5102b81815c8ef7.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/656874efd5102b81815c8ef7.md
deleted file mode 100644
index f7140057ced..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/656874efd5102b81815c8ef7.md
+++ /dev/null
@@ -1,39 +0,0 @@
----
-id: 656874efd5102b81815c8ef7
-title: Step 2
-challengeType: 20
-dashedName: step-2
----
-
-# --description--
-
-A new instance of a class is created by using the function notation: `ClassName()`. The instantiation creates an empty object. Classes can have methods, which are like local functions for each instance. Methods are declared as follows:
-
-```python
-class ClassName:
- def method_name():
- pass
-```
-
-The `__init__` method is a special method that allows you to instantiate an object to a customized state. When a class implements an `__init__` method, `__init__` is automatically called upon instantiation.
-
-Create an `__init__` method inside your `Board` class.
-
-# --hints--
-
-Your method should be named `__init__`. Don't add any parameters.
-
-```js
-assert.match(code, / +def\s+__init__\s*\(\s*\)\:/);
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
---fcc-editable-region--
-class Board:
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/65688efcc78c9495e73acfc9.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/65688efcc78c9495e73acfc9.md
deleted file mode 100644
index 090cb6a7bc2..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/65688efcc78c9495e73acfc9.md
+++ /dev/null
@@ -1,33 +0,0 @@
----
-id: 65688efcc78c9495e73acfc9
-title: Step 3
-challengeType: 20
-dashedName: step-3
----
-
-# --description--
-
-Add two parameters to the `__init__` method, order matters:
-
-- `self`: This is a reference to the instance of the class. It is a convention to name this parameter self.
-- `board`: The board parameter is expected to be passed when creating an instance of the `Board` class.
-
-# --hints--
-
-You should add the parameter `self` and `board` to the method.
-
-```js
-assert.match(code, /def\s+__init__\s*\(\s*self\s*,\s*board\s*\):/);
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
---fcc-editable-region--
-class Board:
- def __init__():
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/65688f22703200963a85dfb7.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/65688f22703200963a85dfb7.md
deleted file mode 100644
index 0315c067b9e..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/65688f22703200963a85dfb7.md
+++ /dev/null
@@ -1,32 +0,0 @@
----
-id: 65688f22703200963a85dfb7
-title: Step 4
-challengeType: 20
-dashedName: step-4
----
-
-# --description--
-
-Inside the `__init__` method, assign the value of the `board` parameter (which is passed when creating an instance of the `Board` class) to an instance variable named `board` using `self.board`.
-
-`self.board` refers to the board attribute of the instance of the class. It's a variable that belongs to the object created from the `Board` class.
-
-# --hints--
-
-You should have `self.board = board` within the `__init__` method.
-
-```js
-assert.match(code, /self\.board\s*=\s*board/);
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
---fcc-editable-region--
-class Board:
- def __init__(self, board):
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/65688f737b0ef396bf0c22d6.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/65688f737b0ef396bf0c22d6.md
deleted file mode 100644
index 4a4115dff1f..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/65688f737b0ef396bf0c22d6.md
+++ /dev/null
@@ -1,60 +0,0 @@
----
-id: 65688f737b0ef396bf0c22d6
-title: Step 5
-challengeType: 20
-dashedName: step-5
----
-
-# --description--
-
-Now you will move to the actual construction of the board, which is a 9x9 grid.
-
-The input puzzle would look like this:
-
-```py
-puzzle = [
- [0, 0, 2, 0, 0, 8, 0, 0, 0],
- [0, 0, 0, 0, 0, 3, 7, 6, 2],
- [4, 3, 0, 0, 0, 0, 8, 0, 0],
- [0, 5, 0, 0, 3, 0, 0, 9, 0],
- [0, 4, 0, 0, 0, 0, 0, 2, 6],
- [0, 0, 0, 4, 6, 7, 0, 0, 0],
- [0, 8, 6, 7, 0, 4, 0, 0, 0],
- [0, 0, 0, 5, 1, 9, 0, 0, 8],
- [1, 7, 0, 0, 0, 6, 0, 0, 5]
-]
-```
-
-The resulting grid would look like this:
-
-
-
-
-Define a method `__str__` within the `Board` class. Also, add the `self` parameter. This method is automatically called when you use the `str()` function on an instance of the class or when you use `print()` with the object.
-
-# --hints--
-
-Your method should be named `__str__`.
-
-```js
-assert.match(code, /def\s+__str__\s*\(/);
-```
-
-You should add the parameter `self` to the method.
-
-```js
-assert.match(code, /def\s+__str__\s*\(\s*self\s*\)\s*:/);
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
---fcc-editable-region--
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/65688f93a1b6e9970f710f62.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/65688f93a1b6e9970f710f62.md
deleted file mode 100644
index 8ef5c8bf774..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/65688f93a1b6e9970f710f62.md
+++ /dev/null
@@ -1,35 +0,0 @@
----
-id: 65688f93a1b6e9970f710f62
-title: Step 6
-challengeType: 20
-dashedName: step-6
----
-
-# --description--
-
-To create the top border of the board, create an `upper_lines` variable and assign it the value of `f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'`.
-
-This string represents the top border of the sudoku board in a visually appealing ASCII art style. It uses special Unicode characters to draw the borders and intersections.
-
-# --hints--
-
-Assign the value of `f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'` to a variable named `upper_lines`.
-
-```js
-({ test: () => assert.match(code, /upper_lines\s*=\s*f("|')\\n╔═══\{\s*(?=[^\1])("|')╤═══\2\s*\*\s*2\s*\}\{\s*\2╦═══\2\s*\}\{\s*\2╤═══\2\s*\*\s*2\s*\}\{\s*\2╦═══\2\s*\}\{\s*\2╤═══\2\s*\*\s*2\s*\}╗\\n\1/m) })
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
---fcc-editable-region--
- def __str__(self):
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/65688fc27e8dda9760c45d7d.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/65688fc27e8dda9760c45d7d.md
deleted file mode 100644
index 09e49231ff5..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/65688fc27e8dda9760c45d7d.md
+++ /dev/null
@@ -1,34 +0,0 @@
----
-id: 65688fc27e8dda9760c45d7d
-title: Step 7
-challengeType: 20
-dashedName: step-7
----
-
-# --description--
-
-To create middle borders of the sudoku board, create a `middle_lines` variable and assign it the value of `f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'`.
-
-# --hints--
-
-You should assign the value of `f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'` to a variable named `middle_lines`.
-
-```js
-({ test: () => assert.match(code, /middle_lines\s*=\s*f("|')╟───\{\s*(?=[^\1])("|')┼───\2\s*\*\s*2\s*\}\{\s*\2╫───\2\s*\}\{\s*\2┼───\2\s*\*\s*2\s*\}\{\s*\2╫───\2\s*\}\{\s*\2┼───\2\s*\*\s*2\s*\}╢\\n\1/m) })
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
---fcc-editable-region--
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/65689020cfd5279803976b25.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/65689020cfd5279803976b25.md
deleted file mode 100644
index 2df9ae6d405..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/65689020cfd5279803976b25.md
+++ /dev/null
@@ -1,35 +0,0 @@
----
-id: 65689020cfd5279803976b25
-title: Step 8
-challengeType: 20
-dashedName: step-8
----
-
-# --description--
-
-To create the bottom border of the sudoku board, create a `lower_lines` variable and assign it the value of `f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'`.
-
-# --hints--
-
-You should add `lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'` to the code.
-
-```js
-({ test: () => assert.match(code, /lower_lines\s*=\s*f("|')╚═══\{\s*(?=[^\1])("|')╧═══\2\s*\*\s*2\s*\}\{\s*\2╩═══\2\s*\}\{\s*\2╧═══\2\s*\*\s*2\s*\}\{\s*\2╩═══\2\s*\}\{\s*\2╧═══\2\s*\*\s*2\s*\}╝\\n\1/m) })
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
---fcc-editable-region--
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568904b83a2f29878578146.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568904b83a2f29878578146.md
deleted file mode 100644
index b6c4ff759c3..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568904b83a2f29878578146.md
+++ /dev/null
@@ -1,42 +0,0 @@
----
-id: 6568904b83a2f29878578146
-title: Step 9
-challengeType: 20
-dashedName: step-9
----
-
-# --description--
-
-Initialize a `board_string` variable with the content of `upper_lines`. This will be the starting point for building the entire visual representation of the sudoku board.
-
-# --hints--
-
-You should have `board_string = upper_lines` within the `__str__` method.
-
-```js
-({ test: () =>
- {
- const str = __helpers.python.getDef(code.replace(/\r/g, ''), "__str__");
- const {function_body} = str;
- assert(function_body.match(/board_string\s*=\s*upper_lines/));
- }
-})
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
---fcc-editable-region--
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568917528820d99236ad811.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568917528820d99236ad811.md
deleted file mode 100644
index 14d4f7cae49..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568917528820d99236ad811.md
+++ /dev/null
@@ -1,53 +0,0 @@
----
-id: 6568917528820d99236ad811
-title: Step 10
-challengeType: 20
-dashedName: step-10
----
-
-# --description--
-
-Now, you need to go over each row in the sudoku board.
-
-Enumeration is a convenient way to keep track of both the element and its position on a list.
-The `enumerate()` function is a built-in function in Python that takes an iterable (such as a list, tuple, or string) and returns an iterator that produces tuples containing indices and corresponding values from the iterable.
-
-Initiate a `for` loop to iterate over each row (`line`) in the sudoku board (`self.board`).
-
-Use enumeration to get both the index (`index`) and the content (`line`) of each row.
-
-The general syntax would be like this:
-
-```js
-for x, y in enumerate(parameter):
-```
-
-# --hints--
-
-You should have `for index, line in enumerate(self.board):` within the `__str__` method.
-
-```js
-assert.match(
- code,
- /for\s+(\w+)\s*,\s*(?!\1)(\w+)\s+in\s+enumerate\s*\(\s*self\.board\s*\)\s*:/m
-);
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
---fcc-editable-region--
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/656896ffecbf07a2d3402a93.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/656896ffecbf07a2d3402a93.md
deleted file mode 100644
index 8e57a17e086..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/656896ffecbf07a2d3402a93.md
+++ /dev/null
@@ -1,57 +0,0 @@
----
-id: 656896ffecbf07a2d3402a93
-title: Step 11
-challengeType: 20
-dashedName: step-11
----
-
-# --description--
-
-Inside the loop, initialize an empty list `row_list` to store the elements of a single row in the sudoku board.
-
-# --hints--
-
-You should have a `row_list` variable.
-
-```js
-({ test: () =>
- {
- const str = __helpers.python.getDef(code.replace(/\r/g, ''), "__str__");
- const {function_body} = str;
- assert(function_body.match(/row_list\s*=/));
- }
-})
-```
-
-`row_list` should be an empty list.
-
-```js
-({ test: () =>
- {
- const str = __helpers.python.getDef(code.replace(/\r/g, ''), "__str__");
- const {function_body} = str;
- assert(function_body.match(/row_list\s*=\s*\[\s*\]/));
- }
-})
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
-
---fcc-editable-region--
- for index, line in enumerate(self.board):
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568991b4d4874a4d5271337.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568991b4d4874a4d5271337.md
deleted file mode 100644
index f18468c6e35..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568991b4d4874a4d5271337.md
+++ /dev/null
@@ -1,48 +0,0 @@
----
-id: 6568991b4d4874a4d5271337
-title: Step 12
-challengeType: 20
-dashedName: step-12
----
-
-# --description--
-
-Next, you are going to split each row in three segments, in order to represent the 3x3 squares properly.
-
-Create a nested `for` loop to iterate over each segment of the row. Use `square_no` and `part` as the iterating variable and the `enumerate()` function. For now, leave the `enumerate()` call empty.
-
-# --hints--
-
-The inner loop should have `square_no` as the counter and `part` as the element from iterable.
-
-```js
-assert.match(code, /for\s+square_no\s*,\s*part/)
-```
-
-You should have `for square_no, part in enumerate()` within the existing `for` loop.
-
-```js
-assert.match(code, /for\s+square_no\s*,\s*part\s+in\s+enumerate\s*\(\s*\)\:/)
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
-
---fcc-editable-region--
- for index, line in enumerate(self.board):
- row_list = []
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568994faf481da5d37bfa40.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568994faf481da5d37bfa40.md
deleted file mode 100644
index 28b1c0bbfc1..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568994faf481da5d37bfa40.md
+++ /dev/null
@@ -1,42 +0,0 @@
----
-id: 6568994faf481da5d37bfa40
-title: Step 13
-challengeType: 20
-dashedName: step-13
----
-
-# --description--
-
-Now, you need to create the three line segments to pass to the `enumerate` function.
-
-Use list slicing to create the three lists of equal length representing the `line` segment of each 3x3 square and pass them to the `enumerate()` call. Add `start = 1` to start the enumeration from `1` instead of `0`.
-
-# --hints--
-
-You should have `enumerate([line[:3], line[3:6], line[6:]], start=1)` within the inner `for` loop.
-
-```js
-assert.match(code, /\[\s*line\s*\[\s*:3\s*\]\s*,\s*line\s*\[\s*3\s*:\s*6\s*\]\s*,\s*line\s*\[\s*6\s*:\s*\]\s*\]\s*,\s*start\s*=\s*1/);
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
-
---fcc-editable-region--
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate():
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568997f94c673a68b035b60.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568997f94c673a68b035b60.md
deleted file mode 100644
index ea512b10f29..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568997f94c673a68b035b60.md
+++ /dev/null
@@ -1,60 +0,0 @@
----
-id: 6568997f94c673a68b035b60
-title: Step 14
-challengeType: 20
-dashedName: step-14
----
-
-# --description--
-
-Now, you would join the elements of the segment (`part`) with the pipe character (`|`).
-
-For that, first, use a `for` loop `for item in part` to access all elements.
-
-Then, use the `join()` method on the `|` character to join the elements of the segment (`part`).
-
-After that, convert each element to a string using `str(item)`.
-
-# --hints--
-
-You should use the `join()` method on the `|` character to join the elements of the segment (`part`).
-add test for "" as well
-
-```js
-assert.match(code, /('|")\|\1\.join\s*\(/)
-```
-
-You should call `str()` on each element in `part` using a generator expression.
-
-```js
-({ test: () => assert.match(code, /\(\s*str\s*\(\s*(\w+)\s*\)\s+for\s+\1\s+in\s+part\s*\)/) })
-```
-
-You should have `'|'.join(str(item) for item in part)` within the inner `for` loop.
-
-```js
-({ test: () => assert.match(code, /("|')\|\1\.join\s*\(\s*str\s*\(\s*(\w+)\s*\)\s+for\s+\2\s+in\s+part\s*\)/m) })
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
-
- for index, line in enumerate(self.board):
- row_list = []
---fcc-editable-region--
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/656899c0478950a7e5db2cc0.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/656899c0478950a7e5db2cc0.md
deleted file mode 100644
index 6477d428c0a..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/656899c0478950a7e5db2cc0.md
+++ /dev/null
@@ -1,41 +0,0 @@
----
-id: 656899c0478950a7e5db2cc0
-title: Step 15
-challengeType: 20
-dashedName: step-15
----
-
-# --description--
-
-Assign the joined string to the variable `row_square`.
-
-# --hints--
-
-You should assign the value of `'|'.join(str(item) for item in part)` to a variable named `row_square`.
-
-```js
-({ test: () => assert.match(code, /row_square\s*=\s*("|')\|\1\.join\s*\(\s*str\s*\(\s*(\w+)\s*\)\s+for\s+\2\s+in\s+part\s*\)/m) })
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
-
- for index, line in enumerate(self.board):
- row_list = []
---fcc-editable-region--
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- '|'.join(str(item) for item in part)
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/656899f4214ee6a881bc8649.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/656899f4214ee6a881bc8649.md
deleted file mode 100644
index a3a58603e1d..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/656899f4214ee6a881bc8649.md
+++ /dev/null
@@ -1,42 +0,0 @@
----
-id: 656899f4214ee6a881bc8649
-title: Step 16
-challengeType: 20
-dashedName: step-16
----
-
-# --description--
-
-Extend the `row_list` with the elements of the `row_square` string.
-
-# --hints--
-
-You should have `row_list.extend(row_square)` within the innermost `for` loop.
-
-```js
-({ test: () => assert.match(code, /row_list\.extend\s*\(\s*row_square\s*\)/m) })
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
-
---fcc-editable-region--
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/65689a748de8fbaa00c5617e.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/65689a748de8fbaa00c5617e.md
deleted file mode 100644
index dad88e5a3f4..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/65689a748de8fbaa00c5617e.md
+++ /dev/null
@@ -1,44 +0,0 @@
----
-id: 65689a748de8fbaa00c5617e
-title: Step 17
-challengeType: 20
-dashedName: step-17
----
-
-# --description--
-
-Within the innermost loop, create an `if` statement to check if the current segment (`square_no`) is not the last one (i.e., not equal to `3`)
-
-# --hints--
-
-You should check if the current segment (`square_no`) is not equal to `3`.
-
-```js
-assert.match(code, /if\s+square_no\s*!=\s*3/m)
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
-
- for index, line in enumerate(self.board):
- row_list = []
-
---fcc-editable-region--
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/65689aa3d3f2b6aad204a59e.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/65689aa3d3f2b6aad204a59e.md
deleted file mode 100644
index 8cef6d1fbea..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/65689aa3d3f2b6aad204a59e.md
+++ /dev/null
@@ -1,45 +0,0 @@
----
-id: 65689aa3d3f2b6aad204a59e
-title: Step 18
-challengeType: 20
-dashedName: step-18
----
-
-# --description--
-
-Inside the `if` block, append a `║` character at the end of `row_list`.
-
-# --hints--
-
-You should have `row_list.append('║')` within the `if` statement.
-
-```js
-({ test: () => assert.match(code, /row_list\.append\s*\(\s*("|')║\1\s*\)/m) })
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
-
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
-
---fcc-editable-region--
- if square_no != 3:
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/65689ad61dfa81ab9ffafc86.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/65689ad61dfa81ab9ffafc86.md
deleted file mode 100644
index e1d0bfac4a9..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/65689ad61dfa81ab9ffafc86.md
+++ /dev/null
@@ -1,48 +0,0 @@
----
-id: 65689ad61dfa81ab9ffafc86
-title: Step 19
-challengeType: 20
-dashedName: step-19
----
-
-# --description--
-
-Next, you will create a string representation of the row with spaces between each element.
-
-For that, outside the innermost `for` loop body, create a string `row`. Assign the following formatted string `f'║ {" ".join(row_list)} ║\n'` to it to join the elements of `row_list` with a space in between.
-
-# --hints--
-
-Assign the formatted string `f'║ {" ".join(row_list)} ║\n'` to a variable named `row`.
-
-```js
-({ test: () => assert.match(code, /row\s*\=\s*f("|')║\s\{(?!\1)("|')\s\2\.join\s*\(\s*row_list\s*\)\s*\}\s║\\n\1/m) })
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
-
- for index, line in enumerate(self.board):
- row_list = []
---fcc-editable-region--
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
-
- if square_no != 3:
- row_list.append('║')
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/65689b055e6f49ac6f82d3cf.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/65689b055e6f49ac6f82d3cf.md
deleted file mode 100644
index 544c48417e5..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/65689b055e6f49ac6f82d3cf.md
+++ /dev/null
@@ -1,60 +0,0 @@
----
-id: 65689b055e6f49ac6f82d3cf
-title: Step 20
-challengeType: 20
-dashedName: step-20
----
-
-# --description--
-
-When you would pass your input puzzle board, `0` would be used for empty cells.
-
-For a better visual representation, replace the empty cells in a row with a space using the `replace` method.
-
-The `replace()` method takes two arguments, the first one is the character to be replaced and the second one is the character to be replaced with.
-
-After replacing, assign the result to a variable `row_empty`.
-
-# --hints--
-
-You should replace each `0` in the row with a space using the `replace` method.
-
-```js
-({ test: () => assert.match(code, /row\.replace\s*\(\s*("|')0\1\s*,\s*("|') \2\s*\)/) })
-```
-
-You should have `row_empty = row.repalce('0', ' ')` within the outermost `for` loop.
-
-```js
-({ test: () => assert.match(code, /row_empty\s*=\s*row\.replace\s*\(\s*("|')0\1\s*,\s*("|') \2\s*\)/m) })
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
-
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
-
- if square_no != 3:
- row_list.append('║')
-
---fcc-editable-region--
- row = f'║ {" ".join(row_list)} ║\n'
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568a242a3e1efc22b07274d.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568a242a3e1efc22b07274d.md
deleted file mode 100644
index c897f6d6919..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568a242a3e1efc22b07274d.md
+++ /dev/null
@@ -1,49 +0,0 @@
----
-id: 6568a242a3e1efc22b07274d
-title: Step 21
-challengeType: 20
-dashedName: step-21
----
-
-# --description--
-
-`board_string` is gradually built up as the loop iterates over each row, creating the full ASCII art representation of the sudoku board.
-
-Add the modified `row_empty` string to the `board_string`.
-
-# --hints--
-
-You should have `board_string += row_empty` within the outermost `for` loop.
-
-```js
-({ test: () => assert.match(code, /board_string\s*\+=\s*row_empty/m) })
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
---fcc-editable-region--
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568bb1ffe8462c427c0d386.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568bb1ffe8462c427c0d386.md
deleted file mode 100644
index c69ed7e6b28..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568bb1ffe8462c427c0d386.md
+++ /dev/null
@@ -1,48 +0,0 @@
----
-id: 6568bb1ffe8462c427c0d386
-title: Step 22
-challengeType: 20
-dashedName: step-22
----
-
-# --description--
-
-Within the outermost `for` loop, create an `if` statement that checks if the current row index is less than `8`. This is because the last row of the sudoku board has an index of `8`, and you want to handle the last row differently.
-
-# --hints--
-
-You should have `if index < 8:` within the outermost `for` loop.
-
-```js
-assert.match(code, /if\s+index\s*<\s*8\s*:/m);
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
---fcc-editable-region--
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
- board_string += row_empty
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568bb656c67e9c54cced2d7.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568bb656c67e9c54cced2d7.md
deleted file mode 100644
index 10df2062e80..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568bb656c67e9c54cced2d7.md
+++ /dev/null
@@ -1,51 +0,0 @@
----
-id: 6568bb656c67e9c54cced2d7
-title: Step 23
-challengeType: 20
-dashedName: step-23
----
-
-# --description--
-
-Now, you need to verify if the row is the last row inside a 3x3 square. This occurs when `index % 3` is equal to `2`.
-
-Inside your existing `if` block, nest another `if` to check that condition.
-
-# --hints--
-
-You should have `if index % 3 == 2:` within the `if index < 8` statement.
-
-```js
-assert.match(code,/if\s+index\s*%\s*3\s*==\s*2\s*:/m)
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
- board_string += row_empty
---fcc-editable-region--
- if index < 8:
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568bba429481cc693fc2570.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568bba429481cc693fc2570.md
deleted file mode 100644
index ea53f09c0f7..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568bba429481cc693fc2570.md
+++ /dev/null
@@ -1,53 +0,0 @@
----
-id: 6568bba429481cc693fc2570
-title: Step 24
-challengeType: 20
-dashedName: step-24
----
-
-# --description--
-
-If the current row is the last row of a 3x3 square, in order to create a visually appealing border you need to append a different border string to `board_string` .
-
-Inside the `if` statement, add the following string to the current value of `board_string`: `f'╠═══{"╪═══"*2}{"╬═══"}{"╪═══"*2}{"╬═══"}{"╪═══"*2}╣\n'`.
-
-# --hints--
-
-You should have `board_string += f'╠═══{"╪═══"*2}{"╬═══"}{"╪═══"*2}{"╬═══"}{"╪═══"*2}╣\n'` within the `if index % 3 == 2` statement.
-
-```js
-assert.match(code, /board_string\s*\+=\s*f("|')╠═══\{\s*(?=[^\1])("|')╪═══\2\s*\*\s*2\s*\}\{\s*\2╬═══\2\s*\}\{\s*\2╪═══\2\s*\*\s*2\s*\}\{\s*\2╬═══\2\s*\}\{\s*\2╪═══\2\s*\*\s*2\s*\}╣\\n\1/)
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
- board_string += row_empty
-
- if index < 8:
---fcc-editable-region--
- if index % 3 == 2:
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568bbc8c3bda1c773e23cf1.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568bbc8c3bda1c773e23cf1.md
deleted file mode 100644
index 6d78bcb93c5..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568bbc8c3bda1c773e23cf1.md
+++ /dev/null
@@ -1,60 +0,0 @@
----
-id: 6568bbc8c3bda1c773e23cf1
-title: Step 25
-challengeType: 20
-dashedName: step-25
----
-
-# --description--
-
-Now, to handle other rows, if the inner condition is `False`, meaning the current row is not the last row of a 3x3 square, append the `middle_lines` string to `board_string`. Include this in an `else` block.
-
-Recall that `middle_lines` represents the middle borders of the sudoku board and includes horizontal separators.
-
-# --hints--
-
-You should add an `else` block to the `if` statement.
-
-```js
-({ test: () => assert.match(code, /else\s*:/m) })
-```
-
-You should have `board_string += middle_lines` within the `else` block.
-
-```js
-({ test: () => assert.match(code, /board_string\s*\+=\s*middle_lines/m) })
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
- board_string += row_empty
-
- if index < 8:
---fcc-editable-region--
- if index % 3 == 2:
- board_string += f'╠═══{"╪═══"*2}{"╬═══"}{"╪═══"*2}{"╬═══"}{"╪═══"*2}╣\n'
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568bc19f3418dc8a8821187.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568bc19f3418dc8a8821187.md
deleted file mode 100644
index 197b47e04e0..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568bc19f3418dc8a8821187.md
+++ /dev/null
@@ -1,64 +0,0 @@
----
-id: 6568bc19f3418dc8a8821187
-title: Step 26
-challengeType: 20
-dashedName: step-26
----
-
-# --description--
-
-Now, you need to handle the last row of the entire board.
-
-`lower_lines` represents the bottom border of the entire sudoku board.
-
-Create an `else` block to append the `lower_lines` string to `board_string` when the outer `if` condition is false.
-
-# --hints--
-
-You should create an `else` block for the outermost `if` statement. Pay attention to the indentation.
-
-```js
-({ test: () => assert.match(code, /else\s*:/m) })
-```
-
-You should have `board_string += lower_lines` within the outermost `else` clause.
-
-```js
-({ test: () => assert.match(code, /board_string\s*\+=\s*lower_lines/m) })
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
- board_string += row_empty
-
---fcc-editable-region--
- if index < 8:
- if index % 3 == 2:
- board_string += f'╠═══{"╪═══"*2}{"╬═══"}{"╪═══"*2}{"╬═══"}{"╪═══"*2}╣\n'
- else:
- board_string += middle_lines
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568bc85c5beadca3e0f6eb1.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568bc85c5beadca3e0f6eb1.md
deleted file mode 100644
index 68b181f4fd6..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568bc85c5beadca3e0f6eb1.md
+++ /dev/null
@@ -1,61 +0,0 @@
----
-id: 6568bc85c5beadca3e0f6eb1
-title: Step 27
-challengeType: 20
-dashedName: step-27
----
-
-# --description--
-
-After the outer loop completes for all rows, return the final `board_string`. This string contains the complete visual representation of the sudoku board in ASCII art style, including borders and separators.
-
-# --hints--
-
-You should return the `board_string` variable at the end of the outer `for` loop.
-
-```js
-const tCode = code.replace(/\r/g, '');
-const str = __helpers.python.getDef(tCode, "__str__");
-const {function_body} = str;
-const indent = function_body.match(/ +/)[0];
-const returnStatement = `${indent}return board_string`;
-assert.match(code, new RegExp(returnStatement));
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
---fcc-editable-region--
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
- board_string += row_empty
-
- if index < 8:
- if index % 3 == 2:
- board_string += f'╠═══{"╪═══"*2}{"╬═══"}{"╪═══"*2}{"╬═══"}{"╪═══"*2}╣\n'
- else:
- board_string += middle_lines
- else:
- board_string += lower_lines
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568bd3741e379ccc220af1b.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568bd3741e379ccc220af1b.md
deleted file mode 100644
index 719913583c9..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568bd3741e379ccc220af1b.md
+++ /dev/null
@@ -1,65 +0,0 @@
----
-id: 6568bd3741e379ccc220af1b
-title: Step 28
-challengeType: 20
-dashedName: step-28
----
-
-# --description--
-
-Now you will work on a method that finds the empty cells in the sudoku board.
-For that, within the `Board` class, create a method named `find_empty_cell`. It takes `self` as a parameter, representing the instance of the class. Include the `pass` keyword inside the function body.
-
-# --hints--
-
-Your method should be named `find_empty_cell`.
-
-```js
-assert.match(code, /def\s+find_empty_cell/);
-```
-
-You should add the parameter `self` to the method.
-
-```js
-assert.match(code, /def\s+find_empty_cell\(\s*self\s*\)/);
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
- board_string += row_empty
-
- if index < 8:
- if index % 3 == 2:
- board_string += f'╠═══{"╪═══"*2}{"╬═══"}{"╪═══"*2}{"╬═══"}{"╪═══"*2}╣\n'
- else:
- board_string += middle_lines
- else:
- board_string += lower_lines
-
- return board_string
---fcc-editable-region--
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568bd85482755cdd26443ae.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568bd85482755cdd26443ae.md
deleted file mode 100644
index 7b181941b50..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568bd85482755cdd26443ae.md
+++ /dev/null
@@ -1,78 +0,0 @@
----
-id: 6568bd85482755cdd26443ae
-title: Step 29
-challengeType: 20
-dashedName: step-29
----
-
-# --description--
-
-Inside the `find_empty_cell` method, create a `for` loop and use the `enumerate()` function to iterate over each row in the sudoku board.
-
-Use `row` for the index of the current row and `contents` for the elements of the current row.
-
-# --hints--
-
-You should create a `for` loop to iterate over `enumerate(self.board)`.
-
-```js
-const empty = __helpers.python.getDef(
- code,
- 'find_empty_cell'
-);
-const { function_body } = empty;
-assert(
- function_body.match(
- /for\s+(\w+)\s*,\s*(?!\1)(\w+)\s+in\s+enumerate\s*\(\s*self\.board\s*\)\s*:/m
- )
-);
-```
-
-You should have `for row, contents in enumerate(self.board):` within the `find_empty_cell` method.
-
-```js
-assert.match(
- code,
- /for\s+row\s*,\s*contents\s+in\s+enumerate\s*\(\s*self\.board\s*\)\s*:/m
-);
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
- board_string += row_empty
-
- if index < 8:
- if index % 3 == 2:
- board_string += f'╠═══{"╪═══"*2}{"╬═══"}{"╪═══"*2}{"╬═══"}{"╪═══"*2}╣\n'
- else:
- board_string += middle_lines
- else:
- board_string += lower_lines
-
---fcc-editable-region--
- def find_empty_cell(self):
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568bdb69e05a9cee01068a8.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568bdb69e05a9cee01068a8.md
deleted file mode 100644
index 4a8ebeae753..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568bdb69e05a9cee01068a8.md
+++ /dev/null
@@ -1,61 +0,0 @@
----
-id: 6568bdb69e05a9cee01068a8
-title: Step 30
-challengeType: 20
-dashedName: step-30
----
-
-# --description--
-
-In the body of the for loop, add a `try` block.
-
-# --hints--
-
-Add a `try` block.
-
-```js
-assert.match(code, /try\s*\:/)
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
- board_string += row_empty
-
- if index < 8:
- if index % 3 == 2:
- board_string += f'╠═══{"╪═══"*2}{"╬═══"}{"╪═══"*2}{"╬═══"}{"╪═══"*2}╣\n'
- else:
- board_string += middle_lines
- else:
- board_string += lower_lines
-
- return board_string
-
---fcc-editable-region--
- def find_empty_cell(self):
- for row, contents in enumerate(self.board):
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568beebba98a3d1f26f6bf8.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568beebba98a3d1f26f6bf8.md
deleted file mode 100644
index 1def274e4ab..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568beebba98a3d1f26f6bf8.md
+++ /dev/null
@@ -1,68 +0,0 @@
----
-id: 6568beebba98a3d1f26f6bf8
-title: Step 31
-challengeType: 20
-dashedName: step-31
----
-
-# --description--
-
-In the `try` block, attempt to find the index of the first occurrence of `0` in the current row using `contents.index(0)`. Store the results in the variable `col`.
-
-# --hints--
-
-Use the index of the first occurrence of `0` in the current row using `contents.index(0)`.
-
-```js
-assert.match(code, /contents\.index\(\s*0\s*\)/)
-```
-
-You should have `col = contents.index(0)` within the `try` block.
-
-```js
-assert.match(code, /col\s*=\s*contents\.index\(\s*0\s*\)/)
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
- board_string += row_empty
-
- if index < 8:
- if index % 3 == 2:
- board_string += f'╠═══{"╪═══"*2}{"╬═══"}{"╪═══"*2}{"╬═══"}{"╪═══"*2}╣\n'
- else:
- board_string += middle_lines
- else:
- board_string += lower_lines
-
- return board_string
-
- def find_empty_cell(self):
- for row, contents in enumerate(self.board):
---fcc-editable-region--
- try:
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568bf22bb5de0d2e8260cf3.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568bf22bb5de0d2e8260cf3.md
deleted file mode 100644
index da49863cccb..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568bf22bb5de0d2e8260cf3.md
+++ /dev/null
@@ -1,65 +0,0 @@
----
-id: 6568bf22bb5de0d2e8260cf3
-title: Step 32
-challengeType: 20
-dashedName: step-32
----
-
-# --description--
-
-If `0` is found, the code immediately returns a tuple (row, col) with the row index and column index of the empty cell.
-
-Return the `row` and `col` values
-
-# --hints--
-
-You should have `return row, col` within the `try` block.
-
-```js
-assert.match(code, /return\s*row\s*,\s*col/)
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
- board_string += row_empty
-
- if index < 8:
- if index % 3 == 2:
- board_string += f'╠═══{"╪═══"*2}{"╬═══"}{"╪═══"*2}{"╬═══"}{"╪═══"*2}╣\n'
- else:
- board_string += middle_lines
- else:
- board_string += lower_lines
-
- return board_string
-
- def find_empty_cell(self):
- for row, contents in enumerate(self.board):
---fcc-editable-region--
- try:
- col = contents.index(0)
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568bf5e5b2f4bd3eb7ef995.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568bf5e5b2f4bd3eb7ef995.md
deleted file mode 100644
index 7edac62cfea..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568bf5e5b2f4bd3eb7ef995.md
+++ /dev/null
@@ -1,64 +0,0 @@
----
-id: 6568bf5e5b2f4bd3eb7ef995
-title: Step 33
-challengeType: 20
-dashedName: step-33
----
-
-# --description--
-
-Create an `except` block to handle the `ValueError` exception that is thrown if `0` is not found.
-
-# --hints--
-
-You should have `except ValueError:` within the innermost `for` loop.
-
-```js
-assert.match(code, /except\s+ValueError/);
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
- board_string += row_empty
-
- if index < 8:
- if index % 3 == 2:
- board_string += f'╠═══{"╪═══"*2}{"╬═══"}{"╪═══"*2}{"╬═══"}{"╪═══"*2}╣\n'
- else:
- board_string += middle_lines
- else:
- board_string += lower_lines
-
- return board_string
-
- def find_empty_cell(self):
- for row, contents in enumerate(self.board):
---fcc-editable-region--
- try:
- col = contents.index(0)
- return row, col
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568bf853bf06dd4ed25d4ca.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568bf853bf06dd4ed25d4ca.md
deleted file mode 100644
index ed2c8bda6b5..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568bf853bf06dd4ed25d4ca.md
+++ /dev/null
@@ -1,68 +0,0 @@
----
-id: 6568bf853bf06dd4ed25d4ca
-title: Step 34
-challengeType: 20
-dashedName: step-34
----
-
-# --description--
-
-If the value `0` is not present in the current row, an exception would be thrown and the `except` block would execute.
-
-The `except` block should pass and continue to the next row.
-Achieve this by using `pass`.
-
-# --hints--
-
-You should have `pass` within the `except` block.
-
-```js
-assert.match(code, /pass/)
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
- board_string += row_empty
-
- if index < 8:
- if index % 3 == 2:
- board_string += f'╠═══{"╪═══"*2}{"╬═══"}{"╪═══"*2}{"╬═══"}{"╪═══"*2}╣\n'
- else:
- board_string += middle_lines
- else:
- board_string += lower_lines
-
- return board_string
-
- def find_empty_cell(self):
- for row, contents in enumerate(self.board):
- try:
- col = contents.index(0)
- return row, col
---fcc-editable-region--
- except ValueError:
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568bfb601a54ed5b367b44f.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568bfb601a54ed5b367b44f.md
deleted file mode 100644
index 0b8f71149cb..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568bfb601a54ed5b367b44f.md
+++ /dev/null
@@ -1,75 +0,0 @@
----
-id: 6568bfb601a54ed5b367b44f
-title: Step 35
-challengeType: 20
-dashedName: step-35
----
-
-# --description--
-
-If the loop completes without finding any empty cells, the method should return `None` to indicate that the sudoku board is filled.
-
-Return `None` outside the `for` loop block.
-
-# --hints--
-
-You should have `return None` outwith the `for` loop.
-
-```js
-({ test: () =>
- {
- const empty = __helpers.python.getDef(code, "find_empty_cell");
- const {function_body} = empty;
- const indent = function_body.match(/ +/)[0];
- const re = new RegExp(`^${indent}return\\s+None`, "m");
- assert.match(function_body, re);
- }
-})
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
- board_string += row_empty
-
- if index < 8:
- if index % 3 == 2:
- board_string += f'╠═══{"╪═══"*2}{"╬═══"}{"╪═══"*2}{"╬═══"}{"╪═══"*2}╣\n'
- else:
- board_string += lower_lines
-
- return board_string
-
-
---fcc-editable-region--
- def find_empty_cell(self):
- for row, contents in enumerate(self.board):
- try:
- col = contents.index(0)
- return row, col
- except ValueError:
- pass
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568bfd65322add674039bde.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568bfd65322add674039bde.md
deleted file mode 100644
index 335eb04b278..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568bfd65322add674039bde.md
+++ /dev/null
@@ -1,86 +0,0 @@
----
-id: 6568bfd65322add674039bde
-title: Step 36
-challengeType: 20
-dashedName: step-36
----
-
-# --description--
-
-Next, you will work on a method that checks if a given number can be inserted into a specified row of the sudoku board.
-
-Create a method named `valid_in_row`. It should take three parameters:
-
-- `self`: representing the instance of the class.
-- `row`: representing the row index.
-- `num`: representing the number to be checked.
-
-Also, don't forget to add the `pass` keyword in the function body.
-
-# --hints--
-
-You should have a `valid_in_row` method.
-
-```js
-const tCode = code.replace(/\r/g, '');
-const board = __helpers.python.getBlock("\n" + tCode, "class Board");
-const valid = __helpers.python.getDef(board.block_body, "valid_in_row");
-assert.exists(valid);
-```
-
-You should have `def valid_in_row(self, row, num)` within the `Board` class.
-
-```js
-const tCode = code.replace(/\r/g, '');
-const {function_parameters} = __helpers.python.getDef(tCode, "valid_in_row");
-assert.match(function_parameters, /self\s*,\s*row\s*,\s*num/);
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
- board_string += row_empty
-
- if index < 8:
- if index % 3 == 2:
- board_string += f'╠═══{"╪═══"*2}{"╬═══"}{"╪═══"*2}{"╬═══"}{"╪═══"*2}╣\n'
- else:
- board_string += middle_lines
- else:
- board_string += lower_lines
-
- return board_string
-
- def find_empty_cell(self):
- for row, contents in enumerate(self.board):
- try:
- col = contents.index(0)
- return row, col
- except ValueError:
- pass
- return None
---fcc-editable-region--
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568c0013b3b62d7617518c7.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568c0013b3b62d7617518c7.md
deleted file mode 100644
index d0c2c410f7d..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568c0013b3b62d7617518c7.md
+++ /dev/null
@@ -1,71 +0,0 @@
----
-id: 6568c0013b3b62d7617518c7
-title: Step 37
-challengeType: 20
-dashedName: step-37
----
-
-# --description--
-
-Create an expression that checks if the number is not already present in that row.
-
-You should check if the number(`num`) is not present in `self.board[row]`.
-
-# --hints--
-
-You should have `num not in self.board[row]` within `valid_in_row`.
-
-```js
-assert.match(code, /num\s+not\s+in\s+self\.board\s*\[\s*row\s*\]/)
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
- board_string += row_empty
-
- if index < 8:
- if index % 3 == 2:
- board_string += f'╠═══{"╪═══"*2}{"╬═══"}{"╪═══"*2}{"╬═══"}{"╪═══"*2}╣\n'
- else:
- board_string += middle_lines
- else:
- board_string += lower_lines
-
- return board_string
-
- def find_empty_cell(self):
- for row, contents in enumerate(self.board):
- try:
- col = contents.index(0)
- return row, col
- except ValueError:
- pass
- return None
-
---fcc-editable-region--
- def valid_in_row(self, row, num):
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568c024933423d85d5ed93c.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568c024933423d85d5ed93c.md
deleted file mode 100644
index 15cf62c49c0..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568c024933423d85d5ed93c.md
+++ /dev/null
@@ -1,76 +0,0 @@
----
-id: 6568c024933423d85d5ed93c
-title: Step 38
-challengeType: 20
-dashedName: step-38
----
-
-# --description--
-
-If `num` is not in the row, the expression evaluates to `True` and it means the number is valid for insertion.
-
-If `num` is in the row, the expression evaluates to `False` and insertion would violate the rules.
-
-Return the value from the expression you wrote in the previous step, so that the validity of a number can be checked.
-
-# --hints--
-
-You should have `return num not in self.board[row]` within `valid_in_row`.
-
-```js
-const tCode = code.replace(/\r/g, '');
-const valid = __helpers.python.getDef(tCode, "valid_in_row");
-const {function_body} = valid;
-assert.match(function_body, /return\s+num\s+not\s+in\s+self\.board\s*\[\s*row\s*\]/);
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
- board_string += row_empty
-
- if index < 8:
- if index % 3 == 2:
- board_string += f'╠═══{"╪═══"*2}{"╬═══"}{"╪═══"*2}{"╬═══"}{"╪═══"*2}╣\n'
- else:
- board_string += middle_lines
- else:
- board_string += lower_lines
-
- return board_string
-
- def find_empty_cell(self):
- for row, contents in enumerate(self.board):
- try:
- col = contents.index(0)
- return row, col
- except ValueError:
- pass
- return None
-
---fcc-editable-region--
- def valid_in_row(self, row, num):
- num not in self.board[row]
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568c073d5f37fd99ab2ab0c.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568c073d5f37fd99ab2ab0c.md
deleted file mode 100644
index 793f94c2cb4..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568c073d5f37fd99ab2ab0c.md
+++ /dev/null
@@ -1,89 +0,0 @@
----
-id: 6568c073d5f37fd99ab2ab0c
-title: Step 39
-challengeType: 20
-dashedName: step-39
----
-
-# --description--
-
-Next, you will create a method that checks if a number can be inserted in a specified column of the sudoku board by checking if the number is not already present in that column for any row.
-
-For that, within the `Board` class, create a method named `valid_in_col`.
-
-It should take three parameters:
-
-- `self`: representing the instance of the class.
-- `col`: representing the column index.
-- `num`: representing the number to be checked.
-
-# --hints--
-
-You should have a `valid_in_col` method.
-
-```js
-const tCode = code.replace(/\r/g, '');
-const {block_body} = __helpers.python.getBlock("\n" + tCode, "class Board");
-const valid = __helpers.python.getDef(block_body, "valid_in_col");
-assert.exists(valid);
-```
-
-The method should take three parameters: `self`, `col`, and `num`. Order matters
-
-```js
-const tCode = code.replace(/\r/g, '');
-const {function_parameters} = __helpers.python.getDef(tCode, "valid_in_col");
-assert.match(function_parameters, /self\s*,\s*col\s*,\s*num/);
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
- board_string += row_empty
-
- if index < 8:
- if index % 3 == 2:
- board_string += f'╠═══{"╪═══"*2}{"╬═══"}{"╪═══"*2}{"╬═══"}{"╪═══"*2}╣\n'
- else:
- board_string += middle_lines
- else:
- board_string += lower_lines
-
- return board_string
-
- def find_empty_cell(self):
- for row, contents in enumerate(self.board):
- try:
- col = contents.index(0)
- return row, col
- except ValueError:
- pass
- return None
-
- def valid_in_row(self, row, num):
- return num not in self.board[row]
---fcc-editable-region--
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568c0a5edddc3daa65d20b2.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568c0a5edddc3daa65d20b2.md
deleted file mode 100644
index 966465e7e8a..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6568c0a5edddc3daa65d20b2.md
+++ /dev/null
@@ -1,77 +0,0 @@
----
-id: 6568c0a5edddc3daa65d20b2
-title: Step 40
-challengeType: 20
-dashedName: step-40
----
-
-# --description--
-
-Now, you need to check if a given number is not equal to the number in the specified column of the current row.
-
-For that, first, iterate over the rows of the 2D list `self.board` using a `for` loop in the range `0` to `8`. Use `row` as the iteration variable.
-
-# --hints--
-
-You should have `for row in range(9)` within `valid_in_col`.
-
-```js
-const tCode = code.replace(/\r/g, '');
-const valid = __helpers.python.getDef(tCode, "valid_in_col");
-const {function_body} = valid;
-assert.match(function_body, /for\s+row\s+in\s+range\(\s*9\s*\)/);
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
- board_string += row_empty
-
- if index < 8:
- if index % 3 == 2:
- board_string += f'╠═══{"╪═══"*2}{"╬═══"}{"╪═══"*2}{"╬═══"}{"╪═══"*2}╣\n'
- else:
- board_string += middle_lines
- else:
- board_string += lower_lines
-
- return board_string
-
- def find_empty_cell(self):
- for row, contents in enumerate(self.board):
- try:
- col = contents.index(0)
- return row, col
- except ValueError:
- pass
- return None
-
- def valid_in_row(self, row, num):
- return num not in self.board[row]
-
---fcc-editable-region--
- def valid_in_col(self, col, num):
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569d83fe4dcc614c2ff971d.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569d83fe4dcc614c2ff971d.md
deleted file mode 100644
index 04c357639d1..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569d83fe4dcc614c2ff971d.md
+++ /dev/null
@@ -1,77 +0,0 @@
----
-id: 6569d83fe4dcc614c2ff971d
-title: Step 41
-challengeType: 20
-dashedName: step-41
----
-
-# --description--
-
-For each element in the specified column (`col`) of the current row (`row`), check whether the value at the current position in the 2D list is not equal to the provided `num`.
-
-# --hints--
-
-You should have `self.board[row][col] != num` within `valid_in_col`.
-
-```js
-const tCode = code.replace(/\r/g, '');
-const valid = __helpers.python.getDef(tCode, "valid_in_col");
-const {function_body} = valid;
-assert.match(function_body, /self\.board\s*\[\s*row\s*\]\s*\[\s*col\s*\]\s*!=\s*num/);
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
- board_string += row_empty
-
- if index < 8:
- if index % 3 == 2:
- board_string += f'╠═══{"╪═══"*2}{"╬═══"}{"╪═══"*2}{"╬═══"}{"╪═══"*2}╣\n'
- else:
- board_string += middle_lines
- else:
- board_string += lower_lines
-
- return board_string
-
- def find_empty_cell(self):
- for row, contents in enumerate(self.board):
- try:
- col = contents.index(0)
- return row, col
- except ValueError:
- pass
- return None
-
- def valid_in_row(self, row, num):
- return num not in self.board[row]
-
-
---fcc-editable-region--
- def valid_in_col(self, col, num):
-
---fcc-editable-region--
- for row in range(9)
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569d8a4b8d85515cbb1ce72.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569d8a4b8d85515cbb1ce72.md
deleted file mode 100644
index 987439b3597..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569d8a4b8d85515cbb1ce72.md
+++ /dev/null
@@ -1,87 +0,0 @@
----
-id: 6569d8a4b8d85515cbb1ce72
-title: Step 42
-challengeType: 20
-dashedName: step-42
----
-
-# --description--
-
-This expression generates a list of boolean values representing whether the condition `self.board[row][col] != num` is `True` or `False` for each element in the specified column across all rows.
-
-Pass this generator expression to the `all()` function to check if all the elements in the column are different from `num`.
-
-Recall that the syntax of the `all` function is as follows:
-
-```py
-all(
- self.board[row][col] != num
- for row in range(9)
- )
-```
-
-# --hints--
-
-You should have `all(self.board[row][col] != num for row in range(9))` within `valid_in_col`.
-
-```js
-const tCode = code.replace(/\r/g, '');
-const valid = __helpers.python.getDef(tCode, "valid_in_col");
-const {function_body} = valid;
-assert.match(function_body, /all\s*\(\s*self\.board\s*\[\s*row\s*\]\s*\[\s*col\s*\]\s*!=\s*num\s+for\s+row\s+in\s+range\s*\(\s*9\s*\)\s*\)/);
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
- board_string += row_empty
-
- if index < 8:
- if index % 3 == 2:
- board_string += f'╠═══{"╪═══"*2}{"╬═══"}{"╪═══"*2}{"╬═══"}{"╪═══"*2}╣\n'
- else:
- board_string += middle_lines
- else:
- board_string += lower_lines
-
- return board_string
-
- def find_empty_cell(self):
- for row, contents in enumerate(self.board):
- try:
- col = contents.index(0)
- return row, col
- except ValueError:
- pass
- return None
-
- def valid_in_row(self, row, num):
- return num not in self.board[row]
-
---fcc-editable-region--
- def valid_in_col(self, col, num):
- self.board[row][col] != num
- for row in range(9)
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569d946293d4f185e32e2da.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569d946293d4f185e32e2da.md
deleted file mode 100644
index 6d564ac5635..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569d946293d4f185e32e2da.md
+++ /dev/null
@@ -1,78 +0,0 @@
----
-id: 6569d946293d4f185e32e2da
-title: Step 43
-challengeType: 20
-dashedName: step-43
----
-
-# --description--
-
-Return the result of the `all()` function call.
-
-# --hints--
-
-You should return the result of the `all()` function call.
-
-```js
-const tCode = code.replace(/\r/g, '');
-const valid = __helpers.python.getDef(tCode, "valid_in_col");
-const {function_body} = valid;
-assert.match(function_body, /return\s+all\s*\(\s*self\.board\s*\[\s*row\s*\]\s*\[\s*col\s*\]\s*!=\s*num\s+for\s+row\s+in\s+range\s*\(\s*9\s*\)\s*\)/m);
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
- board_string += row_empty
-
- if index < 8:
- if index % 3 == 2:
- board_string += f'╠═══{"╪═══"*2}{"╬═══"}{"╪═══"*2}{"╬═══"}{"╪═══"*2}╣\n'
- else:
- board_string += middle_lines
- else:
- board_string += lower_lines
-
- return board_string
-
- def find_empty_cell(self):
- for row, contents in enumerate(self.board):
- try:
- col = contents.index(0)
- return row, col
- except ValueError:
- pass
- return None
-
- def valid_in_row(self, row, num):
- return num not in self.board[row]
-
---fcc-editable-region--
- def valid_in_col(self, col, num):
- all(
- self.board[row][col] != num
- for row in range(9)
- )
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569d98303af38193149b66e.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569d98303af38193149b66e.md
deleted file mode 100644
index 66cc72277e3..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569d98303af38193149b66e.md
+++ /dev/null
@@ -1,96 +0,0 @@
----
-id: 6569d98303af38193149b66e
-title: Step 44
-challengeType: 20
-dashedName: step-44
----
-
-# --description--
-
-Next, you will work on a method that checks if a number can be inserted in the 3x3 square.
-
-Inside the `Board` class, create a method named `valid_in_square`.
-
-It should take four parameters:
-
-- `self`: represents the instance of the class.
-- `row`: represents the row index.
-- `col`: represents the column index.
-- `num`: represents the number to be checked.
-
-# --hints--
-
-You should have a `valid_in_square` method.
-
-```js
-const tCode = code.replace(/\r/g, '');
-const {block_body} = __helpers.python.getBlock("\n" + tCode, "class Board");
-const valid = __helpers.python.getDef(block_body, "valid_in_square");
-assert.exists(valid);
-```
-
-The method should take four parameters: `self`, `row`, `col`, and `num`. Don't forget to add `pass` in the function body. Order matters.
-
-```js
-const tCode = code.replace(/\r/g, '');
-const {function_parameters} = __helpers.python.getDef(tCode, "valid_in_square");
-assert.match(function_parameters, /self\s*,\s*row\s*,\s*col\s*,\s*num/);
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
- board_string += row_empty
-
- if index < 8:
- if index % 3 == 2:
- board_string += f'╠═══{"╪═══"*2}{"╬═══"}{"╪═══"*2}{"╬═══"}{"╪═══"*2}╣\n'
- else:
- board_string += middle_lines
- else:
- board_string += lower_lines
-
- return board_string
-
- def find_empty_cell(self):
- for row, contents in enumerate(self.board):
- try:
- col = contents.index(0)
- return row, col
- except ValueError:
- pass
- return None
-
- def valid_in_row(self, row, num):
- return num not in self.board[row]
-
- def valid_in_col(self, col, num):
- return all(
- self.board[row][col] != num
- for row in range(9)
- )
---fcc-editable-region--
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569d9dfd53db11b176d2963.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569d9dfd53db11b176d2963.md
deleted file mode 100644
index 8e97286836d..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569d9dfd53db11b176d2963.md
+++ /dev/null
@@ -1,86 +0,0 @@
----
-id: 6569d9dfd53db11b176d2963
-title: Step 45
-challengeType: 20
-dashedName: step-45
----
-
-# --description--
-
-Now you need to calculate the starting row index for the 3x3 block in the board grid.
-
-For that, ensure that the starting row index for each 3x3 block is a multiple of 3.
-
-This can be achieved by this mathematical operation: `(row // 3) * 3`.
-Assign the result of this calculation to `row_start`.
-
-# --hints--
-
-You should assign the result of `(row // 3) * 3` to `row_start`.
-
-```js
-const tCode = code.replace(/\r/g, '');
-const valid = __helpers.python.getDef(tCode, "valid_in_square");
-const {function_body} = valid;
-assert.match(function_body, /row_start\s*=\s*\(\s*row\s*\/\/\s*3\s*\)\s*\*\s*3/);
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
- board_string += row_empty
-
- if index < 8:
- if index % 3 == 2:
- board_string += f'╠═══{"╪═══"*2}{"╬═══"}{"╪═══"*2}{"╬═══"}{"╪═══"*2}╣\n'
- else:
- board_string += middle_lines
- else:
- board_string += lower_lines
-
- return board_string
-
- def find_empty_cell(self):
- for row, contents in enumerate(self.board):
- try:
- col = contents.index(0)
- return row, col
- except ValueError:
- pass
- return None
-
- def valid_in_row(self, row, num):
- return num not in self.board[row]
-
- def valid_in_col(self, col, num):
- return all(
- self.board[row][col] != num
- for row in range(9)
- )
-
---fcc-editable-region--
- def valid_in_square(self, row, col, num):
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569da02e7e2641be14ff922.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569da02e7e2641be14ff922.md
deleted file mode 100644
index 4457d8b903c..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569da02e7e2641be14ff922.md
+++ /dev/null
@@ -1,87 +0,0 @@
----
-id: 6569da02e7e2641be14ff922
-title: Step 46
-challengeType: 20
-dashedName: step-46
----
-
-# --description--
-
-Next, you need to calculate the starting column index for the 3x3 block in the board grid.
-
-For that, ensure that the starting row index for each 3x3 block is a multiple of 3.
-
-Similar to the previous step, this can be achieved by this mathematical operation: `(col // 3) * 3`.
-Assign the result of this calculation to `col_start`.
-
-# --hints--
-
-You should assign the result of `(col // 3) * 3` to `col_start`.
-
-```js
-const tCode = code.replace(/\r/g, '');
-const valid = __helpers.python.getDef(tCode, "valid_in_square");
-const {function_body} = valid;
-assert.match(function_body, /col_start\s*=\s*\(\s*col\s*\/\/\s*3\s*\)\s*\*\s*3/);
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
- board_string += row_empty
-
- if index < 8:
- if index % 3 == 2:
- board_string += f'╠═══{"╪═══"*2}{"╬═══"}{"╪═══"*2}{"╬═══"}{"╪═══"*2}╣\n'
- else:
- board_string += middle_lines
- else:
- board_string += lower_lines
-
- return board_string
-
- def find_empty_cell(self):
- for row, contents in enumerate(self.board):
- try:
- col = contents.index(0)
- return row, col
- except ValueError:
- pass
- return None
-
- def valid_in_row(self, row, num):
- return num not in self.board[row]
-
- def valid_in_col(self, col, num):
- return all(
- self.board[row][col] != num
- for row in range(9)
- )
-
---fcc-editable-region--
- def valid_in_square(self, row, col, num):
- row_start = (row // 3) * 3
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569de93a5340b202667deda.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569de93a5340b202667deda.md
deleted file mode 100644
index fa36204c87d..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569de93a5340b202667deda.md
+++ /dev/null
@@ -1,83 +0,0 @@
----
-id: 6569de93a5340b202667deda
-title: Step 47
-challengeType: 20
-dashedName: step-47
----
-
-# --description--
-
-Create a `for` loop that starts at `row_start` and ends just before `row_start + 3`. You can use the `range()` function to generate the sequence. As an example, if `row_start` is `3`, the loop will iterate over the numbers `3`, `4`, and `5`.
-
-# --hints--
-
-You should have `for row_no in range(row_start, row_start + 3):` within `valid_in_square`.
-
-```js
-const tCode = code.replace(/\r/g, '');
-const valid = __helpers.python.getDef(tCode, "valid_in_square");
-const {function_body} = valid;
-assert.match(function_body, /for\s+(\w+)\s+in\s+range\s*\(\s*row_start\s*,\s*row_start\s*\+\s*3\s*\)\s*:/);
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
- board_string += row_empty
-
- if index < 8:
- if index % 3 == 2:
- board_string += f'╠═══{"╪═══"*2}{"╬═══"}{"╪═══"*2}{"╬═══"}{"╪═══"*2}╣\n'
- else:
- board_string += middle_lines
- else:
- board_string += lower_lines
-
- return board_string
-
- def find_empty_cell(self):
- for row, contents in enumerate(self.board):
- try:
- col = contents.index(0)
- return row, col
- except ValueError:
- pass
- return None
-
- def valid_in_row(self, row, num):
- return num not in self.board[row]
-
- def valid_in_col(self, col, num):
- return all(
- self.board[row][col] != num
- for row in range(9)
- )
-
---fcc-editable-region--
- def valid_in_square(self, row, col, num):
- row_start = (row // 3) * 3
- col_start=(col // 3) * 3
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569def38470282151f873ce.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569def38470282151f873ce.md
deleted file mode 100644
index 4596cda03b4..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569def38470282151f873ce.md
+++ /dev/null
@@ -1,84 +0,0 @@
----
-id: 6569def38470282151f873ce
-title: Step 48
-challengeType: 20
-dashedName: step-48
----
-
-# --description--
-
-Inside the loop created in the previous step, nest another `for` loop to iterate over a sequence of three elements starting at `col_start`. Again, use the `range()` function to generate the sequence.
-
-# --hints--
-
-You should have `for col_no in range(col_start, col_start + 3):` within `valid_in_square`.
-
-```js
-const tCode = code.replace(/\r/g, '');
-const valid = __helpers.python.getDef(tCode, "valid_in_square");
-const {function_body} = valid;
-assert.match(function_body, /for\s+(\w+)\s+in\s+range\s*\(\s*col_start\s*,\s*col_start\s*\+\s*3\s*\)\s*:/);
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
- board_string += row_empty
-
- if index < 8:
- if index % 3 == 2:
- board_string += f'╠═══{"╪═══"*2}{"╬═══"}{"╪═══"*2}{"╬═══"}{"╪═══"*2}╣\n'
- else:
- board_string += middle_lines
- else:
- board_string += lower_lines
-
- return board_string
-
- def find_empty_cell(self):
- for row, contents in enumerate(self.board):
- try:
- col = contents.index(0)
- return row, col
- except ValueError:
- pass
- return None
-
- def valid_in_row(self, row, num):
- return num not in self.board[row]
-
- def valid_in_col(self, col, num):
- return all(
- self.board[row][col] != num
- for row in range(9)
- )
-
- def valid_in_square(self, row, col, num):
- row_start = (row // 3) * 3
- col_start=(col // 3) * 3
---fcc-editable-region--
- for row_no in range(row_start, row_start + 3):
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569df1d6fb83d22623b38c5.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569df1d6fb83d22623b38c5.md
deleted file mode 100644
index 9f989410878..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569df1d6fb83d22623b38c5.md
+++ /dev/null
@@ -1,87 +0,0 @@
----
-id: 6569df1d6fb83d22623b38c5
-title: Step 49
-challengeType: 20
-dashedName: step-49
----
-
-# --description--
-
-The next step is to check if the specified number (`num`) is already present in the current cell of the 3x3 square.
-
-Inside the inner `for` loop, create an `if` statement that checks if the current cell in `self.board` is equal to `num`.
-
-# --hints--
-
-You should have `if self.board[row_no][col_no] == num` within `valid_in_square`.
-
-```js
-const tCode = code.replace(/\r/g, '');
-const innerFor = __helpers.python.getBlock(tCode, "for col_no in range(col_start, col_start + 3)");
-const {block_body} = innerFor;
-assert.match(block_body, /if\s+self\.board\s*\[\s*row_no\s*\]\s*\[\s*col_no\s*\]\s*==\s*num\s*\:/);
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
- board_string += row_empty
-
- if index < 8:
- if index % 3 == 2:
- board_string += f'╠═══{"╪═══"*2}{"╬═══"}{"╪═══"*2}{"╬═══"}{"╪═══"*2}╣\n'
- else:
- board_string += middle_lines
- else:
- board_string += lower_lines
-
- return board_string
-
- def find_empty_cell(self):
- for row, contents in enumerate(self.board):
- try:
- col = contents.index(0)
- return row, col
- except ValueError:
- pass
- return None
-
- def valid_in_row(self, row, num):
- return num not in self.board[row]
-
- def valid_in_col(self, col, num):
- return all(
- self.board[row][col] != num
- for row in range(9)
- )
-
- def valid_in_square(self, row, col, num):
- row_start = (row // 3) * 3
- col_start=(col // 3) * 3
- for row_no in range(row_start, row_start + 3):
---fcc-editable-region--
- for col_no in range(col_start, col_start + 3):
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569df6916294723e01f0035.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569df6916294723e01f0035.md
deleted file mode 100644
index 2983662af27..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569df6916294723e01f0035.md
+++ /dev/null
@@ -1,86 +0,0 @@
----
-id: 6569df6916294723e01f0035
-title: Step 50
-challengeType: 20
-dashedName: step-50
----
-
-# --description--
-
-Inside the `if` block, return `False` to indicate that the number cannot be inserted into the square.
-
-# --hints--
-
-You should return `False` inside the `if` block.
-
-```js
-const tCode = code.replace(/\r/g, '');
-const innerIf = __helpers.python.getBlock(tCode, "if self.board[row_no][col_no] == num");
-const {block_body} = innerIf;
-assert.match(block_body, /return\s+False/);
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
- board_string += row_empty
-
- if index < 8:
- if index % 3 == 2:
- board_string += f'╠═══{"╪═══"*2}{"╬═══"}{"╪═══"*2}{"╬═══"}{"╪═══"*2}╣\n'
- else:
- board_string += middle_lines
- else:
- board_string += lower_lines
-
- return board_string
-
- def find_empty_cell(self):
- for row, contents in enumerate(self.board):
- try:
- col = contents.index(0)
- return row, col
- except ValueError:
- pass
- return None
-
- def valid_in_row(self, row, num):
- return num not in self.board[row]
-
- def valid_in_col(self, col, num):
- return all(
- self.board[row][col] != num
- for row in range(9)
- )
-
- def valid_in_square(self, row, col, num):
- row_start = (row // 3) * 3
- col_start=(col // 3) * 3
- for row_no in range(row_start, row_start + 3):
- for col_no in range(col_start, col_start + 3):
---fcc-editable-region--
- if self.board[row_no][col_no] == num:
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569df9e20f74a251d482c5d.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569df9e20f74a251d482c5d.md
deleted file mode 100644
index a36c45118b2..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569df9e20f74a251d482c5d.md
+++ /dev/null
@@ -1,91 +0,0 @@
----
-id: 6569df9e20f74a251d482c5d
-title: Step 51
-challengeType: 20
-dashedName: step-51
----
-
-# --description--
-
-If the number is not present, it can be inserted into the square without violating the rules of sudoku.
-
-Return `True` in that case, and pay attention to the indentation.
-
-# --hints--
-
-You should have `return True` outwith the outermost `for` loop.
-
-```js
-const tCode = code.replace(/\r/g, '');
-const valid = __helpers.python.getDef(tCode, "valid_in_square");
-const {function_body} = valid;
-const indent = function_body.match(/ +/)[0];
-const re = new RegExp(`^${indent}return\\s+True`, "m");
-assert.match(function_body, re);
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
- board_string += row_empty
-
- if index < 8:
- if index % 3 == 2:
- board_string += f'╠═══{"╪═══"*2}{"╬═══"}{"╪═══"*2}{"╬═══"}{"╪═══"*2}╣\n'
- else:
- board_string += middle_lines
- else:
- board_string += lower_lines
-
- return board_string
-
- def find_empty_cell(self):
- for row, contents in enumerate(self.board):
- try:
- col = contents.index(0)
- return row, col
- except ValueError:
- pass
- return None
-
- def valid_in_row(self, row, num):
- return num not in self.board[row]
-
- def valid_in_col(self, col, num):
- return all(
- self.board[row][col] != num
- for row in range(9)
- )
-
---fcc-editable-region--
- def valid_in_square(self, row, col, num):
- row_start = (row // 3) * 3
- col_start=(col // 3) * 3
- for row_no in range(row_start, row_start + 3):
- for col_no in range(col_start, col_start + 3):
- if self.board[row_no][col_no] == num:
- return False
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569dffeee007f26d2b56d46.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569dffeee007f26d2b56d46.md
deleted file mode 100644
index 43eedb08999..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569dffeee007f26d2b56d46.md
+++ /dev/null
@@ -1,104 +0,0 @@
----
-id: 6569dffeee007f26d2b56d46
-title: Step 52
-challengeType: 20
-dashedName: step-52
----
-
-# --description--
-
-Within the `Board` class, create another method `is_valid`.
-It would take three parameters:
-
-- `self` (representing the instance of the class),
-- `empty` (a tuple representing the row and column indices of an empty cell)
-- `num` (representing the number to be checked).
-
-This method checks if a given number is a valid choice for an empty cell in the sudoku board by validating its compatibility with the row, column, and 3x3 square of the specified empty cell.
-
-# --hints--
-
-The method name should be `is_valid`.
-
-```js
-const tCode = code.replace(/\r/g, '');
-const board = __helpers.python.getBlock("\n" + tCode, "class Board");
-const valid = __helpers.python.getDef(board.block_body, "is_valid");
-assert.exists(valid);
-```
-
-The method should take three parameters: `self`, `empty`, and `num`. Order matters
-
-```js
-const tCode = code.replace(/\r/g, '');
-const valid = __helpers.python.getDef(tCode, "is_valid");
-const {function_parameters} = valid;
-assert.match(function_parameters, /self\s*,\s*empty\s*,\s*num/);
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
- board_string += row_empty
-
- if index < 8:
- if index % 3 == 2:
- board_string += f'╠═══{"╪═══"*2}{"╬═══"}{"╪═══"*2}{"╬═══"}{"╪═══"*2}╣\n'
- else:
- board_string += middle_lines
- else:
- board_string += lower_lines
-
- return board_string
-
- def find_empty_cell(self):
- for row, contents in enumerate(self.board):
- try:
- col = contents.index(0)
- return row, col
- except ValueError:
- pass
- return None
-
- def valid_in_row(self, row, num):
- return num not in self.board[row]
-
- def valid_in_col(self, col, num):
- return all(
- self.board[row][col] != num
- for row in range(9)
- )
-
- def valid_in_square(self, row, col, num):
- row_start = (row // 3) * 3
- col_start=(col // 3) * 3
- for row_no in range(row_start, row_start + 3):
- for col_no in range(col_start, col_start + 3):
- if self.board[row_no][col_no] == num:
- return False
- return True
---fcc-editable-region--
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569e2a01a97b231862ba2ff.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569e2a01a97b231862ba2ff.md
deleted file mode 100644
index 26b4a74ecc4..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569e2a01a97b231862ba2ff.md
+++ /dev/null
@@ -1,89 +0,0 @@
----
-id: 6569e2a01a97b231862ba2ff
-title: Step 53
-challengeType: 20
-dashedName: step-53
----
-
-# --description--
-
-Inside the method, unpack the `empty` tuple into `row` and `col`.
-
-# --hints--
-
-You should have `row, col = empty` within `is_valid`.
-
-```js
-const tCode = code.replace(/\r/g, '');
-const {function_body} = __helpers.python.getDef(tCode, "is_valid");
-assert.match(function_body, /row\s*,\s*col\s*=\s*empty/);
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
- board_string += row_empty
-
- if index < 8:
- if index % 3 == 2:
- board_string += f'╠═══{"╪═══"*2}{"╬═══"}{"╪═══"*2}{"╬═══"}{"╪═══"*2}╣\n'
- else:
- board_string += middle_lines
- else:
- board_string += lower_lines
-
- return board_string
-
- def find_empty_cell(self):
- for row, contents in enumerate(self.board):
- try:
- col = contents.index(0)
- return row, col
- except ValueError:
- pass
- return None
-
- def valid_in_row(self, row, num):
- return num not in self.board[row]
-
- def valid_in_col(self, col, num):
- return all(
- self.board[row][col] != num
- for row in range(9)
- )
-
- def valid_in_square(self, row, col, num):
- row_start = (row // 3) * 3
- col_start=(col // 3) * 3
- for row_no in range(row_start, row_start + 3):
- for col_no in range(col_start, col_start + 3):
- if self.board[row_no][col_no] == num:
- return False
- return True
-
---fcc-editable-region--
- def is_valid(self, empty, num):
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569e2e1944fe7329ab21c7f.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569e2e1944fe7329ab21c7f.md
deleted file mode 100644
index 7d0edae2ab9..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569e2e1944fe7329ab21c7f.md
+++ /dev/null
@@ -1,91 +0,0 @@
----
-id: 6569e2e1944fe7329ab21c7f
-title: Step 54
-challengeType: 20
-dashedName: step-54
----
-
-# --description--
-
-Check if the number is valid for insertion in the specified row by calling `self.valid_in_row(row, num)`
-Assign the result to `valid_in_row`
-
-# --hints--
-
-You should have `valid_in_row = self.valid_in_row(row, num)` within `is_valid`.
-
-```js
-const tCode = code.replace(/\r/g, '');
-const {function_body} = __helpers.python.getDef(tCode, "is_valid");
-assert.match(function_body, /valid_in_row\s*=\s*self\.valid_in_row\s*\(\s*row\s*,\s*num\s*\)/);
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
- board_string += row_empty
-
- if index < 8:
- if index % 3 == 2:
- board_string += f'╠═══{"╪═══"*2}{"╬═══"}{"╪═══"*2}{"╬═══"}{"╪═══"*2}╣\n'
- else:
- board_string += middle_lines
- else:
- board_string += lower_lines
-
- return board_string
-
- def find_empty_cell(self):
- for row, contents in enumerate(self.board):
- try:
- col = contents.index(0)
- return row, col
- except ValueError:
- pass
- return None
-
- def valid_in_row(self, row, num):
- return num not in self.board[row]
-
- def valid_in_col(self, col, num):
- return all(
- self.board[row][col] != num
- for row in range(9)
- )
-
- def valid_in_square(self, row, col, num):
- row_start = (row // 3) * 3
- col_start=(col // 3) * 3
- for row_no in range(row_start, row_start + 3):
- for col_no in range(col_start, col_start + 3):
- if self.board[row_no][col_no] == num:
- return False
- return True
-
---fcc-editable-region--
- def is_valid(self, empty, num):
- row, col = empty
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569e309feb5d333867a034a.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569e309feb5d333867a034a.md
deleted file mode 100644
index 3fc6babf606..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569e309feb5d333867a034a.md
+++ /dev/null
@@ -1,93 +0,0 @@
----
-id: 6569e309feb5d333867a034a
-title: Step 55
-challengeType: 20
-dashedName: step-55
----
-
-# --description--
-
-Check if the number is valid for insertion in the specified column by calling `self.valid_in_col(col, num)`
-
-Assign the result to `valid_in_col`.
-
-# --hints--
-
-You should have `valid_in_col = self.valid_in_col(col, num)` within `is_valid`.
-
-```js
-const tCode = code.replace(/\r/g, '');
-const {function_body} = __helpers.python.getDef(tCode, "is_valid");
-assert.match(function_body, /valid_in_col\s*=\s*self\.valid_in_col\s*\(\s*col\s*,\s*num\s*\)/);
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
- board_string += row_empty
-
- if index < 8:
- if index % 3 == 2:
- board_string += f'╠═══{"╪═══"*2}{"╬═══"}{"╪═══"*2}{"╬═══"}{"╪═══"*2}╣\n'
- else:
- board_string += middle_lines
- else:
- board_string += lower_lines
-
- return board_string
-
- def find_empty_cell(self):
- for row, contents in enumerate(self.board):
- try:
- col = contents.index(0)
- return row, col
- except ValueError:
- pass
- return None
-
- def valid_in_row(self, row, num):
- return num not in self.board[row]
-
- def valid_in_col(self, col, num):
- return all(
- self.board[row][col] != num
- for row in range(9)
- )
-
- def valid_in_square(self, row, col, num):
- row_start = (row // 3) * 3
- col_start=(col // 3) * 3
- for row_no in range(row_start, row_start + 3):
- for col_no in range(col_start, col_start + 3):
- if self.board[row_no][col_no] == num:
- return False
- return True
-
---fcc-editable-region--
- def is_valid(self, empty, num):
- row, col = empty
- valid_in_row = self.valid_in_row(row, num)
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569e33a708a3834f6d4879b.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569e33a708a3834f6d4879b.md
deleted file mode 100644
index fe91d3660b6..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569e33a708a3834f6d4879b.md
+++ /dev/null
@@ -1,94 +0,0 @@
----
-id: 6569e33a708a3834f6d4879b
-title: Step 56
-challengeType: 20
-dashedName: step-56
----
-
-# --description--
-
-Check if the number is valid for insertion in the 3x3 square that contains the specified cell by calling `self.valid_in_square(row, col, num)`.
-
-Assign the result to `valid_in_square`.
-
-# --hints--
-
-You should have `valid_in_square = self.valid_in_square(row, col, num)` within `is_valid`.
-
-```js
-const tCode = code.replace(/\r/g, '');
-const {function_body} = __helpers.python.getDef(tCode, "is_valid");
-assert.match(function_body, /valid_in_square\s*=\s*self\.valid_in_square\s*\(\s*row\s*,\s*col\s*,\s*num\s*\)/);
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
- board_string += row_empty
-
- if index < 8:
- if index % 3 == 2:
- board_string += f'╠═══{"╪═══"*2}{"╬═══"}{"╪═══"*2}{"╬═══"}{"╪═══"*2}╣\n'
- else:
- board_string += middle_lines
- else:
- board_string += lower_lines
-
- return board_string
-
- def find_empty_cell(self):
- for row, contents in enumerate(self.board):
- try:
- col = contents.index(0)
- return row, col
- except ValueError:
- pass
- return None
-
- def valid_in_row(self, row, num):
- return num not in self.board[row]
-
- def valid_in_col(self, col, num):
- return all(
- self.board[row][col] != num
- for row in range(9)
- )
-
- def valid_in_square(self, row, col, num):
- row_start = (row // 3) * 3
- col_start=(col // 3) * 3
- for row_no in range(row_start, row_start + 3):
- for col_no in range(col_start, col_start + 3):
- if self.board[row_no][col_no] == num:
- return False
- return True
-
---fcc-editable-region--
- def is_valid(self, empty, num):
- row, col = empty
- valid_in_row = self.valid_in_row(row, num)
- valid_in_col = self.valid_in_col(col, num)
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569e37ec28e853628f18a86.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569e37ec28e853628f18a86.md
deleted file mode 100644
index f11c18328cc..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569e37ec28e853628f18a86.md
+++ /dev/null
@@ -1,93 +0,0 @@
----
-id: 6569e37ec28e853628f18a86
-title: Step 57
-challengeType: 20
-dashedName: step-57
----
-
-# --description--
-
-Insert `valid_in_row`, `valid_in_col`, and `valid_in_square` into a list and pass it to the `all()` function. This will verify that all the function calls return `True`.
-
-# --hints--
-
-You should have `all([valid_in_row, valid_in_col, valid_in_square])` within `is_valid`.
-
-```js
-const tCode = code.replace(/\r/g, '');
-const {function_body} = __helpers.python.getDef(tCode, "is_valid");
-assert.match(function_body, /all\s*\(\s*\[\s*valid_in_row\s*,\s*valid_in_col\s*,\s*valid_in_square\s*\]\s*\)/);
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
-
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
- board_string += row_empty
-
- if index < 8:
- if index % 3 == 2:
- board_string += f'╠═══{"╪═══"*2}{"╬═══"}{"╪═══"*2}{"╬═══"}{"╪═══"*2}╣\n'
- else:
- board_string += middle_lines
- else:
- board_string += lower_lines
-
- return board_string
-
- def find_empty_cell(self):
- for row, contents in enumerate(self.board):
- try:
- col = contents.index(0)
- return row, col
- except ValueError:
- pass
- return None
-
- def valid_in_row(self, row, num):
- return num not in self.board[row]
-
- def valid_in_col(self, col, num):
- return all(
- self.board[row][col] != num
- for row in range(9)
- )
-
- def valid_in_square(self, row, col, num):
- row_start = (row // 3) * 3
- col_start=(col // 3) * 3
- for row_no in range(row_start, row_start + 3):
- for col_no in range(col_start, col_start + 3):
- if self.board[row_no][col_no] == num:
- return False
- return True
-
---fcc-editable-region--
- def is_valid(self, empty, num):
- row, col = empty
- valid_in_row = self.valid_in_row(row, num)
- valid_in_col = self.valid_in_col(col, num)
- valid_in_square = self.valid_in_square(row, col, num)
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569e3a134fea0371fa008de.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569e3a134fea0371fa008de.md
deleted file mode 100644
index 572d2ae8f39..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569e3a134fea0371fa008de.md
+++ /dev/null
@@ -1,91 +0,0 @@
----
-id: 6569e3a134fea0371fa008de
-title: Step 58
-challengeType: 20
-dashedName: step-58
----
-
-# --description--
-
-Now, return the result of the `all()` call.
-
-# --hints--
-
-You should return the result of the `all()` call.
-
-```js
-({ test: () => assert.match(code, /^\s{8}return\s+all\s*\(\s*\[\s*(valid_in_)(row|col|square)\s*,\s*\1(?!\2)(row|col|square)\s*,\s*\1(?!\2|\3)(row|col|square)\s*\]\s*\)/m) })
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
- board_string += row_empty
-
- if index < 8:
- if index % 3 == 2:
- board_string += f'╠═══{"╪═══"*2}{"╬═══"}{"╪═══"*2}{"╬═══"}{"╪═══"*2}╣\n'
- else:
- board_string += middle_lines
- else:
- board_string += lower_lines
-
- return board_string
-
- def find_empty_cell(self):
- for row, contents in enumerate(self.board):
- try:
- col = contents.index(0)
- return row, col
- except ValueError:
- pass
- return None
-
- def valid_in_row(self, row, num):
- return num not in self.board[row]
-
- def valid_in_col(self, col, num):
- return all(
- self.board[row][col] != num
- for row in range(9)
- )
-
- def valid_in_square(self, row, col, num):
- row_start = (row // 3) * 3
- col_start=(col // 3) * 3
- for row_no in range(row_start, row_start + 3):
- for col_no in range(col_start, col_start + 3):
- if self.board[row_no][col_no] == num:
- return False
- return True
-
---fcc-editable-region--
- def is_valid(self, empty, num):
- row, col = empty
- valid_in_row = self.valid_in_row(row, num)
- valid_in_col = self.valid_in_col(col, num)
- valid_in_square = self.valid_in_square(row, col, num)
- all([valid_in_row, valid_in_col, valid_in_square])
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569e3d1418b373839a0aa7b.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569e3d1418b373839a0aa7b.md
deleted file mode 100644
index b773b1552c8..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569e3d1418b373839a0aa7b.md
+++ /dev/null
@@ -1,105 +0,0 @@
----
-id: 6569e3d1418b373839a0aa7b
-title: Step 59
-challengeType: 20
-dashedName: step-59
----
-
-# --description--
-
-Next, you will work on a method that attempts to solve the sudoku in-place, meaning it would modify the existing sudoku board rather than creating a new one.
-
-Within the board class, create a method `solver` that takes one argument(`self`, representing the instance of the class).
-
-# --hints--
-
-Your method should be named `solver`.
-
-```js
-const tCode = code.replace(/\r/g, "");
-const board = __helpers.python.getBlock("\n" + tCode, "class Board");
-const solver = __helpers.python.getDef(board.block_body, "solver");
-assert.exists(solver);
-```
-
-You should add the parameter `self` to the method.
-
-```js
-const tCode = code.replace(/\r/g, "");
-const { function_parameters } = __helpers.python.getDef(tCode, "solver");
-assert.match(function_parameters, /self/);
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
- board_string += row_empty
-
- if index < 8:
- if index % 3 == 2:
- board_string += f'╠═══{"╪═══"*2}{"╬═══"}{"╪═══"*2}{"╬═══"}{"╪═══"*2}╣\n'
- else:
- board_string += middle_lines
- else:
- board_string += lower_lines
-
- return board_string
-
- def find_empty_cell(self):
- for row, contents in enumerate(self.board):
- try:
- col = contents.index(0)
- return row, col
- except ValueError:
- pass
- return None
-
- def valid_in_row(self, row, num):
- return num not in self.board[row]
-
- def valid_in_col(self, col, num):
- return all(
- self.board[row][col] != num
- for row in range(9)
- )
-
- def valid_in_square(self, row, col, num):
- row_start = (row // 3) * 3
- col_start=(col // 3) * 3
- for row_no in range(row_start, row_start + 3):
- for col_no in range(col_start, col_start + 3):
- if self.board[row_no][col_no] == num:
- return False
- return True
-
- def is_valid(self, empty, num):
- row, col = empty
- valid_in_row = self.valid_in_row(row, num)
- valid_in_col = self.valid_in_col(col, num)
- valid_in_square = self.valid_in_square(row, col, num)
- return all([valid_in_row, valid_in_col, valid_in_square])
---fcc-editable-region--
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569e41657a9923953aa7d3c.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569e41657a9923953aa7d3c.md
deleted file mode 100644
index 473bed3d4a2..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569e41657a9923953aa7d3c.md
+++ /dev/null
@@ -1,102 +0,0 @@
----
-id: 6569e41657a9923953aa7d3c
-title: Step 60
-challengeType: 20
-dashedName: step-60
----
-
-# --description--
-
-First, check if there are any empty cells left in the sudoku board.
-
-Use the `find_empty_cell` function call on `self`.
-
-Also, use the walrus operator (:=) to assign the result of `self.find_empty_cell()` to the variable `next_empty`.
-
-By using the walrus operator, you can combine the assignment and the conditional check into a single line, making the code more concise and readable.
-
-# --hints--
-
-You should have `next_empty := self.find_empty_cell()` within the `solver` method.
-
-```js
-const tCode = code.replace(/\r/g, '');
-const {function_body} = __helpers.python.getDef(tCode, "solver");
-assert.match(function_body, /next_empty\s*:=\s*self\.find_empty_cell\(\s*\)/);
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
- board_string += row_empty
-
- if index < 8:
- if index % 3 == 2:
- board_string += f'╠═══{"╪═══"*2}{"╬═══"}{"╪═══"*2}{"╬═══"}{"╪═══"*2}╣\n'
- else:
- board_string += middle_lines
- else:
- board_string += lower_lines
-
- return board_string
-
- def find_empty_cell(self):
- for row, contents in enumerate(self.board):
- try:
- col = contents.index(0)
- return row, col
- except ValueError:
- pass
- return None
-
- def valid_in_row(self, row, num):
- return num not in self.board[row]
-
- def valid_in_col(self, col, num):
- return all(
- self.board[row][col] != num
- for row in range(9)
- )
-
- def valid_in_square(self, row, col, num):
- row_start = (row // 3) * 3
- col_start=(col // 3) * 3
- for row_no in range(row_start, row_start + 3):
- for col_no in range(col_start, col_start + 3):
- if self.board[row_no][col_no] == num:
- return False
- return True
-
- def is_valid(self, empty, num):
- row, col = empty
- valid_in_row = self.valid_in_row(row, num)
- valid_in_col = self.valid_in_col(col, num)
- valid_in_square = self.valid_in_square(row, col, num)
- return all([valid_in_row, valid_in_col, valid_in_square])
-
---fcc-editable-region--
- def solver(self):
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569e481e67f123ad25c5d20.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569e481e67f123ad25c5d20.md
deleted file mode 100644
index d0d28f4596d..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569e481e67f123ad25c5d20.md
+++ /dev/null
@@ -1,96 +0,0 @@
----
-id: 6569e481e67f123ad25c5d20
-title: Step 61
-challengeType: 20
-dashedName: step-61
----
-
-# --description--
-
-Place the condition in an `if` statement and check if it is `None`.
-
-# --hints--
-
-You should have `if (next_empty := self.find_empty_cell()) is None:` within `solver`.
-
-```js
-const tCode = code.replace(/\r/g, '');
-const {function_body} = __helpers.python.getDef(tCode, "solver");
-assert.match(function_body, /if\s*\(\s*next_empty\s*:=\s*self\.find_empty_cell\(\s*\)\s*\)\s*is\s*None:/)
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
- board_string += row_empty
-
- if index < 8:
- if index % 3 == 2:
- board_string += f'╠═══{"╪═══"*2}{"╬═══"}{"╪═══"*2}{"╬═══"}{"╪═══"*2}╣\n'
- else:
- board_string += middle_lines
- else:
- board_string += lower_lines
-
- return board_string
-
- def find_empty_cell(self):
- for row, contents in enumerate(self.board):
- try:
- col = contents.index(0)
- return row, col
- except ValueError:
- pass
- return None
-
- def valid_in_row(self, row, num):
- return num not in self.board[row]
-
- def valid_in_col(self, col, num):
- return all(
- self.board[row][col] != num
- for row in range(9)
- )
-
- def valid_in_square(self, row, col, num):
- row_start = (row // 3) * 3
- col_start=(col // 3) * 3
- for row_no in range(row_start, row_start + 3):
- for col_no in range(col_start, col_start + 3):
- if self.board[row_no][col_no] == num:
- return False
- return True
-
- def is_valid(self, empty, num):
- row, col = empty
- valid_in_row = self.valid_in_row(row, num)
- valid_in_col = self.valid_in_col(col, num)
- valid_in_square = self.valid_in_square(row, col, num)
- return all([valid_in_row, valid_in_col, valid_in_square])
-
---fcc-editable-region--
- def solver(self):
- next_empty := self.find_empty_cell()
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569f6b48716b5402504e216.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569f6b48716b5402504e216.md
deleted file mode 100644
index bed8de977d7..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569f6b48716b5402504e216.md
+++ /dev/null
@@ -1,97 +0,0 @@
----
-id: 6569f6b48716b5402504e216
-title: Step 62
-challengeType: 20
-dashedName: step-62
----
-
-# --description--
-
-If there are no empty cells (i.e., `next_empty` is `None`), the puzzle is solved. So, return `True`.
-
-# --hints--
-
-You should return `True` within the `if` statement.
-
-```js
-const tCode = code.replace(/\r/g, '');
-const {function_body} = __helpers.python.getDef(tCode, "solver");
-assert.match(function_body, /return\s*True/);
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
- board_string += row_empty
-
- if index < 8:
- if index % 3 == 2:
- board_string += f'╠═══{"╪═══"*2}{"╬═══"}{"╪═══"*2}{"╬═══"}{"╪═══"*2}╣\n'
- else:
- board_string += middle_lines
- else:
- board_string += lower_lines
-
- return board_string
-
- def find_empty_cell(self):
- for row, contents in enumerate(self.board):
- try:
- col = contents.index(0)
- return row, col
- except ValueError:
- pass
- return None
-
- def valid_in_row(self, row, num):
- return num not in self.board[row]
-
- def valid_in_col(self, col, num):
- return all(
- self.board[row][col] != num
- for row in range(9)
- )
-
- def valid_in_square(self, row, col, num):
- row_start = (row // 3) * 3
- col_start=(col // 3) * 3
- for row_no in range(row_start, row_start + 3):
- for col_no in range(col_start, col_start + 3):
- if self.board[row_no][col_no] == num:
- return False
- return True
-
- def is_valid(self, empty, num):
- row, col = empty
- valid_in_row = self.valid_in_row(row, num)
- valid_in_col = self.valid_in_col(col, num)
- valid_in_square = self.valid_in_square(row, col, num)
- return all([valid_in_row, valid_in_col, valid_in_square])
-
---fcc-editable-region--
- def solver(self):
- if (next_empty := self.find_empty_cell()) is None:
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569f6ebe558bd4136da96cc.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569f6ebe558bd4136da96cc.md
deleted file mode 100644
index 9df6911a790..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569f6ebe558bd4136da96cc.md
+++ /dev/null
@@ -1,98 +0,0 @@
----
-id: 6569f6ebe558bd4136da96cc
-title: Step 63
-challengeType: 20
-dashedName: step-63
----
-
-# --description--
-
-Create an `else` block to cater the case where there are empty cells and the puzzle is unsolved.
-
-# --hints--
-
-You should have an `else` clause within `solver`.
-
-```js
-const tCode = code.replace(/\r/g, '');
-const {function_body} = __helpers.python.getDef(tCode, "solver");
-assert.match(function_body, /else:/);
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
- board_string += row_empty
-
- if index < 8:
- if index % 3 == 2:
- board_string += f'╠═══{"╪═══"*2}{"╬═══"}{"╪═══"*2}{"╬═══"}{"╪═══"*2}╣\n'
- else:
- board_string += middle_lines
- else:
- board_string += lower_lines
-
- return board_string
-
- def find_empty_cell(self):
- for row, contents in enumerate(self.board):
- try:
- col = contents.index(0)
- return row, col
- except ValueError:
- pass
- return None
-
- def valid_in_row(self, row, num):
- return num not in self.board[row]
-
- def valid_in_col(self, col, num):
- return all(
- self.board[row][col] != num
- for row in range(9)
- )
-
- def valid_in_square(self, row, col, num):
- row_start = (row // 3) * 3
- col_start=(col // 3) * 3
- for row_no in range(row_start, row_start + 3):
- for col_no in range(col_start, col_start + 3):
- if self.board[row_no][col_no] == num:
- return False
- return True
-
- def is_valid(self, empty, num):
- row, col = empty
- valid_in_row = self.valid_in_row(row, num)
- valid_in_col = self.valid_in_col(col, num)
- valid_in_square = self.valid_in_square(row, col, num)
- return all([valid_in_row, valid_in_col, valid_in_square])
-
---fcc-editable-region--
- def solver(self):
- if (next_empty := self.find_empty_cell()) is None:
- return True
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569f70a66ccdc42097ca051.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569f70a66ccdc42097ca051.md
deleted file mode 100644
index 6eaa3de4c2b..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569f70a66ccdc42097ca051.md
+++ /dev/null
@@ -1,100 +0,0 @@
----
-id: 6569f70a66ccdc42097ca051
-title: Step 64
-challengeType: 20
-dashedName: step-64
----
-
-# --description--
-
-If there are still empty cells, create a loop in the `else` block that iterates over numbers from `1` to `9` (inclusive). Your loop should use the variable named `guess`.
-
-# --hints--
-
-You should have `for guess in range(1,10):` within the `else` block.
-
-```js
-const tCode = code.replace(/\r/g, '');
-const {function_body} = __helpers.python.getDef(tCode, "solver");
-const {block_body} = __helpers.python.getBlock(function_body, "else");
-assert.match(block_body, /for\s+\w+\s+in\s+range\(\s*1\s*,\s*10\s*\)/);
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
- board_string += row_empty
-
- if index < 8:
- if index % 3 == 2:
- board_string += f'╠═══{"╪═══"*2}{"╬═══"}{"╪═══"*2}{"╬═══"}{"╪═══"*2}╣\n'
- else:
- board_string += middle_lines
- else:
- board_string += lower_lines
-
- return board_string
-
- def find_empty_cell(self):
- for row, contents in enumerate(self.board):
- try:
- col = contents.index(0)
- return row, col
- except ValueError:
- pass
- return None
-
- def valid_in_row(self, row, num):
- return num not in self.board[row]
-
- def valid_in_col(self, col, num):
- return all(
- self.board[row][col] != num
- for row in range(9)
- )
-
- def valid_in_square(self, row, col, num):
- row_start = (row // 3) * 3
- col_start=(col // 3) * 3
- for row_no in range(row_start, row_start + 3):
- for col_no in range(col_start, col_start + 3):
- if self.board[row_no][col_no] == num:
- return False
- return True
-
- def is_valid(self, empty, num):
- row, col = empty
- valid_in_row = self.valid_in_row(row, num)
- valid_in_col = self.valid_in_col(col, num)
- valid_in_square = self.valid_in_square(row, col, num)
- return all([valid_in_row, valid_in_col, valid_in_square])
-
---fcc-editable-region--
- def solver(self):
- if (next_empty := self.find_empty_cell()) is None:
- return True
- else:
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569f770fd7dc443d6293095.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569f770fd7dc443d6293095.md
deleted file mode 100644
index 27a4244405c..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569f770fd7dc443d6293095.md
+++ /dev/null
@@ -1,101 +0,0 @@
----
-id: 6569f770fd7dc443d6293095
-title: Step 65
-challengeType: 20
-dashedName: step-65
----
-
-# --description--
-
-For each number (`guess`), check if the number is a valid choice for the current empty cell using `self.is_valid(next_empty, guess)`.
-
-# --hints--
-
-You should have `self.is_valid(next_empty, guess)` within the `for` loop.
-
-```js
-const tCode = code.replace(/\r/g, '');
-const {function_body} = __helpers.python.getDef(tCode, "solver");
-const {block_body} = __helpers.python.getBlock(function_body, "for guess in range(1, 10)");
-assert.match(block_body, /self\.is_valid\(\s*next_empty\s*,\s*guess\s*\)/);
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
- board_string += row_empty
-
- if index < 8:
- if index % 3 == 2:
- board_string += f'╠═══{"╪═══"*2}{"╬═══"}{"╪═══"*2}{"╬═══"}{"╪═══"*2}╣\n'
- else:
- board_string += middle_lines
- else:
- board_string += lower_lines
-
- return board_string
-
- def find_empty_cell(self):
- for row, contents in enumerate(self.board):
- try:
- col = contents.index(0)
- return row, col
- except ValueError:
- pass
- return None
-
- def valid_in_row(self, row, num):
- return num not in self.board[row]
-
- def valid_in_col(self, col, num):
- return all(
- self.board[row][col] != num
- for row in range(9)
- )
-
- def valid_in_square(self, row, col, num):
- row_start = (row // 3) * 3
- col_start=(col // 3) * 3
- for row_no in range(row_start, row_start + 3):
- for col_no in range(col_start, col_start + 3):
- if self.board[row_no][col_no] == num:
- return False
- return True
-
- def is_valid(self, empty, num):
- row, col = empty
- valid_in_row = self.valid_in_row(row, num)
- valid_in_col = self.valid_in_col(col, num)
- valid_in_square = self.valid_in_square(row, col, num)
- return all([valid_in_row, valid_in_col, valid_in_square])
-
---fcc-editable-region--
- def solver(self):
- if (next_empty := self.find_empty_cell()) is None:
- return True
- else:
- for guess in range(1, 10):
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569f7c7f6954944d207775f.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569f7c7f6954944d207775f.md
deleted file mode 100644
index 7b8349869ea..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569f7c7f6954944d207775f.md
+++ /dev/null
@@ -1,104 +0,0 @@
----
-id: 6569f7c7f6954944d207775f
-title: Step 66
-challengeType: 20
-dashedName: step-66
----
-
-# --description--
-
-If the guess is valid, the method updates the sudoku board with the guess by assigning `guess` to the cell specified by next_empty.
-
-Unpack the `next_empty` tuple to `row, col`.
-
-# --hints--
-
-You should have `row, col = next_empty` within the innermost `if` statement.
-
-```js
-const tCode = code.replace(/\r/g, '');
-const {function_body} = __helpers.python.getDef(tCode, "solver");
-const {block_body} = __helpers.python.getBlock(function_body, "if self.is_valid(next_empty, guess)");
-assert.match(block_body, /row\s*,\s*col\s*=\s*next_empty/);
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
- board_string += row_empty
-
- if index < 8:
- if index % 3 == 2:
- board_string += f'╠═══{"╪═══"*2}{"╬═══"}{"╪═══"*2}{"╬═══"}{"╪═══"*2}╣\n'
- else:
- board_string += middle_lines
- else:
- board_string += lower_lines
-
- return board_string
-
- def find_empty_cell(self):
- for row, contents in enumerate(self.board):
- try:
- col = contents.index(0)
- return row, col
- except ValueError:
- pass
- return None
-
- def valid_in_row(self, row, num):
- return num not in self.board[row]
-
- def valid_in_col(self, col, num):
- return all(
- self.board[row][col] != num
- for row in range(9)
- )
-
- def valid_in_square(self, row, col, num):
- row_start = (row // 3) * 3
- col_start=(col // 3) * 3
- for row_no in range(row_start, row_start + 3):
- for col_no in range(col_start, col_start + 3):
- if self.board[row_no][col_no] == num:
- return False
- return True
-
- def is_valid(self, empty, num):
- row, col = empty
- valid_in_row = self.valid_in_row(row, num)
- valid_in_col = self.valid_in_col(col, num)
- valid_in_square = self.valid_in_square(row, col, num)
- return all([valid_in_row, valid_in_col, valid_in_square])
-
---fcc-editable-region--
- def solver(self):
- if (next_empty := self.find_empty_cell()) is None:
- return True
- else:
- for guess in range(1, 10):
- if self.is_valid(next_empty, guess):
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569f7f2fa74c045e95676ac.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569f7f2fa74c045e95676ac.md
deleted file mode 100644
index af65f4ff6b2..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569f7f2fa74c045e95676ac.md
+++ /dev/null
@@ -1,103 +0,0 @@
----
-id: 6569f7f2fa74c045e95676ac
-title: Step 67
-challengeType: 20
-dashedName: step-67
----
-
-# --description--
-
-Access the cell at the given row and column in the sudoku board, and assign it the value of `guess`.
-
-# --hints--
-
-You should have `self.board[row][col] = guess` within the innermost `if` block.
-
-```js
-const tCode = code.replace(/\r/g, '');
-const {function_body} = __helpers.python.getDef(tCode, "solver");
-const {block_body} = __helpers.python.getBlock(function_body, "if self.is_valid(next_empty, guess)");
-assert.match(block_body, /self\.board\s*\[\s*row\s*\]\s*\[\s*col\s*\]\s*=\s*guess/);
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
- board_string += row_empty
-
- if index < 8:
- if index % 3 == 2:
- board_string += f'╠═══{"╪═══"*2}{"╬═══"}{"╪═══"*2}{"╬═══"}{"╪═══"*2}╣\n'
- else:
- board_string += middle_lines
- else:
- board_string += lower_lines
-
- return board_string
-
- def find_empty_cell(self):
- for row, contents in enumerate(self.board):
- try:
- col = contents.index(0)
- return row, col
- except ValueError:
- pass
- return None
-
- def valid_in_row(self, row, num):
- return num not in self.board[row]
-
- def valid_in_col(self, col, num):
- return all(
- self.board[row][col] != num
- for row in range(9)
- )
-
- def valid_in_square(self, row, col, num):
- row_start = (row // 3) * 3
- col_start=(col // 3) * 3
- for row_no in range(row_start, row_start + 3):
- for col_no in range(col_start, col_start + 3):
- if self.board[row_no][col_no] == num:
- return False
- return True
-
- def is_valid(self, empty, num):
- row, col = empty
- valid_in_row = self.valid_in_row(row, num)
- valid_in_col = self.valid_in_col(col, num)
- valid_in_square = self.valid_in_square(row, col, num)
- return all([valid_in_row, valid_in_col, valid_in_square])
-
- def solver(self):
- if (next_empty := self.find_empty_cell()) is None:
- return True
- else:
- for guess in range(1, 10):
---fcc-editable-region--
- if self.is_valid(next_empty, guess):
- row, col = next_empty
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569fa5b9d507748bf4ec722.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569fa5b9d507748bf4ec722.md
deleted file mode 100644
index 131c4203ec6..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569fa5b9d507748bf4ec722.md
+++ /dev/null
@@ -1,104 +0,0 @@
----
-id: 6569fa5b9d507748bf4ec722
-title: Step 68
-challengeType: 20
-dashedName: step-68
----
-
-# --description--
-
-While staying in the `if` block, recursively call `self.solver()` to try to solve the rest of the sudoku.
-
-# --hints--
-
-You should have `self.solver()` within the innermost `if` block.
-
-```js
-const tCode = code.replace(/\r/g, '');
-const {function_body} = __helpers.python.getDef(tCode, "solver");
-const {block_body} = __helpers.python.getBlock(function_body, "if self.is_valid(next_empty, guess)");
-assert.match(block_body, /self\.solver\(\s*\)/);
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
- board_string += row_empty
-
- if index < 8:
- if index % 3 == 2:
- board_string += f'╠═══{"╪═══"*2}{"╬═══"}{"╪═══"*2}{"╬═══"}{"╪═══"*2}╣\n'
- else:
- board_string += middle_lines
- else:
- board_string += lower_lines
-
- return board_string
-
- def find_empty_cell(self):
- for row, contents in enumerate(self.board):
- try:
- col = contents.index(0)
- return row, col
- except ValueError:
- pass
- return None
-
- def valid_in_row(self, row, num):
- return num not in self.board[row]
-
- def valid_in_col(self, col, num):
- return all(
- self.board[row][col] != num
- for row in range(9)
- )
-
- def valid_in_square(self, row, col, num):
- row_start = (row // 3) * 3
- col_start=(col // 3) * 3
- for row_no in range(row_start, row_start + 3):
- for col_no in range(col_start, col_start + 3):
- if self.board[row_no][col_no] == num:
- return False
- return True
-
- def is_valid(self, empty, num):
- row, col = empty
- valid_in_row = self.valid_in_row(row, num)
- valid_in_col = self.valid_in_col(col, num)
- valid_in_square = self.valid_in_square(row, col, num)
- return all([valid_in_row, valid_in_col, valid_in_square])
-
- def solver(self):
- if (next_empty := self.find_empty_cell()) is None:
- return True
- else:
- for guess in range(1, 10):
---fcc-editable-region--
- if self.is_valid(next_empty, guess):
- row, col = next_empty
- self.board[row][col] = guess
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569fa85d8f9ed49c8dfb37d.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569fa85d8f9ed49c8dfb37d.md
deleted file mode 100644
index 946cd2d9c0c..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569fa85d8f9ed49c8dfb37d.md
+++ /dev/null
@@ -1,115 +0,0 @@
----
-id: 6569fa85d8f9ed49c8dfb37d
-title: Step 69
-challengeType: 20
-dashedName: step-69
----
-
-# --description--
-
-If the recursive call to `self.solver()` returns `True`, it means the sudoku is solved.
-
-If the recursive call returns `True`, return `True` from the method.
-
-# --hints--
-
-You should have `if self.solver():` within the innermost `if` block.
-
-```js
-const tCode = code.replace(/\r/g, '');
-const {function_body} = __helpers.python.getDef(tCode, "solver");
-const {block_body} = __helpers.python.getBlock(function_body, "if self.is_valid(next_empty, guess)");
-assert.match(block_body, /if\s+self\.solver\(\s*\):/);
-```
-
-You should have `return True` within `if self.solver():`.
-
-```js
-const tCode = code.replace(/\r/g, '');
-const {function_body} = __helpers.python.getDef(tCode, "solver");
-const {block_body} = __helpers.python.getBlock(function_body, "if self.solver()");
-assert.match(block_body, /return\s+True/);
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
- board_string += row_empty
-
- if index < 8:
- if index % 3 == 2:
- board_string += f'╠═══{"╪═══"*2}{"╬═══"}{"╪═══"*2}{"╬═══"}{"╪═══"*2}╣\n'
- else:
- board_string += middle_lines
- else:
- board_string += lower_lines
-
- return board_string
-
- def find_empty_cell(self):
- for row, contents in enumerate(self.board):
- try:
- col = contents.index(0)
- return row, col
- except ValueError:
- pass
- return None
-
- def valid_in_row(self, row, num):
- return num not in self.board[row]
-
- def valid_in_col(self, col, num):
- return all(
- self.board[row][col] != num
- for row in range(9)
- )
-
- def valid_in_square(self, row, col, num):
- row_start = (row // 3) * 3
- col_start=(col // 3) * 3
- for row_no in range(row_start, row_start + 3):
- for col_no in range(col_start, col_start + 3):
- if self.board[row_no][col_no] == num:
- return False
- return True
-
- def is_valid(self, empty, num):
- row, col = empty
- valid_in_row = self.valid_in_row(row, num)
- valid_in_col = self.valid_in_col(col, num)
- valid_in_square = self.valid_in_square(row, col, num)
- return all([valid_in_row, valid_in_col, valid_in_square])
-
- def solver(self):
- if (next_empty := self.find_empty_cell()) is None:
- return True
- else:
- for guess in range(1, 10):
---fcc-editable-region--
- if self.is_valid(next_empty, guess):
- row, col = next_empty
- self.board[row][col] = guess
- self.solver()
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569fabbfe1c094ad838ec4c.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569fabbfe1c094ad838ec4c.md
deleted file mode 100644
index 24367dc9c31..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569fabbfe1c094ad838ec4c.md
+++ /dev/null
@@ -1,108 +0,0 @@
----
-id: 6569fabbfe1c094ad838ec4c
-title: Step 70
-challengeType: 20
-dashedName: step-70
----
-
-# --description--
-
-If `self.solver()` returns `False`, this means the `guess` led to an unsolvable sudoku.
-
-Outside the innermost `if` block, undo the guess by setting the cell value back to `0`.
-
-# --hints--
-
-You should have `self.board[row][col] = 0` outside the innermost `if` block.
-
-```js
-const tCode = code.replace(/\r/g, '');
-const {function_body} = __helpers.python.getDef(tCode, "solver");
-const {block_body} = __helpers.python.getBlock(function_body, "if self.is_valid(next_empty, guess)");
-assert.match(block_body, /self\.board\s*\[\s*row\s*\]\s*\[\s*col\s*\]\s*=\s*0/);
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
- board_string += row_empty
-
- if index < 8:
- if index % 3 == 2:
- board_string += f'╠═══{"╪═══"*2}{"╬═══"}{"╪═══"*2}{"╬═══"}{"╪═══"*2}╣\n'
- else:
- board_string += middle_lines
- else:
- board_string += lower_lines
-
- return board_string
-
- def find_empty_cell(self):
- for row, contents in enumerate(self.board):
- try:
- col = contents.index(0)
- return row, col
- except ValueError:
- pass
- return None
-
- def valid_in_row(self, row, num):
- return num not in self.board[row]
-
- def valid_in_col(self, col, num):
- return all(
- self.board[row][col] != num
- for row in range(9)
- )
-
- def valid_in_square(self, row, col, num):
- row_start = (row // 3) * 3
- col_start=(col // 3) * 3
- for row_no in range(row_start, row_start + 3):
- for col_no in range(col_start, col_start + 3):
- if self.board[row_no][col_no] == num:
- return False
- return True
-
- def is_valid(self, empty, num):
- row, col = empty
- valid_in_row = self.valid_in_row(row, num)
- valid_in_col = self.valid_in_col(col, num)
- valid_in_square = self.valid_in_square(row, col, num)
- return all([valid_in_row, valid_in_col, valid_in_square])
-
- def solver(self):
- if (next_empty := self.find_empty_cell()) is None:
- return True
- else:
- for guess in range(1, 10):
---fcc-editable-region--
- if self.is_valid(next_empty, guess):
- row, col = next_empty
- self.board[row][col] = guess
- if self.solver():
- return True
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569fbbfee025a4e850b6eaf.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569fbbfee025a4e850b6eaf.md
deleted file mode 100644
index 461e0a29539..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569fbbfee025a4e850b6eaf.md
+++ /dev/null
@@ -1,106 +0,0 @@
----
-id: 6569fbbfee025a4e850b6eaf
-title: Step 71
-challengeType: 20
-dashedName: step-71
----
-
-# --description--
-
-Make your method return `False` when none of the guesses leads to a solution.
-
-# --hints--
-
-You should return `False` within the outermost `else` block.
-
-```js
-const tCode = code.replace(/\r/g, '');
-const {function_body} = __helpers.python.getDef(tCode, "solver");
-assert.match(function_body, /return\s+False/);
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
- board_string += row_empty
-
- if index < 8:
- if index % 3 == 2:
- board_string += f'╠═══{"╪═══"*2}{"╬═══"}{"╪═══"*2}{"╬═══"}{"╪═══"*2}╣\n'
- else:
- board_string += middle_lines
- else:
- board_string += lower_lines
-
- return board_string
-
- def find_empty_cell(self):
- for row, contents in enumerate(self.board):
- try:
- col = contents.index(0)
- return row, col
- except ValueError:
- pass
- return None
-
- def valid_in_row(self, row, num):
- return num not in self.board[row]
-
- def valid_in_col(self, col, num):
- return all(
- self.board[row][col] != num
- for row in range(9)
- )
-
- def valid_in_square(self, row, col, num):
- row_start = (row // 3) * 3
- col_start=(col // 3) * 3
- for row_no in range(row_start, row_start + 3):
- for col_no in range(col_start, col_start + 3):
- if self.board[row_no][col_no] == num:
- return False
- return True
-
- def is_valid(self, empty, num):
- row, col = empty
- valid_in_row = self.valid_in_row(row, num)
- valid_in_col = self.valid_in_col(col, num)
- valid_in_square = self.valid_in_square(row, col, num)
- return all([valid_in_row, valid_in_col, valid_in_square])
-
---fcc-editable-region--
- def solver(self):
- if (next_empty := self.find_empty_cell()) is None:
- return True
- else:
- for guess in range(1, 10):
- if self.is_valid(next_empty, guess):
- row, col = next_empty
- self.board[row][col] = guess
- if self.solver():
- return True
- self.board[row][col] = 0
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569fc21837cab5029d82e26.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569fc21837cab5029d82e26.md
deleted file mode 100644
index f601bb35c6d..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569fc21837cab5029d82e26.md
+++ /dev/null
@@ -1,128 +0,0 @@
----
-id: 6569fc21837cab5029d82e26
-title: Step 72
-challengeType: 20
-dashedName: step-72
----
-
-# --description--
-
-Outside the class definition, create a function to print and solve the sudoku board.
-
-Name it `solve_sudoku`. It should take a single parameter `board` that is a 2D list.
-
-# --hints--
-
-You should not have a method `solve_sudoku` within the `Board` class.
-
-```js
-const tCode = code.replace(/\r/g, '');
-const {block_body} = __helpers.python.getBlock("\n" + tCode, "class Board");
-const solve = __helpers.python.getDef(block_body, "solve_sudoku");
-assert.notExists(solve);
-```
-
-You should have a function named `solve_sudoku`.
-
-```js
-const tCode = code.replace(/\r/g, '');
-const solve = __helpers.python.getDef(tCode, "solve_sudoku");
-assert.exists(solve);
-```
-
-The method should take a single `board` parameter.
-
-```js
-const tCode = code.replace(/\r/g, '');
-const {function_parameters} = __helpers.python.getDef(tCode, "solve_sudoku");
-assert.match(function_parameters, /board/);
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
- board_string += row_empty
-
- if index < 8:
- if index % 3 == 2:
- board_string += f'╠═══{"╪═══"*2}{"╬═══"}{"╪═══"*2}{"╬═══"}{"╪═══"*2}╣\n'
- else:
- board_string += middle_lines
- else:
- board_string += lower_lines
-
- return board_string
-
- def find_empty_cell(self):
- for row, contents in enumerate(self.board):
- try:
- col = contents.index(0)
- return row, col
- except ValueError:
- pass
- return None
-
- def valid_in_row(self, row, num):
- return num not in self.board[row]
-
- def valid_in_col(self, col, num):
- return all(
- self.board[row][col] != num
- for row in range(9)
- )
-
- def valid_in_square(self, row, col, num):
- row_start = (row // 3) * 3
- col_start=(col // 3) * 3
- for row_no in range(row_start, row_start + 3):
- for col_no in range(col_start, col_start + 3):
- if self.board[row_no][col_no] == num:
- return False
- return True
-
- def is_valid(self, empty, num):
- row, col = empty
- valid_in_row = self.valid_in_row(row, num)
- valid_in_col = self.valid_in_col(col, num)
- valid_in_square = self.valid_in_square(row, col, num)
- return all([valid_in_row, valid_in_col, valid_in_square])
-
- def solver(self):
- if (next_empty := self.find_empty_cell()) is None:
- return True
- else:
- for guess in range(1, 10):
- if self.is_valid(next_empty, guess):
- row, col = next_empty
- self.board[row][col] = guess
- if self.solver():
- return True
- self.board[row][col] = 0
-
- return False
---fcc-editable-region--
-
---fcc-editable-region--
-
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569fc63a404c8519d918095.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569fc63a404c8519d918095.md
deleted file mode 100644
index e54c1ced4c8..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569fc63a404c8519d918095.md
+++ /dev/null
@@ -1,112 +0,0 @@
----
-id: 6569fc63a404c8519d918095
-title: Step 73
-challengeType: 20
-dashedName: step-73
----
-
-# --description--
-
-Inside the `solve_sudoku` function, create a `gameboard` variable and assign it an instance of the `Board` class passing `board` as the argument.
-
-This initializes the sudoku board with the given initial state.
-
-# --hints--
-
-You should have `gameboard = Board(board)` within the `solve_sudoku` function.
-
-```js
-const tCode = code.replace(/\r/g, '');
-const {function_body} = __helpers.python.getDef(tCode, "solve_sudoku");
-assert.match(function_body, /gameboard\s*=\s*Board\(\s*board\s*\)/);
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
- board_string += row_empty
-
- if index < 8:
- if index % 3 == 2:
- board_string += f'╠═══{"╪═══"*2}{"╬═══"}{"╪═══"*2}{"╬═══"}{"╪═══"*2}╣\n'
- else:
- board_string += middle_lines
- else:
- board_string += lower_lines
-
- return board_string
-
- def find_empty_cell(self):
- for row, contents in enumerate(self.board):
- try:
- col = contents.index(0)
- return row, col
- except ValueError:
- pass
- return None
-
- def valid_in_row(self, row, num):
- return num not in self.board[row]
-
- def valid_in_col(self, col, num):
- return all(
- self.board[row][col] != num
- for row in range(9)
- )
-
- def valid_in_square(self, row, col, num):
- row_start = (row // 3) * 3
- col_start=(col // 3) * 3
- for row_no in range(row_start, row_start + 3):
- for col_no in range(col_start, col_start + 3):
- if self.board[row_no][col_no] == num:
- return False
- return True
-
- def is_valid(self, empty, num):
- row, col = empty
- valid_in_row = self.valid_in_row(row, num)
- valid_in_col = self.valid_in_col(col, num)
- valid_in_square = self.valid_in_square(row, col, num)
- return all([valid_in_row, valid_in_col, valid_in_square])
-
- def solver(self):
- if (next_empty := self.find_empty_cell()) is None:
- return True
- else:
- for guess in range(1, 10):
- if self.is_valid(next_empty, guess):
- row, col = next_empty
- self.board[row][col] = guess
- if self.solver():
- return True
- self.board[row][col] = 0
-
- return False
-
---fcc-editable-region--
-def solve_sudoku(board):
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569fca3cd7a9f52f322a298.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569fca3cd7a9f52f322a298.md
deleted file mode 100644
index 1b33937fc3e..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569fca3cd7a9f52f322a298.md
+++ /dev/null
@@ -1,113 +0,0 @@
----
-id: 6569fca3cd7a9f52f322a298
-title: Step 74
-challengeType: 20
-dashedName: step-74
----
-
-# --description--
-
-Now, add another `print()` call passing `gameboard` as the argument to print the current state of the sudoku board.
-
-Add a `print` call to print the following: `f'\nPuzzle to solve:\n{gameboard}'`.
-
-# --hints--
-
-You should have `print(f'\nPuzzle to solve:\n{gameboard}')` within the `solve_sudoku` function.
-
-```js
-const tCode = code.replace(/\r/g, '');
-const {function_body} = __helpers.python.getDef(tCode, "solve_sudoku");
-assert.match(function_body, /print\(\s*f'\\nPuzzle to solve:\\n\{gameboard\}'\s*\)/);
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
- board_string += row_empty
-
- if index < 8:
- if index % 3 == 2:
- board_string += f'╠═══{"╪═══"*2}{"╬═══"}{"╪═══"*2}{"╬═══"}{"╪═══"*2}╣\n'
- else:
- board_string += middle_lines
- else:
- board_string += lower_lines
-
- return board_string
-
- def find_empty_cell(self):
- for row, contents in enumerate(self.board):
- try:
- col = contents.index(0)
- return row, col
- except ValueError:
- pass
- return None
-
- def valid_in_row(self, row, num):
- return num not in self.board[row]
-
- def valid_in_col(self, col, num):
- return all(
- self.board[row][col] != num
- for row in range(9)
- )
-
- def valid_in_square(self, row, col, num):
- row_start = (row // 3) * 3
- col_start=(col // 3) * 3
- for row_no in range(row_start, row_start + 3):
- for col_no in range(col_start, col_start + 3):
- if self.board[row_no][col_no] == num:
- return False
- return True
-
- def is_valid(self, empty, num):
- row, col = empty
- valid_in_row = self.valid_in_row(row, num)
- valid_in_col = self.valid_in_col(col, num)
- valid_in_square = self.valid_in_square(row, col, num)
- return all([valid_in_row, valid_in_col, valid_in_square])
-
- def solver(self):
- if (next_empty := self.find_empty_cell()) is None:
- return True
- else:
- for guess in range(1, 10):
- if self.is_valid(next_empty, guess):
- row, col = next_empty
- self.board[row][col] = guess
- if self.solver():
- return True
- self.board[row][col] = 0
-
- return False
-
---fcc-editable-region--
-def solve_sudoku(board):
- gameboard = Board(board)
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569fd01dab2ea547d98f093.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569fd01dab2ea547d98f093.md
deleted file mode 100644
index 959c06c3cd4..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569fd01dab2ea547d98f093.md
+++ /dev/null
@@ -1,124 +0,0 @@
----
-id: 6569fd01dab2ea547d98f093
-title: Step 75
-challengeType: 20
-dashedName: step-75
----
-
-# --description--
-
-Create an `if` statement that checks if the `solver()` method call from the `gameboard` object returns `True`.
-
-Then, add a `print()` call inside the `if` block passing the following string: `'\nSolved puzzle:'`.
-
-# --hints--
-
-You should have `if gameboard.solver():` within the `solve_sudoku` function.
-
-```js
-const tCode = code.replace(/\r/g, '');
-const {function_body} = __helpers.python.getDef(tCode, "solve_sudoku");
-const ifBlock = __helpers.python.getBlock(function_body, /if\s+gameboard\.solver\s*\(\s*\)\s*/);
-assert.exists(ifBlock);
-```
-
-You should have `print('\nSolved puzzle:')` within the `if` block.
-
-```js
-const tCode = code.replace(/\r/g, '');
-const {function_body} = __helpers.python.getDef(tCode, "solve_sudoku");
-const {block_body} = __helpers.python.getBlock(function_body, /if\s+gameboard\.solver\s*\(\s*\)\s*/);
-assert.match(block_body, /print\s*\(\s*("|')\\nSolved puzzle:\1\s*\)/);
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
- board_string += row_empty
-
- if index < 8:
- if index % 3 == 2:
- board_string += f'╠═══{"╪═══"*2}{"╬═══"}{"╪═══"*2}{"╬═══"}{"╪═══"*2}╣\n'
- else:
- board_string += middle_lines
- else:
- board_string += lower_lines
-
- return board_string
-
- def find_empty_cell(self):
- for row, contents in enumerate(self.board):
- try:
- col = contents.index(0)
- return row, col
- except ValueError:
- pass
- return None
-
- def valid_in_row(self, row, num):
- return num not in self.board[row]
-
- def valid_in_col(self, col, num):
- return all(
- self.board[row][col] != num
- for row in range(9)
- )
-
- def valid_in_square(self, row, col, num):
- row_start = (row // 3) * 3
- col_start=(col // 3) * 3
- for row_no in range(row_start, row_start + 3):
- for col_no in range(col_start, col_start + 3):
- if self.board[row_no][col_no] == num:
- return False
- return True
-
- def is_valid(self, empty, num):
- row, col = empty
- valid_in_row = self.valid_in_row(row, num)
- valid_in_col = self.valid_in_col(col, num)
- valid_in_square = self.valid_in_square(row, col, num)
- return all([valid_in_row, valid_in_col, valid_in_square])
-
- def solver(self):
- if (next_empty := self.find_empty_cell()) is None:
- return True
- else:
- for guess in range(1, 10):
- if self.is_valid(next_empty, guess):
- row, col = next_empty
- self.board[row][col] = guess
- if self.solver():
- return True
- self.board[row][col] = 0
-
- return False
-
---fcc-editable-region--
-def solve_sudoku(board):
- gameboard = Board(board)
- print(f'\nPuzzle to solve:\n{gameboard}')
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569fd352879475599d0ec66.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569fd352879475599d0ec66.md
deleted file mode 100644
index 19586b83f7a..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569fd352879475599d0ec66.md
+++ /dev/null
@@ -1,115 +0,0 @@
----
-id: 6569fd352879475599d0ec66
-title: Step 76
-challengeType: 20
-dashedName: step-76
----
-
-# --description--
-
-Add another `print` call to print the current state of the board.
-
-# --hints--
-
-You should have `print(gameboard)` within the `if` statement.
-
-```js
-const tCode = code.replace(/\r/g, '');
-const {function_body} = __helpers.python.getDef(tCode, "solve_sudoku");
-const {block_body} = __helpers.python.getBlock(function_body, /if\s+gameboard\.solver\s*\(\s*\)\s*/);
-assert.match(block_body, /print\s*\(\s*gameboard\s*\)/);
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
- board_string += row_empty
-
- if index < 8:
- if index % 3 == 2:
- board_string += f'╠═══{"╪═══"*2}{"╬═══"}{"╪═══"*2}{"╬═══"}{"╪═══"*2}╣\n'
- else:
- board_string += middle_lines
- else:
- board_string += lower_lines
-
- return board_string
-
- def find_empty_cell(self):
- for row, contents in enumerate(self.board):
- try:
- col = contents.index(0)
- return row, col
- except ValueError:
- pass
- return None
-
- def valid_in_row(self, row, num):
- return num not in self.board[row]
-
- def valid_in_col(self, col, num):
- return all(
- self.board[row][col] != num
- for row in range(9)
- )
-
- def valid_in_square(self, row, col, num):
- row_start = (row // 3) * 3
- col_start=(col // 3) * 3
- for row_no in range(row_start, row_start + 3):
- for col_no in range(col_start, col_start + 3):
- if self.board[row_no][col_no] == num:
- return False
- return True
-
- def is_valid(self, empty, num):
- row, col = empty
- valid_in_row = self.valid_in_row(row, num)
- valid_in_col = self.valid_in_col(col, num)
- valid_in_square = self.valid_in_square(row, col, num)
- return all([valid_in_row, valid_in_col, valid_in_square])
-
- def solver(self):
- if (next_empty := self.find_empty_cell()) is None:
- return True
- else:
- for guess in range(1, 10):
- if self.is_valid(next_empty, guess):
- row, col = next_empty
- self.board[row][col] = guess
- if self.solver():
- return True
- self.board[row][col] = 0
-
- return False
-
-def solve_sudoku(board):
- gameboard = Board(board)
- print(f'\nPuzzle to solve:\n{gameboard}')
---fcc-editable-region--
- if gameboard.solver():
- print('\nSolved puzzle:')
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569fd6d3cb95856c9ed2190.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569fd6d3cb95856c9ed2190.md
deleted file mode 100644
index c0489a83e8b..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569fd6d3cb95856c9ed2190.md
+++ /dev/null
@@ -1,125 +0,0 @@
----
-id: 6569fd6d3cb95856c9ed2190
-title: Step 77
-challengeType: 20
-dashedName: step-77
----
-
-# --description--
-
-Create an `else` clause and print the following string inside the new `else` block: `'\nThe provided puzzle is unsolvable.'`.
-
-# --hints--
-
-You should have an `else` clause within `solve_sudoku`.
-
-```js
-const tCode = code.replace(/\r/g, '');
-const {function_body} = __helpers.python.getDef(tCode, "solve_sudoku");
-const elseBlock = __helpers.python.getBlock(function_body, /else\s*/);
-assert.exists(elseBlock);
-```
-
-You should have `print('\nThe provided puzzle is unsolvable.')` within the `else` block.
-
-```js
-const tCode = code.replace(/\r/g, '');
-const {function_body} = __helpers.python.getDef(tCode, "solve_sudoku");
-const {block_body} = __helpers.python.getBlock(function_body, /else\s*/);
-assert.match(block_body, /print\s*\(\s*("|')\\nThe provided puzzle is unsolvable.\1\s*\)/);
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
- board_string += row_empty
-
- if index < 8:
- if index % 3 == 2:
- board_string += f'╠═══{"╪═══"*2}{"╬═══"}{"╪═══"*2}{"╬═══"}{"╪═══"*2}╣\n'
- else:
- board_string += middle_lines
- else:
- board_string += lower_lines
-
- return board_string
-
- def find_empty_cell(self):
- for row, contents in enumerate(self.board):
- try:
- col = contents.index(0)
- return row, col
- except ValueError:
- pass
- return None
-
- def valid_in_row(self, row, num):
- return num not in self.board[row]
-
- def valid_in_col(self, col, num):
- return all(
- self.board[row][col] != num
- for row in range(9)
- )
-
- def valid_in_square(self, row, col, num):
- row_start = (row // 3) * 3
- col_start=(col // 3) * 3
- for row_no in range(row_start, row_start + 3):
- for col_no in range(col_start, col_start + 3):
- if self.board[row_no][col_no] == num:
- return False
- return True
-
- def is_valid(self, empty, num):
- row, col = empty
- valid_in_row = self.valid_in_row(row, num)
- valid_in_col = self.valid_in_col(col, num)
- valid_in_square = self.valid_in_square(row, col, num)
- return all([valid_in_row, valid_in_col, valid_in_square])
-
- def solver(self):
- if (next_empty := self.find_empty_cell()) is None:
- return True
- else:
- for guess in range(1, 10):
- if self.is_valid(next_empty, guess):
- row, col = next_empty
- self.board[row][col] = guess
- if self.solver():
- return True
- self.board[row][col] = 0
-
- return False
-
---fcc-editable-region--
-def solve_sudoku(board):
- gameboard = Board(board)
- print(f'\nPuzzle to solve:\n{gameboard}')
- if gameboard.solver():
- print('\nSolved puzzle:')
- print(gameboard)
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569fdc59fe1b658bc9e23a4.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569fdc59fe1b658bc9e23a4.md
deleted file mode 100644
index 2fa9c57180a..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569fdc59fe1b658bc9e23a4.md
+++ /dev/null
@@ -1,118 +0,0 @@
----
-id: 6569fdc59fe1b658bc9e23a4
-title: Step 78
-challengeType: 20
-dashedName: step-78
----
-
-# --description--
-
-In the end, return your instance of the `Board` class, which represents the final state of the sudoku board after attempting to solve it.
-
-# --hints--
-
-You should have `return gameboard` within the `solve_sudoku` function.
-
-```js
-const tCode = code.replace(/\r/g, '');
-const {function_body} = __helpers.python.getDef(tCode, "solve_sudoku");
-assert.match(function_body, /return\s+gameboard/);
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
- board_string += row_empty
-
- if index < 8:
- if index % 3 == 2:
- board_string += f'╠═══{"╪═══"*2}{"╬═══"}{"╪═══"*2}{"╬═══"}{"╪═══"*2}╣\n'
- else:
- board_string += middle_lines
- else:
- board_string += lower_lines
-
- return board_string
-
- def find_empty_cell(self):
- for row, contents in enumerate(self.board):
- try:
- col = contents.index(0)
- return row, col
- except ValueError:
- pass
- return None
-
- def valid_in_row(self, row, num):
- return num not in self.board[row]
-
- def valid_in_col(self, col, num):
- return all(
- self.board[row][col] != num
- for row in range(9)
- )
-
- def valid_in_square(self, row, col, num):
- row_start = (row // 3) * 3
- col_start=(col // 3) * 3
- for row_no in range(row_start, row_start + 3):
- for col_no in range(col_start, col_start + 3):
- if self.board[row_no][col_no] == num:
- return False
- return True
-
- def is_valid(self, empty, num):
- row, col = empty
- valid_in_row = self.valid_in_row(row, num)
- valid_in_col = self.valid_in_col(col, num)
- valid_in_square = self.valid_in_square(row, col, num)
- return all([valid_in_row, valid_in_col, valid_in_square])
-
- def solver(self):
- if (next_empty := self.find_empty_cell()) is None:
- return True
- else:
- for guess in range(1, 10):
- if self.is_valid(next_empty, guess):
- row, col = next_empty
- self.board[row][col] = guess
- if self.solver():
- return True
- self.board[row][col] = 0
-
- return False
-
---fcc-editable-region--
-def solve_sudoku(board):
- gameboard = Board(board)
- print(f'\nPuzzle to solve:\n{gameboard}')
- if gameboard.solver():
- print('\nSolved puzzle:')
- print(gameboard)
-
- else:
- print('\nThe provided puzzle is unsolvable.')
-
---fcc-editable-region--
-```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569fe0fe5b5425a1bb1f534.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569fe0fe5b5425a1bb1f534.md
deleted file mode 100644
index f8f9ea51048..00000000000
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6569fe0fe5b5425a1bb1f534.md
+++ /dev/null
@@ -1,246 +0,0 @@
----
-id: 6569fe0fe5b5425a1bb1f534
-title: Step 79
-challengeType: 20
-dashedName: step-79
----
-
-# --description--
-
-Now it's time to play the game!
-
-A puzzle has been given in the code.
-
-Call the `solve_sudoku` method with `puzzle` as input.
-
-Now, you can see the solved puzzle as the output.
-
-With this, you are finished with building the sudoku solver!
-
-# --hints--
-
-Call the `solve_sudoku` method with `puzzle` as input.
-
-```js
-assert.match(code, /solve_sudoku\(\s*puzzle\s*\)/);
-```
-
-# --seed--
-
-## --seed-contents--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
- board_string += row_empty
-
- if index < 8:
- if index % 3 == 2:
- board_string += f'╠═══{"╪═══"*2}{"╬═══"}{"╪═══"*2}{"╬═══"}{"╪═══"*2}╣\n'
- else:
- board_string += middle_lines
- else:
- board_string += lower_lines
-
- return board_string
-
- def find_empty_cell(self):
- for row, contents in enumerate(self.board):
- try:
- col = contents.index(0)
- return row, col
- except ValueError:
- pass
- return None
-
- def valid_in_row(self, row, num):
- return num not in self.board[row]
-
- def valid_in_col(self, col, num):
- return all(
- self.board[row][col] != num
- for row in range(9)
- )
-
- def valid_in_square(self, row, col, num):
- row_start = (row // 3) * 3
- col_start=(col // 3) * 3
- for row_no in range(row_start, row_start + 3):
- for col_no in range(col_start, col_start + 3):
- if self.board[row_no][col_no] == num:
- return False
- return True
-
- def is_valid(self, empty, num):
- row, col = empty
- valid_in_row = self.valid_in_row(row, num)
- valid_in_col = self.valid_in_col(col, num)
- valid_in_square = self.valid_in_square(row, col, num)
- return all([valid_in_row, valid_in_col, valid_in_square])
-
- def solver(self):
- if (next_empty := self.find_empty_cell()) is None:
- return True
- else:
- for guess in range(1, 10):
- if self.is_valid(next_empty, guess):
- row, col = next_empty
- self.board[row][col] = guess
- if self.solver():
- return True
- self.board[row][col] = 0
-
- return False
-
-def solve_sudoku(board):
- gameboard = Board(board)
- print(f'\nPuzzle to solve:\n{gameboard}')
- if gameboard.solver():
- print('\nSolved puzzle:')
- print(gameboard)
-
- else:
- print('\nThe provided puzzle is unsolvable.')
- return gameboard
---fcc-editable-region--
-puzzle = [
- [0, 0, 2, 0, 0, 8, 0, 0, 0],
- [0, 0, 0, 0, 0, 3, 7, 6, 2],
- [4, 3, 0, 0, 0, 0, 8, 0, 0],
- [0, 5, 0, 0, 3, 0, 0, 9, 0],
- [0, 4, 0, 0, 0, 0, 0, 2, 6],
- [0, 0, 0, 4, 6, 7, 0, 0, 0],
- [0, 8, 6, 7, 0, 4, 0, 0, 0],
- [0, 0, 0, 5, 1, 9, 0, 0, 8],
- [1, 7, 0, 0, 0, 6, 0, 0, 5]
-]
-
---fcc-editable-region--
-```
-
-# --solutions--
-
-```py
-class Board:
- def __init__(self, board):
- self.board = board
-
- def __str__(self):
- upper_lines = f'\n╔═══{"╤═══"*2}{"╦═══"}{"╤═══"*2}{"╦═══"}{"╤═══"*2}╗\n'
- middle_lines = f'╟───{"┼───"*2}{"╫───"}{"┼───"*2}{"╫───"}{"┼───"*2}╢\n'
- lower_lines = f'╚═══{"╧═══"*2}{"╩═══"}{"╧═══"*2}{"╩═══"}{"╧═══"*2}╝\n'
- board_string = upper_lines
- for index, line in enumerate(self.board):
- row_list = []
- for square_no, part in enumerate([line[:3], line[3:6], line[6:]], start=1):
- row_square = '|'.join(str(item) for item in part)
- row_list.extend(row_square)
- if square_no != 3:
- row_list.append('║')
-
- row = f'║ {" ".join(row_list)} ║\n'
- row_empty = row.replace('0', ' ')
- board_string += row_empty
-
- if index < 8:
- if index % 3 == 2:
- board_string += f'╠═══{"╪═══"*2}{"╬═══"}{"╪═══"*2}{"╬═══"}{"╪═══"*2}╣\n'
- else:
- board_string += middle_lines
- else:
- board_string += lower_lines
-
- return board_string
-
- def find_empty_cell(self):
- for row, contents in enumerate(self.board):
- try:
- col = contents.index(0)
- return row, col
- except ValueError:
- pass
- return None
-
- def valid_in_row(self, row, num):
- return num not in self.board[row]
-
- def valid_in_col(self, col, num):
- return all(
- self.board[row][col] != num
- for row in range(9)
- )
-
- def valid_in_square(self, row, col, num):
- row_start = (row // 3) * 3
- col_start=(col // 3) * 3
- for row_no in range(row_start, row_start + 3):
- for col_no in range(col_start, col_start + 3):
- if self.board[row_no][col_no] == num:
- return False
- return True
-
- def is_valid(self, empty, num):
- row, col = empty
- valid_in_row = self.valid_in_row(row, num)
- valid_in_col = self.valid_in_col(col, num)
- valid_in_square = self.valid_in_square(row, col, num)
- return all([valid_in_row, valid_in_col, valid_in_square])
-
- def solver(self):
- if (next_empty := self.find_empty_cell()) is None:
- return True
- else:
- for guess in range(1, 10):
- if self.is_valid(next_empty, guess):
- row, col = next_empty
- self.board[row][col] = guess
- if self.solver():
- return True
- self.board[row][col] = 0
-
- return False
-
-def solve_sudoku(board):
- gameboard = Board(board)
- print('\nPuzzle to solve:')
- print(gameboard)
- if gameboard.solver():
- print('\nSolved puzzle:')
- print(gameboard)
-
- else:
- print('\nThe provided puzzle is unsolvable.')
- return gameboard
-
-puzzle = [
- [0, 0, 2, 0, 0, 8, 0, 0, 0],
- [0, 0, 0, 0, 0, 3, 7, 6, 2],
- [4, 3, 0, 0, 0, 0, 8, 0, 0],
- [0, 5, 0, 0, 3, 0, 0, 9, 0],
- [0, 4, 0, 0, 0, 0, 0, 2, 6],
- [0, 0, 0, 4, 6, 7, 0, 0, 0],
- [0, 8, 6, 7, 0, 4, 0, 0, 0],
- [0, 0, 0, 5, 1, 9, 0, 0, 8],
- [1, 7, 0, 0, 0, 6, 0, 0, 5]
-]
-
-solve_sudoku(puzzle)
-```
-
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/656873ffdc638f7e290f60de.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/66068fb0bfddba2b7977eb60.md
similarity index 63%
rename from curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/656873ffdc638f7e290f60de.md
rename to curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/66068fb0bfddba2b7977eb60.md
index 1ab5ce99b47..68cdc2f0f0a 100644
--- a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/656873ffdc638f7e290f60de.md
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/66068fb0bfddba2b7977eb60.md
@@ -1,5 +1,5 @@
---
-id: 656873ffdc638f7e290f60de
+id: 66068fb0bfddba2b7977eb60
title: Step 1
challengeType: 20
dashedName: step-1
@@ -11,20 +11,21 @@ In this project, you will learn about classes and objects by building a sudoku p
In Python, a class is a blueprint for creating objects. Objects created from a class are instances of that class. You can create a class using this syntax:
-```js
+```py
class ClassName:
+ pass
```
-First, you will create a 9x9 board by using classes and then populate it with the puzzle values.
+Where `class` is the keyword required to define the class and `ClassName` is the name of the class, written by convention in *PascalCase*.
Begin by creating a `Board` class.
# --hints--
-Your class should be named `Board`.
+You should create a class named `Board`.
```js
-assert.match(code, /class\s+Board\s*\:/);
+({ test: () => assert(runPython(`_Node(_code).has_class("Board")`)) })
```
# --seed--
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/66069167b3307b2f4067b22b.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/66069167b3307b2f4067b22b.md
new file mode 100644
index 00000000000..085fa7a1416
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/66069167b3307b2f4067b22b.md
@@ -0,0 +1,37 @@
+---
+id: 66069167b3307b2f4067b22b
+title: Step 2
+challengeType: 20
+dashedName: step-2
+---
+
+# --description--
+
+A new instance of a class is created by using the function notation, which involves appending a pair of parentheses to the class name.
+
+Outside the class definition, create an instance of the `Board` class and assign it to a variable named `gameboard`.
+
+# --hints--
+
+You should declare a variable `gameboard` outside the `Board` class.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).has_variable("gameboard")`)) })
+```
+
+Your `gameboard` variable should have the value of `Board()`.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_variable("gameboard").is_equivalent("gameboard = Board()")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+--fcc-editable-region--
+class Board:
+ pass
+--fcc-editable-region--
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606927d010be4300a4e5330.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606927d010be4300a4e5330.md
new file mode 100644
index 00000000000..e78464a5796
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606927d010be4300a4e5330.md
@@ -0,0 +1,39 @@
+---
+id: 6606927d010be4300a4e5330
+title: Step 3
+challengeType: 20
+dashedName: step-3
+---
+
+# --description--
+
+The instantiation creates an empty object. But classes can have methods, which are like local functions for each instance. Within a class, methods are declared as follows:
+
+```py
+class ClassName:
+ def method_name():
+ pass
+```
+
+Inside the `Board` class, replace `pass` with an empty method `spam`.
+
+# --hints--
+
+You should define a method named `spam` inside the `Board` class.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").has_function("spam")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+--fcc-editable-region--
+class Board:
+ pass
+
+gameboard = Board()
+--fcc-editable-region--
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606933d6813a8308c962dd1.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606933d6813a8308c962dd1.md
new file mode 100644
index 00000000000..5fae78c5f9e
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606933d6813a8308c962dd1.md
@@ -0,0 +1,34 @@
+---
+id: 6606933d6813a8308c962dd1
+title: Step 4
+challengeType: 20
+dashedName: step-4
+---
+
+# --description--
+
+In order to be an instance method, a method requires a special parameter, named `self` by convention. This parameter is a reference to the instance of the class and must always be the first parameter.
+
+Add a `self` parameter to your `spam` method.
+
+# --hints--
+
+Your `spam` method should have a `self` parameter.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").find_function("spam").has_args("self")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+--fcc-editable-region--
+class Board:
+ def spam():
+ pass
+
+gameboard = Board()
+--fcc-editable-region--
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660699119472f332798860ad.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660699119472f332798860ad.md
new file mode 100644
index 00000000000..e8ec4c31deb
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660699119472f332798860ad.md
@@ -0,0 +1,32 @@
+---
+id: 660699119472f332798860ad
+title: Step 5
+challengeType: 20
+dashedName: step-5
+---
+
+# --description--
+
+Now, replace `pass` with a `print` call and pass it the string `'Spam!'`.
+
+# --hints--
+
+You should delete `pass` and print the string `'Spam!'` within the `spam` method.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").find_function("spam").find_body().is_equivalent("print('Spam!')")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+--fcc-editable-region--
+class Board:
+ def spam(self):
+ pass
+
+gameboard = Board()
+--fcc-editable-region--
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660699aabc59c532f2d556e5.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660699aabc59c532f2d556e5.md
new file mode 100644
index 00000000000..786debeabba
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660699aabc59c532f2d556e5.md
@@ -0,0 +1,40 @@
+---
+id: 660699aabc59c532f2d556e5
+title: Step 6
+challengeType: 20
+dashedName: step-6
+---
+
+# --description--
+
+To call an instance method, you need to use dot notation:
+
+```py
+instance_name.method_name()
+```
+
+Where `instance_name` is the instance or object, and `method_name` is the method you want to call.
+
+Call the `spam` method of the `gameboard` object.
+
+# --hints--
+
+You should call the `spam` method of the `gameboard` object with `gameboard.spam()`.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).has_call("gameboard.spam()")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+--fcc-editable-region--
+class Board:
+ def spam(self):
+ print('Spam!')
+
+gameboard = Board()
+--fcc-editable-region--
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/66069b0b36053733a2f012fe.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/66069b0b36053733a2f012fe.md
new file mode 100644
index 00000000000..48244cc9a79
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/66069b0b36053733a2f012fe.md
@@ -0,0 +1,33 @@
+---
+id: 66069b0b36053733a2f012fe
+title: Step 7
+challengeType: 20
+dashedName: step-7
+---
+
+# --description--
+
+Now, delete your `spam` call.
+
+# --hints--
+
+You should not have `gameboard.spam()` in your code.
+
+```js
+({ test: () => assert.isFalse(runPython(`_Node(_code).has_call("gameboard.spam()")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+--fcc-editable-region--
+class Board:
+ def spam(self):
+ print('Spam!')
+
+gameboard = Board()
+gameboard.spam()
+--fcc-editable-region--
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/66069b992c1c5e3451f3deb0.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/66069b992c1c5e3451f3deb0.md
new file mode 100644
index 00000000000..f757c0d272d
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/66069b992c1c5e3451f3deb0.md
@@ -0,0 +1,46 @@
+---
+id: 66069b992c1c5e3451f3deb0
+title: Step 8
+challengeType: 20
+dashedName: step-8
+---
+
+# --description--
+
+The instantiation creates an empty object. The `__init__` method is a special method that allows you to instantiate an object to a customized state. When a class implements an `__init__` method, `__init__` is automatically called upon instantiation.
+
+Inside your `Board` class, delete the `spam` method and replace it with an `__init__` method that includes a `self` parameter.
+
+# --hints--
+
+You should not have a `spam` method in your `Board` class.
+
+```js
+({ test: () => assert.isFalse(runPython(`_Node(_code).find_class("Board").has_function("spam")`)) })
+```
+
+You should define an `__init__` method in your `Board` class.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").has_function("__init__")`)) })
+```
+
+Your `__init__` method should have a `self` parameter.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").find_function("__init__").has_args("self")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+--fcc-editable-region--
+class Board:
+ def spam(self):
+ print('Spam!')
+
+gameboard = Board()
+--fcc-editable-region--
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/66069d65162e61357c793e0c.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/66069d65162e61357c793e0c.md
new file mode 100644
index 00000000000..5cc6adbad93
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/66069d65162e61357c793e0c.md
@@ -0,0 +1,51 @@
+---
+id: 66069d65162e61357c793e0c
+title: Step 9
+challengeType: 20
+dashedName: step-9
+---
+
+# --description--
+
+The sudoku puzzle to solve will be a list of lists, as the following:
+
+```py
+[
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+```
+
+Note that the empty cells are filled with a zero.
+
+Declare a `puzzle` variable and assign it the list of lists in the example above.
+
+# --hints--
+
+You should declare a variable `puzzle` and assign it the provided 2D-list.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_variable("puzzle").is_equivalent("puzzle = [[0, 0, 2, 0, 0, 8, 0, 0, 0], [0, 0, 0, 0, 0, 3, 7, 6, 2], [4, 3, 0, 0, 0, 0, 8, 0, 0], [0, 5, 0, 0, 3, 0, 0, 9, 0], [0, 4, 0, 0, 0, 0, 0, 2, 6], [0, 0, 0, 4, 6, 7, 0, 0, 0], [0, 8, 6, 7, 0, 4, 0, 0, 0], [0, 0, 0, 5, 1, 9, 0, 0, 8], [1, 7, 0, 0, 0, 6, 0, 0, 5]]")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+
+class Board:
+ def __init__(self):
+ pass
+--fcc-editable-region--
+
+--fcc-editable-region--
+gameboard = Board()
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/66069e5759b800364707988e.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/66069e5759b800364707988e.md
new file mode 100644
index 00000000000..a0bca70274f
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/66069e5759b800364707988e.md
@@ -0,0 +1,53 @@
+---
+id: 66069e5759b800364707988e
+title: Step 10
+challengeType: 20
+dashedName: step-10
+---
+
+# --description--
+
+Going back to the `__init__` method, it requires an additional parameter representing the puzzle to solve.
+
+Add a second parameter named `board` to the `__init__` method and fix the instantiation of `gameboard` by passing it the `puzzle` list as you would pass an argument to a function call.
+
+# --hints--
+
+Your `__init__` method should have two parameters in the order: `self`, and `board`.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").find_function("__init__").has_args("self, board")`)) })
+```
+
+Your `gameboard` variable should have the value of `Board(puzzle)`.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_variable("gameboard").is_equivalent("gameboard = Board(puzzle)")`)) })
+```
+
+
+# --seed--
+
+## --seed-contents--
+
+```py
+--fcc-editable-region--
+class Board:
+ def __init__(self):
+ pass
+
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+
+gameboard = Board()
+--fcc-editable-region--
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/66069f86f58f85371d47123e.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/66069f86f58f85371d47123e.md
new file mode 100644
index 00000000000..6e709ad0fb5
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/66069f86f58f85371d47123e.md
@@ -0,0 +1,48 @@
+---
+id: 66069f86f58f85371d47123e
+title: Step 11
+challengeType: 20
+dashedName: step-11
+---
+
+# --description--
+
+An attribute is a variable associated with an object, which is used to store data as regular variables.
+
+Inside the `__init__` method, assign the `board` parameter (which is passed when creating an instance of the `Board` class) to an instance attribute `board` using `self.board`.
+
+`self.board` refers to the `board` attribute of the instance of the class. It's a variable that belongs to the object created from the `Board` class.
+
+# --hints--
+
+You should delete `pass` and assign the `board` parameter to `self.board` inside the `__init__` method.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").find_function("__init__").find_body().is_equivalent("self.board = board")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+--fcc-editable-region--
+class Board:
+ def __init__(self, board):
+ pass
+
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+
+gameboard = Board(puzzle)
+--fcc-editable-region--
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606a219f9efbf38ad496f67.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606a219f9efbf38ad496f67.md
new file mode 100644
index 00000000000..069b3257d09
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606a219f9efbf38ad496f67.md
@@ -0,0 +1,46 @@
+---
+id: 6606a219f9efbf38ad496f67
+title: Step 12
+challengeType: 20
+dashedName: step-12
+---
+
+# --description--
+
+You can also use dot notation to access an instance attribute.
+
+Outside the `Board` class, after initializing the `gameboard` object, use `gameboard.board` to access the `board` attribute of your `gameboard` object and print the result to the screen.
+
+# --hints--
+
+You should print `gameboard.board`.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).has_call("print(gameboard.board)")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+--fcc-editable-region--
+class Board:
+ def __init__(self, board):
+ self.board = board
+
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+
+gameboard = Board(puzzle)
+--fcc-editable-region--
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606a2f8a6a36f39518e0439.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606a2f8a6a36f39518e0439.md
new file mode 100644
index 00000000000..a24565bb7e6
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606a2f8a6a36f39518e0439.md
@@ -0,0 +1,45 @@
+---
+id: 6606a2f8a6a36f39518e0439
+title: Step 13
+challengeType: 20
+dashedName: step-13
+---
+
+# --description--
+
+As you can see, the board is printed on the screen. Now, delete your `print` call.
+
+# --hints--
+
+You should not have `print(gameboard.board)` in your code.
+
+```js
+({ test: () => assert.isFalse(runPython(`_Node(_code).has_call("print(gameboard.board)")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+--fcc-editable-region--
+class Board:
+ def __init__(self, board):
+ self.board = board
+
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+
+gameboard = Board(puzzle)
+print(gameboard.board)
+--fcc-editable-region--
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606a3ccb1eea93a23c066bf.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606a3ccb1eea93a23c066bf.md
new file mode 100644
index 00000000000..1b50117df68
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606a3ccb1eea93a23c066bf.md
@@ -0,0 +1,52 @@
+---
+id: 6606a3ccb1eea93a23c066bf
+title: Step 14
+challengeType: 20
+dashedName: step-14
+---
+
+# --description--
+
+Now you'll work on a method that finds the empty cells in the sudoku board.
+
+Within the `Board` class, create an empty method named `find_empty_cell` and give it a `self` parameter.
+
+# --hints--
+
+You should define a method named `find_empty_cell` inside your `Board` class.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").has_function("find_empty_cell")`)) })
+```
+
+Your `find_empty_cell` method should have a parameter `self`.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").find_function("find_empty_cell").has_args("self")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+--fcc-editable-region--
+class Board:
+ def __init__(self, board):
+ self.board = board
+
+--fcc-editable-region--
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+
+gameboard = Board(puzzle)
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606a4641ec48b3a9fe8c2fc.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606a4641ec48b3a9fe8c2fc.md
new file mode 100644
index 00000000000..0e716d895f1
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606a4641ec48b3a9fe8c2fc.md
@@ -0,0 +1,57 @@
+---
+id: 6606a4641ec48b3a9fe8c2fc
+title: Step 15
+challengeType: 20
+dashedName: step-15
+---
+
+# --description--
+
+The `enumerate` built-in function takes an iterable as its argument and returns an enumerate object you can iterate over.
+It provides the count (which by default starts at zero) and the value from the iterable.
+
+```py
+iterable = ['a', 'b', 'c']
+for i, j in enumerate(iterable):
+ print(i, j)
+```
+
+The loop from the example above would output the tuples `0, a`, `1, b`, and `2, c`.
+
+Inside the `find_empty_cell` method, replace `pass` with a `for` loop that uses the `enumerate()` function to iterate over each row in the sudoku board. Use `row` as the index of the current row and `contents` for the elements of the current row.
+
+
+# --hints--
+
+You should replace `pass` with a `for` loop that iterates over `enumerate(self.board)`. Use `row` and `contents` as the loop variables.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").find_function("find_empty_cell").find_body().is_equivalent("for row, contents in enumerate(self.board):\\n pass")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+--fcc-editable-region--
+ def find_empty_cell(self):
+ pass
+--fcc-editable-region--
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+
+gameboard = Board(puzzle)
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606b0d602d1e33e81bcef0d.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606b0d602d1e33e81bcef0d.md
new file mode 100644
index 00000000000..d64629762d7
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606b0d602d1e33e81bcef0d.md
@@ -0,0 +1,48 @@
+---
+id: 6606b0d602d1e33e81bcef0d
+title: Step 16
+challengeType: 20
+dashedName: step-16
+---
+
+# --description--
+
+You need to locate the empty cell, which is filled with the number zero.
+
+Replace `pass` with a variable `col` and assign it a call to `.index()` on `contents`, passing `0` as the argument.
+
+# --hints--
+
+You should replace `pass` with a variable `col` and assign it `contents.index(0)`.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").find_function("find_empty_cell").find_for_loops()[0].find_bodies()[0].is_equivalent("col = contents.index(0)")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+--fcc-editable-region--
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ pass
+--fcc-editable-region--
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+
+gameboard = Board(puzzle)
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606b224a69a293f98f8db8f.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606b224a69a293f98f8db8f.md
new file mode 100644
index 00000000000..c7d115c6f54
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606b224a69a293f98f8db8f.md
@@ -0,0 +1,55 @@
+---
+id: 6606b224a69a293f98f8db8f
+title: Step 17
+challengeType: 20
+dashedName: step-17
+---
+
+# --description--
+
+The `.index()` method raises a `ValueError` exception when the value is not found. To prevent the program from halting execution, you'll nest this line of code inside a `try` block. The `try` statement is used to encapsulate code that might raise an exception. The `except` clause, on the other hand, offers alternative code to execute if an exception occurs:
+
+```py
+try:
+
+except:
+
+```
+
+Put the assignment of `col` inside a `try` block. Then, create an `except` clause and fill its body with `pass`.
+
+# --hints--
+
+You should put the assignment of `col` inside a `try` block and create an `except` clause.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").find_function("find_empty_cell").find_for_loops()[0].find_bodies()[0].is_equivalent("try:\\n col = contents.index(0)\\nexcept:\\n pass")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+--fcc-editable-region--
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ col = contents.index(0)
+--fcc-editable-region--
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+
+gameboard = Board(puzzle)
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606b63c0fd55e4314d2ec85.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606b63c0fd55e4314d2ec85.md
new file mode 100644
index 00000000000..9876c1bd00c
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606b63c0fd55e4314d2ec85.md
@@ -0,0 +1,51 @@
+---
+id: 6606b63c0fd55e4314d2ec85
+title: Step 18
+challengeType: 20
+dashedName: step-18
+---
+
+# --description--
+
+If `0` is found, the function should immediately return a tuple containing the row index and column index of the empty cell.
+
+Inside the `try` block, after the assignment of `col`, return `row, col`.
+
+# --hints--
+
+You should return `row, col` from the `try` block.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").find_function("find_empty_cell").find_for_loops()[0].find_bodies()[0].is_equivalent("try:\\n col = contents.index(0)\\n return row, col\\nexcept:\\n pass")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+--fcc-editable-region--
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ except:
+ pass
+--fcc-editable-region--
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+
+gameboard = Board(puzzle)
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606b6b7760d0643c3b4eb29.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606b6b7760d0643c3b4eb29.md
new file mode 100644
index 00000000000..3db152ffaec
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606b6b7760d0643c3b4eb29.md
@@ -0,0 +1,54 @@
+---
+id: 6606b6b7760d0643c3b4eb29
+title: Step 19
+challengeType: 20
+dashedName: step-19
+---
+
+# --description--
+
+If the code inside the `try` block raises an exception, you want the program to continue running, and the `pass` statement accomplishes this.
+
+Although this code works, specifying the exception type after the `except` keyword is considered good practice.
+
+Since you know that a `ValueError` might be raised, leave a space after the `except` keyword and add `ValueError` after that.
+
+# --hints--
+
+You should have `except ValueError:` in your code.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").find_function("find_empty_cell").find_for_loops()[0].find_bodies()[0].is_equivalent("try:\\n col = contents.index(0)\\n return row, col\\nexcept ValueError:\\n pass")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+--fcc-editable-region--
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except:
+ pass
+--fcc-editable-region--
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+
+gameboard = Board(puzzle)
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606b8d31356fe4563f0e99c.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606b8d31356fe4563f0e99c.md
new file mode 100644
index 00000000000..b51a721a190
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606b8d31356fe4563f0e99c.md
@@ -0,0 +1,50 @@
+---
+id: 6606b8d31356fe4563f0e99c
+title: Step 20
+challengeType: 20
+dashedName: step-20
+---
+
+# --description--
+
+Outside the `for` loop, return `None`. This handles the case in which no empty cell is found, indicating that the sudoku board is completely filled.
+
+# --hints--
+
+You should return `None` after the `for` loop.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").find_function("find_empty_cell").has_return("None")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+--fcc-editable-region--
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+--fcc-editable-region--
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+
+gameboard = Board(puzzle)
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606b961ebcf04460f8af76e.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606b961ebcf04460f8af76e.md
new file mode 100644
index 00000000000..56a77e8d9f1
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606b961ebcf04460f8af76e.md
@@ -0,0 +1,56 @@
+---
+id: 6606b961ebcf04460f8af76e
+title: Step 21
+challengeType: 20
+dashedName: step-21
+---
+
+# --description--
+
+Test that the `find_empty_cell` method works properly by calling it on `gameboard` and printing the result.
+
+Note that, although `find_empty_cell` is defined with one parameter, you must not give it a value by passing an argument to the function call, since `self` is automatically passed in as the object you are calling the method on.
+
+# --hints--
+
+You should print `gameboard.find_empty_cell()`.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).has_call("print(gameboard.find_empty_cell())")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+ return None
+
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+
+gameboard = Board(puzzle)
+--fcc-editable-region--
+
+--fcc-editable-region--
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606baaf1828ff46ebcc008c.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606baaf1828ff46ebcc008c.md
new file mode 100644
index 00000000000..f021d193478
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606baaf1828ff46ebcc008c.md
@@ -0,0 +1,54 @@
+---
+id: 6606baaf1828ff46ebcc008c
+title: Step 22
+challengeType: 20
+dashedName: step-22
+---
+
+# --description--
+
+`find_empty_cell` is returning `(0, 0)`, which is the position of the first empty cell in the sudoku board.
+
+Turn the first `0` inside `puzzle` into a `1`. You will see in the output that the next empty cell will be found.
+
+# --hints--
+
+You should modify the first item of the first list in `puzzle` into a `1`.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_variable("puzzle").is_equivalent("puzzle = [[1, 0, 2, 0, 0, 8, 0, 0, 0], [0, 0, 0, 0, 0, 3, 7, 6, 2], [4, 3, 0, 0, 0, 0, 8, 0, 0], [0, 5, 0, 0, 3, 0, 0, 9, 0], [0, 4, 0, 0, 0, 0, 0, 2, 6], [0, 0, 0, 4, 6, 7, 0, 0, 0], [0, 8, 6, 7, 0, 4, 0, 0, 0], [0, 0, 0, 5, 1, 9, 0, 0, 8], [1, 7, 0, 0, 0, 6, 0, 0, 5]]")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+ return None
+--fcc-editable-region--
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+--fcc-editable-region--
+gameboard = Board(puzzle)
+print(gameboard.find_empty_cell())
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606bbd52233b247cf0a56e4.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606bbd52233b247cf0a56e4.md
new file mode 100644
index 00000000000..fec11280338
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606bbd52233b247cf0a56e4.md
@@ -0,0 +1,59 @@
+---
+id: 6606bbd52233b247cf0a56e4
+title: Step 23
+challengeType: 20
+dashedName: step-23
+---
+
+# --description--
+
+Now, turn the `1` you modified earlier back into a `0` to restore the original board configuration. Then, delete your `print` call.
+
+# --hints--
+
+You should turn the first item of the first list of `puzzle` back into a zero.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_variable("puzzle").is_equivalent("puzzle = [[0, 0, 2, 0, 0, 8, 0, 0, 0], [0, 0, 0, 0, 0, 3, 7, 6, 2], [4, 3, 0, 0, 0, 0, 8, 0, 0], [0, 5, 0, 0, 3, 0, 0, 9, 0], [0, 4, 0, 0, 0, 0, 0, 2, 6], [0, 0, 0, 4, 6, 7, 0, 0, 0], [0, 8, 6, 7, 0, 4, 0, 0, 0], [0, 0, 0, 5, 1, 9, 0, 0, 8], [1, 7, 0, 0, 0, 6, 0, 0, 5]]")`)) })
+```
+
+You should not have `print(gameboard.find_empty_cell())` in your code.
+
+```js
+({ test: () => assert.isFalse(runPython(`_Node(_code).has_call("print(gameboard.find_empty_cell())")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+ return None
+--fcc-editable-region--
+puzzle = [
+ [1, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+
+gameboard = Board(puzzle)
+print(gameboard.find_empty_cell())
+--fcc-editable-region--
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606bc4e5535c0484990ccd5.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606bc4e5535c0484990ccd5.md
new file mode 100644
index 00000000000..9192882abd9
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606bc4e5535c0484990ccd5.md
@@ -0,0 +1,62 @@
+---
+id: 6606bc4e5535c0484990ccd5
+title: Step 24
+challengeType: 20
+dashedName: step-24
+---
+
+# --description--
+
+Next, you're going to work on a method that checks if a given number can be inserted into a specified row of the sudoku board.
+
+Within the `Board` class, create a method named `valid_in_row` and give it three parameters: `self`, `row`, and `num`. Where `self` represents the instance of the class, and `row` and `num` are the row index and the number to be checked, respectively.
+
+
+# --hints--
+
+You should create a new method named `valid_in_row` within the `Board` class.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").has_function("valid_in_row")`)) })
+```
+
+Your `valid_in_row` method should have three parameters: `self`, `row`, and `num`, in this order.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").find_function("valid_in_row").has_args("self, row, num")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+ return None
+--fcc-editable-region--
+
+--fcc-editable-region--
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+
+gameboard = Board(puzzle)
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606bd3d02e86548d3ce1a0a.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606bd3d02e86548d3ce1a0a.md
new file mode 100644
index 00000000000..86aa94eac57
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606bd3d02e86548d3ce1a0a.md
@@ -0,0 +1,54 @@
+---
+id: 6606bd3d02e86548d3ce1a0a
+title: Step 25
+challengeType: 20
+dashedName: step-25
+---
+
+# --description--
+
+Replace `pass` with an expression that checks if the number `num` is not already present in that row.
+
+# --hints--
+
+You should replace `pass` with the expression `num not in self.board[row]`.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").find_function("valid_in_row").find_body().is_equivalent("num not in self.board[row]")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+ return None
+--fcc-editable-region--
+ def valid_in_row(self, row, num):
+ pass
+--fcc-editable-region--
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+
+gameboard = Board(puzzle)
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606beade9200b49aaeecd94.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606beade9200b49aaeecd94.md
new file mode 100644
index 00000000000..1dd550c7ed0
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606beade9200b49aaeecd94.md
@@ -0,0 +1,58 @@
+---
+id: 6606beade9200b49aaeecd94
+title: Step 26
+challengeType: 20
+dashedName: step-26
+---
+
+# --description--
+
+If `num` is not in the row, the expression evaluates to `True` and it means the number is valid for insertion.
+
+If `num` is in the row, the expression evaluates to `False` and insertion would violate the rules.
+
+Prepend a `return` keyword to the expression inside the `valid_in_row` method body, so that the validity of the number can be checked.
+
+# --hints--
+
+You should return `num not in self.board[row]`.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").find_function("valid_in_row").find_body().is_equivalent("return num not in self.board[row]")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+ return None
+--fcc-editable-region--
+ def valid_in_row(self, row, num):
+ num not in self.board[row]
+--fcc-editable-region--
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+
+gameboard = Board(puzzle)
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606bf4561f8794a0d345919.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606bf4561f8794a0d345919.md
new file mode 100644
index 00000000000..2eed5cae829
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606bf4561f8794a0d345919.md
@@ -0,0 +1,59 @@
+---
+id: 6606bf4561f8794a0d345919
+title: Step 27
+challengeType: 20
+dashedName: step-27
+---
+
+# --description--
+
+It's time to test the `valid_in_row` method. Call `valid_in_row` on `gameboard`. Pass it `0` and `8` as the arguments and print the result.
+
+Again, note how the method is defined with three parameters, yet it is called with only two arguments because `self` is automatically passed as the object on which the method is called.
+
+# --hints--
+
+You should print the result of calling `valid_in_row(0, 8)` on `gameboard`.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).has_call("print(gameboard.valid_in_row(0, 8))")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+ return None
+
+ def valid_in_row(self, row, num):
+ return num not in self.board[row]
+
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+
+gameboard = Board(puzzle)
+--fcc-editable-region--
+
+--fcc-editable-region--
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606c05b5624a54ab85808fa.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606c05b5624a54ab85808fa.md
new file mode 100644
index 00000000000..41721851b6b
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606c05b5624a54ab85808fa.md
@@ -0,0 +1,57 @@
+---
+id: 6606c05b5624a54ab85808fa
+title: Step 28
+challengeType: 20
+dashedName: step-28
+---
+
+# --description--
+
+As you can see, the output is `False` because `8` is already present in the first row of the board. Now change the `8` into a `7`.
+
+# --hints--
+
+You modify your `print` call to print the result of calling `valid_in_row(0, 7)` on `gameboard`.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).has_call("print(gameboard.valid_in_row(0, 7))")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+ return None
+
+ def valid_in_row(self, row, num):
+ return num not in self.board[row]
+
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+
+gameboard = Board(puzzle)
+--fcc-editable-region--
+print(gameboard.valid_in_row(0, 8))
+--fcc-editable-region--
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606c0dd3293064b30d17a72.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606c0dd3293064b30d17a72.md
new file mode 100644
index 00000000000..82b20ac54f3
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606c0dd3293064b30d17a72.md
@@ -0,0 +1,59 @@
+---
+id: 6606c0dd3293064b30d17a72
+title: Step 29
+challengeType: 20
+dashedName: step-29
+---
+
+# --description--
+
+Great! `7` is not present in the first row of the sudoku board and the method is telling that `7` is a valid choice for that row.
+
+Now delete the `print` call.
+
+# --hints--
+
+You should not have `print(gameboard.valid_in_row(0, 7))` in your code.
+
+```js
+({ test: () => assert.isFalse(runPython(`_Node(_code).has_call("print(gameboard.valid_in_row(0, 7))")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+ return None
+
+ def valid_in_row(self, row, num):
+ return num not in self.board[row]
+
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+
+gameboard = Board(puzzle)
+--fcc-editable-region--
+print(gameboard.valid_in_row(0, 7))
+--fcc-editable-region--
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606c14182435d4bab0de2ee.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606c14182435d4bab0de2ee.md
new file mode 100644
index 00000000000..ef34a921e1f
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606c14182435d4bab0de2ee.md
@@ -0,0 +1,65 @@
+---
+id: 6606c14182435d4bab0de2ee
+title: Step 30
+challengeType: 20
+dashedName: step-30
+---
+
+# --description--
+
+Next, you're going to create a method that checks if a number can be inserted in a specified column of the sudoku board by checking if the number is not already present in that column.
+
+Within the `Board` class, create a method named `valid_in_col` and give it three parameters: `self`, `col` and `num`.
+Where `col` and `num` are the column index and the number to be checked, respectively.
+
+# --hints--
+
+You should create a new method named `valid_in_col` within the `Board` class.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").has_function("valid_in_col")`)) })
+```
+
+Your `valid_in_col` method should have three parameters: `self`, `col`, and `num`, in this order.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").find_function("valid_in_col").has_args("self, col, num")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+ return None
+
+ def valid_in_row(self, row, num):
+ return num not in self.board[row]
+--fcc-editable-region--
+
+--fcc-editable-region--
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+
+gameboard = Board(puzzle)
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606c2d203a8124c83b2234b.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606c2d203a8124c83b2234b.md
new file mode 100644
index 00000000000..ac069897fe7
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606c2d203a8124c83b2234b.md
@@ -0,0 +1,59 @@
+---
+id: 6606c2d203a8124c83b2234b
+title: Step 31
+challengeType: 20
+dashedName: step-31
+---
+
+# --description--
+
+You need to check if a given number is not equal to the number in the specified column of the current row.
+
+For this, replace `pass` with a generator expression that iterates over the range from `0` to `8` (inclusive), and for each `row`, evaluates whether the number at the specified `row` and column `col` on the board is different from `num`.
+
+# --hints--
+
+You should delete `pass` and create a generator expression `(self.board[row][col] != num for row in range(9))`.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").find_function("valid_in_col").find_body().is_equivalent("(self.board[row][col] != num for row in range(9))")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+ return None
+
+ def valid_in_row(self, row, num):
+ return num not in self.board[row]
+--fcc-editable-region--
+ def valid_in_col(self, col, num):
+ pass
+--fcc-editable-region--
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+
+gameboard = Board(puzzle)
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606c3fd5634684d48a7887b.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606c3fd5634684d48a7887b.md
new file mode 100644
index 00000000000..9a886c64188
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606c3fd5634684d48a7887b.md
@@ -0,0 +1,59 @@
+---
+id: 6606c3fd5634684d48a7887b
+title: Step 32
+challengeType: 20
+dashedName: step-32
+---
+
+# --description--
+
+The generator expression you just wrote in the previous step generates a list of boolean values representing whether the condition `self.board[row][col] != num` is `True` or `False` for each element in the specified column across all rows.
+
+Pass that generator expression to the `all()` function to check if all the elements in the column are different from `num` and return the result.
+
+# --hints--
+
+You should pass the generator expression as the argument to an `all()` call and return the result.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").find_function("valid_in_col").find_body().is_equivalent("return all(self.board[row][col] != num for row in range(9))")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+ return None
+
+ def valid_in_row(self, row, num):
+ return num not in self.board[row]
+--fcc-editable-region--
+ def valid_in_col(self, col, num):
+ (self.board[row][col] != num for row in range(9))
+--fcc-editable-region--
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+
+gameboard = Board(puzzle)
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606cb019db4f74f224856f4.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606cb019db4f74f224856f4.md
new file mode 100644
index 00000000000..386bf918d7e
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606cb019db4f74f224856f4.md
@@ -0,0 +1,60 @@
+---
+id: 6606cb019db4f74f224856f4
+title: Step 33
+challengeType: 20
+dashedName: step-33
+---
+
+# --description--
+
+Call `valid_in_col` on `gameboard`. Pass it `0` and `7` as the arguments to see if the number `7` is allowed in the first column of the board and print the result.
+
+# --hints--
+
+You should print the result of calling `valid_in_col(0, 7)` on `gameboard`.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).has_call("print(gameboard.valid_in_col(0, 7))")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+ return None
+
+ def valid_in_row(self, row, num):
+ return num not in self.board[row]
+
+ def valid_in_col(self, col, num):
+ return all(self.board[row][col] != num for row in range(9))
+
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+
+gameboard = Board(puzzle)
+--fcc-editable-region--
+
+--fcc-editable-region--
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606cc088fd3574fa9010a4f.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606cc088fd3574fa9010a4f.md
new file mode 100644
index 00000000000..5e0464e3165
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606cc088fd3574fa9010a4f.md
@@ -0,0 +1,60 @@
+---
+id: 6606cc088fd3574fa9010a4f
+title: Step 34
+challengeType: 20
+dashedName: step-34
+---
+
+# --description--
+
+Now change the `7` into a `1`.
+
+# --hints--
+
+You should modify your `print` call to print the result of calling `valid_in_col(0, 1)` on `gameboard`.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).has_call("print(gameboard.valid_in_col(0, 1))")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+ return None
+
+ def valid_in_row(self, row, num):
+ return num not in self.board[row]
+
+ def valid_in_col(self, col, num):
+ return all(self.board[row][col] != num for row in range(9))
+
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+
+gameboard = Board(puzzle)
+--fcc-editable-region--
+print(gameboard.valid_in_col(0, 7))
+--fcc-editable-region--
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606cc473675e85017b0c53d.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606cc473675e85017b0c53d.md
new file mode 100644
index 00000000000..3ab272768c6
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606cc473675e85017b0c53d.md
@@ -0,0 +1,60 @@
+---
+id: 6606cc473675e85017b0c53d
+title: Step 35
+challengeType: 20
+dashedName: step-35
+---
+
+# --description--
+
+The `1` is already present in the first column. So, everything seems to work fine. Now delete your `print` call.
+
+# --hints--
+
+You should not have `print(gameboard.valid_in_col(0, 1))` in your code.
+
+```js
+({ test: () => assert.isFalse(runPython(`_Node(_code).has_call("print(gameboard.valid_in_col(0, 1))")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+ return None
+
+ def valid_in_row(self, row, num):
+ return num not in self.board[row]
+
+ def valid_in_col(self, col, num):
+ return all(self.board[row][col] != num for row in range(9))
+
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+
+gameboard = Board(puzzle)
+--fcc-editable-region--
+print(gameboard.valid_in_col(0, 1))
+--fcc-editable-region--
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606cc754a8834509cd0afb6.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606cc754a8834509cd0afb6.md
new file mode 100644
index 00000000000..28d7a78067a
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606cc754a8834509cd0afb6.md
@@ -0,0 +1,67 @@
+---
+id: 6606cc754a8834509cd0afb6
+title: Step 36
+challengeType: 20
+dashedName: step-36
+---
+
+# --description--
+
+Another thing to check is if a number can be inserted in a 3x3 square.
+
+Inside the `Board` class, create a method named `valid_in_square` with four parameters: `self`, `row`, `col`, and `num`. Where `row`, `col`, and `num` represent the row index, the column index, and the number to be checked, respectively.
+
+# --hints--
+
+You should create a new method named `valid_in_square` within the `Board` class.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").has_function("valid_in_square")`)) })
+```
+
+Your `valid_in_square` method should have four parameters: `self`, `row`, `col`, and `num`, in this order.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").find_function("valid_in_square").has_args("self, row, col, num")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+ return None
+
+ def valid_in_row(self, row, num):
+ return num not in self.board[row]
+
+ def valid_in_col(self, col, num):
+ return all(self.board[row][col] != num for row in range(9))
+--fcc-editable-region--
+
+--fcc-editable-region--
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+
+gameboard = Board(puzzle)
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606cd69f56e27516583b0cc.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606cd69f56e27516583b0cc.md
new file mode 100644
index 00000000000..33da7d91d09
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606cd69f56e27516583b0cc.md
@@ -0,0 +1,63 @@
+---
+id: 6606cd69f56e27516583b0cc
+title: Step 37
+challengeType: 20
+dashedName: step-37
+---
+
+# --description--
+
+Now you need to calculate the starting row index for the 3x3 square within the board grid and ensure that the starting row index for each 3x3 square is a multiple of 3.
+
+This can be achieved by taking the result of the integer division `row // 3` multiplied by `3`. Replace `pass` with a variable `row_start` and assign it `(row // 3) * 3`.
+
+
+# --hints--
+
+You should delete `pass` and declare a variable `row_start` with the value of `(row // 3) * 3`.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").find_function("valid_in_square").find_body().is_equivalent("row_start = (row//3)*3")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+ return None
+
+ def valid_in_row(self, row, num):
+ return num not in self.board[row]
+
+ def valid_in_col(self, col, num):
+ return all(self.board[row][col] != num for row in range(9))
+--fcc-editable-region--
+ def valid_in_square(self, row, col, num):
+ pass
+--fcc-editable-region--
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+
+gameboard = Board(puzzle)
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606cf1b2b9f65529c161098.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606cf1b2b9f65529c161098.md
new file mode 100644
index 00000000000..5249161fe0d
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606cf1b2b9f65529c161098.md
@@ -0,0 +1,62 @@
+---
+id: 6606cf1b2b9f65529c161098
+title: Step 38
+challengeType: 20
+dashedName: step-38
+---
+
+# --description--
+
+Similarly to the previous step, you need to ensure that the starting column index for each 3x3 square is a multiple of 3.
+
+Declare a variable `col_start` and assign it `(col // 3) * 3`.
+
+# --hints--
+
+You should declare a variable `col_start` with the value of `(col // 3) * 3`.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").find_function("valid_in_square").find_variable("col_start").is_equivalent("col_start = (col//3)*3")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+ return None
+
+ def valid_in_row(self, row, num):
+ return num not in self.board[row]
+
+ def valid_in_col(self, col, num):
+ return all(self.board[row][col] != num for row in range(9))
+--fcc-editable-region--
+ def valid_in_square(self, row, col, num):
+ row_start = (row // 3) * 3
+--fcc-editable-region--
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+
+gameboard = Board(puzzle)
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606d03ff198245383e61d90.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606d03ff198245383e61d90.md
new file mode 100644
index 00000000000..e8494c7e89c
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606d03ff198245383e61d90.md
@@ -0,0 +1,67 @@
+---
+id: 6606d03ff198245383e61d90
+title: Step 39
+challengeType: 20
+dashedName: step-39
+---
+
+# --description--
+
+Now, iterate only over the rows inside the 3x3 square by creating a `for` loop. Use the `range()` function to generate a sequence starting at `row_start`, and use `row_no` as the loop variable.
+
+# --hints--
+
+You should create a `for` loop that iterates over `range(row_start, row_start + 3)`.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").find_function("valid_in_square").find_for_loops()[0].find_for_iter().is_equivalent("range(row_start, row_start + 3)")`)) })
+```
+
+Your `for` loop should use `row_no` as the loop variable.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").find_function("valid_in_square").find_for_loops()[0].find_for_vars().is_equivalent("row_no")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+ return None
+
+ def valid_in_row(self, row, num):
+ return num not in self.board[row]
+
+ def valid_in_col(self, col, num):
+ return all(self.board[row][col] != num for row in range(9))
+--fcc-editable-region--
+ def valid_in_square(self, row, col, num):
+ row_start = (row // 3) * 3
+ col_start = (col // 3) * 3
+--fcc-editable-region--
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+
+gameboard = Board(puzzle)
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606d32096165654b8e73f21.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606d32096165654b8e73f21.md
new file mode 100644
index 00000000000..0883d525ea7
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606d32096165654b8e73f21.md
@@ -0,0 +1,69 @@
+---
+id: 6606d32096165654b8e73f21
+title: Step 40
+challengeType: 20
+dashedName: step-40
+---
+
+# --description--
+
+Inside the loop created in the previous step, nest another `for` loop to iterate over a sequence of three elements starting at `col_start`. Use the `range()` function to generate this sequence and `col_no` as the loop variable.
+
+# --hints--
+
+You should create a `for` loop that iterates over `range(col_start, col_start + 3)` inside the existing loop body.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").find_function("valid_in_square").find_for_loops()[0].find_for_loops()[0].find_for_iter().is_equivalent("range(col_start, col_start + 3)")`)) })
+```
+
+Your `for` loop should use `col_no` as the loop variable.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").find_function("valid_in_square").find_for_loops()[0].find_for_loops()[0].find_for_vars().is_equivalent("col_no")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+ return None
+
+ def valid_in_row(self, row, num):
+ return num not in self.board[row]
+
+ def valid_in_col(self, col, num):
+ return all(self.board[row][col] != num for row in range(9))
+--fcc-editable-region--
+ def valid_in_square(self, row, col, num):
+ row_start = (row // 3) * 3
+ col_start = (col // 3) * 3
+ for row_no in range(row_start, row_start + 3):
+ pass
+--fcc-editable-region--
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+
+gameboard = Board(puzzle)
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606d378de78d55523f08298.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606d378de78d55523f08298.md
new file mode 100644
index 00000000000..510aa44cbec
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606d378de78d55523f08298.md
@@ -0,0 +1,72 @@
+---
+id: 6606d378de78d55523f08298
+title: Step 41
+challengeType: 20
+dashedName: step-41
+---
+
+# --description--
+
+Now, check if the given number `num` is already present in the current cell of the 3x3 square.
+
+Replace `pass` with an `if` statement that checks if the number in the current cell of the sudoku board is equal to `num`. If so, return `False` from the `if` body, indicating that the number is not a valid choice.
+
+# --hints--
+
+You should delete `pass` and create an `if` statement that checks if the current cell of the sudoku board is equal to `num`.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").find_function("valid_in_square").find_for_loops()[0].find_for_loops()[0].find_ifs()[0].find_conditions()[0].is_equivalent("self.board[row_no][col_no] == num")`)) })
+```
+
+You should return `False` from your new `if` statement body.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").find_function("valid_in_square").find_for_loops()[0].find_for_loops()[0].find_ifs()[0].find_bodies()[0].is_equivalent("return False")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+ return None
+
+ def valid_in_row(self, row, num):
+ return num not in self.board[row]
+
+ def valid_in_col(self, col, num):
+ return all(self.board[row][col] != num for row in range(9))
+--fcc-editable-region--
+ def valid_in_square(self, row, col, num):
+ row_start = (row // 3) * 3
+ col_start = (col // 3) * 3
+ for row_no in range(row_start, row_start + 3):
+ for col_no in range(col_start, col_start + 3):
+ pass
+--fcc-editable-region--
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+
+gameboard = Board(puzzle)
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606d589750ad655fa0df168.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606d589750ad655fa0df168.md
new file mode 100644
index 00000000000..57c318d7286
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606d589750ad655fa0df168.md
@@ -0,0 +1,68 @@
+---
+id: 6606d589750ad655fa0df168
+title: Step 42
+challengeType: 20
+dashedName: step-42
+---
+
+# --description--
+
+If the number is not present, it can be inserted into the square without violating the rules of sudoku.
+
+After the outer `for` loop, return `True`.
+
+
+# --hints--
+
+You should return `True` after the outer `for` loop.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").find_function("valid_in_square").has_return("True")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+ return None
+
+ def valid_in_row(self, row, num):
+ return num not in self.board[row]
+
+ def valid_in_col(self, col, num):
+ return all(self.board[row][col] != num for row in range(9))
+--fcc-editable-region--
+ def valid_in_square(self, row, col, num):
+ row_start = (row // 3) * 3
+ col_start = (col // 3) * 3
+ for row_no in range(row_start, row_start + 3):
+ for col_no in range(col_start, col_start + 3):
+ if self.board[row_no][col_no] == num:
+ return False
+--fcc-editable-region--
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+
+gameboard = Board(puzzle)
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606d6138c49e456920fa818.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606d6138c49e456920fa818.md
new file mode 100644
index 00000000000..fe7d7e925a1
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606d6138c49e456920fa818.md
@@ -0,0 +1,69 @@
+---
+id: 6606d6138c49e456920fa818
+title: Step 43
+challengeType: 20
+dashedName: step-43
+---
+
+# --description--
+
+Test the method to ensure it works properly by calling `valid_in_square` on `gameboard`. Pass it `1`, `0`, and `3` as the arguments and print the result.
+
+# --hints--
+
+You should print the result of calling `valid_in_square(1, 0, 3)` on `gameboard`.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).has_call("print(gameboard.valid_in_square(1, 0, 3))")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+ return None
+
+ def valid_in_row(self, row, num):
+ return num not in self.board[row]
+
+ def valid_in_col(self, col, num):
+ return all(self.board[row][col] != num for row in range(9))
+
+ def valid_in_square(self, row, col, num):
+ row_start = (row // 3) * 3
+ col_start = (col // 3) * 3
+ for row_no in range(row_start, row_start + 3):
+ for col_no in range(col_start, col_start + 3):
+ if self.board[row_no][col_no] == num:
+ return False
+ return True
+
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+
+gameboard = Board(puzzle)
+--fcc-editable-region--
+
+--fcc-editable-region--
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606d7bb9e4c6b574235159a.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606d7bb9e4c6b574235159a.md
new file mode 100644
index 00000000000..6f42cb307ec
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606d7bb9e4c6b574235159a.md
@@ -0,0 +1,69 @@
+---
+id: 6606d7bb9e4c6b574235159a
+title: Step 44
+challengeType: 20
+dashedName: step-44
+---
+
+# --description--
+
+The method returns `False` because `3` is already present in that square. Try another square by changing the column index to `6`.
+
+# --hints--
+
+You should print the result of calling `valid_in_square(1, 6, 3)` on `gameboard`.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).has_call("print(gameboard.valid_in_square(1, 6, 3))")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+ return None
+
+ def valid_in_row(self, row, num):
+ return num not in self.board[row]
+
+ def valid_in_col(self, col, num):
+ return all(self.board[row][col] != num for row in range(9))
+
+ def valid_in_square(self, row, col, num):
+ row_start = (row // 3) * 3
+ col_start = (col // 3) * 3
+ for row_no in range(row_start, row_start + 3):
+ for col_no in range(col_start, col_start + 3):
+ if self.board[row_no][col_no] == num:
+ return False
+ return True
+
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+
+gameboard = Board(puzzle)
+--fcc-editable-region--
+print(gameboard.valid_in_square(1, 0, 3))
+--fcc-editable-region--
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606d8795bd533582425a363.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606d8795bd533582425a363.md
new file mode 100644
index 00000000000..23e9f5ee47e
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606d8795bd533582425a363.md
@@ -0,0 +1,69 @@
+---
+id: 6606d8795bd533582425a363
+title: Step 45
+challengeType: 20
+dashedName: step-45
+---
+
+# --description--
+
+Everything works fine. Now delete your `print` call.
+
+# --hints--
+
+You should not have `print(gameboard.valid_in_square(1, 6, 3))` in your code.
+
+```js
+({ test: () => assert.isFalse(runPython(`_Node(_code).has_call("print(gameboard.valid_in_square(1, 6, 3))")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+ return None
+
+ def valid_in_row(self, row, num):
+ return num not in self.board[row]
+
+ def valid_in_col(self, col, num):
+ return all(self.board[row][col] != num for row in range(9))
+
+ def valid_in_square(self, row, col, num):
+ row_start = (row // 3) * 3
+ col_start = (col // 3) * 3
+ for row_no in range(row_start, row_start + 3):
+ for col_no in range(col_start, col_start + 3):
+ if self.board[row_no][col_no] == num:
+ return False
+ return True
+
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+
+gameboard = Board(puzzle)
+--fcc-editable-region--
+print(gameboard.valid_in_square(1, 6, 3))
+--fcc-editable-region--
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606d8c323d6205890fbbd54.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606d8c323d6205890fbbd54.md
new file mode 100644
index 00000000000..5e38ed30dc9
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606d8c323d6205890fbbd54.md
@@ -0,0 +1,76 @@
+---
+id: 6606d8c323d6205890fbbd54
+title: Step 46
+challengeType: 20
+dashedName: step-46
+---
+
+# --description--
+
+Within the `Board` class, create another method `is_valid` and give it three parameters: `self`, `empty`, and `num`. Where `empty` is a tuple representing the row and column indices of an empty cell and `num` is the number to be checked.
+
+This method will check if a given number is a valid choice for an empty cell in the sudoku board by validating its compatibility with the row, column, and 3x3 square of the specified empty cell.
+
+# --hints--
+
+You should create a new method named `is_valid` within the `Board` class.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").has_function("is_valid")`)) })
+```
+
+Your `is_valid` method should have three parameters: `self`, `empty`, and `num`, in this order.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").find_function("is_valid").has_args("self, empty, num")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+ return None
+
+ def valid_in_row(self, row, num):
+ return num not in self.board[row]
+
+ def valid_in_col(self, col, num):
+ return all(self.board[row][col] != num for row in range(9))
+
+ def valid_in_square(self, row, col, num):
+ row_start = (row // 3) * 3
+ col_start = (col // 3) * 3
+ for row_no in range(row_start, row_start + 3):
+ for col_no in range(col_start, col_start + 3):
+ if self.board[row_no][col_no] == num:
+ return False
+ return True
+--fcc-editable-region--
+
+--fcc-editable-region--
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+
+gameboard = Board(puzzle)
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606d9d92fcf78598b3b5184.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606d9d92fcf78598b3b5184.md
new file mode 100644
index 00000000000..6a3f44cf9f5
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606d9d92fcf78598b3b5184.md
@@ -0,0 +1,78 @@
+---
+id: 6606d9d92fcf78598b3b5184
+title: Step 47
+challengeType: 20
+dashedName: step-47
+---
+
+# --description--
+
+A tuple can be unpacked, meaning that the elements contained in the tuple can be assigned to variables, like this:
+
+```py
+spam = ('lemon', 'curry')
+item1, item2 = spam
+```
+
+In the example above, `item1` would have the value `'lemon'` and `item2` would have the value `'curry'`.
+
+Inside the method, delete `pass` and unpack the `empty` tuple into `row` and `col`.
+
+# --hints--
+
+You should delete `pass` and unpack the `empty` tuple into `row` and `col`.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").find_function("is_valid").find_body().is_equivalent("row, col = empty")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+ return None
+
+ def valid_in_row(self, row, num):
+ return num not in self.board[row]
+
+ def valid_in_col(self, col, num):
+ return all(self.board[row][col] != num for row in range(9))
+
+ def valid_in_square(self, row, col, num):
+ row_start = (row // 3) * 3
+ col_start = (col // 3) * 3
+ for row_no in range(row_start, row_start + 3):
+ for col_no in range(col_start, col_start + 3):
+ if self.board[row_no][col_no] == num:
+ return False
+ return True
+--fcc-editable-region--
+ def is_valid(self, empty, num):
+ pass
+--fcc-editable-region--
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+
+gameboard = Board(puzzle)
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606db6a23a1455a402f91ae.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606db6a23a1455a402f91ae.md
new file mode 100644
index 00000000000..a9b47240046
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606db6a23a1455a402f91ae.md
@@ -0,0 +1,69 @@
+---
+id: 6606db6a23a1455a402f91ae
+title: Step 48
+challengeType: 20
+dashedName: step-48
+---
+
+# --description--
+
+Within the `is_valid` method, check if the number is valid for insertion in the specified row by calling the `valid_in_row()` method with `row` and `num` as arguments, and assign the result to a variable `valid_in_row`. Remember to use `self` to reference the methods of the current instance.
+
+# --hints--
+
+You should declare a variable `valid_in_row` and assign it `self.valid_in_row(row, num)`.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").find_function("is_valid").find_variable("valid_in_row").is_equivalent("valid_in_row = self.valid_in_row(row, num)")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+ return None
+
+ def valid_in_row(self, row, num):
+ return num not in self.board[row]
+
+ def valid_in_col(self, col, num):
+ return all(self.board[row][col] != num for row in range(9))
+
+ def valid_in_square(self, row, col, num):
+ row_start = (row // 3) * 3
+ col_start = (col // 3) * 3
+ for row_no in range(row_start, row_start + 3):
+ for col_no in range(col_start, col_start + 3):
+ if self.board[row_no][col_no] == num:
+ return False
+ return True
+--fcc-editable-region--
+ def is_valid(self, empty, num):
+ row, col = empty
+--fcc-editable-region--
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+
+gameboard = Board(puzzle)
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606dcf5a31e4e5b43737417.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606dcf5a31e4e5b43737417.md
new file mode 100644
index 00000000000..1ae8a2c49c4
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606dcf5a31e4e5b43737417.md
@@ -0,0 +1,70 @@
+---
+id: 6606dcf5a31e4e5b43737417
+title: Step 49
+challengeType: 20
+dashedName: step-49
+---
+
+# --description--
+
+Check if the number is valid for insertion in the specified column by calling the `valid_in_col()` method with `col` and `num` as the arguments and assign the result to a variable `valid_in_col`.
+
+# --hints--
+
+You should declare a variable `valid_in_col` and assign it `self.valid_in_col(col, num)`.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").find_function("is_valid").find_variable("valid_in_col").is_equivalent("valid_in_col = self.valid_in_col(col, num)")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+ return None
+
+ def valid_in_row(self, row, num):
+ return num not in self.board[row]
+
+ def valid_in_col(self, col, num):
+ return all(self.board[row][col] != num for row in range(9))
+
+ def valid_in_square(self, row, col, num):
+ row_start = (row // 3) * 3
+ col_start = (col // 3) * 3
+ for row_no in range(row_start, row_start + 3):
+ for col_no in range(col_start, col_start + 3):
+ if self.board[row_no][col_no] == num:
+ return False
+ return True
+--fcc-editable-region--
+ def is_valid(self, empty, num):
+ row, col = empty
+ valid_in_row = self.valid_in_row(row, num)
+--fcc-editable-region--
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+
+gameboard = Board(puzzle)
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606dd63109f9f5c2195e30c.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606dd63109f9f5c2195e30c.md
new file mode 100644
index 00000000000..d235ac18532
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606dd63109f9f5c2195e30c.md
@@ -0,0 +1,71 @@
+---
+id: 6606dd63109f9f5c2195e30c
+title: Step 50
+challengeType: 20
+dashedName: step-50
+---
+
+# --description--
+
+Check if the number is valid for insertion in the specified 3x3 square by calling the `valid_in_square()` method with `row`, `col` and `num` as the arguments and assign the result to a variable `valid_in_square`.
+
+# --hints--
+
+You should declare a variable `valid_in_square` and assign it `self.valid_in_square(row, col, num)`.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").find_function("is_valid").find_variable("valid_in_square").is_equivalent("valid_in_square = self.valid_in_square(row, col, num)")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+ return None
+
+ def valid_in_row(self, row, num):
+ return num not in self.board[row]
+
+ def valid_in_col(self, col, num):
+ return all(self.board[row][col] != num for row in range(9))
+
+ def valid_in_square(self, row, col, num):
+ row_start = (row // 3) * 3
+ col_start = (col // 3) * 3
+ for row_no in range(row_start, row_start + 3):
+ for col_no in range(col_start, col_start + 3):
+ if self.board[row_no][col_no] == num:
+ return False
+ return True
+--fcc-editable-region--
+ def is_valid(self, empty, num):
+ row, col = empty
+ valid_in_row = self.valid_in_row(row, num)
+ valid_in_col = self.valid_in_col(col, num)
+--fcc-editable-region--
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+
+gameboard = Board(puzzle)
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606de006a82e05c9a65cebe.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606de006a82e05c9a65cebe.md
new file mode 100644
index 00000000000..40911802bc0
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606de006a82e05c9a65cebe.md
@@ -0,0 +1,78 @@
+---
+id: 6606de006a82e05c9a65cebe
+title: Step 51
+challengeType: 20
+dashedName: step-51
+---
+
+# --description--
+
+To verify that the number is valid after all those checks, call the `all()` function and pass it a list containing `valid_in_row`, `valid_in_col`, and `valid_in_square`. Also, return the result of the `all()` call.
+
+# --hints--
+
+You should return a call to the `all()` function passing it a list containing `valid_in_row`, `valid_in_col`, and `valid_in_square`.
+
+```js
+({ test: () => assert(runPython(`
+import itertools
+p = list(itertools.permutations(["valid_in_row", "valid_in_col", "valid_in_square"]))
+l = [", ".join(i) for i in p]
+node = _Node(_code).find_class("Board").find_function("is_valid")
+any([node.has_return(f"all([{i}])") for i in l])
+`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+ return None
+
+ def valid_in_row(self, row, num):
+ return num not in self.board[row]
+
+ def valid_in_col(self, col, num):
+ return all(self.board[row][col] != num for row in range(9))
+
+ def valid_in_square(self, row, col, num):
+ row_start = (row // 3) * 3
+ col_start = (col // 3) * 3
+ for row_no in range(row_start, row_start + 3):
+ for col_no in range(col_start, col_start + 3):
+ if self.board[row_no][col_no] == num:
+ return False
+ return True
+--fcc-editable-region--
+ def is_valid(self, empty, num):
+ row, col = empty
+ valid_in_row = self.valid_in_row(row, num)
+ valid_in_col = self.valid_in_col(col, num)
+ valid_in_square = self.valid_in_square(row, col, num)
+--fcc-editable-region--
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+
+gameboard = Board(puzzle)
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606e2f27f19ca5f398c6aed.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606e2f27f19ca5f398c6aed.md
new file mode 100644
index 00000000000..6860061dfdb
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606e2f27f19ca5f398c6aed.md
@@ -0,0 +1,83 @@
+---
+id: 6606e2f27f19ca5f398c6aed
+title: Step 52
+challengeType: 20
+dashedName: step-52
+---
+
+# --description--
+
+Next, you'll work on a method that attempts to solve the sudoku in-place, meaning it will modify the existing sudoku board rather than creating a new one.
+
+Within the `Board` class, create a method named`solver` and give it a single parameter, `self`.
+
+# --hints--
+
+You should create a new method named `solver` within the `Board` class.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").has_function("solver")`)) })
+```
+
+Your `solver` method should have a single parameter `self`.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").find_function("solver").has_args("self")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+ return None
+
+ def valid_in_row(self, row, num):
+ return num not in self.board[row]
+
+ def valid_in_col(self, col, num):
+ return all(self.board[row][col] != num for row in range(9))
+
+ def valid_in_square(self, row, col, num):
+ row_start = (row // 3) * 3
+ col_start = (col // 3) * 3
+ for row_no in range(row_start, row_start + 3):
+ for col_no in range(col_start, col_start + 3):
+ if self.board[row_no][col_no] == num:
+ return False
+ return True
+
+ def is_valid(self, empty, num):
+ row, col = empty
+ valid_in_row = self.valid_in_row(row, num)
+ valid_in_col = self.valid_in_col(col, num)
+ valid_in_square = self.valid_in_square(row, col, num)
+ return all([valid_in_row, valid_in_col, valid_in_square])
+--fcc-editable-region--
+
+--fcc-editable-region--
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+
+gameboard = Board(puzzle)
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606e3e6231702600bd5860c.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606e3e6231702600bd5860c.md
new file mode 100644
index 00000000000..58e13940974
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/6606e3e6231702600bd5860c.md
@@ -0,0 +1,82 @@
+---
+id: 6606e3e6231702600bd5860c
+title: Step 53
+challengeType: 20
+dashedName: step-53
+---
+
+# --description--
+
+Delete `pass` and create an `if` statement that checks if the value returned by `find_empty_cell` is `None`. In that case, the puzzle is solved. Therefore, return `True` from the `if` body.
+
+# --hints--
+
+You should delete `pass` and create an `if` statement that checks if the value returned by `self.find_empty_cell` is `None`.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").find_function("solver").find_ifs()[0].find_conditions()[0].is_equivalent("self.find_empty_cell() is None")`)) })
+```
+
+You should return `True` from your new `if` statement body.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").find_function("solver").find_ifs()[0].find_bodies()[0].is_equivalent("return True")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+ return None
+
+ def valid_in_row(self, row, num):
+ return num not in self.board[row]
+
+ def valid_in_col(self, col, num):
+ return all(self.board[row][col] != num for row in range(9))
+
+ def valid_in_square(self, row, col, num):
+ row_start = (row // 3) * 3
+ col_start = (col // 3) * 3
+ for row_no in range(row_start, row_start + 3):
+ for col_no in range(col_start, col_start + 3):
+ if self.board[row_no][col_no] == num:
+ return False
+ return True
+
+ def is_valid(self, empty, num):
+ row, col = empty
+ valid_in_row = self.valid_in_row(row, num)
+ valid_in_col = self.valid_in_col(col, num)
+ valid_in_square = self.valid_in_square(row, col, num)
+ return all([valid_in_row, valid_in_col, valid_in_square])
+--fcc-editable-region--
+ def solver(self):
+ pass
+--fcc-editable-region--
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+
+gameboard = Board(puzzle)
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660a737f0f72b51de361051c.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660a737f0f72b51de361051c.md
new file mode 100644
index 00000000000..94dabecb93b
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660a737f0f72b51de361051c.md
@@ -0,0 +1,83 @@
+---
+id: 660a737f0f72b51de361051c
+title: Step 54
+challengeType: 20
+dashedName: step-54
+---
+
+# --description--
+
+The `:=` operator gives you the ability to assign variables in the middle of an expression. The syntax is: `name := val`, where `name` is the variable name and `val` is the variable value.
+
+This construct is formally named *assignment expressions*, while the `:=` operator is commonly referred to as the *walrus* operator.
+
+Since you are going to need the `self.find_empty_cell()` call more than once, assign it to a variable `next_empty` by using the walrus operator. Then, enclose the assignment between a pair of parentheses.
+
+In this way, you'll combine the assignment and the conditional check into a single line, making the code more concise.
+
+# --hints--
+
+You should modify the `if` condition into `(next_empty := self.find_empty_cell()) is None`.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").find_function("solver").find_ifs()[0].find_conditions()[0].is_equivalent("(next_empty := self.find_empty_cell()) is None")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+ return None
+
+ def valid_in_row(self, row, num):
+ return num not in self.board[row]
+
+ def valid_in_col(self, col, num):
+ return all(self.board[row][col] != num for row in range(9))
+
+ def valid_in_square(self, row, col, num):
+ row_start = (row // 3) * 3
+ col_start = (col // 3) * 3
+ for row_no in range(row_start, row_start + 3):
+ for col_no in range(col_start, col_start + 3):
+ if self.board[row_no][col_no] == num:
+ return False
+ return True
+
+ def is_valid(self, empty, num):
+ row, col = empty
+ valid_in_row = self.valid_in_row(row, num)
+ valid_in_col = self.valid_in_col(col, num)
+ valid_in_square = self.valid_in_square(row, col, num)
+ return all([valid_in_row, valid_in_col, valid_in_square])
+--fcc-editable-region--
+ def solver(self):
+ if self.find_empty_cell() is None:
+ return True
+--fcc-editable-region--
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+
+gameboard = Board(puzzle)
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660a7a1cac69b7217cbae22d.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660a7a1cac69b7217cbae22d.md
new file mode 100644
index 00000000000..f2dbb731d23
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660a7a1cac69b7217cbae22d.md
@@ -0,0 +1,85 @@
+---
+id: 660a7a1cac69b7217cbae22d
+title: Step 55
+challengeType: 20
+dashedName: step-55
+---
+
+# --description--
+
+After the `if` statement, create a `for` loop to iterate over the range from `1` to `9` inclusive. Use `guess` as the loop variable.
+
+This loop will enable you to systematically check if any cipher from `1` to `9` is suitable to fill an empty cell.
+
+# --hints--
+
+You should create a `for` loop that iterates over `range(1, 10)`.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").find_function("solver").find_for_loops()[0].find_for_iter().is_equivalent("range(1, 10)")`)) })
+```
+
+Your `for` loop should have `guess` as the loop variable.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").find_function("solver").find_for_loops()[0].find_for_vars().is_equivalent("guess")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+ return None
+
+ def valid_in_row(self, row, num):
+ return num not in self.board[row]
+
+ def valid_in_col(self, col, num):
+ return all(self.board[row][col] != num for row in range(9))
+
+ def valid_in_square(self, row, col, num):
+ row_start = (row // 3) * 3
+ col_start = (col // 3) * 3
+ for row_no in range(row_start, row_start + 3):
+ for col_no in range(col_start, col_start + 3):
+ if self.board[row_no][col_no] == num:
+ return False
+ return True
+
+ def is_valid(self, empty, num):
+ row, col = empty
+ valid_in_row = self.valid_in_row(row, num)
+ valid_in_col = self.valid_in_col(col, num)
+ valid_in_square = self.valid_in_square(row, col, num)
+ return all([valid_in_row, valid_in_col, valid_in_square])
+--fcc-editable-region--
+ def solver(self):
+ if (next_empty := self.find_empty_cell()) is None:
+ return True
+--fcc-editable-region--
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+
+gameboard = Board(puzzle)
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660a7cb75dce3d22ab562c0d.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660a7cb75dce3d22ab562c0d.md
new file mode 100644
index 00000000000..71967721182
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660a7cb75dce3d22ab562c0d.md
@@ -0,0 +1,81 @@
+---
+id: 660a7cb75dce3d22ab562c0d
+title: Step 56
+challengeType: 20
+dashedName: step-56
+---
+
+# --description--
+
+Inside the loop body, replace `pass` with an `if` statement that checks if the number is a valid choice for the current cell.
+
+Build the `if` condition with an `is_valid` call, passing `next_empty` and `guess` as the arguments.
+
+# --hints--
+
+You should delete `pass` and create an `if` statement that checks if `self.is_valid(next_empty, guess)` is `True`.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").find_function("solver").find_for_loops()[0].find_bodies()[0].is_equivalent("if self.is_valid(next_empty, guess):\\n pass")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+ return None
+
+ def valid_in_row(self, row, num):
+ return num not in self.board[row]
+
+ def valid_in_col(self, col, num):
+ return all(self.board[row][col] != num for row in range(9))
+
+ def valid_in_square(self, row, col, num):
+ row_start = (row // 3) * 3
+ col_start = (col // 3) * 3
+ for row_no in range(row_start, row_start + 3):
+ for col_no in range(col_start, col_start + 3):
+ if self.board[row_no][col_no] == num:
+ return False
+ return True
+
+ def is_valid(self, empty, num):
+ row, col = empty
+ valid_in_row = self.valid_in_row(row, num)
+ valid_in_col = self.valid_in_col(col, num)
+ valid_in_square = self.valid_in_square(row, col, num)
+ return all([valid_in_row, valid_in_col, valid_in_square])
+--fcc-editable-region--
+ def solver(self):
+ if (next_empty := self.find_empty_cell()) is None:
+ return True
+ for guess in range(1, 10):
+ pass
+--fcc-editable-region--
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+
+gameboard = Board(puzzle)
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660a7ea6e3a21a243d6aa288.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660a7ea6e3a21a243d6aa288.md
new file mode 100644
index 00000000000..589878799fb
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660a7ea6e3a21a243d6aa288.md
@@ -0,0 +1,80 @@
+---
+id: 660a7ea6e3a21a243d6aa288
+title: Step 57
+challengeType: 20
+dashedName: step-57
+---
+
+# --description--
+
+Inside the `if` body, delete `pass` and unpack the tuple `next_empty` into `row, col`.
+
+# --hints--
+
+You should delete `pass` and unpack the tuple `next_empty` into `row, col`.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").find_function("solver").find_for_loops()[0].find_ifs()[0].find_bodies()[0].is_equivalent("row, col = next_empty")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+ return None
+
+ def valid_in_row(self, row, num):
+ return num not in self.board[row]
+
+ def valid_in_col(self, col, num):
+ return all(self.board[row][col] != num for row in range(9))
+
+ def valid_in_square(self, row, col, num):
+ row_start = (row // 3) * 3
+ col_start = (col // 3) * 3
+ for row_no in range(row_start, row_start + 3):
+ for col_no in range(col_start, col_start + 3):
+ if self.board[row_no][col_no] == num:
+ return False
+ return True
+
+ def is_valid(self, empty, num):
+ row, col = empty
+ valid_in_row = self.valid_in_row(row, num)
+ valid_in_col = self.valid_in_col(col, num)
+ valid_in_square = self.valid_in_square(row, col, num)
+ return all([valid_in_row, valid_in_col, valid_in_square])
+--fcc-editable-region--
+ def solver(self):
+ if (next_empty := self.find_empty_cell()) is None:
+ return True
+ for guess in range(1, 10):
+ if self.is_valid(next_empty, guess):
+ pass
+--fcc-editable-region--
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+
+gameboard = Board(puzzle)
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660a7f28d5ce6a24ef856a50.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660a7f28d5ce6a24ef856a50.md
new file mode 100644
index 00000000000..a2a3e147f7f
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660a7f28d5ce6a24ef856a50.md
@@ -0,0 +1,80 @@
+---
+id: 660a7f28d5ce6a24ef856a50
+title: Step 58
+challengeType: 20
+dashedName: step-58
+---
+
+# --description--
+
+Now, modify the board in place by accessing the cell at the given row and column and assigning it the value of `guess`.
+
+# --hints--
+
+You should assign `guess` to `self.board[row][col]`.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").find_function("solver").find_for_loops()[0].find_ifs()[0].find_bodies()[0].is_equivalent("row, col = next_empty\\nself.board[row][col] = guess")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+ return None
+
+ def valid_in_row(self, row, num):
+ return num not in self.board[row]
+
+ def valid_in_col(self, col, num):
+ return all(self.board[row][col] != num for row in range(9))
+
+ def valid_in_square(self, row, col, num):
+ row_start = (row // 3) * 3
+ col_start = (col // 3) * 3
+ for row_no in range(row_start, row_start + 3):
+ for col_no in range(col_start, col_start + 3):
+ if self.board[row_no][col_no] == num:
+ return False
+ return True
+
+ def is_valid(self, empty, num):
+ row, col = empty
+ valid_in_row = self.valid_in_row(row, num)
+ valid_in_col = self.valid_in_col(col, num)
+ valid_in_square = self.valid_in_square(row, col, num)
+ return all([valid_in_row, valid_in_col, valid_in_square])
+--fcc-editable-region--
+ def solver(self):
+ if (next_empty := self.find_empty_cell()) is None:
+ return True
+ for guess in range(1, 10):
+ if self.is_valid(next_empty, guess):
+ row, col = next_empty
+--fcc-editable-region--
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+
+gameboard = Board(puzzle)
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660a8b6cd8de406ae82ce910.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660a8b6cd8de406ae82ce910.md
new file mode 100644
index 00000000000..c8ff3dd05bf
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660a8b6cd8de406ae82ce910.md
@@ -0,0 +1,87 @@
+---
+id: 660a8b6cd8de406ae82ce910
+title: Step 59
+challengeType: 20
+dashedName: step-59
+---
+
+# --description--
+
+Nest an `if` statement inside the current `if`. For the `if` condition, use a recursive call to `solver()` and return `True` from the new `if` body.
+
+# --hints--
+
+You should nest an `if` statement inside the current `if` statement and use `self.solver()` as the condition.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").find_function("solver").find_for_loops()[0].find_ifs()[0].find_ifs()[0].find_conditions()[0].is_equivalent("self.solver()")`)) })
+```
+
+You should return `True` from your new `if` statement.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").find_function("solver").find_for_loops()[0].find_ifs()[0].find_ifs()[0].find_bodies()[0].is_equivalent("return True")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+ return None
+
+ def valid_in_row(self, row, num):
+ return num not in self.board[row]
+
+ def valid_in_col(self, col, num):
+ return all(self.board[row][col] != num for row in range(9))
+
+ def valid_in_square(self, row, col, num):
+ row_start = (row // 3) * 3
+ col_start = (col // 3) * 3
+ for row_no in range(row_start, row_start + 3):
+ for col_no in range(col_start, col_start + 3):
+ if self.board[row_no][col_no] == num:
+ return False
+ return True
+
+ def is_valid(self, empty, num):
+ row, col = empty
+ valid_in_row = self.valid_in_row(row, num)
+ valid_in_col = self.valid_in_col(col, num)
+ valid_in_square = self.valid_in_square(row, col, num)
+ return all([valid_in_row, valid_in_col, valid_in_square])
+--fcc-editable-region--
+ def solver(self):
+ if (next_empty := self.find_empty_cell()) is None:
+ return True
+ for guess in range(1, 10):
+ if self.is_valid(next_empty, guess):
+ row, col = next_empty
+ self.board[row][col] = guess
+--fcc-editable-region--
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+
+gameboard = Board(puzzle)
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660a8c3b21100c6b83e57cb0.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660a8c3b21100c6b83e57cb0.md
new file mode 100644
index 00000000000..72fb8023c51
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660a8c3b21100c6b83e57cb0.md
@@ -0,0 +1,85 @@
+---
+id: 660a8c3b21100c6b83e57cb0
+title: Step 60
+challengeType: 20
+dashedName: step-60
+---
+
+# --description--
+
+If the recursive call returns `False`, it means the guess led to an unsolvable sudoku. So you'll need to restore the cell to be empty and explore another guess.
+
+After the innermost `if` statement, set the current cell value back to `0`.
+
+# --hints--
+
+You should set the current cell value back to `0` after the innermost `if` statement.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").find_function("solver").find_for_loops()[0].find_ifs()[0].find_bodies()[0].is_equivalent("row, col = next_empty\\nself.board[row][col] = guess\\nif self.solver():\\n return True\\nself.board[row][col] = 0")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+ return None
+
+ def valid_in_row(self, row, num):
+ return num not in self.board[row]
+
+ def valid_in_col(self, col, num):
+ return all(self.board[row][col] != num for row in range(9))
+
+ def valid_in_square(self, row, col, num):
+ row_start = (row // 3) * 3
+ col_start = (col // 3) * 3
+ for row_no in range(row_start, row_start + 3):
+ for col_no in range(col_start, col_start + 3):
+ if self.board[row_no][col_no] == num:
+ return False
+ return True
+
+ def is_valid(self, empty, num):
+ row, col = empty
+ valid_in_row = self.valid_in_row(row, num)
+ valid_in_col = self.valid_in_col(col, num)
+ valid_in_square = self.valid_in_square(row, col, num)
+ return all([valid_in_row, valid_in_col, valid_in_square])
+--fcc-editable-region--
+ def solver(self):
+ if (next_empty := self.find_empty_cell()) is None:
+ return True
+ for guess in range(1, 10):
+ if self.is_valid(next_empty, guess):
+ row, col = next_empty
+ self.board[row][col] = guess
+ if self.solver():
+ return True
+--fcc-editable-region--
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+
+gameboard = Board(puzzle)
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660a8d7c5f33c16c67e58b37.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660a8d7c5f33c16c67e58b37.md
new file mode 100644
index 00000000000..9f3c7a46046
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660a8d7c5f33c16c67e58b37.md
@@ -0,0 +1,84 @@
+---
+id: 660a8d7c5f33c16c67e58b37
+title: Step 61
+challengeType: 20
+dashedName: step-61
+---
+
+# --description--
+
+Finally, make the `solver` method return `False` if none of the guesses leads to a solution. Pay attention to the indentation.
+
+# --hints--
+
+You should return `False` after the `for` loop.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").find_function("solver").has_return("False")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+ return None
+
+ def valid_in_row(self, row, num):
+ return num not in self.board[row]
+
+ def valid_in_col(self, col, num):
+ return all(self.board[row][col] != num for row in range(9))
+
+ def valid_in_square(self, row, col, num):
+ row_start = (row // 3) * 3
+ col_start = (col // 3) * 3
+ for row_no in range(row_start, row_start + 3):
+ for col_no in range(col_start, col_start + 3):
+ if self.board[row_no][col_no] == num:
+ return False
+ return True
+
+ def is_valid(self, empty, num):
+ row, col = empty
+ valid_in_row = self.valid_in_row(row, num)
+ valid_in_col = self.valid_in_col(col, num)
+ valid_in_square = self.valid_in_square(row, col, num)
+ return all([valid_in_row, valid_in_col, valid_in_square])
+--fcc-editable-region--
+ def solver(self):
+ if (next_empty := self.find_empty_cell()) is None:
+ return True
+ for guess in range(1, 10):
+ if self.is_valid(next_empty, guess):
+ row, col = next_empty
+ self.board[row][col] = guess
+ if self.solver():
+ return True
+ self.board[row][col] = 0
+--fcc-editable-region--
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+
+gameboard = Board(puzzle)
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660a8ef6b7571f6dddc3553b.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660a8ef6b7571f6dddc3553b.md
new file mode 100644
index 00000000000..54a8e96ddc4
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660a8ef6b7571f6dddc3553b.md
@@ -0,0 +1,96 @@
+---
+id: 660a8ef6b7571f6dddc3553b
+title: Step 62
+challengeType: 20
+dashedName: step-62
+---
+
+# --description--
+
+Outside the class definition, create a function `solve_sudoku` to print and solve the sudoku board.
+
+Give it a single parameter `board` that will be your 2D list.
+
+
+# --hints--
+
+You should define a new function named `solve_sudoku` outside the `Board` class.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).has_function("solve_sudoku")`)) })
+```
+
+Your `solve_sudoku` function should have a single parameter `board`.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_function("solve_sudoku").has_args("board")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+ return None
+
+ def valid_in_row(self, row, num):
+ return num not in self.board[row]
+
+ def valid_in_col(self, col, num):
+ return all(self.board[row][col] != num for row in range(9))
+
+ def valid_in_square(self, row, col, num):
+ row_start = (row // 3) * 3
+ col_start = (col // 3) * 3
+ for row_no in range(row_start, row_start + 3):
+ for col_no in range(col_start, col_start + 3):
+ if self.board[row_no][col_no] == num:
+ return False
+ return True
+
+ def is_valid(self, empty, num):
+ row, col = empty
+ valid_in_row = self.valid_in_row(row, num)
+ valid_in_col = self.valid_in_col(col, num)
+ valid_in_square = self.valid_in_square(row, col, num)
+ return all([valid_in_row, valid_in_col, valid_in_square])
+
+ def solver(self):
+ if (next_empty := self.find_empty_cell()) is None:
+ return True
+ for guess in range(1, 10):
+ if self.is_valid(next_empty, guess):
+ row, col = next_empty
+ self.board[row][col] = guess
+ if self.solver():
+ return True
+ self.board[row][col] = 0
+ return False
+--fcc-editable-region--
+
+--fcc-editable-region--
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+
+gameboard = Board(puzzle)
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660a92e93854486efa68fe6f.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660a92e93854486efa68fe6f.md
new file mode 100644
index 00000000000..f4c822a3ed0
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660a92e93854486efa68fe6f.md
@@ -0,0 +1,88 @@
+---
+id: 660a92e93854486efa68fe6f
+title: Step 63
+challengeType: 20
+dashedName: step-63
+---
+
+# --description--
+
+Inside the `solve_sudoku` function, delete `pass` and create a `gameboard` variable and assign it an instance of the `Board` class, passing `board` as the argument.
+
+# --hints--
+
+You should replace `pass` with a variable `gameboard` and assign it `Board(board)`.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_function("solve_sudoku").find_body().is_equivalent("gameboard = Board(board)")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+ return None
+
+ def valid_in_row(self, row, num):
+ return num not in self.board[row]
+
+ def valid_in_col(self, col, num):
+ return all(self.board[row][col] != num for row in range(9))
+
+ def valid_in_square(self, row, col, num):
+ row_start = (row // 3) * 3
+ col_start = (col // 3) * 3
+ for row_no in range(row_start, row_start + 3):
+ for col_no in range(col_start, col_start + 3):
+ if self.board[row_no][col_no] == num:
+ return False
+ return True
+
+ def is_valid(self, empty, num):
+ row, col = empty
+ valid_in_row = self.valid_in_row(row, num)
+ valid_in_col = self.valid_in_col(col, num)
+ valid_in_square = self.valid_in_square(row, col, num)
+ return all([valid_in_row, valid_in_col, valid_in_square])
+
+ def solver(self):
+ if (next_empty := self.find_empty_cell()) is None:
+ return True
+ for guess in range(1, 10):
+ if self.is_valid(next_empty, guess):
+ row, col = next_empty
+ self.board[row][col] = guess
+ if self.solver():
+ return True
+ self.board[row][col] = 0
+ return False
+--fcc-editable-region--
+def solve_sudoku(board):
+ pass
+--fcc-editable-region--
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+
+gameboard = Board(puzzle)
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660a937220bf966fd844f1ee.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660a937220bf966fd844f1ee.md
new file mode 100644
index 00000000000..f63fb74cd45
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660a937220bf966fd844f1ee.md
@@ -0,0 +1,88 @@
+---
+id: 660a937220bf966fd844f1ee
+title: Step 64
+challengeType: 20
+dashedName: step-64
+---
+
+# --description--
+
+Now, add a `print()` call to print the following f-string: `f'Puzzle to solve:\n{gameboard}'`.
+
+# --hints--
+
+You should print the provided string inside the `solve_sudoku` function.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_function("solve_sudoku").has_call("print(f'Puzzle to solve:\\\\n{gameboard}')")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+ return None
+
+ def valid_in_row(self, row, num):
+ return num not in self.board[row]
+
+ def valid_in_col(self, col, num):
+ return all(self.board[row][col] != num for row in range(9))
+
+ def valid_in_square(self, row, col, num):
+ row_start = (row // 3) * 3
+ col_start = (col // 3) * 3
+ for row_no in range(row_start, row_start + 3):
+ for col_no in range(col_start, col_start + 3):
+ if self.board[row_no][col_no] == num:
+ return False
+ return True
+
+ def is_valid(self, empty, num):
+ row, col = empty
+ valid_in_row = self.valid_in_row(row, num)
+ valid_in_col = self.valid_in_col(col, num)
+ valid_in_square = self.valid_in_square(row, col, num)
+ return all([valid_in_row, valid_in_col, valid_in_square])
+
+ def solver(self):
+ if (next_empty := self.find_empty_cell()) is None:
+ return True
+ for guess in range(1, 10):
+ if self.is_valid(next_empty, guess):
+ row, col = next_empty
+ self.board[row][col] = guess
+ if self.solver():
+ return True
+ self.board[row][col] = 0
+ return False
+--fcc-editable-region--
+def solve_sudoku(board):
+ gameboard = Board(board)
+--fcc-editable-region--
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+
+gameboard = Board(puzzle)
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660a940b3379fb708a83593a.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660a940b3379fb708a83593a.md
new file mode 100644
index 00000000000..389b232bcc7
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660a940b3379fb708a83593a.md
@@ -0,0 +1,101 @@
+---
+id: 660a940b3379fb708a83593a
+title: Step 65
+challengeType: 20
+dashedName: step-65
+---
+
+# --description--
+
+Create an `if` statement that checks if the `solver()` method call from the `gameboard` object returns `True`.
+
+Then, add a `print()` call inside the `if` body passing the following f-string: `f'Solved puzzle:\n{gameboard}'`.
+
+
+# --hints--
+
+You should create an `if` statement that checks if the `solver()` method call from the `gameboard` object returns `True`.
+
+```js
+({ test: () => assert(runPython(`
+conditions = ["gameboard.solver()", "gameboard.solver() == True", "True == gameboard.solver()"]
+node = _Node(_code).find_function("solve_sudoku").find_ifs()[0].find_conditions()[0]
+any(node.is_equivalent(condition) for condition in conditions)`)) })
+```
+
+You should print `f'Solved puzzle:\n{gameboard}'` inside the new `if` body.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_function("solve_sudoku").find_ifs()[0].find_bodies()[0].has_call("print(f'Solved puzzle:\\\\n{gameboard}')")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+ return None
+
+ def valid_in_row(self, row, num):
+ return num not in self.board[row]
+
+ def valid_in_col(self, col, num):
+ return all(self.board[row][col] != num for row in range(9))
+
+ def valid_in_square(self, row, col, num):
+ row_start = (row // 3) * 3
+ col_start = (col // 3) * 3
+ for row_no in range(row_start, row_start + 3):
+ for col_no in range(col_start, col_start + 3):
+ if self.board[row_no][col_no] == num:
+ return False
+ return True
+
+ def is_valid(self, empty, num):
+ row, col = empty
+ valid_in_row = self.valid_in_row(row, num)
+ valid_in_col = self.valid_in_col(col, num)
+ valid_in_square = self.valid_in_square(row, col, num)
+ return all([valid_in_row, valid_in_col, valid_in_square])
+
+ def solver(self):
+ if (next_empty := self.find_empty_cell()) is None:
+ return True
+ for guess in range(1, 10):
+ if self.is_valid(next_empty, guess):
+ row, col = next_empty
+ self.board[row][col] = guess
+ if self.solver():
+ return True
+ self.board[row][col] = 0
+ return False
+--fcc-editable-region--
+def solve_sudoku(board):
+ gameboard = Board(board)
+ print(f'Puzzle to solve:\n{gameboard}')
+--fcc-editable-region--
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+
+gameboard = Board(puzzle)
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660a94f55c3c9b71a37e1c8b.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660a94f55c3c9b71a37e1c8b.md
new file mode 100644
index 00000000000..b2517ac90e0
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660a94f55c3c9b71a37e1c8b.md
@@ -0,0 +1,91 @@
+---
+id: 660a94f55c3c9b71a37e1c8b
+title: Step 66
+challengeType: 20
+dashedName: step-66
+---
+
+# --description--
+
+Create an `else` clause for when the sudoku puzzle is not solvable and print the following string inside the new `else` block: `'The provided puzzle is unsolvable.'`.
+
+# --hints--
+
+You should create an `else` clause and print `'The provided puzzle is unsolvable.'`.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_function("solve_sudoku").find_ifs()[0].find_bodies()[1].has_call("print('The provided puzzle is unsolvable.')")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+ return None
+
+ def valid_in_row(self, row, num):
+ return num not in self.board[row]
+
+ def valid_in_col(self, col, num):
+ return all(self.board[row][col] != num for row in range(9))
+
+ def valid_in_square(self, row, col, num):
+ row_start = (row // 3) * 3
+ col_start = (col // 3) * 3
+ for row_no in range(row_start, row_start + 3):
+ for col_no in range(col_start, col_start + 3):
+ if self.board[row_no][col_no] == num:
+ return False
+ return True
+
+ def is_valid(self, empty, num):
+ row, col = empty
+ valid_in_row = self.valid_in_row(row, num)
+ valid_in_col = self.valid_in_col(col, num)
+ valid_in_square = self.valid_in_square(row, col, num)
+ return all([valid_in_row, valid_in_col, valid_in_square])
+
+ def solver(self):
+ if (next_empty := self.find_empty_cell()) is None:
+ return True
+ for guess in range(1, 10):
+ if self.is_valid(next_empty, guess):
+ row, col = next_empty
+ self.board[row][col] = guess
+ if self.solver():
+ return True
+ self.board[row][col] = 0
+ return False
+--fcc-editable-region--
+def solve_sudoku(board):
+ gameboard = Board(board)
+ print(f'Puzzle to solve:\n{gameboard}')
+ if gameboard.solver():
+ print(f'Solved puzzle:\n{gameboard}')
+--fcc-editable-region--
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+
+gameboard = Board(puzzle)
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660a957f44c096728ba9c41f.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660a957f44c096728ba9c41f.md
new file mode 100644
index 00000000000..45de88d0b9e
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660a957f44c096728ba9c41f.md
@@ -0,0 +1,93 @@
+---
+id: 660a957f44c096728ba9c41f
+title: Step 67
+challengeType: 20
+dashedName: step-67
+---
+
+# --description--
+
+After the conditional statements, return your instance of the `Board` class, which represents the final state of the sudoku board after attempting to solve it.
+
+# --hints--
+
+You should return `gameboard` after the `else` clause.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_function("solve_sudoku").has_return("gameboard")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+ return None
+
+ def valid_in_row(self, row, num):
+ return num not in self.board[row]
+
+ def valid_in_col(self, col, num):
+ return all(self.board[row][col] != num for row in range(9))
+
+ def valid_in_square(self, row, col, num):
+ row_start = (row // 3) * 3
+ col_start = (col // 3) * 3
+ for row_no in range(row_start, row_start + 3):
+ for col_no in range(col_start, col_start + 3):
+ if self.board[row_no][col_no] == num:
+ return False
+ return True
+
+ def is_valid(self, empty, num):
+ row, col = empty
+ valid_in_row = self.valid_in_row(row, num)
+ valid_in_col = self.valid_in_col(col, num)
+ valid_in_square = self.valid_in_square(row, col, num)
+ return all([valid_in_row, valid_in_col, valid_in_square])
+
+ def solver(self):
+ if (next_empty := self.find_empty_cell()) is None:
+ return True
+ for guess in range(1, 10):
+ if self.is_valid(next_empty, guess):
+ row, col = next_empty
+ self.board[row][col] = guess
+ if self.solver():
+ return True
+ self.board[row][col] = 0
+ return False
+--fcc-editable-region--
+def solve_sudoku(board):
+ gameboard = Board(board)
+ print(f'Puzzle to solve:\n{gameboard}')
+ if gameboard.solver():
+ print(f'Solved puzzle:\n{gameboard}')
+ else:
+ print('The provided puzzle is unsolvable.')
+--fcc-editable-region--
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+
+gameboard = Board(puzzle)
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660a95c3da857673124ed698.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660a95c3da857673124ed698.md
new file mode 100644
index 00000000000..dc0f0a7bad5
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660a95c3da857673124ed698.md
@@ -0,0 +1,96 @@
+---
+id: 660a95c3da857673124ed698
+title: Step 68
+challengeType: 20
+dashedName: step-68
+---
+
+# --description--
+
+There's still something to fix. Try to print your `gameboard` object.
+
+# --hints--
+
+You should print `gameboard`.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).has_call("print(gameboard)")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+ return None
+
+ def valid_in_row(self, row, num):
+ return num not in self.board[row]
+
+ def valid_in_col(self, col, num):
+ return all(self.board[row][col] != num for row in range(9))
+
+ def valid_in_square(self, row, col, num):
+ row_start = (row // 3) * 3
+ col_start = (col // 3) * 3
+ for row_no in range(row_start, row_start + 3):
+ for col_no in range(col_start, col_start + 3):
+ if self.board[row_no][col_no] == num:
+ return False
+ return True
+
+ def is_valid(self, empty, num):
+ row, col = empty
+ valid_in_row = self.valid_in_row(row, num)
+ valid_in_col = self.valid_in_col(col, num)
+ valid_in_square = self.valid_in_square(row, col, num)
+ return all([valid_in_row, valid_in_col, valid_in_square])
+
+ def solver(self):
+ if (next_empty := self.find_empty_cell()) is None:
+ return True
+ for guess in range(1, 10):
+ if self.is_valid(next_empty, guess):
+ row, col = next_empty
+ self.board[row][col] = guess
+ if self.solver():
+ return True
+ self.board[row][col] = 0
+ return False
+
+def solve_sudoku(board):
+ gameboard = Board(board)
+ print(f'Puzzle to solve:\n{gameboard}')
+ if gameboard.solver():
+ print(f'Solved puzzle:\n{gameboard}')
+ else:
+ print('The provided puzzle is unsolvable.')
+ return gameboard
+
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+--fcc-editable-region--
+gameboard = Board(puzzle)
+
+--fcc-editable-region--
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660a968ca0838773c9bbfc85.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660a968ca0838773c9bbfc85.md
new file mode 100644
index 00000000000..0c048aca043
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660a968ca0838773c9bbfc85.md
@@ -0,0 +1,104 @@
+---
+id: 660a968ca0838773c9bbfc85
+title: Step 69
+challengeType: 20
+dashedName: step-69
+---
+
+# --description--
+
+When you print your `gameboard` object, you get something like `<__main__.Board object at 0xf3c1c8>`, which is the default representation of an object. This means that the `solve_sudoku` function will also give you an output different from what you expect.
+
+Delete both the `print()` call and the `gameboard` object.
+
+# --hints--
+
+You should not have `print(gameboard)` in your code.
+
+```js
+({ test: () => assert.isFalse(runPython(`_Node(_code).has_call("print(gameboard)")`)) })
+```
+
+You should not have `gameboard = Board(puzzle)` in your code.
+
+```js
+({ test: () => assert.isFalse(runPython(`_Node(_code).has_variable("gameboard")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+ return None
+
+ def valid_in_row(self, row, num):
+ return num not in self.board[row]
+
+ def valid_in_col(self, col, num):
+ return all(self.board[row][col] != num for row in range(9))
+
+ def valid_in_square(self, row, col, num):
+ row_start = (row // 3) * 3
+ col_start = (col // 3) * 3
+ for row_no in range(row_start, row_start + 3):
+ for col_no in range(col_start, col_start + 3):
+ if self.board[row_no][col_no] == num:
+ return False
+ return True
+
+ def is_valid(self, empty, num):
+ row, col = empty
+ valid_in_row = self.valid_in_row(row, num)
+ valid_in_col = self.valid_in_col(col, num)
+ valid_in_square = self.valid_in_square(row, col, num)
+ return all([valid_in_row, valid_in_col, valid_in_square])
+
+ def solver(self):
+ if (next_empty := self.find_empty_cell()) is None:
+ return True
+ for guess in range(1, 10):
+ if self.is_valid(next_empty, guess):
+ row, col = next_empty
+ self.board[row][col] = guess
+ if self.solver():
+ return True
+ self.board[row][col] = 0
+ return False
+
+def solve_sudoku(board):
+ gameboard = Board(board)
+ print(f'Puzzle to solve:\n{gameboard}')
+ if gameboard.solver():
+ print(f'Solved puzzle:\n{gameboard}')
+ else:
+ print('The provided puzzle is unsolvable.')
+ return gameboard
+
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+--fcc-editable-region--
+gameboard = Board(puzzle)
+print(gameboard)
+--fcc-editable-region--
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660a9819ad113774d65a1e7c.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660a9819ad113774d65a1e7c.md
new file mode 100644
index 00000000000..57a4432cc49
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660a9819ad113774d65a1e7c.md
@@ -0,0 +1,102 @@
+---
+id: 660a9819ad113774d65a1e7c
+title: Step 70
+challengeType: 20
+dashedName: step-70
+---
+
+# --description--
+
+The `__str__` method is a special method that is called under the hood when the object is printed using the `print()` function, or converted into a string using the `str()` function.
+
+Define an empty `__str__` method within the `Board` class and give it a `self` parameter.
+
+# --hints--
+
+You should create a new method named `__str__` within the `Board` class.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").has_function("__str__")`)) })
+```
+
+Your `__str__` method should have a single parameter `self`.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").find_function("__str__").has_args("self")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+--fcc-editable-region--
+
+--fcc-editable-region--
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+ return None
+
+ def valid_in_row(self, row, num):
+ return num not in self.board[row]
+
+ def valid_in_col(self, col, num):
+ return all(self.board[row][col] != num for row in range(9))
+
+ def valid_in_square(self, row, col, num):
+ row_start = (row // 3) * 3
+ col_start = (col // 3) * 3
+ for row_no in range(row_start, row_start + 3):
+ for col_no in range(col_start, col_start + 3):
+ if self.board[row_no][col_no] == num:
+ return False
+ return True
+
+ def is_valid(self, empty, num):
+ row, col = empty
+ valid_in_row = self.valid_in_row(row, num)
+ valid_in_col = self.valid_in_col(col, num)
+ valid_in_square = self.valid_in_square(row, col, num)
+ return all([valid_in_row, valid_in_col, valid_in_square])
+
+ def solver(self):
+ if (next_empty := self.find_empty_cell()) is None:
+ return True
+ for guess in range(1, 10):
+ if self.is_valid(next_empty, guess):
+ row, col = next_empty
+ self.board[row][col] = guess
+ if self.solver():
+ return True
+ self.board[row][col] = 0
+ return False
+
+def solve_sudoku(board):
+ gameboard = Board(board)
+ print(f'Puzzle to solve:\n{gameboard}')
+ if gameboard.solver():
+ print(f'Solved puzzle:\n{gameboard}')
+ else:
+ print('The provided puzzle is unsolvable.')
+ return gameboard
+
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660ac1d158923e805d3c3099.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660ac1d158923e805d3c3099.md
new file mode 100644
index 00000000000..58219318e9c
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660ac1d158923e805d3c3099.md
@@ -0,0 +1,95 @@
+---
+id: 660ac1d158923e805d3c3099
+title: Step 71
+challengeType: 20
+dashedName: step-71
+---
+
+# --description--
+
+Replace `pass` with a variable `board_str` and assign it an empty string. You'll use this variable to build the custom string representation to return.
+
+# --hints--
+
+You should replace `pass` with a variable `board_str` and assign it an empty string.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").find_function("__str__").find_body().is_equivalent("board_str = ''")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+--fcc-editable-region--
+ def __str__(self):
+ pass
+--fcc-editable-region--
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+ return None
+
+ def valid_in_row(self, row, num):
+ return num not in self.board[row]
+
+ def valid_in_col(self, col, num):
+ return all(self.board[row][col] != num for row in range(9))
+
+ def valid_in_square(self, row, col, num):
+ row_start = (row // 3) * 3
+ col_start = (col // 3) * 3
+ for row_no in range(row_start, row_start + 3):
+ for col_no in range(col_start, col_start + 3):
+ if self.board[row_no][col_no] == num:
+ return False
+ return True
+
+ def is_valid(self, empty, num):
+ row, col = empty
+ valid_in_row = self.valid_in_row(row, num)
+ valid_in_col = self.valid_in_col(col, num)
+ valid_in_square = self.valid_in_square(row, col, num)
+ return all([valid_in_row, valid_in_col, valid_in_square])
+
+ def solver(self):
+ if (next_empty := self.find_empty_cell()) is None:
+ return True
+ for guess in range(1, 10):
+ if self.is_valid(next_empty, guess):
+ row, col = next_empty
+ self.board[row][col] = guess
+ if self.solver():
+ return True
+ self.board[row][col] = 0
+ return False
+
+def solve_sudoku(board):
+ gameboard = Board(board)
+ print(f'Puzzle to solve:\n{gameboard}')
+ if gameboard.solver():
+ print(f'Solved puzzle:\n{gameboard}')
+ else:
+ print('The provided puzzle is unsolvable.')
+ return gameboard
+
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660ac2873b090d80d6aa6ce2.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660ac2873b090d80d6aa6ce2.md
new file mode 100644
index 00000000000..ae6ecb0932d
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660ac2873b090d80d6aa6ce2.md
@@ -0,0 +1,101 @@
+---
+id: 660ac2873b090d80d6aa6ce2
+title: Step 72
+challengeType: 20
+dashedName: step-72
+---
+
+# --description--
+
+Now, create a `for` loop to iterate over the rows in the board. Use `row` as the loop variable.
+
+# --hints--
+
+You should create a `for` loop that iterates over `self.board`.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").find_function("__str__").find_for_loops()[0].find_for_iter().is_equivalent("self.board")`)) })
+```
+
+You should use `row` as the loop variable.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").find_function("__str__").find_for_loops()[0].find_for_vars().is_equivalent("row")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+--fcc-editable-region--
+ def __str__(self):
+ board_str = ''
+--fcc-editable-region--
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+ return None
+
+ def valid_in_row(self, row, num):
+ return num not in self.board[row]
+
+ def valid_in_col(self, col, num):
+ return all(self.board[row][col] != num for row in range(9))
+
+ def valid_in_square(self, row, col, num):
+ row_start = (row // 3) * 3
+ col_start = (col // 3) * 3
+ for row_no in range(row_start, row_start + 3):
+ for col_no in range(col_start, col_start + 3):
+ if self.board[row_no][col_no] == num:
+ return False
+ return True
+
+ def is_valid(self, empty, num):
+ row, col = empty
+ valid_in_row = self.valid_in_row(row, num)
+ valid_in_col = self.valid_in_col(col, num)
+ valid_in_square = self.valid_in_square(row, col, num)
+ return all([valid_in_row, valid_in_col, valid_in_square])
+
+ def solver(self):
+ if (next_empty := self.find_empty_cell()) is None:
+ return True
+ for guess in range(1, 10):
+ if self.is_valid(next_empty, guess):
+ row, col = next_empty
+ self.board[row][col] = guess
+ if self.solver():
+ return True
+ self.board[row][col] = 0
+ return False
+
+def solve_sudoku(board):
+ gameboard = Board(board)
+ print(f'Puzzle to solve:\n{gameboard}')
+ if gameboard.solver():
+ print(f'Solved puzzle:\n{gameboard}')
+ else:
+ print('The provided puzzle is unsolvable.')
+ return gameboard
+
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660ac35d55a15d81afdedd76.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660ac35d55a15d81afdedd76.md
new file mode 100644
index 00000000000..1c7a3e36ed7
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660ac35d55a15d81afdedd76.md
@@ -0,0 +1,115 @@
+---
+id: 660ac35d55a15d81afdedd76
+title: Step 73
+challengeType: 20
+dashedName: step-73
+---
+
+# --description--
+
+Inside the `for` loop, declare a variable `row_str` and assign it a list comprehension that iterates over `row` and turns each item `i` in `row` into a string. Use the `str()` function for that.
+
+# --hints--
+
+You should declare a variable `row_str`.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").find_function("__str__").find_for_loops()[0].find_bodies()[0].has_variable("row_str")`)) })
+```
+
+You should assign a list comprehension that iterates over `row` to the `row_str` variable.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").find_function("__str__").find_for_loops()[0].find_bodies()[0].find_variable("row_str").find_comp_iters()[0].is_equivalent("row")`)) })
+```
+
+The list comprehension assigned to the `row_str` variable should use `i` as iteration variable.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").find_function("__str__").find_for_loops()[0].find_bodies()[0].find_variable("row_str").find_comp_targets()[0].is_equivalent("i")`)) })
+```
+
+The list comprehension assigned to the `row_str` variable should call `str()` on each item `i` in `row`.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").find_function("__str__").find_for_loops()[0].find_bodies()[0].find_variable("row_str").find_comp_expr().is_equivalent("str(i)")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+--fcc-editable-region--
+ def __str__(self):
+ board_str = ''
+ for row in self.board:
+ pass
+--fcc-editable-region--
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+ return None
+
+ def valid_in_row(self, row, num):
+ return num not in self.board[row]
+
+ def valid_in_col(self, col, num):
+ return all(self.board[row][col] != num for row in range(9))
+
+ def valid_in_square(self, row, col, num):
+ row_start = (row // 3) * 3
+ col_start = (col // 3) * 3
+ for row_no in range(row_start, row_start + 3):
+ for col_no in range(col_start, col_start + 3):
+ if self.board[row_no][col_no] == num:
+ return False
+ return True
+
+ def is_valid(self, empty, num):
+ row, col = empty
+ valid_in_row = self.valid_in_row(row, num)
+ valid_in_col = self.valid_in_col(col, num)
+ valid_in_square = self.valid_in_square(row, col, num)
+ return all([valid_in_row, valid_in_col, valid_in_square])
+
+ def solver(self):
+ if (next_empty := self.find_empty_cell()) is None:
+ return True
+ for guess in range(1, 10):
+ if self.is_valid(next_empty, guess):
+ row, col = next_empty
+ self.board[row][col] = guess
+ if self.solver():
+ return True
+ self.board[row][col] = 0
+ return False
+
+def solve_sudoku(board):
+ gameboard = Board(board)
+ print(f'Puzzle to solve:\n{gameboard}')
+ if gameboard.solver():
+ print(f'Solved puzzle:\n{gameboard}')
+ else:
+ print('The provided puzzle is unsolvable.')
+ return gameboard
+
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660ac44c7eec868220318297.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660ac44c7eec868220318297.md
new file mode 100644
index 00000000000..4b9310e232a
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660ac44c7eec868220318297.md
@@ -0,0 +1,97 @@
+---
+id: 660ac44c7eec868220318297
+title: Step 74
+challengeType: 20
+dashedName: step-74
+---
+
+# --description--
+
+Modify the `row_str` comprehension to give a string only when the item is not zero, and an asterisk character otherwise.
+
+# --hints--
+
+The list comprehension assigned to the `row_str` variable should call `str()` on each item `i` in `row` if `i` is truthy, and it should evaluate to `'*'` otherwise.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").find_function("__str__").find_for_loops()[0].find_bodies()[0].find_variable("row_str").find_comp_expr().is_equivalent("str(i) if i else '*'")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+--fcc-editable-region--
+ def __str__(self):
+ board_str = ''
+ for row in self.board:
+ row_str = [str(i) for i in row]
+--fcc-editable-region--
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+ return None
+
+ def valid_in_row(self, row, num):
+ return num not in self.board[row]
+
+ def valid_in_col(self, col, num):
+ return all(self.board[row][col] != num for row in range(9))
+
+ def valid_in_square(self, row, col, num):
+ row_start = (row // 3) * 3
+ col_start = (col // 3) * 3
+ for row_no in range(row_start, row_start + 3):
+ for col_no in range(col_start, col_start + 3):
+ if self.board[row_no][col_no] == num:
+ return False
+ return True
+
+ def is_valid(self, empty, num):
+ row, col = empty
+ valid_in_row = self.valid_in_row(row, num)
+ valid_in_col = self.valid_in_col(col, num)
+ valid_in_square = self.valid_in_square(row, col, num)
+ return all([valid_in_row, valid_in_col, valid_in_square])
+
+ def solver(self):
+ if (next_empty := self.find_empty_cell()) is None:
+ return True
+ for guess in range(1, 10):
+ if self.is_valid(next_empty, guess):
+ row, col = next_empty
+ self.board[row][col] = guess
+ if self.solver():
+ return True
+ self.board[row][col] = 0
+ return False
+
+def solve_sudoku(board):
+ gameboard = Board(board)
+ print(f'Puzzle to solve:\n{gameboard}')
+ if gameboard.solver():
+ print(f'Solved puzzle:\n{gameboard}')
+ else:
+ print('The provided puzzle is unsolvable.')
+ return gameboard
+
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660ac4f4f784b9829e89632a.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660ac4f4f784b9829e89632a.md
new file mode 100644
index 00000000000..82a32e12416
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660ac4f4f784b9829e89632a.md
@@ -0,0 +1,97 @@
+---
+id: 660ac4f4f784b9829e89632a
+title: Step 75
+challengeType: 20
+dashedName: step-75
+---
+
+# --description--
+
+Next, join the items in `row_str` with a space and add the result to the current value of `board_str`.
+
+# --hints--
+
+You should use `.join()` to join the items in `row_str` with a space and add the result to the current value of `board_str`.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").find_function("__str__").find_for_loops()[0].find_bodies()[0].find_aug_variable("board_str").is_equivalent("board_str += ' '.join(row_str)")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+--fcc-editable-region--
+ def __str__(self):
+ board_str = ''
+ for row in self.board:
+ row_str = [str(i) if i else '*' for i in row]
+--fcc-editable-region--
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+ return None
+
+ def valid_in_row(self, row, num):
+ return num not in self.board[row]
+
+ def valid_in_col(self, col, num):
+ return all(self.board[row][col] != num for row in range(9))
+
+ def valid_in_square(self, row, col, num):
+ row_start = (row // 3) * 3
+ col_start = (col // 3) * 3
+ for row_no in range(row_start, row_start + 3):
+ for col_no in range(col_start, col_start + 3):
+ if self.board[row_no][col_no] == num:
+ return False
+ return True
+
+ def is_valid(self, empty, num):
+ row, col = empty
+ valid_in_row = self.valid_in_row(row, num)
+ valid_in_col = self.valid_in_col(col, num)
+ valid_in_square = self.valid_in_square(row, col, num)
+ return all([valid_in_row, valid_in_col, valid_in_square])
+
+ def solver(self):
+ if (next_empty := self.find_empty_cell()) is None:
+ return True
+ for guess in range(1, 10):
+ if self.is_valid(next_empty, guess):
+ row, col = next_empty
+ self.board[row][col] = guess
+ if self.solver():
+ return True
+ self.board[row][col] = 0
+ return False
+
+def solve_sudoku(board):
+ gameboard = Board(board)
+ print(f'Puzzle to solve:\n{gameboard}')
+ if gameboard.solver():
+ print(f'Solved puzzle:\n{gameboard}')
+ else:
+ print('The provided puzzle is unsolvable.')
+ return gameboard
+
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660ac56326c2eb831583c0de.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660ac56326c2eb831583c0de.md
new file mode 100644
index 00000000000..34a68434ac5
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660ac56326c2eb831583c0de.md
@@ -0,0 +1,98 @@
+---
+id: 660ac56326c2eb831583c0de
+title: Step 76
+challengeType: 20
+dashedName: step-76
+---
+
+# --description--
+
+Add a new line character to the current value of `board_str`.
+
+# --hints--
+
+You should add a `'\n'` character to the current value of `board_str`.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").find_function("__str__").find_for_loops()[0].find_bodies()[0].has_stmt("board_str += '\\\\n'")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+--fcc-editable-region--
+ def __str__(self):
+ board_str = ''
+ for row in self.board:
+ row_str = [str(i) if i else '*' for i in row]
+ board_str += ' '.join(row_str)
+--fcc-editable-region--
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+ return None
+
+ def valid_in_row(self, row, num):
+ return num not in self.board[row]
+
+ def valid_in_col(self, col, num):
+ return all(self.board[row][col] != num for row in range(9))
+
+ def valid_in_square(self, row, col, num):
+ row_start = (row // 3) * 3
+ col_start = (col // 3) * 3
+ for row_no in range(row_start, row_start + 3):
+ for col_no in range(col_start, col_start + 3):
+ if self.board[row_no][col_no] == num:
+ return False
+ return True
+
+ def is_valid(self, empty, num):
+ row, col = empty
+ valid_in_row = self.valid_in_row(row, num)
+ valid_in_col = self.valid_in_col(col, num)
+ valid_in_square = self.valid_in_square(row, col, num)
+ return all([valid_in_row, valid_in_col, valid_in_square])
+
+ def solver(self):
+ if (next_empty := self.find_empty_cell()) is None:
+ return True
+ for guess in range(1, 10):
+ if self.is_valid(next_empty, guess):
+ row, col = next_empty
+ self.board[row][col] = guess
+ if self.solver():
+ return True
+ self.board[row][col] = 0
+ return False
+
+def solve_sudoku(board):
+ gameboard = Board(board)
+ print(f'Puzzle to solve:\n{gameboard}')
+ if gameboard.solver():
+ print(f'Solved puzzle:\n{gameboard}')
+ else:
+ print('The provided puzzle is unsolvable.')
+ return gameboard
+
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660ac59d7ea60083900b83df.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660ac59d7ea60083900b83df.md
new file mode 100644
index 00000000000..52dfcf97bc1
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660ac59d7ea60083900b83df.md
@@ -0,0 +1,99 @@
+---
+id: 660ac59d7ea60083900b83df
+title: Step 77
+challengeType: 20
+dashedName: step-77
+---
+
+# --description--
+
+Finally, return `board_str` after the `for` loop.
+
+# --hints--
+
+You should return `board_str` after the `for` loop.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).find_class("Board").find_function("__str__").has_return("board_str")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+--fcc-editable-region--
+ def __str__(self):
+ board_str = ''
+ for row in self.board:
+ row_str = [str(i) if i else '*' for i in row]
+ board_str += ' '.join(row_str)
+ board_str += '\n'
+--fcc-editable-region--
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+ return None
+
+ def valid_in_row(self, row, num):
+ return num not in self.board[row]
+
+ def valid_in_col(self, col, num):
+ return all(self.board[row][col] != num for row in range(9))
+
+ def valid_in_square(self, row, col, num):
+ row_start = (row // 3) * 3
+ col_start = (col // 3) * 3
+ for row_no in range(row_start, row_start + 3):
+ for col_no in range(col_start, col_start + 3):
+ if self.board[row_no][col_no] == num:
+ return False
+ return True
+
+ def is_valid(self, empty, num):
+ row, col = empty
+ valid_in_row = self.valid_in_row(row, num)
+ valid_in_col = self.valid_in_col(col, num)
+ valid_in_square = self.valid_in_square(row, col, num)
+ return all([valid_in_row, valid_in_col, valid_in_square])
+
+ def solver(self):
+ if (next_empty := self.find_empty_cell()) is None:
+ return True
+ for guess in range(1, 10):
+ if self.is_valid(next_empty, guess):
+ row, col = next_empty
+ self.board[row][col] = guess
+ if self.solver():
+ return True
+ self.board[row][col] = 0
+ return False
+
+def solve_sudoku(board):
+ gameboard = Board(board)
+ print(f'Puzzle to solve:\n{gameboard}')
+ if gameboard.solver():
+ print(f'Solved puzzle:\n{gameboard}')
+ else:
+ print('The provided puzzle is unsolvable.')
+ return gameboard
+
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+```
diff --git a/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660ac60e22aa218400acb4b6.md b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660ac60e22aa218400acb4b6.md
new file mode 100644
index 00000000000..d733758b89a
--- /dev/null
+++ b/curriculum/challenges/english/07-scientific-computing-with-python/learn-classes-and-objects-by-building-a-sudoku-solver/660ac60e22aa218400acb4b6.md
@@ -0,0 +1,187 @@
+---
+id: 660ac60e22aa218400acb4b6
+title: Step 78
+challengeType: 20
+dashedName: step-78
+---
+
+# --description--
+
+And now call the `solve_sudoku` method passing `puzzle` as the argument. You should see the partially empty puzzle to solve, and the solved puzzle as the output.
+
+With this, you completed the sudoku solver project!
+
+# --hints--
+
+You should call `solve_sudoku()` and pass it `puzzle` as the argument.
+
+```js
+({ test: () => assert(runPython(`_Node(_code).has_call("solve_sudoku(puzzle)")`)) })
+```
+
+# --seed--
+
+## --seed-contents--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+
+ def __str__(self):
+ board_str = ''
+ for row in self.board:
+ row_str = [str(i) if i else '*' for i in row]
+ board_str += ' '.join(row_str)
+ board_str += '\n'
+ return board_str
+
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+ return None
+
+ def valid_in_row(self, row, num):
+ return num not in self.board[row]
+
+ def valid_in_col(self, col, num):
+ return all(self.board[row][col] != num for row in range(9))
+
+ def valid_in_square(self, row, col, num):
+ row_start = (row // 3) * 3
+ col_start = (col // 3) * 3
+ for row_no in range(row_start, row_start + 3):
+ for col_no in range(col_start, col_start + 3):
+ if self.board[row_no][col_no] == num:
+ return False
+ return True
+
+ def is_valid(self, empty, num):
+ row, col = empty
+ valid_in_row = self.valid_in_row(row, num)
+ valid_in_col = self.valid_in_col(col, num)
+ valid_in_square = self.valid_in_square(row, col, num)
+ return all([valid_in_row, valid_in_col, valid_in_square])
+
+ def solver(self):
+ if (next_empty := self.find_empty_cell()) is None:
+ return True
+ for guess in range(1, 10):
+ if self.is_valid(next_empty, guess):
+ row, col = next_empty
+ self.board[row][col] = guess
+ if self.solver():
+ return True
+ self.board[row][col] = 0
+ return False
+
+def solve_sudoku(board):
+ gameboard = Board(board)
+ print(f'Puzzle to solve:\n{gameboard}')
+ if gameboard.solver():
+ print(f'Solved puzzle:\n{gameboard}')
+ else:
+ print('The provided puzzle is unsolvable.')
+ return gameboard
+
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+--fcc-editable-region--
+
+--fcc-editable-region--
+```
+
+# --solutions--
+
+```py
+class Board:
+ def __init__(self, board):
+ self.board = board
+
+ def __str__(self):
+ board_str = ''
+ for row in self.board:
+ row_str = [str(i) if i else '*' for i in row]
+ board_str += ' '.join(row_str)
+ board_str += '\n'
+ return board_str
+
+ def find_empty_cell(self):
+ for row, contents in enumerate(self.board):
+ try:
+ col = contents.index(0)
+ return row, col
+ except ValueError:
+ pass
+ return None
+
+ def valid_in_row(self, row, num):
+ return num not in self.board[row]
+
+ def valid_in_col(self, col, num):
+ return all(self.board[row][col] != num for row in range(9))
+
+ def valid_in_square(self, row, col, num):
+ row_start = (row // 3) * 3
+ col_start = (col // 3) * 3
+ for row_no in range(row_start, row_start + 3):
+ for col_no in range(col_start, col_start + 3):
+ if self.board[row_no][col_no] == num:
+ return False
+ return True
+
+ def is_valid(self, empty, num):
+ row, col = empty
+ valid_in_row = self.valid_in_row(row, num)
+ valid_in_col = self.valid_in_col(col, num)
+ valid_in_square = self.valid_in_square(row, col, num)
+ return all([valid_in_row, valid_in_col, valid_in_square])
+
+ def solver(self):
+ if (next_empty := self.find_empty_cell()) is None:
+ return True
+ for guess in range(1, 10):
+ if self.is_valid(next_empty, guess):
+ row, col = next_empty
+ self.board[row][col] = guess
+ if self.solver():
+ return True
+ self.board[row][col] = 0
+ return False
+
+def solve_sudoku(board):
+ gameboard = Board(board)
+ print(f'Puzzle to solve:\n{gameboard}')
+ if gameboard.solver():
+ print(f'Solved puzzle:\n{gameboard}')
+ else:
+ print('The provided puzzle is unsolvable.')
+ return gameboard
+
+puzzle = [
+ [0, 0, 2, 0, 0, 8, 0, 0, 0],
+ [0, 0, 0, 0, 0, 3, 7, 6, 2],
+ [4, 3, 0, 0, 0, 0, 8, 0, 0],
+ [0, 5, 0, 0, 3, 0, 0, 9, 0],
+ [0, 4, 0, 0, 0, 0, 0, 2, 6],
+ [0, 0, 0, 4, 6, 7, 0, 0, 0],
+ [0, 8, 6, 7, 0, 4, 0, 0, 0],
+ [0, 0, 0, 5, 1, 9, 0, 0, 8],
+ [1, 7, 0, 0, 0, 6, 0, 0, 5]
+]
+
+solve_sudoku(puzzle)
+```