Java推箱子项目实战:从地图建模到BFS自动求解
简介基于Java实现的推箱子小游戏项目以炮炮兵趣味形象作为主角界面美观适合Java初学者、课程设计学生及游戏开发爱好者学习Swing/GUI编程、事件监听与游戏状态管理。资源共60个文件以36个关卡地图文件map和10张角色/场景图片gif为主体配以6个class编译文件、4份doc文档开发、测试、用户、程序员文档、背景音乐mid及数据库等辅助内容压缩包仅248KB轻量完整。已有224人学习下载。解压后可直接运行bat批处理启动游戏也可打开mytxz.java源码完整观察从地图读取、角色移动到箱子推拉、关卡通关判定的实现流程多个地图文件便于自行扩展难度。项目还包含音乐播放、资源管理及程序文档覆盖了面向对象设计、集合/数据结构、事件处理等知识点可作为Java课程设计或入门练手的实用参考。1. 拿到PP.rar先别急着解压Java推箱子项目到底要解决什么推箱子这种小游戏看起来只是二维数组里挪几个人和箱子但真把代码写出来你会发现自己同时触碰了地图数据建模、状态机切换、碰撞检测、键盘事件监听和UI重绘这些Java基础面试里最喜欢问的点。网上流传的PP.rar大多装的就是一套课程设计或练手用的推箱子源码文件不大但覆盖面不小很多java面试题里也常拿它的变体来考状态搜索和对象设计。这篇笔记就顺着这个压缩包里的常规结构把从解压到跑通、再到自己动手加功能的路子完整过一遍。新手照着做能把环境、代码、排错全闭环熟手也能看看里边地图读入和状态回滚的设计有没有可改进的空间。2. 从PP.rar到可运行项目地图模型与文件读取2.1 解压与导入IDE别把编码和项目结构坑留到后面很多人在这一步摔跟头倒不是代码问题而是拿到压缩包后直接解压然后用IDEA或Eclipse打开文件夹结果一堆红色报错。常见原因是压缩包里只有.java文件没有标准Maven目录结构也没有.classpath和.project这类IDE配置文件。最省事的做法是先在IDE里新建一个空Java项目再把解压出来的.java文件连同地图文本文件一起拷进src目录让IDE自己重新编译。我一般会先看一眼代码里的文件读取路径。如果用的是相对路径比如maps/level1.txt那就要把地图文件夹拷到项目根目录下而不是只拷Java文件。另一种情况是代码用绝对路径比如C:/Users/.../level1.txt这种代码换台电脑就要改路径建议自己改成相对路径否则后面打包或移动目录时必翻车。还有一点容易被忽略源码文件编码。国内不少课程设计源码是用GBK写的而现代IDE默认UTF-8解压后直接打开会出现中文乱码严重时整个类名都识别不了。这个坑放到第5章细说这里先记住一个动作解压后先用记事本或IDE的“以UTF-8打开”功能看一眼中文注释是否正常不正常就先把项目编码切到GBK或者把源码转码成UTF-8再导入。2.2 地图数据的长相从字符到二维数组的映射推箱子的地图本质是个矩形网格每一格有五种状态空地、墙壁、箱子、目标点、玩家。最常见的做法是用一个文本文件一行行描述地图每个字符代表一种元素。下面是一个最小关卡例子###### # # # .$ # # $ # # # ######这里#是墙.是目标点$是箱子是玩家空格是地板。字符地图的好处是肉眼可读、容易修改坏处是字符宽高不统一而且空格在编辑器里容易被末尾空行吃掉。所以读取代码必须按“每行字符数组独立解析”的思路来不能简单按空格split。2.3 用Java读取地图到二维数组字符矩阵与缺位处理这里给出一个通用的地图读取方法兼容UTF-8和GBK两种编码并且能自动补齐每一行长度不一致导致的地图“空洞”。public static char[][] loadMap(String filePath) throws IOException { ListString lines new ArrayList(); BufferedReader reader new BufferedReader( new InputStreamReader(new FileInputStream(filePath), StandardCharsets.UTF_8)); // 统一按UTF-8读取 String line; while ((line reader.readLine()) ! null) { if (line.trim().isEmpty()) { continue; // 跳过空白行 } lines.add(line); } reader.close(); int rows lines.size(); int cols 0; for (String s : lines) { cols Math.max(cols, s.length()); } char[][] map new char[rows][cols]; for (int i 0; i rows; i) { String row lines.get(i); for (int j 0; j cols; j) { // 不足宽度的位置自动补成墙壁避免越界访问 map[i][j] (j row.length()) ? row.charAt(j) : #; } } return map; }逻辑很简单先逐行读入到列表统计最大行宽再按最大行宽建二维数组缺字符的格子自动填成墙。这样即使某个地图文件里有一行意外短了几列程序也不会在运行时突然抛出ArrayIndexOutOfBoundsException。很多刚上手的同学会写死每行的长度比如new char[9][9]一旦地图文件里多一个空格就会把后面的行列挤歪这就是血泪经验。参数上给两点提示。第一如果地图文件是GBK编码且含中文注释StandardCharsets.UTF_8读出来会是乱码但地图字符本身是ASCII通常不影响判断符号。要彻底避免就把UTF_8换成GBK但更推荐把源文件统一转成UTF-8。第二lines大小是行数如果读进来的地图宽度超过字符数组的声明上限照样会越界所以这里用动态的Math.max而不是固定值。读取这个环节还承担另一个任务把玩家坐标存下来。可以顺手在遍历时记录所在的位置省得后面每次移动都要全图扫描。地图读进来后建议把原始字符数组保留一份副本用于关卡重置。很多PP.rar里的实现会在玩家移动时直接修改同一个char[][]结果玩到一半想重新开始却发现地图已经被改得面目全非只得重启程序。避免这个黑匣子的办法有两个要么每次重置都重新调用loadMap要么在加载后立刻用Arrays.copyOf做一次深拷贝。第二种效率更高也符合常驻内存的做法。3. 移动逻辑与碰撞检测Java对象怎么配合3.1 玩家移动的四方向判定先算坐标再查地图有了二维字符数组移动逻辑就变成了一次“坐标变换 格子内容查询”。方向用dx和dy数组表示对应上下左右。下面这段代码是推箱子移动判定的核心骨架int[] dx {-1, 1, 0, 0}; int[] dy {0, 0, -1, 1}; boolean move(int dir) { int nx playerX dx[dir]; // 玩家目标位置 int ny playerY dy[dir]; // 目标位置是墙壁直接返回失败 if (map[nx][ny] WALL) { return false; } // 目标位置是箱子则要额外判断箱子能不能被推动 if (map[nx][ny] BOX) { int bx nx dx[dir]; // 箱子目标位置 int by ny dy[dir]; if (map[bx][by] WALL || map[bx][by] BOX) { return false; // 箱子前方是墙或另一个箱子推不动 } // 移动箱子先更新箱子位置 map[bx][by] BOX; } // 玩家离开原位置原位置变成空地 map[playerX][playerY] FLOOR; // 玩家站到新位置 map[nx][ny] PLAYER; playerX nx; playerY ny; return true; }这段代码看起来短但已经把三种情况都覆盖了目标位置是空地、目标位置是墙、目标位置是箱子且箱子可以被推动。最容易漏的是第二种情况里map[bx][by]的越界检查。虽然第2章里我们给地图缺位补了墙但如果地图本身最后一列没有墙且箱子紧贴边界那么bx可能超出数组长度代码在执行map[bx][by]时就会抛异常。稳妥的做法是在访问前先检查bx 0 bx rows by 0 by cols不满足直接视为墙。3.2 什么时候允许推箱子两个格子连查推箱子的规则本质上不是“玩家能不能走到目标格”而是“玩家前方的箱子能不能前进”。很多初学者会把玩家移动和箱子移动分开各写一个方法然后调用顺序写成先判断玩家能不能走到箱子所在格能走就再判断箱子能不能移动。这样写本身没问题但状态变更时容易出现“玩家已经走到箱子的位置箱子却没动”这种中间状态。更干净的做法是像上面的代码一样把玩家与箱子的移动放在同一个方法里先统一完成所有判定再一次性修改地图。这也符合“先判定后提交”的开发思路。判定时还要注意目标点.和地板在移动逻辑里是同一类可通行格子但胜利判定时.又需要特殊对待。所以很多项目的char常量里会区分FLOOR、TARGET、BOX_ON_TARGET移动逻辑只管WALL、BOX、PLAYER等移动完成后再去更新目标点状态。我倾向于把地图状态做成“玩家视角”和“逻辑视角”两层逻辑层只关心墙、箱子、玩家三种元素UI层再根据目标点叠加绘制这样后面做BFS搜索时状态空间会小很多。3.3 胜利条件与关卡重置的状态管理胜利条件一般有两种判断方式一是全图扫描数一下还有没有箱子落在非目标格二是维护一个计数器初始统计箱子和目标点数量每次箱子进入目标点加一离开减一当计数器等于箱子总数时即为胜利。第二种方式开销小适合大关卡也更容易写进动画循环。关卡重置要处理的不只是地图数组还有玩家的旧坐标和已用步数。建议把整个关卡封装成一个GameState对象内部持有char[][] map、int playerX、int playerY、int totalBoxes、int placedBoxes。重置时直接把这个对象的所有字段恢复为初始值。下面是一个简单的状态类骨架public class GameState { char[][] map; int playerX; int playerY; int totalBoxes; int boxesOnTarget; int stepCount; public GameState(char[][] sourceMap) { map new char[sourceMap.length][]; for (int i 0; i sourceMap.length; i) { map[i] Arrays.copyOf(sourceMap[i], sourceMap[i].length); } // 扫描玩家位置和箱子数 } void reset() { // 从备份重建map并恢复坐标和计数 } }一定要把reset和loadMap分开前者是内存里恢复副本后者是重新读盘。PP.rar里很多老的课程设计代码喜欢在重置时重新创建一个BufferedReader读文件这样做在单次运行里也能跑但如果你后续把关卡数据包进了jar包读盘路径就会出问题不如从一开始就保存一份内存副本来得干净。4. 界面与事件Swing里跑起来的推箱子4.1 为什么选Swing而不是其他轻量且适合面试现场Java推箱子的图形界面主流选择是Swing也有用JavaFX的。Swing的优势是JDK自带不需要额外引入依赖而且在绝大多数Java基础岗位面试或课程设计中面试官希望你手写界面时首先想到的也是Swing。JavaFX虽然在皮肤和动画上更现代但需要单独配置模块对解压即跑的PP.rar这类源码来说环境问题会劝退很多初学者。这里就按Swing来展开。Swing有两个核心点绘制面板和键盘事件。地图是二维数组绘制最直观的做法是继承JPanel重写paintComponent按每个格子对应的字符画不同颜色的矩形。4.2 绘制游戏面板paintComponent与格子大小计算下面这段是一个最简版的面板绘制代码public class GamePanel extends JPanel { private char[][] map; private static final int TILE_SIZE 48; public GamePanel(char[][] map) { this.map map; } Override protected void paintComponent(Graphics g) { super.paintComponent(g); for (int row 0; row map.length; row) { for (int col 0; col map[row].length; col) { switch (map[row][col]) { case #: g.setColor(new Color(60, 60, 60)); break; case $: g.setColor(new Color(220, 180, 60)); break; case : g.setColor(new Color(70, 130, 200)); break; case .: g.setColor(new Color(200, 200, 120)); break; default: g.setColor(new Color(240, 240, 240)); break; } g.fillRect(col * TILE_SIZE, row * TILE_SIZE, TILE_SIZE, TILE_SIZE); } } } }这里的TILE_SIZE就是每个格子的像素边长。格子大小不是随便定的太小眼睛累太大窗口放不下常见的取值是32到64。如果你要适配高分屏可以让它跟随窗口可放大。还要注意paintComponent里的map引用必须和游戏逻辑里的map是同一个对象否则地图上移动了界面不会刷新。很多新手在逻辑层又复制了一份数组绘制层永远显示旧地图这是一个非常隐蔽的玄学问题。4.3 键盘事件与焦点问题按键没反应的常见元凶Swing面板要接收键盘事件必须调用setFocusable(true)否则无论怎么按键面板都不会收到任何事件。这个细节被淹没在无数教程里导致很多人只写了KeyListener却发现没反应。完整挂载键盘事件的方法如下public void installKeyHandler(GameState state, GamePanel panel) { panel.setFocusable(true); panel.addKeyListener(new KeyAdapter() { Override public void keyPressed(KeyEvent e) { int dir -1; switch (e.getKeyCode()) { case KeyEvent.VK_UP: dir 0; break; case KeyEvent.VK_DOWN: dir 1; break; case KeyEvent.VK_LEFT: dir 2; break; case KeyEvent.VK_RIGHT: dir 3; break; default: return; } if (state.move(dir)) { state.stepCount; panel.repaint(); } } }); }repaint()也很关键——Swing不会在数据变化时自动重绘必须手动通知面板刷新。如果你发现按键有反应、步数也变了但界面一动不动就是漏掉了repaint()。另外焦点丢失的问题通常在窗口刚显示时发生解决方法是窗口setVisible(true)之后调用一次panel.requestFocusInWindow()。这些细节加起来就是一个能跑起来的推箱子界面。5. 常见问题与排查为什么我的箱子推不动、代码跑不起来5.1 运行乱码注释和字符串显示成黑块黑匣子现象代码里中文注释或System.out.println输出变成乱码。 原因源码文件是GBK编码而IDE运行环境按UTF-8读源码或者控制台输出流编码和系统默认编码不一致。 解决统一编码。最省事的是在IDE的File Settings Editor File Encodings里把项目编码和全局编码都改成UTF-8然后手动把源码文件转码。如果源码里硬编码了某些中文提示语且系统环境是GBK也可以在运行配置的VM参数里加-Dfile.encodingGBK。这里没有银弹关键是永远用同一种编码从编译到运行走到底。5.2 解压后无法编译缺少JDK版本或没有源文件夹现象用IDE直接打开解压后的文件夹提示“未配置JDK”或“找不到系统库”。 原因压缩包里通常只有.java和.txt文件没有IDE项目元数据有的源码用了老式import sun.security...导致需要特定JDK版本。 解决不执着于直接打开文件夹。用IDE新建一个Java项目选择JDK版本时先看源码里有没有用var、record之类的语法有就选JDK 11以上没有就选JDK 8兼容性最高。再把源码文件拷进src目录手动编译。如果是Maven项目且源码里声明了别的依赖那说明这根本不是纯命令行小游戏你先检查网络下载依赖但推箱子一般没这么复杂。5.3 按键没反应焦点在控制台而不是窗口现象程序启动后用鼠标点一下窗口再按方向键界面毫无反应。 原因面板没有设置setFocusable(true)或者主窗口弹出来时焦点被其他组件抢走。 解决在keyPressed事件绑定前调用panel.setFocusable(true)并在JFrame.setVisible(true)后加panel.requestFocusInWindow()。如果面板里还有其他按钮按钮会默认抢走焦点可以在按钮上设置button.setFocusable(false)让焦点始终停留在游戏面板上。5.4 箱子推不动或穿墙判定顺序和边界检查出了问题现象玩家能从箱子上穿过或者箱子推到了墙里。 原因移动方法里没有检查箱子前方格子或者检查越界时把数组下标当成地图值判断。 解决严格按照第3章的顺序写先判断玩家目标格再判断箱子目标格两者都通过再更新地图。另外一定要把“越界即视为墙”的规则写进代码。我见过一些人为了省代码把map[bx][by]的越界判断省略结果地图最外圈不开墙的时候箱子直接消失到数组外面这是最常见的事故。5.5 关卡无法重置原始地图被移动逻辑覆盖了现象点击“重新开始”按钮后地图上的箱子还在移动后的位置。 原因GameState持有的是同一个char[][]引用reset方法只是把这个引用重新赋给当前地图没有真正复制原始内容。 解决在初始化时不只保存引用而是用Arrays.copyOf逐行复制一份独立数组。重置时把当前地图字段指向这份独立副本。如果你用老代码里的reset()重新调loadMap也要确认文件读取路径不是绝对路径否则换台机器就找不到关卡文件了。6. 进阶玩法用BFS让游戏自己解题能手动玩通之后最值得加的功能是自动求解器。推箱子是一个典型的状态空间搜索问题状态不光包括玩家的位置还包括所有箱子的位置所以BFS时要序列化整个地图状态。这里给一个简化版思路把地图数组转成字符串当查重键用Queue做广度优先搜索找到一条从当前状态到胜利状态的最短路径。public static ListInteger solve(char[][] startMap, int startX, int startY) { String startKey encode(startMap, startX, startY); QueueString queue new LinkedList(); MapString, Integer steps new HashMap(); MapString, Integer dirFrom new HashMap(); MapString, String prev new HashMap(); queue.offer(startKey); steps.put(startKey, 0); int[] dx {-1, 1, 0, 0}; int[] dy {0, 0, -1, 1}; while (!queue.isEmpty()) { String key queue.poll(); int[] pos decodePos(key); char[][] map decodeMap(key); if (isWin(map)) { return buildPath(prev, dirFrom, key); } for (int d 0; d 4; d) { int nx pos[0] dx[d]; int ny pos[1] dy[d]; char[][] newMap cloneMap(map); int[] newPos new int[]{nx, ny}; if (applyMove(newMap, newPos, pos, d)) { String newKey encode(newMap, newPos[0], newPos[1]); if (!steps.containsKey(newKey)) { steps.put(newKey, steps.get(key) 1); prev.put(newKey, key); dirFrom.put(newKey, d); queue.offer(newKey); } } } } return null; // 无解 }这段代码是求解器的骨架encode和decode负责把地图和玩家坐标压缩成字符串applyMove内部复用了第3章的移动判定只是改成在副本上操作。注意encode时要把玩家位置也拼进字符串否则两个“地图相同但玩家不同”的状态会被误判为同一个导致搜索漏掉正确路径。BFS对小型关卡很有效但对稍大点的地图状态数会指数级增长内存很快撑不住。真要优化可以上双向BFS或优先队列的A*不过那就超出课程设计范围了。走到这里你会发现推箱子早已不是“随便写个二维数组”那么简单了。从编码兼容到状态回滚从Swing焦点到BFS判重每一个环节都在逼你多想一想多看一层。我自己当年手写推箱子时第一版代码300多行处处都是硬编码后来加自动求解功能时不得不全部重写才明白数据结构和对象建模不是八股文而是实实在在的后悔药。希望这篇笔记能帮你少走一段弯路也希望你能亲手把那个求解器跑通——那种看着电脑自己一步步推完一关的感觉真的挺有成就感。本文还有配套的精品资源点击获取

