Windows SDK中国象棋源码解析:Win32 GDI绘图与Alpha-Beta搜索AI实战

简介:这是一份面向Windows平台C++开发初学者与棋类程序爱好者的象棋程序源码包,基于Windows SDK构建,帮助读者理解如何用原生API实现图形界面、消息循环与棋局逻辑。压缩包共38个文件,约24KB,包含4个cpp源文件与6个h头文件承载核心逻辑,18个ico与3个cur提供界面图标资源,另有dsw、dsp工程文件、rc资源脚本及htm、txt说明文档,结构完整可直接用Visual Studio打开编译。已有123人学习下载。资源围绕GDI绘图、鼠标事件处理、棋盘数据结构、走子与吃子规则判断、AI搜索等关键环节展开,适合作为课程设计或自学练手项目,帮助读者掌握SDK窗口编程与象棋算法落地的完整思路。

1. 从一份 Windows SDK 象棋源码包说起:它到底能跑出什么

如果你手头有一份基于 Windows SDK 的象棋源码包,第一反应大概率是:这玩意儿是纯 Win32 API 画的棋盘,还是套了 MFC 壳?能不能直接编译?AI 是搜索还是评估?我拿到这类资源时,习惯先看它依赖哪些头文件和库,再决定值不值得花时间拆。这份资源的核心价值在于,它把中国象棋的完整规则、棋盘绘制、走子逻辑和简易 AI 都压进了原生 Windows 窗口程序里,不依赖 Qt、不依赖 .NET,编译出来就是一个独立 exe。适合谁?适合想学 Win32 GDI 绘图、想搞懂棋类 AI 极小极大搜索、或者需要一份能直接改的课程设计底稿的从业者。新手能跟着把环境搭起来跑通,熟手能直接扒出搜索算法和剪枝参数去调。它不是那种“点开即玩”的成品,而是一份需要你动手编译、调试、改参数的工程底子。

2. 拆开源码包:Win32 窗口、GDI 绘图与棋局数据结构

2.1 先认清工程骨架:Win32 还是 MFC

拿到源码包,别急着双击 .sln。先看根目录有没有stdafx.h、afxwin.h这类 MFC 痕迹。纯 Windows SDK 的象棋工程,入口一定是WinMain,窗口过程是WndProc,消息循环里处理WM_PAINT、WM_LBUTTONDOWN、WM_CREATE这些。常见做法是:一个main.cpp或chess.cpp扛下窗口创建和消息分发,棋盘绘制走WM_PAINT里的 GDI 调用,走子逻辑单独放logic.cpp,AI 搜索放ai.cpp。如果你看到CDialog、CView那基本就是 MFC 套壳,编译依赖会多一层,但核心算法通常还是那套。

我一般会先确认三件事:窗口类注册用的是RegisterClassEx还是AfxWinInit;棋盘是BitBlt贴图还是Rectangle+Ellipse纯画;棋子坐标是像素级还是行列索引。这三件事决定了你后面改 UI 和调 AI 的难度。纯 SDK 的工程,棋盘通常用CreateCompatibleDC做双缓冲,避免闪烁,棋子用TextOut或DrawText输出汉字,简单但够用。

2.2 棋盘与棋子的 GDI 绘制:双缓冲是标配

Win32 下画棋盘,最怕WM_PAINT里直接往窗口 DC 上怼,拖动窗口或刷新时闪得没法看。合格的做法是内存 DC 双缓冲:先在兼容 DC 里画好整张棋盘和所有棋子,再一次性BitBlt到窗口 DC。下面这段是典型骨架,你可以对照源码包里的OnPaint或WM_PAINT分支看。

// 双缓冲绘制棋盘骨架 case WM_PAINT: { PAINTSTRUCT ps; HDC hdc = BeginPaint(hWnd, &ps); // 1. 创建内存 DC 和兼容位图 HDC memDC = CreateCompatibleDC(hdc); HBITMAP memBmp = CreateCompatibleBitmap(hdc, BOARD_W, BOARD_H); HBITMAP oldBmp = (HBITMAP)SelectObject(memDC, memBmp); // 2. 填充背景,画棋盘格线和九宫斜线 HBRUSH bgBrush = CreateSolidBrush(RGB(240, 217, 181)); FillRect(memDC, &clientRect, bgBrush); DrawBoardLines(memDC); // 内部用 MoveToEx/LineTo 画横竖线 // 3. 遍历棋子数组,逐个绘制 for (int i = 0; i < 32; i++) { if (pieces[i].alive) { DrawPiece(memDC, pieces[i]); // 内部用 Ellipse + TextOut } } // 4. 一次性贴到窗口 DC BitBlt(hdc, 0, 0, BOARD_W, BOARD_H, memDC, 0, 0, SRCCOPY); // 5. 清理 GDI 对象,顺序不能反 SelectObject(memDC, oldBmp); DeleteObject(memBmp); DeleteDC(memDC); DeleteObject(bgBrush); EndPaint(hWnd, &ps); return 0; }

