五子棋 AI + GDI 绘图 v0.8

Posted thename

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了五子棋 AI + GDI 绘图 v0.8相关的知识,希望对你有一定的参考价值。

// Gm.cpp : 定义应用程序的入口点。
//
#include <string>
#include "framework.h"
#include "Gm.h"

int BLACK_AI=0,WHITE_AI=1;

int brd[361];
int broad[19][19];
int step=0;
const int windowSize=924,gridSize=44,chessSize=17;

#define A(x,y) ((x)+(y)*19)

#define BlacK (1)
#define NonE (0)
#define WhitE (2)

constexpr int OP(int who){return 3-who;}

long long typeCount[16];
inline int At(int x,int y) {
    if (x>=0&&x<19&&y>=0&&y<19) return broad[x][y];
    else return 3;
}

class Solution {
    typedef long long int64;
public:
    static const int bSz=19;
    void count(int x,int y,int p) {
        static const int dr[4][2]={{1,0},{1,1},{0,1},{1,-1}};
        memset(typeCount,0,sizeof(typeCount));
        for (int di=0;di<4;++di) {
            int dx=dr[di][0],dy=dr[di][1];
            int nx=x+dx,ny=y+dy,mx=x-dx,my=y-dy;
            while (At(nx,ny)==p) nx+=dx,ny+=dy;
            while (At(mx,my)==p) mx-=dx,my-=dy;
            int j1=0,j2=0;
            if (At(nx,ny)==0) {
                for (j1=1;At(nx+dx*j1,ny+dy*j1)==p;++j1);
            }
            if (At(mx,my)==0) {
                for (j2=1;At(mx-dx*j2,my-dy*j2)==p;++j2);
            }
            int jpo=0;
            if (j1>=j2) jpo=(At(nx+dx*j1,ny+dy*j1)==0);
            if (j1<=j2) jpo|=(At(mx-dx*j2,my-dy*j2)==0);
            if (dx) dx=abs(mx-nx)-1;
            else dx=abs(my-ny)-1;
            if (dx>=5) {
                ++typeCount[0];
            } else if (j1|j2) {
                int both=(j1&&j2);
                if (j1<j2) j1=j2;
                if (dx==4) {
                    if (both) ++typeCount[1];
                    else ++typeCount[2];
                } else if (dx+j1>4) {
                    ++typeCount[2];
                    typeCount[7]-=2;
                } else if (dx==3) {
                    if (both&&jpo) ++typeCount[3];
                    else if (jpo||both) ++typeCount[4];
                } else if (dx+j1==4) {
                    if (jpo&&both) ++typeCount[5];
                    else if (jpo||both) ++typeCount[6];
                } else if (dx+j1>2&&jpo) {
                    ++typeCount[7];
                }
            }
        }
    }
}solution;

const long long factor[16]={0x3000000ll,0x700000ll,0x00160000,0x000f0000,0x00001000,0x000b1000,0x00000b00,0x700},
    r5=0x0100000000000000ll,r_4=0x70000000ll,r4=0x00100000,r_3=0x000f0000,r3=0x00001000;

long long runai(int &x,int &y,int who,int depth=0) {
    long long mxval=0,now=0,op;
    for (int i=0;i<19;++i) {
        for (int j=0;j<19;++j) {
            if (broad[i][j]) continue;
            now=1;
            op=0;
            solution.count(i,j,who);
            if (typeCount[0]) {
                x=i;y=j;
                return factor[0]*16;
            }
            for (int k=1;k<8;++k) now+=typeCount[k]*factor[k];
            if (now>factor[0]) now=factor[0];
            else if (now>factor[1]) now=factor[1];
            else if (now>factor[2]*2) now=factor[2]*2;

            solution.count(i,j,OP(who));
            if (typeCount[0]) {
                x=i;y=j;
                mxval=0x3000000ll;
            }
            for (int k=0;k<8;++k) op+=typeCount[k]*factor[k];
            if (op>factor[0]) op=factor[0];
            else if (op>factor[1]) op=factor[1];
            else if (op>factor[2]*2) op=factor[2]*2;
            /*if (typeCount[0]) {
                MessageBox(NULL,L"QAQ",L"aa",0);
            }*/
            if (op<0x001f0000) op/=2;
            now=now*16+op*10;
            if (depth<1) {
                int xx,yy,x3,y3,x4,y4;
                broad[i][j]=who;
                now -= runai(xx,yy,OP(who),depth+1)/4;
                broad[xx][yy]=OP(who);
                now+= runai(x3,y3,who,depth+1)/16;
                //broad[x3][y3]=who;
                //now -= runai(x4,y4,OP(who),depth+1)/96;
                //broad[x3][y3]=0;
                broad[xx][yy]=0;
                broad[i][j]=0;
            }
            if (now>mxval||(now==mxval&&rand()%4==0)) {
                mxval=now;
                x=i;
                y=j;
            }
        }
    }
    return mxval;
}

