[譯]手把手教你創(chuàng)建國際象棋 AI

原文鏈接:A step-by-step guide to building a simple chess AI

我們先來了解一下三妈,在我們創(chuàng)建一個簡單的國際象棋 AI 過程中所會接觸到的一些基本概念:

  • 棋子的移動
  • 繪制棋盤
  • Minimax(極小化極大算法)
  • Alpha-beta 剪枝

我們將一步一步將這些加入最終的算法中,并分別展示它們對算法所產(chǎn)生的影響莫绣。

你可以在 Github 上查看最終版本畴蒲。

譯者試了下最終版本,一不小心就被吊打了...??

第一步:棋子的移動和繪制棋盤

這里我們使用 chess.jschessboard.js 分別來控制棋子的移動和繪制棋盤对室。chess.js 庫實現(xiàn)了所有棋子的移動規(guī)則模燥,基于此我們可以根據(jù)棋局狀態(tài)得到棋子所有可能的移動。

根據(jù)輸入的棋盤狀態(tài)生成所有可能的棋子移動
根據(jù)輸入的棋盤狀態(tài)生成所有可能的棋子移動

有了以上兩個類庫掩宜,我們就能將精力放在最有趣的事上——創(chuàng)建一個能夠找到最佳移動的 AI蔫骂。

接下來就開始創(chuàng)建這樣一個 AI,我們先創(chuàng)建一個方法牺汤,它會在所有合法的移動中隨機選取一個辽旋。

var calculateBestMove =function(game) {
    //generate all the moves for a given position
    var newGameMoves = game.ugly_moves();
    return newGameMoves[Math.floor(Math.random() * newGameMoves.length)];
};

盡管,這個 AI 像一個剛懂規(guī)則的新手檐迟,但是补胚,我們已經(jīng)可以和它下棋了,這是一個好的開始追迟。

