天天看點

c語言黑白棋ai遊戲源碼

#include <graphics.h>   // EasyX_2011驚蟄版
#include <strstream>
#include <ctime>
#pragma comment(lib, "Winmm.lib")
#define T(c) ((c == 'B') ? 'W' : 'B')
using namespace std;
 
// 來自公衆号:c語言與cpp程式設計
 
/*******************************定義全局變量*****************************/
const int difficult = 6;    // 難度
const int move[8][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1},
                        {-1, -1}, {1, -1}, {1, 1}, {-1, 1}};
                            // 八個方向擴充
char map[8][8];             // 棋盤
IMAGE img[5];               // 儲存圖檔
int black, white;           // 雙方的棋子數
int X, Y;                   // 白棋的下子點
 
/**********************************函數聲明*****************************/
void load(void);                // 加載素材
void print(void);               // 畫棋盤
void draw(int, int, char);      // 下目前子
int judge(int, int, char);      // 判斷目前是否可以落下
bool baidu(char);               // 判斷是否有棋可吃
bool quit(char);                // 判斷是否有棋存活
bool ask(void);                 // 彈出對話框
int D(char, int);               // 動态規劃
void play(void);                // 遊戲過程
 
/**********************************定義函數*****************************/
void load(void)     // 加載素材
{
    // 加載圖檔
    loadimage(&img[0], "圖檔\\空位.bmp");
    loadimage(&img[1], "圖檔\\黑子.bmp");
    loadimage(&img[2], "圖檔\\白子.bmp");
    loadimage(&img[3], "圖檔\\黑子1.bmp");
    loadimage(&img[4], "圖檔\\白子1.bmp");
 
    // 加載音樂
    mciSendString("open 音樂\\背景音樂.wma", NULL, 0, NULL);
    mciSendString("open 音樂\\和局.wma", NULL, 0, NULL);
    mciSendString("open 音樂\\勝利.wma", NULL, 0, NULL);
    mciSendString("open 音樂\\失敗.wma", NULL, 0, NULL);
    mciSendString("open 音樂\\下子.wma", NULL, 0, NULL);
 
    // 初始化棋盤
    initgraph(340, 340);
    IMAGE qipan;
    loadimage(&qipan, "圖檔\\棋盤.bmp");
    putimage(0, 0, &qipan);
    setorigin(26, 26);
    SetWindowText(GetHWnd(), "黑白棋AI版");
}
 
void print(void)    // 畫棋盤
{
    int x, y;
    black = white = 0;
    for(x = 0; x < 8; x++)
        for(y = 0; y < 8; y++)
            switch(map[x][y])
            {
                case 0:
                        putimage(37 * y, 37 * x, &img[0]);
                    break;
                case 'B':
                        putimage(37 * y, 37 * x, &img[1]);
                    black++;
                    break;
                case 'W':
                        putimage(37 * y, 37 * x, &img[2]);
                    white++;
                    break;
            }
}
 
void draw(int x, int y, char a) // 下目前子
{
    char b = T(a);                                  // 敵方子
    int i, x1, y1, x2, y2;
    bool sign;          
    for (i = 0; i < 8; i++)
    {
        sign = false;
        x1 = x + move[i][0];
        y1 = y + move[i][1];
        while (0 <= x1 && x1 < 8 && 0 <= y1 && y1 < 8 && map[x1][y1])
        {
            if(map[x1][y1] == b)
                sign = true;
            else
            {
                if(sign)
                {
                    x1 -= move[i][0];
                    y1 -= move[i][1];
                    x2 = x + move[i][0];
                    y2 = y + move[i][1];
                    while (((x <= x2 && x2 <= x1) || (x1 <= x2 && x2 <= x)) && ((y <= y2 && y2 <= y1) || (y1 <= y2 && y2 <= y)))
                    {
                        map[x2][y2] = a;
                        x2 += move[i][0];
                        y2 += move[i][1];
                    }
                }
                break;
            }
            x1 += move[i][0];
            y1 += move[i][1];
        }
    }
    map[x][y] = a;
}
 
int judge(int x, int y, char a) // 判斷目前是否可以落下,同draw函數
{
    if(map[x][y])                       // 如果目前不是空的傳回0值
        return 0;
    char b = T(a);
    int i, x1, y1;
    int n = 0, sign;
    for (i = 0; i < 8; i++)
    {
        sign = 0;
        x1 = x + move[i][0];
        y1 = y + move[i][1];
        while (0 <= x1 && x1 < 8 && 0 <= y1 && y1 < 8 && map[x1][y1])
        {
            if(map[x1][y1] == b)
                sign++;
            else
            {
                n += sign;
                break;
            }
            x1 += move[i][0];
            y1 += move[i][1];
        }
    }
    return n;       // 傳回可吃棋數
}
 
bool baidu(char c)  // 判斷是否有棋可吃
{
    int x, y;
    for(x = 0; x < 8; x++)
        for(y = 0; y < 8; y++)
            if(judge(x, y, c))
                return true;
    return false;
}
 
bool quit(char c)   // 判斷是否有棋存活
{
    int x, y;
    bool b = false, w = false;
    for(x = 0; x < 8; x++)
        for(y = 0; y < 8; y++)
        {
            if(map[x][y] == c)
                return false;
        }
    return true;
}
 
