Hilfe bei Strukturen (Elemente zufügen/löschen/finden)

Anfängerfragen zum Programmieren mit PureBasic.
Benutzeravatar
diceman
Beiträge: 347
Registriert: 06.07.2017 12:24
Kontaktdaten:

Hilfe bei Strukturen (Elemente zufügen/löschen/finden)

Beitrag von diceman »

Okay, ich brauche etwas Hilfe.
Kann sein, daß die jahrelange Nutzung von Blitzbasic mich "verdorben" hat, die solche Dinge mit wenigen Zeilen Codes automatisiert hat, aber ich verstehe ums Verrecken nicht, wie ich Structs in PB richtig verwalte.

Gegeben sei folgendes:

Code: Alles auswählen

Structure MONSTER
    MonsterName$
    HP.i
EndStructure

m.MONSTER
m\MonsterName$ = "Goblin"
m\HP = 30

Debug m\MonsterName$
Debug m\HP
Der Code erzeugt einen Goblin mit 30 Lebenspunkten. Richtig, oder?
Jetzt meine Frage:
Wie füge ich weitere Monster hinzu?
Wie lösche ich Monster? (Wenn ihre Lebenspunkte auf <= 0 fallen)
Wie kann ich durch alle Monster gehen und zum Beispiel alle "Goblins" finden?

Eine Option wäre sicherlich, das mit einem Array zu erledigen, aber Gesetz den Fall, ich weiß gar nicht, wieviel Goblins jemals in meinem Spiel sein werden?
Also:

Dim creature.MONSTER(10)

Code: Alles auswählen

creature.MONSTER
creature(0)\MonsterName$ = "Goblin"
creature(0)\HP = 30

creature.MONSTER
creature(1)\MonsterName$ = "Orc"
creature(1)\HP = 50

For m = 0 To 1
    Debug creature(m)\MonsterName$
    Debug creature(m)\HP
Next
Erzeugt 2 Monster, einen Goblin und einen Orc. Das erscheint mir jedoch relativ unbeholfen und steif. Das heißt, ich muß immer Buch darüber führen, wieviele Monster momentan in meinem Spiel sind, und die Frage bleibt: wie lösche ich ein Monster und gebe den Speicher wieder frei?

Vielen Dank!
Now these points of data make a beautiful line,
And we're out of Beta, we're releasing on time.
Benutzeravatar
Josh
Beiträge: 1028
Registriert: 04.08.2009 17:24

Re: Hilfe bei Strukturen (Elemente zufügen/löschen/finden)

Beitrag von Josh »

Schau mal in der Hilfe unter Maps. Da kannst du allerdings immer nur ein Monster mit dem gleichen Namen verwenden.

Code: Alles auswählen

Structure MONSTER
    HP.i
EndStructure

NewMap Monsters.MONSTER()

Monsters ("Goblin")\HP = 30
Monsters ("Orc")   \HP = 50

ForEach Monsters()
  Debug MapKey (Monsters())
  Debug Monsters()\HP
  Debug ""
Next

Debug "Anzahl Monsters = " + MapSize (Monsters())
DeleteMapElement (Monsters(), "Goblin")
Debug "Anzahl Monsters = " + MapSize (Monsters())
Eventuell kannst du auch LinkedLists verwenden, musst du entscheiden, was für dich sinnvoller ist:

Code: Alles auswählen

Structure MONSTER
    MonsterName$
    HP.i
EndStructure

NewList Monsters.MONSTER()

AddElement (Monsters())
Monsters()\MonsterName$ = "Goblin"
Monsters()\HP           = 30

AddElement (Monsters())
Monsters()\MonsterName$ = "Goblin"
Monsters()\HP           = 10

AddElement (Monsters())
Monsters()\MonsterName$ = "Orc"
Monsters()\HP           = 50

ForEach Monsters()
  Debug Monsters()\MonsterName$
  Debug Monsters()\HP
  Debug ""
Next

Debug "Anzahl Monsters = " + ListSize (Monsters())
ForEach Monsters()
  If Monsters()\HP = 10
    DeleteElement (Monsters())
  EndIf
Next
Debug "Anzahl Monsters = " + ListSize (Monsters())
Mit Lists und Maps kannst du sehr viel machen. Du könntest die z.B. auch kombinieren, dass eine Map alle Namen im Key enthält und die Map je Eintrag eine List enthält, die wiederum alle Monster vom gleichen Namen enthält.
Benutzeravatar
Kurzer
Beiträge: 1614
Registriert: 25.04.2006 17:29
Wohnort: Nähe Hamburg

