Objektkoordinaten 2d Array
-
Photon schrieb:
Nein ich weiss nicht so genau wie es sich mit referenz und wert verhält.
Ich hab da mal was vorbereitet. Auch wenn meine didaktischen Konzepte in diesem Thread schon kritisiert wurden.

Folgendes:
#include <iostream> #include <string> // Held mit Name struct hero { std::string name; int dmg, def, hp; }; bool is_alive(hero h) { bool alive = 0<h.hp; if(alive) std::cout << h.name << " is alive.\n"; else std::cout << h.name << " is dead.\n"; return alive; } // Uebergabe per Wert void break_neck(hero h){ // h ist eine Kopie des übergebenen Objekts std::cout << h.name << " slipped and broke his neck!\n"; h.hp=0; } // Uebergabe per Referenz void meet_dragon(hero& h){ // h ist ein Alias für das übergebene Objekt std::cout << h.name << " took a wrong turn and entered the dragon's lair.\n"; h.hp=0; } int main(){ hero red = { "red", 10, 10, 10 }; hero blue = { "blue", 8, 8, 8 }; break_neck(red); if(is_alive(red)) std::cout << "Impossibru!\n"; meet_dragon(blue); if(is_alive(blue)) std::cout << "goddammit!\n"; }Das spannende sind Zeile 27:
h wird als eine neue Variable vom Typ hero deklariert - das System initialisiert h beim Aufruf mit dem Funktionsargument. h ist also eine Kopie(!) des Arguments.Und im Gegensatz dazu Zeile 33:
h wird als Referenz auf ein hero Objekt (hero&) deklariert. h ist lediglich ein Aliasname für das Funktionsargument. Referenzen erkennst Du am & hinter der Typangabe.Lass das Programm laufen. Hast Du die Ausgabe erwartet?
Wenn ja: Übergabe per Wert/Referenz begriffen.
Wenn nein: nochmal drüber grübeln - ist ganz einfach. Ebenso einfach wie der Unterschied zwischen einer Kopie und einem Alias im echten Leben.Memberfunktionen habe ich bisher bewusst nicht erwähnt.
-
ok ich war das wochende weg aber ich hab mir die sache angeschaut. Ich habe jetzt verstanden wie das mit den referenzen funktioniert und warum es besser ist direkt auf den speicherplatz zuzugreifen anstatt immer neue variablen zu erzeugen und diese auch im speicher abzulegen.
Als nächstes werde ich mir wohl die pointer nochmal genauer ansehen die ja auch was damit zu tun haben. Hab da noch nicht so ganz den durchblick.
Danke furble das war ein gutes beispiel. Jetzt werde ich öfter mal void funktionen nutzen können.
-
Photon schrieb:
ok ich war das wochende weg aber ich hab mir die sache angeschaut. Ich habe jetzt verstanden wie das mit den referenzen funktioniert und warum es besser ist direkt auf den speicherplatz zuzugreifen anstatt immer neue variablen zu erzeugen und diese auch im speicher abzulegen.
Zieh nicht die falschen Schlußfolgerungen. Besser oder schlechter habe ich noch gar nicht gesagt.
Was ich zeigen wollte:
In einer Funktion auf einer Kopie eines Arguments zu arbeiten ist etwas komplett anderes als auf dem Original zu arbeiten.Photon schrieb:
Als nächstes werde ich mir wohl die pointer nochmal genauer ansehen die ja auch was damit zu tun haben. Hab da noch nicht so ganz den durchblick.
Zeiger sind mit Sicherheit ein wichtiger Aspekt von C++, aber als Anfänger kommst Du erstmal gut ohne aus.
Z.B. möchte ich Dir noch zwei Sachen zeigen.
Mein letztes Beispiel enthielt zwei Verzweigungen, in denen ich Codefehler aufspüren wollte:
break_neck(red); if(is_alive(red)) std::cout << "Impossibru!\n"; meet_dragon(blue); if(is_alive(blue)) std::cout << "goddammit!\n";Nachdem rot sich den Hals brach, bzw. blau einen Drachen traf hätten beide tot sein sollen. Sobald eine der beiden Bedingungen wahr wurde war ich einem Programmfehler auf der Spur - in dem Fall
break_neck().
C++ bietet für sowas sog. Assertions.
D.h. wenn Du an einer Stelle im Programmcode eine Bedingung voraussetzt, kannst Du eine Assertion einbauen. Das Programm wird an der Stelle beendet, sollte die Bedingung doch nicht erfüllt sein. Z.B.#include <iostream> #include <string> #include <cassert> // wie oben... int main(){ // ... break_neck(red); assert( !is_alive(red) ); // Laufzeitfehler, wenn assert( false ) meet_dragon(blue); assert( !is_alive(blue) ); // dto. }Sehr hilfreich!
Und weiter noch: siehe z.B. folgenden Code, der weitestgehend identisch mit dem bisherigen ist:
#include <iostream> #include <string> #include <cassert> struct hero { std::string name; int dmg, def, hp; }; bool is_alive(hero h) { bool alive = 0<h.hp; if(alive) std::cout << h.name << " is alive.\n"; else std::cout << h.name << " is dead.\n"; return alive; } void break_neck(hero h){ // um assert() zu demonstrieren immer noch buggy :( std::cout << h.name << " slipped and broke his neck!\n"; h.hp=0; } void meet_dragon(hero& h){ std::cout << h.name << " took a wrong turn and entered the dragon's lair.\n"; h.hp=0; } // Uebergabe per Referenz auf const void print(const hero& h){ // h ist Referenz auf unveraenderliches (const) Objekt v. Typ hero std::cout << h.name << " (hp:" << h.hp << ", dmg:" << h.dmg << ", def:" << h.def << ')'; h.hp = 0; // toedliches print(). Kompiliert nicht. h ist const & ! } int main(){ hero red = { "red", 10, 10, 10 }; hero blue = { "blue", 8, 8, 8 }; print(red); std::cout << '\n'; print(blue); std::cout << '\n'; break_neck(red); assert( !is_alive(red) ); // Laufzeitfehler, wenn assert( false ) meet_dragon(blue); assert( !is_alive(blue) ); // dto. }Hoffentlich kriege ich das mit den Zeilennummern diesmal hin!

