Algorithma Tic Tac Toe dengan HTML5 Canvas


Penasaran membuat game Tic Tac Toe, terutama tentang menambahkan kecerdasan buatan (Artificial Intelligence) untuk melawan pemain, penulis mencoba menuliskan algorithma dan memvisualisasikannya dengan HTML5 Canvas.

Kode program game Tic Tac Toe dibawah ini disertai dengan interaksi mouse dan touch untuk mempermudah penggunaan.

Sedangkan ide kecerdasan buatannya, komputer mencari dulu posisi terbaik untuk dirinya agar menang, baru jika tidak terpenuhi, komputer mencari posisi yang paling tepat untuk bertahan.

<html> 
<head> 
<title>Tic Tac Toe</title> 
</head> 
<body> 
<div id="score" style="font-size:42px;color:#009688;width:500px;text-align:center;"></div> 
<div id="hasil" style="font-size:42px;color:#009688;width:500px;text-align:center;"></div> 
<canvas id="myCanvas" width="500" height="500"> 
</canvas><br/> 
<button onclick="resetFunction()">Play Again</button> 
<script> 

var canvas = document.getElementById("myCanvas"); 
var ctx = canvas.getContext("2d"); 
 
var drawing = false; 
var mousePos = { x:0, y:0 }; 
var lastPos = mousePos; 
canvas.addEventListener("mousedown", function (e) { 
 if(!GAMEOVER)drawing = true; 
 lastPos = getMousePos(canvas, e); 
 //Menggambar(); 
}, false); 
canvas.addEventListener("mouseup", function (e) { 
 //drawing = false; 
}, false); 
canvas.addEventListener("mousemove", function (e) { 
 mousePos = getMousePos(canvas, e); 
}, false); 
 
// Get the position of the mouse relative to the canvas 
function getMousePos(canvasDom, mouseEvent) { 
  var rect = canvasDom.getBoundingClientRect(); 
  return { 
    x: mouseEvent.clientX - rect.left, 
    y: mouseEvent.clientY - rect.top 
  }; 
} 
 
// Set up touch events for mobile, etc 
canvas.addEventListener("touchstart", function (e) { 
 mousePos = getTouchPos(canvas, e); 
 var touch = e.touches[0]; 
 var mouseEvent = new MouseEvent("mousedown", { 
  clientX: touch.clientX, 
  clientY: touch.clientY 
 }); 
 canvas.dispatchEvent(mouseEvent); 
}, false); 
 
canvas.addEventListener("touchend", function (e) { 
  var mouseEvent = new MouseEvent("mouseup", {}); 
  canvas.dispatchEvent(mouseEvent); 
}, false); 
 
canvas.addEventListener("touchmove", function (e) { 
  var touch = e.touches[0]; 
  var mouseEvent = new MouseEvent("mousemove", { 
    clientX: touch.clientX, 
    clientY: touch.clientY 
  }); 
  canvas.dispatchEvent(mouseEvent); 
}, false); 
 
// Get the position of a touch relative to the canvas 
function getTouchPos(canvasDom, touchEvent) { 
  var rect = canvasDom.getBoundingClientRect(); 
  return { 
    x: touchEvent.touches[0].clientX - rect.left, 
    y: touchEvent.touches[0].clientY - rect.top 
  }; 
} 
 
var delta=canvas.width/3; 
 
var Box=[]; 
 
for(var i=0;i<9;i++)Box[i]=0; 
 
var MODETURN=1+Math.floor(2.0*Math.random()); 
var GAMEOVER=false; 
var scoreplayer=0,scorecomputer=0; 
var GRS=-1; 
 
function cariPosisi(turn) 
{ 
 var index=[0,1,2,0,3,6,3,4,5,6,7,8,1,4,7,2,5,8,0,4,8,2,4,6]; 
 for(var i=0;i<index.length/3;i++){ 
  if(Box[index[3*i+0]]==turn && Box[index[3*i+1]]==turn && Box[index[3*i+2]]==0){ 
   return index[3*i+2]; 
  }else if(Box[index[3*i+0]]==turn && Box[index[3*i+1]]==0 && Box[index[3*i+2]]==turn){ 
   return index[3*i+1]; 
  }else if(Box[index[3*i+0]]==0 && Box[index[3*i+1]]==turn && Box[index[3*i+2]]==turn){ 
   return index[3*i+0]; 
  } 
 } 
 return -1; 
} 
 
