SDL 实现五子棋 GUI (三)

来源:互联网 发布:平安产险 人工智能 编辑:程序博客网 时间:2024/05/16 14:25

在拥有了 GUI 以后, 我们就可以专心研究其他的部分, 比如加入音乐, 比如加入 AI, 比如网络对战等. 本文只讨论加入 AI 接口一事, AI 的实现算法不做讨论. 现在我们主要面对的还是代码.

给出我的设计思路, 抛砖引玉尔.

AI 和 GUI 之间使用 BOARD 类作为媒介, 该类保存了棋盘状态, 并且提供棋盘的操作函数, 还有一个独立的判断输赢的函数. 之前还定义了一个 SearchArea 类用于 AI 减小查找面积. 我们来看代码:

#include <iostream>#include <cstring>#include <cstdlib>#include <iomanip>#include <climits>#include <ctime>#include <conio.h>#include <windows.h>using namespace std;#ifndef BOARD_H#define BOARD_H//define constant varibles refer to the playerNo#ifndef PLAYERconst int PLAYER1=1;const int PLAYER2=2;const int EMPTYPLAYER=0;//no stone on the position#endifstruct SearchArea{ int top, left, right, bottom; int exTop, exLeft, exRight, exBottom;//extended area SearchArea(){top=1,left=1,right=1,bottom=1;} SearchArea(int t, int l, int r, int b){top=t,left=l,right=r,bottom=b;} void extendArea(int inc, int height, int width);//extends the search are by inc};class BOARD{ public:  int width;  int height;  int counter_Player1;  int counter_Player2;  int counter_EmptyPos;  SearchArea searchArea;  char *board;//stores the board matrix into a linear structor  BOARD();//default constructor  BOARD(int w, int h);//constructor with w and h  BOARD(const BOARD& b);//copy constructor  ~BOARD();//destructor  char operator ()(int x = 15, int y = 15);//return the value on board[x,y](x,y start from 1)  void move(int x, int y, int playerNo);//put a stone into the board, 0 for legal while -1 for illegal move};//judge the winnerbool isWinned(BOARD & board, int x, int y, int player);#endif


代码中变量名比较长, 但是很容易理解就不给详细注释了. 接下来看一看这个 SearchArea 是怎么工作的.


途中红色线是棋子组成的方框的四个边, 蓝色框子是用于搜索的 Extended Area, 图示中增量为 1. 显然搜索蓝色框速度比搜索整个棋盘快很多, 因为五子棋和围棋不同, 不需要考虑完全孤立的地区, 那些地方放置的棋子难以形成有效杀伤.

BOARD 的定义和操作部分文件打包后提供下载.

既然前文说了 BOARD 类是 GUI 和 AI 的桥梁, 那么我们可以这样设计 AI 接口:

void computerMove(BOARD& board, int playerToBeEvaluated, int& row, int& col);

其中 playerToBeEvaluated 变量告诉 AI 要评估的一方是 PLAYER1 还是 PLAYER2 (黑方还是白方), row 和 col 用于保存 AI 决定要走的步子, 之后这两个变量用于更新 GUI 上相应的部分.

有了这等利器, 那么我们就可以把 GUI 和 BOARD 结合起来了, 先看界面函数的定义, 可以发现和前文相比, startGame 函数多了几个参数:

/**This file defines the GUI written by SDL.The surfaceClass.h is needed.*/#include "wuzi.h"#include "wuziAI.h"#include "surfaceClass.h"#include "buttonClass.h"#include "sdlFont.h"#ifndef SDLGUI_H#define SDLGUI_Hclass SDLGUI{ private:  std::string int2string(int n);//convert int to string  int string2int(std::string str);//convert string to int public:  void startGame(int humanPlayer, int AIPlayer, BOARD& board);};#endif

 

然后看一看实现部分, 这里调用了 AI 接口:

//===================================//the main game loop: startGame()//===================================void SDLGUI::startGame(int humanPlayer, int AIPlayer, BOARD& board){ //constant value const int SCREEN_WIDTH = 800; const int SCREEN_HEIGHT = 600; const int BIT_DEPTH = 32; const Uint32 FLAG = SDL_DOUBLEBUF | SDL_HWSURFACE; const int BOARD_Top = 55;//pixel const int BOARD_Left = 55;//pixel const int BOARD_WIDTH = 490; const int BOARD_HEIGHT = 490; const int PIXEL_PER_GRID = 35; const int BUTTON_X = 605; const int BUTTON_Y = 510; const int BLACK_ICON_X = 600; const int BLACK_ICON_Y = 180; const int WHITE_ICON_X = 600; const int WHITE_ICON_Y = 240; const int TEXT_BLACK_X = 660; const int TEXT_BLACK_Y = 177; const int TEXT_WHITE_X = 660; const int TEXT_WHITE_Y = 237; const int TEXT_TURN_X = 600; const int TEXT_TURN_Y = 320; #ifdef __windows__ SDL_putenv("SDL_VIDEODRIVER=directx"); #endif #ifdef __linux__ SDL_putenv("SDL_VIDEODRIVER=dga"); #endif bool isQuit = false; bool isWin = false; bool isBlackTurn = true; // Alternate each round int row = 0; int col = 0; if (humanPlayer == PLAYER1) isBlackTurn = true; else isBlackTurn = false; ScreenSurface screen(SCREEN_WIDTH, SCREEN_HEIGHT, BIT_DEPTH, FLAG, "MySDL"); PictureSurface backSurface("board.jpg", screen); PictureSurface blackStone("black.png", screen, true); PictureSurface whiteStone("white.png", screen, true); ButtonPlus button("button.png", "button_over.png", "button_press.png", screen, true); TextSurface txtBlackStone(int2string(0), screen, "verdana.ttf", 30, 0x00, 0x00, 0x00); TextSurface txtWhiteStone(int2string(0), screen, "verdana.ttf", 30, 0x00, 0x00, 0x00); TextSurface txtWinning("Your turn", screen, "verdana.ttf", 30, 0x00, 0x00, 0x00); //set back ground image backSurface.blit(); //set start button button.setBtnRegion(BUTTON_X, BUTTON_Y); button.blitOut(); //set stone counter icon and text blackStone.blit(BLACK_ICON_X, BLACK_ICON_Y); whiteStone.blit(WHITE_ICON_X, WHITE_ICON_Y); txtBlackStone.blit(TEXT_BLACK_X, TEXT_BLACK_Y); txtWhiteStone.blit(TEXT_WHITE_X, TEXT_WHITE_Y); txtWinning.blit(TEXT_TURN_X, TEXT_TURN_Y); screen.flip(); while (!isQuit){  //press ESC or click X to quit  SDL_Event gameEvent;  while(SDL_PollEvent(&gameEvent) != 0){   if (gameEvent.type == SDL_QUIT){    isQuit = true;   }   if (gameEvent.type == SDL_KEYUP){    if (gameEvent.key.keysym.sym == SDLK_ESCAPE){     isQuit = true;    }   }   //lay down a stone   if (gameEvent.type == SDL_MOUSEBUTTONDOWN){    if (gameEvent.button.y >= BOARD_Top && gameEvent.button.y <= BOARD_Top + BOARD_HEIGHT     && gameEvent.button.x >= BOARD_Left && gameEvent.button.x <= BOARD_Left + BOARD_WIDTH){      row = (gameEvent.button.y - BOARD_Top) / PIXEL_PER_GRID;      col = (gameEvent.button.x - BOARD_Left) / PIXEL_PER_GRID;      if ((gameEvent.button.y - BOARD_Top) % PIXEL_PER_GRID > (PIXEL_PER_GRID / 2)){       row++;      }      if ((gameEvent.button.x - BOARD_Left) % PIXEL_PER_GRID > (PIXEL_PER_GRID / 2)){       col++;      }      //lay down a stone      if (board(row, col) == EMPTYPLAYER && !isWin){       board.move(row, col, humanPlayer);       if (isBlackTurn){        isBlackTurn = !isBlackTurn;        blackStone.blit(BOARD_Left + col * PIXEL_PER_GRID - PIXEL_PER_GRID / 2,          BOARD_Top + row * PIXEL_PER_GRID - PIXEL_PER_GRID / 2);        //API BOARD board.counter_black        txtBlackStone.setMessage(int2string(board.counter_Player1));        backSurface.blit(TEXT_BLACK_X, TEXT_BLACK_Y, TEXT_BLACK_X, TEXT_BLACK_Y, txtBlackStone.getWidth(), txtBlackStone.getHeight());        txtBlackStone.blit(TEXT_BLACK_X, TEXT_BLACK_Y);       }       else{        //white player's turn        isBlackTurn = !isBlackTurn;        whiteStone.blit(BOARD_Left + col * PIXEL_PER_GRID - PIXEL_PER_GRID / 2,          BOARD_Top + row * PIXEL_PER_GRID - PIXEL_PER_GRID / 2);        //API BOARD board.counter_white        txtWhiteStone.setMessage(int2string(board.counter_Player2));        backSurface.blit(TEXT_WHITE_X, TEXT_WHITE_Y, TEXT_WHITE_X, TEXT_WHITE_Y, txtWhiteStone.getWidth(), txtWhiteStone.getHeight());        txtWhiteStone.blit(TEXT_WHITE_X, TEXT_WHITE_Y);       }       txtWinning.setMessage("AI's turn");       backSurface.blit(TEXT_TURN_X, TEXT_TURN_Y, TEXT_TURN_X, TEXT_TURN_Y, txtWinning.getWidth() + 50, txtWinning.getHeight());       txtWinning.blit(TEXT_TURN_X, TEXT_TURN_Y);       screen.flip();       if (isWinned(board, row, col, humanPlayer)){        //textSurface is winned        txtWinning.setMessage("You WIN!");        backSurface.blit(TEXT_TURN_X, TEXT_TURN_Y, TEXT_TURN_X, TEXT_TURN_Y, txtWinning.getWidth() + 50, txtWinning.getHeight());        txtWinning.blit(TEXT_TURN_X, TEXT_TURN_Y);        isWin = true;        break;       }       //call AI       computerMove(board, (humanPlayer == PLAYER1)? PLAYER2 : PLAYER1, row, col);       if (isBlackTurn){        isBlackTurn = !isBlackTurn;        blackStone.blit(BOARD_Left + col * PIXEL_PER_GRID - PIXEL_PER_GRID / 2,          BOARD_Top + row * PIXEL_PER_GRID - PIXEL_PER_GRID / 2);        //API BOARD board.counter_black        txtBlackStone.setMessage(int2string(board.counter_Player1));        backSurface.blit(TEXT_BLACK_X, TEXT_BLACK_Y, TEXT_BLACK_X, TEXT_BLACK_Y, txtBlackStone.getWidth(), txtBlackStone.getHeight());        txtBlackStone.blit(TEXT_BLACK_X, TEXT_BLACK_Y);       }       else{        //white player's turn        isBlackTurn = !isBlackTurn;        whiteStone.blit(BOARD_Left + col * PIXEL_PER_GRID - PIXEL_PER_GRID / 2,          BOARD_Top + row * PIXEL_PER_GRID - PIXEL_PER_GRID / 2);        //API BOARD board.counter_white        txtWhiteStone.setMessage(int2string(board.counter_Player2));        backSurface.blit(TEXT_WHITE_X, TEXT_WHITE_Y, TEXT_WHITE_X, TEXT_WHITE_Y, txtWhiteStone.getWidth(), txtWhiteStone.getHeight());        txtWhiteStone.blit(TEXT_WHITE_X, TEXT_WHITE_Y);       }       txtWinning.setMessage("Your turn");       backSurface.blit(TEXT_TURN_X, TEXT_TURN_Y, TEXT_TURN_X, TEXT_TURN_Y, txtWinning.getWidth() + 50, txtWinning.getHeight());       txtWinning.blit(TEXT_TURN_X, TEXT_TURN_Y);       if (isWinned(board, row, col, (humanPlayer == PLAYER1)? PLAYER2 : PLAYER1)){        //textSurface is winned        txtWinning.setMessage("AI WIN!");        backSurface.blit(TEXT_TURN_X, TEXT_TURN_Y, TEXT_TURN_X, TEXT_TURN_Y, txtWinning.getWidth() + 50, txtWinning.getHeight());        txtWinning.blit(TEXT_TURN_X, TEXT_TURN_Y);        isWin = true;        break;       }      }    }//if in board   }//if mouse down   //change button's look   if (button.mouseOver(gameEvent) == true){    button.blitOver();   }   else if (button.mouseDown(gameEvent) == true){    button.blitDown();   }   else{    button.blitOut();   }   //if game start btn is pressed   if (button.effectiveClick(gameEvent) == true){    //reset the game    backSurface.blit();    button.blitOut();    txtBlackStone.setMessage("0");    txtWhiteStone.setMessage("0");    //set stone counter icon and text    blackStone.blit(BLACK_ICON_X, BLACK_ICON_Y);    whiteStone.blit(WHITE_ICON_X, WHITE_ICON_Y);    txtBlackStone.blit(TEXT_BLACK_X, TEXT_BLACK_Y);    txtWhiteStone.blit(TEXT_WHITE_X, TEXT_WHITE_Y);    isWin = false;    board.clear();   }   screen.flip();  }//while  SDL_Delay(10); }//main loop return;}