Spannend ist die Zeile 31.
h ist diesmal eine Referenz auf ein konstantes Objekt. D.h. h ist eine Referenz, wie Du sie schon kennst, aber darüberhinaus, kannst Du das Objekt, das h referenziert nicht über h verändern - siehe Zeile 33.Betrachte mit Deinem neuen Wissen Über Referenzen folgenden Code, der nicht ganz wie geplant funktioniert:
// attacking greift attacked an void attack(hero attacking, hero attacked); // Schlagabtausch - a hat die Initiative void showdown(hero a, hero b);Wie könnten Die Funktionen richtig aussehen? Kannst Du sie implementieren?
Wenn Du noch dabei bist - und folgen konntest - würde ich wohl beim nächsten Mal ein paar Worte zu Klassen und deren Member verlieren.
-
Furble Wurble schrieb:
Hoffentlich kriege ich das mit den Zeilennummern diesmal hin!

Spannend ist die Zeile 31.
Boah! Ich bin so ein Depp!

Aber jetzt ist's nur noch ein "Off-by-one"-Fehler.
Natürlich ist nur Zeile 30 spannend!
-
Hey,
Soweit ich es verstanden habe benutzt du die const variable als schutz damit sie nicht ausversehen geändert wird?
Zu den zwei funktionen. Bei der zweiten ist mir denke ich klar was zu tun ist aber bei der ersten weiss ich nicht so genau. Willst du einfach ur ne print funktionen die sagt held a mit den werten x,y,z greift held b mmit werten x,y,z an? und dann halt in er der nächsten wirklich "kämpfen" lasssen?
Ich werde mich nach der schule mal ransetzen und die dinger in deinen code einbauen.
Danke für die lehrstunde und beste Grüße aus Berlin
Photon
-
Photon schrieb:
Hey,
Moin!

