微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

是否有可能对这款 5*5 井字游戏进行暴力破解?

如何解决是否有可能对这款 5*5 井字游戏进行暴力破解?

所以我编造了这个游戏,但我找不到一个总是获胜的好策略。

它与original 3×3 Tic-Tac-Toe非常相似;但有变化。

所以你画了一个 5×5 的板。然后每个玩家轮流放置一个十字架和圆圈。然后我们计算“分数”。

This is a completed game 我画的。得分是通过计算每 3 次连续击球来计算的。因此,例如在第一行,交叉玩家获得 1 分。

然后,您可以水平、垂直和双向对角进行计数;对于每一行、每一列和对角线。

对于 4-in-a-row,您会得到 2 分,因为您可以将其视为 2 个不同的 3-in-row。同样,5 连胜将获得 3 分。

在示例游戏中,cross 获胜,因为它得到 9,而 circle 只得到 7。

我经常玩这个;但总是很难说出下一步该往哪里走。我注意到先开始给你一个显着的优势。为了弥补这一点,我将最先开始的玩家的分数降低了一个

是否有可能强制计算机学习每场比赛的最佳动作?

提前致谢!

旁注:如果有人可以将其编程为具有随机计算机移动的简单游戏,那就太好了。我刚刚开始编程,我很难弄清楚如何去做。

解决方法

蛮力

下面的代码片段将暴力破解玩家 X 和玩家 O 的所有最终游戏

有 33,542,145 个排列可供测试,其中约 5,000,000 个是有效的最终游戏。为了防止页面锁定,它将任务分成 250,000 个排列的组

X 的最佳得分为 16,O 的最佳得分为 14。运行代码段以查看示例最终游戏布局和其他详细信息。

我没有包括任何障碍。

这只能做最终游戏,因为它使用位域来保持高性能。然而,位域没有空板位置的空间。

可以通过反转每个游戏排列的位来优化同时玩两个玩家

const tag = (tag,props = {}) => Object.assign(document.createElement(tag),props);
const append = (par,...sibs) => sibs.reduce((p,sib) => (p.appendChild(sib),p),par);
const log = (el,data,add = true) => add ? append(el,tag("div",{textContent: data.toString()})) :  el.textContent = data.toString();
   
      

const scores = {
    [0b00111] : 1,[0b01110] : 1,[0b11100] : 1,[0b11101] : 1,[0b10111] : 1,[0b01111] : 2,[0b11110] : 2,[0b11111] : 3,};
const rotateMat = [
    0,5,10,15,20,1,6,11,16,21,2,7,12,17,22,3,8,13,18,23,4,9,14,19,24
];
const diagonMat = [
    2,-1,24,];
const diagonMatUp = [
    10,];

function transform(board,matrix) {
    var i = 25,b = 0;
    while (i--) { matrix[i] > -1 && (board & (1 << matrix[i])) && (b |= 1 << i) }
    return b;
}
function scoreLines(board) {
    var i = 5,score = 0,l = 0;
    while (i--) {  score += scores[(board >> (i * 5)) & 0b11111] ?? 0 }        
    return score;
}
function score(board) {
    return scoreLines(board) + 
        scoreLines(transform(board,rotateMat)) +
        scoreLines(transform(board,diagonMat)) +
        scoreLines(transform(board,diagonMatUp));
}
function isValidGame(board,side) {
    var c = 0,i = 25,bits = side + 1;
    while (i-- && c < bits) { (board & (1 << i)) && c++ }
    return c === side;
}
function showBoard(board,score,side) {
    var i = 5;
    log(games,"------------------------");
    log(games,"End game score: " + score + " player: " + (side===13 ? "X" : "O"));
    log(games,"Example end game");
    while (i--) { 
        const line = ((board >> (i * 5)) & 0b11111).toString(2).padStart(5,"0");
        const lined = side === 13 ? 
            line.replace(/1/g,"X").replace(/0/g,"O") :
            line.replace(/1/g,"O").replace(/0/g,"X");
         log(games,lined); 
    }    
}
function brute(side = 13) {
    function doSet(i) {
        var ii = 251357;
        while (i >= min && ii--) {
            if (isValidGame(i,side)) {
                gameCount ++;
                const s = score(i);
                if (s >= maxScore) {
                    if (s > maxScore) { 
                        bestEndGames.length = 0 
                        game = i;
                    }
                    maxScore = s;
                    bestEndGames.push(i);
                }
            }
            i--;
        }        
        if (i >= min) {
            setTimeout(doSet,i);
            log(progress,status + " is: "  + maxScore + " tested: " + ((max - min) - (i - min)) + " of " + (max - min) + " permutations",false);
        } else {
            log(games,status + " is: " + maxScore + " of " + gameCount + " end games");
            log(games,"Number of end games with best score: " + bestEndGames.length);           
            showBoard(game,maxScore,side);
            if (side === 13) { setTimeout(brute,1000,12) }
            else { log(progress,"Done",false) } 
        }
    }
    var game,gameCount = 0;
    var maxScore = 0;
    const bestEndGames = [];
    const status = "Best score player: " + (side===13 ? "X" : "O");
    const [min,max] = side === 13 ? [0b1111111111111,0b1111111111111000000000000] : [0b111111111111,0b1111111111110000000000000];
    doSet(max)
}
brute(13);
<div id="progress"></div>
<div id="games"></div>

