赛博斗地主——使用大语言模型扮演Agent智能体玩牌类游戏。
<p>通过大模型来实现多个智能体进行游戏对局这个想对已经比较成熟了无论是去年惊艳的斯坦福小镇还是比如metaGPT或者类似的框架都是使用智能体技术让大模型来操控,从而让大模型跳出自身“预测下一个token”的文字功能去探索更多的应用落地可能性。不过一直没有真正操作过,直到前段时间看到一个新闻《和GPT-4这些大模型玩狼人杀,人类因太蠢被票死,真·反向图灵测试》决定自己来玩一下。</p><p>斗地主是一款国人比较熟悉的棋牌游戏,考虑到这个游戏受众群体,所以基础大模型使用国产的通义千问提供的API接口(GPT4太贵用不起)。通过阿里云百炼大模型平台即可简单注册并申请使用:https://bailian.console.aliyun.com/</p>
<p>接着就是整体框架设计,其实整个游戏设计比较简单,随机发牌->随机定义一个玩家作为地主并发出尾牌(由于主要是模拟大模型使用Agent的玩牌所以这里就不加入抢地主环节了)->从地主开始玩家轮流出牌->谁的牌出完根据其角色决定是地主胜利还是农民胜利。</p>
<p>游戏整体使用c#编程,游戏主要的处理逻辑就是检测AI出牌的合法性,包括AI出牌是否是当前智能体的持有的手牌、牌型是否正确(单排/连子/对子/顺子/三带一/炸弹),出的牌是否可以压住上一轮玩家的牌等等逻辑。核心的部分如下:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">public</span> (CardsType, <span style="color: rgba(0, 0, 255, 1)">int</span>[]) GetCardsType(<span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)">[] Cards)
{
</span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)">
{
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (Cards.Length == <span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> (CardsType.单牌, GetCardsNumber(Cards));
</span><span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(0, 0, 255, 1)">if</span> (Cards.Length == <span style="color: rgba(128, 0, 128, 1)">2</span><span style="color: rgba(0, 0, 0, 1)">)
{
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (Cards.OrderBy(x => x).SequenceEqual(<span style="color: rgba(0, 0, 255, 1)">new</span> List<<span style="color: rgba(0, 0, 255, 1)">string</span>>() { <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">小王</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">大王</span><span style="color: rgba(128, 0, 0, 1)">"</span> }.OrderBy(x =><span style="color: rgba(0, 0, 0, 1)"> x)))
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> (CardsType.炸弹, GetCardsNumber(Cards));
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (Cards.Select(ReplaceColor).Distinct().Count() == <span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> (CardsType.对子, GetCardsNumber(Cards));
</span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span> Exception(<span style="color: rgba(128, 0, 0, 1)">""</span><span style="color: rgba(0, 0, 0, 1)">);
}
</span><span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(0, 0, 255, 1)">if</span> (Cards.Length == <span style="color: rgba(128, 0, 128, 1)">4</span><span style="color: rgba(0, 0, 0, 1)">)
{
</span><span style="color: rgba(0, 0, 255, 1)">var</span> groupCards = Cards.Select(ReplaceColor).GroupBy(x => x).OrderByDescending(x =><span style="color: rgba(0, 0, 0, 1)"> x.Count()).ToList();
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">三带一</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> (groupCards.Count == <span style="color: rgba(128, 0, 128, 1)">2</span> && groupCards[<span style="color: rgba(128, 0, 128, 1)">0</span>].Count() == <span style="color: rgba(128, 0, 128, 1)">3</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">return</span> (CardsType.三带一, GetCardsNumber(groupCards[<span style="color: rgba(128, 0, 128, 1)">0</span>].ToArray()));<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">三带一只需要看三张牌的大小即可
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">炸弹</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> (groupCards.Count == <span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> (CardsType.炸弹, GetCardsNumber(Cards));
</span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span> Exception(<span style="color: rgba(128, 0, 0, 1)">""</span><span style="color: rgba(0, 0, 0, 1)">);
}
</span><span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(0, 0, 255, 1)">if</span> (Cards.Length >= <span style="color: rgba(128, 0, 128, 1)">5</span><span style="color: rgba(0, 0, 0, 1)">)
{
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">检测是否是顺子</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> (Cards.Length == <span style="color: rgba(128, 0, 128, 1)">6</span><span style="color: rgba(0, 0, 0, 1)">)
{
</span><span style="color: rgba(0, 0, 255, 1)">var</span> groupCards = Cards.Select(ReplaceColor).GroupBy(x => x).OrderByDescending(x =><span style="color: rgba(0, 0, 0, 1)"> x.Count()).ToList();
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (groupCards.Count == <span style="color: rgba(128, 0, 128, 1)">3</span> && groupCards.All(x => x.Count() == <span style="color: rgba(128, 0, 128, 1)">2</span><span style="color: rgba(0, 0, 0, 1)">))
</span><span style="color: rgba(0, 0, 255, 1)">return</span> (CardsType.顺子, GetCardsNumber(groupCards[<span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">].ToArray()));
}
</span><span style="color: rgba(0, 0, 255, 1)">var</span> cardsnumber =<span style="color: rgba(0, 0, 0, 1)"> GetCardsNumber(Cards);
</span><span style="color: rgba(0, 0, 255, 1)">int</span>? currItem = <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">foreach</span> (<span style="color: rgba(0, 0, 255, 1)">var</span> item <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> cardsnumber)
{
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (currItem == <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">)
currItem </span>=<span style="color: rgba(0, 0, 0, 1)"> item;
</span><span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(0, 0, 255, 1)">if</span> (currItem + <span style="color: rgba(128, 0, 128, 1)">1</span> !=<span style="color: rgba(0, 0, 0, 1)"> item)
</span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span> Exception(<span style="color: rgba(128, 0, 0, 1)">""</span><span style="color: rgba(0, 0, 0, 1)">);
}
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> (CardsType.连子, cardsnumber);
}
</span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span> Exception(<span style="color: rgba(128, 0, 0, 1)">""</span><span style="color: rgba(0, 0, 0, 1)">);
}
</span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (Exception e)
{
</span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span> Exception($<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">当所选牌型无效,牌型只能是[{string.Join(</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">, Enum.GetNames(typeof(CardsType)))}],请检查你的牌型</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
}
}</span></pre>
</div>
<p>以及玩牌部分的核心逻辑:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> Play(<span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)">[] Cards)
{
</span><span style="color: rgba(0, 0, 255, 1)">var</span> currPlayer =<span style="color: rgba(0, 0, 0, 1)"> GetCurrnetPlayer();
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (Cards == <span style="color: rgba(0, 0, 255, 1)">null</span> || Cards.Length == <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">)
{
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (!GameRecords.Any(x => x.Player != <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">))
{
</span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span> Exception(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">当前你是地主,必须进行出牌</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
}
</span><span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(0, 0, 255, 1)">if</span> (GameRecords.Last(x => x.Player != <span style="color: rgba(0, 0, 255, 1)">null</span> && x.Cards.Any()).Player.Name ==<span style="color: rgba(0, 0, 0, 1)"> currPlayer.Name)
{
</span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span> Exception(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">上一轮你出牌后其他玩家都过了,本轮该你进行出牌(可以考虑出小牌)</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
}
GameRecords.Add(</span><span style="color: rgba(0, 0, 255, 1)">new</span> GameRecordInfo() { Player = currPlayer, GameRecordText = $<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">玩家名:{currPlayer.Name},角色:{currPlayer.Role},本轮没有出牌</span><span style="color: rgba(128, 0, 0, 1)">"</span>, CardsType = <span style="color: rgba(0, 0, 255, 1)">null</span>, Cards =<span style="color: rgba(0, 0, 0, 1)"> Cards });
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">;
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">首先检查出牌是否在手牌中</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> (IsSubsetWithFrequency(Cards, currPlayer.HandCards.ToArray(), <span style="color: rgba(0, 0, 255, 1)">out</span> <span style="color: rgba(0, 0, 255, 1)">var</span><span style="color: rgba(0, 0, 0, 1)"> missingCards))
{
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">检查最后一个牌组的情况</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> (GameRecords.Any(x => x.Player != <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">))
{
</span><span style="color: rgba(0, 0, 255, 1)">var</span> last = GameRecords.Last(x => x.Player != <span style="color: rgba(0, 0, 255, 1)">null</span> &&<span style="color: rgba(0, 0, 0, 1)"> x.Cards.Any());
</span><span style="color: rgba(0, 0, 255, 1)">var</span> lastcardstype =<span style="color: rgba(0, 0, 0, 1)"> GetCardsType(last.Cards);
</span><span style="color: rgba(0, 0, 255, 1)">var</span> cardstype =<span style="color: rgba(0, 0, 0, 1)"> GetCardsType(Cards);
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (last.Player.Name !=<span style="color: rgba(0, 0, 0, 1)"> currPlayer.Name)
{
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (lastcardstype.Item1 != cardstype.Item1 && cardstype.Item1 !=<span style="color: rgba(0, 0, 0, 1)"> CardsType.炸弹)
{
</span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span> Exception($<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">无效出牌,上一轮的牌型是{lastcardstype.Item1},你必须使用相同牌型出牌</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">相同牌型则检测大小</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> (cardstype.Item1 == CardsType.单牌 || cardstype.Item1 == CardsType.对子 || cardstype.Item1 == CardsType.顺子 || cardstype.Item1 ==<span style="color: rgba(0, 0, 0, 1)"> CardsType.炸弹)
{
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (lastcardstype.Item2[<span style="color: rgba(128, 0, 128, 1)">0</span>] >= cardstype.Item2[<span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">])
</span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span> Exception($<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">无效出牌,你的出牌:[{string.Join(</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">, Cards)}]必须比上一轮出牌:[{string.Join(</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">, last.Cards)}]更大才行</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
}
</span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)">
{
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">连子的情况需要检测两个牌张数一致和最小长大于对方</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> (lastcardstype.Item2.Length !=<span style="color: rgba(0, 0, 0, 1)"> cardstype.Item2.Length)
</span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span> Exception($<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">无效出牌,由于本轮出牌是连子所以你的出牌数:[{Cards.Length}]必须和一轮出牌数:[{last.Cards.Length}]一致</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (lastcardstype.Item2[<span style="color: rgba(128, 0, 128, 1)">0</span>] >= cardstype.Item2[<span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">])
</span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span> Exception($<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">无效出牌,你的出牌:[{string.Join(</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">, Cards)}]必须比上一轮出牌:[{string.Join(</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">, last.Cards)}]更大才行</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
}
}
}
}
</span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)">
{
</span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span> Exception($<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">无效出牌,原因:{missingCards}。请重新出牌</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
}
GameRecords.Add(</span><span style="color: rgba(0, 0, 255, 1)">new</span> GameRecordInfo() { Player = currPlayer, GameRecordText = $<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">玩家名:{currPlayer.Name},角色:{currPlayer.Role},本轮出牌:[{string.Join(</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">, Cards)}],牌型:{GetCardsType(Cards).Item1}</span><span style="color: rgba(128, 0, 0, 1)">"</span>, CardsType = GetCardsType(Cards).Item1, Cards =<span style="color: rgba(0, 0, 0, 1)"> Cards });
Players.HandCards.RemoveAll(x </span>=> Cards.Select(x =><span style="color: rgba(0, 0, 0, 1)"> x.ToLower()).Contains(x.ToLower()));
}</span></pre>
</div>
<p>接着就是一些游戏状态管理,包括初始化牌组、分派给三个玩家手牌,玩家自身的手牌管理等等这里就不一一赘述了,这里主要讲一下基于阿里千问大模型如何设计Agent代理的部分。在阿里百炼上,可以查看模型的调用示例,这里我们选择阿里目前最大的千亿参数大模型千问-MAX,进入调用示例就可以看到类似如下示例代码(如果你喜欢SDK则可以选择python和java的包。如果是其他语言则只有自己手写http请求调用):</p>
<p><img src="https://img2024.cnblogs.com/blog/198579/202406/198579-20240605161250913-257284993.png"></p>
<p> 调用的部分比较简单,就是一个httpclient的封装,以及对调用入参和出参DTO的实体定义:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> ApiClient
{
</span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">readonly</span><span style="color: rgba(0, 0, 0, 1)"> HttpClient _httpClient;
</span><span style="color: rgba(0, 0, 255, 1)">public</span> ApiClient(<span style="color: rgba(0, 0, 255, 1)">string</span> baseUrl, <span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)"> apiKey)
{
_httpClient </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> HttpClient
{
BaseAddress </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Uri(baseUrl)
};
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 配置HttpClient实例</span>
_httpClient.DefaultRequestHeaders.Authorization = <span style="color: rgba(0, 0, 255, 1)">new</span> AuthenticationHeaderValue(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Bearer</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, apiKey);
_httpClient.DefaultRequestHeaders.Accept.Add(</span><span style="color: rgba(0, 0, 255, 1)">new</span> MediaTypeWithQualityHeaderValue(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">application/json</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">));
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">async</span> Task<ApiResponse> PostAsync(<span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)"> resource, TextGenerationRequest request)
{
</span><span style="color: rgba(0, 0, 255, 1)">var</span> jsonData = JsonSerializer.Serialize(request, <span style="color: rgba(0, 0, 255, 1)">new</span> JsonSerializerOptions { PropertyNamingPolicy =<span style="color: rgba(0, 0, 0, 1)"> JsonNamingPolicy.CamelCase });
</span><span style="color: rgba(0, 0, 255, 1)">using</span> <span style="color: rgba(0, 0, 255, 1)">var</span> content = <span style="color: rgba(0, 0, 255, 1)">new</span> StringContent(jsonData.ToLower(), Encoding.UTF8, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">application/json</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">var</span> response = <span style="color: rgba(0, 0, 255, 1)">await</span><span style="color: rgba(0, 0, 0, 1)"> _httpClient.PostAsync(resource, content);
</span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (response.IsSuccessStatusCode)
{
</span><span style="color: rgba(0, 0, 255, 1)">var</span> responseContent = <span style="color: rgba(0, 0, 255, 1)">await</span><span style="color: rgba(0, 0, 0, 1)"> response.Content.ReadAsStringAsync();
</span><span style="color: rgba(0, 0, 255, 1)">var</span> options = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> JsonSerializerOptions
{
PropertyNameCaseInsensitive </span>= <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 忽略大小写</span>
<span style="color: rgba(0, 0, 0, 1)"> };
</span><span style="color: rgba(0, 0, 255, 1)">return</span> JsonSerializer.Deserialize<ApiResponse><span style="color: rgba(0, 0, 0, 1)">(responseContent, options);
}
</span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)">
{
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 错误处理</span>
<span style="color: rgba(0, 0, 255, 1)">var</span> errorContent = <span style="color: rgba(0, 0, 255, 1)">await</span><span style="color: rgba(0, 0, 0, 1)"> response.Content.ReadAsStringAsync();
</span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span> Exception($<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">API 请求失败: {response.StatusCode}, {errorContent}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
}
}
}</span></pre>
</div>
<p>接着就是比较关键的部分,即入参的定义,这决定了大模型如何调用智能体的关键,这里面其实主要还是编写特定的prompt让大模型知道自己要干嘛。由于是斗地主游戏,所以这里我们需要在系统提示词中编写一些关于斗地主的基本游戏规则、不同角色可以采取的常规游戏策略,游戏当前的对局情况。接着在用户提示词中需要告知大模型扮演智能体的角色、持有的手牌,可以调取的游戏函数。其中游戏函数比较关键,这也是大模型唯一可以让游戏“动起来”的方式。以下是我定义的关于斗地主游戏的请求入参:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">TextGenerationRequest GetNowReq()
{
</span><span style="color: rgba(0, 0, 255, 1)">var</span> userprompt = <span style="color: rgba(128, 0, 0, 1)">""</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (game.GameRecords.Where(x => x.Player != <span style="color: rgba(0, 0, 255, 1)">null</span>).Count() == <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">)
{
userprompt </span>= $<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">现在是第一轮,你是{game.GetCurrnetPlayer().Name},你的角色是:{game.GetCurrnetPlayer().Role}请先出牌(如果单牌较少可以考虑尽可能出顺子、连子、三带一或者对子,如果单牌较多则优先考虑出单牌)\r\n手持牌组:{game.GetCurrnetPlayerHandCards()}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
}
</span><span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(0, 0, 255, 1)">if</span> (game.GameRecords.Any(x => x.Player != <span style="color: rgba(0, 0, 255, 1)">null</span>) && game.GameRecords.Last(x => x.Player != <span style="color: rgba(0, 0, 255, 1)">null</span> && x.Cards.Any()).Player.Name ==<span style="color: rgba(0, 0, 0, 1)"> game.GetCurrnetPlayer().Name)
{
userprompt </span>= $<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">你是{game.GetCurrnetPlayer().Name},你的角色是:{game.GetCurrnetPlayer().Role}。上一轮其他玩家都过了你的牌,请你出牌(如果单牌较少可以考虑尽可能出顺子、连子、三带一或者对子,如果单牌较多则优先考虑出单牌)\r\n手持牌组:{game.GetCurrnetPlayerHandCards()}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
}
</span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)">
{
userprompt </span>= $<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">你是{game.GetCurrnetPlayer().Name},你的角色是:{game.GetCurrnetPlayer().Role}。请出牌(如果单牌较少可以考虑尽可能出顺子、连子、三带一或者对子,如果单牌较多则优先考虑出单牌),或者选择本轮不出牌(当你的手牌都小于最后的出牌或者上一轮出牌的玩家是同组玩家时可以不出牌)\r\n手持牌组:{game.GetCurrnetPlayerHandCards()}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
}
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> TextGenerationRequest
{
Model </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">qwen-max</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
Input </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> InputData
{
Messages </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> List<Message><span style="color: rgba(0, 0, 0, 1)">
{
</span><span style="color: rgba(0, 0, 255, 1)">new</span> Message { Role = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">system</span><span style="color: rgba(128, 0, 0, 1)">"</span>, Content = $<span style="color: rgba(128, 0, 0, 1)">"""
</span><span style="color: rgba(0, 0, 0, 1)"> 你正在参与一场斗地主游戏,
#游戏规则
参与游戏的玩家由一个地主和两个农民组成,如果你是地主,你需要出掉所有的牌才能获得胜利。如果你是农民,你和你的队友任意一人出完所有的牌即可获胜。
可以出单牌、【对子】(两张相同数字的牌,如:[</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♥3</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♣3</span><span style="color: rgba(128, 0, 0, 1)">"</span>])、【连子】(从小到大顺序数字的牌5张起出,如:[<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♥4</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♣5</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♦6</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♣7</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♥8</span><span style="color: rgba(128, 0, 0, 1)">"</span>])、【顺子】(三个连起来的对子,如:[<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♥9</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♣9</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♦10</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♣10</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♣j</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♥j</span><span style="color: rgba(128, 0, 0, 1)">"</span>])、【三带一】(三张相同数字的牌+一张任意单牌,如:[<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♥4</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♣4</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♦4</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♣6</span><span style="color: rgba(128, 0, 0, 1)">"</span>])、【炸弹】(四个相同数字的牌或者双王,如:[<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♥4</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♣4</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♦4</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♣4</span><span style="color: rgba(128, 0, 0, 1)">"</span>]或者[<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">小王</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">大王</span><span style="color: rgba(128, 0, 0, 1)">"</span>]),牌从小到大顺序:<span style="color: rgba(128, 0, 128, 1)">3</span>,<span style="color: rgba(128, 0, 128, 1)">4</span>,<span style="color: rgba(128, 0, 128, 1)">5</span>,<span style="color: rgba(128, 0, 128, 1)">6</span>,<span style="color: rgba(128, 0, 128, 1)">7</span>,<span style="color: rgba(128, 0, 128, 1)">8</span>,<span style="color: rgba(128, 0, 128, 1)">9</span>,<span style="color: rgba(128, 0, 128, 1)">10</span>,j,q,k,a,<span style="color: rgba(128, 0, 128, 1)">2</span><span style="color: rgba(0, 0, 0, 1)">,小王,大王。
每一轮出牌必须【大于】对方的出牌,并且必须和对方牌型一致[{</span><span style="color: rgba(0, 0, 255, 1)">string</span>.Join(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">,</span><span style="color: rgba(128, 0, 0, 1)">"</span>,Enum.GetNames(<span style="color: rgba(0, 0, 255, 1)">typeof</span><span style="color: rgba(0, 0, 0, 1)">(CardsType)))}]
##关于炸弹的特别规则
如果当前手牌里有【炸弹】同时手牌里没有【大于】对方的出牌时,可以根据使用炸弹,炸弹可以最大程度的确保你拥有下一轮次的出牌权除非对手有比你更大的炸弹。所以尽可能的不要将炸弹的牌拆成对子、连子、顺子、三带一,如手牌是:[</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♥7</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♣9</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♦10</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♣10</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♣10</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♥10</span><span style="color: rgba(128, 0, 0, 1)">"</span>]尽可能不要拆成[<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♥7</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♦10</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♣10</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♣10</span><span style="color: rgba(128, 0, 0, 1)">"</span>]或者[<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♣10</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♣10</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">]出牌
注意双王是最大炸弹,四个2是第二大的炸弹,请谨慎使用。
##斗地主常见出牌策略参考:
#地主的策略
快速出牌:地主的首要策略是尽可能快地出牌,减少农民合作的机会。地主手中有更多的牌,可以更灵活地控制游戏节奏。
控制大牌:保留关键的大牌(如2、王等)来在关键时刻打破农民的配合或结束游戏。
分割农民的牌:尝试通过出牌强迫农民拆散他们的对子或连牌,破坏他们的出牌计划。
压制对手:地主可以通过连续出牌来压制农民,尤其是当发现农民手牌较少时,增加出牌速度,迫使他们出掉保留的大牌。
记牌:地主需要注意记住已出的关键牌,尤其是农民已经出过的高牌,以合理规划自己的出牌策略。
#农民的策略
配合与合作:两名农民需要通过默契的配合来阻挡地主,比如其中一个尝试出小牌逼地主出大牌,另一个则保留大牌来后期制胜。
堵牌:注意地主可能会形成的牌型,比如顺子、对子等,并尝试通过出相同类型的牌来堵截地主的出牌。
牺牲策略:有时候,一名农民可能需要牺牲自己的一些好牌,以帮助另一名农民形成更强的牌型或打断地主的出牌计划。
保存关键牌:农民应保存一些关键牌,如单张的王或2,用来在关键时刻打断地主的连胜。
记牌与推算:农民需要密切注意牌局的走向和地主的出牌习惯,推算出地主可能保留的牌,合理规划自己的出牌策略。
#所有玩家策略
在斗地主中,观察和记牌是所有玩家的重要技能。无论是地主还是农民,合理利用手中的牌,观察对手的出牌习惯,以及与队友或自己的牌进行策略性的搭配,都是赢得游戏的关键因素。
##游戏已进行的历史
{game.GetGameRecordsHistory()}
</span><span style="color: rgba(128, 0, 0, 1)">"""</span><span style="color: rgba(128, 0, 0, 1)"> },</span>
<span style="color: rgba(0, 0, 255, 1)">new</span> Message { Role = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">user</span><span style="color: rgba(128, 0, 0, 1)">"</span>, Content =<span style="color: rgba(0, 0, 0, 1)">userprompt }
}
},
Parameters </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> InputParametersData()
{
Tools </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> List<Tool><span style="color: rgba(0, 0, 0, 1)">
{
</span><span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Tool
{
Type </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">function</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
Function </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> FunctionDetail
{
Name </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">send_cards</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
Description </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">出牌函数,用于本轮游戏出牌。你的出牌必须包含在你的手持牌组中</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
Parameters </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> List<FunctionDetailParameter><span style="color: rgba(0, 0, 0, 1)">(){
</span><span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> FunctionDetailParameter()
{
properties</span>=<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)">
{
Cards</span>=<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)">
{
type</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">string[]</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
description</span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">选择你要出的牌组,使用逗号\",\"分割,每一个牌必须使用\"\"包裹</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
}
}
}
}
}
}
}
}
};
}</span></pre>
</div>
<p>接下来就是游戏的运行主要部分逻辑,定义一个游戏实例,通过一个死循环检测是否已经有玩家手牌出尽来判断游戏是否已经达到结局,没有出尽则依次让大模型调用智能体通过函数玩游戏,并且当模型出牌不符合规则时通过函数回调告知模型出错的逻辑指导模型重新进行对应的出牌:</p>
<div class="cnblogs_code">
<pre>Console.OutputEncoding =<span style="color: rgba(0, 0, 0, 1)"> System.Text.Encoding.UTF8;
Game game </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Game();
</span><span style="color: rgba(0, 0, 255, 1)">var</span> apiKey = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">通过百炼模型平台申请你的API-KEY</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">var</span> baseUrl = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">var</span> apiClient = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> ApiClient(baseUrl, apiKey);
</span><span style="color: rgba(0, 0, 255, 1)">var</span> request =<span style="color: rgba(0, 0, 0, 1)"> GetNowReq();
</span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)">
{
</span><span style="color: rgba(0, 0, 255, 1)">var</span> rollindex = <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">var</span> rollbigindex = <span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">while</span> (!game.Players.Any(x=>x.HandCards.Count==<span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">))
{
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 0, 1)">game.GameRecords.Any())
{
game.GameRecords.Add(</span><span style="color: rgba(0, 0, 255, 1)">new</span> GameRecordInfo() { GameRecordText = $<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">第{rollbigindex}轮开始</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> });
}
ApiResponse response </span>= <span style="color: rgba(0, 0, 255, 1)">default</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)">
{
response </span>= <span style="color: rgba(0, 0, 255, 1)">await</span> apiClient.PostAsync(<span style="color: rgba(128, 0, 0, 1)">""</span><span style="color: rgba(0, 0, 0, 1)">, request);
}
</span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (Exception e)
{
</span><span style="color: rgba(0, 0, 255, 1)">var</span> jsonData = JsonSerializer.Serialize(request, <span style="color: rgba(0, 0, 255, 1)">new</span> JsonSerializerOptions { PropertyNamingPolicy =<span style="color: rgba(0, 0, 0, 1)"> JsonNamingPolicy.CamelCase });
File.WriteAllText(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">errdata.json</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, jsonData.ToLower());
</span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span> Exception(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">接口请求异常,原始信息:</span><span style="color: rgba(128, 0, 0, 1)">"</span> +<span style="color: rgba(0, 0, 0, 1)"> e.Message);
}
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (response.Output.Choices[<span style="color: rgba(128, 0, 128, 1)">0</span>].Message.Tool_Calls != <span style="color: rgba(0, 0, 255, 1)">null</span> && response.Output.Choices[<span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">].Message.Tool_Calls.Any())
{
</span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)">
{
</span><span style="color: rgba(0, 0, 255, 1)">var</span> argument = JsonSerializer.Deserialize<CardsDto>(response.Output.Choices[<span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">].Message.Tool_Calls.First().Function.Arguments);
game.Play(argument.cards </span>?? Array.Empty<<span style="color: rgba(0, 0, 255, 1)">string</span>><span style="color: rgba(0, 0, 0, 1)">());
</span><span style="color: rgba(0, 0, 255, 1)">var</span> last = game.GameRecords.LastOrDefault(x => x.Player != <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">);
Console.ForegroundColor </span>=<span style="color: rgba(0, 0, 0, 1)"> ConsoleColor.Green;
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (Console.CursorLeft != <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">)
Console.WriteLine($</span><span style="color: rgba(128, 0, 0, 1)">""</span><span style="color: rgba(0, 0, 0, 1)">);
Console.Write($</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">({last.Player.Role})玩家:{last.Player.Name}:</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
Console.ForegroundColor </span>=<span style="color: rgba(0, 0, 0, 1)"> ConsoleColor.Red;
Console.Write((last.Cards </span>== <span style="color: rgba(0, 0, 255, 1)">null</span> || last.Cards.Length == <span style="color: rgba(128, 0, 128, 1)">0</span>) ? <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">过</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> : game.GetCardsNumberText(last.Cards));
Console.ResetColor();
</span><span style="color: rgba(0, 0, 255, 1)">var</span> messageContent = response.Output.Choices[<span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">].Message.Content;
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)">.IsNullOrWhiteSpace(messageContent))
{
messageContent </span>= messageContent.Replace(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">\r\n</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">""</span>).Replace(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">\n</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">""</span>).Replace(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">\r</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">""</span><span style="color: rgba(0, 0, 0, 1)">);
}
Console.WriteLine($</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">({messageContent},余牌:{game.GetCurrnetPlayerHandCards()})</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
rollindex</span>++<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (rollindex == <span style="color: rgba(128, 0, 128, 1)">3</span><span style="color: rgba(0, 0, 0, 1)">)
{
rollindex </span>= <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">;
game.GameRecords.Add(</span><span style="color: rgba(0, 0, 255, 1)">new</span> GameRecordInfo() { GameRecordText = $<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">第{rollbigindex}轮结束,进入下一轮</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> });
rollbigindex</span>++<span style="color: rgba(0, 0, 0, 1)">;
}
game.MoveNextPlayer();
request </span>=<span style="color: rgba(0, 0, 0, 1)"> GetNowReq();
}
</span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)">(JsonException je)
{
</span><span style="color: rgba(0, 0, 255, 1)">var</span> last =<span style="color: rgba(0, 0, 0, 1)"> game.GetCurrnetPlayer();
request </span>=<span style="color: rgba(0, 0, 0, 1)"> GetNowReq();
request.Input.Messages.Add(response.Output.Choices[</span><span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">].Message);
request.Input.Messages.Add(</span><span style="color: rgba(0, 0, 255, 1)">new</span> Message() { Role = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">tool</span><span style="color: rgba(128, 0, 0, 1)">"</span>, Name = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">send_cards</span><span style="color: rgba(128, 0, 0, 1)">"</span>, Content = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">传递了错误的函数调用字符串,无法转化成标准的json格式,原始字符串:</span><span style="color: rgba(128, 0, 0, 1)">"</span> + response.Output.Choices[<span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">].Message.Tool_Calls.First().Function.Arguments });
}
</span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (Exception e)
{
</span><span style="color: rgba(0, 0, 255, 1)">var</span> last =<span style="color: rgba(0, 0, 0, 1)"> game.GetCurrnetPlayer();
request </span>=<span style="color: rgba(0, 0, 0, 1)"> GetNowReq();
request.Input.Messages.Add(response.Output.Choices[</span><span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">].Message);
request.Input.Messages.Add(</span><span style="color: rgba(0, 0, 255, 1)">new</span> Message() { Role = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">tool</span><span style="color: rgba(128, 0, 0, 1)">"</span>, Name = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">send_cards</span><span style="color: rgba(128, 0, 0, 1)">"</span>, Content =<span style="color: rgba(0, 0, 0, 1)"> e.Message });
}
}
</span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)">
{
</span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)">
{
game.Play(Array.Empty</span><<span style="color: rgba(0, 0, 255, 1)">string</span>>());<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">不进行出牌</span>
<span style="color: rgba(0, 0, 255, 1)">var</span> last = game.GameRecords.LastOrDefault(x => x.Player != <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">);
Console.ForegroundColor </span>=<span style="color: rgba(0, 0, 0, 1)"> ConsoleColor.Green;
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (Console.CursorLeft != <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">)
Console.WriteLine($</span><span style="color: rgba(128, 0, 0, 1)">""</span><span style="color: rgba(0, 0, 0, 1)">);
Console.Write($</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">({last.Player.Role})玩家:{last.Player.Name}:</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
Console.ForegroundColor </span>=<span style="color: rgba(0, 0, 0, 1)"> ConsoleColor.Red;
Console.Write((last.Cards </span>== <span style="color: rgba(0, 0, 255, 1)">null</span> || last.Cards.Length == <span style="color: rgba(128, 0, 128, 1)">0</span>) ? <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">过</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> : game.GetCardsNumberText(last.Cards));
Console.ResetColor();
</span><span style="color: rgba(0, 0, 255, 1)">var</span> messageContent = response.Output.Choices[<span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">].Message.Content;
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)">.IsNullOrWhiteSpace(messageContent))
{
messageContent </span>= messageContent.Replace(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">\r\n</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">""</span>).Replace(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">\n</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">""</span>).Replace(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">\r</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">""</span><span style="color: rgba(0, 0, 0, 1)">);
}
Console.WriteLine($</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">({messageContent},余牌:{game.GetCurrnetPlayerHandCards()})</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
rollindex</span>++<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (rollindex == <span style="color: rgba(128, 0, 128, 1)">3</span><span style="color: rgba(0, 0, 0, 1)">)
{
rollindex </span>= <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">;
game.GameRecords.Add(</span><span style="color: rgba(0, 0, 255, 1)">new</span> GameRecordInfo() { GameRecordText = $<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">第{rollbigindex}轮结束,进入下一轮</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> });
rollbigindex</span>++<span style="color: rgba(0, 0, 0, 1)">;
}
game.MoveNextPlayer();
request </span>=<span style="color: rgba(0, 0, 0, 1)"> GetNowReq();
}
</span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (Exception e)
{
</span><span style="color: rgba(0, 0, 255, 1)">var</span> last =<span style="color: rgba(0, 0, 0, 1)"> game.GetCurrnetPlayer();
request </span>=<span style="color: rgba(0, 0, 0, 1)"> GetNowReq();
request.Input.Messages.Add(response.Output.Choices[</span><span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">].Message);
request.Input.Messages.Add(</span><span style="color: rgba(0, 0, 255, 1)">new</span> Message() { Role = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">tool</span><span style="color: rgba(128, 0, 0, 1)">"</span>, Name = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">send_cards</span><span style="color: rgba(128, 0, 0, 1)">"</span>, Content =<span style="color: rgba(0, 0, 0, 1)"> e.Message });
}
}
}
Console.WriteLine($</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">游戏结束,{(game.Players.Any(x => x.Role == </span><span style="color: rgba(128, 0, 0, 1)">"</span>地主<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)"> && x.HandCards.Any()) ? </span><span style="color: rgba(128, 0, 0, 1)">"</span>农民胜利<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)"> : </span><span style="color: rgba(128, 0, 0, 1)">"</span>地主胜利<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">)}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
}
</span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (Exception ex)
{
Console.WriteLine(ex.Message);
Console.WriteLine(ex.StackTrace);
}</span></pre>
</div>
<p>以上内容基本就是主要的部分,演示的内容如下:</p>
<p><img src="https://img2024.cnblogs.com/blog/198579/202406/198579-20240605162216422-456097311.png"></p>
<p><img src="https://img2024.cnblogs.com/blog/198579/202406/198579-20240605162239706-423218438.png"></p>
<p> 可以看到模型的表现还是比较“蠢”,这是因为斗地主是一个典型的信息不完全(信息不透明)的游戏。这意味着在游戏过程中不是所有的信息都是对所有玩家开放的。策略的多样性和不确定性让玩家在游戏中必须基于有限的信息做出决策,比如是否抢地主(本示例没有)、如何出牌以及如何配合或对抗其他玩家。玩家的策略不仅受到手牌的限制,还受到对其他玩家策略的猜测和解读的影响。加之当前大模型对于数学的理解能力较差和逻辑短板导致其表现的比较“智障”。一般的斗地主AI主要依赖搜索算法+剪枝策略或者基于神经网络+强化学习+搜索算法来实现比如典型的棋牌类AI比如Pluribus和AlphaGo都是依赖类似的技术来实现,而大模型本身主要并非转向基于游戏决策做过训练,所以这里也就不展开了。本作主要还是想讨论大模型在智能体应用上有哪些可能的落地方式。</p>
<p>完整的代码如下,有兴趣的朋友可以自行申请百炼的千问API接口进行尝试(没有依赖任何包,所以可以创建一个控制台程序直接粘贴到program.cs即可运行):</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> System.Collections;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> System.Collections.Generic;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> System.Net.Http.Headers;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> System.Text;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> System.Text.Json;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> System.Text.Json.Serialization;
Console.OutputEncoding </span>=<span style="color: rgba(0, 0, 0, 1)"> System.Text.Encoding.UTF8;
Game game </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Game();
</span><span style="color: rgba(0, 0, 255, 1)">var</span> apiKey = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">通过百炼模型平台申请你的API-KEY</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">var</span> baseUrl = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">var</span> apiClient = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> ApiClient(baseUrl, apiKey);
</span><span style="color: rgba(0, 0, 255, 1)">var</span> request =<span style="color: rgba(0, 0, 0, 1)"> GetNowReq();
</span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)">
{
</span><span style="color: rgba(0, 0, 255, 1)">var</span> rollindex = <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">var</span> rollbigindex = <span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">while</span> (!game.Players.Any(x=>x.HandCards.Count==<span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">))
{
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 0, 1)">game.GameRecords.Any())
{
game.GameRecords.Add(</span><span style="color: rgba(0, 0, 255, 1)">new</span> GameRecordInfo() { GameRecordText = $<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">第{rollbigindex}轮开始</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> });
}
ApiResponse response </span>= <span style="color: rgba(0, 0, 255, 1)">default</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)">
{
response </span>= <span style="color: rgba(0, 0, 255, 1)">await</span> apiClient.PostAsync(<span style="color: rgba(128, 0, 0, 1)">""</span><span style="color: rgba(0, 0, 0, 1)">, request);
}
</span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (Exception e)
{
</span><span style="color: rgba(0, 0, 255, 1)">var</span> jsonData = JsonSerializer.Serialize(request, <span style="color: rgba(0, 0, 255, 1)">new</span> JsonSerializerOptions { PropertyNamingPolicy =<span style="color: rgba(0, 0, 0, 1)"> JsonNamingPolicy.CamelCase });
File.WriteAllText(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">errdata.json</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, jsonData.ToLower());
</span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span> Exception(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">接口请求异常,原始信息:</span><span style="color: rgba(128, 0, 0, 1)">"</span> +<span style="color: rgba(0, 0, 0, 1)"> e.Message);
}
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (response.Output.Choices[<span style="color: rgba(128, 0, 128, 1)">0</span>].Message.Tool_Calls != <span style="color: rgba(0, 0, 255, 1)">null</span> && response.Output.Choices[<span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">].Message.Tool_Calls.Any())
{
</span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)">
{
</span><span style="color: rgba(0, 0, 255, 1)">var</span> argument = JsonSerializer.Deserialize<CardsDto>(response.Output.Choices[<span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">].Message.Tool_Calls.First().Function.Arguments);
game.Play(argument.cards </span>?? Array.Empty<<span style="color: rgba(0, 0, 255, 1)">string</span>><span style="color: rgba(0, 0, 0, 1)">());
</span><span style="color: rgba(0, 0, 255, 1)">var</span> last = game.GameRecords.LastOrDefault(x => x.Player != <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">);
Console.ForegroundColor </span>=<span style="color: rgba(0, 0, 0, 1)"> ConsoleColor.Green;
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (Console.CursorLeft != <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">)
Console.WriteLine($</span><span style="color: rgba(128, 0, 0, 1)">""</span><span style="color: rgba(0, 0, 0, 1)">);
Console.Write($</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">({last.Player.Role})玩家:{last.Player.Name}:</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
Console.ForegroundColor </span>=<span style="color: rgba(0, 0, 0, 1)"> ConsoleColor.Red;
Console.Write((last.Cards </span>== <span style="color: rgba(0, 0, 255, 1)">null</span> || last.Cards.Length == <span style="color: rgba(128, 0, 128, 1)">0</span>) ? <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">过</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> : game.GetCardsNumberText(last.Cards));
Console.ResetColor();
</span><span style="color: rgba(0, 0, 255, 1)">var</span> messageContent = response.Output.Choices[<span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">].Message.Content;
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)">.IsNullOrWhiteSpace(messageContent))
{
messageContent </span>= messageContent.Replace(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">\r\n</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">""</span>).Replace(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">\n</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">""</span>).Replace(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">\r</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">""</span><span style="color: rgba(0, 0, 0, 1)">);
}
Console.WriteLine($</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">({messageContent},余牌:{game.GetCurrnetPlayerHandCards()})</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
rollindex</span>++<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (rollindex == <span style="color: rgba(128, 0, 128, 1)">3</span><span style="color: rgba(0, 0, 0, 1)">)
{
rollindex </span>= <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">;
game.GameRecords.Add(</span><span style="color: rgba(0, 0, 255, 1)">new</span> GameRecordInfo() { GameRecordText = $<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">第{rollbigindex}轮结束,进入下一轮</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> });
rollbigindex</span>++<span style="color: rgba(0, 0, 0, 1)">;
}
game.MoveNextPlayer();
request </span>=<span style="color: rgba(0, 0, 0, 1)"> GetNowReq();
}
</span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)">(JsonException je)
{
</span><span style="color: rgba(0, 0, 255, 1)">var</span> last =<span style="color: rgba(0, 0, 0, 1)"> game.GetCurrnetPlayer();
request </span>=<span style="color: rgba(0, 0, 0, 1)"> GetNowReq();
request.Input.Messages.Add(response.Output.Choices[</span><span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">].Message);
request.Input.Messages.Add(</span><span style="color: rgba(0, 0, 255, 1)">new</span> Message() { Role = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">tool</span><span style="color: rgba(128, 0, 0, 1)">"</span>, Name = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">send_cards</span><span style="color: rgba(128, 0, 0, 1)">"</span>, Content = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">传递了错误的函数调用字符串,无法转化成标准的json格式,原始字符串:</span><span style="color: rgba(128, 0, 0, 1)">"</span> + response.Output.Choices[<span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">].Message.Tool_Calls.First().Function.Arguments });
}
</span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (Exception e)
{
</span><span style="color: rgba(0, 0, 255, 1)">var</span> last =<span style="color: rgba(0, 0, 0, 1)"> game.GetCurrnetPlayer();
request </span>=<span style="color: rgba(0, 0, 0, 1)"> GetNowReq();
request.Input.Messages.Add(response.Output.Choices[</span><span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">].Message);
request.Input.Messages.Add(</span><span style="color: rgba(0, 0, 255, 1)">new</span> Message() { Role = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">tool</span><span style="color: rgba(128, 0, 0, 1)">"</span>, Name = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">send_cards</span><span style="color: rgba(128, 0, 0, 1)">"</span>, Content =<span style="color: rgba(0, 0, 0, 1)"> e.Message });
}
}
</span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)">
{
</span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)">
{
game.Play(Array.Empty</span><<span style="color: rgba(0, 0, 255, 1)">string</span>>());<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">不进行出牌</span>
<span style="color: rgba(0, 0, 255, 1)">var</span> last = game.GameRecords.LastOrDefault(x => x.Player != <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">);
Console.ForegroundColor </span>=<span style="color: rgba(0, 0, 0, 1)"> ConsoleColor.Green;
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (Console.CursorLeft != <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">)
Console.WriteLine($</span><span style="color: rgba(128, 0, 0, 1)">""</span><span style="color: rgba(0, 0, 0, 1)">);
Console.Write($</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">({last.Player.Role})玩家:{last.Player.Name}:</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
Console.ForegroundColor </span>=<span style="color: rgba(0, 0, 0, 1)"> ConsoleColor.Red;
Console.Write((last.Cards </span>== <span style="color: rgba(0, 0, 255, 1)">null</span> || last.Cards.Length == <span style="color: rgba(128, 0, 128, 1)">0</span>) ? <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">过</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> : game.GetCardsNumberText(last.Cards));
Console.ResetColor();
</span><span style="color: rgba(0, 0, 255, 1)">var</span> messageContent = response.Output.Choices[<span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">].Message.Content;
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)">.IsNullOrWhiteSpace(messageContent))
{
messageContent </span>= messageContent.Replace(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">\r\n</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">""</span>).Replace(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">\n</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">""</span>).Replace(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">\r</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">""</span><span style="color: rgba(0, 0, 0, 1)">);
}
Console.WriteLine($</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">({messageContent},余牌:{game.GetCurrnetPlayerHandCards()})</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
rollindex</span>++<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (rollindex == <span style="color: rgba(128, 0, 128, 1)">3</span><span style="color: rgba(0, 0, 0, 1)">)
{
rollindex </span>= <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">;
game.GameRecords.Add(</span><span style="color: rgba(0, 0, 255, 1)">new</span> GameRecordInfo() { GameRecordText = $<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">第{rollbigindex}轮结束,进入下一轮</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> });
rollbigindex</span>++<span style="color: rgba(0, 0, 0, 1)">;
}
game.MoveNextPlayer();
request </span>=<span style="color: rgba(0, 0, 0, 1)"> GetNowReq();
}
</span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (Exception e)
{
</span><span style="color: rgba(0, 0, 255, 1)">var</span> last =<span style="color: rgba(0, 0, 0, 1)"> game.GetCurrnetPlayer();
request </span>=<span style="color: rgba(0, 0, 0, 1)"> GetNowReq();
request.Input.Messages.Add(response.Output.Choices[</span><span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">].Message);
request.Input.Messages.Add(</span><span style="color: rgba(0, 0, 255, 1)">new</span> Message() { Role = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">tool</span><span style="color: rgba(128, 0, 0, 1)">"</span>, Name = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">send_cards</span><span style="color: rgba(128, 0, 0, 1)">"</span>, Content =<span style="color: rgba(0, 0, 0, 1)"> e.Message });
}
}
}
Console.WriteLine($</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">游戏结束,{(game.Players.Any(x => x.Role == </span><span style="color: rgba(128, 0, 0, 1)">"</span>地主<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)"> && x.HandCards.Any()) ? </span><span style="color: rgba(128, 0, 0, 1)">"</span>农民胜利<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)"> : </span><span style="color: rgba(128, 0, 0, 1)">"</span>地主胜利<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">)}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
}
</span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (Exception ex)
{
Console.WriteLine(ex.Message);
Console.WriteLine(ex.StackTrace);
}
</span><span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> readerrdatatest()
{
</span><span style="color: rgba(0, 0, 255, 1)">var</span> json = File.ReadAllText(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">errdata.json</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">var</span> obj = JsonSerializer.Deserialize<TextGenerationRequest>(json,<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> JsonSerializerOptions
{
PropertyNameCaseInsensitive </span>= <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">
});
}
TextGenerationRequest GetNowReq()
{
</span><span style="color: rgba(0, 0, 255, 1)">var</span> userprompt = <span style="color: rgba(128, 0, 0, 1)">""</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (game.GameRecords.Where(x => x.Player != <span style="color: rgba(0, 0, 255, 1)">null</span>).Count() == <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">)
{
userprompt </span>= $<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">现在是第一轮,你是{game.GetCurrnetPlayer().Name},你的角色是:{game.GetCurrnetPlayer().Role}请先出牌(如果单牌较少可以考虑尽可能出顺子、连子、三带一或者对子,如果单牌较多则优先考虑出单牌)\r\n手持牌组:{game.GetCurrnetPlayerHandCards()}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
}
</span><span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(0, 0, 255, 1)">if</span> (game.GameRecords.Any(x => x.Player != <span style="color: rgba(0, 0, 255, 1)">null</span>) && game.GameRecords.Last(x => x.Player != <span style="color: rgba(0, 0, 255, 1)">null</span> && x.Cards.Any()).Player.Name ==<span style="color: rgba(0, 0, 0, 1)"> game.GetCurrnetPlayer().Name)
{
userprompt </span>= $<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">你是{game.GetCurrnetPlayer().Name},你的角色是:{game.GetCurrnetPlayer().Role}。上一轮其他玩家都过了你的牌,请你出牌(如果单牌较少可以考虑尽可能出顺子、连子、三带一或者对子,如果单牌较多则优先考虑出单牌)\r\n手持牌组:{game.GetCurrnetPlayerHandCards()}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
}
</span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)">
{
userprompt </span>= $<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">你是{game.GetCurrnetPlayer().Name},你的角色是:{game.GetCurrnetPlayer().Role}。请出牌(如果单牌较少可以考虑尽可能出顺子、连子、三带一或者对子,如果单牌较多则优先考虑出单牌),或者选择本轮不出牌(当你的手牌都小于最后的出牌或者上一轮出牌的玩家是同组玩家时可以不出牌)\r\n手持牌组:{game.GetCurrnetPlayerHandCards()}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
}
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> TextGenerationRequest
{
Model </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">qwen-max</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
Input </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> InputData
{
Messages </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> List<Message><span style="color: rgba(0, 0, 0, 1)">
{
</span><span style="color: rgba(0, 0, 255, 1)">new</span> Message { Role = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">system</span><span style="color: rgba(128, 0, 0, 1)">"</span>, Content = $<span style="color: rgba(128, 0, 0, 1)">"""
</span><span style="color: rgba(0, 0, 0, 1)"> 你正在参与一场斗地主游戏,
#游戏规则
参与游戏的玩家由一个地主和两个农民组成,如果你是地主,你需要出掉所有的牌才能获得胜利。如果你是农民,你和你的队友任意一人出完所有的牌即可获胜。
可以出单牌、【对子】(两张相同数字的牌,如:[</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♥3</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♣3</span><span style="color: rgba(128, 0, 0, 1)">"</span>])、【连子】(从小到大顺序数字的牌5张起出,如:[<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♥4</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♣5</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♦6</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♣7</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♥8</span><span style="color: rgba(128, 0, 0, 1)">"</span>])、【顺子】(三个连起来的对子,如:[<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♥9</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♣9</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♦10</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♣10</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♣j</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♥j</span><span style="color: rgba(128, 0, 0, 1)">"</span>])、【三带一】(三张相同数字的牌+一张任意单牌,如:[<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♥4</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♣4</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♦4</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♣6</span><span style="color: rgba(128, 0, 0, 1)">"</span>])、【炸弹】(四个相同数字的牌或者双王,如:[<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♥4</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♣4</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♦4</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♣4</span><span style="color: rgba(128, 0, 0, 1)">"</span>]或者[<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">小王</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">大王</span><span style="color: rgba(128, 0, 0, 1)">"</span>]),牌从小到大顺序:<span style="color: rgba(128, 0, 128, 1)">3</span>,<span style="color: rgba(128, 0, 128, 1)">4</span>,<span style="color: rgba(128, 0, 128, 1)">5</span>,<span style="color: rgba(128, 0, 128, 1)">6</span>,<span style="color: rgba(128, 0, 128, 1)">7</span>,<span style="color: rgba(128, 0, 128, 1)">8</span>,<span style="color: rgba(128, 0, 128, 1)">9</span>,<span style="color: rgba(128, 0, 128, 1)">10</span>,j,q,k,a,<span style="color: rgba(128, 0, 128, 1)">2</span><span style="color: rgba(0, 0, 0, 1)">,小王,大王。
每一轮出牌必须【大于】对方的出牌,并且必须和对方牌型一致[{</span><span style="color: rgba(0, 0, 255, 1)">string</span>.Join(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">,</span><span style="color: rgba(128, 0, 0, 1)">"</span>,Enum.GetNames(<span style="color: rgba(0, 0, 255, 1)">typeof</span><span style="color: rgba(0, 0, 0, 1)">(CardsType)))}]
##关于炸弹的特别规则
如果当前手牌里有【炸弹】同时手牌里没有【大于】对方的出牌时,可以根据使用炸弹,炸弹可以最大程度的确保你拥有下一轮次的出牌权除非对手有比你更大的炸弹。所以尽可能的不要将炸弹的牌拆成对子、连子、顺子、三带一,如手牌是:[</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♥7</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♣9</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♦10</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♣10</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♣10</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♥10</span><span style="color: rgba(128, 0, 0, 1)">"</span>]尽可能不要拆成[<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♥7</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♦10</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♣10</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♣10</span><span style="color: rgba(128, 0, 0, 1)">"</span>]或者[<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♣10</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♣10</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">]出牌
注意双王是最大炸弹,四个2是第二大的炸弹,请谨慎使用。
##斗地主常见出牌策略参考:
#地主的策略
快速出牌:地主的首要策略是尽可能快地出牌,减少农民合作的机会。地主手中有更多的牌,可以更灵活地控制游戏节奏。
控制大牌:保留关键的大牌(如2、王等)来在关键时刻打破农民的配合或结束游戏。
分割农民的牌:尝试通过出牌强迫农民拆散他们的对子或连牌,破坏他们的出牌计划。
压制对手:地主可以通过连续出牌来压制农民,尤其是当发现农民手牌较少时,增加出牌速度,迫使他们出掉保留的大牌。
记牌:地主需要注意记住已出的关键牌,尤其是农民已经出过的高牌,以合理规划自己的出牌策略。
#农民的策略
配合与合作:两名农民需要通过默契的配合来阻挡地主,比如其中一个尝试出小牌逼地主出大牌,另一个则保留大牌来后期制胜。
堵牌:注意地主可能会形成的牌型,比如顺子、对子等,并尝试通过出相同类型的牌来堵截地主的出牌。
牺牲策略:有时候,一名农民可能需要牺牲自己的一些好牌,以帮助另一名农民形成更强的牌型或打断地主的出牌计划。
保存关键牌:农民应保存一些关键牌,如单张的王或2,用来在关键时刻打断地主的连胜。
记牌与推算:农民需要密切注意牌局的走向和地主的出牌习惯,推算出地主可能保留的牌,合理规划自己的出牌策略。
#所有玩家策略
在斗地主中,观察和记牌是所有玩家的重要技能。无论是地主还是农民,合理利用手中的牌,观察对手的出牌习惯,以及与队友或自己的牌进行策略性的搭配,都是赢得游戏的关键因素。
##游戏已进行的历史
{game.GetGameRecordsHistory()}
</span><span style="color: rgba(128, 0, 0, 1)">"""</span><span style="color: rgba(128, 0, 0, 1)"> },</span>
<span style="color: rgba(0, 0, 255, 1)">new</span> Message { Role = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">user</span><span style="color: rgba(128, 0, 0, 1)">"</span>, Content =<span style="color: rgba(0, 0, 0, 1)">userprompt }
}
},
Parameters </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> InputParametersData()
{
Tools </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> List<Tool><span style="color: rgba(0, 0, 0, 1)">
{
</span><span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Tool
{
Type </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">function</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
Function </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> FunctionDetail
{
Name </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">send_cards</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
Description </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">出牌函数,用于本轮游戏出牌。你的出牌必须包含在你的手持牌组中</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
Parameters </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> List<FunctionDetailParameter><span style="color: rgba(0, 0, 0, 1)">(){
</span><span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> FunctionDetailParameter()
{
properties</span>=<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)">
{
Cards</span>=<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)">
{
type</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">string[]</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
description</span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">选择你要出的牌组,使用逗号\",\"分割,每一个牌必须使用\"\"包裹</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
}
}
}
}
}
}
}
}
};
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> ApiClient
{
</span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">readonly</span><span style="color: rgba(0, 0, 0, 1)"> HttpClient _httpClient;
</span><span style="color: rgba(0, 0, 255, 1)">public</span> ApiClient(<span style="color: rgba(0, 0, 255, 1)">string</span> baseUrl, <span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)"> apiKey)
{
_httpClient </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> HttpClient
{
BaseAddress </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Uri(baseUrl)
};
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 配置HttpClient实例</span>
_httpClient.DefaultRequestHeaders.Authorization = <span style="color: rgba(0, 0, 255, 1)">new</span> AuthenticationHeaderValue(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Bearer</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, apiKey);
_httpClient.DefaultRequestHeaders.Accept.Add(</span><span style="color: rgba(0, 0, 255, 1)">new</span> MediaTypeWithQualityHeaderValue(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">application/json</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">));
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">async</span> Task<ApiResponse> PostAsync(<span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)"> resource, TextGenerationRequest request)
{
</span><span style="color: rgba(0, 0, 255, 1)">var</span> jsonData = JsonSerializer.Serialize(request, <span style="color: rgba(0, 0, 255, 1)">new</span> JsonSerializerOptions { PropertyNamingPolicy =<span style="color: rgba(0, 0, 0, 1)"> JsonNamingPolicy.CamelCase });
</span><span style="color: rgba(0, 0, 255, 1)">using</span> <span style="color: rgba(0, 0, 255, 1)">var</span> content = <span style="color: rgba(0, 0, 255, 1)">new</span> StringContent(jsonData.ToLower(), Encoding.UTF8, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">application/json</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">var</span> response = <span style="color: rgba(0, 0, 255, 1)">await</span><span style="color: rgba(0, 0, 0, 1)"> _httpClient.PostAsync(resource, content);
</span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (response.IsSuccessStatusCode)
{
</span><span style="color: rgba(0, 0, 255, 1)">var</span> responseContent = <span style="color: rgba(0, 0, 255, 1)">await</span><span style="color: rgba(0, 0, 0, 1)"> response.Content.ReadAsStringAsync();
</span><span style="color: rgba(0, 0, 255, 1)">var</span> options = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> JsonSerializerOptions
{
PropertyNameCaseInsensitive </span>= <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 忽略大小写</span>
<span style="color: rgba(0, 0, 0, 1)"> };
</span><span style="color: rgba(0, 0, 255, 1)">return</span> JsonSerializer.Deserialize<ApiResponse><span style="color: rgba(0, 0, 0, 1)">(responseContent, options);
}
</span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)">
{
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 错误处理</span>
<span style="color: rgba(0, 0, 255, 1)">var</span> errorContent = <span style="color: rgba(0, 0, 255, 1)">await</span><span style="color: rgba(0, 0, 0, 1)"> response.Content.ReadAsStringAsync();
</span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span> Exception($<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">API 请求失败: {response.StatusCode}, {errorContent}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
}
}
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> TextGenerationRequest
{
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span> Model { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
</span><span style="color: rgba(0, 0, 255, 1)">public</span> InputData Input { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
</span><span style="color: rgba(0, 0, 255, 1)">public</span> InputParametersData Parameters { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> InputParametersData
{
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span> Result_Format { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span>; } = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">message</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">public</span> List<Tool> Tools { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> InputData
{
</span><span style="color: rgba(0, 0, 255, 1)">public</span> List<Message> Messages { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> Message
{
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span> Name { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span> Role { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
</span><span style="color: rgba(0, 0, 255, 1)">public</span> List<ToolCall> Tool_Calls { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span> Content { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> Tool
{
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span> Type { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
</span><span style="color: rgba(0, 0, 255, 1)">public</span> FunctionDetail Function { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> ToolCall
{
</span><span style="color: rgba(0, 0, 255, 1)">public</span> FunctionCall Function { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span> Id { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span> Type { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> FunctionCall
{
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span> Name { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span> Arguments { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> FunctionDetail
{
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span> Name { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span> Description { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
</span><span style="color: rgba(0, 0, 255, 1)">public</span> List<FunctionDetailParameter> Parameters { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> FunctionDetailParameter
{
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span> type { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span>; } = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">object</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">object</span> properties { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> ApiResponse
{
</span><span style="color: rgba(0, 0, 255, 1)">public</span> OutputResponse Output { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
</span><span style="color: rgba(0, 0, 255, 1)">public</span> UsageData Usage { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span> RequestId { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> OutputResponse
{
</span><span style="color: rgba(0, 0, 255, 1)">public</span> List<Choice> Choices { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> Choice
{
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span> FinishReason { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
</span><span style="color: rgba(0, 0, 255, 1)">public</span> Message Message { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> UsageData
{
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span> TotalTokens { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span> OutputTokens { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span> InputTokens { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> CardsDto
{
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span>[] cards { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> Game
{
</span><span style="color: rgba(0, 0, 255, 1)">string</span>[] array = [<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">3</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">4</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">5</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">6</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">7</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">8</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">9</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">10</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">j</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">q</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">k</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">a</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">2</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">小王</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">大王</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">];
</span><span style="color: rgba(0, 0, 255, 1)">public</span> List<<span style="color: rgba(0, 0, 255, 1)">string</span>> Deck { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
</span><span style="color: rgba(0, 0, 255, 1)">public</span> List<Player> Players { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
</span><span style="color: rgba(0, 0, 255, 1)">public</span> List<<span style="color: rgba(0, 0, 255, 1)">string</span>> BottomCards { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
</span><span style="color: rgba(0, 0, 255, 1)">public</span> Player Landlord { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span> CurrnetPlayerIndex = <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">public</span> List<GameRecordInfo> GameRecords { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> Game()
{
Players </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> List<Player> { <span style="color: rgba(0, 0, 255, 1)">new</span> Player(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Player 1</span><span style="color: rgba(128, 0, 0, 1)">"</span>), <span style="color: rgba(0, 0, 255, 1)">new</span> Player(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Player 2</span><span style="color: rgba(128, 0, 0, 1)">"</span>), <span style="color: rgba(0, 0, 255, 1)">new</span> Player(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Player 3</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">) };
GameRecords </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> List<GameRecordInfo><span style="color: rgba(0, 0, 0, 1)">();
Deck </span>=<span style="color: rgba(0, 0, 0, 1)"> GenerateDeck();
ShuffleDeck();
DealCards();
ChooseLandlord();
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)"> GetGameRecordsHistory()
{
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">string</span>.Join(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">\r\n</span><span style="color: rgba(128, 0, 0, 1)">"</span>, GameRecords.Select(x =><span style="color: rgba(0, 0, 0, 1)"> x.GameRecordText));
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span> GetCurrnetPlayerHandCards(<span style="color: rgba(0, 0, 255, 1)">int</span>? index = <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">)
{
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">string</span>.Join(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">,</span><span style="color: rgba(128, 0, 0, 1)">"</span>, Players.HandCards.OrderBy(x =><span style="color: rgba(0, 0, 0, 1)"> Array.IndexOf(array, ReplaceColor(x))));
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> Player GetCurrnetPlayer()
{
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> Players;
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span>[] GetCardsNumber(<span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)">[] Cards)
{
</span><span style="color: rgba(0, 0, 255, 1)">var</span> cardsnumber = Cards.Select(x =><span style="color: rgba(0, 0, 0, 1)">
{
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (x == <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">小王</span><span style="color: rgba(128, 0, 0, 1)">"</span> || x == <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">大王</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> Array.IndexOf(array, x);
</span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)">
{
</span><span style="color: rgba(0, 0, 255, 1)">var</span> num =<span style="color: rgba(0, 0, 0, 1)"> ReplaceColor(x);
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> Array.IndexOf(array, num);
}
}).ToArray();
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> cardsnumber.Order().ToArray();
}
</span><span style="color: rgba(0, 0, 255, 1)">string</span> ReplaceColor(<span style="color: rgba(0, 0, 255, 1)">string</span> card) => card.Replace(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♠</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">""</span>).Replace(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♥</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">""</span>).Replace(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♦</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">""</span>).Replace(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♣</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">""</span><span style="color: rgba(0, 0, 0, 1)">).ToLower();
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span> GetCardsNumberText(<span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)">[] Cards)
{
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">string</span>.Join(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">,</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, Cards);
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> (CardsType, <span style="color: rgba(0, 0, 255, 1)">int</span>[]) GetCardsType(<span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)">[] Cards)
{
</span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)">
{
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (Cards.Length == <span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> (CardsType.单牌, GetCardsNumber(Cards));
</span><span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(0, 0, 255, 1)">if</span> (Cards.Length == <span style="color: rgba(128, 0, 128, 1)">2</span><span style="color: rgba(0, 0, 0, 1)">)
{
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (Cards.OrderBy(x => x).SequenceEqual(<span style="color: rgba(0, 0, 255, 1)">new</span> List<<span style="color: rgba(0, 0, 255, 1)">string</span>>() { <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">小王</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">大王</span><span style="color: rgba(128, 0, 0, 1)">"</span> }.OrderBy(x =><span style="color: rgba(0, 0, 0, 1)"> x)))
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> (CardsType.炸弹, GetCardsNumber(Cards));
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (Cards.Select(ReplaceColor).Distinct().Count() == <span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> (CardsType.对子, GetCardsNumber(Cards));
</span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span> Exception(<span style="color: rgba(128, 0, 0, 1)">""</span><span style="color: rgba(0, 0, 0, 1)">);
}
</span><span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(0, 0, 255, 1)">if</span> (Cards.Length == <span style="color: rgba(128, 0, 128, 1)">4</span><span style="color: rgba(0, 0, 0, 1)">)
{
</span><span style="color: rgba(0, 0, 255, 1)">var</span> groupCards = Cards.Select(ReplaceColor).GroupBy(x => x).OrderByDescending(x =><span style="color: rgba(0, 0, 0, 1)"> x.Count()).ToList();
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">三带一</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> (groupCards.Count == <span style="color: rgba(128, 0, 128, 1)">2</span> && groupCards[<span style="color: rgba(128, 0, 128, 1)">0</span>].Count() == <span style="color: rgba(128, 0, 128, 1)">3</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">return</span> (CardsType.三带一, GetCardsNumber(groupCards[<span style="color: rgba(128, 0, 128, 1)">0</span>].ToArray()));<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">三带一只需要看三张牌的大小即可
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">炸弹</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> (groupCards.Count == <span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> (CardsType.炸弹, GetCardsNumber(Cards));
</span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span> Exception(<span style="color: rgba(128, 0, 0, 1)">""</span><span style="color: rgba(0, 0, 0, 1)">);
}
</span><span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(0, 0, 255, 1)">if</span> (Cards.Length >= <span style="color: rgba(128, 0, 128, 1)">5</span><span style="color: rgba(0, 0, 0, 1)">)
{
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">检测是否是顺子</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> (Cards.Length == <span style="color: rgba(128, 0, 128, 1)">6</span><span style="color: rgba(0, 0, 0, 1)">)
{
</span><span style="color: rgba(0, 0, 255, 1)">var</span> groupCards = Cards.Select(ReplaceColor).GroupBy(x => x).OrderByDescending(x =><span style="color: rgba(0, 0, 0, 1)"> x.Count()).ToList();
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (groupCards.Count == <span style="color: rgba(128, 0, 128, 1)">3</span> && groupCards.All(x => x.Count() == <span style="color: rgba(128, 0, 128, 1)">2</span><span style="color: rgba(0, 0, 0, 1)">))
</span><span style="color: rgba(0, 0, 255, 1)">return</span> (CardsType.顺子, GetCardsNumber(groupCards[<span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">].ToArray()));
}
</span><span style="color: rgba(0, 0, 255, 1)">var</span> cardsnumber =<span style="color: rgba(0, 0, 0, 1)"> GetCardsNumber(Cards);
</span><span style="color: rgba(0, 0, 255, 1)">int</span>? currItem = <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">foreach</span> (<span style="color: rgba(0, 0, 255, 1)">var</span> item <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> cardsnumber)
{
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (currItem == <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">)
currItem </span>=<span style="color: rgba(0, 0, 0, 1)"> item;
</span><span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(0, 0, 255, 1)">if</span> (currItem + <span style="color: rgba(128, 0, 128, 1)">1</span> !=<span style="color: rgba(0, 0, 0, 1)"> item)
</span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span> Exception(<span style="color: rgba(128, 0, 0, 1)">""</span><span style="color: rgba(0, 0, 0, 1)">);
}
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> (CardsType.连子, cardsnumber);
}
</span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span> Exception(<span style="color: rgba(128, 0, 0, 1)">""</span><span style="color: rgba(0, 0, 0, 1)">);
}
</span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (Exception e)
{
</span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span> Exception($<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">当所选牌型无效,牌型只能是[{string.Join(</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">, Enum.GetNames(typeof(CardsType)))}],请检查你的牌型</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
}
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> MoveNextPlayer()
{
CurrnetPlayerIndex</span>++<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (CurrnetPlayerIndex ==<span style="color: rgba(0, 0, 0, 1)"> Players.Count)
CurrnetPlayerIndex </span>= <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">;
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> Play(<span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)">[] Cards)
{
</span><span style="color: rgba(0, 0, 255, 1)">var</span> currPlayer =<span style="color: rgba(0, 0, 0, 1)"> GetCurrnetPlayer();
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (Cards == <span style="color: rgba(0, 0, 255, 1)">null</span> || Cards.Length == <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">)
{
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (!GameRecords.Any(x => x.Player != <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">))
{
</span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span> Exception(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">当前你是地主,必须进行出牌</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
}
</span><span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(0, 0, 255, 1)">if</span> (GameRecords.Last(x => x.Player != <span style="color: rgba(0, 0, 255, 1)">null</span> && x.Cards.Any()).Player.Name ==<span style="color: rgba(0, 0, 0, 1)"> currPlayer.Name)
{
</span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span> Exception(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">上一轮你出牌后其他玩家都过了,本轮该你进行出牌(可以考虑出小牌)</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
}
GameRecords.Add(</span><span style="color: rgba(0, 0, 255, 1)">new</span> GameRecordInfo() { Player = currPlayer, GameRecordText = $<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">玩家名:{currPlayer.Name},角色:{currPlayer.Role},本轮没有出牌</span><span style="color: rgba(128, 0, 0, 1)">"</span>, CardsType = <span style="color: rgba(0, 0, 255, 1)">null</span>, Cards =<span style="color: rgba(0, 0, 0, 1)"> Cards });
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">;
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">首先检查出牌是否在手牌中</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> (IsSubsetWithFrequency(Cards, currPlayer.HandCards.ToArray(), <span style="color: rgba(0, 0, 255, 1)">out</span> <span style="color: rgba(0, 0, 255, 1)">var</span><span style="color: rgba(0, 0, 0, 1)"> missingCards))
{
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">检查最后一个牌组的情况</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> (GameRecords.Any(x => x.Player != <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">))
{
</span><span style="color: rgba(0, 0, 255, 1)">var</span> last = GameRecords.Last(x => x.Player != <span style="color: rgba(0, 0, 255, 1)">null</span> &&<span style="color: rgba(0, 0, 0, 1)"> x.Cards.Any());
</span><span style="color: rgba(0, 0, 255, 1)">var</span> lastcardstype =<span style="color: rgba(0, 0, 0, 1)"> GetCardsType(last.Cards);
</span><span style="color: rgba(0, 0, 255, 1)">var</span> cardstype =<span style="color: rgba(0, 0, 0, 1)"> GetCardsType(Cards);
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (last.Player.Name !=<span style="color: rgba(0, 0, 0, 1)"> currPlayer.Name)
{
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (lastcardstype.Item1 != cardstype.Item1 && cardstype.Item1 !=<span style="color: rgba(0, 0, 0, 1)"> CardsType.炸弹)
{
</span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span> Exception($<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">无效出牌,上一轮的牌型是{lastcardstype.Item1},你必须使用相同牌型出牌</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">相同牌型则检测大小</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> (cardstype.Item1 == CardsType.单牌 || cardstype.Item1 == CardsType.对子 || cardstype.Item1 == CardsType.顺子 || cardstype.Item1 ==<span style="color: rgba(0, 0, 0, 1)"> CardsType.炸弹)
{
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (lastcardstype.Item2[<span style="color: rgba(128, 0, 128, 1)">0</span>] >= cardstype.Item2[<span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">])
</span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span> Exception($<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">无效出牌,你的出牌:[{string.Join(</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">, Cards)}]必须比上一轮出牌:[{string.Join(</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">, last.Cards)}]更大才行</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
}
</span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)">
{
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">连子的情况需要检测两个牌张数一致和最小长大于对方</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> (lastcardstype.Item2.Length !=<span style="color: rgba(0, 0, 0, 1)"> cardstype.Item2.Length)
</span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span> Exception($<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">无效出牌,由于本轮出牌是连子所以你的出牌数:[{Cards.Length}]必须和一轮出牌数:[{last.Cards.Length}]一致</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (lastcardstype.Item2[<span style="color: rgba(128, 0, 128, 1)">0</span>] >= cardstype.Item2[<span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">])
</span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span> Exception($<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">无效出牌,你的出牌:[{string.Join(</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">, Cards)}]必须比上一轮出牌:[{string.Join(</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">, last.Cards)}]更大才行</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
}
}
}
}
</span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)">
{
</span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span> Exception($<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">无效出牌,原因:{missingCards}。请重新出牌</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
}
GameRecords.Add(</span><span style="color: rgba(0, 0, 255, 1)">new</span> GameRecordInfo() { Player = currPlayer, GameRecordText = $<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">玩家名:{currPlayer.Name},角色:{currPlayer.Role},本轮出牌:[{string.Join(</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">, Cards)}],牌型:{GetCardsType(Cards).Item1}</span><span style="color: rgba(128, 0, 0, 1)">"</span>, CardsType = GetCardsType(Cards).Item1, Cards =<span style="color: rgba(0, 0, 0, 1)"> Cards });
Players.HandCards.RemoveAll(x </span>=> Cards.Select(x =><span style="color: rgba(0, 0, 0, 1)"> x.ToLower()).Contains(x.ToLower()));
}
</span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">bool</span> IsSubsetWithFrequency(<span style="color: rgba(0, 0, 255, 1)">string</span>[] smallList, <span style="color: rgba(0, 0, 255, 1)">string</span>[] bigList, <span style="color: rgba(0, 0, 255, 1)">out</span> <span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)"> missingElements)
{
</span><span style="color: rgba(0, 0, 255, 1)">var</span> bigCount = bigList.GroupBy(x => x).ToDictionary(g => g.Key.ToLower(), g =><span style="color: rgba(0, 0, 0, 1)"> g.Count());
</span><span style="color: rgba(0, 0, 255, 1)">var</span> smallCount = smallList.GroupBy(x => x).ToDictionary(g => g.Key.ToLower(), g =><span style="color: rgba(0, 0, 0, 1)"> g.Count());
</span><span style="color: rgba(0, 0, 255, 1)">var</span> missingList = <span style="color: rgba(0, 0, 255, 1)">new</span> List<<span style="color: rgba(0, 0, 255, 1)">string</span>><span style="color: rgba(0, 0, 0, 1)">();
</span><span style="color: rgba(0, 0, 255, 1)">foreach</span> (<span style="color: rgba(0, 0, 255, 1)">var</span> num <span style="color: rgba(0, 0, 255, 1)">in</span> smallList.Select(x =><span style="color: rgba(0, 0, 0, 1)"> x.ToLower()))
{
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (!bigCount.ContainsKey(num) || bigCount == <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">)
{
missingList.Add(num);
}
</span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)">
{
bigCount</span>--<span style="color: rgba(0, 0, 0, 1)">;
}
}
bigCount </span>= bigList.GroupBy(x => x).ToDictionary(g => g.Key.ToLower(), g =><span style="color: rgba(0, 0, 0, 1)"> g.Count());
StringBuilder sb </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> StringBuilder();
</span><span style="color: rgba(0, 0, 255, 1)">foreach</span> (<span style="color: rgba(0, 0, 255, 1)">var</span> item <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> missingList.Distinct().ToArray())
{
</span><span style="color: rgba(0, 0, 255, 1)">var</span> smallval =<span style="color: rgba(0, 0, 0, 1)"> smallCount;
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">检测一下其他色号</span>
<span style="color: rgba(0, 0, 255, 1)">var</span> num =<span style="color: rgba(0, 0, 0, 1)"> ReplaceColor(item);
Func</span><<span style="color: rgba(0, 0, 255, 1)">string</span>, <span style="color: rgba(0, 0, 255, 1)">bool</span>> check = x => ReplaceColor(x) ==<span style="color: rgba(0, 0, 0, 1)"> num;
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 0, 1)">bigCount.ContainsKey(item))
{
</span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (bigList.Any(check))
{
</span><span style="color: rgba(0, 0, 255, 1)">var</span> all =<span style="color: rgba(0, 0, 0, 1)"> bigList.Where(check).ToList();
sb.AppendLine($</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">你所选的牌{item},不在你的手牌中,可以选择手牌中同数字不同花色的牌:{string.Join(</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">, all)}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
}
</span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)">
{
sb.AppendLine($</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">你所选的牌{item},不在你的手牌中</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
}
}
</span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)">
{
</span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (bigList.Any(check))
{
</span><span style="color: rgba(0, 0, 255, 1)">var</span> all =<span style="color: rgba(0, 0, 0, 1)"> bigList.Where(check).ToList();
sb.AppendLine($</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">你选了{smallval}张{item},但是你的手牌中只有{bigCount}张{item}, 可以选择手牌中同数字不同花色的牌:{string.Join(</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">, all.Where(x => x != item))}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
}
</span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)">
{
sb.AppendLine($</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">你选了{smallval}张{item},但是你的手牌中只有{bigCount}张{item}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
}
}
}
missingElements </span>=<span style="color: rgba(0, 0, 0, 1)"> sb.ToString();
</span><span style="color: rgba(0, 0, 255, 1)">return</span> missingList.Distinct().ToArray().Length == <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">;
}
</span><span style="color: rgba(0, 0, 255, 1)">private</span> List<<span style="color: rgba(0, 0, 255, 1)">string</span>><span style="color: rgba(0, 0, 0, 1)"> GenerateDeck()
{
</span><span style="color: rgba(0, 0, 255, 1)">string</span>[] suits = { <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♠</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♥</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♦</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">♣</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> };
</span><span style="color: rgba(0, 0, 255, 1)">string</span>[] ranks = { <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">3</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">4</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">5</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">6</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">7</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">8</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">9</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">10</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">j</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">q</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">k</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">a</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">2</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> };
List</span><<span style="color: rgba(0, 0, 255, 1)">string</span>> deck = <span style="color: rgba(0, 0, 255, 1)">new</span> List<<span style="color: rgba(0, 0, 255, 1)">string</span>><span style="color: rgba(0, 0, 0, 1)">();
</span><span style="color: rgba(0, 0, 255, 1)">foreach</span> (<span style="color: rgba(0, 0, 255, 1)">var</span> suit <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> suits)
{
</span><span style="color: rgba(0, 0, 255, 1)">foreach</span> (<span style="color: rgba(0, 0, 255, 1)">var</span> rank <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> ranks)
{
deck.Add($</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">{suit}{rank}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
}
}
deck.Add(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">小王</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
deck.Add(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">大王</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> deck;
}
</span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> ShuffleDeck()
{
Random rng </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Random();
</span><span style="color: rgba(0, 0, 255, 1)">int</span> n =<span style="color: rgba(0, 0, 0, 1)"> Deck.Count;
</span><span style="color: rgba(0, 0, 255, 1)">while</span> (n > <span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">)
{
n</span>--<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">int</span> k = rng.Next(n + <span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">var</span> value =<span style="color: rgba(0, 0, 0, 1)"> Deck;
Deck </span>=<span style="color: rgba(0, 0, 0, 1)"> Deck;
Deck </span>=<span style="color: rgba(0, 0, 0, 1)"> value;
}
}
</span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> DealCards()
{
</span><span style="color: rgba(0, 0, 255, 1)">for</span> (<span style="color: rgba(0, 0, 255, 1)">int</span> i = <span style="color: rgba(128, 0, 128, 1)">0</span>; i < <span style="color: rgba(128, 0, 128, 1)">17</span>; i++<span style="color: rgba(0, 0, 0, 1)">)
{
</span><span style="color: rgba(0, 0, 255, 1)">foreach</span> (<span style="color: rgba(0, 0, 255, 1)">var</span> player <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> Players)
{
player.HandCards.Add(Deck.First());
Deck.RemoveAt(</span><span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">);
}
}
BottomCards </span>=<span style="color: rgba(0, 0, 0, 1)"> Deck.ToList();
Deck.Clear();
}
</span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> ChooseLandlord()
{
</span><span style="color: rgba(0, 0, 255, 1)">int</span> landlordIndex = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Random().Next(Players.Count);
Landlord </span>=<span style="color: rgba(0, 0, 0, 1)"> Players;
CurrnetPlayerIndex </span>=<span style="color: rgba(0, 0, 0, 1)"> landlordIndex;
Console.WriteLine($</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">{Landlord.Name} 是候选地主。</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
Landlord.HandCards.AddRange(BottomCards);
Landlord.Role </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">地主</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
Console.WriteLine($</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">{Landlord.Name} 成为地主,获得底牌。</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
}
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> Player
{
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span> Role { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span> Name { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
</span><span style="color: rgba(0, 0, 255, 1)">public</span> List<<span style="color: rgba(0, 0, 255, 1)">string</span>> HandCards { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
</span><span style="color: rgba(0, 0, 255, 1)">public</span> Player(<span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)"> name)
{
Name </span>=<span style="color: rgba(0, 0, 0, 1)"> name;
Role </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">农民</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
HandCards </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> List<<span style="color: rgba(0, 0, 255, 1)">string</span>><span style="color: rgba(0, 0, 0, 1)">();
}
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> GameRecordInfo
{
</span><span style="color: rgba(0, 0, 255, 1)">public</span> Player Player { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span> GameRecordText { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
</span><span style="color: rgba(0, 0, 255, 1)">public</span> CardsType? CardsType { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span>[] CardsNumber { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span>[] Cards { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">enum</span><span style="color: rgba(0, 0, 0, 1)"> CardsType
{
单牌, 对子, 连子, 顺子, 三带一, 炸弹
}</span></pre>
</div>
<p> </p><br><br>
来源:https://www.cnblogs.com/gmmy/p/18233297
頁:
[1]