Skip to main content

総合練習

変数、条件分岐、配列(またはリスト)、列挙、メソッドとクラスを使い、以下のスクリプト作りましょう

ポーカー手札の判定

参考:ポーカー・ハンドの一覧

目標

手札にある5枚のカードを確認し、評価し、Debug.Logで判定を表示。

例:A♥ A♦ 10♣ 7♦ 3♠ - ワンペア

を表示するのは目標である

解析

かなり大きな課題なので、わかりやすい「ミニ課題」に分割しましょう!

スート

スートは「ハート(Heart)、ダイヤ(Diamond)、クラブ(Club)、スペード(Spade)」のことである。固定である値なので、列挙として表現できるので、「CardSuit」の列挙を作る:

CardSuit列挙(答え)
// カードのスート(列挙)を宣言
public enum CardSuit
{
	Heart,
	Spade,
	Diamond,
	Club,
}

カード

カードはスートと数値を持っているし、最後に表示しないといけないので、カードから文字列に変換できるメソッドがほしい。
 ※ ポイント:数値は1~13まで確保しましょう。

Cardクラス - メンバー変数(答え)
// MonoBehaviour(Unityのクラス)ではないので
public class Card
{
	// カードの数字
	private int number;

	// カードのスート
	private CardSuit suit;

	// カードの数字
	public int Number
	{
		get { return number; }
		set
		{
			// Mathf.Clampは最小値と最大値の制限をかける
			number = Mathf.Clamp(value, 1, 13);
		}
	}

	// カードのスート
	public CardSuit Suit
	{
		get { return suit; }
		set { suit = value; }
	}
}
文字列にする

文字列にするとき「1,11、12、13」は「A、J、Q、K」にする。

// 文字列にするメソッド
public string ConvertToString()
{
}
Cardクラス - ConvertToString メソッド
public class Card //(続き)
{
	// 文字列にするメソッド
	public string ConvertToString()
	{
		string result = "";

		// 数字を文字列にする
		if (number >= 2 && number <= 10) // 2~10までの場合
		{
			result = $"{number}"; // 数字を文字列にする
		}
		else if (number == 1) // 「A」の場合
		{
			result = "A";
		}
		else if (number == 11) // 「J」の場合
		{
			result = "J";
		}
		else if (number == 12) // 「Q」の場合
		{
			result = "Q";
		}
		else // 「K」の場合
		{
			result = "K";
		}

		// 模様も文字列にして、連結する
		switch (suit) // "suit"で切り替える
		{
			case CardSuit.Heart:
				result += "♥"; // ハート
				break;
			case CardSuit.Diamond:
				result += "♦"; // ダイヤ
				break;
			case CardSuit.Club:
				result += "♣"; // クラブ
				break;
			case CardSuit.Spade:
				result += "♠"; // スペード
				break;
		}

		return result;
	}
}

ハンド

ハンドはカード5枚のことである。まず、メンバー変数を考えましょう。必ず5枚になるので、伸びるリスト必要なく、ただの配列で十分。

Handクラス - メンバー変数(答え)
// 手札を表すクラス(C#クラス)
public class Hand
{
    // カードの配列 
    Card[] cards = new Card[5]; // 5枚
}

また、それぞれのカード(1枚目、2枚目、3枚目、4枚目、5枚目)の設定できるメソッドもほしい。

// カードを設定
// i: 位置(0~4)
// suit: スート
// number: 数値
public void SetCard(int i, CardSuit suit, int number)
{
}
Handクラス - SetCardメソッド
public class Hand //(続き)
{
	// カードを設定
   // i: 位置(0~4)
    // suit: スート
    // number: 数値
	public void SetCard(int i, CardSuit suit, int number)
	{
		// 範囲を確認
		if (i < 0 || i > 5)
		{
			Debug.Log("無効なカードの位置!");
			return; // なにもしない
		}

		// 新しいカードを作る
		Card card = new Card();
		card.Suit = suit;
		card.Number = number;
		
		// 設定
		cards[i] = card;
	}
}

評価・判定

つぎ、それぞれのハンドの役を評価しましょう。個別に対応すれば、楽になるでしょう。

枚数を数える