Re: Hilfe bei Strukturen (Elemente zufügen/löschen/finden)

Beitrag von Kurzer »

Und wenn Du doch Arrays nehmen möchtest, dann gibt es ja auch noch den "ReDim" befehl zum vergrößern der Dimension.
"Never run a changing system!" | "Unterhalten sich zwei Alleinunterhalter... Paradox, oder?"
PB 6.02 x64, OS: Win 7 Pro x64 & Win 11 x64, Desktopscaling: 125%, CPU: I7 6500, RAM: 16 GB, GPU: Intel Graphics HD 520
Useralter in 2023: 56 Jahre.
Benutzeravatar
diceman
Beiträge: 347
Registriert: 06.07.2017 12:24
Kontaktdaten:

Re: Hilfe bei Strukturen (Elemente zufügen/löschen/finden)

Beitrag von diceman »

Vielen Dank euch beiden!
Ja, ich habe mir schon gedacht, daß das irgendwie mit dem List-Befehl funktioniert, nur Syntax und Mechanik war mir nicht ganz klar, deswegen bin ich beim Rumprobieren auch auf keinen grünen Zweig gekommen.
In Blitzbasic konnte ich auch Arrays erstellen, und wenn ich das nicht tat, wurden erstellte Types automatisch in eine Liste eingetragen:

m.MONSTER = New MONSTER
m\Name$ = "Goblin"
m.MONSTER = New MONSTER
m\Name$ = "Goblin"

hat 2 Goblins erstellt, die ich dann mit
For m.MONSTER = Each MONSTER
aufrufen konnte und ggf. mit Delete MONSTER auch wieder löschen konnte ("m" konnte dabei durch jede beliebige Laufvariable ersetzt werden).

Bei PB ist das natürlich etwas aufwendiger, der Vorteil ist jedoch, daß man wirklich "versteht" was man da tut.

Jetzt noch eine Frage:
Wenn ich in meinem Programm sehr oft neue Structures erstelle und auch wieder lösche (Monster stirbt, neues Monster wird erstellt), besteht dann nicht die Gefahr, daß der Speicher volläuft? Mit DeleteElement() lösche ich ja nur den Zeiger auf eine bestimmte Structure, nicht die erstellte Structure selbst ... :? oder habe ich einen Denkfehler, und der Monster befindet sich gar nicht in der Structure, sondern ist eigentlich ein Objekt in der LinkedList? :? :?
Zuletzt geändert von diceman am 05.02.2018 12:22, insgesamt 3-mal geändert.
Now these points of data make a beautiful line,
And we're out of Beta, we're releasing on time.
Benutzeravatar
Josh
Beiträge: 1028
Registriert: 04.08.2009 17:24

Re: Hilfe bei Strukturen (Elemente zufügen/löschen/finden)

Beitrag von Josh »

diceman hat geschrieben: Jetzt noch eine Frage:
Wenn ich in meinem Programm sehr oft neue Structures erstelle und auch wieder lösche (Monster stirbt, neues Monster wird erstellt), besteht dann nicht die Gefahr, daß der Speicher volläuft? Mit DeleteElement() lösche ich ja nur den Zeiger auf eine bestimmte Structure, nicht die erstellte Structure selbst ...
Eine List belegt keinen zusammenhängenden Speicherbereich. Mit jedem AddElement() wird irgendwo im Speicher der benötigte Platz für genau ein Listelement allociert und mit den anderen Listeinträgen verknüpft. Beim Löschen eines Listeintrages mit DeleteElement() wird der reservierte Speicher für dieses ListElement wieder freigegeben und die davor und dahinter liegenden Elemente in der List neu verknüpft. Deshalb auch der Name 'LinkedList'.

Das funktioniert auch mit komplexeren Lists, die evtl. selbst weitere Lists oder Maps enthalten. Da musst du dir keine Gedanken machen, das macht alles Pb für dich.
Zuletzt geändert von Josh am 05.02.2018 12:32, insgesamt 1-mal geändert.
Benutzeravatar
diceman
Beiträge: 347
Registriert: 06.07.2017 12:24
Kontaktdaten:

Re: Hilfe bei Strukturen (Elemente zufügen/löschen/finden)

Beitrag von diceman »

Perfekt, jetzt habe ich es verstanden! :allright:
Also:



5 Elemente erstellen:
e e e e e
x x x x x (Speicherbelegung)

3tes Element wird gelöscht:
e e - e e
x x x x x

Listen werden neu verknüpft:
e e e e -
x x x x x (reservierter Speicher bleibt konstant)

Zwei neue Elemente werden erstellt:
e e e e E E
x x x x x x



