揭秘2024春晚刘谦魔术——代码还原

其他系列文章导航

Java基础合集
数据结构与算法合集

设计模式合集

多线程合集

分布式合集

ES合集


文章目录

其他系列文章导航

文章目录

前言

一、魔术大概流程

二、代码实现各个步骤

2.1 partition(对半撕牌)

2.2 bottom(将 n 张牌置底)

2.3 insert(三张牌随机插入到五张牌中间)

2.4 pop(丢第一张)

2.5 throwOneOrTwo(男生丢一张牌,女生丢两张)

2.6 mysticalWords(七字真言)

2.7 LeaveOneGoOne (置底一张丢一张)

三、整体代码及结果

四、总结


前言

随着 2024 年春晚的落幕,刘谦的魔术表演再次成为了人们热议的焦点。

从 2009 年到 2019 年,刘谦 10 年间 5 次亮相央视春晚舞台,一句“见证奇迹的时刻”成为刘谦的招牌台词。但从 2019 年在春晚表演《魔壶》之后,刘谦好像销声匿迹了,连续 5 年都与春晚无缘。2024 年 2 月 9 日晚,刘谦终于带着最新魔术节目《守岁共此时》再次亮相春晚,神乎其技的表现让观众直呼不可思议。

今天,我将尝试从编程的角度来揭秘刘谦的魔术,通过代码实现来解析其背后的原理。


一、魔术大概流程

观众们按照一定的顺序撕开扑克牌,通过名字字数、男女性别、南方北方等关键词进行排序筛选,最终丢弃了大部分的碎牌。而剩下的两张碎牌,竟然神奇地凑成了一张完整的牌。

大致流程:

  1. 随机选取四张牌。
  2. 对半撕开并叠在一起。
  3. 按照名字的长度把最上面的牌放到底部。
  4. 最上面三张牌随机插入到五张牌中间。
  5. 把最上面一张牌藏屁股下。
  6. 男生扔掉最上面一张牌,女生扔两张。
  7. 喊出七字真言,每喊一个字将一张牌置底。
  8. 然后置底一张丢一张,直到还剩一张。


二、代码实现各个步骤

2.1 partition(对半撕牌)

    static int[] partition(int[] arr) {
        int[] newArr = new int[arr.length * 2];
        System.arraycopy(arr, 0, newArr, 0, arr.length);
        System.arraycopy(arr, 0, newArr, 4, arr.length);
        return newArr;
    }
  • 目的:将输入的数组arr复制到一个新的数组中,并将arr的元素再复制一次到新的数组中的特定位置。
  • 实现:创建一个新数组newArr,其长度是arr的两倍。然后,使用System.arraycopy方法将arr的元素复制到newArr的前半部分和从索引4开始的位置。

 2.2 bottom(将 n 张牌置底)

    static int[] bottom(int[] arr, int n) {
        int[] newArr = new int[arr.length];
        System.arraycopy(arr, n, newArr, 0, arr.length - n);
        System.arraycopy(arr, 0, newArr, arr.length - n, n);
        return newArr;
    }
  • 目的:将arr数组中的前n个元素移动到数组的末尾,并将其余的元素移到数组的开头。
  • 实现:使用System.arraycopy方法实现元素的移动。

2.3 insert(三张牌随机插入到五张牌中间)

    static int[] insert(int[] arr) {
        int[] newArr = new int[arr.length];
        int n = new Random().nextInt(4) + 1;
        System.arraycopy(arr, 3, newArr, 0, n);
        System.arraycopy(arr, 0, newArr, n, 3);
        System.arraycopy(arr, 3 + n, newArr, 3 + n, arr.length - n - 3);
        return newArr;
    }
  • 目的:将arr数组中的前三个元素随机插入到数组的中间位置。
  • 实现:首先,生成一个1到4之间的随机数n。然后,使用System.arraycopy方法将前三个元素插入到新数组的随机位置,并将其余的元素放在正确的位置。

 2.4 pop(丢第一张)

    static int[] pop(int[] arr) {
        int[] newArr = new int[arr.length - 1];
        System.arraycopy(arr, 1, newArr, 0, arr.length - 1);
        return newArr;
    }
  • 目的:移除arr数组的第一个元素,并返回剩余的元素。
  • 实现:创建一个新的数组newArr,其长度比arr少1。然后,使用System.arraycopy方法将arr从索引1开始的所有元素复制到newArr

