【工程】觉得自己太颓了?强力学术!

· · 科技·工程

前置需要

正文

本文最初参考本篇文章。

1.0 版本

拦截除题目列表和题目外其它页面(包括洛谷进入界面或 AI 界面)。

:::info[代码]

// ==UserScript==
// @name         洛谷强力学术
// @namespace    http://tampermonkey.net/
// @version      1.0
// @author       fire_star_
// @icon         https://cdn.luogu.com.cn/upload/usericon/1805886.png
// @description  tuifei breaker
// @match        *://*/*
// @grant        none
// @license      MIT
// @run-at       document-start
// ==/UserScript==

(function() {
'use strict';
const ALLOW_RULES = [
    /^https:\/\/(www\.)?luogu\.com\.cn\/problem(\/list)?/i
];

function shouldAllow() {
    const currentURL = window.location.href.toLowerCase();
    return ALLOW_RULES.some(regex => regex.test(currentURL));
}
if (!shouldAllow()) {
    console.warn('[学术模式] 拦截非学习网站:', window.location.href);
    window.location.replace('https://www.luogu.com.cn/problem/list');
}
})();

:::

很明显,我只是删了几个网站。

2.0 版本

在页面右上角加了设置键,可以在 做题计划 的输入框中输入最近要做的题的题号。以后就会跳转到所对应的题目,直到做完或不想做后点击 删除计划 即可。

:::info[代码]

// ==UserScript==
// @name         洛谷强力学术 增强版
// @namespace    http://tampermonkey.net/
// @version      2.0
// @author       fire & 增强版
// @icon         https://cdn.luogu.com.cn/upload/usericon/1805886.png
// @description  tuifei breaker 做题计划增强版
// @match        *://*/*
// @grant        none
// @license      MIT
// @run-at       document-start
// ==/UserScript==

(function() {
    'use strict';
    const ALLOW_RULES = [
        /^https:\/\/(www\.)?luogu\.com\.cn\/problem(\/list|\/\w+)?/i
    ];
    const STORAGE_KEY = "luogu_study_plan_pid";
    function getSavePid() {
        return localStorage.getItem(STORAGE_KEY) || '';
    }
    function savePid(pid) {
        localStorage.setItem(STORAGE_KEY, pid.trim());
    }
    function removePid() {
        localStorage.removeItem(STORAGE_KEY);
    }
    function shouldAllow() {
        const currentURL = window.location.href.toLowerCase();
        return ALLOW_RULES.some(regex => regex.test(currentURL));
    }
    const targetPid = getSavePid();
    if (targetPid && !window.location.href.includes(`luogu.com.cn/problem/${targetPid}`)) {
        console.warn('[学术模式-做题计划] 跳转到指定题目:', targetPid);
        window.location.replace(`https://www.luogu.com.cn/problem/${targetPid}`);
    }
    else if (!shouldAllow()) {
        console.warn('[学术模式] 拦截非学习网站:', window.location.href);
        window.location.replace('https://www.luogu.com.cn/problem/list');
    }
    function createSettingUI() {
        const style = document.createElement('style');
        style.textContent = `
            #luogu-setting-btn {
                position: fixed;
                top: 80px;
                right: 20px;
                width: 60px;
                height: 60px;
                border-radius: 50%;
                background: #000;
                color: #fff;
                font-size: 16px;
                border: none;
                cursor: pointer;
                z-index: 9999;
                line-height: 60px;
                text-align: center;
                font-weight: bold;
            }
            #luogu-setting-btn:hover {background: #333;}
            #luogu-modal-mask {
                position: fixed;
                top:0;left:0;right:0;bottom:0;
                background: rgba(0,0,0,0.5);
                z-index: 9998;
                display: none;
            }
            #luogu-modal-box {
                position: fixed;
                top: 50%;left:50%;
                transform: translate(-50%, -50%);
                width: 320px;
                padding: 20px;
                background: #fff;
                border-radius: 8px;
                z-index: 9999;
                display: none;
                box-shadow: 0 0 15px rgba(0,0,0,0.3);
            }
            #luogu-modal-box h3 {margin:0 0 15px 0; color:#333; text-align:center;}
            #luogu-pid-input {
                width: 100%;
                padding: 10px;
                box-sizing: border-box;
                margin-bottom: 15px;
                border: 1px solid #ddd;
                border-radius: 4px;
                font-size: 16px;
            }
            #luogu-modal-btn-group {
                display: flex;
                gap: 10px;
            }
            #luogu-save-btn, #luogu-del-btn {
                flex: 1;
                padding: 8px 0;
                border: none;
                border-radius: 4px;
                cursor: pointer;
                font-size: 14px;
            }
            #luogu-save-btn {background: #0099ff; color:#fff;}
            #luogu-save-btn:hover {background: #0077cc;}
            #luogu-del-btn {background: #ff4444; color:#fff;}
            #luogu-del-btn:hover {background: #cc0000;}
        `;
        document.head.appendChild(style);

        const mask = document.createElement('div');
        mask.id = 'luogu-modal-mask';
        mask.onclick = () => {
            mask.style.display = 'none';
            modalBox.style.display = 'none';
        };
        document.body.appendChild(mask);

        const modalBox = document.createElement('div');
        modalBox.id = 'luogu-modal-box';
        modalBox.innerHTML = `
            <h3>做题计划</h3>
            <input type="text" id="luogu-pid-input" placeholder="请输入洛谷题号,例如:P1001">
            <div id="luogu-modal-btn-group">
                <button id="luogu-save-btn">保存</button>
                <button id="luogu-del-btn">删除计划</button>
            </div>
        `;
        document.body.appendChild(modalBox);

        const settingBtn = document.createElement('button');
        settingBtn.id = 'luogu-setting-btn';
        settingBtn.innerText = '设置';
        settingBtn.onclick = () => {
            mask.style.display = 'block';
            modalBox.style.display = 'block';
            document.getElementById('luogu-pid-input').value = getSavePid();
        };
        document.body.appendChild(settingBtn);

        document.getElementById('luogu-save-btn').onclick = () => {
            const pidInput = document.getElementById('luogu-pid-input');
            const pid = pidInput.value.trim();
            if (pid) {
                savePid(pid);
                alert(`✅ 做题计划保存成功!题号:${pid}\n刷新页面后将自动跳转`);
            } else {
                alert('⚠️ 请输入有效的洛谷题号!');
            }
            mask.style.display = 'none';
            modalBox.style.display = 'none';
        };

        document.getElementById('luogu-del-btn').onclick = () => {
            if (confirm('❓ 确定要删除做题计划吗?删除后将恢复跳转到题目列表')) {
                removePid();
                document.getElementById('luogu-pid-input').value = '';
                alert('✅ 做题计划已删除!');
            }
            mask.style.display = 'none';
            modalBox.style.display = 'none';
        };
    }

    window.addEventListener('load', createSettingUI);
})();

