C#使用代码实现春晚扑克牌魔术

 更新时间:2024年02月20日 15:54:04   作者:全栈小5  
这篇文章主要为大家详细介绍了C#如何使用代码实现龙年春晚扑克牌魔术(守岁共此时),文中的示例代码讲解详细,感兴趣的小伙伴可以了解一下

前言

2024年春晚上,表演了一个魔术《守岁共此时》,博主也跟着做了一遍,确实都成功了。

对于此魔术的好奇心,博主从代码逻辑的角度思考了下,肯定是可以实现的,毕竟代码只是一个工具,只要实际逻辑合理基本没问题。

本篇文章将通过代码步骤进行描述和实现。

实际上,了解原理后,使用递归方法和循环队列去实现是比较合理的。

实现步骤

为了方便查看,每一个步骤都把变化前的扑克牌保存到一个泛型变量里

设置变量

姓名、来自区域、以及性别,这三者为变量,决定每个人手上牌的顺序会不一样。

string myName = "小美";
string positionValue = "北方人";
string sex = "女生";

设置牌

设置好52张扑克牌

List<string> tempList = new List<string>();

string pokerStr = @"黑桃-A、黑桃-2、黑桃-3、黑桃-4、黑桃-5、黑桃-6、黑桃-7、黑桃-8、黑桃-9、黑桃-10、黑桃-J、黑桃-Q、黑桃-K、
红桃-A、红桃-2、红桃-3、红桃-4、红桃-5、红桃-6、红桃-7、红桃-8、红桃-9、红桃-10、红桃-J、红桃-Q、红桃-K、
梅花-A、梅花-2、梅花-3、梅花-4、梅花-5、梅花-6、梅花-7、梅花-8、梅花-9、梅花-10、梅花-J、梅花-Q、梅花-K、
方块-A、方块-2、方块-3、方块-4、方块-5、方块-6、方块-7、方块-8、方块-9、方块-10、方块-J、方块-Q、方块-K";
List<string> pokerList = pokerStr.Split('、').Select(a=>a.Replace("\r\n","").Trim()).ToList();

随机牌

通过上一步骤设置的52张牌,随机产生4张牌

// 随机四张
List<string> myPokerList = new List<string>();
for(int i = 0; i < 4; i++)
{
    int randomIndex = new Random().Next(0, pokerList.Count);
    string pokder = pokerList[randomIndex];
    myPokerList.Add(pokder);
    pokerList.RemoveAt(randomIndex);
}

撕开两半

撕开两半,并且右边的一半放到底部,对于数组而言实际上就是放到首位

// 撕开2半
List<string> newList = new List<string>();
tempList = NewOrder(myPokerList);

// 右半边
for (int i = 0; i < tempList.Count; i++)
{
    newList.Add($"{tempList[i]}-右");
}

// 左半边
for (int i = 0; i < tempList.Count; i++)
{
    newList.Add($"{tempList[i]}-左");
}

姓名牌

每个人姓名长度不一样,顺序也就不一样,下面代码实现比较逻辑,其实目标就是把最上面的一张牌放到底部,多少个字就放几次。
博主姓名是三个字,就依次放三张牌到底部。代码实现逻辑就是数组最后一个值放到首位。

// 姓名数字 - 动态值
int myNameLength = myName.Length;
string nameString = string.Empty;
List<string> nameList = new List<string>();
List<string> nameListMy = new List<string>();
for (int i = 0; i < myNameLength; i++)
{
    string pv = newList[newList.Count - 1 - i];
    nameListMy.Add(pv);
    nameString = $"{pv},{nameString}";
}
for (int i = 0; i < newList.Count - myNameLength; i++)
{
    nameString += $",{newList[i]}";
}
nameList = nameString.Split(',').Where(a => !string.IsNullOrWhiteSpace(a)).ToList();

任意牌

拿起最上面3张牌,插入到任意牌的中间,1、2、3、4、5,1到5之间插入

// 
int topValue = 3;
int randomValue = new Random().Next(1, nameList.Count - topValue - 1);
List<string> top3List = new List<string>();
for (int i = 0; i < nameList.Count - topValue; i++)
{
    if (i == randomValue)
    {
        for (int j = topValue; j > 0; j--)
        {
            top3List.Add(nameList[nameList.Count - j]);
        }
    }

    top3List.Add(nameList[i]);
}

标记牌

