Beginnercode: Pokerdealer Programm

fk1

Mitglied
Hallo zusammen,

da ich mittlerwile die ersten Anfängertutorials durchgearbeitet habe wurde es dann Zeit für Praxis. Ich habe leider keine Idee für ein nützliches Tool gehabt, allerdings ein Faible für Poker. Was liegt also näher als ein Pokerspiel zu programmieren? :D

Naja, ich bin sicherlich weit entfernt davon einen Pokerclient zu coden, allerdings ging mir eine simple Idee dabei nicht mehr aus dem Kopf und so habe ich mich heute mal hingesetzt und ein paar Zeilen geschrieben und probiert ein paar Ideen umzusetzen bzw. Probleme zu lösen.

Ich habe eine Klasse "Dealer" geschrieben, welche die Methode "deal" beinhaltet. In der Methode "deal" definiere ich mittels Arrays, wie eine Karte sich zusammen setzt (Aus Rang und Farbe/suit).

Zusätzlich nutze ich "Random", um zufällige Indezes der Arrays zu wählen und bilde damit dann eine Karte, welche ich ausgebe.

In der main Methode gebe ich 2 Karten an einen Spieler aus. Problem hierbei ist das Austeilen doppelter Karten. Ich dachte, ich füge ausgeteilte Karten einer ArrayList hinzu und lasse für den doppelten Fall einfach erneut die for-schleife durchlaufen.

Das klappt sogar ganz gut, jedoch bekomme ich mit diesem Programm nur 24 exklusive Kombinationen ausgegeben. Da ein Kartendeck aus 52 Karten besteht müssten es allerdings 26 Kombos sein.

Vielleicht findet ja jemand den Fehler. Auch für Anregungen zur Lesbarkeit oder Umsetzung bin ich offen. Habt Nachsicht mit mir, ich bin "nur" IT-Systemelektroniker, also kein Fachinformatiker, und das ist mein erstes Java Programm zum lernen. ;)

Schönen Gruß

E: Frage: kann i negativ werden? Ich gucke gerade nochmal durch meine Ausgabe und kann keinen einzigen King entdecken. Der ist am Ende des ersten Arrays aber definiert.

E2: Habs gefunden, war einfach nur 13 statt 12 als Parameter bei 'int rndrank = rnd.nextInt' :)


Java:
import java.util.ArrayList;
import java.util.Random;

public class Dealer {

    /**
     * @param args
     */
    public static void main(String[] args) {
  
        // ArrayList für ausgeteilte Karten
        ArrayList<String> dealt = new ArrayList<String>();
  
        // for-Schleife um alle möglichen Kombinationen ausgeben zu lassen
        for(int k=0; k<50; k++)    {
      
            // Kartenausteilung (2 holecards, 1 Spieler)
            for(int i=0; i<2; i++){
                String hcard = deal();
          
                // Prüfe ob Karte bereits ausgeteilt wurde
                if(dealt.contains(hcard)) {
                    i--;
                }
                else {
                    // Karte zum Array verteilter Karten hinzufügen und austeilen
                    dealt.add(hcard);
                    System.out.print(hcard);
                }
            }  
            System.out.println();
        }

    }

    public static String deal() {
        // Definition des Kartendecks mittels Arrays
        String[] rank = {"A", "2", "3", "4", "5", "6", "7", "8", "9", "T", "J", "Q", "K"};
        String[] suit = {"c", "s", "d", "h"};
          
        // Generierung einer zufälligen Zahl für Array Indizes (Shuffle)
        Random rnd = new Random();
        int rndrank = rnd.nextInt(12);
        int rndsuit = rnd.nextInt(4);
  
        // Kombination einer Karte
        String card = rank[rndrank] + suit[rndsuit];
  
        return card;
    }
}
 
Zuletzt bearbeitet:
K

kneitzel

Gast
Was für ein Anfängertutorial hast Du denn durchgearbeitet? Ich frage, weil Java Objektorientiert ist und davon sehe ich halt nichts. Gerade bei so Projekten, wenn mehr als nur die 08/15 mini Programme geschrieben werden, ist dies in meinen Augen extrem wichtig.

Ich sehe nicht wirklich, wo der Lerneffekt ist, wenn man ein Poker-Spiel scriptet (Darauf läuft es ja unter dem Strich hinaus).

Ich will Dir da nicht zu nahe treten oder das, was Du machen willst, schlecht reden. Wir helfen Dir auch bei Deinem jetzigen Anliegen, wenn Du das wirklich so machen willst. Aber ich würde das doch etwas anders durchziehen an Deiner Stelle.

Zu Deinem aktuellem Code:
In einer For Schleife die Variable aus der For Schleife zu benutzen halte ich für einen extrem schlechten Coding-Stil. Wenn Du kein sauberes Durchzählen hast, dann nimm eine andere Schleife wie z.B. eine while Schleife.

Konrad
 

fk1

Mitglied
Hi Konrad,

ich habe das hier angeguckt: http://panjutorials.de/tutorials/java-programmieren-fur-anfanger/
Bin allerdings auch nicht ganz fertig mit dem Tutorial, nur bis Video 30 von 40 geguckt. Hole ich natürlich nach, werde wohl auch noch in Zukunft einiges lernen müssen.

Ich hatte "Java ist eine Insel" mal angelesen bis mir aufgefallen ist dass das Buch sich besser als Nachschlagewerk als zur Einarbeitung eignet. Das Konzept "Objektorientiertes Programmieren" habe ich anscheinend noch nicht verstanden. Ich dachte es geht darum, ein Objekt mit Attributen und Werten zu erstellen, mir hängt da noch der Merksatz im Kopf: Ein Auto fährt, verbraucht Sprit und produziert Abgase.

Meine Idee etwas umzusetzen war halt: Der Dealer mischt das Deck, sammelt die Einsätze (kommt noch) und teilt Karten aus. Scheint ja noch nicht so richtig geklappt zu haben. Ich mache mir nochmal Gedanken dazu und probiere das Programm objektorientierter zu gestalten.

for Schleife Nummer Eins ist eigentlich nur zum Testen da. Trotzdem meine Frage: Warum nutze ich die gleiche Variable? ich nutze doch einmal k und einmal i?!

Kann schon sein, dass das Pokerspiel wirklich nicht geeignet ist. Allerdings habe ich gelesen: am besten ist die Praxis um zu lernen und ich habe einfach keine andere Idee. Ich habe aber viel Erfahrung in dem Spiel und vielleicht wird das Ganze spannender wenns um die KI geht ;)

Gruß
Flo
 
Zuletzt bearbeitet:

Jardcore

Top Contributor
Hey fk1,

um das OO zu machen würde die main-Methode der Einstieg in dein Programm sein und in einer Extra Starter-Klasse liegen (z.B.: PokerApp, MainApp ...)
Dort könnte dann ein Objekt Dealer erzeugt werden und auf diesem dann deal() aufgerufen werden.
Java:
public class Dealer {
    private ArrayList<Card> cards;
  
    public void deal() {...}
}

Wahrscheinlich hätte man auch noch ein paar andere Objekte (Table, Player, CardShuffler).

Ich nehme mir vorher immer ein Blatt Papier und zeichne mir alle Komponenten auf und leite daraus meine Objekte ab. Dann siehst du auch auf einem Blick ob dir noch etwas fehlt.

Im Code könntest du auch sogenannte Magic Numbers vermeiden, das sind die Zahlen die man nicht auf Anhieb interpretieren kann. In deinem Beispiel die 50 und die 2, du benutzt dafür ein Kommentar über der for-Schleife, könntest aber auch einfach eine Variable für die beiden Nummern spendieren und hättest damit einen guten Lesefluss.
Allgemein benutzte einfach längere Namen, statt dealt für deine ArrayList, könntest du die Liste auch playedCards, oder wohl möglich auch listOfPlayedCards, dann wüsstest du auf einem Blick was gemeint ist. Sowas ist vor allem bei größeren Projekten Gold wert.

Beste Grüße,
Jar
 

fk1

Mitglied
Hallo zusammen,

@kneitzel: Ich verstehe jetzt erst, was du mit gleicher Variable meinst. Ich überlege mir da mal eine Alternative. Ich glaube auch, du siehst gar nicht das Pokerprogramm skeptisch, sondern das Scripten statt OOP. Das hatte ich gestern Abend falsch verstanden.

Falls dem so ist, sehe ich das genau so. Deswegen poste ich hier, ich möchte konform sein mit der Java Idee/OOP/den Developern.

Ich komme durch ein kleines AutoIT Projekt auf die Idee, Programmieren zu lernen. Ich finde die Idee der OO Programmierung auch super, das AutoIT Projekt bestand aus 500 Anfängerlines. Hat Spaß gemacht und seinen Job getan, war aber absolut unübersichtlich :D

@Jardcore: Danke für deine Tipps, auch da werde ich einiges adaptieren und mir nochmal Gedanken zum Thema OO machen. Eine Skizze mache ich auch mal, ich versuche mal mit Diagrammen zu arbeiten um das besser zu planen.

Edit: Noch ein paar Fragen:

Gruß
Flo
 
