当前位置:网站首页>C# 之 扑克游戏 -- 21点规则介绍和代码实现
C# 之 扑克游戏 -- 21点规则介绍和代码实现
2022-07-31 17:28:00 【陈言必行】
一,游戏介绍
1.1 游戏规则
21点又名黑杰克,该游戏由2到6个人玩,使用除大小王之外的52张牌,游戏者的目标是使手中的牌的点数之和不超过21点且尽量大。
1.2 牌点计算
A至10牌,按其原点数计算;J、Q、K都算作10点。
1.3 判断胜负
二十一点玩法规则和概率在二十一点游戏中,拥有最高点数的玩家获胜,其点数必须等于或低于21点;超过21点的玩家称为爆牌。拥有最高点数的玩家获胜,其点数必须等于或低于21点;超过21点之间判负。
二,游戏设计
2.1 游戏流程
发牌:
玩家和AI每人发两张牌,由手牌点数和大的玩家优先选择是否在牌堆中取牌取牌:
手牌点数和小于21,等待1中优先选择后再顺时针轮到其他玩家选择是否取牌取牌后:
若牌点大于21则直接判负出局,场上只剩1人,直接游戏结束;否则重复2-3
若牌点小于等于21则轮到下家取牌,重复2-3游戏结束
其他玩家取牌后都超过21点,只剩1人,直接获胜
所有玩家都选择不取牌后,按规则比较所有玩家手牌点数和,牌点大的获胜。
2.2 玩家类
由玩家自己选择是否继续拿牌。(输入Y继续拿牌,N为不拿牌)
2.3 AI类
简化AI逻辑,发牌后AI手牌和为4-8时继续拿牌,一直到17点或17点以上不再拿牌;因为此时再拿牌就有一半以上的概率超过21点。
三,参考代码
using System;
namespace _21dian
{
using System;
using System.Collections.Generic;
namespace Game21Points
{
class Project
{
static void Main(string[] args)
{
Console.WriteLine("----- 游戏开始 -----");
// 扑克牌
List<int> cards = new List<int>()
{
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52
};
// 创建对象
Poker poker = new Poker(cards);
Player player = new Player();
AIPlayer ai = new AIPlayer();
// --> 玩家入场
player.playerName = "Czhenya";
ai.playerName = "AI";
poker.AddPlayer(player);
poker.AddPlayer(ai);
// 事件关系绑定
poker.GameSratrHandler += player.GameStart;
poker.GameSratrHandler += ai.GameStart;
// 游戏开始
poker.GameStart();
// 每人发两张牌
poker.SendCard();
poker.SendCard();
// 询问取牌
poker.TaskCard();
Console.ReadKey();
}
}
abstract class AbsPlayer
{
public string playerName;
public bool IsContinueTakeCard = true;
public List<int> handCards = new List<int>();
public abstract void GameStart();
public virtual void SendCard(int card)
{
handCards.Add(card);
}
public abstract bool TakeCard();
public bool GameOver()
{
bool isGameOver;
if (HandCardsPoint > 21)
{
isGameOver = true;
}
else
{
isGameOver = !IsContinueTakeCard;
}
return isGameOver;
}
public int HandCardsPoint {
get {
return PokeTools.HandCardsSum(handCards); } }
}
class Player : AbsPlayer
{
public override void GameStart()
{
handCards.Clear();
Console.WriteLine("玩家整理了一下衣服,准备开局;");
}
public override void SendCard(int card)
{
handCards.Add(card);
Console.WriteLine("玩家发牌:" + PokeTools.PokerBrandByPoint(card));
}
public override bool TakeCard()
{
Console.WriteLine("当前您的手牌点数和为:" + HandCardsPoint);
Console.WriteLine("是否继续取牌(Y/N)?");
string readStr = Console.ReadLine();
// 输入Y取牌,其他为不取牌
IsContinueTakeCard = readStr.Equals("Y");
return IsContinueTakeCard;
}
}
class AIPlayer : AbsPlayer
{
public override void GameStart()
{
handCards.Clear();
Console.WriteLine("AI:清理一下内存,与之一战;");
}
public override void SendCard(int card)
{
base.SendCard(card);
Console.WriteLine("AI发牌:" + PokeTools.PokerBrandByPoint(card));
}
public override bool TakeCard()
{
// 手牌数点数小于17,就继续取牌
return HandCardsPoint < 17;
}
}
class Poker
{
List<AbsPlayer> players = new List<AbsPlayer>();
public Action GameSratrHandler;
public Action<int> SendCardHandler;
public Func<int, bool> TaskCardHandler;
// 发牌用
List<int> sendCards;
public Poker(List<int> cards)
{
// 复制一份发牌用
sendCards = new List<int>(cards);
}
public void AddPlayer(AbsPlayer player)
{
players.Add(player);
}
public void GameStart()
{
for (int i = 0; i < players.Count; i++)
{
if (!players[i].GameOver())
{
players[i].GameStart();
}
}
}
/// <summary>
/// 发牌 -- 会剔除已经发过的牌
/// </summary>
public void SendCard()
{
for (int i = 0; i < players.Count; i++)
{
players[i].SendCard(SendOneCard());
}
}
int SendOneCard()
{
// 随机发一张牌
Random random = new Random();
int index = random.Next(0, sendCards.Count);
// 取到牌值
int cardPoint = sendCards[index];
// 从手牌中移除 --> 为避免发到相同的牌
sendCards.RemoveAt(index);
return cardPoint;
}
public void TaskCard()
{
for (int i = 0; i < players.Count; i++)
{
// 选择取牌后再发一张牌
if (players[i].TakeCard())
{
players[i].SendCard(SendOneCard());
}
Console.WriteLine($"玩家:{
players[i].playerName} 手牌:{
PokeTools.ShowHandCard(players[i].handCards)}");
}
if (!GameOver())
{
TaskCard();
}
}
public bool GameOver()
{
int playerCount = 0;
for (int i = 0; i < players.Count; i++)
{
if (!players[i].GameOver())
{
playerCount++;
}
}
bool isGameOver = playerCount <= 1;
if (isGameOver)
{
Console.WriteLine("游戏结束:");
List<AbsPlayer> playerList = new List<AbsPlayer>();
int maxPoint = 0;
for (int i = 0; i < players.Count; i++)
{
if (players[i].HandCardsPoint > 21)
{
Console.WriteLine($"玩家:{
players[i].playerName} 爆牌了" );
}
else
{
playerList.Add(players[i]);
if (maxPoint < players[i].HandCardsPoint)
{
maxPoint = players[i].HandCardsPoint;
}
}
}
if (playerList.Count == 0)
{
Console.WriteLine("平局");
}
else if (playerList.Count == 1)
{
Console.WriteLine($"玩家:{
playerList[0].playerName} 赢了");
}
else
{
for (int i = 0; i < playerList.Count; i++)
{
if (maxPoint == playerList[i].HandCardsPoint)
{
Console.WriteLine($"玩家:{
playerList[i].playerName} 赢了");
}
}
}
}
return isGameOver;
}
}
}
class PokeTools
{
/// <summary>
/// 根据牌点返回牌名 如:14 ->红桃3
/// </summary>
/// <param name="card"></param>
/// <returns></returns>
public static string PokerBrandByPoint(int card)
{
if (card > 52 || card <= 0)
{
Console.WriteLine("不是扑克牌点");
return "不是扑克牌点";
}
string[] flowerColor = new string[4] {
"黑桃", "红桃", "梅花", "方片" };
string[] points = new string[13] {
"K", "A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q" };
int huaSe = (card - 1) / 13;
int point = card % 13;
// 返回花色 + 牌点 如:红桃3
return flowerColor[huaSe] + points[point];
}
/// <summary>
/// 手牌求和
/// </summary>
/// <param name="handCards"></param>
/// <returns></returns>
public static int HandCardsSum(List<int> handCards)
{
// "K", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q"
int[] points = new int[13] {
10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10 };
int sumRes = 0;
for (int i = 0; i < handCards.Count; i++)
{
sumRes += points[handCards[i] % 13];
}
return sumRes;
}
// 显示手牌
public static (string, string) ShowHandCard(List<int> handCards)
{
string resStr = "";
for (int i = 0; i < handCards.Count; i++)
{
resStr += PokeTools.PokerBrandByPoint(handCards[i]);
if (handCards.Count - 1 != i)
{
resStr += ",";
}
}
return (resStr, "牌点和:" + PokeTools.HandCardsSum(handCards));
}
}
}
测试结果:
边栏推荐
- 【愚公系列】2022年07月 Go教学课程 021-Go容器之切片操作
- All-platform GPU general AI video supplementary frame super-score tutorial
- UVM RAL模型和内置seq
- 牛客网刷题(四)
- MySQL---基本的select语句
- 多数据中心操作和检测并发写入
- server certificate verification failed. CAfile: /etc/ssl/certs/ca-certificates.crt CRLfile: none 失败
- 保证接口数据安全的10种方式
- iNeuOS工业互联网操作系统,设备运维业务和“低代码”表单开发工具
- 上传图片-微信小程序(那些年的坑记录2022.4)
猜你喜欢

