This commit is contained in:
dengqichen 2025-11-27 10:34:59 +08:00
parent 0fef5d7f74
commit d4cc237ccd
11 changed files with 615 additions and 17 deletions

View File

@ -0,0 +1,120 @@
/**
* 高级分析找出"成功模式"而不是"成功BIN"
* 目标在保持BIN多样性的同时提高成功率
*/
// 70张成功卡号
const fullCards = [
// 原始16张
'6228367545055812', '6228367548774419', '6228367546781457', '6228367542738949',
'6228367542602400', '6228367548575105', '6228367546496080', '6228367540057649',
'6228367549574719', '6228367548435128', '6228367542797374', '6228367545956423',
'6228367547237848', '6228367540385107', '6228367544252006', '6228367547562054',
// 今天54张
'6228367541130577', '6228367540744030', '6228367549888788', '6228367549131205',
'6228367541450744', '6228367547238010', '6228367547300364', '6228367540814288',
'6228367546042579', '6228367546361755', '6228367542443235', '6228367543564435',
'6228367548400627', '6228367544445204', '6228367542653734', '6228367549976732',
'6228367540810302', '6228367540707201', '6228367545237808', '6228367544322734',
'6228367541880148', '6228367549130520', '6228367547863197', '6228367541210049',
'6228367549031561', '6228367542464926', '6228367542487000', '6228367545452860',
'6228367548491592', '6228367545022853', '6228367545864858', '6228367544742832',
'6228367540023658', '6228367547416988', '6228367547093159', '6228367549198576',
'6228367548160064', '6228367546223252', '6228367544873785', '6228367541299976',
'6228367542940032', '6228367546998937', '6228367545800241', '6228367543770784',
'6228367545976843', '6228367547542551', '6228367543917914', '6228367545657930',
'6228367586381796', '6228367544322809', '6228367549131254', '6228367543917146',
'6228367546998903', '6228367545864460'
];
console.log('=== 高级分析:成功模式识别 ===\n');
// 分析1BIN的第10-12位extension的规律
console.log('1. BIN Extension第10-12位分析:\n');
const extensions = {};
fullCards.forEach(card => {
const ext = card.slice(9, 12); // 第10-12位
extensions[ext] = (extensions[ext] || 0) + 1;
});
const sortedExt = Object.entries(extensions)
.sort((a, b) => b[1] - a[1])
.slice(0, 10);
sortedExt.forEach(([ext, count]) => {
const percent = (count / 70 * 100).toFixed(1);
console.log(` ${ext}: ${count}次 (${percent}%)`);
});
// 分析2完整BIN13位的第13位规律
console.log('\n2. BIN最后一位第13位分析:\n');
const lastDigits = {};
fullCards.forEach(card => {
const last = card[12]; // 第13位
lastDigits[last] = (lastDigits[last] || 0) + 1;
});
for (let i = 0; i <= 9; i++) {
const count = lastDigits[i] || 0;
const percent = (count / 70 * 100).toFixed(1);
console.log(` ${i}: ${count}次 (${percent}%)`);
}
// 分析3后3位数字的"和"的规律
console.log('\n3. 后3位数字之和的分布:\n');
const sums = {};
fullCards.forEach(card => {
const last3 = card.slice(-4, -1);
const sum = parseInt(last3[0]) + parseInt(last3[1]) + parseInt(last3[2]);
sums[sum] = (sums[sum] || 0) + 1;
});
const sortedSums = Object.entries(sums)
.sort((a, b) => b[1] - a[1])
.slice(0, 10);
sortedSums.forEach(([sum, count]) => {
const percent = (count / 70 * 100).toFixed(1);
console.log(` 和=${sum}: ${count}次 (${percent}%)`);
});
// 分析4后3位数字的"奇偶性"规律
console.log('\n4. 后3位奇偶性分析:\n');
const patterns = {
'偶偶偶': 0, '偶偶奇': 0, '偶奇偶': 0, '偶奇奇': 0,
'奇偶偶': 0, '奇偶奇': 0, '奇奇偶': 0, '奇奇奇': 0
};
fullCards.forEach(card => {
const last3 = card.slice(-4, -1);
const pattern = last3.split('').map(d => parseInt(d) % 2 === 0 ? '偶' : '奇').join('');
patterns[pattern]++;
});
Object.entries(patterns)
.sort((a, b) => b[1] - a[1])
.forEach(([pattern, count]) => {
const percent = (count / 70 * 100).toFixed(1);
console.log(` ${pattern}: ${count}次 (${percent}%)`);
});
// 分析5Luhn校验位的分布
console.log('\n5. Luhn校验位最后一位分布:\n');
const checkDigits = {};
fullCards.forEach(card => {
const check = card[15]; // 最后一位
checkDigits[check] = (checkDigits[check] || 0) + 1;
});
for (let i = 0; i <= 9; i++) {
const count = checkDigits[i] || 0;
const percent = (count / 70 * 100).toFixed(1);
console.log(` ${i}: ${count}次 (${percent}%)`);
}
console.log('\n=== 关键发现 ===\n');
console.log('基于以上分析,可以优化生成策略:');
console.log('1. 优先选择高频的BIN Extension');
console.log('2. 后3位数字之和倾向于某些值');
console.log('3. 奇偶性组合有明显偏好');
console.log('4. 结合马尔可夫链在保持BIN多样性的同时提高成功率');

