JS解出最近比較火的刑偵推理題

王玉略發表於2018-03-14

最近網上出了一個比較火的刑偵推理題,王二比較感興趣,於是抽空做了做。

一、推理題如下

Alt text

二、遇到的問題

剛開始,王二寫下了如下程式碼:

<script>
    var arr = new Array(10).fill("A");
    
    recursion(); 

    function a1 (){
        return true;
    }
    function a2 (){
        switch(arr[1])
        {
        case "A":
            return arr[4] === "C"
        case "B":
            return arr[4] === "D"
        case "C":
            return arr[4] === "A"
        case "D":
            return arr[4] === "B"
        default:
            return false;
        }
    }
    function a3 (){
        switch(arr[2])
        {
        case "A":
            return arr[5] === arr[1] && arr[5] === arr[3]
        case "B":
            return arr[2] === arr[1] && arr[2] === arr[3]
        case "C":
            return arr[5] === arr[2] && arr[5] === arr[3]
        case "D":
            return arr[5] === arr[1] && arr[5] === arr[2]
        default:
            return false;
        }
    }
    function a4 (){
        var f1 = arr[0] === arr[4] ,
            f2 = arr[1] === arr[6] ,
            f3 = arr[0] === arr[8] ,
            f4 = arr[5] === arr[9] ;
        switch(arr[3])
        {
        case "A":
            return f1 && !f2 && !f3 && !f4
        case "B":
            return !f1 && f2 && !f3 && !f4
        case "C":
            return !f1 && !f2 && f3 && !f4
        case "D":
            return !f1 && !f2 && !f3 && f4
        default:
            return false;
        }
    }
    function a5 (){
        switch(arr[4])
        {
        case "A":
            return arr[7] === "A"
        case "B":
            return arr[3] === "B"
        case "C":
            return arr[8] === "C"
        case "D":
            return arr[6] === "D"
        default:
            return false;
        }
    }
    function a6 (){
        var f1 = arr[7] === arr[1] && arr[7] === arr[3] ,
            f2 = arr[7] === arr[0] && arr[7] === arr[5] ,
            f3 = arr[7] === arr[2] && arr[7] === arr[9] ,
            f4 = arr[7] === arr[4] && arr[7] === arr[8] ;
        switch(arr[5])
        {
        case "A":
            return f1 && !f2 && !f3 && !f4
        case "B":
            return !f1 && f2 && !f3 && !f4
        case "C":
            return !f1 && !f2 && f3 && !f4
        case "D":
            return !f1 && !f2 && !f3 && f4
        default:
            return false;
        }
    }
    function a7 (){
        var c1 = arr.filter((i)=>{return i === "A"}).length ,
            c2 = arr.filter((i)=>{return i === "B"}).length ,
            c3 = arr.filter((i)=>{return i === "C"}).length ,
            c4 = arr.filter((i)=>{return i === "D"}).length ;
        switch(arr[6])
        {
        case "A":
            return Math.min(c1,c2,c3,c4) === c3
        case "B":
            return Math.min(c1,c2,c3,c4) === c2
        case "C":
            return Math.min(c1,c2,c3,c4) === c1
        case "D":
            return Math.min(c1,c2,c3,c4) === c4
        default:
            return false;
        }
    }
    function a8 (){
        switch(arr[7])
        {
        case "A":
            return Math.abs(arr[0].charCodeAt(0) - arr[6].charCodeAt(0))>=2
        case "B":
            return Math.abs(arr[0].charCodeAt(0) - arr[4].charCodeAt(0))>=2
        case "C":
            return Math.abs(arr[0].charCodeAt(0) - arr[1].charCodeAt(0))>=2
        case "D":
            return Math.abs(arr[0].charCodeAt(0) - arr[9].charCodeAt(0))>=2
        default:
            return false;
        }
    }
    function a9 (){
        var flag = arr[0] === arr[5],
            f1 = (arr[4] === arr[5]) === !flag ,
            f2 = (arr[4] === arr[9]) === !flag ,
            f3 = (arr[4] === arr[1]) === !flag ,
            f4 = (arr[4] === arr[8]) === !flag ;
        switch(arr[8])
        {
        case "A":
            return f1 && !f2 && !f3 && !f4
        case "B":
            return !f1 && f2 && !f3 && !f4
        case "C":
            return !f1 && !f2 && f3 && !f4
        case "D":
            return !f1 && !f2 && !f3 && f4
        default:
            return false;
        }
    }
    function a10 (){
        var c1 = arr.filter((i)=>{return i === "A"}).length ,
            c2 = arr.filter((i)=>{return i === "B"}).length ,
            c3 = arr.filter((i)=>{return i === "C"}).length ,
            c4 = arr.filter((i)=>{return i === "D"}).length ;
        switch(arr[9])
        {
        case "A":
            return Math.max(c1,c2,c3,c4) - Math.min(c1,c2,c3,c4) === 3
        case "B":
            return Math.max(c1,c2,c3,c4) - Math.min(c1,c2,c3,c4) === 2
        case "C":
            return Math.max(c1,c2,c3,c4) - Math.min(c1,c2,c3,c4) === 4
        case "D":
            return Math.max(c1,c2,c3,c4) - Math.min(c1,c2,c3,c4) === 1
        default:
            return false;
        }
    }

    function vali () {
        return a1() && a2() && a3() && a4() && a5() && a6() && a7() && a8() && a9() && a10() ;
    }
    
    //遞迴遍歷arr的所有排列組合
    function recursion (){
        if(vali()){
            console.log(arr);
        }
        for(var x=0 ; x<arr.length ; x++){
            switch(arr[x])
            {
            case "A":
                arr[x] = "B" ;
                recursion () ;
                return ;
            case "B":
                arr[x] = "C" 
                recursion () ;
                return ;
            case "C":
                arr[x] = "D" ;
                recursion () ;
                return ;
            case "D":
                if(x===9) return ;
                arr[x] = "A" ;
                continue ;
            default:
                return ;
            }
        }
    }
