蘋果棋的人工智慧

2021-02-28 神奇海螺萬歲

我做了三個難度

初級

初級難度就是隨便下,上一篇,有一個函數 getLegal 用來獲取所有可以落子的坐標

初級難度,cpu就是自己隨機選擇一個

const arr = engine.getLegal();
const [ col, row ] = arr[parseInt(Math.random() * arr.length)];
const data = { col, row, color: _this.getColor() };
const e = { type: AIPlayer.EVENT.MOVE, data };
_this.dispatchEvent(e);

中級

中級我們按照有限度做了策略

Roxanne 策略 詳見 《Analysis of Monte Carlo Techniques in Othello》
提出者:Canosa, R. Roxanne canosa homepage. https://www.cs.rit.edu/~rlc/

我們把8*8的所有位置分了一下優先級

我們畫個圖清楚的表現一下

那麼根據Roxanne策略寫一個類,就是讓cpu按照優先級落子,這就是中級難度

class Roxanne {
constructor() {
this._table = [ // 優先級
[ [0, 0], [0, 7], [7, 0], [7, 7] ],
[ [2, 2], [2, 5], [5, 2], [5, 5] ],
[ [3, 2], [3, 5], [4, 2], [4, 5], [2, 3], [2, 4], [5, 3], [5, 4] ],
[ [2, 0], [2, 7], [5, 0], [5, 7], [0, 2], [0, 5], [7, 2], [7, 5] ],
[ [3, 0], [3, 7], [4, 0], [4, 7], [0, 3], [0, 4], [7, 3], [7, 4] ],
[ [2, 1], [2, 6], [5, 1], [5, 6], [1, 2], [1, 5], [6, 2], [6, 5] ],
[ [3, 1], [3, 6], [4, 1], [4, 6], [1, 3], [1, 4], [6, 3], [6, 4] ],
[ [1, 1], [1, 6], [6, 1], [6, 6] ],
[ [1, 0], [1, 7], [6, 0], [6, 7], [0, 1], [0, 6], [7, 1], [7, 6]]
];
}
select(arr) {
if (arr && arr.length > 0) {
for(const moves of this._table) { // 按照優先級遍歷所有策略
moves.sort(() => 0.5 - Math.random()); // 隨機排列該等級策略
for(const move of moves) {
if(arr.findIndex(n => n[0] === move[0] && n[1] === move[1]) > -1) { // 判斷可下的位置是否在策略裡
return move;
}
}
}
} else {
return false;
}
}
}

高級

高級使用的是蒙特卡洛算法

蒙特卡羅方法於20世紀40年代美國在第二次世界大戰中研製原子彈的「曼哈頓計劃」計劃的成員S.M.烏拉姆和J.馮·諾伊曼首先提出。數學家馮·諾伊曼用馳名世界的賭城—摩納哥的Monte Carlo—來命名這種方法,為它蒙上了一層神秘色彩。在這之前,蒙特卡羅方法就已經存在。1777年,法國數學家布豐(Georges Louis Leclere de Buffon,1707—1788)提出用投針實驗的方法求圓周率π。這被認為是蒙特卡羅方法的起源。

所謂的蒙特卡洛算法,其實就是試驗模擬結果,然後算高分

模擬人腦思考對手

我們是要創建一個模擬玩家,去走棋(落子)。

為了提升效率,不考慮比較差的走法,我們就按照Roxanne的優先級落子

/**
* 模擬玩家
* @param {int} color 顏色
*/
class SimulatePlayer {
/**
*
* @param {enum} color 顏色
* @param {enum} type 類型
*/
constructor(color, type) {
this.color = color;
this.type = type;
this.roxnane = new Roxanne();
}
/**
* 走棋
* @param {Array} arr 可以走的位置
* @returns 走棋步驟[col, row]
*/
getMove(arr) {
return this.roxnane.select(arr);
}
}