void  draw(HDC hdc){
    HPEN hpen1 = CreatePen(PS_SOLID,1,RGB(139,90,43));
    HBRUSH hbrush1 = CreateSolidBrush(RGB(139,90,43));
    SelectObject(hdc,hpen1);
    SelectObject(hdc,hbrush1);
    Rectangle(hdc,0,0,windowSize,windowSize);
    hpen1 = CreatePen(PS_SOLID,1,RGB(0,0,0));
    hbrush1 = CreateSolidBrush(RGB(0,0,0));    
    SelectObject(hdc,hpen1);
    SelectObject(hdc,hbrush1);
    for (int i=0;i<19;++i) {
        MoveToEx(hdc,gridSize*(i+1),gridSize,NULL);
        LineTo(hdc,gridSize*(i+1),gridSize*19);
        MoveToEx(hdc,gridSize,gridSize*(i+1),NULL);
        LineTo(hdc,gridSize*19,gridSize*(i+1));
    }
    for (int i=0;i<19;++i) {
        for (int j=0;j<19;++j) {
            if (broad[j][i]==1) {
                Ellipse(hdc,gridSize*(i+1)-chessSize,gridSize*(j+1)-chessSize,
                  gridSize*(i+1)+chessSize,gridSize*(j+1)+chessSize);
            }
        }
    }
    hpen1 = CreatePen(PS_SOLID,1,RGB(255,255,255));
    hbrush1 = CreateSolidBrush(RGB(255,255,255));
    SelectObject(hdc,hpen1);
    SelectObject(hdc,hbrush1);
    for (int i=0;i<19;++i) {
        for (int j=0;j<19;++j) {
            if (broad[j][i]==2) {
                Ellipse(hdc,gridSize*(i+1)-chessSize,gridSize*(j+1)-chessSize,
                  gridSize*(i+1)+chessSize,gridSize*(j+1)+chessSize);
            }
        }
    }
}

using namespace std;

#define MAX_LOADSTRING 100

// 全局变量:
HINSTANCE hInst;                                // 当前实例
WCHAR szTitle[MAX_LOADSTRING];                  // 标题栏文本
WCHAR szWindowClass[MAX_LOADSTRING];            // 主窗口类名

// 此代码模块中包含的函数的前向声明:
ATOM                MyRegisterClass(HINSTANCE hInstance);
BOOL                InitInstance(HINSTANCE, int);
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPWSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    // TODO: 在此处放置代码。
    srand(GetTickCount64());
    // 初始化全局字符串
    LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadStringW(hInstance, IDC_GM, szWindowClass, MAX_LOADSTRING);
    MyRegisterClass(hInstance);

    // 执行应用程序初始化:
    if (!InitInstance (hInstance, nCmdShow))
    {
        return FALSE;
    }

    HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_GM));

    MSG msg;

    // 主消息循环:
    while (GetMessage(&msg, nullptr, 0, 0))
    {
        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    return (int) msg.wParam;
}



//
//  函数: MyRegisterClass()
//
//  目标: 注册窗口类。
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEXW wcex;

    wcex.cbSize = sizeof(WNDCLASSEX);

    wcex.style          = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = WndProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = hInstance;
    wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_GM));
    wcex.hCursor        = LoadCursor(nullptr, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName   = MAKEINTRESOURCEW(IDC_GM);
    wcex.lpszClassName  = szWindowClass;
    wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

    return RegisterClassExW(&wcex);
}

//
//   函数: InitInstance(HINSTANCE, int)
//
//   目标: 保存实例句柄并创建主窗口
//
//   注释:
//
//        在此函数中,我们在全局变量中保存实例句柄并
//        创建和显示主程序窗口。
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   hInst = hInstance; // 将实例句柄存储在全局变量中

   HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0,windowSize,windowSize, nullptr, nullptr, hInstance, nullptr);

   if (!hWnd)
   {
      return FALSE;
   }

   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   return TRUE;
}

//
//  函数: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  目标: 处理主窗口的消息。
//
//  WM_COMMAND  - 处理应用程序菜单
//  WM_PAINT    - 绘制主窗口
//  WM_DESTROY  - 发送退出消息并返回
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    POINT pt;
    wstring s;
    switch (message)
    {
    case WM_PAINT:
        {
            GetCursorPos(&pt);
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, &ps);
            draw(hdc);
            ReleaseDC(hWnd,hdc);
            EndPaint(hWnd, &ps);
            //InvalidateRect(hWnd,NULL,TRUE);
        }
        break;
    case WM_LBUTTONDOWN: // WM_LBUTTONDOWN是鼠标左键按下的事件“枚举”
    {
        GetCursorPos(&pt);
        ScreenToClient(hWnd,&pt);
        int x=(pt.y-gridSize/2)/gridSize,y=(pt.x-gridSize/2)/gridSize;
        if (step==0) {
            x=9;y=9;
            broad[x][y]=step%2+1;
            ++step;
            InvalidateRect(hWnd,NULL,TRUE);
            break;
        }
        if (x>=0&&x<19&&y>=0&&y<19&&broad[x][y]==0) {
            broad[x][y]=step%2+1;
            solution.count(x,y,step%2+1);
            //wstring out;
            //for (int i=0;i<8;++i) out+=to_wstring(typeCount[i])+L",";
            ++step;
            InvalidateRect(hWnd,NULL,TRUE);
            if (typeCount[0]) {
                step=0;
                MessageBox(hWnd,L"YOU WIN!",L"win",0);
                memset(broad,0,sizeof(broad));
                InvalidateRect(hWnd,NULL,TRUE);
                break;
            }
            if (WHITE_AI) {
                runai(x,y,step%2+1);
                solution.count(x,y,step%2+1);
                broad[x][y]=step%2+1;
                ++step;
                InvalidateRect(hWnd,NULL,TRUE);
                
                if (typeCount[0]) {
                    step=0;
                    MessageBox(hWnd,L"YOU LOSE!",L"lose",0);
                    memset(broad,0,sizeof(broad));
                    InvalidateRect(hWnd,NULL,TRUE);
                    break;
                }
            }
        }
        
        break;
    }
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

 

以上是关于五子棋 AI + GDI 绘图 v0.8的主要内容,如果未能解决你的问题,请参考以下文章

C# winform GDI+ 五子棋 :基本界面和胜负判断

在 Qt 中通过 Windows GDI 绘图

五子棋AI算法-重构代码

使用 gdi+ 进行无闪烁绘图

五子棋AI算法-Zobrist

GDI Win32 绘图图