Loop?


  • Mod

    Zu der Schleife: Warum nicht game auf false setzen, wenn Ende gewählt wurde?



  • Seldon, vielen Dank für die ausführliche Erklärung!

    Und SeppJ:
    Sobald die Runden gestartet sind, soll der Punktestand nach jeder Aktion (sprich entweder c für Karte oder e für Ende) angezeigt werden. Wenn Ende gewählt wird, wird game auf false gesetzt; jedoch auch am Ende der Schleife falls c gewählt wurde - um nicht in einer Endlosschleife auszuarten.
    Eine Funktion ermittelt dann jede Runde ob weder Spieler noch Dealer über 21 haben oder kein Geld mehr zum Setzen haben.

    Vielleicht hab ich heut Nacht etwas zu kompliziert gedacht. Vielleicht aber auch nicht - ich werd mich heute wieder ransetzen! :>



  • Irre ich mich oder ist die Kartenfarbe völlig irrelevant für Black Jack?

    #include <algorithm>
    #include <iostream>
    #include <vector>
    #include <string>
    
    std::string whichCard(int card)
    {
        std::string result;
        switch (card/13)
        {
            case 0:  result.append("Karo  "); break;
            case 1:  result.append("Herz  "); break;
            case 2:  result.append("Pik   "); break;
            default: result.append("Kreuz ");
        }
        switch (card%13)
        {
            case 0:  result.append("  2  ");break;
            case 1:  result.append("  3  ");break;
            case 2:  result.append("  4  ");break;
            case 3:  result.append("  5  ");break;
            case 4:  result.append("  6  ");break;
            case 5:  result.append("  7  ");break;
            case 6:  result.append("  8  ");break;
            case 7:  result.append("  9  ");break;
            case 8:  result.append(" 10  ");break;
            case 9:  result.append("Bube ");break;
            case 10: result.append("Dame ");break;
            case 11: result.append("King ");break;
            case 12: result.append("Ace  ");break;
        }
        return result;
    }
    
    bool game(std::vector<int> &sledge)
    {
        // game logic ... use back() and pop_back() to deal a card
        // deal first cards, then enter your game until player decides to stay or busts the game
        // return true until player wants to leave
    
        for (int c(0); c<sledge.size();++c)
            std::cout << whichCard(sledge[c]) << std::endl;
    
        return false;
    }
    
    int main(int argc, char *argv[])
    {
        // some randomness
        srand ( unsigned ( time (NULL) ) );
    
        // create a deck of cards
        std::vector<int> cards;
        cards.reserve(52);
    
        // fill with cardsvalues
        for (int col(0);col<4;++col)
            for (int card(0);card<13;++card)
            {
                cards.push_back(col*13+card); // [1...51]
            }
    
        bool theEnd=false;
        while (!theEnd)
        {
            // create a card sledge
            std::vector<int> sledge;
            sledge.reserve(52*6);
    
            for (int decks(0);decks<6;++decks)
                sledge.insert(sledge.end(),cards.begin(),cards.end());
    
            // shuffle sledge
            random_shuffle ( sledge.begin(), sledge.end() );
    
            // the loop
            bool play = true;
            while (play && sledge.size() > (52)) // if only one deck left, leave game
            {
                play = game(sledge);
                if (!play) { theEnd=true; }
            }
        }
    }
    


  • Kartenfarbe ist völlig irrelevant, richtig. Ist halt nur "just to make everything a little bit... cooler!". Es kann auf jedenfall nicht schaden, beim Lernen einer Programmiersprache allerhand Elemente einzubauen - die vielleicht nicht relevant sind, aber lehrreich! :>

    Und danke für den Quellcode - werd ich mir mal genauer angucken. Ein paar Dinge sind mir beim Drüberfliegen schon mal unbekannt vorgekommen :<



  • Ich repräsentiere jede Karte eines französischen Blattes durch einen Integer von 0 (Karo 2) bis 12 (Karo As) macht 13 Karten * 4 Farben == Zahlen [0..51]. whichCard() gibt dir den "String" zurück. Die Pack ich in nen Vector der ein "Blatt" darstellt. Dann pack ich 6 davon in einen Schlitten (lt. Wikipedia läuft das wohl so beim heutigen BlackJack). random_shuffle aus <algorithm> kann jeden Container mit randomiteratoren mischen. Danach benutze ich den Schlitten (perReference Übergabe an game(vector<int> &sledge) ) zum Spielen solange noch mindestens 52 Karten rest sind. ... danach wird der Schlitten neu bestückt. mit sledge.back() bekommste die letzte Karte, mit pop_back() erntfernst du die vom Sledge ... damit kann man das austeilen "simulieren".

    // so könnte man den Wert einer Karte ermitteln ...
    int whichValue(int card, bool aceLow=false)
    {
        switch (card)
        {
            case 0:
            case 1:
            case 2:
            case 3:
            case 4:
            case 5:
            case 6:
            case 7: return (card+2); // 2,3,4,5,6,7,8,9
            case 12: if (aceLow) {return 1;} return 11;
        }
    
        return 10;  // 10,Bube,Dame,König
    }
    

    Je nachdem wie anspruchsvoll dein BlackJack werden wird, kanns schwierig werden alle Karten des Spielers zu überprüfen ... wenn du SPLIT erlaubst würde ich jedem Spieler einen std::vector<std::vector<int> > ownedCards mitgeben, sowie einen std::vector<int> moneyOnCards . Wenn du dann überprüfen willst wie viel Punkte eine Hand hast gehste über alle ownedCards, summierst für jeden inneren vector die Kartenwerte (zweimal falls er ein Ass drin hat und >21 ist ... beim zweiten mal whichValue(...,true). Wenn er bustet entfernste diese Karten aus ownedCards und den Einsatz aus moneyOnCards der den selben index hat wie das gebustete Blatt ... Noch sinniger im Rahmen der Lernerfahrung wäre aber wohl eine vernünftige Kapselung in Klassen.



  • Hammer Erklärung, danke.

    Was mir aber noch nicht so ganz klar ist:
    - Wofür ist bei vector<int> , das <int>?
    - Ganz blick ich noch nicht was das std::string whichCard(int card) std da sucht? Scheint ja wohl ne Klasse zu sein? Nur was macht sie?
    - Ist for (int col(0);col<4;++col) das selbe wie for (int col = 0 [...] ?

    Btw.: Die Idee mit dem (card + 2) gefällt mir! Irgendwie habe ich mir dafür eine Min/Max-Funktion geschrieben!

    Wegen der Klassen: Stimmt schon. Nur bin ich erst seit gestern wieder bei C++ - daher wieder mal prinzipiell in Syntax und Co. einarbeiten.
    Ob sich die Erfahrung mit PHP seit 5 Jahren in der Hinsicht auch bezahlt macht? Zwar ist PHP in keinster Weiße mit C++ zu vergleichen, aber die Anlehnung von PHP an C++ ist deutlich erkennbar - und das Prinzip der Klassen sollte doch ähnlich sein? :>



  • Das sind Klassen aus dem Namespace std::
    http://www.cplusplus.com/reference/string/string/
    http://www.cplusplus.com/reference/stl/vector/

    Vector ist ein generischer Container ... mein vector ist ein Container für int's (sozusagen ein spezielle Ausprägung des generischen Containers). Der Vorteil der STL Container ist einfach, das die die ganze Speicherverwaltung vom Benutzer kapseln ... wesentlich einfacher und sicherer zu nutzen als rohe Arrays int cards[52]; oder sogar noch selbst allociertes Zeug (new/delete).

    std::string whichCard(int card) { ... } ist ne Methode: Rückgabetyp, Name(Übergabeparameter) { was sie tut } ... im Wesentlichen gibt die dir den String zurück 😉

    Statt jedesmal std::vector<int>; std::cout; std::string zu schreiben kannst du das auch anders machen: http://www.cplusplus.com/doc/tutorial/namespaces/ aber in .h's bitte nicht 😉

    Das mi for (int i(0) ..) ist das selbe ... kann sein das man so einen Copyconstruktor spart .. aber ich glaube das wird eh rausoptimiert. Bin grad zu faul zu deassemblieren.



  • Vielen Dank! 🙂


  • Mod

    Eieiei, das sind wirklich grundlegendste Grundlagen, man merkt, dass du erst seit gestern dabei bist. Die zwei wichtigen Stichworte: Templates, Namespaces

    Das <int> bei vector<int> ist ein Templateparameter. vector ist keine vollständige Klasse für ein dynamisches Array, sondern nur die Vorlage (=Template) für eine solche Klasse. Das heißt die ganzen Algorithmen sind schon da, aber sie wissen noch nicht von welchem Typ das dynamische Array ist. Denn die verwaltung eines dyamischen Arrays gefüllt mit ints funktioniert genauso wie eines gefüllt mit floats, oder std::strings oder mit MeinerEigenenKlasse. Der Templateparameter sagt dem Compiler von welcher Sorte der vector denn nun tatsächlich sein soll. Der Setzt dann quasi diesen Typen in die ganzen Algorithmen ein und macht aus der Klassenvorlage vector eine konkrete Klasse namens vector<int>. Man kann natürlich die Vorlage auch mehrmals für verschiedenen Typen benutzen.

    das std:: bei std::string ist die Angabe für den Namespace (Namensraum) in den string zu finden ist. Namensräume dienen dazu Namenskollisionen zu vermeiden. Beispielsweise liegen alle Klassen und Funktionen aus der C++-Standardbibliothek im Namensraum std. Auf diese Weise kannst du selber Klassen, Funktion oder Variablen mit dem Namen string benutzen, ohne dass es zu Konflikten mit der Klasse aus der Standardbibliothek kommt. Am besten packst du deine eigene Klasse string natürlich auch noch in einen extra Namensraum (zum Beispiel Yada::string). So kommt es dann auch nicht zu Konflikten, wenn du deinen Code mal mit dem Code von anderen Entwicklern mischen musst, die eventuell selber den Bezeichner string irgendwo benutzt haben.

    edit: Oh, zu langsam. das kommt davon wenn man so viel schreibt.



  • padreigh schrieb:

    Das mi for (int i(0) ..) ist das selbe ... kann sein das man so einen Copyconstruktor spart .. aber ich glaube das wird eh rausoptimiert. Bin grad zu faul zu deassemblieren.

    Es ist 100%ig das selbe.
    Hat auch nichts mit Optimierungen zu tun.
    int i = 3;
    Ruft niemals einen Zuweisungsoperator oder gar Copy-CTor auf.

    bb


Anmelden zum Antworten