View File

@ -0,0 +1,90 @@
/**
* 聚类分析 - 找出成功案例的"家族"模式
*/
// 70张成功卡号
const fullCards = [
// 原始16张
'6228367545055812', '6228367548774419', '6228367546781457', '6228367542738949',
'6228367542602400', '6228367548575105', '6228367546496080', '6228367540057649',
'6228367549574719', '6228367548435128', '6228367542797374', '6228367545956423',
'6228367547237848', '6228367540385107', '6228367544252006', '6228367547562054',
// 今天54张
'6228367541130577', '6228367540744030', '6228367549888788', '6228367549131205',
'6228367541450744', '6228367547238010', '6228367547300364', '6228367540814288',
'6228367546042579', '6228367546361755', '6228367542443235', '6228367543564435',
'6228367548400627', '6228367544445204', '6228367542653734', '6228367549976732',
'6228367540810302', '6228367540707201', '6228367545237808', '6228367544322734',
'6228367541880148', '6228367549130520', '6228367547863197', '6228367541210049',
'6228367549031561', '6228367542464926', '6228367542487000', '6228367545452860',
'6228367548491592', '6228367545022853', '6228367545864858', '6228367544742832',
'6228367540023658', '6228367547416988', '6228367547093159', '6228367549198576',
'6228367548160064', '6228367546223252', '6228367544873785', '6228367541299976',
'6228367542940032', '6228367546998937', '6228367545800241', '6228367543770784',
'6228367545976843', '6228367547542551', '6228367543917914', '6228367545657930',
'6228367586381796', '6228367544322809', '6228367549131254', '6228367543917146',
'6228367546998903', '6228367545864460'
];
console.log('=== 聚类分析:找出成功案例的家族 ===\n');
// 提取BIN13位前缀
const binGroups = {};
fullCards.forEach(card => {
const bin = card.slice(0, 13);
if (!binGroups[bin]) {
binGroups[bin] = [];
}
binGroups[bin].push(card);
});
// 按数量排序
const sortedBins = Object.entries(binGroups)
.sort((a, b) => b[1].length - a[1].length);
console.log('=== BIN家族分布前10个 ===\n');
sortedBins.slice(0, 10).forEach(([bin, cards], i) => {
console.log(`${i + 1}. BIN: ${bin} (${cards.length}张)`);
cards.forEach(card => {
const last3 = card.slice(-4, -1);
console.log(` ${card} -> 后3位: ${last3}`);
});
console.log();
});
// 分析每个BIN家族的后3位模式
console.log('=== 每个BIN家族的后3位规律 ===\n');
sortedBins.slice(0, 10).forEach(([bin, cards]) => {
if (cards.length < 2) return;
console.log(`BIN: ${bin} (${cards.length}张)`);
const last3s = cards.map(c => c.slice(-4, -1));
// 统计每位的分布
const pos1 = {}, pos2 = {};
last3s.forEach(l3 => {
pos1[l3[0]] = (pos1[l3[0]] || 0) + 1;
pos2[l3[1]] = (pos2[l3[1]] || 0) + 1;
});
console.log(' 百位分布:', Object.entries(pos1).sort((a, b) => b[1] - a[1]).map(([d, c]) => `${d}:${c}`).join(', '));
console.log(' 十位分布:', Object.entries(pos2).sort((a, b) => b[1] - a[1]).map(([d, c]) => `${d}:${c}`).join(', '));
console.log();
});
// 找出"热门BIN"成功率高的BIN
console.log('=== 热门BIN推荐成功案例>=2张===\n');
const hotBins = sortedBins.filter(([_, cards]) => cards.length >= 2);
console.log(`共找到 ${hotBins.length} 个热门BIN\n`);
hotBins.forEach(([bin, cards]) => {
const last3s = cards.map(c => c.slice(-4, -1));
console.log(`${bin}: ${last3s.join(', ')}`);
});
// 生成配置建议
console.log('\n=== 优化建议 ===\n');
console.log(`1. 优先使用热门BIN${hotBins.length}个),它们的成功率更高`);
console.log(`2. 对于热门BIN可以直接从已知成功的后3位变异生成`);
console.log(`3. 冷门BIN只有1张成功可以降低权重或跳过`);