這就是在模擬人腦,比如你在下棋時候,也會自己想設想一下走完這一步對方怎麼走,想出5~8步再落子,機器的運算能力高,我們就可以算到最終勝負

/**
* 模擬器
*/
class Simulator {
/**
* 構造
* @param {Player} black 黑棋模擬選手
* @param {Player} white 白棋模擬選手
* @param {Engine} engine 引擎
* @param {int} current 現在棋手
*/
constructor(black, white, engine, current) {
this.black = black;
this.white = white;
this.current = current;
this.engine = engine;
}
run() {
let n = 0;
while(!this.engine.isGameOver()) {
this.shift();
const arr = this.engine.getLegal(this.current.color);
if(arr && arr.length > 0) {
const action = this.current.getMove(arr);
this.engine.move(action[1], action[0]);
}
if(n >100)
break;
else
n++;
}
return this.engine.getResult();
}
/**
* 設置current玩家
*/
shift() {
const color = this.engine.getPlayer();
if(isNaN(color)) {
this.current = this.black;
} else {
this.current = color === Engine.CHESS.BLACK ? this.black : this.white;
}
return this.current;
}
}

蒙特卡洛算法

首先創建一個蒙特卡洛樹

其實就代表了一步棋,它擁有children可以無限差分,就是把下面的走法放到子步驟裡;它也有一個parent方便尋找上一級計算得分

/**
* 夢特卡洛樹
*/
class TreeNode {
constructor(parent, color) {
this.parent = parent;
this.w = 0;
this.n = 0;
this.row = NaN;
this.col = NaN;
this.color = color;
this.children = [];
}
/**
* 設置走棋步驟
* @param {array} move [col, row]
*/
setMove(move) {
this.row = move[1];
this.col = move[0];
}
/**
* 獲得走棋步驟
*/
getMove() {
return [this.col, this.row];
}
/**
* 添加節點,去重
* @param {TreeNode} node 蒙特卡洛樹節點
*/
add(node) {
if(this.children.findIndex(p => p.row === node.row && p.col === node.col) === -1) {
this.children.push(node);
}
}
}

然後就是開始執行蒙特卡洛算法了,其實也就是模擬走棋然後選出最佳方案

這裡要注意的是,js沒有真正的多線程,所以我使用的Promise配合setInterval創建一個異步任務保證這個計算運行的同時不阻塞程序

