和Claude对战黑白棋!一起开发AI对弈游戏

序言

为了提升自己的多模态处理能力和API调用技巧,我决定挑战一个有趣的项目——开发一款可以与Claude对战的黑白棋游戏!这个项目不仅涉及游戏逻辑的实现,还需要调用Claude的API,让AI作为对手进行博弈。通过这个过程,我希望能够深入理解多模态交互的实现方式,同时提升自己在AI集成和API开发方面的技能。接下来,就让我来分享这个项目的构思和开发过程吧!

 我的计划是利用 Claude 3.5 Sonnet多模态功能,让 Claude 通过分析棋盘图像来计算下一步最佳落子策略。相比传统的 API 仅处理文本输入,这次的挑战在于如何让 Claude 通过视觉信息理解棋局局势,并给出合理的走法建议。这不仅是对 Claude 多模态能力的测试,也是一次结合图像处理与 AI 交互的实践探索。

让AI编码

整个代码的实现都将交给 Claude 来完成!

这不仅是一次 AI 对战的实验,也是对 AI 代码生成能力的挑战。我会专注于设计思路,而所有的代码,包括棋盘状态的解析、游戏逻辑的实现、以及 Claude 的 API 调用,都会完全由 Claude 生成。通过这个方式,我希望能验证 Claude 在实际编程任务中的表现,同时也能更加专注于优化交互体验和 AI 对弈策略。

我是使用 Anthropic 的控制台 进行的实验。
界面看起来虽然简单,但其实内置了 Prompt 生成器 等实用功能,非常值得一试!

如果你还没有用过,不妨尝试一下,或许会对提升你的 AI 交互体验有所帮助。

 

 

首先,我们来编写黑白棋的代码。


我打算先实现一个基础的黑白棋游戏。

在网上搜索了一下,发现有人使用 Python 的 numpy 和 matplotlib 来还原棋盘,我决定采用这种方法。

接下来,我执行了以下的提示词(Prompt)。

使用 Python 的 numpy 和 matplotlib 创建一个黑白棋(Othello)的棋盘。- 在横轴上标注 A~H。
- 在纵轴上标注 1~8。- 创建一个放置棋子(disc)的函数 `put_disc`。- `put_disc` 函数的参数有 4 个:`x`、`y`、`color` 和 `board`。- `x` 表示放置棋子的位置,接受 a~h(不区分大小写)。- `y` 只能接受 1~8 作为合法输入。- `color` 只能是 `BLACK` 或 `WHITE`。- `board` 代表当前棋盘的状态。- 如果尝试在 不可放置的位置 落子,应返回错误。- 放置棋子后,应翻转相应的棋子颜色。- 返回 更新后的棋盘状态。- 创建一个检查棋盘状态并 判断游戏是否结束 的函数 `judge`。- 若分出胜负,则返回 获胜方(BLACK 或 WHITE)。- 若游戏尚未结束,则返回 `None`。- 创建一个函数,将当前棋盘状态 导出为 PNG 图片。

Claude 为我生成了 Python 代码