</script>
複製程式碼

以上的程式碼邏輯上沒有問題,但是還是報了個錯——棧溢位

Alt text

雖然王二也試著用尾遞迴優化來嘗試解決問題,但依然報錯

三、解決方法

後來王二躺床上又尋思怎麼才能解決這噁心的報錯,然後想到try catch 可以捕獲錯誤,或許我們能遞迴呼叫 try catch 來解決這個問題。按照這個思路王二又在程式碼片段中新增了如下的程式碼:

var flag = true ;

function run () {
    try {
        if(flag){
            flag = false ;
            recursion() ;
        }
    } catch (err) {
        flag = true;
        run();
    }
}
複製程式碼

意思是如果棧溢位報錯,則在 catch 再次呼叫 run() 方法 ,直到它不報錯為止,不報錯也就意味著arr陣列所有排列組合的可能性都被遍歷完了。

執行後,還真他孃的起作用了。

完整的程式碼片段如下所示(可以拷貝下來嘗試執行):

<script>
    var arr = new Array(10).fill("A");
    var flag = true ;

    run(); // ["B", "C", "A", "C", "A", "C", "D", "A", "B", "A"]

    function run () {
        try {
            if(flag){
                flag = false ;
                recursion() ;
            }
        } catch (err) {
            flag = true;
            run();
        }
    }
    
    function a1 (){
        return true;
    }
    function a2 (){
        switch(arr[1])
        {
        case "A":
            return arr[4] === "C"
        case "B":
            return arr[4] === "D"
        case "C":
            return arr[4] === "A"
        case "D":
            return arr[4] === "B"
        default:
            return false;
        }
    }
    function a3 (){
        switch(arr[2])
        {
        case "A":
            return arr[5] === arr[1] && arr[5] === arr[3]
        case "B":
            return arr[2] === arr[1] && arr[2] === arr[3]
        case "C":
            return arr[5] === arr[2] && arr[5] === arr[3]
        case "D":
            return arr[5] === arr[1] && arr[5] === arr[2]
        default:
            return false;
        }
    }
    function a4 (){
        var f1 = arr[0] === arr[4] ,
            f2 = arr[1] === arr[6] ,
            f3 = arr[0] === arr[8] ,
            f4 = arr[5] === arr[9] ;
        switch(arr[3])
        {
        case "A":
            return f1 && !f2 && !f3 && !f4
        case "B":
            return !f1 && f2 && !f3 && !f4
        case "C":
            return !f1 && !f2 && f3 && !f4
        case "D":
            return !f1 && !f2 && !f3 && f4
        default:
            return false;
        }
    }
    function a5 (){
        switch(arr[4])
        {
        case "A":
            return arr[7] === "A"
        case "B":
            return arr[3] === "B"
        case "C":
            return arr[8] === "C"
        case "D":
            return arr[6] === "D"
        default:
            return false;
        }
    }
    function a6 (){
        var f1 = arr[7] === arr[1] && arr[7] === arr[3] ,
            f2 = arr[7] === arr[0] && arr[7] === arr[5] ,
            f3 = arr[7] === arr[2] && arr[7] === arr[9] ,
            f4 = arr[7] === arr[4] && arr[7] === arr[8] ;
        switch(arr[5])
        {
        case "A":
            return f1 && !f2 && !f3 && !f4
        case "B":
            return !f1 && f2 && !f3 && !f4
        case "C":
            return !f1 && !f2 && f3 && !f4
        case "D":
            return !f1 && !f2 && !f3 && f4
        default:
            return false;
        }
    }
    function a7 (){
        var c1 = arr.filter((i)=>{return i === "A"}).length ,
            c2 = arr.filter((i)=>{return i === "B"}).length ,
            c3 = arr.filter((i)=>{return i === "C"}).length ,
            c4 = arr.filter((i)=>{return i === "D"}).length ;
        switch(arr[6])
        {
        case "A":
            return Math.min(c1,c2,c3,c4) === c3
        case "B":
            return Math.min(c1,c2,c3,c4) === c2
        case "C":
            return Math.min(c1,c2,c3,c4) === c1
        case "D":
            return Math.min(c1,c2,c3,c4) === c4
        default:
            return false;
        }
    }
    function a8 (){
        switch(arr[7])
        {
        case "A":
            return Math.abs(arr[0].charCodeAt(0) - arr[6].charCodeAt(0))>=2
        case "B":
            return Math.abs(arr[0].charCodeAt(0) - arr[4].charCodeAt(0))>=2
        case "C":
            return Math.abs(arr[0].charCodeAt(0) - arr[1].charCodeAt(0))>=2
        case "D":
            return Math.abs(arr[0].charCodeAt(0) - arr[9].charCodeAt(0))>=2
        default:
            return false;
        }
    }
    function a9 (){
        var flag = arr[0] === arr[5],
            f1 = (arr[4] === arr[5]) === !flag ,
            f2 = (arr[4] === arr[9]) === !flag ,
            f3 = (arr[4] === arr[1]) === !flag ,
            f4 = (arr[4] === arr[8]) === !flag ;
        switch(arr[8])
        {
        case "A":
            return f1 && !f2 && !f3 && !f4
        case "B":
            return !f1 && f2 && !f3 && !f4
        case "C":
            return !f1 && !f2 && f3 && !f4
        case "D":
            return !f1 && !f2 && !f3 && f4
        default:
            return false;
        }
    }
    function a10 (){
        var c1 = arr.filter((i)=>{return i === "A"}).length ,
            c2 = arr.filter((i)=>{return i === "B"}).length ,
            c3 = arr.filter((i)=>{return i === "C"}).length ,
            c4 = arr.filter((i)=>{return i === "D"}).length ;
        switch(arr[9])
        {
        case "A":
            return Math.max(c1,c2,c3,c4) - Math.min(c1,c2,c3,c4) === 3
        case "B":
            return Math.max(c1,c2,c3,c4) - Math.min(c1,c2,c3,c4) === 2
        case "C":
            return Math.max(c1,c2,c3,c4) - Math.min(c1,c2,c3,c4) === 4
        case "D":
            return Math.max(c1,c2,c3,c4) - Math.min(c1,c2,c3,c4) === 1
        default:
            return false;
        }
    }

    function vali () {
        return a1() && a2() && a3() && a4() && a5() && a6() && a7() && a8() && a9() && a10() ;
    }
    
    //遞迴遍歷arr的所有排列組合
    function recursion (){
        if(vali()){
            console.log(arr);
        }
        for(var x=0 ; x<arr.length ; x++){
            switch(arr[x])
            {
            case "A":
                arr[x] = "B" ;
                recursion () ;
                return ;
            case "B":
                arr[x] = "C" 
                recursion () ;
                return ;
            case "C":
                arr[x] = "D" ;
                recursion () ;
                return ;
            case "D":
                if(x===9) return ;
                arr[x] = "A" ;
                continue ;
            default:
                return ;
            }
        }
    }
