【C#】使用代码实现龙年春晚扑克牌魔术(守岁共此时),代码实现篇

欢迎来到《小5讲堂》
大家好,我是全栈小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#】约瑟夫原理举例2个代码实现
【C#】List泛型数据集如何循环移动,最后一位移动到第一位,以此类推

温故而知新,不同阶段重温知识点,会有不一样的认识和理解,博主将巩固一遍知识点,并以实践方式和大家分享,若能有所帮助和收获,这将是博主最大的创作动力和荣幸。也期待认识更多优秀新老博主。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/397006.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Sora:新一代实时音视频通信框架

一、Sora简介 Sora是一个开源的实时音视频通信框架&#xff0c;旨在提供高效、稳定、可扩展的音视频通信解决方案。它基于WebRTC技术&#xff0c;支持跨平台、跨浏览器的实时音视频通信&#xff0c;并且具备低延迟、高并发、易集成等特点。 --点击进入Sora(一定要科学哦&#x…

爬虫学习笔记-scrapy爬取电影天堂(双层网址嵌套)

1.终端运行scrapy startproject movie,创建项目 2.接口查找 3.终端cd到spiders,cd scrapy_carhome/scrapy_movie/spiders,运行 scrapy genspider mv https://dy2018.com/ 4.打开mv,编写代码,爬取电影名和网址 5.用爬取的网址请求,使用meta属性传递name ,callback调用自定义的…

PyQt应用程序中的多线程:使用Qt还是Python线程?

多线程模块能够更加高效得完成任务&#xff0c;但是在PyQt 应用程序中实现多线程可以使用 Qt 的线程模块&#xff08;QThread&#xff09;或者 Python 的 threading 模块。两者各有优劣&#xff0c;具体选择取决于项目需求和个人偏好。下面我们将以案例来说明两种模块具体得优缺…

欠定方程组及其求解

欠定方程组是指方程的数量少于未知数的数量的方程组。在这种情况下&#xff0c;通常有无限多个解&#xff0c;因为给定的方程不足以唯一确定所有未知数的值。在某些情况下&#xff0c;我们可以利用额外的信息或假设&#xff0c;如稀疏性或其他约束&#xff0c;来找到一个合理的…

嵌入式 系统 开发 - 第一件事 “搭开发环境”

无论是对DSP&#xff0c;FPGA&#xff0c;或其他可编程芯片开发 都要 “搭开发环境” &#xff1a; 懒得写太多字&#xff0c;画个图来扯淡吧&#xff01; 看看实际 怎么搞的 &#xff1a;&#xff09; 这张照片仅仅是 老哥 自己的一个DSP开发实际连结的搞法儿啊&#xff0c…

【Docker】集群容器监控和统计 Portainer基本用法

Portainer是一款轻量级的应用&#xff0c;它提供了图形化界面&#xff0c;用川于方便地管理Docker环境&#xff0c;包括单机环境和集群环境。 主要功能&#xff1a;实现集群容器的监控和统计 下载安装 官网&#xff1a;https://www.portainer.io 文档&#xff1a;https://do…

移动通信相关知识学习笔记

一、移动通信架构简图 移动无线的接入网是专指各种基站设备。核心网就是各种交换机。 二、无线信号基本原理 无线网络中&#xff0c;使用AP设备和天线来实现有线和无线信号互相转换。如上图所示&#xff0c;有线网络侧的数据从AP设备的有线接口进入AP后&#xff0c;经AP处理为…

ElasticSearch之Index Template 和Dynamic Template

写在前面 在ElasticSearch之Mapping 一文中我们一起看了es的dynamic mapping机制&#xff0c;通过该机制允许我们不需要显式的定义mapping信息&#xff0c;而是es根据插入的文档值来自动生成 &#xff0c;比如插入如下的文档&#xff1a; {"firstName": "Chan…

MySQL Replication

0 序言 MySQL Replication 是 MySQL 中的一个功能&#xff0c;允许从一个 MySQL 数据库服务器&#xff08;称为主服务器或 master&#xff09;复制数据和数据库结构到另一个服务器&#xff08;称为从服务器或 slave&#xff09;。这种复制是异步的&#xff0c;意味着从服务器不…

cRIO9040中NI9381模块的测试