View File

@ -0,0 +1,93 @@
/**
* 马尔可夫链分析 - 分析位置之间的转移概率
*/
// 70张成功卡号
const fullCards = [
// 原始16张
'6228367545055812', '6228367548774419', '6228367546781457', '6228367542738949',
'6228367542602400', '6228367548575105', '6228367546496080', '6228367540057649',
'6228367549574719', '6228367548435128', '6228367542797374', '6228367545956423',
'6228367547237848', '6228367540385107', '6228367544252006', '6228367547562054',
// 今天54张
'6228367541130577', '6228367540744030', '6228367549888788', '6228367549131205',
'6228367541450744', '6228367547238010', '6228367547300364', '6228367540814288',
'6228367546042579', '6228367546361755', '6228367542443235', '6228367543564435',
'6228367548400627', '6228367544445204', '6228367542653734', '6228367549976732',
'6228367540810302', '6228367540707201', '6228367545237808', '6228367544322734',
'6228367541880148', '6228367549130520', '6228367547863197', '6228367541210049',
'6228367549031561', '6228367542464926', '6228367542487000', '6228367545452860',
'6228367548491592', '6228367545022853', '6228367545864858', '6228367544742832',
'6228367540023658', '6228367547416988', '6228367547093159', '6228367549198576',
'6228367548160064', '6228367546223252', '6228367544873785', '6228367541299976',
'6228367542940032', '6228367546998937', '6228367545800241', '6228367543770784',
'6228367545976843', '6228367547542551', '6228367543917914', '6228367545657930',
'6228367586381796', '6228367544322809', '6228367549131254', '6228367543917146',
'6228367546998903', '6228367545864460'
];
// 提取后3位不含校验位
const patterns = fullCards.map(card => card.slice(-4, -1));
console.log('=== 马尔可夫链分析:位置转移概率 ===\n');
// 统计转移概率:百位 -> 十位
const transitions = {};
patterns.forEach(p => {
const d1 = p[0]; // 百位
const d2 = p[1]; // 十位
if (!transitions[d1]) {
transitions[d1] = {};
}
transitions[d1][d2] = (transitions[d1][d2] || 0) + 1;
});
// 打印转移概率矩阵
console.log('百位 -> 十位 转移概率:\n');
for (let i = 0; i <= 9; i++) {
if (!transitions[i]) continue;
const total = Object.values(transitions[i]).reduce((sum, count) => sum + count, 0);
console.log(`百位=${i} (${total}次):`);
const sorted = Object.entries(transitions[i])
.sort((a, b) => b[1] - a[1])
.slice(0, 5); // 只显示前5个最高概率
sorted.forEach(([digit, count]) => {
const prob = (count / total * 100).toFixed(1);
console.log(` -> ${digit}: ${count}次 (${prob}%)`);
});
console.log();
}
// 生成转移概率配置
console.log('\n=== 生成马尔可夫转移配置 ===\n');
console.log('const markovTransitions = {');
for (let i = 0; i <= 9; i++) {
if (!transitions[i]) {
console.log(` '${i}': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1], // 无数据,均匀分布`);
continue;
}
const weights = Array.from({length: 10}, (_, j) => transitions[i][j] || 0);
console.log(` '${i}': [${weights.join(', ')}],`);
}
console.log('};');
// 分析是否有明显的模式
console.log('\n=== 关键发现 ===\n');
for (let i = 0; i <= 9; i++) {
if (!transitions[i]) continue;
const total = Object.values(transitions[i]).reduce((sum, count) => sum + count, 0);
const max = Math.max(...Object.values(transitions[i]));
const maxDigit = Object.entries(transitions[i]).find(([_, count]) => count === max)[0];
const maxProb = (max / total * 100).toFixed(1);
if (maxProb > 25) {
console.log(`⚠️ 百位=${i} 时,十位=${maxDigit} 的概率高达 ${maxProb}%`);
}
}

