• Teuflische Folge

      0 comments

    Soderle,

    dann werde ich mal den Grundlagen Bereich einweihen 🙂

    Wir fangen mal nicht ganz unten mit den Grundlagen an, sondern mit einem kleinen, aber feinen Algoritmus (keine Angst, Grundlagen zu Variabeln etc. kommen auch noch :))

    Wir betrachten heute mal die teuflische Zahlenfolge. Diese ist mathematisch in der folgenden Formel definiert:

    x_{n+1} =\left\{ \begin {array} {cc} x_n/2 & wenn x_n gerade \\ (3*x_n+1)/2 & wenn x_n ungerade \end {array} \right.

    Die Formel besagt, dass wir eine beliebige Zahl n

    • wenn sie gerade ist durch 2 teilen => n/2
    • wenn sie jedoch ungerade ist, wird auf n 1 addiert, also n+1.

    Wie bilden wir nun diese doch relativ einfache mathematische Formel nun in C++ ab?

    Dazu erstellt eine Source Datei. Diese Datei hat die Endung .cpp
    Ich habe meine Datei „folge.cpp“ genannt.

    Nun müssen wir noch eine Bibliothek unserem Sourcecode hinzufügen.
    Diese Bibliothek ist nur für die Ausgabe unserer berechneten Zahlenfolgen notwendig. Natürlich hat die Bibliothek noch andere Funktionen,
    aber auf diese gehen wir in einem anderen Beitrag ein.
    Die Bibliothek die wir für die Ausgabe benötigen heisst „iostream“. Folgendermaßen wird die Bibliothek in den Sourcecode eingefügt:

    #include <iostream>

    Mit dieser #include Anweisung können noch weitere Bibliotheken in euren Sourcecode eingebunden werden, ist hier aber nicht sinnvoll.

    Um nun ein Lauffähiges Programm zu haben, brauchen wir eine Funktion, die beim Starten der Anwendung immer aufgerufen wird. Das ist die „main()“ Funktion.

    Jedesmal wenn ihr ein Programm startet, wird diese Funktion als erstes ausgeführt.
    Der einfachheit halber habe ich den ganzen Algoritmus zur Berechnung der „Teuflischen Zahlenfolge“ in die Main Funktion gepackt.
    So sieht der Code im ganzen aus:

    #include "stdafx.h"
    #include  <iostream>
     
    using namespace std;
     
    int main(int argc, _TCHAR* argv[]) 
    {
       int n = 666; //Eine Teuflische Zahl für einen Teuflischen Algoritmus
       while (n != 1) 
       {
         if ((n % 2) == 0) 
         {
    	n = n / 2;
         } 
         else 
         {
    	n = (n * 3 + 1) / 2;
         }
         cout << n << endl;
       }
       cin >> n;
       return 0;
    }

    In diesem Code haben wir verschiedene Bedingte Anweisungen und Schleifen.
    Zum einen haben wir die „while“ Schleife. Diese wiederholt den Code, der innerhalb des Schleifenrumpes steht solange, bist die Bedingung erfüllt ist,
    die im Schleifenkopf angegeben ist.
    In dem Fall durchläuft die Schleife den Schleifenrumpf, solange „n != 1“ (gesprochen: n ist ungleich 1) ist.

    Innerhalb der Schleife haben wir die Bedingte Anweisung (oder auch If-Statement genannt).
    Mit ihr können wir eine True-False Bedingung abfragen.
    Im Sourcecode steht

    if ((n % 2) == 0)

    Hier wird der Modulo von n zur Zahl 2 berechnet. Es wird also nichts anderes gemacht, als den Rest der Division von n durch 2 zu ermitteln.
    Ist das Ergebnis der Berechnung 0, ist die Zahl gerade.
    Ist das Ergebnis der Berechnung ungleich 0, ist die Zahl ungerade.
    Wers mir nicht glaubt, kanns ja selber mal nachrechnen 😉

    Nun ist es so, falls das Ergebnis der Berechnung gerade, also 0 (oder true) ist , wird der obere Teil des If-Statements „betreten“ und auch nur dieser ausgeführt.
    Somit wird die Berechnung n=n/2 ausgeführt.
    Ist das Ergebnis der Berechnung ungerade, also ungleich 0 (oder eben false), wird der „else“ Teil des If-Statements „betreten“ und ebenfalls nur dieser ausgeführt.
    Es wird praktisch der obere Teil des If-Statements übersprungen.

    Als letzes haben wir noch eine Einfache Ausgabe für die berechneten Zahlen.
    Dies wird mittels std::cout bewerkstelligt.

    Ich hoffe Ihr habt nun viel Spass mit den Teuflischen Zahlen.

    P.S.: Wer mehr erfahren will, kann auch mal nach dem „Collatz-Problem“ suchen. Das ist im Grunde genau dieses Problem hier.

  • TurtleGrafik – der teuflische Weg in langsamen kleinen Schritten zum Fraktal

      0 comments

    Ok nachdem der Engel nun ihre Version zur Turtlegrafik vorgelegt hat, kommt nun meine… natürlich viel… nativere Version 😉 die ISO Version.

    Der Konstruktor oder soll ich sagen die Konstruktoren?? Diese Version der TurtleGrafik besitzt neben dem Standardkontruktor noch einen überladenen Konstruktor, der eine Startkoordinate der Turtle entgegennimmt

    Turtle::Turtle() : mXPos(0), mYPos(0), mAngle(0)
    {
     
    }
     
    Turtle::Turtle(int x, int y) : mXPos(x), mYPos(y), mAngle(0)
    {
     
    }

    Besonderheit an den Konstruktoren ist die verkürzte Schreibweise zur Initialisierung der Klassenvariablen.
    Durch den überladenen Konstruktor wird in dieser Version auf die Methode SetXY verzichtet, da sie für den Pythagorasbaum nur einmal genutzt werden würde, um den Startpunkt des Baumes zu definieren. Für andere Fraktale, wo ein versetzen der Turtle notwendig ist müsste die Funktion trotz des überladenen Konstruktors der Turtle – Klasse hinzugefügt werden, aber wie gesagt für den Pythagorasbaum ist sie nicht notwendig.
    Und die Turtle rennt los mit ihrem Stift …. naja ihrem Grafikobjekt

    void Turtle::forward(int n, CDC* pDC)
    {
    	int xStart = mXPos;
    	int yStart = mYPos;
    	double rad = (M_PI * (mAngle - 90)) / 180;
    	mXPos += (int)floor(n * cos(rad) + 0.5);
    	mYPos += (int)floor(n * sin(rad) + 0.5);
     
    	pDC-&gt;MoveTo(xStart, yStart);
    	pDC-&gt;LineTo(mXPos, mYPos);
    }

    Schnell die Startposition gesichert und mittels Bogenmaß und Trigonometrie unsere Zielkoordinate berechnet. Wer zum Bogenmaß ne Erläuterung brauch, so schaue er doch bitte gen Himmel der Engel hat das gut erklärt. Jedoch gibts da zum Vergleich zur managed Version eine kleine Besonderheit – das Runden. Leider verfügt die Nativität des ISOs nicht über eine so schöne Rundungsfunktion wie in der managed Version – Oder ich bin blind und hab sie nicht gefunden so bitte da unten kurz ein Kommentar reintippeln vielleicht gibt es dann eine zweite Version.
    Nun wie runden wir hier nun korrekt. Alles was unter 0.5 ist wollen wir normal abrunden alles was über 0.5 ist soll aufgerundet werden – so richtig mathematisch korrekt. Mit floor runden wir wie es der Name schon sagt alles ab. Also floor(0.9)=0.0, damit wir nun richtig, runden bedienen wir uns einem kleinem Trick. Wir addieren zu dem Wert, der gerundert werden soll, einfach ein 0.5 hinzu. Was passiert da in unserem Beispiel floor(0.9+0.5)? Durch die Addition überschreiten wir sozusagen die Rundungsgrenze, d.h. wir überschreiten den Wert 1. Dadurch, dass wir alles abrunden haben wir nun richtig mathematisch gerundet, denn floor(0.9+0.5)=1.0 clever oder? 😉
    Da auf einem Grafikelement das Fraktal gezeichnet wird (für die Gui hab ich mich für das gute alte MFC – Framework entschieden) müssen wir nun die kleine teuflische Schildkröte nur noch dazu bringen ein Strich zu unsere Zielkoordinate zu malen. Mit der Memberfunktion Moveto setzen wir den „Stift“ sozusagen auf unseren Startpunkt ab und Lineto bewegt unsere Turtle samt Stift an unsere Zielkoordinate.

    Und zu guter Letzt – dreh dich Turtle dreh dich

    void Turtle::turn(int a)
    {
    	mAngle = (mAngle + a) % 360;
    }

    Die Methode unterscheidet sich nicht zu der der managed Version.

    Et Voíla – natives Schildkrötchen vollendet.

  • Strich für Strich zum Fraktal – die Turtlegrafik

      0 comments

    Turtle-, Igel- oder Froschgrafik – viele Ausdrücke für eine doch recht einfache Bildbeschreibungsgrafik, genutzt bei Stiftplottern oder der vielleicht doch bekannten Programmierprache LOGO.

    Für die Programmierherausforderung wird die Turtlegrafik genutzt, um das eigentliche Fraktal zu zeichnen. Weil im gesamten Programmverlauf mehr als ein Turtle – Objekt genutzt wird, wird die Turtlegrafik als eigenstädige Klasse implementiert.

    Neben den 4 erlaubten Methoden beinhaltet die Turtle-Klasse einen Konstruktor, in dem alle wichtigen Variablen initialisiert werden.

    TurtleGrafic( Color color)
    {
         Winkel=0;
         xPos=0;
         yPos=0;
         redPen = gcnew Pen(color);
         redPen->Width=1.0F;
    }

    Neben der Initialisierung der Variablen, wird auch ein Pen – Objekt mit der vom User ausgewählten Farbe initialisiert. Dazu bekommt es noch die Strichstärke von 1. Der Pen wird genutzt, um auf unserem Graphics – Element später zu zeichnen.

    Die wichtigste Methode ist wohl neben dem Konstruktor die forward – Methode. Diese berechnet die neuen Koordinaten, zu der die Turtle “laufen” und dabei einen ganz normalen Strich zeichnen soll.

    void forward(Graphics ^gr,Int32 n)
    {
      Int32 xStart, yStart;
      xStart=xPos;
      yStart=yPos;
      g=gr;
      Double pi=System::Math::PI;
      Double rad = (pi * (Winkel-90))/180;
      xPos+= Convert::ToInt32(
    	          System::Math::Round(
    		      Convert::ToDouble(n*System::Math::Cos(rad))));
      yPos+= Convert::ToInt32(
    		  System::Math::Round(
    		      Convert::ToDouble(n*System::Math::Sin(rad))));
      g->DrawLine(redPen,xStart,yStart,xPos,yPos);
    }

    Die Berechnung des Punktes, zu dem unsere Turtle laufen soll, erfolgt in zwei bzw. drei (wenn man die Berechnung für den x und y Wert getrennt betracht) Schritten.
    Schritt 1:
    Umwandlung des gegebenen Winkels ins Bogenmaß. In der Schule wird dazu die Gleichung gelehrt
    Bogenmaß = Grad * Pi/180. Fast die gleiche benutzt die Turtle auch, nur mit dem Unterschied, dass aufgrund der Tatsache, dass der Koordinatenursprung links oben in der Ecke liegt, die Turtel noch einmal um 90° nach links gedreht wird.
    Schritt 2:
    Mithilfe des eben berechneteten Bogenmaßes wird die neue Koordinate berechnet. Um den neuen y-Wert zu berechnen, wird der sin(winkel) gezogen. Der X-Wert aus dem cos(Winkel). Da die Grundlänge einen Wert n hat und nicht dem Einheitskreis entspricht, wird die Grundlänge n noch dazu multipliziert.
    Mit den neuen Koordinaten kann die Turtle schlußendlich ihre Linie zeichnen.
    Als Dritte wichtige Methode ist noch die turn Methode zu erwähnen.

    void turn(Int32 a)
    {
        Winkel =(Winkel+a)% 360;
    }

    Die kleine Methode dreht den Blickwinkel unserer Turtle um den Winkel den wir angeben.
    Je nach Vorzeichen dreht sie sich nach links oder nach rechts.

    Um die Turtel an einer bestimmten Koordinate zu platzieren, wird die Methode SetXY genutzt.

    void setXY(Int32 x, Int32 y)
    {
        Winkel=0;
        xPos=x;
        yPos=y;
    }
  • Slotmachine Teil 1 in – ISO C++

      0 comments

    Was der Engel kann, kann ich schon lang 😉

    Ok wir haben die gleichen Rahmenbedingungen, wie für den „engelhaften“ Weg. Auch ist in dem Fall die Entwicklungsumgebung Visual Studio 2010.

    Als Projekt nutzen wir eine Win32 Konsolenanwendung und auch hier ist uns Visual Studio behilflich und erstellt das Grundgerüst für unser Anwendung.

    #include "stdafx.h"
     
    int _tmain(int argc, _TCHAR* argv[])
    {
    	return 0;
    }

    Anders wie im in der C++/CLI Version müssen wir noch ein Header includieren, damit wir schöne Ausgaben in die Konsole schreiben können … das Leben ist so ungerecht… Gut includieren wir den Header iostream

    Der IOStream Header erlaubt uns das wir mit cout unsere Ausgaben schön an die Konsole rausschicken können, ohnedas wir groß mit Klammern und so arbeiten müssen. fügen wir gleich noch unsere Variablen ein 4 Integer, davon eine gleich mit 100 initialisieren und ein Char …. so erledigt

    #include "stdafx.h"
    #include <iostream>
    int _tmain(int argc, _TCHAR* argv[])
    {
            int punkte = 100;	
    	int i, j, k;		
    	char wahl;
    	return 0;
    }

    Was wir auf unserem teuflischen Weg nicht brauchen ist eine Variable für den Random, in Visual Studio kommt die Funktion mit der stdafx.h mit, ansonsten benötigt man den Header stdlib.h

    #include "stdafx.h"
    #include <iostream>
    int _tmain(int argc, _TCHAR* argv[])
    {
            int punkte = 100;	
    	int i, j, k;		
    	char wahl;
    	i = (rand() % 10) + 1;
    	j = (rand() % 10) + 1;
    	k = (rand() % 10) + 1;		
    	return 0;
    }

    Ein weiteren Unterschied zu dem engelhaften Weg ist die Angabe der Grenzen für die Randomfunktion. Während man unter CLI sowohl die untere als auch obere Grenze genau angeben kann, so läuft die Randomfunktion unter ISO von 0 bis zu einer oberen Grenze, dabei ist die Obere Grenze in den Bereich nicht mit eingeschlossen, d.h. mit anderen Worten wie ermitteln eine Zahl zwischen 0 und 9 und verschieben danach den Wertebereich um ein Zähler nach oben.

    Den, je nach dem wie uns Lady Luck oder der Spieler mag, endlosen Spielablauf erreichen wir auch mit einer Do – While schleife. So spielt der Benutzer mindestens einmal (keinmal wäre ja auch doof)
    Abbruchbedingungen sind wie vorgegeben weiter spielen solange man noch Punkte hat in dem man „j“ drückt.
    Mit noch ein wenig Künstlerischen ausschmücken in Text und Form haben wir schon ein fast fertiges exemplar.
    Das cin ist dann für uns so nett und liest den Benutzerinput ein und übergibt es an unsere wahl Variable, die wir dann in unserer While Anweisung auswerten

    #include "stdafx.h"
    #include <iostream>
    int _tmain(int argc, _TCHAR* argv[])
    {
       int punkte = 100;	
       int i, j, k;		
       char wahl;
       do
       {
          i = (rand() % 10) + 1;
          j = (rand() % 10) + 1;
          k = (rand() % 10) + 1;
          cout << "Position1 hat den Wert: " << i << endl;
          cout << "Position2 hat den Wert: " << j << endl;
          cout << "Position3 hat den Wert: " << k << endl;
          cout << "Sie haben jetzt " << punkte <<endl;
          cout<< " Punkte" << endl;
          cout <<"Wollen sie noch eine Runde spielen?" << endl;
          cin >> wahl;
       } while (wahl == 'j' && punkte != 0);
       cout << "Ihr Spiel wurde beendet."<<endl;
       cout << "Ihre Punktzahl ist: " << punkte << endl;	
       return 0;
    }

    Fehlt nur noch der Gewinn und der Verlust … *hust* Einsatz natürlich, wir verlieren ja nicht und der Vergleich ob wir gewonnen haben und bitte schön fertig ist die erste Slot in Iso C++

    #include "stdafx.h"
    #include <iostream>
    using namespace std;
    int _tmain(int argc, _TCHAR* argv[])
    {
       int punkte = 100;	
       int i, j, k;		
       char wahl;			
       do
       {
    	i = (rand() % 10) + 1;
    	j = (rand() % 10) + 1;
    	k = (rand() % 10) + 1;
    	if (i == j && j == k)
    	{
                punkte += 5;
    	    cout << "Position1 hat den Wert: " << i << endl;
                cout << "Position2 hat den Wert: " << j << endl;
                cout << "Position3 hat den Wert: " << k << endl;
                cout << "Sie haben jetzt " << punkte <<endl;
                cout<< " Punkte" << endl;
    	}
    	else
    	{
    	   punkte -= 5;
    	   cout << "Position1 hat den Wert: " << i << endl;
               cout << "Position2 hat den Wert: " << j << endl;
               cout << "Position3 hat den Wert: " << k << endl;
               cout << "Sie haben jetzt " << punkte <<endl;
               cout<< " Punkte" << endl;
    	}
          cout <<"Wollen sie noch eine Runde spielen?" << endl;
          cout << "Druecken sie fuer JA die Taste j und" << endl;
          cout << "bestaetigen sie ihre Auswahl mit Enter" << endl;
          cin >> wahl;
         } while (wahl == 'j' && punkte != 0);
         cout << "Ihr Spiel wurde beendet."<<endl;
         cout << "Ihre Punktzahl ist: " << punkte << endl;	
    	return 0;
    }

    Gar nicht so schwer oder? Naja vielleicht wird Version 2 eine größere Herrausforderung.

    Eure littleDevil

  • Slotmaschine Teil 1

      0 comments

    Als Entwicklungsumgebung nutze ich das Visual Studio 2010 von Microsoft (auch wenn ich mich mit dem fehlenden IntelliSense schwer abfinden kann). Als .NET Frameworks habe ich bis zu Version 4 alle installiert. Die Entwicklung selber funktioniert auch bei ältern Versionen ohne Probleme.

    Als Projekt nutze ich eine CLR – Konsolenanwendung.
    Das Grundgerüst wird automatisch von der Entwicklungsumgebung erstellt.

    #include "stdafx.h"
     
    using namespace System;
     
    int main(array<System::String ^> ^args)
    {
        Console::WriteLine(L"Hello World");
        return 0;
    }

    Die „Hello World“ Konsolenausgabe werden wir nachher für unsere Zwecke nutzen, somit brauchen wir sie nicht zu löschen.

    Wir benötigen folgenden Variablen

    Punkte – Eine Ganzzahl, die wir mit dem Wert 100 vorbelegen
    3 Slots – 3 Ganzzahlen die mit Zufallswerten zwischen 1 und 10 „gefüttert“ werden
    Random – Das Randomobjekt, das uns die Zufallswerte ermittelt
    Wahl – Wir lesen eine Tastatureingabe ein um das Spiel am laufen zu halten

    Das Programm sollte nun so aussehen

    #include "stdafx.h"
     
    using namespace System;
     
    int main(array<System::String ^> ^args)
    {
        Int32 punkte=100;
        Int32 slot1, slot2, slot3;
        Random random;
        char wahl;
        Console::WriteLine(L"Hello World");
        return 0;
    }

    Für das Erzeugen von zufälligen Werten und die Belegung unserer Slots mit diesen Werten muss zuerst das Randomobjekt initialisiert werden.
    Nachdem dies geschehen ist weisen wir einfach mit random->Next(1,10); den einzelnen Slots die Zufallswerte hinzu.

    Damit man auch etwas im Konsolenprogramm sieht führen wir nehmen den Ausgaben unserer Slots , noch eine Abfrage ein ob wir eine weitere Runde spielen wollen.

    #include "stdafx.h"
     
    using namespace System;
     
    int main(array<System::String ^> ^args)
    {
        Int32 punkte=100;
        Int32 slot1, slot2, slot3;
        Random ^random= gcnew Random();
        char wahl;
        slot1= random->Next(1,10);
        slot2= random->Next(1,10);
        slot3= random->Next(1,10);
        Console::WriteLine("Position1 hat den wert: {0}",slot1);
        Console::WriteLine("Position2 hat den wert: {0}",slot2);
        Console::WriteLine("Position3 hat den wert: {0}",slot3);
        Console::WriteLine("Wollen sie noch eine Runde spielen?");
        Console::WriteLine("Drücken sie für JA die Taste j");  
        Console::WriteLine("und mit enter bestätigen");
        wahl=Convert::ToChar(Console::ReadLine());
        return 0;
    }

    Nun ist es fast geschafft. Nun benötigen wir nur noch eine Schleife, die es uns ermöglicht weitere runden zu spielen. Ebenso muss noch der Einsatz abgezogen und gegebenfalls der Gewinn zu unseren Punkten hinzugerechnet werden.

    #include "stdafx.h"
     
    using namespace System;
     
    int main(array<System::String ^> ^args)
    {
      Int32 punkte=100;
      Int32 slot1, slot2, slot3;
      Random ^random= gcnew Random();
      char wahl;
      do
      {
        slot1= random->Next(1,10);
        slot2=random->Next(1,10);
        slot3=random->Next(1,10);
        if (slot1==slot2 && slot2==slot3)
       {
         punkte+=5;
         Console::WriteLine("Slot1 hat den wert: {0}",slot1);
         Console::WriteLine("Slot2 hat den wert: {0}",slot2);
         Console::WriteLine("Slot3 hat den wert: {0}",slot3);
         Console::WriteLine("Sie haben jetzt {0} Punkte",punkte);
        }
        else
        {
          punkte-=5;
          Console::WriteLine("Slot1 hat den wert: {0}",slot1);
          Console::WriteLine("Slot2 hat den wert: {0}",slot2);
          Console::WriteLine("Slot3 hat den wert: {0}",slot3);
          Console::WriteLine("Sie haben jetzt {0} Punkte",punkte);
         }
        Console::WriteLine("Wollen sie noch eine Runde spielen?");
        Console::WriteLine("Drücken sie für JA die Taste j" );
        Console::WriteLine("und mit enter bestätigen");
        wahl=Convert::ToChar(Console::ReadLine());
      }
      while(wahl=='j' && punkte!=0);
      return 0;
    }

    Et Voíla die erste Version der Slotmaschine ist fertig.

    Viel Spaß mit dem 1. Teil

    littleAngel