LoginSignup
12
10

More than 5 years have passed since last update.

JavaScriptでGUIのポーカーを作ってみた

Posted at

はじめに

唐突にアウトプットしたさに駆られたのですが、書く内容が無かったので数カ月前に作ったポーカーについて書こうと思います。

リポジトリ

機能定義

ポーカーのルールを満たしている

配列に53枚のカードを収納 シャッフルorランダムで5枚を限度に抽出 選択した枚数だけ引き直し
役が高い順から判定
ジョーカーはオールマイティ

ディーラー(CPU)は自動的に実行

抽出後の配列からこちらもランダムで5枚抽出

GUIで動く

交換したいカードをクリックすることで選択する

CPUの難易度設定

easyは交換しないnormalは交換する

事前準備

表示する画像の準備

いらすとやから拝借しました
以下のようにファイル名を付けます

image.png

変数の用意

poker.js

var cards = [];    //山札
var my_hand = [];    //自分の手札
var my_rank = 11;    //自分の役
var cpu_rank = 11;   //CPUの役
var my_rank_name;    //自分の役名
var cpu_rank_name;   //CPUの役名
var difficultyNum = 0;    //難易度設定

プログラミングの流れ

-山札の準備
-山札から手札を引きつつ表示する
-CPUの手札を引く
-手札を判定しつつ、役名を表示する
-CPUの手札を判定する
 --選択した手札を交換する(任意)
 --手札を判定する(任意)
 --役名を表示する(任意)
-勝負結果を表示する
 --難易度がNORMALの場合、CPUの手札を交換する
 --CPUの手札を公開する

山札の準備

poker.js

//開始ボタン
start = () => {
    initCard(); //山札セット
    shuffleCard(); //山札シャッフル
    first();
    $("#startbutton").hide();
    $("#changebutton").show();
    $("#judgebutton").show();
}

//カードを山札にセット
initCard = () => {
    x = 0;
    for (i = 1; i <= 13; i++) {
        cards[x] = new Card(0, i);
        x++;
        cards[x] = new Card(1, i);
        x++;
        cards[x] = new Card(2, i);
        x++;
        cards[x] = new Card(3, i);
        x++;
    }
    cards[52] = new Card(4, 15);
}

//カードシャッフル
shuffleCard = () => {
    for (i = 0; i < 53; i++) {
        r = Math.floor(Math.random() * 13 * 4);
        w = cards[i];
        cards[i] = cards[r];
        cards[r] = w;
    }
}

function Card(mark, num) {
    this.mark = mark;
    this.num = num;
}

53枚のカードに画像のファイル名と同じようにスートと数字を与えます。

山札から手札を引きつつ表示する

poker.js

//カードを表示する関数
dispCard = (card) => {
    let imgurl = "";
    for (i = 0; i < card.length; i++) {
        imgurl = `${card[i].mark}_${card[i].num}`;
        // console.log(imgurl);
        $("#disp").append(`<img src=img/${imgurl}.png alt=card${i}>`);
    }
}

//山札から引きつつ山札削除&表示
draw = () => {
    my_hand = cards.slice(0, 5);
    cards.splice(0, 5);
    dispCard(my_hand);
    my_rank_name = rank(my_hand);
    $("#rank_name").text(my_rank_name);
}

山札から先頭の5枚を取り出しつつ、山札から削除。
カードの変数からスートの値と数字の値を取り出し、imgタグの文字列を形成しブラウザ上に表示します。

CPUの手札を引く

poker.js
//CPUの手札準備
cpu_draw = () => {
    cpu_hand = cards.slice(0, 5);
    cards.splice(0, 5);
    for (i = 0; i < 5; i++) {
        $("#cpu_disp").append(`<img src = img/0_0.png alt=card${i}>`);
    };
}

自分の手札と同じように山札から引くが、すべて裏面で表示する。

手札を判定しつつ、役名を表示

poker.js
//役判定&表示
rank = (my_hand, my_rank, my_rank_name) => {
    my_rank = rank_judge(my_hand);
    my_rank_name = disp_rank(my_rank, my_rank_name);
    return my_rank_name;
}

手札判定の詳細

rank.js