相关新闻

MySQL Workbench汉化实战:菜单、语言包与排障指南

MySQL Workbench汉化实战:菜单、语言包与排障指南

前两天帮一个刚入行的同学配环境,他盯着MySQL Workbench里那一排File、Edit、Database、Tools的菜单有点发怵,问我能不能把界面弄成中文。我说能是能,但这里面坑不少,不是简单装个语言包就完事。后来我把自己的操作步骤和踩过的坑…

2026/10/9 6:10:05 阅读更多 →
IPv6地址规划方法论:路由聚合、HD门限与过渡技术避坑指南

IPv6地址规划方法论:路由聚合、HD门限与过渡技术避坑指南

简介:《IPv6地址规划方法》文档系统总结了IPv4地址耗尽后IPv6地址规划的科学方法,面向网络规划工程师、运营商技术管理者及高校网络专业学习者,可帮助解决路由膨胀、地址利用率低、管理溯源难等现实问题。压缩包内仅含1个doc文档,…

2026/10/9 6:10:05 阅读更多 →
MySQL Workbench汉化教程:修改main_menu.xml实现中文界面

MySQL Workbench汉化教程:修改main_menu.xml实现中文界面

MySQL Workbench 什么都好,唯一的“劝退点”就是那一整排英文菜单。新手装好之后,对着“File、Edit、Query、Database”愣半天,想导个数据都得先查翻译;团队培训时,讲师还得反复解释“这个 Navigator 是导航面板&#…