Zuletzt bearbeitet:

CSHW89

Bekanntes Mitglied
Um deine ursprüngliche Frage zu beantworten: dein Dealer wird sicherlich keinen König austeilen.
Java:
int rndrank = rnd.nextInt(12);
Da muss eine 13 stehen. Solche Fehler entstehen übrigens genau wegen Magic-Numbers, was @Jardcore bereits angesprochen hat. Besser ist dort:
Java:
int rndrank = rnd.nextInt(rank.length);
... bei suit genauso.

lg Kevin

Edit: ups hab den Edit nicht gelesen. Ich lass es aber mal trotzdem stehen
 

fk1

Mitglied
Danke Kevin, wusste bis jetzt noch nicht, dass das so funktioniert.

Ich sitze hier und überlege wie ich Struktur in ein Diagramm bekomme und ich schätze, ich muss das mal ganz simpel herunterbrechen.

Allgemein gilt: Ein Objekt ist eine Instanz aus einer Klasse. Also ist z.B. eine card ein draw aus einem Deck.

Was ist dann der Dealer? Für mich ein Objekt, da er z.B. Karten austeilt (Methode) und die Regeln kennt (Eigenschaft). Bleibt die Frage: Zu welcher Klasse gehört der Dealer?

Ich dachte an die Klasse Holdem, da der Dealer Holdem Regeln befolgt. Das würde künftig eine Erweiterbarkeit liefern, da man dann andere Klassen wie z.B. Omaha (Variante mit 4 Karten) erstellen kann.

Kann eine Klasse mehrere verschiedene Objekte beinhalten? Ich würde dann in der Klasse Holdem, welche die Variante darstellt, alle variantenbezogenen Objekte packen, z.B. auch die Anzahl der holecards (2) oder die Regeln der Auswertung einer Hand.

e: Alternative: Ich erzeuge eine Klasse Dealer, aus der ich ein Objekt holdemdealer instanzieren kann.
 
Zuletzt bearbeitet:
K

kneitzel

Gast
Ok, also bist Du für die Objektorientierte Herangehensweise offen. Das war mir für mein Verständnis wichtig.

Die objektorientierte Entwicklung kann man recht gut mit der realen Welt vergleichen. Wenn man das Beispiel Auto nimmt, dann hat man einen groben Plan, wie das Auto aufgebaut ist. Aber man muss nicht alles bauen. Man kann auch Schnittstellen definieren und dann nutzt man ggf. vorhandene Dinge. Also ich muss, wenn ich ein Auto bauen will, nicht alles selbst bauen. Ich brauche einen Motor (der dann eine gewisse Schnittstelle hat), aber den baue ich nicht selbst, sondern dafür nehme ich mir dann halt den de.vw.sportmotor.MotorMitVielLeistung, der halt IMotor implementiert. Und wenn der mit nicht gefällt, dann tausche ich den evtl. gegen de.fiat.500erMotor und tausche den ggf. relativ einfach aus, weil alle Zugriffe über das Interface IMotor gehen.

Aber ich will Dich mit einem Beispiel Auto nicht verwirren. Nehmen wir das Poker-Spiel:
- Du brauchst ein Kartendeck. Dieses besteht aus Karten. Diese können gemischt werden.
- Du hast evtl. einen Kartenstapel - dieser bietet die Möglichkeit an, Kartendecks aufzunehmen und es können Karten entnommen werden.
- Du hast Spieler. Diese haben irgendwelche Poker-Karten (Hier kenne ich mich nicht aus. Ich habe früher mal was gespielt mit geschlossenen Karten, aber da gibt es irgendwelche Varianten mit offenen und verdeckten Karten ... das wirst Du besser wissen.) Hier würde dann die Logik rein gehören, welche Karten getauscht werden oder so.
- Die Kartenhand hat die Logik bezüglich Auswertung. Was habe ich? Full House? Zwei Pärchen? (Ich habe keine Ahnung, was es so gibt...)
- Evtl. gibt es einen Spieltisch mit gemeinsamen Karten? (Ich habe keine Ahnung, sorry.)
- Und dann hast Du evtl. ein Pokerspiel. Das Spiel hat diverse Spieler, die jeweils Ihre Karten haben. Ggf. ein Spielfeld. Hier findet sich dann auch alle Logik des Spiels. Wer darf wann welche Karten nehmen.

Wichtig ist, dass Du versuchst natürliche Grenzen zu finden. Und dass Du keinen Code an Stellen schreibst, wo dies nicht unbedingt hin gehört. Also nicht zentral im Pokerspiel das Mischen implementieren. Das gehört ja in das Kartenspiel. Das kann dann auch eine Universelle Klasse werden, die Du überall verwendest. Hier kommt dann die Wiederverwendung von Klassen zum tragen.

Ich fange immer ganz normal an - ich nutze dazu dann ein Namespace der meist de.kneitzel.<Projekt> heisst. Wenn ich dann Klassen schreibe, die ich für universell halte, dann schiebe ich die meist in ein eigenes Library Projekt de.kneitzel.lib.*. So würde ich später die Spielkarte (Hier einen möglichst Aussagekräftigen Namen verwenden. Nicht nur Karte, denn das könnte ja auch eine Straßenkarte oder so sein), Kartendeck und Kartenstapel in einen Namespace de.kneitzel.lib.gaming verschieben. Wenn ich dann ein anderes Projekt erstelle z.B. ein Skatspiel, dann habe ich die gleich parat.
Aber das ist etwas, das Du im ersten Schritt außen vor lassen kannst.

Ein weiterer Bereich, den Du Dir evtl. anschauen solltest, sind sogenannte Unit-Tests. Mit welcher IDE arbeitest Du? Evtl. kannst Du das relativ einfach anfangen. Das würde ich zuerst auch nicht zu sehr verkomplizieren. Die Kernidee kann auch erst einmal sein, dass Du eine Klasse Tests schriebst in der du dann eine main Funktion hast, die dann verschiedene Dinge testet. So könntest Du z.B. ein Kartenspiel erzeugen und die Schnittstellen prüfen. Klappt das Mischen? Oder bei einem Kartenstapel: Klappt das Hinzufügen von Kartenspielen, klappt die Entnahme von Karten? All sowas. Die Idee ist halt, dass Du einzelne kleine Komponenten zuerst fertig stellen und dann auch direkt testen kannst. Statt von so main Methoden, die Du aufrufst gibt es dann Methoden, die von einem Tool aufgerufen werden. Das geht zwar relativ weit für einen Anfänger, aber den Punkt möchte ich erwähnt haben. So es Dich wirklich interessiert könnten wir / ich Dich da ein kleines bisschen führen und unterstützen.

Damit hätten wir schon ein sehr breites Feld abgedeckt. Dabei will ich es an dieser Stelle kurz belassen und Dein Feedback abwarten (Und evtl. auch das Feedback von Dritten). Ich würde an der Stelle als Feedback vor allem erwarten, wie Du gerne weiter vorgehen möchtest (und mit welcher IDE. Ich nutze IntelliJ aber jede IDE, die auch einen Debugger und so enthält, ist sehr brauchbar. Wichtig ist, dass Du ein brauchbares Tool verwendest, denn das nimmt Dir erst einmal viel Arbeit ab) und dann würde ich evtl. im Detail weiter vorgehen. Bezüglich möglicher Aufteilung von Klassen kannst Du natürlich auch noch deutlich detailierter werden, wie Du Dir das vorstellst incl. Informationen, was da jeweils enthalten sein soll und was für Schnittstellen Du da erst einmal sehen würdest.

Hoffe das war nicht zu viel und hoffentlich bringe ich nicht viel zu viel auf einmal. Am Anfang ist die Thematik Softwareentwicklung leider extrem umfangreich.

Konrad
 

fk1

Mitglied
Mega Beitrag, daher mega dankeschön :)

Erschlagen fühle ich mich bisher noch nicht wirklich. Ich habe bisher noch überlegt, wo ich die main Methode unterbringe, also in welcher Klasse, aber scheint wohl am besten wirklich erstmal am besten zu sein eine Start bzw. Test Klasse zu erzeugen.

Also ich denke, damit ich konformer mit der Java Welt werde, erstelle ich nochmal ein UML konformes Klassendiagramm oder Objektdiagramm, damit man weiss, was ich so vorhabe. Fällt mir noch ein wenig schwer, sieht man ja an dem Post von mir über dir, mit der Klasse für den Dealer.

Ich denke, ich realisiere das mit Klasse: Dealer, Objekt: holdemdealer (variantenbasiert). Dann ist ein holdemdealer eine Instanz der Klasse Dealer und die OO Idee erfüllt.
 

Jardcore

Top Contributor
Man kann auch ganz witzige Sachen mit dem Strategy Pattern machen und dem Dealer eine Strategie verpassen. Also falls du vorhast das der Dealer mehrere Spiele anbieten kann.

Java:
public class Dealer() {
    private Strategy strategy;

    public Dealer(Strategy strategy) {
        this.strategy = strategy;
    }

    public void deal() {
        strategy.update();
    }
}

Java:
public class Holdem extends Strategy() {
    public void update() {
        // logik hier
    }
}

