From 84055e4d0cb58f94ac8e6be28885c7d51d13ef3a Mon Sep 17 00:00:00 2001
From: Hong-Phuc Bui <hong-phuc.bui@htwsaar.de>
Date: Mon, 13 May 2024 02:54:33 +0200
Subject: [PATCH] Example for functions

---
 funktion-modular/README.md                                               |    5 +
 .gitignore                                                               |    3 
 python-grundlage/Lissajous-turtle.py                                     |   35 +++++--
 funktion-modular/calendar/__pycache__/month_of_year.cpython-312.pyc      |    0 
 funktion-modular/calendar/test_month_of_year.py                          |   25 +++++
 funktion-modular/calendar/HOWTO.md                                       |   15 +++
 funktion-modular/calendar/__pycache__/test_month_of_year.cpython-312.pyc |    0 
 funktion-modular/calendar/month_of_year.py                               |   99 +++++++++++++++++++
 python-grundlage/Lissajous-np.py                                         |   16 ++
 funktion-modular/calendar/month_of_year-no-fn.py                         |   90 ++++++++++++++++++
 10 files changed, 273 insertions(+), 15 deletions(-)

diff --git a/.gitignore b/.gitignore
index f282e9f..ae4b8a2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
 sandbox*
-queens*
\ No newline at end of file
+queens*
+*.venv*
\ No newline at end of file
diff --git a/funktion-modular/README.md b/funktion-modular/README.md
new file mode 100644
index 0000000..c09b1de
--- /dev/null
+++ b/funktion-modular/README.md
@@ -0,0 +1,5 @@
+# README
+
+1. One project one directory with unittest
+2. Use typing annotation for every function.
+
diff --git a/funktion-modular/calendar/HOWTO.md b/funktion-modular/calendar/HOWTO.md
new file mode 100644
index 0000000..56f2d5d
--- /dev/null
+++ b/funktion-modular/calendar/HOWTO.md
@@ -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'
+```
diff --git a/funktion-modular/calendar/__pycache__/month_of_year.cpython-312.pyc b/funktion-modular/calendar/__pycache__/month_of_year.cpython-312.pyc
new file mode 100644
index 0000000..7934e3f
--- /dev/null
+++ b/funktion-modular/calendar/__pycache__/month_of_year.cpython-312.pyc
Binary files differ
diff --git a/funktion-modular/calendar/__pycache__/test_month_of_year.cpython-312.pyc b/funktion-modular/calendar/__pycache__/test_month_of_year.cpython-312.pyc
new file mode 100644
index 0000000..f14a14a
--- /dev/null
+++ b/funktion-modular/calendar/__pycache__/test_month_of_year.cpython-312.pyc
Binary files differ
diff --git a/funktion-modular/calendar/month_of_year-no-fn.py b/funktion-modular/calendar/month_of_year-no-fn.py
new file mode 100755
index 0000000..d03cb1e
--- /dev/null
+++ b/funktion-modular/calendar/month_of_year-no-fn.py
@@ -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)
diff --git a/funktion-modular/calendar/month_of_year.py b/funktion-modular/calendar/month_of_year.py
new file mode 100755
index 0000000..29bac62
--- /dev/null
+++ b/funktion-modular/calendar/month_of_year.py
@@ -0,0 +1,99 @@
+#! /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: 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}\n"
+    return calendar_view
+
+
+if __name__ == "__main__":
+    month = int(sys.argv[1])
+    year = int(sys.argv[2])
+    cal = build_calendar(month, year, 4)
+    print(cal)
\ No newline at end of file
diff --git a/funktion-modular/calendar/test_month_of_year.py b/funktion-modular/calendar/test_month_of_year.py
new file mode 100644
index 0000000..074bf03
--- /dev/null
+++ b/funktion-modular/calendar/test_month_of_year.py
@@ -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()
diff --git a/python-grundlage/Lissajous-np.py b/python-grundlage/Lissajous-np.py
index 4460ee5..f51902c 100644
--- a/python-grundlage/Lissajous-np.py
+++ b/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()
 
+
diff --git a/python-grundlage/Lissajous-turtle.py b/python-grundlage/Lissajous-turtle.py
index 62a1d4a..9f44134 100644
--- a/python-grundlage/Lissajous-turtle.py
+++ b/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()

--
Gitblit v1.10.0-SNAPSHOT