Seite 1 von 2
2D-Liste
Verfasst: Samstag 20. Juni 2009, 20:00
von roschi
Hallo!
Ich stehe mal wieder vor einem Problem:
Ich muss eine Art Karte abbilden koennen. Diese besteht aus n mal m Feldern und ist immer rechteckig. Jedes Feld soll durch ein Zeichen dargestellt werden, und am Ende soll diese Karte in einer Datei gespeichert werden. Da diese Karte jedoch zur Laufzeit erstellt wird, weiss ich nie, wie hoch und breit sie werden wird. Ich dachte daran, das Ganze in einer Liste mit mehreren Unterlisten darzustellen, z.B. so (fuer 8 mal 6 Felder):
Code: Alles auswählen
width = 8
height = 6
karte = [[" " for i in xrange(width)] for i in xrange(height)]
Der Benutzer befindet sich am Anfang an einem bestimmten Punkt. Jetzt gibt er ein, dass er sich z.B. nach rechts bewegen will. Dann soll kontrolliert werden, ob rechts der aktuellen Position schon ein Feld existiert, und wenn nein, soll eines erstellt werden. Außerdem soll bei einer Bewegung die aktuelle Position auf das aktuelle Feld gesetzt werden, so dass der Benutzer das aktuelle Feld modifizieren kann (eine Eigenschaft, wie z.B. das Symbol aendern). Irgendwann sollen die entstandenen Daten dann in eine Datei als Plaintext geschrieben werden (nicht benutzte Felder als Leerzeichen, so dass alles exakt untereinander ist).
Mir fehlt nun komplett die Idee, wie ich das angehen koennte.
Ich wuerde mich riesig freuen, wenn mir jemand helfen koennte.
Liebe Grueße
roschi
Verfasst: Samstag 20. Juni 2009, 20:47
von EyDu
Dann würde ich keine Liste nehmen, sondern ein Dictionary. Als Schlüssel verwendest du dann die Koordinaten: (x, y). Ob ein Schlüssel existiert kannst du dann mit der "has_key"-Methode abfangen oder du benutze Exceptions. Letzteres macht es ein wenig übersichtlicher.
Verfasst: Samstag 20. Juni 2009, 21:00
von roschi
EyDu hat geschrieben:Dann würde ich keine Liste nehmen, sondern ein Dictionary. Als Schlüssel verwendest du dann die Koordinaten: (x, y). Ob ein Schlüssel existiert kannst du dann mit der "has_key"-Methode abfangen oder du benutze Exceptions. Letzteres macht es ein wenig übersichtlicher.
Das hatte ich mir auch schon gedacht.
Aber wie stelle ich die Karte daen in der Karte gut da?
Wie kriege ich mit halbwegs gutem Code raus, wo ich anfangen muss zu schreiben usw?
Kann mir eventuell jemand etwas Code posten?
Waere sehr nett
Liebe Grueße
roschi
Verfasst: Samstag 20. Juni 2009, 21:11
von EyDu
roschi hat geschrieben:Aber wie stelle ich die Karte daen in der Karte gut da?
Wie kriege ich mit halbwegs gutem Code raus, wo ich anfangen muss zu schreiben usw?
Kann mir eventuell jemand etwas Code posten?
Könntest du das noch etwas präzisieren, die Fragen ergeben für mich gerade keinen Sinn. Am besten mit mehr als fünf Worten. Vorzugsweise mit mehreren gut strukturierten Sätzen
Meinst du mit Schreiben, wie du die Karte dann in eine Datei bekommst? Dazu speicherst du dir jeweils den kleinsten und den größten x-Wert, das selbe natürlich noch mit den y-Werten. Dann gehst du einfach jeden möglichen Index durch und schaust was du schreiben musst.
Als Implementierung würde ich eine Klasse schreiben, welche entweder von "dict" erbt oder die Karte als Dictionary hält. Darauf kann man sich dann einige komfortable Methoden zusammenbauen.
Verfasst: Samstag 20. Juni 2009, 21:20
von roschi
EyDu hat geschrieben:roschi hat geschrieben:Aber wie stelle ich die Karte daen in der Karte gut da?
Wie kriege ich mit halbwegs gutem Code raus, wo ich anfangen muss zu schreiben usw?
Kann mir eventuell jemand etwas Code posten?
Könntest du das noch etwas präzisieren, die Fragen ergeben für mich gerade keinen Sinn. Am besten mit mehr als fünf Worten. Vorzugsweise mit mehreren gut strukturierten Sätzen