function cariDekat(turn) 
{ 
 for(var i=0;i<9;i++){ 
  if(Box[i]==turn){ 
   var io=i%3; 
   var jo=i/3; 
   if(io==1){ 
    io=(5*Math.random()<3)?io-1:io+1; 
   }else{ 
    io=(io==0)?io+1:io-1; 
   } 
   if(jo==1){ 
    jo=(5*Math.random()<3)?jo-1:jo+1; 
   }else{ 
    jo=(jo==0)?jo+1:jo-1; 
   } 
   return (io+3*jo); 
  } 
 } 
 return -1; 
} 
 
function jumTerisi() 
{ 
 var jum=0; 
 for(var i=0;i<9;i++){ 
  if(Box[i]!=0){ 
   jum++; 
  } 
 } 
 return jum; 
} 
 
function checkMenang() 
{ 
 var menang=0; 
 if(Box[0]==Box[1] && Box[0]==Box[2]){ 
  menang=Box[0];GRS=0; 
 } 
 if(menang==0 && Box[3]==Box[4] && Box[3]==Box[5]){ 
  menang=Box[3];GRS=1; 
 } 
 if(menang==0 && Box[6]==Box[7] && Box[6]==Box[8]){ 
  menang=Box[6];GRS=2; 
 } 
 if(menang==0 && Box[0]==Box[3] && Box[0]==Box[6]){ 
  menang=Box[0];GRS=3; 
 } 
 if(menang==0 && Box[1]==Box[4] && Box[1]==Box[7]){ 
  menang=Box[1];GRS=4; 
 } 
 if(menang==0 && Box[2]==Box[5] && Box[2]==Box[8]){ 
  menang=Box[2];GRS=5; 
 } 
 if(menang==0 && Box[0]==Box[4] && Box[0]==Box[8]){ 
  menang=Box[0];GRS=6; 
 } 
 if(menang==0 && Box[2]==Box[4] && Box[2]==Box[6]){ 
  menang=Box[2];GRS=7; 
 } 
 return menang; 
} 
 
function resetFunction() 
{ 
 GAMEOVER=false; 
 for(var i=0;i<9;i++)Box[i]=0; 
 MODETURN=1+Math.floor(2.0*Math.random()); 
 Menggambar(); 
} 

