C++简单五子棋的AI设计实现

时间:2022-11-27 10:00:55

本文实例为大家分享了C++五子棋的AI设计实现代码,供大家参考,具体内容如下

设计思路:通过接口获取信息来确定颜色,通过set_chess函数来确定落点。

  • 对每个点位给出两种颜色棋子的打分,分别存在两个15*15的数组里,数组下标代表点的位置。
  • 确定最大值所在数组之后,遍历该数组找出所有最大值对应的位置,然后对这些位置统计另一种颜色的棋子的分数,再选取一次最大值,从而确定要落点的位置。
  • 打分函数的设计:在四个方向分别统计然后相加。对于某一个方向的分数统计,则分为正反两个方向进行,统计的时候如果有连成5个则直接返回一个最大值(最高分)。其他情况则按不同情况设置不同的权重,触发结束某一个方向上的统计的事件如下:遇到异色棋子;空白格子超过两个;遇到棋盘边界。其中遇到异色棋子和棋盘边界均视为一边被堵死,相比空白来说适当减分,而1个空白相比于完全连续则应再适当减分,最后取10的次幂,以保证不同情况的优先级,即不至于出现因为下到位置A可以形成4个活2而放弃下可以形成1个活4的位置B。

具体代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
#pragma once
#ifndef AI_H
#define AI_H
#include "renju.h"
#include <vector>
#include <math.h>
 
class Ai
{
public:
  Ai(chessboard &bd, state hm)
  {
    ms.set_color(hm);
    this->p_bd = &bd;
  }
  chess set_chess();
 
private:
  int evaluate(position pos, state color, position (*pf)(position ,bool ));//给出落子位置和方向移动函数,返回该落子位置在该方向上的评分
 
  int point(position pos, state color);//给出一个落子位置,返回该落子的得分
 
  void whole_points(int points[][15], state color );//给定颜色 ,记录该颜色棋子下在每一处的得分
 
  int best_posits(const int points[][15], position p_s[], int& count); //给出分数数组,找出最大值对应的位置(可能不止一个),返回分数最大值
 
  chess ms;
  const chessboard *p_bd;
};
 
//确定落子
chess Ai:: set_chess()
{
  int points_b[15][15];    //记录黑棋各落点分数
  int points_w[15][15];    //记录白棋各落点分数
  position best_b[20];    //记录黑棋最大分数对应的落点位置
  position best_w[20];    //记录白棋最大分数对应的落点位置
  int s_black = 0, s_white = 0;    //记录黑白棋分别的最大分数值
  int count_b = 0,count_w = 0;      //记录黑白棋最大分数对应的落点位置个数
 
  whole_points(points_b, black);
  whole_points(points_w, white);
  s_white = best_posits(points_w, best_w,count_w);
  s_black = best_posits(points_b, best_b,count_b);
 
  if( s_black > s_white )   //黑棋最高分高过白棋,在黑棋最高分对应的位置中选出白棋分数最大的位置落子
  {
  sb: int a[20];
    for(int i = 0;i < count_b;i++)
    {
      a[i] = point(best_b[i],white);
    }
    int max_w = MAX(a, count_b);
    for(int i = 0;i < count_b;i++)
    {
      if(a[i] == max_w)
      {
        ms.set_point(best_b[i]);
        return ms;
      }
    }
  }
  if( s_black < s_white )   //白棋最高分高过黑棋,在白棋最高分对应的位置中选出黑棋分数最大的位置落子
  {
  sw: int a[20];
    for(int i = 0;i < count_w;i++)
    {
      a[i] = point(best_w[i],black);
    }
    int max_b = MAX(a, count_b);
    for(int i = 0;i < count_w;i++)
    {
      if(a[i] == max_b)
      {
        ms.set_point(best_w[i]);
        return ms;
      }
    }
  }
  if( s_black == s_white ) 
  {
    if(ms.get_color() == white)
      goto sw;
    if(ms.get_color() == black)
      goto sb;
  }
}
 
//给出分数数组,找出最大值对应的位置(可能不止一个),返回分数最大值
int Ai::best_posits(const int points[][15], position p_s[], int& count)
{
  int max_row[15];
  int max_all;
  for(int i = 0;i < 15;i++)
  max_row[i] = MAX(points[i],15);
  max_all = MAX(max_row,15);
  cout<<"maxall"<<max_all;
  count = 0;
  for(int i = 0;i < 15;i++)
  {
    for(int j =0;j < 15;j++)
    {
      if(points[i][j] == max_all)
      {
        position x(i,j);
        p_s[count] = x;
        count++;
      }
    }
  }
  return max_all;
}
 
