使用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