关于四子棋的AI,四子棋高手进

关于四子棋的AI,四子棋高手进,第1张

#include <windows.h>

HINSTANCE hInst

HWND hWnd

ATOMMyRegisterClass(HINSTANCE hInstance)

BOOLInitInstance(HINSTANCE, int)

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM)

void MyPaint()

BOOL XiaQi(int whichPlay, LPARAM lParam)

BOOL IsWin(int whichPlay)

void SetMap()

HBITMAP bmp[3],bg,bufBmp

HDC mdc,hdc,bufDC

int who=1

const int h=11,w=12

const int picH=40,picW=40

int map[w][h]

unsigned long now,pass

void SetMap()

{

for(int i=0i<wi++)

{

for(int j=0j<hj++)

{

map[i][j]=0

}

}

}

int APIENTRY WinMain(HINSTANCE hInstance,

HINSTANCE hPrevInstance,

LPSTR lpCmdLine,

int nCmdShow)

{

MSG msg

MyRegisterClass(hInstance)

if (!InitInstance (hInstance, nCmdShow))

{

return FALSE

}

while( msg.message!=WM_QUIT )

{

if( PeekMessage( &msg, NULL, 0,0 ,PM_REMOVE) )

{

TranslateMessage( &msg )

DispatchMessage( &msg )

}

else

{

now=GetTickCount()

if(pass-now>=40)

{

MyPaint()

}

}

}

return msg.wParam

}

ATOM MyRegisterClass(HINSTANCE hInstance)

{

WNDCLASSEX wcex

wcex.cbSize = sizeof(WNDCLASSEX)

wcex.style = CS_HREDRAW | CS_VREDRAW

wcex.lpfnWndProc = (WNDPROC)WndProc

wcex.cbClsExtra = 0

wcex.cbWndExtra = 0

wcex.hInstance = hInstance

wcex.hIcon = NULL

wcex.hCursor = NULL

wcex.hCursor = LoadCursor(NULL, IDC_ARROW)

wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1)

wcex.lpszMenuName = NULL

wcex.lpszClassName = "canvas"

wcex.hIconSm = NULL

return RegisterClassEx(&wcex)

}

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)

{

hInst = hInstance

hWnd = CreateWindow("canvas", "五子棋" , WS_OVERLAPPEDWINDOW,

CW_USEDEFAULT,0,0, 0, NULL, NULL, hInstance, NULL)

if (!hWnd)

{

return FALSE

}

SetMap()

bmp[0]=(HBITMAP)LoadImage(NULL,"white.bmp",IMAGE_BITMAP,picW,picH,LR_LOADFROMFILE)

bmp[1]=(HBITMAP)LoadImage(NULL,"red.bmp",IMAGE_BITMAP,picW,picH,LR_LOADFROMFILE)

bmp[2]=(HBITMAP)LoadImage(NULL,"black.bmp",IMAGE_BITMAP,picW,picH,LR_LOADFROMFILE)

if(!bmp[0] || !bmp[1] || !bmp[2])

{

MessageBox(hWnd,"找不要需要的资源,程序将退出.","错误提示",MB_ICONERROR)

ExitProcess(0)

}

MoveWindow(hWnd,10,10,640,480,true)

ShowWindow(hWnd, nCmdShow)

UpdateWindow(hWnd)

hdc=GetDC(hWnd)

SetTextColor(hdc,RGB(255,0,0))

TextOut(hdc,500,100,"红方先下棋",strlen("红方先下棋"))

mdc=CreateCompatibleDC(hdc)

bufDC=CreateCompatibleDC(hdc)

bufBmp=CreateCompatibleBitmap(hdc,w*picW,h*picW)

SelectObject(mdc,bufBmp)

MyPaint()

return TRUE

}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

