Mit find Probleme [snake]
-
Hi,
ich habe ein Problem:
#include <cstdlib> #include <iostream> #include <conio.h> #include <windows.h> #include <list> #include <algorithm> #define RIGHT 1 #define LEFT 2 #define UP 3 #define DOWN 4 #define LAENGESNAKE 15 #define FELDGROESSE_Y 30 #define FELDGROESSE_X 20 using namespace std; //******** positionen schlange ******** struct s { int x; int y; }; //******** goto X and Y in Konsole ******** void gotoxy(int xpos, int ypos) { COORD scrn; HANDLE hOuput = GetStdHandle(STD_OUTPUT_HANDLE); scrn.X = xpos; scrn.Y = ypos; SetConsoleCursorPosition(hOuput,scrn); } void del(int px, int py) {gotoxy(py,px);cout<<" ";} void einf(int px, int py) {gotoxy(py,px);cout<<(char)219;} int main(int argc, char *argv[]) { int y = FELDGROESSE_Y, x = FELDGROESSE_X; int richtung = RIGHT; int punktX = x/2; int punktY = y/2; char c,d; bool exit = false; //******** ini schlange in list ******** list<s> snake; s schlange[LAENGESNAKE]; for(int i = 0; i < LAENGESNAKE; i++) { schlange[i].x= x/2; schlange[i].y= (y/2)-i; snake.push_front(schlange[i]); } //******** ini spielfeld ******** char feld[x][y]; feld[0][0] = 218; feld[0][y-1] = 191; feld[x-1][0] = 192; feld[x-1][y-1]= 217; for(int i = 1; i<(y-1);i++) { feld[0][i] = 196; feld[x-1][i] = 196; } for(int i =1; i<(x-1); i++) { for(int i1 = 1; i1<(y-1); i1++) { feld[i][i1] = ' '; } } for(int i = 1; i<(x-1); i++) { feld[i][0] = 179; feld[i][y-1] = 179; } //******** zeichne schlange in spielfeld ******** for(list<s>::iterator pos=snake.begin();pos!=snake.end();++pos) { s tmp; tmp = *pos; feld[tmp.x][tmp.y] = 219; } //******** zeichne spielfeld mit schlange ******** for(int i =0; i<(x); i++) { for(int i1 = 0; i1<(y); i1++) cout<<feld[i][i1]; cout<<endl; } while(!exit) { if(kbhit()) { d = getch(); if((int)d == 27)c = d; else c = getch(); switch(c) { case 77: if(richtung != LEFT) richtung = RIGHT; break; //rechts case 75: if(richtung != RIGHT) richtung = LEFT; break; //links case 72: if(richtung != DOWN) richtung = UP; break; //oben case 80: if(richtung != UP) richtung = DOWN; break; //unten case 27: exit = true; break; //exit } } Sleep(40); list<s>::iterator pos_first = snake.begin(); //Schwanzende list<s>::iterator pos_last = snake.end(); //Kopf s tmp; bool crossed = false; switch(richtung) { case RIGHT: tmp = *pos_first; snake.pop_front(); del(tmp.x,tmp.y); tmp = *--pos_last; if(tmp.y == y-2) tmp.y = 1; else tmp.y++; snake.push_back(tmp); einf(tmp.x,tmp.y); break; case LEFT: tmp = *pos_first; snake.pop_front(); del(tmp.x,tmp.y); tmp = *--pos_last; if(tmp.y == 1) tmp.y = y-2; else tmp.y--; snake.push_back(tmp); einf(tmp.x,tmp.y); break; case UP: tmp = *pos_first; snake.pop_front(); del(tmp.x,tmp.y); tmp = *--pos_last; if(tmp.x == 1) tmp.x = x-2; else tmp.x--; snake.push_back(tmp); einf(tmp.x,tmp.y); break; case DOWN: tmp = *pos_first; snake.pop_front(); del(tmp.x,tmp.y); tmp = *--pos_last; if(tmp.x == x-2) tmp.x = 1; else tmp.x++; snake.push_back(tmp); einf(tmp.x,tmp.y); break; case 27: exit=true;break; } //cout<<count(snake.begin(), snake.end(), tmp); list<s>::iterator it = find(snake.begin(), snake.end(), tmp); //<-- HIER FEHLERMELDUNG /* int z; for(list<s>::iterator pos=snake.begin();pos!=snake.end();++pos) { s vergleich = *pos; z++; if(vergleich.x == tmp.x && vergleich.y == tmp.y && z < LAENGESNAKE-2) { crossed = true; gotoxy(5, 5); cout<<"LOST"; } } */ } return EXIT_SUCCESS; }Mein kleines snake programm in den anfängen, nun möchte ich mit find irgendwie prüfen ob die nächste xy koord nicht in die schlange selbst "beißt" und dann das Programm quasi beenden... aber beim kompilieren bringt er mir einen Fehler und springt in die stl_algo.h rein.

