前言

  • 使用技术:
    • canvas
    • 算法
    • 三维数组
    • 循环遍历(计算赢法,计算坐标)

棋盘阴影

  1. display: block;
  2. margin: 50px auto;
  3. box-shadow: 5px 5px 5px #b9b9b9, -2px -2px 2px #efefef;

背景渐变

  1. background-image: linear-gradient(to top, #fbc2eb 0%, #a6c1ee 100%);

绘制棋盘

  1. // 获取棋盘元素容器
  2. let chess = document.querySelector('.chess');
  3. // 获取显示胜利的元素
  4. let title = document.querySelector('h3');
  5. // 获取开始游戏按钮
  6. let start = document.querySelector('.start');
  7. // 控制游戏状态
  8. let flag = false;
  9. // 将该元素变成一个可绘制的画板
  10. let context = chess.getContext('2d');
  11. // 设置画笔绘制颜色
  12. context.strokeStyle = '#b9b9b9';
  13. // 定义一个绘制棋盘的函数
  14. function drawChessBoard () {
  15. // 循环遍历生成棋盘
  16. for (let i = 0; i < 15; i++) {
  17. // 设置横线起始点坐标
  18. context.moveTo(15, 15+i*30);
  19. // 设置横线结束点坐标
  20. context.lineTo(435, 15+i*30);
  21. // 连接 2 点
  22. context.stroke();
  23. // 设置竖线起始点坐标
  24. context.moveTo(15+i*30, 15);
  25. // 设置竖线结束点坐标
  26. context.lineTo(15+i*30, 435);
  27. // 连接 2 点
  28. context.stroke();
  29. }
  30. }

赢法数组

  • 定义一个赢法数组
  • 将每个子的坐标放入数组中,判断五个子的坐标是否和赢法数组相匹配,匹配则赢,不匹配则继续游戏 ```javascript // 定义赢法数组 let wins = []; // 循环生成赢法数组 for(let i = 0; i < 15; i++) { wins[i] = [] for(let j = 0; j < 15; j++) {
    1. wins[i][j] = []
    } }

// 设置赢法编号 let count = 0; // 统计横线赢 for(let i = 0; i < 15; i++) { for(let j = 0; j < 11; j++) { for(let k = 0; k < 5; k++) { wins[j+k][i][count]=true; } count++; } }

// 统计竖线赢 for(let i = 0; i <15; i++) { for(let j = 0; j < 11; j++) { for(let k = 0; k < 5; k++) { wins[i][j+k][count]=true; } count++; } }

// 统计正斜线赢 for(let i = 0; i < 11; i++) { for(let j = 0; j < 11; j++) { for(let k = 0; k < 5; k++) { wins[i+k][j+k][count]=true; } count++; } }

// 统计反斜线赢 for(let i = 0; i < 11; i++) { for(let j = 14; j > 3; j—) { for(let k = 0; k < 5; k++) { wins[i+k][j-k][count]=true; } count++; } }

// 判断棋盘上的每个坐标内是否已经下了棋子 // 定义一个二维数组,标记棋盘上的所有坐标 let chessboard = []; // 循环遍历棋盘所有坐标 for(let i = 0; i < 15; i++) { chessboard[i]=[]; for(let j = 0; j < 15; j++) { chessboard[i][j] = 0; } }

// 下棋 let me = true; // 标记玩家是否可以下棋 let over = false; // 标记游戏是否结束

chess.onclick = function(e) { // 如果游戏结束,不可以下棋 if(over) { return; } // 判断玩家是否可以下棋 if(!me) { return; } // 获取 x 轴坐标 let x = e.offsetX; // 获取 y 轴坐标 let y = y.offsetY;

let i = Math.floor(x/30); let j = Math.floor(y/30);

if(chessboard[i][j] == 0) { // 下一个子 chessboard[i][j] = 1; } }

  1. <a name="mB0pk"></a>
  2. # 落子方法(绘制棋子)
  3. ```javascript
  4. function oneStep(i, j, me) {
  5. // 绘制棋子
  6. ctx.beginPath();
  7. ctx.arc(15+i*30, 15+j*30, 13, 0, 2*Math.PI);
  8. ctx.closePath();
  9. // 判断玩家或AI下棋,更改棋子颜色
  10. let color;
  11. if(me){
  12. color = '#000'
  13. }else {
  14. color = '#fff'
  15. }
  16. // 更改画笔颜色并填充
  17. ctx.fillStyle = color;
  18. ctx.fill()
  19. }

下棋

  1. 判断玩家是否可以下棋
  2. 游戏是否结束
  3. 记录玩家赢法分值
  4. 记录AI赢法分值

    1. // 定义所需变量
    2. let me = true; // 标记玩家是否可以下棋
    3. let over = false; // 标记游戏是否结束
    4. let myWin = []; // 记录玩家在赢法上的分值
    5. let computerWin = []; // 记录计算机在赢法上的分值
    1. // 初始化玩家赢法分值与AI赢法分值
    2. for(let i = 0; i < count; i++) {
    3. myWin[i] = 0;
    4. computerWin[i] = 0;
    5. }
    1. // 判断是否点击开始游戏
    2. start.onclick = () => {
    3. if(!flag){
    4. flag = !flag;
    5. start.innerHTML = '重新开始';
    6. }else {
    7. window.location.reload()
    8. }
    9. }
    // 点击画板落子
    chess.onclick = function(e) {
     // 如果游戏结束,不可以下棋
    if(flag) {
     if(over) {
       return;
     }
     // 判断玩家是否可以下棋
     if(!me) {
       return;
     }
     // 获取 x 轴坐标
     let x = e.offsetX;
     // 获取 y 轴坐标
     let y = e.offsetY;
    
     let i = Math.floor(x/30);
     let j = Math.floor(y/30);
    
     if(chessboard[i][j] == 0) {
       // 下一个子
       oneStep(i, j, me);
       chessboard[i][j] = 1;
    
       for(let k = 0; k < count; k++) {
         if(wins[i][j][k]) {
           myWin[k]++;
           if(myWin[k] == 5) {
             title.innerHTML = 'player win!'
             over = true;
           }
         }
       }
     }
    
     if(!over) {
       me = !me;
       // 计算机落子
       computerAI();
     }
    
     // AI落子
     function computerAI() {
       // 空白子在用户所占用赢法上的分值
       let myScore = [];
       // 空白子在计算机所占用赢法上的分值
       let computerScore = [];
    
       for(let i = 0; i < 15; i++) {
         myScore[i] = [];
         computerScore[i] = [];
         for(let j = 0; j < 15; j++) {
           myScore[i][j] = 0;
           computerScore[i][j] = 0;
         }
       }
       // 空白子的最大分值
       let max = 0;
       // 最大分值空白子所在的坐标
       let x = 0, y = 0;
       for(let i = 0; i < 15; i++) {
         for(let j = 0; j < 15; j++) {
           // 判断是否是空白子
           if(chessboard[i][j] == 0) {
             for(let k = 0; k < count; k++) {
               if(wins[i][j][k]) {
                 // 玩家分值
                 if(myWin[k] == 1) {
                   myScore[i][j] += 200;
                 }else if(myWin[k] == 2) {
                   myScore[i][j] += 400;
                 }else if(myWin[k] == 3) {
                   myScore[i][j] += 2000;
                 }else if(myWin[k] == 4) {
                   myScore[i][j] += 10000;
                 }
                 // AI分值
                 if(computerWin[k] == 1) {
                   computerScore[i][j] += 220;
                 }else if(computerWin[k] == 2) {
                   computerScore[i][j] += 420;
                 }else if(computerWin[k] == 3) {
                   computerScore[i][j] += 2200;
                 }else if(computerWin[k] == 4) {
                   computerScore[i][j] += 20000;
                 }
               }
             }
             // 判断玩家最大分值的空白子
             if(myScore[i][j] > max) {
               max = myScore[i][j];
               x = i;
               y = j;
             }else if(myScore[i][j] == max) {
               if(computerScore[i][j] > max) {
                 max = computerScore[i][j];
                 x = i;
                 y = j;
               }
             }
                         // 判断AI最大分值的空白子
             if(computerScore[i][j] > max) {
               max = computerScore[i][j];
               x = i;
               y = j;
             }else if(computerScore[i][j] == max){
               if(myScore[i][j] > max) {
                 max = myScore[i][j];
                 x = i;
                 y = j;
               }
             }
           }
         }
       }
       oneStep(x, y, me);
       chessboard[x][y] = 1;
       // 判断计算机是否赢
       for(let k = 0; k < count; k++) {
         if(wins[x][y][k]) {
           computerWin[k] += 1;
           if(computerWin[k] == 5) {
             title.innerHTML = 'AI win!'
             over = true;
           }
         }
       }
       if(!over) {
         me = !me;
       }
     }
    
     // 落子方法
    }
    }
    

    落子方法

     function oneStep(i, j, me) {
       // 绘制棋子
       ctx.beginPath();
       ctx.arc(15+i*30, 15+j*30, 13, 0, 2*Math.PI);
       ctx.closePath();
    
       // 判断玩家或AI下棋,更改棋子颜色
       let color;
       if(me){
         color = '#000'
       }else {
         color = '#fff'
       }
    
       // 更改画笔颜色并填充
       ctx.fillStyle = color;
       ctx.fill()
     }