{

int i=0

switch (message)

{

case WM_LBUTTONDOWN:

if(XiaQi(who,lParam))

{

MyPaint()

if(who==1)

{

if(IsWin(who))

{

MessageBox(hWnd,"红方获胜.","恭喜",MB_OK)

SetMap()

}

who=2

SetTextColor(hdc,RGB(0,0,0))

TextOut(hdc,500,100,"轮到黑方下棋",strlen("轮到黑方下棋"))

}

else

{

if(IsWin(who))

{

MessageBox(hWnd,"黑方获胜.","恭喜",MB_OK)

SetMap()

}

who=1

SetTextColor(hdc,RGB(255,0,0))

TextOut(hdc,500,100,"轮到红方下棋",strlen("轮到红方下棋"))

}

}

break

case WM_DESTROY:

for(i=0i<3i++)

{

DeleteObject(bmp[i])

}

ReleaseDC(hWnd,bufDC)

DeleteObject(bufBmp)

ReleaseDC(hWnd,mdc)

ReleaseDC(hWnd,hdc)

PostQuitMessage(0)

break

default:

return DefWindowProc(hWnd, message, wParam, lParam)

}

return 0

}

void MyPaint()

{

SelectObject(mdc,bg)

for(int i=0i<wi++)

{

for(int j=0j<hj++)

{

SelectObject(bufDC,bmp[map[i][j]])

BitBlt(mdc,picW*i,picW*j,picW*w,picH*h,bufDC,0,0,SRCCOPY)

}

}

BitBlt(hdc,0,0,picW*w,picH*h,mdc,0,0,SRCCOPY)

pass=GetTickCount()

}

BOOL XiaQi(int whichPlay, LPARAM lParam)

{

if( LOWORD(lParam) <= picW*w &&LOWORD(lParam)>=0 &&

HIWORD(lParam) <= picH*h &&HIWORD(lParam)>=0)

{

int x=0,y=0

for(int i=1i<=wi++)

{

if( i*picW >= LOWORD(lParam) )

{

x=i

x--

break

}

}

for(int j=1j<=hj++)

{

if( j*picH >= HIWORD(lParam) )

{

y=j

y--

break

}

}

if(whichPlay==1)

{

if(map[x][y]==0)

{

map[x][y]=1

}

else

{

return FALSE

}

}

else

{

if(map[x][y]==0)

{

map[x][y]=2

}

else

{

return FALSE

}

}

return TRUE

}

else

{

return FALSE

}

}

BOOL IsWin(int whichPlay)