import numpy as np
import matplotlib.pyplot as plt# 常量定义
EMPTY = 0
BLACK = 1
WHITE = 2def create_board():"""创建初始棋盘"""board = np.zeros((8, 8), dtype=int)# 初始布局board[3:5, 3:5] = np.array([[WHITE, BLACK],[BLACK, WHITE]])return boarddef draw_board(board, filename=None):"""绘制棋盘"""fig, ax = plt.subplots(figsize=(8, 8))# 设置背景颜色为绿色ax.set_facecolor('forestgreen')# 绘制网格for i in range(9):ax.axhline(i, color='black', linewidth=1)ax.axvline(i, color='black', linewidth=1)# 设置坐标轴标签ax.set_xticks(np.arange(8))ax.set_yticks(np.arange(8))ax.set_xticklabels(['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'])ax.set_yticklabels(['1', '2', '3', '4', '5', '6', '7', '8'])# 绘制棋子for i in range(8):for j in range(8):if board[i, j] == BLACK:circle = plt.Circle((j + 0.5, 7.5 - i), 0.4, color='black')ax.add_patch(circle)elif board[i, j] == WHITE:circle = plt.Circle((j + 0.5, 7.5 - i), 0.4, color='white')ax.add_patch(circle)ax.set_aspect('equal')if filename:plt.savefig(filename)plt.close()def convert_position(x, y):"""将坐标转换为内部表示"""if not isinstance(x, str) or len(x) != 1:raise ValueError("x 必须是单个字符")x = x.upper()if x not in 'ABCDEFGH':raise ValueError("x 必须在 A 到 H 之间")if not isinstance(y, int) or y < 1 or y > 8:raise ValueError("y 必须在 1 到 8 之间")return 8 - y, ord(x) - ord('A')def is_valid_move(board, row, col, color):"""检查指定位置是否可以落子"""if board[row, col] != EMPTY:return Falsedirections = [(0,1), (1,0), (0,-1), (-1,0), (1,1), (-1,-1), (1,-1), (-1,1)]valid = Falsefor dx, dy in directions:if check_direction(board, row, col, dx, dy, color):valid = Truereturn validdef check_direction(board, row, col, dx, dy, color):"""检查某个方向上是否可以翻转棋子"""opponent = WHITE if color == BLACK else BLACKx, y = row + dx, col + dyif not (0 <= x < 8 and 0 <= y < 8) or board[x, y] != opponent:return Falsewhile 0 <= x < 8 and 0 <= y < 8:if board[x, y] == EMPTY:return Falseif board[x, y] == color:return Truex, y = x + dx, y + dyreturn Falsedef put_disc(x, y, color, board):"""落子"""row, col = convert_position(x, y)if not is_valid_move(board, row, col, color):raise ValueError("无效的落子位置")new_board = board.copy()new_board[row, col] = colordirections = [(0,1), (1,0), (0,-1), (-1,0), (1,1), (-1,-1), (1,-1), (-1,1)]for dx, dy in directions:if check_direction(board, row, col, dx, dy, color):x, y = row + dx, col + dywhile board[x, y] != color:new_board[x, y] = colorx, y = x + dx, y + dyreturn new_boarddef judge(board):"""判断胜负"""black_count = np.sum(board == BLACK)white_count = np.sum(board == WHITE)empty_count = np.sum(board == EMPTY)if empty_count == 0:if black_count > white_count:return BLACKelif white_count > black_count:return WHITEelse:return None# 仍有空位时,游戏未结束return None# 使用示例
if __name__ == "__main__":board = create_board()draw_board(board, "initial_board.png")# 示例:落子try:board = put_disc('C', 4, BLACK, board)draw_board(board, "after_move.png")except ValueError as e:print(f"错误: {e}")# 判断胜负result = judge(board)if result == BLACK:print("Black wins!")elif result == WHITE:print("White wins!")else:print("Game is not finished yet")

执行后,生成了以下图像

看起来非常不错!!🎉

不过,我觉得棋盘格子的坐标标识可能不太直观,所以我用以下的提示词让 Claude 进行了调整,使其在棋盘上显示更清晰的标签。

请在棋盘的每个格子中央添加对应的坐标标签(如 A1、B2)。字体大小 请设置为较大,以确保清晰可见。
字体颜色 设为黑色,以提高可读性。
标签位置 应符合标准棋盘标识方式,左上角为 A8,右下角为 H1。

 

效果非常不错! 

修改后的代码

