前言
过去的国庆节中难得整理完自己的事情之后可以休息一下,闲来无事学了点国际象棋,感觉还挺有意思的,与中国象棋还是有些许差别的,看着手里的ChatGPT,想着可不可以整一点好玩的?
简单讲一下国际象棋的规则与符号术语吧,照顾一下没时间又想学的同学们
国际象棋规则与符号术语
国际象棋是一款两人对战游戏,双方各有16个棋子,包括一个国王(王)、一个王后(后)、两个主教(象)、两个骑士(马)、两个战车(车)和八个兵(兵),目标是将对方的国王将死(即没有任何合法走法能拯救国王)。
棋子和走法:
- 国王(K):每次走一格,任意方向。
- 皇后(Q):任意方向,任意格数。
- 车(R):直线(横或竖),任意格数。
- 象(B):对角线,任意格数。
- 马(N):走“日”字,跳过其他棋子。
- 兵(P):直走一格(首次可走两格),斜吃对方棋子。
特殊情况:
- 将军:你的棋子攻击对方国王。
- 将死:对方国王被攻击且无路可逃,胜利。
- 和棋:双方无法取胜时平局。
游戏中白棋先走,双方需要通过使用不同棋子的走法来保护自己的国王,并试图将死对方国王。
在国际象棋中,PGN(Portable Game Notation)是用来记录棋局的一种标准格式。以下是解释一些常见的国际象棋符号和术语:
棋子符号:
- N:骑士(Knight)。在国际象棋中,“N”代表骑士,因为“K”已经用于国王(King)
- B:象(Bishop)
- R:车(Rook)
- Q:皇后(Queen)
- K:国王(King)
移动方式:
例如,Nc6表示骑士(N)移到c6这个格子。
Bh4表示主教(B)移到h4这个格子。
只有d4格子,则默认为兵的行动。
O-O:短易位(Kingside castling),国王向右(王翼)移动两格,然后车子越过国王放在国王旁边。
O-O-O:长易位(Queenside castling),国王向左(后翼)移动两格,然后车子越过国王放在国王旁边。
g8=Q:兵升变,白兵走到 g8 并升变为皇后(Queen),当一个兵走到对方棋盘的最后一排(对黑棋来说是第1行,对白棋来说是第8行)时,它可以升变为其他棋子,通常是皇后,因为皇后是最强的棋子,能最大化提升实力。不过,玩家也可以选择将兵升变为车(Rook)、象(Bishop)或马(Knight)。
特殊符号:
#:代表"将死"(checkmate)。例如,Qe7# 表示皇后移动到e7格,结束棋局,将死对方国王。
+:代表"将军"(check)。这个符号表示对方的国王被将军,但还没有将死。
其他符号:
dxc4:表示用d线上的兵吃掉c4格上的棋子。"x"表示"吃子"(capture)。所以dxc4表示d线的兵移动并吃掉c4格上的棋子。
如何让LLM下棋?
如果是尝试通过简单的聊天让 ChatGPT 下棋,那可能会与预想有差别。因为该模型只在内存中保存大约十步棋,而且经常做出非法动作。
为了使像 ChatGPT 这样的语言模型 (LLM) 正常工作,我们需要利用它的一个特性:它以统计方式再现了它在训练期间学到的东西。
在国际象棋中,有一种称为"PGN"(便携式游戏符号)的格式,它是一种长文本,包括一个包含有关游戏的一般信息(结果、玩家、ELO 等)的标题和一个包含一系列所走棋步的正文,也就是我们上面说的符号术语
通过提供 PGN 文件的开头并要求 LLM 生成后续内容,它可以更连贯地下棋。
使用"bresse"库进行实验
Bresse 是一个用于国际象棋 AI 等 LLM(大型语言模型)的库。该库利用了 LLM 可以重现表示国际象棋游戏的格式(称为 PGN)这一事实。
可以利用各种工具来促进实验、推理过程中的 PGN 修改以及各种有用的信息。
该第三库可以允许 LLM 使用该chess库下棋。
而该库是怎么促进移动生成的呢?
- 处理棋谱文件(PGN)
国际象棋的棋局通常记录在PGN文件中,里面详细记录了每一步棋的走法。
我们需要先对这些文件进行处理,以便让人工智能模型更好地理解它们。因为现有的棋库(chess library)主要是给人和程序员用的,不是专门为AI模型设计的。
- 优化棋步的合法性:
在让AI选择下一步棋的时候,我们可以用一种“温度”的概念。这就像是让AI尝试一些变化的可能性,而不是总是选择最明显的一步。
然后,我们可以让AI尝试多个走法,看看它最常推荐哪一步。这样就能提高选出的棋步的准确性,确保AI走的棋更符合规则。
- 选择使用的AI模型
我们可以选择不同的AI模型来帮忙,比如OpenAI、HuggingFaceHub或MistralAI。这就像是选择不同的工具,每个工具在性能和特点上都有不同。
- 了解使用这些模型的成本
使用这些AI模型通常是按生成的数据量收费的。
比如,我们可以计算出用这些模型花1美元能生成多少次预测,这样我们就能知道使用这些模型的费用大概是多少。
- 检测非法的走法
即使AI建议了一些走法,我们也需要用棋库来检查这些走法是否合法。就像一个裁判一样,确保每一步棋都符合国际象棋的规则。
如果AI给出了非法的走法,棋库就会指出来,这样我们就可以再调整AI的预测,直到得到符合规则的走法。
与 ChatGPT 下棋
以下是使用该库让用户与 ChatGPT 进行游戏的示例代码:
import os
from dotenv import load_dotenvfrom bresse import generate_pgn, game_play_san
from bresse.models import OpenAIModel
# 加载环境变量
load_dotenv()
# 生成 PGN 游戏
game = generate_pgn(
white= "Alpha Zero" ,
black= "Stockfish" ,
white_elo= 3200 ,
black_elo= 3200 ,
# base_pgn="1. e4 c6 2. d4 d5 3. Nc3 dxe4" # 允许强制开局。
)
# 加载 OpenAI 模型
model = OpenAIModel(
model_id= "gpt-3.5-turbo-instruct" ,
api_key=os.getenv( "OPENAI_API_KEY" )
)
while True :
# 要求用户走一步
input_ = input ( "输入你的走法 (san): " )
try :
# 走用户的一步
game_play_san(game, input_)
# 玩模型的动作('chess' 库会就地修改游戏)
model.play(game)
except Exception as exception:
print ( f"Error: {exception} " )
break
print ( f"Final game:\n {game} " )
游戏示例如下:
AI互玩(GPT vs GPT)
同样,我们可以让AI自己跟自己下国际象棋。
这听起来很有意思,但是在实际操作中会遇到一个小问题:
- 每次让AI做出下一步棋的决定时,我们都要向AI发出一个请求。
- 随着棋局进行,每一步棋都会记录在棋谱文件(PGN)中,这个文件会越来越大。
因为这个棋谱文件变大了,每次请求的时候,我们需要提供更多的内容给AI参考(就像是给AI提供一个越来越长的历史记录)。
这样一来,AI处理这些请求的"费用"也会跟着增加。虽然每次增加的费用看起来不算太高,但因为是每一步都要发请求,所以最终整个棋局的成本也可能变得比较高。
import os
from dotenv import load_dotenv
from bresse import generate_pgn, pgn_to_board, generate_opening
from bresse.models import OpenAIModel
# 加载环境变量
load_dotenv()
# 使用 Polyglot(书籍开局)生成随机开局
base_game = generate_opening( 'gm2600.bin' )
# 生成带有开局的 PGN 游戏
game = generate_pgn(
white= "Alpha Zero" ,
black= "Stockfish" ,
white_elo= 3200 ,
black_elo= 3200 ,
base_pgn= f" {base_game} " ,
)
# 加载 OpenAI 模型
model = OpenAIModel(
model_id= "gpt-3.5-turbo-instruct" ,
api_key=os.getenv( "OPENAI_API_KEY" )
)
total_cost = 0
while True :
try :
# 播放模型的动作('chess' 库会就地修改游戏)
output = model.play(game)
# 获取推理成本
total_cost += output.cost
print ( f"This inference cost: {output.cost: .8 f} $" )
except ExceptionGroup as exception_group:
print ( f"Exception group:{exception_group} " )
for exception in exception_group.exceptions:
print ( f"\t- {exception} " )
break
except KeyboardInterrupt:
print ( "Game interrupted" )
break
print(f"Final game:\n{game}")
print(f"Total cost: {total_cost:.8f}$")
下面是Round 1中完整的下棋位置行为 (步数:白棋 黑棋)
1.d4 Nf6 2. Nf3 d5 3. c4 e6 4. Nc3 c6
5.Bg5 h6 6. Bh4 dxc4 7. e4 g5 8. Bg3 b5
9.Be2 Bb7 10. O-O Nbd7 11. Ne5 Bg7 12. Nxd7 Nxd7
13.Bd6 a6 14. e5 c5 15. dxc5 Nxe5 16. Re1 Qd7 17. Bh5 Nd3
18.Re3 O-O-O 19. Rxd3 cxd3 20. Qxd3 f5 21. Rd1 Qc6 22. Bf3 Qd7
23.c6 Bxc6 24. Na4 bxa4 25. Qxa6+ Bb7 26. Rc1+ Qc6 27. Rxc6+ Kd7
28.Qxb7+ Ke8 29. Qe7# *
请注意,从第15步(15.dxc5)开始,棋局的走法进入了较为不常见的变招,因此这些后续的步数在开局数据库中不再被记录。尽管如此,棋局仍然可以继续进行,最终下到第29步,总推理成本约为0.03美元。这意味着,如果维持当前的平均成本水平,每美元大约可以支持35步棋的推理。
降低自动游戏的成本
有没有方法降低自动游戏的成本呢?
有的,当想让 LLM 从头到尾自动运行的时候,最好让它在一次推理中生成整个游戏,因为在这种情况下,我们不需要修改正在进行的 PGN 来添加我自己的动作。
from dotenv import load_dotenv
from bresse import generate_pgn, generate_opening
from bresse.models import OpenAIModel
# 加载环境变量
load_dotenv()
# 加载 OpenAI 模型
model = OpenAIModel(
model_id="gpt-3.5-turbo-instruct",
api_key=os.getenv("OPENAI_API_KEY")
)
# 使用 Polyglot 生成随机开局
base_game = generate_opening('gm2600.bin')
# 生成带有开局的 PGN 游戏
game = generate_pgn(
white="Alpha Zero",
black="Stockfish",
white_elo=3200,
black_elo=3200,
base_pgn=f"{base_game}",
)
# 进行一次推理以生成所有动作
output_inf = model.auto_play(game, max_moves=150)
print(f"{game}")
print(f"Total cost: {output_inf.cost:.8f}$")
print(f"Number of requests for $1: {output_inf.number_requests_per_dollar}")
1. e4 c5 2. Nf3 d6 3. d4 cxd4 4. Nxd4 Nf6 5. Nc3 a6 6. Be3 e5 7. Nb3 Be6 8. f3 Be7 9. Qd2 O-O 10. O-O-O Nbd7
11. g4 b5 12. g5 Nh5 13. Kb1 Nb6 14. Na5 Rc8 15. Nd5 Nxd5 16. exd5 Bxd5 17. Qxd5 Qxa5 18. c4 Qa4 19. b3 Qa3 20. cxb5 axb5
21. Bxb5 Nf4 22. Bxf4 exf4 23. h4 Rc5 24. Qb7 Ra8 25. Rh2 Bf8 26. Bc4 Ra7 27. Qe4 Re5 28. Qxf4 g6 29. h5 Rf5 30. Qe3 Re7
31. Qc1 Qxc1+ 32. Kxc1 Rxg5 33. hxg6 hxg6 34. Rxd6 Rg1+ 35. Kc2 Kg7 36. a4 Ree1 37. Rd7 Rc1+ 38. Kb2 Rb1+ 39. Kc3 Rbc1+
40. Rc2 Rxc2+ 41. Kxc2 Bb4 42. Rxf7+ Kh6 43.Rb7 Rg2+ 44.Kd3 Rd2+ 45.Ke4 Bc3 46.Rb5 Rd4+ 47.Ke3 Rd6 48.a5 Bd2+ 49.Ke2 Bc3 50.b4 Rd2+
51.Ke3 Rb2 52.a6 Bd2+ 53.Kd3 Bxb4 54.a7 Rd2+ 55 .Ke3 Rd8 56.Rb8 Bc5+ 57.Ke4 Bxa7 58.Rxd8 Bc5 59.Rd5 Be7 60.f4 Kg7
61.Rd7 Kf6 62.Rxe7 Kxe7 63.Ke5 Kf8 64.Kf6 g5 65.fxg5 Ke8 66.g6 Kd7 67.g7 Kd6 68. g8=Q Kc5 69. Qd5+ Kb4 70. Qb5+ Kc3
71. Qb3+ Kd4 72. Qd3+ Kc5 73. Qd5+ Kb4 74. Ke5 Kc3 75. Qd4+ Kb4 76. Bd3+ Kb3 77. Qc4+ Kb2 78. Qc2+ Ka3 79. Qb1 Ka4 80. Bc4 Ka3
81. Qb3# *
Total cost: 0.00412800$
Number of requests for $1: 242
在这个例子中,ChatGPT顺利完成了81步棋的对弈,并且没有发生任何非法动作。然而需要注意的是,LLM(大语言模型)在某些情况下仍有可能产生非法动作,导致游戏在结束前中断。不过在这次实验中,模型成功完成了整个对弈。
本场棋局棋局的81步对弈成本约为0.004128美元,相比于逐步请求生成动作的方式,这次一次性推理生成整个棋局的成本要更低。在逐步请求的情况下,每一步棋的推理成本相对较高,并且每次请求都需要累积历史记录的内容,因此整体开销更大。
相比之前逐步请求生成约30步棋的对弈,成本为0.03美元,这次完整对弈81步的成本显著降低为0.004128美元,约减少了18.5倍。这表明,通过优化生成策略,我们可以在增加对弈步数的同时显著降低整体成本。
最后有话说
如果你想亲自测试该库,可以在以下github地址中找到,直接导入即可:
bresse库:github.com/Athroniaeth…
在与ChatGPT进行棋局对弈的实验中,我们发现该模型在执行复杂棋局时表现出色,能够完成高达81步的对弈而不产生非法动作。这显示了其在处理游戏规则和策略时的有效性。相比于传统的逐步请求生成策略,ChatGPT通过一次性生成整个棋局,大幅降低了成本,从而提升了效率。
然而,尽管模型在此实验中表现良好,但仍需注意,LLM存在偶尔产生非法动作的风险,这可能会影响对弈的准确性和完整性。因此,尽管ChatGPT在对弈中的能力令人印象深刻,但在实际应用中,依然需要谨慎对待其决策过程,以确保游戏的合法性和公正性。
总体而言,ChatGPT在下棋方面展现了其潜力,但在进一步的开发和优化中,确保模型在复杂环境下的稳定性和准确性将是未来的重要方向。
如果你想升级chatgpt4的话,也可以看看往期文章👇
(2024 最新 GPT4、GPT4.0 升级教程)ChatGPT 升级银行卡被拒绝,教你 5 分钟快速升级 chatgpt4
觉得升级费用暂时承担不起,也可以看看ChatGPT镜像站,价格会比官方便宜很多很多👇
ChatGPT4.0账号被封了怎么办?gpt4怎么买更便宜?先试试这个国内最新替代镜像站吧