View File

@ -0,0 +1,61 @@
// 分析成功卡号的规律完整16位卡号
const fullCards = [
// 原始16张
'6228367545055812', '6228367548774419', '6228367546781457', '6228367542738949',
'6228367542602400', '6228367548575105', '6228367546496080', '6228367540057649',
'6228367549574719', '6228367548435128', '6228367542797374', '6228367545956423',
'6228367547237848', '6228367540385107', '6228367544252006', '6228367547562054',
// 今天54张
'6228367541130577', '6228367540744030', '6228367549888788', '6228367549131205',
'6228367541450744', '6228367547238010', '6228367547300364', '6228367540814288',
'6228367546042579', '6228367546361755', '6228367542443235', '6228367543564435',
'6228367548400627', '6228367544445204', '6228367542653734', '6228367549976732',
'6228367540810302', '6228367540707201', '6228367545237808', '6228367544322734',
'6228367541880148', '6228367549130520', '6228367547863197', '6228367541210049',
'6228367549031561', '6228367542464926', '6228367542487000', '6228367545452860',
'6228367548491592', '6228367545022853', '6228367545864858', '6228367544742832',
'6228367540023658', '6228367547416988', '6228367547093159', '6228367549198576',
'6228367548160064', '6228367546223252', '6228367544873785', '6228367541299976',
'6228367542940032', '6228367546998937', '6228367545800241', '6228367543770784',
'6228367545976843', '6228367547542551', '6228367543917914', '6228367545657930',
'6228367586381796', '6228367544322809', '6228367549131254', '6228367543917146',
'6228367546998903', '6228367545864460'
];
// 提取后3位不含校验位
const patterns = fullCards.map(card => card.slice(-4, -1));
// 统计每个位置的数字频率
const pos1 = {}; // 百位
const pos2 = {}; // 十位
patterns.forEach(p => {
const d1 = p[0];
const d2 = p[1];
pos1[d1] = (pos1[d1] || 0) + 1;
pos2[d2] = (pos2[d2] || 0) + 1;
});
console.log('=== 70张成功卡号的数字分布规律 ===\n');
console.log('位置1千位频率:');
for (let i = 0; i <= 9; i++) {
const count = pos1[i] || 0;
const percent = (count / patterns.length * 100).toFixed(1);
console.log(` ${i}: ${count}次 (${percent}%)`);
}
console.log('\n位置2十位频率:');
for (let i = 0; i <= 9; i++) {
const count = pos2[i] || 0;
const percent = (count / patterns.length * 100).toFixed(1);
console.log(` ${i}: ${count}次 (${percent}%)`);
}
// 生成权重数组用于config.ts- 只需要2位
console.log('\n=== 生成权重配置后2位不含校验位===\n');
console.log('const positionWeights = [');
console.log(' [' + Array.from({length: 10}, (_, i) => pos1[i] || 0).join(', ') + '], // 百位');
console.log(' [' + Array.from({length: 10}, (_, i) => pos2[i] || 0).join(', ') + '] // 十位');
console.log('];');

View File

@ -1,27 +1,27 @@
# Windsurf 注册自动化配置
site:
name: Windsurf
url: https://windsurf.com/refer?referral_code=55424ec434
url: https://windsurf.com/account/register
# 工作流定义
workflow:
# ==================== 步骤 0: 处理邀请链接 ====================
- action: navigate
name: "打开邀请链接"
url: "https://windsurf.com/refer?referral_code=55424ec434"
options:
waitUntil: 'networkidle2'
timeout: 30000
- action: click
name: "点击接受邀请"
selector:
- text: 'Sign up to accept referral'
selector: 'button'
- css: 'button.bg-sk-aqua'
- css: 'button:has-text("Sign up to accept referral")'
timeout: 30000
waitForNavigation: true
# - action: navigate
# name: "打开邀请链接"
# url: "https://windsurf.com/refer?referral_code=55424ec434"
# options:
# waitUntil: 'networkidle2'
# timeout: 30000
#
# - action: click
# name: "点击接受邀请"
# selector:
# - text: 'Sign up to accept referral'
# selector: 'button'
# - css: 'button.bg-sk-aqua'
# - css: 'button:has-text("Sign up to accept referral")'
# timeout: 30000
# waitForNavigation: true
# 验证跳转到注册页面带referral_code
- action: verify

