Seite 1 von 1

63 Buttons erzeugen und auswerten (Dart-Projekt)

Verfasst: Mittwoch 24. Juni 2020, 12:23
von thludwig
Hallo zusammen.


Ich habe mir jetzt Tage lang den Kopf zerbrochen, wie ich am besten diese 63 Buttons erzeuge, abfrage und deren Wert den Spielerpunkten zuordne.
Leider habe ich mich mittlerweile im Dschungel der Möglichkeiten verirrt...Buttons mit Index, Listen und und und. Es ist auch problematisch, sich für eine Möglichkeit zu entscheiden, wenn man ständig denkt, dass es da bestimmt noch mehr und einfachere gibt. Bevor ich mich jetzt also hier verrenne, wollte ich mal die erfahrenen Prohgrammierer fragen, welche Vorgehensweise sie mir empfehlen würden.

Was habe ich vor? Ich will 63 Buttons mittels Touchscreen verwenden, um die im Laufe eines Dart-Spiels geworfenen Punkte einzugeben. Ich werfe also drei Pfeile, gehe an den Bildschirm, tippe auf 3 Buttons und bestätige die Eingabe. Die Punkte, die sich hinter den einzelnen Buttons verbergen, sollen (je nach Spielmodus) vom Punktekonto des jeweiligen Spielers abgezogen bzw. hinzuaddiert oder sonstwie verarbeitet werden.
Die 63 Buttons sollen in 3er-Spalten angeordnet werden.
Oben angefangen in der ersten Reihe Bull (25 Punkte), Bull's Eye (50 Punkte) Fehlwurf.
In der zweiten Reihe sind dann die 20er dran, also S20 (20), D20 (40), T20 (60). darunter die 19 usw. bis runter zur 1.

Wenn jetzt ein Spieler dran ist, wirft er seine 3 Darts und geht dann an den Bildschirm, um die 3 getroffenen Felder auszuwählen. Diese werden dann den 3 Würfen des Spielers zugeordnet.
z.B. mit den Variablen player=Nummer des Spielers (1-4, mehr habe ich im Moment nicht vorgesehen), round=Runde im Spiel (1-x), dart=Nummer des Darts (1-3)
Den Parameter pro geworfenem Dart stelle ich mir in etwa so vor: player_runde_dart=x
Der zweite Dart in der sechsten Runde von Spieler 1 auf Triple16 würde dann so aussehen: 1_6_2=T16
Dann folgt die Addition der drei Würfe bzw. der sich dahinter verbergenden Punkte und die Subtraktion (bei X01-Spielen, wo man z.B. von 301 auf 0 runterwerfen muss) von der Punktezahl des Spielers.

Ich möchte nun ungern anfangen, die Buttons aufgrund meiner Anfängerkenntnisse manuell und einzeln zu setzen und mit IF-Abfragen auszuwerten, um dann festzustellen, dass ich die Werte nicht addieren/subtraheieren kann, weil ich die nicht richtig zugeordnet habe.

Was ich also bräuchte, wären Hinweise oder Vorschläge, wie ihr das machen würdet. Also wie würdet ihr die Buttons erzeugen, wie beschriften, wie abfragen und wie dem jeweiligen Spieler/Runde/Dart zuordnen.

Ich erwarte kein fertiges Programm, nur ein paar Schubser in die richtige Richtung.

Das Programm würde ich natürlich an interessierte Dartspieler weitergeben, aber aufgrund des speziellen Setups mit Pi und 19"-Touchmonitor reicht es mir völlig, wenn es bei mir gut läuft....schön - also vom Quellcode her - muss es auch nicht sein :roll:

Ich hoffe auf eure Hilfe :)

Gruß
Thorsten

Re: 63 Buttons erzeugen und auswerten (Dart-Projekt)

