Seite 4 von 16

Verfasst: Samstag 12. Juli 2008, 10:00
von wuf
Hallo numerix

Stimmt natürlich. Dein Vorschlag habe ich nicht übersehen. Ich weiss aber nicht wie 'derkai' dies interpretiert.

Danke für deinen genialen Tipp.

Gruss wuf :wink:

Verfasst: Samstag 12. Juli 2008, 10:20
von derkai
derkai ist gerade erst wach geworden und wird gleich loslegen.

toggle ist nun auch klar.

Kai

Verfasst: Samstag 12. Juli 2008, 12:21
von derkai
so, nun habe ich den Code schon einmal meinen Wünschen angepasst.
Als nächstes werde ich mich noch um die Farben kümmern müssen und anschließend versuche ich die Veränderungen zu verstehen.

Danach geht es dann mit dem Erstellen einer Liste aller Koordinaten weiter -
ich möchte ja später gezielt die Position, Farbe und Eigenschaften jedes einzelnen Feldes auslesen können ....

Ich weiss, dass haben wir hier schon angesprochen, ich muß aber leider immer noch erst einen Fuss vor den anderen setzen.

Guckst Du :

Code: Alles auswählen

import Tkinter as tk
from math import sqrt
from random import choice

def calculate_polygon_points(laenge,xorg,yorg):
    """Berechne die Eckpunkte für ein Sechseck"""

    x1 = xorg
    y1 = yorg
    x2 = x1 + laenge
    y2 = y1
    x3 = x2 + (laenge/2.0)
    y3 = y2 + ((laenge * sqrt(3)/2))
    x4 = x2
    y4 = (sqrt(3) * laenge) + y2
    x5 = x1
    y5 = y4
    x6 = x1 - (laenge / 2.0)
    y6 = y3

    #~~ Gebe die berechneten Eckpunkte in einer Liste zurück
    return [x1,y1,x2,y2,x3,y3,x4,y4,x5,y5,x6,y6]

def create_hex_polygon(spiel,xpos,ypos,points,farbe):
    """Erzeugt das grafische Sechseck-Objekt"""

    x1,y1,x2,y2,x3,y3,x4,y4,x5,y5,x6,y6 = points

    x1 += xpos
    y1 += ypos
    x2 += xpos
    y2 += ypos
    x3 += xpos
    y3 += ypos
    x4 += xpos
    y4 += ypos
    x5 += xpos
    y5 += ypos
    x6 += xpos
    y6 += ypos

    return spiel.create_polygon(x1,y1,x2,y2,x3,y3,x4,y4,x5,y5,x6,y6,
                outline="black",fill=choice(farbe))

def calculate_xyoffset(points):
    """Berechnet die X- und Y-Versatzabstände"""

    x1,y1,x2,y2,x3,y3,x4,y4,x5,y5,x6,y6 = points

    laenge = x2 - x1
    xoffset = laenge + (x3-x2)
    yoffset = y5 - y1

    return (xoffset,yoffset)

def main():
    
    master = tk.Tk()
    spiel = tk.Canvas(master, width=1024, height=768)
    spiel.pack()

    hex_laenge = 20 # Bestimmt die Sechseckgrösse
    hex_xorg = 15
    hex_yorg = 5

    #~~ Eckpunkte für das Sechseck berechnen
    hex_point_list = calculate_polygon_points(hex_laenge,hex_xorg,hex_yorg)

    #~~ Horizontaler- & Vertikaler-Versatz die Sechseck-Platzierung berechnen
    xoffset, yoffset = calculate_xyoffset(hex_point_list)

    xpos = xorg = 10                                            # X Start-Koordinate
    ypos = yorg = 10                                            # Y Start-Koordinate
    ungerade_spalten = 17                                       # Spalten
    gerade_spalten = 16                                         # Zeilen
    farbe = ("green","green","green","green","green","green",
             "brown","green","blue","green")                     # Zufalls-Farben

    #Vorbelegung der Spalten/Zeilen
    GERADE = True
    UNGERADE = False 
    spalten_nummer = GERADE

    #~~ Platziere den zweidimensionalen Sechseck-Array

    for x in range(42):

        if spalten_nummer == GERADE :
            for x in range(ungerade_spalten):
                create_hex_polygon(spiel,xpos,ypos,hex_point_list,farbe)
                xpos = xpos + (xoffset *2)
            spalten_nummer = UNGERADE
            xpos = xorg + xoffset
            ypos = ypos + yoffset / 2


        else :
            for x in range(gerade_spalten):
                create_hex_polygon(spiel,xpos,ypos,hex_point_list,farbe)
                xpos = xpos + (xoffset *2)
            spalten_nummer = GERADE
            xpos = xorg
            ypos = ypos + yoffset / 2         


    master.mainloop()

