JS+canvas五子棋人机大战
1. 创建实例 function Gobang () { this.over = false; // 是否结束 this.player = true; // true:我 false:电脑 this.allChesses = []; // 所有棋子 this.existChesses = [] // 已经落下的棋子 this.winsCount = 0; // 赢法总数 this.wins = []; // 所有赢法统计 this.myWins = []; //我的赢法统计 this.computerWins = []; //电脑赢法统计 } 2. 初始化 //初始化 Gobang.prototype.init = function(opts) { // 生成canvas棋盘 this.createCanvas(opts); //棋盘初始化 this.boardInit(); // 鼠标移动聚焦功能实现 this.mouseMove(); //算法初始化 this.algorithmInit(); //落子功能实现 this.dorpChess(); } 3. 生成canvas棋盘 //初始化 //生成canvas Gobang.prototype.createCanvas = function(opts) { var opts = opts || {}; if (opts.width && opts.width%30 !== 0) throw new RangeError(opts.width+'不是30的倍数'); this.col = (opts.width && opts.width/30) || 15; // 棋盘列 var oCanvas = document.createElement('canvas'); oCanvas.width = oCanvas.height = opts.width || 450; this.canvas = oCanvas; document.querySelector(opts.container || 'body').appendChild(this.canvas); this.ctx = oCanvas.getContext('2d'); } 4. 初始化棋盘 //棋盘初始化 Gobang.prototype.boardInit = function(opts){ this.drawBoard(); } // 画棋盘 Gobang.prototype.drawBoard = function(){ this.ctx.strokeStyle = "#bfbfbf"; for (var i = 0; i < this.col; i++) { this.ctx.moveTo(15+ 30*i, 15); this.ctx.lineTo(15+ 30*i, this.col*30-15); this.ctx.stroke(); this.ctx.moveTo(15, 15+ 30*i); this.ctx.lineTo(this.col*30-15, 15+ 30*i); this.ctx.stroke(); } } 5. 画棋子 // 画棋子 Gobang.prototype.drawChess = function(x, y, player){ var x = 15 + x * 30, y = 15 + y * 30; this.ctx.beginPath(); this.ctx.arc(x, y, 13, 0, Math.PI*2); var grd = this.ctx.createRadialGradient(x + 2, y - 2, 13 , x + 2, y - 2, 0); if (player) { //我 == 黑棋 grd.addColorStop(0, '#0a0a0a'); grd.addColorStop(1, '#636766'); }else{ //电脑 == 白棋 grd.addColorStop(0, '#d1d1d1'); grd.addColorStop(1, '#f9f9f9'); } this.ctx.fillStyle = grd; this.ctx.fill() } 6. 移动聚焦 // 鼠标移动时触发聚焦效果, 需要前面的聚焦效果消失, 所有需要重绘canvas Gobang.prototype.mouseMove = function(){ var that = this; this.canvas.addEventListener('mousemove', function (e) { that.ctx.clearRect(0, 0, that.col*30, that.col*30); var x = Math.floor((e.offsetX)/30), y = Math.floor((e.offsetY)/30); //重绘棋盘 that.drawBoard(); //移动聚焦效果 that.focusChess(x, y); //重绘已经下好的棋子 that.redrawedChess() }); } //鼠标移动聚焦 Gobang.prototype.focusChess = function(x, y){ this.ctx.beginPath(); this.ctx.fillStyle = '#E74343'; this.ctx.arc(15 + x * 30, 15 + y * 30, 6, 0, Math.PI*2); this.ctx.fill(); } //重绘当前下好的棋子 Gobang.prototype.redrawedChess = function(x, y){ for (var i = 0; i < this.existChesses.length; i++) { this.drawChess(this.existChesses[i].x, this.existChesses[i].y, this.existChesses[i].player); } } 7. 算法初始化 //算法初始化 Gobang.prototype.algorithmInit = function(){ //初始化棋盘的每个位置和赢法 for (var x = 0; x < this.col; x++) { this.allChesses[x] = []; this.wins[x] = []; for (var y = 0; y < this.col; y++) { this.allChesses[x][y] = false; this.wins[x][y] = []; } } //获取所有赢法 this.computedWins(); // 初始化电脑和我每个赢法当前拥有的棋子数 for (var i = 0; i < this.winsCount; i++) { this.myWins[i] = 0; this.computerWins[i] = 0; } } 8. 获取所有赢法 Gobang.prototype.computedWins = function(){ /* 直线赢法 以15列为准 */ for (var x = 0; x < this.col; x++) { //纵向所有赢法 for (var y = 0; y < this.col-4; y ++) { this.winsCount ++; /* 如: 1.组成的第一种赢法 [0,0] [0,1] [0,2] [0,3] [0,4] 2.组成的第二种赢法 [0,1] [0,2] [0,3] [0,4] [0,5] 以此类推一列最多也就11种赢法, 所有纵向x有15列 每列最多11种, 所有纵向总共15 * 11种 */ //以下for循环给每种赢法的位置信息储存起来 for (var k = 0; k < 5; k ++) { this.wins[x][y+k][this.winsCount] = true; /* 位置信息 第一种赢法的时候: this.wins = [ [ [1:true], [1:true], [1:true], [1:true], [1:true] ], [ ...... ] ] 虽然这是一个三维数组, 我们把它拆分下就好理解了 相当于 this.wins[0][0][1], this.wins[0][4][1], this.wins[0][5][1], this.wins[0][6][1], this.wins[0][7][1] 因为对象可以这样取值: var obj = { a: 10, b: 'demo' } obj['a'] === obj.a 所有也就相当于 this.wins[0][0].1, this.wins[0][8].1, this.wins[0][9].1, this.wins[0][10].1, this.wins[0][11].1 虽然数组不能这么取值,可以这么理解 所以 this.wins[0][0].1 就可以理解为 在 x=0, y=0, 上有第一种赢法 this.wins[0][12].1 就可以理解为 在 x=0, y=1, 上有第一种赢法 ...... 以上this.wins[0][0],this.wins[0][13]...可以看作是 this.wins[x][y] 所以第一种赢法的坐标就是: [0,0] [0,1] [0,2] [0,3] [0,4] */ } } } for (var y = 0; y < this.col; y++) { //横向所有赢法, 同纵向赢法一样,也是15 * 11种 for (var x = 0; x < this.col-4; x ++) { this.winsCount ++; for (var k = 0; k < 5; k ++) { this.wins[x+k][y][this.winsCount] = true; } } }