2024春晚 刘谦&尼格买提 扑克魔术 C++ 复现

本文介绍了如何使用C++编写一个名为PokerMagic的程序,模仿春晚魔术中的扑克牌排列过程,涉及随机数生成、数组操作和算法应用。
摘要由CSDN通过智能技术生成

2024春晚 刘谦&尼格买提 扑克魔术 C++ 复现
std::rotate
知乎

// clang-format off
/*
rm -rf *.o *.out;g++ poker_magic.cpp -o ./poker_magic.out -Wall -g3 -gdwarf-2 -m64 -std=c++17 -Werror=reorder -Werror=sign-compare -Werror=strict-aliasing -fdiagnostics-color -fsanitize=address -fno-elide-constructors -fsanitize=undefined -fsanitize=leak -Wconversion -pedantic -Wextra -Werror;./poker_magic.out

*/
#include <any>
#include <tuple>
#include <deque>
#include <vector>
#include <random>
#include <cassert>
#include <iostream>
#include <algorithm>
#include <unordered_set>
// clang-format on

namespace NS_PokerMagic
{
	inline namespace _utility
	{
		inline static std::random_device random_device_{};
		inline static std::mt19937 generator_{random_device_()};

		uint64_t generate_rand_number()
		{
			static std::uniform_int_distribution<uint64_t> distribute(1ul, 13ul);  // 使用均匀分布生成[1, 13]范围内的随机整数
			return distribute(generator_);
		}
		uint64_t generate_specified_random_number(const std::vector<uint64_t>& specified_set)
		{
			std::uniform_int_distribution<uint64_t> distribute(0ul, specified_set.size() - 1ul);
			return specified_set.at(distribute(generator_));
		}

		template <typename T>
		void print_deque(const std::deque<T>& pokers, const bool enable = true)
		{
			if (!enable) return;

			for (auto&& element : pokers)
			{
				std::cout << element << " ";
			}
			std::cout << std::endl;
		}
		enum class NameWords : uint64_t
		{
			kTwo = 2ul,
			kThree = 3ul,
			kSeven = 7ul
		};
		enum class Area : uint64_t
		{
			kNorth = 1ul,
			kSouth = 2ul,
			kUnknown = 3ul
		};
		enum class Gender : uint64_t
		{
			kGirl = 0ul,
			kBoy = 1ul
		};
	}  // namespace _utility

	class Poker
	{
	public:
		Poker() { reset(); }
		~Poker() = default;

		Poker(const Poker&) = delete;
		Poker& operator=(const Poker&) = delete;

		Poker(Poker&&) noexcept = delete;
		Poker& operator=(Poker&&) noexcept = delete;

		void reset()
		{
			std::unordered_set<uint64_t> four_random_pokers;
			while (four_random_pokers.size() < 4ul)
			{
				four_random_pokers.insert(generate_rand_number());
			}
			poker_.assign(four_random_pokers.begin(), four_random_pokers.end());
			std::copy(poker_.begin(), poker_.end(), std::back_inserter(poker_));
			assert(poker_.size() == 8ul);
			std::cout << "Pokers = ";
			print_deque(poker_, true);
		}

		operator std::deque<uint64_t>&() { return poker_; }

		std::deque<uint64_t>& get_poker() { return poker_; }

	private:
		std::deque<uint64_t> poker_{};
	};

	class Person
	{
	public:
		Person() { random_infomation(); }
		~Person() = default;

		Person(const NameWords& name_words, const Area& area, const Gender& gender) : Person(static_cast<uint64_t>(name_words), static_cast<uint64_t>(area), static_cast<uint64_t>(gender)) {}

		Person(const Person&) = delete;
		Person& operator=(const Person&) = delete;

		Person(Person&&) noexcept = delete;
		Person& operator=(Person&&) noexcept = delete;