bool ask(void)  // 彈出對話框
{
    HWND wnd = GetHWnd();
    int key;
    char str[50];
    ostrstream strout(str, 50);
    strout <<"黑:" <<black <<"  白:" <<white <<endl;
    if (black == white)
        strout <<"世界和平";
    else if(black > white)
        strout <<"恭喜你赢了!";
    else
        strout <<"小樣,還想赢我。";
    strout <<"\n再來一局嗎?" <<ends;
    if(black == white)
        key = MessageBox(wnd, str, "和局", MB_YESNO | MB_ICONQUESTION);
    else if(black > white)
        key = MessageBox(wnd, str, "黑勝", MB_YESNO | MB_ICONQUESTION);
    else
        key = MessageBox(wnd, str, "白勝", MB_YESNO | MB_ICONQUESTION);
    if(key == IDYES)
        return true;
    else
        return false;
}
 
int D(char c, int step)
{
    // 判斷是否結束遞歸
    if (step > difficult)   // 限制步數之内
        return 0;
    if (!baidu(c))
    {
        if (baidu(T(c)))
            return -D(T(c), step);
        else
            return 0;
    }
 
    int i, j, max = 0, temp, x, y;
    bool ans = false;
 
    // 建立臨時數組
    char **t = new char *[8];
    for (i = 0; i < 8; i++)
        t[i] = new char [8];
    for (i = 0; i < 8; i++)
        for (j = 0; j < 8; j++)
            t[i][j] = map[i][j];
 
    // 搜尋解法
    for (i = 0; i < 8; i++)
        for (j = 0; j < 8; j++)
            if (temp = judge(i, j, c))
            {
                draw(i, j, c);
                temp -= D(T(c), step + 1);
                if (temp > max || !ans)
                {
                    max = temp;
                    x = i;
                    y = j;
                    ans = true;
                }
                for (int k = 0; k < 8; k++)
                    for (int l = 0; l < 8; l++)
                        map[k][l] = t[k][l];
            }
 
    // 撤銷空間
    for (i = 0; i < 8; i++)
        delete [] t[i];
    delete [] t;
 
    // 如果是第一步則辨別白棋下子點
    if (step == 1)
    {
        X = x;
        Y = y;
    }
 
    return max; // 返會最優解
}
 
void play(void)         // 遊戲過程
{
    MOUSEMSG m;
    int x, y;
 
    // 初始化棋子
    for(x = 0; x < 8; x++)
        for(y = 0; y < 8; y++)
            map[x][y] = 0;
    map[3][4] = map[4][3] = 'B';
    map[3][3] = map[4][4] = 'W';
 
    // 開始遊戲
    print();
    mciSendString("play 音樂\\背景音樂.wma from 0 repeat", NULL, 0, NULL);
    do
    {
        if (baidu('B'))                                     // 如果玩家有下子位置                            
        {
            A:
            while(true)
            {
                m = GetMouseMsg();                          // 擷取滑鼠消息
                if(m.uMsg == WM_LBUTTONDOWN && m.x - 26 < 37 * 8 && m.y - 26 < 37 * 8)
                                                            // 如果左鍵點選
                    break;
            }
            x = (m.y - 26) / 37;
            y = (m.x - 26) / 37;
            if(judge(x, y, 'B'))                            // 如果目前位置有效
            {
                draw(x, y, 'B');                            // 下子
                mciSendString("play 音樂\\下子.wma from 0", NULL, 0, NULL);
                print();
                putimage(37 * y, 37 * x, &img[3]);          // 辨別下子點
            }
            else
                goto A;
            if (quit('W'))                                  // 計算機是否失敗
                break;
        }
        if (baidu('W'))                                     // 如果計算機有下子位置
        {
            clock_t start;
            start = clock();
            D('W', 1);                                      // 搜尋解法
            while (clock() - start < CLOCKS_PER_SEC);
            draw(X, Y, 'W');
            print();
            mciSendString("play 音樂\\下子.wma from 0", NULL, 0, NULL);
            putimage(37 * Y, 37 * X, &img[4]);  // 辨別下子點
            if (quit('B'))                                  // 玩家是否失敗
                break;
        }
    }while (baidu('B') || baidu ('W'));
 
    // 播放慶祝音樂
    mciSendString("stop 音樂\\背景音樂.wma", NULL, 0, NULL);
    if (black > white)
        mciSendString("play 音樂\\勝利.wma from 0", NULL, 0, NULL);
    else if (black < white)
        mciSendString("play 音樂\\失敗.wma from 0", NULL, 0, NULL);
    else
        mciSendString("play 音樂\\和局.wma from 0", NULL, 0, NULL);
}
 
// 主函數
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    load();
    do
    {
        play();
    } while(ask());
 
    // 關閉音樂
    mciSendString("close 音樂\\背景音樂.wma", NULL, 0, NULL);
    mciSendString("close 音樂\\和局.wma", NULL, 0, NULL);
    mciSendString("close 音樂\\勝利.wma", NULL, 0, NULL);
    mciSendString("close 音樂\\失敗.wma", NULL, 0, NULL);
    mciSendString("close 音樂\\下子.wma", NULL, 0, NULL);
    closegraph();
    return 0;
}
 
/***********************************THE END************************************/

      

繼續閱讀