Java:
public abstract class Strategy() {
    public void update();
}
 

fk1

Mitglied
Danke @Jardcore für den Tip. Allerdings werde ich erstmal genug mit der einen Variante zu tun haben, also wird das mit Strategy noch ein wenig dauern. Ich versuche daran zu denken, wenn sich die Frage wieder stellt.

Ich saß gestern Abend immer abwechselnd vor meinen paar Zeilen und einem Diagramm, bis ich dann mal eine Idee hatte. Es hapert aber noch an der Umsetzung. Irgendwie habe ich noch nicht richtig die Übergabe von einem Objekt einer Klasse in eine andere Klasse verstanden. Ich möchte aber erst noch mal selbst recherchieren, bevor ich euch eine konkrete Frage stelle.

Im Anhang könnt ihr mal das Objektdiagramm betrachten. Da ich hier auch nur Internetrecherche betrieben habe und dies mein erstes ist, könnt ihr auch gerne Verbesserungsvorschläge hierzu posten. Ich hoffe daraus wird wenigstens verständlich, wie ich das bisher Geschriebe umgestalten möchte.

Ich habe probiert, meinen vorhandenen Code OO zu gestalten. Hier mal der Code vom Deck:

Code:
import java.util.ArrayList;
import java.util.Random;

public class Deck{
 
    // Definition des Kartendecks mittels Arrays
    String[] rank = {"A", "2", "3", "4", "5", "6", "7", "8", "9", "T", "J", "Q", "K"};
    String[] suit = {"c", "s", "d", "h"};
     
    // ArrayList für ausgeteilte Karten
    ArrayList<String> dealtCards = new ArrayList<String>();
             
    // Generierung einer zufälligen Zahl für Array Indizes (Shuffle)
    Random rnd = new Random();
    int rndrank = rnd.nextInt(13);
    int rndsuit = rnd.nextInt(4);
     
    // Kombination von Rank und Suit zu einer Karte
    String card = rank[rndrank] + suit[rndsuit];{
 
        //Neu shuffeln, falls Karte bereits verteilt
        while(dealtCards.contains(card)){
            rndrank = rnd.nextInt(13);
            rndsuit = rnd.nextInt(4);
            card = rank[rndrank] + suit[rndsuit];
        }
    }
 
    public String getCard(){
        dealtCards.add(card);
        return card;
    }
}

Ich habe hier das Problem mit der benutzten Variable i der for-Schleife in der for-Schleife selbst behoben. Auch die ArrayList dealtCards habe ich jetzt in der Klasse Deck selbst, also nicht mehr im eigentlichen Deal-Prozess plötzlich Script-like drin.

Ich muss heute mal das Tutorial zu Ende machen und mich dann nochmal mehr mit den setten & getten beschäftigen, irgendwie hat es gestern Abend und heute noch nicht geklappt. Liegt wohl daran, dass ich mehr probiere, als studiere :p

Allerdings beschäftigt mich schon wieder eine Frage, noch bevor ich alles fertig gecodet habe:

Wenn ich später mal 2 Karten generiere, die verteilt werden und dem ArrayList dealtCards hinzugefügt werden, bleiben die dann in dealtCards überhaupt bestehen?

Ich frage, weil die Klasse Deck nicht static ist, daher meines bescheidenen Wissens, nachdem sie nicht mehr benötigt wird, aus dem Speicher gelöscht wird. Wie verhält sich das? Muss ich hier umdenken oder kann ich das wie geplant umsetzen? die Klasse lässt sich laut Eclipse auch nicht static setzen.

E:
dealtCards.add(card); hinzugefügt
 

Anhänge

  • IMG_0163.PNG
    IMG_0163.PNG
    140,6 KB · Aufrufe: 47
Zuletzt bearbeitet:

Jardcore

Top Contributor
Solange eine Referenz auf ein Objekt besteht wird es auch nicht aus dem Speicher entfernt.
Statische Objekte bestehen allerdings auch ohne eine Referenz.
Für den Anfang brauchst du dir da keinen Kopf machen, statische Klassen, Attribute und Methoden kann man erstmal ignorieren.

Zu deinem Diagramm: Glaube ein klassisches UML würde dir mehr helfen. Du kannst dir auch (falls du Eclipse benutzt) die Extention ObjectAid runterladen, mit dem Tool kannst du dir ein UML deines Codes anzeigen lassen. Damit kann man bisschen üben wie man was Modellieren kann.

Hab leider gerade keine Zeit dein Problem in UML dazustellen.

Edit:
Java:
    // Kombination von Rank und Suit zu einer Karte
    String card = rank[rndrank] + suit[rndsuit];{

        //Neu shuffeln, falls Karte bereits verteilt
        while(dealtCards.contains(card)){
            rndrank = rnd.nextInt(13);
            rndsuit = rnd.nextInt(4);
            card = rank[rndrank] + suit[rndsuit];
        }
    }
Hier fehlt irgendwie die Methode oder? :)
Und ein Getter sollte nur etwas zurück geben, aber nicht noch irgendwas machen was man anhand des Names nicht erwartet.
 
Zuletzt bearbeitet:

Jardcore

Top Contributor
Ich habe mir gerade mal auch einen Code gebastelt.
3 Klassen (Card, Deck, MainApp)
2 Enums (Rank, Suit)

Meine Ausgabe:
Code:
Card(   NINE,    CLUB)
Card(   FIVE,   HEART)
Card(  THREE, DIAMOND)
Card(  SEVEN,   SPADE)
Card(  SEVEN, DIAMOND)
Card(    TWO,    CLUB)
Card(    TEN,   SPADE)
Card(  QUEEN,   SPADE)
Card(  QUEEN, DIAMOND)
Card(     AS,   SPADE)
Card(   FOUR,    CLUB)
Card(     AS, DIAMOND)
Card(   FOUR, DIAMOND)
Card(  JOKER,   SPADE)
Card(  SEVEN,   HEART)
Card(    SIX,   SPADE)
Card(    TEN,    CLUB)
Card(  THREE,   HEART)
Card(  QUEEN,   HEART)
Card(  EIGTH,   SPADE)
Card(  EIGTH,    CLUB)
Card(   KING, DIAMOND)
Card(   NINE,   SPADE)
Card(   FOUR,   HEART)
Card(  QUEEN,    CLUB)
Card(   FIVE,    CLUB)
Card(   KING,   SPADE)
Card(    TWO,   HEART)
Card(    TEN,   HEART)
Card(    TEN, DIAMOND)
Card(  JOKER,   HEART)
Card(    SIX, DIAMOND)
Card(   NINE, DIAMOND)
Card(  THREE,   SPADE)
Card(   KING,    CLUB)
Card(   KING,   HEART)
Card(  JOKER, DIAMOND)
Card(     AS,    CLUB)
Card(     AS,   HEART)
Card(    SIX,   HEART)
Card(  EIGTH, DIAMOND)
Card(   FIVE, DIAMOND)
Card(    TWO, DIAMOND)
Card(  JOKER,    CLUB)
Card(    SIX,    CLUB)
Card(    TWO,   SPADE)
Card(  SEVEN,    CLUB)
Card(  THREE,    CLUB)
Card(   FOUR,   SPADE)
Card(   NINE,   HEART)
Card(   FIVE,   SPADE)
Card(  EIGTH,   HEART)

P.S: Du kannst mit Collections.shuffle(List<>...) eine Liste zufällig mischen.
 

fk1

Mitglied
@Jardcore: Scheint ja mit enums und Collection.shuffle effektiv zu sein wenn du das mal eben programmierst, ich sitze ja jetzt schon ein paar Tage daran, die Idee umzusetzen. ^^

Ich hatte auch erst überlegt eine card als extra Klasse zu erstellen, das Deck dann mit fester Reihenfolge von 52 card Objekten zu gestalten, die der Dealer dann bei Bedarf mischt (Wie in der Realität).

Ich wollte es dann aber erstmal simpel halten und meinen bisherigen Code OO gestalten.

Da fehlt bestimmt eine Methode wenn du es sagst, ich muss auch zugeben, dass ich dachte, ich hätte das Grundkonzept verstanden. Doch dann fiel mir auf, dass ich gar nicht richtig die Methoden zuornden kann:

Wenn ein Objekt eine Instanz einer Klasse ist, was ist dann eine Methode? Wie kann ich das zuordnen? Ist eine Methode eine Fähigkeit einer Klasse oder Objekt? Oder ist eine Methode die Instanz der Klasse?

Und zu meinem Code: Ich definiere da ja den String card, allerdings ist das dann noch kein Objekt, oder? Ich schätze, die Methode getCard ist nicht die Methode, die du vermisst.
 

Jardcore

Top Contributor
Ich habe dir ja mit Absicht nicht meinen Code gezeigt, nur einen Ausblick was du erreichen kannst :)

Also Objekte sind im Prinzip deine Klassen (public class Deck {...})
Wenn du nun davon eine Instanz erzeugst (new Deck()), hast du eine Instanz diese Objekts erzeugt.
Wenn du diese Instanz speichern willst (Deck meinDeck = new Deck) dann hast du eine Referenz auf deine Instanz mit dem Namen meinDeck.

