Feld erstellen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Benutzeravatar
jonas
User
Beiträge: 156
Registriert: Dienstag 9. September 2008, 21:03

Donnerstag 25. September 2008, 10:26

Hallo.
Habe nach Betätigen der SuFu nichts für mich passendes gefunden.
Ich möchte mal kurz mein Problem schildern:

Ich möchte gern komplett von eine graphischen Oberfläche getrennt
eine Art festgelegtes Spielfeld erzeugen.
Ich habe aber keine Ahnung für einen Ansatz.
(höchstens etwas in folgender Richtung erstellen:
Feld = ((x0,y0),(x1,y1)...) um die Koordinaten einzeln
festzulegen.)
Das erscheint mir allerdings sehr kompliziert.
Im Bezug hierauf verweise ich auf den AntMe! Klon
(den es zu erstellen ja bereits einen eigenen Thread hat)
Ich hoffe ich habe das Problem einigermaßen plausibel beschrieben.

Mit freundlichen Grüßen
Jonas
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Donnerstag 25. September 2008, 11:10

Ein Spielfeld könnte man so repräsentieren:

Code: Alles auswählen

class Field:
    def __init__(self, x, y):
        self.x, self.y = x, y

class Board:
    def __init__(self, width, height, cls=Field):
        self.width, self.height = width, height
        self.fields = [cls(x, y) for y in range(height) for x in range(width)]
        
    def __getitem__(self, (x, y)):
        return self.fields[x + y * self.width]

    def __iter__(self):
        return iter(self.fields)

b = Board(3, 4)
b[2, 1].name = "Heimat"
for f in b:
    print f.x, f.y
Wenn es nur wenige relevante Felder gibt -- etwa bei einer Weltraumkarte, die im wesentlichen leer ist -- könnte man auch Koordinaten-Tupel als Schlüssel für eine Hashmap benutzen.

Code: Alles auswählen

class Space:
    def __init__(self):
        self.planets = {}
        
    def distribute_planets(self, planets):
        for planet in planets:
            while True:
                xy = random.randrange(100), random.randrange(100)
                if xy not in self.planets: break
            self.planets[xy] = planet
    
    def __getitem__(self, xy):
        return self.planet.get(xy)
Ist die Karte nicht regelmäßig aufgebaut -- man denke die Länder des Brettspiels Risiko -- ist es vielleicht sinnvoll, Objekte mit einer Nachbarschaftsrelation anzulegen:

Code: Alles auswählen

NORTH, WEST, SOUTH, EAST = range(4)

class Field:
    def __init__(self):
        self.neighbors = [None, None, None, None]

    def north_of(self, field):
        self.neighbors[SOUTH] = field
        field.neighbors[NORTH] = self
        
    def south_of(self, field):
        field.north_of(self)
    
    def west_of(self, field):
        self.neighbors[EAST] = field
        field.neighbors[WEST] = self
    
    def east_of(self, field):
        field.west_of(self)

usa, europe, africa, asia = Field(), Field(), Field(), Field()
usa.west_of(europe)
africa.south_of(europe)
asia.east_of(europe)
Stefan
Benutzeravatar
wuf
User
Beiträge: 1478
Registriert: Sonntag 8. Juni 2003, 09:50

Donnerstag 25. September 2008, 11:58

Hallo jonas

Hier noch eine kleine Erweiterung für das erste Code-Snippet von 'sma'. (Eine minimale Zeichen-Grafik-Ausgabe auf die Konsole)

Code: Alles auswählen

class Field:
    def __init__(self, x, y):
        self.x, self.y = x, y

class Board:
    def __init__(self, width, height, cls=Field):
        self.width, self.height = width, height
        self.fields = [cls(x, y) for y in range(height) for x in range(width)]

    def __getitem__(self, (x, y)):
        return self.fields[x + y * self.width]

    def __iter__(self):
        return iter(self.fields)

def output_board(board_obj):
    """Gebe die Belegung der Spielflaeche aus"""

    print
    print "Spielfeld-Belegung:"
    print "(Geometrie: X=%d Y=%d)" % (board_obj.height, board_obj.width)
    for y in xrange(board_obj.height):
        for x in xrange(board_obj.width):
            try:
                name = board_obj[x, y].name
                field_symbol = "X"
            except:
                field_symbol = "."
            print field_symbol,
        print
    print

b = Board(10, 4)
b[2, 1].name = "Heimat"
for f in b:
    print f.x, f.y

output_board(b)
Gruss wuf :wink:
Take it easy Mates!
Benutzeravatar
jonas
User
Beiträge: 156
Registriert: Dienstag 9. September 2008, 21:03

Donnerstag 25. September 2008, 12:05