Verfasst: Mittwoch 24. Juni 2020, 12:49
von Sirius3
Doch, es muß "schön" sein, denn alles andere macht Dir früher oder später Probleme. Was Du an Grundlagen brauchst, ist Objektorientierte Programmierung, denn ohne Klassendefinitionen für die Fenster und Spieler kommst Du nicht weit. Die Knöpfe erzeugt man in einer Schleife, wobei die erste Zeile ein Sonderfall ist.
Ansonsten gibt es hier im Forum etliche Bespiele, wie schlechte tkInter-Programme aussehen, und wie sie zu verbessern sind. Wenn ich mich recht erinnere, ist da auch hin und wieder ein Taschenrechner dabei, der ja ganz ähnlich eine Reihe von Knöpfen braucht.

Re: 63 Buttons erzeugen und auswerten (Dart-Projekt)

Verfasst: Mittwoch 24. Juni 2020, 13:34
von thludwig
Ich kann mir vorstellen, was du meinst: schön = übersichtlich und damit gut zu überarbeiten. Leider hab ich das nie richtig gelernt, alles was ich gemacht habe, war quick (mehr oder weniger) and dirty, so dass es geht.
Ich werde mir Mühe geben, dass bei dem Projekt nicht was rauskommt, was nur funktionert. Aber dafür werde ich eure Hilfe brauchen. Mit meinen bisherigen Kenntnissen würde ich vielleicht die Positionierung der Buttons hinkriegen, aber die Abfragen nicht, fürchte ich.


Die Erzeugung der Buttons in einer Schleife hab ich auch schon gesehen. Mit einer FOR-Schleife 0-2 für die Spalten und einer darin liegenden 0-20 für die Reihen?
Die Werte würde man dann aus einer Liste holen? Soweit ich gesehen habe, kann man den Buttons dann auch einen "Index" aus [Spalte,Reihe] verpassen.

Die Liste würde so aussehen:
Bull,DBull,Miss,S20,D20,T20,S19,D19,T19,S18,D18,T18,S17,D17,T17,S16,D16,T16,S15,D15,T15,S14,D14,T14,S13,D13,T13,S12,D12,T12,S11,D11,T11,S10,D10,T10,S9,D9,T9,S8,D8,T8,S7,D7,T7,S6,D6,T6,S5,D5,T5,S4,D4,T4,S3,D3,T3,S2,D2,T2,S1,D1,T1

Bitte, wenn ich hier nur Bullshit schreibe, dann dürft ihr das ruhig sagen. Und wenn es irgendwo etwas nachzulesen gibt, was mir auf die Sprünge hilft, dann wäre ich für einen Link dankbar. Wo könnte ich z.B. am besten etwas über die von dir genannten Klassen(definitionen) lernen?

Re: 63 Buttons erzeugen und auswerten (Dart-Projekt)

Verfasst: Mittwoch 24. Juni 2020, 14:45
von __blackjack__
@thludwig: Ich würde mir an Deiner Stelle gar nicht erst ``for``-Schleifen nur über Zahlen angewöhnen. Das ist in den allermeisten Fällen ein Code-Smell. Eigentlich willst Du ja über etwas anderes pro Spalte iterieren, nämlich über die Notation für die Spalten (oder Zeilen) *und* einer laufenden Zahl um die an die enstprechende Stelle im `grid()` zu setzen. Wenn man *zusätzlich* eine Zahl braucht, dann nimmt man `enumerate()`.

Etwas aus der Hüfte geschossen und ungetestet:

Code: Alles auswählen

#!/usr/bin/env python3
import tkinter as tk
from itertools import chain, repeat


class NeedsSomeBetterNameFrame(tk.Frame):
    def __init__(self, master):
        tk.Frame.__init__(self, master)
        self._variables = list()
        for row, second_part in enumerate(
            chain([""], map(str, (reversed(range(21)))))
        ):
            for column, first_part in enumerate(
                chain([("Bull", "DBull", "Miss")], repeat(("S", "D", "T")))
            ):
                variable = tk.StringVar()
                self._variables.append(variable)
                notation = f"{first_part}{second_part}"
                tk.Checkbutton(
                    self,
                    text=notation,
                    indicatoron=False,
                    onvalue=notation,
                    offvalue="",
                    variable=variable,
                ).grid(row=row, column=column)

    def reset_selection(self):
        for variable in self._variables:
            variable.set("")

    def get_selection(self):
        result = [
            variable.get() for variable in self._variables if variable.get()
        ]
        return result if len(result) == 3 else None