/**
* 夢特卡洛算法
* @param {int} color 顏色
* @param {int} expire 限時
*/
class MonteCarlo {
constructor(color, expire = 2000) {
this.color = color;
this.expire = expire;
this.tick = 0;
this.black = new SimulatePlayer(Engine.CHESS.BLACK);
this.white = new SimulatePlayer(Engine.CHESS.WHITE);
}
/**
* 運行
* @param {Engine} engine 引擎
*/
run(engine) {
this.tick = new Date().getTime();
const root = new TreeNode(null, this.color);
return new Promise((resolve, reject) => {
const sid = setInterval(() => {
const simulateEngine = engine.clone();
const choice = this.select(root, simulateEngine);
this.expand(choice, simulateEngine);
const {winner} = this.simulate(choice, simulateEngine);
let backScore = [0.5, 1, 0][winner];
if (choice.color === Engine.CHESS.BLACK) {
backScore = 1 - backScore;
}
this.backProp(choice, backScore);
if(new Date().getTime() - this.tick > this.expire - 1) {
clearInterval(sid);
let bestN = -1;
let bestMove = null;
for(const k in root.children) {
if(root.children[k].n > bestN) {
bestN = root.children[k].n;
bestMove = root.children[k].getMove();
}
}
resolve(bestMove);
}
}, 1);

});
}
/**
* 蒙特卡洛樹搜索,節點選擇
* @param {TreeNode} node 節點
* @param {Engine} engine 引擎
* @returns 搜索樹向下遞歸選擇子節點
*/
select(node, engine) {
if (node.children.length === 0) {
return node;
} else {
let bestScore = -1;
let bestMove = null;
for (const k in node.children) {
if (node.children[k].n === 0) {
bestMove = k;
break;
} else {
let N = node.n;
let n = node.children[k].n;
let w = node.children[k].w;
const score = w / n + Math.sqrt(2 * Math.log(N) / n);
if (score > bestScore) {
bestScore = score;
bestMove = k;
}
}
}
return this.select(node.children[bestMove], engine);
}
}
/**
* 蒙特卡洛樹搜索,節點擴展
* @param {TreeNode} node 節點
* @param {Engine} engine 引擎
* @returns 搜索樹向下遞歸選擇子節點
*/
expand(node, engine) {
for (const move of engine.getLegal(node.color)) {
const child = new TreeNode(node, node.color);
child.setMove(move);
node.add(child);
}
}
/**
* 蒙特卡洛樹搜索,採用Roxanne策略代替隨機策略搜索,模擬擴展搜索樹
* @param {TreeNode} node 節點
* @param {Engine} engine 引擎
*/
simulate(node, engine) {
const current = node.color === Engine.CHESS.WHITE ? Engine.CHESS.BLACK : Engine.CHESS.WHITE;
const simulator = new Simulator(this.black, this.white, engine, current);
return simulator.run();
}
/**
* 蒙特卡洛樹搜索,反向傳播,回溯更新模擬路徑中的節點獎勵
* @param {TreeNode} node 節點
* @param {int} score 計分
*/
backProp(node, score) {
node.n += 1;
node.w += score;
if (node.parent) {
this.backProp(node.parent, 1 - score);
}
}
/**
* 蒙特卡洛樹搜索
* @param {Engine} engine 引擎
* @returns 採取最佳拓展落子策略
*/
getMove(engine) {
this.tick = new Date().getTime();
const action = this.mcts(engine.clone());
return action;
}
}

這樣,cpu的AI就完成了

擴展

其實蒙特卡洛樹算法,並不是最佳。這裡就是電腦跟人腦的一個大區別,電腦只能看出眼前的優先級,並不能跟人一樣輕鬆使用「爬邊」、「斯通納陷阱」之類先抑後揚的戰術

術語

C位、星位(C-squares and X-squares):C位就是位於(0, 1)、(0, 6)、(1, 0)、(1, 7)、(6, 0)、(6, 7)、(7, 1)和(7, 6)的位置,星位就是位於(1, 1)、(1, 6)、(6, 1)和(6, 6)的位置。這些位置務必要小心佔用。

中心(Center):局面的中心就是內部子的集合。

控制中心(Control of the center):一種策略,它試圖在局面中心擁有儘可能多的棋子,沿邊界擁有儘可能少的棋子,以獲得最大可能的行動力。

角(Corner):角就是位於(0,0)、(0,7)、(7,0)和(7,7)的位置。這些位置不可能被對方夾吃。

爬邊(Edge creeping):一種以弱邊(不平衡邊)為代價,在一條或兩條邊上獲得最大數量棋步的策略。爬邊者試圖通過將全部邊界都留給對手來快速耗盡他的棋步,但是如果爬邊不能湊效,壞邊產生的效應將使他的局面迅速變弱。

邊界(Frontier):邊緣子的集合,也就是說那些與空位相鄰的棋子。

獲得餘裕手(Gain a tempo):在棋盤的某個區域內比對手多下一步棋,以迫使他在其他地方先開始下棋(從而延長他的邊界)。

效應(Influence):當棋手的棋子迫使他同時在多個方向上翻轉棋子時,我們就說這些棋子產生了效應。

內部子(Internal discs)、邊緣子(external discs):內部子就是不與空位相鄰的棋子。沒有內部子在戰略上是很糟的。

自由(Liberty):非災難性的棋步。「缺少自由」:在不久的將來不得不送角。

