☰

Rock Maths Auto Solver PRO

Automatic multiplication solver with digit verification

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला Tampermonkey, Greasemonkey किंवा Violentmonkey यासारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला Tampermonkey किंवा Violentmonkey यासारखे एक्स्टेंशन इंस्टॉल करावे लागेल..

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला Tampermonkey यासारखे एक्स्टेंशन इंस्टॉल करावे लागेल..

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्क्रिप्ट व्यवस्थापक एक्स्टेंशन इंस्टॉल करावे लागेल.

(माझ्याकडे आधीच युझर स्क्रिप्ट व्यवस्थापक आहे, मला इंस्टॉल करू द्या!)

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला Stylus सारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला Stylus सारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला Stylus सारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्टाईल व्यवस्थापक इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्टाईल व्यवस्थापक इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्टाईल व्यवस्थापक इंस्टॉल करावे लागेल.

(माझ्याकडे आधीच युझर स्टाईल व्यवस्थापक आहे, मला इंस्टॉल करू द्या!)

// ==UserScript==
// @name         Rock Maths Auto Solver PRO
// @namespace    rockmaths
// @version      5.1
// @description  Automatic multiplication solver with digit verification
// @match        *://*/*
// @run-at       document-idle
// @grant        none
// ==/UserScript==