2.5 throwOneOrTwo(男生丢一张牌,女生丢两张)

    static int[] throwOneOrTwo(int[] arr, String gender) {
        if (gender.equals("女")) {
            int[] newArr = new int[arr.length - 2];
            System.arraycopy(arr, 2, newArr, 0, arr.length - 2);
            return newArr;
        } else {
            return pop(arr);
        }
    }
  • 目的:根据提供的性别(男或女)移除数组中的元素。如果是女性,则移除前两个元素;如果是男性,则移除第一个元素。
  • 实现:根据性别,调用pop方法或创建一个新的数组并复制从索引2开始的所有元素。

2.6 mysticalWords(七字真言)

     static int[] mysticalWords(int[] arr) {
        if (arr.length == 5) {
            return bottom(arr, 2);
        } else {
            return bottom(arr, 1);
        }
    }
  • 目的:根据数组的长度,将数组中的元素移动到特定的位置。如果数组长度为5,则移动最后两个元素到数组的底部;否则,移动最后一个元素到数组的底部。
  • 实现:根据数组的长度,调用bottom方法并传递相应的参数。

2.7 LeaveOneGoOne (置底一张丢一张)

    static int[] LeaveOneGoOne(int[] arr) {
        while (arr.length > 1) {
            int[] bottom = bottom(arr, 1);
            arr = pop(bottom);
        }
        return arr;
    }
  • 目的:不断从数组中移除元素,直到数组中只剩下一个元素。
  • 实现:使用while循环和前面定义的bottompop方法,每次循环都将数组的最后一个元素移动到数组的底部,并从数组中移除它。

三、整体代码及结果

代码:

public class Magic {
    public static void main(String[] args) {
        int[] arr = {1, 2, 3, 4};
        System.out.println("选取四张牌:"+ Arrays.toString(arr));
        int[] partition = partition(arr);
        System.out.println("对半撕开并叠在一起:"+ Arrays.toString(partition));
        int[] bottom = bottom(partition, 3);
        System.out.println("按照名字的长度把最上面的牌放到底部:"+ Arrays.toString(bottom));
        int[] insert = insert(bottom);
        System.out.println("最上面三张牌随机插入到五张牌中间:"+ Arrays.toString(insert));
        System.out.println("现在最上面的一张牌是:"+ insert[0]);
        int[] pop = pop(insert);
        System.out.println("把最上面一张牌藏屁股下,还剩:"+ Arrays.toString(pop));
        int[] throwOneOrTwo = throwOneOrTwo(pop, "女");
        System.out.println("男生扔掉最上面一张牌,女生扔两张:"+ Arrays.toString(throwOneOrTwo));
        int[] mysticalWords = mysticalWords(throwOneOrTwo);
        System.out.println("喊出七字真言,每喊一个字将一张牌置底"+ Arrays.toString(mysticalWords));
        int[] leaveOneGoOne = LeaveOneGoOne(mysticalWords);
        System.out.println("然后开始留下一张置底丢一张,直到还剩一张:"+ leaveOneGoOne[0]);
    }

    static int[] partition(int[] arr) {
        int[] newArr = new int[arr.length * 2];
        System.arraycopy(arr, 0, newArr, 0, arr.length);
        System.arraycopy(arr, 0, newArr, 4, arr.length);
        return newArr;
    }

    //下放 n 个
    static int[] bottom(int[] arr, int n) {
        int[] newArr = new int[arr.length];
        System.arraycopy(arr, n, newArr, 0, arr.length - n);
        System.arraycopy(arr, 0, newArr, arr.length - n, n);
        return newArr;
    }

    //最上面三个随机插入到五个中间
    static int[] insert(int[] arr) {
        int[] newArr = new int[arr.length];
        int n = new Random().nextInt(4) + 1;
        System.arraycopy(arr, 3, newArr, 0, n);
        System.arraycopy(arr, 0, newArr, n, 3);
        System.arraycopy(arr, 3 + n, newArr, 3 + n, arr.length - n - 3);
        return newArr;
    }

