惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

H
Help Net Security
博客园 - Franky
GbyAI
GbyAI
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
爱范儿
爱范儿
IT之家
IT之家
酷 壳 – CoolShell
酷 壳 – CoolShell
aimingoo的专栏
aimingoo的专栏
博客园_首页
MongoDB | Blog
MongoDB | Blog
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Recent Announcements
Recent Announcements
Scott Helme
Scott Helme
有赞技术团队
有赞技术团队
M
MIT News - Artificial intelligence
C
CERT Recently Published Vulnerability Notes
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
Jina AI
Jina AI
F
Fortinet All Blogs
N
Netflix TechBlog - Medium
L
LangChain Blog
L
LINUX DO - 最新话题
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
H
Hacker News: Front Page
MyScale Blog
MyScale Blog
P
Palo Alto Networks Blog
G
Google Developers Blog
Google DeepMind News
Google DeepMind News
AI
AI
T
Troy Hunt's Blog
Microsoft Azure Blog
Microsoft Azure Blog
阮一峰的网络日志
阮一峰的网络日志
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Vercel News
Vercel News
Microsoft Security Blog
Microsoft Security Blog
罗磊的独立博客
S
Secure Thoughts
大猫的无限游戏
大猫的无限游戏
博客园 - 叶小钗
人人都是产品经理
人人都是产品经理
Blog — PlanetScale
Blog — PlanetScale
博客园 - 司徒正美
Apple Machine Learning Research
Apple Machine Learning Research
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园 - 三生石上(FineUI控件)
S
Security @ Cisco Blogs
Cloudbric
Cloudbric
E
Exploit-DB.com RSS Feed
Attack and Defense Labs
Attack and Defense Labs

博客园 - 枫

2015半年记 再写一帖~就《离开上海》一文再说明 再见,上海~非主流码农在上海的9年心路历程 Mac下配置mysql-python 《Rework》摘录读后随感 Event Sourcing与大数据 无题(1) 在Mac上安装Hadoop [原创]一步一步用C#编写三国杀(二):牌堆的设计 [原创]一步一步用C#编写三国杀(一):规则和需求描述 走进单元测试(3):消灭HttpContext的依赖,兼谈单元测试的设计辅助性 走进单元测试(2):必须要自动化 我也想对广大程序员说一些话 走进单元测试(1):为什么难以广泛应用? 高级语言发展之回归人类思维——听老赵的Session有感 缺乏自信怎么办? 梦话对象之三:三要素的差异与统一 梦话对象之二:事件之无限扩展 梦话对象之一:逃不开的生死问题
[原创]一步一步用C#编写三国杀(三):设计流程
· 2010-08-04 · via 博客园 - 枫

原创文章,转载请保留作者署名!

前面已经说了牌堆的设计,那么现在就正式进入流程,满足我们在(一)中所说的需求。

由于在(二)中已经说了要维护扩展,因此对于之前定义的Scene,则需要定义一个所选择的扩展包,代码如下:

扩展包

        private readonly IPackage[] selectedPackages;/// <summary>
        
/// 初始化新的<see cref="Scene"/>类的实例。
        
/// </summary>
        
/// <param name="packages">所要加载的包。</param>
        public Scene(IEnumerable<IPackage> packages)
        {
            players[currentToken].HasToken 
= true;
            selectedPackages 
= packages.ToArray();
        }

由于玩家是轮动的,因此设定一个令牌,只有持有令牌的玩家才能行动。

private int currentToken;

那么定义一个Start方法,开始游戏循环。

首先要根据选择的扩展包生成游戏牌堆。对于游戏牌堆,由于我们之前已经定义好了牌堆基类,因此实现就比较简单了,将扩展包中的游戏牌载入并洗牌即可。

游戏牌堆

    /// <summary>
    
/// 表示游戏牌牌堆。
    
/// </summary>
    public sealed class GameCardHeap : CardHeap<GameCard>
    {
        
/// <summary>
        
/// 初始化新的<see cref="GameCardHeap"/>类的实例。
        
/// </summary>
        
/// <param name="packages">所要加载的扩展包。</param>
        public GameCardHeap(IEnumerable<IPackage> packages)
        {
            
foreach (var package in packages)
            {
                ((List
<GameCard>) Items).AddRange(package.GameCards);
            }
            Items.Shuffle();
        }
    }

 回头看我们上面的Start方法,在牌堆创建后,就进入了流程循环,还是直接来代码吧,注释都写的蛮清楚的

流程循环

        /// <summary>
        
/// 开始游戏。
        
/// </summary>
        public void Start()
        {
            Player currentPlayer;
            GameCardHeap heap 
= new GameCardHeap(selectedPackages);  // 创建牌堆

            
while(true)
            {
                currentPlayer 
= players[currentToken];  // 设置当前有令牌的玩家// 摸牌阶段
                GameCard[] newCards = heap.Pop(2true);
                currentPlayer.Draw(newCards);
// 出牌阶段
                while(currentPlayer.HasPlayableCard)
                {
                    
// NOTE:为了简单,先实现只杀下家,并只使用杀、闪、桃
                    int nextToken = currentToken == players.Length - 1 ? 0 : currentToken + 1;
                    currentPlayer.Play(players[nextToken], currentPlayer.FirstPlayableCard);
if (IsGameEnds())
                        
goto label;
                }
// 弃牌阶段
                
// NOTE:为了简单,先实现只弃从头开始的牌到当前体力值
                int disCardCount = currentPlayer.HandCards.Length - currentPlayer.Hp;
                
if (disCardCount > 0)
                {
                    GameCard[] removeCards 
= currentPlayer.HandCards.Take(disCardCount).ToArray();
                    currentPlayer.Discard(removeCards);
                }
// 将令牌给下一个人
                GiveTokenToNext();
            }
            label:
            Console.WriteLine(
"游戏结束!");
        }

这里使用了一个死循环,但在游戏结束的时候使用goto语句跳出循环。所涉及到的一些方法如下:

一些辅助方法

        private void GiveTokenToNext()
        {
            
if (currentToken == players.Length - 1)
                currentToken 
= 0;
            
else
                currentToken
++;

            players[currentToken].HasToken 

= true;
        }
private bool IsGameEnds()
        {
            
return players.Any(p => p.IsDead);  // 如果选择到IsDead的Player,游戏结束
        }

注意,流程的设计中,由于玩家是在游戏逻辑边界内的,因此采用了主动的做法来进行设计。这样对于程序来说,我只要去考虑玩家的摸牌、出牌和弃牌所引起的各种变化即可。