hi sma!
Erstmal vielen Dank für deine schnelle Antwort!
Ich habe ein paar Fragen zu deinem Code:
(habe mich noch nicht mit Klassen beschäftigt :oops:)
was bringt denn in der Klasse

Code: Alles auswählen

 
def __init__(self, x, y): 
        self.x, self.y = x, y 
außerdem was macht cls?
Danke im voraus, für deine Antwort.
@wuf: Sry als ich die Antwort geschrieben habe
war dein Beitrag noch nicht da...

Mit freundlichen Grüßen
Jonas
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Donnerstag 25. September 2008, 12:12

jonas hat geschrieben:Ich habe ein paar Fragen zu deinem Code:
(habe mich noch nicht mit Klassen beschäftigt :oops:)
was bringt denn in der Klasse

Code: Alles auswählen

 
def __init__(self, x, y): 
        self.x, self.y = x, y 
außerdem was macht cls?
Das Codesnippsel speichert die Werte von ``x`` und ``y`` in der Instanz der Klasse, damit sie auch in anderen Methoden über ``self.x`` und ``self.y`` erreichbar sind; ``x`` und ``y`` gehen ja am Ende von ``__init__`` sonst verloren.

``cls`` ist einfach ein Parameter dessen Vorbelegung ``Field`` ist, also wird bei ``cls(x, y)`` in der Regel ``Field(x, y)`` aufgerufen.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Benutzeravatar
Hyperion
Moderator
Beiträge: 7472
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Donnerstag 25. September 2008, 13:43

@wuf: Das Symbol eines Zeichens sollte man sich dann aber besser im Objekt selber merken (ob direkt oder zur absoluten Trennung zwischen Daten und Aussehen in einem verlinkten Objekt). Solche if-else Kaskaden sind da schnell unflexibel und häßlich :-)
Benutzeravatar
wuf
User
Beiträge: 1478
Registriert: Sonntag 8. Juni 2003, 09:50

Donnerstag 25. September 2008, 13:48

Hallo Hyperion

Danke für deinen Tipp. Ich wollte das Kern-Code-Snippet von 'sma' nicht antasten.

Gruss wuf :wink:
Take it easy Mates!
Benutzeravatar
wuf
User
Beiträge: 1478
Registriert: Sonntag 8. Juni 2003, 09:50

Donnerstag 25. September 2008, 14:00

Hallo Hyperion

Hast du es in etwa so gemeint?

Code: Alles auswählen

class Field:
    def __init__(self, x, y):
        self.x, self.y = x, y
        self.name = "."

class Board:
    def __init__(self, width, height, cls=Field):
        self.width, self.height = width, height
        self.fields = [cls(x, y) for y in range(height) for x in range(width)]

    def __getitem__(self, (x, y)):
        return self.fields[x + y * self.width]

    def __iter__(self):
        return iter(self.fields)

def output_board(board_obj):
    """Gebe die Belegung der Spielflaeche aus"""

    print
    print "Spielfeld-Belegung:"
    print "(Geometrie: X=%d Y=%d)" % (board_obj.height, board_obj.width)
    for y in xrange(board_obj.height):
        for x in xrange(board_obj.width):
            name = board_obj[x, y].name
            print name,
        print
    print

b = Board(10, 4)
b[2, 1].name = "X"
for f in b:
    print f.x, f.y

output_board(b)
Gruss wuf :wink:
Take it easy Mates!
Benutzeravatar
Hyperion
Moderator
Beiträge: 7472
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Donnerstag 25. September 2008, 14:09

Japp so in etwa :-)

Man könnte sich auch noch folgendes ausdenken:

Code: Alles auswählen

ascii_art = {"leer":".", "player":"x"}

class Field:
    def __init__(self, x, y, name="leer"):
        self.x, self.y = x, y
        self.name = name

def output_board(board_obj):
...
            name = board_obj[x, y].name
            print ascii_art[name],
...

b = Board(10, 4)
b[2, 1].name = "player"
for f in b:
    print f.x, f.y
So ließen sich schon sehr einfach eigene "Themes" erstellen ;-)

Noch gekapselter dürfte es sein, eine Repräsentationsklasse zu erstellen, von der jedes field ein object kennt, oder der Zusammenhang wie oben über ein Dictionary vorgenommen wird. In dieser Repräsentationsklasse definiert man sich eine paint()-Methode o.ä. und dort findet dann die Ausgabe statt. Bei simpler Ausgabe im Textmodus eben ASCII Zeichen per print, bei SDL eben auch echte Grafik usw.
Benutzeravatar
jonas
User
Beiträge: 156
Registriert: Dienstag 9. September 2008, 21:03

Donnerstag 25. September 2008, 16:53

hi @ all.
ich liebe dieses forum :D
find ich immer klasse wie schnell man was für
antworten bekommt, und dass sich die antwort-
geber sogar noch versuchen zu "übertrumpfen" :lol:

Mit freundlichen Grüßen
Jonas

EDIT: Noch eine Frage zu sma's erstem Post:

Code: Alles auswählen

b[2, 1].name = "Heimat" ##Das definiert ein Teil des Feldes mit
                                     ## Namen oder?
for f in b: ##Und was macht das (wo kommt das f her?)
    print f.x, f.y
Benutzeravatar
wuf
User
Beiträge: 1478
Registriert: Sonntag 8. Juni 2003, 09:50

Donnerstag 25. September 2008, 17:04

Hallo Hyperion

Ich finde deinen Vorschlag gut! Besten Dank!

@jonas: Ich habe den Vorschlag von 'Hyperion' in ein ausführbares Code-Snippet einfliessen lassen.

Code: Alles auswählen

class Field:
    def __init__(self, x, y, name="leer"):
        self.x, self.y = x, y
        self.name = name

class Board:
    def __init__(self, width, height, cls=Field):
        self.width, self.height = width, height
        self.fields = [cls(x, y) for y in range(height) for x in range(width)]

    def __getitem__(self, (x, y)):
        return self.fields[x + y * self.width]

    def __iter__(self):
        return iter(self.fields)

def output_board(board_obj):
    """Gebe die Belegung der Spielflaeche aus"""

    print
    print "Spielfeld-Belegung:"
    print "(Geometrie: X=%d Y=%d)" % (board_obj.height, board_obj.width)
    for y in xrange(board_obj.height):
        for x in xrange(board_obj.width):
            name = board_obj[x, y].name
            print ascii_art[name],
        print
    print

ascii_art = {"leer":".", "ant-1":"1", "ant-2":"2", "ant-3":"3", "ant-4":"4"}

b = Board(10, 4)
b[2, 1].name = "ant-1"
b[9, 3].name = "ant-2"
b[5, 2].name = "ant-3"
b[1, 0].name = "ant-4"

for f in b:
    print f.x, f.y 

#~~ Test Spielflaeche-Belegung
output_board(b)
Gruss wuf :wink:
Take it easy Mates!
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Donnerstag 25. September 2008, 17:14

jonas hat geschrieben:EDIT: Noch eine Frage zu sma's erstem Post:

Code: Alles auswählen

b[2, 1].name = "Heimat" ##Das definiert ein Teil des Feldes mit
                                     ## Namen oder?
for f in b: ##Und was macht das (wo kommt das f her?)
    print f.x, f.y
Ersteres setzt das Attribut ``name`` auf 'Heimat' auf dem Objekt, dass unter dem Index ``2, 1`` am Objekt ``b`` erreichbar ist.
Zweiteres: das ``f`` wird einfach gesetzt, es ist eine Schleife und ``f`` nimmt in jedem Durchlauf den Wert von ``b[0]``, ``b[1]``, ... ``b[n-1]`` ein (``n`` ist die Länge von ``b``). Also es iteriert über jeden Indexwert.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Benutzeravatar
jonas
User
Beiträge: 156
Registriert: Dienstag 9. September 2008, 21:03

Samstag 27. September 2008, 00:31

nabend.
Diese Klassen machen mich noch völlig fertig...
Ich versteh ein Teil des Codes immer noch nicht...

Was bringen die Funktionen :

Code: Alles auswählen


 def __getitem__(self, (x, y)):
        return self.fields[x + y * self.width]

    def __iter__(self):
        return iter(self.fields)

und warum müssen bei der Klasse Field für x und y nichts angegeben
werden? Werden da "automatisch" Werte eingesetzt (0,1,2...) ?

Mit freundlichen Grüßen
Jonas
PS: Kann mir gut vorstellen, dass ich euch langsam, aber sicher sehr
auf die Nerven gehe, würde mir auch so gehen. (Sorry)
Bitte trotzdem um gescheite Antworten, sonst muss ich noch öfters
fragen :oops:
BlackJack

Samstag 27. September 2008, 08:03

Vielleicht solltest Du Dich dann erst einmal mit Klassen und wie die funktionieren im Allgemeinen beschäftigen und nicht gleich so eine relativ grosse Klasse am Stück verstehen wollen.
Benutzeravatar
wuf
User
Beiträge: 1478
Registriert: Sonntag 8. Juni 2003, 09:50

Samstag 27. September 2008, 09:44

Hallo

Ehrlich gesagt ist bei mir der Groschen betreffs der Methode:

Code: Alles auswählen

  def __iter__(self):
        return iter(self.fields)
trotzt Docs auch noch nicht gefallen.

Wie würde diese in Low-Level Python-Code geschrieben aussehen?

Gruss wuf :wink:
Take it easy Mates!
Antworten