JS+canvas实现五子棋(穷举法)

 

  1 <!DOCTYPE html>
  2 <html>
  3 <head>
  4     <meta charset="utf-8"/>
  5     <title>五子棋</title>
  6     <style type="text/css">
  7         canvas {
  8             display: block;
  9             margin: 50px auto;
 10             box-shadow: -2px -2px 2px #efefef, 5px 5px 5px #b9b9b9;
 11         }
 12 
 13         .restart {
 14             text-align: center;
 15         }
 16 
 17         .restart > span {
 18             display: inline-block;
 19             padding: 10px 20px;
 20             color: #fff;
 21             background-color: #45c01a;
 22             border-radius: 5px;
 23         }
 24     </style>
 25 </head>
 26 <body>
 27 <canvas id="chess" width="450px" height="450px"></canvas>
 28 <div id='restart' class="restart">
 29     <span>重新开始</span>
 30 </div>
 31 <script type="text/javascript" charset="utf-8">
 32     var chess = document.getElementById("chess");
 33     var context = chess.getContext('2d');
 34     context.strokeStyle = '#bfbfbf'; //边框颜色
 35     //绘画棋盘
 36     var drawChessBoard = function () {
 37         for (var i = 0; i < 15; i++) {
 38             //画竖线
 39             context.beginPath();
 40             context.moveTo(15 + i * 30, 15);
 41             context.lineTo(15 + i * 30, 435);
 42             context.closePath();
 43             context.stroke();
 44             //画横线
 45             context.beginPath();
 46             context.moveTo(15, 15 + i * 30);
 47             context.lineTo(435, 15 + i * 30);
 48             context.closePath();
 49             context.stroke();
 50         }
 51     };
 52     drawChessBoard();
 53 
 54     var over = false;//超出边界
 55     var me = true; //
 56 
 57     //初始化棋盘
 58     var chressBord = [];//棋盘
 59     for (var i = 0; i < 15; i++) {
 60         chressBord[i] = [];
 61         for (var j = 0; j < 15; j++) {
 62             chressBord[i][j] = 0;
 63         }
 64     }
 65 
 66     //画旗子
 67     var oneStep = function (i, j, me) {
 68         context.beginPath();
 69         context.arc(15 + i * 30, 15 + j * 30, 13, 0, 2 * Math.PI);//画圆
 70         context.closePath();
 71         //渐变
 72         var gradient = context.createRadialGradient(15 + i * 30 + 2, 15 + j * 30 - 2, 13, 15 + i * 30 + 2, 15 + j * 30 - 2, 0);
 73 
 74         if (me) {
 75             gradient.addColorStop(0, '#0a0a0a');
 76             gradient.addColorStop(1, '#636766');
 77         } else {
 78             gradient.addColorStop(0, '#d1d1d1');
 79             gradient.addColorStop(1, '#f9f9f9');
 80         }
 81         context.fillStyle = gradient;
 82         context.fill();
 83     };
 84 
 85     //赢法数组,记录五子棋所有的赢法,三维数组
 86     var wins = [];
 87     for (var i = 0; i < 15; i++) {
 88         wins[i] = [];
 89         for (var j = 0; j < 15; j++) {
 90             wins[i][j] = [];
 91         }
 92     }
 93     var count = 0; //赢法总数(穷举)
 94     //竖线赢法
 95     //(i,j)代表坐标,count表示第几种赢法
 96     for (var i = 0; i < 15; i++) {
 97         for (var j = 0; j < 11; j++) {
 98             for (var k = 0; k < 5; k++) {
 99                 wins[i][j + k][count] = true;
100             }
101             count++;
102         }
103     }
104     //横线赢法
105     for (var i = 0; i < 15; i++) {
106         for (var j = 0; j < 11; j++) {
107             for (var k = 0; k < 5; k++) {
108                 wins[j + k][i][count] = true;
109             }
110             count++;
111         }
112     }
113     //正斜线赢法
114     for (var i = 0; i < 11; i++) {
115         for (var j = 0; j < 11; j++) {
116             for (var k = 0; k < 5; k++) {
117                 wins[i + k][j + k][count] = true;
118             }
119             count++;
120         }
121     }
122     //反斜线赢法
123     for (var i = 0; i < 11; i++) {
124         for (var j = 14; j > 3; j--) {
125             for (var k = 0; k < 5; k++) {
126                 wins[i + k][j - k][count] = true;
127             }
128             count++;
129         }
130     }
131     //赢法的统计数组,一维数组
132     var myWin = [];
133     var computerWin = [];
134     //玩家与计算机的统计数组初始化
135     for (var i = 0; i < count; i++) {
136         myWin[i] = 0;
137         computerWin[i] = 0;
138     }
139 
140     chess.onclick = function (e) {
141         if (over) {
142             return;
143         }
144         if (!me) {
145             return;
146         }
147         var x = e.offsetX;
148         var y = e.offsetY;
149         var i = Math.floor(x / 30);
150         var j = Math.floor(y / 30);
151         if (chressBord[i][j] == 0) {
152             oneStep(i, j, me);
153             chressBord[i][j] = 1;//1代表玩家,2代表计算机,0代表没有子
154 
155             for (var k = 0; k < count; k++) {
156                 //第k种赢法时,玩家统计数组第k个自加
157                 if (wins[i][j][k]) {
158                     myWin[k]++;
159                     computerWin[k] = 6;//这个位置对方不可能赢了
160                     if (myWin[k] == 5) {//第k种赢法的5个子都落下
161                         window.alert('你赢了');
162                         over = true;
163                     }
164                 }
165             }
166             if (!over) {
167                 me = !me;
168                 computerAI();
169             }
170         }
171 
172     };
173 
174 
175     //计算机下棋
176     var computerAI = function () {
177         var myScore = [];
178         var computerScore = [];
179         var max = 0; //最高分数
180         var u = 0, v = 0; //最高分数的点的坐标
181         //玩家和计算机的得分数组,二维数组
182         for (var i = 0; i < 15; i++) {
183             myScore[i] = [];
184             computerScore[i] = [];
185             for (var j = 0; j < 15; j++) {
186                 myScore[i][j] = 0;
187                 computerScore[i][j] = 0;
188             }
189         }
190         //遍历棋盘
191         for (var i = 0; i < 15; i++) {
192             for (var j = 0; j < 15; j++) {
193                 //如果(i,j)没有落子
194                 if (chressBord[i][j] == 0) {
195                     //遍历所有的赢法,如果第k种赢法在(i,j)这个点为true,根据不同的分数等级找到分数最高的点
196                     for (var k = 0; k < count; k++) {
197                         if (wins[i][j][k]) {
198                             if (myWin[k] == 1) {//第k种赢法玩家已落1子
199                                 myScore[i][j] += 200;
200                             } else if (myWin[k] == 2) {
201                                 myScore[i][j] += 400;
202                             } else if (myWin[k] == 3) {
203                                 myScore[i][j] += 2000;
204                             } else if (myWin[k] == 4) {
205                                 myScore[i][j] += 10000;
206                             }
207                             if (computerWin[k] == 1) {//第k种赢法计算机已落1子
208                                 computerScore[i][j] += 220;
209                             } else if (computerWin[k] == 2) {
210                                 computerScore[i][j] += 420;
211                             } else if (computerWin[k] == 3) {
212                                 computerScore[i][j] += 2100;
213                             } else if (computerWin[k] == 4) {
214                                 computerScore[i][j] += 20000;
215                             }
216                         }
217                     }
218 
219                     //找到分数最高的点
220                     if (myScore[i][j] > max) {
221                         max = myScore[i][j];
222                         u = i;
223                         v = j;
224                     } else if (myScore[i][j] == max) {
225                         if (computerScore[i][j] > computerScore[u][v]) {
226                             u = i;
227                             v = j;
228                         }
229                     }
230                     if (computerScore[i][j] > max) {
231                         max = computerScore[i][j];
232                         u = i;
233                         v = j;
234                     } else if (computerScore[i][j] == max) {
235                         if (myScore[i][j] > myScore[u][v]) {
236                             u = i;
237                             v = j;
238                         }
239                     }
240 
241                 }
242             }
243         }
244         //计算机落子
245         oneStep(u, v, false);
246         chressBord[u][v] = 2;
247         //更新赢法的统计数组
248         for (var k = 0; k < count; k++) {
249             if (wins[u][v][k]) {
250                 computerWin[k]++;
251                 myWin[k] = 6;//这个位置对方不可能赢了
252                 if (computerWin[k] == 5) {
253                     window.alert('计算机赢了');
254                     over = true;
255                 }
256             }
257         }
258         if (!over) {
259             me = !me;
260         }
261     };
262 
263 
264     document.getElementById("restart").onclick = function () {
265         window.location.reload();
266     }
267 
268 </script>
269 </body>
270 </html>

 

总结一下:

1、wins[i][j][count]表示所有的赢法(横线竖线斜线)

2、myWin[count]和computerWin[count]表示每种赢法的落子个数,玩家点击后,myWin值自加,计算机的值为6,  当myWin值为5则玩家赢

3、遍历棋盘上的每个空点,获取每种赢法对应的分数值,找出最大值的点后计算机落子, computerWin值自加,玩家的值为6,  当computerWin值为5则玩家赢

 

参考:http://www.imooc.com/learn/644

 

posted @ 2017-10-20 15:25  wanghuohuo  阅读(426)  评论(0编辑  收藏  举报