View File

@ -0,0 +1,47 @@
/**
* 测试BIN分布
*/
import pkg from './src/tools/card/CardGeneratorTool.js';
const { CardGeneratorTool } = pkg;
async function test() {
console.log('生成1000张卡分析BIN分布...\n');
const cardGen = new CardGeneratorTool();
await cardGen.initialize({});
const cards = await cardGen.generateBatch(1000, 'unionpay');
// 统计BIN分布
const binCounts = {};
cards.forEach(card => {
const bin = card.number.slice(0, 13);
binCounts[bin] = (binCounts[bin] || 0) + 1;
});
// 排序
const sorted = Object.entries(binCounts)
.sort((a, b) => b[1] - a[1]);
console.log('=== BIN分布前10个 ===\n');
sorted.slice(0, 10).forEach(([bin, count], i) => {
const percent = (count / 1000 * 100).toFixed(1);
const isHot = ['6228367549131', '6228367544322', '6228367545864', '6228367546998', '6228367543917'].includes(bin);
const mark = isHot ? '🔥' : ' ';
console.log(`${i + 1}. ${mark} ${bin}: ${count}次 (${percent}%)`);
});
// 统计热门BIN的总占比
const hotBins = ['6228367549131', '6228367544322', '6228367545864', '6228367546998', '6228367543917'];
const hotCount = hotBins.reduce((sum, bin) => sum + (binCounts[bin] || 0), 0);
const hotPercent = (hotCount / 1000 * 100).toFixed(1);
console.log(`\n=== 热门BIN统计 ===`);
console.log(`热门BIN总占比: ${hotCount}/1000 (${hotPercent}%)`);
console.log(`期望占比: ~${(5 * 5 / (5 * 5 + 60 * 1) * 100).toFixed(1)}% (权重5 vs 权重1)`);
}
test().catch(err => {
console.error('错误:', err.message);
console.error(err.stack);
});

View File

@ -0,0 +1,23 @@
/**
* 简单测试卡号生成
*/
const {CardGeneratorTool} = require('./src/tools/card/CardGeneratorTool');
async function test() {
console.log('开始测试...');
const cardGen = new CardGeneratorTool();
await cardGen.initialize({});
console.log('生成10张测试卡...\n');
for (let i = 0; i < 10; i++) {
const card = await cardGen.generate('unionpay');
console.log(`${i + 1}. ${card.number} (${card.month}/${card.year}) - ${card.issuer}-${card.cvv}`);
}
}
test().catch(err => {
console.error('错误:', err.message);
console.error(err.stack);
});

View File

