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

推荐订阅源

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-07-25 · via 博客园 - 枫

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

最近做翻译做的头疼,疼过之余,想想之前公司内组织的三国杀开发兴趣小组在三国杀开发问题上几乎又停滞了。于是又翻出来搞了搞,这次却搞的有点像模像样了,特地把思路和方法都共享出来,一起学习。

三国杀在上海是挺风靡的,如果你还不知道玩法和规则,请猛击这里

今天要说的是实现的第一步。为了尽量简化需求,我们最初要实现的东西也挺简单,就是能支持两个玩家自动对战。具体的描述如下:在一个场景中设置两个玩家,游戏的牌堆中只有三种基本牌:杀、闪、桃。其中,只有杀和桃是属于主动性游戏牌,即可以在自己行动回合将其打出;闪是被动性游戏牌,只有当别人对自己出杀的时候才可以出闪,否则扣除一点体力,而使用桃则为自己增加一点体力。同样,为了简化实现,只要有能使用的牌,就必须使用;而且,如果你的手牌数量大于体力值,则需要弃牌直到手牌数与体力值相等。在这种情况下,只要有一方体力为0,游戏结束!

对需求进行整理,不难发现有以下需求待实现:

1、游戏结束的条件:只要有玩家死亡即宣告结束。

2、牌堆的实现,注意牌堆中拿出的牌需要从牌堆中移除,以及洗牌的功能。

3、杀、闪、挑的逻辑实现。

4、从手牌中计算是否还有可用的牌。

5、玩家轮询行动的实现。

在设计中,我的思路是这样的:一局游戏实际都在一个场景中进行,直到游戏结束。因此首先有场景的定义:

/// <summary>
/// 表示游戏场景。
/// </summary>
public class Scene
{
    
private readonly Player[] players;
}

其中场景中定义了游戏玩家,因为场景中的游戏玩家在场景生成之后就固定了,所以使用了readonly。

同样,游戏实际是个循环,结束的条件就是有玩家死亡。因此,先定义玩家死亡的条件:

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

这样,由于其中引用到了Player类,因此,建立玩家类,来对其按照需求进行设计。代码如下:

Player

    /// <summary>
    
/// 表示游戏中的玩家。
    
/// </summary>
    public class Player
    {
        
private readonly List<GameCard> handCards = new List<GameCard>(20);public Player(string name, byte maxHp)
        {
            
this.Name = name;
            
this.Hp = maxHp;
            
this.MaxHp = maxHp;
        }
/// <summary>
        
/// 表示该玩家的名称。
        
/// </summary>
        public string Name { getprivate set; }/// <summary>
        
/// 表示该玩家是否已经死亡。
        
/// </summary>
        public bool IsDead
        {
            
get { return Hp == 0; }
        }
/// <summary>
        
/// 表示该玩家所选武将的当前HP.
        
/// </summary>
        public byte Hp { getprivate set; }/// <summary>
        
/// 表示该玩家所选武将的最大HP.
        
/// </summary>
        public byte MaxHp { getprivate set; }
    }

其中的handCards表示玩家手中可以拿的手牌数量,这里设定上限为20张。那么同样要开始定义游戏卡牌,代码如下:

GameCard

    /// <summary>
    
/// 表示游戏中用作游戏的卡牌。
    
/// </summary>
    public abstract class GameCard
    {
        
/// <summary>
        
/// 表示牌的花色。
        
/// </summary>
        public CardMark Mark { getprotected set; }/// <summary>
        
/// 表示牌的大小。
        
/// </summary>
        public CardValue Value { getprotected set; }/// <summary>
        
/// 表示牌的名称。
        
/// </summary>
        public string Name { getprotected set; }/// <summary>
        
/// 对目标玩家使用卡牌。
        
/// </summary>
        
/// <param name="source">使用卡牌的源对象。</param>
        
/// <param name="target">使用卡牌的目标对象。</param>
        public abstract void Use(Player source, Player target);
    }

直到现在,所需要的定义已经基本完成。这其中的代码有很多不规范的地方,之所以展现出来,也是为了表现自己的思维过程,在后面会有很多对目前代码的重构。

在这样定义完了之后,下一步将开始仔细分析流程,按照流程先写出最初能运行的版本。(未完待续...)