​
import matplotlib.pyplot as plt
import numpy as np# 常量定义
EMPTY = 0
BLACK = 1
WHITE = 2def create_board():"""创建初始棋盘"""board = np.zeros((8, 8), dtype=int)# 初始布局board[3:5, 3:5] = np.array([[WHITE, BLACK], [BLACK, WHITE]])return boarddef draw_board(board, filename=None):"""绘制棋盘"""fig, ax = plt.subplots(figsize=(8, 8))# 设置背景为绿色ax.set_facecolor('forestgreen')# 绘制网格for i in range(9):ax.axhline(i, color='black', linewidth=1)ax.axvline(i, color='black', linewidth=1)# 设置标签ax.set_xticks(np.arange(8))ax.set_yticks(np.arange(8))ax.set_xticklabels(['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'])ax.set_yticklabels(['1', '2', '3', '4', '5', '6', '7', '8'])# 在网格中添加坐标标签(从 A8 到 H1)for i in range(8):for j in range(8):label = f"{chr(65+j)}{8-i}"ax.text(j + 0.5, 7.5 - i, label,horizontalalignment='center',verticalalignment='center',color='black',fontsize=12,alpha=0.3)  # 设置透明度# 绘制棋子for i in range(8):for j in range(8):if board[i, j] == BLACK:circle = plt.Circle((j + 0.5, 7.5 - i), 0.4, color='black')ax.add_patch(circle)elif board[i, j] == WHITE:circle = plt.Circle((j + 0.5, 7.5 - i), 0.4, color='white')ax.add_patch(circle)ax.set_aspect('equal')if filename:plt.savefig(filename)plt.close()def convert_position(x, y):"""将坐标转换为内部表示"""if not isinstance(x, str) or len(x) != 1:raise ValueError("x 必须是单个字符")x = x.upper()if x not in "ABCDEFGH":raise ValueError("x 必须在 A 到 H 之间")if not isinstance(y, int) or y < 1 or y > 8:raise ValueError("y 必须在 1 到 8 之间")return 8 - y, ord(x) - ord("A")def is_valid_move(board, row, col, color):"""检查是否可以在指定位置落子"""if board[row, col] != EMPTY:return Falsedirections = [(0, 1), (1, 0), (0, -1), (-1, 0),(1, 1), (-1, -1), (1, -1), (-1, 1)]valid = Falsefor dx, dy in directions:if check_direction(board, row, col, dx, dy, color):valid = Truereturn validdef check_direction(board, row, col, dx, dy, color):"""检查某个方向是否可以翻转棋子"""opponent = WHITE if color == BLACK else BLACKx, y = row + dx, col + dyif not (0 <= x < 8 and 0 <= y < 8) or board[x, y​

使用 Streamlit 开发 UI

接下来,我计划创建一个 对战界面,让游戏更直观、更容易操作!

我将使用 Streamlit 来构建用户界面,让玩家可以通过网页直接进行黑白棋对战,同时实现棋盘的可视化显示和交互功能。

