link-link-xyk
Version:
A small TypeScript SDK for Link-Link games, including grid generation, colored console printing, and connection checking with type definitions.
119 lines (118 loc) • 4.9 kB
JavaScript
/** 随机生成网格 */
export function createRandomGrids(row, col, kind) {
const total = row * col;
if (total % 2 !== 0)
throw new Error("格子总数必须为偶数才能成对生成");
// 生成成对图标数组
const icons = [];
for (let i = 0; i < total / 2; i++) {
const value = Math.floor(Math.random() * kind) + 1;
icons.push(value, value); // 成对加入
}
// 打乱顺序
for (let i = icons.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[icons[i], icons[j]] = [icons[j], icons[i]];
}
// 填充网格
const grids = Array.from({ length: row }, () => Array.from({ length: col }, () => 0));
let idx = 0;
for (let y = 0; y < row; y++) {
for (let x = 0; x < col; x++) {
grids[y][x] = icons[idx++];
}
}
return grids;
}
/** 彩色打印网格 */
export function logGrid(grids) {
// 先找最大位数
const maxLen = Math.max(...grids.flat().map(num => String(num).length));
// 打印网格
grids.forEach(row => {
console.log(row.map(num => {
const padded = String(num).padStart(maxLen, "0"); // 左侧填空格
return `\x1b[9${num % 8}m${padded}\x1b[0m`; // num % 8 避免颜色码越界
})
.join(" "));
});
}
/** 检查是否能连接 */
export function canLink(inputGrids, row1, col1, row2, col2) {
const line = [];
if (!Number.isInteger(row1) || !Number.isInteger(col1) || !Number.isInteger(row2) || !Number.isInteger(col2))
return { success: false, line };
if (row1 < 0 || row1 >= inputGrids.length || col1 < 0 || col1 >= inputGrids[0].length || row2 < 0 || row2 >= inputGrids.length || col2 < 0 || col2 >= inputGrids[0].length)
return { success: false, line };
if (inputGrids[row1][col1] !== inputGrids[row2][col2])
return { success: false, line };
if (row1 === row2 && col1 === col2)
return { success: false, line };
const rowlen = inputGrids.length + 2;
const collen = inputGrids[0].length + 2;
const map = new Map(); //bfs图
const grids = Array.from({ length: rowlen }, () => Array.from({ length: collen }, () => 0));
grids.forEach((row, raw) => {
row.forEach((_, col) => {
if (raw === 0 || raw === rowlen - 1 || col === 0 || col === collen - 1)
grids[raw][col] = 0;
else
grids[raw][col] = inputGrids[raw - 1][col - 1];
map.set(`${raw}_${col}`, {
point: `${raw}_${col}`,
value: grids[raw][col],
turns: 999,
direction: null,
lastPoint: null,
});
});
});
const begin = `${row1 + 1}_${col1 + 1}`;
const end = `${row2 + 1}_${col2 + 1}`;
map.get(begin).turns = 0;
const queue = [begin];
const visited = new Set([begin]);
while (queue.length > 0) {
const current = queue.shift();
visited.add(current);
if (current === end) {
let currentNode = current;
while (currentNode !== begin) {
const node = map.get(currentNode);
line.push(node.point.split("_").map(item => Number(item) - 1).join("_"));
currentNode = node.lastPoint;
}
line.push(begin.split("_").map(item => Number(item) - 1).join("_"));
line.reverse();
return { success: true, line };
}
const currentNode = map.get(current);
const row = parseInt(current.split("_")[0]);
const col = parseInt(current.split("_")[1]);
const next1 = `${row - 1}_${col}`;
const next2 = `${row + 1}_${col}`;
const next3 = `${row}_${col - 1}`;
const next4 = `${row}_${col + 1}`;
const nexts = [next1, next2, next3, next4];
nexts.forEach((next, index) => {
const row = parseInt(next.split("_")[0]);
const col = parseInt(next.split("_")[1]);
if (row >= 12 || row < 0 || col >= 12 || col < 0)
return { success: false, line };
if (!visited.has(next) && grids[row][col] === 0 || next === end) {
const nextNode = map.get(next);
const isTurn = currentNode.direction !== null && currentNode.direction !== index; // 是否发生了转向
const turns = isTurn ? currentNode.turns + 1 : currentNode.turns;
if (turns < nextNode.turns && turns <= 2) {
queue.push(next);
nextNode.turns = turns;
nextNode.lastPoint = current;
nextNode.direction = index;
}
}
});
}
return { success: false, line };
}
const defaultExport = { createRandomGrids, logGrid, canLink };
export default defaultExport;