Seite 1 von 2
Klasse verschiedene varianten
Verfasst: Donnerstag 12. Januar 2017, 20:06
von Pygoscelis papua
Ich möchte folgendes Programmieren:
Ich habe eine Hauptklasse, und möchte von dieser Unterklassen erstellen.
Die Unterklassen sollen aber auch nur leichte Änderungen in ein Paar Funktionen haben,
so dass z.B. eine Variable unterschiedlich ist.
Diese soll aber eigentlich nicht als Parameter übergeben werden, da ich von den Unterklassen viele Instanzen bilden möchte
und nicht immer wieder die gleichen Parameter mit übergeben möchte.
Wie ist hier die eleganteste Lösung? was würdet ihr tuen?
In meinm Programm ist das dann so:
Ich habe einen Hauptgebäudetyp, (die klasse Building)
aus dem ich
viele verschiedene andere Gebäude erstellen möchte,
die z.B. einen Anderen Namen oder aussehen haben.
Von diesen können dann alle beim Programmablauf vom user sehr oft gebaut, d.h. es können viele Instanzen gebildet werden.
Würdet ihr hier dennoch alle Gebäude als neue Klasse definieren, die von Building erbt?
Oder eventuell eine Funktion die diese Definiert? also z.B. so:
Code: Alles auswählen
def register_building(name, image, ...):
class Building:
def __init__(self, position, owner):
self.position = position
self.owner = owner
self.name = name
self.image = image
self..... =...
return Building
Re: Klasse verschiedene varianten
Verfasst: Donnerstag 12. Januar 2017, 20:15
von BlackJack
@Pygoscelis papua: Also wenn ich das richtig verstehe, dann unterscheiden sich die Klassen gar nicht, sondern nur die Exemplare die daraus erstellt werden. Also sollte man da nicht verschiedene Klassen erstellen, die dann auch noch alle den gleichen Namen haben.
Das Problem ist hier IMHO viel zu allgemein beschrieben als das man da konkret was zu sagen kann, ausser das es verschiedene Möglichkeiten gibt das lösen. Zum Beispiel mit Funktionen. Die man, wenn es wirklich so einfach ist das sich einfach nur festgelegte Argumente für das erstellen der Exemplare unterscheiden, mit `functools.partial()` erstellen könnte. Es könnte aber auch sein das man das mit anderen Mitteln besser lösen kann.
Re: Klasse verschiedene varianten
Verfasst: Donnerstag 12. Januar 2017, 21:11
von Pygoscelis papua
Also es ist im moment noch nicht viel mehr als das beschriebene da.
Die Gebäude sollen verschiedene Eigenschaften haben, wie halt das aussehen
aber auch z.B. ob dort etwas mit getan werden kann, z.B. das dort etwas Produziert wird etc.
Dazu wird teilweise dann auch eine Funktion geändert werden müssen aber oft halt auch nur ein ganz kleiner Teil
wie eine oder 2 variablen.
Hier ist ein Beispiel für die Oberklasse:
Code: Alles auswählen
class Building:
def __init__(selfposition, owner):
self.owner = owner
self.position = position
def can_build(self):
return True
def on_turn_start(self, turn):
do_something()
Und dann kann z.B. do_something() immer etwas anderes sein
oder die Funktion can_build, welche True zurückgeben soll wenn der Spieler das Gebäude an der gegeben Position bauen darf
Es kann aber halt auch sein das nur noch eine variable hinzugefügt wird, wie ein anderer Name,
der dann auch beim GUI bewirkt, dass dieser ein anderes Bild für das Gebäude auf das Feld setzt.
Da ich später das Spiel noch erweitern möchte, sollten dort möglichst viele Möglichkeiten offen gehalten werden,
aber ich glaube nicht das es Sinn macht dann jedes mal eine Neue Unter-Klasse zu definieren,
zumal so wie so eine Liste mit allen Gebäude-typen erstellt werden muss.
Ich weiß jetzt nicht so richtig was ich noch konkretisieren soll,
wenn noch etwas wichtiges Fehlt bitte einfach Fragen.
Re: Klasse verschiedene varianten
Verfasst: Donnerstag 12. Januar 2017, 21:35
von BlackJack
@Pygoscelis papua: Das klingt eher so als wäre die eine Klasse zu wenig und ein bisschen danach das möglichst *alles* variabel und flexibel sein soll, so für die Zukunft und so. Man kann solche Entscheidungen aber nur bedingt weit verschieben. Irgendwann muss man konkret werden und auch Einschränkungen machen. Und beschreibt ein `Building`-Exemplar ein konkretes Gebäude, oder einen Gebäudetyp? Denn ob ein konkretes Gebäude an einer bestimmten Position gebaut werden kann, bestimmt eigentlich nicht das Gebäude, das sollte vorher geklärt worden sein. Wenn das erstellt wurde mit einer Position, dann erwarte ich eigentlich das das gebaut wurde an der Position. Kann es sein das Du hier schon zwei Dinge vermischst die eigentlich gar nicht in einem Datentyp abgebildet werden sollten?
Eventuell möchtest Du Dir das Strategie-Entwurfsmuster anschauen. Und/oder das Command-Muster. Und falls das ein Projekt mit Abgabedatum und Benotung ist, würde ich wieder Meilensteine bei der Planung empfehlen und mit einem ganz einfachen aber tatsächlich spielbaren Programm anfangen, bevor man sich da sonstwelche komplizierten Regeln und Varianten ausdenkt. Aufpassen das man beim Planen und Implementieren nicht YAGNI-Code produziert.
Re: Klasse verschiedene varianten
Verfasst: Donnerstag 12. Januar 2017, 21:54
von Pygoscelis papua
Also die Funktionen müssen auf jeden Fall änderbar sein, da vor allem anhand dieser die Gebäude charakterisiert werden.
Zu der build Funktion: ja letztendlich sollte pos eher Parameter dieser anstatt der init-funktion sein,
die Funktion muss auch für jedes Gebäude verschieden sein, d.h. sie kann nicht extern definiert werden,
da jedes Gebäude woanders gebaut werden können muss.
Diese Funktion kann aber erst nach dem erstellen des Objektes aufgerufen werden, weil sonst self ja fehlt....
von daher ist es eigentlich egal ob die Funktion die Position erst festlegt oder schon init,
das Objekt kann ja einfach gelöscht werden, wenn Festgestellt wird, dass man das so nicht bauen kann.
Zu den Meilensteinen: Die habe ich mir schon gemacht ...
Im Moment bin ich halt bei den Gebäuden angekommen, die gehen theoretisch auch schon, aber die
werden im Moment über eine register-funktion erstellt. (die Klassen, nicht die Instanzen)
Zur Benotung: Nein der Pythonteil wird nicht wirklich bewertet, der ist nur zusätztlich, nachdem festgelegt wurde, dass wir gegen die Erwartungen
in Delphi/Lazarus/Pascal programmieren müssen