Ein Objekt kann Methoden und Attribute haben. Diese können auch noch verschiedene Sichtbarkeitbereiche haben (public, private, protected, "packagePrivate") Attribute bestimmen dabei den Zustand eines Objektes.
Methoden kann man wirklich als Fähigkeiten bezeichnen. Die Fähigkeiten können auch aus anderen Instanzen aufgerufen werden, solange die Methode public ist und die andere Instanz wiederrum eine Referenz auf meine Instanz hat (klingt verwirrend) Private Methoden können nur innerhalb des Objektes aufgerufen werden.

Für die Sichtbarkeiten hier mal ein Link: http://openbook.rheinwerk-verlag.de...05_002.htm#mjf5b3fff9748ae6323d1923016a906a8f
Würde sonst meinen Zeitlichenrahmen sprengen^^

getCard() war nicht die Methode :p

EDIT:
Ein Enum ist übrigens so ähnlich wie eine Klasse, hilft wenn man Aufzählungstypen hat, oder etwas gruppieren möchte.

Java:
public enum Jahreszeiten {
FRUELING,
SOMMER,
HERBST,
WINTER;
}
 
Zuletzt bearbeitet:

fk1

Mitglied
Danke für deine Antwort Jardcore. Der Verweis auf "Java ist auch eine Insel" sagt mir, dass ich mehr studieren sollte, bevor ich weiter mache. Ich lese mich mal ein paar Tage weiter ein. Ich glaube ich hab einfach noch zu wenig Basics verstanden. Allerdings musste ich wohl auch erst mal mit den ersten Zeilen beginnen um das zu verstehen :)

Sobald ich neue Erkenntnisse und Ideen in Code umgesetzt habe schreibe werde ich dann hier berichten!
 

fk1

Mitglied
Lese mich gerade schlau und kann mir die Erkenntnisteilung nicht verkneifen :D

Das ganze Haareraufen gestern basiert darauf, weil ich nicht wusste, das es 2 Arten von Methoden gibt. Natürlich bin ich gestern daran verzweifelt, wieso ich eine Klassenmethode nicht als Instanz/Objektmethode in Dealer.class aufrufen kann ^^

@Jardcore: Jetzt verstehe ich auch, wieso du nach einer Methode fragst. Da ist noch ein } übrig geblieben, als ich den Code umstrukturiert hatte.

Das bringt mich aber auf die Idee, das shuffeln als methode zu verpacken um es bei gleicher card wieder nutzen zu können:cool:
 

Jardcore

Top Contributor
Die frage ist, wie es zu gleichen Karten kommen kann. Ich bin so vorgegangen.
Ein Deck hat 52 Karten, die Anzahl entsteht durch die Kombination aus Suit und Rank. Wenn nun der Dealer eine Karte vom Stapel nimmt sind es nurnoch 51 Karten und nur der Rest kann ausgespielt werden.
Erstmal ist egal was mit den Karten geschieht. Ob es einen Ablagestapel gibt oder nicht ist bei Holdem unwichtig.
Wenn das Spiel zuende ist wird einfach ein neues Deck erzeugt und man hat wieder 52 gemischte Karten
 

fk1

Mitglied
Ich gucke mir gerade die letzten Videos des Tutorials an und bin bei Polymorphie: http://panjutorials.de/java-anfanger-tutorial-35-polymorphie/?replytocom=110#respond

Ich habe nur eine Frage zu der for-Schleife des Beispiels:

Java:
for(int i=0; i&lt;einAuto.length; i++){
einAuto[i].reparieren();

Ist das nicht wieder der schlechte Stil, den ich vermeiden soll? Wundere mich, dass der Tutor das so macht, eigentlich hat das Tutorial viele gute Rezensionen (komme ich über google-> giga drauf) und frage mich jetzt ob der schlechten Coding Stil betreibt oder ich da was falsch verstanden habe.
 

Jardcore

Top Contributor
Man kann i schon ab und an mal als Zählvariable benutzen.
Leider muss man sagen das auch viele Fachbücher schlechten Code enthalten, darauf stößt man immer wieder.
Wenn man Code anschaut und nicht flüssig begreifen kann was dort geschieht ist es meistens ein Indiz dafür.
Dabei muss man nicht jede Zeile sofort verstehen.
Aber wenn man z.B:
Code:
private void run () {
    for (int i = 0; i < 10; i++) {
        if (al.size > 0) {
            al[i].setX (al [i].getX () + 1);
        }
    }
}
...oder:
Code:
private void moveAllAgentsToRight () {
    if (agentsNotExists() {
        return;
    }
    for (int i = 0; i < numberOfAgents; i++) {
        moveRight (agents [i]);
    }
}
...liest, kann man dem zweiten Beispiel hoffentlich besser folgen. Was nun moveRight macht ist erstmal unwichtig. Jedoch nimmt man an, dass es wohl einen Agenten nach rechts schiebt.

Im Grunde gehts darum verständlichen Code zu schreiben.
 

Jardcore

Top Contributor
Man hätte bei deinem Auto Beispiel auch eine foreach Schleife nehmen können. Denn der zähler war ja nicht nötig. Gleiches gilt für mein Beispiel.
Java:
for (Auto auto : autos) {
    auto.reparieren();
}
Java:
for (Agent agent : agents) {
    moveRight (agent);
    //oder: agent.moveRight ();
}
 

fk1

Mitglied
Ich bin mit der Anfängertutorialreihe durch und beschäftige mich inzwischen wieder mit meinem ersten Code.

Gestern Abend saß ich dann mal völlig verwirrt und planlos vor dem Rechner. Heute will ich daher das Problem wieder ganz einfach angehen, also brechen wir das alles mal ganz simpel herunter:

Ich erstelle als erstes eine Klasse Card. Eine Karte besteht aus Suit und Rank, also füge ich der Klasse diese als Array hinzu. Enums lasse ich nochmal außen vor. Ich schätze, enums eignen sich viel besser für mein Vorhaben wenn @Jardcore mir das vorschlägt. Ich bleibe aber doch erstmal zwecks Lerneffekt bei Arrays.

In der Klasse Cards gibt es den Constructor Cards, der zwei int Parameter rankIndex & suitIndex benötigt, damit er eine Card zusammen setzen kann. Welche Karte man dann genau als Instanz erzeugen möchte, kann man mit den zu übergebenen Parametern dann immer selbst bestimmen.


Java:
public class Card {

    // Arrays für die Eigenschaften einer Karte
    String[] rank = {"A", "2", "3", "4", "5", "6", "7", "8", "9", "T", "J", "Q", "K"};
    String[] suit = {"c", "s", "d", "h"};
    String card;

    // Konstruktor für Karte
    public Card(int rankIndex, int suitIndex){
    card = rank[rankIndex] + suit[suitIndex];

    }
}

Ich glaube, die Lösung zur Erstellung einer Karte ist jetzt OOer als vorher.

Jetzt widme ich mich der Klasse Deck. Diese Klasse ist nach meiner Überlegung nur ein Array bestehend aus 52 Card Objekten. Ein frisch gekauftes Deck ist sogar sortiert. Meiner Meinung nach kommt daher das Karten Mischen weder in die Klasse Cards noch Deck. Ich denke man verpackt das am besten als Dealer-method, aber eins nach dem anderen.

Ich möchte zunächst einfach nur ein Array aus 52 Cards generieren:

Java:
public class Deck{

    Card newDeck[] = new Card[52];

}

Das habe ich dann mal testweise ausgeben lassen. Da ich ja gar keine Parameter übergebe, bekomme ich null ausgegeben. Wie kann ich bei der Erstellung des arrays Parameter übergeben? Geht das überhaupt?

Der Plan ist, ein 52er Kartendeck sortiert zu erzeugen. Die Hoffnung besteht darin, das sortierte Deck-Array mischen zu können und dann Karte für Karte auszuteilen. In Java: eine methode nextCard zu erzeugen, den Index des gemischten Arrays als Karte austeilen, dann den index um Eins erhöhen.

So würde ich mir die Liste ausgeteilter Karten sparen können.
 

n00b4u

Mitglied
Mhm... du hast zwar Arrays mit den Werten, aber die Arrays machen erstmal nichts. und Mit new Card[52] erzeugst du ein Array mit 52 leeren Feldern.

Am einfachsten wäre es wahrscheinlich wenn du eine Schleife durchiterierst die dir dann die Karten erzeugt.

Und natürlich sollte Card dann ein zweidimensionales Array sein, also Card [][].

Und spätestens hier, sind dann Enums die bessere Wahl. Oder willst du die Karten im Spiel über den Index ansprechen?
 
Zuletzt bearbeitet:

n00b4u

Mitglied
Wenn du dann mit randomize arbeiten willst, und ein Array verwenden, dann würde ich für den Anfang vielleicht sogar empfehlen, alle Karten fest in einem Array zu erzeugen, so schnell werden sich die Karten ja nicht ändern und dann diesen eindimensionalen Array mit einem Random über den Index austeilen.
 

Jardcore

Top Contributor
Meine Idee mit den Enums ist nicht non plus ultra, man kann das nach belieben machen :)

Deine Card Klasse hat aber leider noch paar Macken.
Die Klasse soll ja eine Art Blaupause sein. Also wenn man mal so rangeht: Eine Karte hat immer nur EINE Farbe und Form, mehr nicht.
Deine Karte hat jedoch alle Farben und alle Formen und dann noch ein String der die eigentliche Karte repräsentieren soll.

Du könntest einen Dealer erstellen, welcher die beiden Arrays aus deiner Card Klasse enthält. Der Dealer erzeugt dir deine 52 Karten und diese kannst du dann einem Deck übergeben.
Die Card Klasse erhält dann zwei Strings, einen für Farbe, eine für Form.

Deine Deck Klasse benötigt eigentlich nicht mehr viel. Eine toString Methode einen Konstruktor der ein Liste von Karten akzeptiert und eine Methode die dir die oberste Karte ausgibt. (Vielleicht könnte auch der Dealer das Deck haben und du fragst den Dealer nach einer Karte)

Am besten du schaust dir mal Listen an (ArrayList<>) das würde die Sache an einigen Stellen vereinfachen.

@n00b4u
wäre aber nicht sehr objektorientiert...
 

n00b4u

Mitglied
@Jardcode

Das kommt doch drauf an. Wenn ich den Kartensatz in einer Klasse Spiel erzeuge und nicht als eigene Klasse verwende, wo ist da das Problem? Mann muss ja nicht für jedes Tischbein des Pokertischs ne eigene Klasse schreiben.

Natürlich gibt es elegantere Wege, da hast du Recht. Und ich muss gestehen, als ich mit dem programmieren anfing, waren Arrays mein Hass-Thema Nummer 1. Ich finde für Einsteiger ist das schon recht knackig, da kann man einen einfachen Entwurf zum Verständnis schonmal gutheissen oder? ;-)
 

