为一副通用纸牌设计数据结构
大家好,我是易安,今天我们来聊一道笔试题,这也是我曾经面试华为时做过的题,今天分享给大家。
题目:
如何设计一个通用的扑克牌数据结构?请解释如何继承它来实现特定的扑克游戏,以及如何继承这些数据结构来实现二十一点游戏。
建议:请先在IDE上尝试解法,然后再去看解决方案
解决方案:
首先,我们需要认识到“通用”的扑克牌可以有很多种。通用可能意味着可以用于类似扑克的游戏的标准牌组,或者甚至可以扩展到Uno或棒球卡。
实现特定的扑克牌游戏
假设这个牌组是一个标准的52张牌组,就像你在二十一点或扑克游戏中看到的那样。如果是这样,设计可能看起来像这样:
这里的结构很清晰:一副牌包含四种花色和13张牌。每张牌的数字值从1到13。如果您考虑一下扑克牌游戏,不同的游戏有不同的发牌和回收牌的方式。因此,我们可以在“Deck”类中有一组抽象方法,以允许子类实现其自己的发牌方式。我画的类图在这里:
img
Java版本:
这里只是写了大概的流程节点,关键需要你自己补充
要设计一个通用的扑克牌数据结构,可以考虑使用以下类来表示扑克牌:
代码语言:javascript复制public class Card {
private final Suit suit; // 花色
private final Rank rank; // 点数
public Card(Suit suit, Rank rank) {
this.suit = suit;
this.rank = rank;
}
// Getter and Setter methods
@Override
public String toString() {
return rank " of " suit;
}
}
public enum Suit {
CLUBS, DIAMONDS, HEARTS, SPADES;
}
public enum Rank {
ACE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING;
}
Card
类有两个实例变量:suit
和rank
,分别表示花色和点数。Suit
和Rank
分别是枚举类型,用于限定花色和点数的范围。通过这个类,我们可以轻松地创建一副扑克牌。
为了实现特定的扑克游戏,可以创建一个继承自Card
的类,来表示具有特殊规则的游戏中的牌。例如,在五十二张牌的德州扑克中,有四种花色和十三种点数,但是在游戏中,有一张叫做“大王”的牌,它并不属于上述任何一种花色或点数。可以创建一个TexasHoldemCard
类,继承自Card
类,并添加一个名为isJoker()
的方法,用于判断该牌是否为“大王”。
public class TexasHoldemCard extends Card {
private boolean isJoker;
public TexasHoldemCard(Suit suit, Rank rank) {
super(suit, rank);
this.isJoker = false;
}
public boolean isJoker() {
return isJoker;
}
public void setJoker(boolean joker) {
isJoker = joker;
}
}
在TexasHoldemCard
类中,添加了一个名为isJoker()
的方法,用于判断该牌是否为“大王”。如果是“大王”,则返回true
;否则返回false
。
为了实现二十一点游戏,可以创建一个名为Blackjack
的类,继承自Card
类,用于表示二十一点游戏中的牌。在二十一点游戏中,每张牌都有一个点数,其中A牌可以表示1或11点,而J、Q、K牌都表示10点。因此,在Blackjack
类中,需要添加一个名为getValue()
的方法,用于返回该牌的点数。
public class BlackjackCard extends Card {
public BlackjackCard(Suit suit, Rank rank) {
super(suit, rank);
}
public int getValue() {
switch (rank) {
case TWO:
return 2;
case THREE:
return 3;
case FOUR:
return 4;
case FIVE:
return 5;
case SIX:
return 6;
case SEVEN:
return 7;
case EIGHT:
return 8;
case NINE:
return 9;
case TEN:
case JACK:
case QUEEN:
case KING:
return 10;
case ACE:
return 1; // A牌默认为1点
default:
throw new IllegalStateException("Unexpected value: " rank);
}
}
}
在BlackjackCard
类中,添加了一个名为getValue()
的方法,用于返回该牌的点数。在此方法中,使用了一个switch
语句,根据不同的点数返回不同的点数值。需要注意的是,A牌的点数可以为1或11,但是在此方法中默认为1。
现在,我们已经设计了通用的扑克牌数据结构,并且使用继承的方式,实现了特定的扑克游戏和二十一点游戏。下面是一个简单的例子,展示如何使用上述代码:
代码语言:javascript复制public class Main {
public static void main(String[] args) {
Card card = new Card(Suit.HEARTS, Rank.ACE);
System.out.println(card); // Output: ACE of HEARTS
TexasHoldemCard joker = new TexasHoldemCard(Suit.CLUBS, Rank.ACE);
joker.setJoker(true);
System.out.println(joker.isJoker()); // Output: true
BlackjackCard king = new BlackjackCard(Suit.SPADES, Rank.KING);
System.out.println(king.getValue()); // Output: 10
}
}
在上述代码中,首先创建了一个普通的扑克牌对象,然后创建了一个继承自Card
的TexasHoldemCard
对象,该对象被标记为“大王”,最后创建了一个继承自Card
的BlackjackCard
对象,表示一张K牌,其点数为10。
运行该程序,输出结果为:
代码语言:javascript复制ACE of HEARTS
true
10
这表明我们成功地创建了一个通用的扑克牌数据结构,并使用继承的方式,实现了特定的扑克游戏和二十一点游戏。
完整代码如下:
代码语言:java复制public class Card {
private final Suit suit; // 花色
private final Rank rank; // 点数
public Card(Suit suit, Rank rank) {
this.suit = suit;
this.rank = rank;
}
public Suit getSuit() {
return suit;
}
public Rank getRank() {
return rank;
}
@Override
public String toString() {
return rank " of " suit;
}
}
enum Suit {
CLUBS, DIAMONDS, HEARTS, SPADES;
}
enum Rank {
ACE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING;
}
public class TexasHoldemCard extends Card {
private boolean isJoker;
public TexasHoldemCard(Suit suit, Rank rank) {
super(suit, rank);
this.isJoker = false;
}
public boolean isJoker() {
return isJoker;
}
public void setJoker(boolean joker) {
isJoker = joker;
}
}
public class BlackjackCard extends Card {
public BlackjackCard(Suit suit, Rank rank) {
super(suit, rank);
}
public int getValue() {
switch (rank) {
case TWO:
return 2;
case THREE:
return 3;
case FOUR:
return 4;
case FIVE:
return 5;
case SIX:
return 6;
case SEVEN:
return 7;
case EIGHT:
return 8;
case NINE:
return 9;
case TEN:
case JACK:
case QUEEN:
case KING:
return 10;
case ACE:
return 1; // A牌默认为1点
default:
throw new IllegalStateException("Unexpected value: " rank);
}
}
}
public class Main {
public static void main(String[] args) {
Card card = new Card(Suit.HEARTS, Rank.ACE);
System.out.println(card); // Output: ACE of HEARTS
TexasHoldemCard joker = new TexasHoldemCard(Suit.CLUBS, Rank.ACE);
joker.setJoker(true);
System.out.println(joker.isJoker()); // Output: true
BlackjackCard king = new BlackjackCard(Suit.SPADES, Rank.KING);
System.out.println(king.getValue()); // Output: 10
}
}