Korrekt? :lurk:
Now these points of data make a beautiful line,
And we're out of Beta, we're releasing on time.
Benutzeravatar
Bisonte
Beiträge: 2427
Registriert: 01.04.2007 20:18

Re: Hilfe bei Strukturen (Elemente zufügen/löschen/finden)

Beitrag von Bisonte »

äh fast ;)

Ein Element besteht im Speicher grob gesagt aus 3 Teilen.

Adresse Vorheriges Element (0 wenn es das erste ist)
Das Element selbst
Adresse des nächsten Elements (0 wenn nichts mehr kommt)

Dieser gesamte "Block" wird komplett freigegeben, wenn ein DeleteElement() kommt. da bleibt nichts über, da gibts keine "Lücken".

Stell dir vor es ist ein Schrank mit verdammt vielen Schubladen. In jeder Schublade ist ausser dem inhalt noch ein Zettel drin, wo draufstehen könnte : "Schublade 14", Kommt von Schublade 10 und geht zu schublade 22. Wenn man jetzt ein Element löscht, nimmt man die Schublade 14
Kippt sie aus und schiebt sie zurück. Die ist leer. dann geht man zu schublade 10, nimmt den zettel und schreibt drauf : Geht zu schublade 22.
Bei Schublade 22 schreibt man auf den zettel : Kommt von Schublade 10.

Bei z.B. SortList werden alle Schubladenzettel neu beschriftet. Alles andere (Position der Schubladen) bleibt im Speicher (Schrank) erhalten. nur das "Kommt von ... - Geht zu .... " ändert sich.

Listen haben den Vorteil : Man kann laufend neue Elemente hinzufügen, Löschen, usw. Auch Sortieren.... Es ist nur aufwendig das begehrte Element zu finden.

Maps dagegen sind fast wie eine Mischung aus Array's und Listen. Man kann schnell ein Element finden, aber es ist immer nur ein Element mit dem Namen vorhanden und man kann sie nicht sortieren.
PureBasic 6.04 LTS (Windows x86/x64) | Windows10 Pro x64 | Asus TUF X570 Gaming Plus | R9 5900X | 64GB RAM | GeForce RTX 3080 TI iChill X4 | HAF XF Evo | build by vannicom​​
Benutzeravatar
Kurzer
Beiträge: 1614
Registriert: 25.04.2006 17:29
Wohnort: Nähe Hamburg

Re: Hilfe bei Strukturen (Elemente zufügen/löschen/finden)

Beitrag von Kurzer »

Bisonte hat geschrieben:Dieser gesamte "Block" wird komplett freigegeben, wenn ein DeleteElement() kommt. da bleibt nichts über, da gibts keine "Lücken".
Deswegen stell dir statt der Schubladen lieber aufgeblasene Luftballons vor, auf denen "kommt von X" und "geht nach Y" steht.

Wenn Du ein Element löschst ist das so wie einen der Luftballons zerplatzen zu lassen. Der ist dann quasi weg und nimmt auch keinen Raum (Speicher) mehr ein. Das Schubladenbeispiel ist ein bisschen unglücklich gewählt, weil da wäre ja noch die leere Schublade... die verschwindet ja nicht und da könnte man denken, dass der Speicher dafür noch alloziert bleibt. Ist aber nicht so.

Möglicherweise ist es so, dass der PB interne Memory-Manager Speicher in größeren Blöcken am Stück reserviert bzw. freigibt, aber das ist dann wirklich "hinter den Kulissen" und spielt für den Anwender keine Rolle. Wichtig zu wissen ist, dass man nach DeleteElement() nicht selbst irgendwelchen Speicher freigeben muss.

Erst, wenn Du die gesamte Liste nicht mehr brauchst, musst du sie mit FreeList(Liste()) freigeben.
"Never run a changing system!" | "Unterhalten sich zwei Alleinunterhalter... Paradox, oder?"
PB 6.02 x64, OS: Win 7 Pro x64 & Win 11 x64, Desktopscaling: 125%, CPU: I7 6500, RAM: 16 GB, GPU: Intel Graphics HD 520
Useralter in 2023: 56 Jahre.
Benutzeravatar
diceman
Beiträge: 347
Registriert: 06.07.2017 12:24
Kontaktdaten:

Re: Hilfe bei Strukturen (Elemente zufügen/löschen/finden)

Beitrag von diceman »

Eine weitere Frage, diesmal zum Extends-Befehl:
Folgendes Snippet erzeugt mir ein Goblin und eine Schatztruhe - beide leiten sich von der Oberklasse "Actor" ab (ich habe jeweils eine Liste angelegt für Monster und Objekte):