, die letzten jahrgänge durften auch andere Sprachen verwenden und uns wurde das im letzten Halbjahr auch noch so gesagt

Re: Klasse verschiedene varianten
Verfasst: Donnerstag 12. Januar 2017, 22:17
von BlackJack
@Pygoscelis papua: Auch nach diesem Beitrag ist mir immer noch nicht klar was ”Gebäude” denn nun eigentlich ist. Jedes Gebäude muss woanders gebaut werden können oder Gebäudetypen müssen woanders gebaut werden können? Deine Register-Funktion erstellt Gebäude oder Gebäudetypen? Was von `self` wird in der `can_build()`-Methode denn verwendet? Nur die Position? Die könnte man auch als Argument übergeben. Dir ist klar das es auch Klassenmethoden und statische Methoden gibt? Und Metaklassen? Und das man die Trennung zwischen Gebäude und Gebäudetyp auch tatsächlich durch zwei Klassen erreichen kann? Oder vielleicht auch einfach durch eine oder mehrere Funktionen?
Eine Register-Funktion die etwas erstellt ist übrigens ein bisschen überraschend, da würde man eher erwarten das die, nun ja etwas registriert und nichts zurück gibt. Und dann vielleicht auch eine Methode auf einer Klasse ist, die die registrierten Objekte verwaltet.
Wenn die ”Funktionen” das Verhalten der Gebäude charakterisieren, dann willst Du entweder eine Klasse pro Gebäudetyp, wo das verhalten dann halt als Methoden umgesetzt wird, oder das Strategie-Muster wenn die Verhalten selbst noch mal parametrisiert und vielleicht auch verschieden kombiniert werden sollen.
Ich persönlich würde wohl mit einem Gebäude(typ) als ganz normale Klasse anfangen. Und dann sieht man, wenn man anfängt den nächsten zu schreiben, was man da an Gemeinsamkeiten/Unterschiede hat, ohne das man bei so etwas wie dynamisch Klassen per Funktion zu erstellen landet. Was mir ein bisschen zu viel Magie wäre, vor allem weil ich den Sinn hier nicht sehe.
Re: Klasse verschiedene varianten
Verfasst: Donnerstag 12. Januar 2017, 22:46
von Pygoscelis papua
BlackJack hat geschrieben:@Pygoscelis papua: Auch nach diesem Beitrag ist mir immer noch nicht klar was ”Gebäude” denn nun eigentlich ist. Jedes Gebäude muss woanders gebaut werden können oder Gebäudetypen müssen woanders gebaut werden können? Deine Register-Funktion erstellt Gebäude oder Gebäudetypen? Was von `self` wird in der `can_build()`-Methode denn verwendet? Nur die Position? Die könnte man auch als Argument übergeben. Dir ist klar das es auch Klassenmethoden und statische Methoden gibt? Und Metaklassen? Und das man die Trennung zwischen Gebäude und Gebäudetyp auch tatsächlich durch zwei Klassen erreichen kann? Oder vielleicht auch einfach durch eine oder mehrere Funktionen?
Ok vieleicht habe ich mich etwas unverständlich ausgedrückt, normaler weise meint Gebäude die Instanz und Gebäudetyp die Klasse.
Natürlich muss nur jeder Gebäudetyp eine woanders gebaut werden können, das hängt dann von anderen Gebäuden rundrum bzw. von den
"Landschaftlichen" Eingenschaften ab. Da die Position auch in andern Funktionen, wie z.B. on_turn_start verwendet werden wird, macht es auch snn, diese schon bein __init__ zu übergeben, da sie sich eh nicht ändert ( meine Gebäude laufen nicht

)
für can_build wird außerdem vermutlich erst mal nichts übergeben, ich überlege gerade nur, wie die Funktion dann tatsächlich auf die Karte zugreift.
Eventuell muss die als Argument übergeben werden.
Klassenmethoden habe ich mir schon mal angeschaut, ich habe sie aber noch nicht verwendet. Sollte ich soetwas für can_build verwenden, um keine instanz haben zu müssen oder wie geht das?
Über statische Methoden habe ich noch nicht viel gehört, vieleicht könntest du mir einen guten Link senden? Sonst suche ich auch selber, etwas habe ich das auch schon gemacht.
Und Zuerst hatte ich auch Building als Metaklasse realisiert, aber hier ist eben meine Frage:
ist es Sinn der Sache jedes mal für die kleinen Änderungen (von Meta-gebäude zu einzelnem Gebäudetyp) eine Neue Klasse zu schreiben,
wie ich das jetzt verstanden habe schon. Oder?
BlackJack hat geschrieben:
Eine Register-Funktion die etwas erstellt ist übrigens ein bisschen überraschend, da würde man eher erwarten das die, nun ja etwas registriert und nichts zurück gibt. Und dann vielleicht auch eine Methode auf einer Klasse ist, die die registrierten Objekte verwaltet.
Die Register Funktion erstellt die Klasse und registriert sie für die Oberklasse Game (methode von Game) (bis jetzt ist das ein ablegen in einer Liste)
um dann überprüfen zu können welche Gebäude es gibt, diese dann aufzulisten bzw. nach dem Namen dann ein Gebäudetyp zum bauen auszuwählen.
BlackJack hat geschrieben:
Wenn die ”Funktionen” das Verhalten der Gebäude charakterisieren, dann willst Du entweder eine Klasse pro Gebäudetyp, wo das verhalten dann halt als Methoden umgesetzt wird, oder das Strategie-Muster wenn die Verhalten selbst noch mal parametrisiert und vielleicht auch verschieden kombiniert werden sollen.
Ich persönlich würde wohl mit einem Gebäude(typ) als ganz normale Klasse anfangen. Und dann sieht man, wenn man anfängt den nächsten zu schreiben, was man da an Gemeinsamkeiten/Unterschiede hat, ohne das man bei so etwas wie dynamisch Klassen per Funktion zu erstellen landet. Was mir ein bisschen zu viel Magie wäre, vor allem weil ich den Sinn hier nicht sehe.
Ok wie ich das jetzt verstanden habe wird jedes Gebäude eine Klasse sein die von Building (Metaklasse) erbt, vermutlich werden es erstmal auch garnicht 200 Gebäudetypen ...