逻辑说明:CreateCompatibleDC创建的内存 DC 默认只有 1x1 单色位图,必须SelectObject一块和窗口 DC 兼容的位图才能画彩色。BitBlt的SRCCOPY表示直接拷贝像素。参数上,BOARD_W、BOARD_H通常按 9 列 10 行、每格 60 像素算,约 540x600,你可以在源码里找到对应宏。清理顺序反了会泄漏 GDI 对象,任务管理器里看到 GDI 对象数只涨不跌,就是这里翻车。

2.3 棋局状态怎么存:数组、位棋盘还是对象列表

象棋 32 个棋子,最直白的存法是struct Piece { int type; int side; int row; int col; bool alive; },全局数组pieces[32]。走子就是改row/col,吃子就是alive = false。这种写法对新手友好,调试时直接看数组。另一种是 10x9 的二维数组int board[10][9],每个格子存棋子编码,空为 0。搜索 AI 时二维数组更顺手,因为评估函数要频繁扫盘。

源码包里如果用的是对象数组,你改 AI 时可能要先转成二维数组再搜,多一层拷贝。我一般会建议:如果只是跑通看效果,别动数据结构;如果要改搜索深度或加置换表,先把棋盘转成int board[10][9]的扁平表示,搜索里用memcpy做走子/撤销,比逐个改对象快得多。常见做法是走子前把整个 board 拷进栈,撤销时直接拷回来,省去反向操作的逻辑错误。

3. 编译与运行:从 .sln 到可执行 exe 的完整链路

3.1 环境准备:VS 版本与 Windows SDK 版本对齐

这类工程通常带.sln和.vcxproj,用 Visual Studio 打开即可。关键是平台工具集和 Windows SDK 版本要对上。如果工程是 VS2015 建的,你拿 VS2022 打开,会提示“重定向项目”,点确定一般能编,但v141工具集可能没装。稳妥做法是打开“Visual Studio Installer”,勾选对应版本的“MSVC v141 - VS 2017 C++ x64/x86 生成工具”和“Windows 10 SDK (10.0.17763.0)”这类旧 SDK。

另一个坑是字符集。Win32 工程分 Unicode 和多字节。如果源码里TextOut直接传char*字符串,而工程属性设了 Unicode,编译会报const char*无法转LPCWSTR。解决办法:项目属性 → 配置属性 → 高级 → 字符集,改成“使用多字节字符集”;或者把字符串全改成_T("车")并用TCHAR。我一般先看源码里有没有_T宏,有就保持 Unicode,没有就切多字节,别硬改代码。

3.2 编译命令与常见链接错误

如果你不想开 IDE,可以用 MSBuild 命令行编译:

:: 在 Developer Command Prompt for VS 里执行 msbuild chess.sln /p:Configuration=Release /p:Platform=x86 :: 如果只想编单个 vcxproj msbuild chess.vcxproj /p:Configuration=Debug /p:Platform=Win32

参数说明:/p:Configuration指定 Debug 或 Release,Release 会开优化,AI 搜索速度明显快;/p:Platform指定 Win32 或 x64,老工程多半只有 Win32。链接阶段最常见的错误是unresolved external symbol __imp__TextOutA,这通常是因为字符集和库不匹配,或者没链接gdi32.lib、user32.lib。检查项目属性 → 链接器 → 输入 → 附加依赖项,确保有gdi32.lib;user32.lib;。

如果报LNK1104 无法打开文件“xxx.lib”,先看这个 lib 是不是 Windows SDK 里的,是的话检查 SDK 版本是否装全;不是的话看源码包有没有附带 lib 目录,把路径加到“附加库目录”。

3.3 运行时的窗口与消息响应验证

编译出 exe 后,双击运行。正常应该弹出一个固定大小的窗口,棋盘居中,棋子可点。如果窗口一闪而过,多半是WinMain里CreateWindow返回 NULL 后没处理,直接退出了。用 VS 调试运行,在CreateWindowEx后面下断点,看GetLastError()返回什么。常见是RegisterClassEx失败,因为窗口类名重复注册,或者hInstance传错。

