一、项目简介

 

• 项目内容:结对编程,将传统平面二维五子棋改写为三维空间五子棋

• 编程语言:C++、openGL

• 开发环境:Microsoft Visual Studio 2013集成环境

• 人员分工:本人负责2维转化3维图形界面程序编写,肖负责五子棋人机对战程序编写

二、功能展示

我们程序实现的3维五子棋场景是在一个房间里面的桌子上下棋,改变了传统只有2维棋盘的下棋方式,具有更好的趣味性、空间性和灵活性。

下面是最开始进入游戏的画面:

android人机五子棋 人机五子棋编程_鼠标坐标

进入游戏后,可以通过键鼠交互改变视角,得到最佳的下棋角度。实现的交互功能:

1、鼠标左击,使“眼睛”看向鼠标点击的方向;

2、按下键盘按键‘a’、‘d’分别向左向右旋转视角;按下键盘‘w’、‘s’分别向当前视线方向向前向后移动“眼睛”位置;

 

键鼠共同操作得到多个视角的场景:

 

android人机五子棋 人机五子棋编程_android人机五子棋_02

android人机五子棋 人机五子棋编程_结对编程_03

在调整好下棋视角后,按下'f'键(代表fix)固定视角,开始下棋,下面是多个不同视角下棋时和下棋结束时的图片:

android人机五子棋 人机五子棋编程_android人机五子棋_04

 玩家执黑棋,电脑白棋,在每下完一步后会有绿色边框显示最后一步。

android人机五子棋 人机五子棋编程_Game_05

上图为电脑赢,赢后会有红线连接5颗棋子,并锁定屏幕无法再下子。

android人机五子棋 人机五子棋编程_Game_06

在下棋时或结束后,可以按下'r'键,重置棋盘进行下一局。上图为第二局,黑棋胜利。可以看见与上上图 ,我们的视角有所改变,我们在结束后改变了视角:若当前处于固定视角状态,按下f键会修改为活动状态,即可调整视角。

三、设计思路与实现

android人机五子棋 人机五子棋编程_结对编程_07

左图为工程结构图。本次程序抽象出了4个类:Scene、Eye、ChessBoard、Game。其定义分别为:

Scene类主要负责绘制游戏场景,房间和桌子。

使用指定顶点图元画GL_QUADS和用glutSolidCube()函数画体。为了增加真实感,还用了纹理贴图。

class Scene
{
public:
    static void drawScene();
public:
    static const int house_length;
    static const int house_width;
    static const int house_height;

    static const int desk_length;
    static const int desk_width;
    static const int desk_thickness;
    
    static const int leg_height;
    static const int leg_margin;
};

Eye类则负责根据键鼠交互,计算视角。

在鼠标点击时,调用对应的callback函数,得到的鼠标坐标为光标的屏幕位置。因此,需要逆变换得到三维空间坐标,其OpenGL函数为gluUnProject()。此即为视线上的点,可以直接作为gluLookAt()的第4、5、6个参数。在重绘时就可以看见视线方向的变化。

键、鼠交互函数的注册分别用glutKeyboardFunc(&myKeyBoard); glutMouseFunc(&myMouse);

 

class Eye
{
public:
    static void CalcPos(bool back);
    static void CalcMousePos(int x,int y);
public:
    /*the position of eyes*/
    static float pos_x;
    static float pos_z;
    static float pos_y;
    /*视线上一点的坐标(鼠标的世界坐标)*/
    static float mouse_x;
    static float mouse_y;
    static float mouse_z;
    /*是否为固定状态*/
    static bool fixed;
};

ChessBoard类则绘制棋盘及与下棋相关的画面,比如棋子,最后一步的边框以及结束时的五子连珠红线。

在下棋的时候用到了openGL提供的鼠标挑选机制,进行下棋。

class ChessBoard
{
public:
    static const int board_len;
    static const int board_y;
public:
    static void drawBoard(GLenum mode);
};

Game类则为肖实现的人机对战程序。

电脑的实现机制AI,在人落子之后,电脑扫描整个棋盘,看看是否有三颗棋子相连的地方,看看有没有四颗棋子相连的地方,如果有的话,落下最后一字,即能取得最终的胜利。人是根据电脑落子后进行落子。实际上,是根据当前最后一个落子的情况来判断胜负的。需要从四个位置判断,以该子为出发点的水平,竖直和两条分别为 45度角和135度角的线,目的是看在这四个方向是否最后落子的一方构成连续五个的棋子,如果是的话,就表示该盘棋局已经分出胜负。

class Game
{
public:
    Game();
    void initArray();
    /* 返回-1平局 1玩家赢 2玩家输 */
    int isOver();
    /* 返回-1放置失败 1放置成功 */
    int checkPosition(int row, int column);
    void AIsolve();

public:
//    static int chess[8][8];
    /* 电脑棋子为o 人的为* */
    char data[12][12];
    bool istaked[12][12];
    int lastStepX;
    int lastStepY;
    /*存储最终5子连珠的5个点及连珠模式*/
    int line5pos[2];
    int mode;  //1-4  横 竖 撇 捺
};

 

四、项目总结

本次项目采取结对编程的方式进行。在项目初期,我们两人讨论了项目方向与内容确定做五子棋的2D到3D,然后根据自己的情况分配了各自的任务,每个人下去根据自己的任务找资料学习。在学习阶段,我们也互相交流进一步确定了程序要实现的细节,和整体框架。在感觉思考成熟之后,开始着手编程。编程的时候,大部分时间是两人一起编写,在责任人编写其负责的代码时,另一个人在旁边了解思路,帮助找出错误,并了解如何对接彼此的程序。在编程期间,我们也互相鼓励,战胜编程时的枯燥,最终完成了项目。通过此次项目的完成,我们增进了彼此的友谊,锻炼了编程合作能力,同时也从对方身上学习到了很多编程知识。

此外,此次项目给我最深的感受就是,计算机作为一门实用学科,特别是学习编程,动手实践才是学习最有效率的途径,而不是老是盯着书本。在最初编写代码前,我一直在看openGL红宝书,致力于关注所有的细节。但是我发现,在真正编程的时候,自己所看的内容大部分都忘记了。原因就是,书本上的东西太多了,光看不做既不知道重点,也不可能有很深的印象。而在动手实践的时候,才会真正懂得函数的用法以及需要注意的地方。并且在这种合作编程的项目中,若一个人拖慢了项目进度,会导致其他人也无法进行下去,项目也会因为个人而推迟。