使用Qt5.12.9的QGraphicsItem來實現俄羅斯方塊,使用簡單的評估函數,實現AI機器人玩俄羅斯方塊遊戲。這是AI機器人的第一步,這個算法很簡單,但頗有效,大多數狀況能消5百層以上,最近的爲數很少的測試中,最高紀錄已經消了超過2500層。在這個基礎上,能夠方便的積累原始數據,我但願能抽取模式,進行模式識別及至機器學習。python
在手動遊戲基礎上進行改造,借鑑回放的經驗,只須要加入一個評估算法,爲每個新方塊找出一個放置的姿態(旋轉次數)和最終位置座標就能夠了。個人算法設計也很簡單,就是爲每個方塊窮舉其放置方法,使用一個緊密程度的評估算法進行評分,取出最高分的操做,如有相同得分的操做,用隨機數二一添作五。linux
界面操做控制變量,作到隨時能夠在手動與自動兩種模式之間進行切換。git
if (isAutoRunning) { //自動模式 autoProcessCurBlock(); //處理當前方塊,使用評估函數肯定方塊的最終姿態與位置 block->relocate(curPos); //放置 block->setBlockNotActive(); //固定方塊 generateNextBlock(); //取下一個方塊,遊戲繼續 }else //手動模式 this->moveBlockDown(); ...
個人設計思想很直觀,俄羅斯方塊就是要儘可能緊密的堆積在一塊兒,因此對每個組成方塊的block都檢測一個它周圍的四個位置,看是否有block(包括邊界)存在,如有就加1分,沒有不加分。這塊的加分,並無區別組成方塊自身的block和外界的block,由於每一個方塊都是與本身進行比較,因此區分與不區分效果是同樣的。起始分由深度肯定,越深我認爲效果越好。另個,block的垂直下方最好不要有空洞,如有會減分。github
int Game::evaluate(Tetris* t) { QPoint pos = t->getPos(); int ct = pos.y(); //深度爲基礎分 int cct = t->cleanCount(); if (cct > 1) //能消層,加分 ct += 10 * (cct - 1); for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { if (t->data[i][j]) { ct += t->hasTetrisBlock(pos.x() + j + 1, pos.y() + i) ? 1 : 0; //檢測block右邊的位置 ct += t->hasTetrisBlock(pos.x() + j - 1, pos.y() + i) ? 1 : 0; //檢測block左邊的位置 ct += t->hasTetrisBlock(pos.x() + j, pos.y() + i + 1) ? 1 : 0; //檢測block下方的位置 ct += t->hasTetrisBlock(pos.x() + j, pos.y() + i - 1) ? 1 : 0; //檢測block上方的位置 if (i == 3 || t->data[i + 1][j] == 0) { if (!t->hasTetrisBlock(pos.x() + j, pos.y() + i + 1)) { //block下方的緊臨空洞 ct -= 4; } else { int k = 2; while (pos.y() + i + k <= 19) { if (!t->hasTetrisBlock(pos.x(), pos.y() + i + k)) { //block下方的非緊臨空洞 ct -= 1; break; } k++; } } } } } } return ct; }
一個方塊最多隻有四種姿態,把方塊的每一種姿態都從左到右moveDownEnd一次,進行評分,取得分最高的方案。算法
void Game::autoProcessCurBlock() { int max = 0; QPoint initPos = block->getPos(); Tetris* tmp = new Tetris(initPos, block->getShape(), -1); //構造當前方塊的替身,blockType爲-1,這種方塊不會顯示 int rotateCt = block->getRotateNum(); //同步替身初始姿態 for (int k = 0; k < rotateCt; k++) tmp->rotate(); rotateCt = 0; //用於保存方塊的最終姿態 for (int r = 0; r < 4; r++) { //四種姿態遍歷,其實能夠優化,有的方塊不須要四次 if (r > 0) { tmp->relocate(initPos); //注意,旋轉要在方塊進入遊戲界面的地方旋轉,否則可能旋轉不成功 tmp->rotate(); } while (tmp->moveLeft()); //從最左邊開始 do { tmp->moveDownEnd(); tmp->setBlockNotActive(); //固定方塊,以便進行評分 int score = evaluate(tmp); //評分 if (score > max) { //找到當前最優方案 max = score; curPos = tmp->getPos(); rotateCt = r; } else if (score == max) { //出現相等評分,隨機取 if (qrand() % 2 == 1) { curPos = tmp->getPos(); rotateCt = r; } } //initPos.setX(tmp->getPos().x()); tmp->relocate(QPoint(tmp->getPos().x(), initPos.y())); //返回到遊戲空間上方 tmp->setBlockTest(); //方塊恢復到測試狀態 } while (tmp->moveRight()); //方塊右移,直到不能移動 } delete tmp; //銷燬測試方塊,忽然想到這塊能夠優化,只須要建七個方塊就好,這樣就不用不斷的建立和銷燬了 for (int k = 0; k < rotateCt; k++) block->rotate(); }
使用python從新實現全部功能,也再也不用Qt,就用python自帶的tkinter就好。把重點放在模式提取,讓AI自動玩遊戲,寫個算法,提取優秀的操做模式。而後使用模式匹配或機器學習算法來優化AI。如今尚未具體的想法,只有這麼個大概的設想。windows
項目採用cmake組織,請安裝cmake3.10以上版本。下面腳本是windows下基於MSVC的,其它操做系統上基本相似,或者使用qtcreator打開進行操做。機器學習
cmake -A win32 -Bbuild . cd build cmake --build . --config Release
注:本項目採用方案能跨平臺運行,已經適配過windows,linux,mac。函數
源代碼:學習
https://gitee.com/zhoutk/qtetris.git
或測試
https://gitee.com/zhoutk/qtdemo/tree/master/tetrisGraphicsItem
或
https://github.com/zhoutk/qtDemo/tree/master/tetrisGraphicsItem