【C++】B2112 石头剪子布



博客主页:[小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C++


文章目录



💯前言

  • "石头剪子布"是一种经典游戏,它不仅规则简单,还能引发复杂的编程逻辑讨论。在本篇文章中,我们将以一道 C++ 的编程题为例,深入剖析解题的思路、优化方法,以及延伸出的编程概念。通过对比两种实现方式(我的实现和老师的实现),结合扩展性和代码优化的思路,帮助读者全面理解这一题目及其潜在的编程技巧。
    C++ 参考手册

💯题目描述

B2112 石头剪子布

石头剪子布,是一种猜拳游戏,起源于中国,然后传到日本,朝鲜等地,随着亚欧贸易的不断发展它传到西欧,到了现代化逐渐国际化的世界中。简单明了的规则,使得石头剪子布没有任何知识和规则漏洞可钻,单次玩法让比赛公平,容易且充满心理博弈,使得石头剪子布这个古老的游戏同时用于"意外"与"技术"两种特性,深受世界人民喜爱。

游戏规则:

石头剪子布,布包石头,石头砸剪刀,剪刀剪布。

现在,需要你写一个程序来判断石头剪子布游戏的结果。

输入格式:

第一行是一个整数 N,表示一共进行 N 次游戏。1 <= N <= 100。

接下来 N 行的每一行包括两个字符串,表示游戏参与者 Player1,Player2 的选择(石头、剪刀或者布):S1,S2。

字符串之间以空格隔开 S1 S2 只可能取值在 [Rock, Scissors, Paper](大小写敏感)中。

输出格式:

输出包括 N 行,每一行对应一个胜利者(Player1 或者 Player2),或者游戏出现平局,则输出 Tie。

输入输出样例:

输入 #1

3
Rock Scissors
Paper Paper
Rock Paper

输出 #1

Player1
Tie
Player2

解题分析与实现

接下来,我们将从两个实现方式出发:我的做法、老师的做法,逐步剖析解决问题的不同方式,最后对比两种实现,并延展出优化和扩展思路。

💯我的做法

以下是我的代码实现:

cpp 复制代码
#include <iostream>
#include <string>
using namespace std;

int main()
{	
	int n;
	cin >> n;
	string s1, s2;
	for(int i = 0; i < n; i++)
	{
		cin >> s1 >> s2;
		if(s1 == "Rock")
		{
			if(s2 == "Scissors")
				cout << "Player1" << endl;
			else if(s2 == "Paper")
				cout << "Player2" << endl;
			else
				cout << "Tie" << endl;
		}
		else if(s1 == "Scissors")	
		{
			if(s2 == "Scissors")
				cout << "Tie" << endl;
			else if(s2 == "Paper")
				cout << "Player1" << endl;
			else
				cout << "Player2" << endl;
		}
		else
		{
			if(s2 == "Scissors")
				cout << "Player2" << endl;
			else if(s2 == "Paper")
				cout << "Tie" << endl;
			else
				cout << "Player1" << endl;
		}
	}
	
    return 0;
}

实现逻辑

  1. 输入处理:读取整数 n,表示对局次数,循环读取 Player1Player2 的选择。

  2. 判断规则:

    • 通过嵌套的 if-else 分支,根据 Player1 的选择 (Rock, Scissors, Paper) 逐步判断 Player2 的选择,从而决定胜负。
    • 平局条件 (s1 == s2) 被单独处理。
  3. 逐行输出:根据每场比赛的结果,输出 "Player1"、"Player2" 或 "Tie"。

优点与不足

  • 优点:

    • 逻辑清晰,适合初学者。
    • 每种情况都显式列出,容易理解。
  • 不足:

    • 冗余逻辑:大量的条件分支导致代码较为臃肿。
    • 可扩展性差:如果加入新规则(如 "Lizard" 和 "Spock"),代码需要大规模改动。

💯老师的做法

以下是老师的代码实现:

cpp 复制代码
#include <iostream>
#include <string>
using namespace std;

int main()
{
	int n = 0;
	cin >> n;
	int i = 0;
	string s1;
	string s2;
	while(n--)
	{
		cin >> s1;
		cin >> s2;
		if(s1 == s2)
			cout << "Tie" << endl;
		else if (s1 == "Rock" && s2 == "Scissors")
			cout << "Player1" << endl;
		else if (s1 == "Scissors" && s2 == "Paper")
			cout << "Player1" << endl;
		else if (s1 == "Paper" && s2 == "Rock")
			cout << "Player1" << endl;
		else
			cout << "Player2" << endl;
	}	
	return 0;
}

实现逻辑

  1. 使用 while 循环减少代码结构的复杂性,每次循环中处理一场比赛。
  2. 平局条件 (s1 == s2) 优先判断,避免进入更多分支。
  3. Player1 的胜利条件通过显式列举的方式判断。
  4. 如果上述条件都不满足,则默认为 Player2 胜出。

优点与不足

  • 优点:

    • 代码结构简洁,分支层次少。
    • 平局条件优先处理,逻辑顺畅。
  • 不足:

    • 同样存在条件分支冗余问题。
    • 可扩展性不足。

💯对比分析

对比点 我的做法 老师的做法
代码结构 使用嵌套 if-else,分支较多 使用单层 if-else,逻辑更清晰
冗余程度 条件分支更多,显式判断所有情况 条件分支较少,但仍有显式判断
可扩展性 新规则需要大规模修改 新规则需要大规模修改
适合初学者 逻辑直观,适合初学者练习 逻辑简化,更适合掌握基本结构的学生

💯优化与扩展

为了进一步优化和扩展,我们可以使用数据结构来简化逻辑,提高可扩展性。

优化代码实现

通过使用 map 存储胜负规则,可以避免显式列举所有情况。

cpp 复制代码
#include <iostream>
#include <string>
#include <map>
using namespace std;

int main() {
    int n;
    cin >> n;

    // 定义胜负规则
    map<string, string> winRules = {
        {"Rock", "Scissors"},
        {"Scissors", "Paper"},
        {"Paper", "Rock"}
    };

    string s1, s2;
    while (n--) {
        cin >> s1 >> s2;
        if (s1 == s2) {
            cout << "Tie" << endl;
        } else if (winRules[s1] == s2) {
            cout << "Player1" << endl;
        } else {
            cout << "Player2" << endl;
        }
    }

    return 0;
}

优化后的优点

  1. 逻辑简化:通过查表判断胜负,避免嵌套的 if-else
  2. 易扩展性:增加新规则只需扩展 map,无需修改核心逻辑。
  3. 代码简洁:主逻辑更清晰,减少冗余判断。

扩展场景

  1. 多种新规则:如引入 "Lizard" 和 "Spock"。
  2. 支持多轮游戏:记录每场比赛的胜利者,并统计最终胜负结果。
  3. 本地化支持:使用多语言输出结果。

💯总结

通过这道题目,我们探讨了两种不同的解法,以及如何优化代码逻辑。我的实现和老师的实现都能正确解决问题,但在简洁性和扩展性上存在一定不足。优化后的代码通过数据结构简化了逻辑,提高了代码的可维护性和可扩展性。

编程不仅仅是实现功能,还在于如何更优雅、更高效地实现。本题为我们提供了一个非常好的练习机会,希望读者在掌握了这些方法后,能更深入地理解编程的本质和技巧。



  1. 理解C++的基础
    学习重点:

  2. 掌握基本语法

    • 学会声明变量、条件语句、循环、函数等核心语法。
    • 掌握数组、指针、引用等基础知识。
  3. 熟悉标准输入输出

    • 掌握 cincout 的用法。
    • 理解格式化输出,例如 std::setwstd::fixed
  4. 记住编译器的角色

    • 理解源代码如何通过编译器转换为可执行程序,选择一款好的IDE(如Visual Studio、Clion、VSCode)。

建议:用大量小程序练习这些基础语法,比如写一个计算器、模拟猜数字游戏等。


  1. 深入学习C++的特性
    学习重点:

  2. 面向对象编程(OOP)

    • 理解类和对象,熟悉如何定义类、成员变量和成员函数。
    • 掌握封装、继承、多态三大核心特性。
  3. 内存管理

    • 理解指针的用法,掌握动态内存分配(newdelete)。
    • 学习如何避免内存泄漏,熟悉智能指针(如std::unique_ptrstd::shared_ptr)。
  4. 标准模板库(STL)

    • 熟悉常用的容器(如vectormapset)和算法(如sortfind)。
    • 掌握迭代器的用法。
  5. 异常处理

    • 学习使用try-catch块处理异常。
    • 理解异常的用途以及如何设计健壮的代码。

建议:尝试开发一个小型项目,比如一个学生管理系统,综合应用类、STL、指针和动态内存分配。


  1. 掌握进阶内容
    学习重点:

  2. 模板

    • 理解函数模板和类模板,掌握泛型编程思想。
    • 学习模板特化和模板元编程的基本概念。
  3. 多线程与并发

    • 学习 C++11 提供的多线程支持(如std::thread)。
    • 熟悉互斥锁(std::mutex)和条件变量(std::condition_variable)。
  4. C++与C的兼容性

    • 学习如何在C++中使用C语言代码,理解C和C++的区别。
    • 掌握C风格字符串(char[])和C++字符串(std::string)的转换。

建议:在这一阶段,可以挑战更复杂的项目,比如开发一个小型的HTTP服务器,学习网络编程并结合多线程。


  1. 学习资源与实践方法
    学习资源:

  2. 书籍

    • 《C++ Primer》:非常适合初学者的经典书籍。
    • 《Effective C++》:进阶学习C++最佳实践的指南。
    • 《The C++ Programming Language》:Bjarne Stroustrup(C++之父)的权威著作。
  3. 在线课程

    • Coursera 上的 C++ 编程课程。
    • YouTube 上免费的 C++ 系列教程。
  4. 社区与文档

实践方法:

  1. 多写代码,多调试
    • 每学一个概念后,写至少两个示例代码并进行调试。
  2. 做小项目
    • 从简单的控制台程序开始,比如文件读写、计算器、小游戏等。
    • 慢慢过渡到图形界面或网络程序开发。
  3. 阅读他人代码
    • 阅读开源项目的代码,理解优秀代码的设计思路。
  4. 参加编程比赛
    • 比如 LeetCode 或 Codeforces,可以帮助你提升算法能力和C++的熟练度。

  1. 保持耐心与兴趣

学习C++可能会面临以下困难:

  1. 复杂的语法:如模板、智能指针、多线程等。
  2. 调试困难:指针错误、内存泄漏、未定义行为可能让人头疼。

如何应对:

  • 将大问题拆解成小问题,逐步解决。
  • 不断重复基础知识,以加深理解。
  • 保持兴趣,尝试一些有趣的项目,比如写一个游戏、制作一个简单的图形程序。

小结

学习C++需要一个循序渐进的过程,从基础语法到面向对象编程,再到进阶的模板和并发编程,每一步都需要耐心和实践。通过充分利用学习资源、进行大量编码练习,以及挑战实际项目,你一定可以成为C++的高手。记住,学习的核心在于理解,而非死记硬背。

祝你学有所成,享受C++编程的乐趣!


相关推荐
oioihoii6 分钟前
《C++11》深入剖析正则表达式库:解锁文本处理的高效之道
c++·mysql·正则表达式
源文雨10 分钟前
新版 MacOS 无法从 /usr/local/lib 加载动态链接库的解决办法
c语言·c++·macos·unix·环境变量·动态链接库·posix
hakesashou22 分钟前
python如何设计矩阵
开发语言·python·矩阵
捕鲸叉23 分钟前
C++并发编程之多线程环境下使用无锁数据结构的重要准则
c++·并发编程
敖行客 Allthinker23 分钟前
Ruby JSON 优化之路:性能提升的探索与实践
开发语言·json·ruby
lly2024061 小时前
PHP Filesystem
开发语言
lly2024061 小时前
PHP 字符串
开发语言
捕鲸叉1 小时前
C++并发编程之异常安全性增强
c++·算法·并发编程
Alvin's Tech Blog1 小时前
内联变量(inline variables):在多个文件中共享全局常量
c++·inline variable
Allen Bright1 小时前
【JVM-7】JVM 命令行工具 jstack 的使用和具体应用案例
java·开发语言·jvm