C:\Dev-Cpp\include\c++\3.4.2\bits\stl_algo.h In function `_InputIterator std::find(_InputIterator, _InputIterator, const _Tp&, std::input_iterator_tag) [with _InputIterator = std::_List_iterator<s>, _Tp = s]':
314 C:\Dev-Cpp\include\c++\3.4.2\bits\stl_algo.h instantiated from `_InputIterator std::find(_InputIterator, _InputIterator, const _Tp&) [with _InputIterator = std::_List_iterator<s>, _Tp = s]'
Könnte mir wer weiterhelfen, oder einen Anhaltspunkt geben?
MfG Gustl
-
Bitte die ganze Fehlermeldung, und die in code-tags.
So bringt das recht wenig, man sieht ja nur woe in den std-lib-headern ein Fehler auftritt, aber nicht wo indeinem Source, oder (wichtiger) welcher Fehler.
-
C:\Dev-Cpp\include\c++\3.4.2\bits\stl_algo.h In function `_InputIterator std::find(_InputIterator, _InputIterator, const _Tp&, std::input_iterator_tag) [with _InputIterator = std::_List_iterator<s>, _Tp = s]': 314 C:\Dev-Cpp\include\c++\3.4.2\bits\stl_algo.h instantiated from `_InputIterator std::find(_InputIterator, _InputIterator, const _Tp&) [with _InputIterator = std::_List_iterator<s>, _Tp = s]' 167 F:\Programmieren\Konsolenprog\snake2\main.cpp instantiated from here 172 C:\Dev-Cpp\include\c++\3.4.2\bits\stl_algo.h no match for 'operator==' in '(&__first)->std::_List_iterator<_Tp>::operator* [with _Tp = s]() == __val' note C:\Dev-Cpp\include\objbase.h:80 candidates are: BOOL operator==(const GUID&, const GUID&) F:\Programmieren\Konsolenprog\snake2\Makefile.win [Build Error] [main.o] Error 1Hoffe man erkennt etwas.
-
Les dir die Fehlermeldung durch und du solltest wissen was fehlt.
TIP:
std::find muss vergleichen. Dies geschieht mit dem operator==, damit eben sowas wieif( lVal == rVal ) //...möglich ist.
Und die Frage: Gibt es für dein "struct s" diesen? (Ist übrigens ein wirklich schrecklich nichtssagender Name...)
-
Du benötigst für deine Struktur 's' (besser wäre wohl ein aussagekräftigerer Name!) noch den Vergleichsoperator '=='.
Edit: und die Aufteilung deiner main-Funktion in einzelne Unterfunktionen bzw. einer eigenen Klasse wäre auch nicht schlecht...
-
Th69 schrieb:
Edit: und die Aufteilung deiner main-Funktion in einzelne Unterfunktionen bzw. einer eigenen Klasse wäre auch nicht schlecht...
Ganz zu schweigen davon dass #defines in C++ einfach bäh sind, dass dein
char feld[x][y];kein gültiges C++ ist (Die Arraygrößen müssen Compilezeit-Konstanten sein) und bei dem Code-Wust auch du selbst in absehbarer Zeit nichtmehr durchblicken wirst.
-
ja, operator overload... klasse, danke.
Macht mich doch nicht so fertig, ich war eigentlich schon der Meinung das des ganze Programm recht übersichtlich und ganz ok ist....

pumuckl schrieb:
Th69 schrieb:
Edit: und die Aufteilung deiner main-Funktion in einzelne Unterfunktionen bzw. einer eigenen Klasse wäre auch nicht schlecht...
Ganz zu schweigen davon dass #defines in C++ einfach bäh sind, dass dein
char feld[x][y];kein gültiges C++ ist (Die Arraygrößen müssen Compilezeit-Konstanten sein) und bei dem Code-Wust auch du selbst in absehbarer Zeit nichtmehr durchblicken wirst.Dann wäre wohl hier die bessere wahl mit const?
Th69 schrieb:
Du benötigst für deine Struktur 's' (besser wäre wohl ein aussagekräftigerer Name!) noch den Vergleichsoperator '=='.
Edit: und die Aufteilung deiner main-Funktion in einzelne Unterfunktionen bzw. einer eigenen Klasse wäre auch nicht schlecht...
Ich wollte jetzt eigentlich nur erstmal die Schlange mit obst (fressen) zum laufen bringen.
Und dann das ganze in Klassen aufteilen.
Da ja s die einzige Struktur ist, dachte ich mir das es egal ist.Aber danke euch, werd jetzt mal den operator == überladen und dann gehts bestimmt:) THX
MfG Gustl
-
Gustl schrieb:
Macht mich doch nicht so fertig, ich war eigentlich schon der Meinung das des ganze Programm recht übersichtlich und ganz ok ist....