2026/10/9 6:10:05 阅读更多 →

最新新闻

Swift常量let深度解析:不可变绑定、编译优化与并发安全

Swift常量let深度解析:不可变绑定、编译优化与并发安全

学习Swift的人越来越多,但真正能把let用明白的,说实话不多。很多同行写了几年Swift,提到"常量"仍然只会说"let就是不可变的var",可一旦深问下去——常量什么时候能延迟初始化、常量和并发安全有什么关系、为什…

2026/10/9 6:36:28 阅读更多 →
Swift常量正确打开方式:从let原理到编译期优化与并发安全实践

Swift常量正确打开方式:从let原理到编译期优化与并发安全实践

接手一个维护了三年的iOS项目,你最想吐槽的往往不是架构本身,而是散落在代码各个角落的魔法字符串和魔法数字。同一个key四处复制,隔三差五手滑拼错,改一处漏三处。这时候大家才会想起来,Swift里有个再基础不过的东西—…

2026/10/9 6:36:28 阅读更多 →
MiMo-V2.6自我改进强化学习规模化:MoE与因果推断实战解析

MiMo-V2.6自我改进强化学习规模化:MoE与因果推断实战解析

1. 从"自我改进"这个词说起:MiMo-V2.6到底想解决什么问题第一次看到"自我改进的强化学习规模化"这个说法,我的反应是:又是一个造词运动。但把技术报告翻了两遍之后,我改主意了——这次他们想解决的是一个真实…

