Klasse verschiedene varianten
Und im Hinblick auf den "Register-Quatsch" hatte ich ja schon im Code angedeutet, dass man die Registierung der Gebäudetypen in __init__ als Dictionary Comprehension per Einzeiler abfrühstücken kann. Eine nachträgliche Registrierung von Gebäudetypen während des Spiels ist doch sowieso unrealistisch. Oder geht es um die Freischaltung weiterer Gebäudetypen? Dann würde ich das wahrscheinlich eher über ein activated-Atrribut lösen. Denn ich kenne es so, dass Gebäude aus höheren Stufen zunächst ausgegraut sind. Dass ein angefangenes Spiel plötzlich komplett neue Gebäudetypen erhält, habe ich bisher noch nicht gesehen. Wenn das irgendwann möglich sein soll, dann wäre eine Plugin-API für diesen Punkt vielleicht geeigneter.
Wobei man IMHO schon viel Erfahrung braucht, um so ein Projekt quasi auf dem Papier durchplanen zu können. Der OP kommt mir so vor als wenn er zwar nicht gänzlich neu auf dem Feld der Programmierung ist, aber noch recht am Anfang bei der Progammierung komplexer Spiele steht. Vieles ist dann auch einfach Learning By Doing mit dem häufigen auf die Nase fallen inklusive.kbr hat geschrieben:Noch eine Stufe vorher empfehle ich ein großes Blatt Papier, einen Bleistift, sowie einen *großen* Radiergummi.snafu hat geschrieben:Also wie schon vorgeschlagen wurde, ruhig zu Beginn ein paar Containerklassen definieren, jeweils für Koordinaten, Feldinfo und sowas.
Etwas im Vorfeld fehlerfrei durchplanen zu können halte ich für unrealistisch. Es geht vielmehr darum einen Einstieg zu finden, der einem später möglichst wenig Kopfschmerzen bereitet. Ohne Plan zu starten ist schlecht - selbst bei agiler Entwicklungsnafu hat geschrieben:Wobei man IMHO schon viel Erfahrung braucht, um so ein Projekt quasi auf dem Papier durchplanen zu können.

-
- User
- Beiträge: 206
- Registriert: Freitag 13. März 2015, 18:36
Also das Blatt Papier existiert schon 
Ich habe: - eine Liste Für die meilensteine,
- ein Klassendiagramm
- ein Groben schriftlichen Text für die Anforderungen
- einen Plan für die Graphische Oberfläche
Und die Änderungen von Snafu sind auch schon übernommen,
die Registrierung ist jetzt eben nicht mehr in der Game-Klasse sondern in dem building_types.py Modul, von welchem man das importieren kann.
Den Rest schaue ich mir heute mal an.
Vieleicht habe ich in letzter Zeit zu viel lua und pascal programmiert und muss mich in Python erst wieder reinfinden

Ich habe: - eine Liste Für die meilensteine,
- ein Klassendiagramm
- ein Groben schriftlichen Text für die Anforderungen
- einen Plan für die Graphische Oberfläche
Und die Änderungen von Snafu sind auch schon übernommen,
die Registrierung ist jetzt eben nicht mehr in der Game-Klasse sondern in dem building_types.py Modul, von welchem man das importieren kann.
Den Rest schaue ich mir heute mal an.
Vieleicht habe ich in letzter Zeit zu viel lua und pascal programmiert und muss mich in Python erst wieder reinfinden