まず、「同じ数値のカード何枚あるのか」はよく現れるパターンであるので、メソッドにしましょう:

// 同じカードの枚数を数える
// number: 数えたい数値(1〜13)
private int CountSameNumber(int number)
{
}
Handクラス - CountSameNumber メソッド
// 同じカードの枚数を数える
// number: 数えたい数値(1〜13)
private int CountSameNumber(int number)
{
    // 範囲を確認
    if (number < 1 || number > 13)
    {
        Debug.Log("無効なカードの数値!");
        return 0; // なにもしない
    }
    
    int count = 0;
    foreach (Card c in cards)
    {
        if (c.Number == number)
            count++;
    }

    return count;
}
ワンペア

同じ数値のカードが2枚ある? - CountSameNumber を活用!

// ワンペアであるか?
private bool IsOnePair()
{
}
Handクラス - IsOnePair メソッド
// ワンペアであるか?
private bool IsOnePair()
{
    // いずれかの2枚のカードは同じ数値だったら、ワンペアになる
    for (int i = 1; i <= 13; i++)
    {
        if (CountSameCard(i) == 2)
            return true;
    }
    return false;
}
ツーペア

ワンペアと似ているが、1つ目のペアの数値は2つ目のペアと異なることが前提条件であるので、ご注意ください!

// ワンペアであるか?
private bool IsTwoPair()
{
}
Handクラス - IsTwoPair メソッド
// ツーペアであるか?
private bool IsTwoPair()
{
    // ワンペアと似ているが、2つのペアは異なるカードじゃないとだめ
    int match = 0;  // 1つ目のペアの数値
    for (int i = 1; i <= 13; i++)
    {
        if (CountSameCard(i) == 2)
            match = i;
    }
    
    // なにも一致しなかった
    if (match == 0)
        return false;
    
    // もう一つのペアがないか確認する
    for (int i = 1; i <= 13; i++)
    {
        // 2枚がある「かつ」前のペアと異なる
        if (CountSameCard(i) == 2 && i != match)
            return true;
    }
    
    return false;
}	
スリー・オブ・ア・カインド

ワンペアと似ているが、2枚ではなく、3枚を確認すべき。