Das war noch kein "Fertigmachen", sowas sieht hier im Forum anders aus

Du hast ja schon die ersten Unterteilungen mit deinen Kommentaren gemacht. Zieh das durch und mach es mit Funktionen. Die ganze Initialisierung z.B. könnte eine Funktion sein und direkt die main() entrümpeln.
Auch die Schleife würde sinnvollerweise in eine eigene Funktion kommen und dann nur noch in der main() mit StartGameLoop() o.ä. gestartet werden.
Du siehst bestimmt noch andere Stellen, wo du was sauberer strukturieren könntest (neben den Umbenennung der struct, die ja echt nichtssagend klingt).
-
Ich versuch dir mal einen ersten Schritt zu zeigen wie man das angehen könnte:
#include <cstdlib> #include <iostream> #include <conio.h> #include <windows.h> #include <list> #include <algorithm> enum Direction { RIGHT, LEFT, UP, DOWN }; //******** positionen schlange ******** struct Position { int x; int y; }; class Konsole { char fill; public: Konsole : fill(219) {} //kann man später evtl. als Parameter machen //******** goto X and Y in Konsole ******** void gotoxy(Position pos) { COORD scrn; HANDLE hOuput = GetStdHandle(STD_OUTPUT_HANDLE); scrn.X = pos.x; scrn.Y = pos.y; SetConsoleCursorPosition(hOuput,scrn); } void del(Position pos) { gotoxy(pos);cout<<" "; } void einf(Position pos) { gotoxy(pos);cout<<fill; } }; class Schlange { const static std::size_t LAENGESNAKE = 15; std::list<Position> snake; public: Schlange() { //******** ini schlange in list ******** Position p = Feld::mitte(); for(int i = 0; i < LAENGESNAKE; ++i) { snake.push_front(p); p.y -= 1; } } }; class Feld { static const std::size_t FELDGROESSE_X = 20; static const std::size_t FELDGROESSE_Y = 30; static const char TopLeft = 218; static const char BottomLeft = 191; static const char TopRight = 192; static const char BottomRight = 217; static const char Horizontal = 196; static const char Vertical = 218; static const char Blank = ' '; char feld[FELDGROESSE_X][FELDGROESSE_Y]; public: Feld() { //******** ini spielfeld ******** feld[0][0] =TopLeft; feld[0][FELDGROESSE_Y-1] = BottomLeft; feld[FELDGROESSE_X-1][0] = TopRight; feld[FELDGROESSE_x-1][FELDGROESSE_y-1]= BottomRight; for(int i = 1; i<(FELDGROESSE_Y-1); ++i) { feld[0][i] = Horizontal; feld[FELDGROESSE_X-1][i] = Horizontal; } for(int i =1; i<(FELDGROESSE_X-1); ++i) { for(int i1 = 1; i1<(FELDGROESSE_Y-1); ++i1) { feld[i][i1] = Blank; } } for(int i = 1; i<(FELDGROESSE_X-1); ++i) { feld[i][0] = Vertikal; feld[i][FELDGROESSE_Y-1] = Vertikal; } } static Position mitte() { Position dieMitte; dieMitte.x = FELDGROESSE_X/2; dieMitte.y = FELDGROESSE_Y/2; return dieMitte; } }; int main(int argc, char *argv[]) { Direction richtung = RIGHT; char c,d; bool exit = false; Schlange schlange; Feld feld; schlange.zeichneInFeld(feld); feld.zeicheInKonsole(); //usw. }Versuch einfach in kleinen Schritten (viel kleiner als ich das da angedeutet hab) die einzelnen Funktionalitäten aus deiner Mainfunktion rauszuziehen und in Funktionen und Klassen wegzukapseln. Wenn du die dann noch gut benennst liest sich die Mainfunktion dann ganz ohne Kommentare sehr einfach.
-
Ist schon richtig klasse wie du dir so einen (für mich) sauberen code einfach so aus den fingern ziehst.

Dank dir, liest sich sehr schön. Aber so ähnlich wollte ich das dann später auch machen, also mit Funktionen, damit eben nur Funktionen von den Klassen in der main stehen.
Werde aber auch versuchen etwas von deinem Vorschlag mit einzubaun, und den code auch weiter so versuchen zu schreiben.