Oh je

Man sollte vielleicht doch nicht telefonieren, und nebenbei nachdenken (oder es versuchen) und gleichzeitig Posten.
Tut mir leid, ich erklaer es richtig:
EyDu hat geschrieben:Meinst du mit Schreiben, wie du die Karte dann in eine Datei bekommst? Dazu speicherst du dir jeweils den kleinsten und den größten x-Wert, das selbe natürlich noch mit den y-Werten. Dann gehst du einfach jeden möglichen Index durch und schaust was du schreiben musst.
Als Implementierung würde ich eine Klasse schreiben, welche entweder von "dict" erbt oder die Karte als Dictionary hält. Darauf kann man sich dann einige komfortable Methoden zusammenbauen.
Genau das habe ich auch schon gedacht, aber geht es nicht noch ein bisschen schoener? Moeglich waere es zwar, aber irgendwie kommt mir das ein bisschen umstaendlich vor. Ich werde es wohl so machen. Ich dachte nur, es gibt eine huebschere Methode, die ich nur noch nicht kenne

.
Ich danke vielmals!
Falls ich noch auf weitere Probleme stoßen sollte, werde ich es euch wissen lassen.
Liebe Grueße und vielen dank nochmals!
roschi
PS: Schon 200 Beitraege! Kam mir gar nicht soviel vor

.
Verfasst: Samstag 20. Juni 2009, 21:38
von EyDu
Was ist denn daran nicht schön? Auch beim Speichern einer Karte, welche du durch verschachtelte Listen repräsentierst, musst du du jedes Feld einmal anfassen. Durch Dictionaries sparst du dir das Programmieren von einigen Verwaltungsvorgängen. Wenn du die Schnittstelle der Klasse gut schreibst, dann wird man kein Unterschied merken, ob man auf Listen oder auf einem Dictionary arbeitet.
Verfasst: Samstag 20. Juni 2009, 21:38
von str1442
Ist dein Hauptproblem jetzt, alles in eine Datei zu speichern oder die Struktur einer solchen Karte an sich? Du sprichst ja von beidem. Wenn es nur darum geht, irgendwie die Struktur abzuspeichern, kannst du einfach pickle benutzen. Ansonsten musst du dir ein eigenes Format (wie von EyDu beschrieben) ausdenken oder aber die Logik irgendwie in XML/JSON/YAML abbilden.
Ich würde selbst nicht von dict erben (Ist eine Karte wirklich ein Dictionary bzw. ein Namensraum oder doch mehr?), sondern mit einer Field Klasse beginnen. Ich habe für meinen Tetris Klon Tetrix0r (der schon ganz schön angestaubt ist, aber nunja) soetwas gemacht samt allem drum und dran. Ist nicht das Musterbeispiel für klaren und gut strukturierten Code, aber kannst du dir ja mal anschauen. Such einfach im Forum danach.
dict.has_key ist übringens deprecated. Man sollte "key in dict" benutzen.
Verfasst: Samstag 20. Juni 2009, 22:34
von roschi
EyDu hat geschrieben:Was ist denn daran nicht schön? Auch beim Speichern einer Karte, welche du durch verschachtelte Listen repräsentierst, musst du du jedes Feld einmal anfassen. Durch Dictionaries sparst du dir das Programmieren von einigen Verwaltungsvorgängen. Wenn du die Schnittstelle der Klasse gut schreibst, dann wird man kein Unterschied merken, ob man auf Listen oder auf einem Dictionary arbeitet.
Stimmt schon, aber es sieht schon ein wenig lustig aus die Eintraege so zu zerstueckeln