Jardcore

Top Contributor
Der Name einer Klasse sollte die Verantwortlichkeit beschreiben (Single-Responsibility-Prinzip).
Man sollte mit 25 Wörter beschreiben können was eine Klasse tut.

Eine Methode sollte maximal 20 Zeilen haben.
If und Else Blöcke sollten nur eine Zeile lang sein.
Und Methoden sollten nur eine Aufgabe erfüllen.

Wenn man das beherzigt dann hat man das Zeug dazu guten Code zu schreiben.

Also wenn es Sinn ergibt, dass die Beine des Pokertisches Klassen brauchen, dann werden diese auch erstellt.
Aber wir schweifen ab, hier geht es nicht darum ein Pokerspiel zu programmieren, sondern ein Pokerdealer Programm.
 
Zuletzt bearbeitet:

Jardcore

Top Contributor
Hier noch eine kleine Deckstütze zum erzeugen der 52 Karten in einem Array:
Java:
Card[] cards = new Card[52];
int index = 0;
for(String rank : ranks) {
     for(String suit : suits) {
         cards[index] = new Card(rank, suit);
         index++;
     }
}
 

fk1

Mitglied
Ich bin schon wieder verwirrt. @Jardcore die ranks und suits sind doch Eigenschaften einer Karte. Warum soll ich die dann beim Dealer speichern und den Dealer Karten generieren lassen? Der reale Dealer produziert doch auch keine Karten?! Er mischt und verteilt nur.

Okay, das klingt wahrscheinlich ein wenig überspitzt und klugscheisserisch, aber evtl bringt mich das weiter. Wenn also ranks und suits Eigenschaften einer Karte sind, die Definition aller möglichen Eigenschaften aber nicht in der Klasse selbst definiert werden sollen, dann bleiben ja eigentlich nur seperate enum Listen!?

Nichts für ungut aber ich finde, beim Dealer haben ranks und suits nichts verloren, ich meine das Speichern verteilter Karten hatte da immerhin auch nichts zu suchen :p Aber so sehe ich dann wenigstens einen Grund für enums ^^
 
Zuletzt bearbeitet:

fk1

Mitglied
Gerade mal probiert enums zu erstellen:

Java:
public enum Ranks {
    A,
    2,
    3,
    4,
    5,
    6,
    7,
    8,
    9,
    T,
    J,
    Q,
    K;
}

funzt nicht, eclipse meckert bezüglich syntax errors. Enum suits klappt wunderbar. Liegt es daran, dass ich Buchstaben und Zahlen mixe?

Falls ja, sind enums für mein Vorhaben weniger zu gebrauchen. Ich möchte schon die Ausgabe in Form von "AhAc" haben. In Poker Diskussionsforen gibt es da einen gewissen Standard bei der Darstellung, den ich einhalten möchte.

Neue Möglichkeiten, neue Probleme.


E: Ah ich glaub ich habs, sec...
E2: ne, doch nicht. Dachte mit ACE("A"), ... funktioniert es, aber hilft auch nicht. Das ist das Dilemma eines Anfängers, der gar nicht wirklich weiss, was er da überhaupt macht...
 
Zuletzt bearbeitet:

Jardcore

Top Contributor
Liegt es daran, dass ich Buchstaben und Zahlen mixe?
Jaein, man kann in Java keine "Variablen" mit einer Zahl beginnen.

Für dein Vorhaben müsstest du dein Enum etwas erweitern... aber wie ich sagte ist ein Enum nicht das non plus Ultra, deine Anforderungen lassen sich auch mit einem String Array umsetzten.

Wenn du doch ein Enum nehmen möchtest würde es so aussehen:
Code:
public enum Rank {
    ACE("A"),
    TWO("2"),
    THREE("3"),
    FOUR("4"),
    FIVE("5"),
    SIX("6"),
    SEVEN("7"),
    EIGHT("8"),
    NINE("9"),
    TEN("T"),
    JOKER("J"),
    QUEEN("Q"),
    KING("K");

    private String text;
 
    private Rank(String text) {
        this.text = text;
    }
 
    public String getText() {
        return text;
    }
}

Das ist ein erweitertes Enum, du kannst z.B mit Rank.ACE.getText() das "A" bekommen... usw.
Die Card Klasse würde dann wie folgt aussehen:
Code:
public class Card {
    private Suit suit;
    private Rank rank;
 
    public Card(Rank rank, Suit suit) {
        this.rank = rank;
        this.suit = suit;
    }
 
    public Rank getRank() {
        return rank;
    }
 
    public Suit getSuit() {
        return suit;
    }
 
    @Override
    public String toString() {
        return String.format("%s %s", suit, rank.getText());
    }
}
Beachte hier das rank.getText() in der toString Methode

Einfachhalber habe das Suit Enum gerade vereinfacht erstellt und nicht in dem Schema wie Rank.
Code:
public enum Suit {
    c,
    s,
    d,
    h;
}

Edit:
Rank hat übrigens einen privaten Konstruktor... das Enum verknüpft vereinfacht gesagt automatisch deine Variable mit dem EnumWert (der EnumWert ist dabei ACE, TWO... und die Variable, dass was in der Klammer dahinter steht. Dort kann man auch Integer oder sogar Objekte reinpacken.
 

fk1

Mitglied
Erstmal Danke für deine Vorlagen. Lass uns doch nochmal über Suits und Ranks im Allgemeinen sprechen: Eigentlich haben diese Attribute ja nichts mit einem Dealer zu tun. Gibt es vielleicht andere Klassen, die du erstellen würdest, wenn du an ein komplettes Spiel denkst?

Ich möchte jetzt ungerne deine Lösungen copy/pasten. Ich lerne da jetzt für die Zukunft von aber wenn ich jetzt alles vorgekaut bekomme, komme ich ja nicht weiter.

Da ich bis jetzt keine Idee habe, wo ich alle möglichen Suits/Ranks hinpacke: Wie ist folgende Idee?

Java:
public class Ranks {
    private String[] rank = {"A", "2", "3", "4", "5", "6", "7", "8", "9", "T", "J", "Q", "K"};
  
    public String getRank(int rankIndex){
        return rank[rankIndex];
    }
}

Kann man das so machen oder ist das "schlechter Code/Stil"? Wir machen quasi aus Ranks und Suits auch noch seperate Klassen bzw. erzeugen Objekte, aus denen wir die Karten generieren.
 

Jardcore

Top Contributor
Das kann man so machen... mit einem Zusatz... der dich jetzt nicht freuen wird :) (weil du das vielleicht in deinen Übungen noch nicht hattest, wenn doch... HURA :) )

Du müsstest der Klasse Ranks den Modifier abstract geben, also:
Java:
public abstract class Ranks {
}
Dein Array rank und die Methode getRank(int ...) musst du dann den static Modifier verpassen.

Und warum das ganze?
Weil du sonst immer eine Instanz der Ranks Klasse erstellen müsstest. Ranks ranks = new Ranks und dann ranks.getRank(...) das ist ziemlich umstäntlich.
Mit der Umstellung würdest du nur Ranks.getRank(...) aufrufen.

Und nein das ist kein schlechter Stil, das kann man so machen, eigentlich ist alles erlaubt, erst wenn es drauf ankommt auf Erweiterbarkeit, Einfachheit und Performance müsste man nochmal gucken.

