200行Qt贪吃蛇实战:QPainter自绘与QTimer驱动
简介面向 Qt 初学者的完整贪吃蛇项目演示如何用约 200 行代码搭建一个界面版游戏。项目覆盖 QWidget 主窗口、QGraphicsView/Scene 图形渲染、定时器驱动的蛇移动、键盘方向控制以及食物生成与碰撞检测等核心机制适合刚接触 Qt 的学生或开发者用作课程设计与入门练手。压缩包共 68 个文件以 cpp/h 源码、pro/pri 工程配置、png 图片素材和 exe 可执行程序为主同时包含 Visual Studio 与 Qt Creator 工程文件、编译中间产物及调试记录整体约 57.11MB解压后目录结构清晰源码、资源与配置分离便于对照阅读和二次修改。目前已有 570 人学习下载说明其实用性和参考价值得到了不少同阶段学习者认可。通过对源码和可运行程序的分析可以直观掌握贪吃蛇游戏从界面搭建到逻辑实现的完整流程包括移动状态更新、分数刷新、开始/暂停/重新开始等交互设计同时体会模块化封装与 Qt 信号槽通信在小型项目中的实际应用为后续开发更复杂的 Qt 程序积累经验。1. 200行Qt贪吃蛇别被QGraphicsScene吓住“200行代码写一个简易的Qt界面贪吃蛇”这句话听起来像标题党但按下面这套组合做下来实际代码量就是能压在200行上下QWidget做窗口、QTimer做心跳、QPainter画画面。不需要QGraphicsScene不需要设计器拖控件也不需要单独建UI文件。这套方案的立足点是把游戏逻辑看成一串可变状态界面只负责把状态画出来。所以它真正解决的是用最小的代码量把Qt的事件循环、定时器、键盘输入和自绘机制完整走一遍。适合刚学完基础信号槽、想动手折腾一个小项目的开发者也适合做课程设计时不想让代码被模板占满的人。贪吃蛇虽然简单但“蛇身怎么存、方向怎么防掉头、撞自己怎么判断”这些点跟做正式一点的小游戏是同一套思路。下面我按自己复现这个方向时的拆解顺序讲先定数据结构再写绘制最后接定时器与按键并把踩过的坑单独放一章。2. 先建模型再碰界面蛇身、食物和方向的存储设计很多初学者一上手就开一个.ui文件先把格子底图画出来再想着怎么让蛇动起来最后被布局和信号槽拖住。我一般反过来先写游戏状态再考虑画布。贪吃蛇的画面完全由状态推导蛇身坐标变了重绘就变了食物坐标变了重绘就变了。界面只是状态的一张照片照片随时可以重拍。2.1 为什么不用QGraphicsScene复杂度全在渲染不在这里Qt 官方示例和不少教程里小游戏偏爱 QGraphicsScene因为它有现成的碰撞检测、可拖拽 Item、动画框架。但这个题目只有一块 20×20 的网格活动对象最多几十个用 QGraphicsScene 引入的 Item 管理、场景更新反而成了额外负担。更现实的问题是当把蛇身拆成多个 GraphicsItem 时方向、碰撞、生长逻辑都被拆散到 Item 层排查起来特别绕。自绘 QWidget 的思路是所有逻辑都写在step()一个函数里画面只负责根据状态画出来这种单向依赖最好调试。所以这里不用 QGraphicsScene连 QMainWindow 都可以不用。直接继承 QWidget自己处理 paintEvent 和 keyPressEvent。这样整个程序只有一个类、一个文件逻辑从头到尾是线性的新手也能看清每一行在干什么。2.2 核心数据结构一个QWidget子类四个变量先定义全局的棋盘常量再给出类定义。这两个常量建议放到代码文件最上方后面所有函数共用避免在多个地方出现魔法数字。#include QWidget #include QTimer #include QPainter #include QKeyEvent #include QPoint #include QVector #include QRandomGenerator #include algorithm const int kGrid 20; // 每行/每列的格子数 const int kCell 20; // 初始每个格子的像素边长 const int kInterval 100; // 初始定时器间隔单位ms class SnakeGame : public QWidget { public: explicit SnakeGame(QWidget* parent nullptr); protected: void paintEvent(QPaintEvent*) override; void keyPressEvent(QKeyEvent*) override; private: QTimer timer_; QVectorQPoint snake_; // 蛇身头在 front() QPoint food_; int dx_ 1; // 当前方向增量1向右 int dy_ 0; // 0垂直不动-1向上 int score_ 0; bool over_ false; void reset(); void newFood(); void step(); };这里没写Q_OBJECT宏因为我们不需要自定义信号槽也不使用tr()、property等元对象特性。这样单个 cpp 文件可以直接编译不需要额外跑 moc大大降低上手门槛。snake_用QVectorQPoint存front()是头push_back是尾。方向用坐标增量而不是枚举省去一大段 switch 映射也方便判断是否掉头。dx_ 1表示当前向右dy_ 0表示垂直方向没有移动。这个设计看起来简单但后面所有逻辑都建立在它上面改起来非常顺手。2.3 初始化与食物生成让随机不落在蛇身上游戏开始和按“重新开始”时都需要把状态拉回初值。蛇身我习惯放 3 个格子头在中间偏右的位置初始方向向右。食物则通过一个看起来有点“暴力”的循环生成随机取一个单元格如果落在蛇身上就重新随机一次。20×20 的棋盘上蛇身不长时命中概率很低等蛇身占到三分之一以上循环次数才会明显增加但那时游戏也快结束了完全可接受。void SnakeGame::reset() { snake_.clear(); snake_ QPoint(10, 10) QPoint(9, 10) QPoint(8, 10); dx_ 1; dy_ 0; score_ 0; over_ false; newFood(); } void SnakeGame::newFood() { while (true) { int x QRandomGenerator::global()-bounded(kGrid); int y QRandomGenerator::global()-bounded(kGrid); QPoint p(x, y); if (!snake_.contains(p)) { food_ p; break; } } }QRandomGenerator::global()-bounded(kGrid)返回 0 到 kGrid-1 的随机数正好落在网格下标范围内。如果你用的是 Qt 5 老代码习惯写qrand() % kGrid效果一样但 Qt 6 里建议用 QRandomGenerator因为它的分布质量更好调用也更直接。reset()里必须先clear()再追加初始蛇身防止上一次游戏留下的坐标残留。构造函数里启动定时器并连接 timeout 到step()这部分放到第 4 章说。一个值得注意的细节食物生成时QVector::contains会逐个比较 QPoint 坐标蛇身短时开销很小。千万不要为了“优化”去写一个 bool 二维数组那会让整个类多一个成员而且在 200 行预算里毫无必要。3. 用QPainter把网格画出来drawRect画蛇drawEllipse画食物数据模型定下来之后界面绘制就纯粹是体力活了。paintEvent 里唯一要做的事是根据snake_和food_的坐标把对应格子涂上颜色。我习惯先画背景再画食物最后画蛇。顺序不是随意定的背景垫底食物要露出来蛇身如果覆盖在食物上也应该正常盖住这样层级最直观。3.1 paintEvent整体布局先背景再食物最后蛇void SnakeGame::paintEvent(QPaintEvent*) { QPainter p(this); p.fillRect(rect(), QColor(30, 30, 36)); // 根据实际窗口大小动态计算格子像素避免拉伸错位 const int cell std::min(width(), height()) / kGrid; // 食物红色圆形 p.setPen(Qt::NoPen); p.setBrush(QColor(255, 85, 85)); p.drawEllipse(food_.x() * cell 2, food_.y() * cell 2, cell - 4, cell - 4); // 蛇圆角矩形蛇头颜色更亮 for (int i 0; i snake_.size(); i) { QRect r(snake_[i].x() * cell 1, snake_[i].y() * cell 1, cell - 2, cell - 2); p.setBrush(i 0 ? QColor(140, 255, 170) : QColor(80, 210, 130)); p.drawRoundedRect(r, 4, 4); } }这里std::min(width(), height()) / kGrid是关键。窗口的实际客户区和顶层窗口大小之间会有平台差异如果直接用固定的kCell计算坐标在部分平台上右侧或底部会被裁掉一条。动态计算虽然只差一两个像素但能保证任何尺寸下网格都完整落在画布内。setPen(Qt::NoPen)必须显式设置否则 QPainter 默认会用黑色画一个 1 像素的边框把每个色块框起来在深色背景下特别难看。食物画圆形时cell - 4相当于在格子四周各留 2 像素边距视觉上不会顶着边。蛇身用drawRoundedRect圆角半径 4 像素比直角方块耐看。蛇头单独用一个浅绿色玩家不用数格子也能快速定位方向。3.2 参数选择网格数、格子像素、窗口尺寸怎么组合下面这张表是我在模拟项目 X 里实际用过的一组参数直接照着填就能跑。它们之间是联动关系改动时要一起调。参数取值作用备注kGrid20每行每列的格子数越小地图越简单越大蛇的活动范围越大kCell20初始每个格子的像素边长实际绘制用动态 cell这里只决定窗口初始大小窗口尺寸400×400初始窗口用setFixedSize(kGrid * kCell, kGrid * kCell)定时器间隔100蛇每 100ms 移动一格相当于 10 帧/秒节奏适中如果你把kGrid改成 30窗口固定尺寸也要改成 600×600否则每个格子会被压缩得很小。如果改成kCell16界面会更紧凑但圆角半径 4 像素在部分低分辨率屏幕上会显得像圆点。我建议新手先用 2020 这套组合跑通再去调这些值。窗口尺寸这里有个细节setFixedSize(kGrid * kCell, kGrid * kCell)设置的是 QWidget 自身的大小在 Windows 这类带边框和标题栏的系统上实际客户区会比这个数小一点。所以绘制时一定要用std::min(width(), height()) / kGrid动态计算格子像素而不是拿kCell硬算。这也是我后来不再纠结 400 还是 396 的原因。3.3 闪烁处理QWidget自带双缓冲别再自己画QPixmap网上有些老文章会教你建立一个 QPixmap把所有画面画到 pixmap 上再一次性drawPixmap到窗口理由是防止闪烁。这个做法在 Qt 4 时代还有必要但现代 Qt 的 QWidget 内部已经有 backing store普通小游戏直接重绘并不会出现肉眼可见的闪烁。真正需要留意的是setAttribute(Qt::WA_OpaquePaintEvent)。这个属性告诉系统“这个控件完全由自己绘制不需要预填充背景”。如果你设了它但又忘了在 paintEvent 里fillRect上一帧的画面会残留在新的画布上形成类似重影的现象。我们的代码里每帧都先fillRect(rect(), QColor(30, 30, 36))所以不开这个属性也没问题。遇到闪烁时优先检查是不是用了 WA_OpaquePaintEvent而不是一开始就去搭双缓冲。4. 移动、转向与碰撞一帧更新三步走绘制完成后游戏还不会动。动起来靠的是 QTimer 每隔 100ms 触发一次step()在step()里完成三件事计算新蛇头位置、判断是否吃到食物、判断是否死亡。这里要特别强调移动逻辑必须写在step()里不能写在paintEvent()里。paintEvent 可能因为窗口移动、遮挡等任意时机被调用如果在那里改状态会出现蛇像抽搐一样一次走两步的怪象。4.1 用QTimer驱动单步100ms的间隔参数要这样调构造函数中把定时器连接好SnakeGame::SnakeGame(QWidget* parent) : QWidget(parent) { resize(kGrid * kCell, kGrid * kCell); setFocusPolicy(Qt::StrongFocus); // 让窗口能接收键盘事件 connect(timer_, QTimer::timeout, this, SnakeGame::step); timer_.setInterval(kInterval); reset(); }setFocusPolicy(Qt::StrongFocus)很关键没有它键盘事件可能只在点击窗口后才有效很多人因此以为按键失效。connect只调用这一次之后无论重开多少次游戏都不要再次 connect否则同一个 timeout 信号会触发多个step()蛇会肉眼可见地加速。step()的完整实现void SnakeGame::step() { if (over_) return; // 1. 计算新蛇头位置 QPoint head snake_.front(); head.rx() dx_; head.ry() dy_; // 2. 撞墙判断 if (head.x() 0 || head.x() kGrid || head.y() 0 || head.y() kGrid) { over_ true; update(); return; } // 3. 判断是否吃到食物 bool ate (head food_); snake_.prepend(head); if (ate) { score_; newFood(); } else { snake_.pop_back(); } // 4. 撞自己判断从下标1开始找跳过蛇头自己 if (snake_.indexOf(snake_.front(), 1) ! -1) over_ true; update(); }这段代码的顺序是不能换的。先算 head再撞墙再prepend然后决定是否pop_back最后才判断撞自己。这样当蛇头下一步会移动到原本尾巴的位置时因为尾巴已经被pop_back()移除不会误判为撞到自己。如果先判断碰撞再移动蛇在贴着自己尾巴走的时候会莫名死亡。每次step()做完所有状态修改后调用update()。update()会异步触发一次 paintEvent不要直接调repaint()那样会强制立刻重绘在事件循环紧张的瞬间造成不必要的开销。4.2 方向输入四个方向的判断与防掉头键盘输入是另一个常见翻车点。防掉头不是“当前在水平方向就不能按上下”而是“不能按与当前方向完全相反的方向”。我见过很多新手这么写if (dx_ ! 0) break;然后允许按上结果蛇水平向右时按“下”也被放行了这是合法的转弯但如果你同时拦住了左问题就变成“向右时按上会直接掉头”还是“向←时按上”所以正确写法是只禁反向void SnakeGame::keyPressEvent(QKeyEvent* e) { switch (e-key()) { case Qt::Key_Up: if (dy_ 1) break; // 当前正在向下禁反向 dx_ 0; dy_ -1; break; case Qt::Key_Down: if (dy_ -1) break; // 当前正在向上禁反向 dx_ 0; dy_ 1; break; case Qt::Key_Left: if (dx_ 1) break; // 当前正在向右禁反向 dx_ -1; dy_ 0; break; case Qt::Key_Right: if (dx_ -1) break; // 当前正在向左禁反向 dx_ 1; dy_ 0; break; default: QWidget::keyPressEvent(e); return; } }注意这里判断的是“当前方向的反向”而不是“当前方向本身”。例如当前向右dx_ 1按左时dx_ 1成立说明玩家想直接掉头于是拦下。按上时dy_ 1不成立说明不是反向允许转上。这个逻辑只要写错一条就会出现“按上却向下走”的玄学问题。另外一个细节方向变化是立即生效的不是等下一帧。如果你在step()内部读dx_/dy_按键事件发生在两次 step 之间那么下一次 step 就会按新方向走这符合直觉。不要为了“平滑”而缓冲方向那样反而会让操控有延迟感。4.3 吃食物与碰撞检测prepend和pop_back的顺序不能换前面 step 的代码已经体现了顺序。这里再单独把吃食物这条线拎出来说说。很多实现会这样写if (head food_) { snake_.prepend(head); newFood(); } else { snake_.prepend(head); snake_.pop_back(); }也能跑但多了一个分支代码量不紧凑。更简洁的方式是先prepend再根据ate决定是否pop_back。顺序一旦反过来比如先pop_back()再prepend(head)吃到食物时蛇身长度仍然会加 1但尾巴被错误地截掉了视觉上就是“食物消失但蛇没变长”。碰撞检测里还有一个细节撞自己的判断要放在pop_back()之后。如果蛇头即将移动到尾巴当前的位置而尾巴本来就要在下一步移走这时候不应该算碰撞。我们的顺序天然规避了这个问题。如果你想写“撞尾巴也算死”的严格模式可以把碰撞判断挪到pop_back()之前但那是另一套玩法别让初版代码混进这种边界规则。5. 避坑贪吃蛇最容易翻车的5个现场与排查方案这里把我在调试过程中遇到最多的问题列出来。每一条都是先讲现象再讲原因最后给解决。新手照着对照自己的代码能省掉大量瞎猜时间。5.1 按键只在第一次生效焦点没拿到现象窗口刚弹出来时按方向键完全没反应用鼠标点一下窗口之后再按就正常了。原因QWidget 默认不接受键盘焦点。按键事件只会发给当前聚焦的 widget而 QWidget 没有设置焦点策略时不会主动获取焦点。很多例子里只 show 了窗口没有指定焦点策略。解决构造函数里加上setFocusPolicy(Qt::StrongFocus);并且在show()之后调用setFocus()。如果游戏内部还有子控件比如把画布放到一个 QFrame 里那要确保是画布拿到焦点而不是外层的 QWidget。最简单还是让整个游戏窗口就只有一个 widget不给焦点四处跑的机会。5.2 按下“上”直接掉头往回走方向判断写反了现象蛇正向右走按“上”后蛇头却掉头向左瞬间撞死。原因键盘分支里判断反向时写成了if (dx_ ! 0)或其他变形。比如当前向右dx_1按“上”时你判断if (dx_ ! 0) break;这个条件成立直接 break但实际应该放行的是“非反向”按键。更常见的是写成这样case Qt::Key_Up: if (dy_ 0) break; // 错误当前水平移动时 dy_0按上被拦 dx_ 0; dy_ -1;结果就是水平移动时上下键完全失效等垂直移动时按左右又把方向打乱。解决按上只检查dy_ 1按下只检查dy_ -1按左只检查dx_ 1按右只检查dx_ -1。逻辑想不通就画张坐标图把四个方向的增量标出来一眼就明白。5.3 蛇越跑越快定时器被反复start现象游戏开始是正常速度玩到中途突然加速像按了快进。原因最常见是connect被写进了reset()或构造函数之外会被重复调用的函数。每调用一次connect就多一个 timeout 到 step 的连接一个信号触发多个 step蛇天然变快。另一种情况是误以为timer_.start()会“加速”在吃到食物时反复调用start()但 start 只是启动或重启计时器不会改变 interval。解决connect只在构造函数执行一次。加速逻辑用timer_.setInterval()修改间隔不要反复 start。如果发现代码里有循环start先把那个循环拆掉。实在不行在 start 前先timer_.stop()但治标不治本。5.4 蛇吃到了食物但长度不变逻辑顺序错了现象食物被蛇头碰上后消失分数也加了但蛇身长度没有增加甚至有时候蛇尾突然少一截。原因在prepend之前就做了pop_back或者吃食物分支里还执行了pop_back。典型的错误写法snake_.prepend(head); if (ate) { newFood(); } snake_.pop_back(); // 不管吃没吃都弹尾巴解决把pop_back()放到else分支里或者像第 4 章那样用bool ate控制。这个 bug 不会导致崩溃但视觉上非常明显而且是新手最容易犯的顺序问题。调试时可以专门在吃食物的瞬间打印snake_.size()看是否从 3 变成 4一目了然。5.5 窗口被拖拽后网格错位没有锁定尺寸现象窗口边缘可以拉伸拉大后蛇身和食物跟网格线对不上右侧留白或者画布被裁掉。原因绘制时用了固定kCell 20计算坐标但窗口实际尺寸变了20×20 的网格像素和窗口不匹配。另一个原因是顶层窗口的边框和标题栏占用了尺寸固定 400×400 的窗口客户区并不是 400。解决两种方案任选。第一种是setFixedSize(kGrid * kCell, kGrid * kCell);禁止拉伸适合纯展示。第二种是在 paintEvent 里动态计算cell std::min(width(), height()) / kGrid;所有绘制都用这个 cell而不是固定 kCell。我推荐第二种因为它同时兼容窗口管理器差异也不用担心不同系统的边框宽度。如果用了第二种还错位检查一下是不是有地方把width()和height()写反了。6. 从200行到300行计分、加速、暂停与重开跑通基础版之后很多人会忍不住往里加功能。这里我给几条最小化的扩展方向每一段都不超过几行不会把代码撑爆。6.1 计分不用QLabel直接写进窗口标题最省事的计分方式是把分数更新到窗口标题里。在step()吃到食物时加一行setWindowTitle(QStringLiteral(贪吃蛇 分数%1).arg(score_));这样不需要额外布局也不会遮挡游戏画面。如果你想要分数在画布内显示也可以直接在 paintEvent 里用p.drawText(QPoint(5, 5), ...)但 0 行是网格坐标文字会和格子重叠反而不如标题栏整洁。6.2 加速缩短定时器间隔要有下限吃食物后让蛇稍微快一点能显著增加可玩性。常见做法是每次食物把间隔减 5但不设下限。void SnakeGame::speedUp() { int interval timer_.interval(); if (interval 50) timer_.setInterval(interval - 5); }下限 50ms 对应 20 帧每秒再快就接近纯视觉极限键盘输入会开始有“吞按键”的感觉。加速操作放在step()中吃到食物的分支里调用speedUp()。6.3 暂停和重开空格与R键的最小实现在keyPressEvent里加两个分支case Qt::Key_Space: if (timer_.isActive()) timer_.stop(); else timer_.start(); break; case Qt::Key_R: reset(); timer_.start(); break;空格暂停的依据是定时器当前状态不需要额外布尔变量。R 重开时先reset()再start()因为reset()只是把状态拉回初值并不会自动重启定时器。注意如果游戏已经over_ truestep 里会直接 return所以按 R 后必须显式 start否则蛇永远不动。我的一个习惯是每次加功能后跑十局观察手感。如果按方向键有“卡一下”的感觉优先检查是不是在 paintEvent 里做了耗时操作如果快速连按方向键偶尔会掉头那说明你某个分支的反向判断漏了一条。这些小功能并不难难的是保持状态修改都在step()一个入口里别让按键直接改蛇身坐标否则重绘时你会看到蛇瞬间瞬移那才是真让人头大。希望这份经验帮到你动手写一个出来比光看文章有效十倍。本文还有配套的精品资源点击获取