(() => {
    'use strict';

    if (window.rockMathsPro) return;
    window.rockMathsPro = true;

    let enabled = true;
    let busy = false;
    let lastQuestion = '';
    let observerTimer = null;

    const sleep = ms =>
        new Promise(resolve => setTimeout(resolve, ms));

    function visible(el) {
        if (!el) return false;
        const r = el.getBoundingClientRect();
        const s = getComputedStyle(el);

        return r.width > 0 &&
            r.height > 0 &&
            s.display !== 'none' &&
            s.visibility !== 'hidden';
    }

    function readQuestion() {
        const text = document.body.innerText || '';

        const match = text.match(
            /(\d{1,3})\s*[×x*]\s*(\d{1,3})\s*=/
        );

        if (!match) return null;

        const progress = text.match(/\b(\d+)\s*\/\s*(\d+)\b/);

        const a = Number(match[1]);
        const b = Number(match[2]);

        return {
            answer: String(a * b),
            id: `${a}x${b}:${progress?.[0] || ''}`
        };
    }

    function findKeys() {
        const controls = [
            ...document.querySelectorAll(
                'button,[role="button"],[onclick]'
            )
        ].filter(visible);

        const groups = {};

        for (let n = 0; n <= 9; n++) {
            groups[n] = controls.filter(el =>
                el.textContent.trim() === String(n)
            );

            if (!groups[n].length) return null;
        }

        let root = groups[0][0];

        while (
            root &&
            !Object.values(groups).every(group =>
                group.some(el => root.contains(el))
            )
        ) {
            root = root.parentElement;
        }

        if (!root) return null;

        const keys = {};

        for (let n = 0; n <= 9; n++) {
            keys[n] = groups[n]
                .filter(el => root.contains(el))
                .sort((a, b) => {
                    const x = a.getBoundingClientRect();
                    const y = b.getBoundingClientRect();

                    return x.width * x.height -
                        y.width * y.height;
                })[0];

            if (!keys[n]) return null;
        }

        return { root, keys };
    }

    function findSpecialButtons(root, keys) {
        const digitKeys = Object.values(keys);

        const controls = [
            ...root.querySelectorAll(
                'button,[role="button"],[onclick]'
            )
        ].filter(el =>
            visible(el) &&
            !digitKeys.includes(el) &&
            !digitKeys.some(k => el.contains(k))
        );

        if (controls.length < 2) return null;

        const bottom = controls.filter(el => {
            const r = el.getBoundingClientRect();
            const rr = root.getBoundingClientRect();

            return r.bottom > rr.bottom - 110;
        });

        if (bottom.length < 2) return null;

        bottom.sort((a, b) =>
            a.getBoundingClientRect().left -
            b.getBoundingClientRect().left
        );

        return {
            clear: bottom[0],
            submit: bottom[bottom.length - 1]
        };
    }

    function findAnswerDisplay(root) {
        const rr = root.getBoundingClientRect();

        const candidates = [
            ...document.querySelectorAll('div,span,p')
        ].filter(el => {
            if (!visible(el) || el.children.length > 1) {
                return false;
            }

            const r = el.getBoundingClientRect();

            return r.bottom <= rr.top + 5 &&
                r.right > rr.left + rr.width * 0.55;
        });

        return candidates.sort((a, b) => {
            const x = a.getBoundingClientRect();
            const y = b.getBoundingClientRect();

            return x.width * x.height -
                y.width * y.height;
        })[0] || null;
    }

    function click(el) {
        if (!visible(el)) return false;
        el.click();
        return true;
    }

    async function waitForDisplay(display, expected) {
        const start = Date.now();

        while (Date.now() - start < 1500) {
            if (!enabled) return false;

            if (display.textContent.trim() === expected) {
                return true;
            }

            await sleep(30);
        }

        return false;
    }

    async function solve() {
        if (!enabled || busy) return;

        const q = readQuestion();

        if (!q || q.id === lastQuestion) return;

        const keypad = findKeys();

        if (!keypad) return;

        const special = findSpecialButtons(
            keypad.root,
            keypad.keys
        );

        if (!special) return;

        const display = findAnswerDisplay(keypad.root);

        if (!display) return;

        busy = true;

        try {
            // Clear the current answer.
            if (!click(special.clear)) return;

            await sleep(150);

            let current = readQuestion();

            if (!current || current.id !== q.id) return;

            // Enter and verify every digit.
            let typed = '';

            for (const digit of q.answer) {
                if (!enabled) return;

                current = readQuestion();

                if (!current || current.id !== q.id) return;

                if (!click(keypad.keys[digit])) return;

                typed += digit;

                const verified = await waitForDisplay(
                    display,
                    typed
                );

                if (!verified) {
                    console.warn(
                        '[Rock Maths] Digit verification failed:',
                        typed
                    );
                    return;
                }
            }

            // Verify the complete answer.
            if (display.textContent.trim() !== q.answer) {
                return;
            }

            current = readQuestion();

            if (!current || current.id !== q.id) return;

            await sleep(120);

            if (!enabled) return;

            if (display.textContent.trim() !== q.answer) {
                return;
            }

            // Submit only when verified.
            if (click(special.submit)) {
                lastQuestion = q.id;
            }

            await sleep(400);

        } catch (error) {
            console.error('[Rock Maths]', error);
        } finally {
            busy = false;
        }
    }

    // Create status button.
    const badge = document.createElement('button');

    Object.assign(badge.style, {
        position: 'fixed',
        right: '12px',
        bottom: '12px',
        zIndex: '2147483647',
        padding: '11px 15px',
        border: 'none',
        borderRadius: '9px',
        color: 'white',
        fontWeight: 'bold',
        cursor: 'pointer'
    });

    function updateBadge() {
        badge.textContent = enabled
            ? 'SMART SOLVER: ON'
            : 'SMART SOLVER: OFF';

        badge.style.background = enabled
            ? '#145b49'
            : '#a52d35';
    }

    badge.onclick = () => {
        enabled = !enabled;
        updateBadge();

        if (enabled) solve();
    };

    document.body.appendChild(badge);
    updateBadge();

    // Alt + M toggles the solver.
    document.addEventListener('keydown', event => {
        if (
            event.altKey &&
            event.key.toLowerCase() === 'm'
        ) {
            enabled = !enabled;
            updateBadge();

            if (enabled) solve();
        }
    });

    // Detect new questions automatically.
    const observer = new MutationObserver(() => {
        clearTimeout(observerTimer);
        observerTimer = setTimeout(solve, 70);
    });

    observer.observe(document.body, {
        childList: true,
        subtree: true,
        characterData: true
    });

    setTimeout(solve, 500);

})();