main()
Kai

Verfasst: Samstag 12. Juli 2008, 12:24
von derkai
das habe ich gerade noch geändert :
(Spielfeld ist auch eine Variable)

Code: Alles auswählen

    xpos = xorg = 10                                            # X Start-Koordinate
    ypos = yorg = 10                                            # Y Start-Koordinate
    ungerade_spalten = 17                                       # Spalten
    gerade_spalten = 16                                         # Spalten
    spielfeld = 42                                              #Gesamtanzahl der Zeilen
    farbe = ("green","green","green","green","green","green",
             "brown","green","blue","green")                     # Zufalls-Farben

    #Vorbelegung der Spalten/Zeilen
    GERADE = True
    UNGERADE = False 
    spalten_nummer = GERADE

    #~~ Platziere den zweidimensionalen Sechseck-Array

    for x in range(spielfeld):

Verfasst: Samstag 12. Juli 2008, 13:04
von derkai
ok, Farbe ist vorerst auch fertig :

Code: Alles auswählen

    farbe = ("#F6C783","#F6C783","#F6C783",         
             "#F6C783","#F6C783","#F6C783",                     #hellbaun
             "#F6C783","#F6C783","#F6C783",                     
             "#F6C783","#F6C783","#F6C783",
             "#F6C783","#F6C783","#F6C783",
             "#18C85A","#A0A6F5")                               #gruen,blau
      
Kai

Verfasst: Samstag 12. Juli 2008, 13:18
von numerix
derkai hat geschrieben:ok, Farbe ist vorerst auch fertig :

Code: Alles auswählen

    farbe = ("#F6C783","#F6C783","#F6C783",         
             "#F6C783","#F6C783","#F6C783",                     #hellbaun
             "#F6C783","#F6C783","#F6C783",                     
             "#F6C783","#F6C783","#F6C783",
             "#F6C783","#F6C783","#F6C783",
             "#18C85A","#A0A6F5")                               #gruen,blau
      
Kai
Dann mach es doch wenigstens so:

Code: Alles auswählen

farbe = ("#F6C783",)*15+("#18C85A","#A0A6F5")

Verfasst: Samstag 12. Juli 2008, 13:30
von derkai
ja, das ist viel besser. schon geändert

Gruß
Kai

Verfasst: Samstag 12. Juli 2008, 15:50
von ~Mitneid~
Das sieht ja schon ganz schön gut aus!

vielleicht magst Du ja noch zwischen Zeile 58 und 59 noch:

Code: Alles auswählen

master.state('zoomed')# maximiert automatisch das Fenster aus Vollbild
master.overrideredirect( 1 )# die Kopfzeile wird entfernt (mehr Platz :-) )
Vielleicht sagt Dir ja eines von beiden zu. Das Fenster läßt sich nach overridedirect mit "Alt F4" Taste wieder schließen, bis man einen Mechanismus gebastelt hat, um auf andere Wege das Fenster zu schließen.
ausserdem könnte man den Hintergrund noch einfärben

Code: Alles auswählen

 spiel = tk.Canvas(master, width=1024, height=768,bg="yellow")# kannst ja mal ein paar Farben probieren..

natürlich nur wenn Du magst.. ist ja Dein Blumenkohl :wink:

Verfasst: Samstag 12. Juli 2008, 16:01
von numerix

Code: Alles auswählen

