e95f1821545846d70b82d8aaf7542ec2964f5d96..7f5f315ce79b213b153684910c20654039a91369
2024-05-15 Hong-Phuc Bui
Template 4 Students OK
7f5f31 diff | tree
2024-05-15 Hong-Phuc Bui
Ende Vorlesung 15.5.
7df20a diff | tree
2024-05-15 Hong-Phuc Bui
Template 4 Students OK
987936 diff | tree
2024-05-13 Hong-Phuc Bui
demo Bug
772cea diff | tree
2024-05-13 Hong-Phuc Bui
Example for functions
84055e diff | tree
4 files modified
10 files added
448 ■■■■■ changed files
.gitignore 6 ●●●● patch | view | raw | blame | history
funktion-modular/README.md 5 ●●●●● patch | view | raw | blame | history
funktion-modular/calendar/HOWTO.md 15 ●●●●● patch | view | raw | blame | history
funktion-modular/calendar/__pycache__/month_of_year.cpython-312.pyc patch | view | raw | blame | history
funktion-modular/calendar/__pycache__/test_month_of_year.cpython-312.pyc patch | view | raw | blame | history
funktion-modular/calendar/month_of_year-no-fn.py 90 ●●●●● patch | view | raw | blame | history
funktion-modular/calendar/month_of_year.py 101 ●●●●● patch | view | raw | blame | history
funktion-modular/calendar/test_month_of_year.py 25 ●●●●● patch | view | raw | blame | history
funktion-modular/study-effort/README.md 43 ●●●●● patch | view | raw | blame | history
funktion-modular/study-effort/Vorlesungen.txt 5 ●●●●● patch | view | raw | blame | history
funktion-modular/study-effort/effort_semester.py 102 ●●●●● patch | view | raw | blame | history
python-grundlage/Lissajous-np.py 16 ●●●● patch | view | raw | blame | history
python-grundlage/Lissajous-turtle.py 35 ●●●● patch | view | raw | blame | history
python-grundlage/dice-simulation.py 5 ●●●●● patch | view | raw | blame | history
.gitignore
@@ -1,2 +1,6 @@
sandbox*
queens*
queens*
*.venv*
    |test|
funktion-modular/README.md
New file
@@ -0,0 +1,5 @@
# README
1. One project one directory with unittest
2. Use typing annotation for every function.
funktion-modular/calendar/HOWTO.md
New file
@@ -0,0 +1,15 @@
# HOWTO
## Run unittest
* For all unittests in directory
```shell
python -m unittest
```
* For some files
```shell
python -m unittest -p '*_test.py'
```
funktion-modular/calendar/__pycache__/month_of_year.cpython-312.pyc
Binary files differ
funktion-modular/calendar/__pycache__/test_month_of_year.cpython-312.pyc
Binary files differ
funktion-modular/calendar/month_of_year-no-fn.py
New file
@@ -0,0 +1,90 @@
#! /usr/bin/env python
"""
Description:
    Programm zur Ausgabe einer Ansicht eines Monats wie gängige Kalender-Format
Usage:
```
$ python month_of_year-no-fn.py 12 2024
```
"""
from typing import Final
import sys
month: Final[int] = int(sys.argv[1])
year: Final[int] = int(sys.argv[2])
# Calender setup
weekdays: Final[tuple[str, ...]] = ("So", "Mo", "Di", "Mi", "Do", "Fr", "Sa")
first_day_of_week: Final[int] = 1  # it is monday, common in Europa
months: Final[tuple[ tuple[str, int], ...]] = (("", 0),
                                             ("Januar", 31), ("Februar", 28), ("März", 31),
                                             ("April", 30), ("Mai", 31), ("Juni", 30),
                                             ("July", 31), ("August", 31), ("September", 30),
                                             ("Oktober", 31), ("November", 30), ("Dezember", 31))