{

int num=0

for(int i=0i<wi++)

{

for(int j=0j<hj++)

{

if(whichPlay==1)

{

if(map[i][j]==2 || map[i][j]==0 )

{

num=0

}

if(map[i][j]==1 )

{

num++

if(num==5)

{

return TRUE

}

}

}

else

{

if(map[i][j]==1 || map[i][j]==0)

{

num=0

}

if(map[i][j]==2)

{

num++

if(num==5)

{

return TRUE

}

}

}

}

}

num=0

for( i=0i<wi++)

{

for(int j=0j<hj++)

{

if(whichPlay==1)

{

if(map[j][i]==2 || map[j][i]==0)

{

num=0

}

if(map[j][i]==1)

{

num++

if(num==5)

{

return TRUE

}

}

}

else

{

if(map[j][i]==1||map[j][i]==0)

{

num=0

}

if(map[j][i]==2)

{

num++

if(num==5)

{

return TRUE

}

}

}

}

}

num=0

int k=0

for(i=w-1i>=0i--)

{

for(int j=0j<=ij++)

{

if(whichPlay==1)

{

if(map[j+k][j]==0 || map[j+k][j]==2)

{

num=0

}

if(map[j+k][j]==1)

{

num++

}

if(num==5)

{

return TRUE

}

}

else

{

if(map[j+k][j]==0 || map[j+k][j]==1)

{

num=0

}

if(map[j+k][j]==2)

{

num++

}

if(num==5)

{

return TRUE

}

}

}

num=0

k++

}

num=0

k=0

for(i=w-1i>=0i--)

{

for(int j=0j<=ij++)

{

if(whichPlay==1)

{

if(map[j][j+k]==0 || map[j][j+k]==2)

{

num=0

}

if(map[j][j+k]==1)

{

num++

}

if(num==5)

{

return TRUE

}

}

else

{

if(map[j][j+k]==0 || map[j][j+k]==1)

{

num=0

}

if(map[j][j+k]==2)

{

num++

}

if(num==5)

{

return TRUE

}

}

}

num=0

k++

}

num=0

for(i=0i<wi++)

{

k=i

for(int j=w-1j>=ij--,k++)

{

if(whichPlay==1)

{

if(map[j][k]==0 || map[j][k]==2)

{

num=0

}

if(map[j][k]==1)

{

num++

}

if(num==5)

{

return TRUE

}

}

else

{

if(map[j][k]==0 || map[j][k]==1)

{

num=0

}

if(map[j][k]==2)

{

num++

}

if(num==5)

{

return TRUE

}

}

}

num=0

}

num=0

for( i=w-1i>=0i--)

{

k=0

for(int j=ij>=0j--,k++)

{

if(whichPlay==1)

{

if(map[j][k]==0 || map[j][k]==2)

{

num=0

}

if(map[j][k]==1)

{

num++

}

if(num==5)

{

return TRUE

}

}

else

{

if(map[j][k]==0 || map[j][k]==1)

{

num=0

}

if(map[j][k]==2)

{

num++

}

if(num==5)

{

return TRUE

}

}

}

num=0

}

return FALSE

}

专门给你写的楼档宴裂主,满意的话补分哦~

发现问题给我发消息,我修正

有简单的ai,最好是两个人玩或者左右互搏

开始的有说明菜单

代码的第三行WIN改成几就是几子棋

#include <stdio.h>

#include <conio.h>

#include <stdlib.h>

#include <string.h>

#define WIN 5

char *view[19][19]

char *const BLACK="○",*const WHITE="●",*const POS="¤"

char *const LT="┌",*const TOP="┬",*const RT="┐"

char *const LEFT="├",*const CENTER="┼",*const RIGHT="┤"

char *const LF="└",*const FOOT="┴",*const RF="┘"

int step[4][2]={1,1,1,-1,1,0,0,1}

int pro

int side

int px,py

int end

int pvc

int pside

int dpx,dpy

int round

int style

void show(int x,int y)

{

int i,j

printf("\t\t%d子棋\n第%d手\n",WIN,round)

for(i=0i<19i++)

{

for(j=0j<19j++)

if(i==x&&j==y)

printf("%s",POS)

else

printf("%s",view[i][j])

puts("")

}

if(side)

printf("\n%s黑方回合",BLACK)

else

printf("\n%s白方回合",WHITE)

}

void login()

{

char sel

getch()

puts("* *** 作说明*\n")

puts("方向↑ : W键 或者 小键盘8")

puts("方向↓ : S键 或者 小键盘5")

puts("方向← : A键 或者 小键盘4")

puts("方向→ : D键 或者 小键盘6")

puts("落子 : 其他任意键\n")

system("pause"祥肆)

system("cls")

puts("*请选择模式*\n")

pvc=0

do

{

pvc=!pvc

if(pvc)

printf("\r单人游戏")

else

printf("\r双行闭人游戏")

sel=getch()

}while(sel!='\r')

puts("\n")

if(pvc)

{

pside=1

do

{

pside=!pside

if(pside)

printf("\r选择黑棋(先行)")

else

printf("\r选择白棋(后行)")

sel=getch()

}while(sel!='\r')

puts("\n")

style=1

do

{

style=!style

if(style)

printf("\r电脑风格进攻")

else

printf("\r电脑风格防守")

sel=getch()

}while(sel!='\r')

}

system("cls")

}