Re: 63 Buttons erzeugen und auswerten (Dart-Projekt)

Verfasst: Mittwoch 24. Juni 2020, 15:13
von thludwig
Oh wow o_O

OK...itertools, chain, repeat.....das sind komplett böhmische Dörfer für mich. Ich hab schon bisschen über Klassendefinitionen gelesen, aber für das hier reicht mein Kung Fu bei weitem nicht :mrgreen:

Das muss ich mir mal in aller Ruhe zu Gemüte führen und Stück für Stück auseinanderdröseln, was da gemacht wird :roll:

Danke erst Mal!

PS: Das mit dem Nicht Angwöhnen von FOR-Schleifen mit Zahlen kommt leider viel zu spät, das hätte mir jemand in den 80ern sagen müssen, als ich auf dem C64 die For-Next-Schleife gelernt und seitdem scheinbar nicht mehr viel dazugelernt habe :wink:

Re: 63 Buttons erzeugen und auswerten (Dart-Projekt)

Verfasst: Mittwoch 24. Juni 2020, 20:33
von thludwig
Geez, der Code ist echt die reinste Raketentechnik für mich :cry:

Ich hab mal angefangen, mich über die einzelnen Termini zu informieren, aber das muss ich ein paar Mal lesen und vielleicht kleinere Übungen machen, damit sich das setzen kann...mit 51 lernt es sich nimmer so schnell ;)

Mal ne doofe Frage....was macht das alles, was passiert da? Wenn ich den Code in Spyder kopiere und starte, passiert scheinbar nix..oder zumindest nix, was ich sehen könnte. Da fehlt noch Coder, damit was passiert, oder? Sorry für eventuelle dumme Fragen :roll:
Ich glaube verstanden zu haben, dass die erste Reihe Buttons mit Bull, DBull und Miss beschriftet wird und dann wird ab der zweiten Reihe durchgezählt....aber wie das passiert, ist mir noch völlig schleierhaft :?

Wie gesagt, ich brauch da wohl ein paar Tage, bis ich dahintersteige....wenn überhaupt....scheint was mit schwarzer Magie im Vollmondlicht zu tun zu haben :mrgreen:

Gruß
Thorsten

Re: 63 Buttons erzeugen und auswerten (Dart-Projekt)

Verfasst: Mittwoch 24. Juni 2020, 20:41
von Sirius3
Der Code definiert nur eine Klasse für einen Frame, den Du dann in Dein Fenster mit den Spieleransichten einbinden mußt. Siehe Deinen anderen Thread.

Re: 63 Buttons erzeugen und auswerten (Dart-Projekt)

Verfasst: Donnerstag 25. Juni 2020, 00:22
von __blackjack__
@thludwig: Nimm das einfach mal Stück für Stück auseinander und probier es in einer Python-Shell live aus. Das hat Python ja mit dem guten alten BASIC V2 auf dem C64 gemeinsam: man kann auch einfach Sachen im ”Direktmodus” mal ausprobieren und bekommt sofort Rückmeldung/ein Ergebnis zu sehen.

Die ganzen Beschriftungen bestehen ja aus zwei Teilen. ”Was” und "wie viel". Also Beispielsweise ”was” kann "S" sein, und ”wie viel” kann 8 sein. Ergibt zusammen "S8". Diese ganzen Möglichkeiten müssen wir in drei Spalten erzeugen. Da kann man sich jetzt überlegen in welcher Reihenfolge man das macht — for jede Spalte die Zeilenwerte erzeugen, oder für jede Zeile die Spaltenwerte erzeugen. Ich habe mich für zeilenweises Erzeugen entschieden.

