摘要:所有獲勝的數量和數量統計經過通過棋盤上所有可能勝利的情況不過種而已計算最合適的落棋目標如果我是計算機,接下來我要做的就是當聰明的人類下好棋之后,我怎樣下好自己的棋。
1.前言
記得讀大學時,有段時間特別喜歡和室友們下五子棋,由于腦子不是特別靈光,再加上室友確實經驗豐富,自己自然是屢屢戰敗。時光荏苒,一眨眼好多年過去了,很是懷念那時愜意的時光!大學畢業后,室友們都從事了不同行業的工作,我也是如愿選擇了做“程序員”。AI近些年來一直很火熱,其他行業的小伙伴總是誤認為我們很厲害的樣子,殊不知“如魚飲水,冷暖自知”。不過“專業思想”還確實是有的,所以有感寫了這篇博文,和大家就五子棋探討一下“計算機”思維和“人類”思維的區別和聯系。話不多說,先上一張“戰敗”效果圖(我承認我還是下不過自己的智能算法):點擊查看源代碼:
五子棋的棋盤很簡單,不過是一些橫豎交叉的線條而已。懂canvas的同學自然知道是怎么回事:設計好坐標之后,在畫布上畫15條橫豎交叉的線就可以了,也是橫x,豎y,兩個for循環而已。上代碼:
context.strokeStyle = "#BFBFBF"; //設置線條顏色 function drawChessBoard() { //繪制棋盤 for(var i=0; i<15; i++) { //橫線條 context.moveTo(20 + i*40, 20); context.lineTo(20 + i*40, 580); context.stroke(); //豎線條 context.moveTo(20, 20 + i*40); context.lineTo(580, 20 + i*40); context.stroke(); } }2.2畫黑白棋子
“棋子”是圓的,有黑、白兩種顏色。只要我們找好圓心點,設置好半徑,顏色就可以了。為了使棋子看起來更加逼真,可以給棋子中心添加漸變光澤,也不過是調用一個函數,封裝成函數代碼如下:
function drawChessMan(i, j) { //繪制棋子 context.beginPath(); context.arc(20 + i*40, 20 + j*40, 18, 0, 2*Math.PI); context.closePath(); var gradient = context.createRadialGradient(23 + i*40, 17 + j*40, 18, 23 + i*40, 17 + j*40, 0); if(curColor === "white") { gradient.addColorStop(0, "#D1D1D1"); gradient.addColorStop(1, "#F9F9F9"); } if(curColor === "black") { gradient.addColorStop(0, "#0A0A0A"); gradient.addColorStop(1, "#636766"); } context.fillStyle = gradient; context.fill(); curColor = (curColor === "white") ? "black" : "white"; }2.3 鼠標點擊交替畫黑白棋子
增加鼠標點擊事件,在棋盤上尋找最近的落子點繪制棋子。設置一個當前棋子顏色變量,黑白交替繪制,實現這個功能在棋子繪制函數中就已經存在:curColor = (curColor === "white") ? "black" : "white";下邊是鼠標事件監聽函數
//鼠標落下,畫棋子 chessboard.onclick = function(e) { ...... var x = e.offsetX; var y = e.offsetY; var i = Math.floor(x / 40); var j = Math.floor(y / 40); if(chessManStatus[i][j] === 0) { drawChessMan(i, j); ...... } }3.核心算法——計算機是怎樣思考的? 3.1 計算所有可能會贏的數據
我們不得不承認“計算機”的計算速度比人類要快的多,它能夠每秒進行億萬次計算,而且按照既定的流程走,它永遠不會累,也不會失誤。如果我是“計算機”,我就把所有對手可能會贏的情況全都算出來,然后根據下棋的過程,根據每一次的數據情況,計算出一個坐標,這個坐標棋子能夠阻止對手贏比賽,也能讓自己更快的贏比賽。事實上,計算機也是這樣做的,提前計算好所有可能會贏的情況對聰明的人類來說只需要幾秒,但是對于計算機來說,做完這件事情并存儲所有的數據,只是毫秒間的工作而已。下面是程序的實現(和我們想象的一樣:將橫的、豎的、傾斜的連著五個相同棋子的情況都考慮進去,就是所有會贏的情況。而且計算機還將棋子的狀態,自己和人的數據做分類處理。)
var wins = [], personWin = [], computerWin = [],chessManStatus = [], winCount = 0; //所有獲勝的數量和數量統計 for(var i=0;i<15;i++) { wins[i] = []; chessManStatus[i] = []; for(var j=0;j<15;j++) { wins[i][j] = []; chessManStatus[i][j] = 0; } } for(var i=0;i<15;i++) { for(var j=0;j<11;j++) { for(var k=0;k<5;k++){ wins[i][j+k][winCount] = true; } winCount++; } } for(var i=0;i<15;i++) { for(var j=0;j<11;j++) { for(var k=0;k<5;k++){ wins[j+k][i][winCount] = true; } winCount++; } } for(var i=0;i<11;i++) { for(var j=0;j<11;j++) { for(var k=0;k<5;k++){ wins[i+k][j+k][winCount] = true; } winCount++; } } for(var i=0;i<11;i++) { for(var j=14;j>3;j--) { for(var k=0;k<5;k++){ wins[i+k][j-k][winCount] = true; } winCount++; } } for(var i=0; i經過通過棋盤上所有可能勝利的情況不過572種而已!
3.2 計算最合適的落棋目標如果我是計算機,接下來我要做的就是當“聰明的人類”下好棋之后,我怎樣下好自己的棋。這個棋的目標:不讓人類贏,讓自己贏!作為人類的我會大概看一下棋盤上的所有棋子,然后選好一個落棋點,我很羨慕計算機的計算能力,如果我是它我就可以計算一下棋盤上的每一個坐標點,對它們的情況進行評估打分,然后選得分最高的點下棋。當然計算機就是這么做的,每一次下棋它都做了128700次計算來挑選出最合適的落子點。而進行這么多次計算也不過是毫秒之間的事情,所以計算機下棋特別的快,快到“人類”看不出它的反應,幾乎和自己同時下棋的,或許你的棋子剛落下,它就贏了,感覺特別沮喪!
function computerAI() { //電腦智能下棋 var personScore = [],computerScore = [],maxScore = 0,curX = 0, curY = 0; for(var i=0; i<15; i++) { personScore[i] = [];computerScore[i] = []; for(var j=0; j<15; j++) { personScore[i][j] = 0;computerScore[i][j] = 0; } } for(var i=0; i<15; i++) { for(var j=0; j<15; j++) { if(chessManStatus[i][j] == 0) { for(var k=0; kmaxScore) { maxScore = personScore[i][j]; curX = i; curY = j; }else if(personScore[i][j] == maxScore) { if(computerScore[i][j] > computerScore[curX][curY]) { curX = i; curY = j; } } if(computerScore[i][j] > maxScore) { maxScore = computerScore[i][j]; curX = i; curY = j; }else if(computerScore[i][j] == maxScore) { if(personScore[i][j] > personScore[curX][curY]) { curX = i; curY = j; } } } } } drawChessMan(curX, curY); ...... } 這個打分算法是整個算法的核心。計算機將連在一起的棋子做打分,1個棋子分數很低,只有200;兩個棋子就會翻到800;三個棋子會更高,冪次運算。有了評分標準以后,計算機開始評分,先給對手評分,給對手評完分數后再給自己評分,計算機自己的評分規則比對手評分規則高,但是原則上是2個棋子連在一起的評分不會高于對手三個棋子連在一起的:計算機在自己贏之前是不會讓對手有贏的機會的。
3.4 游戲狀態判斷那么游戲什么事件結束呢?當然是有五個棋子連在一起就結束了。這些工作就交給計算機來做吧:計算機記錄每一個贏的情況下連珠棋子的個數,當有棋子達到5時游戲就結束了,當然黑白棋子是互斥的,當白棋在一個位置有連珠時,黑棋就永遠沒有機會了,我們在程序上給它設置為6,不管它怎樣加連珠,都不可能是5了。初始化一個gameOver變量為false,標識游戲是否結束,當游戲結束時,取反就行:gameOver = !gameOver了。
for(var k=0; k4.更多細節與感悟 我承認自己代碼寫的很爛,考慮不到很多優化的情況。但是我把能想到的,能做到的還都是盡力做到了。比如我在一個已經有棋子的地方點擊,是不會讓系統重新繪制棋子的;我在游戲結束之后,不會讓接下來的工作繼續進行的;沒有重新開始,沒有善后工作,這些就留想要做一個完美作品的人來做吧。寫這個智能算法給我的感悟就是我更能夠像計算機一樣的去思考問題了,人類的思考能力會受到情感的左右,而計算機不會,一個越成熟的人,越會像計算機一樣,像程序一樣,做事情井然有序,受情感因素的干擾會很小。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/98972.html
摘要:簡言之,機器學習是內功,而數據挖掘則是機器學習的一種用途。但本質上是我在學習機器學習方面的實戰項目,所以我想辦法利用機器學習的方面的算法實現。 BetaMeow的起源 前段時間AlphaGo和李世石廣受關注,作為人工智能的腦殘粉,看完比賽后激動不已,因為有一定的機器學習的基礎,便打算擼一個棋類的AI,但我還算有點自知之明,圍棋AI,甚至google打算做得通用AI是做不出的了,所以打算...
摘要:的前世今生去年月,橫空出世,戰勝了韓國棋手李世石,贏下了人機對弈的第一戰。當然,隨著技術的不斷發展,人工智能有望在所有領域完全超越人類,成為超人類智能,為人類文明的發展做出更大的貢獻。 showImg(https://segmentfault.com/img/bVOgwC?w=900&h=385); AlphaGo 的前世今生 去年 3 月,AlphaGo 橫空出世,4:1 戰勝了韓國...
摘要:可以說,每個評估函數就是一個選手,對不同的棋型每個選手自然有不同的看法和應對措施,當然他們的棋力也就因此各不相同了。方搜索最大值,人類方搜索最小值。了解了上述原理之后,就可以自己寫代碼實現了。 公眾號:Charles的皮卡丘作者:Charles 開發工具:Python版本:3.6.4相關模塊:graphics模塊。 環境搭建:安裝Python并添加到環境變量即可。 原理簡介:對于五子棋...
閱讀 992·2021-11-04 16:08
閱讀 2967·2021-09-13 10:37
閱讀 504·2019-08-30 15:56
閱讀 1952·2019-08-30 15:55
閱讀 2235·2019-08-30 15:53
閱讀 2078·2019-08-30 13:13
閱讀 2918·2019-08-30 12:51
閱讀 1540·2019-08-29 16:06