回溯算法--三连游戏(人机对战)
2017-08-24 16:47
555 查看
程序的核心部分在于计算机如何选择下棋的位置。采用的策略叫作极小极大策略。通过一个赋值函数来给一个位置的“好坏”定值。能使计算机获胜的位置得到值+1;平局得到0;使计算机输棋的位置得到值-1。通过考察盘面就能够确定输赢的位置叫作终端位置。
如果一个位置不是终端位置,那么该位置的值通过递归假设双方最优棋步而确定。这叫做极小极大策略,因为下棋的一方(人)试图极小化这个位置的值,而另一方(计算机)却要使它的值达到极大。
采用数组下标1-9代表九个格子,随机生成一个数来确定先手。如果计算机先手,因为此时盘面处于平局,计算机总会选择第一个位置,所以随机生成一个位置给计算机。
头文件
cpp文件
main.cpp
结果
如果一个位置不是终端位置,那么该位置的值通过递归假设双方最优棋步而确定。这叫做极小极大策略,因为下棋的一方(人)试图极小化这个位置的值,而另一方(计算机)却要使它的值达到极大。
采用数组下标1-9代表九个格子,随机生成一个数来确定先手。如果计算机先手,因为此时盘面处于平局,计算机总会选择第一个位置,所以随机生成一个位置给计算机。
头文件
#include <vector> using namespace std; class TicTacToe { public: static const int COMP=1; static const int HUMAN=-1; TicTacToe():board(10){} bool fullBoard() { for(int i=1;i<=9;++i) { if(board[i]==0) return false; } return true; } bool isEmpty(int i) { if(board[i]==0) return true; else return false; } void place(int i,int player) { board[i]=player; } void unplace(int i) { board[i]=0; } bool immediateWin(int & bestMove,int player); int findCompMove(int & bestMove); int findHumanMove(int & bestMove); void setChessPiece(int location,int player); void showBoard(); bool check(int i); private: static const int DRAW=0; static const int COMP_WIN=1; static const int COMP_LOSS=-1; vector<int> board; };
cpp文件
#include "TicTacToe.hpp" #include <iostream> bool TicTacToe::immediateWin(int & bestMove,int player) { for(int i=1;i<=9;++i) { if(isEmpty(i)) { bool flag=false; place(i, player); if(i==1) { if( (board[i]==board[i+1]&&board[i]==board[i+2]) ||(board[i]==board[i+3]&&board[i]==board[i+6]) ||(board[i]==board[i+4]&&board[i]==board[i+8]) ) { flag=true; } } if(i==2) { if( (board[i]==board[i+1]&&board[i]==board[i-1]) ||(board[i]==board[i+3]&&board[i]==board[i+6]) ) { flag=true; } } if(i==3) { if( (board[i]==board[i-1]&&board[i]==board[i-2]) ||(board[i]==board[i+3]&&board[i]==board[i+6]) ||(board[i]==board[i+2]&&board[i]==board[i+4]) ) { flag=true; } } if(i==4) { if( (board[i]==board[i+3]&&board[i]==board[i-3]) ||(board[i]==board[i+2]&&board[i]==board[i+1]) ) { flag=true; } } if(i==5) { if( (board[i]==board[i+3]&&board[i]==board[i-3]) ||(board[i]==board[i-1]&&board[i]==board[i+1]) ||(board[i]==board[i-4]&&board[i]==board[i+4]) ||(board[i]==board[i-2]&&board[i]==board[i+2]) ) { flag=true; } } if(i==6) { if( (board[i]==board[i-1]&&board[i]==board[i-2]) ||(board[i]==board[i+3]&&board[i]==board[i-3]) ) { flag=true; } } if(i==7) { if( (board[i]==board[i+1]&&board[i]==board[i+2]) ||(board[i]==board[i-6]&&board[i]==board[i-3]) ||(board[i]==board[i-2]&&board[i]==board[i-4]) ) { flag=true; } } if(i==8) { if( (board[i]==board[i+1]&&board[i]==board[i-1]) ||(board[i]==board[i-6]&&board[i]==board[i-3]) ) { flag=true; } } if(i==9) { if( (board[i]==board[i-1]&&board[i]==board[i-2]) ||(board[i]==board[i-6]&&board[i]==board[i-3]) ||(board[i]==board[i-8]&&board[i]==board[i-4]) ) { flag=true; } } unplace(i); if(flag) { bestMove=i; return true; } } } return false; } int TicTacToe::findCompMove(int & bestMove) { int i,responseValue; int dc; //do not care int value; if(fullBoard()) value=DRAW; else { if(immediateWin(bestMove, COMP)) return COMP_WIN; else { value=COMP_LOSS;bestMove=1; for(i=1;i<=9;++i) { if(isEmpty(i)) { place(i, COMP); responseValue=findHumanMove(dc); unplace(i); if(responseValue>value) { value=responseValue; bestMove=i; } } } } } return value; } int TicTacToe::findHumanMove(int & bestMove) { int i,responseValue; int dc; int value; if(fullBoard()) value=DRAW; else { if(immediateWin(bestMove, HUMAN)) return COMP_LOSS; else { value=COMP_WIN;bestMove=1; for(i=1;i<=9;++i) { if(isEmpty(i)) { place(i, HUMAN); responseValue=findCompMove(dc); unplace(i); if(responseValue<value) { value=responseValue; bestMove=i; } } } } } return value; } void TicTacToe::showBoard() { for(int i=0;i<20;++i) cout<<"\n"; vector<string> out(10); for(int i=1;i<=9;++i) { if(board[i]==0) out[i]=' '; else if(board[i]==-1) { out[i]="Ο"; } else { out[i]="Χ"; } } cout<<"________________"<<endl; cout<<"| "<<out[1]<<" | "<<out[2]<<" | "<<out[3]<<" |"<<endl; cout<<"| | | |"<<endl; cout<<"|—-——|—-——|—-——|"<<endl; cout<<"| "<<out[4]<<" | "<<out[5]<<" | "<<out[6]<<" |"<<endl; cout<<"| | | |"<<endl; cout<<"|——-—|—-——|—-——|"<<endl; cout<<"| | | |"<<endl; cout<<"| "<<out[7]<<" | "<<out[8]<<" | "<<out[9]<<" |"<<endl; cout<<"|____|____|____|"<<endl; } bool TicTacToe::check(int i) { if(i==1) { if( (board[i]==board[i+1]&&board[i]==board[i+2]) ||(board[i]==board[i+3]&&board[i]==board[i+6]) ||(board[i]==board[i+4]&&board[i]==board[i+8]) ) { return true; } } if(i==2) { if( (board[i]==board[i+1]&&board[i]==board[i-1]) ||(board[i]==board[i+3]&&board[i]==board[i+6]) ) { return true; } } if(i==3) { if( (board[i]==board[i-1]&&board[i]==board[i-2]) ||(board[i]==board[i+3]&&board[i]==board[i+6]) ||(board[i]==board[i+2]&&board[i]==board[i+4]) ) { return true; } } if(i==4) { if( (board[i]==board[i+3]&&board[i]==board[i-3]) ||(board[i]==board[i+2]&&board[i]==board[i+1]) ) { return true; } } if(i==5) { if( (board[i]==board[i+3]&&board[i]==board[i-3]) ||(board[i]==board[i-1]&&board[i]==board[i+1]) ||(board[i]==board[i-4]&&board[i]==board[i+4]) ||(board[i]==board[i-2]&&board[i]==board[i+2]) ) { return true; } } if(i==6) { if( (board[i]==board[i-1]&&board[i]==board[i-2]) ||(board[i]==board[i+3]&&board[i]==board[i-3]) ) { return true; } } if(i==7) { if( (board[i]==board[i+1]&&board[i]==board[i+2]) ||(board[i]==board[i-6]&&board[i]==board[i-3]) ||(board[i]==board[i-2]&&board[i]==board[i-4]) ) { return true; } } if(i==8) { if( (board[i]==board[i+1]&&board[i]==board[i-1]) ||(board[i]==board[i-6]&&board[i]==board[i-3]) ) { return true; } } if(i==9) { if( (board[i]==board[i-1]&&board[i]==board[i-2]) ||(board[i]==board[i-6]&&board[i]==board[i-3]) ||(board[i]==board[i-8]&&board[i]==board[i-4]) ) { return true; } } return false; } void TicTacToe::setChessPiece(int location,int player) { if(location>0&&location<10&&isEmpty(location)) { board[location]=player; } else { cout<<"try again"; cin>>location; setChessPiece(location, player); } }
main.cpp
#include <iostream> #include <stdlib.h> #include <time.h> #include <unistd.h> #include "TicTacToe.hpp" using namespace std; int main() { TicTacToe board; board.showBoard(); int move; srand((unsigned)time(NULL)); bool turn=rand()%2; //决定先手 if(turn==0) { sleep(1.5); move=rand()%9+1; //随机选择一个位置 board.setChessPiece(move, board.COMP); board.showBoard(); turn=1; } else { cout<<"Human First"; } while (1) { if(turn) { cin>>move; board.setChessPiece(move, board.HUMAN); turn=0; } else { sleep(1.5); board.findCompMove(move); board.setChessPiece(move, board.COMP); turn=1; } board.showBoard(); if(board.check(move)) { if(!turn) cout<<"human win"<<endl<<endl; else cout<<"computer win"<<endl<<endl; return 0; } if(board.fullBoard()) { cout<<"draw"<<endl<<endl; return 0; } } return 0; }
结果
相关文章推荐
- 数独游戏(sudoku)算法 回溯+剪枝
- 人机对战初体验:Python基于Pygame实现四子棋游戏
- QT五子棋项目详解之四:AI人机对战max-min极大极小值博弈算法
- HTML5+JS 《五子飞》游戏实现(八)人机对战
- HDOJ —2009 翻纸牌游戏——搜索(回溯)算法
- 人机对战初体验—四子棋游戏
- 【源码】斗地主人机对战程序算法2012完整版
- 人机对战初体验—四子棋游戏
- 人机对战之取火柴游戏
- 游戏视野系统算法 (FOV using recursive shadowcasting)
- 游戏开发经常使用算法概述
- 一个连连看游戏的通路检测算法
- 常用算法之-回溯法
- android游戏开发之我的小小游戏1——五子棋游戏5之蓝牙对战
- 一个硬币移动游戏的求解算法
- 护航者,腾讯云: 2017年度游戏行业DDoS态势报告—回溯与前瞻
- 结构体案例之对战游戏
- 回溯算法 8皇后问题的一种解法 适合初学者观察整个回溯的过程
- 空谈实现游戏的网络对战(一)