Gibt es vielleicht andere Klassen, die du erstellen würdest, wenn du an ein komplettes Spiel denkst?
Ich würde wie schon erwähnt mich hinsetzten überlegen wie so ein Spiel abläuft und mir auf Papier aufschreiben was für Klassen ich so bräuchte. Also was gehört alles zum Spiel: Wahrscheinlich die Spieler, Tisch, Dealer, WieAuchImmerGeradeDieChipsHeißen, Pot, ... (ich bin gerade in Gedanken an einem Pokertisch... kenne mich aber nicht so wahnsinnig mit Poker aus ^^) Vielleicht noch paar Tischbeine :p
 

fk1

Mitglied
Ich meinte andere Klassen, in die du dann die Definition aller Suits und Ranks packen würdest. Aber wenn das so i.O. ist, dann orientiere ich mich jetzt mal an diesen Start und arbeite damit mal weiter.

abstract hatte ich kurz angeschnitten aber schon wieder vergessen. Von daher ist das ja gut, denn so muss ich nochmal nachlesen. :p Ich sage mal danke und probiere daraus dann demnächst ein Deck zu formen und in einer Test.class auszugeben.

Jetzt muss ich mich fertig machen, heute Abend steht der neue Star Wars Streifen auf dem Programm. Möge die Macht mit euch sein :D
 

fk1

Mitglied
Guten Abend,

Star Wars war ok... irgendwie alles schon mal gesehen. Eventuell muss ich ihn ein zweites Mal sehen.

Heute Drei Zeilen Code geschrieben. Dann 3 Stunden Fehler Recherche betrieben :p

Erst mal der Code:

Java:
public abstract class Suits {
    private String[] suits = {"c", "h", "s", "d"};

    public String getSuit(int suitIndex){
        return suits[suitIndex];
    }
}

Java:
public abstract class Ranks {
    private String[] ranks = {"A", "2", "3", "4", "5", "6", "7", "8", "9", "T", "J", "Q", "K"};

    public String getRank(int rankIndex){
        return ranks[rankIndex];
    }
}

Möchte nun in der Card.class lediglich alles zusammen setzen:

Java:
public class Card {

    String card;
     
    public Card(int rankIndex, int suitIndex){
        card = Ranks.getRank(rankIndex) + Suits.getSuit(suitIndex);
    }
}

Wird quittiert mit

Cannot make a static reference to the non-static method getSuit/getRank from the type getSuit/getRank

Google befragt. Scheint allgemein Anfänger zu überfordern. Jetzt mein Versuch das zu verstehen:

Ich kann in der Card.class die methode nicht als solche vollenden, da sie sich auf eine nicht-statische Methode bezieht. Also instanziere ich zuvor ein Objekt, damit ich etwas statisches kreirt habe, auf das ich mich beziehen kann.

Aber hey, die Suits/Ranks sind ja abstract und somit nicht instanzierbar, wenn ich das richtig verstanden habe (nachgelesen in Java ist auch eine Insel).

Jetzt sitze ich wieder hier, probiere herum. Aber alles durch die Reihe static setzen bringts irgendwie auch nicht. Es kommen nur Folgefehler, außerdem habe ich einen Artikel zum Thema gefunden in dem es auch heisst, dass alles static setzen auch nichts mehr mit OOP zu tun. Wie gesagt, das erschien mir eh nicht als das Gelbe vom Ei.

Leider finde ich immer nur die Lösung, ein neues Objekt a la Suits suit = new Suits; zu erstellen. Blöd ist es dann, wenn das bei abstract ja nicht funktioniert?!

Fühlt sich an wie 2 Wochen recherchiert aber nix wirklich verstanden. :(
 

fk1

Mitglied
Ich habe noch eine Stunde gegoogled und probiert. Zwei Erkenntnisse:

Ohne abstrakte Klassen Suits & Ranks scheint folgende Card.class realisierbar:

Java:
public class Card {

    String card;
    int suitIndex;
    int rankIndex;

    public Card(int rankIndex, int suitIndex){
        Ranks cardRank = new Ranks();
        Suits cardSuit = new Suits();
        card = cardRank.getRank(rankIndex) + cardSuit.getSuit(suitIndex);
 
    }
}

Zumindest meckert Eclipse jetzt nicht mehr.

Ansonsten habe ich noch in einem englischen Forum gelesen das ich die abstrakten Methoden einer Klasse nutzen kann, wenn ich die Klasse Cards extende. Dann wäre noch die Frage: Kann ich die Klasse um zwei Klassen extenden?

Ich habs :cool:

Java:
public class Suits {
    private String[] suits = {"c", "h", "s", "d"};

    public String getSuit(int suitIndex){
        return suits[suitIndex];
    }
}
Java:
public class Ranks extends Suits {
    private String[] ranks = {"A", "2", "3", "4", "5", "6", "7", "8", "9", "T", "J", "Q", "K"};
 
    public String getRank(int rankIndex){
        return ranks[rankIndex];
    }
}
Java:
public class Card extends Ranks{
 
    String card;
    int suitIndex;
    int rankIndex;
 
    public Card(int rankIndex, int suitIndex){
        Ranks cardRank = new Ranks();
        Suits cardSuit = new Suits();
        card = cardRank.getRank(rankIndex) + cardSuit.getSuit(suitIndex);
     
    }
}

Klasse Ranks extends Suits und Card extends Ranks und dann meckert Eclipse auch nicht mehr. Jetzt ist für mich das letzte Rätsel, dass @Jardcore meinte, die neuen Objekte/Instanzen muss ich bei Nutzung von abstract nicht erstellen. Lasse ich die im Konstrukto weg, bekomme ich leider immer noch den Fehler bezüglich static/non-static.

Ich probiere morgen ein Deck zu erzeugen.
 
Zuletzt bearbeitet:

fk1

Mitglied
Ich stelle gerade fest, dass die classes doch nicht abstract gesetzt sind und die Vererbung anscheinend nichts gebracht hat, da die Instanzierung dann nicht mehr funzt, sobald man Suits&Ranks abstract setzt.

image.jpg
 

Jardcore

Top Contributor
Du musst nochmal gucken was du da jetzt eigentlich gemacht hast...
Deine Card Klasse ist jetzt ein spezielleres Konzept von Ranks... das ist aber nicht so.
Genauso ist Ranks kein spezielleres Konzept von Suits.

Spezielleres Konzept heißt soviel wie ein VW ist ein spezielleres Konzept von Auto. Eine Katze ist ein spezielleres Konzept eines Säugetieres, was wiederum ein spezielleres Konzept eines Tieres ist.

In deinem Fall würde man ja nicht sagen das eine Karte ein spezielleres Konzept einer Farbe ist... usw.

Wieso möchtest du denn eigentlich über den Index auf die Ranks und Suits zugreifen. Eigentlich willst du doch nur 52 Karten erstellen also alle Kombinationen aus Ranks und Suits. Der Index müsste eigentlich egal sein. Die Kombinationen sollen dann in einem Deck landen und man soll dann wahrscheinlich immer eine Karte aus dem Deck ziehen können.

Java:
public abstract class DeckBuilder {
     private static final String[] RANKS = {"A", "2", "3", "4", "5", "6", "7", "8", "9", "T", "J", "Q", "K"};
     private static final String[] SUITS = {"c", "h", "s", "d"};

     /**
      * Erstellt ein Deck und fügt 52 geordnete Karten hinzu.
      * Dabei werden die Kombinationen aus RANKS und SUITS gebildet.
      * @return Deck mit 52 geordneten Karten.
      */
     public static Deck createDeck() {
         // neues Deck erzeugen
         Deck deck = new Deck();
         // Alle Suits einmal durchgehen
         for(String suit : SUITS) {
             // Alle Ranks einmal durchgehen
             for(String ranks : RANKS) {
                 // Neue Karte erzeugen und Suit und Rank übergeben, anschließend zum Deck hinzuzufügen
                 deck.add(new Card(suit, rank));
             }
         }
         // das neue Deck mit allen Karten zurückgeben.
         return deck;
     }
}
Ich hab hier mal einfach einen "DeckBuilder" erstellt, der macht nichts weiter als ein Deck zusammen zu stellen. Dafür muss deine Deck Klasse eine add Methode haben die eine Karte zu der Liste der vorhandenen Karten hinzufügt.
Diesmal voll kommentiert, glaube das hilft dir mehr.

Die Extra Klassen für Rank bzw Ranks würde nur Sinn ergeben wenn du deiner Card Klasse beibringen würdest damit auch ordentlich umzugehen. Also als Attribute ala private Suit suit, private Rank rank.

P.S: Die Klasse ist eine abstrakte Klasse und du kannst createDeck wie folgt benutzten.
Deck deck = DeckBuilder.createDeck();
 

fk1

Mitglied
Extenden wollte ich, weil die von dir beschriebene Variante, eine abstrakte Methode aufzurufen, bei mir nicht funktioniert hat. Ich lösche den ganzen extends Unsinn und setze die Suits/Ranks wieder abstract. Jetzt sieht meine Card.class so aus:

Java:
public class Card {

    String card;
    int suitIndex;
    int rankIndex;

    public Card(int rankIndex, int suitIndex){
        Ranks cardRank = new Ranks.getRank(rankIndex);
        Suits cardSuit = new Suits.getRank(suitIndex);
        card = cardRank + cardSuit;
    }
}

Das geht so nicht. eclipse: "can not instantiate the type Suits/Ranks". Auch außerhalb des Konstruktors geht das nicht. Zumindest bei mir nicht. Daher war ich auf Abhilfe im Netz unterwegs und fand extend, damit es geht. Aber wie du schon sagst, das ist rein logisch Unsinn und funktioniert davon abgesehen auch gar nicht, also vergessen wir das mit extend mal wieder.

Ich will eigentlich einfach zunächst am Ende nur ein SimpleDeck:

Java:
public class SimpleDeck {

    String[] deck = {
            "Ac", "Ah", "As", "Ad",
            "2c", "2h", "2s", "2d",
            "3c", "3h", "3s", "3d",
            "4c", "4h", "4s", "4d",
            "5c", "5h", "5s", "5d",
            "6c", "6h", "6s", "6d",
            "7c", "7h", "7s", "7d",
            "8c", "8h", "8s", "8d",
            "9c", "9h", "9s", "9d",
            "Tc", "Th", "Ts", "Td",
            "Jc", "Jh", "Js", "Jd",
            "Qc", "Qh", "Qs", "Qd",
            "Kc", "Kh", "Ks", "Kd"
    };
}

Am Anfang wollte ich einfach nur eine intelligentere Lösung für das Deck, als es stumpf von Karte 1 bis 52 herunterzuschreiben. Das ist quasi deine Klasse DeckBuilder.

Danke übrigens für die DeckBuilder.class und comments. Du hattest eine ähnliche Lösung ja bereits vorher gepostet. Ich hatte die sogar ohne comments verstanden und wollte die auch nutzen. Aber so weit bin ich ja gar nicht erst gekommen.

Ich habs nochmal weiter mit meiner Variante ohne abstract & extends bei Suits&Ranks probiert:

Java:
public class Card {
    String card;
    int suitIndex;
    int rankIndex;
    public Card(int rankIndex, int suitIndex){
        Ranks cardRank = new Ranks();
        Suits cardSuit = new Suits();
        card = cardRank.getRank(rankIndex) + cardSuit.getSuit(suitIndex);
    }
}

Dann mal eine Karte testweise ausgeben lassen:

Java:
public class Test {

    public static void main(String[] args) {
        Card card0 = new Card(0,0);
        System.out.println(card0);
    }

}

Spuckt die Konsole mir folgendes aus: "Card@4edf9252"

War also bisher ein voller Misserfolg. :D Aber es ging ja auch darum, ein wenig OO zu denken und da hab ich jetzt auf jeden Fall schon ein wenig mehr gelernt. Klar, man kann es mit dem DeckBuilder lösen, man kann es simpel herunterschreiben, oder halt OOer und sogar die Karten als eigene Klasse definieren.

Kann ja mal sein, dass man später MauMau spielen will und dann keine 52 Karten mehr braucht. Oder man spielt ein Spiel, in dem Joker benötigt werden. Der Satz "Denk ich an Java, denk ich an Wiederverwertbarkeit" hängt mir da im Kopf.

Lange Rede, kurzer Sinn: Ich wollte jetzt erst mal vernünftig ein Objekt der Klasse Card erzeugen und nicht mal das haut richtig hin. Irgendwas hab ich da immer noch nicht verstanden.

Ein Card ist ein Objekt der Klasse Cards. Es hat die Attribute rank & suit. Wie soll das idealerweise aussehen?
 

CSHW89

Bekanntes Mitglied
Die Ausgabe mit dem @ und den Zahlen ist die Standardausgabe eines jeden Objekts. Java kann ja nicht wissen, dass du den Inhalt der Variablen 'String card' ausgeben willst. Um es Java begreiflich zu machen, überschreibt man die toString-Methode in der Klasse Card:
Java:
public class Card
    ...
    public String toString() {
        return card;
    }
    ...
}
Allerdings ist es etwas schlechter Stil, die toString-Repräsentation in einem Attribut zu speichern. Man könnte die Erstellung des Strings in die toString-Methode auslagern. Die beiden Attribute 'suitIndex' und 'rankIndex' solltest du aber auch noch befüllen. Dann würde es so aussehen:
Java:
public class Card {
    int suitIndex;
    int rankIndex;
    public Card(int rankIndex, int suitIndex){
        this.rankIndex = rankIndex;
        this.suitIndex = suitIndex;
    }
    