// スリー・オブ・ア・カインドであるか?
private bool IsThreeOfAKind()
{
}
Handクラス - IsThreeOfAKind メソッド
// スリー・オブ・ア・カインドであるか?
private bool IsThreeOfAKind()
{
    // いずれかの3枚のカードは同じ数値だったら、 スリー・オブ・ア・カインドになる
    for (int i = 1; i <= 13; i++)
    {
        if (CountSameCard(i) == 3)
            return 3;
    
    return false;
}	
ストレート

これは新しいやつ!すべての数値が連続であることが確認すべき。

ヒント:

  • まず、最も数値が小さいカードを求める
  • ストレートであれば、以下は事実である:
    • 最も小さいカード +0 → 1枚
    • 最も小さいカード +1 → 1枚
    • 最も小さいカード +2 → 1枚
    • 最も小さいカード +3 → 1枚
    • 最も小さいカード +4 → 1枚
// ストレートであるか?
private bool IsStraight()
{     
}
Handクラス - IsStraight メソッド
// ストレートであるか?
private bool IsStraight()
{
    // 連続になっているのかを確認が必要
    // 例えば: 8-9-10-J(11)-Q(12)
    
    // まず、最低のカードを求めましょう
    int smallCard = 14; // Kよりも高いから始まる
    foreach (Card c in cards)
    {
        if (c.Number < smallCard)
            smallCard = c.Number; // 最低カードを更新
    }
    
    // では、5枚も連続であれば、各カード +1 は
    // 必ず1枚ずつがあるはず
    for (int i = smallCard; i < smallCard + 5; i++)
    {
        // 1つだけ!
        if (CountSameNumber(i) != 1)
            return false;
    }
    
    // 順番に1枚ずつがあった!
    return true;

    // メモ:A-K-Q-J-10 に対応していない
    // 興味がある学生、ご自分でお試しください。		
}
フラッシュ

すべてのカードが同じスートであるかを確認しましょう!

// フラッシュであるか?
private bool IsFlush()
{
}
Handクラス - IsFlush メソッド
// フラッシュであるか?
private bool IsFlush()
{
    // すべて同じスートでであればOK
    CardSuit suit = cards[0].Suit;
    
    // 残りのを確認
    foreach(Card c in cards)
    {
        if (c.Suit != suit)
            return false;
    }
    
    return true;
}
フールハウス

これはツーペアと似ているが、2枚と2枚ではなく、2枚と3枚のパターンである

// フルハウスであるか?
private bool IsFullHouse()
{
}
Handクラス - IsFullHouse メソッド
// フルハウスであるか?
private bool IsFullHouse()
{
    // ツーペアと似ているが、枚数は2枚と3枚になる
    int match = 0;  // 1つ目のペアの数値
    for (int i = 1; i <= 13; i++)
    {
        if (CountSameNumber(i) == 2)
            match = i;
    }
    
    // なにも一致しなかった
    if (match == 0)
        return false;
    
    // 残りの3枚を数える
    for (int i = 1; i <= 13; i++)
    {
        // 3枚がある「かつ」前のペアと異なる
        if (CountSameNumber(i) == 3 && i != match)
            return true;
    }
    
    return false;
}
フォー・オブ・ア・カインド

もうわかるでしょう~

// フルハウスであるか?
private bool IsFullHouse()
{
}
Handクラス - IsFourOfAKind メソッド
// フォー・オブ・ア・カインドであるか?
private bool IsFourOfAKind()
{
    // いずれかの4枚のカードは同じ数値だったら、 フォー・オブ・ア・カインドになる
    for (int i = 1; i <= 13; i++)
    {
        if (CountSameNumber(i) == 4)
            return true;
    
    return false;
}	
ストレートフラッシュ

ストレート「かつ」フラッシュである

// ストレートフラッシュであるか?
private bool IsStraightFlush()
{
}
Handクラス - IsStraightFlush メソッド
// ストレートフラッシュであるか?
private bool IsStraightFlush()
{
    // ストレート「かつ」フラッシュなので…
    return IsStraight() && IsFlush();
}

確認用のスクリプト

いくつかのハンドを確認してみてください:

// TestPoker.cs

using UnityEngine;

public class TestPoker : MonoBehaviour
{
    void Start()
    {
        // いろんな組み合わせを試す
        Hand hand = new Hand();

        // フールハウス
        hand.SetCard(0, CardSuit.Heart, 8);
        hand.SetCard(1, CardSuit.Club, 8);
        hand.SetCard(2, CardSuit.Diamond, 8);
        hand.SetCard(3, CardSuit.Heart, 11);
        hand.SetCard(4, CardSuit.Spade, 11);
        hand.CheckResult();
        
        // ストレート
        hand.SetCard(0, CardSuit.Heart, 5);
        hand.SetCard(1, CardSuit.Club, 7);
        hand.SetCard(2, CardSuit.Diamond, 8);
        hand.SetCard(3, CardSuit.Heart, 6);
        hand.SetCard(4, CardSuit.Spade, 9);
        hand.CheckResult();

        // ストレートフラッシュ
        hand.SetCard(0, CardSuit.Spade, 5);
        hand.SetCard(1, CardSuit.Spade, 7);
        hand.SetCard(2, CardSuit.Spade, 8);
        hand.SetCard(3, CardSuit.Spade, 6);
        hand.SetCard(4, CardSuit.Spade, 9);
        hand.CheckResult();
        
        // ツーペア
        hand.SetCard(0, CardSuit.Heart, 5);
        hand.SetCard(1, CardSuit.Diamond, 5);
        hand.SetCard(2, CardSuit.Club, 12);
        hand.SetCard(3, CardSuit.Spade, 12);
        hand.SetCard(4, CardSuit.Diamond, 13);
        hand.CheckResult();
        
        // ハイカード
        hand.SetCard(0, CardSuit.Heart, 5);
        hand.SetCard(1, CardSuit.Diamond, 1);
        hand.SetCard(2, CardSuit.Club, 8);
        hand.SetCard(3, CardSuit.Spade, 12);
        hand.SetCard(4, CardSuit.Diamond, 9);
        hand.CheckResult();
    }
}