多子策略(Maximum disc strategy):許多初學者所用的錯誤策略,他們每步棋都試圖翻轉最大數量的棋子。

行動力(Mobility):棋手合法的可能棋步數量。更進一步說,當棋手擁有大量的可能棋步時,他就擁有好的行動力。

奇偶性(Parity):一種在對手佔據的每個區域內都留下偶數個空位的策略。

安靜步(Quiet move):不翻轉邊緣子的一步棋,通常這是步好棋。

穩定子(Stable discs):絕對不會被翻轉的棋子。角就是一個穩定子的實例。

斯通納陷阱/四通陷阱(Stoner Trap):一種針對弱邊局面強迫進行角交換的攻擊。

不平衡邊(Unbalanced edge):由非6個同色棋子組成的邊結構。

AlphaGo

因為這個遊戲展示是純前臺的,如果帶後臺,我們可以更方便的窮盡所有的走棋步驟,存入資料庫方便復用,而不是只按照優先級落子

後記

人工智慧介紹完畢,後面會介紹一下3D棋盤的前端canvas技術,也就是基於threejs框架的webgl

遊戲引擎請看 蘋果棋的遊戲引擎

在線遊戲請看 蘋果棋

相關焦點

  • 蘋果2億美元收購人工智慧公司 或與iPhone有關
    蘋果以2億美元收購人工智慧公司Xnor.ai2017年,Xnor.ai從非營利組織艾倫人工智慧研究院中獨立出來,其具備的技術能夠讓手機或其他便攜設備在本地執行深度學習算法,而不需要上傳到雲服務中計算。此外,Xnor.ai公司還承諾完全保密數據,鑑於蘋果公司向來追求隱私保護層面的技術,所以收購這一類型的公司並不令人感到意外。Xnor.ai與蘋果追求隱私安全方面相契合另有相關人士透露:蘋果會不時收購規模較小的技術型公司,目前雙方比較低調,不對外表露目的與計劃。
  • 人工智慧大動作不斷,海信在下一步什麼棋?
    先是布局無人駕駛市場,ADAS(高級駕駛輔助系統)下半年上市,再是布局無人超市、智慧公路綜合運營管理平臺,科技範兒越來越強的海信究竟在下一步什麼棋?在很多人的傳統印象裡,海信是一個家電企業。畢竟,它在家電領域至今都保持著強悍的優勢——2017年,海信電視零售額和零售量佔有率再次雙雙佔據中國市場第一。至此,海信已連續14年穩居中國彩電第一。
  • AlphaGo、康德和人工智慧
    人工智慧早已從技術領域破圈到大眾文化之中,成為一個被廣泛討論的熱詞,那麼除了在技術領域,給生活帶來的更多便利性之外,作為非技術人員,能在人工智慧當中學到什麼,又可以由此改變什麼呢?而且當年「深藍」的策略,似乎也有些暴力,就是利用機器的強大算力,去推測每一步棋的最優解,不過「深藍」也不過能看到未來6步棋的情況。可以說,當時的「深藍」只體現出計算機的算法能力和計算水平,但還遠遠達不到所謂人工智慧的意義。
  • 各大高校新增人工智慧專業,關於人工智慧,你知道多少?
    然後團隊讓不同版本的阿爾法狗相互之間下棋,通過每盤棋的勝負來優化和升級下棋策略。這樣相互下棋的數量你知道有多少嗎?3000萬盤棋。在實際下棋過程中,則體現了計算機巨大的計算力。阿爾法狗在下每一步棋的時候,系統都要搜索本方最可能落子的點,然後將每種可能估算出勝率,再下勝率最高的那一步棋。這個計算的量是非常巨大的。
  • 【WWDC18 專訪】蘋果獎學金的背後,是哪些神奇的人和 App?
    也許,這就是蘋果所希望看到的創造力吧。這些獲獎作品中,有解構漢字歷史的《De-Chinese》,中國民間傳統遊戲《褲襠棋》,分享同性戀成長故事的《Coming Out》,以及用AI算法解數學題的《漢諾塔》。
  • AlphaGo對圍棋研究謝幕 留下輔助學棋的軟體
    與AlphaGo的對局恐怕是柯潔記憶最深的苦戰12月13日凌晨,人工智慧AlphaGo的研發公司DeepMind科學家黃士傑博士,在社交媒體上發布了AlphaGo的「臨別感言」。他表示DeepMind公司和本人將轉到其他項目的研究中去。這也標誌著AlphaGo對圍棋研究的謝幕。
  • 馬斯克將通過連線訪談參加2020世界人工智慧大會
    馬斯克將通過連線訪談參加2020世界人工智慧大會 澎湃新聞記者 張若婷 虞涵棋 2020-07-01 19:46 來源
  • 挖角谷歌AI元老John Giannandrea,蘋果想在人工智慧領域幹點啥?
    4月3日,蘋果宣布聘用Google搜索和人工智慧主管John Giannandrea。 他將負責蘋果的機器學習和人工智慧戰略,直接向蘋果執行長庫克報告。這聽起來對蘋果來說是個好消息。 就人工智慧領域而言,蘋果一直落後於谷歌,毫無疑問,谷歌是人工智慧領域明確的領導者。
  • 谷歌頂級人工智慧專家Ian Goodfellow加入蘋果公司 擔任總監級別職務
    北京時間4月5日凌晨消息,據美國媒體CNBC報導,作為曾經谷歌人工智慧領域的頂尖人物之一,Ian Goodfellow已加入蘋果公司擔任總監級別職務。     這段僱傭關係得益於蘋果公司越來越努力利用人工智慧來推動其軟體和硬體的發展。去年,蘋果公司聘請谷歌人工智慧負責人John Giannandrea負責監督人工智慧戰略。
  • 馬雲馬斯克探討人工智慧;華為9月在慕尼黑推出Mate30系列手機;蘋果...
    要聞必讀1、馬雲馬斯克探討人工智慧2、華為將於9月在慕尼黑推出Mate30系列手機3、蘋果將停止Siri語音分析業務4、微軟或於10月發布雙屏Surface設備5、百度發布全自研崑崙雲伺服器科技馬雲馬斯克探討人工智慧在今日開幕的2019世界人工智慧大會上,聯合國數字合作高級別小組聯合主席馬雲和特斯拉聯合創始人兼執行長埃隆
  • 新奧杯彭立堯驚天逆轉 譜經典番棋故事
    五番棋22日休戰一天,第三局23日開賽,這時研究室的氛圍是討論「比賽結束後是否立刻舉行頒獎儀式」。局後的柯潔 第三局彭立堯要破柯潔的「執白棋」,更主要是前兩局彭立堯並沒有表現出後盤的堅韌和頑強,尤其機會來臨時始終不能精準把握,柯潔五番棋3比0直落三局取勝似乎毫無懸念。
  • Square Off智能象棋將哈利波特巫師棋帶進現實
    (原標題:Square Off智能象棋將哈利波特巫師棋帶進現實)
  • 有趣的民間遊戲:墨點棋、扇子棋、五虎棋、五角星棋、扎槍蘿蔔
    本文屬鳳姐說民間遊戲原創,素材來自網絡,如果喜歡請關注我導語:墨點棋、扇子棋、五虎棋、五角星棋、扎槍蘿蔔墨點棋:墨點棋是一項二人對弈遊戲,玩法與搭橋棋有一定相似之處墨點棋的棋盤由100個墨點,即100個單獨的棋位構成,縱橫各10路,棋盤。2.連線。雙方輪流在棋盤上的任意兩個墨點之間連線,一次一筆。可橫向、豎向連線,但不可斜向連線,也不能重複連線。連線的目的是為了將四個墨點連成一個正方形。3.勝負。在一個正方形內,邊線可以是自己連的線,也可以是對方連的線,但最後封口是哪一方,這個正方形就歸哪一方所有。
  • 星陣網頁智能對弈免費開放 人人可享頂尖職業免費指導棋
    對於普通愛好者來講,此功能無異於人人可把人類世界冠軍水平的AI老師請進家門,免費下指導棋了!人工智慧棋手族介紹星陣圍棋陪練中的人工智慧棋手族通過人工智慧的方式,模擬了各個水平段人類的圍棋下法,形成了30個經過嚴格訓練和測試的等級。
  • 蘋果出人意料地改用自研電腦晶片,到底在下一盤多大的棋?
    自2005年,蘋果從PowerPC架構轉向英特爾的處理器架構,至今為止,蘋果與英特爾合作了長達15年之久,幾乎每一代的Mac電腦都會用上英特爾的定製化晶片。如今蘋果正式公布了自己研發電腦晶片的計劃,等於說蘋果與英特爾之間的合作關係要從此告一段落。
  • 有趣的民間遊戲:乘棋、丁字棋、梯形棋、分割包圍、對角棋
    有趣的民間遊戲:乘棋、丁字棋、梯形棋、分割包圍、對角棋本文屬蓮姐說民間遊戲原創,素材來自網絡,如果喜歡請關注我導語:乘棋、丁字棋、梯形棋、分割包圍、對角棋乘棋:乘模是一項玩法類似於連棋的二人對弈遊戲,又稱城棋、直棋、三口棋、行直棋、放直棋、成列棋等。
  • 樊麾回應輸給電腦:最初不信它能贏 自己棋太臭
    我想贏,而且盡了我的全力,只能說,可能我棋比較臭唄。」「阿爾法」戰傳奇李世石?英國時間27日下午6點,位於倫敦的谷歌旗下人工智慧研究機構DeepMind在世界頂級學術雜誌《自然》發表了關於圍棋人工智慧項目的論文,頓時成為業界焦點。阿爾法在堪稱人工智慧難關中的皇冠——圍棋項目中達到了裡程碑的成績,被譽為開創了人工智慧的新紀元。
  • 【芯視野】蘋果的下一盤大棋?
    蘋果已然不是最初的「蘋果」,自造芯活動開啟以來,戰功赫赫,2019年已成功躋身全球十大半導體廠商之列。在近期將Mac電腦晶片轉向自研並大放光芒之後,蘋果的下一輪徵戰再次浮出水面。據彭博社報導,蘋果已開始研發自己的內部蜂窩數據機即基帶,以便在未來取代目前 iPhone 所搭載的高通基帶。
  • 漫畫:什麼是人工智慧?
    由此可見,人類距離實現真正意義上的人工智慧,還有很長的道路要走。人工智慧是如何實現的?在人工智慧的研究早期,使用的算法相對比較原始,其中比較有代表性的實現算法是搜索算法。當人工智慧需要作出決策的時候,會枚舉出所有可能的選擇,並按優劣為每一個選擇做一個評分。最終,評分最高的選擇被視為最優決策。IBM研發的深藍就是利用了搜索算法,在走棋的時候會枚舉出眾多的棋局變化,對每一種局面給出相應的分數,最終選擇走出一步程序認為最優的棋。但是,為了減少計算,深藍並不會盲目地枚舉出全部棋局,而是忽略掉一些明顯是「送死」的選擇。這種算法上的優化被稱為「剪枝」。
  • 棋後侯逸凡分享自己的學習和人生經歷
    2017年4月10日中午,西洋棋特級大師( ),棋後( )侯逸凡與我校師生分享她的學習和人生經歷。這位「大師」年齡與學生們年齡相仿,但15歲時就已經是「國際棋後」,大眾眼中的神童、「人生贏家」。關於人工智慧,其實更多應該思考如何用好人工智慧,可以不將它當成對手,而是幫手。