Vue 实现人机五子棋,Canvas绘图,不难理解直接上码
发布于 6 年前 作者 varscc 4151 次浏览 来自 分享
  • 核心代码
export default {
  data () {
    return {
      chess: {},
      context: {},
      chessBoard: [], // 记录是否走过
      me: true,
      count: 0, // 所有赢法数量
      wins: [], // 赢法数组
      myWin: [], // 我方赢法的统计数组
      computerWin: [], // 计算机赢法的统计数组
      over: false,
    }
  },
  mounted () {
    setTimeout(_ => {
      this.init()
    })
  },
  methods: {
    // 初始化
    init () {
      this.chess = this.$refs.canvas
      this.context = this.chess.getContext("2d")
      this.drawImage( _ => {
        this.drawChessBoard()
      })
      this.fillArray()
    },
    // 填充数组
    fillArray () {
      // 是否走过
      for (let i = 0; i < 15; i++) {
        this.chessBoard[i] = []
        for (let j = 0; j < 15; j++) {
          this.chessBoard[i][j] = 0
        }
      }
      // 赢法数组
      for (let i = 0; i < 15; i++) {
        this.wins[i] = []
        for (let j = 0; j < 15; j++) {
          this.wins[i][j] = []
        }
      }
      // 横
      for (let i = 0; i < 15; i++) {
        for (let j = 0; j < 11; j++) {
          for (let k = 0; k < 5; k++) {
            this.wins[i][j+k][this.count] = true
          }
          this.count++
        }
      }
      // 竖
      for (let i = 0; i < 15; i++) {
        for (let j = 0; j < 11; j++) {
          for (let k = 0; k < 5; k++) {
            this.wins[j+k][i][this.count] = true
          }
          this.count++
        }
      }
      // 斜
      for (let i = 0; i < 11; i++) {
        for (let j = 0; j < 11; j++) {
          for (let k = 0; k < 5; k++) {
            this.wins[i+k][j+k][this.count] = true
          }
          this.count++
        }
      }
      // 反斜
      for (let i = 0; i < 11; i++) {
        for (let j = 14; j > 3; j--) {
          for (let k = 0; k < 5; k++) {
            this.wins[i+k][j-k][this.count] = true
          }
          this.count++
        }
      }
      // 赢法的统计数组
      for (let i = 0; i < this.count; i++) {
        this.myWin[i] = 0
        this.computerWin[i] = 0
      }
    },
    // 绘制水印
    drawImage (callback) {
      const { context } = this
      const img = new Image()
      img.src = "/images/logo.svg"
      img.onload = _ => {
        context.drawImage(img, (450 - img.width)/2, (450 - img.height)/2, img.width, img.height)
        callback()
      }
    },
    // 绘制棋盘
    drawChessBoard () {
      const { context } = this
      context.strokeStyle = '#bfbfbf'
      for (let i = 0; i < 15; i++) {
        context.moveTo(15 + i * 30, 15)
        context.lineTo(15 + i * 30, 435)
        context.stroke()
        context.moveTo(15, 15 + i * 30)
        context.lineTo(435, 15 + i * 30)
        context.stroke()
      }
    },
    // 落子实现
    onStep (x, y, me) {
      const { context } = this
      context.beginPath()
      context.arc(15 + x * 30, 15 + y * 30, 13, 0, 2 * Math.PI)
      context.closePath()
      const gradient = context.createRadialGradient(15 + x * 30 + 2, 15 + y * 30 - 2, 13, 15 + x * 30 + 2, 15 + y * 30 - 2, 0)
      if (me) {
        gradient.addColorStop(0, '#0a0a0a')
        gradient.addColorStop(1, '#636766')
      } else {
        gradient.addColorStop(0, '#d1d1d1')
        gradient.addColorStop(1, '#f9f9f9')
      }
      context.fillStyle = gradient
      context.fill()
    },
    // 我方落子
    chessClick (e) {
      if (this.over) {
        return
      }
      if (!this.me) {
        return
      }
      const ox = e.offsetX
      const oy = e.offsetY
      const x = Math.floor(ox/30)
      const y = Math.floor(oy/30)

      if (this.chessBoard[x][y] === 0) {
        this.chessBoard[x][y] = 1
        this.onStep(x, y, this.me)

        // 统计赢法
        for (let k = 0; k < this.count; k++) {
          if (this.wins[x][y][k]) {
            this.myWin[k]++
            this.computerWin[k] = 6
            if (this.myWin[k] === 5) {
              alert('你赢了')
              this.over = true
            }
          }
        }
        if (!this.over) {
          this.me = !this.me
          this.computerAI()
        }
      }
    },
    // 计算机落子
    computerAI () {
      const myScore = []
      const computerScore = []
      let max = 0 // 最大分数
      let u = 0, v = 0 // 所在坐标

      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
        }
      }
      // 遍历棋盘
      for (let i = 0; i < 15; i++) {
        for (let j = 0; j < 15; j++) {
          if (this.chessBoard[i][j] === 0) {
            // 遍历所有赢法
            for (let k = 0; k < this.count; k++) {
              if (this.wins[i][j][k]) {
                // 我方
                if (this.myWin[k] === 1) {
                  myScore[i][j] += 200
                } else if (this.myWin[k] === 2) {
                  myScore[i][j] += 400
                } else if (this.myWin[k] === 3) {
                  myScore[i][j] += 2000
                } else if (this.myWin[k] === 4) {
                  myScore[i][j] += 10000
                }
                // 计算机
                if (this.computerWin[k] === 1) {
                  computerScore[i][j] += 220
                } else if (this.computerWin[k] === 2) {
                  computerScore[i][j] += 420
                } else if (this.computerWin[k] === 3) {
                  computerScore[i][j] += 2100
                } else if (this.computerWin[k] === 4) {
                  computerScore[i][j] += 20000
                }
              }
            }
            // 比较分数
            if (myScore[i][j] > max) {
              max = myScore[i][j]
              u = i
              v = j
            } else if (myScore[i][j] === max) {
              if (computerScore[i][j] > computerScore[u][v]) {
                u = i
                v = j
              }
            }
            if (computerScore[i][j] > max) {
              max = computerScore[i][j]
              u = i
              v = j
            } else if (computerScore[i][j] === max) {
              if (myScore[i][j] > myScore[u][v]) {
                u = i
                v = j
              }
            }
          }
        }
      }
      this.onStep(u, v, false)
      this.chessBoard[u][v] = 2
      // 统计赢法
      for (let k = 0; k < this.count; k++) {
        if (this.wins[u][v][k]) {
          this.computerWin[k]++
          this.myWin[k] = 6
          if (this.computerWin[k] === 5) {
            alert('计算机赢了')
            this.over = true
          }
        }
      }
      if (!this.over) {
        this.me = !this.me
      }
    }
  }
}

原文地址:https://unnue.com/article/50

2 回复

ai部分有点6 . 不过这个代码是不是能优化下啊, 过深的循环和if else嵌套 魔数,太过程式,可以考虑一些地方用fp的方式封装下.

回到顶部