[原創]一步一步用C#編寫三國殺(二):牌堆的設計

來源:互聯網
上載者:User

原創文章,轉載請保留作者署名!

 

前一節說到了一些基礎性的定義。這一節開始將進入流程的分析。

 

首先,在遊戲的情境建立之後,你就必須有一個牌堆。對於目前的需求來說,只要有手牌的牌堆即可;儘管後面可能還要有身份牌堆和武將牌堆,但目前只考慮手牌,即遊戲牌。於是有以下定義:

 

    /// <summary>
    /// 定義牌堆的基本類型。
    /// </summary>
    /// <typeparam name="T">參數類型。</typeparam>
    public abstract class CardHeap<T> : Collection<T>
    {

    }

 

 

 定義為抽象的,是我希望能提供一些通用的方法以簡化其他牌堆的設計。

 

對於牌堆來說,其一個重要的功能就是能夠壓出牌以供使用,因此定義如下:

 

壓牌

        /// <summary>
        /// 從牌堆中壓出指定數量的牌,這些牌將會從牌堆中移除。
        /// </summary>
        /// <param name="number">要壓出的牌的數量。</param>
        /// <returns>所壓出的牌的數組。</returns>
        public T[] Pop(int number)
        {
            if (number <= 0)
                return new T[0];

            if (Items.Count < number)
                number = Items.Count;

            T[] newT = new T[number];
            for (int i = 0; i < number; i++)
            {
                newT[i] = Items.First();
                Items.RemoveAt(0);
            }

            return newT;
        }

 

 

牌堆定義之後就需要定義洗牌的操作。由於我定義了從Collection<T> 繼承,其內部有個IList<T>類型的Items屬性,因此編寫一個擴充方法,對IList<T>類型的資料進行類似洗牌的操作:

 

洗牌擴充

    /// <summary>
    /// 定義對List的擴充方法。
    /// </summary>
    public static class ListExtension
    {
        /// <summary>
        /// 將IList中的元素進行洗牌操作。
        /// </summary>
        /// <typeparam name="T">型別參數。</typeparam>
        /// <param name="list">所要洗牌的List。</param>
        public static void Shuffle<T>(this IList<T> list)
        {
            Random random = new Random();
            int count = list.Count;

            for (int i = 0; i < count; i++)
            {
                int currentIndex = random.Next(0, count - i);
                T tempCard = list[currentIndex];
                list[currentIndex] = list[count - 1 - i];
                list[count - 1 - i] = tempCard;
            }
        }
    }

 

 

很明顯,只要遊戲沒有結束,牌堆中拿出使用過的廢牌總要回收進行迴圈利用,所以廢牌要儲存起來,並讓牌堆支援其中的Items的重生。因此CardHeap中便多了如下定義:

 

牌堆重生

        private readonly IList<T> usedItems = new List<T>();

        private void ReCreate()
        {
            // 將usedItems的牌還原到Items中,並進行洗牌,然後清空usedItems
            ((List<T>) Items).AddRange(usedItems);
            usedItems.Clear();
            Items.Shuffle();            
        }

 

 

既然多了usedItems,那麼上面定義的Pop就需要有個重載,以指定牌堆是否可以進行重生,所以重構上面的Pop方法,改為重載:

 

重載Pop

        /// <summary>
        /// 從牌堆中壓出指定數量的牌,這些牌將會從牌堆中移除。如果牌堆的牌數量不夠,則只返回牌堆中剩餘的牌。
        /// </summary>
        /// <param name="number">要壓出的牌的數量。</param>
        /// <returns>所壓出的牌的數組。</returns>
        public T[] Pop(int number)
        {
            return Pop(number, false);
        }

        /// <summary>
        /// 從牌堆中壓出指定數量的牌,這些牌將會從牌堆中移除。
        /// </summary>
        /// <param name="number">要壓出的牌的數量。</param>
        /// <param name="recreateHeap">在壓出牌數量不夠的時候是否重新建立牌堆。</param>
        /// <returns>所壓出的牌的數組。</returns>
        public T[] Pop(int number, bool recreateHeap)
        {
            if (number <= 0)
                return new T[0];

            if (Items.Count < number && !recreateHeap)
                number = Items.Count;

            T[] newT = new T[number];
            for (int i = 0; i < number; i++)
            {
                if (recreateHeap && Items.Count == 0)
                {
                    ReCreate();
                }

                newT[i] = Items.First();
                Items.RemoveAt(0);
                usedItems.Add(newT[i]);
            }

            return newT;
        }

 

 

這樣,牌堆的定義就算基本完成了。但在此基礎上考慮考慮擴充包的問題。實際上擴充包主要是牌的擴充,而且在設計初期,就已經考慮將標準版的牌從這個Core中分離,即除了基本牌的殺、閃、桃之外,錦囊和裝備、武將都是由擴充包來提供。因此定義了個擴充包的介面:

 

擴充包介面

    /// <summary>
    /// 定義擴充包所必須實現的介面。
    /// </summary>
    public interface IPackage
    {
        /// <summary>
        /// 擴充包中的遊戲牌。
        /// </summary>
        GameCard[] GameCards { get; }
    }

 

 

好,牌堆的設計就說到這裡,後面就定義實際的基本牌,並將進入實際流程迴圈。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.