硬件准备 CompactRIO9040NI9381直流电源&#xff08;可调&#xff09;网线 软件安装 下载地址 LabVIEW Real-Time 模块 NI CompactRIO 设备驱动程序 LabVIEW FPGA 模块&#xff08;可选&#xff09; 仅以下情况需要LabVIEW FPGA模块&#xff1a; 想为CompactRIO终端设计FP…

数据结构之线性表插入与删除运算

线性表 线性表的定义 线性表&#xff0c;或称表&#xff0c;是一种非常灵便的结构&#xff0c;可以根据需要改变表的长度&#xff0c;也可以在表中任何位置对元素进行访问、插入或删除等操作。另外&#xff0c;还可以将多个表连接成一个表&#xff0c;或把一个表拆分成多个表…

【git 使用】超级好用的 git reset 和 git revert 功能对比和使用方法

首先你要知道 git 区分暂存区和工作区&#xff0c;如果你用过 sourcetree 你就会知道 git reset 超级好用 git reset 命令用于将当前分支的 HEAD 指针移动到指定的提交&#xff0c;并且可以选择性地修改工作区和暂存区的状态。git reset 命令有几种常用的用法&#xff0c;主要…

【conda环境 安装 tensorflow2.2】 解决方案

1.检查anaconda安装&#xff1a;在cmd输入 conda --version 2.检测已经安装的环境&#xff1a;conda info --envs 3.新建一个python3.5的环境&#xff0c;tensorflow&#xff1a; ###conda create -n xxx python3.5 xxx为虚拟环境名 ###conda create -n xxx python3.6 xxx为虚拟…

VO、DTO、DO、BO、PO

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 VO、DTO、DO、BO1.概念阿里Java开发手册分层领域模型&#xff1a; 2. VO 和 DTO 使用场景以下是一个使用VO和DTO的典型案例&#xff1a; 3.BO和DTO的区别 案例 VO、…

【SpringBoot3】Spring Security 常用注解

注&#xff1a;本文基于Spring Boot 3.2.1 以及 Spring Security 6.2.1 Spring Security 6 的常用注解包括以下几种&#xff0c;通过这些注解可以更加方便的控制资源权限。 Secured &#xff1a;方法执行前检查&#xff0c;直接判断有没有对应的角色PreAuthorize&#xff1a;方…

Qt C++春晚刘谦魔术约瑟夫环问题的模拟程序

什么是约瑟夫环问题&#xff1f; 约瑟夫问题是个有名的问题&#xff1a;N个人围成一圈&#xff0c;从第一个开始报数&#xff0c;第M个将被杀掉&#xff0c;最后剩下一个&#xff0c;其余人都将被杀掉。例如N6&#xff0c;M5&#xff0c;被杀掉的顺序是&#xff1a;5&#xff…

tkinter做一个秒表

文章目录 需求和框架布局和主流程计时函数 需求和框架 本文试图实现一个简单的秒表&#xff0c;内容如下 这个软件非常简单&#xff0c;其UI元素只有一个文字标签外加三个按钮&#xff0c;这三个按钮的功能如下 点击Start按钮&#xff0c;开始进行计时&#xff0c;同时Start变…

已解决:IDEA中@Autowired自动注入MyBatis Mapper报红警告的几种解决方法

今天在使用 IDEA 使用 MyBatis 的时候遇到了这种情况&#xff1a; 可以看到 userMapper 下有个红色的波浪警告&#xff0c;虽然代码没有任何问题&#xff0c;能正常运行&#xff0c;但是这个红色警告在这里杵着确实让人很窝心。 于是我在网上找了找&#xff0c;最终明白了原因…

【鸿蒙系统学习笔记】状态管理

一、介绍 资料来自官网&#xff1a;文档中心 在声明式UI编程框架中&#xff0c;UI是程序状态的运行结果&#xff0c;用户构建了一个UI模型&#xff0c;其中应用的运行时的状态是参数。当参数改变时&#xff0c;UI作为返回结果&#xff0c;也将进行对应的改变。这些运行时的状…

电脑提醒待办事项:高效、快捷、更科学的方法

在这个快节奏的社会里&#xff0c;我常常感到时间不够用&#xff0c;仿佛一天24小时根本不够我分配。每天都有一大堆待办事项等着我&#xff0c;但总是有这样那样的事情让我分心&#xff0c;导致我经常忘记一些重要的任务。 每次当我想起那些被遗忘的待办事项时&#xff0c;都…