//役判定
rank_judge = (my_hand) => {
    let joker_flg = 0;
    let cnt = 0;
    let current_rank = 11;
    sort(my_hand);
    joker_flg = joker_judge(my_hand, joker_flg);
    cnt = sameNum(my_hand);
    current_rank = various_rank(my_hand, cnt, current_rank, joker_flg);

    if (sameMark(my_hand)) {
        if (current_rank > 5) {
            current_rank = 5;
        };
    }

    if (stairs_judge(my_hand, joker_flg)) {
        if (sameMark(my_hand)) {
            if (current_rank != 0) {
                current_rank = rsf(my_hand);
            }
        } else {
            if (current_rank > 6) {
                current_rank = 6;
            };
        };
    };

    returnAce(my_hand);
    if (joker_flg == 1) {
        my_hand.push(new Card(4, 15));
    };
    return current_rank;
}
-手札を数字順に並べる
-ジョーカーの有無を調べる
 --ジョーカーがあった場合、ジョーカーを削除し、--フラグを立てる。以後は4枚で判定
-同じ数字のカードの数を調べる
-階段以外の役の判定をする
-マークが全て同じかを調べる
-階段は作れるかを調べる
 --ストレートフラッシュかを調べる
   --ロイヤルストレートフラッシュかを調べる

-順番に判定していき、より高い役の判定が通れば随時役を更新していく

手札を数字順に並べる

rank.js
//最初に並べ替え
sort = (my_hand) => {
    my_hand.sort(function (a, b) {
        if (a.num < b.num) return -1;
        if (a.num > b.num) return 1;
        return 0;
    });
}

ジョーカーの有無を調べる

rank.js
//JOKERフラグ判定
joker_judge = (my_hand, joker_flg) => {
    if (my_hand[my_hand.length - 1].mark == 4) {
        my_hand.pop();
        joker_flg = 1;
    };
    return joker_flg;
}

ジョーカーはファイル名で数字を14としているので、ソートした場合5番目に現れます。
5番目のカードのスートが4かであるかでジョーカーの有無を判定します。

同じ数字のカードの数を調べる

rank.js
//同じ数字の枚数判定
sameNum = (my_hand) => {
    let cnt = 0;
    for (let i = my_hand.length; i >= 2; i--) {
        if (my_hand[i - 1].num == my_hand[i - 2].num) {
            cnt++;
        };
    };
    return cnt;
}

隣り合う数字を比べ、同じ数字のカードの数を調べる
1ペアなら1、2ペアなら2、3カードなら2、フルハウスなら3、フォーカードなら3

階段以外の役の判定をする

rank.js

//階段以外の約判定
various_rank = (my_hand, cnt, current_rank, joker_flg) => {
    switch (cnt) {
        case 0:
            switch (joker_flg) {
                case 0:
                    current_rank = 10;
                    return current_rank;
                    break;

                case 1:
                    current_rank = 9;
                    return current_rank;
                    break;
            }
            break;

        case 1:
            switch (joker_flg) {
                case 0:
                    current_rank = 9;
                    return current_rank;
                    break;

                case 1:
                    current_rank = 7;
                    return current_rank;
                    break;
            }
            break;

        case 2:
            if ((my_hand[0].num == my_hand[1].num && my_hand[1].num == my_hand[2].num) ||
                (my_hand[1].num == my_hand[2].num && my_hand[2].num == my_hand[3].num) ||
                (my_hand[my_hand.length - 1].num == my_hand[my_hand.length - 2].num && my_hand[my_hand.length - 2].num == my_hand[my_hand.length - 3].num)) {
                switch (joker_flg) {
                    case 0:
                        current_rank = 7;
                        return current_rank;
                        break;

                    case 1:
                        current_rank = 3;
                        return current_rank;
                        break;
                };
                break;
            } else {
                switch (joker_flg) {
                    case 0:
                        current_rank = 8;
                        return current_rank;
                        break;

                    case 1:
                        current_rank = 4;
                        return current_rank;
                        break;
                };
            };
            break;

        case 3:
            if (my_hand[1].num == my_hand[2].num && my_hand[2].num == my_hand[3].num) {
                switch (joker_flg) {
                    case 0:
                        current_rank = 3;
                        return current_rank;
                        break;

                    case 1:
                        current_rank = 0;
                        return current_rank;
                        break;
                };
                break;
            } else {
                current_rank = 4;
                return current_rank;
            };
            break;
    };
}

