自定义尺寸TicTacToe局部获胜检查算法角落位置失效求助
问题分析与修复方案
核心问题梳理
行/列坐标完全混淆
根据getPawnAtCoords的索引计算逻辑(index = row * gameSize + column),落子的行应为moveRow = moveIdx / gameSize,列应为moveCol = moveIdx % gameSize。但原代码把行赋值给moveX、列赋值给moveY,后续范围计算完全错位,角落位置的检查区间会彻底偏离正确区域。水平赢检查错误遍历多行
水平赢的本质是同一行内连续N个相同棋子,原代码却循环遍历startY到endY的多行,完全偏离水平检查逻辑,角落位置时会直接漏检或错检。边界范围越界
棋盘索引范围是0到gameSize-1,但原代码clamp的max参数传入gameSize,会导致endX/endY等于gameSize,循环时会访问超出棋盘的索引,引发逻辑错误。候选棋子初始化错误
原代码将candidate初始化为当前行第0列的棋子,但水平检查是从startX开始遍历,这个初始值会破坏连续计数逻辑,在角落位置时错误尤为明显。
修复后的代码
修正的水平赢检查函数
private boolean checkHorizontalWin(String gameBoard, int gameSize, int gameDifficulty, int moveIdx) { // 正确计算落子的行和列 int moveRow = moveIdx / gameSize; int moveCol = moveIdx % gameSize; // 计算水平检查的列范围:仅覆盖当前行中可能形成连续连子的区间 int startCol = Math.max(0, moveCol - (gameDifficulty - 1)); int endCol = Math.min(gameSize - 1, moveCol + (gameDifficulty - 1)); char candidate = '-'; int counter = 0; // 仅遍历当前行的目标列范围 for (int col = startCol; col <= endCol; col++) { char pawn = getPawnAtCoords(gameBoard, gameSize, moveRow, col); if (pawn == candidate && pawn != '-') { counter++; if (counter == gameDifficulty) { return true; } } else { candidate = pawn; counter = (pawn != '-') ? 1 : 0; } } return false; }
修正的Clamp函数(可选,也可直接用Math.max/min)
private int clamp(int val, int min, int max) { // 限制最大值为gameSize-1,避免索引越界 return Math.max(min, Math.min(max - 1, val)); }
坐标获取函数(保持不变)
private char getPawnAtCoords(String board, int gameSize, int row, int column) { int index = row * gameSize + column; return board.charAt(index); }
额外说明
- 水平赢仅需检查落子所在单行,既符合你“局部检查”的性能优化初衷,也避免了无意义的多行遍历。
- 列范围计算逻辑:确保覆盖所有可能形成连续
gameDifficulty个棋子的区间,比如难度为3时,落子在列5会检查列3到列7,保证能容纳3个连续棋子。 - 增加空棋子
'-'的判断,避免空位置被误计入连续计数。
内容的提问来源于stack exchange,提问作者Kacper Rydzyński
相关产品推荐
相关产品推荐

