トップへ(mam-mam.net/)

WEBサイトでリバーシ ゲーム(白と黒の駒を裏返すゲーム)

検索:

Javascriptで対戦型のゲーム「リバーシ」を作る

リバーシ

盤をクリックしてコンピューターと交互に駒を配置できます。「開始」ボタンを押すとやり直しできます。




<!DOCTYPE html>
<html>
<head>
  <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=yes">
  <META charset="UTF-8">
  <title></title>
<script>
  function TReversi(can,tx,button){
    'use strict';
    this.wh=320;
    this.canvas=can;
    this.cx=this.canvas.getContext('2d', {willReadFrequently:true});
    this.canvas.style.width="70vmin";
    this.canvas.style.height="70vmin";
    this.canvas.setAttribute("width",this.wh+"px");
    this.canvas.setAttribute("height",this.wh+"px");
    this.textarea=tx;
    this.ai=[
      {x:0,y:0},{x:0,y:7},{x:7,y:7},{x:7,y:0},
      {x:2,y:2},{x:2,y:5},{x:5,y:5},{x:5,y:2},
      {x:2,y:0},{x:0,y:2},{x:0,y:5},{x:2,y:7},
      {x:5,y:7},{x:7,y:5},{x:7,y:2},{x:5,y:0},
      {x:3,y:1},{x:1,y:3},{x:1,y:4},{x:3,y:6},
      {x:4,y:6},{x:6,y:4},{x:6,y:3},{x:4,y:1},
      {x:3,y:0},{x:0,y:3},{x:0,y:4},{x:3,y:7},
      {x:4,y:7},{x:7,y:4},{x:7,y:3},{x:4,y:0},
      {x:3,y:2},{x:2,y:3},{x:2,y:4},{x:3,y:5},
      {x:4,y:5},{x:5,y:4},{x:5,y:3},{x:4,y:2},
      {x:2,y:1},{x:1,y:2},{x:1,y:5},{x:2,y:6},
      {x:5,y:6},{x:6,y:5},{x:6,y:2},{x:5,y:1},
      {x:1,y:0},{x:0,y:1},{x:0,y:6},{x:1,y:7},
      {x:6,y:7},{x:7,y:6},{x:7,y:1},{x:6,y:0},
      {x:1,y:1},{x:1,y:6},{x:6,y:6},{x:6,y:1},
      {x:3,y:3},{x:3,y:4},{x:4,y:4},{x:4,y:3}
    ];
    this.board=[];
    this.pcuser="";//"","pc","user"
    this.user_iro=1;//1:white 2:black
    this.pc_iro=2;//1:white 2:black
    this.winResize=function(event){
    }
    //開始
    this.start=function(){
      this.textarea.innerHTML="";
      let x,y;
      for(x=0;x<8;x++){
        this.board[x]=[];
        for(y=0;y<8;y++){
          this.board[x][y]=0;
        }
      }
      this.board[3][3]=1;
      this.board[4][4]=2;
      this.board[3][4]=2;
      this.board[4][3]=1;
      if(Math.random()>0.5){
        this.pcuser="pc";
      }else{
        this.pcuser="user";
      }
      if(Math.random()>0.5){
        this.user_iro=1;
        this.pc_iro=2;
      }else{
        this.user_iro=2;
        this.pc_iro=1;
      }
      this.draw();
      this.textout_count();
      this.textout();
      if(this.pcuser=="pc"){
        setTimeout(this.calculate.bind(this),1000);
      }
    }
    //描画
    this.draw=function(){
      this.cx.fillStyle="#3C3";
      this.cx.fillRect(0,0,this.wh,this.wh);
      let x,y;
      this.cx.strokeStyle="#FFF";
      this.cx.lineWidth=4;
      for(x=0;x<8;x++){
        this.cx.beginPath();
        this.cx.moveTo(this.wh/8*x,0);
        this.cx.lineTo(this.wh/8*x,this.wh);
        this.cx.stroke();
      }
      for(y=0;y<8;y++){
        this.cx.beginPath();
        this.cx.moveTo(0,this.wh/8*y);
        this.cx.lineTo(this.wh,this.wh/8*y);
        this.cx.stroke();
      }
      this.lineWidth=2;
      for(x=0;x<8;x++){
        for(y=0;y<8;y++){
          if(this.board[x][y]==1){
            this.cx.strokeStyle="#000";
            this.cx.fillStyle="#FFF";
            this.cx.beginPath();
            this.cx.arc(this.wh/8*(x+0.5),this.wh/8*(y+0.5),this.wh/8/2*0.7,0,Math.PI*2,false);
            this.cx.fill();
            this.cx.stroke();
          }
          if(this.board[x][y]==2){
            this.cx.strokeStyle="#FFF";
            this.cx.fillStyle="#000";
            this.cx.beginPath();
            this.cx.arc(this.wh/8*(x+0.5),this.wh/8*(y+0.5),this.wh/8/2*0.7,0,Math.PI*2,false);
            this.cx.fill();
            this.cx.stroke();
          }
        }
      }
    }
    //文字出力(順番)
    this.textout=function(){
      let ucol="",pcol="";
      if(this.user_iro==1){ucol="白";pcol="黒";}else{ucol="黒";pcol="白";}
      if(this.pcuser=="user"){this.textarea.innerHTML=this.textarea.innerHTML+'\nあなたの番('+ucol+')';}
      if(this.pcuser=="pc"){this.textarea.innerHTML+='\nPCの番('+pcol+')';}
      this.textarea.scrollTop=this.textarea.scrollHeight;
    }
    //文字列出力(駒の数)
    this.textout_count=function(){
      let ucol="",pcol="";
      if(this.user_iro==1){ucol="白";pcol="黒";}else{ucol="黒";pcol="白";}
      let x, y;
      let pc_count=0, user_count=0;
      for(x=0;x<8;x++){
        for(y=0;y<8;y++){
          if(this.board[x][y]==this.user_iro){
            user_count++;
          }else if(this.board[x][y]==this.pc_iro){
            pc_count++;
          }
        }
      }
      this.textarea.innerHTML+='\nあなた('+ucol+'):'+user_count+'  PC('+pcol+'):'+pc_count;
      this.textarea.scrollTop=this.textarea.scrollHeight;
      if(this.cannot_pc_user()){
        this.pcuser="";
        this.textarea.innerHTML+='\nゲーム終了';
        this.textarea.scrollTop=this.textarea.scrollHeight;
      }
    }
    this.canputpiece=function(x,y,okuiro,dx,dy){
      let kaesuiro=1;
      if(okuiro==1){kaesuiro=2;}
      let flag=0;
      let spx=x+dx;
      let spy=y+dy;
      while(spx>=0 && spx<=7 && spy>=0 && spy<=7){
        if(this.board[spx][spy]==0){
          break;
        }else if(this.board[spx][spy]==kaesuiro){
          flag=1;
        }else if(this.board[spx][spy]==okuiro){
          if(flag==1){flag=2;}
          break;
        }
        spx+=dx;
        spy+=dy;
      }
      if(flag==2){
        return true;
      }else{
        return false;
      }
    }
    this.canputpieces=function(x,y,okuiro){
      let flag=false;
      if(this.canputpiece(x,y,okuiro, 0,-1)){flag=true;}
      if(this.canputpiece(x,y,okuiro,-1,-1)){flag=true;}
      if(this.canputpiece(x,y,okuiro,-1, 0)){flag=true;}
      if(this.canputpiece(x,y,okuiro,-1, 1)){flag=true;}
      if(this.canputpiece(x,y,okuiro, 0, 1)){flag=true;}
      if(this.canputpiece(x,y,okuiro, 1, 1)){flag=true;}
      if(this.canputpiece(x,y,okuiro, 1, 0)){flag=true;}
      if(this.canputpiece(x,y,okuiro, 1,-1)){flag=true;}
      return flag;
    }
    this.reversepiece=function(x,y,okuiro,dx,dy){
      let kaesuiro=1;
      if(okuiro==1){kaesuiro=2;}
      let res=this.canputpiece(x,y,okuiro,dx,dy);
      if(res){
        let spx=x+dx;
        let spy=y+dy;
        while(this.board[spx][spy]==kaesuiro&&spx>=0&&spx<=7&&spy>=0&&spy<=7){
          this.board[spx][spy]=okuiro;
          spx+=dx;
          spy+=dy;
        }
      }
    }
    this.reversepieces=function(x,y,okuiro){
      let flag=false;
      if(this.reversepiece(x,y,okuiro, 0,-1)){flag=true;}
      if(this.reversepiece(x,y,okuiro,-1,-1)){flag=true;}
      if(this.reversepiece(x,y,okuiro,-1, 0)){flag=true;}
      if(this.reversepiece(x,y,okuiro,-1, 1)){flag=true;}
      if(this.reversepiece(x,y,okuiro, 0, 1)){flag=true;}
      if(this.reversepiece(x,y,okuiro, 1, 1)){flag=true;}
      if(this.reversepiece(x,y,okuiro, 1, 0)){flag=true;}
      if(this.reversepiece(x,y,okuiro, 1,-1)){flag=true;}
      return flag;
    }
    //交代
    this.orderchange=function(){
      if(this.pcuser=="user"){
        this.pcuser="pc";
      }else if(this.pcuser="pc"){
        this.pcuser="user";
      }
      this.textout_count();
      this.textout();
      if(this.pcuser=="pc"){
        setTimeout(this.calculate.bind(this),1000);
      }
    }
    //次の手を探す
    this.calculate=function(){
      if(this.pcuser!="pc"){return false;}
      let dx=-1;
      let dy=-1;
      let i;
      for(i=0;i<this.ai.length;i++){
        if(this.board[this.ai[i].x][this.ai[i].y]==0){
          if(this.canputpieces(this.ai[i].x,this.ai[i].y,this.pc_iro)){
            dx=this.ai[i].x;
            dy=this.ai[i].y;
            break;
          }
        }
      }
      if(dx==-1){
        this.textarea.innerHTML+='\nPC:駒を置けないのでパス';
        this.textarea.scrollTop=this.textarea.scrollHeight;
      }else{
        this.board[dx][dy]=this.pc_iro;
        this.reversepieces(dx,dy,this.pc_iro);
      }
      this.orderchange();
      this.draw();
    }
    //ユーザーが駒を置けない(true)
    this.cannot_user=function(){
      let x,y;
      let flag=true;
      for(x=0;x<8;x++){
        for(y=0;y<8;y++){
          if(this.board[x][y]==0){
            if(this.canputpieces(x,y,this.user_iro)){
              flag=false;
              break;
            }
          }
        }
      }
      return flag;
    }
    //PCが駒を置けない(true)
    this.cannot_pc=function(){
      let x,y;
      let flag=true;
      for(x=0;x<8;x++){
        for(y=0;y<8;y++){
          if(this.board[x][y]==0){
            if(this.canputpieces(x,y,this.pc_iro)){
              flag=false;
              break;
            }
          }
        }
      }
      return flag;
    }
    //PCもユーザーも駒を置けない(true)
    this.cannot_pc_user=function(){
      let flag=true;
      let x,y;
      for(x=0;x<8;x++){
        for(y=0;y<8;y++){
          if(this.board[x][y]==0){
            flag=false;
            break;
          }
        }
      }
      if(flag==false){
        if(this.cannot_user()&&this.cannot_pc()){
          flag=true;
        }
      }
      return flag;
    }
    this.click=function(event){
      if(this.pcuser=="user"){
        let stl = window.getComputedStyle(this.canvas);
        let wh=parseFloat(stl.width)/8;
        let x=Math.floor((event.clientX-event.target.getBoundingClientRect().left)/wh);
        let y=Math.floor((event.clientY-event.target.getBoundingClientRect().top)/wh);
        if(x>=0&&x<=7&&y>=0&&y<=7){
          if(this.board[x][y]==0 && this.canputpieces(x,y,this.user_iro)){
            this.board[x][y]=this.user_iro;
            this.reversepieces(x,y,this.user_iro);
            this.orderchange();
            this.draw();
            setTimeout(this.calculate.bind(this),1000);
          }else{
            this.textarea.innerHTML+='\n指定した場所には置けません';
            this.textarea.scrollTop=this.textarea.scrollHeight;
          }
        }
      }
    }
    button.addEventListener("click",this.start.bind(this));
    this.start();
    this.canvas.addEventListener("click",this.click.bind(this));
  }


  var reversi;
  window.addEventListener('DOMContentLoaded',function(event){
    reversi=new TReversi(
      document.getElementById("reversi_canvas"),  //描画キャンバス
      document.getElementById("reversi_textarea"),//状態を表示するtextarea
      document.getElementById("reversi_start")    //スタートボタン
    );
    window.addEventListener("resize",reversi.winResize);
  });
</script>
</head>
<body>
<button id="reversi_start">開始</button><br>
<canvas id="reversi_canvas"></canvas>
<textarea id="reversi_textarea" rows="8" style="width:100%;"></textarea>
<br>
<br>
</body>
</html>