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() 怎么实现吧.
- SDL 实现五子棋 GUI (三)
- SDL 实现五子棋 GUI (一)
- SDL 实现五子棋 GUI (二)
- SDL 实现五子棋 GUI (四) Code::Blocks 的配置
- vc配合sdl编写五子棋游戏
- SDL入门学习之三.加载BMP图片,实现动画
- SDL之三
- SDL资料(三):DC++
- SDL学习(三)
- Unity3D学习(2)——GUI五子棋
- Digital Oscilloscope GUI base on SDL.
- 五子棋设计与实现
- VB.net实现五子棋
- 五子棋算法实现
- QQ五子棋外挂实现
- 如何实现简单五子棋?
- C实现的五子棋
- 一步一步实现五子棋1
- inline函数使用方法之二
- int/int 返回整数
- 好久没有见过的彩虹
- 关于 Java Collections API
- ZOJ-3635-Cinema in Akiba
- SDL 实现五子棋 GUI (三)
- linux 下 mysql自动备份脚本
- UIImagePickerController学习
- 从零开始学习OpenGL ES之一 – 基本概念
- 从零开始学习OpenGL ES之二 – 简单绘图概述
- 推荐一系列优秀的Android开发源码
- 从零开始学习OpenGL ES之三 – 透视
- Visual Studio Tips:关闭XAML Designer
- 使用Tomcat数据源