Die erste Zeile fällt aus dem Rahmen weil wir da in jeder Spalte ein ”was” haben, aber kein ”wie viel”. Da das Ergebnis am Ende eine Zeichenkette ist, kann man da einfach die leere Zeichenkette nehmen.

Danach kommt dann für jede weitere Zeile das ”wie viel” von 20 bis runter zur 1. Und da sehe ich auch gerade einen Fehler — das `range()` muss bei 1 anfangen. 😳

Also die Zahlen von 1 bis 20:

Code: Alles auswählen

In [31]: range(1, 21)                                                           
Out[31]: range(1, 21)
Hier kommt dann auch schon das erste was man in CBM BASIC V2 nicht hat: ein iterierbares Objekt. Das braucht man für ``for``-Schleifen. Und für Funktionen die so etwas entgegennehmen und was damit machen. Nicht selten selbst wieder ein iterierbares Objekt als Ergebnis liefern.

Iterierbar heisst, das man die `iter()`-Funktion damit aufrufen kann, und einen Iterator zurückbekommt. Das ist ein Objekt mit dem man die `next()`-Funktion aufrufen kann und dann entweder das nächste Element bekommt, oder einen `StopIteration`-Ausnahme wenn es keine weiteren Elemente mehr gibt. Mal mit einem etwas kleineren `range()`:

Code: Alles auswählen

In [32]: iterator = iter(range(1, 4))                                           

In [33]: iterator                                                               
Out[33]: <range_iterator at 0x7fa0f6d19d80>

In [34]: next(iterator)                                                         
Out[34]: 1

In [35]: next(iterator)                                                         
Out[35]: 2

In [36]: next(iterator)                                                         
Out[36]: 3

In [37]: next(iterator)                                                         
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-37-4ce711c44abc> in <module>
----> 1 next(iterator)

StopIteration:
Genau das macht *jede* ``for``-Schleife in Python intern. Von dem Ergebnis des Ausdrucks der hinter ``in`` steht wird ein Iterator abgefragt und der wird dann für jeden Schleifendurchlauf nach dem nächsten Element gefragt.

Wenn man die Werte mal sehen will, kann man sie in einer Liste sammeln. Das macht `list()` wenn man ein iterierbares Objekt übergibt: solange nach Elementen fragen und die in einer Liste speichern, bis keine Elemente mehr da sind:

Code: Alles auswählen

In [38]: list(range(1, 21))                                                     
Out[38]: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
Wir wollen die Elemente aber in umgekehrter Reihenfolge haben, also `reversed()`:

Code: Alles auswählen