-
- User
- Beiträge: 206
- Registriert: Freitag 13. März 2015, 18:36
Ich bin gerade noch dabei die Anmerkungen welche ihr mir gegeben habt um zu setzten.
Dabei ist aber etwas sehr seltsames passiert. Ich habe die klasse Planet wie folgt definiert:
und jetzt wird mir immer der __name__ von allen Planet-instanzen auf "instance" gesetzt, wobei die Methoden gleich verwendet werden können.
Das bedeutet die ausgabe von planetinstance.__repr__() ist dann "instance{x=..., y=...}".
wie kann das passiert sein?
Dabei ist aber etwas sehr seltsames passiert. Ich habe die klasse Planet wie folgt definiert:
Code: Alles auswählen
class Planet():
def __init__(self, position, size):
self.position = position
self.size = size
self.map = [
[MapField((x, y), ground_types["G"]) for x in range(size)]
for y in range(size)
]
print(type(self))
def __repr__(self):
class_name = type(self).__name__
x, y = self.position
return '{}(x={}, y={})'.format(class_name, x, y)
def place_commando_center(self, owner):
position = _randpos(self.size)
return self.build_building(position, "Commando Center", owner)
def has_commando_center(self, player): #must be tested!
return any(
field.get_owner() == player and
isinstance(field.get_building(), CommandoCenter)
for field in self._get_all_fields()
)
def get_field(self, position):
x, y = position
return self.map[x][y]
def set_ground(self, position, ground):
field = self.get_field(position)
field.set_ground(ground)
def build_building(self, position, building_name, owner):
field = self.get_field(position)
return field.build_building(self, building_name, owner)
def _show(self):
print(self)
print('\n'.join([str(i) for i in self.map]))
def _get_all_fields(self):
return [field for row in self.map for field in row]
Das bedeutet die ausgabe von planetinstance.__repr__() ist dann "instance{x=..., y=...}".
wie kann das passiert sein?
Zuletzt geändert von Anonymous am Samstag 14. Januar 2017, 18:41, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
__repr__ hast du ja selbst definiert und vorgegeben, was da bei return zurückkommt. Neben x und y auch class_name. Praktischerweise wird class_name genau 2 Zeilen drüber festgelegt. Wenn du dir das anschaust, welche Ausgabe würdest du erwarten, wenn nicht "instance"? Solche Fragen kann man gut im interaktiven Interpreter ausprobieren und Schritt für Schritt leichter oder komplizierter werden, bis alle Unklarheiten beseitigt sind.Pygoscelis papua hat geschrieben:jetzt wird mir immer der __name__ von allen Planet-instanzen auf "instance" gesetztCode: Alles auswählen
class Planet(): def __repr__(self): class_name = type(self).__name__ x, y = self.position return '{}(x={}, y={})'.format(class_name, x, y)
die ausgabe von planetinstance.__repr__() ist dann "instance{x=..., y=...}".
wie kann das passiert sein?

MorgenGrauen: 1 Welt, 8 Rassen, 13 Gilden, >250 Abenteuer, >5000 Waffen & Rüstungen,
>7000 NPC, >16000 Räume, >200 freiwillige Programmierer, nur Text, viel Spaß, seit 1992.
>7000 NPC, >16000 Räume, >200 freiwillige Programmierer, nur Text, viel Spaß, seit 1992.
@Kebap: Also mich würde auch interessieren warum da 'instance' bei raus kommen soll:
[codebox=pycon file=Unbenannt.txt]>>> class Planet():
... def __repr__(self):
... class_name = type(self).__name__
... x, y = self.position
... return '{}(x={}, y={})'.format(class_name, x, y)
...
>>> p = Planet()
>>> p
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in __repr__
AttributeError: 'Planet' object has no attribute 'position'
>>> p.position = (1,2)
>>> p
Planet(x=1, y=2)
>>> type(p)
<class '__main__.Planet'>
>>> type(p).__name__
'Planet'[/code]
@Pygoscelis papua: Konvention für `__repr__()` ist das da entweder etwas raus kommt das man im Quelltext so schreiben könnte um ein gleiches Objekt zu erhalten, oder das die `repr()`-Darstellung in spitze Klammern eingefasst wird. Beispielsweise '<Planet x=… y=…>'.
[codebox=pycon file=Unbenannt.txt]>>> class Planet():
... def __repr__(self):
... class_name = type(self).__name__
... x, y = self.position
... return '{}(x={}, y={})'.format(class_name, x, y)
...
>>> p = Planet()
>>> p
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in __repr__
AttributeError: 'Planet' object has no attribute 'position'
>>> p.position = (1,2)
>>> p
Planet(x=1, y=2)
>>> type(p)
<class '__main__.Planet'>
>>> type(p).__name__
'Planet'[/code]
@Pygoscelis papua: Konvention für `__repr__()` ist das da entweder etwas raus kommt das man im Quelltext so schreiben könnte um ein gleiches Objekt zu erhalten, oder das die `repr()`-Darstellung in spitze Klammern eingefasst wird. Beispielsweise '<Planet x=… y=…>'.
Der Sinn, warum man den Namen dynamisch über das __name__ Attribut des Typen ermittelt anstatt ihn einfach direkt hinzuschreiben, ist übrigens der Gedanke an Vererbung. Wenn jetzt jemand einen RedPlanet ableiten würde, dann zeigt __repr__() einem automatisch RedPlanet(...) an, ohne dass man die Methode anpassen müsste. Ausgenommen sind natürlich Fälle, wo neue Attribute eingeführt werden. Die werden dann nicht automatisch angezeigt. Wenn man das auf die Spitze treiben möchte, dann ginge auch so etwas:
Aber das nur nebenbei. Gibt ja bereits nametuple(), sodass man diese Dinge eigentlich nicht nochmal neu erfinden muss. In echtem Code würde ich das wahrscheinlich als Mixin implementieren, wenn nametuple() mir aus irgendwelchen Gründen nicht geeignet erscheint.
Code: Alles auswählen
class Planet(object):
def __init__(self, position, size):
self.position = position
self.size = size
self._repr_names = ['position', 'size']
def __repr__(self):
class_name = type(self).__name__
signature = ', '.join(
'{}={!r}'.format(name, getattr(self, name))
for name in self._repr_names
)
return '{}({})'.format(class_name, signature)
class ColoredPlanet(Planet):
def __init__(self, position, size, color):
Planet.__init__(self, position, size)
self.color = color
self._repr_names.append('color')
def main():
planet = Planet((23, 42), 2342)
red_planet = ColoredPlanet((23, 42), 2342, 'red')
print(planet)
print(red_planet)
if __name__ == '__main__':
main()
-
- User
- Beiträge: 206
- Registriert: Freitag 13. März 2015, 18:36
die Ausgabe instance ist aber nicht nur bei __repr__() sondern auch bei
type(Planet).__name__ bzw. wenn ich schreibe Planer(parameter).name
Woran kann das denn liegen? Ich kapier es einfach nicht.
Und die __repr__() funktion hat snafu geschrieben nicht ich
@kepab ich hätte dort die ausgabe "Planet" erwartet wie bei allen anderen klassen
meine klasse heißt ja nicht instance.
hier mal dazu eine Ausgabe aus meinem Interpreter:
type(Planet).__name__ bzw. wenn ich schreibe Planer(parameter).name
Woran kann das denn liegen? Ich kapier es einfach nicht.
Und die __repr__() funktion hat snafu geschrieben nicht ich