Photon schrieb:
Soweit ich es verstanden habe benutzt du die const variable als schutz damit sie nicht ausversehen geändert wird?
So kannst Du es sehen.
Ein "tödliches print()" ist ein Bug, den ich so schon beim Kompilieren finde.Man spricht von "const-correctness" und die finde ich so wichtig, dass ich sie Dir von Beginn an nahelege.
Photon schrieb:
Zu den zwei funktionen. Bei der zweiten ist mir denke ich klar was zu tun ist aber bei der ersten weiss ich nicht so genau. Willst du einfach ur ne print funktionen die sagt held a mit den werten x,y,z greift held b mmit werten x,y,z an? und dann halt in er der nächsten wirklich "kämpfen" lasssen?
In der ersten sollst Du einen Angriff
attacker->attackedschreiben. Den richtigen Angriff. D.h. den Schaden berechnen und evtl.attackedLebenspunkte abziehen.
Aber es ist gar nicht der Inhalt auf den ich hinauswill: ich will nur sehen, dass Du die Funktionssignatur änderst - speziell die Typen der formalen Parameter.Dto. in der zweiten - wobei Du bei der Implementierung hoffentlich auf die erste Funktion zurückgreifst - dann wird's ein Zwei- oder Dreizeiler.
-
Ich habe jetzt eine weile nachgedacht aber ich komme nicht drauf.
Für die erste funktion habe ich das hier verwendet:
void attack(hero attacking, hero& attacked){ attacking.dmg -= attacked.def; if(attacking.dmg>0){ attacked.hp -= attacking.dmg;} }Aber wie du das jetzt mit der zweiten meinst verstehe ich nicht. Was genau soll jetzt noch bei showdown passieren? Ich steh irgendwie auf dem schlauch

-
Photon schrieb:
void attack(hero attacking, hero& attacked){ attacking.dmg -= attacked.def; if(attacking.dmg>0){ attacked.hp -= attacking.dmg;} }Aber wie du das jetzt mit der zweiten meinst verstehe ich nicht. Was genau soll jetzt noch bei showdown passieren? Ich steh irgendwie auf dem schlauch

