canvas實現的五子棋程式碼例項

admin發表於2017-02-13

分享一段程式碼例項,它利用canvas實現了五子棋的人機大戰效果。

程式碼例項如下:

[HTML] 純文字檢視 複製程式碼
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="author" content="http://www.softwhy.com/" />
<title>螞蟻部落</title>
</head>
<body>
<style>
* {
  margin: 0;
  padding: 0;
}
.chess_game {
  margin: 16px auto;
  width: 1200px;
}
canvas:nth-child(1) {
  margin: 0 auto;
  display: inline-block;
  float: left;
  top: 20px;
  cursor: pointer;
  border-radius: 5px;
  box-shadow: 3px 3px 5px gray;
}
canvas:nth-child(2) {
  position: relative;
  left: 0px;
  top: -600px;
  cursor: pointer;
}
</style>
<div class="chess_game">
  <canvas id="chess" width="1200" height="600"></canvas>
  <canvas id="animate" width="1200" height="600"></canvas>
</div>
<script>
var chess = document.getElementById("chess");
var c = chess.getContext("2d"); //獲取上下文
var animate = document.getElementById("animate");
var a = animate.getContext("2d"); //獲取上下文
var backimage = new Image(); //建立背景
//    backimage.src="../images/board.jpg";
backimage.src = "demo/js/img/wuzi.jpg";
backimage.onload = function() { //載入背景
  c.drawImage(backimage, 0, 0, 1200, 600); //繪製背景
  drawChessBoard(); //繪製棋盤
  drawTaiJi(c, 200, 300, 150, "#000000", Math.PI); //繪製太極
  drawTaiJi(c, 1000, 300, 150, "#ffffff", 0);
  drawChessPiece(c, 200, 225, false); //繪製太極棋眼
  drawChessPiece(c, 1000, 375, true);
  c.font = "bolder 50px 宋體";
  c.fillText("Player", 950, 540);
  c.fillStyle = "#ffffff";
  c.fillText("AlphaDog", 50, 540);
  reset();
}
var chessBoard = []; //將落子座標化,建立棋盤二維陣列;
var me = true; //設定第一步為me落棋,即黑子
var over = false;
var x, y, t = 500; //定義畫布座標,animation時間;
function reset() { //重置棋盤;
  for (var i = 0; i < 15; i += 1) {
    chessBoard<i> = [];
    for (var j = 0; j < 15; j += 1) {
      chessBoard<i>[j] = 0; //遍歷陣列,值初始化為0;
    }
  }
  a.clearRect(0, 0, 1200, 600);
  me = true; //設定第一步為me落棋,即黑子
  over = false;
}
 
var wins = []; //建立贏法三維陣列;
for (var i = 0; i < 15; i += 1) {
  wins<i> = [];
  for (var j = 0; j < 15; j += 1) {
    wins<i>[j] = [];
  }
}
var count = 0;
for (var i = 0; i < 15; i += 1) { //遍歷橫向贏法陣列
  for (var j = 0; j < 11; j += 1) {
    for (var k = 0; k < 5; k += 1) {
      wins<i>[j + k][count] = true;
    }
    count++;
  }
}
for (var i = 0; i < 15; i += 1) { //遍歷縱向贏法陣列
  for (var j = 0; j < 11; j += 1) {
    for (var k = 0; k < 5; k += 1) {
      wins[j + k]<i>[count] = true;
    }
    count++;
  }
}
for (var i = 0; i < 11; i += 1) { //遍歷反斜向贏法陣列
  for (var j = 0; j < 11; j += 1) {
    for (var k = 0; k < 5; k += 1) {
      wins[i + k][j + k][count] = true;
    }
    count++;
  }
}
for (var i = 4; i < 15; i += 1) { //遍歷斜向贏法陣列
  for (var j = 0; j < 11; j += 1) {
    for (var k = 0; k < 5; k += 1) {
      wins[i - k][j + k][count] = true;
    }
    count++;
  }
}
var myWin = [];
var computerWin = [];
for (var i = 0; i < count; i++) { //初始化陣列;
  myWin<i> = 0;
  computerWin<i> = 0
}
 
 
function drawChessBoard() { //定義繪製棋盤函式
  c.strokeStyle = "#454545";
  c.lineWidth = 1;
  for (var i = 0; i < 15; i += 1) {
    c.moveTo(320 + i * 40, 20);
    c.lineTo(320 + i * 40, 580);
    c.stroke();
    c.moveTo(320, 20 + i * 40);
    c.lineTo(880, 20 + i * 40);
    c.stroke();
  }
}
 
function oneStep(i, j, me) { //定義落子函式;
  c.beginPath();
  c.arc(320 + i * 40, 20 + j * 40, 15, 0, Math.PI * 2);
  c.closePath();
  //建立圓形漸變,兩個圓之間為漸變區域;
  var gradient = c.createRadialGradient(320 + i * 40, 20 + j * 40, 10, 320 + i * 40 + 2, 20 + j * 40 - 2, 0); 
  if (me) { //繪製黑棋;
    //可以在漸變區域漸變多種顏色;
    gradient.addColorStop(0, "#0a0a0a"); // gradient.addColorStop(0.3,"blue"); 
    gradient.addColorStop(1, "#636363");
  } else { //繪製白棋;
    gradient.addColorStop(0, "#e1e1e1");
    gradient.addColorStop(1, "#f1f1f1");
  }
  c.fillStyle = gradient;
  setTimeout(function() { //延遲落子,時間為動畫時間;
    c.fill();
  }, 500);
}
 