master.state('zoomed')# maximiert automatisch das Fenster aus Vollbild
master.overrideredirect( 1 )# die Kopfzeile wird entfernt (mehr Platz :-) )
Die Geschichte mit dem "zoomed" funktioniert bei mir nicht:

Code: Alles auswählen

Traceback (most recent call last):
  File "nixnix.py", line 4, in <module>
    master.state('zoomed') # maximiert automatisch das Fenster aus Vollbild
  File "../python2.5/lib-tk/Tkinter.py", line 1594, in wm_state
    return self.tk.call('wm', 'state', self._w, newstate)
_tkinter.TclError: bad argument "zoomed": must be normal, iconic, or withdrawn

Verfasst: Samstag 12. Juli 2008, 17:19
von yipyip
Hallo Leute,
sorry, wenn ich mich hier einmische.
:D
Ich verfolge diesen Thread schon seit 3 Tagen.
Gestern Nacht juckte es mich derart in den Fingern, dass
ich nicht umhin kam, endlich auch so ein Hexfeld Programm
zu schreiben.

Inspiriert von wuf's code bin ich
(vorlaeufig) auf Folgendes gekommen...

Code: Alles auswählen

#!/usr/bin/env python

####

import Tkinter as tk
from math import sin, cos, pi
import random as rand

####

def unit_poly(n):

  delta = 2 * pi / n
  return([(cos(i * delta), sin(i * delta)) for i in xrange(n)])

####

def scale_poly(x_scale, y_scale, poly):

  return [(x_scale * x, y_scale * y) for (x, y) in poly]

####

def trans_poly(x_tr, y_tr, poly):

  return [(x_tr + x, y_tr + y) for (x, y) in poly]

####
          
def int_poly(poly):

  return [(int(x + 0.5), int(y + 0.5)) for (x, y) in poly]

####
          
def draw_hexes(cv, x_offset, y_offset, x_delta, x_max, y_max,
               colors, distrib):

  poly = unit_poly(6)
  x_delta3 = x_delta / 3.0
  x_delta2 = x_delta / 2.0 
  y_delta = sin(pi / 3.0) * x_delta3 
  
  poly = scale_poly(x_delta3, x_delta3, poly)

  x_max1 = x_max - 1
  even_odd = 1
  
  for iy in xrange(y_max):
    even_odd ^= 1
    y_pos = y_offset + iy * y_delta

    for ix in xrange((x_max, x_max1)[even_odd]):
      x_pos = x_offset +  ix * x_delta + (0, x_delta2)[even_odd]
      col = colors[rand.choice(distrib)]
      draw_poly(cv, int_poly(trans_poly(x_pos, y_pos, poly)), col)

####

def draw_poly(cv, poly, col, bordcol='#000000'):
  
  cv.create_polygon(poly, fill=col, outline=bordcol)

####

def distribute(weights):
  '''generate a list for weighted color indices'''
  
  return reduce(lambda x, y: x + y,
                [[i] * w for i, w in zip(xrange(len(weights)), weights)])

####

def main_hex(**conf):

  root = tk.Tk()
  hexfield = tk.Canvas(root, width=conf['width'], height=conf['height'],
                       bg=conf['backcol'])
  hexfield.pack()

  # make the hexfield reproducible
  startseed = conf['startseed']
  if startseed:
    rand.seed(startseed)
    
  draw_hexes(hexfield, conf['x_offset'], conf['y_offset'],
             conf['delta'], conf['x_max'], conf['y_max'],
             conf['colors'], distribute(conf['weights']))
  
  root.mainloop()
                       
####

the_conf = {'width': 800,
            'height': 600,
            'backcol': '#000000',
            'x_offset': 15,
            'y_offset': 15,
            'delta': 22,
            'x_max': 36,
            'y_max': 91,
            'colors': ['#00ff00', '#ffff00', '#00ffff'],
            'weights': [8, 3, 2],
            'startseed': 1}

####
  
if __name__ == '__main__':

  main_hex(**the_conf)