Code: Alles auswählen

Structure ACTOR
	x.i
	y.i
EndStructure
Global NewList act.ACTOR()

Structure MONSTER Extends ACTOR
	name$
	hp.i
EndStructure
Global NewList mon.MONSTER()

Structure OBJECT Extends ACTOR
	type$
	locked.i
EndStructure
Global NewList obj.OBJECT()

AddElement(mon())
mon()\x = 10
mon()\y = 5
mon()\name$ = "Goblin"
mon()\hp = 20

AddElement(obj())
obj()\x = 10
obj()\y = 5
obj()\type$ = "Schatztruhe"
obj()\locked = 0

ForEach mon()
	Debug mon()\name$+" ("+mon()\hp+")   "+mon()\x+","+mon()\y
Next
ForEach obj()
	Debug obj()\type$+" ("+obj()\locked+")   "+obj()\x+","+obj()\y
Next
Jetzt meine Frage: gibt es einen Befehl/Trick/whatever, beim Erstellen von Monstern und Objekten auch automatisch eine "Actor"-Liste pflegen zu lassen, ohne dieses jedesmal von Hand erledigen zu müssen? Also daß das Programm erkennt, daß sich das Monster-Element, welches ich soeben zu einer Liste hinzugefügt habe, aus der "Actor"-Klasse ableitet und auch automatisch ein Actor-Element erzeugt?
So könnte ich mir beispielsweise mit ForEach act() die x und y-Koordinaten sowohl vom Goblin, als auch der Schatztruhe anzeigen lassen.
Now these points of data make a beautiful line,
And we're out of Beta, we're releasing on time.
Benutzeravatar
Bisonte
Beiträge: 2427
Registriert: 01.04.2007 20:18

Re: Hilfe bei Strukturen (Elemente zufügen/löschen/finden)

Beitrag von Bisonte »

diceman hat geschrieben:Jetzt meine Frage: gibt es einen Befehl/Trick/whatever, beim Erstellen von Monstern und Objekten auch automatisch eine "Actor"-Liste pflegen zu lassen, ohne dieses jedesmal von Hand erledigen zu müssen? Also daß das Programm erkennt, daß sich das Monster-Element, welches ich soeben zu einer Liste hinzugefügt habe, aus der "Actor"-Klasse ableitet und auch automatisch ein Actor-Element erzeugt?
So könnte ich mir beispielsweise mit ForEach act() die x und y-Koordinaten sowohl vom Goblin, als auch der Schatztruhe anzeigen lassen.
Das wird nicht funktionieren, da es trotz der "Ableitung" immer noch zwei getrennte Listen sind.

Aber ich frage mich gerade... Wieso solltest du das in diesem Fall (Goblin/Schatztruhe) machen wollen müssen ?
Goblin ist beweglich (also koordinaten ändern sich) .... Truhe ist unbeweglich (Koordinaten sind bis zu Abholung gleich)

Da sich deine beiden strukturen auch sehr ähneln würde ich die sogar zusammenlegen... (Falls es da nicht noch auf anderes ankommt)

Du hast bei beiden x und y als Integer, einen Namen als String und nochmal einen Integerwert.

Warum nicht gleich sowas wie ....:

Code: Alles auswählen

Structure s_gameobject
  
  oType.i ; Objekttype (Ist es ein "Mob" oder ein "Objekt" oder ein Bestandteil der Welt oder was auch immer)
  x.i     ; Koordinate
  y.i     ; Koordinate
   
  Name.s  ; Bezeichnung (Anzeigename)
  iVar.i  ; Individueller Wert. Auswertung im Programm über oType.i
  
EndStructure

Procedure.i Examine(*Object.s_gameobject)
  
  Protected String.s = ""
  
  If *Object
    
    Select *Object\oType
      Case #NPC
        String = "NPC hat " + Str(*Object\iVar) + " Leben."
      Case #Truhe
        If *Object\iVar = 0
          String = "Truhe ist verschlossen"
        Else
          String = "Truhe ist offen"
        EndIf
    EndSelect
    
  EndIf
  
  ProcedureReturn String
  
EndProcedure

; Aufruf

ForEach Object()
  Debug Examine(@Object())
Next
(Achtung nicht lauffähig, dient nur der Theorie ;) )
PureBasic 6.04 LTS (Windows x86/x64) | Windows10 Pro x64 | Asus TUF X570 Gaming Plus | R9 5900X | 64GB RAM | GeForce RTX 3080 TI iChill X4 | HAF XF Evo | build by vannicom​​
Antworten