相关新闻

C++工程集成MINIZIP静态库:从链接错误到压缩解压的完整避坑指南

C++工程集成MINIZIP静态库:从链接错误到压缩解压的完整避坑指南

简介:MINIZIP压缩解压缩资源包面向需要在应用程序中集成ZIP功能的C/C开发者,基于成熟的ZLIB库封装而成,保留了轻量级、跨平台特性,同时支持AES-256加密、UTF-8等多语言文件名以及解压进度显示,适合嵌入式环境或对交互体…

2026/10/14 14:00:05 阅读更多 →
基于dq控制的并联有源滤波器设计与谐波补偿实践

基于dq控制的并联有源滤波器设计与谐波补偿实践

1. 项目背景与核心价值 在工业电力系统中,非线性负载(如变频器、整流设备等)的广泛应用导致电网谐波污染日益严重。传统无源滤波器虽然成本低廉,但存在谐振风险、只能补偿固定次谐波等固有缺陷。而基于dq控制算法的并联有源滤波器…

2026/10/14 13:59:05 阅读更多 →
基于dq控制的并联有源滤波器设计与Simulink仿真

基于dq控制的并联有源滤波器设计与Simulink仿真

1. 项目背景与核心价值在工业电力系统中,谐波污染和无功功率问题一直是影响电能质量的关键因素。传统无源滤波器虽然结构简单,但存在滤波性能固定、容易与系统发生谐振等问题。而基于dq控制算法的并联有源滤波器(APF)通过实时检测…

