VC++ MFC双人对决围棋程序实战:从落子提子到胜负计算

简介:这是一份基于VC++与MFC框架编写的双人对决围棋程序源码,面向正在学习Windows游戏编程、希望理解MFC文档视图架构与图形绘制流程的开发者。程序支持双人轮流落子,并可根据15、17寸液晶屏选择合适窗口尺寸,落子响应迅速,适合作为课程设计、毕业设计或自学练手项目。压缩包共24个文件,约36KB,包含7个h头文件与6个cpp源文件,构成视图、文档、主框架等核心模块;另有3个bmp位图与2个ico图标提供棋盘与界面素材,以及dsp、dsw工程文件、rc资源脚本和clw类向导文件,方便直接编译运行。目前已有171人学习下载。通过阅读源码,读者可掌握MFC单文档程序的搭建方式、棋盘绘制与鼠标交互逻辑、落子判定与界面刷新思路,并借鉴作者在图形类封装上的组织方法,为后续扩展胜负判断、悔棋或人机对战功能打下基础。

1. 双人对决的VC++围棋程序:一个能直接跑起来的MFC实战项目

很多做VC++的朋友都有个心结:MFC学了一堆控件和消息映射,却始终没做出一个像样的完整程序。这个双人对决的围棋程序正好补上这一环——它不是那种只画个棋盘就结束的Demo,而是把落子、提子、禁着点判断、胜负计算都串了起来,用纯VC++和MFC写成,打开解决方案就能编译运行。适合两类人:一是刚学完MFC基础、想找个有真实业务逻辑的项目练手的;二是想研究棋类游戏状态管理和界面刷新机制的。棋盘绘制走的是GDI双缓冲,避免闪烁;规则部分独立成类,和界面解耦,改起来不伤筋动骨。下面按“能干什么、怎么跑、怎么改”的顺序拆一遍。

2. 项目架构与核心模块:棋盘、规则、界面三层怎么分

2.1 整体目录结构与文件职责

拿到源码包,第一件事是看目录。这个项目没有用第三方库,全部依赖VC++自带组件,结构很干净:

GoGame/ ├── GoGame.sln // VS解决方案文件 ├── GoGame/ │ ├── GoGame.h/.cpp // 应用程序入口,CWinApp派生 │ ├── MainFrm.h/.cpp // 主框架窗口 │ ├── GoGameView.h/.cpp // 视图类,负责棋盘绘制和鼠标交互 │ ├── GoGameDoc.h/.cpp // 文档类,持有棋盘数据 │ ├── Board.h/.cpp // 棋盘逻辑核心:落子、提子、气计算 │ ├── RuleEngine.h/.cpp // 规则引擎:禁着点、打劫、胜负判定 │ └── res/ // 图标、菜单等资源

文档/视图架构是MFC的经典模式,这里用得比较到位。CGoGameDoc持有Board对象,CGoGameView负责把Board的状态画出来,鼠标点击时反过来调用Board的落子接口。RuleEngine单独拆出来,是因为规则判断和棋盘数据是两回事——棋盘只管“哪里有没有子”,规则管“这步能不能下”。

常见做法是把所有逻辑塞进View里,几百行就乱成一团。这个项目把规则独立出来,后面想加AI或者悔棋,改动点很明确。

2.2 棋盘数据结构:二维数组还是位棋盘

Board类内部用的是最直观的二维数组:

// Board.h class Board { public: static const int BOARD_SIZE = 19; enum Stone { EMPTY = 0, BLACK = 1, WHITE = 2 }; Board(); void Reset(); Stone GetStone(int row, int col) const; bool PlaceStone(int row, int col, Stone color); int GetLiberties(int row, int col) const; void RemoveGroup(int row, int col); private: Stone m_grid[BOARD_SIZE][BOARD_SIZE]; // 记录每步落子,用于悔棋 std::vector<std::pair<int,int>> m_history; };

