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