File size: 8,880 Bytes
079c32c |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 |
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;
} |