2026/10/9 6:36:28 阅读更多 →
观察者模式实战:直播间送礼系统的解耦设计与实现

观察者模式实战:直播间送礼系统的解耦设计与实现

打开任何一个直播App,走进一个正在热闹开播的直播间。观众点了一下礼物栏,送出一发火箭。接下来几秒钟里,弹幕频道滚出"XXX 送出了火箭",全屏特效炸开,主播的语音感谢响起,礼物榜排名跳动&#x…

2026/10/9 6:36:28 阅读更多 →
学嵌入式Day1:先啃Linux基础命令,别急着点亮屏幕

学嵌入式Day1:先啃Linux基础命令,别急着点亮屏幕

学嵌入式第一天,很多人恨不得马上点亮一块LCD屏幕、跑一个MQTT协议栈,结果折腾三天连板子都没识别出来。我的建议反着来:第一天什么都别做,先把Linux基础命令在终端里敲熟。说句不太好听的话,嵌入式开发的大部分时间其…

2026/10/9 6:36:28 阅读更多 →
生产级Coding Agent调优实战:Harness工程化决定落地下限

生产级Coding Agent调优实战:Harness工程化决定落地下限

1. 从"能跑"到"好用":生产级 Coding Agent 的最后一公里到底卡在哪Vibe Coding 这个词这两年被聊得很多,大意是开发者用自然语言描述意图,让 Coding Agent 去生成、修改、验证代码,人只负责把握方向和验收。听…

