Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!
Werbeanzeige
Quellcode |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 |
/* Game of Life - nach dem Mathematiker John H. Conway Quellcode von viti, 22.-23.12.2014 Drei Dinge machen es schwer: (1) Die Grösse des Feldes soll vom Benutzer festgelegt werden -> dynamisches Array (2) Das Feld stellt eine Kugel dar, dh eine Zelle am linken Rand hat Nachbarn am rechten Rand. Gleiches gilt für oberen und unteren Rand. (3) Es muss ein 2D-Array in ein 1D-Array umgewandelt werden (container ua Methoden kenn ich noch nicht.) Meine Formel für 2D-Array in 1D-Array: Position [a][b] im Array[x*y] ==> Array[x*b+a] Ideen für bessere Perfomance: (a) Nachbarzählung abbrechen, sobald vier Nachbarn gefunden wurden (b) Nicht jedes mal das ganze Array kopieren (Funktion 'CopyArray'), statt dessen nur die Koordinaten lebender Zellen speichern ==> GetNeighbours müsste ziemlich umgeschrieben werden Andere Ausbaumöglichkeiten: - Generation 0 aus einer Datei auslesen! */ #include <iostream> #include <time.h> //für den Zufallsgenerator //#include "log.hpp" //==>Logfile zur Fehlersuche deaktiviert using namespace std; /* Klasse cFeld - Programm wäre auch ohne Klasse, dh. nur mit Funktionen möglich. Wäre das sinnvoller und warum? */ class cFeld { private: int xPos, yPos, //Grösse des Feldes n; //Generation bool *pCells; bool *pOldCells; //cLog *pLog; public: cFeld(int x, int y, int b); //Feld erstmals erstellen und zufällig füllen ~cFeld(); void Paint(); //Feld malen void NewStatus(); //Zellen im Feld neu berechnen void CopyArray(); int GetNeighbours(int a, int b); }; cFeld::cFeld(int x, int y, int b) //Konstruktor { //pLog=new cLog; //pLog->Init(); n=0; xPos=x; yPos=y; pCells=new bool[xPos*yPos]; //2-Dimensionales Array auf 1-D-Array abbilden pOldCells=new bool[xPos*yPos]; int random=0; //Zufallsgenerator starten time_t t; time(&t); srand((unsigned int)t); for (int i=0; i<xPos*yPos; i++) //Feld erstmals mit Zellen füllen if ((rand()%b)==1) pCells[i]=true; //pLog->Write("Konstruktor aufgerufen"); } void cFeld::Paint() //Malt das Feld { cout << "Generation " << n << ":" << endl << endl; for (int i=0; i<yPos; i++) { cout << "|"; for (int j=0; j<xPos; j++) { if (pCells[xPos*i+j]==true) //'width * row + col' wegen 2D->1D cout << "*"; else cout << " "; } cout << "|" << endl; } } cFeld::~cFeld() //Destruktor { delete[] pCells; delete[] pOldCells; pCells=NULL; pOldCells=NULL; //pLog->Write("Destruktor aufgerufen!"); } void cFeld::NewStatus() { n++; //pLog->Write("Neue Generation"); int neighbours=0; for (int i=0; i<yPos; i++) { for (int j=0; j<xPos; j++) { //pLog->Write("BEGINNE MIT ZELLE", j, i); neighbours=GetNeighbours(j, i); if (pOldCells[xPos*i+j]==true) { //pLog->Write("Lebende Zelle identifiziert", j, i); if (neighbours>3||neighbours<2) { //pLog->Write("Zelle gestorben", j, i); pCells[xPos*i+j]=false; } } else { //pLog->Write("Tote Zelle identifiziert", j, i); if (neighbours>2) { //pLog->Write("Zelle geboren", j, i); pCells[xPos*i+j]=true; } } } } } int cFeld::GetNeighbours(int a, int b) { int count=0; int aMinus, aPlus, bMinus, bPlus; if (a==0) //Alles wegen dem offenen Feldrand!! { aMinus=xPos-1; //->liegt a am linken Rand, so mach aus (a-1) den rechten Rand aPlus=a+1; } else if (a==xPos-1) { aPlus=0; //->liegt a am rechten Rand, so mach auch a+1 den linken Rand aMinus=a-1; } else { aMinus=a-1; aPlus=a+1; } //und das gleiche Spiel für oben/unten... if (b==0) { bMinus=yPos-1; bPlus=b+1; } else if (b==yPos-1) { bPlus=0; bMinus=b-1; } else { bMinus=b-1; bPlus=b+1; } //Jetzt können die Nachbarn gezählt werden! //pLog->Write("Prüfe Nachbarzelle", aMinus, bMinus); if (pOldCells[xPos*bMinus+aMinus]==true) { //pLog->Write("Nachbar gefunden auf", aMinus, bMinus); count++; } //pLog->Write("Prüfe Nachbarzelle", a, bMinus); if (pOldCells[xPos*bMinus+a]==true) { //pLog->Write("Nachbar gefunden auf", a, bMinus); count++; } //pLog->Write("Prüfe Nachbarzelle", aPlus, bMinus); if (pOldCells[xPos*bMinus+aPlus]==true) { //pLog->Write("Nachbar gefunden auf", aPlus, bMinus); count++; } //pLog->Write("Prüfe Nachbarzelle", aMinus, b); if (pOldCells[xPos*b+aMinus]==true) { count++; //pLog->Write("Nachbar gefunden auf", aMinus, b); } //pLog->Write("Prüfe Nachbarzelle", aPlus, b); if (pOldCells[xPos*b+aPlus]==true) { count++; //pLog->Write("Nachbar gefunden auf", aPlus, b); } //pLog->Write("Prüfe Nachbarzelle", aMinus, bPlus); if (pOldCells[xPos*bPlus+aMinus]==true) { //pLog->Write("Nachbar gefunden auf", aMinus, bPlus); count++; } //pLog->Write("Prüfe Nachbarzelle", a, bPlus); if (pOldCells[xPos*bPlus+a]==true) { //pLog->Write("Nachbar gefunden auf", a, bPlus); count++; } //pLog->Write("Prüfe Nachbarzelle", aPlus, bPlus); if (pOldCells[xPos*bPlus+aPlus]==true) { //pLog->Write("Nachbar gefunden auf", aPlus, bPlus); count++; } //pLog->Write("Lebende Nachbarzellen:", count, 0); return (count); } void cFeld::CopyArray() { for (int i=0; i<yPos; i++) { for (int j=0; j<xPos; j++) { pOldCells[xPos*i+j]=pCells[xPos*i+j]; } } } int main() { int x, y, b; cout << endl; cout << "---------------------" << endl; cout << "G A M E O F L I F E" << endl; cout << "---------------------" << endl << endl; do { cout << "How big should the map be (max. 70*70)?" << endl; cout << "Length (x): "; cin >> x; cout << "Height (y): "; cin >> y; cout << "If 2 means that 1/2 of the initial map is alive..." << endl; cout << "...select a fraction of your choice (2-20): "; cin >> b; cout << endl << endl << endl; }while (x<1||y<1||x>70||y>70||b<2||b>20); cFeld *pFeld; //Feld auf dem Heap erstellen pFeld=new cFeld(x,y,b); cin.ignore(); cout << "Random initialization of the map:" << endl << endl; pFeld->Paint(); cout << endl << "Press Enter to continue..." << endl; cin.ignore(); do { cout << "Calculating...." << endl << endl; pFeld->CopyArray(); pFeld->NewStatus(); pFeld->Paint(); cout << endl << "Press Enter to continue..." << endl << endl; cin.ignore(); }while (x>0); //Momentan eine Endlosschleife if (pFeld!=0) //wegen Endlosschlaufe grad obsolet { delete pFeld; pFeld=NULL; } return 0; } |
Bool-Vergleiche: if (a == true) ist äquivalent zu if (a).
C-/C++-Quelltext |
|
1 2 3 4 5 6 7 8 9 10 11 |
#include <iostream> using namespace std; int main() { // your code goes here if(2==true) cout << "Ja 1"; if(2) cout << "Ja 2"; return 0; } |
Zitat
Der RCCSWU (RandomCamelCaseSomtimesWithUndersquare) Stil bricht auch mal mit den veraltet strukturierten Denkmustern und erlaubt dem Entwickler seine Kreativität zu entfalten.
Da stand doch Bool-Vergleiche. 2 ist in keiner Welt ein boolscher Wert in der EDV.
C-/C++-Quelltext |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 |
#include <cstddef> #include <cctype> #include <stdexcept> #include <algorithm> #include <chrono> #include <random> #include <array> #include <vector> #include <string> #include <sstream> #include <iostream> #define _WIN32_WINNT 0x0500 #define WIN32_LEAN_AND_MEAN #define NOMINMAX #include <windows.h> #include <conio.h> class console_window { HWND window_handle; HANDLE output_handle; unsigned max_width; unsigned max_height; unsigned width; unsigned height; HANDLE original_buffer; HANDLE front_buffer; HANDLE back_buffer; public: console_window( console_window const & ) = delete; console_window & operator=( console_window ) = delete; console_window() : window_handle { GetConsoleWindow() }, output_handle {}, max_width {}, max_height {}, width {}, height {}, original_buffer {}, front_buffer {}, back_buffer {} { if( !window_handle ) { if( !AllocConsole() ) throw std::runtime_error{ "An attempt to allocate a console for this process failed!" }; window_handle = GetConsoleWindow(); } output_handle = GetStdHandle( STD_OUTPUT_HANDLE ); if( !output_handle || output_handle == INVALID_HANDLE_VALUE ) throw std::runtime_error{ "Couldn't get standard output handle!" }; COORD max_size( GetLargestConsoleWindowSize( output_handle ) ); max_width = max_size.X; max_height = max_size.Y; CONSOLE_SCREEN_BUFFER_INFOEX csbiex{ sizeof csbiex }; GetConsoleScreenBufferInfoEx( output_handle, &csbiex ); width = csbiex.srWindow.Right - csbiex.srWindow.Left + 1; height = csbiex.srWindow.Bottom - csbiex.srWindow.Top + 1; resize( width, height ); } console_window( unsigned width, unsigned height ) : console_window{} { resize( width, height ); } ~console_window() { if( original_buffer ) toggle_double_buffering(); } unsigned get_max_width() const { return max_width; } unsigned get_max_height() const { return max_height; } unsigned get_width() const { return width; } unsigned get_height() const { return height; } void set_title( std::string const & title ) { SetConsoleTitleA( title.c_str() ); } void move_window( unsigned x, unsigned y ) { SetWindowPos( window_handle, nullptr, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER ); } void resize( unsigned new_width, unsigned new_height ) { if( !new_width || !new_height || new_width > max_width || new_height > max_height ) throw std::runtime_error{ "New dimensions for console window exceed system limits!" }; CONSOLE_SCREEN_BUFFER_INFOEX csbiex{ sizeof csbiex }; GetConsoleScreenBufferInfoEx( output_handle, &csbiex ); csbiex.srWindow = { 0, 0, 1, 1 }; SetConsoleWindowInfo( output_handle, TRUE, &csbiex.srWindow ); csbiex.dwSize = { new_width, new_height }; SetConsoleScreenBufferInfoEx( output_handle, &csbiex ); csbiex.srWindow = { 0, 0, new_width - 1, new_height - 1 }; SetConsoleWindowInfo( output_handle, TRUE, &csbiex.srWindow ); width = new_width; height = new_height; } void set_font_size( unsigned size ) { if( size < 2 ) throw std::runtime_error{ "Can't set a console font size smaller than 2!" }; CONSOLE_FONT_INFOEX cfiex{ sizeof cfiex }; GetCurrentConsoleFontEx( output_handle, FALSE, &cfiex ); cfiex.dwFontSize.Y = size; SetCurrentConsoleFontEx( output_handle, FALSE, &cfiex ); COORD max_size( GetLargestConsoleWindowSize( output_handle ) ); max_width = max_size.X; max_height = max_size.Y; } void gotoxy( unsigned x, unsigned y ) { if( !SetConsoleCursorPosition( output_handle, COORD{ x, y } ) ) throw std::runtime_error{ "gotoxy() failed!" }; } void write_buffer( char const * buffer, std::size_t length, std::size_t x, std::size_t y ) { DWORD written; WriteConsoleOutputCharacterA( front_buffer ? back_buffer : front_buffer, buffer, static_cast< DWORD >( length ), COORD{ static_cast< SHORT >( x ), static_cast< SHORT >( y ) }, &written ); } bool kbhit () const { return _kbhit() != 0; } int getch () const { return _getch(); } int ungetch ( int key ) const { return _ungetch( key ); } void sleep ( DWORD ms ) const { Sleep( ms ); } void toggle_double_buffering() { if( !front_buffer ) { front_buffer = original_buffer = CreateFileA( "CONOUT$", GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr ); back_buffer = CreateConsoleScreenBuffer( GENERIC_READ | GENERIC_WRITE, 0, nullptr, CONSOLE_TEXTMODE_BUFFER, nullptr ); } else { SetConsoleActiveScreenBuffer( original_buffer ); CloseHandle( original_buffer == front_buffer ? back_buffer : front_buffer ); original_buffer = front_buffer = back_buffer = nullptr; } } HANDLE get_front_buffer() const { return front_buffer; } HANDLE get_back_buffer() const { return back_buffer; } void flip() { std::swap( front_buffer, back_buffer ); SetConsoleActiveScreenBuffer( front_buffer ); } }; class game_of_life { public: class ruleset { std::array< std::size_t, 9 > birth; std::array< std::size_t, 9 > survival; public: ruleset() : birth ({ 0, 0, 0, 1, 0, 0, 0, 0, 0 }), // { 3 } survival ({ 0, 0, 1, 1, 0, 0, 0, 0, 0 }) // { 2, 3 } {} ruleset( std::vector< unsigned > & birth_neighbours, std::vector< unsigned > & survival_neighbours ) : birth {}, survival {} { for( auto i : birth_neighbours ) birth.at( 1 << i ) = 1; for( auto i : survival_neighbours ) survival.at( 1 << i ) = 1; } bool dead_or_alive( bool cell, std::size_t neighbours_alive ) const { return cell && survival[ neighbours_alive ] || birth[ neighbours_alive ]; } }; private: typedef std::vector< char > state; static char const * caption; static char const * caption_separator; static char const * stats_title; static char const * stats_separator; static char const * stats_generation_title; static char const * stats_population_title; std::size_t const width; std::size_t const height; std::size_t generation; std::size_t population; state current_state; state next_state; ruleset rules; std::size_t get_moore_neighbours( std::size_t i ) const { return current_state[ i - width - 1 ] + current_state[ i - width ] + current_state[ i - width + 1 ] + current_state[ i - 1 ] + current_state[ i + 1 ] + current_state[ i + width - 1 ] + current_state[ i + width ] + current_state[ i + width + 1 ]; } public: game_of_life( std::size_t field_width, std::size_t field_height, ruleset const & rules = ruleset{} ) : width { field_width + 2 }, height { field_height + 2 }, generation {}, population {}, current_state { width * height, 0 }, next_state { width * height, 0 }, rules { rules } {} std::size_t get_width() const { return width - 2; } std::size_t get_height() const { return height - 2; } state::const_pointer operator[]( std::size_t y ) const { if( y > height - 2 ) throw std::runtime_error{ "Line number out of range!" }; return ¤t_state[ ( y + 1 ) * width + 2 ]; } std::size_t get_generation() const { return generation; } std::size_t get_population() const { return population; } std::string generate_stats_line() const { std::stringstream ss{ caption }; ss.seekp( 0, std::ios::end ); ss << caption_separator << stats_title << get_width() << " x " << get_height() << stats_separator << stats_population_title << population << stats_separator << stats_generation_title << generation; return ss.str(); } void reset() { generation = population = 0; std::fill( std::begin( current_state ), std::end( current_state ), 0 ); std::fill( std::begin( next_state ), std::end( next_state ), 0 ); } template< typename Engine > void randomize( double probability_of_life, Engine & engine ) { std::bernoulli_distribution distribution( probability_of_life ); std::transform( std::begin( current_state ) + width, std::end( current_state ) - width, std::begin( current_state ) + width, [&]( state::value_type ){ return distribution( engine ); } ); for( std::size_t i{ width }; i < current_state.size() - width; ++i ) { current_state[ i ] = 0; current_state[ i += width - 1 ] = 0; } } void iterate() { population = 0; for( std::size_t y{ 1 }; y < height - 1; ++y ) { for( std::size_t x{ 1 }; x < width - 1; ++x ) { std::size_t i{ y * width + x }; if( next_state[ i ] = rules.dead_or_alive( current_state[ i ] != 0, get_moore_neighbours( i ) ) ) ++population; } } std::swap( current_state, next_state ); ++generation; } }; char const * game_of_life::caption { "Game of Life" }; char const * game_of_life::caption_separator { " - " }; char const * game_of_life::stats_title { "Stats: " }; char const * game_of_life::stats_separator { " | " }; char const * game_of_life::stats_generation_title { "Generation: " }; char const * game_of_life::stats_population_title { "Population: " }; int main() { try { console_window console{}; console.set_font_size( 5 ); console.resize( console.get_max_width() - 4, console.get_max_height() - 4 ); console.move_window( 0, 0 ); console.toggle_double_buffering(); game_of_life life{ console.get_width(), console.get_height() }; std::mt19937 random_engine{ static_cast< unsigned >( std::chrono::high_resolution_clock::now().time_since_epoch().count() ) }; double const life_chances{ 0.08 }; life.randomize( life_chances, random_engine ); bool run{ true }; DWORD delay{}; do { if( console.kbhit() ) { switch( std::tolower( console.getch() ) ) { case 'r': life.reset(); life.randomize( life_chances, random_engine ); break; case ' ': if( console.ungetch( console.getch() ) == ' ' ) console.getch(); break; case 0x1b: // esc run = false; break; case '+': if( delay ) delay -= 10; break; case '-': delay += 10; break; } } else { life.iterate(); for( std::size_t y{}; y < life.get_height(); ++y ) console.write_buffer( life[ y ], life.get_width(), 0, y ); console.flip(); console.set_title( life.generate_stats_line() ); console.sleep( delay ); } } while( run ); } catch( std::runtime_error & exception ) { std::cerr << exception.what() << "\n\n"; return EXIT_FAILURE; } catch( ... ) { std::cerr << "An unknown error occured!\n\n"; return EXIT_FAILURE; } } |
Werbeanzeige