仿生毛毛虫机器人源码

Combinatorics Notes (6) Associative Algebra of Locally Finite Partially Ordered Sets, Möbius Inversion Formula

新型电信“套路”,我爸中招了!

宁波大学NBU IT项目管理期末考试知识点整理

20.支持向量机—数学原理知识

基于WPF重复造轮子,写一款数据库文档管理工具(一)

AcWing 1282. 搜索关键词 题解((AC自动机)Trie+KMP)+bfs)

学生管理系统第一天:完成登录退出操作逻辑 PyQt5 + MySQL5.8

全平台GPU通用AI视频补帧超分教程

After Effects tutorial, How to adjust overexposed snapshots in After Effects?
随机推荐
牛客 HJ17 坐标移动
获取抖音视频详情 API
牛客 HJ20 密码验证合格程序
LevelSequence源码分析
Masterless replication system (2) - read and write quorum
牛客网刷题(四)
MySQL---基本的select语句
每日练习------随机产生一个1-100之间的整数,看能几次猜中。要求:猜的次数不能超过7次,每次猜完之后都要提示“大了”或者“小了”。
多数据中心操作和检测并发写入
Huawei's top engineers lasted nine years "anecdotal stories network protocol" PDF document summary, is too strong
Golang 必知必会Go Mod命令
JD.com searches for products by keyword API
【NLP】什么是模型的记忆力!
【pytorch】pytorch 自动求导、 Tensor 与 Autograd
go记录之——slice
【luogu P8326】Fliper (Graph Theory) (Construction) (Eulerian Circuit)
Last write wins (discards concurrent writes)
UserAgent 解析
mysql的备份表的几种方法
Verilog实现占空比为5/18的9分频