14.5 Player

前面定义的类可用于任何扑克牌游戏,即我们没有在这些类中实现任何 Crazy Eights 特有的规则。这可能是件好事,因为以后要开发另一款游戏时,可轻松地重用这些类。

接下来该实现这些规则了。为此,我们将使用两个类:PlayerEights,前者封装了玩家策略,后者创建并维护游戏的状态。下面列出了 Player 类定义的开头部分:

  1. public class Player {
  2. private String name;
  3. private Hand hand;
  4. public Player(String name) {
  5. this.name = name;
  6. this.hand = new Hand(name);
  7. }

Player 有两个私有属性:namehand。构造函数接受玩家的名字,并将其存储到实例变量 name 中。在这里,我们必须用 this 将同名的实例变量和形参区分开来。

Player 提供的主要方法是 play;每当轮到玩家出牌时,都用它来决定出哪张牌:

  1. public Card play(Eights eights, Card prev) {
  2. Card card = searchForMatch(prev);
  3. if (card == null) {
  4. card = drawForMatch(eights, prev);
  5. }
  6. return card;
  7. }

第一个形参是一个引用,指向封装了游戏状态的 Eights 对象。需要取牌时要用到这个对象。第二个形参 prev 指的是弃牌堆最上面的扑克牌。

我们采用自上而下的开发,让 play 调用两个辅助方法——searchForMatchdrawForMatchsearchForMatch 在当前玩家手中查找与前一个玩家所出的牌匹配的牌:

  1. public Card searchForMatch(Card prev) {
  2. for (int i = 0; i < hand.size(); i++) {
  3. Card card = hand.getCard(i);
  4. if (cardMatches(card, prev)) {
  5. return hand.popCard(i);
  6. }
  7. }
  8. return null;
  9. }

这里的策略非常简单:for 循环找到并返回第一张匹配的。如果没有匹配的牌,就返回 null。在这种情况下,就必须不断取牌,直到获得匹配的牌:

  1. public Card drawForMatch(Eights eights, Card prev) {
  2. while (true) {
  3. Card card = eights.draw();
  4. System.out.println(name + " draws " + card);
  5. if (cardMatches(card, prev)) {
  6. return card;
  7. }
  8. hand.addCard(card);
  9. }
  10. }

其中的 while 循环将不断运行,直到取到匹配的牌(这里暂时假设终将取到匹配的牌)。它用 Eights 对象来取一张牌。如果这张牌是匹配的,就返回该牌;否则就将其放到玩家手里,并继续取牌。

searchForMatchdrawForMatch 都使用了 cardMatchescardMatches 是一个静态方法,也是在 Player 类中定义的,其以简单的方式实现了这个游戏的规则:

  1. public static boolean cardMatches(Card card1, Card card2) {
  2. if (card1.getSuit() == card2.getSuit()) {
  3. return true;
  4. }
  5. if (card1.getRank() == card2.getRank()) {
  6. return true;
  7. }
  8. if (card1.getRank() == 8) {
  9. return true;
  10. }
  11. return false;
  12. }

最后,Player 还提供了 score,它在游戏结束时根据玩家手里余下的牌计算罚分:

  1. public int score() {
  2. int sum = 0;
  3. for (int i = 0; i < hand.size(); i++) {
  4. Card card = hand.getCard(i);
  5. int rank = card.getRank();
  6. if (rank == 8) {
  7. sum -= 20;
  8. } else if (rank > 10) {
  9. sum -= 10;
  10. } else {
  11. sum -= rank;
  12. }
  13. }
  14. return sum;
  15. }