document.getElementById("score").innerHTML=scoreplayer+":"+scorecomputer; 
function Menggambar() 
{ 
 document.getElementById("hasil").innerHTML=(MODETURN==1)?"Player turn":"Computer turn"; 
 
 if(MODETURN==2){ 
  var jumisi=jumTerisi(); 
  if(jumisi==0){ 
   Box[Math.floor(9.0*Math.random())]=2; 
   MODETURN=1; 
  }else if(jumisi==1 || jumisi==2){ 
   var pasang=-1; 
   while(pasang<0){ 
    var a=cariDekat(1); 
    if(a<0)a=cariDekat(2); 
    if(a>=0 && Box[a]==0){ 
     Box[a]=2; 
     pasang=1; 
    } 
   } 
   MODETURN=1; 
  }else if(jumisi>2){ 
   var a=cariPosisi(2); 
   var no=a; 
   if(a<0){ 
    a=cariPosisi(1); 
    if(a<0){ 
     var pasang=-1; 
     while(pasang<0 && jumisi<9){ 
      no=Math.floor(9.0*Math.random()); 
      if(no>=0 && Box[no]==0)pasang=1; 
     } 
    } 
    else no=a; 
   } 
   if(no>=0){ 
    if(Box[no]==0){ 
     Box[no]=2; 
     MODETURN=1; 
    } 
   } 

  } 
 } 
 
 if(drawing){ 
  if(MODETURN==1){ 
   var ax=Math.floor(lastPos.x/delta); 
   var ay=Math.floor(lastPos.y/delta); 
   var n=ax+ay*3; 
   if(n>=0 && n<9){ 
    if(Box[n]==0){ 
     Box[n]=1; 
     MODETURN=2; 
    } 
   } 
  } 
  drawing=false; 
 } 

 ctx.fillStyle="white"; 
 ctx.fillRect(0,0,canvas.width,canvas.height); 

 ctx.strokeStyle="black"; 
 ctx.lineWidth=5; 
 ctx.beginPath(); 
 ctx.moveTo(delta,0); 
 ctx.lineTo(delta,canvas.height); 
 ctx.moveTo(2*delta,0); 
 ctx.lineTo(2*delta,canvas.height); 
 ctx.moveTo(0,delta); 
 ctx.lineTo(canvas.width,delta); 
 ctx.moveTo(0,2*delta); 
 ctx.lineTo(canvas.width,2*delta); 
 ctx.stroke(); 
 ctx.closePath(); 

 ctx.save(); 
 ctx.shadowBlur = 5; 
 ctx.shadowOffsetX = 3; 
 ctx.shadowOffsetY = 3; 
 ctx.shadowColor = "black"; 
 ctx.lineWidth=15; 
 for(var i=0;i<9;i++){ 
  var io=i%3; 
  var jo=Math.floor(i/3)%3; 
  if(Box[i]==1){ 
   ctx.strokeStyle="red"; 
   ctx.beginPath(); 
   ctx.arc((io+0.5)*delta,(jo+0.5)*delta,0.35*delta, 0, 2 * Math.PI); 
   ctx.stroke(); 
  }else if(Box[i]==2){ 
   ctx.strokeStyle="blue"; 
   ctx.beginPath(); 
   ctx.moveTo(io*delta,jo*delta); 
   ctx.lineTo((io+1)*delta,(jo+1)*delta); 
   ctx.moveTo((io+1)*delta,jo*delta); 
   ctx.lineTo(io*delta,(jo+1)*delta); 
   ctx.stroke(); 
  } 
 } 

 var mng=checkMenang(); 
 if(mng!=0){ 
  GAMEOVER=true; 

  ctx.lineWidth=30; 
  ctx.strokeStyle="green"; 
  ctx.beginPath(); 
  if(GRS==0){ 
   ctx.moveTo(0,0.5*delta); 
   ctx.lineTo(canvas.width,0.5*delta); 
  }else if(GRS==1){ 
   ctx.moveTo(0,1.5*delta); 
   ctx.lineTo(canvas.width,1.5*delta); 
  }else if(GRS==2){ 
   ctx.moveTo(0,2.5*delta); 
   ctx.lineTo(canvas.width,2.5*delta); 
  }else if(GRS==3){ 
   ctx.moveTo(0.5*delta,0); 
   ctx.lineTo(0.5*delta,canvas.height); 
  }else if(GRS==4){ 
   ctx.moveTo(1.5*delta,0); 
   ctx.lineTo(1.5*delta,canvas.height); 
  }else if(GRS==5){ 
   ctx.moveTo(2.5*delta,0); 
   ctx.lineTo(2.5*delta,canvas.height); 
  }else if(GRS==6){ 
   ctx.moveTo(0,0); 
   ctx.lineTo(canvas.width,canvas.height); 
  }else if(GRS==7){ 
   ctx.moveTo(canvas.width,0); 
   ctx.lineTo(0,canvas.height); 
  } 
  ctx.stroke(); 

  document.getElementById("hasil").innerHTML=(mng==1)?"Player win":"Computer win"; 
  if(mng==1)scoreplayer++; 
  if(mng==2)scorecomputer++; 
  document.getElementById("score").innerHTML=scoreplayer+":"+scorecomputer; 
 }else{ 
  if(jumisi==9){ 
   GAMEOVER=true; 
   document.getElementById("hasil").innerHTML="Match"; 
  } 
 } 
 ctx.restore(); 

 if(!GAMEOVER)window.requestAnimationFrame(Menggambar); 
} 
 
Menggambar(); 
</script> 
</body> 
</html> 

Komentar



Postingan populer dari blog ini

Apps Script untuk Cetak Sertifikat

Cara Menentukan Arah Kiblat Menggunakan Google Maps

Algorithma FPB dan KPK dengan Javascript

Peringatan: Aksi Penipuan Skimming Melalui Aplikasi Android M-Pajak

Jasa Penjadwalan Semester, UTS dan UAS Perguruan Tinggi menggunakan Google Sheet

Genetics Algorithm Method with Progressive Error Prediction

Kebodohan Karyawan Menyalahkan Sistem

Apps Script untuk Copy File ke Folder berdasarkan ID yang Terdaftar di Google Sheets

Menambahkan Random Key sebagai ID Pembeda di Google Sheet dengan Apps Script

Menampilkan Struktur Tabel MySQL dengan JTree