void initial()

{

int i,j

srand(time(NULL))

view[0][0]=LT

for(i=1i<18i++)

view[0][i]=TOP

view[0][18]=RT

for(i=1i<18i++)

{

view[i][0]=LEFT

for(j=1j<18j++)

view[i][j]=CENTER

view[i][18]=RIGHT

}

view[18][0]=LF

for(i=1i<18i++)

view[18][i]=FOOT

view[18][18]=RF

px=9,py=9

end=0

side=1

pro=1

for(i=0i<WINi++)

pro*=WIN

show(px,py)

}

int final(int base,int direction)

{

return

direction==1?18:direction==0?-1:0

}

int judge(int x,int y)

{

int i,j,num,t

for(t=0t<4t++)

{

i=x,j=y,num=1

while(i!=final(i,-step[t][0])

&&j!=final(j,-step[t][1])

&&view[i-step[t][0]][j-step[t][1]]==view[x][y])

i-=step[t][0],j-=step[t][1],num++

i=x,j=y

while(i!=final(i,step[t][0])

&&j!=final(j,step[t][1])

&&view[i+step[t][0]][j+step[t][1]]==view[x][y])

i+=step[t][0],j+=step[t][1],num++

if(num>=WIN)

return 1

}

return 0

}

void move()

{

char cmd=getch()

switch(cmd)

{

case 119:case 56:

if(!px)

px=18

else

px--break

case 115:case 53:

if(px==18)

px=0

else

px++break

case 97: case 52:

if(!py)

py=18

else

py--break

case 100:case 54:

if(py==18)

py=0

else

py++break

default:

if(view[px][py]!=BLACK

&&view[px][py]!=WHITE)

{

if(side)

view[px][py]=BLACK

else

view[px][py]=WHITE

side=!side

if(judge(px,py))

end=1

}

}

}

void win()

{

if(side)

puts("\r白方胜! ")

else

puts("\r黑方胜! ")

}

int uabs(int i)

{

return i<0?-i:i

}

int cml(int i)

{

return i>0?i-19:19+i

}

void AI_move(int ai_side,int dis)

{

int i,j

char *AI_SIDE=ai_side?BLACK:WHITE

i=dpx-px

j=dpy-py

if(uabs(i)>9)

i=cml(i)

if(uabs(j)>9)

j=cml(j)

while(i||j)

{

if(i)

{

i>0?(i--,px++):(i++,px--)

if(px<0||px>18)

px=cml(px)

}

if(j)

{

j>0?(j--,py++):(j++,py--)

if(py<0||py>18)

py=cml(py)

}

if(dis)

{

system("cls")

show(px,py)

}

}

view[px][py]=AI_SIDE

if(judge(px,py))

end=1

side=!side

}

void computer_attack(int ai_side)

{

int fx,fy,i,j,same,len,tlen,t,tsame,maxscore=0,score,u

char *AI_SIDE=ai_side?BLACK:WHITE

char *P_SIDE=AI_SIDE==WHITE?BLACK:WHITE

for(fx=0fx<19fx++)

for(fy=0fy<19fy++)

{

if(view[fx][fy]==BLACK||view[fx][fy]==WHITE)

continue

same=0,len=0

for(t=0t<4t++)

{

i=fx,j=fy,tlen=1,tsame=0,u=pro

while(i!=final(i,-step[t][0])

&&j!=final(j,-step[t][1])

&&view[i-step[t][0]][j-step[t][1]]!=P_SIDE

&&(fx-i!=WIN*step[t][0]|| fy-j!=WIN*step[t][1]))

{

if(view[i-step[t][0]][j-step[t][1]]==AI_SIDE)

tsame+=u,u*=WIN

else

u/=WIN

i-=step[t][0],j-=step[t][1],tlen++

}

i=fx,j=fy,u=pro

while(i!=final(i,step[t][0])

&&j!=final(j,step[t][1])

&&view[i+step[t][0]][j+step[t][1]]!=P_SIDE

&&(i-fx!=WIN*step[t][0]|| j-fy!=WIN*step[t][1]))

{

if(view[i+step[t][0]][j+step[t][1]]==AI_SIDE)

tsame+=u,u*=WIN

else

u/=WIN

i+=step[t][0],j+=step[t][1],tlen++

}

if(tlen>=WIN)

same+=tsame,len+=tlen

}

score=same+len

if(score>maxscore)

{

maxscore=score

dpx=fx,dpy=fy

}

}

}

