如何用Java 8 Streams更优雅地实现扫雷相邻地雷计数?
优化扫雷相邻地雷计数的纯流式方案
嘿,看到你在用Java 8 Streams重构扫雷项目来熟悉流式编程,这路子太对了!针对你现在纠结的相邻地雷计数问题,我给你几个更清爽的纯流式优化方案,完美避开繁琐条件和嵌套循环:
方案一:简洁的数学范围判断
直接通过绝对值判断地雷坐标是否在目标位置的3×3范围内,同时排除目标位置自身(毕竟扫雷要统计的是周围地雷,不是当前点击的位置),代码瞬间简洁很多:
private int calculateNearby(int x, int y) { return (int) Arrays.stream(arsenal.getArsenal()) .filter(mine -> Math.abs(mine.getX() - x) <= 1 && Math.abs(mine.getY() - y) <= 1 && !(mine.getX() == x && mine.getY() == y) ) .count(); }
这个方案的核心逻辑是:只要地雷的x坐标和目标x的差的绝对值≤1,且y坐标同理,就说明在3×3范围内,最后加上排除自身的判断,完全替代了原来8个冗长的条件判断,纯流式无循环,逻辑清晰易懂。
方案二:抽离判断逻辑,提升可读性
如果想要代码更易维护、更具复用性,可以把相邻判断的逻辑抽成独立方法,让流式代码更干净:
// 抽离的相邻判断方法,可复用 private boolean isAdjacent(Mine mine, int targetX, int targetY) { int dx = Math.abs(mine.getX() - targetX); int dy = Math.abs(mine.getY() - targetY); // 范围在3×3内,且不是自身 return dx <= 1 && dy <= 1 && !(dx == 0 && dy == 0); } private int calculateNearby(int x, int y) { return (int) Arrays.stream(arsenal.getArsenal()) .filter(mine -> isAdjacent(mine, x, y)) .count(); }
这样处理后,流式操作的意图一目了然,而且isAdjacent方法还能在其他需要判断相邻的场景复用,符合代码复用原则。
方案三:流式生成相邻坐标匹配(可选)
如果你想把“生成所有相邻坐标”的过程也用流式实现,可以先生成目标位置周围的8个坐标点,再匹配地雷数组中的坐标:
private int calculateNearby(int x, int y) { // 流式生成所有相邻坐标(排除自身) List<Point> adjacentCoords = IntStream.rangeClosed(-1, 1) .boxed() .flatMap(offsetX -> IntStream.rangeClosed(-1, 1) .boxed() .filter(offsetY -> !(offsetX == 0 && offsetY == 0)) .map(offsetY -> new Point(x + offsetX, y + offsetY)) ) .collect(Collectors.toList()); // 统计地雷数组中属于相邻坐标的数量 return (int) Arrays.stream(arsenal.getArsenal()) .filter(mine -> adjacentCoords.contains(new Point(mine.getX(), mine.getY()))) .count(); }
注意:这里如果用自定义的坐标类代替java.awt.Point,一定要确保重写了equals()和hashCode()方法,否则contains判断会失效。这个方案的优势是把所有逻辑都用流式处理,但性能上略逊于前两个方案(因为contains是O(n)操作),适合地雷数量不多的场景。
总结
如果追求高效和简洁,优先选方案一;如果看重代码可读性和复用性,方案二更合适;方案三则适合想要完全用流式覆盖所有步骤的场景,按需选择就行~
内容的提问来源于stack exchange,提问作者Nico
相关产品推荐
相关产品推荐

