最近一段时间,我一直在体验 ChatGPT / GPT-4,这个工具给了我很大的震撼和帮助。网上有很多人使用 GPT 生成简单项目的介绍,我也尝试了一下,本文记录的就是这样一次尝试。
多年前我写过一篇博客,介绍了熄灯游戏,这是一个简单但又需要一定逻辑的小游戏,我决定试试让 GPT-4 来实现一下。
首先我给 GPT-4 输入了游戏的定义以及我的要求:
熄灯游戏(Lights Out)是一个规则很简单的游戏,在一个 n * n 个格子的面板上,每个格子中有一个灯,灯有亮着和熄灭两种状态,初始状态下,所有的灯都是亮着的,点击某一个格子,会影响到那个格子以及它上、下、左、右四个相邻格子中的灯的状态,影响的规则为如果灯原来亮着则将其熄灭,如果原来熄灭则将其打开。游戏的目标是要将面板上所有的灯全部熄灭。
请写一个网页,实现这个游戏。
GPT-4 很快给出了一个 HTML 页面,初步实现了需求。这个页面的 JavaScript 逻辑基本正确,但在样式方面却有很多问题,比如所有格子都横向排列了,并没有排成 n * n 的方格,同时灯的开和关状态也没有正确显示。
于是我继续向它提要求:
样式似乎有错误,没有区分灯的开和关状态,另外灯的排列位置也有误。
它立刻承认了错误,并给出了修改后的代码片断。我将新的代码片断复制到文档后,发现功能正常了。此时,游戏的界面看起来如下图所示:
游戏可以玩了,但代码中写死了格子的尺寸为 5x5,如果想玩其他尺寸怎么办呢?于是我继续向 GPT-4 提要求:
接下来,我想让用户可以直接在页面上调整格子的数量,怎么修改?
GPT-4 给出了方案,在页面上添加一个 <input>
组件让用户输入数字,再添加一个按钮进行确认。
我觉得让用户手动输入太麻烦了,继续提要求:
不要让用户输入数字,改为下拉框的形式,让用户可以从 2 ~ 30 之间的数字选择。
GPT-4 又给出了新的方案,但这次,它又犯了一个错误,给出的 HTML 代码片断如下:
<select id="grid-size">
<!-- 使用for循环生成下拉框选项 -->
<% for (let i = 2; i <= 30; i++) { %>
<option value="<%= i %>"><%= i %></option>
<% } %>
</select>
<button id="update-grid">更新面板</button>
我告诉它,这是纯静态页面,不能使用类似 <% ... %>
这样的模板语言,另外又告诉它,<select>
的值变化后就直接生成新的游戏,不要再让用户点击按钮确认。几个来回之后,GPT-4 终于实现了我想要的功能。
此时,游戏界面如下图所示:
可以看到,现在可以手动指定格子的尺寸(比如调整为 5x5、6x6 等)了,但在之前的调整中,一些样式也发生了期望之外的变化,比如两行格子之间多了 2px 的空隙,看起来不是很美观。
接下来,我又给了 GPT-4 一系列指令,让它调整游戏界面的样式,最后得到了这样的结果:
老实说,我对这个结果已经挺满意了。
不过这个时候,页面的代码比较混乱,因为这些代码是经过和 GPT-4 的多次交流生成的,除了第一次之外,后面的交流中 GPT-4 都只给出了有变化的部分,我则从对话中将这些代码片断复制到源文件中。现在代码虽然能工作了,但看起来并不是很整洁,于是我将整个游戏的代码(120 行)复制了一份,丢回给 GPT-4,让它整理优化一下。
很快,GPT-4 返回了结果,代码变短了一些(114 行),结构上也更清晰了。
此时这个游戏已经可以游玩了,但作为一个游戏,总该再显示一些必要信息,比如一共点了多少次?还有多少个格子亮着?以及如果我想重新开局怎么办?
于是我继续向 GPT-4 提要求:
接下来,在游戏面板下方添加以下内容:
1. 点击数次,记录各个格子被点击的次数,点到其余地方不计数。当改变格子数或者点击重置按钮时此项清零。
2. 剩余亮着的格子数。
3. 重置游戏按钮,点击后重新生成当前游戏,所有格子的灯全部恢复为点亮状态,点击数次也重设为0。
GPT-4 很快就完成了任务。
我又注意到,当格子全部被点灭时代表着游戏胜利,这时应该给用户一个提示。于是继续向 GPT-4 提要求:
当剩余亮着的格子数为 0 时,表示游戏胜利,在页面上显示游戏胜利信息。
GPT-4 轻松地完成了任务,当用户游戏胜利时,界面上会显示“恭喜!你赢了!”的提示语。
我觉得纯文字的提示有一点单调,让 GPT-4 加一些 emoji,于是 GPT-4 又将提示语改成了“🎉 恭喜!你赢了! 🎉”。
另外,我也让 GPT-4 调整了一下文案,最后,游戏的效果(胜利时)如下:
这时,这个小游戏的功能已经算是完备了,但样式上还不是很好看,尤其是那个下拉框以及按钮。能否让 GPT-4 改进一下样式外观呢?我又向 GPT-4 继续提要求。
由于之前的会话已经很长,我开启了一个新的会话,将最新的代码复制了进去:
// 游戏完整代码
请优化上面的代码,将其中的下拉框以及按钮的样式改得漂亮一些。
很快,GPT-4 返回了结果,效果如下:
可以看到,它将下拉列表改成了绿色,将重置游戏按钮改成了红色。也许这个样式无法与人工实现的优秀设计相比,但与原来的样式相比已经是很不错的效果了,我决定采纳这个设计。
最后,我又想到,GPT-4 有着强大的翻译能力,那么能否给这个小游戏添加多语言版本呢?于是继续向它提要求:
给这个页面添加一个多语言切换菜单,允许在中文和英文之间切换。
GPT-4 果然轻松地完成了任务,它还将页面中出现的文案提取到了一个对象中:
const translations = {
zh: {
title: "熄灯游戏",
instruction: "请把所有格子的灯熄灭。",
clickCountLabel: "点击数次:",
remainingLightsLabel: "剩余格子数:",
winMessage: "🎉 恭喜!你赢了! 🎉",
resetButton: "重置游戏",
},
en: {
title: "Lights Out Game",
instruction: "Turn off all the lights.",
clickCountLabel: "Click count:",
remainingLightsLabel: "Remaining lights:",
winMessage: "🎉 Congratulations! You won! 🎉",
resetButton: "Reset Game",
},
};
虽然这个对象在后续的代码优化中又被 GPT-4 移除了,但这个操作还是让我觉得很惊艳。
此时的效果如下图所示:
可以见到,GPT-4 在页面的最顶部添加了一个选择语言的下拉框,并且参考了之前的样式,将这个下拉框的样式设为了蓝色。
至此,这个游戏便基本完成了,后面我又将完整代码发给 GPT-4 让它进行优化,让它给鼠标 hover 和点击操作添加一些动画效果,它顺利地完成了任务,同时除了做一些代码上精简调整外,还将选择格子下拉框的显示文案从单个数字变成了 5x5 这样更直观的数字,这也让我很是惊讶。
当然,它也有一些不足,比如“点击次数”、“剩余格子数”后面它使用了半角的冒号,我让它替换为全角的冒号它却始终不明白,也许是我的描述有一些问题,最后我不得不手动修改了一下,这也是整个游戏代码中我唯一手动修改过的地方。
下面是这个游戏的最终效果图:
你可以点击 https://oldj.net/static/lights-out/2.html 在线体验。
整个游戏的实现我一行代码也没有写,完全是通过与 GPT-4 的问答式交互生成的。
这个游戏还很简单,但 GPT-4 所表现出来的能力也已经非常令人惊讶,可以想象,如果应用得当,GPT-4 将会是多么犀利的效率神器。