五子棋算法 vc++(MFC)

2024-12-04 22:50:54
推荐回答(5个)
回答1:

Option Explicit

'五子棋程序 人机对战版本
'需要2个Label控件 2个CommandButton控件

Private Declare Function SetWindowRgn Lib "user32" (ByVal hWnd As Long, ByVal hRgn As Long, ByVal bRedraw As Boolean) As Long
Private Declare Function CreateRoundRectRgn Lib "gdi32" (ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long, ByVal X3 As Long, ByVal Y3 As Long) As Long

'Dim PlayStep() As String '记录棋谱的数组
'Dim Label2Cap As String
Private Const BoxL As Single = 50, BoxT As Single = 50, BoxW As Single = 25, BoxN As Integer = 18

Dim Table() As Long '棋盘(0-BoxN,0-BoxN) 0-空 1-黑子 2-白子
Dim PsCore() As Long '定义当前玩家桌面空格的分数
Dim CsCore() As Long '定义当前电脑桌面空格的分数
Dim pWin() As Boolean '定义玩家的获胜组合
Dim cWin() As Boolean '定义电脑的获胜组合
Dim pFlag() As Boolean '定义玩家的获胜组合标志
Dim cFlag() As Boolean '定义电脑的获胜衡肆悔组合标志
Dim ThePlayFlag As Boolean '定义游戏有效标志

Private Sub Command1_Click()
If Not ThePlayFlag Then Call InitPlayEnvironment: Exit Sub
If MsgBox("本局还没有下完,是否重新开始?(Y/N)", vbYesNo) = vbNo Then Exit Sub
Call InitPlayEnvironment
End Sub

Private Sub Command2_Click()
End
End Sub

Private Sub Form_Load()
Dim i As Long, lw As Long, lh As Long
'Label2Cap = "000 黑方 行 00 列 00"咐正
Me.Width = 10815: Me.Height = 8040
' Me.Caption = "五子棋 - 人机对战": Me.Show
lw = Me.Width \ Screen.TwipsPerPixelX: lh = Me.Height \ Screen.TwipsPerPixelY
SetWindowRgn Me.hWnd, CreateRoundRectRgn(0, 0, lw, lh, 60, 60), True
With Label1
.Alignment = vbCenter: .FontSize = 12: .FontBold = True
.ForeColor = vbRed: .BackStyle = 0: .AutoSize = True: .Move 8910, 510
End With
Label2.AutoSize = True: Label2.WordWrap = True
Label2.BackStyle = 0: Label2.Move 8040, 1050, 2280
Command1.Move 8025, 7035, 1020, 435: Command1.Caption = "再来一局"
Command2.Move 9300, 7035, 1020, 435: Command2.Caption = "雹拿不玩了"
Call DrawChessBoard: Me.FillStyle = 0: Call InitPlayEnvironment
End Sub

Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
End
End Sub

Private Sub Form_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
Dim iRow As Long, iCol As Long, i As Long, k As Long, t As String
If Not ThePlayFlag Then Exit Sub
If Button = vbLeftButton Then '左键下棋
iRow = -1: iCol = -1
For i = 0 To BoxN '鼠标必须落在交叉点 半径10以内 若是则给出行列号
If (Y + 10) > (BoxT + i * BoxW) And (Y - 10) <= (BoxT + i * BoxW) Then iRow = i
If (X + 10) > (BoxL + i * BoxW) And (X - 10) <= (BoxL + i * BoxW) Then iCol = i
Next
If (iRow = -1) Or (iCol = -1) Then Beep: Exit Sub
If Table(iCol, iRow) > 0 Then Exit Sub
Table(iCol, iRow) = 2: Label1.Caption = "下一步 黑方"
Me.FillColor = vbWhite: Me.Circle (iCol * BoxW + BoxT, iRow * BoxW + BoxL), 8
For i = 0 To UBound(cWin, 3)
If cWin(iCol, iRow, i) = True Then cFlag(i) = False
Next
Call CheckWin: Call DianNao '检查当前玩家是否获胜 调用电脑算法
End If
End Sub

