☰

Rock Maths Auto Solver PRO

Automatic multiplication solver with digit verification

Du musst eine Erweiterung wie Tampermonkey, Greasemonkey oder Violentmonkey installieren, um dieses Skript zu installieren.

Um dieses Skript zu installieren, müssen Sie eine Erweiterung wie Tampermonkey oder Violentmonkey installieren.

Um dieses Skript zu installieren, müssen Sie eine Erweiterung wie Tampermonkey oder Violentmonkey installieren.

Um dieses Skript zu installieren, müssen Sie eine Erweiterung wie Tampermonkey oder Userscripts installieren.

Um dieses Skript zu installieren, müssen Sie eine Erweiterung wie Tampermonkey installieren.

Sie müssten eine Skript Manager Erweiterung installieren damit sie dieses Skript installieren können

(Ich habe schon ein Skript Manager, Lass mich es installieren!)

Um dieses Design zu installieren, müssen Sie eine Erweiterung wie Stylus installieren.

Um dieses Design zu installieren, müssen Sie eine Erweiterung wie Stylus installieren.

Um dieses Design zu installieren, müssen Sie eine Erweiterung wie Stylus installieren.

Um diesen Stil zu installieren, müssen Sie eine Erweiterung für den Benutzerstil Verwaltung installieren.

Um diesen Stil zu installieren, müssen Sie eine Erweiterung für den Benutzerstil Verwaltung installieren.

Um diesen Stil zu installieren, müssen Sie eine Erweiterung für den Benutzerstil Verwaltung installieren.

(Ich habe bereits einen Benutzerstil Verwaltung, ich möchte ihn installieren!)

// ==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);

})();