.
str1442 hat geschrieben:Ist dein Hauptproblem jetzt, alles in eine Datei zu speichern oder die Struktur einer solchen Karte an sich? Du sprichst ja von beidem. Wenn es nur darum geht, irgendwie die Struktur abzuspeichern, kannst du einfach pickle benutzen. Ansonsten musst du dir ein eigenes Format (wie von EyDu beschrieben) ausdenken oder aber die Logik irgendwie in XML/JSON/YAML abbilden.
Ich sprach von beidem. Ich moechte die Karte dann richtig in eine Datei schreiben, als ASCI-Grafik.
str1442 hat geschrieben:Ich würde selbst nicht von dict erben (Ist eine Karte wirklich ein Dictionary bzw. ein Namensraum oder doch mehr?), sondern mit einer Field Klasse beginnen. Ich habe für meinen Tetris Klon Tetrix0r (der schon ganz schön angestaubt ist, aber nunja) soetwas gemacht samt allem drum und dran. Ist nicht das Musterbeispiel für klaren und gut strukturierten Code, aber kannst du dir ja mal anschauen. Such einfach im Forum danach.
Ich hab mir das Tetris frueher schonmal angeschaut, aber schon wieder alle Details vergessen

. Ich habe die Struktur jetzt so, wie von EyDu vorgeschlagen wurde: eine Klasse, die ein Dictionary besitzt, welches die koordinaten als key und das jeweilige symbol als value enthaelt. Jetzt implementiere ich das Schreiben in eine Datei - mal sehen.
Liebe Grueße
roschi
Verfasst: Sonntag 21. Juni 2009, 07:21
von numerix
Code: Alles auswählen
from random import randrange
# Initialisierung
breite, hoehe = 20, 12
karte = [["_" for i in xrange(breite)] for i in xrange(hoehe)]
# Zufallsbefüllung
for i in xrange(40):
x, y = randrange(breite), randrange(hoehe)
karte[y][x] = "x"
# Karte speichern
datei = open("karte.txt","w")
for zeile in karte:
datei.write("".join(zeile)+"\n")
datei.close()
Verfasst: Sonntag 21. Juni 2009, 07:46
von bwbg
Zur Initialisierung:
Grüße... Heiko
Verfasst: Sonntag 21. Juni 2009, 08:28
von BlackJack
@bwbg: Keine gute Idee:
Code: Alles auswählen
In [3]: karte = [['_'] * 10] * 5
In [4]: karte[1][3] = '*'
In [5]: karte
Out[5]:
[['_', '_', '_', '*', '_', '_', '_', '_', '_', '_'],
['_', '_', '_', '*', '_', '_', '_', '_', '_', '_'],
['_', '_', '_', '*', '_', '_', '_', '_', '_', '_'],
['_', '_', '_', '*', '_', '_', '_', '_', '_', '_'],
['_', '_', '_', '*', '_', '_', '_', '_', '_', '_']]
Verfasst: Sonntag 21. Juni 2009, 08:35
von wuf
Hallo Zusammen
BlackJack hat einmal etwas vorgestellt, welches ich schon mehrfach erfolgreich eingesetzt habe:
http://www.python-forum.de/post-105266.html#105266
Gruss wuf

Verfasst: Sonntag 21. Juni 2009, 08:50
von bwbg
BlackJack hat geschrieben:@bwbg: Keine gute Idee:
(...)
Ist auch irgendwie logisch. Danke für die Info.
Grüße... Heiko
Verfasst: Sonntag 21. Juni 2009, 09:50
von sma
Hier ist mein Vorschlag:
Code: Alles auswählen
class VirtualMap(object):
def __init__(self, default=None):
self.fields = {}
self.default = default
def __getitem__(self, coord):
return self.fields.get(coord, self.default)
def __setitem__(self, coord, value):
self.fields[coord] = value
@property
def minx(self): return min(x for x, y in self.fields.iterkeys())
@property
def maxx(self): return max(x for x, y in self.fields.iterkeys())
@property
def width(self): return self.maxx - self.minx + 1
@property
def miny(self): return min(y for x, y in self.fields.iterkeys())
@property
def maxy(self): return max(y for x, y in self.fields.iterkeys())
@property
def height(self): return self.maxy - self.miny + 1
def __str__(self):
minx, maxx, miny, maxy = self.minx, self.maxx, self.miny, self.maxy
return "%s-%s, %s-%s\n%s" % (minx, maxx, miny, maxy,
"\n".join(" ".join(self[x, y] or " "
for x in range(minx, maxx + 1))
for y in range(miny, maxy + 1)))
Stefan
Verfasst: Sonntag 21. Juni 2009, 10:28
von wuf
Hallo sma
Ich finde dein Vorschlag interessant. Um besser zu verstehen was dabei genau abläuft könntest du bitte ein kleines Anwendungsbeispiel für eine 2D-Liste mit der Dimesion x=10 und y=10 zeigen, welche man mit:
auf die Konsole ausgeben kann.
Danke für deine Bemühung. Sorry für die eventuell naive Frage.
Gruss wuf

