Python :: Aufgabe #228 :: Lösung #2
2 Lösungen
#228
Das Zahnstochermuster und die Sequenz der Anzahl freier Spitzen im Muster
Fortgeschrittener - Python
von hollst
- 01.10.2019 um 18:15 Uhr
Man kann sogar mit Zahnstochern Mathematik bzw. Informatik betreiben!
Ein Zahnstochermuster wird schrittweise erzeugt: Im ersten Schritt legt man einen Zahnstocher
beliebig und flach auf eine 2D-Fläche ab. Ohne besondere Einschränkungen seien angenommen, dass jeder Zahnstocher
genau die Länge 1 (eins) hat und das erste Exemplar senkrecht und mittig in einem (X, Y)-Koordinatensystem
liegt. Das Muster hat nach dem ersten Schritt zwei freie Spitzen bei (1/2, 0) und (-1/2, 0).
Im zweite Schritt werden senkrecht zum ersten Zahnstocher auf die zwei freien Spitzen jeweils ein weiterer Zahnstocher gelegt,
danach haben wir vier freie Spitzen (siehe Bild step_2). Auf diese Weise wird schrittweise fortgefahren.
Die Sequenz der Anzahl freier Spitzen im Muster beginnt so:
Schritt........: 1..2..3..4..5....6..7..8..9..10 11 12 13 14 15 16 17 18 19 ...
freie Spitzen: 2..4..4..4..8..12, 8, 4, 8, 12, 12, 16, 28, 32, 16, 4, 8, 12, 12 ...
Sie steigt zunächst an bis 12 (Schritt 6), um danach auf 4 abzufallen (Schritt 8). Dieses Auf und Ab
zieht sich stetig fort (bis in alle Ewigkeit, was noch zu beweisen wäre [jedoch nicht von uns]).
Die Entwicklung des Zahnstochermusters hat fraktalen Charakter. Anhand von Bild step_10_14_17 soll dies belegt sein.
Die Programmieraufgabe bestehe darin, die Musterentwicklung bis zum Schritt 100 "interaktiv" darzustellen (Bild step_100)
und auch die Anzahl freier Zahnstocherspitzen jeweils anzugeben.
Viel Spaß!
Ein Zahnstochermuster wird schrittweise erzeugt: Im ersten Schritt legt man einen Zahnstocher
beliebig und flach auf eine 2D-Fläche ab. Ohne besondere Einschränkungen seien angenommen, dass jeder Zahnstocher
genau die Länge 1 (eins) hat und das erste Exemplar senkrecht und mittig in einem (X, Y)-Koordinatensystem
liegt. Das Muster hat nach dem ersten Schritt zwei freie Spitzen bei (1/2, 0) und (-1/2, 0).
Im zweite Schritt werden senkrecht zum ersten Zahnstocher auf die zwei freien Spitzen jeweils ein weiterer Zahnstocher gelegt,
danach haben wir vier freie Spitzen (siehe Bild step_2). Auf diese Weise wird schrittweise fortgefahren.
Die Sequenz der Anzahl freier Spitzen im Muster beginnt so:
Schritt........: 1..2..3..4..5....6..7..8..9..10 11 12 13 14 15 16 17 18 19 ...
freie Spitzen: 2..4..4..4..8..12, 8, 4, 8, 12, 12, 16, 28, 32, 16, 4, 8, 12, 12 ...
Sie steigt zunächst an bis 12 (Schritt 6), um danach auf 4 abzufallen (Schritt 8). Dieses Auf und Ab
zieht sich stetig fort (bis in alle Ewigkeit, was noch zu beweisen wäre [jedoch nicht von uns]).
Die Entwicklung des Zahnstochermusters hat fraktalen Charakter. Anhand von Bild step_10_14_17 soll dies belegt sein.
Die Programmieraufgabe bestehe darin, die Musterentwicklung bis zum Schritt 100 "interaktiv" darzustellen (Bild step_100)
und auch die Anzahl freier Zahnstocherspitzen jeweils anzugeben.
Viel Spaß!
#2
von Klaus (1960 Punkte)
- 11.03.2020 um 10:52 Uhr
Zur Implementierung der GUI habe ich PySimpleGUI genutzt. Basierend auf tkinter ist PySimpleGUI aus meiner Sicht eine einfache und pragmatische Lösung, um schnell eine grafische Benutzeroberfläche mit wenig Code zu kreieren.
Installation über
pip install pysimplegui
oder
conda install pysimplegui.
Alles weitere unter https://pysimplegui.readthedocs.io/en/latest/
Installation über
pip install pysimplegui
oder
conda install pysimplegui.
Alles weitere unter https://pysimplegui.readthedocs.io/en/latest/
Python-Code
import PySimpleGUI as sg # Die Konstanten können je nach Bedarf angepasst werden # Anzahl der Schritte, die durchlaufen werden sollen NUMBER_OF_ITERATIONS = 100 # Größe des Gitters, das angezeigt werden soll (bei einer Streichholzlänge von 1) GRID_SIZE = 55 # Zoom-Faktor, um unterschiedliche Display-Größen auszugleichen ZOOM_FACTOR = 15 # Zeitverzögerung (in Millisekunden) der Anzeige zwischen den einzelnen Schritten TIME_DELAY = 500 class Point: def __init__(self, x_coordinate, y_coordinate, state): """state: free, occupied""" self.x_coordinate = x_coordinate self.y_coordinate = y_coordinate self.state = state def __repr__(self): """zum Debuggen""" return f' (POINT({self.x_coordinate}/{self.y_coordinate})-{self.state}) ' class Line: def __init__(self, start, middle, end, orientation): """orientation: horizontal, vertical""" self.start = start self.middle = middle self.end = end self.orientation = orientation def __repr__(self): """zum Debuggen""" return f' LINE({self.start}/{self.middle}/{self.end}) - {self.orientation}) ' class Model: def __init__(self, start_line): self.list_of_points = [start_line.start, start_line.middle, start_line.end] self.list_of_lines = [start_line] def return_free_points(self): """gibt eine Liste der freien Punkte zurück""" return_list = [] for point in self.list_of_points: if point.state == 'free': return_list.append(point) return return_list def return_number_of_free_points(self): """gibt die Anzahl der freien Punkte zurück""" return len(self.return_free_points()) def return_new_point_orientation(self, point): """gibt die erforderliche Ausrichtung einer neuen Linie zurück""" for line in self.list_of_lines: if point == line.start or point == line.middle or point == line.end: if line.orientation == 'vertical': return 'horizontal' elif line.orientation == 'horizontal': return 'vertical' def check_point_exists_already(self, point): """prüft, ob ein Punkt bereits belegt ist und gibt diesen dann zurück""" for compare_point in self.list_of_points: if compare_point.x_coordinate == point.x_coordinate and compare_point.y_coordinate == point.y_coordinate: return compare_point return None def add_line(self, free_point, orientation): """gibt ein neues Line-Objekt basierend auf dem Ausgangspunkt und die richtige Ausrichtung zurück""" free_point.state = 'occupied' if orientation == 'vertical': start_point = Point(free_point.x_coordinate, free_point.y_coordinate - 0.5, 'free') middle_point = free_point end_point = Point(free_point.x_coordinate, free_point.y_coordinate + 0.5, 'free') elif orientation == 'horizontal': start_point = Point(free_point.x_coordinate + 0.5, free_point.y_coordinate, 'free') middle_point = free_point end_point = Point(free_point.x_coordinate - 0.5, free_point.y_coordinate, 'free') first_point = self.check_point_exists_already(start_point) if isinstance(first_point, Point): start_point = first_point start_point.state= 'occupied' else: self.list_of_points.append(start_point) second_point = self.check_point_exists_already(end_point) if isinstance(second_point, Point): end_point = second_point end_point.state='occupied' else: self.list_of_points.append(end_point) line = Line(start_point, middle_point, end_point, orientation) self.list_of_lines.append(line) return line class GUI: def __init__(self): self.layout = [[sg.Graph(canvas_size=(GRID_SIZE * ZOOM_FACTOR, GRID_SIZE * ZOOM_FACTOR), graph_bottom_left=(GRID_SIZE / -2 * ZOOM_FACTOR, GRID_SIZE / -2 * ZOOM_FACTOR), graph_top_right=(GRID_SIZE / 2 * ZOOM_FACTOR, GRID_SIZE / 2 * ZOOM_FACTOR), background_color='white', key='_graph_')], [sg.Text('RUNDE 1: Freie Punkte 2', size=(int(GRID_SIZE*ZOOM_FACTOR/6),1), text_color='black', background_color='white', justification='center', key='_text_', font=('Arial', 8))]] self.window = sg.Window('Zahnstochermuster', self.layout, finalize = True, background_color='white', return_keyboard_events=True) self.graph = self.window.FindElement('_graph_') self.text = self.window.FindElement('_text_') def draw_a_line(self, line, color): """zeichnet eine neue Linie basierend auf dem Line-Objekt auf den Graph""" self.graph.draw_line((line.start.x_coordinate * ZOOM_FACTOR, line.start.y_coordinate * ZOOM_FACTOR), (line.end.x_coordinate * ZOOM_FACTOR, line.end.y_coordinate * ZOOM_FACTOR), color=color, width = 1) class Controller: def __init__(self, number_of_iterations): self.number_of_iterations = number_of_iterations start_line = Line(Point(0, 0.5, 'free'), Point(0, 0, 'occupied'), Point(0, -0.5, 'free'), 'vertical') self.m = Model(start_line) self.new_lines=[start_line] self.old_lines = [] self.gui = GUI() self.run() def run(self): for iteration in range(2, self.number_of_iterations + 1): for line in self.new_lines: self.gui.draw_a_line(line, 'red') self.old_lines = self.new_lines self.new_lines = [] for free_point in self.m.return_free_points(): new_line = self.m.add_line(free_point, self.m.return_new_point_orientation(free_point)) self.new_lines.append(new_line) event, values = self.gui.window.read(timeout = TIME_DELAY) if event is not None: for line in self.old_lines: self.gui.draw_a_line(line, 'black') for line in self.new_lines: self.gui.draw_a_line(line, 'red') self.gui.text(f'RUNDE {iteration}: Freie Punkte {self.m.return_number_of_free_points()}') if event is None: break while True: self.gui.text('TASTE zum Beenden') event, values = self.gui.window.read() if event is None or len(event)==1: print(event) break self.gui.window.close() Controller(NUMBER_OF_ITERATIONS)
Kommentare:
Für diese Lösung gibt es noch keinen Kommentar
Seite 1 von 0
1