import json
import base64
import boto3
import httpx# 创建 Amazon Bedrock 客户端
bedrock_client = boto3.client('bedrock-runtime', region_name='us-east-1')# 获取棋盘图片并进行 Base64 编码
image_url = "https://your-image-url.com/board.png"  # 请替换为实际的棋盘图片 URL
image_media_type = "image/png"
image_data = base64.standard_b64encode(httpx.get(image_url).content).decode("utf-8")# 生成请求体
prompt = "请分析当前黑白棋的棋盘状态,并建议下一步的最佳落子位置。"request_body = {"anthropic_version": "bedrock-2023-05-31","max_tokens": 50,"messages": [{"role": "user","content": [{"type": "text", "text": prompt},{"type": "image","source": {"type": "base64","media_type": image_media_type,"data": image_data  # 传入棋盘图片的 Base64 数据}}]}]
}# 调用 Amazon Bedrock 运行 Claude 3.5 Sonnet
response = bedrock_client.invoke_model(modelId="anthropic.claude-3-5-sonnet-20240620-v1:0",body=json.dumps(request_body),contentType="application/json",accept="application/json"
)# 解析 AI 返回的结果
response_data = json.loads(response['body'].read())
ai_reply = response_data.get("content", [{}])[0].get("text", "")print("Claude's move suggestion:", ai_reply)

生成的代码

import streamlit as st
import base64
import io
import boto3
import numpy as np
from othello import *  # Assuming this contains your Othello game logic
import matplotlib.pyplot as plt
import tempfile
import os
import json
import uuid# Initialize Amazon Bedrock client
bedrock_client = boto3.client('bedrock-runtime', region_name='us-east-1')# Store all active game sessions
if 'game_sessions' not in st.session_state:st.session_state.game_sessions = {}def save_board_image(board):"""Save board image to temporary file and return path"""temp_dir = tempfile.gettempdir()temp_path = os.path.join(temp_dir, f'othello_board_{uuid.uuid4().hex}.png')draw_board(board, temp_path)return temp_pathdef get_board_image_bytes(board):"""Convert board image to bytes and encode as base64"""buf = io.BytesIO()draw_board(board)plt.savefig(buf, format='png', bbox_inches='tight')buf.seek(0)return base64.b64encode(buf.getvalue()).decode('utf-8')def get_valid_moves(board, color):"""Get list of valid moves"""valid_moves = []for i in range(8):for j in range(8):if is_valid_move(board, i, j, color):col = chr(j + ord('A'))row = 8 - ivalid_moves.append(f"{col}{row}")return valid_movesdef get_ai_move(board, valid_moves):"""Get AI's next move"""if not valid_moves:return None, Noneboard_image_base64 = get_board_image_bytes(board)prompt = f"""You are playing as White in this Othello/Reversi game.
Valid moves available to you are: {', '.join(valid_moves)}
Analyze the board and choose one move from the valid moves listed above.
Respond with ONLY the move coordinate (e.g., 'E6') - no other text."""request_body = {"anthropic_version": "bedrock-2023-05-31","max_tokens": 50,"messages": [{"role": "user","content": [{"type": "text", "text": prompt},{"type": "image","source": {"type": "base64","media_type": "image/png","data": board_image_base64}}]}]}response = bedrock_client.invoke_model(modelId="anthropic.claude-3-5-sonnet-20240620-v1:0",body=json.dumps(request_body),contentType="application/json",accept="application/json")response_body = json.loads(response['body'].read().decode('utf-8'))ai_response = response_body['content'][0]['text'].strip()if ai_response in valid_moves:return ai_response[0], int(ai_response[1])else:print(f"Invalid AI response. Using first valid move: {valid_moves[0]}")return valid_moves[0][0], int(valid_moves[0][1])def get_session_id():"""Get or create a session ID for the current player"""if 'session_id' not in st.session_state:st.session_state.session_id = str(uuid.uuid4())# Initialize new game state for this sessionst.session_state.game_sessions[st.session_state.session_id] = {'board': create_board(),'game_over': False}return st.session_state.session_iddef main():st.title("Othello vs AI")# Get current player's sessionsession_id = get_session_id()session = st.session_state.game_sessions[session_id]# Display boardboard_path = save_board_image(session['board'])st.image(board_path)# Show stone countsblack_count = np.sum(session['board'] == BLACK)white_count = np.sum(session['board'] == WHITE)st.write(f"Black (You): {black_count} stones")st.write(f"White (AI): {white_count} stones")if not session['game_over']:valid_moves = get_valid_moves(session['board'], BLACK)if valid_moves:col1, col2 = st.columns(2)with col1:x = st.selectbox("Column (A-H)", list("ABCDEFGH"))with col2:y = st.number_input("Row (1-8)", min_value=1, max_value=8)st.write("Valid moves:", ", ".join(valid_moves))if st.button("Place Stone"):try:session['board'] = put_disc(x, y, BLACK, session['board'])print(f"\nPlayer's move: {x}{y}")result = judge(session['board'])if result is not None:session['game_over'] = Trueelse:ai_valid_moves = get_valid_moves(session['board'], WHITE)if ai_valid_moves:ai_x, ai_y = get_ai_move(session['board'], ai_valid_moves)if ai_x and ai_y:session['board'] = put_disc(ai_x, ai_y, WHITE, session['board'])print(f"AI's move: {ai_x}{ai_y}")result = judge(session['board'])if result is not None:session['game_over'] = Truest.rerun()except ValueError as e:st.error(f"Invalid move: {e}")print(f"Error: {e}")else:st.write("No valid moves available for you. Skipping turn...")ai_valid_moves = get_valid_moves(session['board'], WHITE)if ai_valid_moves:ai_x, ai_y = get_ai_move(session['board'], ai_valid_moves)if ai_x and ai_y:session['board'] = put_disc(ai_x, ai_y, WHITE, session['board'])st.rerun()else:session['game_over'] = Trueif session['game_over']:result = judge(session['board'])if result == BLACK:st.success("You win!")elif result == WHITE:st.error("AI wins!")else:st.info("Draw!")if st.button("New Game"):session['board'] = create_board()session['game_over'] = Falsest.rerun()if __name__ == "__main__":main()

让我们运行看看吧!

streamlit run app.py

正确的表示出了棋盘!

 ​​​​​​​

AI也能正确的做出响应! 

总结

我们成功完成了 黑白棋(Othello) 的开发~~

在过程中,虽然 多次想要自己修改代码,但最终还是完全依靠 生成式 AI 完成了整个编程工作。

对于 严格的业务逻辑,可能仍然存在一定的挑战,但通过 生成式 AI,即使是 零编程经验 的人,也能体验到 创造软件的乐趣,这确实是一件很棒的事情!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/24163.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

R-INLA实现绿地与狐狸寄生虫数据空间建模:含BYM、SPDE模型及PC先验应用可视化...

全文链接&#xff1a;https://tecdat.cn/?p40720 本论文旨在为对空间建模感兴趣的研究人员客户提供使用R-INLA进行空间数据建模的基础教程。通过对区域数据和地统计&#xff08;标记点&#xff09;数据的分析&#xff0c;介绍了如何拟合简单模型、构建和运行更复杂的空间模型&…

ubuntu20.04安装docker

3台主机&#xff0c;2台都能正确安装&#xff0c;第三台怎么都安装不成功&#xff1b; 3台主机都是一样的配置和系统&#xff1b; 后来看来是其外网的ip不一样&#xff0c;导致第三台主机可能被Qiang&#xff0c;不过错误只是提示签名不正确&#xff0c;在设置签名时好像没有…

【Android】用 chrome://inspect/#devices 调试H5页面

通常做Android开发的过程中&#xff0c;不可避免的需要遇到去与H5交互&#xff0c;甚至有时候需要去调试H5的信息。 这里分享一下Android工程里如何调试H5页面信息&#xff1a; 直接在浏览器地址栏输入 &#xff1a; chrome://inspect/#devices 直接连接手机usb,打开开发者模式…

AI多模态梳理与应用思考|从单文本到多视觉的生成式AI的AGI关键路径

摘要&#xff1a; 生成式AI正从“文本独舞”迈向“多感官交响”&#xff0c;多模态将成为通向AGI的核心路径。更深度的多模态模型有望像ChatGPT颠覆文字交互一样&#xff0c;重塑物理世界的智能化体验。 一、多模态的必然性&#xff1a;从单一到融合 生成式AI的起点是文本生成…

精美登录注册UI,登录页面设计模板

精美登录注册UI,登录页面设计模板 引言 在网页设计中,按钮是用户交互的重要元素之一。一个炫酷的按钮特效不仅能提升用户体验,还能为网页增添独特的视觉吸引力。今天,我们将通过CSS和JavaScript来实现一个“精美登录注册UI,登录页面设计模板”。该素材呈现了数据符号排版…

kotlin 知识点一 变量和函数

在Kotlin中定义变量的方式和Java 区别很大&#xff0c;在Java 中如果想要定义一个变 量&#xff0c;需要在变量前面声明这个变量的类型&#xff0c;比如说int a表示a是一个整型变量&#xff0c;String b表 示b是一个字符串变量。而Kotlin中定义一个变量&#xff0c;只允许在变量…

海洋 CMS V9SQL注入漏洞

目录 禁用information_schema解决方法 方法一&#xff1a;替换法 sys performance_schema ​编辑 方法二&#xff1a;无列名注入 利用lxml模块进行布尔盲注 XPATH XPATH介绍: XPATH语法: 布尔盲注 标准代码&#xff1a; 运行结果&#xff1a; ​编辑 时间盲注 标准代…

springcloud nacos 整合seata解决分布式事务

文章目录 nacos安装Mysql5.7安装及表初始化seata server安装下载并解压seata安装包在conf文件夹修改file.conf文件向本地数据库导入seata需要的表修改registry.conf文件将seata配置信息添加到nacos配置中心启动seata server springcloud整合seata测试流程正常下单流程扣减库存失…

Linux搜索查找类指令

1、find指令 基本语法&#xff1a;find [搜索范围] [选项] 功能&#xff1a;将从指定目录向下递归地遍历其各个子目录&#xff0c;将满足条件的文件或目录显示在终端。 常用选项&#xff1a; 操作 命令示例 说明 查找指定路径下的所有文件 find /path/to/dir 查找指定目…

uniapp 网络请求封装(uni.request 与 uView-Plus)

一、背景 在开发项目中&#xff0c;需要经常与后端服务器进行交互&#xff1b;为了提高开发效率和代码维护性&#xff0c;以及降低重复性代码&#xff0c;便对网络请求进行封装统一管理。 二、创建环境文件 2.1、根目录新建utils文件夹&#xff0c;utils文件夹内新建env.js文…

ReentrantLock 用法与源码剖析笔记

&#x1f4d2; ReentrantLock 用法与源码剖析笔记 &#x1f680; 一、ReentrantLock 核心特性 &#x1f504; 可重入性&#xff1a;同一线程可重复获取锁&#xff08;最大递归次数为 Integer.MAX_VALUE&#xff09;&#x1f527; 公平性&#xff1a;支持公平锁&#xff08;按等…

【蓝桥杯单片机】客观题

一、第十三届省赛&#xff08;一&#xff09; 二、第十三届省赛&#xff08;二&#xff09;

数据库(MySQL):使用命令从零开始在Navicat创建一个数据库及其数据表(一).创建基础表

一. 使用工具和命令 1.1 使用的工具 Navicat Premium 17 &#xff1a;“Navicat”是一套可创建多个连接的数据库管理工具。 MySQL版本8.0.39 。 1.2 使用的命令 Navicat中使用的命令 命令 命令解释 SHOW DATABASES&#xff1b; 展示所有的数据库 CREATE DATABASE 数据…

deepseek清华大学第二版 如何获取 DeepSeek如何赋能职场应用 PDF文档 电子档(附下载)

deepseek清华大学第二版 DeepSeek如何赋能职场 pdf文件完整版下载 https://pan.baidu.com/s/1aQcNS8UleMldcoH0Jc6C6A?pwd1234 提取码: 1234 或 https://pan.quark.cn/s/3ee62050a2ac

【Linux Oracle】time命令+oracle exp压缩

Linux && Oracle相关文档&#xff0c;希望互相学习&#xff0c;共同进步 风123456789&#xff5e;-CSDN博客 1.说明 Linux中的time命令&#xff1a;主要用于测量命令的执行时间&#xff0c;并显示该命令在执行过程中所使用的系统资源情况&#xff0c;如CPU时间、内存和…

游戏引擎学习第123天

仓库:https://gitee.com/mrxiao_com/2d_game_3 黑板&#xff1a;线程同步/通信 目标是从零开始编写一个完整的游戏。我们不使用引擎&#xff0c;也不依赖任何库&#xff0c;完全自己编写游戏所需的所有代码。我们做这个节目不仅是为了教育目的&#xff0c;同时也是因为编程本…

MCP协议

原理讲解 基础概念 Introduction - Model Context Protocol MCP Host&#xff1a;想要通过 MCP 访问数据的程序&#xff0c;例如 Claude Desktop、IDE 或 AI 工具MCP Clients&#xff1a;与服务器保持 1:1 连接的协议客户端MCP Servers&#xff1a;轻量级程序&#xff0c;每个…

Maven环境搭建

Maven 1. 概述 ApacheMaven是一个软件项目管理和构建工具。基于项目对象模型&#xff08;POM&#xff09;的概念&#xff0c;Maven可以从中心信息中管理项目的构建、报告和文档 理解: maven构建项目&#xff08;100%&#xff09;而且帮你完成jar的统一管理。 思考: 原来的jar—…

llaMa模型的创新

LLaMa介绍 LLaMa是基于transformer encoder的生成式模型。 目前有&#xff1a;LLAMA, LLAMA2, LLAMA3 三个大的版本 论文 LLAMA 2: Open Foundation and Fine-Tuned Chat Models&#xff1a; https://arxiv.org/pdf/2307.09288 LLAMA 3: The Llama 3 Herd of Models https…

渗透测试实验

1、seacmsv9注入管理员密码 获取管理员账号&#xff08;name&#xff09; http://www.test2.com/comment/api/index.php?gid1&page2&rlist[]%27,%20extractvalue(1,%20concat_ws(0x20,%200x5c,(select%20(name)from%20sea_admin))),%27 2、获取管理员密码 http://www…