    //第一个去掉,藏屁股底下
    static int[] pop(int[] arr) {
        int[] newArr = new int[arr.length - 1];
        System.arraycopy(arr, 1, newArr, 0, arr.length - 1);
        return newArr;
    }

    //男生扔1,女生扔2
    static int[] throwOneOrTwo(int[] arr, String gender) {
        if (gender.equals("女")) {
            int[] newArr = new int[arr.length - 2];
            System.arraycopy(arr, 2, newArr, 0, arr.length - 2);
            return newArr;
        } else {
            return pop(arr);
        }
    }

    //七字真言
    static int[] mysticalWords(int[] arr) {
        if (arr.length == 5) {
            return bottom(arr, 2);
        } else {
            return bottom(arr, 1);
        }
    }

    //留下一个走一个
    static int[] LeaveOneGoOne(int[] arr) {
        while (arr.length > 1) {
            int[] bottom = bottom(arr, 1);
            arr = pop(bottom);
        }
        return arr;
    }
}

结果: 


四、总结

刘谦老师的魔术本质其实就是约瑟夫环的问题。

我认为这是语言类节目第一名。

充满了真情实感的欢声笑语。大家的参与性很高,过大年,追求的不过是热热闹闹,开开心心,这个节目做到了。


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

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

相关文章

Hive3.1.2——企业级调优

前言 本篇文章主要整理hive-3.1.2版本的企业调优经验,有误请指出~ 一、性能评估和优化 1.1 Explain查询计划 使用explain命令可以分析查询计划,查看计划中的资源消耗情况,定位潜在的性能问题,并进行相应的优化。 explain执行计划…

力扣---通配符匹配

题目描述: 给你一个输入字符串 (s) 和一个字符模式 (p) ,请你实现一个支持 ? 和 * 匹配规则的通配符匹配: ? 可以匹配任何单个字符。 * 可以匹配任意字符序列(包括空字符序列)。 判定匹配成功的充要条件是&#xff…

GPT-4影响高度创新思维的领域(一)

GPT-4的应用范围不再局限于对现有信息的检索、整理和复述,而是进一步拓展到了诸如文学创作、科学假设生成、教育辅导、商业策略建议等需要高度创新思维的领域。这种独立思考和创新能力赋予了GPT-4作为虚拟助手时更加丰富多元的角色定位,使其成为一种强大…

VBAR设置方法

Uboot源码: /** Setup vector:* (OMAP4 spl TEXT_BASE is not 32 byte aligned.* Continue to use ROM code vector only in OMAP4 spl)*/ #if !(defined(CONFIG_OMAP44XX) && defined(CONFIG_SPL_BUILD))/* Set V0 in CP15 SCTLR register - for VBAR to …

SelfAttention|自注意力机制ms简单实现

自注意力机制学习有感 观看b站博主的讲解视频以及跟着他的pytorch代码实现mindspore的自注意力机制:up主讲的很好,推荐入门自注意力机制。 import mindspore as ms import mindspore.nn as nn from mindspore import Parameter from mindspore import …

LeetCode 0987.二叉树的垂序遍历:遍历时存节点信息,遍历完自定义排序

【LetMeFly】987.二叉树的垂序遍历:遍历时存节点信息,遍历完自定义排序 力扣题目链接:https://leetcode.cn/problems/vertical-order-traversal-of-a-binary-tree/ 给你二叉树的根结点 root ,请你设计算法计算二叉树的 垂序遍历…

前端秘法进阶篇之事件循环

目录 一.浏览器的进程模型 1.进程 2.线程 二.浏览器的进程和线程 1. 浏览器进程 2. 网络进程 3. 渲染进程 三.渲染主线程 四.异步 五.优先级 1. 延时队列: 2.交互队列: 3.微队列: 六.JS 的事件循环 附加:JS 中的计时器能做到精…

XMall 开源商城 SQL注入漏洞复现(CVE-2024-24112)

0x01 产品简介 XMall 开源电商商城 是开发者Exrick的一款基于SOA架构的分布式电商购物商城 前后端分离 前台商城:Vue全家桶 后台管理:Dubbo/SSM/Elasticsearch/Redis/MySQL/ActiveMQ/Shiro/Zookeeper等。 0x02 漏洞概述 XMall 开源商城 /item/list、/item/listSearch、/sys/…

【Android】使用Android Studio打包APK文件