Public Sub InitPlayEnvironment()
'*****************************************************************************
' 模块名称: InitPlayEnvironment [初始化过程]
'
' 描述: 1. 设置背景音乐。 2. 设置游戏状态有效。
' 3. 初始化游戏状态标签。 4. 直接指定电脑的第一步走法。
' 5. 初始化基本得分桌面。 6. 电脑和玩家获胜标志初始化。
' 7. 初始化所有获胜组合。 8. 重新设定玩家的获胜标志。
'*****************************************************************************
Dim i As Long, j As Long, m As Long, n As Long

ThePlayFlag = True: Label1.Caption = "下一步 白方": Label2.Caption = ""
Me.FillColor = vbBlack: Me.FillStyle = 0: Me.AutoRedraw = True
Me.Cls: Me.Circle (9 * BoxW + BoxL, 9 * BoxW + BoxT), 8
ReDim Table(0 To BoxN, 0 To BoxN) As Long
ReDim pFlag(NumsWin(BoxN + 1) - 1) As Boolean
ReDim cFlag(UBound(pFlag)) As Boolean
ReDim PsCore(BoxN, BoxN) As Long, CsCore(BoxN, BoxN) As Long
ReDim pWin(BoxN, BoxN, UBound(pFlag)) As Boolean
ReDim cWin(BoxN, BoxN, UBound(pFlag)) As Boolean

For i = 0 To UBound(pFlag): pFlag(i) = True: cFlag(i) = True: Next
Table(9, 9) = 1 '假定电脑先手 并下了(9, 9)位 将其值设为1
'******** 初始化获胜组合 ****************************************
For i = 0 To BoxN: For j = 0 To BoxN - 4
For m = 0 To 4
pWin(j + m, i, n) = True: cWin(j + m, i, n) = True
Next
n = n + 1
Next: Next
For i = 0 To BoxN: For j = 0 To BoxN - 4
For m = 0 To 4
pWin(i, j + m, n) = True: cWin(i, j + m, n) = True
Next
n = n + 1
Next: Next
For i = 0 To BoxN - 4: For j = 0 To BoxN - 4
For m = 0 To 4
pWin(j + m, i + m, n) = True: cWin(j + m, i + m, n) = True
Next
n = n + 1
Next: Next
For i = 0 To BoxN - 4: For j = BoxN To 4 Step -1
For m = 0 To 4
pWin(j - m, i + m, n) = True: cWin(j - m, i + m, n) = True
Next
n = n + 1
Next: Next
'******** 初始化获胜组合结束 *************************************
For i = 0 To UBound(pWin, 3) '由于电脑已下了(9, 9)位 所以需要重新设定玩家的获胜标志
If pWin(9, 9, i) = True Then pFlag(i) = False
Next
End Sub

Public Function DrawChessBoard() As Long
'容器的(BoxL, BoxT)为左上角坐标画一个 BoxN*BoxN, 每格边长为 BoxW 象素的棋盘
Dim i As Long, j As Long, cx As Long, cy As Long
Me.ScaleMode = 3: Me.FillStyle = 1: Me.AutoRedraw = True: Me.Cls
For i = 0 To BoxN '画棋盘
Me.Line (BoxL + i * BoxW, BoxT)-(BoxL + i * BoxW, BoxT + BoxN * BoxW)
Me.Line (BoxL, BoxT + i * BoxW)-(BoxL + BoxN * BoxW, BoxT + i * BoxW)
Me.CurrentX = BoxL + i * BoxW - IIf(i > 9, 6, 2)
Me.CurrentY = BoxT - 20: Me.Print Format(i)
Me.CurrentX = BoxL - IIf(i > 9, 23, 20)
Me.CurrentY = BoxT + i * BoxW - 6: Me.Print Format(i)
Next
For i = 3 To 16 Step 6: For j = 3 To 16 Step 6 '画小标志
cx = BoxL + j * BoxW - 3: cy = BoxT + i * BoxW - 3
Me.Line (cx, cy)-(cx + 6, cy + 6), , B
Next: Next
Me.AutoRedraw = False: Set Me.Picture = Me.Image
End Function