		void show(Poker& pk, const bool enable_print = 0)
		{
			std::deque<uint64_t>& poker = pk;

			// 1. 根据名字内字的个数 将牌移到后面
			std::rotate(poker.begin(), poker.begin() + name_words_, poker.end());
			print_deque(poker, enable_print);

			// 2. 将前三张牌插入中间
			auto middle = (poker.begin() + 3ul) + (poker.size() - 3ul) / 2ul;
			std::rotate(poker.begin(), poker.begin() + 3, middle);
			print_deque(poker, enable_print);

			// 3. 取出预留目标牌 (即最上面的一张)
			const uint64_t target = poker.at(0ul);
			std::cout << "Target = " << target << std::endl;
			poker.pop_front();
			print_deque(poker, enable_print);

			// 3. 根据地区:北方/南方/不明, 将前 1/2/3 张插入中间
			middle = (poker.begin() + area_) + (poker.size() - area_) / 2ul;
			std::rotate(poker.begin(), poker.begin() + area_, middle);
			print_deque(poker, enable_print);

			// 4. boys 丢掉一张或 girls 丢掉两张
			if (gender_ == 1ul)  // boys
			{
				poker.pop_front();
			}
			else  // girls
			{
				poker.pop_front();
				poker.pop_front();
			}
			print_deque(poker, enable_print);

			// 5. 见证奇迹的时刻
			constexpr std::string_view seven_character_mantra{"见证奇迹的时刻"};
			constexpr uint64_t seven_size = (seven_character_mantra.size() / 3ul);
			for (uint64_t i = 0; i < seven_size; ++i)
			{
				std::rotate(poker.begin(), poker.begin() + 1, poker.end());
				print_deque(poker, enable_print);
			}

#if 0  // 现场
			if (gender_ == 1ul)
			{
				while (poker.size() != 2ul)
				{
					std::rotate(poker.begin(), poker.begin() + 1ul, poker.end());
					poker.pop_front();
				}
			}
			else
			{
				while (poker.size() != 1)
				{
					std::rotate(poker.begin(), poker.begin() + 1ul, poker.end());
					poker.pop_front();
				}
			}
			if (gender_ == 1ul)
			{
				assert(poker.size() == 2ul);
				std::rotate(poker.begin(), poker.begin() + 1ul, poker.end());
				poker.pop_front();
			}
			else
			{
				assert(poker.size() == 1ul);
			}
#else
			// 6. 好运留下来 烦恼丢出去
			while (poker.size() != 1ul)
			{
				std::rotate(poker.begin(), poker.begin() + 1ul, poker.end());
				poker.pop_front();
			}
#endif
			// 7. 预期 assert
			assert(poker.size() == 1ul);
			std::cout << "Remain = ";
			print_deque(poker, true);
			assert(poker.at(0ul) == target);
		}

		static void test_magic_show()
		{
			Poker poker;

			Person person_1;
			person_1.show(poker);

			Person person_2(NameWords::kTwo, Area::kNorth, Gender::kBoy);
			poker.reset();
			person_2.show(poker);

			Person person_3(NameWords::kThree, Area::kNorth, Gender::kGirl);
			poker.reset();
			person_3.show(poker);
		}

	private:
		Person(const uint64_t name_words, const uint64_t area, const uint64_t gender) : name_words_(name_words), area_(area), gender_(gender)
		{
			assert(name_words == 2ul || name_words == 3ul || name_words == 7ul);
			assert(area == 1ul || area == 2ul || area == 3ul);
			assert(gender == 1ul || gender == 0ul);
		}

		void random_infomation()
		{
#define CAST(arg) static_cast<uint64_t>(arg)
			const std::vector<uint64_t> name_word_collect{CAST(NameWords::kTwo), CAST(NameWords::kThree), CAST(NameWords::kSeven)};
			const std::vector<uint64_t> area_collect{CAST(Area::kNorth), CAST(Area::kSouth), CAST(Area::kUnknown)};
			const std::vector<uint64_t> gender_collect{CAST(Gender::kGirl), CAST(Gender::kBoy)};
#undef CAST

			name_words_ = generate_specified_random_number(name_word_collect);
			area_ = generate_specified_random_number(area_collect);
			gender_ = generate_specified_random_number(gender_collect);
		}

	private:
		uint64_t name_words_;
		uint64_t area_;
		uint64_t gender_;
	};
}  // namespace NS_PokerMagic

int main([[maybe_unused]] int argc, [[maybe_unused]] const char* argv[])
{
	NS_PokerMagic::Person::test_magic_show();
	return 0;
}

输出

Pokers = 8 13 2 7 8 13 2 7 
Target = 2
Remain = 2 

Pokers = 1 4 2 5 1 4 2 5 
Target = 4
Remain = 4 

Pokers = 3 11 1 4 3 11 1 4 
Target = 1
Remain = 1 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值