文章目录 1. 新建项目2. 打包生成APK3. 安装APK 1. 新建项目 打包APK之前,首先需要新建项目,有基础的可以跳过。 无基础的可以参考:使用Android Studio运行Hello World项目 2. 打包生成APK 1.找到Build -> Generate Signed Bundle or …

【C/C++语法基础】2.输入与输出(✨新手推荐阅读)

前言 在C中,输入与输出是程序与用户进行交互的基本方式。C提供了多种方式进行数据的输入与输出,其中最常用的是printf、scanf、cin和cout。此外,我们还会讨论如何取消cin和cout的同步流,以及了解各种转义字符的用法。 1.printf函…

arkTS开发鸿蒙OS个人商城案例【2024最新 新年限定开发案例QAQ】

龙年前述 源码获取>文章下方二维码,回复关键字“鸿蒙OS商场源码” 前言 arkTS是华为自己研发的一套前端语言,是在js和ts技术的基础上又进行了升级而成! 本篇文章会带领大家通过arkTSnode.jsmongoDB来完成一个鸿蒙OS版本的商城案例&…

flask cors 跨域问题解决

座右铭:怎么简单怎么来,以实现功能为主。 欢迎大家关注公众号与我交流 环境安装 pip install -U flask-cors 示例代码 from flask import Flask from flask_cors import CORS, cross_originapp Flask(__name__) CORS(app, supports_credentialsTrue)…

__attribute__ ---Compile

Section for attribute attribute_?嵌入式C代码属性怎么定义 https://www.elecfans.com/d/2269222.html section 属性的主要作用是:在程序编译时,将一个函数或者变量放到指定的段,即指定的section 中。 一个可执行文件注意由代…

AI算法初识之分类汇总

一、背景 AI算法的分类方式多种多样,可以根据不同的学习机制、功能用途以及模型结构进行划分。以下是一些主要的分类方式及相应的代表性算法: 1. 按照学习类型 - **监督学习**: - 线性回归(Linear Regression) …

学会如何备份u盘数据,让数据安全有保障

随着科技的发展,U盘已成为我们日常生活和工作中不可或缺的数据存储设备。然而,无论U盘的质量如何,数据丢失的风险始终存在。可能是硬件故障、意外删除、病毒感染或其他不可预见的原因。 尽管当前提供了多种数据恢复方案,然而没有一…

【Midjourney】解密Midjourney付费订阅:畅享全新体验!(详细流程与各版本一览)

一、Midjourney 付费订阅流程 1、在首页点击Purchase plan 2、进入到midjourney年月选择页面 3、这里续费一个最便宜的版本 , 按年付费 8 , 按月 10 4、输入银行卡信息 , 用的WildCard虚拟信用卡 ,打开 5、填写完银行卡信息就订阅成功 二、Midjourney 各版本介绍…

山西电力市场日前价格预测【2024-02-12】

日前价格预测 预测说明: 如上图所示,预测明日(2024-02-12)山西电力市场全天平均日前电价为127.42元/MWh。其中,最高日前电价为369.24元/MWh,预计出现在18:45。最低日前电价为0.00元/MWh,预计出…

QT 菜单栏

添加/删除菜单栏 默认情况下QMainWindow项目一创建就自带了菜单栏,可以在对象树窗口中,右键菜单栏对象,移除菜单栏: 删除后也可以创建菜单栏,此时在对象树中右键MainWindow对象,菜单里边会多了创建菜单栏的…

[OPEN SQL] 新增数据

INSERT语句用于数据的新增操作 本次操作使用的数据库表为SCUSTOM&#xff0c;其字段内容如下所示 航班用户(SCUSTOM) 该数据库表中的部分值如下所示 1.插入单条数据 语法格式 INSERT <dbtab> FROM <wa>. INSERT INTO <dbtab> VALUES <wa>. INSERT &…

Hive的相关概念——分区表、分桶表

目录 一、Hive分区表 1.1 分区表的概念 1.2 分区表的创建 1.3 分区表数据加载及查询 1.3.1 静态分区 1.3.2 动态分区 1.4 分区表的本质及使用 1.5 分区表的注意事项 1.6 多重分区表 二、Hive分桶表 2.1 分桶表的概念 2.2 分桶表的创建 2.3 分桶表的数据加载 2.4 …