マークが全て同じかを調べる

rank.js
//マークは全て同じ?
sameMark = (my_hand) => {
    let i = 0;
    while (my_hand[i].mark == my_hand[i + 1].mark) {
        i++;
        if (i == my_hand.length - 1) {
            break;
        };
    };
    if (i == my_hand.length - 1) {
        return true;
    } else {
        return false;
    };
}

階段は作れるか?

rank.js

//階段判定
stairs_judge = (my_hand, joker_flg) => {
    if (stairs(my_hand)) {
        return true;
    } else if (joker_flg == 1) {
        if (joker_stairs(my_hand)) {
            return true;
        } else {
            changeAce(my_hand);
            if (joker_stairs(my_hand)) {
                return true;
            } else {
                return false;
            };
        };
    } else {
        changeAce(my_hand);
        if (stairs(my_hand)) {
            return true;
        } else {
            return false;
        };
    };
}
手札の数字は階段か?
js
//数字は階段?
stairs = (my_hand) => {
    let i = my_hand.length;
    while (my_hand[i - 1].num - my_hand[i - 2].num == 1) {
        i--;
        if (i == 1) {
            break;
        };
    };
    if (i == 1) {
        return true;
    } else {
        return false;
    };
}
Aを14に変えたら階段になるか?
rank.js
//Aの変換関数
changeAce = (my_hand) => {
    sort(my_hand);
    while (my_hand[0].num == 1) {
        my_hand[0].num += 13;
        sort(my_hand);
    };
}

//Aを戻す関数
returnAce = (my_hand) => {
    sort(my_hand);
    while (my_hand[my_hand.length - 1].num == 14) {
        my_hand[my_hand.length - 1].num -= 13;
        sort(my_hand);
    };
}

JOKERを使えば階段になる?
rank.js

//JOKER使えば作れる?
joker_stairs = (my_hand) => {
    if ((my_hand[3].num - my_hand[2].num == 2 && my_hand[2].num - my_hand[1].num == 1 && my_hand[1].num - my_hand[0].num == 1) ||
        (my_hand[3].num - my_hand[2].num == 1 && my_hand[2].num - my_hand[1].num == 2 && my_hand[1].num - my_hand[0].num == 1) ||
        (my_hand[3].num - my_hand[2].num == 1 && my_hand[2].num - my_hand[1].num == 1 && my_hand[1].num - my_hand[0].num == 2)) {
        return true;
    } else {
        return false;
    };
}

ロイヤルストレートフラッシュか?
rank.js

//ロイヤルストレートフラッシュ判定
rsf = (my_hand, current_rank) => {
    if (my_hand[0].num == 10 || my_hand[my_hand.length - 1].num == 14) {
        current_rank = 1;
        return current_rank;
    } else {
        current_rank = 2;
        return current_rank;
    };
}

役名を表示する

rank.js

//役名表示
disp_rank = (my_rank, my_rank_name) => {
    switch (my_rank) {
        case 0:
            my_rank_name = "ファイブカード";
            break;

        case 1:
            my_rank_name = "ロイヤルストレートフラッシュ";
            break;

        case 2:
            my_rank_name = "ストレートフラッシュ";
            break;

        case 3:
            my_rank_name = "フォーカード";
            break;

        case 4:
            my_rank_name = "フルハウス";
            break;

        case 5:
            my_rank_name = "フラッシュ";
            break;

        case 6:
            my_rank_name = "ストレート";
            break;

        case 7:
            my_rank_name = "スリーカード";
            break;

        case 8:
            my_rank_name = "ツーペア";
            break;

        case 9:
            my_rank_name = "ワンペア";
            break;

        case 10:
            my_rank_name = "豚さん";
            break;
    };
    // $("#rank_name").text(my_rank_name);
    return my_rank_name;
}

選択した手札を交換する

選択した手札の色を変える

poker.js


//表示カードをクリックしたら画像変更&class付与
$("#disp").on("click", "img", function () {
    $(this).toggleClass("clicked");
});

poker.css


.clicked{
  background-color: blue;
  opacity: 0.5; /** 画像の透明度 */
  display: block;
}

選択した手札を交換する