拿起最上面一张牌,就是黑桃3-右,放到一遍,在数组里就是移除此张牌,并保存到一个变量里

// 【第一次移除牌】
// 拿起最上面一张牌,就是黑桃3-右,放到一遍
string topPoker = top3List[top3List.Count - 1];
List<string> sevenList = new List<string>();
for (int i = 0; i < top3List.Count - 1; i++)
{
    sevenList.Add(top3List[i]);
}

区域牌

南方人:拿起一张牌、北方人:拿起两张牌、不知道是南方还是北方人:拿起三张牌

插入到剩下牌的中间,1到5或者1到6之间插入

int fromValue = (positionValue == "南方人" ? 1 : positionValue == "北方人" ? 2 : 3);
int randomValue2 = new Random().Next(1, sevenList.Count - fromValue - 1);
List<string> fromList = new List<string>();
for (int i = 0; i < sevenList.Count - fromValue; i++)
{
    if (i == randomValue2)
    {
        for (int j = fromValue; j > 0; j--)
        {
            fromList.Add(sevenList[sevenList.Count - j]);
        }
    }

    fromList.Add(sevenList[i]);
}

性别牌

男生:拿起一张、女生:拿起两张、拿起的牌,撒到空中去,就是从数组中移除

// 【再次移除牌】

int sexType = (sex == "男生" ? 1 : 2);
List<string> sexList = new List<string>();
for (int i = 0; i < fromList.Count - sexType; i++)
{
    sexList.Add(fromList[i]);
}

循环牌

见证奇迹的时刻,这是七个字,就是循环遍历7次,对于数组而言,就是循环从最后一个值移动到第一个值。

string textValue = "见证奇迹的时刻";
List<string> forList = new List<string>();
for (int i = 0; i < sexList.Count; i++)
{
    forList.Add(sexList[i]);
}

for (int i = 0; i < textValue.Length; i++)
{
    string lastElement = forList[forList.Count - 1]; // 保存最后一个元素的值
    forList.RemoveAt(forList.Count - 1); // 移除最后一个元素
    forList.Insert(0, lastElement); // 将最后一个元素插入到第一个位置
}

好运牌

最后一个环节:好运留下来,烦恼丢出去

第一张放到下面,然后最上面的丢出去,就是移除数组最后一个

List<string> lastList = new List<string>();
for (int i = 0; i < forList.Count; i++)
{
    lastList.Add(forList[i]);
}
while (lastList.Count > 1)
{
    string lastElement = lastList[lastList.Count - 1]; // 保存最后一个元素的值
    lastList.RemoveAt(lastList.Count - 1); // 移除最后一个元素
    lastList.Insert(0, lastElement); // 将最后一个元素插入到第一个位置

    lastList.RemoveAt(lastList.Count - 1);
}
string lastPoker = lastList[0];

// 合并扑克牌
string allPoker = $"【{lastPoker}】【{topPoker}】";

约瑟夫原理

上面扑克牌魔术没想到用到了这个原理,不是每个人都能快速理解各种各样的原理,所以这也早就了魔术神奇而又神秘的一面。

约瑟夫原理(也称为约瑟夫问题或约瑟夫环)是一个著名的理论问题,其起源可以追溯到公元1世纪的一个历史事件。据传,著名犹太历史学家Josephus和他的同伴被敌人包围,在面临绝境时,他们决定通过自杀的方式结束生命。为了执行这个决定,他们围成一个圈,然后按照一定的规则来选择自杀的人,直到只剩下最后一个人。Josephus作为一个不愿意自杀的人,快速地计算出了一个位置,使得他成为了最后一个存活的人,从而有机会逃脱。

这个问题可以用数学模型进行抽象和解释。假设有n个人围成一圈,从某个人开始,按顺时针方向逐一编号。接着从编号为1的人开始报数,每数到m就将该人从圈中排除,然后从下一个人重新开始报数,直到圈中只剩下一个人。最后剩下的这个人的位置就是从1开始数的序号。这个问题可以用数学公式或伪代码进行求解。

约瑟夫原理在理论计算机科学、组合数学、离散数学等领域有着广泛的应用。它不仅是一个有趣的问题,还可以用于解决各种实际问题,如任务调度、资源管理、网络通信等。通过研究和应用约瑟夫原理,可以更好地理解和解决一些复杂的计算和决策问题。

完整代码