Dickes THX!
MfG Gustl
EDIT: Eine kleine Frage noch, bezüglich Pumuckls Code:
Wozu std::size_t ? und nicht unsigned int? wäre doch das gleiche oder?
Hab gelesen das man size_t in bezug auf speichergrößen verwendet...
-
Gustl schrieb:
Ist schon richtig klasse wie du dir so einen (für mich) sauberen code einfach so aus den fingern ziehst.

Ist wie gesagt nur ein erster Schritt, da kann noch einiges dran verbessert werden. Aber eben Schritt für Schritt

so ähnlich wollte ich das dann später
Später ist nie. Weißt ja wie das mit guten Vorsätzen ist. Kennst du die "kaputte Fenster"-Theorie? Wenn irgendwo ein fenster kaputt ist dauerts nicht lang bis dienächsten zu Bruch gehen. So ähnlich isses mit Code: wenn der unordentlich und unübersichtlich ist, hat neuer Code kaum Chancen übersichtlicher zu werden. Deshalb lieber gleich übersichtlich anfangen und gleich aufräumen wenn man etwas sieht was aufgeräumt werden sollte.
-
So, habe es nun probiert mit Klasse einigermaßen zu ordnen... auf Verbesserungsvorschläge würde ich mich sehr freuen.
Zudem will ich noch beim erstellen vom Projekt feld die größe x und y per konstruktor übergeben, aber da ja char[feldgroesse][feldgroesse] private ist, braucht er da wohl einen Wert... und ich weiß nicht so genau wie ich das realisieren soll... genau das gleiche mit snakelaenge.
Hier der COde:
main.cpp
//--------------------------------------------------------------------------- #pragma argsused #include "game.h" #include "feld.h" #include "schlange.h" #include "konsole.h" int main(int argc, char *argv[]) { //unsigned int FELDGROESSE_X = 20; //unsigned int FELDGROESSE_Y = 30; Feld feld; Schlange schlange; Game game; feld.printEmptyFeld(); schlange.print(); game.start(); system("PAUSE"); return 0; } //---------------------------------------------------------------------------feld.h
//--------------------------------------------------------------------------- #ifndef feldH #define feldH #include <iostream> struct Position { int x; int y; }; class Feld { protected: static const unsigned int FELDGROESSE_X = 20; static const unsigned int FELDGROESSE_Y = 30; private: static const char TopLeft = 218; static const char BottomLeft = 191; static const char TopRight = 192; static const char BottomRight = 217; static const char Horizontal = 196; static const char Vertical = 218; static const char Blank = ' '; char feld[FELDGROESSE_X][FELDGROESSE_Y]; public: Feld(); static Position mitte(); void printEmptyFeld(); }; //--------------------------------------------------------------------------- #endiffeld.cpp
//--------------------------------------------------------------------------- #pragma hdrstop #include "feld.h" Feld::Feld() { feld[0][0] = TopLeft; feld[0][FELDGROESSE_Y-1] = BottomLeft; feld[FELDGROESSE_X-1][0] = TopRight; feld[FELDGROESSE_X-1][FELDGROESSE_Y-1] = BottomRight ; for(int i = 1; i<(FELDGROESSE_Y-1);i++) { feld[0][i] = 196; feld[FELDGROESSE_X-1][i] = 196; } for(int i =1; i<(FELDGROESSE_X-1); i++) { for(int i1 = 1; i1<(FELDGROESSE_Y-1); i1++) { feld[i][i1] = ' '; } } for(int i = 1; i<(FELDGROESSE_X-1); i++) { feld[i][0] = 179; feld[i][FELDGROESSE_Y-1] = 179; } } Position Feld::mitte() { Position dieMitte; dieMitte.x = FELDGROESSE_X/2; dieMitte.y = FELDGROESSE_Y/2; return dieMitte; } void Feld::printEmptyFeld() { for(int i =0; i<(FELDGROESSE_X); i++) { for(int i1 = 0; i1<(FELDGROESSE_Y); i1++) std::cout<<feld[i][i1]; std::cout<<std::endl; } } //--------------------------------------------------------------------------- #pragma package(smart_init)schlange.h
//--------------------------------------------------------------------------- #ifndef schlangeH #define schlangeH #include <list> #include "konsole.h" class Schlange : public Konsole { const static std::size_t LAENGESNAKE = 6; protected: std::list<Position> snake; public: Schlange(); void print(); }; //--------------------------------------------------------------------------- #endifschlange.cpp
//--------------------------------------------------------------------------- #pragma hdrstop #include "schlange.h" Schlange::Schlange() { Position p = Feld::mitte(); for(int i = 0; i < LAENGESNAKE; ++i) { snake.push_front(p); p.y -= 1; } } void Schlange::print() { for(std::list<Position>::iterator pos=snake.begin();pos!=snake.end();++pos) { Position tmp; tmp = *pos; einf(tmp); } } //--------------------------------------------------------------------------- #pragma package(smart_init)konsole.h
//--------------------------------------------------------------------------- #ifndef konsoleH #define konsoleH #include <windows.h> #include <iostream> #include "feld.h" class Konsole : public Feld { public: Konsole(); void gotoxy(Position pos); void del(Position pos); void einf(Position pos); }; //--------------------------------------------------------------------------- #endifkonsole.cpp
//--------------------------------------------------------------------------- #pragma hdrstop #include "konsole.h" Konsole::Konsole(){} void Konsole::gotoxy(Position pos) { COORD scrn; HANDLE hOuput = GetStdHandle(STD_OUTPUT_HANDLE); scrn.Y = pos.x; scrn.X = pos.y; SetConsoleCursorPosition(hOuput,scrn); } void Konsole::del(Position pos) { gotoxy(pos);std::cout<<" "; } void Konsole::einf(Position pos) { gotoxy(pos);std::cout<<(char)219; } //--------------------------------------------------------------------------- #pragma package(smart_init)game.h
//--------------------------------------------------------------------------- #ifndef gameH #define gameH #include "schlange.h" #include <conio.h> class Game : public Schlange { static const int RIGHT = 1; static const int LEFT = 2; static const int UP = 3; static const int DOWN = 4; int richtung; char d,c; bool exit; public: Game(); void start(); }; //--------------------------------------------------------------------------- #endifgame.cpp
//--------------------------------------------------------------------------- #pragma hdrstop #include "game.h" Game::Game() { richtung = RIGHT; exit = false; } void Game::start() { while(!exit) { if(kbhit()) { d = getch(); if((int)d == 27)c = d; else c = getch(); switch(c) { case 77: if(richtung != LEFT) richtung = RIGHT; break; //rechts case 75: if(richtung != RIGHT) richtung = LEFT; break; //links case 72: if(richtung != DOWN) richtung = UP; break; //oben case 80: if(richtung != UP) richtung = DOWN; break; //unten case 27: exit = true; break; //exit } } Sleep(40); std::list<Position>::iterator pos_first = snake.begin(); //Schwanzende std::list<Position>::iterator pos_last = snake.end(); //Kopf Position tmp; switch(richtung) { case RIGHT: tmp = *pos_first; snake.pop_front(); del(tmp); tmp = *--pos_last; if(tmp.y == FELDGROESSE_Y-2) tmp.y = 1; else tmp.y++; snake.push_back(tmp); einf(tmp); break; case LEFT: tmp = *pos_first; snake.pop_front(); del(tmp); tmp = *--pos_last; if(tmp.y == 1) tmp.y = FELDGROESSE_Y-2; else tmp.y--; snake.push_back(tmp); einf(tmp); break; case UP: tmp = *pos_first; snake.pop_front(); del(tmp); tmp = *--pos_last; if(tmp.x == 1) tmp.x = FELDGROESSE_X-2; else tmp.x--; snake.push_back(tmp); einf(tmp); break; case DOWN: tmp = *pos_first; snake.pop_front(); del(tmp); tmp = *--pos_last; if(tmp.x == FELDGROESSE_X-2) tmp.x = 1; else tmp.x++; snake.push_back(tmp); einf(tmp); break; case 27: exit=true;break; } } } //--------------------------------------------------------------------------- #pragma package(smart_init)Mit den Vererbungen hatte ich bisher noch nicht viel zu tun.
MfG Gustl
-
Gustl schrieb:
Mit den Vererbungen hatte ich bisher noch nicht viel zu tun.
Sieht man
du vererbst krampfhaft wo es nichts zu vererben gibt. Vererben bedeutet eine "ist ein"-Beziehung. Mit deinen Vererbungen sagst du "ein Spiel ist eine Schlange", "eine Schlange ist eine Konsole" und "eine Konsole ist ein Feld" - stimmt irgendwie alles nicht so recht
Lass die Vererbung einfach weg.
Was die Länge der Schlange angeht: die kannst du einfach als Parameter im Konstruktor übergeben, natürlich darf die Variable dann nicht mehr static sein. Mit dem Feld ists dann ein wenig komplizierter, dafür müsstest du dir mal zweidimensionale dynamische Arrays oder Container wie z.B. std::vector anschauen.
-
Aber wenn ich die Vererbungen ganz weg lasse müsste ich ein Objekt in manchen klassen definieren, da ich ja manche Funktionen aus anderen Klassen benötige, darf man das?
Stimmt, das mit der Snakelänge wäre als übergabeparameter einfach, nur das feld... ok, werde mich mal stärker mit der dynamischen anlegeung von Arrays auseinandersetzen.
Danke.
Vielleicht fällt ja den ein oder anderen noch etwas schwerwiegendes auf was man verbessern könnte?
MfG Gustl
-
Gustl schrieb:
Aber wenn ich die Vererbungen ganz weg lasse müsste ich ein Objekt in manchen klassen definieren, da ich ja manche Funktionen aus anderen Klassen benötige, darf man das?
Natürlich. Du kannst ein Objekt als Mitglied einer anderen Klasse definieren. Das wird auch Komposition genannt. Wenn die Vererbung eine "ist ein" Beziehung ist, ist die Komposition die "besteht aus" Beziehung.
Was mir noch auffällt ist: in einem deiner switches sind ziemlich viele magic numbers, also Zahlen deren Bedeutung man sich zusammenreimen muss. Vielleicht durch Konstanten ersetzen?
-
Gustl schrieb:
Aber wenn ich die Vererbungen ganz weg lasse müsste ich ein Objekt in manchen klassen definieren, da ich ja manche Funktionen aus anderen Klassen benötige, darf man das?
Nein brauchst du auch nicht unbedingt. Wenn du die Schlange beispielsweise in das Feld zeichnest, musst du dafür öffentliche Methoden des Feldes benutzen. Um zu wissen, in welches Feld du sie zeichnest, gibst du der zeichnen-Methode einen Parameter mit, nämlich eine Referenz auf das Feld. In meinem Beispiel hatte ich das auch schon so angedeutet.
Ich würds vermutlich so machen dass ich in main() nur das Game erzeuge und die Schlange und das Feld Member vom Game sind. Die Konsole wrd ich privat erzeugen und dem Game eine Referenz darauf mitgeben.
-
Ok, alles klar, super wenn man objekte auch in klassen definieren darf (dachte immer das wird nicht gern gesehn).
Dann werde ich das dann so ähnlich machen, vielleicht auch mit referenzübergaben, schau ma mal.
Aber jetzt ist es denk ich viiiiel einfacher, als mit den vererbungen... da bin ich gestern fast verzweifelt.