m_grid是19×19的枚举数组,每个位置存EMPTY、BLACK或WHITE。m_history用vector记录落子顺序,悔棋时直接pop_back再恢复棋盘状态。这里没有用位棋盘压缩,因为双人对决场景下性能完全够用,19×19=361个格子,一次气计算最多遍历整个棋盘,现代CPU毫秒级完成。

参数说明:BOARD_SIZE改成9或13就能切换小棋盘,但界面绘制那边也要同步改,后面会讲。PlaceStone返回bool表示是否成功,失败原因包括位置已有子、越界等,规则层面的禁着点判断放在RuleEngine里做。

2.3 气与提子的计算逻辑

围棋最核心的算法就是“气”的计算。一块棋的气等于它所有相邻空点的集合,如果气为0就要被提掉。GetLiberties用广度优先搜索实现:

// Board.cpp int Board::GetLiberties(int row, int col) const { Stone color = m_grid[row][col]; if (color == EMPTY) return 0; bool visited[BOARD_SIZE][BOARD_SIZE] = { false }; std::queue<std::pair<int,int>> q; std::set<std::pair<int,int>> liberties; // 用set去重 q.push({row, col}); visited[row][col] = true; const int dr[] = {-1, 1, 0, 0}; const int dc[] = {0, 0, -1, 1}; while (!q.empty()) { auto [r, c] = q.front(); q.pop(); for (int i = 0; i < 4; ++i) { int nr = r + dr[i], nc = c + dc[i]; if (nr < 0 || nr >= BOARD_SIZE || nc < 0 || nc >= BOARD_SIZE) continue; if (visited[nr][nc]) continue; if (m_grid[nr][nc] == EMPTY) { liberties.insert({nr, nc}); } else if (m_grid[nr][nc] == color) { visited[nr][nc] = true; q.push({nr, nc}); } } } return (int)liberties.size(); }

逻辑说明:从目标点出发,把同色连通块全部找出来,同时收集所有相邻的空点。用set是为了避免同一个空点被多个棋子重复计数。四个方向用dr/dc数组表示,这是棋盘类算法的标准写法。

参数说明:visited数组每次调用都重新初始化,在19×19规模下开销可忽略。如果以后要支持更大棋盘,可以改成成员变量加时间戳标记,避免反复清零。

提子的触发时机是在PlaceStone之后:先落子,然后检查上下左右四个方向的对方棋块,如果某块气为0就整块移除。这里有个容易翻车的地方——提子后自己的棋可能反而没气了(自杀手),所以顺序必须是“先提对方,再检查自己”。

3. 编译运行与界面交互:从解决方案到落子响应

3.1 环境准备与编译步骤

这个项目用的是VC++和MFC,推荐用Visual Studio 2019或2022,安装时勾选“使用C++的桌面开发”和“MFC支持”。打开GoGame.sln后,配置选Debug x64或Release x64都行,直接F7编译。如果报错“无法打开 afxwin.h”,说明MFC组件没装,去VS Installer里补上。

编译通过后F5运行,会出现一个带菜单栏的窗口,棋盘是19×19的网格。菜单里有“新游戏”“悔棋”“退出”几个基本项。没有用对话框做设置,所有操作都在主窗口完成,减少了一层消息传递。

提示:如果编译时提示std::pair相关错误,检查是否包含了<utility>和<queue>头文件。VC++不同版本对标准库的隐式包含行为有差异,显式包含最稳妥。

3.2 棋盘绘制的双缓冲实现

MFC的OnDraw直接画图会闪烁,因为每次重绘都先擦背景再画前景。这个项目在CGoGameView::OnDraw里用了内存DC做双缓冲:

void CGoGameView::OnDraw(CDC* pDC) { CGoGameDoc* pDoc = GetDocument(); CRect rect; GetClientRect(&rect); // 内存DC CDC memDC; memDC.CreateCompatibleDC(pDC); CBitmap bmp; bmp.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height()); CBitmap* pOldBmp = memDC.SelectObject(&bmp); // 先填充背景 memDC.FillSolidRect(&rect, RGB(220, 179, 92)); // 木色 // 画网格线 int margin = 30; int cellSize = (min(rect.Width(), rect.Height()) - 2 * margin) / 18; for (int i = 0; i < 19; ++i) { memDC.MoveTo(margin, margin + i * cellSize); memDC.LineTo(margin + 18 * cellSize, margin + i * cellSize); memDC.MoveTo(margin + i * cellSize, margin); memDC.LineTo(margin + i * cellSize, margin + 18 * cellSize); } // 画棋子 for (int r = 0; r < 19; ++r) for (int c = 0; c < 19; ++c) { Board::Stone s = pDoc->GetBoard().GetStone(r, c); if (s == Board::EMPTY) continue; int x = margin + c * cellSize; int y = margin + r * cellSize; CBrush brush(s == Board::BLACK ? RGB(0,0,0) : RGB(255,255,255)); CBrush* pOldBrush = memDC.SelectObject(&brush); memDC.Ellipse(x - cellSize/2 + 2, y - cellSize/2 + 2, x + cellSize/2 - 2, y + cellSize/2 - 2); memDC.SelectObject(pOldBrush); } // 一次性拷贝到屏幕 pDC->BitBlt(0, 0, rect.Width(), rect.Height(), &memDC, 0, 0, SRCCOPY); memDC.SelectObject(pOldBmp); }

逻辑说明:所有绘制先在memDC上完成,最后用BitBlt一次性贴到屏幕DC。这样屏幕只刷新一次,肉眼看不到闪烁。cellSize根据窗口大小动态计算,窗口拉伸时棋盘跟着缩放。

参数说明:margin是棋盘边缘留白,改成50可以让棋盘更居中。cellSize/2 - 2里的减2是让棋子之间留一点缝隙,看起来更舒服。如果想画星位(天元、角星),在固定坐标画小圆点即可,这个项目没做,算是个可扩展点。

3.3 鼠标点击到落子的消息链路

鼠标左键按下时,OnLButtonDown被触发,把屏幕坐标转换成棋盘行列,再调用文档对象的落子接口:

void CGoGameView::OnLButtonDown(UINT nFlags, CPoint point) { CGoGameDoc* pDoc = GetDocument(); CRect rect; GetClientRect(&rect); int margin = 30; int cellSize = (min(rect.Width(), rect.Height()) - 2 * margin) / 18; // 屏幕坐标 -> 棋盘行列(四舍五入到最近交叉点) int col = (point.x - margin + cellSize/2) / cellSize; int row = (point.y - margin + cellSize/2) / cellSize; if (row < 0 || row >= 19 || col < 0 || col >= 19) return; // 交给规则引擎判断 if (pDoc->GetRuleEngine().IsValidMove(row, col, pDoc->GetCurrentColor())) { pDoc->GetBoard().PlaceStone(row, col, pDoc->GetCurrentColor()); pDoc->GetRuleEngine().ApplyCapture(pDoc->GetBoard(), row, col); pDoc->SwitchColor(); Invalidate(); // 触发重绘 } else { MessageBeep(MB_ICONWARNING); // 非法落子提示音 } CView::OnLButtonDown(nFlags, point); }

逻辑说明:坐标转换用(point.x - margin + cellSize/2) / cellSize,加半个格子宽是为了让点击落在交叉点附近就能命中,而不是必须精确点到交叉点。IsValidMove检查禁着点和打劫,通过后才真正落子、提子、切换执子方。

参数说明:MessageBeep是Windows API,非法落子时响一声,比弹对话框轻量。如果觉得吵可以去掉,改成状态栏提示。Invalidate()会触发OnDraw,配合双缓冲完成界面更新。

4. 规则引擎与胜负判定:禁着点、打劫、数子

4.1 禁着点判断:自杀手和打劫

RuleEngine::IsValidMove要处理两种情况:一是落子后自己没气且不能提对方(自杀手),二是打劫(重复上一手局面)。自杀手判断可以复用Board的气计算:

bool RuleEngine::IsValidMove(Board& board, int row, int col, Board::Stone color) { if (board.GetStone(row, col) != Board::EMPTY) return false; // 模拟落子 board.SetStone(row, col, color); // 检查是否能提对方 bool canCapture = false; const int dr[] = {-1,1,0,0}, dc[] = {0,0,-1,1}; for (int i = 0; i < 4; ++i) { int nr = row + dr[i], nc = col + dc[i]; if (nr < 0 || nr >= 19 || nc < 0 || nc >= 19) continue; if (board.GetStone(nr, nc) == Opponent(color)) { if (board.GetLiberties(nr, nc) == 0) { canCapture = true; break; } } } // 自己是否有气 bool hasLiberty = (board.GetLiberties(row, col) > 0); // 恢复 board.SetStone(row, col, Board::EMPTY); if (!hasLiberty && !canCapture) return false; // 自杀手 // 打劫判断:和上上步局面相同则禁止 if (IsKo(board, row, col, color)) return false; return true; }

逻辑说明:先模拟落子,然后检查四个方向是否有对方无气棋块(可提),再检查自己是否有气。两者都不满足就是自杀手。打劫判断需要保存历史局面,简单做法是记录最近两步的棋盘哈希,如果当前落子后和两步前相同则禁止。

参数说明:Opponent是个辅助函数,黑返回白、白返回黑。打劫判断在双人对决里可以简化——很多业余对局不严格判打劫,但既然做了规则引擎,加上更完整。

4.2 数子与胜负计算

双人对决结束时,需要计算双方地盘。中国规则是数子法:活棋加围住的空点。RuleEngine::CalculateScore遍历棋盘,对每个空点做洪水填充,如果只被一种颜色包围就归该方:

std::pair<int,int> RuleEngine::CalculateScore(Board& board) { bool visited[19][19] = { false }; int blackScore = 0, whiteScore = 0; for (int r = 0; r < 19; ++r) { for (int c = 0; c < 19; ++c) { if (board.GetStone(r, c) == Board::BLACK) { blackScore++; continue; } if (board.GetStone(r, c) == Board::WHITE) { whiteScore++; continue; } if (visited[r][c]) continue; // 洪水填充空区域 std::queue<std::pair<int,int>> q; std::set<Board::Stone> borders; int emptyCount = 0; q.push({r, c}); visited[r][c] = true; while (!q.empty()) { auto [cr, cc] = q.front(); q.pop(); emptyCount++; for (int i = 0; i < 4; ++i) { int nr = cr + dr[i], nc = cc + dc[i]; if (nr < 0 || nr >= 19 || nc < 0 || nc >= 19) continue; Board::Stone s = board.GetStone(nr, nc); if (s == Board::EMPTY && !visited[nr][nc]) { visited[nr][nc] = true; q.push({nr, nc}); } else if (s != Board::EMPTY) { borders.insert(s); } } } if (borders.size() == 1) { if (*borders.begin() == Board::BLACK) blackScore += emptyCount; else whiteScore += emptyCount; } // borders为空或两种颜色都有,是公气,不计分 } } return {blackScore, whiteScore}; }

逻辑说明:遍历所有空点,对每个未访问的空区域做BFS,同时记录接触到的棋子颜色。如果只接触黑色,这块空归黑;只接触白色归白;两种都有则是公气,双方都不算。最后加上棋子本身的数量。

参数说明:这个算法在19×19上跑一次不到10毫秒,终局时调用一次完全没问题。dr/dc数组在多个函数里重复定义,实际项目里可以提成类静态成员。

4.3 悔棋功能的实现

悔棋在双人对决里很实用,实现依赖Board里的m_history。每步落子前把当前棋盘状态压栈,悔棋时弹出恢复:

void Board::Undo() { if (m_history.empty()) return; auto last = m_history.back(); m_history.pop_back(); m_grid[last.first][last.second] = EMPTY; // 如果有提子,需要恢复被提的棋子,这里简化处理 }

实际项目中,提子后恢复比较复杂,需要在落子时把被提棋子的位置也记录下来。常见做法是定义一个MoveRecord结构,包含落子位置、被提棋子列表、执子方,悔棋时反向操作。这个项目如果只做单步悔棋,可以接受简化版;要做多步悔棋,建议把MoveRecord补全。

5. 避坑与常见问题:编译、绘制、规则里的那些坑

5.1 编译报错“无法打开源文件 afxwin.h”

现象:打开解决方案后直接编译,提示找不到MFC头文件。 原因:Visual Studio安装时没有勾选MFC组件,或者项目属性里的“使用MFC”设置不对。 解决:打开VS Installer,修改当前VS版本,在“单个组件”里搜索MFC并勾选安装。安装完成后重启VS,再检查项目属性 → 配置属性 → 常规 → “使用MFC”是否为“在共享DLL中使用MFC”。

5.2 棋盘绘制闪烁严重

现象:窗口拉伸或落子后,棋盘明显闪一下。 原因:OnDraw里直接往屏幕DC画图,没有用内存DC缓冲。 解决:按3.2节的写法,先创建兼容DC和位图,所有绘制在内存DC完成,最后BitBlt一次性输出。另外在OnEraseBkgnd里直接返回TRUE,阻止系统擦背景。

5.3 落子位置偏移

现象:点击交叉点附近,棋子画到了隔壁位置。 原因:坐标转换时没有加半个格子的偏移,或者margin和cellSize的计算在绘制和点击两处不一致。 解决:把margin和cellSize的计算抽成一个公共函数,绘制和点击都调用它。坐标转换公式统一为(point.x - margin + cellSize/2) / cellSize。

5.4 提子后棋盘状态错乱

现象:提掉对方一块棋后,自己的棋反而消失了,或者棋盘上出现空白。 原因:提子顺序错误,先检查了自己没气就移除,或者移除时没有正确遍历整块棋。 解决:严格按“落子 → 检查对方四方向棋块 → 移除无气块 → 检查自己”的顺序。移除时用BFS找到整块同色棋,全部置EMPTY,不要只移除一个子。

5.5 打劫判断导致正常落子被禁

现象:明明可以下的地方,程序提示非法。 原因:打劫判断过于严格,把普通提子也当成了打劫。 解决:打劫的严格定义是“单子提单子且局面重复”,需要比较落子前后的棋盘哈希。简化做法是只记录最近一步的落子位置,如果当前落子位置和上一步提子位置相同且只提了一个子,才判打劫。不要把所有提子都当打劫。

6. 二次开发改造:从双人对决到AI对战和网络版

这个项目最值钱的地方是规则和界面解耦,改起来有明确的切入点。如果你想加一个简单AI,不用动界面,只需要在RuleEngine旁边加一个AIPlayer类,实现一个GetMove(Board&)接口。最基础的随机落子AI十行代码就能写:

std::pair<int,int> AIPlayer::GetMove(Board& board, Board::Stone color) { std::vector<std::pair<int,int>> validMoves; for (int r = 0; r < 19; ++r) for (int c = 0; c < 19; ++c) if (m_rule.IsValidMove(board, r, c, color)) validMoves.push_back({r, c}); if (validMoves.empty()) return {-1, -1}; return validMoves[rand() % validMoves.size()]; }

然后在View的落子逻辑里,判断当前执子方如果是AI,就调用GetMove自动落子。想强一点,可以加一个简单的启发式评分:优先选靠近已有棋子、靠近边角的位置。再强一点就要上蒙特卡洛树搜索了,那是另一个量级的工程。

改网络版的话,核心是把Board的状态序列化后通过Socket传输。MFC自带CSocket类,可以在文档类里加一个CGoGameSocket成员。落子后把(row, col, color)打包发出去,对方收到后调用同样的落子接口。注意网络延迟会导致双方视图不一致,常见做法是本地先落子再发消息,收到对方确认后如果冲突就回滚。这块坑比较多,建议先做局域网直连,别一上来就搞房间匹配。

我自己的习惯是,每次改规则相关代码后,都会手动下几盘棋验证:先测普通落子、再测提子、再测打劫、最后测终局数子。这四步走完,基本能覆盖90%的规则bug。从那以后我每次动RuleEngine都强制走一遍这个流程,省了很多后悔药。希望帮到你。

本文还有配套的精品资源,点击获取

相关新闻

arping 命令详解:局域网 MAC 地址探测与 IP 冲突排查实战

arping 命令详解:局域网 MAC 地址探测与 IP 冲突排查实战

简介&#xff1a;这是一份面向网络管理员、运维工程师及网络编程学习者的 arping 工具源码资源包&#xff0c;聚焦以太网环境下基于 ARP 协议探测主机在线状态并获取其 MAC 地址这一典型场景。资源共 19 个文件&#xff0c;以 cpp 与 h 源文件为核心&#xff0c;涵盖 ARP 报文构…

2026/10/21 2:43:59 阅读更多 →
基于协同过滤的电影推荐系统:Django+MySQL毕业设计实战拆解

基于协同过滤的电影推荐系统:Django+MySQL毕业设计实战拆解

简介&#xff1a;这套基于协同过滤的电影推荐系统毕业设计源码&#xff0c;面向计算机相关专业学生与推荐系统初学者&#xff0c;完整实现了基于用户与基于物品两种推荐算法&#xff0c;涵盖相似度计算、评分预测与 Top-N 推荐等完整流程。项目基于 Django 2.2.1、Python 3.7 与…

2026/10/21 2:43:59 阅读更多 →
2011款iMac装Win10:绕过BootCamp蓝屏,手动更新显卡驱动实战

2011款iMac装Win10:绕过BootCamp蓝屏,手动更新显卡驱动实战

简介&#xff1a;这份资源面向仍在使用 iMac 27 2011 Mid 一体机、并在其上安装 Windows 10 的用户&#xff0c;尤其是遇到播放视频时偶发蓝屏、苦于 Boot Camp 自带驱动版本过旧的人群。资源提供的是从 AMD 官网获取的较新显卡驱动&#xff0c;安装后驱动日期显示为 2015/8/19…

2026/10/21 2:43:59 阅读更多 →

最新新闻

MALA幅度感知线性注意力如何高效改造YOLO26

MALA幅度感知线性注意力如何高效改造YOLO26

最近在忙目标检测模型的落地优化&#xff0c;把精力主要放在了YOLO26的注意力机制改造上。试过不少主流的注意力模块&#xff0c;要么计算量上去了推理变慢&#xff0c;要么就是涨点不明显&#xff0c;白折腾。后来读到一篇当时挂在学术预印平台上的新工作&#xff0c;核心是提…

2026/10/21 3:33:25 阅读更多 →
Kettle ETL实战:为什么老工具在混乱数据场景中依然不可替代

Kettle ETL实战:为什么老工具在混乱数据场景中依然不可替代

1. 为什么今天还在用Kettle做ETL&#xff1f;一个被低估的“老派”工具的真实价值很多人看到“Kettle”这个词&#xff0c;第一反应是&#xff1a;这玩意儿不是十年前就该淘汰了吗&#xff1f;现在不都上Airflow、Dagster、dbt&#xff0c;或者直接云厂商的DataFlow、Glue、Dat…

2026/10/21 3:33:25 阅读更多 →
用pgzrun零基础实现克隆人游戏:Python游戏开发入门实践

用pgzrun零基础实现克隆人游戏:Python游戏开发入门实践

1. 项目概述&#xff1a;为什么一个“克隆人”游戏值得用pgzrun重做&#xff1f;最近在某高校的编程入门工作坊里&#xff0c;我带学生做了一个小项目——用Python复刻经典街机游戏《阿肯色克隆人》&#xff08;Arkansas Clone&#xff09;&#xff0c;但没碰Pygame原生API&…

2026/10/21 3:33:25 阅读更多 →
MapLibre Native 地图样式切换指南:3 种方式让地图不重启应用就换外观

MapLibre Native 地图样式切换指南:3 种方式让地图不重启应用就换外观

MapLibre Native 地图样式切换指南&#xff1a;3 种方式让地图不重启应用就换外观 【免费下载链接】maplibre-native MapLibre Native - Interactive vector tile maps for iOS, Android and other platforms. 项目地址: https://gitcode.com/GitHub_Trending/ma/maplibre-na…

2026/10/21 3:33:25 阅读更多 →
REA 逆向工程快速上手:把 REA 装进 AI 编码助手,跑通第一次二进制分析

REA 逆向工程快速上手:把 REA 装进 AI 编码助手,跑通第一次二进制分析

REA 逆向工程快速上手&#xff1a;把 REA 装进 AI 编码助手&#xff0c;跑通第一次二进制分析 【免费下载链接】rea Reverse engineer anything with agents, from app behavior down to native binaries. 项目地址: https://gitcode.com/GitHub_Trending/rea2/rea REA&…

2026/10/21 3:33:25 阅读更多 →
51单片机贪吃蛇实战:12864驱动、EEPROM掉电保存与嵌入式分层设计

51单片机贪吃蛇实战:12864驱动、EEPROM掉电保存与嵌入式分层设计

简介&#xff1a;本资源是一套面向大学本科课程设计的51单片机贪吃蛇游戏完整开发方案&#xff0c;适用于单片机原理与应用、嵌入式系统实践等课程学习与项目实训。资源包含Proteus仿真工程&#xff08;.pdsprj&#xff09;、Keil C51源码&#xff08;.c/.a51&#xff09;、编译…

2026/10/21 3:32:25 阅读更多 →

日新闻

统一内存+量化:锐龙AI Max PRO 400如何本地跑320B大模型

统一内存+量化:锐龙AI Max PRO 400如何本地跑320B大模型

这段时间硬件圈和AI圈都在传一个事&#xff1a;AMD锐龙AI Max PRO 400系列把最高192GB统一内存搬进了PC形态的产品里&#xff0c;按宣传口径&#xff0c;本地跑320B参数的大家伙不再是纸面概念。我第一反应倒不是“内存真大”&#xff0c;而是这话背后的含金量——它把过去只能…

2026/10/21 0:00:11 阅读更多 →
AI助手深度使用体验:对话质量、长文本处理与指令遵循如何留住用户

AI助手深度使用体验:对话质量、长文本处理与指令遵循如何留住用户

1. 从“封号重开”这个行为说起&#xff1a;用户到底在追求什么“封号重开”这四个字&#xff0c;放在任何产品语境里都带着一股决绝的味道。一个账号从零开始积累使用记录、调教偏好、沉淀工作流&#xff0c;背后是大量的时间和精力成本。正常情况下&#xff0c;没有人愿意主动…

2026/10/21 0:00:11 阅读更多 →
ROS中YOLOv3工程落地:通信同步、坐标变换与性能调优

ROS中YOLOv3工程落地:通信同步、坐标变换与性能调优

1. 为什么在ROS里硬刚YOLOv3不是“炫技”&#xff0c;而是工程落地的必经之路我第一次在某高校机器人实验室看到那台搭载Jetson TX2的移动底盘原地打转、反复识别错垃圾桶时&#xff0c;就意识到&#xff1a;单纯跑通darknet_ros demo和真正让YOLOv3在ROS里“干活”&#xff0c…

2026/10/21 0:00:11 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型&#xff08;GMM&#xff09;的语音识别系统&#xff0c;很多人第一反应就是一堆数学公式&#xff0c;觉得门槛很高。但如果你真的在MATLAB里把它落地跑通&#xff0c;会发现核心其实就是三件事&#xff1a;把声音变成特征向量&#xff0c;用GMM给每个类别…

2026/10/20 10:02:13 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人&#xff0c;但落到具体操作上&#xff0c;无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程&#xff1a;对图像做反白、改调色板、彩色转灰度&#xff0c;最后把像素数据导出成txt文件。单看每一…

2026/10/20 20:43:59 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词&#xff0c;你会发现一个很有意思的现象&#xff1a;每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型&#xff0c;有人指的是运动控制系统&#xff0c;还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/20 2:50:50 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 10:02:08 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:45 阅读更多 →