[JAVA] Implémentation de "Black Jack".

Déclencheur

Les examens de fin d'études des débutants devraient développer le "Blackjack"

Inspiré de l'article "Un examen de fin d'études d'un débutant en programmation devrait développer 'Blackjack'", j'ai essayé de créer un blackjack en Java. Étonnamment difficile ... La faible compétence de conception est perceptible. La difficulté de mise en œuvre était juste. Le temps de montage est-il d'environ 3 heures?

J'aimerais le garder propre, alors veuillez le signaler.

La source

Le code source a été téléchargé sur github. https://github.com/akiyu33333/blackjack

Environnement de développement

Source complète (au 22/06)

Les spécifications sont l'article original de Qiita ou github README Veuillez vous y référer.

~~ * Refactorisé en réponse à l'indication. ~~ De plus, nous avons mis en place un refactoring et un calcul de score.

22/06 postscript J'ai apporté d'autres corrections en réponse au point de @ watashi_da. On m'a conseillé d'avoir un indicateur CPU, et à la suite de la refactorisation, j'ai finalement décidé de diviser les classes en ** User ** et ** Dealer **.

Main.java

Main.java


import blackjackgame.BlackJackGame;

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

BlackJackGame.java Nom de classe et nom de package modifiés.

BlackJackGame.java


package blackjackgame;

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

public class BlackJackGame {

    /**
     *début du jeu
     */
    public void start() {
        System.out.println("★ ☆ ★ ☆ ★ ☆ ★ ☆ ★ ☆ ★ ☆ Bienvenue au Blackjack! ★ ☆ ★ ☆ ★ ☆ ★ ☆ ★ ☆ ★ ☆\n");
        System.out.println("Commencer le jeu.\n");

        Deck deck     = new Deck();
        AbstractPlayer user   = new User("tu");
        AbstractPlayer dealer = new Dealer("Marchand");

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

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

        printGameResult(user, dealer);

        System.out.println("\n Le Blackjack est terminé! Veuillez rejouer ★");
    }

    /**
     *Afficher les résultats du jeu
     * @param player1 player1
     * @param player2 player 2
     */
    private void printGameResult(AbstractPlayer player1, AbstractPlayer player2) {
        if (player1.calcScore() == player2.calcScore()) {
            System.out.println("C'est un tirage au sort.");
            return;
        }
        AbstractPlayer winner = !player1.isBust() && (player2.isBust() || player1.calcScore() > player2.calcScore())
                ? player1
                : player2;
        System.out.println( winner.getName() + "Est le gagnant!" );
    }
}

~~Player.java~~ → AbstractPlayer.java J'étais conscient de ne générer de «lombok» que là où c'était nécessaire. Au début, j'en ai fait une classe abstraite, mais comme je n'en ai plus besoin, j'en ai fait une classe concrète. Dois-je créer une interface et l'implémenter? ~~ getPoint () ~~ J'ai personnellement ressenti la croissance de pouvoir écrire le lambda de calcScore () (rires)

Renommé «getPoint» en «calcScore». J'ai oublié ce qui suit du code lisible.

De nombreux programmeurs sont habitués à la convention selon laquelle les méthodes commençant par get sont des "accesseurs légers" qui ne renvoient que les valeurs des membres. Le non-respect de ces conditions peut être trompeur.

Puisque le processus de calcul est inclus ici, getXXX n'est pas bon.

Ajout d'une logique de calcul pour A. La méthode consistait à calculer autre que A, puis à calculer à partir du nombre de A et à additionner.

22/06 postscript Puisqu'il s'agit d'une classe abstraite, le nom est également modifié.

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);
    }

    /**
     *Piochez une carte du jeu
     * @pont de pont param
     * @param isHidden Masquer la carte piochée
     */
    public void draw(Deck deck, boolean isHidden) {
        Card card = deck.draw();
        addCardList(card);
        if (calcScore() > BUST_POINT) setBust(true);
        String msg = isHidden
                ? this.name + "Je ne connais pas la carte que j'ai dessinée."
                : this.name + "La carte dessinée par" + card.toString() + "est.";
        System.out.println( msg );
    }

    /**
     *Créer une première main
     * @pont de pont param
     */
    public abstract void initCardList(Deck deck);

    /**
     *Piochez une carte du jeu
     * @pont de pont param
     */
    public abstract void drawCard(Deck deck);
}

User.java 22/06 postscript Nouvellement créé pour faire la distinction entre le lecteur et le processeur.

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() + "Le score actuel de" + calcScore() + "C'est un point.\n");
        try (Scanner sc = new Scanner(System.in)) {
            String line = null;
            while (!isBust() && !Objects.equals(line, "N")) {
                System.out.println("Tirez-vous une carte? Entrez N si vous ne voulez pas dessiner Y.");
                line = sc.nextLine();
                if (Objects.equals(line, "Y")) {
                    draw(deck);
                    System.out.println( getName() + "Le score actuel de" + calcScore() + "C'est un point.\n");
                } else if (!Objects.equals(line, "N")) {
                    System.out.println("Y/Tout autre élément que N a été saisi.");
                }
            }
        }
    }
}

Dealer.java 22/06 postscript Nouvellement créé pour faire la distinction entre le lecteur et le processeur.

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() + "Le score actuel de" + calcScore() + "C'est un point.\n");
        while (calcScore() < 17){
            draw(deck);
            System.out.println( getName() + "Le score actuel de" + calcScore() + "C'est un point.\n");
        }
    }
}

Card.java Rend le champ «final». Le "commutateur" et l'opérateur ternaire sont maladroits.

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() + "de" + this.toDisplayValue();
    }

}

Deck.java J'ai essayé d'utiliser la méthode d'initialisation. Lambda ici aussi se sentait bien (rires) Je veux remplacer la valeur de retour du lambda par bill telle quelle sans utiliser ~~new ArrayList <> (), mais je ne savais pas comment l'écrire. ~~ J'ai pu l'écrire en lambda, donc je l'ai corrigé. Bien que la langue soit différente, j'ai lu cet article et j'ai pensé que je ne devrais pas utiliser foreach pour quoi que ce soit. Utiliser forEach avec JavaScript est le dernier recours En fait, ce n'est pas du JavaScript, donc le contenu de l'article ne peut pas être utilisé tel quel, mais j'ai été impressionné par l'idée. Collections.shuffle J'ai aussi appris cela pour la première fois. Il existe une méthode pratique.

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 Mon «énum» préféré. J'ai oublié d'utiliser lombok même avec ʻenum`, alors je l'ai corrigé.

Suit.java


package card;

import lombok.AllArgsConstructor;
import lombok.Getter;

@AllArgsConstructor
public enum Suit {
    SPADE("bêche"),
    HEART("cœur"),
    DIAMOND("diamant"),
    CLUB("club");

    @Getter
    private final String mark;
}

Résumé

était amusant. IntelliJ n'a pas de raccourci pour créer Javadoc. Puisque nous avons permis de diviser ~~ A entre 1 et 11 et ~~ A, nous aimerions prendre en charge plusieurs joueurs.

Recommended Posts

Implémentation de "Black Jack".
[Progression de la production] Black Jack: 03
[Progression de la production] Black Jack: 01
[Progression de la production] Black Jack: 02
Fonction de commentaire implémentée
[Progression de la production] Black Jack: 04