隨機移動溶其,[點擊試玩](https://jsfiddle.net/lhartikk/m14epfwb/4)
隨機移動,[點擊試玩](https://jsfiddle.net/lhartikk/m14epfwb/4)

第二步:棋盤狀態(tài)評估

現(xiàn)在敦间,我們試著計算在棋局某一狀態(tài)下哪邊更具優(yōu)勢瓶逃,最簡單的方法就是根據(jù)下表來統(tǒng)計棋局剩余棋子權(quán)重束铭。

棋子對應(yīng)權(quán)重表
棋子對應(yīng)權(quán)重表

根據(jù)這個方法,我們就能讓我們的 AI 選擇在棋局某一狀態(tài)下使棋局權(quán)重最高的移動了厢绝。

var calculateBestMove = function (game) {

    var newGameMoves = game.ugly_moves();
    var bestMove = null;
    //use any negative large number
    var bestValue = -9999;

    for (var i = 0; i < newGameMoves.length; i++) {
        var newGameMove = newGameMoves[i];
        game.ugly_move(newGameMove);

        //take the negative as AI plays as black
        var boardValue = -evaluateBoard(game.board())
        game.undo();
        if (boardValue > bestValue) {
            bestValue = boardValue;
            bestMove = newGameMove
        }
    }

    return bestMove;

};

加入了計算權(quán)重后契沫,我們的 AI 就會盡可能地去吃對方的棋子。

盡可能地吃子代芜,[點擊試玩](https://jsfiddle.net/lhartikk/m5q6fgtb/1/)
盡可能地吃子埠褪,[點擊試玩](https://jsfiddle.net/lhartikk/m5q6fgtb/1/)

第三步:使用極小化極大算法來探索樹

下一步,我們使用 極小化極大算法(Minimax) 來使我們的 AI 能從探索樹中選出最優(yōu)移動挤庇。

首先钞速,我們先根據(jù)給定深度遞歸構(gòu)建棋子所有可能移動的樹,并用上一節(jié)的方法來計算所有子節(jié)點的權(quán)重

然后嫡秕,依據(jù)不同的行棋顏色渴语,父節(jié)點取子節(jié)點的最大或最小值,若白子則取子節(jié)點的最大值返回給父節(jié)點昆咽,反之返回最小值驾凶。

深度為 2 的情況下,極小化極大算法圖解
深度為 2 的情況下掷酗,極小化極大算法圖解
var minimax = function (depth, game, isMaximisingPlayer) {
    if (depth === 0) {
        return -evaluateBoard(game.board());
    }
    var newGameMoves = game.ugly_moves();
    if (isMaximisingPlayer) {
        var bestMove = -9999;
        for (var i = 0; i < newGameMoves.length; i++) {
            game.ugly_move(newGameMoves[i]);
            bestMove = Math.max(bestMove, minimax(depth - 1, game, !isMaximisingPlayer));
            game.undo();
        }
        return bestMove;
    } else {
        var bestMove = 9999;
        for (var i = 0; i < newGameMoves.length; i++) {
            game.ugly_move(newGameMoves[i]);
            bestMove = Math.min(bestMove, minimax(depth - 1, game, !isMaximisingPlayer));
            game.undo();
        }
        return bestMove;
    }
};

加入了極小化極大算法之后调违,我們的 AI 已經(jīng)不再是任人宰割了。

加入了極小化極大算法泻轰,[點擊試玩](https://jsfiddle.net/lhartikk/m5q6fgtb/1/)
加入了極小化極大算法技肩,[點擊試玩](https://jsfiddle.net/lhartikk/m5q6fgtb/1/)

極小化極大算法很大程度上取決于我們能夠探索深度混巧,下一步我們就來優(yōu)化它叙赚。

第四步:Alpha-beta 剪枝

Alpha-beta 剪枝 是對極小化極大算法的一種優(yōu)化,用于減少搜索樹中需要探索的節(jié)點數(shù)插勤。這樣在同樣的資源條件下泳挥,就增加了探索樹的搜索深度然痊。

當(dāng)探索路徑的結(jié)果比之前探索的更糟時,Alpha-beta 剪枝就不再搜索該子樹屉符。它并不影響極小化極大算法的計算結(jié)果剧浸,而是加快極小化極大算法運算速度。無論何種情況筑煮,Alpha-beta 剪枝總是能優(yōu)化計算效率辛蚊,即使,我們最初探索的就是最優(yōu)解真仲。

alpha-beta 剪枝用于極小化極大算法
alpha-beta 剪枝用于極小化極大算法

如下圖所示袋马,通過 alpha-beta 剪枝,我們能顯著減少極小化極大算法的計算次數(shù)秸应。

深度為 4 時虑凛,使用或不使用 alpha-beta 剪枝時的計算次數(shù)
深度為 4 時碑宴,使用或不使用 alpha-beta 剪枝時的計算次數(shù)
var minimax = function (depth, game, alpha, beta, isMaximisingPlayer) {
    positionCount++;
    if (depth === 0) {
        return -evaluateBoard(game.board());
    }

    var newGameMoves = game.ugly_moves();

    if (isMaximisingPlayer) {
        var bestMove = -9999;
        for (var i = 0; i < newGameMoves.length; i++) {
            game.ugly_move(newGameMoves[i]);
            bestMove = Math.max(bestMove, minimax(depth - 1, game, alpha, beta, !isMaximisingPlayer));
            game.undo();
            alpha = Math.max(alpha, bestMove);
            if (beta <= alpha) {
                return bestMove;
            }
        }
        return bestMove;
    } else {
        var bestMove = 9999;
        for (var i = 0; i < newGameMoves.length; i++) {
            game.ugly_move(newGameMoves[i]);
            bestMove = Math.min(bestMove, minimax(depth - 1, game, alpha, beta, !isMaximisingPlayer));
            game.undo();
            beta = Math.min(beta, bestMove);
            if (beta <= alpha) {
                return bestMove;
            }
        }
        return bestMove;
    }
};

第五步:升級計算權(quán)重方法

最初計算權(quán)重的方法相當(dāng)簡單就是通過計算棋盤上棋子所對應(yīng)的權(quán)重,單憑這一點無法判斷棋的局勢桑谍。為了改善這一點延柠,我們需要將棋子在棋盤中的位置因素計算在內(nèi)。比如锣披,騎士在棋盤中間就比在棋盤邊緣位置更優(yōu)贞间,這樣它可以有更多的選擇。

這里我們在 chess-programming-wiki 所提供的表格的基礎(chǔ)上稍作修改已適應(yīng)我們的程序雹仿。

棋子位置所對應(yīng)的權(quán)重表
棋子位置所對應(yīng)的權(quán)重表

這樣我們的 AI 就已經(jīng)像模像樣了增热,至少從業(yè)余玩家的角度來說。

優(yōu)化后胧辽,[點擊試玩](https://jsfiddle.net/lhartikk/m5q6fgtb/1/)
優(yōu)化后峻仇,[點擊試玩](https://jsfiddle.net/lhartikk/m5q6fgtb/1/)

結(jié)語

總的來說,我們所創(chuàng)造的這個簡單的 AI 不會犯一些愚蠢的錯誤邑商,但依舊缺乏大局觀摄咆。

通過以上我介紹的方法,已經(jīng)能夠使我們的 AI 進(jìn)行基本的對戰(zhàn)人断。最終 AI 部分的代碼(不包括移動棋子)不足 200 行吭从,這意味著它實現(xiàn)來非常簡單。你可以在 Github 上查看最終版本恶迈。

我們還可以繼續(xù)優(yōu)化我們的 AI影锈,比如:

如果你對此感興趣枣抱,你可以到 chess programming wiki 中發(fā)現(xiàn)更多內(nèi)容熔吗。

感謝閱讀。

更多文章歡迎訪問譯者博客佳晶,已升級為 PWA桅狠,支持離線訪問、訂閱和添加至桌面轿秧。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末中跌,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子菇篡,更是在濱河造成了極大的恐慌漩符,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,888評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件驱还,死亡現(xiàn)場離奇詭異嗜暴,居然都是意外死亡凸克,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,677評論 3 399
  • 文/潘曉璐 我一進(jìn)店門闷沥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來萎战,“玉大人,你說我怎么就攤上這事舆逃÷煳” “怎么了?”我有些...
    開封第一講書人閱讀 168,386評論 0 360
  • 文/不壞的土叔 我叫張陵路狮,是天一觀的道長虫啥。 經(jīng)常有香客問我,道長览祖,這世上最難降的妖魔是什么孝鹊? 我笑而不...
    開封第一講書人閱讀 59,726評論 1 297
  • 正文 為了忘掉前任,我火速辦了婚禮展蒂,結(jié)果婚禮上又活,老公的妹妹穿的比我還像新娘。我一直安慰自己锰悼,他們只是感情好柳骄,可當(dāng)我...
    茶點故事閱讀 68,729評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著箕般,像睡著了一般耐薯。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上丝里,一...
    開封第一講書人閱讀 52,337評論 1 310
  • 那天曲初,我揣著相機與錄音,去河邊找鬼杯聚。 笑死臼婆,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的幌绍。 我是一名探鬼主播颁褂,決...
    沈念sama閱讀 40,902評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼傀广!你這毒婦竟也來了颁独?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,807評論 0 276
  • 序言:老撾萬榮一對情侶失蹤伪冰,失蹤者是張志新(化名)和其女友劉穎誓酒,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體糜值,經(jīng)...
    沈念sama閱讀 46,349評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡丰捷,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,439評論 3 340
  • 正文 我和宋清朗相戀三年坯墨,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片病往。...
    茶點故事閱讀 40,567評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡捣染,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出停巷,到底是詐尸還是另有隱情耍攘,我是刑警寧澤,帶...
    沈念sama閱讀 36,242評論 5 350
  • 正文 年R本政府宣布畔勤,位于F島的核電站蕾各,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏庆揪。R本人自食惡果不足惜式曲,卻給世界環(huán)境...
    茶點故事閱讀 41,933評論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望缸榛。 院中可真熱鬧吝羞,春花似錦、人聲如沸内颗。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,420評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽均澳。三九已至恨溜,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間找前,已是汗流浹背糟袁。 一陣腳步聲響...
    開封第一講書人閱讀 33,531評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留躺盛,地道東北人系吭。 一個月前我還...
    沈念sama閱讀 48,995評論 3 377
  • 正文 我出身青樓,卻偏偏與公主長得像颗品,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子沃缘,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,585評論 2 359

推薦閱讀更多精彩內(nèi)容

  • 棋類游戲?qū)?zhàn)的實現(xiàn) 六洲棋 五子棋 AI對戰(zhàn) 藍(lán)牙對戰(zhàn) 在線對戰(zhàn) 六洲棋 六洲棋躯枢,又稱:泥棋、插方槐臀、來馬锄蹂、五福棋,...
    天機否閱讀 1,230評論 0 9
  • 簡評:本文通過實際范例教大家如何實現(xiàn)一個低配版國際象棋 AI水慨。 文中的基本概念如下得糜,先自行搜索以方便理解: mov...
    極小光閱讀 1,340評論 0 2
  • 五子棋 五子棋五子棋是比較流行的棋類游戲了敬扛,玩法簡單,基本上人人會玩朝抖,在此就不介紹游戲規(guī)則了啥箭。下面使用 swift...
    天機否閱讀 20,517評論 3 29
  • 代碼提取 上面我們通過實例講解了肉眼識別Uri更部分的方式,但在代碼中又要怎樣提取呢治宣。下面就看看Uri中提取各部分...
    LandBlink閱讀 2,100評論 0 0
  • 2017年10月14號急侥,星期六,天氣:晴 星期六的早上想偷個懶侮邀,沒找到二寶小鑫還想著上個星期姥爺答應(yīng)來接她去坏怪,這家...
    于浩晨閱讀 467評論 0 3