点击棋子没反应,检查WM_LBUTTONDOWN里有没有把lParam的坐标转成行列。LOWORD(lParam)是 x,HIWORD(lParam)是 y,除以格子宽高得到col和row。如果点哪都没反应,先看消息循环里TranslateMessage和DispatchMessage有没有漏,再看WndProc的switch里有没有处理WM_LBUTTONDOWN。

4. 象棋 AI 的搜索内核:极小极大、Alpha-Beta 与评估函数

4.1 极小极大搜索的递归框架

棋类 AI 的底子就是极小极大:轮到红方走,红方选分值最大的走法;轮到黑方走,黑方选分值最小的走法。递归到叶子节点,用评估函数给局面打分。源码包里的 AI 如果只有一层,那就是直接对每个合法走法调评估函数,选最优。如果有多层,就是递归搜索。

// 极小极大搜索骨架,depth 为剩余深度 int Minimax(int board[10][9], int depth, int side) { if (depth == 0 || IsGameOver(board)) { return Evaluate(board, side); // 叶子节点返回评估分 } std::vector<Move> moves = GenerateMoves(board, side); if (moves.empty()) return Evaluate(board, side); int best = (side == RED) ? -INF : INF; for (auto& m : moves) { int captured = MakeMove(board, m); // 走子,返回被吃棋子 int score = Minimax(board, depth - 1, 1 - side); UndoMove(board, m, captured); // 撤销 if (side == RED) best = max(best, score); else best = min(best, score); } return best; }

逻辑说明:MakeMove和UndoMove必须严格配对,否则棋盘状态会乱。GenerateMoves要过滤掉走后己方被将军的走法,否则 AI 会送将。参数depth控制搜索层数,每加一层,节点数指数增长,纯极小极大搜到 4 层就很吃力了。

4.2 Alpha-Beta 剪枝:把搜索量砍掉一大半

极小极大有个致命问题:很多分支根本不用看。Alpha-Beta 剪枝维护两个边界:alpha是红方已找到的最大值,beta是黑方已找到的最小值。如果某个分支的返回值已经不可能影响上层决策,直接剪掉。