Public Sub CheckWin()
'*****************************************************************************
' 模块名称: CheckWin [获胜检查算法]
'
' 描述: 1. 检查是否和棋。 2. 检查电脑是否获胜。 3. 检查玩家是否获胜。
'*****************************************************************************
Dim i As Long, j As Long, k As Long, m As Long, n As Long
Dim cA As Long, pA As Long, cN As Long

For i = 0 To UBound(cFlag): cN = IIf(cFlag(i) = False, cN + 1, cN): Next

If cN = UBound(cFlag) - 1 Then '设定和棋规则
Label1.Caption = "双方和棋!": ThePlayFlag = False: Exit Sub
End If
For i = 0 To UBound(cFlag) '检查电脑是否获胜
If cFlag(i) = True Then
cA = 0: For j = 0 To BoxN: For k = 0 To BoxN
If Table(j, k) = 1 And cWin(j, k, i) = True Then cA = cA + 1
Next: Next
If cA = 5 Then Label1.Caption = "电脑获胜!": ThePlayFlag = False: Exit Sub
End If
Next
For i = 0 To UBound(pFlag) '检查玩家是否获胜
If pFlag(i) = True Then
pA = 0: For j = 0 To BoxN: For k = 0 To BoxN
If Table(j, k) = 2 And pWin(j, k, i) = True Then pA = pA + 1
Next: Next
If pA = 5 Then Label1.Caption = "玩家获胜!": ThePlayFlag = False: Exit Sub
End If
Next
End Sub

Public Sub DianNao()
'*****************************************************************************
' 模块名称: DianNao [电脑算法]

' 描述: 1. 初始化赋值系统。 2. 赋值加强算法。 3. 计算电脑和玩家的最佳攻击位。
' 4. 比较电脑和玩家的最佳攻击位并决定电脑的最佳策略。 5. 执行检查获胜函数。
'*****************************************************************************
Dim i As Long, j As Long, k As Long, m As Long, n As Long
Dim Dc As Long, cAb As Long, pAb As Long

ReDim PsCore(BoxN, BoxN) As Long, CsCore(BoxN, BoxN) As Long '初始化赋值数组

'******** 电脑加强算法 ********
For i = 0 To UBound(cFlag)
If cFlag(i) = True Then
cAb = 0
For j = 0 To BoxN: For k = 0 To BoxN
If Table(j, k) = 1 And cWin(j, k, i) = True Then cAb = cAb + 1
Next: Next
Select Case cAb
Case 3
For m = 0 To BoxN: For n = 0 To BoxN
If Table(m, n) = 0 And cWin(m, n, i) = True Then CsCore(m, n) = CsCore(m, n) + 5
Next: Next
Case 4
For m = 0 To BoxN: For n = 0 To BoxN
If Table(m, n) = 0 And cWin(m, n, i) = True Then
Table(m, n) = 1: Label1.Caption = "下一步 白方"
Me.FillColor = vbBlack: Me.Circle (m * BoxW + BoxL, n * BoxW + BoxT), 8
For Dc = 0 To UBound(pWin, 3)
If pWin(m, n, Dc) = True Then pFlag(Dc) = False: Call CheckWin: Exit Sub
Next
End If
Next: Next
End Select
End If
Next

