JavaScript: 神経衰弱ゲームの作り方

トランプゲームの定番ゲーム、「神経衰弱」をつくります。

カードを2枚めくり、違う数値ならやり直し、同じ数値ならそのカード2枚が消えます。 全てのカードがなくなると、下に表示されている経過秒数がストップします。

動作サンプル、サンプルコード、コード解説の順番で記述しています。

動作サンプル

HTML


<div id="panel"></div>

<div id="result">経過秒数: </div>

CSS


#panel {
    width: 310px;
    height: 340px;
    overflow: hidden;
}

.card {
    width: 60px;
    height: 80px;
    line-height: 80px;
    border: 1px solid silver;
    border-radius: 10px;
    text-align: center;
    font-size: 26px;
    font-weight: bold;
    box-shadow: gray 2px 2px;
    background: white;
    float: left;
    cursor: pointer;
}
/* 裏の状態 */
.back {
    background-image: url('img/back.png');
    background-size: 60px 80px;
}
/* 終了時 */
.finish {
    opacity: 0;
    cursor: default;
}
/* 経過秒数 */
#result {
    font-size: 1.2em;
    font-weight: bold;
}

JavaScript


// グローバル
// div要素を格納
var cards = [];
// 開始時間
var startTime;
// 経過秒数用 タイマーID
var timer;
// カードめくり用 タイマーID
var backTimer;
// 1枚目かどうかのフラグ   1枚目: true   2枚目: false
var flgFirst = true;
// 1枚目のカードを格納
var cardFirst;
// そろえた枚数
var countUnit = 0;

window.onload = function(){
    // 数字格納 一時配列
    var arr = [];
    
    for (var i = 0; i < 10; i++){
        // ペアの数字を10組
        arr.push(i);
        arr.push(i);
    }
    
    // シャッフル
    shuffle(arr);
    
    var panel = document.getElementById('panel');
    
    // div要素作成
    for (i = 0; i < 20; i++){
        var div = document.createElement('div');
        div.className = 'card back';
        div.index = i;
        div.number = arr[i];
        div.innerHTML = '';
        div.onclick = turn;
        panel.appendChild(div);
        cards.push(div);
    }
    // 開始時刻を取得
    startTime = new Date();
    // タイマー開始
    startTimer();
    
}

// シャッフル用関数
function shuffle(arr) {
    var n = arr.length;
    var temp, i;

    while (n) {
        i = Math.floor(Math.random() * n--);
        temp = arr[n];
        arr[n] = arr[i];
        arr[i] = temp;
    }
    return arr;
}

// クリック時の処理
function turn(e){
    
    var div = e.target;
    
    // カードのタイマー処理が動作中は return
    if (backTimer) return;

    // 裏向きのカードをクリックした場合は数字を表示する
    if (div.innerHTML == ''){
        div.className = 'card';
        div.innerHTML = div.number; 
    }else{
        // 数字が表示されているカードは return
        return;
    }
    
    // 1枚目の処理
    if (flgFirst){
        // cardFirst は2枚目の処理のときに使う
        cardFirst = div;
        // フラグ変更
        flgFirst = false;
        
    // 2枚目の処理
    }else{
        
        // 数字が1枚目と一致する場合
        if (cardFirst.number == div.number){
            countUnit++;
            // 見えない状態にする
            backTimer = setTimeout(function(){
                div.className = 'card finish';
                cardFirst.className = 'card finish';
                backTimer = NaN;
                
                if (countUnit == 10){
                    clearInterval(timer);  // timer終了
                }
            }, 500)

        // 一致しない場合
        }else{  
            // カードを裏側に戻す
            backTimer = setTimeout(function(){
                div.className = 'card back';
                div.innerHTML = '';
                cardFirst.className = 'card back';
                cardFirst.innerHTML = '';
                cardFirst = null;
                backTimer = NaN;
            }, 500);
        }
        
        flgFirst = true;
    }  
}

// タイマー開始
function startTimer(){
    timer = setInterval(showSecond, 1000);
}

// 秒数表示
function showSecond(){

    var nowTime = new Date();
    var elapsedTime = Math.floor((nowTime - startTime) / 1000);
    var str = '経過秒数: ' + elapsedTime + '秒';

    var re = document.getElementById('result');
    re.innerHTML = str;
}

コード解説

カードの並べ方

カードの並べ方は、div要素を20個作成し、それをfloat: leftで並べています。 tableタグは使っていませんが、tebleタグで配置をコントロールしてもいいと思います。


#panel {
    overflow: hidden;
}

.card {
    float: left;
}

カードの状態は3種類

カードの状態は3種類あり、それぞれクラスを設定します。

裏向きの状態class="card back"
数字が表示されている状態class="card"
数字がそろって非表示の状態class="card finish"

.card {

}
/* 裏の状態 */
.back {

}
/* 終了時 */
.finish {

}

JavaScriptの処理は大きく分けて6つ

JavaScriptのコードは大きく分けて次の6つになります。

一番重要な部分はクリック時の処理 turn()です。

グローバル変数設定
初期設定window.onload
配列シャッフルshuffle()
クリック時の処理turn()
タイマー開始startTimer()
経過秒数表示showSecond()

turn()のif文構造

turn()のif文の構造だけを抜き出したものです。

めくられたカードが1枚目か2枚目かで処理がわかれ、 さらに2枚目の場合は、数字が1枚目と一致するかどうかに処理がわかれます。

この条件分岐がこのプログラムの重要な骨組みとなります。


    // 1枚目の処理
    if (flgFirst){

    // 2枚目の処理
    }else{
        
        // 数字が1枚目と一致する場合
        if (cardFirst.number == div.number){

        // 一致しない場合
        }else{  

        }
    }  

JavaScript入門