animate.onclick = function(e) { //定義棋盤點選落子事件
  if (over) {
    return;
  }
  if (!me) {
    return;
  }
  var x = e.offsetX; //用offset方法獲取螢幕點與canvas元素原點的相對座標;
  var y = e.offsetY;
  //向下取整;完整演算法為:(x-邊距+棋格寬度/2)/40,此處邊距等於棋格一半;
  var i = Math.floor(x / 40 - 7.5); 
  var j = Math.floor(y / 40);
  if (chessBoard<i>[j] == 0) { //判斷當前位置是否有棋子,無則執行落棋
    var m = i * 40 + 320; //計算計算落子的座標
    var n = j * 40 + 20;
    animation(m, n, me); //執行落子動畫;
    oneStep(i, j, me); //落子;
    chessBoard<i>[j] = 1; //設定黑子位置為1;
    for (var k = 0; k < count; k++) {
      if (wins<i>[j][k]) {
        myWin[k]++;
        computerWin[k] = 6;
        if (myWin[k] == 5) {
          c.font = "bolder 50px 宋體";
          c.fillStyle = "#000000";
          c.fillText("You Win!", 950, 100);
          over = true;
        }
      }
    }
    if (!over) {
      me = !me; //將me取反為false,對方落子;
      setTimeout(computerAI, 500); //延遲電腦落子500毫秒;
    }
  }
}
 
function computerAI() { //定義計算機智慧落子函式;
  var myScore = [];
  var computerScore = [];
  var max = 0;
  var u = 0,
    v = 0;
  for (var i = 0; i < 15; i++) {
    myScore<i> = [];
    computerScore<i> = [];
    for (var j = 0; j < 15; j++) {
      myScore<i>[j] = 0;
      computerScore<i>[j] = 0;
    }
  }
  for (var i = 0; i < 15; i += 1) {
    for (var j = 0; j < 15; j += 1) {
      if (chessBoard<i>[j] == 0) {
        for (var 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;
            }
            if (computerWin[k] == 1) {
              computerScore<i>[j] += 210;
            } else if (computerWin[k] == 2) {
              computerScore<i>[j] += 420;
            } else if (computerWin[k] == 3) {
              computerScore<i>[j] += 2400;
            } else if (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;
          }
        }
      }
    }
  }
  var m = u * 40 + 320; //計算計算落子的座標
  var n = v * 40 + 20;
  animation(m, n, me); //執行落子動畫;
  oneStep(u, v, me); //在分數最高的位置落子;
  chessBoard<u>[v] = 2; //設定白子位置為2;
  for (var k = 0; k < count; k++) {
    if (wins<u>[v][k]) {
      computerWin[k]++;
      myWin[k] = 6;
      if (computerWin[k] == 5) {
        c.font = "bolder 50px 宋體";
        c.fillStyle = "#ffffff";
        c.fillText("αDog Win!", 30, 100);
        over = true;
      }
    }
  }
  if (!over) {
    me = !me;
  }
}
 
//定義繪製太極圖函式,引數為上下文id,x/y座標,半徑,顏色,角度;
function drawTaiJi(context, x, y, r, color, deg) { 
  context.save(); //儲存狀態
  context.translate(x, y); //設定畫布旋轉的中心點
  context.rotate(deg);
  context.translate(-x, -y); //
  context.shadowColor = "rgba(10,10,10,0.5)"; //陰影顏色
  context.shadowOffsetX = context.shadowOffsetY = 5; //陰影方向
  context.shadowBlur = 5; //高斯值
  context.fillStyle = color;
  context.beginPath();
  context.arc(x, y, r, Math.PI * 1.5, Math.PI * 0.5);
  context.arc(x, y + r / 2, r / 2, Math.PI * 0.5, Math.PI * 1.5);
  context.arc(x, y - r / 2, r / 2, Math.PI * 0.5, Math.PI * 1.5, true); //預設順時針,值為false;逆時針為true;
  context.lineJoin = "round";
  context.closePath();
  context.fill();
  context.shadowColor = "rgba(10,10,10,0)"; //初始化陰影顏色
  context.restore(); //恢復狀態;
}
 
function drawChessPiece(context, x, y, color) { //繪製棋子函式
  context.beginPath();
  context.arc(x, y, 15, 0, 2 * Math.PI);
  context.closePath();
  var gradient = c.createRadialGradient(x, y, 10, x + 2, y - 2, 0); //建立圓形漸變,兩個圓之間為漸變區域;
  if (color) { //繪製黑棋;
    gradient.addColorStop(0, "#0a0a0a");
    gradient.addColorStop(1, "#636363");
  } else { //繪製白棋;
    gradient.addColorStop(0, "#e1e1e1");
    gradient.addColorStop(1, "#f1f1f1");
  }
  context.fillStyle = gradient;
  context.fill();
}
 
function animation(i, j, me) { //棋子落子時的動畫函式;
  if (me) { //判斷哪方落子
 
    var sx = (1000 - i) / 10; //將兩點之間x軸、y軸分別分成10段
    var sy = (375 - j) / 10;
    var k = 1;
    timer();
 
    function timer() {
      if (k < 11) {
        a.clearRect(0, 0, 1200, 600);
        //                    c.globalAlpha=1; //繪製畫素的透明度;
 
        drawChessPiece(a, 1000 - sx * k, 375 - sy * k, true); //繪製十次棋子
        k++;
        setTimeout(timer, 50);
      }
    }
  } else { //白子落子;
    var sx = (200 - i) / 10;
    var sy = (225 - j) / 10;
    var k = 1;
    timer();
 
    function timer() {
      if (k < 11) {
        a.clearRect(0, 0, 1200, 600); //清除畫布;
        drawChessPiece(a, 200 - sx * k, 225 - sy * k, false); //繪製十次棋子
        k++;
        setTimeout(timer, 50);
      }
    }
  }
}
</script>
</body>
</html>

相關文章