In [40]: list(reversed(range(1, 21)))                                           
Out[40]: [20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
Das sind Zahlen, wir brauchen aber Zeichenketten, also mit `map()` auf jedes Element `str()` anwenden:

Code: Alles auswählen

In [41]: list(map(str, reversed(range(1, 21))))                                 
Out[41]: 
['20',
 '19',
 '18',
 '17',
 '16',
 '15',
 '14',
 '13',
 '12',
 '11',
 '10',
 '9',
 '8',
 '7',
 '6',
 '5',
 '4',
 '3',
 '2',
 '1']
Mit `chain()` kann man mehrere iterierbare Objekte verketten, das heisst deren Elemente werden alle nacheinander geliefert. Für die erste Zeile brauchen wir eine leere Zeichenkette:

Code: Alles auswählen

In [42]: list(chain([""], map(str, reversed(range(1, 21)))))                    
Out[42]: 
['',
 '20',
 '19',
 '18',
 '17',
 '16',
 '15',
 '14',
 '13',
 '12',
 '11',
 '10',
 '9',
 '8',
 '7',
 '6',
 '5',
 '4',
 '3',
 '2',
 '1']
Und nun brauchen wir für das `grid()` noch eine Zeilennummer für jedes Element:

Code: Alles auswählen

 In [43]: list(enumerate(chain([""], map(str, reversed(range(1, 21))))))         
Out[43]: 
[(0, ''),
 (1, '20'),
 (2, '19'),
 (3, '18'),
 (4, '17'),
 (5, '16'),
 (6, '15'),
 (7, '14'),
 (8, '13'),
 (9, '12'),
 (10, '11'),
 (11, '10'),
 (12, '9'),
 (13, '8'),
 (14, '7'),
 (15, '6'),
 (16, '5'),
 (17, '4'),
 (18, '3'),
 (19, '2'),
 (20, '1')]
Standard bei `enumerate()` ist 0 als Startwert, man kann aber auch einen anderen Wert angeben und eine Schrittweite wenn man möchte.

Und bei der inneren Schleife habe ich dann einen weiteren Fehler gemacht, denn das ist eine Endlosschleife. Denn `repeat()` liefert *endlos* das was man da übergeben hat. Damit das nicht passiert muss man das zu einer Schleife zusammenfassen mit `zip()`.

So rum müsste es stimmen, aber wie beim letzten Mal ungetestet und bei `what`, `i_dont_know_how_to_call_this`, und `no_idea` weiss ich nicht wie ich das nennen soll. Keine Ahnung von Dart halt…

Code: Alles auswählen

    def __init__(self, master):
        tk.Frame.__init__(self, master)
        self._variables = list()

        what = chain([("Bull", "DBull", "Miss")], repeat(("S", "D", "T")))
        quantities = chain([""], map(str, (reversed(range(21)))))

        for row, (quantity, i_dont_know_how_to_call_this) in enumerate(
            zip(quantities, what)
        ):
            for column, no_idea in enumerate(i_dont_know_how_to_call_this):
                variable = tk.StringVar()
                self._variables.append(variable)
                notation = f"{no_idea}{quantity}"
                tk.Checkbutton(
                    self,
                    text=notation,
                    indicatoron=False,
                    onvalue=notation,
                    offvalue="",
                    variable=variable,
                ).grid(row=row, column=column)

Re: 63 Buttons erzeugen und auswerten (Dart-Projekt)

Verfasst: Donnerstag 25. Juni 2020, 09:45
von thludwig
Und da sehe ich auch gerade einen Fehler — das `range()` muss bei 1 anfangen.


Typischer Anfängerfehler :mrgreen: :wink:

Ich danke dir ganz herzlich für die Mühe, die du dir gemacht hast!!!

Ich muss leider einsehen, dass ich mich in Python (und generell in der objektorientierten Programmierung) noch viiiiel zu wenig auskenne, als dass ich deinen fortgeschrittenen Code verstehen geschweige denn verwenden könnte....ich wüsste nicht mal, wie ich daraus jetzt etwas machen kann, was man auch sieht. Wenn ich ehrlich bin, habe ich erst am Montag angefangen, mich mit Python zu beschäftigen und ich dachte wie so oft: Das kann doch nicht so kompliziert sein, ich hab ja schließlich schon mal programmiert. Mir ist allerdings ziemlich schnell bewusst geworden, dass mein Programmier-Gestümpere wenig mit richtigem Programmieren zu tun hat und ich zwar (mit umständlichem Code und viel Gefrickel) die Oberfläche und 63 Buttons "malen" könnte, die Abfrage und Berechnung der Dart-Würfe aber nochmal ein ganz anderes, viel größeres Problem darstellt. Vom Code-Smell einmal ganz abgesehen :oops:

Das heißt für mich, ich muss mir erst noch die Grundlagen draufschaffen und viel üben. Tutorials anschauen, lesen, Code in Spyder testen. Parallel zu den entsprechenden Tutorials werde ich mir deine Erläuterungen durchlesen und versuchen zu verstehen, was du da machst. Und vielleicht schaffe ich es im Laufe der nächsten Woche, deinen Code so zu erweitern, dass ich beim Starten auch was angezeigt bekomme :roll:

Gruß
Thorsten