From a20b2d9318016f72e5838aa3329a60b0f1e3019b Mon Sep 17 00:00:00 2001 From: beginner_contributor <315730032+open-source-learner@users.noreply.github.com> Date: Wed, 12 Aug 2026 20:27:16 +0200 Subject: [PATCH 01/12] Fix typo in section title for class definitions --- data/part-8/3-defining-classes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/part-8/3-defining-classes.md b/data/part-8/3-defining-classes.md index 4f494391..c0c9d444 100644 --- a/data/part-8/3-defining-classes.md +++ b/data/part-8/3-defining-classes.md @@ -266,7 +266,7 @@ Please also include a constructor in each class. The constructor should take the -## Using objecs formed from your own classes +## Using objects formed from your own classes Objects formed from your own class definitions are no different from any other Python objects. They can be passed as arguments and return values just like any other object. We could, for example, write some helper functions for working with bank accounts: From b8f6c8430973ada5404fffbafc48e14b16fb520a Mon Sep 17 00:00:00 2001 From: beginner_contributor <315730032+open-source-learner@users.noreply.github.com> Date: Wed, 12 Aug 2026 20:28:49 +0200 Subject: [PATCH 02/12] Fix typo in rectangle description Corrected a typo in the description of the rectangle representation. --- data/part-8/5-more-examples-of-classes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/part-8/5-more-examples-of-classes.md b/data/part-8/5-more-examples-of-classes.md index 68c6ea36..9f2499b4 100644 --- a/data/part-8/5-more-examples-of-classes.md +++ b/data/part-8/5-more-examples-of-classes.md @@ -43,7 +43,7 @@ A new `Rectangle` is created with two tuples as arguments. These tuples contain The methods `area` and `perimeter` calculate the area and perimeter of the rectangle based on the height and width. The method `move` moves the rectangle by the x and y values given as arguments. -The rectanlge is represented in a coordinate system where the x coordinates increase from left to right, and the y coordinates increase from top to bottom. This is a common way of handling coordinates in programming because it is often easier and more natural to consider the top left corner of the computer screen as the point where x and y equal zero. +The rectangle is represented in a coordinate system where the x coordinates increase from left to right, and the y coordinates increase from top to bottom. This is a common way of handling coordinates in programming because it is often easier and more natural to consider the top left corner of the computer screen as the point where x and y equal zero. The following program tests the `Rectangle` class: From d6aa16e0812d58f931b78b5edbea357516518b6f Mon Sep 17 00:00:00 2001 From: beginner_contributor <315730032+open-source-learner@users.noreply.github.com> Date: Wed, 12 Aug 2026 20:30:18 +0200 Subject: [PATCH 03/12] Fix class name from 'Cargo Hold' to 'CargoHold' --- data/part-9/6-more-examples-with-classes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/part-9/6-more-examples-with-classes.md b/data/part-9/6-more-examples-with-classes.md index 7c1719eb..0192e237 100644 --- a/data/part-9/6-more-examples-with-classes.md +++ b/data/part-9/6-more-examples-with-classes.md @@ -287,7 +287,7 @@ Please note that there is an issue resulting from an update in Python, which con -In this series of exercises you will create the classes `Item`, `Suitcase` and `Cargo Hold`, which will let you further practice working on objects which contain references to other objects. +In this series of exercises you will create the classes `Item`, `Suitcase` and `CargoHold`, which will let you further practice working on objects which contain references to other objects. ## Item From 498c85d17a254d9db095bb680e0a7ade713e8595 Mon Sep 17 00:00:00 2001 From: beginner_contributor <315730032+open-source-learner@users.noreply.github.com> Date: Wed, 12 Aug 2026 20:31:09 +0200 Subject: [PATCH 04/12] Change credits type from str to int in Student class Updated the credits parameter type in the Student class constructor from str to int. --- data/part-10/1-class-hierarchies.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/part-10/1-class-hierarchies.md b/data/part-10/1-class-hierarchies.md index 552c2c71..d43c0c5a 100644 --- a/data/part-10/1-class-hierarchies.md +++ b/data/part-10/1-class-hierarchies.md @@ -24,7 +24,7 @@ Let's have a look at two class definitions: `Student` and `Teacher`. Getter and class Student: - def __init__(self, name: str, id: str, email: str, credits: str): + def __init__(self, name: str, id: str, email: str, credits: int): self.name = name self.id = id self.email = email @@ -92,7 +92,7 @@ class Person: class Student(Person): - def __init__(self, name: str, id: str, email: str, credits: str): + def __init__(self, name: str, id: str, email: str, credits: int): self.name = name self.id = id self.email = email From 768376c68339e933ff764f14d79620bd7ac42bd9 Mon Sep 17 00:00:00 2001 From: beginner_contributor <315730032+open-source-learner@users.noreply.github.com> Date: Wed, 12 Aug 2026 20:35:57 +0200 Subject: [PATCH 05/12] Change product price output format Updated sample output format for product prices. --- data/part-10/3-oo-programming-techniques.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/part-10/3-oo-programming-techniques.md b/data/part-10/3-oo-programming-techniques.md index 82ad8d33..abe9facb 100644 --- a/data/part-10/3-oo-programming-techniques.md +++ b/data/part-10/3-oo-programming-techniques.md @@ -77,8 +77,8 @@ print(orange.cheaper(banana)) -Apple (2.99) -Orange (3.95) +Apple (price 2.99) +Orange (price 3.95) From 290d16d618af287101b19bf06f779a16f7783bdf Mon Sep 17 00:00:00 2001 From: beginner_contributor <315730032+open-source-learner@users.noreply.github.com> Date: Wed, 12 Aug 2026 20:38:27 +0200 Subject: [PATCH 06/12] Fix typos and enhance text clarity in documentation Corrected typos and improved clarity in the text. --- data/part-10/4-application-development.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/data/part-10/4-application-development.md b/data/part-10/4-application-development.md index 691af894..f887de1d 100644 --- a/data/part-10/4-application-development.md +++ b/data/part-10/4-application-development.md @@ -26,7 +26,7 @@ Objects and classes are by no means necessary in every programming context. For When programs grow in complexity, the amount of details quickly becomes unmanageable, unless the program is organised in some systematic way. Even some of the more complicated exercises on this course so far would have benefited from the examples set in this part of the material. -Fo decades the concept of [separation of concerns](https://en.wikipedia.org/wiki/Separation_of_concerns) has been one of the central principles in programming, and the larger field of computer science. Quoting from Wikipedia: +For decades the concept of [separation of concerns](https://en.wikipedia.org/wiki/Separation_of_concerns) has been one of the central principles in programming, and the larger field of computer science. Quoting from Wikipedia: _Separation of concerns is a design principle for separating a computer program into distinct sections such that each section addresses a separate concern. A concern is a set of information that affects the code of a computer program._ @@ -147,7 +147,7 @@ application = PhoneBookApplication() application.execute() ``` -This program doesn't do very much yet, but let's go through the contents. The constructor method creates a new PhoneBook, which is stored in a private attribute. The method `execute(self)` starts the program's text-based user interface, the core of which is the `while` loop, which keeps asking the user for commands until they type in the command for exiting. There is also a method for intructions, `help(self)`, which is called before entering the loop, so that the instructions are printed out. +This program doesn't do very much yet, but let's go through the contents. The constructor method creates a new PhoneBook, which is stored in a private attribute. The method `execute(self)` starts the program's text-based user interface, the core of which is the `while` loop, which keeps asking the user for commands until they type in the command for exiting. There is also a method for instructions, `help(self)`, which is called before entering the loop, so that the instructions are printed out. Now, let's add some actual functionality. First, we implement adding new data to the phone book: @@ -680,7 +680,7 @@ The file handling process in the PhoneBook application proceeds as follows: the There are many good guidebooks for learning about good programming practices. One such is [Clean Code](https://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882) by Robert Martin. The code examples in the book are implemented in Java, however, so working through the examples can be quite cumbersome at this point in your programming career, although the book itself is much recommended by the course staff. The themes of easily maintained, expandable, good quality code will be further explored on the courses [Software Development Methods](https://studies.helsinki.fi/courses/cu/hy-CU-118024742-2020-08-01) and [Software Engineering](https://studies.helsinki.fi/courses/cu/hy-CU-118024909-2020-08-01). -Writing code according to established object oriented programming principles comes at a price. You will likely end up writing more code than you would, were you to write your implementation in one continuous bout of spaghetti code. One of the key skills of a porgrammer is to decide the best approach for each situation. Sometimes it is necessary to just hack something together quickly for immediate use. On the other hand, if in the foreseeable future it can be expected that the code will be reused, maintained or futher developed, either by you or, more critically, by someone else entirely, the readability and logical modularity of the program code become essential. More often than not, if it is worth doing, it is worth doing well, even in the very early stages of development. +Writing code according to established object oriented programming principles comes at a price. You will likely end up writing more code than you would, were you to write your implementation in one continuous bout of spaghetti code. One of the key skills of a programmer is to decide the best approach for each situation. Sometimes it is necessary to just hack something together quickly for immediate use. On the other hand, if in the foreseeable future it can be expected that the code will be reused, maintained or further developed, either by you or, more critically, by someone else entirely, the readability and logical modularity of the program code become essential. More often than not, if it is worth doing, it is worth doing well, even in the very early stages of development. To finish off this part of the material you will implement one more larger application. @@ -828,7 +828,7 @@ class CloudHandler: # code for saving the contents of the phone book # in a cloud service on the internet -storage_service = CloudHandler("amazon-cloud", "username", "passwrd") +storage_service = CloudHandler("amazon-cloud", "username", "password") application = PhoneBookApplication(storage_service) application.execute() ``` From 33179c9a5e169700a3c8ce693a6785290dd1ec45 Mon Sep 17 00:00:00 2001 From: beginner_contributor <315730032+open-source-learner@users.noreply.github.com> Date: Wed, 12 Aug 2026 20:41:10 +0200 Subject: [PATCH 07/12] Update 3-recursion.md --- data/part-11/3-recursion.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/data/part-11/3-recursion.md b/data/part-11/3-recursion.md index 4f829fe1..fd7ed88e 100644 --- a/data/part-11/3-recursion.md +++ b/data/part-11/3-recursion.md @@ -127,7 +127,7 @@ def factorial(n: int): return n * factorial(n - 1) if __name__ == "__main__": - # Tesing our function + # Testing our function for i in range(1, 7): print(f"The factorial of {i} is {factorial(i)}") @@ -146,7 +146,7 @@ The factorial of 6 is 720 If the parameter of the recursive factorial function is 0 or 1, the function returns 1, because this is how the factorial operation is defined. In any other case the function returns the value `n * factorial(n - 1)`, which is the value of its parameter `n` multiplied by the return value of the function call `factorial(n - 1)`. -The crucial part here is that the function definition contains a stop condition. If this is met, the recursion ends. In this case that condition is `n < 2`. We know it will be reached eventually, beacuse the value passed as the argument to the function is decreased by one on each level of the recursion. +The crucial part here is that the function definition contains a stop condition. If this is met, the recursion ends. In this case that condition is `n < 2`. We know it will be reached eventually, because the value passed as the argument to the function is decreased by one on each level of the recursion. The [visualisation tool](http://www.pythontutor.com/visualize.html#mode=edit) can be a great help in making sense of recursive programs. @@ -166,9 +166,9 @@ factorial(5) Take a look at how the [visualisation tool](http://www.pythontutor.com/visualize.html#code=def%20factorial%28n%3A%20int%29%3A%0A%20%20%20%20if%20n%20%3C%202%3A%0A%20%20%20%20%20%20%20%20return%201%0A%0A%20%20%20%20factorial_one_level_down%20%3D%20factorial%28n%20-%201%29%0A%20%20%20%20factorial_now%20%3D%20n%20*%20factorial_one_level_down%0A%20%20%20%20return%20factorial_now%0A%20%20%20%20%0Afactorial%285%29&cumulative=false&curInstr=5&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false) demonstrates the progress of the recursion. -The visualisation tool has a small quirk in the way it handles the call stack, as it seems to "grow" downwards. Usually call stacks are depicted as just that: stacks, where the new calls are placed on top. In the visualisation tool, the currently active function call is the shaded block at the bottom, which has its own copies of the variables visible. +The visualisation tool has a small quirk in the way it handles the call stack, as it seems to "grow" downwards. Usually call stacks are depicted as just that: stacks, where the new calls are placed on top. In the visualisation tool, the currently active function call is the shaded block at the bottom, which has its own copies of the variables shown. -When the recursive factorial function is called, the call stack is built until the limit posed by `n < 2` is reached. Then the final function call in the stack returns with a value - it is `1`, as `n` is now less than 2. This return value is passed to the previous function call in the stack, where it is used to calculate that function call's return value, and so forth back out of the stack. +When the recursive factorial function is called, the call stack is built until the limit posed by `n < 2` is reached. Then the final function call in the stack returns with a value, in this case, `1`, as `n` is now less than 2. This return value is passed to the previous function call in the stack, where it is used to calculate that function call's return value, and so forth back out of the stack. The return value of each function call is stored in the helper variable `factorial_now`. Please go through the visualisation carefully until you understand what happens at each step, and pay special attention to the value returned at each step. From e5108703248d45fe488c067d9ee270e63bfe8b3b Mon Sep 17 00:00:00 2001 From: beginner_contributor <315730032+open-source-learner@users.noreply.github.com> Date: Wed, 12 Aug 2026 20:44:08 +0200 Subject: [PATCH 08/12] Fix typo in functional programming documentation --- data/part-12/3-functional-programming.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/part-12/3-functional-programming.md b/data/part-12/3-functional-programming.md index 50483c06..5f778ecf 100644 --- a/data/part-12/3-functional-programming.md +++ b/data/part-12/3-functional-programming.md @@ -650,7 +650,7 @@ If the initial value is left out, `reduce` takes the first item in the list as t -**NB:** if the items in the series are of a different type than the intended reduced result, the thrd argument is mandatory. The example with the bank accounts would not work without the initial value. That is, trying this +**NB:** if the items in the series are of a different type than the intended reduced result, the third argument is mandatory. The example with the bank accounts would not work without the initial value. That is, trying this ```python balances_total = reduce(balance_sum_helper, accounts) From 26fd9285eeb7c6eeab767c6c59a8aa9b0fc0ae88 Mon Sep 17 00:00:00 2001 From: beginner_contributor <315730032+open-source-learner@users.noreply.github.com> Date: Wed, 12 Aug 2026 20:47:29 +0200 Subject: [PATCH 09/12] Update 1-pygame.md --- data/part-13/1-pygame.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/part-13/1-pygame.md b/data/part-13/1-pygame.md index 18b2c5b3..3fdb353d 100644 --- a/data/part-13/1-pygame.md +++ b/data/part-13/1-pygame.md @@ -142,7 +142,7 @@ The program uses this image of a robot, which is stored in the file `robot.png`: -The file `robot.png` has to be in the same directory with the source code of the your program, or the program won't be able to find it. In the exercise templates for this part the images are waiting in the exercise directory. +The file `robot.png` has to be in the same directory with the source code of your program, or the program won't be able to find it. In the exercise templates for this part the images are waiting in the exercise directory. The window should now look like this: From 6fb5327076bafde9072de6aed5f4bde7d824b677 Mon Sep 17 00:00:00 2001 From: beginner_contributor <315730032+open-source-learner@users.noreply.github.com> Date: Wed, 12 Aug 2026 20:49:00 +0200 Subject: [PATCH 10/12] Update 2-animation.md Corrected typos and improved clarity in the explanation of rotation and animation. --- data/part-13/2-animation.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/data/part-13/2-animation.md b/data/part-13/2-animation.md index 0ba54bc1..cf33c6b7 100644 --- a/data/part-13/2-animation.md +++ b/data/part-13/2-animation.md @@ -180,7 +180,7 @@ Running the above code should look like this: -Rotation in a relatively precise circle is achieved with the help of some basic trigonometric functions. The varible `angle` contains the angle of the robots location in relation to the centre of the window and the horizontal line running through it. The sine and cosine functions from the Python math library are used to calculate the coordinates of the robot's location: +Rotation in a relatively precise circle is achieved with the help of some basic trigonometric functions. The variable `angle` contains the angle of the robots location in relation to the centre of the window and the horizontal line running through it. The sine and cosine functions from the Python math library are used to calculate the coordinates of the robot's location: ```python x = 320+math.cos(angle)*100-robot.get_width()/2 @@ -189,7 +189,7 @@ Rotation in a relatively precise circle is achieved with the help of some basic The robot rotates around a circle of radius 100 around the centre of the window. The hypotenuse in this scenario is the radius of the circle. The cosine function gives the length of the _adjacent_ side of a right triangle in relation to the hypotenuse, which means that it gives us the `x` coordinate of the location. The sine function gives the length of the _opposite_ side, i.e. the `y` coordinate. The location is then adjusted for the size of the image, so that the centre of the circle is at the centre of the window. -With each iteration the size of the `angle` is incremented by 0.01:llä. As we are using radians, a full circle is 2π, which equals about 6.28. It takes about 628 iterations for the robot to go a full circle, and at 60 iterations per second this takes just over 10 seconds. +With each iteration the size of the `angle` is incremented by 0.01. As we are using radians, a full circle is 2π, which equals about 6.28. It takes about 628 iterations for the robot to go a full circle, and at 60 iterations per second this takes just over 10 seconds. @@ -235,7 +235,7 @@ The exercise template contains the image `ball.png`. -Please create an animation where robots fall from the sky randomly. When a robot reaches the ground, it starts moving to the left or to the right, and finaly disappears off the screen. The end result should look like this: +Please create an animation where robots fall from the sky randomly. When a robot reaches the ground, it starts moving to the left or to the right, and finally disappears off the screen. The end result should look like this: From ac988119105e57038a54fcde345cb76f2b3f84ed Mon Sep 17 00:00:00 2001 From: beginner_contributor <315730032+open-source-learner@users.noreply.github.com> Date: Wed, 12 Aug 2026 20:49:52 +0200 Subject: [PATCH 11/12] Update 2-robot-and-boxes.md Corrected typos and improved clarity in the explanation of the game's grid state management and refactoring considerations. --- data/part-14/2-robot-and-boxes.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/data/part-14/2-robot-and-boxes.md b/data/part-14/2-robot-and-boxes.md index f8fddb97..642383df 100644 --- a/data/part-14/2-robot-and-boxes.md +++ b/data/part-14/2-robot-and-boxes.md @@ -128,7 +128,7 @@ If the execution of the method has reached this point without returning, it is t ## Refactoring? -Using only the grid to store the state of the game at all times is very handy in the sense that only one variable is permanently invlved in the whole process, and it is relatively easy to update the state of the grid through simple additions and subtractions. +Using only the grid to store the state of the game at all times is very handy in the sense that only one variable is permanently involved in the whole process, and it is relatively easy to update the state of the grid through simple additions and subtractions. The downside is that it can be a tad difficult to understand the program code of the game. If someone unfamiliar with the logic used saw this following line of code, they would likely be a bit perplexed: @@ -136,7 +136,7 @@ The downside is that it can be a tad difficult to understand the program code of if self.map[box_new_y][box_new_x] in [1, 3, 5]: ``` -The code snippet above makes use of _magic numbers_ to represent the squares in the grid. ANyone reading the code would have to know that 1 means wall, 3 means a box and 5 means a box in a target square. +The code snippet above makes use of _magic numbers_ to represent the squares in the grid. Anyone reading the code would have to know that 1 means wall, 3 means a box and 5 means a box in a target square. The lines involving the clever subtractions and additions would look even more baffling: @@ -144,7 +144,7 @@ The lines involving the clever subtractions and additions would look even more b self.map[robot_new_y][robot_new_x] -= 3 ``` -The number 3 meant a box just previously, but now it is subtracted from the value of a square on the grid. This works in the context of our numbering scheme, as it changes a box (3) into a normal floor square (0), or a target square with a box (5) into an empty target square (2), but understanding this requiares a primer in the numbering scheme used. +The number 3 meant a box just previously, but now it is subtracted from the value of a square on the grid. This works in the context of our numbering scheme, as it changes a box (3) into a normal floor square (0), or a target square with a box (5) into an empty target square (2), but understanding this requires a primer in the numbering scheme used. We could make it easier for anyone reading the code by _refactoring_ our implementation. That means improving the structure and readability of the code. One way to achieve this would be to use the names of the squares instead of the numbers 0 to 6, even though this would still not explain how and why numbers can be added and subtracted while maintaining the integrity of the grid. From 5fe689c7d6606cda4f57f9c20c36bc50c6c1533e Mon Sep 17 00:00:00 2001 From: beginner_contributor <315730032+open-source-learner@users.noreply.github.com> Date: Wed, 12 Aug 2026 20:51:45 +0200 Subject: [PATCH 12/12] Update 3-finishing-the-game.md --- data/part-14/3-finishing-the-game.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/data/part-14/3-finishing-the-game.md b/data/part-14/3-finishing-the-game.md index 4e92fc9b..8d28155e 100644 --- a/data/part-14/3-finishing-the-game.md +++ b/data/part-14/3-finishing-the-game.md @@ -8,9 +8,9 @@ Our game is already quite functional, so it is time to add some finishing touche ## Move counter -The move counter near the bottom edge of the game window displaye the number of moves taken by the player so far. This can be used to find the solution with the least number of moves. +The move counter near the bottom edge of the game window displays the number of moves taken by the player so far. This can be used to find the solution with the least number of moves. -The counter requires some shanges to the code. First, let's change the constructor so that there is adequate space for the counter, and that we have an appropriate font at our disposal in order to draw the text: +The counter requires some changes to the code. First, let's change the constructor so that there is adequate space for the counter, and that we have an appropriate font at our disposal in order to draw the text: ```python def __init__(self): @@ -117,14 +117,14 @@ The player can still see the game grid and the final state of the game, however. When developing games it often happens that you'd want to check what happens in some later situation in the game. For example, in this game the moment where the game is solved is one such situation. -It can be difficult to test the correct functioning of a situation like that, as you'd normally ahve to solve the game to reach that point in the game. As programmers we can make some temporary alleviations in our games, to make it easier to test them. For example, we could add the following to make it temporarily easier to solve the game: +It can be difficult to test the correct functioning of a situation like that, as you'd normally have to solve the game to reach that point in the game. As programmers we can make some temporary alleviations in our games, to make it easier to test them. For example, we could add the following to make it temporarily easier to solve the game: ```python def game_solved(self): return True ``` -Now the method always returns `True`, which means that the game is "solved" to begin with. This makes it easy to check that the noification at the end looks good and the player can no longer move on the grid after solving. When this functionality is thoroughly tested, we can revoke the changes. +Now the method always returns `True`, which means that the game is "solved" to begin with. This makes it easy to check that the notification at the end looks good and the player can no longer move on the grid after solving. When this functionality is thoroughly tested, we can revoke the changes. ## Your game on GitHub?