博主使用C#语言比较多,因此下面是以C#代码进行实现,感兴趣的小伙伴可以使用其他语言实现

主要代码

string myName = "小美";
string positionValue = "北方人";
string sex = "女生";

List<string> tempList = new List<string>();

string pokerStr = @"黑桃-A、黑桃-2、黑桃-3、黑桃-4、黑桃-5、黑桃-6、黑桃-7、黑桃-8、黑桃-9、黑桃-10、黑桃-J、黑桃-Q、黑桃-K、
红桃-A、红桃-2、红桃-3、红桃-4、红桃-5、红桃-6、红桃-7、红桃-8、红桃-9、红桃-10、红桃-J、红桃-Q、红桃-K、
梅花-A、梅花-2、梅花-3、梅花-4、梅花-5、梅花-6、梅花-7、梅花-8、梅花-9、梅花-10、梅花-J、梅花-Q、梅花-K、
方块-A、方块-2、方块-3、方块-4、方块-5、方块-6、方块-7、方块-8、方块-9、方块-10、方块-J、方块-Q、方块-K";
List<string> pokerList = pokerStr.Split('、').Select(a=>a.Replace("\r\n","").Trim()).ToList();

// 随机四张
List<string> myPokerList = new List<string>();
for(int i = 0; i < 4; i++)
{
    int randomIndex = new Random().Next(0, pokerList.Count);
    string pokder = pokerList[randomIndex];
    myPokerList.Add(pokder);
    pokerList.RemoveAt(randomIndex);
}


// 撕开2半
List<string> newList = new List<string>();
tempList = NewOrder(myPokerList);

// 右半边
for (int i = 0; i < tempList.Count; i++)
{
    newList.Add($"{tempList[i]}-右");
}

// 左半边
for (int i = 0; i < tempList.Count; i++)
{
    newList.Add($"{tempList[i]}-左");
}

// 姓名数字 - 动态值
int myNameLength = myName.Length;
string nameString = string.Empty;
List<string> nameList = new List<string>();
List<string> nameListMy = new List<string>();
for (int i = 0; i < myNameLength; i++)
{
    string pv = newList[newList.Count - 1 - i];
    nameListMy.Add(pv);
    nameString = $"{pv},{nameString}";
}
for (int i = 0; i < newList.Count - myNameLength; i++)
{
    nameString += $",{newList[i]}";
}
nameList = nameString.Split(',').Where(a => !string.IsNullOrWhiteSpace(a)).ToList();

// 拿起最上面3张牌,插入到任意牌的中间,1、2、3、4、5,1到5之间插入
int topValue = 3;
int randomValue = new Random().Next(1, nameList.Count - topValue - 1);
List<string> top3List = new List<string>();
for (int i = 0; i < nameList.Count - topValue; i++)
{
    if (i == randomValue)
    {
        for (int j = topValue; j > 0; j--)
        {
            top3List.Add(nameList[nameList.Count - j]);
        }
    }

    top3List.Add(nameList[i]);
}

// 【第一次移除牌】
// 拿起最上面一张牌,就是黑桃3-右,放到一遍
string topPoker = top3List[top3List.Count - 1];
List<string> sevenList = new List<string>();
for (int i = 0; i < top3List.Count - 1; i++)
{
    sevenList.Add(top3List[i]);
}

// 南方人:拿起一张牌、北方人:拿起两张牌、不知道是南方还是北方人:拿起三张牌
// 插入到剩下牌的中间,1到5或者1到6之间插入
int fromValue = (positionValue == "南方人" ? 1 : positionValue == "北方人" ? 2 : 3);
int randomValue2 = new Random().Next(1, sevenList.Count - fromValue - 1);
List<string> fromList = new List<string>();
for (int i = 0; i < sevenList.Count - fromValue; i++)
{
    if (i == randomValue2)
    {
        for (int j = fromValue; j > 0; j--)
        {
            fromList.Add(sevenList[sevenList.Count - j]);
        }
    }

    fromList.Add(sevenList[i]);
}

// 【再次移除牌】
// 男生:拿起一张、女生:拿起两张、拿起的牌,撒到空中去,就是从数组中移除
int sexType = (sex == "男生" ? 1 : 2);
List<string> sexList = new List<string>();
for (int i = 0; i < fromList.Count - sexType; i++)
{
    sexList.Add(fromList[i]);
}

