跳转至

深入探索 Java 实现的 21 点游戏

简介

21 点游戏(Blackjack)是一种广泛流行的纸牌游戏,在赌场和家庭聚会中都很常见。使用 Java 来实现 21 点游戏不仅能加深我们对 Java 编程的理解,还能锻炼我们的面向对象编程思维。本文将全面介绍 Java 实现 21 点游戏的相关内容,包括基础概念、使用方法、常见实践和最佳实践。

目录

  1. 基础概念
  2. 使用方法
  3. 常见实践
  4. 最佳实践
  5. 小结
  6. 参考资料

基础概念

21 点游戏规则

  • 游戏目标是使手中牌的点数之和接近但不超过 21 点,超过 21 点则“爆点”输牌。
  • 牌面点数:数字牌按牌面数字计算点数,J、Q、K 计为 10 点,A 可以计为 1 点或 11 点(取对玩家最有利的值)。
  • 游戏流程:玩家和庄家各发两张牌,玩家可以选择“要牌”(Hit)或“停牌”(Stand),最后比较玩家和庄家的牌点数决定胜负。

Java 实现的关键类

  • Card 类:表示一张扑克牌,包含牌面和花色信息。
  • Deck 类:表示一副扑克牌,负责洗牌和发牌操作。
  • Player 类:表示玩家或庄家,包含手中的牌和计算牌点数的方法。
  • BlackjackGame 类:表示整个 21 点游戏,负责游戏流程的控制。

使用方法

环境准备

确保你已经安装了 Java 开发环境(JDK),可以使用任何 Java 开发工具,如 IntelliJ IDEA 或 Eclipse。

代码示例

// Card 类
class Card {
    private String suit;
    private String rank;

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

    public String getSuit() {
        return suit;
    }

    public String getRank() {
        return rank;
    }

    @Override
    public String toString() {
        return rank + " of " + suit;
    }
}

// Deck 类
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

class Deck {
    private List<Card> cards;

    public Deck() {
        cards = new ArrayList<>();
        String[] suits = {"Hearts", "Diamonds", "Clubs", "Spades"};
        String[] ranks = {"2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack", "Queen", "King", "Ace"};
        for (String suit : suits) {
            for (String rank : ranks) {
                cards.add(new Card(suit, rank));
            }
        }
        shuffle();
    }

    public void shuffle() {
        Collections.shuffle(cards);
    }

    public Card dealCard() {
        return cards.remove(0);
    }
}

// Player 类
import java.util.ArrayList;
import java.util.List;

class Player {
    private List<Card> hand;

    public Player() {
        hand = new ArrayList<>();
    }

    public void receiveCard(Card card) {
        hand.add(card);
    }

    public int getHandValue() {
        int value = 0;
        int aces = 0;
        for (Card card : hand) {
            String rank = card.getRank();
            if (rank.equals("Ace")) {
                aces++;
                value += 11;
            } else if (rank.equals("Jack") || rank.equals("Queen") || rank.equals("King")) {
                value += 10;
            } else {
                value += Integer.parseInt(rank);
            }
        }
        while (value > 21 && aces > 0) {
            value -= 10;
            aces--;
        }
        return value;
    }

    public List<Card> getHand() {
        return hand;
    }
}

// BlackjackGame 类
import java.util.Scanner;

public class BlackjackGame {
    public static void main(String[] args) {
        Deck deck = new Deck();
        Player player = new Player();
        Player dealer = new Player();

        // 发初始牌
        player.receiveCard(deck.dealCard());
        dealer.receiveCard(deck.dealCard());
        player.receiveCard(deck.dealCard());
        dealer.receiveCard(deck.dealCard());

        // 玩家回合
        Scanner scanner = new Scanner(System.in);
        while (true) {
            System.out.println("Your hand: " + player.getHand());
            System.out.println("Your hand value: " + player.getHandValue());
            System.out.println("Dealer's visible card: " + dealer.getHand().get(0));
            System.out.println("Do you want to hit (h) or stand (s)?");
            String choice = scanner.nextLine().toLowerCase();
            if (choice.equals("h")) {
                player.receiveCard(deck.dealCard());
                if (player.getHandValue() > 21) {
                    System.out.println("You bust! Dealer wins.");
                    return;
                }
            } else if (choice.equals("s")) {
                break;
            }
        }

        // 庄家回合
        while (dealer.getHandValue() < 17) {
            dealer.receiveCard(deck.dealCard());
            if (dealer.getHandValue() > 21) {
                System.out.println("Dealer busts! You win.");
                return;
            }
        }

        // 比较结果
        System.out.println("Your hand value: " + player.getHandValue());
        System.out.println("Dealer's hand value: " + dealer.getHandValue());
        if (player.getHandValue() > dealer.getHandValue()) {
            System.out.println("You win!");
        } else if (player.getHandValue() < dealer.getHandValue()) {
            System.out.println("Dealer wins.");
        } else {
            System.out.println("It's a tie.");
        }
    }
}

使用步骤

  1. 将上述代码保存为 .java 文件,例如 BlackjackGame.java
  2. 打开命令行,进入代码所在目录。
  3. 编译代码:javac BlackjackGame.java
  4. 运行程序:java BlackjackGame
  5. 根据提示输入 hs 进行要牌或停牌操作。

常见实践

异常处理

在实际开发中,可能会遇到牌堆为空的情况,需要在 Deck 类的 dealCard 方法中添加异常处理:

public Card dealCard() {
    if (cards.isEmpty()) {
        throw new IllegalStateException("The deck is empty.");
    }
    return cards.remove(0);
}

增加游戏交互性

可以添加更多的提示信息和错误处理,提高用户体验。例如,当用户输入无效的选择时,提示用户重新输入。

最佳实践

面向对象设计

遵循面向对象的设计原则,将不同的功能封装到不同的类中,提高代码的可维护性和可扩展性。

代码复用

可以将一些通用的方法提取出来,如计算牌点数的方法,避免代码重复。

测试驱动开发

使用 JUnit 等测试框架对各个类的方法进行单元测试,确保代码的正确性。

小结

本文介绍了 Java 实现 21 点游戏的基础概念、使用方法、常见实践和最佳实践。通过实现 21 点游戏,我们可以更好地理解 Java 的面向对象编程和异常处理等知识。同时,在开发过程中遵循最佳实践可以提高代码的质量和可维护性。

参考资料

  • 《Effective Java》
  • Java 官方文档
  • JUnit 官方文档