For i = 0 To UBound(pFlag)
If pFlag(i) = True Then
pAb = 0
For j = 0 To BoxN: For k = 0 To BoxN
If Table(j, k) = 2 And pWin(j, k, i) = True Then pAb = pAb + 1
Next: Next
Select Case pAb
Case 3
For m = 0 To BoxN: For n = 0 To BoxN
If Table(m, n) = 0 And pWin(m, n, i) = True Then PsCore(m, n) = PsCore(m, n) + 30
Next: Next
Case 4
For m = 0 To BoxN: For n = 0 To BoxN
If Table(m, n) = 0 And pWin(m, n, i) = True Then
Table(m, n) = 1: Label1.Caption = "下一步 白方"
Me.FillColor = vbBlack: Me.Circle (m * BoxW + BoxL, n * BoxW + BoxT), 8
For Dc = 0 To UBound(pWin, 3)
If pWin(m, n, Dc) = True Then pFlag(Dc) = False: Call CheckWin: Exit Sub
Next
End If
Next: Next
End Select
End If
Next
'******** 电脑加强算法结束 ********

'******** 赋值系统 ****************
For i = 0 To UBound(cFlag)
If cFlag(i) = True Then
For j = 0 To BoxN: For k = 0 To BoxN
If (Table(j, k) = 0) And cWin(j, k, i) Then
For m = 0 To BoxN: For n = 0 To BoxN
If (Table(m, n) = 1) And cWin(m, n, i) Then CsCore(j, k) = CsCore(j, k) + 1
Next: Next
End If
Next: Next
End If
Next

For i = 0 To UBound(pFlag)
If pFlag(i) = True Then
For j = 0 To BoxN: For k = 0 To BoxN
If (Table(j, k) = 0) And pWin(j, k, i) Then
For m = 0 To BoxN: For n = 0 To BoxN
If (Table(m, n) = 2) And pWin(m, n, i) Then PsCore(j, k) = PsCore(j, k) + 1
Next: Next
End If
Next: Next
End If
Next
'******** 赋值系统结束 ************

'******** 分值比较算法 ************
Dim a As Long, b As Long, c As Long, d As Long
Dim cS As Long, pS As Long

For i = 0 To BoxN: For j = 0 To BoxN
If CsCore(i, j) > cS Then cS = CsCore(i, j): a = i: b = j
Next: Next
For i = 0 To BoxN: For j = 0 To BoxN
If PsCore(i, j) > pS Then pS = PsCore(i, j): c = i: d = j
Next: Next

If cS > pS Then
Table(a, b) = 1: Label1.Caption = "下一步 白方"
Me.FillColor = vbBlack: Me.Circle (a * BoxW + BoxL, b * BoxW + BoxT), 8
For i = 0 To UBound(pWin, 3)
If pWin(a, b, i) = True Then pFlag(i) = False
Next
Else
Table(c, d) = 1: Label1.Caption = "下一步 白方"
Me.FillColor = vbBlack: Me.Circle (c * BoxW + BoxL, d * BoxW + BoxL), 8
For i = 0 To UBound(pWin, 3)
If pWin(c, d, i) = True Then pFlag(i) = False
Next
End If
'******** 分值比较算法结束 ********

Call CheckWin

End Sub

Public Function NumsWin(ByVal n As Long) As Long
'根据输入的棋盘布局 n*n 计算总共有多少种获胜组合
'假定棋盘为 10 * 10 相应的棋盘数组就是 Table(9, 9)
'水平方向 每一列获胜组合是6 共10列 6*10=60
'垂直方向 每一行获胜组合是6 共10行 8*10=60
'正对角线方向 6 + (5 + 4 + 3 + 2 + 1) * 2 = 36
'反对角线方向 6 + (5 + 4 + 3 + 2 + 1) * 2 = 36
'总的获胜组合数为 60 + 60 + 36 + 36 = 192
Dim i As Long, t As Long
For i = n - 5 To 1 Step -1: t = t + i: Next
NumsWin = 2 * (2 * t + n - 4) + 2 * n * (n - 4)
End Function

回答2:

就是给1000分,估计也没有人为这个给你写代码。因为来这里的高手才不稀罕分数,而低手又写不出来。