Hmm...ja, mein Fehler. Ich dachte in
showdown()würde a erst b schlagen und b dann a - aber meinattack()ist Deinshowdown().
Egal:
Wieso übergibst Duattackingper Value?
Wieso ziehst Du vonattacking.dmgab? Verliert der Angreifer (bzw. dessen Kopie) Schadenspunkte?Meine Implementierungen:
void attack(const hero& attacker, hero& attacked){ assert(alive(attacker) && alive(attacked)); int dmg = attacked.def < attacker.dmg ? attacker.dmg - attacked.def : 0; attacked.hp = dmg < attacked.hp ? attacked.hp - dmg : 0; } void showdown(hero& a, hero& b){ attack(a, b); if(alive(b)) attack(b, a); }Der Ternäre Operator ist wahrscheinlich noch neu für Dich.
Funktioniert ganz einfach:
Bedingung ? Wert_wenn_Bedingung_wahr : Wert_wenn_Bedingung_falsch;Ist klar warum ich die Parameter so deklariere, wie ich sie deklariere?
-
achso ok ähm ja nein also:
void attack(hero attacking, hero& attacked){ attacking.dmg -= attacked.def; //<- dmg - def! if(attacking.dmg>0){ attacked.hp -= attacking.dmg;} //attacked als referenz weil von ihm hp dauerhaft abgezogen werden sollen }Also ich erzeuge für den Angreifer eine kopie damit der schaden nicht dauerhaft beeinflusst wird.
Ich habe mich die ganze zeit gefragt ob es gut ist eine funktion in einen funktion zu packen und war auch schon kurz davor das zu machen aber dann dachte ich mir das es vieleicht zu verschachtelt wird und man wieder leicht den überblick verlieren könnte.
WAs && || usw. machen weiss ich

Allerdings mag ich diese Assertmeldung nicht. Bzw. nich in diesem beispiel weil das ein hero in der rauen welt da draussen stribt ist eine zulässige aktion. Zumindest wenn es nach dem Universum geht.
-
Sry für den doppelpost hier is meine version
#include <iostream> #include <string> #include <cassert> struct hero { std::string name; int dmg, def, hp; }; bool is_alive(hero h) { bool alive = 0<h.hp; /** if(alive) std::cout << h.name << " is alive.\n"; else std::cout << h.name << " is dead.\n"; **/ return alive; } void print(const hero& h){ std::cout << h.name << " (hp:" << h.hp << ", dmg:" << h.dmg << ", def:" << h.def << ')'; } void attack(hero attacking, hero& attacked){ attacking.dmg -= attacked.def; if(attacking.dmg>0){ attacked.hp -= attacking.dmg;} } void showdown(hero& a, hero& b){ while (is_alive(a) && is_alive(b)){ attack(a,b); if (is_alive(b)){ attack(b,a);} print(a); std::cout << "\n"; print(b); std::cout << "\n"; } } int main(){ hero red = { "red", 10, 10, 10 }; hero blue = { "blue", 8, 8, 8 }; showdown(red,blue); }
-
Photon schrieb:
Also ich erzeuge für den Angreifer eine kopie damit der schaden nicht dauerhaft beeinflusst wird.
Guter, richtiger Gedanke. Allein das gesamte struct hero zu kopieren, ist aufwändiger, als über eine Referenz auf const nur lesend zuzugreifen. Siehe mein Beispiel.
Photon schrieb:
Ich habe mich die ganze zeit gefragt ob es gut ist eine funktion in einen funktion zu packen
Das ist absolut üblich. Komplexe Funktionen lassen sich so bequem aus einfachen anderen Funktionen zusammenbauen. Siehe z.B. mein showdown(): 3 Zeilen für einen Schlagabtausch von zwei Helden.
Photon schrieb:
Allerdings mag ich diese Assertmeldung nicht. Bzw. nich in diesem beispiel weil das ein hero in der rauen welt da draussen stribt ist eine zulässige aktion. Zumindest wenn es nach dem Universum geht.
Das assert() steht als erste Zeile in der Funktion. Ich will also nur verhindern, dass auf Tote eingeschlagen wird, bzw. das Tote noch angreifen.
Aha: ich sehe Du hast jetzt einen Kampf auf Leben und Tod daraus gemacht.Ich geh jetzt nochmal einen Schritt weiter.
Bisher istheroein POD - plain old data - sowas benutzt man schon seit 40 Jahren in C.C++ lässt mich zusätzlich zu Daten (name, hp, def, dmg) noch Methoden in ein struct einfügen.
Betrachte z.B. folgenden Code
#include <iostream> #include <string> struct hero { std::string name_; int hp_, dmg_, def_; // default constructor (ohne Parameter) hero() : name_("Unsung hero"), hp_(180), dmg_(80), def_(70) { /* body */ } // Ein Konstruktor mit Parametern hero(std::string name, int hp, int dmg, int def) : name_(name), hp_(hp), dmg_(dmg), def_(def) {} }; void print(const hero& h, std::ostream& out) { out << h.name_ << " (hp:" << h.hp_ << ", dmg:" << h.dmg_ << ", def:" << h.def_ << ')' << '\n'; } int main(){ using namespace std; hero h{"Parzival", 200, 100, 100}; print( h, cout ); hero hh; // default konstruierter Held print( hh, cout ); }Das sieht erstmal wild aus.
Ist allerdings im großen und ganzen unserstruct hero, wie vorher auch (ich habe nur die Daten member umbenannt z.B.name->name_)Diesmal hat hero allerdings 2 Konstruktoren. Konstruktoren sorgen dafür, dass Objekte der Klasse zu der sie gehören von Anfang an in einem definierten Zustand sind. Sieh Dir die Konstruktoren an (Zeilen 8-10 u. 12-14). Ist leicht einzusehen, was da passiert, oder?
In Zeile 24 benutze ich den Konstruktor, der Parameter entgegennimmt. In Zeile 27 benutze ich den ohne Parameter.
Beachte auch, dass jeder Konstruktor noch einen body hat - da könnte noch Code zwischen den geschweiften Klammern stehen - wie in einer Funktion.Fragen bis jetzt?
Schreib Dir vielleicht eine andere Klasse mit ein paar Membern. Schau, ob Du den Konstruktor implementiert bekommst.Das nächste Ziel heisst wohl Methoden - damit wird's richtig spannend.

-
Ok das mit dem kontruktor habe ich denke ich soweit verstanden. aber die printfunktion macht mir zu schaffen ich weiß nicht so genau was ostream da macht und meine nachforchung hat mit auch nicht schlauer gemacht.
So oder so werde ich morgen mal was kleines schreiben um das bisher gelernte anzuweden.

-
Photon schrieb:
aber die printfunktion macht mir zu schaffen ich weiß nicht so genau was ostream da macht und meine nachforchung hat mit auch nicht schlauer gemacht.
Das war eine kleine Gemeinheit, die ich eingebaut habe.
Schauen wir uns die mal an:void print(const hero&, std::ostream&);print()ist also eine Funktion, die nichts zurückgibt und zwei Parameter erwartet.
Der erste Parameter ist eine Referenz aufconst hero.
Der zweite Parameter ist eine Referenz aufstd::ostream.Dieser zweite Parameter gibt das "Ziel" für
print()vor.
std::ostreamist ein Typ aus der Standardbibliothek von C++. Dieser Typ stellt verschiedene Funktionen bereit um in einen Stream zu schreiben. Ein Stream bezeichnet in diesem Zusammenhang einen Strom von Zeichen.
std::coutist vom Typstd::ostreamund wird im Header<iostream>deklariert.
D.h.std::coutist ein vortreffliches Argument für den zweiten Parameter vonprint().
Aber auch jeder andere ostream geht, z.B. Schreiben in eine Datei:#include <iostream> #include <fstream> #include <string> struct hero { std::string name_; int hp_, dmg_, def_; hero() : name_("Unsung hero"), hp_(180), dmg_(80), def_(70) {} hero(std::string name, int hp, int dmg, int def) : name_(name), hp_(hp), dmg_(dmg), def_(def) {} }; void print(const hero& h, std::ostream& out) { out << h.name_ << " (hp:" << h.hp_ << ", dmg:" << h.dmg_ << ", def:" << h.def_ << ')' << '\n'; } int main(){ using namespace std; hero heroes[] = { {"Parzival", 200, 100, 100}, {"Bors", 205, 90, 100}, {"Lancelot", 190, 90, 90}, {}, }; ofstream file{"heroes.txt"}; // ein ofstream ist ein spezieller ostream if( !file ) return -1; // Datei konnte nicht geoeffnet werden for(const hero& h : heroes) print( h, file ); }Hausaufgabe: Schau Dir den Header
<iostream>Deiner Standardbibliothek an.
-
Hey,
ich sitze gerade an dem projekt und habe nun 2 kleine probleme
#include <iostream> struct pos{int x, y;}; struct creep {int hp; char pic;}; creep() : hp(30), pic('o') {} // Warum geht das nicht? ich bekomme fehler //error: expected unqualified-id before ')' token void print (const creep& cr){ std::cout << cr.hp << cr.pic << std::endl; } int main() { creep paul; print(paul); return 0; }Wenn ich jetzt noch pos in die sctruct creep argumente nehme:
#include <iostream> struct pos{int x, y;}; struct creep {pos p; int hp; char pic;}; creep() : pos(5,5) hp(30), pic('o') {} // Wie initialisiert man pos ? void print (const creep& cr){ std::cout << cr.p << cr.hp << cr.pic << std::endl; } int main() { creep paul; print(paul); return 0; }Desweiteren sieht der konstruktor mit werten für mich aus als ob man einfach das struct initialisiert bis auf den part in den geschweiften klammern also
creep paul={5,6,7};So wäre es ja ganz normal bei deinen konstruktor sieht es wie gesagt eigentlich genau so aus in der main ich verstehe nicht so wirklich denn sinn.
Grüße
Photon
-
Photon schrieb:
Hey,
ich sitze gerade an dem projekt und habe nun 2 kleine probleme
#include <iostream> struct pos{int x, y;}; struct creep {int hp; char pic;}; creep() : hp(30), pic('o') {} // Warum geht das nicht? ich bekomme fehler //error: expected unqualified-id before ')' token void print (const creep& cr){ std::cout << cr.hp << cr.pic << std::endl; }Der Konstruktor muss in die struct, vor dem };.
Wenn ich jetzt noch pos in die sctruct creep argumente nehme:
#include <iostream> struct pos{int x, y;}; struct creep {pos p; int hp; char pic;}; creep() : pos(5,5) hp(30), pic('o') {} // Wie initialisiert man pos ? void print (const creep& cr){ std::cout << cr.p << cr.hp << cr.pic << std::endl; } }Du kannst pos so initialisieren, wenn pos einen Konstruktor hat, der int, int nimmt.
Desweiteren sieht der konstruktor mit werten für mich aus als ob man einfach das struct initialisiert bis auf den part in den geschweiften klammern also
creep paul={5,6,7};So wäre es ja ganz normal bei deinen konstruktor sieht es wie gesagt eigentlich genau so aus in der main ich verstehe nicht so wirklich denn sinn.
Ja, so kann man auch initialisieren.
Aber wenn einige Elemente private sind, das heißt, man auf sie nicht zugreifen kann, geht das nicht.
Überhaupt ist man mit Konstruktoren viel flexibler (und btw: Seit C++11 ist das lediglich eine andere Syntax zum Konstruktoraufruf).
Aber ich rate dir wirklich, ein GUTES Lehrbuch zu C++(11) zu kaufen.
-
Jop danke nathan für die schnelle antwort
ich werde das mal mit den konstruktor bei pos. bekomme ich bestimmt hin.Ja ich war heut im laden und hab mir Primer c++ bestellt und es kommt morgen schon
leider die englische ausgabe aber das geht denke ich klar
-
Photon schrieb:
So wäre es ja ganz normal bei deinen konstruktor sieht es wie gesagt eigentlich genau so aus in der main ich verstehe nicht so wirklich denn sinn.
Ja. Anstatt einfacher Memberfunktionen ausgerechnet Konstruktoren für den Anfang zu wählen war wirklich nicht schlau von mir...

-
Ich hoffe übrigens, dass ich die Zeit bis zum Primer gut zu überbrücken geholfen habe.

Mir ist noch eine Nutzung von Konstruktoren eingefallen, die Dir ohne weiteren Stoff einleuchten wird. Die Benutzung des Bodies für über die Initialisierung hinausgehende Aktionen.
Siehe z.B. hier, wo Heroes sich in Burgen registrieren können:#include <iostream> #include <vector> #include <string> struct castle{ std::string name; std::vector<std::string> heroes; // Dies ist ein default constructor // Er kann prinzipiell ohne Parameter aufgerufen werden, // weil ich einen "Default Wert" bereitstelle castle(std::string name="Grayskull") : name(name) {} }; void enlist(const std::string& name, castle& c){ c.heroes.push_back(name); std::cout << name << " enlisted at castle " << c.name <<'\n'; } struct hero{ std::string name; hero() :name("Attila") { std::cout << name << " is a rogue hero!\n"; } hero(std::string name, castle& where) :name(name) { enlist(name, where); } }; void print(const castle& c, std::ostream& out){ switch(c.heroes.size()){ case 0: out << "No heroes enlisted at castle " << c.name << '\n'; break; case 1: out << "There is one hero enlisted at castle " << c.name << '\n'; break; default: out << "There are " << c.heroes.size() << " heroes enlisted at castle " << c.name << '\n'; } } int main(){ castle c; // default c'tor hero heroes[]={ {"Lancelot", c}, {"Parzival", c}, {} // default c'tor }; print( c, std::cout ); }
-
Ja das leuchtet ein man könnte auch weitere funktionen anheften damit direkt etwas mit dem hero passiert oder?
Jedenfall hier mal mein aktueller stand ich bin wieder etwas am hapern:
#include <iostream> #include <vector> struct pos{int x, y; //Speicher positionen für spielfeld pos(int y,int x) : y(y),x(x){} }; struct field { char map_[30][30]; std::vector<pos> cre; //Die Vektoren sind bisher noch überflüssig. std::vector<pos> twr; }; void draw_map(field& maze){ //Zeichnet das spielfeld. Gibt es etwas schnelleres als 2 schleifen? for(int y=0;y<30;y++){ for(int x=0;x<30;x++){ if (x==0 || x==29 || y==0 || y==29 ){maze.map_[y][x]='@';} else{if (maze.map_[x][y]!='O' || maze.map_[x][y] != 'X') maze.map_[y][x]= ' ';} std::cout << maze.map_[y][x]; } std::cout << "\n"; } } struct creep {pos p; int hp; char pic; //Ja die creeps creep() : p(15,15), hp(30), pic('O') {} }; void cr_move (creep& cr, field& fl){ //Hier liegt der fehler irgendwo cr.p.y+=5; fl.map_[cr.p.y][cr.p.x]='O'; fl.map_[cr.p.y-1][cr.p.x]=' '; draw_map(fl); } void cr_stats (const creep& cr){ std::cout << "<creep pos x: "<< cr.p.x << " pos y: " << cr.p.y << " hp: " << cr.hp << " pic: " << cr.pic << " >\n\n"; } struct creep_wave{std::vector<creep> wave;}; //Sowas in der art würde ich gerne benutzen. int main() { field lvl1; creep paul; draw_map(lvl1); cr_stats(paul); cr_move(paul,lvl1); cr_stats(paul); return 0; }Leider wird der creep nicht auf der map gedruckt

Teilweise bin ich noch etwas unsicher welche funktion in welche soll damit es übersichtlic bleibt. Auch habe ich das gefühl nicht alles sollte void und mit referenzübergabe sein aber es scheint am praktischsten für die bisher implementierten sachen.
Ja du hast mich stark motiviert und ich bekomme langsam eine vorstellung wie das alles funktioniert und warum. Danke nochmal

-
Ich glaube, die Bedingung in Zeile 18 ist verquer - die ODER Verknüpfung sollte wohl ein UND sein.
Ausserdem solltest Du map_ initialisieren:field() : map_{{0}}{} //initialisiert jeden char von map_ mit 0, doppelte Klammer muss bei Array-InitialisierungPhoton schrieb:
Teilweise bin ich noch etwas unsicher welche funktion in welche soll damit es übersichtlic bleibt. Auch habe ich das gefühl nicht alles sollte void und mit referenzübergabe sein aber es scheint am praktischsten für die bisher implementierten sachen.
Wow. Jetzt bin ich beeindruckt.
Das stimmt total und liegt - zumindest was den hinteren Teil anbelangt - daran, dass wir noch immer einen Mischmasch aus C und C++ benutzen.
Der vordere Teil ist Teil der Trennlinie zwischen guten und schlechten Entwicklern.
Also nochmal die Ohren gespitzt:
Wie schon gesagt lässt uns C++ neben Daten auch Methoden (member functions) in Klassen definieren.
Die Deklaration sieht aus wie immer, wird nur in die Klassendefinition gezogen.
In Methoden kann ich ohne weiteres auf weitere Member zugreifen.
Siehe z.B:#include <iostream> struct pos { int x, y; }; struct creep{ pos p; creep() : p{0,0} {} void move( pos newpos ) { p=newpos; } void print( std::ostream& out ) const { // const hier bedeutet: veraendert creep nicht out << "Creep @" << p.x << ' ' << p.y << '\n'; } }; int main(){ creep c; c.print( std::cout ); // Notation fuer Methodenaufruf - wie fuer alle member c.move( {1,2} ); c.print( std::cout ); }Wie Du siehst: viel übersichtlicher.
Aber achte auf const correctness: "read-only" Funktionen deklarierst Du alsconst! (Zeile 10)Photon schrieb:
Ja du hast mich stark motiviert und ich bekomme langsam eine vorstellung wie das alles funktioniert und warum. Danke nochmal

Fein!

PS: Sei nicht zu geizig mit vertikalem Platz z.B. Z. 18 bei Dir finde ich zu lang. Und wenn möglich nutz einen Editor, der Dir bei der Einrückung hilft.