poker.js
//交換するボタン
change = () => {
    let cnt = $(".clicked").length;
    for (let i = 0; i < cnt; i++) {
        let card_src = $(`.clicked:eq(${i})`).attr("src");
        card_src = card_src.split("_");
        card_src[0] = card_src[0].replace("img/", "");
        card_src[1] = card_src[1].replace(".png", "");
        my_hand.some(function (v, i) {
            if (v.mark == card_src[0] && v.num == card_src[1]) my_hand.splice(i, 1); //id:3の要素を削除
        });
    }
    $(".clicked").remove();
    let addarray = cards.slice(0, cnt);
    dispCard(addarray);
    Array.prototype.push.apply(my_hand, addarray);
    cards.splice(0, cnt);
    my_rank_name = rank(my_hand);
    $("#rank_name").text(my_rank_name);
    $("#changebutton").hide();
}

勝負結果を表示する

CPUの手札交換(難易度がNORMAL)

cpu?change.js
cpuChange =(cpu_hand,cpu_rank)=>{
    cpu_hand = cpuSplice(cpu_hand,cpu_rank);
    cpu_hand = cpuAdd(cpu_hand);
    returnAce(cpu_hand);
    return cpu_hand;
}

cpuSplice = (cpu_hand, cpu_rank) => {
    cpu_rank = rank_judge(cpu_hand);
    let joker_flg = 0;
    joker_flg = joker_judge(cpu_hand, joker_flg);
    switch (joker_flg) {
        case 0:
            cpu_hand = normalCpuChange(cpu_hand, cpu_rank);
            return cpu_hand;
            break;

            case 1:
            cpu_hand = jokerCpuChange(cpu_hand, cpu_rank);
            returnAce(cpu_hand);
            cpu_hand.push(new Card(4, 15));
            return cpu_hand;
            break;
        };
    console.log(cpu_hand);
}

cpuAdd =(cpu_hand)=>{

    let addarray = cards.slice(0, 5 - cpu_hand.length);
    cards.splice(0, 5 - cpu_hand.length);
    Array.prototype.push.apply(cpu_hand, addarray);
    console.log(cpu_hand);
    return cpu_hand;
}

CPUの手札の交換基準

--ジョーカーを持ってない
 |
 |-- 役がない -- マークが4つ揃ってる -- 1枚交換
 |       |
 |            -- 階段まであと1枚 -- 1枚交換
 |            |
 |            -- マークが3つ揃ってる -- 2枚交換
 |            |
 |            -- 全部変える
 |
 |-- 1ペア -- マークが4つ揃ってる -- 1枚交換
 |       |
 |       -- 階段まであと1枚 -- 1枚交換
 |       |
 |       -- ペア以外の3枚を変える
 |
 |-- 2ペア -- ペア以外の1枚を変える
 |
 |-- 3カード -- 3カード以外の2枚を変える
 |
--ジョーカーを持っている
 |
 |-- 1ペア -- マークが3つ揃ってる -- 1枚交換
 |       |
 |       -- 階段まであと2枚 -- 1枚交換
 |       |
 |       -- 全部変える
 |
  -- 3カード -- ペア以外の2枚を変える


ジョーカーを持っていないときの交換

cpu_change.js

normalCpuChange = (cpu_hand, cpu_rank) => {
    sort(cpu_hand);
    cpu_rank = rank_judge(cpu_hand);
    switch (cpu_rank) {
        case 10:
            cpu_hand = sameMarkMock(cpu_hand);            
            if (cpu_hand.length == 4) {
                return cpu_hand;
                break;
            }
            cpu_hand = stairMock(cpu_hand);
            if (cpu_hand.length == 4) {
                return cpu_hand;
                break;
            }
            cpu_hand = sameThreeMark(cpu_hand);            
            if (cpu_hand.length == 3) {
                return cpu_hand;
                break;
            }            
            cpu_hand = [];
            return cpu_hand;
            break;

        case 9:
            cpu_hand = sameMarkMock(cpu_hand);
            if (cpu_hand.length == 4) {
                return cpu_hand;
                break;
            };
            cpu_hand = stairMock(cpu_hand);
            if (cpu_hand.length == 4) {
                return cpu_hand;
                break;
            };
            cpu_hand = onePairSampling(cpu_hand);
            return cpu_hand;
            break;

        case 8:
            cpu_hand = twoPairSampling(cpu_hand);
            return cpu_hand;
            break;

        case 7:
            cpu_hand = threeCardSampling(cpu_hand);
            return cpu_hand;
            break;
    };
    return cpu_hand;
}