</script>
複製程式碼

這樣的寫話棧溢位的問題似乎就比較完美的被解決了。


2018年04月27日補充:

其實那天晚上王二腦子進水了,其實這裡沒有必要用到遞迴呼叫,現修改程式碼如下:

var arr = new Array(10).fill("A");

while(recursion(arr)!=='done'){
    vali() && console.log(arr)
}

function a1 (){
    return true;
}
function a2 (){
    switch(arr[1])
    {
    case "A":
        return arr[4] === "C"
    case "B":
        return arr[4] === "D"
    case "C":
        return arr[4] === "A"
    case "D":
        return arr[4] === "B"
    default:
        return false;
    }
}
function a3 (){
    switch(arr[2])
    {
    case "A":
        return arr[5] === arr[1] && arr[5] === arr[3]
    case "B":
        return arr[2] === arr[1] && arr[2] === arr[3]
    case "C":
        return arr[5] === arr[2] && arr[5] === arr[3]
    case "D":
        return arr[5] === arr[1] && arr[5] === arr[2]
    default:
        return false;
    }
}
function a4 (){
    var f1 = arr[0] === arr[4] ,
        f2 = arr[1] === arr[6] ,
        f3 = arr[0] === arr[8] ,
        f4 = arr[5] === arr[9] ;
    switch(arr[3])
    {
    case "A":
        return f1 && !f2 && !f3 && !f4
    case "B":
        return !f1 && f2 && !f3 && !f4
    case "C":
        return !f1 && !f2 && f3 && !f4
    case "D":
        return !f1 && !f2 && !f3 && f4
    default:
        return false;
    }
}
function a5 (){
    switch(arr[4])
    {
    case "A":
        return arr[7] === "A"
    case "B":
        return arr[3] === "B"
    case "C":
        return arr[8] === "C"
    case "D":
        return arr[6] === "D"
    default:
        return false;
    }
}
function a6 (){
    var f1 = arr[7] === arr[1] && arr[7] === arr[3] ,
        f2 = arr[7] === arr[0] && arr[7] === arr[5] ,
        f3 = arr[7] === arr[2] && arr[7] === arr[9] ,
        f4 = arr[7] === arr[4] && arr[7] === arr[8] ;
    switch(arr[5])
    {
    case "A":
        return f1 && !f2 && !f3 && !f4
    case "B":
        return !f1 && f2 && !f3 && !f4
    case "C":
        return !f1 && !f2 && f3 && !f4
    case "D":
        return !f1 && !f2 && !f3 && f4
    default:
        return false;
    }
}
function a7 (){
    var c1 = arr.filter((i)=>{return i === "A"}).length ,
        c2 = arr.filter((i)=>{return i === "B"}).length ,
        c3 = arr.filter((i)=>{return i === "C"}).length ,
        c4 = arr.filter((i)=>{return i === "D"}).length ;
    switch(arr[6])
    {
    case "A":
        return Math.min(c1,c2,c3,c4) === c3
    case "B":
        return Math.min(c1,c2,c3,c4) === c2
    case "C":
        return Math.min(c1,c2,c3,c4) === c1
    case "D":
        return Math.min(c1,c2,c3,c4) === c4
    default:
        return false;
    }
}
function a8 (){
    switch(arr[7])
    {
    case "A":
        return Math.abs(arr[0].charCodeAt(0) - arr[6].charCodeAt(0))>=2
    case "B":
        return Math.abs(arr[0].charCodeAt(0) - arr[4].charCodeAt(0))>=2
    case "C":
        return Math.abs(arr[0].charCodeAt(0) - arr[1].charCodeAt(0))>=2
    case "D":
        return Math.abs(arr[0].charCodeAt(0) - arr[9].charCodeAt(0))>=2
    default:
        return false;
    }
}
function a9 (){
    var flag = arr[0] === arr[5],
        f1 = (arr[4] === arr[5]) === !flag ,
        f2 = (arr[4] === arr[9]) === !flag ,
        f3 = (arr[4] === arr[1]) === !flag ,
        f4 = (arr[4] === arr[8]) === !flag ;
    switch(arr[8])
    {
    case "A":
        return f1 && !f2 && !f3 && !f4
    case "B":
        return !f1 && f2 && !f3 && !f4
    case "C":
        return !f1 && !f2 && f3 && !f4
    case "D":
        return !f1 && !f2 && !f3 && f4
    default:
        return false;
    }
}
function a10 (){
    var c1 = arr.filter((i)=>{return i === "A"}).length ,
        c2 = arr.filter((i)=>{return i === "B"}).length ,
        c3 = arr.filter((i)=>{return i === "C"}).length ,
        c4 = arr.filter((i)=>{return i === "D"}).length ;
    switch(arr[9])
    {
    case "A":
        return Math.max(c1,c2,c3,c4) - Math.min(c1,c2,c3,c4) === 3
    case "B":
        return Math.max(c1,c2,c3,c4) - Math.min(c1,c2,c3,c4) === 2
    case "C":
        return Math.max(c1,c2,c3,c4) - Math.min(c1,c2,c3,c4) === 4
    case "D":
        return Math.max(c1,c2,c3,c4) - Math.min(c1,c2,c3,c4) === 1
    default:
        return false;
    }
}

function vali () {
    return a1() && a2() && a3() && a4() && a5() && a6() && a7() && a8() && a9() && a10() ;
}


function recursion(arr){
    for(var x=0 ; x<arr.length ; x++){
        switch(arr[x])
        {
        case "A":
            arr[x] = "B" ;
            return arr;
        case "B":
            arr[x] = "C" 
            return arr;
        case "C":
            arr[x] = "D" ;
            return arr;
        case "D":
            if(x===9) return 'done';
            arr[x] = "A" ;
            continue ;
        default:
            return 'error';
        }
    }
}
複製程式碼

如此簡單的問題王二那天想的那麼複雜,也是醉了。

原文地址:王玉略的個人網站

相關文章