int AlphaBeta(int board[10][9], int depth, int side, int alpha, int beta) { if (depth == 0 || IsGameOver(board)) { return Evaluate(board, side); } std::vector<Move> moves = GenerateMoves(board, side); // 走法排序:吃子走法优先,能提高剪枝效率 SortMovesByCapture(board, moves); if (side == RED) { int best = -INF; for (auto& m : moves) { int captured = MakeMove(board, m); int score = AlphaBeta(board, depth - 1, 1 - side, alpha, beta); UndoMove(board, m, captured); best = max(best, score); alpha = max(alpha, best); if (alpha >= beta) break; // 剪枝 } return best; } else { int best = INF; for (auto& m : moves) { int captured = MakeMove(board, m); int score = AlphaBeta(board, depth - 1, 1 - side, alpha, beta); UndoMove(board, m, captured); best = min(best, score); beta = min(beta, best); if (alpha >= beta) break; // 剪枝 } return best; } }

参数说明:初始调用时alpha = -INF,beta = INF。SortMovesByCapture把吃子走法排前面,因为吃子走法更容易触发剪枝,实测能减少 30% 到 50% 的节点。depth每加 1,搜索时间大约翻 3 到 5 倍,取决于剪枝效果。如果源码包里 AI 反应慢,先看有没有走法排序,没有就加上,比换算法见效快。

4.3 评估函数:棋子分值、位置分与机动性

评估函数决定 AI 的“棋风”。最简单的版本只算子力:车 9 分、马 4 分、炮 4.5 分、兵 1 分,过河兵 2 分。红方总分减黑方总分,正数对红方有利。但这样 AI 只会吃子,不会占位。进阶一点加位置分:马在中心加 0.5,炮在巡河加 0.3,兵越靠近对方九宫分越高。

int Evaluate(int board[10][9], int side) { int score = 0; for (int r = 0; r < 10; r++) { for (int c = 0; c < 9; c++) { int p = board[r][c]; if (p == 0) continue; int val = PIECE_VALUE[abs(p)]; // 位置加成:红方兵过河加分,马在中心加分 if (p == RED_PAWN && r <= 4) val += 1; if (abs(p) == HORSE && c >= 2 && c <= 6) val += 0.5; score += (p > 0) ? val : -val; } } return (side == RED) ? score : -score; }

逻辑说明:PIECE_VALUE数组按棋子编码索引,红正黑负。side用来把分数转成当前走子方的视角,因为极小极大里红方取最大、黑方取最小,统一视角后代码更简洁。位置分不要加太猛,否则 AI 会为了占位丢子。我一般先只算子力,跑通后再逐项加位置分,每加一项看 AI 对局表现有没有变好。

5. 避坑与排查:编译、走子、AI 卡死的血泪记录

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

现象:打开 .sln 直接编译,报fatal error C1083: 无法打开源文件“afxwin.h”。原因:工程其实是 MFC 项目,但你装的 VS 没勾选 MFC 组件。解决:打开 Visual Studio Installer,修改当前 VS,在“单个组件”里搜“MFC”,勾选“适用于最新 v143 生成工具的 C++ MFC”,装完重启 VS 再编。如果不想装 MFC,就找纯 Win32 版本的源码包,别硬改。

5.2 点击棋子后棋盘重绘闪烁

现象:每次点击棋子,整个窗口白闪一下再画出棋盘。原因:WM_LBUTTONDOWN里直接调了InvalidateRect(hWnd, NULL, TRUE),TRUE表示擦除背景,导致先刷白再画。解决:把InvalidateRect第三个参数改成FALSE,并在WM_PAINT里用双缓冲。如果还闪,检查有没有在WM_ERASEBKGND里返回 0 并自己填背景,避免系统默认擦除。

5.3 AI 走子后轮到玩家,但棋子位置错乱

现象:AI 走完一步,棋盘上棋子位置和实际逻辑对不上,比如两个棋子叠在一起。原因:MakeMove里改了board数组,但绘制时用的还是旧的pieces对象数组,两套数据没同步。解决:统一数据源,要么绘制也读board,要么每次走子后把board同步回pieces。常见做法是只保留board二维数组,绘制时遍历它,省掉同步逻辑。

5.4 AI 搜索时窗口卡死无响应

现象:玩家走完一步,AI 开始思考,窗口直接白屏,点关闭都没反应。原因:AI 搜索在 UI 线程里同步执行,搜索深度 5 层以上时耗时几秒,消息循环被阻塞。解决:把 AI 搜索放到单独线程,用CreateThread或std::thread,搜完后PostMessage通知 UI 线程刷新。注意线程里不要直接调 GDI 函数,只改数据,绘制交给 UI 线程。如果不想多线程,至少把搜索深度降到 3 层,并在搜索前SetCursor成等待光标。

5.5 评估函数返回 NaN 或分数异常大

现象:AI 偶尔走出送将的棋,或者分数突然变成几万。原因:Evaluate里用了未初始化的变量,或者PIECE_VALUE数组索引越界。比如abs(p)当p为 0 时返回 0,但PIECE_VALUE[0]没定义。解决:在Evaluate开头加if (p == 0) continue;,并确保PIECE_VALUE数组大小覆盖所有棋子编码。调试时可以在Evaluate里打印每个棋子的分值,看哪一步开始异常。

6. 进阶调优:让 AI 从“能走”到“能打”的几个实操技巧

6.1 用置换表缓存重复局面

Alpha-Beta 搜索里,不同走法顺序可能到达同一个局面,重复搜索浪费算力。置换表用哈希存已搜过的局面和分值,下次遇到直接查表。常见做法是用 Zobrist 哈希:给每个棋子在每个位置分配一个随机数,局面哈希就是所有棋子随机数的异或。走子时增量更新哈希,比每次重算快得多。

// Zobrist 哈希增量更新示例 UINT64 zobrist[15][10][9]; // 棋子类型 x 行 x 列 UINT64 boardHash = 0; void InitZobrist() { for (int p = 0; p < 15; p++) for (int r = 0; r < 10; r++) for (int c = 0; c < 9; c++) zobrist[p][r][c] = RandomUINT64(); } // 走子时更新哈希 void UpdateHash(int piece, int fromR, int fromC, int toR, int toC) { boardHash ^= zobrist[piece][fromR][fromC]; boardHash ^= zobrist[piece][toR][toC]; }

参数说明:zobrist数组第一维是棋子编码,红黑各 7 种共 14 种,留 15 够用。RandomUINT64用rand()拼两个 32 位即可,不用真随机。置换表用std::unordered_map<UINT64, Entry>,Entry存深度、分值、标志位。注意哈希冲突,简单做法是冲突时直接覆盖,对棋类 AI 够用。

6.2 迭代加深与时间控制

固定深度搜索有个问题:深度设 4 层,简单局面秒出,复杂局面等半天。迭代加深从深度 1 开始搜,逐层加深,每层记录最佳走法,下一层优先搜这个走法。配合时间控制,搜到限定时间就停,返回当前层最佳。

Move IterativeDeepening(int board[10][9], int side, int maxTimeMs) { Move bestMove = {0}; DWORD start = GetTickCount(); for (int depth = 1; depth <= MAX_DEPTH; depth++) { Move m = AlphaBetaRoot(board, side, depth); if (GetTickCount() - start > maxTimeMs) break; bestMove = m; } return bestMove; }

逻辑说明:AlphaBetaRoot是根节点搜索,返回最佳走法。每层搜完检查耗时,超时就不进入下一层。MAX_DEPTH设 6 到 8,实际能搜到几层看机器。参数maxTimeMs一般设 1000 到 3000,给玩家体验留余地。迭代加深的额外好处是,浅层搜索的最佳走法能用来排序深层走法,剪枝效率更高。

6.3 开局库与残局库的取舍

开局库存常见开局的前几步,AI 直接查库走子,省算力也避免开局乱走。残局库更复杂,需要穷举所有残局局面,文件动辄几百 MB。对这份源码包来说,我建议只加简易开局库:用文本文件存“炮二平五”“马八进七”这类走法序列,AI 开局前 5 步查库,查不到再搜索。残局库先别碰,投入产出比太低。

开局库格式可以很简单,每行一个局面哈希加最佳走法:

# 开局库示例:哈希 走法(fromR,fromC,toR,toC) 0x1A2B3C4D 9,1,7,2 0x5E6F7A8B 9,7,7,6

加载时读进unordered_map<UINT64, Move>,搜索前先查。注意开局库的哈希要和 Zobrist 一致,否则查不到。我一般会先用 AI 自己跑几十局,把前 5 步的走法记下来,人工筛掉明显臭棋,再存成开局库。这样比网上找的开局库更贴合这份源码的评估函数。

6.4 用日志验证 AI 决策链路

AI 走子不符合预期时,别靠猜。在AlphaBeta里加日志,记录每层搜索的最佳走法和分值,输出到文件。看日志能快速定位是评估函数给分不对,还是剪枝剪错了。

// 在 AlphaBeta 返回前加日志 #ifdef _DEBUG char buf[128]; sprintf_s(buf, "depth=%d side=%d best=%d alpha=%d beta=%d\n", depth, side, best, alpha, beta); OutputDebugStringA(buf); #endif

用 DebugView 工具看OutputDebugString输出,或者直接写文件。重点看根节点返回的最佳走法分值,如果某个明显该吃的子没吃,看评估函数里那个棋子的分值是不是设低了。如果 AI 反复走同一步,看置换表是不是把不同局面哈希冲突了。我习惯在调完评估函数后,让 AI 自己跟自己下 10 局,看有没有出现循环走子或送将,有就回去查日志。

从那以后我每次拆这类 Win32 棋类源码,都先把双缓冲和消息循环跑通,再动 AI 搜索,绝不一上来就改评估函数。希望帮到你。

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

相关新闻

Vue3 defineProps与defineExpose:父组件通信的收与给

Vue3 defineProps与defineExpose:父组件通信的收与给

前两天帮人排查一个表单联动的bug&#xff0c;现象很典型&#xff1a;子组件内部已经把校验逻辑封装好了&#xff0c;父组件也正确绑定了ref&#xff0c;结果一调用validate方法就报“not a function”。我点开子组件一看&#xff0c;<script setup>里写了一大堆方法&…

2026/10/20 6:17:29 阅读更多 →
Python实战:从零构建PPT自动生成工具,实现内容与样式分离

Python实战:从零构建PPT自动生成工具,实现内容与样式分离

1. 为什么我要自己动手做一个PPT生成工具先说说我做这个项目的起因。我在一家中型公司做技术方案和产品汇报&#xff0c;平均每周要产出三到五份PPT&#xff0c;多的时候一天两场评审。最开始我也是老老实实打开演示软件&#xff0c;一页一页拖文本框、调对齐、配图标&#xff…

2026/10/20 6:17:29 阅读更多 →
专科毕业论文必备!10款AI论文写作软件全功能实测盘点

专科毕业论文必备!10款AI论文写作软件全功能实测盘点

全网最全10个AI论文写作软件&#xff0c;专科生毕业论文必备&#xff01;先别急着划走。作为一个前前后后帮学弟学妹改过上百份专科毕业论文的老油条&#xff0c;我必须说一句大实话&#xff1a;专科毕业论文被卡的原因&#xff0c;八成不是“研究不够深”&#xff0c;而是“格…

2026/10/20 6:16:29 阅读更多 →

最新新闻

相机标定与3D坐标转换:从像素到三维坐标的完整流程

相机标定与3D坐标转换:从像素到三维坐标的完整流程

简介&#xff1a;面向计算机视觉开发者和机器人、自动驾驶等领域的从业者&#xff0c;这份压缩包给出了一套完整的相机标定与二维到三维坐标转换方案&#xff0c;不仅覆盖常见RGB相机标定、红外相机标定和图像去畸变&#xff0c;还包含平面直线算法、PnP算法、8点算法等多种位姿…

2026/10/20 7:03:50 阅读更多 →
PySpark UDF 详解:从原理到性能优化实战

PySpark UDF 详解:从原理到性能优化实战

1. UDF 是什么&#xff0c;为什么 PySpark 偏偏需要它先说结论&#xff1a;UDF&#xff08;User Defined Function&#xff0c;用户定义函数&#xff09;就是让你把 Python 普通函数注册成 Spark SQL 或 DataFrame 里能调用的“算子”&#xff0c;从而按行处理数据。我刚接触 P…

2026/10/20 7:03:50 阅读更多 →
企业服务总线ESB平台方案:从蜘蛛网到统一消息中枢的集成治理

企业服务总线ESB平台方案:从蜘蛛网到统一消息中枢的集成治理

简介&#xff1a;面向企业架构师、系统集成工程师及IT决策者的企业服务总线ESB平台解决方案文档&#xff0c;系统阐述ESB如何将多个异构系统、应用程序和服务纳入统一集成体系&#xff0c;支撑业务流程自动化、数据交换与业务智能分析。文档基于标准、松耦合、事件驱动的服务导…

2026/10/20 7:03:50 阅读更多 →
SWTChart实战:为SWT桌面应用打造轻量原生图表的选型与避坑指南

SWTChart实战:为SWT桌面应用打造轻量原生图表的选型与避坑指南

简介&#xff1a;SWTChart是一款基于SWT的Java图表类库&#xff0c;体积轻巧、集成方便&#xff0c;无需引入重型绘图框架&#xff0c;适合需要在桌面端或Eclipse RCP环境中展示数据图表的Java开发者使用。资源包共三十六个文件、约二百八十七KB&#xff0c;包含二十四个Java源…

2026/10/20 7:03:50 阅读更多 →
跨境电商商品生命周期管理:从引入期到衰退期的实操打法

跨境电商商品生命周期管理:从引入期到衰退期的实操打法

做跨境电商的&#xff0c;手里大多都有过这么几个“烂摊子”&#xff1a;某款产品刚上架那会儿数据漂亮得不行&#xff0c;广告一停就断崖式下跌&#xff1b;有的款补了三个月的货&#xff0c;结果两个月就卖不动了&#xff0c;库存堆在海外仓每天烧仓储费&#xff1b;还有的款…

2026/10/20 7:03:50 阅读更多 →
HBase大Cell写入异常:超10M报错的原因与拆分方案

HBase大Cell写入异常:超10M报错的原因与拆分方案

1. 问题背景与异常现象拆解1.1 一个看似普通的写入操作为何突然报错第一次碰到这个异常是在一个日志聚合场景里。业务侧把一整段经过序列化的消息体直接塞进了一个列族&#xff0c;平时单条消息也就几十KB&#xff0c;跑了大半年相安无事。直到某天上游做了一次批量回补&#x…

2026/10/20 7:02:50 阅读更多 →

日新闻

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

/* 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 1:01:30 阅读更多 →
ESP32舵机控制指南:原理、多路驱动与避坑实战

ESP32舵机控制指南:原理、多路驱动与避坑实战

/* 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 1:01:30 阅读更多 →
位移法实现一阶低通滤波:单片机ADC采样降噪实战

位移法实现一阶低通滤波:单片机ADC采样降噪实战

/* 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 1:01:30 阅读更多 →

周新闻

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

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

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

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

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

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

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

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

如果你的信息流最近也天天刷到“机器人大脑”这个词&#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/19 2:54:50 阅读更多 →
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/19 9:10:22 阅读更多 →
黑夜航拍船只数据集训练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/18 12:16:16 阅读更多 →