[JAVA] "Black Jack" implementiert.

Auslösen

Abschlussprüfungen von Anfängern sollten "Blackjack" entwickeln

Inspiriert von dem Artikel "Eine Abschlussprüfung eines Programmieranfängers sollte" Blackjack "entwickeln" versuchte ich, einen Blackjack in Java zu erstellen. Überraschend schwierig ... Die geringe Designfähigkeit macht sich bemerkbar. Die Schwierigkeit der Implementierung war genau richtig. Ist die Montagezeit ca. 3 Stunden?

Ich möchte es sauber halten, also weisen Sie bitte darauf hin.

Quelle

Der Quellcode wurde auf github hochgeladen. https://github.com/akiyu33333/blackjack

Entwicklungsumgebung

Vollständige Quelle (Stand 22.06.)

Die Spezifikationen sind Qiitas Originalartikel oder github README Bitte nehmen Sie Bezug darauf.

~~ * Überarbeitet, nachdem darauf hingewiesen wurde. ~~ Zusätzlich haben wir Refactoring & A Score Berechnung implementiert.

06/22 Nachtrag Ich habe weitere Korrekturen vorgenommen, um auf den Punkt von @ watashi_da zu reagieren. Mir wurde geraten, ein CPU-Flag zu haben, und als Ergebnis des Refactorings entschied ich mich schließlich, die Klassen in ** Benutzer ** und ** Händler ** zu unterteilen.

Main.java

Main.java


import blackjackgame.BlackJackGame;

public class Main {
    public static void main(String[] args) {
        new BlackJackGame().start();
    }
}

BlackJackGame.java Klassenname und Paketname geändert.

BlackJackGame.java


package blackjackgame;

import card.Deck;
import player.Dealer;
import player.AbstractPlayer;
import player.User;

public class BlackJackGame {

    /**
     *Spiel starten
     */
    public void start() {
        System.out.println("Willkommen beim Blackjack! ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ☆\n");
        System.out.println("Starte das Spiel.\n");

        Deck deck     = new Deck();
        AbstractPlayer user   = new User("Sie");
        AbstractPlayer dealer = new Dealer("Händler");

        user.initCardList(deck);
        dealer.initCardList(deck);

        user.drawCard(deck);
        if(!user.isBust()) dealer.drawCard(deck);

        printGameResult(user, dealer);

        System.out.println("\n Blackjack ist vorbei! Bitte nochmal spielen ★");
    }

    /**
     *Spielergebnisse anzeigen
     * @param player1 player1
     * @param player2 player 2
     */
    private void printGameResult(AbstractPlayer player1, AbstractPlayer player2) {
        if (player1.calcScore() == player2.calcScore()) {
            System.out.println("Es ist eine Zeichnung.");
            return;
        }
        AbstractPlayer winner = !player1.isBust() && (player2.isBust() || player1.calcScore() > player2.calcScore())
                ? player1
                : player2;
        System.out.println( winner.getName() + "Ist der Gewinner!" );
    }
}

~~Player.java~~ → AbstractPlayer.java Ich war mir bewusst, "Lombok" nur dort zu erzeugen, wo es gebraucht wurde. Zuerst habe ich es zu einer abstrakten Klasse gemacht, aber da ich es nicht mehr brauche, habe ich es zu einer konkreten Klasse gemacht. Soll ich eine Schnittstelle erstellen und implementieren? ~~ getPoint () ~~ Ich persönlich habe das Wachstum gespürt, das Lambda von calcScore () schreiben zu können (lacht)

Umbenennung von "getPoint" in "calcScore". Ich habe das Folgende des lesbaren Codes vergessen.

Viele Programmierer sind an die Konvention gewöhnt, dass Methoden, die mit get beginnen, "Lightweight Accessors" sind, die nur Mitgliedswerte zurückgeben. Die Nichtbeachtung dieser Bedingungen kann irreführend sein.

Da der Berechnungsprozess hier enthalten ist, ist getXXX nicht gut.

Berechnungslogik für A hinzugefügt. Die Methode bestand darin, andere als A zu berechnen, dann aus der Anzahl von A zu berechnen und zu addieren.

06/22 Nachtrag Da es sich um eine abstrakte Klasse handelt, wird auch der Name geändert.

AbstractPlayer.java


package player;

import card.Card;
import card.Deck;
import lombok.Getter;
import lombok.Setter;

import java.util.ArrayList;
import java.util.List;

public abstract class AbstractPlayer {
    protected static final int BUST_POINT = 21;

    @Getter
    private final String name;
    private List<Card> cardList = new ArrayList<>();
    @Getter
    @Setter
    private boolean isBust = false;

    public AbstractPlayer(String name) {
        this.name = name;
    }

    private void addCardList(Card card){
        cardList.add(card);
    }

    public int calcScore(){
        int score = cardList.stream().filter(card -> card.getPoint() > 1 ).mapToInt(card -> card.getPoint()).sum();
        int aceCardCount = (int) cardList.stream().filter(card -> card.getPoint() == 1 ).count();
        if (aceCardCount == 0) return score;
        int borderScore = 11 - aceCardCount;
        return score > borderScore ? score + aceCardCount : score + 10 + aceCardCount ;
    }

    public void draw(Deck deck) {
        draw(deck,false);
    }

    /**
     *Ziehe eine Karte aus dem Stapel
     * @Param Deck Deck
     * @param isHidden Verstecke die gezogene Karte
     */
    public void draw(Deck deck, boolean isHidden) {
        Card card = deck.draw();
        addCardList(card);
        if (calcScore() > BUST_POINT) setBust(true);
        String msg = isHidden
                ? this.name + "Ich kenne die Karte, die ich gezogen habe, nicht."
                : this.name + "Die Karte gezogen von" + card.toString() + "ist.";
        System.out.println( msg );
    }

