Mit find Probleme [snake]
-
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.