From 18f5012f4a7be865c498e360b0a016855a80f3cf Mon Sep 17 00:00:00 2001 From: Jonny007-MKD <1-23-4-5@web.de> Date: Mon, 13 Jan 2014 00:44:05 +0100 Subject: [PATCH] Added Comments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Das sollte ausführlich genug sein --- Hazard/Hazard/CParser.cpp | 14 +- Hazard/Hazard/Cell.cpp | 35 ++- Hazard/Hazard/Cell.h | 26 +- Hazard/Hazard/CellCollection.cpp | 58 +++- Hazard/Hazard/CellCollection.h | 44 +-- Hazard/Hazard/Hazard.cpp | 173 ++++++----- Hazard/Hazard/KV.cpp | 341 ++++++++++++++-------- Hazard/Hazard/KV.h | 106 +++---- Hazard/Hazard/KV_PiEleLoc.h | 22 +- Hazard/Hazard/KV_PiGroup.cpp | 66 +++-- Hazard/Hazard/KV_PiGroup.h | 19 +- Hazard/Hazard/PrimImplikant.cpp | 78 +++-- Hazard/Hazard/PrimImplikant.h | 84 ++++-- Hazard/Hazard/PrimImplikantCollection.cpp | 88 ++++-- Hazard/Hazard/PrimImplikantCollection.h | 41 ++- Hazard/Hazard/Tools.cpp | 97 ++++-- Hazard/Hazard/Tools.h | 17 +- Hazard/Hazard/Wertetabelle.cpp | 102 ++++--- Hazard/Hazard/Wertetabelle.h | 36 +-- 19 files changed, 908 insertions(+), 539 deletions(-) diff --git a/Hazard/Hazard/CParser.cpp b/Hazard/Hazard/CParser.cpp index 94b7a10..b1dd1eb 100644 --- a/Hazard/Hazard/CParser.cpp +++ b/Hazard/Hazard/CParser.cpp @@ -86,7 +86,7 @@ int CParser::yyparse(PrimImplikantCollection* &pic, vector* &variables) { case IDENTIFIER: *IP_List << "Variable " << yylval.s << endl; - variables->push_back(yylval.s.c_str()); + variables->push_back(yylval.s.c_str()); // Add variable name to vector break; case TERMS: *IP_List << endl; @@ -99,10 +99,10 @@ int CParser::yyparse(PrimImplikantCollection* &pic, vector* &variables) { case STRING1: *IP_List << "Term Key " << yylval.s << endl; - pic->add(yylval.s.c_str()); + pic->add(yylval.s.c_str()); // Add PrimImplikant with string break; case INTEGER1: - *IP_List << "Term Key " << (unsigned int)yylval.i << endl; + *IP_List << "Term Key " << (unsigned int)yylval.i << endl; // Add PrimImplikant with int pic->add(yylval.i); break; case (int)'>': @@ -114,14 +114,14 @@ int CParser::yyparse(PrimImplikantCollection* &pic, vector* &variables) } break; case P_TERMS_VALUE: - if (tok == INTEGER1) + if (tok == INTEGER1) // Check whether KNF was already set and then check consitency { if (!KNFset) { KNF = (yylval.i == 0); KNFset = true; } - else if ((yylval.i == 0) ^ KNF) + else if ((yylval.i == 0) != KNF) { *IP_Error << "*** FATAL ERROR *** You can only define either KNF or DNF!" << endl; *IP_Error << "In line " << setw(3) << setfill('0') << IP_LineNumber << ": " << pic->back()->name << '>' << yylval.i << endl; @@ -137,8 +137,8 @@ int CParser::yyparse(PrimImplikantCollection* &pic, vector* &variables) } } - dimension = variables->size(); - numElements = (unsigned int)pow(2.0f, (int)dimension); + dimension = variables->size(); // set global variable dimension + numElements = (unsigned int)pow(2.0f, (int)dimension); // set global variabl numElements return 0; } diff --git a/Hazard/Hazard/Cell.cpp b/Hazard/Hazard/Cell.cpp index 0f059a5..b418488 100644 --- a/Hazard/Hazard/Cell.cpp +++ b/Hazard/Hazard/Cell.cpp @@ -6,48 +6,65 @@ using namespace std; -extern uint dimension; +extern uint dimension; // number of variables +/// +/// Gets all PrimImplikants that cover this Cell from globalPIC +/// void Cell::refresh(PrimImplikantCollection* &globalPIC) { this->primImplikanten = globalPIC->primImplikantenAt(index); } +/// +/// Gets all Cells that lie next to this Cell (Hamming distance = 1) +/// +/// A vector with Cells with size: dimension vector* Cell::getNeighbors(vector &allCells) { vector* neighbors = new vector(); + neighbors->resize(dimension); uint j = 1; - for (unsigned char i = 0; i < dimension; i++) + for (unsigned char i = 0; i < dimension; i++) // for all bits { - neighbors->push_back(allCells[this->index ^ j]); + neighbors->at(i) = allCells[this->index ^ j]; // add Cell that is different at one bit (j) j <<= 1; } return neighbors; } +/// +/// Looks for hazards around this Cell +/// +/// A vector with those Cells that lie next to this Cell and to which a hazard may occur vector* Cell::getHazards(vector &allCells) { vector* hazardous = new vector(); vector* neighbors = this->getNeighbors(allCells); - for (vector::iterator neighbor = neighbors->begin(); neighbor < neighbors->end(); neighbor++) + for (vector::iterator neighbor = neighbors->begin(); neighbor < neighbors->end(); neighbor++) // for each neighbor { - if ((*neighbor)->value == false) + if ((*neighbor)->value == false) // if the neighbor is not covered by a PrimImpliaknt, no hazard can occur continue; - if ((*neighbor)->hasOneOfThose(this->primImplikanten) == false) - hazardous->push_back(*neighbor); + if ((*neighbor)->hasOneOfThose(this->primImplikanten) == false) // check whether at least one PrimImplikant that covers this Cell also covers the neighbor cell + hazardous->push_back(*neighbor); // if not, add it to hazardous } delete neighbors; return hazardous; } +/// +/// Checks whether this Cell is covered by a PrimImplikant that is member of the specified PrimImplikantCollection (of another Cell) +/// +/// True: A PrimImplikant in foreignPic also covers this Cell bool Cell::hasOneOfThose(PrimImplikantCollection &foreignPic) { - for (uint i = 0; i < foreignPic.size(); i++) - if (this->primImplikanten.contains(foreignPic[i])) + for (uint i = 0; i < foreignPic.size(); i++) // for each foreign PrimImplikant + if (this->primImplikanten.contains(foreignPic[i])) // check whether it also covers this Cell return true; + return false; } \ No newline at end of file diff --git a/Hazard/Hazard/Cell.h b/Hazard/Hazard/Cell.h index c9f6674..1a421aa 100644 --- a/Hazard/Hazard/Cell.h +++ b/Hazard/Hazard/Cell.h @@ -1,30 +1,36 @@ +#pragma once + #include #include #include "PrimImplikantCollection.h" using namespace std; -#ifndef CELL -#define CELL class Cell { public: - bool value; - unsigned int index; + bool value; // DNF value + unsigned int index; // position of this Cell - vector* getNeighbors(vector &allCells); // returns numElements Cells + vector* getNeighbors(vector &allCells); // returns all Cells which's Hamming distance 1 vector* getHazards(vector &allCells); // returns the neighbor Cells which are hazardous - bool hasOneOfThose(PrimImplikantCollection &foreignPIC); - void refresh(PrimImplikantCollection* &globalPIC); // refreshes the local primImplikantCollection + bool hasOneOfThose(PrimImplikantCollection &foreignPIC); // returns whether this Cell is covered by a PrimImplikant of the specified foreignPIC + void refresh(PrimImplikantCollection* &globalPIC); // refreshes the local primImplikantCollection from globalPIC - Cell(unsigned int index, PrimImplikantCollection* &globalPIC) + /// + /// Constructor of Cell + /// + Cell(uint index, PrimImplikantCollection* &globalPIC) { this->index = index; this->refresh(globalPIC); - this->value = this->primImplikanten.size() > 0; + this->value = this->primImplikanten.size() > 0; // if a PrimImplikant covers this Cell, it is true in DNF } - PrimImplikantCollection primImplikanten; + PrimImplikantCollection primImplikanten; // all PrimImplikants that cover this Cell }; +#ifndef CELLITERATOR +#define CELLITERATOR +typedef vector::iterator CellIt; #endif \ No newline at end of file diff --git a/Hazard/Hazard/CellCollection.cpp b/Hazard/Hazard/CellCollection.cpp index c027444..b12466c 100644 --- a/Hazard/Hazard/CellCollection.cpp +++ b/Hazard/Hazard/CellCollection.cpp @@ -6,43 +6,52 @@ using namespace std; -extern uint dimension; -extern uint numElements; +extern uint dimension; // number of variables +extern uint numElements; // number of Cells/possible numbers +/// +/// Add a Cell to the collection +/// void CellCollection::add(Cell* &cell) { this->cells.push_back(cell); } -void CellCollection::init(PrimImplikantCollection* &globalPIC) +/// +/// Creates all Cells that exist with the specified number of variables +/// +void CellCollection::init() { - this->globalPIC = globalPIC; this->cells.resize(numElements); for (uint i = 0; i < numElements; i++) - this->cells[i] = new Cell(i, globalPIC); + this->cells[i] = new Cell(i, this->globalPIC); } +/// +/// The hazard detection algorithm +/// We look at every second Cell and if this Cell's value is true (DNF) we asksits neighbors whether there is a PrimImplikant that covers both Cells. If not, we have found a hazard and can create a PrimImplikant that solves it. +/// void CellCollection::findHazards() { - for (uint i = 0; i < numElements; i += 2) // we only need to check every 2nd as long as it's gray + for (uint i = 0; i < numElements; i += 2) // only every 2nd Cell because hazards are checked on all sides of the Cell { uint I = i ^ (i/2); // transform to gray code --> Schachbrettmuster Cell* currentCell = cells[I]; // this is the cell we are currently checking - if (currentCell->value == false) // no hazard can occur + if (currentCell->value == false) // no hazard can occur because no PrimImplikant covers this Cell continue; cout << " Checking cell " << I << endl; - vector* hazardousNeighbors = currentCell->getHazards(this->cells); + vector* hazardousNeighbors = currentCell->getHazards(this->cells); // get neighbor Cells with hazards - if (hazardousNeighbors->size() == 0) // no hazard found + if (hazardousNeighbors->size() == 0) // no hazard was found { delete hazardousNeighbors; continue; } - for (vector::iterator nc = hazardousNeighbors->begin(); nc < hazardousNeighbors->end(); nc++) + for (CellIt nc = hazardousNeighbors->begin(); nc < hazardousNeighbors->end(); nc++) // foreach neighbor Cell with hazard { printf("Hazard found! Cell %d <--> Cell %d\n", I, (*nc)->index); this->globalPIC->add(I, (*nc)->index); // add PI that solves hazard. Not quite smart... @@ -56,35 +65,54 @@ void CellCollection::findHazards() +/// +/// Deletes all Cell instances in this collection +/// Beware: Only do this at the end! All collections are storing pointers to the Cells and maybe some other object is still using them. Dispose() may only be called by the last instance of this class (which we could check programmatically and then integrate it into the destructor) +/// void CellCollection::Dispose() { - for (uint i = 0; i < this->cells.size(); i++) - delete cells[i]; + for (CellIt i = this->cells.begin(); i < this->cells.end(); i++) + delete (*i); + this->cells.clear(); } +/// +/// Returns the number of Cells in this Collection +/// uint CellCollection::size() { return cells.size(); } +/// +/// Returns the last Cell in here +/// Cell* CellCollection::back() { return cells.back(); } +/// +/// Returns the first Cell in here +/// Cell* CellCollection::front() { return cells.front(); } -Cell* CellCollection::at(uint index) +/// +/// Returns the Cell at the specified index +/// +Cell* CellCollection::at(const uint index) { return cells.at(index); } - -Cell * CellCollection::operator[](uint &index) +/// +/// Returns the Cell at the specified index +/// +Cell * CellCollection::operator[](const uint &index) { return cells.at(index); } \ No newline at end of file diff --git a/Hazard/Hazard/CellCollection.h b/Hazard/Hazard/CellCollection.h index 2e8abea..9232b26 100644 --- a/Hazard/Hazard/CellCollection.h +++ b/Hazard/Hazard/CellCollection.h @@ -6,34 +6,38 @@ using namespace std; -#ifndef _CELLCOLLEC_H -#define _CELLCOLLEC_H - -class CellCollection { +/// +/// This class contains a number of Cells and provides some methods to operate on/with those +/// +class CellCollection +{ +private: + void init(); // creates a CellCollection with numElements Cells and adds the associated PrimImplikants to each of those public: - void add(Cell* &cell); - void init(PrimImplikantCollection* &globalPIC); - void findHazards(); + void add(Cell* &cell); // adds a Cell to this collection + void findHazards(); // the hazard detection algorithm - void Dispose(); + void Dispose(); // delete all referenced Cell objects - uint size(); - Cell* back(); - Cell* front(); - Cell* at(uint index); - Cell* operator[](uint &index); + uint size(); // the number of Cells in this collection + Cell* back(); // the last Cell in here + Cell* front(); // the first Cell in here + Cell* at(const uint index); // the Cell at the specified index + Cell* operator[](const uint &index);// the Cell at the specified index + /// + /// Constructor of CellCollection + /// CellCollection(PrimImplikantCollection* &globalPIC) { - this->init(globalPIC); + this->globalPIC = globalPIC; + this->init(); this->hazardsFound = false; }; - vector cells; - PrimImplikantCollection* globalPIC; - bool hazardsFound; -}; - -#endif \ No newline at end of file + vector cells; // vector with Cells + PrimImplikantCollection* globalPIC; // a reference to the global PrimImplikantCollection + bool hazardsFound; // whether findHazards() found hazards =) +}; \ No newline at end of file diff --git a/Hazard/Hazard/Hazard.cpp b/Hazard/Hazard/Hazard.cpp index 810d17e..8c69adb 100644 --- a/Hazard/Hazard/Hazard.cpp +++ b/Hazard/Hazard/Hazard.cpp @@ -6,30 +6,41 @@ #include "CParser.h" #include "PrimImplikant.h" #include "PrimImplikantCollection.h" -#include "Cell.h" #include "CellCollection.h" #include "Wertetabelle.h" #include "KV.h" using namespace std; -uint dimension = 0; // = variables.size() -uint numElements = 0; // = 2 ^ dimension -bool KNF = false; -bool fileChosen = false; -char fnInput[256]; - +uint dimension = 0; // number of variables = variables.size() +uint numElements = 0; // number of elements/cells = 2 ^ dimension +bool KNF = false; // Is the output in KNF or DNF. This is only used for output. All calc is done in DNF +bool fileChosen = false; // Whether the input file shall be opened again next time +char fnInput[256]; // The path to the input file +/// +/// Takes care of opening the input and output file streams. +/// It also asks the user to select the input file using GetOpenFileName +/// +/// The input file where we will read the data from +/// The parser error log file +/// The parser listing log file +/// The output file for the Wertetabelle +/// An error code: +/// - 0, 9: Everything fine +/// - 1: File open error +/// - 2: User aborted GetOpenFileName +/// int open_files(ifstream &input, ofstream &error, ofstream &list, ofstream &wt) { - if (fileChosen == true) // don't reopen files + if (fileChosen == true) // do not reopen files return 9; - GetCurrentDirectory(sizeof(fnInput), fnInput); + GetCurrentDirectory(sizeof(fnInput), fnInput); // returns the current working directory - if (!error.is_open()) + if (!error.is_open()) // if we have not opened the parser error log file before { - char fnError[256]; + char fnError[256]; // create path: .\res\errorParser.txt strcpy_s(fnError, (string(fnInput) + "\\res\\errorParser.txt").c_str()); error.open(fnError, ofstream::out|ofstream::app); if (!error.is_open()) @@ -38,9 +49,9 @@ int open_files(ifstream &input, ofstream &error, ofstream &list, ofstream &wt) return 1; } } - if (!list.is_open()) + if (!list.is_open()) // if we have not opened the parser listing log file before { - char fnLists[256]; + char fnLists[256]; // create path: .\res\listParser.txt strcpy_s(fnLists, (string(fnInput) + "\\res\\listParser.txt").c_str()); list.open(fnLists, ofstream::out|ofstream::trunc); if (!list.is_open()) @@ -49,9 +60,9 @@ int open_files(ifstream &input, ofstream &error, ofstream &list, ofstream &wt) return 1; } } - if (!wt.is_open()) + if (!wt.is_open()) // if we have not opened the Wertetabelle file before { - char fnWt[256]; + char fnWt[256]; // create path: .\res\Wertetabelle.txt strcpy_s(fnWt, (string(fnInput) + "\\res\\Wertetabelle.txt").c_str()); wt.open(fnWt, ofstream::out|ofstream::trunc); if (!wt.is_open()) @@ -61,134 +72,134 @@ int open_files(ifstream &input, ofstream &error, ofstream &list, ofstream &wt) } } - strcpy_s(fnInput, (string(fnInput) + "\\res\\input.txt").c_str()); + strcpy_s(fnInput, (string(fnInput) + "\\res\\input.txt").c_str()); // create initial input path: .\res\input.txt - OPENFILENAME ofn; - ZeroMemory(&ofn, sizeof(ofn)); - ofn.lStructSize = sizeof(ofn); - ofn.hwndOwner = NULL; - ofn.lpstrFile = fnInput; - ofn.nMaxFile = sizeof(fnInput); - ofn.lpstrFilter = "All\0*.*\0Text\0*.TXT\0"; - ofn.nFilterIndex = 1; - ofn.lpstrFileTitle = NULL; + OPENFILENAME ofn; // create OPENFILENAME structure for Windows method + ZeroMemory(&ofn, sizeof(ofn)); // zero everything + ofn.lStructSize = sizeof(ofn); // tell windows the size of the struct + ofn.hwndOwner = NULL; // we do not have a window handle (perhaps GDE does?) + ofn.lpstrFile = fnInput; // input file path + ofn.nMaxFile = sizeof(fnInput); // maximum input file path length + ofn.lpstrFilter = "All\0*.*\0Text\0*.TXT\0";// selection filter + ofn.nFilterIndex = 1; // default selected filter + ofn.lpstrFileTitle = NULL; ofn.nMaxFileTitle = 0; ofn.lpstrInitialDir = NULL; ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; - if (GetOpenFileName(&ofn) != TRUE) + if (GetOpenFileName(&ofn) != TRUE) // if the user aborted GetOpenFileName or something else went wrong { cout << "Auswahl der Inputdatei abgebrochen!"; return 2; } - fileChosen = true; + fileChosen = true; // do not reload input file next time again - if (input.is_open()) - input.close(); - input.open(fnInput, ifstream::in); + if (input.is_open()) // if a input file was opened before + input.close(); // close it + input.open(fnInput, ifstream::in); // and then open the new file if (!input.is_open()) { perror("Fehler beim Lesen der Inputdatei"); return 1; } + return 0; } -void pause() -{ -#ifdef DEBUG - system("pause"); -#endif -} - +/// +/// The main user function that is called by the GDE. +/// It is running in a global while and performs all calculation. void user_main(void) { - ifstream fInput; - ofstream fError, fList, fWt; - KV* kv; + ifstream fInput; // the input file + ofstream fError, fList, fWt; // some output files: parser error, parser listing, Wertetabelle + KV* kv; // pointer to KV class while(1) { - switch(open_files(fInput, fError, fList, fWt)) + switch(open_files(fInput, fError, fList, fWt)) // try to open the file streams { - case 1: // some error + case 1: // some error fileChosen = false; perror("Error while opening a file (1)"); continue; - case 2: // user aborted - ExitProcess(2); + case 2: // user aborted GetOpenFileName + ExitProcess(2); // we do not tolerate those users! :> break; - case 9: // same input as before - // We could skip recalculation, but then the GDE is not redrawn (updatescr doesn't help) :/ - case 0: // new file opened + case 9: // same input file as before + // We could skip recalculation, but then the GDE is not redrawn (updatescr only doesn't help. And since we are not storing the PrimImplikantCollection without solved Hazards we have to do everything again) :/ + case 0: // new file opened { cout << endl << endl << endl << endl; - PrimImplikantCollection* globalPIC = new PrimImplikantCollection(); - vector* variables = new vector(); + PrimImplikantCollection* globalPIC = new PrimImplikantCollection(); // a new collection of PrimImplikants + vector* variables = new vector(); // a collection with the variable names fInput.clear(); - fInput.seekg(0, fInput.beg); - CParser* parser = new CParser(fInput, fError, fList); - int parseFailure = parser->yyparse(globalPIC, variables); - delete parser; + fInput.seekg(0, fInput.beg); // rewind fInput + CParser* parser = new CParser(fInput, fError, fList); // init our parser + int parseFailure = parser->yyparse(globalPIC, variables); // parse the specified file, write data into globalPIC and variables + delete parser; // we do not need it anymore + parser = NULL; - if (parseFailure != 0) + if (parseFailure != 0) // something went wrong { - fileChosen = false; - string error = "Error while parsing the input ("; + fileChosen = false; // let the user select a new file next time + string error = "Error while parsing the input ("; // create a string with the error char buf[5]; _itoa_s(parseFailure, buf, 10); error += buf; error += ")"; perror(error.c_str()); fError << error << endl; - continue; + continue; // start over again } - // initialize Cells - CellCollection* allCells = new CellCollection(globalPIC); + + CellCollection* allCells = new CellCollection(globalPIC); // initialize our Cells collection - fWt.seekp(0, fWt.beg); + fWt.seekp(0, fWt.beg); // rewind fWt // print Wertetabelle and KV of imported data - Wertetabelle* wt = new Wertetabelle(allCells, variables, fWt); - wt->Print(); + Wertetabelle* wt = new Wertetabelle(allCells, variables, fWt); // init Wertetabelle + wt->Print(); // print Wertetabelle to console and fWt - kv = new KV(globalPIC, allCells, 30,variables); - kv->Print(30); + kv = new KV(globalPIC, allCells, 30,variables); // init KV + kv->Print(30); // print KV diagram at offset 30,30 - // find and solve Hazards - allCells->findHazards(); + allCells->findHazards(); // find and solve Hazards + // this is the actual hazard detection and resolving algorithm if (allCells->hazardsFound) - // print Wertetabelle and KV of corrected data - wt->Print(); + wt->Print(); // print Wertetabelle of corrected data - kv->Print(30 + kv->width() + 30, 30); // Diagramm neben dem vorherigen + kv->Print(30 + kv->width() + 30, 30); // print KV of corrected data + // this KV is next to previous KV - kv->Buttons(); - delete wt; + // if we would not recalculate everything we could save this stuff: + delete wt; // but as it is now we do not need it anymore. Let's delete it so it won't take any memory wt = NULL; - globalPIC->Dispose(); - delete globalPIC; + globalPIC->Dispose(); // delete all PrimImplikanten in globalPIC (= all PrimImplikanten) + delete globalPIC; // Dispose() could not be moved to ~destructor since we are using this class at several other points where it get's destroyed again. And we want to keep our PrimImplikanten globalPIC = NULL; - allCells->Dispose(); + allCells->Dispose(); // it's the same with our Cells delete allCells; allCells = NULL; - delete variables; + delete variables; // also the variables can be deleted variables = NULL; - break;} + + kv->Buttons(); // Print the GDE buttons and wait for user input + } } - if (kv->StopProcess()) + if (kv->StopProcess()) // user want's to stop us { - if (kv != NULL) - delete kv; + if (kv != NULL) // delete KV class here, we did need it for the buttons + delete kv; kv = NULL; fInput.close(); fList.close(); @@ -197,5 +208,9 @@ void user_main(void) fileChosen = false; break; } + + if (kv != NULL) // delete KV class here, we did need it for the buttons + delete kv; + kv = NULL; } } \ No newline at end of file diff --git a/Hazard/Hazard/KV.cpp b/Hazard/Hazard/KV.cpp index 1cdc211..92e325e 100644 --- a/Hazard/Hazard/KV.cpp +++ b/Hazard/Hazard/KV.cpp @@ -6,29 +6,40 @@ #include "Tools.h" #include "KV.h" -extern uint dimension; -extern uint numElements; -extern bool KNF; -extern bool fileChosen; +extern uint dimension; // number of variables +extern uint numElements; // number of elements/fields +extern bool KNF; // KNF/DNF +extern bool fileChosen; // set false to open a new input file using namespace std; - +/// +/// Clears the GDE screen and adjusts the drawing area +/// void KV::Clear() { int ww, hh; get_windowsize(&ww,&hh); - set_drawarea(ww,hh); // Setzen des Zeichenbereiches - clrscr(); // Clear screen + set_drawarea(ww,hh); + clrscr(); } +/// +/// Prints a KV diagram at position [offset | offset] +/// +/// The X and Y offset in px void KV::Print(uint offset) { this->Print(offset, offset); } +/// +/// Prints a KV diagram at position [offsetX | offsetY] +/// +/// Free space to the left side in Pixels +/// Free space to the upper side in Pixels void KV::Print(uint offsetX, uint offsetY) { - if (this->numVarX == 0 || this->numVarY == 0) + if (this->numVarX == 0 || this->numVarY == 0) // Import failed return; this->offsetX = offsetX; @@ -40,46 +51,57 @@ void KV::Print(uint offsetX, uint offsetY) this->PrintCellValues(); this->PrintPrimImplikanten(); - updatescr(); // make this f****** GDE update, does not work everytime :/ + updatescr(); } +/// +/// Returns the width of a KV diagram +/// uint KV::width() { return this->widthPx; } +/// +/// Returns the height of a KV diagram +/// uint KV::height() { return this->heightPx; } +/// +/// Sets the variables VarXY_Length and string_VarXY +/// The variable names are separated by X/Y position. Then the size of the first X row and first Y column is calculated +/// void KV::Setstring_Var() { - this->string_VarY = ""; this->string_VarX = ""; + this->string_VarY = ""; - for (uint i = 0; i < this->variables->size(); i++) + for (uint i = 0; i < this->variables->size(); i++) // für alle Variablen { - if (i >= this->numVarY) + if (i >= this->numVarY) // wenn X-Zeile this->string_VarX += this->variables->at(i) + " "; - else + else // wenn Y-Spalte this->string_VarY += this->variables->at(i) + " "; } - this->string_VarX = this->string_VarX.substr(0, this->string_VarX.size()-1); - this->string_VarY = this->string_VarY.substr(0, this->string_VarY.size()-1); + this->string_VarX = this->string_VarX.substr(0, this->string_VarX.size()-1); // letztes Leerzeichen löschen + this->string_VarY = this->string_VarY.substr(0, this->string_VarY.size()-1); // letztes Leerzeichen löschen - // Weitere Initialisierung der restlichen privaten Klassenelemente. - - this->VarX_Length = max(this->edgeLength+1, this->string_VarX.size() * 9); + this->VarX_Length = max(this->edgeLength+1, this->string_VarX.size() * 9); // berechnen der Größe. Pro Buchstabe werden 9 Pixel geschätzt. this->VarY_Length = max(this->edgeLength+1, this->string_VarY.size() * 9); } -void KV::PrintRaster() // Erstellt die Felder: ▯▯▯ -{ // ▯▯▯ - // ▯▯▯ - - this->Line(this->VarY_Length, 0, this->VarY_Length, this->heightPx, BLACK); // first vertical line, one edge shorter - this->Line(0, this->VarX_Length, 0, this->heightPx, BLACK); // second vertical line - for (uint w = 1; w <= this->numFieldX ; w++) // vertical lines. Periodic with (edgeLength + 1) +/// +/// Generates the skeleton of a KV diagram: +/// ▯▯▯ +/// ▯▯▯ +/// ▯▯▯ +/// +void KV::PrintRaster() +{ + this->Line(0, this->VarX_Length, 0, this->heightPx, BLACK); // first vertical line, one edge shorter + for (uint w = 0; w <= this->numFieldX ; w++) // vertical lines. Periodic with (edgeLength + 1) { uint X = w * (this->edgeLength + 1) + VarY_Length; // X position of the line this->Line(X, 0, X, this->heightPx, BLACK); @@ -87,194 +109,219 @@ void KV::PrintRaster() // Erstellt die Felder: ▯▯▯ this->Line(this->VarY_Length, 0, this->widthPx, 0, BLACK); // first horizontal line, one edge shorter - this->Line(0, this->VarX_Length, this->widthPx, this->VarX_Length, BLACK); // +10 to avoid the strings collision - // second horizontal line - for (uint h = 1; h <= this->numFieldY ; h++) // horizontal lines. Periodic with (edgeLength + 1) + for (uint h = 0; h <= this->numFieldY ; h++) // horizontal lines. Periodic with (edgeLength + 1) { uint Y = h * (this->edgeLength + 1) + this->VarX_Length; // Y position of the line this->Line(0, Y, this->widthPx, Y, BLACK); } } +/// +/// Generates the variable names in the first cell +/// â–ˆ ▯▯ +/// ▯▯▯ +/// ▯▯▯ +/// void KV::PrintString_Var() { - char* valueY = (char*)this->string_VarY.c_str(); - char* valueX= (char*)this->string_VarX.c_str(); - uint x1_valueY = 2; // coordinante of ValueY - uint y1_valueY = this->VarX_Length-16; + uint x_valueX = this->VarY_Length-16; // coordinante of variables in first row (X) + uint y_valueX = this->VarX_Length-12; - uint x1_valueX = this->VarY_Length-16; // coordinante of ValueX - uint y1_valueX = this->VarX_Length-12; + uint x_valueY = 2; // coordinante of variables in first column (Y) + uint y_valueY = this->VarX_Length-16; - this->Text(x1_valueX, y1_valueX, 10, BLACK, WHITE, 90, 0, valueX); - this->Text(x1_valueY, y1_valueY, 10, BLACK, WHITE, 00, 0, valueY); + this->Text(x_valueX, y_valueX, 10, BLACK, WHITE, 90, (char*)this->string_VarX.c_str()); // 90°, Black + this->Text(x_valueY, y_valueY, 10, BLACK, WHITE, 00, (char*)this->string_VarY.c_str()); // 0°, Black } -void KV::PrintVariables() // Erstellt die Werte der Variablen in der ersten X- und Y-Spalte: â–¯ 0 1 -{ // 0 ▯▯ - // 1 ▯▯ - for (uint w = 0; w < this->numFieldX; w++) // horizontal variable text +/// +/// Generates the variable values in the first row (X) and column (Y) +/// â–¯ 0 1 +/// 0 ▯▯ +/// 1 ▯▯ +/// +void KV::PrintVariables() +{ + for (uint w = 0; w < this->numFieldX; w++) // horizontal variable text (X) { - uint XL = w * (this->edgeLength + 1) + this->VarY_Length; - uint XR = XL + this->edgeLength; - char* value = Tools::BinaryToChars(w ^ (w / 2), this->numVarX); // in Gray und String umwandeln - this->TextBoxBold(XL, 0, XR, this->VarX_Length, 10, BLACK, TRANS, TRANS, SINGLE_LINE|CENTER_ALIGN|BOTTOM_ALIGN, value); + uint XL = w * (this->edgeLength + 1) + this->VarY_Length; // left side = position of cell (see PrintRaster) + uint XR = XL + this->edgeLength; // right side = left side + cell size + uint YT = 0; // upper side = 0 (first row) + uint YB = this->VarX_Length; // lower side = height of first row + char* value = Tools::BinaryToChars(w ^ w/2, this->numVarX); // convert w in Gray and in String + this->TextBoxBold(XL, YT, XR, YB, 10, BLACK, TRANS, TRANS, SINGLE_LINE|CENTER_ALIGN|BOTTOM_ALIGN, value); delete value; } - for (uint h = 0; h < this->numFieldY; h++) // vertical variable text + for (uint h = 0; h < this->numFieldY; h++) // vertical variable text (Y) { - uint YT = h * (this->edgeLength + 1) + this->VarX_Length + 1; - uint YB = YT + this->edgeLength; - char* value = Tools::BinaryToChars(h ^ (h / 2), this->numVarY); // in Gray und String umwandeln - this->TextBoxBold(0, YT, this->VarY_Length-5, YB, 10, BLACK, TRANS, TRANS, SINGLE_LINE|RIGHT_ALIGN|VCENTER_ALIGN, value); + uint XL = 0; // left side = 0 (first column) + uint XR = this->VarY_Length-5; // right side = width of column - offset to border + uint YT = h * (this->edgeLength + 1) + this->VarX_Length + 1; // upper side = position of cell (see PrintRaster) + uint YB = YT + this->edgeLength; // lower side = upper side + cell size + char* value = Tools::BinaryToChars(h ^ (h / 2), this->numVarY); // convert w in Gray and in String + this->TextBoxBold(XL, YT, XR, YB, 10, BLACK, TRANS, TRANS, SINGLE_LINE|RIGHT_ALIGN|VCENTER_ALIGN, value); delete value; } } -void KV::PrintCellValues() // Erstellt die Werte der jeweiligen Zellen: ▯▯▯ -{ // â–¯ x x - // â–¯ x x - for (uint h = 0; h < this->numFieldY; h++) // jede Spalte durchgehen +/// +/// Generates the values of the inner cells +/// ▯▯▯ +/// â–¯ x x +/// â–¯ x x +/// +void KV::PrintCellValues() +{ + for (uint h = 0; h < this->numFieldY; h++) // für jede Spalte { - uint YT = h * (this->edgeLength + 1)+ this->VarX_Length; // Y Positionen berechnen + uint YT = h * (this->edgeLength + 1)+ this->VarX_Length; // Y-Positionen berechnen uint YB = YT + this->edgeLength; - for (uint w = 0; w < this->numFieldX; w++) // jede Zeile durchgehen + for (uint w = 0; w < this->numFieldX; w++) // für jede Zeile { - uint XL = w * (this->edgeLength + 1) + this->VarY_Length; // X Positionen berechnen + uint XL = w * (this->edgeLength + 1) + this->VarY_Length; // X-Positionen berechnen uint XR = XL + this->edgeLength; - uint i = ((h^h / 2) << this->numVarX) | (w^w / 2); // w und h müssen getrennt in Gray umgewandelt werden (weil sie so aufgetragen wurden) - // zusammengesetzt ergeben sie dann unsere aktuelle Position + uint i = ((h ^ h/2) << this->numVarX) | (w ^ w/2); // nun muss noch die aktuelle Position berechnet werden + // hierbei werden Y und X getrennt in Gray umgewandelt und dann kombiniert // Dies sind die Zellnummern: /* char* I = new char[(int)(ceil(log10((float)numElements)))+1]; - itoa(i, I, 10); - this->TextBox(XL, YT, XR, YB, 10, BLACK, TRANS, TRANS, CENTER, I); + itoa(i, I, 10); // aktuelle Position zu String + this->TextBox(XL, YT, XR, YB, 10, BLACK, TRANS, TRANS, CENTER, I); // schreiben */ // Dies sind die Zellwerte: ///* - char* I = new char[2]; - _itoa_s(this->allCells->at(i)->value ^ KNF, I, 2, 10); - this->TextBox(XL, YT, XR, YB, 10, BLACK, TRANS, TRANS, CENTER, I); + char* I = new char[2]; // nur ein Charakter + _itoa_s(this->allCells->at(i)->value ^ KNF, I, 2, 10); // value der Zelle XOR KNF in String + this->TextBox(XL, YT, XR, YB, 10, BLACK, TRANS, TRANS, CENTER, I); // schreiben delete I; //*/ } } } +/// +/// Generates KV_PiGroups for every PrimImplikant and lets PrintPrimImplikantenGroup() print it +/// We have to use these Groups because we can only draw (and see) 2D images but we need more dimensions to display the Cells next to all their neighbors. Due to this limitation not cells may not be next to all of their neighbors which results in several groups that represent a PrimImplikant +/// void KV::PrintPrimImplikanten() { - srand((uint)time(NULL) ^ rand()); - vector piGroups; + srand((uint)time(NULL) ^ rand()); // give us some randomity =) + vector piGroups; // our vector with groups - for (uint i = 0; i < this->globalPic->size(); i++) // for each PrimImplikant + for (uint i = 0; i < this->globalPic->size(); i++) // for each PrimImplikant, main loop { PrimImplikant* currentPI = this->globalPic->at(i); - uint color; + uint color; // define a color for this PrimImplikant char random; - if (currentPI->name.find("|") != string::npos) // define a color for this PI + if (currentPI->name.find("|") != string::npos) // this PrimImplikant solves a hazard { - random = -1; + random = -1; // save this fact in random uint r = rand() % 128 + 128; uint gb = rand() % 100; - color = RGB(r, gb, gb); // some red color + color = RGB(r, gb, gb); // some red color (r > gb, g == b) } else { - random = rand() % 10; - if (currentPI->elements.size() == 1) - color = GREEN; - else + random = rand() % 10; // get some random number [0;9] + uint r, g, b; + do { - uint r, g, b; - do - { - r = rand() % 256; - g = rand() % 256; - b = rand() % 256; - } - while ( - (r + g + b) / 3 > 200 || // avoid light colors - r > g + b); // avoid red colors - color = RGB(r, g, b); + r = rand() % 256; // get some random colors + g = rand() % 256; + b = rand() % 256; } + while ( + (r + g + b) / 3 > 200 || // but avoid too light colors + r > g + b && (int)abs((int)g - (int)b) < 50); // and also avoid red colors + + color = RGB(r, g, b); // these rules are not professional } - vector* locations = currentPI->locations(); - for (uint j = 0; j < locations->size(); j++) // for each Element in PrimImplikant + vector* locations = currentPI->locations(); // get XY values for each element in currentPI + for (uint j = 0; j < locations->size(); j++) // for each of these { KV_PiEleLoc* currentEl = locations->at(j); bool foundGroup = false; - for (uint k = 0; k < piGroups.size(); k++) // for each Group/Kuller of this PrimImplikant + for (uint k = 0; k < piGroups.size(); k++) // for each existing Group (Kuller) of this PrimImplikant { KV_PiGroup* currentGroup = piGroups[k]; - if (currentGroup->LiesNextTo(currentEl)) + if (currentGroup->LiesNextTo(currentEl)) // if this element lies next to the Group { currentGroup->Add(currentEl); // sort Element into group - foundGroup = true; + foundGroup = true; // we have found an appropriate group break; } } // for each Group if (foundGroup == false) // element was not added to a group { - KV_PiGroup* newGroup = new KV_PiGroup(); + KV_PiGroup* newGroup = new KV_PiGroup(); // we have to create a new group for this el newGroup->Add(currentEl); piGroups.push_back(newGroup); } } // for each Element in PrimImplikant + // now we have created all groups for this PrimImplikant + for (uint k = 0; k < piGroups.size(); k++) // for each Group/Kuller of this PrimImplikant { this->PrintPrimImplikantenGroup(piGroups[k], random, color); // draw it - delete piGroups[k]; + delete piGroups[k]; // and then let's delete it piGroups[k] = NULL; } - piGroups.clear(); + + piGroups.clear(); // clear the group vector } // for each PrimImplikant } -// Prints the Kuller of a KV_PiGroup + +/// +/// Prints the KV_PiGroups that PrintPrimImplikanten generated +/// +/// A pointer to the group that shall be printed +/// Some random number for the rectangle size, or -1 if the PI solves a hazard +/// Some random color for the rectangles void KV::PrintPrimImplikantenGroup(KV_PiGroup* &group, char random, uint &color) { - group->MakeCoords(this->edgeLength, this->VarX_Length, this->VarY_Length); // makes X1, X2, Y1, Y2 - uint X1 = group->X1; - uint X2 = group->X2; - uint Y1 = group->Y1; - uint Y2 = group->Y2; + uint X1, Y1, X2, Y2; // coordinates for the rectangle of this group + group->MakeCoords(this->edgeLength, this->VarX_Length, this->VarY_Length, &X1, &Y1, &X2, &Y2); // makes X1, X2, Y1, Y2 - - if (random == -1) // make hazard groups as small as possible + if (random == -1) // make hazard groups as small as possible, but add a little ransom { - random = rand() % 2; + random = rand() % 2; // [0;1] X1 += 12 - random; X2 -= 12 - random; - random = rand() % 2; + random = rand() % 2; // [0;1] Y1 += 9 - random; Y2 -= 9 - random; } else // make size random, so the groups won't overlap { - X1 += random; - X2 -= random; - Y1 += random; - Y2 -= random; + X1 += random; // lower upper bound --> smaller + X2 -= random; // higher lower bound --> smaller + Y1 += random; // higher left bound --> smaller + Y2 -= random; // lower right bound --> smaller } - this->Rechteck(X1, Y1, X2, Y2, color, TRANS); + + this->Rectangle(X1, Y1, X2, Y2, color, TRANS); } +/// +/// Generates the Buttons to restart and to open a new file and then waits for a mouse click on one of those +/// void KV::Buttons() { int b, h, x, y; @@ -286,48 +333,104 @@ void KV::Buttons() updatescr(); while ( - !(mouseclick(&x,&y) == 1 && (y > h-40 && y < h-5) && ( - (x > b-120 && x < b-5) || - (x > b-240 && x < b-125) - ))) + !(mouseclick(&x,&y) == 1 && // wait for mouse click + (y > h-40 && y < h-5) && ( // if y fits into button + (x > b-120 && x < b-5) || // if x fits into button "Restart" + (x > b-240 && x < b-125) // or x fits into button "Other file" + ))) // then end this loop and resume operation { printf("."); - if(stopProcess())break; + if(stopProcess())break; // if stop was pressed the loop will also be quit }; - if ((x > b-240 && x < b-125) && (y > h-40 && y < h-5)) + if ((x > b-240 && x < b-125) && (y > h-40 && y < h-5)) // if button "Other file" was clicked: tell the main loop fileChosen = false; } +/// +/// Checks whether stopProcess() is true. This is a wrapper for all users of KV class +/// bool KV::StopProcess() { - return (bool)stopProcess(); + return stopProcess() == TRUE; } - +/// +/// Prints a line from [x1,y1] to [x2,y2] adding the global offset +/// +/// Left starting point (X) +/// Upper starting point (Y) +/// Right ending point (X) +/// Lower ending point (Y) +/// The color of the line void KV::Line(uint x1, uint y1, uint x2, uint y2, int color) { line(x1 + this->offsetX, y1 + this->offsetY, x2 + this->offsetX, y2 + this->offsetY, color); } -void KV::Text(uint x, uint y, uint size, int color, int bkcolor, int angle, int align, char* theText) +/// +/// Prints theText at the specified [x,y] position adding the global offset +/// +/// Left position where text starts (X) +/// Upper position where text starts (Y) +/// Text size +/// The color of the text +/// Background color of the text rectangle +/// Angle to rotate the text +/// String that shall be printed +void KV::Text(uint x, uint y, uint size, int color, int bkcolor, int angle, char* theText) { - text(x + this->offsetX, y + this->offsetY, size, color, bkcolor, angle, align, theText); + text(x + this->offsetX, y + this->offsetY, size, color, bkcolor, angle, NULL, theText); } +/// +/// Prints a rectangle that containts text adding the global offset +/// +/// Left starting point (X) +/// Upper starting point (Y) +/// Right ending point (X) +/// Lower ending point (Y) +/// Text size +/// Color of the text +/// Color of the border of the textbox +/// Background color of the rectangle that makes up the textbox +/// Some alignment flags +/// String that shall be printed void KV::TextBox(uint x1, uint y1, uint x2, uint y2, uint size, int ctext, int cframe, int cfill, int flags, char* theText) { textbox(x1 + this->offsetX + 1, y1 + this->offsetY, x2 + this->offsetX + 1, y2 + this->offsetY, size, ctext, cframe, cfill, flags, theText); } +/// +/// Prints a rectangle that containts bold text adding the global offset +/// +/// Left starting point (X) +/// Upper starting point (Y) +/// Right ending point (X) +/// Lower ending point (Y) +/// Text size +/// Color of the text +/// Color of the border of the textbox +/// Background color of the rectangle that makes up the textbox +/// Some alignment flags +/// String that shall be printed void KV::TextBoxBold(uint x1, uint y1, uint x2, uint y2, uint size, int ctext, int cframe, int cfill, int flags, char* theText) { textbox(x1 + this->offsetX + 1, y1 + this->offsetY, x2 + this->offsetX + 1, y2 + this->offsetY, size, ctext, cframe, cfill, flags, theText); textbox(x1 + this->offsetX + 2, y1 + this->offsetY, x2 + this->offsetX + 2, y2 + this->offsetY, size, ctext, TRANS, TRANSPARENT, flags, theText); // write twice to simulate bold font } -void KV::Rechteck(uint x1, uint y1, uint x2, uint y2, int cframe, int cfill) +/// +/// Prints a rectangle at the specified position adding the global offset +/// +/// Left starting point (X) +/// Upper starting point (Y) +/// Right ending point (X) +/// Lower ending point (Y) +/// Border color +/// Background color +void KV::Rectangle(uint x1, uint y1, uint x2, uint y2, int cframe, int cfill) { rectangle(x1 + this->offsetX + 1, y1 + this->offsetY + 1, x2 + this->offsetX + 1, y2 + this->offsetY + 1, cframe, cfill); } \ No newline at end of file diff --git a/Hazard/Hazard/KV.h b/Hazard/Hazard/KV.h index bfc3908..7f06394 100644 --- a/Hazard/Hazard/KV.h +++ b/Hazard/Hazard/KV.h @@ -14,39 +14,14 @@ extern bool KNF; class KV { -public: - void Print(uint offset); // Ausgabe-Methode, KV-Diagramm an der Position [offset | offset] - void Print(uint offsetX, uint offsetY); // Ausgabe-Methode, KV-Diagramm an der Position [offsetX | offsetY] - uint width(); // Gibt die Breite eines KV-Diagramms zurück (widthPx) - uint height(); // Gibt die Höhe eines KV-Diagramms zurück (heightPx) - - void Buttons(); - bool StopProcess(); - - // Konstruktor - KV(PrimImplikantCollection* globalPic, CellCollection* allCells, uint size, vector* &variables) - : edgeLength(size), - numVarX(((uint)floor(dimension / 2.0f))), numVarY(((uint)ceil(dimension / 2.0f))), - numFieldX((uint)pow(2, (float)numVarX)), numFieldY((uint)pow(2, (float)numVarY)) - { - this->globalPic = globalPic; - this->allCells = allCells; - this->variables = variables; - Setstring_Var(); - this->widthPx = numFieldX * (this->edgeLength + 1) + this->VarY_Length; - this->heightPx = numFieldY * (this->edgeLength + 1) + this->VarX_Length; - - this->Clear(); - } - private: - PrimImplikantCollection* globalPic; - CellCollection* allCells; - vector* variables; + PrimImplikantCollection* globalPic; // Globale PrimImplikantCollection + CellCollection* allCells; // Alle Zellen + vector* variables; // Variablennamen - uint offsetX; // Der freie Platz nach links in Pixeln - uint offsetY; // Der freie Platz nach rechts in Pixeln + uint offsetX; // Der freie Platz links vom KV-Diagramm in Pixeln + uint offsetY; // Der freie Platz oben vom KV-Diagramm in Pixeln const uint edgeLength; // Die Kantenlänge der einzelnen Felder @@ -56,31 +31,64 @@ private: const uint numFieldY; // Wieviele Felder in Y-Richtung gezeichnet werden = pow(2, numVarY) uint widthPx; // Breite des KV-Diagramms in Pixeln uint heightPx; // Höhe des KV-Diagramms in Pixeln - uint VarX_Length; // Höhe der Variablen in X-Richtung in Pixeln - uint VarY_Length; // Breite der Variablen in Y-Richtung in Pixeln - string string_VarX; // Variables_String in X-Richtung - string string_VarY; // Variables_String in Y-Richtung + uint VarX_Length; // Höhe der Variablenzeile (oben) in Pixeln + uint VarY_Length; // Breite der Variablenspalte (links) in Pixeln + string string_VarX; // Variablen String oben + string string_VarY; // Variablen String links - void Setstring_Var(); // Einfuegen von String_Varx & String_VarY mit Variables. - void PrintRaster(); // Erstellt die Felder - void PrintVariables(); // Erstellt die Werte der Variablen in der ersten X- und Y-Spalte - void PrintCellValues(); // Erstellt die Werte der jeweiligen Zellen + void Setstring_Var(); // Initialisieren von VarX/Y_Length und string_VarX/Y + void PrintRaster(); // Erstellt die Felder/das Raster + void PrintVariables(); // Erstellt die Werte der Variablen in der ersten Zeile und der ersten Spalte + void PrintCellValues(); // Erstellt die Werte in den jeweiligen Zellen void PrintPrimImplikanten(); // Generiert die einzelnen PrimImplikanten-Kuller (Gruppen) - void PrintPrimImplikantenGroup(KV_PiGroup* &group, char random, uint &color); // Erstellt die einzelnen PrimImplikanten-Kuller - void PrintString_Var(); // Erstellt den horizontalen TextVariable & vertikalen Textvariable + void PrintPrimImplikantenGroup(KV_PiGroup* &group, char random, uint &color); // Druckt die einzelnen PrimImplikanten-Kuller + void PrintString_Var(); // Erstellt den horizontalen & vertikalen Text mit Variablennamen - void Clear(); + void Clear(); // Löscht die GDE - void Line(uint x1, uint y1, uint x2, uint y2, int color); // Zeichnet eine Linie mit Offset - void Text(uint x, uint y, uint size, int color, int bkcolor, int angle, int align, char* theText); // Zeichnet einen Text mit Offset - void KV::TextBox(uint x1, uint y1, uint x2, uint y2, uint size, int ctext, int cframe, int cfill, int flags, char* theText); // Zeichnet eine TextBox mit Offset - void KV::TextBoxBold(uint x1, uint y1, uint x2, uint y2, uint size, int ctext, int cframe, int cfill, int flags, char* theText); // Zeichnet eine TextBox mit Offset und fetter Schrift - void KV::Rechteck(uint x1, uint y1, uint x2, uint y2, int cframe, int cfill); // Zeichnet ein Rechteck mit Offset und fetter Schrift + void Line(uint x1, uint y1, uint x2, uint y2, int color); // Zeichnet eine Linie mit Offset + void Text(uint x, uint y, uint size, int color, int bkcolor, int angle, char* theText); // Zeichnet einen Text mit Offset + void KV::TextBox(uint x1, uint y1, uint x2, uint y2, uint size, int ctext, int cframe, int cfill, int flags, char* theText); // Zeichnet eine TextBox mit Offset + void KV::TextBoxBold(uint x1, uint y1, uint x2, uint y2, uint size, int ctext, int cframe, int cfill, int flags, char* theText); // Zeichnet eine TextBox mit Offset und fetter Schrift + void KV::Rectangle(uint x1, uint y1, uint x2, uint y2, int cframe, int cfill); // Zeichnet ein Rechteck mit Offset + +public: + void Print(uint offset); // Ausgabe-Methode, KV-Diagramm an der Position [offset | offset] + void Print(uint offsetX, uint offsetY); // Ausgabe-Methode, KV-Diagramm an der Position [offsetX | offsetY] + uint width(); // Gibt die Breite eines KV-Diagramms zurück (widthPx) + uint height(); // Gibt die Höhe eines KV-Diagramms zurück (heightPx) + + void Buttons(); // Zeichnet Buttons und wartet auf user input + bool StopProcess(); // Prüft das stop flag der GDE + + /// + /// Konstruktor von KV + /// + /// Globale PrimImplikantCollection + /// Alle Zellen (CellCollection) + /// Die Kantenlänge eines Feldes (Rastergröße) + /// Variablennamen + KV(PrimImplikantCollection* globalPic, CellCollection* allCells, uint size, vector* &variables) + : edgeLength(size), // Kantenlänge festlegen + numVarX(((uint)floor(dimension / 2.0f))), // Anzahl der Variablen in X- und Y-Richtung festlegen + numVarY(((uint) ceil(dimension / 2.0f))), + numFieldX((uint)pow(2, (float)numVarX)), // Anzahl der Felder in X- und Y-Richtung festlegen + numFieldY((uint)pow(2, (float)numVarY)) // = 2 ^ numVar + { + this->globalPic = globalPic; + this->allCells = allCells; + this->variables = variables; + this->Setstring_Var(); // Initialisiert VarY_Length und VarX_Length + this->widthPx = numFieldX * (this->edgeLength + 1) + this->VarY_Length; // Breite eines KV-Diagramms + this->heightPx = numFieldY * (this->edgeLength + 1) + this->VarX_Length;// Höhe eines KV-Diagramms + + this->Clear(); // GDE löschen + } - char* Binary(uint x, char length); // Wie itoa(x, char[], 2), allerdings mit fester Breite }; - -#define CENTER SINGLE_LINE|CENTER_ALIGN|VCENTER_ALIGN \ No newline at end of file +#ifndef CENTER +#define CENTER SINGLE_LINE|CENTER_ALIGN|VCENTER_ALIGN +#endif \ No newline at end of file diff --git a/Hazard/Hazard/KV_PiEleLoc.h b/Hazard/Hazard/KV_PiEleLoc.h index e0393e6..d784624 100644 --- a/Hazard/Hazard/KV_PiEleLoc.h +++ b/Hazard/Hazard/KV_PiEleLoc.h @@ -7,23 +7,31 @@ using namespace std; extern uint dimension; +/// +/// This class saves the X and Y values in a KV diagram for the specified i +/// class KV_PiEleLoc { public: uint i; uint w; uint h; - + + /// + /// Constructor of KV_PiEleLoc + /// KV_PiEleLoc(uint &i) { - const uint numVarX = (uint)floor(dimension / 2.0f); + const uint numVarX = (uint)floor(dimension / 2.0f); // get the number of variables in X direction this->i = i; - this->w = i & ((0x1 << (numVarX)) - 1); // get x coord - this->w = Tools::GrayToBinary(w); + // we need numVarX ones here + // example: numVarX = 3 --> (0001 << 3) - 1 = 1000 - 1 = 0111 + this->w = i & ((0x1 << (numVarX)) - 1); // get x coord out of i (lower numVarX bits) + this->w = Tools::GrayToBinary(w); // convert from gray to binary - this->h = i >> numVarX; // get y coord - this->h = Tools::GrayToBinary(h); + this->h = i >> numVarX; // get y coord out of i (higher bits) + this->h = Tools::GrayToBinary(h); // convert from gray to binary } -}; +}; \ No newline at end of file diff --git a/Hazard/Hazard/KV_PiGroup.cpp b/Hazard/Hazard/KV_PiGroup.cpp index 1e715fe..20661dc 100644 --- a/Hazard/Hazard/KV_PiGroup.cpp +++ b/Hazard/Hazard/KV_PiGroup.cpp @@ -5,57 +5,77 @@ using namespace std; +/// +/// Checks whether the specified el lies next to this group (in 2D, not Hamming distance) +/// +/// The element that shall be checked bool KV_PiGroup::LiesNextTo(KV_PiEleLoc* &el) { - for (uint i = 0; i < this->elements.size(); i++) - { + for (uint i = 0; i < this->elements.size(); i++) // for each element in this group + { // (there should be a better way) KV_PiEleLoc* elG = this->elements[i]; - if (elG->h - el->h == 0 && abs((int)elG->w - (int)el->w) == 1 || - elG->w - el->w == 0 && abs((int)elG->h - (int)el->h) == 1) + if (elG->h - el->h == 0 && abs((int)elG->w - (int)el->w) == 1 || // if el lies next to elG in X direction + elG->w - el->w == 0 && abs((int)elG->h - (int)el->h) == 1) // or el lies next to elG in Y direction return true; } + return false; } +/// +/// Add the specified KV_PiElelLoc el to this group +/// void KV_PiGroup::Add(KV_PiEleLoc* &el) { this->elements.push_back(el); } -void KV_PiGroup::MakeCoords(uint edgeLength, uint VarX_Length, uint VarY_Length) +/// +/// Calculate the X and Y coordinates with all elements +/// +void KV_PiGroup::MakeCoords(uint edgeLength, uint VarX_Length, uint VarY_Length, uint* XX1, uint* YY1, uint* XX2, uint* YY2) { - uint x1, x2, y1, y2; - uint X1 = -1, X2 = 0, Y1 = -1, Y2 = 0; - KV_PiEleLoc* loc; - for (uint i = 0; i < this->elements.size(); i++) + uint x1, x2, y1, y2; // coords for each single element + uint X1 = -1, X2 = 0, Y1 = -1, Y2 = 0; // resulting group coords with initial maximum/minimum values + + for (uint i = 0; i < this->elements.size(); i++) // for all locations in this group { - loc = this->elements[i]; - x1 = loc->w * (edgeLength + 1) + VarY_Length; // Upper coord - x2 = x1 + edgeLength; // Lower coord - y1 = loc->h * (edgeLength + 1) + VarX_Length; // Left coord - y2 = y1 + edgeLength; // Right coord + KV_PiEleLoc* loc = this->elements[i]; // current location + x1 = loc->w * (edgeLength + 1) + VarY_Length; // Upper coord for rectangle around loc + x2 = x1 + edgeLength; // Lower coord for rectangle around loc + y1 = loc->h * (edgeLength + 1) + VarX_Length; // Left coord for rectangle around loc + y2 = y1 + edgeLength; // Right coord for rectangle around loc - X1 = min(X1, x1); - X2 = max(X2, x2); - Y1 = min(Y1, y1); - Y2 = max(Y2, y2); + X1 = min(X1, x1); // Store it if upper coord is higher than previous X1 + X2 = max(X2, x2); // Store it if lower coord is lower than previous X2 + Y1 = min(Y1, y1); // Store it if left coord is lefter than previous Y1 + Y2 = max(Y2, y2); // Store it if right coord is righter than previous Y2 } - - this->X1 = X1; - this->X2 = X2; - this->Y1 = Y1; - this->Y2 = Y2; + + *XX1 = X1; + *YY1 = Y1; + *XX2 = X2; + *YY2 = Y2; } +/// +/// Returns the KV_PiEleLoc at the specified index +/// KV_PiEleLoc* KV_PiGroup::operator[](uint &index) { return this->elements.at(index); } +/// +/// Returns the KV_PiEleLoc at the specified index +/// KV_PiEleLoc* KV_PiGroup::at(uint &index) { return this->elements.at(index); } +/// +/// Returns the size of this KV_PiGroup +/// uint KV_PiGroup::size() { return this->elements.size(); diff --git a/Hazard/Hazard/KV_PiGroup.h b/Hazard/Hazard/KV_PiGroup.h index 22613c8..ed199e8 100644 --- a/Hazard/Hazard/KV_PiGroup.h +++ b/Hazard/Hazard/KV_PiGroup.h @@ -8,18 +8,19 @@ using namespace std; extern uint dimension; +/// +/// This class stores several KV_PiEleLoc objects and thus represents one "Kuller" of the PrimImplikant +/// class KV_PiGroup { private: - vector elements; + vector elements; // locations public: - bool LiesNextTo(KV_PiEleLoc* &el); - void Add(KV_PiEleLoc* &el); - void MakeCoords(uint edgeLength, uint VarX_Length, uint VarY_Length); + bool LiesNextTo(KV_PiEleLoc* &el); // whether the specified el lies next to this group + void Add(KV_PiEleLoc* &el); // add a location to this group + void MakeCoords(uint edgeLength, uint VarX_Length, uint VarY_Length, uint* X1, uint* Y1, uint* X2, uint* Y2); // Generates the coordinates for this group - KV_PiEleLoc* operator[](uint &index); - KV_PiEleLoc* at(uint &index); - uint size(); - - uint X1, X2, Y1, Y2; + KV_PiEleLoc* operator[](uint &index); // location at index + KV_PiEleLoc* at(uint &index); // location at index + uint size(); // number of locations }; \ No newline at end of file diff --git a/Hazard/Hazard/PrimImplikant.cpp b/Hazard/Hazard/PrimImplikant.cpp index df67f53..a16ef98 100644 --- a/Hazard/Hazard/PrimImplikant.cpp +++ b/Hazard/Hazard/PrimImplikant.cpp @@ -7,65 +7,89 @@ using namespace std; -bool PrimImplikant::valueAt(uint pos) { - for (vector::iterator i = elements.begin(); i < elements.end(); ++i) - if (*i == pos) - return true; +uint PrimImplikant::globalCount = 0; + +/// +/// Checks whether this PrimImplikant covers the specified position +/// +/// The position that shall be checked +bool PrimImplikant::valueAt(uint position) { + for (vector::iterator i = elements.begin(); i < elements.end(); ++i) // for each element + if (*i == position) // if it is matched + return true; // this PI covers this position return false; } -void PrimImplikant::parser(string input) { // Analyser +/// +/// Converts the specified input string to a number of elements by replacing a x by 0 and 1 and then calling itself again +/// +/// The input string from CParser that defines this PrimImplikant +void PrimImplikant::parser(string input) { uint implikant = 0; - string text0 = ""; - string text1 = ""; - for (uint i = 0; i < input.size(); i++) + for (uint i = 0; i < input.size(); i++) // for each character { - char c = input[i]; - if (c == 'x' || c == 'X') + char c = input[i]; // can we get a pointer to this char? + if (c == 'x' || c == 'X') // we found an X { - text0 = input; - text1 = input; - text0[i] = '0'; - text1[i] = '1'; - parser(text0); - parser(text1); + input[i] = '0'; // replace X by 0 and call parse again + parser(input); + input[i] = '1'; // replace X by 1 and call parse again + parser(input); return; } - if (c != '0' && c != '1') + if (c != '0' && c != '1') // if the character is neither X nor 0 nor 1: error! { - printf("**** FATAL ERROR **** %s is not binary\n", input); + printf("**** FATAL ERROR **** %s is not binary\n", input); // perhaps we should log to error file return; } - implikant <<= 1; // *2 - implikant += (uint)c - (uint)'0'; + + implikant <<= 1; // no X found yet + implikant |= (uint)(c - '0'); // convert the string to a number } - elements.push_back(implikant); + this->elements.push_back(implikant); // add the converted number } +/// +/// Sort elements using Tools:compareAsGray. They will be ordered in Gray order ascending +/// algorithm.h uses InsertionSort +/// void PrimImplikant::sort() { - std::sort(this->elements.begin(), this->elements.end(), &PrimImplikant::compareGray); -} - -bool PrimImplikant::compareGray(uint a, uint b) -{ - return Tools::GrayToBinary(a) < Tools::GrayToBinary(b); + std::sort(this->elements.begin(), this->elements.end(), &Tools::compareAsGray); } +/// +/// Creates a KV_PiEleLoc for each _element. Therefore it has to sort elements first (see this->sort()) and then fills _locations +/// void PrimImplikant::makeLocations() { this->sort(); this->_locations = new vector(); this->_locations->resize(this->elements.size()); for (uint i = 0; i < this->elements.size(); i++) +<<<<<<< HEAD this->_locations->at(i) = new KV_PiEleLoc(this->elements[i]); // zu fragen +======= + this->_locations->at(i) = new KV_PiEleLoc(this->elements[i]); +>>>>>>> Added Comments } +/// +/// Lazy initialisation of this->_locations +/// vector* PrimImplikant::locations() { if (this->_locations == NULL) this->makeLocations(); return this->_locations; +} + +/// +/// Returns the number of Cells that this PrimImplikant covers +/// +uint PrimImplikant::size() +{ + return this->elements.size(); } \ No newline at end of file diff --git a/Hazard/Hazard/PrimImplikant.h b/Hazard/Hazard/PrimImplikant.h index 9f86294..66794e0 100644 --- a/Hazard/Hazard/PrimImplikant.h +++ b/Hazard/Hazard/PrimImplikant.h @@ -6,53 +6,84 @@ using namespace std; +/// +/// This class represents a PrimImplikant. It contains a vector with all covered positions/locations +/// class PrimImplikant { private: - static bool compareGray(uint a, uint b); - void makeLocations(); + vector elements; // The positions this PrimImplikant covers + vector* _locations; // The XY coordinates in a KV for each position - vector* _locations; + static uint globalCount; // A counter used for ID generation -public: - string name; - uint id; - vector elements; - - PrimImplikant(string input) + /// + /// Sets default values for id and _locations + /// + void init() { - this->name = input; - this->parser(input); + this->id = PrimImplikant::globalCount++; this->_locations = NULL; } + + void makeLocations(); // Generates _locations + void parser(string input); // Parses an input string to fill elements +public: + string name; // The name of the PrimImplikant as imported + uint id; // The unique identifier (see ::globalCount) + + /// + /// Sets name and calls this->parser(input) + /// + /// The imported string that defines this PrimImplikant + PrimImplikant(string input) + { + init(); + this->name = input; + this->parser(input); + } + /// + /// Creates a PrimImplikant that covoers only the specified input position + /// + /// The imported position PrimImplikant(uint input) { + init(); char nameC[sizeof(uint)*8+1]; _itoa_s(input, nameC, sizeof(uint)*8+1, 10); this->name = nameC; this->elements.push_back(input); - this->_locations = NULL; } + /// + /// Creates a PrimImplikant that covers two positions. This is used to solve detected hazards + /// Beware: No checks are done here, you could easily add a PrimImplikant that cannot exist logically! + /// + /// A number + /// A number which's Hanning distance to input1 is only 1 PrimImplikant(uint input1, uint input2) { - char nameC[sizeof(uint)*8+1]; - _itoa_s(input1, nameC, sizeof(uint)*8+1, 10); + init(); + char nameC[sizeof(uint)*8+1]; // generate the name + _itoa_s(input1, nameC, sizeof(uint)*8+1, 10); // convert input1 this->name = nameC; - _itoa_s(input2, nameC, sizeof(uint)*8+1, 10); - this->name.append("|"); + this->name.append("|"); // add delimiter + _itoa_s(input2, nameC, sizeof(uint)*8+1, 10); // convert inpiut2 this->name.append(nameC); - this->elements.push_back(input1); + this->elements.push_back(input1); // add both input1 and input2 to elements this->elements.push_back(input2); - this->_locations = NULL; } - bool valueAt(uint position); - void parser(string input); - void sort(); - vector* locations(); + //vector* elements(); // returns elements + uint size(); // returns the number of elements in elements + bool valueAt(uint position); // returns whether this PrimImplikant covers the specified position + void sort(); // sort elements as Gray numbers + vector* locations(); // get the locations of elements in a KV + /// + /// Deletes all KV_PiLocs and _locations itself + /// ~PrimImplikant() { if (this->_locations) @@ -64,4 +95,11 @@ public: this->_locations = NULL; } } -}; \ No newline at end of file +}; + + + +#ifndef PRIMIMPLIKANTITERATOR +#define PRIMIMPLIKANTITERATOR +typedef vector::iterator PrimImplikantIt; +#endif \ No newline at end of file diff --git a/Hazard/Hazard/PrimImplikantCollection.cpp b/Hazard/Hazard/PrimImplikantCollection.cpp index 7ef4595..baa44fb 100644 --- a/Hazard/Hazard/PrimImplikantCollection.cpp +++ b/Hazard/Hazard/PrimImplikantCollection.cpp @@ -5,87 +5,129 @@ using namespace std; -uint PrimImplikantCollection::globalCount = 0; - +/// +/// Adds the specified PrimImplikant PI to the collection +/// +/// The PrimImplikant that shall be added to the collection void PrimImplikantCollection::add(PrimImplikant* &PI) { PIVector.push_back(PI); } +/// +/// Adds a PrimImplikant with the specified input to the collection +/// +/// The parsed data from CParser out of the input file void PrimImplikantCollection::add(string input) { PrimImplikant* PI = new PrimImplikant(input); - - PI->id = PrimImplikantCollection::globalCount++; this->add(PI); } +/// +/// Adds a PrimImplikant with the specified input to the collection +/// +/// The parsed data from CParser out of the input file void PrimImplikantCollection::add(uint input) { PrimImplikant* PI = new PrimImplikant(input); - PI->id = PrimImplikantCollection::globalCount++; this->add(PI); } +/// +/// Adds a PrimImplikant which covers both input1 and input2. +/// Beware: No checks are done here, you could easily add a PrimImplikant that cannot exist logically! +/// +/// Some number +/// Some other number void PrimImplikantCollection::add(uint input1, uint input2) { PrimImplikant* PI = new PrimImplikant(input1, input2); - PI->id = PrimImplikantCollection::globalCount++; this->add(PI); } +/// +/// Returns whether a PrimImplikant covers the specified position +/// +/// The position you want to check. It is a normal binary number +/// True: A PrimImplikant was found. False: No was not found at this position bool PrimImplikantCollection::valueAt(uint position) { - for (vector::iterator i = PIVector.begin(); i < PIVector.end(); i++) - if ((*i)->valueAt(position)) - return true; - return false; + for (PrimImplikantIt i = PIVector.begin(); i < PIVector.end(); i++) // for each PrimImplikant + if ((*i)->valueAt(position)) // if one is true + return true; // the collection is true, too + return false; // nothing found, the collection is false } +/// +/// Generates a new PrimImplikantCollection with a subset of the saved PrimImplikants: All those that cover the specified position. +/// +/// The position. It is a number +/// A new PrimImplikantCollection with all found PrimImplikants PrimImplikantCollection PrimImplikantCollection::primImplikantenAt(uint position) { PrimImplikantCollection pic; - for (vector::iterator i = PIVector.begin(); i < PIVector.end(); i++) - if ((*i)->valueAt(position)) - pic.add(*i); + for (PrimImplikantIt i = PIVector.begin(); i < PIVector.end(); i++) // for every PrimImplikant + if ((*i)->valueAt(position)) // if it is true + pic.add(*i); // add it to the new collection return pic; } +/// +/// Looks for the specified PrimImplikant foreign in this collection +/// +/// True: foreign was found in here and is not foreign. False: foreign is indeed foreign bool PrimImplikantCollection::contains(PrimImplikant* foreign) { - for (vector::iterator i = PIVector.begin(); i < PIVector.end(); i++) - if ((*i)->id == foreign->id) - return true; + for (PrimImplikantIt i = PIVector.begin(); i < PIVector.end(); i++) // for all PrimImplikants + if ((*i)->id == foreign->id) // if ID matches + return true; // we found it return false; } +/// +/// Returns the number of PrimImplikants in this collection +/// uint PrimImplikantCollection::size() { return this->PIVector.size(); } +/// +/// Returns the last added PrimImplikant +/// PrimImplikant* PrimImplikantCollection::back() { return this->PIVector.back(); } +/// +/// Returns the first added PrimImplikant +/// PrimImplikant* PrimImplikantCollection::front() { return this->PIVector.front(); } -PrimImplikant* PrimImplikantCollection::at(uint &index) +/// +/// Returns the PrimImplikant at the specified index +/// +PrimImplikant* PrimImplikantCollection::at(const uint &index) { return this->PIVector.at(index); } - -PrimImplikant* PrimImplikantCollection::operator[](uint &index){ - if (index < PIVector.size()) - return this->PIVector.at(index); - - return 0; +/// +/// Returns the PrimImplikant at the specified index +/// +PrimImplikant* PrimImplikantCollection::operator[](const uint &index){ + return this->PIVector.at(index); } +/// +/// Deletes all PrimImplikant instances in this collection. +/// Beware: Only do this at the end! All collections are storing pointers to the PrimImplikants and maybe some other object is still using them. Dispose() may only be called by the last instance of this class (which we could check programmatically and then integrate it into the destructor) +/// void PrimImplikantCollection::Dispose() { for (uint i = 0; i < this->size(); i++) delete this->at(i); + this->PIVector.clear(); } \ No newline at end of file diff --git a/Hazard/Hazard/PrimImplikantCollection.h b/Hazard/Hazard/PrimImplikantCollection.h index 3f5ef7a..21d9635 100644 --- a/Hazard/Hazard/PrimImplikantCollection.h +++ b/Hazard/Hazard/PrimImplikantCollection.h @@ -5,31 +5,30 @@ #include "PrimImplikant.h" using namespace std; -extern uint dimension; -extern uint numElements; -extern bool KNF; -class PrimImplikantCollection{ +/// +/// This class contains a vector with pointers to instances of PrimImplikant and also provides some methods to operate on those data +/// +class PrimImplikantCollection +{ +private: + vector PIVector; // vector with PrimImplikants public: - void add(PrimImplikant* &PI); - void add(string input); - void add(uint input); - void add(uint input1, uint input2); + void add(PrimImplikant* &PI); // adds the specified PrimImplikant to the collection + void add(string input); // imports the specified input + void add(uint input); // imports the specified input + void add(uint input1, uint input2); // imports the specified input1 and input2 - bool valueAt(uint position); - PrimImplikantCollection primImplikantenAt(uint position); - bool contains(PrimImplikant* foreign); + bool valueAt(uint position); // looks for any PrimImplikant that touches the specified position + PrimImplikantCollection primImplikantenAt(uint position); // returns the PrimImplikanten that touch the specified position + bool contains(PrimImplikant* foreign); // looks for the specified PrimImplikant in this colleciton - void Dispose(); + void Dispose(); // delete all PrimImplikants in here - uint size(); - PrimImplikant* back(); - PrimImplikant* front(); - PrimImplikant* at(uint &index); - PrimImplikant* operator[](uint &index); -private: - vector PIVector; - - static uint globalCount; + uint size(); // size of vector PIVector + PrimImplikant* back(); // last element of PIVector + PrimImplikant* front(); // first element of PIVector + PrimImplikant* at(const uint &index); // element at specified index of PIVector + PrimImplikant* operator[](const uint &index); // element at specified index of PIVector }; \ No newline at end of file diff --git a/Hazard/Hazard/Tools.cpp b/Hazard/Hazard/Tools.cpp index 91181ee..aadbc38 100644 --- a/Hazard/Hazard/Tools.cpp +++ b/Hazard/Hazard/Tools.cpp @@ -3,70 +3,105 @@ using namespace std; -extern uint numElements; +extern uint numElements; // 2 ^ dimesion uint* Tools::GrayToBinaryTable = NULL; uint Tools::GrayToBinaryTableSize = 0; -// convert the binary representation of x to a string with the specified length +/// +/// Converts the binary representation of x to a string with the specified length +/// The difference to itoa() is the fixed length +/// +/// The number that shall be converted +/// The length of the char[] (= number of variables) +/// A pointer to a new char[] char* Tools::BinaryToChars(uint x, char length) { - // warning: this breaks for numbers with more than 64 bits (= variables) - char* c = new char[length+1]; - c += length; // last char + char* c = new char[length+1]; // allocate memory + c += length; // point to last char (at length + 1 - 1) - *c = 0; + *c = 0; // '\0' do { - *--c = '0' + (x & 1); // 0 or 1 at the specified position - x >>= 1; + *--c = '0' + (x & 1); // 0 or 1 at the specified position, convert to char + x >>= 1; // next position } while (--length); - return c; + return c; // return char[] now pointing to the beginning again } +/// +/// Converts the specified number x from gray back to binary +/// To boost the performance it inits a lookup table on first run. When the number of variables changes (different input file) it changes the size of the lookup table, too. This could be done a little more efficient. +/// uint Tools::GrayToBinary(uint x) { - if (Tools::GrayToBinaryTableSize < numElements && Tools::GrayToBinaryTable != NULL) + if (Tools::GrayToBinaryTableSize < numElements && Tools::GrayToBinaryTable != NULL) // number of variables was increased { - delete[] Tools::GrayToBinaryTable; - Tools::InitGrayToBinaryTable(); + delete[] Tools::GrayToBinaryTable; // delete old table + Tools::InitGrayToBinaryTable(); // make new table. It would be better to increase the allocated amount of memory } - else if (Tools::GrayToBinaryTable == NULL) - Tools::InitGrayToBinaryTable(); + else if (Tools::GrayToBinaryTable == NULL) // no table existed + Tools::InitGrayToBinaryTable(); // make new table - return Tools::GrayToBinaryTable[x]; + return Tools::GrayToBinaryTable[x]; // do the lookup } +/// +/// Allocates memory for the GrayToBinaryTable and sets its values +/// void Tools::InitGrayToBinaryTable() { - Tools::GrayToBinaryTable = new uint[numElements]; - Tools::GrayToBinaryTableSize = numElements; - for (uint i = 0; i < numElements; i++) - Tools::GrayToBinaryTable[i] = Tools::CalcGrayToBinary(i); + Tools::GrayToBinaryTable = new uint[numElements]; // make uint[] + Tools::GrayToBinaryTableSize = numElements; // save size to detect changes + for (uint i = 0; i < numElements; i++) // for all possible numbers + Tools::GrayToBinaryTable[i] = Tools::ConvertGrayToBinary(i); // convert gray to binary } -// converts a gray number to its binary representation -uint Tools::CalcGrayToBinary(uint x) + +/// +/// Converts a gray number to its binary representation by converting to gray a special number of times. +/// 31 is the maximum number of loops because uint only has 32 bits and works for every x. Calculation of r on the base of x is more efficient). +/// +/// The binary number that is associated with the gray x +uint Tools::ConvertGrayToBinary(uint x) { uint x1 = x; - char r = 0; // r = ceil(ld(x)) - do - r++; - while (x1 >>= 1); - if ((r & (r-1)) != 0) // keine Potenz von 2 - { - char r1 = 0; // r1 = ceil(ld(r)) + char r = 0; // r shall contain the position of the first positive bit + 1 in x + do // do while --> ceil. while do --> floor. + r++; + while (x1 >>= 1); // r = ceil(ld(x)) + // r = 0 | x = 3 r = 0 | x = 5 + // 1 | 011 1 | 101 + // 2 | 001 2 | 010 + // 3 | 000 3 | 001 + // 4 | 000 + + if ((r & (r-1)) != 0) // if r is no multiple of 2 <-- 100 & 011 = 000 == 0 101 & 100 = 100 != 0 + { // we need to round r up to the next multiple of 2. Let's use same algorithm as above. + char r1 = 0; // r1 shall contain the position of the first positive bit + 1 in r do r1++; - while (r >>= 1); + while (r >>= 1); // r1 = ceil(ld(r)) - r = 1 << r1; // aufrunden auf Zweierpotenz + r = 1 << r1; // r = 2^(ceil(ld(r))) > 2^(ld(r)) (== r) } - for (char i = 1; i < r; i++) // Umwandeln von Gray in Binary + for (char i = 1; i < r; i++) // do gray conversion r times --> binary. Do gray conversion r+1 times --> gray again x ^= x / 2; return x; +} + + +/// +/// Compare to gray numbers. Since computers can only compare binary numbers we have to convert them first +/// +/// Number that InsertionSort is processing (and that may be repositioned) +/// Number that a is compared to (precendants of a) +/// True: a should be positioned in front of b +bool Tools::compareAsGray(uint a, uint b) +{ + return Tools::GrayToBinary(a) < Tools::GrayToBinary(b); } \ No newline at end of file diff --git a/Hazard/Hazard/Tools.h b/Hazard/Hazard/Tools.h index 6ba2889..87210ef 100644 --- a/Hazard/Hazard/Tools.h +++ b/Hazard/Hazard/Tools.h @@ -1,14 +1,19 @@ #pragma once +/// +/// This is a static class that provides some methods that could be used anywhere +/// class Tools { public: - static char* Tools::BinaryToChars(uint x, char length); + static char* Tools::BinaryToChars(uint x, char length); // convert a number to a string in it's binary representation - static uint GrayToBinary(uint x); + static uint GrayToBinary(uint x); // convert a gray number back to binary using a lookup table + static bool compareAsGray(uint a, uint b); // compary towo gray numbers (convert it first) private: - static void InitGrayToBinaryTable(); - static uint* GrayToBinaryTable; - static uint GrayToBinaryTableSize; - static uint Tools::CalcGrayToBinary(uint x); + static uint* GrayToBinaryTable; // gray to binary lookup table + static uint GrayToBinaryTableSize; // size of GrayToBinaryTable + + static void InitGrayToBinaryTable(); // init GrayToBinaryTable + static uint Tools::ConvertGrayToBinary(uint x); // convert a gray number back to binary }; \ No newline at end of file diff --git a/Hazard/Hazard/Wertetabelle.cpp b/Hazard/Hazard/Wertetabelle.cpp index 3ff1b2a..e753eb5 100644 --- a/Hazard/Hazard/Wertetabelle.cpp +++ b/Hazard/Hazard/Wertetabelle.cpp @@ -13,95 +13,109 @@ extern uint dimension; extern uint numElements; extern bool KNF; +/// +/// Prints the complete truth table +/// void Wertetabelle::Print() { - printHeader(); + this->makeHeader(); + + this->printHeader(); // print the header lines + + ushort w = (ushort)ceil(log10((float)numElements)); // calculate width of decimal maximum number - int w = (uint)ceil(log10((float)numElements)); for (uint i = 0; i < numElements; i++) { cout << "| "; // => | - cout << setfill(' ') << setw(w) << i; // => 4 + cout << setfill(' ') << setw(w) << i; // => 5 cout << " |"; // => | - *fot << "| "; // => | - *fot << setfill(' ') << setw(w) << i; // => 4 - *fot << " |"; // => | - this->printI(i); // => 0 1 0 0 + *fot << "| "; + *fot << setfill(' ') << setw(w) << i; + *fot << " |"; + this->printI(i); // => 0 1 0 1 cout << "| "; // => | cout << ((*this->cells)[i]->value ^ KNF); // => 1 cout << " |"; // => | - *fot << "| "; // => | - *fot << ((*this->cells)[i]->value ^ KNF); // => 1 - *fot << " |"; // => | - this->printPrimImplikanten(i); // => 0 0x1 4 - cout << endl; // ==> | 4 | 0 1 0 0 | 1 | 0 0x1 4 - *fot << endl; // ==> | 4 | 0 1 0 0 | 1 | 0 0x1 4 + *fot << "| "; + *fot << ((*this->cells)[i]->value ^ KNF); + *fot << " |"; + this->printPrimImplikanten(i); // => 0 x01 5|3 + cout << endl; // ==> | 5 | 0 1 0 1 | 1 | 0 x01 5|3 + *fot << endl; - if (i > 0 && i % 31 == 0 && numElements - i > 5) // reprint header so you dont have to scroll - printHeader(); + if (i > 0 && i % 31 == 0 && numElements - i > 5) // reprint header so you do not have to scroll + this->printHeader(); } cout << string(this->width, '-') << endl; *fot << string(this->width, '-') << endl; } -string Wertetabelle::makeHeader() +/// +/// Generates the header line of the truth table with the variable names +/// +void Wertetabelle::makeHeader() { - bool setPad = padding.size() == 0; + ushort w = (ushort)ceil(log10((float)numElements)); // calculate width of decimal maximum number + this->header = "|" + string(w + 2, ' ') + "|"; // spare out line number - string row2 = "|" + string((uint)ceil(log10((float)numElements)) + 2, ' ') + "|"; - for (vector::iterator v = variables->begin(); v < variables->end(); v++) + for (vector::iterator v = variables->begin(); v < variables->end(); v++) // for each variable { - row2 += " " + *v; - if (setPad) - padding.push_back((v->size()-1) / 2.0f); + this->header += " " + *v; // add variable name to string + padding.push_back((v->size()-1) / 2.0f); // calculate the padding (spaces left & right) depending on string length } - row2 += " | y |"; + this->header += " | y |"; // output variable - this->width = row2.size(); + this->width = this->header.size(); // set global with of truth table (for horizontal lines) - row2 += " PrimImplikanten"; - - return row2; + this->header += " PrimImplikanten"; // add header for PIs } +/// +/// Print the header lines +/// void Wertetabelle::printHeader() -{ - string row2 = this->makeHeader(); - +{ cout << string(this->width, '-') << endl; // repeat '-' several times => --------------------- - cout << row2 << endl; // print header row => | a bärchen c d | y | PrimtImpl. + cout << this->header << endl; // print header row => | a bärchen c d | y | PrimtImpl. cout << string(this->width, '-') << endl; // repeat '-' several times => --------------------- - *fot << string(this->width, '-') << endl; // repeat '-' several times => --------------------- - *fot << row2 << endl; // print header row => | a bärchen c d | y | PrimtImpl. - *fot << string(this->width, '-') << endl; // repeat '-' several times => --------------------- + *fot << string(this->width, '-') << endl; + *fot << this->header << endl; + *fot << string(this->width, '-') << endl; } +/// +/// Print the binary repesentation of i +/// This method also takes care of the padding around the single bits (depending on the length of their variable names) +/// void Wertetabelle::printI(uint i) { string row = " "; - for (int j = dimension - 1; j >= 0; j--) // Variablen rückwärts durchlaufen (s.u.) + for (int j = dimension - 1; j >= 0; j--) // iterate variables backwards for shifting i rightwards { - char iAtJ = (i & 0x1) + '0'; // Maskierung (aktuelle Stelle j, die ausgegeben wird) - i >>= 1; // Schieben für nächstes Mal - // ' ' + Padding left (' ') + 1 | 0 + Padding right (' ') + row + char iAtJ = (i & 0x1) + '0'; // masking current bit (position j is being printed) and converting to char + i >>= 1; // Shift right for next round + + // ' ' + Padding left (' ') + 1 | 0 + Padding right (' ') + row row = string((uint)ceil(padding[j]) + 1, ' ') + iAtJ + string((uint)floor(padding[j]), ' ') + row; } + cout << row; *fot << row; } +/// +/// Prints the names of all PrimImplikants at the current position +/// void Wertetabelle::printPrimImplikanten(uint i) { - cout << ' '; - *fot << ' '; - Cell* cell = cells->at(i); + Cell* cell = cells->at(i); // get current Cell - for (uint pi = 0; pi < cell->primImplikanten.size(); pi++) // for every PrimImplikant in Cell + for (uint pi = 0; pi < cell->primImplikanten.size(); pi++) // for each PrimImplikant in Cell { - cout << cell->primImplikanten[pi]->name << " "; - *fot << cell->primImplikanten[pi]->name << " "; + cout << ' ' << cell->primImplikanten[pi]->name; // print name + *fot << ' ' << cell->primImplikanten[pi]->name; } } \ No newline at end of file diff --git a/Hazard/Hazard/Wertetabelle.h b/Hazard/Hazard/Wertetabelle.h index 926f6d5..920fc2a 100644 --- a/Hazard/Hazard/Wertetabelle.h +++ b/Hazard/Hazard/Wertetabelle.h @@ -10,32 +10,34 @@ using namespace std; -#ifndef WERTETABELLE -#define WERTETABELLE - +/// +/// This class is responsible for the printing of truth tables to cout and the output file +/// class Wertetabelle { public: - void Print(); + void Print(); // print the complete truth table + /// + /// Constructor of Wertetabelle + /// Wertetabelle(CellCollection* cells, vector* variables, ofstream &fWt) { - this->cells = cells; + this->cells = cells; // store a reference to allCells (thus we will get all changes) this->variables = variables; this->fot = &fWt; } private: - string makeHeader(); - void printHeader(); - void printI(uint i); - void printPrimImplikanten(uint i); + void makeHeader(); // Generates the header lines + void printHeader(); // Prints the header lines + void printI(uint i); // Prints the binary representation of the specified i in table format + void printPrimImplikanten(uint i); // Print all PrimImplikants that cover the specified position i - CellCollection* cells; - vector* variables; - vector padding; - uint width; - ofstream* fot; -}; - -#endif \ No newline at end of file + CellCollection* cells; // all cells + vector* variables; // variable names + vector padding; // padding depending on length of variable names + uint width; // with of truth table + ofstream* fot; // output file stream + string header; // header line +}; \ No newline at end of file