Spaces:
Sleeping
Sleeping
export const patterns = { | |
five: new RegExp('11111'), | |
blockfive: new RegExp('211111|111112'), | |
four: new RegExp('011110'), | |
blockFour: new RegExp('10111|11011|11101|211110|211101|211011|210111|011112|101112|110112|111012'), | |
three: new RegExp('011100|011010|010110|001110'), | |
blockThree: new RegExp('211100|211010|210110|001112|010112|011012'), | |
two: new RegExp('001100|011000|000110|010100|001010'), | |
} | |
export const shapes = { | |
FIVE: 5, | |
BLOCK_FIVE: 50, | |
FOUR: 4, | |
FOUR_FOUR: 44, // 双冲四 | |
FOUR_THREE: 43, // 冲四活三 | |
THREE_THREE: 33, // 双三 | |
BLOCK_FOUR: 40, | |
THREE: 3, | |
BLOCK_THREE: 30, | |
TWO_TWO: 22, // 双活二 | |
TWO: 2, | |
NONE: 0, | |
}; | |
export const performance = { | |
five: 0, | |
blockFive: 0, | |
four: 0, | |
blockFour: 0, | |
three: 0, | |
blockThree: 0, | |
two: 0, | |
none: 0, | |
total: 0, | |
} | |
// 使用字符串匹配的方式实现的形状检测,速度较慢,但逻辑比较容易理解 | |
export const getShape = (board, x, y, offsetX, offsetY, role) => { | |
const opponent = -role; | |
let emptyCount = 0; | |
let selfCount = 1; | |
let opponentCount = 0; | |
let shape = shapes.NONE; | |
// 跳过为空的节点 | |
if (board[x + offsetX + 1][y + offsetY + 1] === 0 | |
&& board[x - offsetX + 1][y - offsetY + 1] === 0 | |
&& board[x + 2 * offsetX + 1][y + 2 * offsetY + 1] === 0 | |
&& board[x - 2 * offsetX + 1][y - 2 * offsetY + 1] === 0 | |
) { | |
return [shapes.NONE, selfCount, opponentCount, emptyCount]; | |
} | |
// two 类型占比超过一半,做一下优化 | |
// 活二是不需要判断特别严谨的 | |
for (let i = -3; i <= 3; i++) { | |
if (i === 0) continue; | |
const [nx, ny] = [x + i * offsetX + 1, y + i * offsetY + 1]; | |
if (board[nx] === undefined || board[nx][ny] === undefined) continue; | |
const currentRole = board[nx][ny]; | |
if (currentRole === 2) { | |
opponentCount++; | |
} else if (currentRole === role) { | |
selfCount++; | |
} else if (currentRole === 0) { | |
emptyCount++; | |
} | |
} | |
if (selfCount === 2) { | |
if (!opponentCount) { | |
return [shapes.TWO, selfCount, opponentCount, emptyCount]; | |
} else { | |
return [shapes.NONE, selfCount, opponentCount, emptyCount]; | |
} | |
} | |
// two 类型优化结束,不需要的话可以在直接删除这一段代码不影响功能 | |
// three类型大约占比有20%,也优化一下 | |
emptyCount = 0; | |
selfCount = 1; | |
opponentCount = 0; | |
let resultString = '1'; | |
for (let i = 1; i <= 5; i++) { | |
const [nx, ny] = [x + i * offsetX + 1, y + i * offsetY + 1]; | |
const currentRole = board[nx][ny]; | |
if (currentRole === 2) resultString += '2'; | |
else if (currentRole === 0) resultString += '0'; | |
else resultString += currentRole === role ? '1' : '2'; | |
if (currentRole === 2 || currentRole === opponent) { | |
opponentCount++; | |
break; | |
} | |
if (currentRole === 0) { | |
emptyCount++; | |
} | |
if (currentRole === role) { | |
selfCount++; | |
} | |
} | |
for (let i = 1; i <= 5; i++) { | |
const [nx, ny] = [x - i * offsetX + 1, y - i * offsetY + 1]; | |
const currentRole = board[nx][ny]; | |
if (currentRole === 2) resultString = '2' + resultString; | |
else if (currentRole === 0) resultString = '0' + resultString; | |
else resultString = (currentRole === role ? '1' : '2') + resultString; | |
if (currentRole === 2 || currentRole === opponent) { | |
opponentCount++; | |
break; | |
} | |
if (currentRole === 0) { | |
emptyCount++; | |
} | |
if (currentRole === role) { | |
selfCount++; | |
} | |
} | |
if (patterns.five.test(resultString)) { | |
shape = shapes.FIVE; | |
performance.five++; | |
performance.total++; | |
} else if (patterns.four.test(resultString)) { | |
shape = shapes.FOUR; | |
performance.four++; | |
performance.total++; | |
} else if (patterns.blockFour.test(resultString)) { | |
shape = shapes.BLOCK_FOUR; | |
performance.blockFour++; | |
performance.total++; | |
} else if (patterns.three.test(resultString)) { | |
shape = shapes.THREE; | |
performance.three++; | |
performance.total++; | |
} else if (patterns.blockThree.test(resultString)) { | |
shape = shapes.BLOCK_THREE; | |
performance.blockThree++; | |
performance.total++; | |
} else if (patterns.two.test(resultString)) { | |
shape = shapes.TWO; | |
performance.two++; | |
performance.total++; | |
} | |
// 尽量减少多余字符串生成 | |
if (selfCount <= 1 || resultString.length < 5) return [shape, selfCount, opponentCount, emptyCount]; | |
return [shape, selfCount, opponentCount, emptyCount]; | |
} | |
const countShape = (board, x, y, offsetX, offsetY, role) => { | |
const opponent = -role; | |
let innerEmptyCount = 0; // 棋子中间的内部空位 | |
let tempEmptyCount = 0; | |
let selfCount = 0; | |
let totalLength = 0; | |
let sideEmptyCount = 0; // 边上的空位 | |
let noEmptySelfCount = 0, OneEmptySelfCount = 0; | |
// right | |
for (let i = 1; i <= 5; i++) { | |
const [nx, ny] = [x + i * offsetX + 1, y + i * offsetY + 1]; | |
const currentRole = board[nx][ny]; | |
if (currentRole === 2 || currentRole === opponent) { | |
break; | |
} | |
if (currentRole === role) { | |
selfCount++; | |
sideEmptyCount = 0; | |
if (tempEmptyCount) { | |
innerEmptyCount += tempEmptyCount; | |
tempEmptyCount = 0; | |
} | |
if (innerEmptyCount === 0) { | |
noEmptySelfCount++; | |
OneEmptySelfCount++; | |
} else if (innerEmptyCount === 1) { | |
OneEmptySelfCount++; | |
} | |
} | |
totalLength++; | |
if (currentRole === 0) { | |
tempEmptyCount++; | |
sideEmptyCount++; | |
} | |
if (sideEmptyCount >= 2) { | |
break; | |
} | |
} | |
if (!innerEmptyCount) OneEmptySelfCount = 0; | |
return { selfCount, totalLength, noEmptySelfCount, OneEmptySelfCount, innerEmptyCount, sideEmptyCount }; | |
} | |
// 使用遍历位置的方式实现的形状检测,速度较快,大约是字符串速度的2倍 但理解起来会稍微复杂一些 | |
export const getShapeFast = (board, x, y, offsetX, offsetY, role) => { | |
// 有一点点优化效果:跳过为空的节点 | |
if (board[x + offsetX + 1][y + offsetY + 1] === 0 | |
&& board[x - offsetX + 1][y - offsetY + 1] === 0 | |
&& board[x + 2 * offsetX + 1][y + 2 * offsetY + 1] === 0 | |
&& board[x - 2 * offsetX + 1][y - 2 * offsetY + 1] === 0 | |
) { | |
return [shapes.NONE, 1]; | |
} | |
let selfCount = 1; | |
let totalLength = 1; | |
let shape = shapes.NONE; | |
let leftEmpty = 0, rightEmpty = 0; // 左右边上的空位 | |
let noEmptySelfCount = 1, OneEmptySelfCount = 1; | |
const left = countShape(board, x, y, -offsetX, -offsetY, role); | |
const right = countShape(board, x, y, offsetX, offsetY, role); | |
selfCount = left.selfCount + right.selfCount + 1; | |
totalLength = left.totalLength + right.totalLength + 1; | |
noEmptySelfCount = left.noEmptySelfCount + right.noEmptySelfCount + 1; | |
OneEmptySelfCount = Math.max(left.OneEmptySelfCount + right.noEmptySelfCount, left.noEmptySelfCount + right.OneEmptySelfCount) + 1; | |
rightEmpty = right.sideEmptyCount; | |
leftEmpty = left.sideEmptyCount; | |
if (totalLength < 5) return [shape, selfCount]; | |
// five | |
if (noEmptySelfCount >= 5) { | |
if (rightEmpty > 0 && leftEmpty > 0) { | |
return [shapes.FIVE, selfCount]; | |
} else { | |
return [shapes.BLOCK_FIVE, selfCount]; | |
} | |
} | |
if (noEmptySelfCount === 4) { | |
// 注意这里的空位判断条件, 右边有有两种,分别是 XX空 和 XX空X,第二种情况下,虽然 rightEmpty 可能不是true,也是符合的,通过 OneEmptySelfCount > noEmptySelfCount 来判断 | |
if ((rightEmpty >= 1 || right.OneEmptySelfCount > right.noEmptySelfCount) && (leftEmpty >= 1 || left.OneEmptySelfCount > left.noEmptySelfCount)) { // four | |
return [shapes.FOUR, selfCount]; | |
} else if (!(rightEmpty === 0 && leftEmpty === 0)) { // block four | |
return [shapes.BLOCK_FOUR, selfCount]; | |
} | |
} | |
if (OneEmptySelfCount === 4) { | |
return [shapes.BLOCK_FOUR, selfCount]; | |
} | |
// three | |
if (noEmptySelfCount === 3) { | |
if ((rightEmpty >= 2 && leftEmpty >= 1) || (rightEmpty >= 1 && leftEmpty >= 2)) { | |
return [shapes.THREE, selfCount]; | |
} else { | |
return [shapes.BLOCK_THREE, selfCount]; | |
} | |
} | |
if (OneEmptySelfCount === 3) { | |
if ((rightEmpty >= 1 && leftEmpty >= 1)) { | |
return [shapes.THREE, selfCount]; | |
} else { | |
return [shapes.BLOCK_THREE, selfCount]; | |
} | |
} | |
if ((noEmptySelfCount === 2 || OneEmptySelfCount === 2) && totalLength > 5) { // two | |
shape = shapes.TWO; | |
} | |
return [shape, selfCount]; | |
} | |
export const isFive = (shape) => { | |
return shape === shapes.FIVE || shape === shapes.BLOCK_FIVE; | |
}; | |
export const isFour = (shape) => { | |
return shape === shapes.FOUR || shape === shapes.BLOCK_FOUR; | |
}; | |
export const getAllShapesOfPoint = (shapeCache, x, y, role) => { | |
const roles = role ? [role] : [1, -1]; | |
const result = []; | |
for (const r of roles) { | |
for (const d of [0, 1, 2, 3]) { | |
const shape = shapeCache[r][d][x][y]; | |
if (shape > 0) { | |
result.push(shape); | |
} | |
} | |
} | |
return result; | |
} |