2026/10/9 6:35:27 阅读更多 →

日新闻

Java时间API实战:LocalDate、Date与ZonedDateTime的转换与避坑指南

Java时间API实战:LocalDate、Date与ZonedDateTime的转换与避坑指南

Java时间API这个话题,隔三差五就会在群里被翻出来讨论一次。上周还有个同事线上处理一个订单超时问题,排查到最后发现是ZonedDateTime序列化后时区丢了,用户在下单当天晚上看到的时间整整差了8个小时。这类问题几乎每个做Java开发的人都遇到过…

2026/10/9 0:00:49 阅读更多 →
EasyTier实践:从NAT穿透到子网代理的异地组网部署与排错

EasyTier实践:从NAT穿透到子网代理的异地组网部署与排错

前几个月我手头有好几台机器需要互相访问:办公室台式机、家里 NAS、还有一台云主机。如果只是偶尔传个文件倒还好,问题是工作场景经常要在几处环境之间来回切换,每次都先登录跳板机再层层代理,实在折腾。我先后试过端口映射、自建…

2026/10/9 0:00:49 阅读更多 →
AI Agent工程实战:从七要素到七个决策点的系统设计指南

AI Agent工程实战:从七要素到七个决策点的系统设计指南

AI Agent 这个词在过去一年里被反复提及,但真正动手搭过一套能跑起来的 Agent 系统的人都知道,从"知道它是什么"到"让它稳定干活"之间隔着一整套工程决策。我前后参与过几个 Agent 项目的落地,从最初用现成框架拼装&…

2026/10/9 0:01:50 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

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

2026/10/8 15:26:32 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

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

2026/10/8 15:26:40 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

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

2026/10/8 10:10:36 阅读更多 →

月新闻

我发现了一个新思路:用 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/8 21:13:17 阅读更多 →
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/8 15:26: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/9 6:17:20 阅读更多 →