同じマークが手札-1枚か?
cpu_change.js

//同じマークが手札-1枚か?
sameMarkMock = (cpu_hand) => {
    let cpu_hand2 = cpu_hand.slice();
    for (var i = 0; i < cpu_hand.length; i++) {
        cpu_hand2.splice(i, 1);
        // console.log(cpu_hand2);
        if (sameMark(cpu_hand2)) {
            return cpu_hand2;
            break;
        };
        cpu_hand2 = cpu_hand.slice();
        // console.log(cpu_hand2);
    };
    return cpu_hand2;
}
あと1枚で階段?
cpu_change.js

//あと1枚で階段?
stairMock = (cpu_hand, joker_flg) => {
    sort(cpu_hand);
    let cpu_hand2 = cpu_hand.slice();
    joker_flg = 1;
    for (var i = 0; i < 5; i++) {
        cpu_hand2.splice(i, 1);
        console.log(joker_flg);
        if (stairs_judge(cpu_hand2, joker_flg)) {
            returnAce(cpu_hand2);
            return cpu_hand2;
            break;
        };
        cpu_hand2 = cpu_hand.slice();
        returnAce(cpu_hand);
    };
    joker_flg = 0;
    return cpu_hand2;
}

同じマークが手札-2枚か?
cpu_change.js
//同じマークが手札-2枚か?
sameThreeMark = (cpu_hand) => {
    let cpu_hand2 = cpu_hand.slice();
    for (var i = 0; i < 4; i++) {
        cpu_hand2.splice(i, 1);
        let cpu_hand3 = cpu_hand2.slice();
        for (var j = i; j < 4; j++) {
            cpu_hand3.splice(j, 1);
            if (sameMark(cpu_hand3)) {
                return cpu_hand3;
                break;
            };
            cpu_hand3 = cpu_hand2.slice();
        };
        if (cpu_hand.length == 3) {
            return cpu_hand3;
            break;
        };
        cpu_hand2 = cpu_hand.slice();
    };
    if (cpu_hand.length == 3) {
        return cpu_hand3;
    } else {
        return cpu_hand2
    };
}
ワンペアの時、ペアの2枚を抜き取る
cpu_chaneg.js

//ワンペア時、ペアの2枚を取る
onePairSampling = (cpu_hand) => {
    sort(cpu_hand);
    for (var i = 0; cpu_hand[i].num != cpu_hand[i + 1].num; i++) {};
    cpu_hand = cpu_hand.splice(i, 2);
    return cpu_hand;
}
ツーペアの時、残りの1枚を抜き取る
cpu_change.js

//ツーペア時、残りの一枚を抜き取る
twoPairSampling = (cpu_hand) => {
    sort(cpu_hand);
    if (cpu_hand[1].num == cpu_hand[2].num && cpu_hand[3].num == cpu_hand[4].num) {
        cpu_hand.splice(0, 1);
        return cpu_hand;
    } else if (cpu_hand[0].num == cpu_hand[1].num && cpu_hand[3].num == cpu_hand[4].num) {
        cpu_hand.splice(2, 1);
        return cpu_hand;
    } else if (cpu_hand[0].num == cpu_hand[1].num && cpu_hand[2].num == cpu_hand[3].num) {
        cpu_hand.splice(4, 1);
    };
    return cpu_hand;
}
スリーカード時に3枚を抜きだす
cpu_change.js

//スリーカード時に三枚を抜き出す
threeCardSampling = (cpu_hand) => {
    sort(cpu_hand);
    if (cpu_hand[0].num == cpu_hand[1].num && cpu_hand[1].num == cpu_hand[2].num) {
        cpu_hand.splice(3, 2);
    } else if (cpu_hand[1].num == cpu_hand[2].num && cpu_hand[2].num == cpu_hand[3].num) {
        cpu_hand.splice(0, 1);
        cpu_hand.splice(3, 1);
    } else if (cpu_hand[2].num == cpu_hand[3].num && cpu_hand[3].num == cpu_hand[4].num) {
        cpu_hand.splice(0, 2);
    };
    return cpu_hand;
}