Wenn ich dann schlange, feld... in game erzeuge steht ja fast nix mehr in der main.

Wenn das ganze dann soweit fertig ist, möchte ich noch ein menü hinzufügen... würdet ihr da auch eine eigene klasse eröffnen?
danke.
MfG Gustl
-
Gustl schrieb:
Wenn ich dann schlange, feld... in game erzeuge steht ja fast nix mehr in der main.

Das ist toll! Ein typisches C++ Programm hat ne main <10 Zeilen! Zumindest sollte es das haben, wenn man alles richtig macht :).
Wenn das ganze dann soweit fertig ist, möchte ich noch ein menü hinzufügen... würdet ihr da auch eine eigene klasse eröffnen?
Es kommt drauf an, was das Menü leisten soll. Oft reichen auch einfach ein Paar geschickt verschachtelte Funktionen aus. Wenn du zum Beispiel immer Textmenüs hast, wo der Benutzer mit den Pfeiltasten und Enter Sachen auswählt, dann wäre für diese Funktionalität eine Klasse sinnvoll. In den Objekten speicherst du dann die Menüoptionen und was der Benutzer ausgewählt hat.
-
Hallo nochmal, habe versucht eure Ratschläge umzusetzten, aber leider finde ich den code jetzt doch sehr unübersichtlich.
Die schlage frisst jetzt auch und wächst, level und speed habe ich auch mit integriert. hat alles soweit gepasst.
Nun wollte ich das Feld noch dynamisch machen...
Und das objekt feld(50,60); zB. dann als referenz an game übergeben. das funktioniert auch, aber die Schlange reizt das feld nicht aus, bzw. nur das alte, das im defaultkonstruktor auch drin ist.Vielleicht hat ja einer lust sich durch den code zu wühlen und könnte mir sagen wo mein Fehler ist, bzw. einen ansatz... ich denke das die zeiger schuld sind in der game.cpp bzw. game.h.
Hier der Code: (Konsole lasse ich mal weg...)
main.cpp//--------------------------------------------------------------------------- #pragma hdrstop //--------------------------------------------------------------------------- #pragma argsused #include "game.h" #include "feld.h" #include "konsole.h" int main(int argc, char *argv[]) { Feld feld(50,60); Game game(feld); feld.printEmptyFeld(); game.start(); return 0; }feld.h
#ifndef feldH #define feldH #include <iostream> #include <vector> using namespace std; struct Position { int x; int y; bool operator==(const Position &pos) { if(this -> x == pos.x && this -> y == pos.y) return true; else return false; } }; class Feld { int feldX; int feldY; char **feld; private: static const char TopLeft = 218; static const char BottomLeft = 191; static const char TopRight = 192; static const char BottomRight = 217; static const char Horizontal = 196; static const char Vertical = 218; static const char Blank = ' '; //char feld[FELDGROESSE_X][FELDGROESSE_Y]; public: Feld(int x = 20, int y = 30); ~Feld(); Position mitte(); void printEmptyFeld(); int getfeld_x(); int getfeld_y(); }; #endiffeld.cpp
#pragma hdrstop #include "feld.h" Feld::Feld(int x, int y) { feldX = x; feldY = y; feld = new char*[x]; for (int i = 0; i < x; ++i) *(feld+i) = new char[y]; feld[0][0] = TopLeft; feld[0][feldY-1] = BottomLeft; feld[feldX-1][0] = TopRight; feld[feldX-1][feldY-1] = BottomRight; for(int i = 1; i<(feldY-1);i++) { feld[0][i] = 196; feld[feldX-1][i] = 196; } for(int i =1; i<(feldX-1); i++) { for(int i1 = 1; i1<(feldY-1); i1++) { feld[i][i1] = ' '; } } for(int i = 1; i<(feldX-1); i++) { feld[i][0] = 179; feld[i][feldY-1] = 179; } } Position Feld::mitte() { Position dieMitte; dieMitte.x = feldX/2; dieMitte.y = feldY/2; return dieMitte; } Feld::~Feld() { for (int i = 0; i < feldX; i++) delete [] feld[i]; delete [] feld; } void Feld::printEmptyFeld() { for(int i =0; i<(feldX); i++) { for(int i1 = 0; i1<(feldY); i1++) cout<<feld[i][i1]; cout<<endl; } } int Feld::getfeld_x() { return feldX; } int Feld::getfeld_y() { return feldY; } //--------------------------------------------------------------------------- #pragma package(smart_init)game.h
//--------------------------------------------------------------------------- #ifndef gameH #define gameH #include "schlange.h" #include "feld.h" #include "konsole.h" #include <conio.h> #include <algorithm> class Game { static const int RIGHT = 1; static const int LEFT = 2; static const int UP = 3; static const int DOWN = 4; int richtung; char d,c; bool exit; bool crossed; unsigned int level, speed, punkte; Position food; int zaehler_food; Feld *p_feld; Schlange *p_schlange; Konsole konsole; public: Game(Feld &feld); void start(); void createFood(); void showPunkte(); void showLevel(); }; //--------------------------------------------------------------------------- #endifgame.cpp
//--------------------------------------------------------------------------- #pragma hdrstop #include "game.h" Game::Game(Feld &feld) { richtung = RIGHT; exit = false; crossed = false; level = 1; punkte = 0; speed = 80; zaehler_food = 0; p_feld = &feld; Schlange schlange(feld); p_schlange = &schlange; } void Game::start() { p_schlange->print(); createFood(); showPunkte(); showLevel(); while(!exit) { if(kbhit()) { d = getch(); if((int)d == 27)c = d; else c = getch(); switch(c) { case 77: if(richtung != LEFT) richtung = RIGHT; break; //rechts case 75: if(richtung != RIGHT) richtung = LEFT; break; //links case 72: if(richtung != DOWN) richtung = UP; break; //oben case 80: if(richtung != UP) richtung = DOWN; break; //unten case 27: exit = true; break; //exit } } Sleep(speed); if(!p_schlange->move(richtung))crossed = true; if(!p_schlange->findPosition_inSnake(food)) { punkte += 20; createFood(); showPunkte(); p_schlange->grow(); if(++zaehler_food == 8) { zaehler_food = 0; level++; speed -= 18; showLevel(); } } if(crossed == true) { Position over; over.x = p_feld->getfeld_x() +2; over.y = p_feld->getfeld_x()/2; konsole.gotoxy(over);std::cout<<"GAME OVER!"; cin.get(); exit = true; } } } //create food als 'X' ins Feld void Game::createFood() { srand(time(NULL)); Position random; random.x = rand() % p_feld->getfeld_x(); random.y = rand() % p_feld->getfeld_y(); while(!p_schlange->findPosition_inSnake(random) || random.x == p_feld->getfeld_x()-1 || random.x == 0 || random.y == p_feld->getfeld_y()-1 || random.y == 0) { random.x = rand() % p_feld->getfeld_x(); random.y = rand() % p_feld->getfeld_y(); } food = random; konsole.gotoxy(random);std::cout<<"X"; } void Game::showPunkte() { Position Ausgabe; Ausgabe.x = p_feld->getfeld_x(); Ausgabe.y = 1; konsole.gotoxy(Ausgabe);std::cout<<"Punkte: "<<punkte; } void Game::showLevel() { Position Ausgabe; Ausgabe.x = p_feld->getfeld_x(); Ausgabe.y = p_feld->getfeld_y()-9; konsole.gotoxy(Ausgabe);std::cout<<"Level: "<<level; } //--------------------------------------------------------------------------- #pragma package(smart_init)schlange.h
//--------------------------------------------------------------------------- #ifndef schlangeH #define schlangeH #include <list> #include "konsole.h" class Schlange { static const int RIGHT = 1; static const int LEFT = 2; static const int UP = 3; static const int DOWN = 4; const static std::size_t LAENGESNAKE = 6; Konsole konsole; Position growPos; Feld *p_feld; protected: std::list<Position> snake; std::list<Position>::iterator pos_first; std::list<Position>::iterator pos_last; std::list<Position>::iterator it; public: Schlange(Feld &feld); void print(); void popFront(); bool findPosition_inSnake(Position &p); bool move(int richtung); void grow(); }; //--------------------------------------------------------------------------- #endifschlange.cpp
//--------------------------------------------------------------------------- #pragma hdrstop #include "schlange.h" //ini Schlange in list Schlange::Schlange(Feld &feld) { p_feld = &feld; Position p = p_feld->mitte(); for(int i = 0; i < LAENGESNAKE; ++i) { snake.push_front(p); p.y -= 1; } } //zeichen schlange konsole void Schlange::print() { for(std::list<Position>::iterator pos=snake.begin();pos!=snake.end();++pos) { Position tmp; tmp = *pos; konsole.einf(tmp); } } //lösche letztes schwanzstück von schlange void Schlange::popFront() { Position first = *pos_first; growPos = *pos_first; //merke pos, falls sie wachsen soll snake.pop_front(); konsole.del(first); } //überprüfe ob schlange sich selbst frisst bool Schlange::findPosition_inSnake(Position &p) { it = find(snake.begin(), snake.end(), p); if(*it==p) return false; else return true; } //lasse schlange wachsen void Schlange::grow() { snake.push_front(growPos); konsole.einf(growPos); } bool Schlange::move(int richtung) { pos_first = snake.begin(); //Schwanzende pos_last = snake.end(); //Kopf popFront(); Position last = *--pos_last; switch(richtung) { case RIGHT: if(last.y == p_feld->getfeld_y()-2) last.y = 1; else last.y++; break; case LEFT: if(last.y == 1) last.y = p_feld->getfeld_y()-2; else last.y--; break; case UP: if(last.x == 1) last.x = p_feld->getfeld_x()-2; else last.x--; break; case DOWN: if(last.x == p_feld->getfeld_x()-2) last.x = 1; else last.x++; break; } it = find(snake.begin(), snake.end(), last); if(*it==last) return false; else { snake.push_back(last); konsole.einf(last); return true; } } //--------------------------------------------------------------------------- #pragma package(smart_init)
MfG Gustl
-
game.cpp:
Game::Game(Feld &feld) { ... Schlange schlange(feld); p_schlange = &schlange; }Was passiert hier? Ein lokales Objekt schlange wird erzeugt. Ein Zeiger auf dieses Objekt wird im Gameobjekt gespeichert. Der Konstruktor wird beendet und das schlange-Objekt natülich zerstört. Der im Gameobjekt gespeicherte Zeiger ist damit ungültig, dass danach alle möglichen bösen Dinge passieren können, ist klar.
Also etwaGame::Game(Feld &feld) { ... p_schlange = new Schlange(feld);und dann im Destruktor zerstören. Sinnvoller ist es aber, Schlange (und eigentlich auch Feld) als Member von Game zu gestalten und dort nicht nur Zeiger zu speichern.
Ungefähr soclass Game { ... Feld feld; Schlange schlange; ... Game(int x, int y); ... }; Game::Game(int x, int y) : richtung(RIGHT),exit(false),crossed(false),level(1),punkte(0),speed(80),zaehler_food(0), feld(x,y), schlange(feld) { feld.printEmptyFeld(); }P.S. Das Ganze nur überflogen, ob es dein Problem löst, ist damit nicht garantiert.
int main() { Game game(50,60); game.start(); return 0; }nur noch 3 Zeilen. toll.
-
Doch bestimmt ist das mein Problem, ich sah den Wald vor lauter Bäume wohl nicht..
is ja klar das das objekt gelöscht wird...Dank dir.
Aber wie übergeb ich nun die x und y parameter von game an dem objekt feld in der game klasse?
Das mit der Initialisierungsliste ist auch ne gute idee.
Edit: ach dann übergebe ich einfach die zwei int werte der printempty funktion und erstelle dort das feld.