javascript　神経衰弱ゲーム（自分なりの解説）

今回も、書籍[ゲームで学ぶJavascript入門](https://www.amazon.co.jp/%E3%82%B2%E3%83%BC%E3%83%A0%E3%81%A7%E5%AD%A6%E3%81%B6JavaScript%E5%85%A5%E9%96%80-HTML5-CSS%E3%82%82%E8%BA%AB%E3%81%AB%E3%81%A4%E3%81%8F%EF%BC%81-%E7%94%B0%E4%B8%AD-%E8%B3%A2%E4%B8%80%E9%83%8E-ebook/dp/B019WTE1FE)で紹介されている
神経衰弱ゲームの知識定着のために自分なりに解説をしてみます。

##シャッフル処理

書籍の中では、
まず配列のprototypeの中に、
配列をシャッフルをする処理を記述してあります。(書籍と記述が異なります。）

```js:shuffle.js
Array.prototype.shuffle = function(){
  var length = array.length;
  for(var i = length - 1; i > 0; i--) {
      var j = Math.floor(Math.random() * (i + 1));
      var tmp = this[i];
      this[i] = this[j];
      this[j] = tmp;
  }
　return this;
}

```

トランプが10枚あるなら
10枚目のカードを、乱数で決めた2番目と入れ替える
9枚目のカードを、乱数で決めた5番目と入れ替える
8枚目のカードを、、、を繰り返して配列をバラバラにしている処理です。
ここでのthisは配列です。

こちらでシャッフルします。

```js.shuffte.js
var cards=[]
for(var i=1 ;i<=10;i++){
 cards.push(i); 
 cards.push(i);　//1-10が2枚ずつの配列を

cards.shuffle();
}

```



##トランプを表示させる

読み込み際に以下のhtmlを出力するようにjsで記述できればOKです。

```html:card.html
<table id="table">
      <tr>
        <td class="card back"></td>
        <td class="card back"></td>
        <td class="card back"></td>
        <td class="card back"></td>
        <td class="card back"></td>
      </tr>
      <tr>
        <td class="card back"></td>
        <td class="card back"></td>
        <td class="card back"></td>
        <td class="card back"></td>
        <td class="card back"></td>
      </tr>
      <tr>
        <td class="card back"></td>
        <td class="card back"></td>
        <td class="card back"></td>
        <td class="card back"></td>
        <td class="card back"></td>
      </tr>
      <tr>
        <td class="card back"></td>
        <td class="card back"></td>
        <td class="card back"></td>
        <td class="card back"></td>
        <td class="card back"></td>
      </tr>
    </table>

```

元々のhtmlは

```html:base.html
  <body onload="init()">
    <h2>経過時間：<span id="time">0</span>秒</h2>
  </body>
```

前回の15puzzleにもありましたがこのような記述となります。

```js:create.js
//初期化
funcion init(){ 
var table = document.getElementById("table")

for (var i =0; i<4; i++){
var tr = document.createElement("tr")// 

for( var j =0;j<5;J++){
  var td=document.createElement("td");//tdを作成
  td.className = "card back";　
  td.number = cards[i*5+j]; //0-19まで すでに数字はバラバラにしておく必要がある。
　td.onclick = flip; //flip関数を設定。後ほど記述
  tr.appendChild(td); //　trのお尻にtdの閉じタグ
}
　table.appendChild(tr); tableのお尻にtrの閉じタグ
}
}
```

また開いたと同時に経過時間を表示させるために、
1秒おきに時間を取得して、開いた時間と引き算をして経過時間を表すtick関数も走らせます。

```js:tick.js
startTime = new Date();
timer = setInterval(tick,1000);

function tick(){
var now = new Date();//今時間をnowに入れる
var elapsed = Math.floor((now.getTime()-startTime.getTime())/1000);
document.getElementById("time").textContent = elapsed;
}
}

```

##トランプの裏返しの処理

oncilckで設定したflip関数を走らせます。

```js:flip.js
funciont flip(e){

var src = e.srcElement //押したtdの情報が取れます。
var num = src.number //initでnumberを値を設定しました。
src.className = "card";
src.textContent = num; //値をtextContentに入れて表示されます。

//１枚目
if(prevCard ==null){ //１枚目では未定義です。
   prevCard = src;
   return;
}

//２枚目
if(preCard.number ==num){//番号が一致
　if(++score ==10){ //1ペアになれば、1追加　
  clearInterval(timer)　//10ペア完成したら タイマーを止める。
}
prevCard = null;

```

トランプをめくったときには、className="card"となり表を向いた表示がされます。
ただ数字が一致しない場合はclassName = "card back"と裏を向く処理が必要です。
preCardと構造が同じならif(preCard == num）があるのでそれのelseで、裏返しの処理となります。

```js:flip.js
else{
src.className = "card back"; 2枚目を裏に
src.textContent ="";
prevCard.className = "card back";
prevCard.textContent ="";
prevCard = null;初期化
}
```

プログラムは瞬時に働くので、これだと瞬時に表に戻ってしまいます。
前引いた番号を自分で覚えるのが神経衰弱の面白さなので、1秒間待ってから消す作業に移ります。

```js:flip.js
setTimeout(function(){
src.className = "card back";
src.textContent = "";
prevCard.className ="card back";
prevCard.textContent ="";
prevCard =null;
},1000) //1秒後に実行
```

ところでsetTimeoutには戻り値があります。
戻り値timeId　（数字）です。

setTimeoutで実行した処理を止めるため
clearTimeout(timeId)でプログラムを止めることができます。

setTimeoutが実際にプログラムが動きだす前から、timeIdを吐き出しています。
timeId = setTimeout(処理、100000）なら、100000を待たなくてもコードがそこを通れば
timeIdは出ます。

書籍ではこのような記述がされています。

```js:flip.js
flipTimer =setTimeout(function(){

src.className = "card back";
src.textContent = "";
prevCard.className ="card back";
prevCard.textContent ="";
prevCard =null;

flipTimer = null;
},1000) //1秒後に実行
```

中のfunctionが実行される前から、setTimeoutは戻り値を返しますので
flipTimerにはtimeIdを持つわけです。

そして実際にfunctionが走ると、flipTimerをnullにされます。
flipTimerが値が持ってる1秒間は、他のトランプをクリックしても開かせない処理に。
flipTimerが値を持っていない時は、2枚は裏に戻ったので、クリックしたら開く処理に。

```js:flip.js
function flip(e){
var src =e.srcElement;
//fliptimerが値があるのは、2枚開いてる間　or すでに表になってるカードを押してる
if(flipTime ||src.textContent !=""){ 

   return;　//何もしない
}

```