Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions data/part-10/1-class-hierarchies.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions data/part-10/3-oo-programming-techniques.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@ print(orange.cheaper(banana))

<sample-output>

Apple (2.99)
Orange (3.95)
Apple (price 2.99)
Orange (price 3.95)

</sample-output>

Expand Down
8 changes: 4 additions & 4 deletions data/part-10/4-application-development.md
Original file line number Diff line number Diff line change
Expand Up @@ -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._

Expand Down Expand Up @@ -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:

Expand Down Expand Up @@ -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.

Expand Down Expand Up @@ -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()
```
Expand Down
8 changes: 4 additions & 4 deletions data/part-11/3-recursion.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)}")

Expand All @@ -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.

Expand All @@ -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.

Expand Down
2 changes: 1 addition & 1 deletion data/part-12/3-functional-programming.md
Original file line number Diff line number Diff line change
Expand Up @@ -650,7 +650,7 @@ If the initial value is left out, `reduce` takes the first item in the list as t

</text-box>

**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)
Expand Down
2 changes: 1 addition & 1 deletion data/part-13/1-pygame.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ The program uses this image of a robot, which is stored in the file `robot.png`:

<img src="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:

Expand Down
6 changes: 3 additions & 3 deletions data/part-13/2-animation.md
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ Running the above code should look like this:

<img src="pygame_rotation.gif">

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
Expand All @@ -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.

<programming-exercise name='Vertical movement' tmcname='part13-05_vertical_movement'>

Expand Down Expand Up @@ -235,7 +235,7 @@ The exercise template contains the image `ball.png`.

<programming-exercise name='Robot invasion' tmcname='part13-10_robot_invasion'>

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:

<img src="pygame_invasion.gif">

Expand Down
6 changes: 3 additions & 3 deletions data/part-14/2-robot-and-boxes.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,23 +128,23 @@ 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:

```python
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:

```python
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.

Expand Down
8 changes: 4 additions & 4 deletions data/part-14/3-finishing-the-game.md
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -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?

Expand Down
2 changes: 1 addition & 1 deletion data/part-8/3-defining-classes.md
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ Please also include a constructor in each class. The constructor should take the

</programming-exercise>

## 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:

Expand Down
Loading