####
@ derkai:
Ich weiss, das Obiges ein bisschen arg komprimiert fuer Dich ist.
Falls Du jedoch weiter machst wie bisher,
hast Du spaetestens nach 600 Zeilen
den Ueberblick verloren.
(Ist wirklich nicht boese gemeint :wink: )
Daher wuerde ich Dir raten, noch etwas mehr Zeit in die Strukturierung Deines Programmes zu investieren,
und genau zu ueberlegen, welche Datenstrukturen,
Funktionen, usw. du brauchst und wie diese interagieren sollen.

...ach so, der 1. Entwurf ist meistens fuer die Tonne,
ist auch bei mir so... :wink:

Bitte nimms mir nicht uebel...
:wink:
LG yipyip

Verfasst: Samstag 12. Juli 2008, 17:45
von derkai
schon in Ordnung, schön dass es auch alte Hasen juckt.

Ich bin ja froh, dass ich für den Moment noch vieles verstehe,
daher ist an eine Komprimierung für mich im Moment noch
wirklich nicht zu denken.

Wenn diese Modul mal alles kann, was ich so benötige, dann
werde ich das in Angriff nehmen.

Das mit dem Zoomen ist für den Moment noch nicht so interessant,
da das Spielfeld am Ende mehr als doppelt so groß wie Stand heute werden wird. Da werde ich dann wohl noch Scrolbalken einfügen müssen.

Kai

Verfasst: Samstag 12. Juli 2008, 19:30
von numerix
@yipyip:

Dein Code enthält interessante (neue) Ansätze, manche davon sicher bedenkenswert.

Die Sache mit int_poly() ist aber z.B. überflüssig. Die Canvas-Zeichenmethoden kommen auch mit Fließkommawerten zurecht.

Das mit dem even_odd gefällt mir nicht; dass man den alternierenden Ablauf eleganter lösen kann als mit einer wechselnden Indexierung einer eigens dafür aufgesetzten Sequenz, wurde in diesem Thread ja schon gezeigt.

Verfasst: Samstag 12. Juli 2008, 19:59
von yipyip
...das wusste ich nicht, das Tkinter da auch Fliesskommazahlen schluckt...
Vielleicht kann man's ja dann fuer eine andere Graphikbibliothek brauchen.
:-)

Das Bit-toggeln stammt wohl noch aus meiner
C-Vergangenheit.
Ich halte das im Vergleich zur
Modulo-Rechnung aber
nicht fuer sooo vollkommen unelegant.

(...an der Stelle passte es mir besser ins Gesamtkonzept...)

LG yipyip

Verfasst: Samstag 12. Juli 2008, 20:44
von numerix
yipyip hat geschrieben:Das Bit-toggeln stammt wohl noch aus meiner
C-Vergangenheit. Ich halte das im Vergleich zur
Modulo-Rechnung aber nicht fuer sooo vollkommen unelegant.
Mir ging es ja nicht um die Bit-Geschichte, sondern um das künstliche Aufsetzen einer Sequenz um den alternierenden Zugriff zu realisieren. Wer lieber mit Bits als mit modulo arbeitet, kann die Zeile, auf die du dich beziehst, ja auch so schreiben ... :wink:

Code: Alles auswählen

ypos = yorg + (not x&1)*0.5*yoffset

Verfasst: Samstag 12. Juli 2008, 21:37
von wuf
Hallo yipyip

Herzlich willkommen im Sub-Forum der Programmierkünstler. Es ist nett von dir, dass du hier dein super Code-Snippet veröffentlichst. Hut ab! Natürlich freut es uns auch speziell, dass du ein GUI-Toolkit einsetzt das uns auch bekannt ist. Hier ist jedes Code-Snippet willkommen. Da jedes geschriebene Stück Code Wissen bereitstellt, welches beim optimieren des Projekt-Codes einfliessen kann.
yipyip hat geschrieben:Gestern Nacht juckte es mich derart in den Fingern, dass
ich nicht umhin kam, endlich auch so ein Hexfeld Programm
zu schreiben.
Es ist Absicht, dass dieses doch schon längere Thema zum 'jucken' reizt.

P.S. Be aware you are working with an outcasted GUI-Toolkit :lol:

Für mich ist dein Beitrag fast ein bisschen 'suspect'! Dein Super-Code, die brauchbaren Anregungen und dies schon bei deinem ersten Forum-Beitrag. In anderen Worten möchte ich dich als 'Under Cover Agent' entlarven. Das heisst du könntes dir als Mitglied, welches schon länger diesem Forum angehört, einen zweiten Benutzer-Namen zugelegt haben um hier nicht aufzufallen. :lol:

Es war nur Spass und nicht so gemeint. :wink:
yipyip hat geschrieben:Daher wuerde ich Dir raten, noch etwas mehr Zeit in die Strukturierung Deines Programmes zu investieren,
und genau zu ueberlegen, welche Datenstrukturen,
Funktionen, usw. du brauchst und wie diese interagieren sollen.
Ja schon aber ich würde dies nur unter Einbeziehung des Target-GUI-Toolkit befürworten.

Es stimmt gewisse Leute haben ein Problem mit Programmen deren Code-Zeilen eine bestimmte Anzahl übersteigt. Das hängt aber nur von der Darstellung und Dokumentation des Skriptes ab. Für mich kann ein Skript 50 oder 10'000 Zeilen haben, sofern es mit einer überblickbaren Struktur aufgebaut ist. Eine Gefahr sind lange kommentarlose 'Einzeiler', welche mit Logik und Mathematik verlinkt sind. Da fragt man sich manchmal, wo ist die gute Lesbarkeit des Pythoncodes geblieben. Damit hätte ich auch Mühe nicht nur nach 600 sondern schon weniger Zeilen den Code in kurzer Zeit zu verstehen. OK das ist eine rein persönliche Sache. Es kommt darauf an in welchem Umfeld jemand aufgewachsen ist.

Ich habe auch schon versucht mich in Sourcen von Programmen einzuarbeiten die aus vielen Subsourcen bestanden. Bei der ersten Source mit zwei 'include' Statements dachte ich noch ist kein Problem es sind ja nur zwei weitere Dokumente. Aber beim durchlesen dieser zwei Subsourcen wurde mir schnell einmal klar das dies noch lange nicht das Ende ist. Auf der ersten Subsource standen vier weitere 'include' Statements und auf der zweiten Subsource standen sogar 10! weitere 'include'-Statements und so ging es weiter den ganzen Baum hinunter. Da möchte einmal dabei sein, wenn sich ein Neuling einarbeiten muss.

OK. yipyip willkommen im Forum und noch alles Gute wuf :wink:

Verfasst: Samstag 12. Juli 2008, 21:40
von EyDu
Numerix Ansatz kann man mit Booleans noch etwas erweitern:

Code: Alles auswählen

>>> (not True)*0.5
0.0
>>> (not False)*0.5
0.5
>>> 

Verfasst: Samstag 12. Juli 2008, 21:44
von yipyip
Mit den Sequenzen kann ich die benoetigten Parameter
schon vor der zeitkritischen Hauptschleife berechnen.

Ich denke, sowas wie

Code: Alles auswählen

half_yoffset = yoffset / 2.0
....
for...
    ypos = yorg + [0, half_yoffset][togglebit]
sollte etwas schneller sein als

Code: Alles auswählen

for...
    ypos = yorg + togglebit * 0.5 * yoffset
Ausserdem finde ich es sogar praktischer und uebersichtlicher.

Aber ich weiss, Python ist nicht der Ort, wo man
um Prozessortakte feilscht.
;-)
LG yipyip

Verfasst: Samstag 12. Juli 2008, 22:00
von wuf
Hallo Midneid

Code: Alles auswählen

master.state('zoomed')# maximiert automatisch das Fenster aus Vollbild
Mit dem habe ich die gleichen Probleme wie 'numerix'. Mein OS hier ist SuSE 10.0 Linux.
Du verwendest vermutlich Windows?

Ich hole mir die Schirmabmessungen mit den Methoden:

Code: Alles auswählen

master.winfo_screenwidth()
master.winfo_screenheight()
Gruss wuf :wink:

Verfasst: Samstag 12. Juli 2008, 22:52
von yipyip
Hach Leute...
ich wollte hier doch keine Lawine lostreten...
:D
Erstmal vielen Dank fuer die tolle Begruessung!
Ihr macht einen ja ganz verlegen...
;-)

Zuerst muss ich jedoch was klarstellen:
Bin weder ein Code-Guru noch Sonstwie-Experte,
Leuten wie 'BlackJack' oder vielen anderen kann
ich garantiert nicht das Wasser reichen.
(Programmiere in Python erst seit
knapp einem 3/4 Jahr)
Ich bilde mir jedoch ein, ein gewisses
Grundverstaendnis fuers Programmieren
zu besitzen.

Da mich das Thema reizte und ich befuerchtete,
dass derkai noch weiter ins Schwimmen geraet,
wollte ich das Ganze etwas
in die 'richtigere' Richtung lenken.

Mit den '600 Zeilen' wollte ich eigentlich ausdruecken,
dass derkai sich mehr mit den Grundlagen
auseinandersetzen sollte, etwa im Stil von
http://www.htdp.org/2003-09-26/Book/
(Nein, ich habs auch noch nicht gemacht :wink: )
Sowas wie Tkinter sollte erst viel spaeter folgen.

Womit wir beim naechsten Thema waeren:
Ich mag Tkinter bzw. das TK! :-)
(...auch wenns unsexy ist...
...und Totgesagte leben meistens laenger...)

'It fits my brain' , weil es nicht der C++ Denkweise
in WxPython entspricht (hab letzteres aber nur kurz angelesen).

Das 'zoomed' funktioniert bei mir uebrigens auch nicht.
(Ubuntu 8.04, Python 2.5.2)

So, das waers fuers erste.
(Nein, ich hab hier wirklich keinen anderen Account...)
:wink:

Goodnight
yipyip

Verfasst: Sonntag 13. Juli 2008, 11:45
von derkai
tja, also irgendwie fehlt mir wieder einmal der entscheidende Hinweis ?

ich möchte ein Dictionary erzeugen :
feld_liste {}

dieses soll dann foglende Werte bei jedem Schleifendurchlauf erhalten
(UND DAS ERST EINMAL WIEDER VÖLLIG SIMPEL UND MIT ZU VIEL CODE)

INDEX :
- Index soll bsp so aussehen : (Zeile/Reihe) 01 + (Feld Nr.) 14 = INDEX
0114 (das soll dann eben logischer Weise das 14 te Feld der Reihe 1
bedeuten)
WERTE :
- x1,y1 ... x6,y6
- Farbe
- spätere Eigenschaften, die die Felder der unterschiedlichen Farbe
erhalten werden

meine Schleife sieht ja bekanntlich so aus :

Code: Alles auswählen

    for feld in range(1,3):

        if spalten_nummer == UNGERADE :

            for f in range(ungerade_spalten):
                create_hex_polygon(spiel,xpos,ypos,hex_point_list,farbe)
                xpos = xpos + (xoffset *2)
            spalten_nummer = GERADE
            xpos = xorg + xoffset
            ypos = ypos + yoffset / 2

        else :
            
            for f in range(gerade_spalten):
                create_hex_polygon(spiel,xpos,ypos,hex_point_list,farbe)
                xpos = xpos + (xoffset *2)
            spalten_nummer = UNGERADE
            xpos = xorg
            ypos = ypos + yoffset / 2         
Jetzt ist aber das Problem, dass sich die XY Werte ja in der Funktion
create_hex-polygon befinden und "nur" als Rückgabewerte zur Verfügung
stehen. Es ist doch aber richtig, dass eine Funktion nur EINEN Rückgabeaufrug haben kann, oder ?

mit feld_liste [f] = hex_ponit

könnte ich beispielsweise das Dictionary füllen.

Wie sage ich nun aber, dass der INDEX/KEY "F" eine Kombination
der Zählervariablen der Schleifen "feld" + "f" ist ?

Mal nebenbei gefragt, welche Auskünfte erhalte ich eigentlich über
die jeweilige ID ? Hilft mir die hier vielleicht weiter ?

Mit für Eure Geduld dankenden Grüßen

Kai