@ -0,0 +1,90 @@
/**
* 测试生成的卡号是否有效
*/
import pkg from './src/tools/card/CardGeneratorTool.js';
const { CardGeneratorTool } = pkg;
// Luhn算法验证
function validateLuhn(cardNumber) {
let sum = 0;
let isEven = false;
for (let i = cardNumber.length - 1; i >= 0; i--) {
let digit = parseInt(cardNumber[i]);
if (isEven) {
digit *= 2;
if (digit > 9) digit -= 9;
}
sum += digit;
isEven = !isEven;
}
return sum % 10 === 0;
}
async function test() {
console.log('生成20张卡验证有效性...\n');
const cardGen = new CardGeneratorTool();
await cardGen.initialize({});
const cards = await cardGen.generateBatch(20, 'unionpay');
let luhnPass = 0;
let luhnFail = 0;
console.log('=== 卡号验证 ===\n');
cards.forEach((card, i) => {
const isValid = validateLuhn(card.number);
const status = isValid ? '✅' : '❌';
if (isValid) luhnPass++;
else luhnFail++;
console.log(`${i + 1}. ${status} ${card.number}`);
console.log(` 有效期: ${card.month}/${card.year}`);
console.log(` CVV: ${card.cvv}`);
console.log(` 发卡行: ${card.issuer} (${card.country})`);
console.log();
});
console.log('=== 验证结果 ===');
console.log(`Luhn校验通过: ${luhnPass}/20`);
console.log(`Luhn校验失败: ${luhnFail}/20`);
// 验证有效期范围
console.log('\n=== 有效期检查 ===');
const months = cards.map(c => parseInt(c.month));
const years = cards.map(c => parseInt(c.year));
const validMonths = months.filter(m => m >= 1 && m <= 12).length;
const validYears = years.filter(y => y >= 26 && y <= 30).length;
console.log(`月份有效: ${validMonths}/20 (范围: 01-12)`);
console.log(`年份有效: ${validYears}/20 (范围: 26-30)`);
// 验证CVV长度
console.log('\n=== CVV检查 ===');
const validCVV = cards.filter(c => c.cvv.length === 3).length;
console.log(`CVV长度正确: ${validCVV}/20 (应为3位)`);
// 显示有效期和CVV的分布
console.log('\n=== 有效期分布 ===');
const expiryDist = {};
cards.forEach(c => {
const key = `${c.month}/${c.year}`;
expiryDist[key] = (expiryDist[key] || 0) + 1;
});
Object.entries(expiryDist)
.sort((a, b) => b[1] - a[1])
.forEach(([expiry, count]) => {
console.log(` ${expiry}: ${count}`);
});
}
test().catch(err => {
console.error('错误:', err.message);
console.error(err.stack);
});

View File

@ -0,0 +1,74 @@
/**
* 测试卡号生成规律
*/
import pkg from './src/tools/card/CardGeneratorTool.js';
const { CardGeneratorTool } = pkg;
async function test() {
console.log('开始生成1000张卡...\n');
const cardGen = new CardGeneratorTool();
await cardGen.initialize({});
const cards = await cardGen.generateBatch(1000, 'unionpay');
// 统计后4位的分布
const pos1 = {};
const pos2 = {};
const pos3 = {};
cards.forEach(card => {
const last4 = card.number.slice(-4);
const digits = last4.slice(0, 3);
pos1[digits[0]] = (pos1[digits[0]] || 0) + 1;
pos2[digits[1]] = (pos2[digits[1]] || 0) + 1;
pos3[digits[2]] = (pos3[digits[2]] || 0) + 1;
});
console.log('=== 生成的1000张卡的数字分布 ===\n');
console.log('位置1千位频率:');
for (let i = 0; i <= 9; i++) {
const count = pos1[i] || 0;
const percent = (count / 1000 * 100).toFixed(1);
const expected = [14, 9, 7, 8, 10, 2, 4, 7, 7, 2][i];
const expectedPercent = (expected / 70 * 100).toFixed(1);
console.log(` ${i}: ${count}次 (${percent}%) [期望: ${expectedPercent}%]`);
}
console.log('\n位置2百位频率:');
for (let i = 0; i <= 9; i++) {
const count = pos2[i] || 0;
const percent = (count / 1000 * 100).toFixed(1);
const expected = [10, 7, 10, 2, 5, 8, 2, 11, 8, 7][i];
const expectedPercent = (expected / 70 * 100).toFixed(1);
console.log(` ${i}: ${count}次 (${percent}%) [期望: ${expectedPercent}%]`);
}
console.log('\n位置3十位频率:');
for (let i = 0; i <= 9; i++) {
const count = pos3[i] || 0;
const percent = (count / 1000 * 100).toFixed(1);
const expected = [10, 2, 4, 11, 8, 9, 6, 6, 7, 7][i];
const expectedPercent = (expected / 70 * 100).toFixed(1);
console.log(` ${i}: ${count}次 (${percent}%) [期望: ${expectedPercent}%]`);
}
console.log('\n=== 前20张生成的卡号 ===\n');
cards.slice(0, 20).forEach((card, i) => {
const last4 = card.number.slice(-4);
console.log(`${i + 1}. ${card.number} (后4位: ${last4})`);
});
const uniqueNumbers = new Set(cards.map(c => c.number));
console.log(`\n=== 去重检查 ===`);
console.log(`生成: 1000张`);
console.log(`唯一: ${uniqueNumbers.size}`);
console.log(`重复: ${1000 - uniqueNumbers.size}`);
}
test().catch(err => {
console.error('错误:', err.message);
console.error(err.stack);
});