@kepab ich hätte dort die ausgabe "Planet" erwartet wie bei allen anderen klassen
meine klasse heißt ja nicht instance.
hier mal dazu eine Ausgabe aus meinem Interpreter:
Code: Alles auswählen
[GCC 4.9.3] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> class House():
... pass
...
>>> House.__name__
'House'
>>>
Übrigens, type(Planet()).__name__ ergibt "instance", wenn man die Klasse unter Python 2.x ohne Basisklasse definiert. Daher sollte man immer von object erben, wenn man keine andere Basisklasse hat. Sonst erhält man unter Python 2 oldstyle-Klassen.
-
- User
- Beiträge: 206
- Registriert: Freitag 13. März 2015, 18:36
was ist denn da der Unterschied?
hier eine andere Ausgabe aus meinem interpreter:
und ich verwende ja nur Python3
EDIT: ich habe gerade gesehen das meine IDE irgendwie auf Python2 umgestellt hatte, daher rührte der Fehler also
Da hätte ich jetzt auch noch wochen im code suchen können
nächstes mal teste ich es auch außerhalb der IDE ...
hier eine andere Ausgabe aus meinem interpreter:
Code: Alles auswählen
>>> class House:
... def __repr__(self):
... return type(self).__name__
...
>>> a = House()
>>> a
House
>>> a.__repr__()
'House'
EDIT: ich habe gerade gesehen das meine IDE irgendwie auf Python2 umgestellt hatte, daher rührte der Fehler also

Da hätte ich jetzt auch noch wochen im code suchen können

Ich kenne deine Entwicklungsumgebung nicht, aber "instance" kann bei type(self).__name__ AFAIK nur unter Python 2.x herauskommen, wenn wie gesagt eine "nackte" Klasse ohne Basisklasse definiert wird. Python 3.x verwendet immer automatisch Newstyle-Klassen, auch ohne "object". Ich schreibe es trotzdem immer hin, weil es nicht wehtut und den Code damit kompatibel zu Python 2.x hält.
EDIT:
Dann hat sich das ja aufgeklärt. Und sorry, dass ich dich gerade so angefahren habe. Ich hatte das "ist nicht von mir -- snafu hat das so gezeigt" wohl ich den falschen Hals gekriegt...
EDIT:
Dann hat sich das ja aufgeklärt. Und sorry, dass ich dich gerade so angefahren habe. Ich hatte das "ist nicht von mir -- snafu hat das so gezeigt" wohl ich den falschen Hals gekriegt...

Zuletzt geändert von snafu am Samstag 14. Januar 2017, 22:26, insgesamt 1-mal geändert.
-
- User
- Beiträge: 206
- Registriert: Freitag 13. März 2015, 18:36
ok dann mache ich das auch.