2023 面向对象程序设计实践(Java)OJ 作业,遇到这么一个折磨人的东西。debug 过久,遂记录。
题目描述
21点又名黑杰克(Blackjack),起源于法国,已流传到世界各地,有着悠久的历史。现在在世界各地的赌场中都可以看到二十一点。随着互联网的发展,二十一点开始走向网络时代。该游戏由2到6个人玩,使用除大小王之外的52张牌,游戏者的目标是使手中的牌的点数之和不超过21点且尽量大。
大家手中扑克点数的计算规则是:2至9牌,按其原点数计算;K、Q、J和10牌都算作10点;A 牌(ace)既可算作1点也可算作11点,由玩家自己决定(当玩家停牌时,点数一律视为最大而尽量不爆,如A+9为20,A+4+8为13,A+3+A视为15)。
你的任务设计基于指定策略的一个21点游戏的部分功能。
指定策略为:如果手中牌的点数之和小于17点则继续要下一张牌,直到大于等于17点为止。如果手里的牌有A,且A的点数当成11点没有超过21点,则此时A要按11点计算,如果超过21点,则A要按1点计算。
一个参考的设计为:1、设计一个card类,用于保存一张牌;2、设计一个hand类,用于保存一手牌;3、设计一个player类,该类可以基于指定策略完成一次游戏过程。
输入
若干行(至少2行),每行代表一张牌。具体格式见样例。
输出
若干行。
读入前两张牌不输出,从第三张牌开始(如果需要),则每次要牌,要先输出Hit,然后读入下一张牌,并依次输出该牌的花色及点数(A输出1 11,即它有两个点数)。当不再要牌时要先输出Stand,然后在一行内输出这一手牌,牌与牌之间用一个空格分隔。
牌输出的顺序为先看牌面,牌面小的在前(牌面由小到大的顺序为A,2,3....J,Q,K),当牌面相同时看花色,输出顺序从前到后为Spade, Heart, Diamond, Club。
最后一行输出这一手牌的结果,如果总点数超过21点,则输出Bust,如果是Blackjack(一手牌只有两张牌且点数相加和为21点),则输出Blackjack。其他情况则输出一个整数,代表这手牌的点数(尽量大且不爆)。具体格式见样例。
样例输入
Spade 4
Heart A
Heart 3
样例输出
Hit
Heart 3
Stand
HeartA Heart3 Spade4
18
完整代码
package hw2.C;
import java.util.*;
class Card implements Comparable<Card> {
private String suit;
private String rank;
private static final HashMap<String, Integer> suits = new HashMap<>();
private static final HashMap<String, Integer> ranks = new HashMap<>();
static {
suits.put("Spade", 1);suits.put("Heart", 2);suits.put("Diamond", 3);suits.put("Club", 4);
ranks.put("A", 1);ranks.put("2", 2);ranks.put("3", 3);ranks.put("4", 4);
ranks.put("5", 5);ranks.put("6", 6);ranks.put("7", 7);ranks.put("8", 8);
ranks.put("9", 9);ranks.put("10", 10);ranks.put("J", 11);ranks.put("Q", 12);ranks.put("K", 13);
}
public Card(String suit, String rank) {
this.suit = suit;
this.rank = rank;
}
public String getSuit() {
return suit;
}
public String getRank() {
return rank;
}
public int getValue() {
if (rank.equals("A")) {
return 11;
} else if (rank.equals("K") || rank.equals("Q") ||
rank.equals("J") || rank.equals("10")) {
return 10;
} else {
return Integer.parseInt(rank);
}
}
@Override
public String toString() {
return suit + " " + rank;
}
@Override
public int compareTo(Card o) {
int diffOfRank = ranks.get(this.getRank()) - ranks.get(o.getRank());
int diffOfSuit = suits.get(this.getSuit()) - suits.get(o.getSuit());
if (diffOfRank > 0) {
return 1;
} else if (diffOfRank < 0) {
return -1;
} else {
if (diffOfSuit > 0) {
return 1;
} else if (diffOfSuit < 0) {
return -1;
} else {
return 0;
}
}
}
}
class Hand {
private PriorityQueue<Card> cards;
public Hand() {
this.cards = new PriorityQueue<>();
}
public void addCard(Card c) {
cards.add(c);
}
public int getValue() {
int value = 0;
int aces = 0;
for (Card c : cards) {
value += c.getValue();
if (c.getRank().equals("A")) {
aces++;
}
}
while (value > 21 && aces > 0) {
value -= 10;
aces--;
}
return value;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
PriorityQueue<Card> pq = new PriorityQueue<>(cards);
while (!pq.isEmpty()) {
Card c = pq.poll();
sb.append(c.getSuit()).append(c.getRank()).append(" ");
}
return sb.toString().trim();
}
}
class Player {
private Hand hand;
public Player() {
hand = new Hand();
}
public void addCard(Card c) {
hand.addCard(c);
}
public int getValue() {
return hand.getValue();
}
public boolean canHit() {
return this.getValue() < 17;
}
public void hit(Card c) {
System.out.println("Hit");
this.hand.addCard(c);
if (c.getRank().equals("A")) {
System.out.println(c.getSuit() + " 1 11");
} else {
System.out.println(c.getSuit() + " " + c.getValue());
}
}
public void stand() {
System.out.println("Stand");
System.out.println(hand.toString());
int n = this.getValue();
if (n == 21 && hand.toString().split(" ").length == 2) {
System.out.println("Blackjack");
} else if (n > 21) {
System.out.println("Bust");
} else {
System.out.println(n);
}
}
}
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
LinkedList<Card> queue = new LinkedList<>();
while (sc.hasNextLine()) {
String[] arr = sc.nextLine().split(" ");
Card c = new Card(arr[0], arr[1]);
queue.addLast(c);
}
Player p = new Player();
p.addCard(queue.removeFirst());
p.addCard(queue.removeFirst());
while (p.canHit() && !queue.isEmpty()) {
Card c = queue.removeFirst();
p.hit(c);
}
p.stand();
}
}
最后问题出在这里
多亏了 newbing,整个类的设计真的很优雅。我觉得比较关键的是 Card
的成员变量还是只存基本的 suit
和 rank
,其点数值由于会随着摸牌过程发生变化,所以把它写成一个成员方法 getValue()
来实时返回。
设计!设计!还是设计!