Matrix operation
-
SeppJ schrieb:
class Matrix { std::size_t num_lines, num_rows; std::vector<short> data; public: Matrix(std::size_t lines, std::size_t rows): num_lines(lines), num_rows(rows), data(num_lines*num_rows) { } short operator()(std::size_t x, std::size_t y) const { return data[x*num_rows + y]; } short& operator()(std::size_t x, std::size_t y) { return data[x*num_rows + y]; } };
Zum Sortieren schreibst du dir einen Zeilen- oder Spalteniterator (je nachdem, was du sortieren möchtest) und wirfst das deiner Lieblingssortierfunktion (hoffentlich std::sort) vor.
Vielen Dank, werde das mal testen. Dynamisch soll die Matrix nur in dem Umfang sein, dass sie einmalig mit einer zum Programmstart noch unbekannten Zeilen/Spalten Anzahl erstellt wird.
Die Sortierung kann ich leider nicht auf std::sort abschieben Das ist nämlich der Knackpunkt der ganzen Sache.
Die bisherige Klasse sieht momentan noch ziemlich dünn aus:class Block { private: short Zeilen; short Spalten; short Bloecke; short** Aktuell; //Aktuelle Matrix short** Ziel; //Ziel Matrix short Right_Block, False_Block, Right_Column, Amount_false_Blocks; void create_matrix(short** Matrix){ int i=0; Matrix=new short* [Spalten]; //for (i = 0; i < Spalten; i++) //alternativ als for schleife // Matrix[i] = new int[Zeilen]; while (i<Spalten){ Matrix[i]=new short[Zeilen]; i++; } } void clear_matrix(short** Matrix){ short i=0,j; while (i<Spalten){ j=0; while (j<Zeilen){ Matrix[i][j]=0; j++; } i++; } } void generate_matrix(short **Matrix){ //hier soll aus den spalten/zeilen/blöcken eine mögliche blockkombination erstellt werden } public: Block (short init_Zeilen,short init_Spalten,short init_Bloecke){ //konstruktor if (init_Spalten > 2) Spalten=init_Spalten; else Spalten=3; if (init_Zeilen > 1) Zeilen=init_Zeilen; else Zeilen=3; if (init_Bloecke > 1 && init_Bloecke < Spalten*Zeilen) Bloecke=init_Bloecke; else Bloecke=4; } ~Block(){ //Destruktor delete Aktuell; delete Ziel; } bool set_target_matrix(){ create_matrix(Ziel); clear_matrix(Ziel); //generate_matrix(Ziel); Ziel[0][0]=2; Ziel[0][1]=1; Ziel[0][2]=3; Ziel[1][0]=4; Ziel[2][0]=5; return true; } bool set_current_matrix(){ create_matrix(Aktuell); clear_matrix(Aktuell); //generate_matrix(Aktuell); Aktuell[1][1]=1; Aktuell[0][0]=2; Aktuell[0][2]=3; Aktuell[1][0]=4; Aktuell[0][1]=5; return true; }
Ich will die "Zahlen" von einer Ausgangs- in eine Zielkonstelantion bringen. Dabei muss immer von oben abgebaut werden, nach einem Kran-Prinzip. Deshalb habe ich mich für das Matrix prinzip entschieden
-
Was soll das überhaupt werden? Bisher klang es ja nach Mathematik, aber so langsam bekomme ich den Eindruck, dass du ein Spiel programmieren möchtest.
Dein bisherige Klasse: Autsch! Neben den immer noch falschen create und dem (so wie es benutzt wird) unnötigen clear: Was, wenn jemand nur eine oder gar keine der set-funktionen aufruft bevor der Destruktor aufgerufen wird? Bumm! Was, wenn jemand eine Kopie einer Matrix macht und deren Destruktor aufgerufen wird? Bumm! Was, wenn jemand eine Matrix einer anderen zuweist? Speicherloch! Was wenn ein new eine Exception schmeißt? Bumm! Was passiert mit den Spalten? Speicherloch!
Du solltest unbedingt dieses Design vermeiden Das explodiert schon, wenn Tibet eine Grille zu laut zirpt. Google mal:
Google: RAII
Google: exception safety
Google: rule of three
Google: copy & swapOder nutz eben, wie von mir beschrieben, die Klassen der Standardbibliothek. Die machen das intern alles schon so und wenn du sie als Member benutzt, dann bekommen deine Klassen deren Sicherheit gratis* mit dazu.
*: Ja, all diese Sicherheiten sind gratis. Reine Programmlogik, kein Laufzeitnachteil.
-
SeppJ schrieb:
Was soll das überhaupt werden? Bisher klang es ja nach Mathematik, aber so langsam bekomme ich den Eindruck, dass du ein Spiel programmieren möchtest.
Nein es soll ein effizienter Sortieralgorithmus werden. Es soll ein Anfangskonstellation gegeben sein und mit möglichst wenig Bewegungen die Zielkonstellation erreicht werden.
SeppJ schrieb:
Dein bisherige Klasse: Autsch! Neben den immer noch falschen create
Wie schon erwähnt bin ich C++ Anfänger. Wie hätte ich den in so kurzer Zeit die Funktion anpassen sollen nur weil du mir sagst verwende std::vector und std::array. Auch dein Matrixbeispiel hilft mir ohne Erklärung leider fast überhaupt nicht. In der mir zur verfügungstehenden Literatur habe ich dazu noch keinerlei Hinweise gefunden.
SeppJ schrieb:
und dem (so wie es benutzt wird) unnötigen clear
es soll nur dazu dienen sicherzugehen, dass die Matrix mit 0en gefüllt ist, da ich die 0er für spätere Abfragen brauche.
SeppJ schrieb:
Was, wenn jemand nur eine oder gar keine der set-funktionen aufruft bevor der Destruktor aufgerufen wird? Bumm! Was, wenn jemand eine Kopie einer Matrix macht und deren Destruktor aufgerufen wird? Bumm!
Da hast du vollkommen recht. Über den Destruktor habe ich mir noch keine weiteren Gedanken gemacht, ich habe einfach mal einen entworfen um überhaupt einen zu haben.
SeppJ schrieb:
Was, wenn jemand eine Matrix einer anderen zuweist? Speicherloch!
Was wenn ein new eine Exception schmeißt? Bumm! Was passiert mit den Spalten? Speicherloch!Da außer mir da niemand an der (übrigends meine erste!) Klasse rumhantiert, mache ich mir darüber momentan erstmal keine Gedanken. Wenn das ganze dann überhaupt mal Funktioniert werde ich mich darum kümmern.
SeppJ schrieb:
Du solltest unbedingt dieses Design vermeiden Das explodiert schon, wenn Tibet eine Grille zu laut zirpt. Google mal:
Google: RAII
Google: exception safety
Google: rule of three
Google: copy & swapVielen Dank für die Hinweise, ich werde mich bei Zeiten damit beschäftigen.
SeppJ schrieb:
Oder nutz eben, wie von mir beschrieben, die Klassen der Standardbibliothek. Die machen das intern alles schon so und wenn du sie als Member benutzt, dann bekommen deine Klassen deren Sicherheit gratis mit dazu.
Das habe ich die letzten Stunden leider mit eher weniger Erfolg versucht.
Was ich bräuchte und worum es eigentlich von Anfang an ging ist eine einfache, leicht verständliche Lösung des Problems ala:bool set_target_matrix(){ /*soll das im privat definierte Array Ziel erstellen und mit 0en füllen*/ create_matrix(Ziel); /*hier soll das Array Ziel(bzw Aktuell) dynamisch erstellt werden. wie groß es ist, steht in den Variablen im Privatteil. Das ganze soll mit Ziel[Spalte][Zeile] ansprechbar sein*/ clear_matrix(Ziel); /*hier soll ein Array als Parameter übergeben werden und alle Elemente sollen auf 0 gesetzt werden. Wieviele das sind wird über die Variablen im Private bestimmt*/
Dabei möchte ich wenn möglich auf das erstellen von zusätzlichen Klassen erstmal verzichten. Die Array-Klasse (System) funktioniert leider nicht, wie ich versuche sie zu implementieren. Es gibt doch bestimmt eine ganz einfache Lösung wie ich das 2D-Array erzeugen und als Parameter verwenden kann
-
Hallo zusammen,
habe erstmal eine Lösung für mein Problem gefunden. Ich habe die Funktion zum erstellen der dynamischen Matrix auskommentiert und den code einfach in die beiden set Funktionen gepackt:bool set_target_matrix(){ //create_matrix(Ziel); int i=0; Ziel=new short* [Spalten]; while (i<Spalten){ Ziel[i]=new short[Zeilen]; i++; } clear_matrix(Ziel); //generate_matrix(Ziel); //solange die zufallsfunktion noch nicht fertig ist, wird die matrix manuell beschrieben Ziel[0][0]=2; Ziel[0][1]=1; Ziel[0][2]=3; Ziel[1][0]=4; Ziel[2][0]=5; return true; }
Jetzt habe ich aber noch 2 Fragen.
1. Wieso funktioniert genau der gleiche code wenn ich ihn direkt mit der short** aufrufe aber nicht wenn ich ihn mit einem short** als Parameter in einer eigenen Funktion aufrufe.
2. Kann mir jemand ein gutes Tutorial zur klasse std::array mitteilen? Also Initialisierung, dynamisches Erstellen, Verwendung als Parameter,Methoden,Eigenschaften usw. Ich habe nur eines zur Klasse system::Array von MSDN gefunden (http://msdn.microsoft.com/de-de/library/system.array.aspx). Da ich mit Visual Studio 2005 arbeite ist das ja an sich in Ordnung. Allerdings bekomme ich eine Fehlermeldung wenn ich versuche ein Array dieser Klasse in meiner Klasse zu erstellen. Irgendwas mit Verwalter
-
Sherlock schrieb:
Jetzt habe ich aber noch 2 Fragen.
1. Wieso funktioniert genau der gleiche code wenn ich ihn direkt mit der short** aufrufe aber nicht wenn ich ihn mit einem short** als Parameter in einer eigenen Funktion aufrufe.Weil du nicht verstanden hast, wie man in C call by reference macht. Wenn du einen Zeiger ändern möchtest, dann muss man eben einen Zeiger auf diesen Zeiger übergeben. Das ist aber auch nicht so schlimm ,wenn man dies nicht weiß, weil das in C++ eigentlich ganz anders geht.
2. Kann mir jemand ein gutes Tutorial zur klasse std::array mitteilen?
Wichtiger wäre erst einmal std::vector, da du hier eine dynamische Datenstruktur hast und insgesamt braucht man häufiger vector. Das lernst du in jedem guten C++-Buch (siehe meine Signatur). Du machst bisher ein grauenhaftes C-mit-Klassen Gefrickel. Du sagst, du kommst von C. Versuche nicht, C in C++ zu machen! Lern vernünftig C++! C und C++ sind zwei sehr verschiedene Sprachen, bloß aus historischen Gründen kannst du in C++ auch C-Konstruktionen benutzen. Tu das nicht! Die Erfahrung zeigt ganz eindeutig, dass du damit in C++ nicht erfolgreich werden wirst. Lern C++ wie eine neue Sprache mit einer dir schon bekannten Grammatik.
-
So habe die dynamisch erzeuge Matrix durch einen vector of vector of short ersetzt
Die Klasse sieht jetzt wie folgt aus:
// Block.h #pragma once //#ifndef _BLOCK_ // Mehrfaches Inkludieren verhindern, wenn #pragma once nicht funktioniert //#define _BLOCK_ // Funktioniert aber bei Visual Studio :) #include <cstdlib> #include <iostream> #include <vector> #include <time.h> //wird zum initialisieren der random funktion gebraucht using namespace std; class Block { private: //############# Private Eigenschaften########################### short Zeilen; short Spalten; short Bloecke; vector<vector<short>> Aktuell; //Aktuelle Matrix bool Aktuell_created; vector<vector<short>> Ziel; //Ziel Matrix bool Ziel_created; //###################privat Methoden################## short random(int lowerboundary, int upperboundary) { if(!Aktuell_created && !Ziel_created) srand( (unsigned) time(0) ); //wenn die funktion das erste mal aufgerufen wird, (meine boolchecks also noch auf false stehen) wird die random funktion initialisiert return lowerboundary + rand() % (upperboundary - lowerboundary + 1); } bool Find_Free_Column(short Spalte1,short Spalte2, short* Zielspalte){ //spalte1=spalte in die der block bewegt werden soll, spalte2 spalte in der der block liegt int i=0; bool ok=false; while (ok == false && i<Spalten){ while ((i == Spalte1 || i == Spalte2) && i<Spalten) i++; if (Blocks_per_Column(Aktuell,i)<Zeilen) ok=true; else i++; } *Zielspalte=i; return ok; } void generate_matrix(vector<vector<short>>& Matrix){ //hier soll aus den spalten/zeilen/blöcken eine mögliche blockkombination erstellt werden vector<short> Blockschleife; short i=0, Blockpos, Spalte,Upperbound,Zeile; Blockschleife.resize(Bloecke); while (i<Bloecke){ Blockschleife.at(i)=i+1; i++; } i=0; while (i<Bloecke){ if (Blockschleife.size()>0) Upperbound=Blockschleife.size()-1; else Upperbound=Blockschleife.size(); Blockpos=random(0,Upperbound); //eine Position im vector erstellen, wo irgendein block darin steht :) Spalte=random(0,Spalten-1); //eine spalte generieren, wo der block landen soll Zeile=Blocks_per_Column(Matrix, Spalte); //die Anzahl Blocke=spalte while (Zeile >= Zeilen-1){ //wenn er eine spalte liefert die keine freien elemente hat nochmal eine generieren Spalte=random(0,Spalten-1); Zeile=Blocks_per_Column(Matrix, Spalte); } Matrix[Spalte][Zeile]=Blockschleife[Blockpos]; Blockschleife.erase (Blockschleife.begin()+Blockpos); i++; } } short Blocks_per_Column(vector<vector<short>>& Matrix,short Spalte){ int i=0; while (Matrix[Spalte][i]>0 && i<Zeilen) i++; return i; } bool Set_Top_Block(short Spalte,short Block){ short i; bool check=false; i=0; while (Aktuell[Spalte][i]!=0 && i<Zeilen) i++; //das oberste freie element suchen if (i<Zeilen){ Aktuell[Spalte][i]=Block; //die oberste 0(=kein block) auf den block setzen check=true; //wenn in der spalte ein element frei war auf true setzten } if (check==false) cout << "Block konnte nicht gesetzt werden!"<<endl; return check; } short Find_False_Blocks_Column(short Spalte){ short Anzahl_ziel,Anzahl_aktuell, i, false_elements; bool check; Anzahl_ziel=Blocks_per_Column(Ziel,Spalte); //Anzahl der blöcke in der zielmatrix zählen Anzahl_aktuell=Blocks_per_Column(Aktuell,Spalte); //anzahl der blöcke in aktueller matrix zählen if (Anzahl_ziel==0) return 0; //wenn kein element im ziel vorhanden ist 0 zurückgeben i=0; false_elements=Anzahl_ziel; //sonst die anzahl falscher auf die anzahl blöcke setzen check=true; while (i<Anzahl_ziel && check){ //die elemente durchgehen bis ein falsches dabei sit if (Ziel[Spalte][i]==Aktuell[Spalte][i]) false_elements--; //solange die elemente in ziel und aktuell gleich sind die anzahl falscher elemente reduzieren else check=false; i++; } if (false_elements == 0) return 0; //wenn die spalte nicht schon fertig gebaut ist soll die differenz die noch falsch darauf liegt auf die falschen addiert werden else{ if (Anzahl_aktuell>Anzahl_ziel) false_elements+=(Anzahl_aktuell-Anzahl_ziel); } return false_elements; } bool Find_rightandfalse_BlockNr(short Spalte, short* Right_Block, short* False_Block){ int i=0; while (Ziel[Spalte][i]==Aktuell[Spalte][i] && i<Zeilen) i++; //solange die elemente in der spalte übereinstimmen ein element nach oben gehen bis das ende des bereiches erreicht ist *Right_Block= Ziel[Spalte][i]; //der Block der eigentlich richtig wäre *False_Block= Aktuell[Spalte][i]; //der block der statdessen an der position liegt if (*Right_Block==0 && *False_Block==0) return false; else return true; } bool Find_Column(short Right_Block, short* Right_Block_Column){ short i=0,j=0; if (Right_Block==0) return false; else { while (Aktuell[i][j]!=Right_Block){ // spalte=i, zeile=j jede spalte wird bis zum obersten element gezählt ->zeile hochzählen, dann spalte j=0; while (Aktuell[i][j]!=Right_Block && j<Zeilen-1){ j++; //if (j>=Zeilen) j--; } if (Aktuell[i][j]==Right_Block) break; else i++; } } *Right_Block_Column=i; return true; } bool Move_Pos_Free(short Bauspalte, short False_Block, short Right_Block_Column){ //Right_Block_ ist die spalte wo jetzt freigeräumt wird short i=0,j=0,Zielspalte; //sp1=spalte die gebaut wird sp2=spalte wo der richtige block liegt j=Zeilen-1; //marker wird auf das oberste element der spalte gelegt while (Aktuell[Bauspalte][j]!=False_Block){ //bis zum falschen Block arbeiten if (Aktuell[Bauspalte][j]>0){ //nur wenn da ein block liegt soll er bewegt werden if (Find_Free_Column(Bauspalte,Right_Block_Column,&Zielspalte)){ //wenn eine spalte gefunden wurde, die blöcke aufnehmen kann Set_Top_Block(Zielspalte,Aktuell[Bauspalte][j]); //wird der flasche block auf diese spalte oben angefügt Aktuell[Bauspalte][j]=0; //und der block verschwindet von der alten position } else return false; } j--; //jetzt wird der marker nochmal nach unten geschoben } //jetzt noch den falschen block wegräumen und die spalte liegt für den richtigen block frei if(Find_Free_Column(Bauspalte,Right_Block_Column,&Zielspalte)){ Set_Top_Block(Zielspalte,Aktuell[Bauspalte][j]); Aktuell[Bauspalte][j]=0; } else return false; return true; } bool Move_Block_Free(short Bauspalte, short Right_Block, short Right_Block_Column){ //Bauspalte ist die spalte wo der richtige block am ende landen soll short i=0,j=0,Zielspalte; //sp1=spalte die gebaut wird sp2=spalte wo der richtige block liegt j=Zeilen-1; //marker wird auf das oberste element der spalte mit dem richtigen block legen while (Aktuell[Right_Block_Column][j]!=Right_Block){ //bis zum richtigen Block arbeiten if (Aktuell[Right_Block_Column][j]>0){ if (Find_Free_Column(Bauspalte,Right_Block_Column, &Zielspalte)){ //nur wenn da ein block liegt soll er bewegt werden //wenn eine spalte gefunden wurde, die blöcke aufnehmen kann weitermachen Set_Top_Block(Zielspalte,Aktuell[Right_Block_Column][j]); //wird der flasche block auf diese spalte oben angefügt Aktuell[Right_Block_Column][j]=0; //und der block verschwindet von der alten position } else return false ; } j--; //jetzt wird der marker nochmal nach unten geschoben bis man beim richtigen block ist } Set_Top_Block(Bauspalte,Right_Block); //jetzt noch den richtigen block auf die richtie position bewegen Aktuell[Right_Block_Column][j]=0; return true; } public: //#######################public Methoden##################### Block (short init_Zeilen,short init_Spalten,short init_Bloecke){ //konstruktor if (init_Spalten > 2) Spalten=init_Spalten; else Spalten=3; if (init_Zeilen > 1) Zeilen=init_Zeilen; else Zeilen=3; if (init_Bloecke > 1 && init_Bloecke < Spalten*Zeilen) Bloecke=init_Bloecke; else Bloecke=4; Aktuell_created=false; Ziel_created=false; } ~Block(){ //Destruktor //if (Aktuell_created=true) delete Aktuell; //da es keine dyn. speicher mehr sind unnötig //if (Ziel_created=true) delete Ziel; } bool set_target_matrix(){ Ziel.resize(Spalten,vector<short>(Zeilen,0)); Ziel_created=true; //clear_matrix(Ziel); //da alles mit 0 initialisiert wird die fkt nicht gebraucht generate_matrix(Ziel); return true; } bool set_current_matrix(){ Aktuell.resize(Spalten,vector<short>(Zeilen,0)); Aktuell_created=true; //clear_matrix(Aktuell); generate_matrix(Aktuell); return true; } void display_target_matrix(){ int scounter,zcounter; zcounter=Zeilen-1; while(zcounter>=0){ scounter=0; while(scounter<Spalten){ if (Ziel[scounter][zcounter]) printf("[%d]\t",Ziel[scounter][zcounter]); else printf("\t"); scounter++; } printf("\n"); zcounter--; } printf("\n"); } void display_current_matrix(){ int scounter,zcounter; zcounter=Zeilen-1; while(zcounter>=0){ scounter=0; while(scounter<Spalten){ if (Aktuell[scounter][zcounter]) printf("[%d]\t",Aktuell[scounter][zcounter]); else printf("\t"); scounter++; } printf("\n"); zcounter--; } printf("\n"); } short get_minfalse_column(){ short i,max=1000,temp, value=NULL; i=0; while (i<Spalten){ temp=Find_False_Blocks_Column(i); if (temp<max && temp>0) value=i; i++; } return value; } short get_maxfalse_blocks(){ short i,max,temp; max=Find_False_Blocks_Column(0); i=1; while (i<Spalten){ temp=Find_False_Blocks_Column(i); if (temp>max) max=temp; i++; } return max; } bool solve_block(short Spalte){ short i=0, Right_Block=0, Right_Block_Column=0, False_Block=0; //false_Block_Column = Spalte ;) if (!Find_rightandfalse_BlockNr(Spalte, &Right_Block, &False_Block)) {cerr << "Fehler beim finden der Blöcke" << endl; return false;} //ermittlen der blocknr bis zu der abgebaut werden muss, da sie falsch ist(false_block) und des blockes der dann an die position soll(right_Block) if (!Find_Column(Right_Block,&Right_Block_Column)) {cerr <<"Der Block wurde nicht gefunden" << endl; return false;} //die spalte finden in welcher der richtige block liegt if (!Move_Pos_Free(Spalte,False_Block, Right_Block_Column)) {cerr <<"keine freie Spalte gefunden" << endl; return false;} if (!Move_Block_Free(Spalte,Right_Block,Right_Block_Column)) {cerr <<"keine freie Spalte gefunden" << endl; return false;} //Spalte ist die return true; } };
Die display Funktionen sind nicht von mir, deshalb noch komplett in C Code.
Der Aufruf:
// Klassentest.cpp: Hauptprojektdatei. #include "stdafx.h" #include <cstdlib> #include <iostream> #include "D:\Filesystem\Projekte\Visual Studio Projekte\Block\Block\Block.h" using namespace std; int main(void) { short Zeilen=5,Spalten=3,Bloecke=4,zaehler=0,i=0; cout << "Das programm wird gestartet, die initialisierung von block.h hat funktioniert" << endl; Block Blocksworld(Zeilen,Spalten,Bloecke); //erstellen und initialisieren des objektes Blocksworld.set_current_matrix(); //Aktuelle matrix erstellen Blocksworld.set_target_matrix(); //zeilmatrix erstellen cout << "Die Zielmatrix:"; Blocksworld.display_target_matrix(); //zielmatrix ausgeben cout << "Die momentane Matrix :"; Blocksworld.display_current_matrix(); //aktuelle matrix ausgeben while(Blocksworld.get_maxfalse_blocks()!=0 && i<4){ //solange es noch eine spalte mit mehr als einem falschen element gibt if(!Blocksworld.solve_block(Blocksworld.get_minfalse_column())) i++; //soll in der spalte, wo die wenigsten elemente falsch sind ein block bearbeitet werden //cout << "blockkonstellation" << endl; //Blocksworld.display_current_matrix(); //cout << endl; zaehler++; } if (i>3) cout << "Das Problem konnte nicht geloest werden!" << endl; else cout << "Nach: " <<zaehler<< " Schritten sieht die Matrix wie folgt aus" << endl; Blocksworld.display_current_matrix();/**/ //ausgabe der aktuellen matrix um mit der zielmatrix zu vergleichen system("PAUSE"); return 0; }
Das ganze ist nocht nicht optimiert. z.B. soll anstatt eine nichtlösbare Spalte 3mal zu versuchen, die Spalte gewechselt werden. Auch das find_Free_Column ist nocht ziemlich "dumm". Wollte nur gerne wissen, inwieweit das jetzt besser oder immernoch grob falsch/schlecht ist
Vielen Dank!
-
Ja, pragma one funktioniert bei VS. ifdef & Co. jedoch auch. Dafür funktionieren ifdef & Co. aber auch überall.
Der Header ist sehr überfrachtet. Müssen die Funktionen alle inline sein? Die meisten sind so groß, da dürfte dies wenig bringen oder sogar hinderlich sein.
using namespace std im Header: Nun hat jeder der deinen Header benutzt den gesamten std-Namensraum im globalen Namensraum. Also ist das Prinzip der Namespaces mit einem Schlag dahin. using namespace hat daher nichts in Headern zu suchen.
time.h heißt in C++ ctime.
Wenn du aus
vector<vector<short>>
einvector<vector<short> >
machen würdest, könnte man deinen Code sogar mit einem strengen Nicht-C++11-Compiler übersetzen.vector<vector>> ist kein 2D-Array, das wurde dir schon erklärt.
if(!Aktuell_created && !Ziel_created) srand( (unsigned) time(0) ); //wenn die funktion das erste mal aufgerufen wird, (meine boolchecks also noch auf false stehen) wird die random funktion initialisiert
Sehr abenteuerlich. Lass das. Viel Aufwand für einen eher hinderlichen Effekt. Eine Matrix hat keine globalen Zufallszahlengeneratoren anzufassen. Was ist, wenn ich meinen Generator anders initialisieren möchte? Noch schlimmer: Was ist, wenn es mehrere Blocks gibt?
Falls du unbedingt lokale Zufallsgeneratoren pro Block brauchst, dann schreib dir selber einen oder nimm einen aus C++11 oder TR1 (oder aus nicht-standard Bibliotheken).Wenn du deine Variablen nicht am Funktionsanfang definieren würdest, sondern erst dort, wo du sie brauchst, dann würdest du auch merken, dass du sehr viele unbenutzte Variablen hast. Außerdem wäre es für die meisten C++-Programmierer einfacher lesbar, weil gewohnt.
Den leeren Destruktor lasse ich mal durchgehen, da du offensichtlich den alten nur auskommentieren wolltest anstatt ihn ganz zu löschen. Aber du könntest gleich die ganze Definition auskommentieren, nicht nur den Funktionskörper.
Für printf fehlt der Header cstdio. Aber: Welchen Vorteil versprichst du dir hier von printf gegenüber einem guten alten
ostream::operator<<
?Das Design gefallt mir nicht. So wie es aussieht, muss man immer set_current_matrix und set_target_matrix aufrufen, bevor man irgendetwas anderes mit deinem Block machen kann. Wieso findet das nicht im Konstruktor statt?
Die ganze Klasse scheint mir total überladen. Abstrahiere! Zerlege in Teilprobleme!
So richtig genau angesehen habe ich mir den Algorithmus nicht, ist einfach viel zu viel Code. Daher kann ich nicht sagen, ob die Grundidee was taugt, sondern kritisiere nur die Umsetzung. Außerdem habe ich hier nur die Sachen aufgezählt, die mir nicht gefielen und habe keinen Kommentar abgegeben, wenn etwas gut war.
-
SeppJ schrieb:
Ja, pragma one funktioniert bei VS. ifdef & Co. jedoch auch. Dafür funktionieren ifdef & Co. aber auch überall.
Alles klar habe auf ifdef umgestellt. Vielen Dank für den Tipp
SeppJ schrieb:
Der Header ist sehr überfrachtet. Müssen die Funktionen alle inline sein? Die meisten sind so groß, da dürfte dies wenig bringen oder sogar hinderlich sein.
Puh hier bin ich echt überfragt. Kann da leider nicht auf Erfahrungswerte zurückgreifen. Würde mich da über Tipps/Bewertungen sehr freuen.
SeppJ schrieb:
using namespace std im Header: Nun hat jeder der deinen Header benutzt den gesamten std-Namensraum im globalen Namensraum. Also ist das Prinzip der Namespaces mit einem Schlag dahin. using namespace hat daher nichts in Headern zu suchen.
Habe den namespace aus dem Header entfernt. War mir zwar klar, dass es dann im globalen Namensraum landet, habe es aber für eine (für mich erstmal) bessere Leslichkeit des Codes hinzugefügt
SeppJ schrieb:
time.h heißt in C++ ctime.
Vielen dank für die Info habe es mir gemekrt. Inzwischen aber eh verschwunden, da ich das mit dem srand() nicht mehr mache
SeppJ schrieb:
Wenn du aus
vector<vector<short>>
einvector<vector<short> >
machen würdest, könnte man deinen Code sogar mit einem strengen Nicht-C++11-Compiler übersetzen.Umgesetzt und gemerkt
SeppJ schrieb:
vector<vector>> ist kein 2D-Array, das wurde dir schon erklärt.
Ist auch angekommen. Alle Matrix[][] Aufrufe wurden inzwischen durch Matrix.at().at() ersetzt. Leider bin ich noch nicht zur Implementierung eines checked Vector gekommen. Das Prinzip Vector of Vector habe ich (hoffentlich) verstanden.
SeppJ schrieb:
Wenn du deine Variablen nicht am Funktionsanfang definieren würdest, sondern erst dort, wo du sie brauchst, dann würdest du auch merken, dass du sehr viele unbenutzte Variablen hast. Außerdem wäre es für die meisten C++-Programmierer einfacher lesbar, weil gewohnt.
Habe die ein oder andere unnötige Variable gefunden und gelöscht. Leider habe ich mich inzwischen an das definieren von Variablen beim Funktionsanfang gewöhnt. Werde es beim nächsten Projekt anders machen und sehen, was mir besser gefällt
SeppJ schrieb:
Den leeren Destruktor lasse ich mal durchgehen, da du offensichtlich den alten nur auskommentieren wolltest anstatt ihn ganz zu löschen. Aber du könntest gleich die ganze Definition auskommentieren, nicht nur den Funktionskörper.
Destruktor ist jetzt leer
SeppJ schrieb:
Für printf fehlt der Header cstdio. Aber: Welchen Vorteil versprichst du dir hier von printf gegenüber einem guten alten
ostream::operator<<
?Inzwischen durch std::cout ersetzt und <cstdlib> wurde entfernt.
SeppJ schrieb:
Das Design gefallt mir nicht. So wie es aussieht, muss man immer set_current_matrix und set_target_matrix aufrufen, bevor man irgendetwas anderes mit deinem Block machen kann. Wieso findet das nicht im Konstruktor statt?
Ein sehr guter Einwand! Sie waren zu testzwecken erstmal auserhalb des Konstruktors machen innerhalb aber natürlich viel mehr Sinn
SeppJ schrieb:
Die ganze Klasse scheint mir total überladen. Abstrahiere! Zerlege in Teilprobleme!
Ganz so viel macht die Klasse eigentlich garnicht^^ Eventuell hast du einen Tipp für mich sonst würde ich das erstmal so lassen.
Leider tretten seit dem Umstellen der dynamischen Matrix in einen Vector of Vector of short öfters mal Bereichsüberschreitungsfehler auf. Wo habe ich leider noch nicht lokalisieren können
Der neue Code:
// Block.h //#pragma once //ist durch ifndef abgewickelt #ifndef _BLOCK_ // Mehrfaches Inkludieren verhindern, wenn #pragma once nicht funktioniert #define _BLOCK_ // Funktioniert aber bei Visual Studio, ifndef aber bei jedem #include <iostream> //für cout #include <vector> //für matrix und vector für zufallsverteilung #include "D:\Filesystem\Projekte\Visual Studio Projekte\Logfile\Logfile\Logfile.h" //using namespace std; //std namespace soll nicht in den globalen namensbereich geladen werden -> vor vector,cout,cerr,endl einfach std:: geschrieben bzw vor die random System:: class Block { private: //############# Private Eigenschaften ########################### short Zeilen; short Spalten; short Bloecke; std::vector<std::vector<short> > Aktuell; //Aktuelle Matrix std::vector<std::vector<short> > Ziel; //Ziel Matrix Matrixlog log_matrix; Rowlog log_row; //############# Private Methoden ########################## bool set_target_matrix(){ Ziel.resize(Spalten,std::vector<short>(Zeilen,0)); generate_matrix(Ziel); return true; } bool set_current_matrix(){ Aktuell.resize(Spalten,std::vector<short>(Zeilen,0)); generate_matrix(Aktuell); return true; } int random(int lowerboundary, int upperboundary){ return lowerboundary + rand() % (upperboundary - lowerboundary + 1); } void generate_matrix(std::vector<std::vector<short> >& Matrix){ //hier soll aus den spalten/zeilen/blöcken eine mögliche blockkombination erstellt werden std::vector<short> Blockschleife; //hier stehen alle blöcke drin unsigned short i=0, Blockpos, Spalte,Upperbound,Zeile; while (i<Bloecke){ Blockschleife.push_back(i+1); //den block hinten an den vector anhängen i++; } i=0; while (i<Bloecke){ if (Blockschleife.size()>0) Upperbound=Blockschleife.size()-1; //wenn nurnoch der 0er index exestiert soll nicht auf -1 gesetzt werden else Upperbound=Blockschleife.size(); Blockpos=random(0,Upperbound); //eine Position im vector erstellen, wo irgendein block darin steht :) Spalte=random(0,Spalten-1); //eine spalte generieren, wo der block landen soll Zeile=Blocks_per_Column(Matrix, Spalte); //die Anzahl Blocke=spalte while (Zeile >= Matrix.at(Spalte).size()){ //wenn er eine spalte liefert die keine freien elemente hat nochmal eine generieren Spalte=random(0,Spalten-1); Zeile=Blocks_per_Column(Matrix, Spalte); } Matrix.at(Spalte).at(Zeile)=Blockschleife[Blockpos]; Blockschleife.erase (Blockschleife.begin()+Blockpos); i++; } } /*bool Find_Free_Column(const short& Spalte1,const short& Spalte2, short* Zielspalte){ //spalte1=spalte in die der block bewegt werden soll, spalte2 spalte in der der block liegt //alte version int i=0; bool ok=false; while (ok == false && i<Spalten){ while (i<Spalten && (i == Spalte1 || i == Spalte2)) i++; if (Blocks_per_Column(Aktuell,i)<Zeilen) ok=true; else i++; } *Zielspalte=i; return ok; } */ bool Find_Free_Column(short Spalte1,short Spalte2, short* Zielspalte, short Blocknummer){ //spalte1=spalte in die der block bewegt werden soll, spalte2 spalte in der der block liegt int i=0,j=0; int minZeilen=Zeilen; // -1 für 0-orientierte Zählweise int tmp; bool ok=false; while (i<Spalten && minZeilen != 0){ if(i == Spalte1 || i == Spalte2) i++; // Spalte überspringen else { // i=Spalte, j=Zeile while (j<Zeilen && Aktuell.at(i).at(j)>0 && Aktuell.at(i).at(j)!= Blocknummer) j++; if(Aktuell.at(i).at(j)==Blocknummer) { minZeilen=0; // Todo: schnelleres Rausspringen implementieren *Zielspalte=i; ok=true; } tmp=Blocks_per_Column(Aktuell,i); if(tmp<minZeilen) { ok=true; minZeilen=tmp; *Zielspalte=i; } i++; } } return ok; } short Blocks_per_Column(const std::vector<std::vector<short> >& Matrix,const short& Spalte){ short i=0; while (i<Zeilen && Matrix.at(Spalte).at(i)>0) i++; return i; } bool Set_Top_Block(const short& Spalte,const short& Block){ short i; bool check=false; i=0; while (i<Zeilen && Aktuell.at(Spalte).at(i)!=0) i++; //das oberste freie element suchen if (i<Zeilen){ Aktuell.at(Spalte).at(i)=Block; //die oberste 0(=kein block) auf den block setzen check=true; //wenn in der spalte ein element frei war auf true setzten } if (check==false) std::cout << "Block konnte nicht gesetzt werden!"<<std::endl; return check; } short Find_False_Blocks_Column(short Spalte){ short Anzahl_ziel,Anzahl_aktuell, i, false_elements; bool check; Anzahl_ziel=Blocks_per_Column(Ziel,Spalte); //Anzahl der blöcke in der zielmatrix zählen Anzahl_aktuell=Blocks_per_Column(Aktuell,Spalte); //anzahl der blöcke in aktueller matrix zählen if (Anzahl_ziel==0) return 0; //wenn kein element im ziel vorhanden ist 0 zurückgeben i=0; false_elements=Anzahl_ziel; //sonst die anzahl falscher auf die anzahl blöcke setzen check=true; while (i<Anzahl_ziel){ //die elemente durchgehen bis ein falsches dabei sit if (Ziel.at(Spalte).at(i)==Aktuell.at(Spalte).at(i)) false_elements--; //solange die elemente in ziel und aktuell gleich sind die anzahl falscher elemente reduzieren else break; i++; } if (false_elements == 0) return 0; //wenn die spalte nicht schon fertig gebaut ist soll die differenz die noch falsch darauf liegt auf die falschen addiert werden else{ if (Anzahl_aktuell>Anzahl_ziel) false_elements+=(Anzahl_aktuell-Anzahl_ziel); } return false_elements; } bool Find_rightandfalse_BlockNr(const short& Spalte, short* Right_Block, short* False_Block){ int i=0; while (i<Zeilen && Ziel.at(Spalte).at(i)==Aktuell.at(Spalte).at(i) ) i++; //solange die elemente in der spalte übereinstimmen ein element nach oben gehen bis das ende des bereiches erreicht ist *Right_Block = Ziel.at(Spalte).at(i); //der Block der eigentlich richtig wäre *False_Block = Aktuell.at(Spalte).at(i); //der block der statdessen an der position liegt if (*Right_Block==0 && *False_Block==0) return false; else return true; } bool Find_Column(const short& Block, short* Block_Column){ unsigned short i=0,j=0; if (Block==0) return false; else { while (Aktuell.at(i).at(j)!=Block){ // spalte=i, zeile=j jede spalte wird bis zum obersten element gezählt ->zeile hochzählen, dann spalte j=0; while (j<Aktuell.at(i).size()-1 && Aktuell.at(i).at(j)!=Block) j++; if (Aktuell.at(i).at(j)==Block) break; else i++; } } *Block_Column=i; return true; } bool Move_Pos_Free(const short& Bauspalte,const short& False_Block, const short& Right_Block_Column){ //Right_Block_ ist die spalte wo jetzt freigeräumt wird short j=0,Zielspalte; //sp1=spalte die gebaut wird sp2=spalte wo der richtige block liegt j=Zeilen-1; //marker wird auf das oberste element der spalte gelegt while (Aktuell.at(Bauspalte).at(j)!=False_Block){ //bis zum falschen Block arbeiten if (Aktuell.at(Bauspalte).at(j)>0){ //nur wenn da ein block liegt soll er bewegt werden if (Find_Free_Column(Bauspalte,Right_Block_Column,&Zielspalte,Aktuell.at(Bauspalte).at(j))){ //wenn eine spalte gefunden wurde, die blöcke aufnehmen kann Set_Top_Block(Zielspalte,Aktuell.at(Bauspalte).at(j)); //wird der flasche block auf diese spalte oben angefügt Aktuell.at(Bauspalte).at(j)=0; //und der block verschwindet von der alten position } else return false; } j--; //jetzt wird der marker nochmal nach unten geschoben } //jetzt noch den falschen block wegräumen und die spalte liegt für den richtigen block frei if(Find_Free_Column(Bauspalte,Right_Block_Column,&Zielspalte,Aktuell.at(Bauspalte).at(j))){ Set_Top_Block(Zielspalte,Aktuell.at(Bauspalte).at(j)); Aktuell.at(Bauspalte).at(j)=0; } else return false; return true; } bool Move_Block_Free(const short& Bauspalte,const short& Right_Block){ //Bauspalte ist die spalte wo der richtige block am ende landen soll unsigned short j=0 ; short Zielspalte=0, Right_Block_Column; //sp1=spalte die gebaut wird sp2=spalte wo der richtige block liegt j=Zeilen-1; //marker wird auf das oberste element der spalte mit dem richtigen block legen Find_Column(Right_Block, &Right_Block_Column); while (j<Aktuell.at(Right_Block_Column).size() && Aktuell.at(Right_Block_Column).at(j)!=Right_Block){ //bis zum richtigen Block arbeiten if (Aktuell.at(Right_Block_Column).at(j)>0){ if (Find_Free_Column(Bauspalte,Right_Block_Column, &Zielspalte,Aktuell.at(Right_Block_Column).at(j))){ //nur wenn da ein block liegt soll er bewegt werden //wenn eine spalte gefunden wurde, die blöcke aufnehmen kann weitermachen Set_Top_Block(Zielspalte,Aktuell.at(Right_Block_Column).at(j)); //wird der flasche block auf diese spalte oben angefügt Aktuell.at(Right_Block_Column).at(j)=0; //und der block verschwindet von der alten position } else return false ; } j--; //jetzt wird der marker nochmal nach unten geschoben bis man beim richtigen block ist } Set_Top_Block(Bauspalte,Right_Block); //jetzt noch den richtigen block auf die richtie position bewegen Aktuell.at(Right_Block_Column).at(j)=0; return true; } public: //#######################public Methoden##################### Block (short init_Zeilen,short init_Spalten,short init_Bloecke){ //konstruktor if (init_Spalten > 2) Spalten=init_Spalten; else Spalten=3; if (init_Zeilen > 1) Zeilen=init_Zeilen; else Zeilen=3; if (init_Bloecke > 1 && init_Bloecke < Spalten*Zeilen) Bloecke=init_Bloecke; else Bloecke=4; set_current_matrix(); set_target_matrix(); } ~Block(){} //Destruktor void display_target_matrix(){ int scounter,zcounter; zcounter=Zeilen-1; while(zcounter>=0){ scounter=0; while(scounter<Spalten){ if (Ziel.at(scounter).at(zcounter)) std::cout << "["<<Ziel.at(scounter).at(zcounter)<<"]\t" ; else std::cout << "\t"; scounter++; } std::cout << "\n"; zcounter--; } std::cout << "\n"; } void display_current_matrix(){ int scounter,zcounter; zcounter=Zeilen-1; while(zcounter>=0){ scounter=0; while(scounter<Spalten){ if (Aktuell.at(scounter).at(zcounter)) std::cout << "[" << Aktuell.at(scounter).at(zcounter) << "]\t" ; else std::cout << "\t"; scounter++; } std::cout << "\n"; zcounter--; } std::cout << "\n"; } short get_minfalse_column(){ short i,max=1000,temp, value=NULL; i=0; while (i<Spalten){ temp=Find_False_Blocks_Column(i); if (temp<max && temp>0) value=i; i++; } return value; } short get_minfalse_column_2(short order){ short i=0,temp,j=0; //2x3 Matrix mit Spaltennr. und der Anzahl der Bloecke darin std::vector< std::vector <short> > Blockcount; Blockcount.resize(3,std::vector<short>(2,0)); //Matrix mit Werten belegen while (j<3 && i<Spalten){ temp=Find_False_Blocks_Column(i); if (temp>0) { Blockcount.at(j).at(0) = i; Blockcount.at(j).at(1) = temp; j++; } i++; } //kleinstes Element suchen if (Blockcount.at(1).at(1)<Blockcount.at(0).at(1) && Blockcount.at(1).at(1)) std::swap(Blockcount.at(1),Blockcount.at(0)); if (Blockcount.at(2).at(1)<Blockcount.at(0).at(1) && Blockcount.at(2).at(1)) std::swap(Blockcount.at(2),Blockcount.at(0)); //groestes Element suchen if (Blockcount.at(1).at(1)>Blockcount.at(2).at(1) && Blockcount.at(2).at(1)) std::swap(Blockcount.at(1),Blockcount.at(2)); //Restliche Spalten durchgehen und in Matrix eintragen while (i<Spalten){ temp=Find_False_Blocks_Column(i); if (temp>0) { //neues kleinstes if (temp<Blockcount.at(0).at(1)) { Blockcount.at(2).at(0) = Blockcount.at(1).at(0); Blockcount.at(2).at(1) = Blockcount.at(1).at(1); Blockcount.at(1).at(0) = Blockcount.at(0).at(0); Blockcount.at(1).at(1) = Blockcount.at(0).at(1); Blockcount.at(0).at(0) = i; Blockcount.at(0).at(1) = temp; } //neue mitte if (temp>Blockcount.at(0).at(1) && temp<Blockcount.at(1).at(1)) { Blockcount.at(2).at(0) = Blockcount.at(1).at(0); Blockcount.at(2).at(1) = Blockcount.at(1).at(1); Blockcount.at(1).at(0) = i; Blockcount.at(1).at(1) = temp; } //neues groesstes if (temp>Blockcount.at(1).at(1) && temp<Blockcount.at(2).at(1)) { Blockcount.at(2).at(0) = i; Blockcount.at(2).at(1) = temp; } } i++; } return Blockcount.at(order-1).at(0); } short get_maxfalse_blocks(){ short i,max,temp; max=Find_False_Blocks_Column(0); i=1; while (i<Spalten){ temp=Find_False_Blocks_Column(i); if (temp>max) max=temp; i++; } return max; } bool solve_block(short Spalte){ short Right_Block=0, Right_Block_Column=0, False_Block=0; //false_Block_Column = Spalte ;) if (!Find_rightandfalse_BlockNr(Spalte, &Right_Block, &False_Block)) {std::cerr <<"Fehler beim finden der Blöcke" << std::endl; return false;} //ermittlen der blocknr bis zu der abgebaut werden muss, da sie falsch ist(false_block) und des blockes der dann an die position soll(right_Block) if (!Find_Column(Right_Block,&Right_Block_Column)) {std::cerr <<"Der Block wurde nicht gefunden" << std::endl; return false;} //die spalte finden in welcher der richtige block liegt if (!Move_Pos_Free(Spalte,False_Block,Right_Block_Column)) {std::cerr <<"keine freie Spalte gefunden" << std::endl; return false;} if (!Move_Block_Free(Spalte,Right_Block)) {std::cerr <<"keine freie Spalte gefunden" << std::endl; return false;} unsigned short moves=1; log_row.write_to_log(Aktuell ,moves); log_matrix.write_to_log(Aktuell ,moves); return true; } }; #endif _BLOCK_ // Logfile.h #ifndef _LOGFILE_ // Mehrfaches Inkludieren verhindern, wenn #pragma once nicht funktioniert #define _LOGFILE_ #include <sstream> //für die int to String via stringstream #include <fstream> #include <vector> class Logfile{ protected: //################private proberty################### std::string path; std::fstream logfile; //#################private method################### std::string get_Time_string(){ System::DateTime Zeit = System::DateTime::Now; //die Katuelle Systemzeit in Zeit schreiben std::ostringstream Stringstream; //hier wird der integer hineingestreamt //#######Stunden einlesen Stringstream << Zeit.Hour; //Stunde in den Stringstream schreiben std::string h(Stringstream.str()); // den Stringstream in den string h schreiben //#######Minuten einlesen Stringstream.str(""); //den Stream leermachen, da sonst die stunde noch davor steht Stringstream << Zeit.Minute; //integer wird eingelesen std::string min(Stringstream.str()); //der stream wird in min geschrieben //#######Sekunden einlesen Stringstream.str(""); Stringstream << Zeit.Second; std::string sec(Stringstream.str()); //#######String zusammenführen std::string value = h + ":" + min + ":" + sec; return value; } std::string get_Date_string(){ System::DateTime Datum = System::DateTime::Now; //die Katuelle Systemzeit in Zeit schreiben std::ostringstream Stringstream; //hier wird der integer hineingestreamt //#######Jahr einlesen Stringstream << Datum.Year; //das Jahr in den Stringstream schreiben std::string year(Stringstream.str()); // den Stringstream in den string year schreiben //#######Monat einlesen Stringstream.str(""); //den Stream leermachen, da sonst das jahr Stringstream << Datum.Month; //integer wird eingelesen std::string mon(Stringstream.str()); //der stream wird in mon geschrieben //#######Tag einlesen Stringstream.str(""); Stringstream << Datum.Day; std::string day(Stringstream.str()); //#######String zusammenführen std::string value = day + "." + mon + "." + year; return value; } void start_log(){ logfile.open(path.c_str(), std::ios::app); if(logfile.good()){ logfile << "Beginn des Logvorgangs um: " << get_Time_string() << "\n"; logfile.close(); } } void end_log(){ logfile.open(path.c_str(), std::ios::app); if(logfile.good()){ logfile << "Ende des Logvorgangs um: " << get_Time_string() << "\n"; logfile.close(); } } public: //###################public methoden################ Logfile(){} ~Logfile(){} }; class Matrixlog : protected Logfile { public: Matrixlog(){ path = "log_format_" + get_Date_string()+ ".txt"; start_log(); } ~Matrixlog(){end_log();} bool write_to_log(const std::vector<std::vector<short> >& Matrix, unsigned short moves){ short scounter, zcounter; short Spalten = Matrix.size(); short Zeilen = Matrix.at(0).size(); logfile.open(path.c_str(), std::ios::app); //#### Formatierte Ausgabe if(this->logfile.good()){ //Überprüfung ob Datei geöffnet werden konnte logfile << "Zeit: " << get_Time_string() << "\n"; zcounter=Zeilen-1; while(zcounter>=0){ scounter=0; while(scounter<Spalten){ logfile << Matrix.at(scounter).at(zcounter); //Schreiben der Werte in Matrix logfile << "\t"; //Strukturierte Ausgabe scounter++; } logfile << "\n"; //strukturierte Ausgabe zcounter--; } logfile<<"Umstapelungen= "<< moves <<"\n"<<"---------------------------------------------"<<"\n"; logfile.close(); return true; } else return false; } }; class Rowlog : protected Logfile { public: Rowlog(){ path = "log_normal_" + get_Date_string()+ ".txt"; start_log(); } ~Rowlog(){end_log();} bool write_to_log(const std::vector<std::vector<short> >& Matrix, unsigned short moves){ short scounter, zcounter; short Spalten = Matrix.size(); short Zeilen = Matrix.at(0).size(); logfile.open(path.c_str(), std::ios::app); //#### Formatierte Ausgabe if(this->logfile.good()){ //Überprüfung ob Datei geöffnet werden konnte logfile << "Zeit: " << get_Time_string() << "\n"; zcounter=0; while(zcounter<Zeilen){ scounter=0; while(scounter<Spalten){ logfile << Matrix.at(scounter).at(zcounter); //Schreiben der Werte in Matrix logfile << ","; //Strukturierte Ausgabe scounter++; } logfile << (" ; "); //strukturierte Ausgabe zcounter++; } logfile<<"Umstapelungen= "<< moves <<"\n"<<"---------------------------------------------"<<"\n"; logfile.close(); return true; } else return false; } }; #endif _LOGFILE_
// Klassentest.cpp: Hauptprojektdatei. #include "stdafx.h" #include <String> #include <iostream> #include <ctime> #include "D:\Filesystem\Projekte\Visual Studio Projekte\Block\Block\Block.h" using namespace std; int main(void) { short Zeilen=8,Spalten=5,Bloecke=10,zaehler=0,i=0,j; srand(unsigned(time(NULL))); //globalen randomzähler initialisieren cout << "Das programm wird gestartet, die initialisierung von block.h hat funktioniert" << endl; Block Blocksworld(Zeilen,Spalten,Bloecke); //erstellen und initialisieren des objektes cout << "Die Zielmatrix:"; Blocksworld.display_target_matrix(); //zielmatrix ausgeben cout << "Die momentane Matrix :"; Blocksworld.display_current_matrix(); //aktuelle matrix ausgeben while(Blocksworld.get_maxfalse_blocks()!=0 && i<4){ //solange es noch eine spalte mit mehr als einem falschen element gibt //#########################Variante 1 ################################ //if(!Blocksworld.solve_block(Blocksworld.get_minfalse_column())) i++; //soll in der spalte, wo die wenigsten elemente falsch sind ein block bearbeitet werden //#########################Variante 2 ############################### j=i+1; if(!Blocksworld.solve_block(Blocksworld.get_minfalse_column_2(j))) i++; else i=0; //cout << "blockkonstellation" << endl; //Blocksworld.display_current_matrix(); //cout << endl; zaehler++; } if (i>3) cout << "Das Problem konnte nicht geloest werden!" << endl; else cout << "Nach: " <<zaehler<< " Schritten sieht die Matrix wie folgt aus" << endl; Blocksworld.display_current_matrix(); //ausgabe der aktuellen matrix um mit der zielmatrix zu vergleichen system("PAUSE"); return 0; }
Ich weiß es ist ziemlich viel Code. Wie sinnvoll die einzelnen Algorithmen sind soll natürlich keiner prüfen. Es geht mir nur um Fehler/Verbesserungsvorschläge zum Thema Programmieren in C++. Über weitere Kritik bin ich sehr dankbar.
-
Hat sich erledigt, habe um den Code für andere kompilierbar zu machen wieder auf srand/rand umgestellt
-
Up
-
Tu dir einen Gefallen, besorg dir ein schlaues C++ Buch und lerne C++ richtig.
Includes mit absoluten Pfaden sind Pfui. Dafür gibt es die Möglichkeit, Suchpfade für Includes anzugeben.
Es sieht nicht so aus, als wüsstest du, wie man Implementierungen der Elementfunktionen von der Klassendefinition trennen kann. Und trennen solltest du das bei relativ vielen Funktionen.
-
Sherlock schrieb:
// [...] bzw vor die random System::
Es gibt kein System-namespace in C++.
-
Bitte poste keinen Quelltext mit 50 Zeilen oder mehr!
-
Edit: lol, verlesen.