要为游戏得分,下一个片段将这样做。有点黑客,在输入字段中输入游戏并会吐出分数。

const tag = (tag,side,asStr) {
    var c = 0,bits = side + 1;
    while (i-- && c < bits) { (
        (asStr[24-i] !== "-" &&  asStr[24-i] !== " ") && board & (1 << i)) && c++ 
    }
    return [c <= side,c];
}
function showBoard(board,asStr) {
    var i = 0;
    var j = 0;
    while (i < 5) { 
        const line = ((board >> ((4-i) * 5)) & 0b11111).toString(2).padStart(5,"0");
        const lined = line.replace(/1/g,"O");
        var str = "";
        j = 0;
        while (j < 5) {
            str += (asStr[i * 5 + j] !== "-" && asStr[i * 5 + j] !== " ") ? lined[j] : ".";
            j++;
        }
        log(games,str); 
        i++;
    }    
}
gameVal1.addEventListener("input",testGame);
gameVal2.addEventListener("input",testGame);
gameVal3.addEventListener("input",testGame);
gameVal4.addEventListener("input",testGame);
gameVal5.addEventListener("input",testGame);

function testGame() {
    var board = gameVal1.value.slice(0,5).padEnd(5,"-");
    board += gameVal2.value.slice(0,"-");
    board += gameVal3.value.slice(0,"-");
    board += gameVal4.value.slice(0,"-");
    board += gameVal5.value.slice(0,"-");
    board = board.replace(/[^OX\- ]/gi,"-");
    const X = eval("0B" + board.replace(/X/gi,"1").replace(/O|-| /gi,"0"));
    const O = eval("0B" + board.replace(/X|-| /gi,"0").replace(/O/gi,"1"));
    const [vx,movesX] = isValidGame(X,board);
    const [vo,movesY] = isValidGame(O,board);
    vx && log(resultX,"Player X score: " + score(X) + " moves: " + movesX,false);
    vo && log(resultO,"Player O score: " + score(O) + " moves: " + movesY,false);
    games.innerHTML = "";
    showBoard(X,board);
}
testGame()
input  {
   font-family: monospace;
   font-size: large;
}
.fixFont {
   font-family: monospace;
   font-size: large;
}
#games {
   position: absolute;
   top: 28px;
   left: 80px;
   border: 1px solid black;
   padding: 0px 3px;
   letter-spacing: 3px;
}
#resultX {
   position: absolute;
   top: 40px;
   left: 160px;
}
#resultO {
   position: absolute;
   top: 60px;
   left: 160px;
}
<div class="fixFont">
Enter "x" "x" "O" or "o". Empty slots "-" or space<br>
<input type="text" id="gameVal1" value="XXXXX" size="5"><br>
<input type="text" id="gameVal2" value="XXXXO" size="5"><br>
<input type="text" id="gameVal3" value="XXXXO" size="5"><br>
<input type="text" id="gameVal4" value="OOOOO" size="5"><br>
<input type="text" id="gameVal5" value="OOOOO" size="5"><br>
<div id="resultX"></div>
<div id="resultO"></div>
<div id="games"></div>
</div>

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。