# 2.3 纸牌游戏

## 2.3.1 问题描述

设有两个玩家PA和PB，他们玩一副具有$N(N<10)$个不同面值的扑克牌，每个面值有两张牌。

玩法1：顺序抓牌顺序出牌。

第一步，发牌。将扑克牌均分成两份，玩家PA、PB各得一份，或轮流抓牌各得一半牌。牌按得牌顺序前后有序。

第二步，玩牌。当双方手中都有牌时，双方依得牌顺序交替出牌，设出牌面值为X，重复下列操作。

1. 如果桌面上没有与X相同面值的牌，将牌X放到牌桌上且压在已有牌的上方。
2. 如果桌面上有与X相同面值的牌，出牌人赢牌，执行下列操作。
    1. 把出的牌X添加到牌尾。
    2. 把桌面上的牌直到面值为X的牌依次添加到出牌人的牌尾。

第三步，赢家。如果有一方玩家手中无牌，游戏结束，无牌的玩家为输家，有牌的玩家为赢家。

第四步，摊牌。输出赢家手中的牌和桌上的牌。

玩法2：玩家1依得牌顺序出牌，玩家2随意出牌。

此玩法中，显然玩家1的玩法与玩法1相同，顺序出牌，顺序将赢的牌插人牌尾；而玩家2可以根据赢的可能性出牌。

## 2.3.2 分析与设计提示

1. 牌的信息  
    牌只有牌面值一个信息。玩家和桌上均有若干张牌，可以分别用整型数组表示。

2. 功能设计  
    该任务的完成主要涉及以下功能：
    1. 发牌。
    2. 玩法1。
    3. 玩法2。
    4. 摊牌。

3. 存储设计  
    对于玩法1的设计如下。
    1. 玩家手中的牌是先抓到的牌先出，赢的牌添加在牌尾，具有“先来先服务”特性，可以用队列表示。
    2. 桌上的牌是后出的牌压在先出牌的上面，可以用栈存储。
    3. 由于牌总数可知，所以队列和栈均可用顺序存储。

    对于玩法2的设计如下。
    1. 与玩法1相同的理由，玩家1手中的牌用顺序队列存储；桌上的牌是后出的牌压在先出牌的上面，用顺序栈存储。
    2. 玩家2手中的牌没有出牌顺序要求，采用链表较好。

4. 算法设计  
    1. 发牌。  
    通过初始化或随机数，为两个玩家分牌。
    2. 玩法1。  
    设队列QA和QB分别表示玩家PA和玩家PB手中的牌，堆栈S表示桌上的牌。设玩家PA先出牌，根据玩法，玩牌的操作如下。  
        **Step 1** 只要QA和QB均不空，重复下列操作。  
        1. 取QA队队头元素pa.
        2. 如果堆栈中有值等于PA的牌sa。
            1. pa入QA队尾。
            2. sa前的元素依次出栈、入队列QA，sa出栈入队列QA。
        3. 如果堆栈中没有值等于pa的牌，pa入栈。

        **Step 2** 只要QA和QB中有一个为空队，进行下列操作。
        1. 空队列的玩家为输家。
        2. 显示赢家手中的牌信息及桌上牌信息。
        3. 游戏结束。
    3. 玩法2。  
    为了减少对方赢的可能，需要一些策略，如不出对方有的牌；出手中成对的牌，以便能收回等。请自行从实际中总结经验，决定出牌策略。
    4. 摊牌。  
    赢家手中的牌，对于玩法1，依次出队输出；对于玩法2，遍历线性表输出。桌上的牌，依次出栈并输出。

## 2.3.3 性能要求

本系统的性能要求如下。

1. 展示玩家得牌信息。
2. 展示玩牌中出牌和赢牌信息。
3. 思考以复杂度$O(1)$判断桌上是否有当前出的牌。
4. 多组数据测试，说明玩法1是否一定会产生赢家。
5. 多组数据测试，说明自行出牌的玩家是否一定能赢。
6. 牌的点数不超过10。