//给定颜色 ,记录该颜色棋子下在每一处的得分
void Ai::whole_points(int points[][15], state color )
{
  for( int i =0;i < 15;i++)
  {
    for(int j = 0;j < 15;j++)
    {
      position temp(i,j);
      points[i][j] = point(temp,color);
    }
  }
}
 
//位置函数,用于上下移动棋子并判断是否越界
position up(position pos,bool dir)
{
  position r;
  if(dir)
  {
    while(pos.y > 0)
    {
      r.x = pos.x;
      r.y = pos.y - 1;
      return r;
    }
    throw 0;
  }
  else
  {
    while(pos.y < 14)
    {
      r.x = pos.x;
      r.y = pos.y + 1;
      return r;
    }
    throw 0;
  }
}
 
//位置函数,用于左右移动棋子并判断是否越界
position left(position pos,bool dir)
{
  position r;
  if(dir)
  {
    while(pos.x > 0)
    {
      r.x = pos.x - 1;
      r.y = pos.y;
      return r;
    }
    throw 0;
  }
  else
  {
    while(pos.x < 14)
    {
      r.x = pos.x + 1;
      r.y = pos.y;
      return r;
    }
    throw 0;
  }
}
 
//位置函数,用于左上右下移动棋子并判断是否越界
position left_up(position pos,bool dir)
{
  position r;
  if(dir)
  {
    while(pos.x > 0 && pos.y > 0)
    {
      r.x = pos.x - 1;
      r.y = pos.y - 1;
      return r;
    }
    throw 0;
  }
  else
  {
    while(pos.x < 14 && pos.y < 14)
    {
      r.x = pos.x + 1;
      r.y = pos.y + 1;
      return r;
    }
    throw 0;
  }
}
 
//位置函数,用于右上左下移动棋子并判断是否越界
position right_up(position pos,bool dir)
{
  position r;
  if(dir)
  {
    while(pos.x < 14 && pos.y > 0)
    {
      r.x = pos.x + 1;
      r.y = pos.y - 1;
      return r;
    }
    throw 0;
  }
  else
  {
    while(pos.x > 0 && pos.y < 14)
    {
      r.x = pos.x - 1;
      r.y = pos.y + 1;
      return r;
    }
    throw 0;
  }
}
 
int Ai::evaluate(position pos, state color, position (*pf)(position ,bool ))
{
  int sum = 0;
  position p_i = pos;
  int count = 0,mc = 1;
  bool flag = true;
  int c_blank = 0;
  state judge_t;
 
  try
  {
    do
    {
      p_i = pf(p_i, flag);
      judge_t = p_bd -> viewboard(p_i);
      if(judge_t == color)
      {
        if(c_blank == 1)
        {
          count += 1;
        }
        else
        {
          mc++;
          if(mc == 5)
            return 100000000000;
          count += 2;
        }
      }
      else
      {
        if(judge_t == blank)
        {
          if(c_blank >= 1)
            flag = false;
          else
          {
            c_blank++;
          }
        }
        else
        {
          count-=2;
          flag = false;
        }
      }
    }while(flag);
  }
  catch(int key)
  {
    flag = false;
    if(c_blank == 0)count-=2;
  }
 
  p_i = pos;
  int b_blank = 0;//记录另一半的空白格子
  try
  {
    do
    {
      p_i = pf(p_i, flag);
      judge_t = p_bd -> viewboard(p_i);
      if(judge_t == color)
      {
        if(b_blank == 1)
        {
          count += 1;
        }
        else
        {
          if(c_blank == 0 && b_blank == 0)
            mc++;
          if(mc == 5)
            return 100000000000;
          count += 2;
        }
      }
      else
      {
        if(judge_t == blank)
        {
        if(b_blank >= 1)
            flag = true;
          else
          {
            b_blank++;
          }
        }
        else
        {
          count-=2;
          flag = true;
        }
      }
    }while(!flag);
  }
  catch(int key)
  {
    if(b_blank == 0)count-=2;
    return pow(10,count);
  }
  return pow(10,count);
}
//给出一个落子位置,返回该落子的得分
int Ai::point(position pos, state color)
{
  if(p_bd -> viewboard(pos) != blank)
  {
    return 0;
  }
 
  position (*p_f)(position,bool) = NULL;
  int sum = 0;
 
  p_f = up;
  sum += evaluate(pos, color, p_f);
  p_f = left;
  sum += evaluate(pos, color, p_f);
  p_f = left_up;
  sum += evaluate(pos, color, p_f);
  p_f = right_up;
  sum += evaluate(pos, color, p_f);
 
  return sum;
}
#endif

其中所需要的头文件在上一篇文章中有提到:C++语言设计实现五子棋

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

原文链接:https://blog.csdn.net/black_kyatu/article/details/79331463