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 🙂


  • Mod

    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 & swap

    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.

    *: 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 & swap

    Vielen 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 🙂


  • Mod

    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!


  • Mod

    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>> ein vector<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>> ein vector<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.


Anmelden zum Antworten