Verfasst: Sonntag 21. Juni 2009, 10:35
von EyDu
Im Prinzip smas __str__-Methode:
Code: Alles auswählen
v = VirtualMap(" ")
#fill map here
for y in range (10):
for x in range(10):
v[x,y] = "x" if (x+y)%2 else "o"
for y in range(v.miny, v.miny + v.height):
for x in range(v.minx, v.minx +v .width):
print v[x, y],
print
ungetestet.
Verfasst: Sonntag 21. Juni 2009, 10:36
von sma
Was kann ich, was nicht auch du ausprobieren könntest?
Code: Alles auswählen
>>> m = VirtualMap('.')
>>> m[0,0] = m[9,9] = 'x'
>>> print m
0-9, 0-9
x . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . x
Verfasst: Sonntag 21. Juni 2009, 11:14
von wuf
Hallo sma und EyDu
Danke für eure Antworten. Beides funktioniert.
sma hat geschrieben:Was kann ich, was nicht auch du ausprobieren könntest?
Wenn ich es nicht versucht hätte würde ich dich auch nicht fragen!
Gruss wuf

Verfasst: Montag 29. Juni 2009, 08:34
von roschi
Hallo!
Hier hat sich ja waehrend meiner Abwesenheit viel um die Frage gedreht, wie ich sehe

.
Mein jetziger Stand:
Der Mapper funktioniert soweit.
Den Code der Map-Klasse findet ihr hier:
http://paste.pocoo.org/show/125687/
Verwendet wird das Ganze dann z.B. so:
Code: Alles auswählen
# liste der verschiedenen himmelsrichtungen,
# ihren positionsaenderung auf den achsen
# und den Gegenrichtungen
# (die in dem beispiel aber nicht gebraucht werden)
DIRECTIONS = {"n":(0, 1, "s"),
"o":(1, 0, "w"),
"s":(0, -1, "n"),
"w":(-1, 0, "o"),
"no":(1, 1, "sw"),
"so":(1, -1, "nw"),
"sw":(-1, -1, "no"),
"nw":(-1, 1, "so")}
# benutzung der klasse
map = Map()
current_cords = (0, 0)
# beispiel fuer norden:
direction = "n"
new_cords = (current_cords[0] + DIRECTIONS[direction][0],
current_cords[1] + DIRECTIONS[direction][1])
# ...
# hier werden im orginialscript noch informationen
# gespeichert, damit die aktion wieder rueckgaengig
# gemacht werden kann.
# ...
current_cords = new_cords
map.write_field(current_cords, DEFAULT_SYMBOL)
# karte in datei schreiben
map.write_into_file("map.txt")
Der Benutzer kann sich nun (in einem Spiel) durch die Himmelsrichtungen bewegen, und eine Funktion im Script wird dabei aufgerufen, die die Aenderungen dann in die Karte eintraegt. Nun habe ich allerdings noch ein grundsaetzliches Problem:
Der Spieler geht z.B. folgenden Weg: norden, nordem, norden, osten, sueden, sueden, sueden.
Man wuerde nun in der karte das hier sehen:
Keiner weiß nun, ob er nicht vielleicht immer zwischen Westen und Osten gewechselt hat, da man keine Verbindungen zwischen den einzelnen Feldern sieht.
Hat vielleicht jemand einen Vorschlag, wie ich diese Verbindungen noch mit in die Karte schreiben koennte? Mir wuerde ein Beispielcode sehr helfen.
lg und vielen Dank fuer die Hilfe
roschi
[edit]
Typo im Code gefixt.
[/edit]
Verfasst: Montag 29. Juni 2009, 09:40
von numerix
Du könntest die Rauten ersetzen z.B. durch Buchstaben N, S, O, W, wobei der Buchstabe jeweils angibt, aus welcher Richtung das Feld belegt wurde.