如何用 GPT-4 帮你写游戏(以24点游戏举例)
目录
最近呢掀起了一阵GPT-4的热潮,很多人都想用GPT-4,这里呢我就打一个广告(嘿嘿),如果不知道国内如何使用GPT的,可以看看这个博客:GPT-4的免费使用方法分享(续)_我爱OJ的博客-CSDN博客
目前你想要用上 GPT-4,主要的渠道是 ChatGPT Plus 。作为交了订阅费的用户,你可以在对话的时候选择模型来使用。
另一种渠道,就是申请官方 API 的排队。我在申请通义千问的时候,耐心被折磨了4,5 天了,每天回家都兴致勃勃的看手机有没有短信。所以这次申请完就放在一边了。啥时候通过申请,听天由命吧。(所以这次我就拿国内的GPT-3.5来为大家测试)
给我一个24点游戏
游戏规则
“24点”是一种扑克牌游戏,正如象棋、围棋一样是一种人们喜闻乐见的娱乐活动。
它以自己独具的数学魅力和丰富的内涵正逐渐被越来越多的人们所接受。这种游戏方式简单易学,能健脑益智,是一项极为有益的活动。
具体内容及操作方法
一副牌中抽去大小王剩下52张,任意抽取4张牌,利用四则运算把牌面上的数算成24。每张牌能且只能用一次。
游戏技巧
1.利用3×8=24、4×6=24、2×12=24求解。
把牌面上的四个数想办法凑成3和8、4和6、2和12,再相乘求解。实践证明,这种方法是利用率最大、命中率最高的一种方法。
2.利用0、1的运算特性求解。
如3、4、4、8可组成3×8×(4÷4)=24。又如4、7、1、1可组成4×1(7-1)×1=24。
3.看4张牌中是否有2,3,4,6,8,Q,
如果有,考虑用乘法,将剩余的3个数凑成对应数。如果有两个相同的6,8,Q,比如已有两个6,剩下的只要能凑成3,4,5都能算出24,已有两个8,剩下的只要能凑成2,3,4,已有两个Q,剩下的只要能凑成1,2,3都能算出24,比如(9,J,Q,Q)。如果没有2,3,4,6,8,Q,看是否能先把两个数凑成其中之一。总之,乘法是很重要的,24是30以下公因数最多的整数。
4、将4张牌加加减减得到24。
5、先相乘再加、减去某数。
6、在计算过程中有分数出现。有一个规律,设4个数为a,b,c,d。必有ab+c=24或ab-c=24 d=a或b。若d=a 有a(b+c/a)=24 或 a(b-c/a)=24。只能用此法的只有17种。
7、在计算过程中有较大数(30以上)出现。相对较难,但有时也只有该解法。比如(6,9,9,10)为9×10÷6+9。
GPT给的代码
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
double eval(string s) // 计算字符串表达式的值
{
int len = s.size();
int p = 0; // 指向当前遍历到的位置
double ans = 0.0; // 累计所有项的和
int op = 1; // 当前符号的正负号,1表示加法或正号,-1表示减法或负号
int last_op = 1; // 上一个符号的正负号
double num = 0.0; // 当前遍历到的数值
while(p < len)
{
char c = s[p];
if(c == '+' || c == '-') // 遇到加减号
{
ans += op * last_op * num;
num = 0.0;
last_op = op = (c == '+') ? 1 : -1;
}
else if(c == '*' || c == '/') // 遇到乘除号
{
double next_num = 0.0;
++p;
while(p < len && '0' <= s[p] && s[p] <= '9')
next_num = next_num*10 + s[p++] - '0';
num = (c == '*') ? num * next_num : num / next_num;
}
else if(c == '(') // 遇到左括号
{
int cnt = 1;
int q = p + 1;
while(q < len && cnt > 0)
{
if(s[q] == '(')
++cnt;
else if(s[q] == ')')
--cnt;
++q;
}
num = eval(s.substr(p+1, q-p-2));
p = q;
}
else if(c == ' ') // 空格分隔符
{
++p;
continue;
}
else // 遇到数字
{
num = num*10 + c - '0';
++p;
}
}
ans += op * last_op * num;
return ans;
}
int main()
{
srand(time(NULL)); // 初始化随机数生成器
int a = rand()%9+1, b = rand()%9+1, c = rand()%9+1, d = rand()%9+1; // 生成四个1~9之间的整数
cout << "请使用加、减、乘、除以及括号使得以下四个数构成算式的结果为24:" << endl;
cout << a << " " << b << " " << c << " " << d << endl;
bool found = false; // 标记是否找到合法的算式
char ops[5] = {'+', '-', '*', '/'}; // 运算符集合
for(int i=0; i<4 && !found; ++i) // 枚举第一个数到第四个数
for(int j=0; j<4 && !found; ++j) // 枚举第二个数到第四个数
if(j != i)
for(int k=0; k<4 && !found; ++k) // 枚举第三个数到第四个数
if(k != j && k != i)
for(int l=0; l<4 && !found; ++l) // 枚举第四个数
if(l != k && l != j && l != i)
{
// 构造算式
string s = "";
s += to_string(a) + ops[i] + to_string(b) + ops[j] + to_string(c) + ops[k] + to_string(d);
// 枚举中间结果的算式
for(int i2=0; i2<4 && !found; ++i2)
for(int j2=0; j2<4 && !found; ++j2)
if(j2 != i2)
for(int k2=0; k2<4 && !found; ++k2)
if(k2 != j2 && k2 != i2)
{
// 构造中间结果的算式
string s2 = "";
s2 += "(" + to_string(a) + ops[i] + to_string(b) + ")" + ops[i2] + "(" + to_string(c) + ops[j] + to_string(d) + ")" + ops[j2] + to_string(ops[k2] - '+' + '*');
// 计算结果
if(eval(s2) == 24)
{
cout << "恭喜您,找到了一个合法的算式:" << endl;
cout << s << " = " << eval(s) << endl;
found = true;
}
}
}
if(!found)
cout << "很遗憾,没有找到合法的算式。" << endl;
return 0;
}
不出意外的话意外就要来了
但是但是,我上网找了半天,终于知道为什么了,因为我的C++版本太低了,解决办法也很简单 ,如下
依次点击菜单:工具(Tools)->编译选项(Compiler Options) -> 代码生成/优化(Settings) ->代码生成( Code Generation),找到最后一项语言标准(即Language standard),可以看到后面的选项默认是空的。
下拉选项栏,选中ISO C++11,点击确定后再进行编译就不会报错了
运行后是这样的:
可以看到,没有输出结果,这时我就来气了,就对GPT说
改进
下面是改正后的代码
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <stack>
#include <vector>
using namespace std;
double eval(vector<string>& tokens) // 计算逆波兰表达式的值
{
stack<double> nums;
for(string& token: tokens)
{
if(token == "+") // 加法
{
double num2 = nums.top();
nums.pop();
double num1 = nums.top();
nums.pop();
nums.push(num1 + num2);
}
else if(token == "-") // 减法
{
double num2 = nums.top();
nums.pop();
double num1 = nums.top();
nums.pop();
nums.push(num1 - num2);
}
else if(token == "*") // 乘法
{
double num2 = nums.top();
nums.pop();
double num1 = nums.top();
nums.pop();
nums.push(num1 * num2);
}
else if(token == "/") // 除法
{
double num2 = nums.top();
nums.pop();
double num1 = nums.top();
nums.pop();
nums.push(num1 / num2);
}
else // 数字
{
nums.push(stod(token)); // stod() 可以将字符串转换为 double 类型
}
}
return nums.top();
}
bool solve(vector<int>& nums, vector<string>& tokens) // 递归解决24点游戏
{
if(nums.empty()) // 无数字剩余,得出解法
{
return eval(tokens) == 24;
}
for(int i=0; i<nums.size(); ++i)
{
int num = nums[i];
nums.erase(nums.begin() + i); // 去掉当前数
tokens.push_back(to_string(num)); // 转换为字符串并加入逆波兰表达式
if(solve(nums, tokens)) // 尝试解决剩余的数字
return true;
tokens.pop_back();
nums.insert(nums.begin() + i, num); // 还原当前数
}
return false;
}
int main()
{
srand(time(NULL)); // 初始化随机数生成器
vector<int> nums(4);
for(int& num: nums)
num = rand()%9+1; // 生成四个 1~9 之间的整数
cout << "请使用加、减、乘、除以及括号使得以下四个数构成算式的结果为24:" << endl;
cout << nums[0] << " " << nums[1] << " " << nums[2] << " " << nums[3] << endl;
vector<string> tokens;
if(solve(nums, tokens)) // 寻找解法
{
cout << "恭喜您,找到了一个合法的算式:" << endl;
for(string& token: tokens)
cout << token << " ";
cout << "= 24" << endl;
}
else
{
cout << "很遗憾,没有找到合法的算式。" << endl;
}
return 0;
}
输出结果
很明显,这边已经强多了,但是我能让它这么轻而易举吗,于是我继续提问题:
再改进
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <stack>
#include <string>
#include <vector>
using namespace std;
double eval(vector<string>& tokens) // 计算逆波兰表达式的值
{
stack<double> nums;
for (string& token : tokens) {
if (token == "+") // 加法
{
double num2 = nums.top();
nums.pop();
double num1 = nums.top();
nums.pop();
nums.push(num1 + num2);
}
else if (token == "-") // 减法
{
double num2 = nums.top();
nums.pop();
double num1 = nums.top();
nums.pop();
nums.push(num1 - num2);
}
else if (token == "*") // 乘法
{
double num2 = nums.top();
nums.pop();
double num1 = nums.top();
nums.pop();
nums.push(num1 * num2);
}
else if (token == "/") // 除法
{
double num2 = nums.top();
nums.pop();
double num1 = nums.top();
nums.pop();
nums.push(num1 / num2);
}
else // 数字
{
nums.push(stod(token)); // stod() 可以将字符串转换为 double 类型
}
}
return nums.top();
}
bool solve(vector<int>& nums, vector<string>& tokens, int step) // 递归解决24点游戏
{
if (nums.empty()) // 无数字剩余,得出解法
{
if (eval(tokens) == 24)
{
cout << "恭喜您,找到了一个合法的算式:" << endl;
for (string& token : tokens)
cout << token << " ";
cout << "= 24" << endl;
return true;
}
else
{
return false;
}
}
if (step == 0) // 已经尝试了 5 次,输出如何用这些数字组成 24
{
cout << "很遗憾,五次机会已用完。以下是如何用这些数字组成 24。" << endl;
return false;
}
for (int i = 0; i < nums.size(); ++i) {
int num = nums[i];
nums.erase(nums.begin() + i); // 去掉当前数
tokens.push_back(to_string(num)); // 转换为字符串并加入逆波兰表达式
if (solve(nums, tokens, step - 1))
return true;
tokens.pop_back();
nums.insert(nums.begin() + i, num); // 还原当前数
}
return false;
}
int main()
{
srand(time(NULL)); // 初始化随机数生成器
vector<int> nums(4);
for (int& num : nums)
num = rand() % 9 + 1; // 生成四个 1~9 之间的整数
cout << "您有五次机会使用加、减、乘、除以及括号使得以下四个数构成算式的结果为 24:" << endl;
cout << nums[0] << " " << nums[1] << " " << nums[2] << " " << nums[3] << endl;
vector<string> tokens;
bool found_solution = false; // 是否已经找到解法
for (int i = 1; i <= 5; ++i) {
cout << "第" << i << "次尝试:请输入您的算式(支持加减乘除和括号):" << endl;
string input;
getline(cin, input);
tokens.push_back(input); // 将输入的字符串加入 vector 中
if (eval(tokens) == 24)
{
cout << "恭喜您,找到了一个合法的算式:" << endl;
cout << input << " = 24" << endl;
found_solution = true;
break;
}
else if (i < 5)
{
cout << "计算结果不为 24,请继续尝试。" << endl;
}
tokens.pop_back(); // 将输入的字符串从 vector 中弹出
}
if (!found_solution) // 五次机会用完,输出如何用这些数字组成 24
{
vector<string> empty_tokens;
if (solve(nums, empty_tokens, 5))
{
// 已经在函数中输出了解法
}
else
{
cout << "无法组成 24,以下是如何使用这些数字组成 24:" << endl;
// 输出如何用这些数字组成 24 的方法
// ...
}
}
return 0;
}
GPT真的很认真修改代码,之后运行效果是这样的
我不禁感慨了一句感慨:还学啥C++
当然,任何一个有经验的程序员,都可以站出来指出 GPT-4 辅助编程的种种缺点,然后断言它永远替代不了优秀的开发者。
你别忘了, GPT-4 发布才不到一年,目前一众大语言模型还在以狂飙的姿态进化中。再说了,谁说它的目标是替代「优秀的开发者」了?
目前,我还没有答案。想听听你的看法。欢迎留言,咱们一起交流讨论