不过,我可以给你提供一个思路。

这个,可以用深度优先搜索算法。

提供一个伪代码给你:

//写一个估值函数
int 获得价值( int nPlayer, int x, int y )
{
// 函数说明:
// 假设把棋子落到x,y处,所能获得的价值。
// nPlyaer == 1表示黑方,nPlyaer==2表示白方

1、判断如果是赢(横向、纵向、斜向五个连起来)就返回无穷大(一个远远大于最高价值的值,例如1000)
2、判断如果是双冲4,返回 200
3、判断如果是冲四活三,返回150
4、判断如果是双活三,返回100
5、如果挨着自己的棋子,两头又有空隙,返回50
6、其他的有利的判断。。。。
7、返回以上判断的价值
}

//写一个获得最佳位置的函数
//int 获得最哗培佳位置( int 黑方或白方, int 层数, POINT& 返回位置 )
int GetBestPosition( int nP, int n, POINT& ptBest )
{
1、枚举所有可以落子的位置。
2、假设将棋子落到该处。
3、获得该处的价值( 保存在 int nJiazhi );

4、如果层数==1,转到第7步:;
5、否则:
6、//递归的调用GetBastPosition( 对方, 层数减一 );
nJiazhi -= GetBastPositon( nP == 1 ? 2 : 1, -- n );
7、找出所枚举的所有的落子点中价值最高的那个位置。
8、将7中找到的位置存入ptBest,返回nJiazhi.
}

说明一下:
层数,就是想让程序袭明能够考虑几步。

总体的思路就是,搜索所有可以落子的地点(当然可以优化,比如远离交战焦点的地方可以忽略),假设将棋子落到该处,然后评估这个位置的价值,再减去敌人能获得的最高价值,就等于这个拍芦告位置的实际价值,找出实际价值最高的点,就是最好的落子点了。

最难的就是写估值函数。一个良好的估值函数,加上搜索的一些优化,就是一个很好的博弈算法。

回答3:

以卖羡前我也有想过电脑下五子棋的思路。
和楼主的想法是完全一致的,难点也是在如何智能下棋的算法,
我觉得这个需要把所有可下的位置进行比较,选择一个最优的。至于具体算法本人也没想出什么结果。

不过我觉得这是人工智能的知识领域,计算机专业研究生都开着门课程。
正是包含这样的问题的解决方法,楼主有空可以学习下。

我觉得即便是从网上或者从别人那里得到一个答案中御拍而且理解思路,由于拆姿没有系统的学习过这方面的知识,也不太利于融会百通。不如系统的学习一下,使自己提高一个层次,再遇到其他属于人工智能问题就可以迎刃而解,

回答4:

我曾经写过五子棋,现在已经忘了具体的部分。
不过我可以把我的写“电脑”下棋的部分的思路晌哪给你说哈。我是使用“二叉搜索亮正树”来解决对电脑应该怎么下棋,遍历所有能下子的路径,找寻最优化的路径。

这个还扯不到人工智能哈。。只能算是粘了点敬谨悔边边。如果真的是想要达到人与人下棋的那种成度,你可以用CList建一个危险点的列表集,对电脑下子前,用搜索树优先遍历这些点。[个人意见,哈哈]

回答5:

两个办法:1.找你所在地区的大学相关专业的高年级学生联系下拿竖,请他们利用手头资源帮你找个类似的程序按你的要盯基求改好,因为现在基本所有大学都有相关的社团或兴趣小组玩这个,五子棋更是很基础的...(找到人后估计再半个小时就好了)
2.留个邮箱,人家以前如果做过这个的可以直接发给你(估计人家看到你邮箱再5分钟发信过去就好了)
另:刚才我看了下,我手头能进的3个大学的论坛都有现成的,估计其他大消则大学也很好下,但不是我做的也不好把人家的成果拿来炫,你就找做过这个的人吧