File size: 4,874 Bytes
4f05ffd e2fe8e8 4f05ffd e2fe8e8 4f05ffd e2fe8e8 8b3004b 4f05ffd e2fe8e8 4f05ffd 8b3004b 4f05ffd 8b3004b e2fe8e8 8b3004b 4f05ffd 8b3004b e2fe8e8 8b3004b 4f05ffd e2fe8e8 4f05ffd e2fe8e8 8b3004b 4f05ffd e2fe8e8 4f05ffd 8b3004b e2fe8e8 8b3004b e2fe8e8 8b3004b e2fe8e8 8b3004b e2fe8e8 8b3004b e2fe8e8 8b3004b e2fe8e8 4f05ffd 8b3004b e2fe8e8 4f05ffd 8b3004b e2fe8e8 4f05ffd 8b3004b e2fe8e8 4f05ffd 8b3004b 4f05ffd e2fe8e8 8b3004b e2fe8e8 4f05ffd e2fe8e8 | 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 | const fs = require('fs');
const path = require('path');
// Pastikeun file imageProcessor.js aya dina folder anu sarua
const { extractTextFromImage } = require('./imageProcessor');
// --- KONFIGURASI & MAPPING ---
const NUMBER_WORDS = {
'nol': '0', 'satu': '1', 'dua': '2', 'tiga': '3', 'empat': '4', 'lima': '5',
'enam': '6', 'tujuh': '7', 'delapan': '8', 'sembilan': '9', 'sepuluh': '10',
'sebelas': '11', 'one': '1', 'two': '2', 'three': '3', 'four': '4', 'five': '5',
'six': '6', 'seven': '7', 'eight': '8', 'nine': '9', 'ten': '10',
'zero': '0', 'eleven': '11', 'twelve': '12'
};
const LEET_MAP = {
'4': 'a', '@': 'a', '8': 'b', '3': 'e', '6': 'g', '1': 'i', '!': 'i', '0': 'o',
'5': 's', '$': 's', '7': 't', '+': 't', '2': 'z'
};
// --- FUNGSI HELPER ---
function safeString(s) { return (s || '').toString(); }
function normalizeText(text) {
let normalized = safeString(text).normalize('NFD').replace(/[\u0300-\u036f]/g, '');
normalized = normalized.toLowerCase();
// Apply Leet Map (anti-deteksi karakter anéh)
let leetOut = '';
for (const ch of normalized) { leetOut += (LEET_MAP[ch] !== undefined) ? LEET_MAP[ch] : ch; }
normalized = leetOut;
// Beberesih karakter non-alfanumerik
normalized = normalized.replace(/[^a-z0-9\s]/g, ' ').replace(/\s+/g, ' ').trim();
// Mapping kecap angka jadi digit
const tokens = normalized.split(/\s+/);
return tokens.map(t => NUMBER_WORDS[t] !== undefined ? NUMBER_WORDS[t] : t).join(' ');
}
function levenshtein(a = '', b = '') {
const alen = a.length, blen = b.length;
if (alen === 0) return blen;
if (blen === 0) return alen;
const matrix = Array.from({ length: alen + 1 }, () => new Array(blen + 1));
for (let i = 0; i <= alen; i++) matrix[i][0] = i;
for (let j = 0; j <= blen; j++) matrix[0][j] = j;
for (let i = 1; i <= alen; i++) {
for (let j = 1; j <= blen; j++) {
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
matrix[i][j] = Math.min(matrix[i - 1][j] + 1, matrix[i][j - 1] + 1, matrix[i - 1][j - 1] + cost);
}
}
return matrix[alen][blen];
}
function similarity(a, b) {
a = normalizeText(a); b = normalizeText(b);
if (a === b || a.includes(b) || b.includes(a)) return 1;
const dist = levenshtein(a, b);
const maxLen = Math.max(a.length, b.length);
return maxLen === 0 ? 1 : 1 - (dist / maxLen);
}
// --- LOGIKA UTAMA SOLVER ---
async function solve(data) {
try {
console.log("🛠️ Processing Antibot Challenge...");
const mainBuffer = Buffer.from(data.main, 'base64');
const botsBuffers = data.bots.map(b => Buffer.from(b, 'base64'));
// OCR Gambar Instruksi Utama
const mainOCR = await extractTextFromImage(mainBuffer);
let rawMain = (mainOCR.response || "").toLowerCase();
console.log("🎯 Raw Instruction:", rawMain);
// --- BAGIAN TARGET NU DIUBAH (LEMBUT TAPI TEGAS) ---
const targets = rawMain
.replace(/please\s*click\s*on\s*the\s*anti-bot\s*links\s*in\s*the\s*following\s*order/gi, '')
.replace(/[:.,|+&-]/g, ' ') // Ganti karakter separator ku spasi
.split(/\s+/)
.filter(t => t.length > 0 && t !== 'and');
console.log("🔍 Cleaned Targets:", targets);
// OCR Kabéh Gambar Pilihan (Bots)
const botResults = [];
for (let i = 0; i < botsBuffers.length; i++) {
const res = await extractTextFromImage(botsBuffers[i]);
botResults.push({
index: (i + 1).toString(),
text: normalizeText(res.response || "")
});
console.log(`🖼️ Bot ${i+1} OCR: "${res.response}"`);
}
// Matching Strategy
let finalOrder = [];
let usedIndices = new Set();
for (const target of targets) {
let bestMatch = { index: null, score: -1 };
for (const bot of botResults) {
if (usedIndices.has(bot.index)) continue;
const score = similarity(bot.text, target);
if (score > bestMatch.score) {
bestMatch = { index: bot.index, score: score };
}
}
// Skor minimal 0.3 (30%) bisi OCR-na rada burem
if (bestMatch.index && bestMatch.score > 0.3) {
finalOrder.push(bestMatch.index);
usedIndices.add(bestMatch.index);
}
}
// Fallback: Mun aya bot nu can kapaéh, asupkeun dumasar urutan
if (finalOrder.length < botsBuffers.length) {
botResults.forEach(b => {
if(!usedIndices.has(b.index)) finalOrder.push(b.index);
});
}
// Pastikeun ngan ngirim jumlah nu sarua jeung bot nu aya
finalOrder = finalOrder.slice(0, botsBuffers.length);
console.log("✅ Final Solution:", finalOrder.join(", "));
return { status: "Success", result: finalOrder };
} catch (error) {
console.error("❌ Solver Error:", error.message);
return { status: "Error", message: error.message, result: ["1", "2", "3"] };
}
}
module.exports = solve;
|