ジョーカーを持っているときの交換

cpu_change.js
jokerCpuChange = (cpu_hand, cpu_rank) => {
    sort(cpu_hand);
    switch (cpu_rank) {
        case 9:
            cpu_hand = sameMarkMock(cpu_hand);
            if (cpu_hand.length == 3) {
                return cpu_hand
                break;
            };
            cpu_hand = onePairstairMock(cpu_hand);
            if (cpu_hand.length == 3) {
                return cpu_hand;
                break;
            };
            cpu_hand = [];
            return cpu_hand;
            break;

        case 7:
            cpu_hand = jokerThreeCardSampling(cpu_hand);
            return cpu_hand;
            break;
    };
}
ジョーカー所持時、あと2枚で階段ができるか?
cpu_change.js
onePairstairMock = (cpu_hand) => {
    sort(cpu_hand);
    let cpu_hand2 = cpu_hand.slice();
    let joker_flg = 1;
    for (var i = 0; i < 5; i++) {
        cpu_hand2.splice(i, 1);
        if (jokerStairsMockJudge(cpu_hand2, joker_flg)) {
            returnAce(cpu_hand2);
            return cpu_hand2;
            break;
        };
        cpu_hand2 = cpu_hand.slice();
    };
    joker_flg = 0;
    return cpu_hand2;
}


jokerStairsMockJudge = (my_hand, joker_flg) => {
    if (stairs(my_hand)) {
        return true;
    } else if (joker_flg == 1) {
        if (jokerStairsMock(my_hand)) {
            return true;
        } else {
            changeAce(my_hand);
            if (jokerStairsMock(my_hand)) {
                return true;
            } else {
                return false;
            };
        };
    } else {
        changeAce(my_hand);
        if (stairs(my_hand)) {
            return true;
        } else {
            return false;
        };
    };
}

jokerStairsMock = (cpu_hand) => {
    if ((cpu_hand[2].num - cpu_hand[1].num == 2 && cpu_hand[1].num - cpu_hand[0].num == 1) ||
        (cpu_hand[2].num - cpu_hand[1].num == 1 && cpu_hand[1].num - cpu_hand[0].num == 2)) {
        return true;
    } else {
        return false;
    };
}
ジョーカー所持時、ペアの2枚を抜き出す
cpu_change.js

//ジョーカー所持時、ペア2枚を抜き出す
jokerThreeCardSampling = (cpu_hand) => {
    sort(cpu_hand);
    if (cpu_hand[0].num == cpu_hand[1].num) {
        cpu_hand.splice(2, 2);
    } else if (cpu_hand[1].num == cpu_hand[2].num) {
        cpu_hand.splice(0, 1);
        cpu_hand.splice(2, 1);
    } else if (cpu_hand[2].num == cpu_hand[3].num) {
        cpu_hand.splice(2, 2);
    };
    return cpu_hand;
}

CPUの結果表示&勝敗表示

poker.js

//勝ち負け判定
showdown = (my_rank, my_hand, cpu_rank, cpu_hand) => {
    console.log(difficultyNum);
    if(difficultyNum == 1){
        cpu_hand = cpuChange(cpu_hand,cpu_rank);
    };
    let imgurl = "";
    $("#cpu_disp img").remove();
    for (i = 0; i < cpu_hand.length; i++) {
        imgurl = `${cpu_hand[i].mark}_${cpu_hand[i].num}`;
        // console.log(imgurl);
        $("#cpu_disp").append(`<img src=img/${imgurl}.png alt=card${i}>`);
    }
    cpu_rank_name = rank(cpu_hand, cpu_rank, cpu_rank_name);
    $("#cpu_rank_name").text(cpu_rank_name);
    my_rank = rank_judge(my_hand);
    cpu_rank = rank_judge(cpu_hand);
    if (my_rank < cpu_rank) {
        $("#result").text("win");
    } else if (my_rank > cpu_rank) {
        $("#result").text("lose");
    } else {
        $("#result").text("draw");
    };
    $("#judgebutton").hide();
    $("#changebutton").hide();
    $("#difficulty").hide();
    $("#onemorebutton").show();
}

終わりに

圧倒的駄記事になってしまった

12
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
10