:::

2.1 版本

在设置中加入了是否可以查看题解(默认开启)。关闭后查看题解效果如下图所示:

目前 bug:设置做题计划后无论是否打开都无法打开,将在 2.2 修复。

upd:2.2 已修复。

:::info[代码]

// ==UserScript==
// @name         洛谷强力学术 增强版
// @namespace    http://tampermonkey.net/
// @version      2.1
// @author       fire
// @icon         https://cdn.luogu.com.cn/upload/usericon/1805886.png
// @description  tuifei breaker 做题计划增强版
// @match        *://*/*
// @grant        none
// @license      MIT
// @run-at       document-start
// ==/UserScript==

(function() {
    'use strict';
    const ALLOW_RULES = [
        /^https:\/\/(www\.)?luogu\.com\.cn\/problem(\/list|\/\w+)?/i
    ];
    const STORAGE_KEY_PID = "luogu_study_plan_pid";
    const STORAGE_KEY_SOLUTION = "luogu_study_plan_solution";

    function getSavePid() {
        return localStorage.getItem(STORAGE_KEY_PID) || '';
    }

    function savePid(pid) {
        localStorage.setItem(STORAGE_KEY_PID, pid.trim());
    }

    function removePid() {
        localStorage.removeItem(STORAGE_KEY_PID);
    }

    function getSolutionStatus() {
        return localStorage.getItem(STORAGE_KEY_SOLUTION) !== 'false';
    }

    function saveSolutionStatus(status) {
        localStorage.setItem(STORAGE_KEY_SOLUTION, status);
    }

    function shouldAllow() {
        const currentURL = window.location.href.toLowerCase();
        return ALLOW_RULES.some(regex => regex.test(currentURL));
    }

    function blockSolutionAccess() {
        const currentURL = window.location.href;
        if (!getSolutionStatus() && /luogu\.com\.cn\/problem\/solution\/\w+/.test(currentURL)) {
            console.warn('[学术模式] 已拦截题解访问');
            window.location.replace(`https://www.luogu.com.cn/problem/${getSavePid() || ''}`);
            return true;
        }
        return false;
    }

    function monitorSolutionElements() {
        if (!getSolutionStatus()) {
            const observer = new MutationObserver((mutations) => {
                mutations.forEach((mutation) => {
                    mutation.addedNodes.forEach((node) => {
                        if (node.nodeType === 1) {
                            const solutionLinks = node.querySelectorAll('a[href*="/problem/solution/"], button, div');
                            solutionLinks.forEach(link => {
                                if (link.textContent.includes('题解') || link.href?.includes('/problem/solution/')) {
                                    link.style.display = 'none';
                                }
                            });
                        }
                    });
                });
            });

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

    const targetPid = getSavePid();
    if (blockSolutionAccess()) return;

    if (targetPid && !window.location.href.includes(`luogu.com.cn/problem/${targetPid}`)) {
        console.warn('[学术模式-做题计划] 跳转到指定题目:', targetPid);
        window.location.replace(`https://www.luogu.com.cn/problem/${targetPid}`);
    }
    else if (!shouldAllow()) {
        console.warn('[学术模式] 拦截非学习网站:', window.location.href);
        window.location.replace('https://www.luogu.com.cn/problem/list');
    }

    function createSettingUI() {
        const style = document.createElement('style');
        style.textContent = `
            #luogu-setting-btn {
                position: fixed;
                top: 80px;
                right: 20px;
                width: 60px;
                height: 60px;
                border-radius: 50%;
                background: #000;
                color: #fff;
                font-size: 16px;
                border: none;
                cursor: pointer;
                z-index: 9999;
                line-height: 60px;
                text-align: center;
                font-weight: bold;
            }
            #luogu-setting-btn:hover {background: #333;}
            #luogu-modal-mask {
                position: fixed;
                top:0;left:0;right:0;bottom:0;
                background: rgba(0,0,0,0.5);
                z-index: 9998;
                display: none;
            }
            #luogu-modal-box {
                position: fixed;
                top: 50%;left:50%;
                transform: translate(-50%, -50%);
                width: 320px;
                padding: 20px;
                background: #fff;
                border-radius: 8px;
                z-index: 9999;
                display: none;
                box-shadow: 0 0 15px rgba(0,0,0,0.3);
            }
            #luogu-modal-box h3 {margin:0 0 15px 0; color:#333; text-align:center;}
            #luogu-pid-input {
                width: 100%;
                padding: 10px;
                box-sizing: border-box;
                margin-bottom: 15px;
                border: 1px solid #ddd;
                border-radius: 4px;
                font-size: 16px;
            }
            #luogu-solution-switch {
                display: flex;
                align-items: center;
                margin-bottom: 15px;
                gap: 10px;
            }
            #luogu-solution-switch input {
                width: 20px;
                height: 20px;
                cursor: pointer;
            }
            #luogu-modal-btn-group {
                display: flex;
                gap: 10px;
            }
            #luogu-save-btn, #luogu-del-btn {
                flex: 1;
                padding: 8px 0;
                border: none;
                border-radius: 4px;
                cursor: pointer;
                font-size: 14px;
            }
            #luogu-save-btn {background: #0099ff; color:#fff;}
            #luogu-save-btn:hover {background: #0077cc;}
            #luogu-del-btn {background: #ff4444; color:#fff;}
            #luogu-del-btn:hover {background: #cc0000;}
        `;
        document.head.appendChild(style);

        const mask = document.createElement('div');
        mask.id = 'luogu-modal-mask';
        mask.onclick = () => {
            mask.style.display = 'none';
            modalBox.style.display = 'none';
        };
        document.body.appendChild(mask);

        const modalBox = document.createElement('div');
        modalBox.id = 'luogu-modal-box';
        modalBox.innerHTML = `
            <h3>做题计划</h3>
            <input type="text" id="luogu-pid-input" placeholder="请输入洛谷题号,例如:P1001">
            <div id="luogu-solution-switch">
                <input type="checkbox" id="luogu-solution-checkbox">
                <label for="luogu-solution-checkbox">允许查看题解</label>
            </div>
            <div id="luogu-modal-btn-group">
                <button id="luogu-save-btn">保存</button>
                <button id="luogu-del-btn">删除计划</button>
            </div>
        `;
        document.body.appendChild(modalBox);

        const settingBtn = document.createElement('button');
        settingBtn.id = 'luogu-setting-btn';
        settingBtn.innerText = '设置';
        settingBtn.onclick = () => {
            mask.style.display = 'block';
            modalBox.style.display = 'block';
            document.getElementById('luogu-pid-input').value = getSavePid();
            document.getElementById('luogu-solution-checkbox').checked = getSolutionStatus();
        };
        document.body.appendChild(settingBtn);

        document.getElementById('luogu-save-btn').onclick = () => {
            const pidInput = document.getElementById('luogu-pid-input');
            const pid = pidInput.value.trim();
            const solutionChecked = document.getElementById('luogu-solution-checkbox').checked;

            saveSolutionStatus(solutionChecked);

            if (pid) {
                savePid(pid);
                alert(`✅ 做题计划保存成功!题号:${pid}\n查看题解:${solutionChecked ? '开启' : '关闭'}\n刷新页面后生效`);
            } else {
                alert(`✅ 设置保存成功!\n查看题解:${solutionChecked ? '开启' : '关闭'}`);
            }
            mask.style.display = 'none';
            modalBox.style.display = 'none';
        };

        document.getElementById('luogu-del-btn').onclick = () => {
            if (confirm('❓ 确定要删除做题计划吗?删除后将恢复跳转到题目列表')) {
                removePid();
                document.getElementById('luogu-pid-input').value = '';
                alert('✅ 做题计划已删除!');
            }
            mask.style.display = 'none';
            modalBox.style.display = 'none';
        };

        monitorSolutionElements();
    }

    window.addEventListener('load', createSettingUI);
})();

:::

2.2 版本

修改了 2.1 时的 bug。

:::info[代码]

// ==UserScript==
// @name         洛谷强力学术 增强版
// @namespace    http://tampermonkey.net/
// @version      2.2
// @author       fire
// @icon         https://cdn.luogu.com.cn/upload/usericon/1805886.png
// @description  tuifei breaker 做题计划增强版
// @match        *://*/*
// @grant        none
// @license      MIT
// @run-at       document-start
// ==/UserScript==

(function() {
    'use strict';
    const ALLOW_RULES = [
        /^https:\/\/(www\.)?luogu\.com\.cn\/problem(\/list|\/\w+)?/i
    ];
    const STORAGE_KEY_PID = "luogu_study_plan_pid";
    const STORAGE_KEY_SOLUTION = "luogu_study_plan_solution";

    function getSavePid() {
        return localStorage.getItem(STORAGE_KEY_PID) || '';
    }

    function savePid(pid) {
        localStorage.setItem(STORAGE_KEY_PID, pid.trim());
    }

    function removePid() {
        localStorage.removeItem(STORAGE_KEY_PID);
    }

    function getSolutionStatus() {
        return localStorage.getItem(STORAGE_KEY_SOLUTION) !== 'false';
    }

    function saveSolutionStatus(status) {
        localStorage.setItem(STORAGE_KEY_SOLUTION, status);
    }

    function shouldAllow() {
        const currentURL = window.location.href.toLowerCase();
        const targetPid = getSavePid();
        if (targetPid) {
            return /^https:\/\/(www\.)?luogu\.com\.cn\/problem(\/list|\/\w+|\/solution\/\w+)?/i.test(currentURL);
        }
        return ALLOW_RULES.some(regex => regex.test(currentURL));
    }

    function blockSolutionAccess() {
        const currentURL = window.location.href;
        const targetPid = getSavePid();
        if (!getSolutionStatus() && targetPid && new RegExp(`luogu\\.com\\.cn\\/problem\\/solution\\/${targetPid}`).test(currentURL)) {
            console.warn('[学术模式] 已拦截题解访问');
            window.location.replace(`https://www.luogu.com.cn/problem/${targetPid || ''}`);
            return true;
        }
        return false;
    }

    function monitorSolutionElements() {
        if (!getSolutionStatus()) {
            const observer = new MutationObserver((mutations) => {
                mutations.forEach((mutation) => {
                    mutation.addedNodes.forEach((node) => {
                        if (node.nodeType === 1) {
                            const solutionLinks = node.querySelectorAll('a[href*="/problem/solution/"], button, div');
                            solutionLinks.forEach(link => {
                                if (link.textContent.includes('题解') || link.href?.includes('/problem/solution/')) {
                                    link.style.display = 'none';
                                }
                            });
                        }
                    });
                });
            });

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

    const targetPid = getSavePid();
    if (blockSolutionAccess()) return;

    if (targetPid && !window.location.href.includes(`luogu.com.cn/problem/${targetPid}`) && !window.location.href.includes(`luogu.com.cn/problem/solution/${targetPid}`)) {
        console.warn('[学术模式-做题计划] 跳转到指定题目:', targetPid);
        window.location.replace(`https://www.luogu.com.cn/problem/${targetPid}`);
    }
    else if (!shouldAllow()) {
        console.warn('[学术模式] 拦截非学习网站:', window.location.href);
        window.location.replace('https://www.luogu.com.cn/problem/list');
    }

    function createSettingUI() {
        const style = document.createElement('style');
        style.textContent = `
            #luogu-setting-btn {
                position: fixed;
                top: 80px;
                right: 20px;
                width: 60px;
                height: 60px;
                border-radius: 50%;
                background: #000;
                color: #fff;
                font-size: 16px;
                border: none;
                cursor: pointer;
                z-index: 9999;
                line-height: 60px;
                text-align: center;
                font-weight: bold;
            }
            #luogu-setting-btn:hover {background: #333;}
            #luogu-modal-mask {
                position: fixed;
                top:0;left:0;right:0;bottom:0;
                background: rgba(0,0,0,0.5);
                z-index: 9998;
                display: none;
            }
            #luogu-modal-box {
                position: fixed;
                top: 50%;left:50%;
                transform: translate(-50%, -50%);
                width: 320px;
                padding: 20px;
                background: #fff;
                border-radius: 8px;
                z-index: 9999;
                display: none;
                box-shadow: 0 0 15px rgba(0,0,0,0.3);
            }
            #luogu-modal-box h3 {margin:0 0 15px 0; color:#333; text-align:center;}
            #luogu-pid-input {
                width: 100%;
                padding: 10px;
                box-sizing: border-box;
                margin-bottom: 15px;
                border: 1px solid #ddd;
                border-radius: 4px;
                font-size: 16px;
            }
            #luogu-solution-switch {
                display: flex;
                align-items: center;
                margin-bottom: 15px;
                gap: 10px;
            }
            #luogu-solution-switch input {
                width: 20px;
                height: 20px;
                cursor: pointer;
            }
            #luogu-modal-btn-group {
                display: flex;
                gap: 10px;
            }
            #luogu-save-btn, #luogu-del-btn {
                flex: 1;
                padding: 8px 0;
                border: none;
                border-radius: 4px;
                cursor: pointer;
                font-size: 14px;
            }
            #luogu-save-btn {background: #0099ff; color:#fff;}
            #luogu-save-btn:hover {background: #0077cc;}
            #luogu-del-btn {background: #ff4444; color:#fff;}
            #luogu-del-btn:hover {background: #cc0000;}
        `;
        document.head.appendChild(style);

        const mask = document.createElement('div');
        mask.id = 'luogu-modal-mask';
        mask.onclick = () => {
            mask.style.display = 'none';
            modalBox.style.display = 'none';
        };
        document.body.appendChild(mask);

        const modalBox = document.createElement('div');
        modalBox.id = 'luogu-modal-box';
        modalBox.innerHTML = `
            <h3>做题计划</h3>
            <input type="text" id="luogu-pid-input" placeholder="请输入洛谷题号,例如:P1001">
            <div id="luogu-solution-switch">
                <input type="checkbox" id="luogu-solution-checkbox">
                <label for="luogu-solution-checkbox">允许查看题解</label>
            </div>
            <div id="luogu-modal-btn-group">
                <button id="luogu-save-btn">保存</button>
                <button id="luogu-del-btn">删除计划</button>
            </div>
        `;
        document.body.appendChild(modalBox);

        const settingBtn = document.createElement('button');
        settingBtn.id = 'luogu-setting-btn';
        settingBtn.innerText = '设置';
        settingBtn.onclick = () => {
            mask.style.display = 'block';
            modalBox.style.display = 'block';
            document.getElementById('luogu-pid-input').value = getSavePid();
            document.getElementById('luogu-solution-checkbox').checked = getSolutionStatus();
        };
        document.body.appendChild(settingBtn);

        document.getElementById('luogu-save-btn').onclick = () => {
            const pidInput = document.getElementById('luogu-pid-input');
            const pid = pidInput.value.trim();
            const solutionChecked = document.getElementById('luogu-solution-checkbox').checked;

            saveSolutionStatus(solutionChecked);

            if (pid) {
                savePid(pid);
                alert(`✅ 做题计划保存成功!题号:${pid}\n查看题解:${solutionChecked ? '开启' : '关闭'}\n刷新页面后生效`);
            } else {
                alert(`✅ 设置保存成功!\n查看题解:${solutionChecked ? '开启' : '关闭'}`);
            }
            mask.style.display = 'none';
            modalBox.style.display = 'none';
        };

        document.getElementById('luogu-del-btn').onclick = () => {
            if (confirm('❓ 确定要删除做题计划吗?删除后将恢复跳转到题目列表')) {
                removePid();
                document.getElementById('luogu-pid-input').value = '';
                alert('✅ 做题计划已删除!');
            }
            mask.style.display = 'none';
            modalBox.style.display = 'none';
        };

        monitorSolutionElements();
    }

    window.addEventListener('load', createSettingUI);
})();

:::

到此个人感觉功能已经够用了。

欢迎大家使用!如果发现问题或提出建议,也欢迎私信我!