Java开发Dungeon游戏时如何校验玩家是否遍历棋盘所有面板
问题根因
你现在的实现有3个核心问题,导致访问校验完全失效:
- 用允许重复元素的
List逐次记录每一步移动位置,会产生大量重复坐标:比如玩家在两个格子之间来回走,列表长度很快就能凑到总格子数,但实际根本没走遍全图,单纯比对两个列表的长度没有任何意义。 - 用只存单个键值对的
HashMap<Integer,Integer>存(x,y)坐标属于冗余设计,平白增加后续内容比对的复杂度。 - 现有校验逻辑只统计两个列表的元素个数,完全没有做集合内容的匹配,哪怕长度相等,内容完全不相关也会误判。
修正方案
1. 替换存储结构
直接删掉用来存全图坐标的boardPlaces列表、存移动路径的movesRecorded列表,改用HashSet<String>存玩家已经到访过的坐标——HashSet自带去重特性,同一个格子不管走多少次,集合里只会存一次,不需要手动去重。
坐标直接拼成固定格式的字符串存储即可,比如x坐标 + "," + y坐标,不需要额外自定义类、重写equals和hashCode,适配这个练习的规模完全够用。
全图总格子数不需要提前遍历棋盘存列表,直接用棋盘长度 * 棋盘高度就能算出来,省掉无意义的初始化遍历。
2. 修正移动记录逻辑
每次处理单个移动指令、确认坐标不越界之后,再更新玩家位置,同时把新坐标加入访问记录集合。注意不要在移动无效(撞边界)的时候重复记录相同坐标。
修正后的移动方法代码:
// 类成员变量,替换原来的movesRecorded private HashSet<String> visitedPositions = new HashSet<>(); // 玩家初始化到起点位置时,先把起点加入访问集合 visitedPositions.add(this.x + "," + this.y); public void updatePosition(String m) { char[] moveSeq = m.toCharArray(); for (char move : moveSeq) { int nextX = this.x; int nextY = this.y; // 先计算下一步坐标,判断是否越界 if (move == 'w' && this.y - 1 >= 0) { nextY--; } if (move == 's' && this.y + 1 <= height - 1) { nextY++; } if (move == 'a' && this.x - 1 >= 0) { nextX--; } if (move == 'd' && this.x + 1 <= length - 1) { nextX++; } // 更新到合法位置,记录访问点 this.x = nextX; this.y = nextY; visitedPositions.add(this.x + "," + this.y); } moves--; // 所有指令处理完成后再做棋盘渲染即可,位置计算不受渲染时机影响 }
3. 简化胜利校验逻辑
原来双重循环计数的代码可以全部删掉,校验逻辑只需要两行:
int totalCells = length * height; // 敌人全灭 或者 访问过的格子数等于总格子数,即达成胜利条件 return vamps.isEmpty() || player.getVisitedPositions().size() == totalCells;
如果你非要保留原有两个List比对的写法(非常不推荐,冗余度很高),需要先把两个List都转为HashSet去重,再用
containsAll做双向内容匹配:HashSet<HashMap<Integer,Integer>> boardSet = new HashSet<>(boardPlaces); HashSet<HashMap<Integer,Integer>> moveSet = new HashSet<>(playerMovesRecorded); boolean allVisited = boardSet.containsAll(moveSet) && moveSet.containsAll(boardSet);这种写法不仅性能差,还可能因为HashMap的键值匹配问题出现判断错误,没必要在这个小练习里用。
内容的提问来源于stack exchange,提问作者morloq
相关产品推荐
相关产品推荐