至此就搭建好 GUI 和用户以及 AI 的结构了, 之后就专心研究函数 computerMove() 怎么实现吧.

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 走路走多了脚痛怎么办 胃疼怎么办简单按摩法 经常胃疼的厉害怎么办 半夜胃疼的厉害怎么办 吃消炎药伤胃了怎么办 吃药伤胃了胃疼怎么办 宝宝吃药伤胃了怎么办 胃胀胃痛怎么办快速解决方法 半夜2点3点胃疼怎么办 晚上吃多了胃疼怎么办 骨折打石膏后痒怎么办 脚脖子崴了肿了怎么办 喝酒喝的吐血了怎么办 感冒后咳嗽有痰怎么办 嗓子里老是有痰怎么办 物业把水停了怎么办 机洗衬衫缩水了怎么办 羊绒大衣洗缩水了怎么办 棉质衣服缩水了怎么办 衣服洗了变小了怎么办 毛衣洗后缩水了怎么办 鼻子又大又塌怎么办 苹果6被停用了怎么办 苹果6s手机停用怎么办 苹果4手机已停用怎么办 苹果手机5停用了怎么办 老公被骗300多万怎么办 苹果手机被抹除怎么办 钓鱼邮件点开了怎么办 幼犬吃多了拉稀怎么办 幼犬半夜醒了叫怎么办 相爱相杀的感情怎么办 冬天玩电脑手冷怎么办 被陌生人骗了钱怎么办 被网上骗了钱怎么办 20岁欠了10万怎么办 我赌博欠了10万怎么办 孩子见到生人不爱说话怎么办 18岁了个子矮小怎么办 1岁宝宝个子矮70怎么办 喋血街头2进监狱怎么办