    /**
     *Eine erste Hand erstellen
     * @Param Deck Deck
     */
    public abstract void initCardList(Deck deck);

    /**
     *Ziehe eine Karte aus dem Stapel
     * @Param Deck Deck
     */
    public abstract void drawCard(Deck deck);
}

User.java 06/22 Nachtrag Neu erstellt, um zwischen Player und CPU zu unterscheiden.

User.java


package player;

import card.Deck;

import java.util.Objects;
import java.util.Scanner;

public class User extends AbstractPlayer {
    public User(String name) {
        super(name);
    }

    @Override
    public void initCardList(Deck deck) {
        draw(deck);
        draw(deck);
    }

    @Override
    public void drawCard(Deck deck) {
        System.out.println( getName() + "Die aktuelle Punktzahl von" + calcScore() + "Es ist ein Punkt.\n");
        try (Scanner sc = new Scanner(System.in)) {
            String line = null;
            while (!isBust() && !Objects.equals(line, "N")) {
                System.out.println("Ziehst du eine Karte? Geben Sie N ein, wenn Sie kein Y zeichnen möchten.");
                line = sc.nextLine();
                if (Objects.equals(line, "Y")) {
                    draw(deck);
                    System.out.println( getName() + "Die aktuelle Punktzahl von" + calcScore() + "Es ist ein Punkt.\n");
                } else if (!Objects.equals(line, "N")) {
                    System.out.println("Y/Alles andere als N wurde eingegeben.");
                }
            }
        }
    }
}

Dealer.java 06/22 Nachtrag Neu erstellt, um zwischen Player und CPU zu unterscheiden.

Dealer.java


package player;

import card.Deck;

public class Dealer extends AbstractPlayer {

    public Dealer(String name) {
        super(name);
    }

    @Override
    public void initCardList(Deck deck) {
        draw(deck);
        draw(deck, true);
    }
    @Override
    public void drawCard(Deck deck) {
        System.out.println( getName() + "Die aktuelle Punktzahl von" + calcScore() + "Es ist ein Punkt.\n");
        while (calcScore() < 17){
            draw(deck);
            System.out.println( getName() + "Die aktuelle Punktzahl von" + calcScore() + "Es ist ein Punkt.\n");
        }
    }
}

Card.java Hat das Feld "endgültig" gemacht. Der "Schalter" und der ternäre Operator sind umständlich.

Card.java


package card;

import lombok.AllArgsConstructor;

@AllArgsConstructor
public class Card {

    private final Suit suit;
    private final int rank;

    private String toDisplayValue() {
        switch (this.rank) {
            case 1:
                return "A";
            case 11:
                return "J";
            case 12:
                return "Q";
            case 13:
                return "K";
            default:
                return String.valueOf(this.rank);
        }
    }
    public int getPoint() {
        return this.rank > 10 ? 10 : this.rank;
    }
    @Override
    public String toString() {
        return this.suit.getMark() + "von" + this.toDisplayValue();
    }

}

Deck.java Ich habe versucht, die Initialisierungsmethode zu verwenden. Lambda hier fühlte sich auch gut an (lacht) Ich möchte den Rückgabewert des Lambda durch "bill" ersetzen, wie es ist, ohne ~~ "new ArrayList <> ()" zu verwenden, aber ich wusste nicht, wie ich es schreiben soll. ~~ Ich konnte es in Lambda schreiben, also habe ich es korrigiert. Obwohl die Sprache anders ist, habe ich diesen Artikel gelesen und dachte, ich sollte foreach für nichts verwenden. Die Verwendung von forEach mit JavaScript ist der letzte Ausweg Eigentlich ist es kein JavaScript, daher kann der Inhalt des Artikels nicht so verwendet werden, wie er ist, aber ich war beeindruckt von der Denkweise. Collections.shuffle Das habe ich auch zum ersten Mal gelernt. Es gibt eine bequeme Methode.

Deck.java


package card;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class Deck {
    private List<Card> bill;
    {
        bill = Arrays.stream(Suit.values()).flatMap(s -> IntStream.rangeClosed(1,13).mapToObj(i -> new Card(s,i))).collect(Collectors.toList());
        Collections.shuffle(bill);
    }

    public Card draw(){
        Card card = bill.get(0);
        bill.remove(0);
        return card;
    }
}

Suit.java Mein Lieblings-Enum. Ich habe vergessen, lombok mit enum zu verwenden, also habe ich es behoben.

Suit.java


package card;

import lombok.AllArgsConstructor;
import lombok.Getter;

@AllArgsConstructor
public enum Suit {
    SPADE("Spaten"),
    HEART("Herz"),
    DIAMOND("Diamant"),
    CLUB("Verein");

    @Getter
    private final String mark;
}

Zusammenfassung

war Spaß. IntelliJ hat keine Verknüpfung, um Javadoc zu erstellen. Da wir es möglich gemacht haben, ~~ A zwischen 1 und 11 und ~~ A zu teilen, möchten wir mehrere Spieler unterstützen.

Recommended Posts

"Black Jack" implementiert.
[Produktionsfortschritt] Black Jack: 03
[Produktionsfortschritt] Black Jack: 01
[Produktionsfortschritt] Black Jack: 02
Kommentarfunktion implementiert
[Produktionsfortschritt] Black Jack: 04