    public String toString() {
        Ranks cardRank = new Ranks();
        Suits cardSuit = new Suits();
        return cardRank.getRank(rankIndex) + cardSuit.getSuit(suitIndex);
    }
}
Nun erstellt man in der toString-Methode immer zwei neue Objekte vom Typ Ranks und Suits. Das kann man so machen, man könnte aber auch wieder die abstract-static-Variante wählen. Man sagt Anfängern oft, alles static machen wäre schlechter Stil. Das stimmt zwar in vielen Fällen, aber definitiv nicht in allen, sonst würde es static ja gar nicht geben. In diesem Fall wäre es durchaus angemessen, die beiden Klassen Ranks und Suit abstract, und die Methoden getXXX bzw die Arrays auf static zu setzen.
Es gäbe noch eine weitere Möglichkeit, Stichwort Singleton. Das kannst du ja mal googlen. Es ist etwas OOPiger, verhindert aber, dass du ständig neue Objekte von Typ Ranks und Suits erstellst. Ist aber wie ich finde, nur eine etwas aufgeblasene abstract-static-Variante.

lg Kevin
 

Jardcore

Top Contributor
Das geht so nicht. eclipse: "can not instantiate the type Suits/Ranks".
Das liegt daran das du das falsch Aufrufst, wenn du mal zurückblätterst siehst du wie man eine Methode in einer abstrakten Klasse aufruft.
Statt:
Ranks cardRank = new Ranks.getRank(rankIndex);
Musst du nämlich nur
?String? cardRank = Ranks.getRank(rankIndex);
aufrufen ohne "new" du willst ja eben KEINE Instanz erzeugen.

Die Methode getRank gibt übrigens (meins Wissens) einen String zurück. Und du hattest vor kurzen Suit und Rank auch noch als String in Card gespeichert. Die Ranks bzw. Suits Klasse sind nur Hilfscontainer die das Wissen aller möglichen Kartentypen enthalten.

Klar ist es später wahrscheinlich einfacher eine Rank und eine Suit Klasse zu haben, nur glaube ich das du noch nicht genau verstanden hast was eine Klasse bzw. ein Objekt ist und was eine Instanz eines Objekts ist. Deswegen sind deine Ranks, Suits und deine Card auch nicht ganz sauber.

Vielleicht nochmal der Versuch. Deine Card.class ist die Repräsentation EINER einzigen Karte. Und eine Karte hat nur EIN Bild und EINEN Wert.
Java:
public class Card {
    String suit;
    String rank;

    public Card(String suit, String rank) {
        this.suit = suit;
        this.rank = rank;
    }

    @Override
    public String toString() {
        return "Card " + suit + " " + rank;
    }
}
Man kann sich das auch gut merken indem man überlegt... Was HAT eine Karte, und das alles sind Attribute der Klasse. Also HAT eine Karte eine card? Ich glaube nicht.

Wie man hier sieht gibt es deshalb auch kein Attribut Namens card (String card...), denn die Instanz von Card selbst ist eben deine Repräsentation einer Karte.

Den ganzen Kram mit dem Index müsstest du, wenn überhaupt, machen bevor du die Karte erzeugst und das Ergebnis dann an den Konstruktor der Card beim Erzeugen übergeben.

P.S: Guck dir mal Listen in Java an (ArrayList ...) das würde dir... immernoch sehr viel Arbeit ersparen :)
 

Luecx

Mitglied
Heyho,

Ich hab grad mal auf die schnelle versucht mich in dein Programm reinzuarbeiten und muss dir sagen, dass das so funktioniert, aber ÜBERHAUPT nicht schön ist... Du arbeitest schließlich Objektorientiert und es wäre am einfachsten alles als ein Objekt anzusehen. Mach eine Klasse Karte, eine Klasse Deck und dann die Klasse Dealer, dann brauchst du ne klasse chips, ne klasse Spieler... Bau dir für alles eine Klasse. Du kannst dann einfach die Klasse Deck haben, ne Methode programmieren, die dann intern deiner ARRAYLIST<Karte> jeweils 52 unterschiedliche Karten hinzufügt und so weiter, dann ne Methode shuffle zum mischen und dann nimmst du immer die obersten karten und gibst sie den Spielern weiter. Der Code wird viel einfacher, und Vllt auch kürzer ;)

Mit freundlichen Grüßen,
Luecx
 

InfectedBytes

Top Contributor
Java:
public class SimpleDeck {