2026/10/14 13:59:05 阅读更多 →

最新新闻

MySQL SELECT与SHOW实战:从基础查询到性能排查的完整指南

MySQL SELECT与SHOW实战:从基础查询到性能排查的完整指南

从接触数据库开始,大多数人的第一条SQL都是SELECT,而SHOW往往是那个“我知道它存在,但很少深入研究”的兄弟命令。这个主题虽然叫“简单检索”,但SELECT和SHOW几乎撑起了日常数据库操作的半边天:前者负责从一张或多张表…

2026/10/14 14:38:54 阅读更多 →
主成分分析PCA从原理到实战:高维数据降维的核心技术解析

主成分分析PCA从原理到实战:高维数据降维的核心技术解析

很多人在刚开始接触数据分析时,面对几十个甚至上百个特征,第一反应往往是茫然。画出来的散点图矩阵密密麻麻,算出来的相关系数表让人眼花缭乱,跑出来的模型又总被多重共线性拖后腿。这时候,主成分分析(PCA&…

2026/10/14 14:38:54 阅读更多 →
Pandas线性插值实战:空气质量数据异常值与缺失值处理

Pandas线性插值实战:空气质量数据异常值与缺失值处理

这段时间帮某个环境监测项目处理城市空气质量数据,遇到最多的不是模型效果差,而是数据本身的问题。一套PM2.5、PM10、NO2、SO2浓度数据拿过来,缺失值、异常值、重复记录混在一起,直接建模结果根本没法看。把这些数据清洗干净&…

2026/10/14 14:37:53 阅读更多 →
Res2dmod二维正演原理与地形建模实战指南

Res2dmod二维正演原理与地形建模实战指南

简介:本资源为地球物理勘探领域专业正演软件Res2dmod的完整安装包,面向地质勘查、矿产与石油勘探、环境及工程地质等方向的科研人员与高年级本科生/研究生,用于开展二维高密度电法正演模拟与反演建模。包内共5个文件:setup.exe与s…

2026/10/14 14:37:53 阅读更多 →
Feature-level SMOTE:破解PHM故障诊断中的类别不平衡难题

Feature-level SMOTE:破解PHM故障诊断中的类别不平衡难题

1. 从一次翻车的轴承故障诊断说起去年帮一个做风电齿轮箱状态监测的团队调模型,他们手里有三年多的振动数据,正常样本几十万条,早期微弱故障样本满打满算不到三百条。当时用常规的SMOTE在原始时序上做增强,训练集AUC能刷到0.98&am…

2026/10/14 14:37:53 阅读更多 →
Python第4周循环与列表常见错误深度复盘

Python第4周循环与列表常见错误深度复盘

1. 这不是一份普通作业复盘,而是一份“Python语法肌肉记忆”养成指南你打开浏览器,输入“Python语言程序设计第4周测验练习题复盘”,页面跳出的多半是零散的答案截图、几道题的简短解析,或者某个学生在论坛里发的“求大佬帮看第3题…

2026/10/14 14:37:53 阅读更多 →

日新闻

AnyPS5通用适配层设计:兼容性与性能的工程取舍

AnyPS5通用适配层设计:兼容性与性能的工程取舍

1. 从"AnyPS5"这个名字说起:它到底想解决什么问题第一次看到"AnyPS5"这个标题,我脑子里冒出来的第一个念头是:这大概率是一个围绕"跨平台运行"或者"通用适配"做文章的项目。名字里的"Any"…

2026/10/14 0:00:41 阅读更多 →
Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

1. 项目概述:Flutter跨平台二手交易应用开发作为一名长期从事移动应用开发的工程师,我最近完成了一个基于Flutter框架的二手物品交易平台项目。这个项目最吸引我的地方在于它完美结合了Flutter的跨平台优势与HarmonyOS的生态特性,实现了"…

2026/10/14 0:00:41 阅读更多 →
DFS算法解决飞机降落调度问题实战

DFS算法解决飞机降落调度问题实战

1. 项目背景与核心思路飞机降落问题是一个经典的调度优化场景,也是算法竞赛和面试中的高频题目。这个题目要求我们合理安排多架飞机的降落顺序和时间,确保所有飞机都能安全着陆而不发生冲突。在实际航空管制中,这类问题直接关系到飞行安全和机…

2026/10/14 0:00:41 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/13 16:22:04 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 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/13 22:01:27 阅读更多 →
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/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练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/14 7:53:34 阅读更多 →