# calculate the weekday of the 1.st day of the given month
# Not possible to test next lines of code, since all variables are global
first_date: Final[int] = 1  # first day of the month
y0 = year - ((14 - month)//12)
x = y0 + (y0//4) - (y0//100) + (y0//400)
m0 = month + 12 * ((14 - month)//12) - 2
day_of_first_date = (first_date + x + (31 * m0) // 12) % 7
# test and comment out
# print(weekdays[first_day_of_month])
# calculate how many days of last month get places in the first week
# of this month
diff: Final[int] = (7 + day_of_first_date - first_day_of_week) % 7
# test and comment out
# print(diff)
# calculate how many days in the month
days_in_months = months[month][1]
# check leap year
if month == 2:
    if (year % 4 == 0 and year % 100 != 0) or year % 400 == 0:
        days_in_months += 1
# print the calendar
column_width: Final[int] = 5  # at least 3, since days in month have at most 2 digits
calendar_width: Final[int] = 7 * column_width  # 7 days of a week, each day need 3 spaces
head_line = f"{months[month][0]} {year}"
fmt_head_line = f"{head_line}".center(calendar_width, '-')
# test and comment out
# print(fmt_head_line)
# calender_view is initialized with Headline
calendar_view: str = fmt_head_line + "\n"
# 7 weekdays
for d in weekdays:
    calendar_view += f"{d}".rjust(column_width, ' ')
# test and comment out
calendar_view += "\n"
# print(calendar_view)
# the empty columns in the first week of the month
for _ in range(diff, 0, -1):
    calendar_view += ("#"*(column_width-1) + "-")  # mark empty columns with some characters to let debug easier
# print the days in the first week
day = 1
days_in_first_week = ""
while day + diff <= 7:
    days_in_first_week += (f"{day}".rjust(column_width))
    day += 1
calendar_view += days_in_first_week + "\n"
while day <= days_in_months:
    calendar_view += (f"{day}".rjust(column_width))
    if (day + diff) % 7 == 0:  # reaches the last day of week
        calendar_view += "\n"
    day += 1
print(calendar_view)
funktion-modular/calendar/month_of_year.py
New file
@@ -0,0 +1,101 @@
#! /usr/bin/env python
"""
Description:
    Programm zur Ausgabe einer Ansicht eines Monats wie gängige Kalender-Format
Usage:
```
$ python month_of_year.py 12 2024
```
"""
from typing import Final
import sys
# Calender setup
weekdays: Final[tuple[str, ...]] = ("So", "Mo", "Di", "Mi", "Do", "Fr", "Sa")
first_day_of_week: Final[int] = 1  # it is monday, common in Europa
months: Final[tuple[ tuple[str, int], ...]] = (("", 0),
                                             ("Januar", 31), ("Februar", 28), ("März", 31),
                                             ("April", 30), ("Mai", 31), ("Juni", 30),
                                             ("July", 31), ("August", 31), ("September", 30),
                                             ("Oktober", 31), ("November", 30), ("Dezember", 31))
def is_leap_year(year: int) -> bool:
    return (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0)
def weekday_of_date(day: int, month: int, year: int) -> int:
    y0 = year - ((14 - month) // 12)
    x = y0 + (y0 // 4) - (y0 // 100) + (y0 // 400)
    m0 = month + 12 * ((14 - month) // 12) - 2
    return (day + x + (31 * m0) // 12) % 7
def count_days_in_month(month: int, year: int) -> int:
    count_days = months[month][1]
    if month == 2 and is_leap_year(year):
        count_days += 1
    return count_days
def build_calendar_head(month: int, year: int, calendar_width: int, fill_char: str =' ') -> str:
    head_line = f"{months[month][0]} {year}"
    return head_line.center(calendar_width, fill_char)
def build_weekdays_line(column_width) -> str:
    wd_line = ""
    for i in range(0, 7):
        d = (i + first_day_of_week) % 7
        wd_line += f"{weekdays[d]}".rjust(column_width, ' ')
    return wd_line
def format_day(day: int, column_width: int) -> str:
    return f"{day}".rjust(column_width)
def build_month_view(month: int, year: int, column_width: int) -> str:
    month_view = ""
    day = 1
    # the first week
    day_of_first_date = weekday_of_date(day, month, year)
    # how many columns before the first day of this month
    diff = (7 + day_of_first_date - first_day_of_week) % 7
    # -> empty column
    for _ in range(diff, 0, -1):
        month_view += ("-" + "#"*(column_width - 1) )
    # -> next days in the first week
    while day + diff <= 7:
        month_view += format_day(day, column_width)
        day += 1
    month_view += "\n"
    # next weeks
    days_in_month = count_days_in_month(month, year)
    while day <= days_in_month:
        month_view += format_day(day, column_width)
        if (day + diff) % 7 == 0 and (day < days_in_month):
            month_view += "\n"
        day += 1
    return month_view
def build_calendar(month: int, year: int, column_width: int = 3) -> str:
    calendar_width = 7 * column_width
    head_line = build_calendar_head(month, year, calendar_width, fill_char="-")
    calendar_view = f"{head_line}\n"
    weekdays_line = build_weekdays_line(column_width)
    calendar_view += f"{weekdays_line}\n"
    month_view = build_month_view(month, year, column_width)
    calendar_view += f"{month_view}"
    return calendar_view
if __name__ == "__main__":
    month = int(sys.argv[1])
    year = int(sys.argv[2])
    cal = build_calendar(month, year, 5)
    print(cal)
funktion-modular/calendar/test_month_of_year.py
New file
@@ -0,0 +1,25 @@
import unittest
import month_of_year as mofy
class MofyTestCase(unittest.TestCase):
    def test_2024_leapyear(self):
        year = 2024
        is_leap_year = mofy.is_leap_year(year)
        self.assertEqual(is_leap_year, True)
    def test_2000_leapyear(self):
        year = 2000
        is_leap_year = mofy.is_leap_year(year)
        self.assertEqual(is_leap_year, True)  # add assertion here
    def test_weekday_of_day(self):
        d, m, y = (1, 2, 2024)
        wd = mofy.weekday_of_date(d, m, y)
        self.assertEqual(wd, 4)
if __name__ == '__main__':
    unittest.main()
funktion-modular/study-effort/README.md
New file
@@ -0,0 +1,43 @@
# Study Effort
1. Erstellen Sie einen Ordner `study-effort` für das Projekt!
2. In der Ordner legen Sie die Datei `Vorlesungen.txt` mit folgenden Inhalt an:
```text
#Name; ECTS; Veranstaltungen pro Woche
Programmierung 2; 5; 2
Mathematik 2; 5; 3
```
3. Schreiben Sie ein Python Programm `effort_semester.py`, das wie folgt genutzt wird:
```shell
$ python3 effort_semester.py Vorlesungen.txt
                 Vorlesung ECTS         V-Ü-T/Woche   Selbstudiumszeit pro Woche
          Programmierung 2 5            2              <>
              Mathematik 2 5            3              <>
--------------------------------------------------------------------------------
                                                       <>
```
Die Platzhalter `<>` sollen mit richtigen Werten ersetzt werden.
Sie können folgenden Funktionen benutzen:
* String Verarbeitung
    * `str.split()`
    * `str.ljust()`
    * `str.rjust()`
* Datei-Handling
    * `open()`
Sie sollen das Programm nach Semantik in Funktionen aufteilen.
Ergänzen Sie die Datei `Vorlesungen.txt` mit weiteren Vorlesungen und testen Sie das Programm,
ob es noch korrekt funktioniert.
funktion-modular/study-effort/Vorlesungen.txt
New file
@@ -0,0 +1,5 @@
#Vorlesung; ECTS; Veranstaltung
Programmierung 2; 5; 2
Mathematik 2; 5; 3
# Wahlfach
Design Pattern in Software; 5; 2
funktion-modular/study-effort/effort_semester.py
New file
@@ -0,0 +1,102 @@
#! /usr/bin/evn python
"""
Programm zum Berechnen den Aufwand für das Selbststudium pro Woche in einem Semester.
Das Semester hat 15 Woche.
Eine Doppelstunde (DS) entspricht 90 Minuten. Ein ECTS entspricht einen Aufwand von 30 Stunden.
Eine Veranstaltung (Vorlesung, Übung, Tutorium) ist 2 DS.
Die Vorlesungen in einem Semester werden in einer Text-Datei erfasst. Ein Template ist wie folgt:
```txt
#Name; ECTS; Veranstaltung pro Woche
Programmierung 2; 5; 2
Mathematik 2; 5; 3
```
Usage:
$python effort_semester.py Vorlesungen.txt
                 Vorlesung ECTS         V-Ü-T/Woche   Selbstudiumszeit pro Woche
          Programmierung 2 5            2              <>
              Mathematik 2 5            3              <>
--------------------------------------------------------------------------------
                                                       <>
"""
import sys
from typing import Final, Any
SEMESTER_LENGTH: Final[int] = 15  # 15 Woche pro Semester
ECTS_EFFORT = 30  # 1 ECTS ~ 30 h
DS = 1.5  # DS = Doppelstunde = 2 Unterrichtstunden
def parse_line(line: str) -> tuple[str, float, float]:
    line = line.strip()
    line = [e.strip() for e in line.split(";")]
    return line[0], float(line[1]), float(line[2])
def collect_lectures_from_file(lecture_filename:str) -> list[tuple[str, float, float]]:
    # Your code here
    lectures = []
    with open(lecture_filename) as file:
        while line := file.readline():
            line = line.strip()
            if line[0] != '#':
                line = parse_line(line)
                lectures.append( line )
    return lectures
def lecture_effort(lecture: tuple[str, float, float]) -> float:
    sum_effort = lecture[1] * ECTS_EFFORT
    lecture_effort = SEMESTER_LENGTH * (lecture[2] * DS)
    return (sum_effort - lecture_effort) / SEMESTER_LENGTH
def compute_semester_effort(lectures: list[tuple[str, float, float]]) -> list[tuple[str, float, float, float]]:
    effort = [
        (e[0], e[1], e[2], lecture_effort(e)) for e in lectures
    ]
    return effort
def print_effort(effort: list[tuple[str, float, float, float]]) -> None:
    header = ("Vorlesung", "ECTS", "V;U;T/Woche", "Aufwand/Woche")
    max_char = len(header)
    sep_width = 3
    sum_effort = 0
    for l in effort:
        if (c := len(l[0])) > max_char:
            max_char = c
        sum_effort += l[-1]
    lecture_col_width = sep_width + max_char
    ects_width = len(header[1])
    veranstaltung_col_width = len(header[2])
    effort_col_width = len(header[3])
    def format_line(line: list[tuple[Any, Any, Any, Any]] ):
        lecture = f"{line[0]}".rjust(lecture_col_width)
        ects = f"{line[1]}".center(ects_width)
        v = f"{line[2]}".center(veranstaltung_col_width)
        e = f"{line[3]}".center(effort_col_width)
        return f"{lecture}  {ects}  {v}  {e}"
    print(format_line(header))
    for l in effort:
        print(format_line(l))
    print(f"Summe: {sum_effort}")
if __name__ == "__main__":
    lecture_filename = sys.argv[1]
    lectures = collect_lectures_from_file(lecture_filename)
    print(lectures)
    effort = compute_semester_effort(lectures)
    #print(effort)
    print_effort(effort)
python-grundlage/Lissajous-np.py
@@ -1,5 +1,5 @@
#! /usr/bin/env python
import sys
from typing import Final
import numpy as np
from numpy import pi
@@ -7,12 +7,13 @@
amplitude: tuple[float, float] = (1, 1)
# frequent
omega: tuple[float, float] = (-1, -2)
# frequent, some values (-3, 5) (-3, 8) (3, 11)
omega: tuple[float, float] = (3, 11)
# phase
phi: tuple[float, float] = (pi/2, 3*pi/4)
N: Final[int] = 100
N: Final[int] = 360*2
T = np.linspace(0, 2*pi, num=N)
x = amplitude[0] * np.cos(omega[0]*T + phi[0])
y = amplitude[1] * np.cos(omega[1]*T + phi[1])
@@ -21,5 +22,12 @@
fig, ax = plt.subplots()
ax.plot(x, y, linewidth=2.0)
write_to_file = False
if write_to_file:
    output_dir = "../../2024/python-output"
    image_filename = f"{output_dir}/{sys.argv[0].replace('.py','.pdf')}"
    plt.savefig(image_filename)
plt.show()
python-grundlage/Lissajous-turtle.py
@@ -1,19 +1,19 @@
#! /usr/bin/env python
import sys
from typing import Final
from math import pi, cos
import turtle
amplitude: tuple[float, float] = (1, 1)
amplitude: Final[tuple[float, float]] = (1, 1)
# frequent
omega: tuple[float, float] = (-1, -2)
omega: Final[tuple[float, float]] = (3, 11)
# phase
phi: tuple[float, float] = (pi/2, 3*pi/4)
phi: Final[tuple[float, float]] = (pi/2, 3*pi/4)
# Diskretisieren
N: Final[int] = 360
step = (2*pi) / N
T = [k * step for k in range(N)]
step: Final = (2*pi) / N
T: Final = [k * step for k in range(N)]
points = [(
        amplitude[0] * cos(omega[0]*t + phi[0]),
        amplitude[1] * cos(omega[1]*t + phi[1])
@@ -22,18 +22,33 @@
# Plot with turtle
(canvaswidth, canvasheight) = turtle.screensize()
point_size = 3
point_size = 1.5
turtle.setup(width=canvaswidth + 5*point_size, height=canvaswidth + 5*point_size)
# scale up
x_factor = (canvaswidth / 2) / amplitude[0]
y_factor = (canvasheight / 2) / amplitude[1]
print(x_factor, y_factor)
# as fast as possible
turtle.speed(0)
turtle.pendown()
turtle.penup()
turtle.pensize(point_size)
for p in points:
    x = x_factor * p[0]
    y = y_factor * p[1]
    turtle.teleport(x, y)
    turtle.dot(point_size)
    #turtle.teleport(x, y)
    #turtle.dot(point_size)
    turtle.goto(x, y)
    turtle.pendown()
p0 = points[0]
turtle.goto(x_factor * p0[0], y_factor * p0[1])
write_to_file = False
if write_to_file:
    output_dir = "../../2024/python-output"
    image_filename = f"{output_dir}/{sys.argv[0].replace('.py','.eps')}"
    print(f"save file to {image_filename}")
    canvas_screen = turtle.getscreen().getcanvas()
    canvas_screen.postscript(file=image_filename)
turtle.done()
python-grundlage/dice-simulation.py
@@ -1,8 +1,9 @@
#! /usr/bin/evn python
import random
from typing import Final
random.seed(5643)
experiments = 500
experiments: Final[int] = 500
dice_roll = tuple(random.randint(1, 6) for r in range(0, experiments))
absolute_frequency = tuple((face, len([f for f in dice_roll if f == face]))
                           for face in range(1, 6 + 1)
@@ -16,4 +17,4 @@
relative_frequency = tuple(
    (absolute_frequency[idx][0], absolute_frequency[idx][1] / experiments) for idx in range(1, 6 + 1)
)
)