bis jetzt sind 7 in den Meilensteinen festgelegt ...
Habe ich das jetzt so richtig verstanden?
Re: Klasse verschiedene varianten
Verfasst: Donnerstag 12. Januar 2017, 23:50
von BlackJack
@Pygoscelis papua: Wenn jeder Gebäudetyp eine Klasse ist die von `Building` erbt, dann ist `Building` keine Metaklasse sondern einfach nur eine Basisklasse.
Letztlich kann man so allgemein, wie schon gesagt, gar nichts sagen, es ist halt nur so, dass eine Methode die Klassen dynamisch erstellt, wirklich so ziemlich am Ende des magischen Spektrums ist, und ich da insbesondere bei Anfängern so ähnlich wie bei `eval()` drauf reagiere: Das ist mit ziemlicher Sicherheit der falsche, viel zu flexible und ”magische” Ansatz. Mir ist immer noch nicht klar was gegen ganz normale Klassen für die Gebäudetypen spricht, mit Vererbung wenn man gemeinsames Verhalten in Oberklassen herausziehen kann. (Wobei „Oberklasse Game“ übrigends auch wieder total verwirrend ist, weil ich glaube (hoffe?) das war nicht wirklich so gemeint wie es sich anhört, denn `Game` ist ziemlich sicher keine Oberklasse von `Building`, denn ein Gebäude ist kein Spiel. Nehme ich jetzt mal an.
Re: Klasse verschiedene varianten
Verfasst: Freitag 13. Januar 2017, 06:27
von Pygoscelis papua
Ok und was ist dann eine Metaklasse?
Und meine Frage war eben ob man solche Funktionen zum erstellen verwenden sollte oder halt wirklich Unterklassen schreibt die von Building erben.
Wie ich das jetzt verstanden habe ja.
Und nein Game ist eine Andere Klasse Oberklasse ist der Falsche Ausdruck ...
Aber Building ist in so fern von Game abhängig, dass es nur dort verwendet wird,
Wenn es kein Game gibt wird auch kein Gebäude (keine Instanz von Building) erstellt.
Re: Klasse verschiedene varianten
Verfasst: Freitag 13. Januar 2017, 08:46
von snafu
Die Test-Funktion, ob ein Gebäude gebaut werden kann, würde ich so in der Art definieren:
Code: Alles auswählen
class Building:
def __init__(self, ...):
# ...
# Some methods
@staticmethod
def is_buildable(game_map):
# Only concrete buildings are buildable
return False
class Farm(Building):
# ...
@staticmethod
def is_buildable(game_map):
# Check the map
# Return True or False
Statische Methoden sind im Grunde auf der Klasse definierte Funktionen. Sie werden ohne das self definiert, da in dem Moment noch kein Exemplar der Klasse verwendet wird. Der Aufruf kann somit auf der Klasse selbst erfolgen:
Ich würde die Methode nutzen, um dem Spieler bereits vorab z.B. mittels roter Markierung sagen zu können, dass das Gebäude nicht gebaut werden kann. Und in __init__ würde ich sie auch nochmal aufrufen (nur zur Sicherheit) und eine Exception werfen, wenn die Test-Methode False liefert. Übrigens, self.is_buildable(game_map) ist trotzdem möglich.
Re: Klasse verschiedene varianten
Verfasst: Freitag 13. Januar 2017, 09:20
von snafu
Pygoscelis papua hat geschrieben:Die Register Funktion erstellt die Klasse und registriert sie für die Oberklasse Game (methode von Game) (bis jetzt ist das ein ablegen in einer Liste)
um dann überprüfen zu können welche Gebäude es gibt, diese dann aufzulisten bzw. nach dem Namen dann ein Gebäudetyp zum bauen auszuwählen.
Alles nachvollziehbar, aber der Name ist ungünstig gewählt, da man unter Registrierung normalerweise versteht, dass bereits vorhandene Dinge irgendwo angemeldet werden. Wenn die Funktion zur Registrierung diese Dinge erst selbst erstellen muss, dann ist das halt ungewöhnlich. Auch hier ein Vorschlag wie ich das wahrscheinlich lösen würde:
Code: Alles auswählen
class GameMap:
# ...
def build_object(self, object_type, position, *optargs):
if not object_type.is_buildable(self):
# entsprechende Darstellung, z.B. roter Bereich
# als eigene Methode auslagern
else:
# Erzeuge Exemplar von Gebäudetyp
# Gib die Map (d.h. dich selbst) als Argument mit
# Optionale Argumente für Anzahl, Farbe, ... möglich
obj = object_type(self, *optargs)
self.register(obj)
return obj
Demnach würde man dann natürlich die Basisklasse Buiding so definieren, dass sie eine Map als Argument erwartet. Die konkreten Gebäudetypen können neben einer Map auch weitere Argumente erwarten, falls nötig. Aufruf mit dem Farm-Beispiel wäre dann:
Code: Alles auswählen
game_map.build_object(Farm, (pos_x, pos_y))
# Oder mit optionalen Argumenten
game_map.build_object(Farm, (pos_x, pos_y), weiteres_arg, noch_eins)
EDIT:
Habe Map und Positionierung vermischt. Aber ich hoffe, es ist klar geworden, was ich meinte.
Re: Klasse verschiedene varianten
Verfasst: Freitag 13. Januar 2017, 13:47
von BlackJack
@Pygoscelis papua: Klassen beschreiben die Eigenschaften und das Verhalten von Objekten die man aus der Klasse erstellen kann. Sind also so eine Art Bauplan für Objekte. Da Klassen selbst in Python auch Objekte sind, gibt es mit Metaklassen die Möglichkeit einen Bauplan für Klassen zu definieren. Das ist ziemlich ”magisch” und wird nicht wirklich oft verwendet, aber es ermöglicht so Sachen wie den ORM von SQLAlchemy mit den ”Deklarationen” auf Klassenebene.
Re: Klasse verschiedene varianten
Verfasst: Freitag 13. Januar 2017, 17:16
von Pygoscelis papua
Ok cool da hab ich mal wieder was nützliches dazu gelernt

Nochmal danke an snafu und BlackJack fürs Antworten, ich weiß jetzt zumindest wie ich weiter machen muss
Zu den Metaklassen (nur aus interesse) könntet ihr mir dafür ein Beispiel nennen (als Code am besten) ?
Re: Klasse verschiedene varianten
Verfasst: Freitag 13. Januar 2017, 18:26
von BlackJack
@Pygoscelis papua: Im Blogartikel
Python metaclasses by example gibt es neben einer Erklärung auch ein paar Beispiele, unter anderem `string.Template` aus der Standardbibliothek.
Und noch ein Zitat von Python-Kernentwickler Tim Peters: „Metaclasses are deeper magic that 99% of users should never worry about. If you wonder whether you need them, you don't (the people who actually need them know with certainty that they need them, and don't need an explanation about why).“
Re: Klasse verschiedene varianten
Verfasst: Freitag 13. Januar 2017, 18:43
von Pygoscelis papua
Ich dachte, da es ja immer was an code auszusetzten gibt, bzw. ich garantiert keinen perfekten Code schreibe,
stelle ich den jetzt hier einfach nochmal rein, vieleicht findet ihr ja Fehler
Code: Alles auswählen
#!/usr/bin/python3
import random
class Game():
def __init__(self, size, planetcount, planetmapsize, playercount, buildings):
self.registered_buildings = {}
for building_class in buildings:
self.register_building(building_class)
self.turn = 0
self.undetermined_commands = []
#place planets
self.planets = []
for plnt in range(planetcount):
x, y = [random.randrange(size) for i in range(2)]
pos = (x, y)
self.planets.append(Planet(pos, planetmapsize))
##init player
if planetcount < playercount:
raise ValueError("planetcount less then playercount")
#give every player one planet:
for player in range(playercount):
self.planets[player].place_commando_center(player)
#we can do this because all planets where placed randomly
def _show_all_planets(self): #only for Test
for plnt in self.planets:
plnt._show()
def get_player_first_planet(self, player):
return self.planets[player]
def build_object(self, planet, player, pos, object):
planet = self.planets[planet]
if not object.is_buildable(planet, player, pos):
return False
field = planet.get_field(pos)
planet.set_field(pos, [field[0], object(planet, player, pos)])
return True
def register_building(self, building_class):
self.registered_buildings[building_class.__name__] = building_class
def turn_end(self):
while self.undetermined_commands:
command = self.undetermined_commands.pop(random.randrange(len(
self.undetermined_commands)))
self.run_command(command)
self.undetermined_commands = []
def add_command(self, command):
self.undetermined_commands.append(command)
def run_command(self, command):
name = command[0]
if name == "build":
self.build_object(command[1], command[2], command[3],
self.registered_buildings[command[4]])
class Planet():
def __init__(self, pos, size):
self.x, self.y = pos
self.map = []
self.map_size = size
for row in range(size):
self.map.append([])
for row in self.map:
for column in range(size):
row.append(["d", None])
def place_commando_center(self, player):
pos = [random.randrange(self.map_size) for i in range(2)]
field = self.get_field(pos)
self.set_field(pos, [field[0], CommandoCenter(self, player, pos)])
def has_commando_center(self, player):
for y in map:
for x in y:
if type(x[1]) == CommandoCenter:
if x[1].owner == player:
return True
return False
def get_field(self, pos):
return self.map[pos[0]][pos[1]]
def set_field(self, pos, field):
self.map[pos[0]][pos[1]] = field
def _show(self):
print("planet", (self.x, self.y))
for i in self.map:
print(i)
class Building():
__name__ = "Building"
def __init__(self, planet, owner, pos):
self.owner = owner
self.planet = planet
@staticmethod
def is_buildable(planet, owner, pos):
return True
class CommandoCenter(Building):
__name__ = "Commando Center"
class House(Building):
__name__ = "House"
@staticmethod
def is_buildable(planet, owner, pos):
#TODO: make it only buildable near CommandoCenter
return True
buildings = []
buildings.append(CommandoCenter)
buildings.append(House)
class SpaceShip():
def __init__(self, pos, target):
self.dir_vector = dir_vector
self.pos = pos
self.target = target
def on_step():
pass#NotImplementedYet
##test section
print(buildings)
g = Game(10, 3, 5, 3, buildings)
print("NEW GAME", end="\n"*3)
g.add_command(("build", 0, 0, (0, 0), "House"))
g.turn_end()
g._show_all_planets()
Re: Klasse verschiedene varianten
Verfasst: Freitag 13. Januar 2017, 22:14
von snafu
- Überschreiben von Builtins vermeiden (z.B. von map)
- List Comprehensions nutzen, wenn möglich
- pythonische Lösungen (z.B. zip() und any()) gegenüber klassischen Ansätzen bevorzugen
- bei Factory-Methoden das erstellte Objekt liefern oder None anstatt True/False
- ...
Bei weitem nicht alles, was ich verbessern würde, aber hier ein paar Ansätze (ungetestet):
Code: Alles auswählen
#!/usr/bin/python3
from random import randrange
def _randpos(size):
return randrange(size), randrange(size)
class Game():
def __init__(
self, game_size, planet_size, num_planets, num_players, building_types
):
if num_players > num_planets:
raise ValueError('num_players must not exceed num_planets')
self.planets = [
Planet(_randpos(game_size), planet_size)
for _ in range(num_planets)
]
for i, planet in zip(range(num_players), self.planets):
planet.place_commando_center(i)
self.building_types = {tp.__name__: tp for tp in building_types}
self.turn = 0
self.undetermined_commands = []
def _show_all_planets(self):
# Only meant for testing purposes
for plnt in self.planets:
plnt._show()
def get_home_planet(self, player):
return self.planets[player]
def build_object(self, planet_id, player_id, position, object_type):
planet = self.planets[planet]
if object_type.is_buildable(planet, player_id, position):
field = planet.get_field(position)
obj = object_type(planet_id, player, position)
planet.set_field(position, (field[0], obj))
return obj
def turn_end(self):
while self.undetermined_commands:
command = self.undetermined_commands.pop(random.randrange(len(
self.undetermined_commands)))
self.run_command(command)
self.undetermined_commands = []
def add_command(self, command):
self.undetermined_commands.append(command)
def run_command(self, command):
name = command[0]
if name == "build":
self.build_object(command[1], command[2], command[3],
self.registered_buildings[command[4]])
class Planet():
def __init__(self, position, size):
self.position = position
self.size = size
self.map = [
[('d', None) for _ in range(size)] for _ in range(size)
]
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, player_id):
position = _randpos(self.size)
field = self.get_field(pos)
commando_center = CommandoCenter(self, player_id, position)
self.set_field(position, (field[0], commando_center))
def has_commando_center(self, player_id):
return any(
field[1].owner == player_id and isinstance(field[1], CommandoCenter)
for row in self.map for field in row
)
def get_field(self, position):
x, y = position
return self.map[x][y]
def set_field(self, position, field):
x, y = position
self.map[x][y] = field
def _show(self):
print(self)
print('\n'.join(self.map))
class Building():
__name__ = "Building"
def __init__(self, planet, owner, pos):
self.owner = owner
self.planet = planet
@staticmethod
def is_buildable(planet, owner, pos):
return True
class CommandoCenter(Building):
__name__ = "Commando Center"
class House(Building):
__name__ = "House"
@staticmethod
def is_buildable(planet, owner, pos):
#TODO: make it only buildable near CommandoCenter
return True
buildings = []
buildings.append(CommandoCenter)
buildings.append(House)
class SpaceShip():
def __init__(self, pos, target):
self.dir_vector = dir_vector
self.pos = pos
self.target = target
def on_step():
pass#NotImplementedYet
##test section
print(buildings)
g = Game(10, 3, 5, 3, buildings)
print("NEW GAME", end="\n"*3)
g.add_command(("build", 0, 0, (0, 0), "House"))
g.turn_end()
g._show_all_planets()
Re: Klasse verschiedene varianten
Verfasst: Freitag 13. Januar 2017, 23:28
von Pygoscelis papua
Vielleicht sollte ich mir mal ein cheat sheet für die häufigsten Python Funktionen erstellen ... any z.B. hatte ich mir lange nicht mehr angeschaut

