Greasy Fork is available in English.

二定排除加(减)

排除加

// ==UserScript==
// @name         二定排除加(减)
// @namespace    http://tampermonkey.net/
// @version      0.7
// @description  排除加
// @author       You
// @include        http*://q1.88666333.com/*
// @include        http*://a1.qqqq663.com/*
// @grant   GM_xmlhttpRequest
// @grant   GM.getTab
// @grant   GM.saveTab
// @grant   GM.setValue
// @grant   GM.getValue
// @run-at document-body
// ==/UserScript==

(function() {
    'use strict';
    const MAX_TIMES = [4, 7, 6, 1, 6, 6, 6, 6, 6];
    const BET_AMOUNTS = [
        [1, 1, 1, 1],
        [1, 2, 4, 8, 16, 32, 64, 128],
        [1, 2, 4, 8, 16, 32, 64, 128],
        [1],
        [1, 2, 4, 8, 16, 32, 64, 128],
        [1, 2, 4, 8, 16, 32, 64, 128],
        [1, 2, 4, 8, 16, 32, 64, 128],
        [1, 2, 4, 8, 16, 32, 64, 128],
        [1, 2, 4, 8, 16, 32, 64, 128],
    ]
    // const PLACE_HOLDERS = ['abXXX', 'aXbXX', 'aXXbX', 'aXXXb', 'XabXX', 'XaXbX', 'XaXXb', 'XXabX', 'XXaXb', 'XXXab'];
    const PLACE_HOLDERS = ['abXXX'];
    const LEN = PLACE_HOLDERS.length;

    const POOL1 = (index, resNums1, resNums2) => {
        let holder = PLACE_HOLDERS[index];
        let resNumA1, resNumA2, resNumB1, resNumB2
        for (let i = 0; i < 5 ; i++) {
            if (holder[i] === 'a') {
                resNumA1 = parseInt(resNums1[i]);
                resNumA2 = parseInt(resNums2[i]);
            } else if (holder[i] === 'b') {
                resNumB1 = parseInt(resNums1[i]);
                resNumB2 = parseInt(resNums2[i]);
            }
        }
        /*
        let filterNumA = resNumA1 - resNumA2;
        if (filterNumA < 0) {
            filterNumA = (resNumA1 + resNumA2) % 10;
        }
        let filterNumB = resNumB1 - resNumB2;
        if (filterNumB < 0) {
            filterNumB = (resNumB1 + resNumB2) % 10;
        }
        */
        let filterNumA = (resNumA1 + resNumA2) % 10;
        let filterNumB = (resNumB1 + resNumB2) % 10;
        let numsA = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].filter(a => a !== filterNumA);
        let numsB = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].filter(a => a !== filterNumB);
        // console.log(resNumB1, resNumB2, filterNumB, numsB);
        let pools = [];
        numsA.forEach(a => {
            numsB.forEach(b => {
                pools.push(holder.replace('a', a).replace('b', b));
            });
        });
        pools = pools.sort();
        return pools;
    };

    const POOLS = [POOL1];

    function signalA(index, gameResult) {
        if (gameResult.length < 4) {
            return false;
        }
        if ((gameResult[0][0] + 1) % 10 !== ENV[GameType].Current.Code % 10) { // wait for previous result
            return false;
        }
        /*
        if (POOL1(index, gameResult[1][1], gameResult[2][1]).includes(resToMask(gameResult[0][1])[index])) {
            return false;
        }
        */
        return true;
    }
    const SIGNALS = [signalA];
    var wait = ms => new Promise(resolve => setTimeout(resolve, ms));
    function isPromise(obj) {
        return !!obj && ((typeof obj === 'object' && typeof obj.then === 'function') || (typeof obj === 'function' && typeof obj().then === 'function'));
    }
    /**
     * Wait Resource.
     *
     * @param {Function} resourceFn pred function to check resource
     * @param {Object} options
     * @returns Promise
     */
    function waitResource(resourceFn, options) {
        var optionsRes = Object.assign(
            {
                interval: 1000,
                max: 6
            },
            options
        );
        var current = 0;
        return new Promise((resolve, reject) => {
            var timer = setInterval(() => {
                if (isPromise(resourceFn)) {
                    resourceFn().then(res => {
                        if(res) {
                            clearInterval(timer);
                            resolve();
                        }
                    });
                } else if (resourceFn()) {
                    clearInterval(timer);
                    resolve();
                }
                current++;
                if (current >= optionsRes.max) {
                    clearInterval(timer);
                    reject('Time out');
                }
            }, optionsRes.interval);
        });
    }


    function requestAsync(data) {
        // console.log(data);
        return new Promise((resolve, reject) => {
            var reportAJAX_Error = (rspObj) => {
                console.error (`Request error: ${data}`);
                reject(`Request => Error ${data}  RES ${rspObj.status}!  ${rspObj.statusText}`);
            }

            var processJSON_Response = (rspObj) => {
                if (rspObj.status != 200 && rspObj.status != 304) {
                    reportAJAX_Error (rspObj);
                } else {
                    let resJSON = {};
                    try{
                        resJSON = JSON.parse(rspObj.responseText);
                    } catch(err) {
                        // ignore
                        console.log(err);
                    }
                    resolve(resJSON);
                }
            };
            GM_xmlhttpRequest ( {
                method:         "POST",
                url:            document.location.origin + "/!/MemberBet",
                headers: {
                    "Referer": document.location.href,
                    "Content-Type": "application/x-www-form-urlencoded"
                },
                data:           data,
                // responseType:   "json",
                onload:         processJSON_Response,
                onabort:        reportAJAX_Error,
                onerror:        reportAJAX_Error,
                ontimeout:      reportAJAX_Error
            });
        });
    }

        function ajaxAsync(method, url, data) {
         return new Promise((resolve, reject) => {
             $.ajax({
                 type: method,
                 url: url,
                 cache: false,
                 timeout: 1000 * 30,
                 dataType: 'json',
                 data: data,
                 success: function (msg) {
                     if (!msg || msg.error) {
                         reject(`Request ${url} => Error ${msg.error}`);
                     } else {
                         resolve(msg);
                     }
                 },
                 error: function () {
                     reject(`Fail to request ${url} with data ${data}`);
                 }
             });
         });
    }

    async function requestGameResult(gameDate) {
        return await ajaxAsync('get', '/!/GameListDate', {
            GameType: GameType,
            GameDate: gameDate,
            PageSize: 20,
            PageIndex: 0
        });
    }

    function parseResult(gameResult) {
        console.log(gameResult);
        if (!gameResult || !gameResult.List) {
            return null;
        }
        let res = [];
        gameResult.List.forEach(a => {
            if (a.Result) {
                res.push([a.Code, a.Result]);
            }
        });
        return res;
    }

    function resToMask(res) {
        return PLACE_HOLDERS.map(a => {
            let mask = 'XXXXX'.split('');
            for(let i = 0; i < 5; i++) {
                if (a[i] !== 'X') {
                    mask[i] = res[i];
                }
            }
            return mask.join('');
        });
    }

    async function bet(pools, amount) {
        let count = pools.length;
        pools = pools.map(a => `${a}%3D${amount}`);
        //const REQ_DATA = `SourceType=quick-comb&SourceData=%7B%22bet-type%22%3A%22d3%22%2C%22bet-count%22%3A${count}%2C%22dingwei-include%22%3A1%2C%22dingwei-1%22%3A%2212%22%2C%22dingwei-2%22%3A%221%22%2C%22dingwei-3%22%3A%221%22%2C%22hefeng-include%22%3A1%2C%22dan-include%22%3A1%2C%22shuang-include%22%3A1%7D&Game=${GameType}&Pools=${pools.join('%2C')}&Amount=${amount}`;
        const REQ_DATA = `SourceType=txt-import&SourceData=${count}+%E4%B8%AA%E5%8F%B7%E7%A0%81%EF%BC%88%E5%B8%A6%E9%87%91%E9%A2%9D%EF%BC%89&Game=${GameType}&Pools=${pools.join('%2C')}&Amount=`;
        console.log(REQ_DATA);
        return await requestAsync(REQ_DATA);
    }

    function addUI() {
        let divAll=document.createElement("div");
        divAll.setAttribute("style", "float:left;z-index:100000;position:absolute;background-color: #229ACB");
        let controlBtn = document.createElement("BUTTON");
        controlBtn.innerText = "隐藏";
        controlBtn.onclick = (event) => {
            if (event.target.innerText === "隐藏") {
                event.target.innerText = "打开";
                document.querySelector('#betAssitInfos').style.display = 'none';
            } else {
                event.target.innerText = "隐藏";
                document.querySelector('#betAssitInfos').style.display = 'block';
            }
        }
        divAll.appendChild(controlBtn);
        let divList=document.createElement("div");
        divList.setAttribute("id", "betAssitInfos");
        divAll.appendChild(divList);

        let div=document.createElement("div");
        div.setAttribute("style", "width:170px");
        let btn=document.createElement("BUTTON");
        btn.setAttribute("style", "width:160px");
        btn.setAttribute("id", "betBtn");
        div.appendChild(btn);
        /*
        let select = document.createElement("SELECT");
        select.setAttribute("id", "strategy");
        select.innerHTML = "<option value =0>不翻倍</option><option value =1>进七</option>";
        div.appendChild(select);
        */
        let amount = document.createElement("INPUT");
        amount.setAttribute("id", "betAmount");
        amount.setAttribute("style", "width:160px;Padding:0px");
        amount.setAttribute("placeholder", "金额");
        amount.setAttribute("type", "text");
        div.appendChild(amount);

        let takeProfit = document.createElement("INPUT");
        takeProfit.setAttribute("id", "takeProfit");
        takeProfit.setAttribute("style", "width:80px;Padding:0px");
        takeProfit.setAttribute("placeholder", "止盈");
        takeProfit.setAttribute("type", "text");
        div.appendChild(takeProfit);

        let stopLose = document.createElement("INPUT");
        stopLose.setAttribute("id", "stopLose");
        stopLose.setAttribute("style", "width:80px;Padding:0px");
        stopLose.setAttribute("placeholder", "止损");
        stopLose.setAttribute("type", "text");
        div.appendChild(stopLose);

        divList.appendChild(div);

        for(let i = 0; i < PLACE_HOLDERS.length; i++) {
            let div = document.createElement("DIV");
            for (let ci = 0; ci < 5; ci++) {
                let checkbox = document.createElement("INPUT");
                checkbox.type = "checkbox";
                checkbox.setAttribute("id", `checkbox${i}-${ci}`);
                checkbox.setAttribute("style", "width:19px");
                if (PLACE_HOLDERS[i][ci] !== 'X') {
                    checkbox.checked = true;
                    checkbox.disabled = true;
                }
                checkbox.onclick = (event) => {
                    for (let j = 0; j < 5; j++) {
                        let idx = (ci + 5 - j) % 5;
                        let cb = document.querySelector(`#checkbox${i}-${idx}`);
                        if (cb.disabled) {
                            cb.disabled = false;
                            cb.checked = false;
                            break;
                        }
                    }
                    event.target.disabled = true;

                    let text = '';
                    let curChar = 'a';
                    for (let j = 0; j < 5; j++) {
                        let cb = document.querySelector(`#checkbox${i}-${j}`);
                        if (cb.checked) {
                            text += curChar;
                            curChar = 'b';
                        } else {
                            text += 'X';
                        }
                    }
                    document.querySelector(`#text${i}`).innerText = text;
                }
                div.appendChild(checkbox);
            }
            let text = document.createElement("span");
            text.innerText = PLACE_HOLDERS[i];
            text.setAttribute("id", `text${i}`);
            text.setAttribute("style", "width:100px");
            div.appendChild(text);

            divList.appendChild(div);
        }
        let node = document.querySelector('#top');
        let parentNode = node.parentNode;
        parentNode.insertBefore(divAll, node);
    }

    async function main() {
        if (window !== top) {
            console.log("NOT THE TOP");
            return;
        }
        console.log("START...", new Date());
        if (window.location.pathname === "/") { // login
            let user = await GM.getTab();
            console.log("DEBUG ", user);
            if (!!user && !!user.name) {
                await wait(1000);
                document.querySelector('#login-id').value = user.name;
                await wait(500);
                document.querySelector('#password').value = user.password;
                await wait(500);
                document.querySelector('.btn-primary').click();
            } else {
                document.querySelector('.btn-primary').onclick = async () => {
                    user.name = document.querySelector('#login-id').value;
                    user.password = document.querySelector('#password').value;
                    await GM.saveTab(user);
                }
            }
            return;
        }
        if (window.location.pathname === "/agreement.html") {
            await wait(500);
            document.querySelector('#lnk-agree').click();
            return;
        }
        await waitResource(async () => {
            console.log(document.querySelector('#account'));
            return typeof ENV  !== "undefined" && !!ENV[GameType] && !!ENV[GameType].Resulted && !!document.querySelector('#branch-info');
        });

        addUI();
        while (true) {
            let tabObj = await GM.getTab();
            // console.log('tabObj: ', tabObj);
            if (tabObj.started) {
                if (tabObj.gameType !== GameType) {
                    document.querySelector(`#game-type-${tabObj.gameType}`).click();
                }
                let lenInfo = tabObj.betInfos ? tabObj.betInfos.map(a => a.length).join(',') : '';
                document.querySelector('#betBtn').innerText = `结束(${lenInfo})`;
                // document.querySelector("#strategy").selectedIndex = tabObj.selectedIndex;
                document.querySelector("#betAmount").value = tabObj.amount;
                document.querySelector("#takeProfit").value = tabObj.takeProfit || '';
                document.querySelector("#stopLose").value = tabObj.stopLose || '';
                if (tabObj.betPatterns) {
                    for (let i = 0; i < PLACE_HOLDERS.length; i++) {
                        if (tabObj.betPatterns[i]) {
                            PLACE_HOLDERS[i] = tabObj.betPatterns[i]; // change the pattern
                            for (let j = 0; j < 5; j++) {
                                let cb = document.querySelector(`#checkbox${i}-${j}`);
                                if (tabObj.betPatterns[i][j] === 'X') {
                                    cb.checked = false;
                                    cb.disabled = false;
                                } else {
                                    cb.checked = true;
                                    cb.disabled = true;
                                }
                            }
                        }
                    }
                }
                document.querySelector('#betBtn').onclick = async () => {
                    tabObj.started = false;
                    tabObj.betInfos = null;
                    await GM.saveTab(tabObj);
                    document.querySelector('#betBtn').innerText = "...";
                }
            } else {
                document.querySelector('#betBtn').innerText = "开始";
                document.querySelector('#betBtn').onclick = async () => {
                    tabObj.started = true;
                    // tabObj.selectedIndex = document.querySelector("#strategy").selectedIndex;
                    tabObj.selectedIndex = 0;
                    tabObj.amount = parseFloat(document.querySelector("#betAmount").value) || 0.1;
                    tabObj.amount = tabObj.amount.toFixed(1);
                    tabObj.takeProfit = parseFloat(document.querySelector("#takeProfit").value) || 0;
                    tabObj.stopLose = parseFloat(document.querySelector("#stopLose").value) || 0;
                    tabObj.betInfos = Array(LEN).fill([]);
                    tabObj.betPatterns = [];
                    for (let i = 0; i < PLACE_HOLDERS.length; i++) {
                        tabObj.betPatterns.push(document.querySelector(`#text${i}`).innerText);
                    }
                    tabObj.gameType = GameType;
                    tabObj.gameResult = [];
                    tabObj.lastGameID = 0;
                    console.log(tabObj);
                    await GM.saveTab(tabObj);
                    document.querySelector('#betBtn').innerText = "...";
                }
            }

            // 卡住了
            if (tabObj.started && new Date().getTime() / 1000 > (ENV[GameType].Current.End + 60)) {
                throw('卡住了');
            }
            if (!tabObj.started || new Date().getTime() / 1000 > ENV[GameType].Current.Close) {
                await wait(1000);
                continue;
            }

            // update game Result
            if (!tabObj.gameResult || tabObj.gameResult < 15 || ENV[GameType].Resulted[0][0] > tabObj.gameResult[0][0]) {
                let gameResult = parseResult(await requestGameResult(new Date().formatDate()));
                if (gameResult.length < 15) {
                    let preDateStr = new Date((new Date() - 1000 * 3600 * 24)).formatDate();
                    gameResult = gameResult.concat(parseResult(await requestGameResult(preDateStr)));
                    gameResult = gameResult.slice(0, 30);
                }
                tabObj.gameResult = gameResult;
                console.log("game result", gameResult);
                await GM.saveTab(tabObj);
            }
            // end update game result

            // 最后100 秒, 上次结果还没更新
            if (((tabObj.gameResult[0][0] + 1) % 10 !== ENV[GameType].Current.Code % 10) && new Date().getTime() / 1000  + 100 > ENV[GameType].Current.Close) {
                throw('开奖结果没更新');
            }

            // take profit or stop loss
            if ((tabObj.takeProfit > 0 && ENV.User.BalanceHF / 1000 >= tabObj.takeProfit)
                || (tabObj.stopLose > 0 && ENV.User.BalanceHF / 1000 < tabObj.stopLose)) {
                tabObj.started = false;
                tabObj.betInfos = null;
                await GM.saveTab(tabObj);
                document.querySelector('#betBtn').innerText = "...";
                console.log("Take profit OR Stop lose");
                continue;
            }
            // work
            if (tabObj.selectedIndex < POOLS.length) {
                for (let i = 0; i < LEN; i++) {
                    if (!!tabObj.betInfos[i] && tabObj.betInfos[i].length === 0) { // 初始下单
                        if (SIGNALS[tabObj.selectedIndex](i, tabObj.gameResult)) {
                            let pool = POOLS[tabObj.selectedIndex](i, tabObj.gameResult[0][1], tabObj.gameResult[1][1]);
                            // console.log(tabObj.gameResult[0][1], tabObj.gameResult[1][1], pool);
                            if (pool.length === 0) { // 空码
                                continue;
                            }
                            let betAmount = tabObj.amount * BET_AMOUNTS[tabObj.selectedIndex][0];
                            if (betAmount !== 0) {
                                let res = await bet(pool, betAmount);
                                if (res.Error && res.Error !== '额度不足' && res.Error !== '账号已停用下注') {
                                    throw(res);
                                }
                                console.log(res);
                            }
                            tabObj.betInfos[i] = [ENV[GameType].Current.Code];
                            await GM.saveTab(tabObj);
                            continue;
                        }
                    }

                    if (!!tabObj.betInfos[i] && tabObj.betInfos[i].length > 0) { // 加码
                        let resultedLen = tabObj.gameResult.length;// ENV[GameType].Resulted.length;
                        if (tabObj.betInfos[i][tabObj.betInfos[i].length - 1] < tabObj.gameResult[resultedLen - 1][0]) {  // N期不下,重新开始
                            tabObj.betInfos[i] = [];
                            await GM.saveTab(tabObj);
                            continue;
                        }
                        let resIdx = -1; // 防止跳期
                        for (let idx = resultedLen - 1; idx >= 0; idx--) {
                            if (tabObj.betInfos[i][tabObj.betInfos[i].length - 1] === tabObj.gameResult[idx][0]) {
                                resIdx = idx;
                                break;
                            }
                        }
                        if (resIdx !== -1) { // 开奖
                            let pool = POOLS[tabObj.selectedIndex](i, tabObj.gameResult[resIdx + 1][1], tabObj.gameResult[resIdx + 2][1]);
                            let betRes = tabObj.gameResult[resIdx][1];
                            let betMaskRes = resToMask(betRes)[i];
                            console.log("开奖结果:", i, betMaskRes, `resIdx:${resIdx}`);
                            //if (pool.includes(betMaskRes)) { // 中奖
                            //    console.log("中奖", i, betRes);
                            //    tabObj.betInfos[i] = [];
                            //    await GM.saveTab(tabObj);
                            // } else { // 不中奖
                            if (tabObj.betInfos[i].length < MAX_TIMES[tabObj.selectedIndex]) { // 加码
                                let betAmount = tabObj.amount * BET_AMOUNTS[tabObj.selectedIndex][tabObj.betInfos[i].length];
                                if (betAmount !== 0) {
                                    let pool = POOLS[tabObj.selectedIndex](i, tabObj.gameResult[0][1], tabObj.gameResult[1][1]);
                                    let res = await bet(pool, betAmount);
                                    if (res.Error && res.Error !== '额度不足' && res.Error !== '账号已停用下注') {
                                        throw(res);
                                    }
                                }
                                tabObj.betInfos[i].push(ENV[GameType].Current.Code);
                                await GM.saveTab(tabObj);
                            } else {
                                // tabObj.started = false;
                                tabObj.betInfos[i] = [];
                                await GM.saveTab(tabObj); // 超出,重新开始
                            }
                            // }
                        }
                    }
                }
            }
            // end work
            await wait(1000);
        }
    }
    main()
        .then(() => console.log("Main Done"))
        .catch((err) => {
        console.error(err, "Restart in 6 secs ...");
        setTimeout(() => location.reload(), 6 * 1000);
    });
})();