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