Danke für die Tipps. Ich glaub ich werde die Gebäude insgesamt in eine andere Datei auslagern, auf welche dann als Modul zugegriffen wird.
Dann kann ich mir den ganzen register-Quatsch sparen

, das wird dann mit ausgelagert ...
Re: Klasse verschiedene varianten
Verfasst: Samstag 14. Januar 2017, 09:26
von Sirius3
@Pygoscelis papua: für den Ablauf ist es egal, wie Du Dein Programm strukturierst; auch wenn die Gebäudetypen in einem eigenen Modul sind, brauchst Du irgendeinen „register-Quatsch“. Weil building_classes building heißen, macht es für mich schwer lesbar. register_building ist auch überflüssig, weil damit sowieso nur ein Wörterbuch in ein anderes kopiert wird. Bei build_object übergibst Du ein object, das aber eine Klasse ist. Wäre auch sonst komisch, einer Funktion, die build_object heißt, schon ein Objekt zu übergeben. Besser als direkt die Klasse wäre es, den Gebäudetypnamen zu übergeben, wozu hast Du denn registered_building_types.
Die Methode sollte dann auch build_building heißen. Du arbeitest auch noch mit zu vielen unstrukturierten Listen und magischen Indizes. Warum muß man einem set_field erst das 0. Element des ursprünglichen Feldes übergeben? Für turn_end schau Dir mal random.shuffle an. Bei run_command benutzt Du wieder eine Liste anstelle eines strukturierten Objekts. Am besten schreibst Du für jeden Befehlstyp eine eigene Klasse. In has_commando_center ist y für eine Feldzeile der falsche Name, x für ein Feld ebenso. type sollte man nicht zum Vergleichen benutzen, isinstance ist besser, eine eigene Methode is_commando_center noch besser. __name__ ist ein internes Attribut, das beim Erzeugen einer Klasse automatisch gesetzt wird. Das selbst zu setzen ist ein Fehler, da es keine Auswirkung hat. Nenn es doch einfach BUILDING_TYPE. Bisher sind Planeten und Spieler nur Nummern, was dem Game-Objekt die Aufgabe aufbürdet das alles zu verwalten. Arbeite mehr mit Objekten.
Re: Klasse verschiedene varianten
Verfasst: Samstag 14. Januar 2017, 09:52
von snafu
Genau, das wollte ich auch noch sagen: Anstatt mit 2-elementrigen Listen zu arbeiten, die man über den Index ansprechen muss, sind namedtuples viel besser. Also wie schon vorgeschlagen wurde, ruhig zu Beginn ein paar Containerklassen definieren, jeweils für Koordinaten, Feldinfo und sowas. Denkbar sind auch mehrschichtige Strukturen, sodass man ein benanntes Tupel für ein Feld hat und dieses besitzt als Attribute die Koordinaten (wieder als eigener Typ) sowie eine Info zur Bebauung.
Re: Klasse verschiedene varianten
Verfasst: Samstag 14. Januar 2017, 11:08
von kbr
snafu hat geschrieben:Also wie schon vorgeschlagen wurde, ruhig zu Beginn ein paar Containerklassen definieren, jeweils für Koordinaten, Feldinfo und sowas.
Noch eine Stufe vorher empfehle ich ein großes Blatt Papier, einen Bleistift, sowie einen *großen* Radiergummi.