// 见证奇迹的时刻
string textValue = "见证奇迹的时刻";
List<string> forList = new List<string>();
for (int i = 0; i < sexList.Count; i++)
{
    forList.Add(sexList[i]);
}

for (int i = 0; i < textValue.Length; i++)
{
    string lastElement = forList[forList.Count - 1]; // 保存最后一个元素的值
    forList.RemoveAt(forList.Count - 1); // 移除最后一个元素
    forList.Insert(0, lastElement); // 将最后一个元素插入到第一个位置
}

// 最后一个环节:好运留下来,烦恼丢出去
// 第一张放到下面,然后最上面的丢出去,就是移除数组最后一个
List<string> lastList = new List<string>();
for (int i = 0; i < forList.Count; i++)
{
    lastList.Add(forList[i]);
}
while (lastList.Count > 1)
{
    string lastElement = lastList[lastList.Count - 1]; // 保存最后一个元素的值
    lastList.RemoveAt(lastList.Count - 1); // 移除最后一个元素
    lastList.Insert(0, lastElement); // 将最后一个元素插入到第一个位置

    lastList.RemoveAt(lastList.Count - 1);
}
string lastPoker = lastList[0];

// 合并扑克牌
string allPoker = $"【{lastPoker}】【{topPoker}】";

打乱顺序

private List<string> NewOrder(List<string> list)
{
    Random random = new Random();

    for (int i = list.Count - 1; i > 0; i--)
    {
        int j = random.Next(i + 1);
        string temp = list[i];
        list[i] = list[j];
        list[j] = temp;
    }

    return list;
}

到此这篇关于C#使用代码实现春晚扑克牌魔术的文章就介绍到这了,更多相关C#扑克牌魔术内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C#生成Word文档代码示例

    C#生成Word文档代码示例

    这篇文章主要介绍了C#生成Word文档代码示例,本文直接给出代码实例,需要的朋友可以参考下
    2015-06-06
  • C#中Type类的具体使用

    C#中Type类的具体使用

    C#中的Type类是System命名空间的核心组件,可通过typeof、GetType或Type.GetType获取,支持检查类型结构、动态创建对象及调用成员,下面就来具体介绍一下
    2025-07-07
  • C#高保真实现Word转HTML实战指南

    C#高保真实现Word转HTML实战指南

    在数字化办公中,文档内容的高效流转与展示是企业应用和Web服务不可或缺的一环,本文将探讨如何利用 C# 语言,并借助专业的文档处理库,实现高保真的 Word转HTML 转换,需要的可以了解下
    2025-08-08
  • C#中Socket通信用法实例详解

    C#中Socket通信用法实例详解

    这篇文章主要介绍了C#中Socket通信用法,以实例形式较为详细的分析了UDP及TCP两种通信方式的具体实现技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-09-09
  • C#判断页面中的多个文本框输入值是否有重复的实现方法

    C#判断页面中的多个文本框输入值是否有重复的实现方法

    这篇文章主要介绍了C#判断页面中的多个文本框输入值是否有重复的实现方法,是一个非常简单实用的技巧,需要的朋友可以参考下
    2014-10-10
  • C#中判断、验证字符串是否为日期格式的实现代码

    C#中判断、验证字符串是否为日期格式的实现代码

    这篇文章主要介绍了C#中判断、验证字符串是否为日期格式的实现代码,使用DateTime类中自带的两个方法实现,需要的朋友可以参考下
    2014-08-08
  • Unity调用打印机打印图片

    Unity调用打印机打印图片

    这篇文章主要为大家详细介绍了Unity通过调用打印机打印图片的代码,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-10-10
  • C#实现窗体抖动的两种方法

    C#实现窗体抖动的两种方法

    这篇文章主要为大家详细介绍了C#实现窗体抖动的两种方法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-11-11
  • C#程序最小化到托盘图标操作步骤与实现代码

    C#程序最小化到托盘图标操作步骤与实现代码

    设置窗体属性showinTask=false;加notifyicon控件notifyIcon1,为控件notifyIcon1的属性Icon添加一个icon图标;添加窗体最小化事件(首先需要添加事件引用)接下来介绍实现代码,感兴趣的朋友可以研究下
    2012-12-12
  • C#中 paint()与Onpaint()的区别

    C#中 paint()与Onpaint()的区别

    paint是事件onpaint方法onpaint方法是调用paint事件的,用哪一个,效果是一样,就看那一个方便了内部是这样实现的:
    2013-04-04

最新评论