    String[] deck = {
            "Ac", "Ah", "As", "Ad",
            "2c", "2h", "2s", "2d",
            "3c", "3h", "3s", "3d",
            "4c", "4h", "4s", "4d",
            "5c", "5h", "5s", "5d",
            "6c", "6h", "6s", "6d",
            "7c", "7h", "7s", "7d",
            "8c", "8h", "8s", "8d",
            "9c", "9h", "9s", "9d",
            "Tc", "Th", "Ts", "Td",
            "Jc", "Jh", "Js", "Jd",
            "Qc", "Qh", "Qs", "Qd",
            "Kc", "Kh", "Ks", "Kd"
    };
}
Die verschiedenen Karten würde ich auch nicht als String kodieren. Mach lieber eine enum für die Farbe und einen int für den Wert (oder auch eine enum):
Java:
public enum Color {
  CLUBS, SPADES, HEARTS, DIAMONDS
}
public class Card {
  Color color;
  int value; // 1 = Ass , 2=2 , .... 11=Bube, 12=Dame, 13=König
}
Anstatt dem int kannst du natürlich auch hier eine Enum benutzen:
Java:
public enum Value {
  AS, D2, D3, D4, D5, D6, D7, D8, D9, D10, JACK, QUEEN, KING
}
 

fk1

Mitglied
@Jardcore: Danke für die Tips und deine Geduld. Du hast recht, da ist inzwischen einiges durcheinander gekommen und das ist wohl auch der Grund, wieso ich das noch nicht richtig verstanden habe. Ich dachte immer, um einen Wert auszugeben, muss man ihn auch zuvor definieren. Daher hat Card bei mir bisher eine card :D Ein String Wert, der sich aus Rank + Suit zusammen setzt.

Wenn ich von deinem Card Beispiel nun ein Objekt erzeuge, macht das doch gar nix, außer die Werte Suit & Rank setzen (Nur Konstruktor betrachtet)!? Verstehe nicht, wie ich damit weiterarbeiten soll. getString() ist ja dann wieder nur dazu da, mir die Karte als Text zu übergeben. Wieso dann nicht auch als String speichern? Warum statt dessen als methode "holen"?

Bzgl: ArrayLists: Ich glaube ich weiss was das ist, Listen halt. Dynamische/flexible Arrays. Wieso mir das jetzt mehr Arbeit erspart, scheine ich nicht zu sehen.

@Luecx Habe ich auf den letzten Seiten schon zu hören bekommen, aufgenommen und arbeite seitdem daran es zu verstehen, zu verinnerlichen und umzusetzen.

@InfectedBytes Eine Erläuterung, warum Enums einem String Array vorzuziehen sind, wären hilfreich. Die Enums hat @Jardcore schon eine Seite zuvor vorgeschlagen. Ich wollte nur nicht alles vorgekaut bekommen und habe es deswegen mit meiner Idee mittels Arrays/Strings probiert.
 

fk1

Mitglied
Z8aCpJDzCuqWY.gif

Frohes fest zusammen! :)

Ich gebs auf!

Besser gesagt: Ich möchte einen Strich ziehen. Das, was bisher besprochen wurde, als Lehrmaterial nutzen und einfach mal weiter machen.

Ich habe mich der Enum Lösung nochmal angenommen und die Basis von @Jardcore übernommen:

Java:
public enum Suits {
        c,
        s,
        d,
        h;
}
Java:
public enum Ranks {
    ACE("A"),
    TWO("2"),
    THREE("3"),
    FOUR("4"),
    FIVE("5"),
    SIX("6"),
    SEVEN("7"),
    EIGHT("8"),
    NINE("9"),
    TEN("T"),
    JOKER("J"),
    QUEEN("Q"),
    KING("K");

    private String text;
    private Ranks(String text) {
        this.text = text;
    }
    public String getText() {
        return text;
    }
}
Java:
public class Card {
    private Suits suit;
    private Ranks rank;
    public Card(Ranks rank, Suits suit) {
        this.rank = rank;
        this.suit = suit;
    }
    public Ranks getRank() {
        return rank;
    }
    public Suits getSuit() {
        return suit;
    }
    @Override
    public String toString() {
        return String.format("%s%s", rank.getText(), suit);
    }
}

Hier meine Frage zu den Methoden getSuit & getRank: Da die bisher nicht verwendet werden, sind die rein provisorisch angelegt?

Weiter mit dem Deck in Form einer ArrayList:

Java:
import java.util.*;

public class Deck{
   
    ArrayList<Card> deck = new ArrayList<Card>();
   
    public void createDeck(){
        for(Ranks rank : Ranks.values()){
            for (Suits suit : Suits.values()){
                deck.add(new Card(rank, suit));
            }
        }
    }   
}

Hier mal eine Verständnisfrage: in den erweiterten for-Schleifen beginnen wir mit "Ranks rank". Ist das ein neu erzeugter Wert der Klasse bzw. Enums rank? Wie muss ich das verstehen?

Ranks.values erzeugt ein Array aller Ranks Enums und die foreach Schleife durchläuft das dann. Soweit, so gut. Nur woher kommt Ranks rank bzw. wie setzt sich das zusammen?

Dann zwecks Ausgabe eine Test class:

Java:
public class Test {
   
    public static void main(String[] args) {
        Deck blueDeck = new Deck();
        blueDeck.createDeck();
        System.out.print(blueDeck.toString());
    }

}

Ich erzeuge in der test class mal ein neues Deck blueDeck (gibt ja in einer Packung meist 2 Decks, ein rotes und ein blaues, rein der Übersicht wegen. Deck deck = new Deck(); ist dann schwer nach zu vollziehen für mich als Anfänger)

Jetzt bekomme ich wieder diese Zeichenkette ausgegeben: Deck@70c787d7

Habe ja dank @CSHW89 schon gelernt dass das die Java Ausgabe ist und noch nicht als String konvertiert. Ich dachte jetzt, das habe ich dank blueDeck.toString(), konvertiert aber anscheinend doch nicht?! Irgendwas mache ich anscheinend falsch...
 

Jardcore

Top Contributor
Die Zeichenkette zeigt zur Adresse im Speicher, also wo das Deck liegt.
Damit du dein Deck als String ausgeben kannst musst du deiner Deck Klasse eine toString Methode definieren und dort wiederrum festlegen wie dein Deck als String aussehen soll.

Die Verwirrung um Deck deck = new Deck kann man schnell auflösen. Jedes Objekt hat einen Standardkonstruktor, dieser ist der Name der Klasse ohne Parameter. Das heißt wenn du keinen eigenen Standartkonstruktor definkerst wird einfach der schon vorhandene genommen. Der Standartkonstruktor macht meist einfach nichts :)
Soweit, so gut. Nur woher kommt Ranks rank bzw. wie setzt sich das zusammen?
Du bekommst mit Ranks.values ALLE möglichen Werte die du in Ranks definiert hast. Dann gehst du in der for(each) jeden Wert nacheinander durch, und der Wert bei dem die Schleife aktuell ist wird vorrübergehend in Ranks rank gespeichert. Du könntest das Enum auch nur Rank nennen dann könnte das vllt Verwirrungen vermeiden.

Beste Grüße und frohe Weinachten
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
B Batchdatei, Prüfe ob Programm X läuft Softwareentwicklung 2
N Pop-up Programm mit Live-Video Softwareentwicklung 7
C Programm "Road Chat" realisierbar? Softwareentwicklung 2
J Suche noch eine Loesung fuer Kommunikation zwischen Webserver und ein Programm Softwareentwicklung 0
P Benutzeroberfläche Programm Bewertung Softwareentwicklung 2
KranzKrone Architektur für einfaches Gui Programm Softwareentwicklung 6
G Make or Buy? - Tagging-Programm Softwareentwicklung 4
G Linux: Programm mit UI einmalig beim Systemstart ausführen Softwareentwicklung 3
B WHILE und GOTO Programm Softwareentwicklung 32
I Tool / Programm etc. zur Testdokumentation gesucht Softwareentwicklung 2
T Kommerziellen Programm unter Verwendung div. Libraries mit div. Lizenzen Softwareentwicklung 7
Airwolf89 Java-Programm in C++ portieren Softwareentwicklung 4
Steev Javaprogram aus C/AL-Programm ansteuern Softwareentwicklung 13
clupus Verbindung mit c-Programm Softwareentwicklung 4
V AGB's in Programm einbauen? Softwareentwicklung 3
J Design Patterns in Programm hineinfließen lassen Softwareentwicklung 23
sparrow Welche Lizenz für ein offenes Programm Softwareentwicklung 2
G Suche Programm für Masken Design für Pflichtenheft Softwareentwicklung 5
T Programm mit Passwort schützen. Softwareentwicklung 44
J Finde Fehler im Programm nicht (Klasse Kreis) Softwareentwicklung 1
E Java Programm distributen Softwareentwicklung 35
X Möglichst unverständliches Programm Softwareentwicklung 13
P Grafik-Programm mit JAVA? Softwareentwicklung 21
F Kleines Programm für Windows Softwareentwicklung 2
M Kurvendiskussion, Funktions-Plotter, Mathe-Programm. Softwareentwicklung 3
W Herangehensweise an ein Java Programm Softwareentwicklung 4

Ähnliche Java Themen

Neue Themen


Oben