void first_round()

{

if(round==1)

{

dpx=rand()%10+5,dpy=rand()%10+5

}

if(round==2)

{

dpx=px+rand()%3-1,dpy=py+rand()%3-1

dpx==-1?dpx+=2:0

dpx==19?dpx-=2:0

dpy==-1?dpy+=2:0

dpy==19?dpy-=2:0

}

}

void AI_think(int def)

{

int tpx=px,tpy=py,tside=side

char *tview[19][19]

if(round<3)

{

first_round()

return

}

memcpy(tview,view,19*19*sizeof(char*))

while(!end)

{

if(side==tside)

{

computer_attack(!pside)

AI_move(!pside,0)

}

else

{

computer_attack(pside)

AI_move(pside,0)

}

}

memcpy(view,tview,19*19*sizeof(char*))

px=tpx,py=tpy

end=0

if(side!=tside)

{

side=tside

computer_attack(!pside)

return

}

else

{

while(def-->0)

{

computer_attack(pside)

AI_move(pside,0)

}

memcpy(view,tview,19*19*sizeof(char*))

px=tpx,py=tpy

side=tside

if(end)

computer_attack(pside)

else

computer_attack(!pside)

end=0

}

}

void turn()

{

int tside=side

round++

if(pvc&&side!=pside)

{

AI_think(style?2:WIN)

AI_move(!pside,1)

}

else

{

while(tside==side)

{

move()

system("cls")

show(px,py)

}

}

}

int main()

{

login()

initial()

while(!end)

turn()

win()

system("pause")

}

我写过五子棋程序,也思考过棋类程序的算法,希望能给楼主参考

双方对弈棋类算法,其基本思想就是人工智能中关念败吵于 最小-最大问题 的 alpha-beta 剪枝,楼主可搜索一下,这个随便一本人工智能书里都有讲。

下面就是具体程序中该如何实现其思想

一般都要先有一个招法生成器,用于给出当前局面下所有可走的行棋可能。对四子棋来说就仔侍相当简单了,只要看一下每一列,只要未满即可。

然后要有一个局面评估函数,大体评价下双方局势的分数。此函数尽量简单能反映优劣即可,因为后面的 alpha-beta 算法要大量调用此函数

最后实现 alpha-beta 的算法,采用迭代加深的广度优先搜索能有效剪枝。(剪枝效率取决于前面的局面评估函数,如果评估函数能非常准确的估值,那么将会大大减小搜索范围,但复杂的评估函数又会增加开销,这是一个枯李两难的抉择)

不过对于四子棋由于非常简单,楼主也可以尝试仅用简单的广度优先搜索。按每个局面 7 列只有 7 种走法来算,5步深的全搜索也只有 1 万多种情况。对一般人来说5步深也足够强了。不满意的话再考虑上面的正统算法。

然后是一点小技巧,关于棋盘的存储和运算,尽量采用位棋盘和位运算来完成,多利用位运算的并行性来提高效率

这里毕竟字数有限,如果还想更深入了解的话推荐来这里看看:http://www.elephantbase.net/computer.htm

一个相当好的棋类算法网站

虽然是讲象棋的,但基本思路都一样,绝对能学到很多东西。


欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/yw/12445716.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-25
下一篇 2023-05-25

发表评论

登录后才能评论

评论列表(0条)

保存