ぬるーむ

Unity初心者が誰もが知っているゲームの模倣をしています。個人的な備忘録ですが、入門書を読み終えたばかりの初心者の方は「こんなへなちょこでもいいのか!」「俺の方がうまく作れる」と作成意欲がわいたりするかもしれません。

Unityによる大富豪の作り方 3 ~役の取得~


スポンサードリンク

役の取得

自分が親か子なのかで取得方法は異なります。

親のとき

概要
  • 手札が4枚より多いときは一番強いカード(2、革命時は3)を除いた手札から、そうでないときは手札のすべてから階段を取得します。 ただし、階段を構成しているすべてのカードが2枚以上である場合は階段として取得しません。
  • 階段を除いた手札で同一ランクが2枚以上あればそれらをグループとします。
  • 階段にもグループにも使われなかったカードは単体とします。

例1
手札が♠️3 ♠️4 ♠️5 ♦️5 ♦️10 ♣️10 ❤️10 ♠️K ♦️K ♠️1 ♠️2の場合
役は[ ♠️3 ♠️4 ♠️5 ] [ ♦️10 ♣️10 ❤️10 ] [ ♠️K ♦️K ] [♦️5] [♠️1] [♠️2]となります。

例2
手札が♠️3 ♦️3 ♠️4 ♦️4 ♠️5 ♦️5 ♣️5の場合
役は[♠️3 ♦️3][ ♠️4 ♦️4] [♠️5 ♦️5 ♣️5]となります。

実装
//役を取得する
private static BitUtility bit = BitUtility.Instance;

private List<ulong> GetBitHands(bool isRevolutionalizing)
{
    var bitHands = new List<ulong>();
    var single = GetSingle(bitPlayerCard);
    var noStrongest = bitPlayerCard;
    var other = bitPlayerCard;
    int cnt = bit.CountBit(bitPlayerCard);

    //手札が4枚以下のとき階段役が存在すれば、階段役のみか、階段役+単数役であり、上がりきる可能性が高いので
    //最強ランクも階段に含める
    if (cnt > 4)
    {
        if (isRevolutionalizing)
        {
            noStrongest = bitPlayerCard & 0x000ffffffffffff0ul;
        }
        else
        {
            noStrongest = bitPlayerCard & 0x0000fffffffffffful;
        }
    }

    bit.GetSequenceList(noStrongest).ForEach(s =>
    {
        if ((s & single) > 0)
        {
            bitHands.Add(s);
            other ^= s;
        }
    });

    bit.GetGroupList(other).ForEach(g =>
    {
        bitHands.Add(g);
        other ^= g;
    });

    //BitCard型のカードの集合(other)から1枚ずつ取り出し、BitCard型のリストに変換
    var list = bit.ToBitList(other);
    bitHands.AddRange(list);

    return bitHands;
}

//単数役を取得
private ulong GetSingle(ulong bitCard)
{
    var qpSingle = bit.ToQPCard(bitCard) & BitUtility.M0001;

    return bit.ToBitCard(qpSingle, bitCard);
}
//枚数位置型をBitCard型に変換
public ulong ToBitCard(ulong qpCard, ulong bitCard)
{
    var result = 0ul;

    while (qpCard != 0)
    {
        int i = BitScanForward(qpCard);
        int r = i / 4;

        result |= bitCard & (15ul << (r * 4));
        qpCard &= qpCard - 1;
    }

    return result;
}

//ulongから1ビットずつ取り出してリストに変換
public List<ulong> ToBitList(ulong bit)
{
    var list = new List<ulong>();

    while (bit != 0)
    {
        var b = GetMostSignificantBit(bit);
        list.Add(b);
        bit ^= b;
    }

    return list;
}

子のとき

概要

場に出せる役(合法役)をすべて取得します。 特に単体やグループの場合、考えうるすべての組み合わせの役を取得します。

例1
場が♠️3 ♠️4 ♠️5
手札が♠️6 ♠️7 ♠️8 ♠️9 ♦️9 ♦️10 ♦️Jの場合
合法役は[ ♠️6 ♠️7 ♠️8 ] [ ♠️7 ♠️8 ♠️9 ] [ ♦️9 ♦️10 ♦️J ]となります。

例2
場が♠️3 ♦️3
手札が♠️4 ♦️4 ♣️4 ♠️5 ♠️6の場合
合法役は[ ♠️4 ♦️4 ] [ ♠️4 ♣️4 ] [ ♦️4 ♣️4 ]となります。

例2の場合、合法役は3通りあるが♠️4残すと手札に[ ♠️4 ♠️5 ♠️6 ]が残り有利となるので[ ♦️4 ♣️4 ]を場に出すのが最善となります。

このように場に出した後の手札のことを考える必要があるので、単体やグループ役を出す場合は、考えうるすべての組み合わせの役を取得する必要があります。

実装
//合法役を取得する
private static BitUtility bit = BitUtility.Instance;

private List<ulong> GetBitLegalHands(int cnt, ulong bitFieldCard,
    bool isRevolutionalizing)
{
    List<ulong> bitHands;

    var higher = bit.GetHigherBitCard(bitPlayerCard, bitFieldCard,
        isRevolutionalizing);

    if (bit.IsSequence(bitFieldCard, cnt))
    {
        bitHands = bit.GetSequenceList(higher, cnt);
    }
    else
    {
        bitHands = new List<ulong>();
        var grps = bit.GetGroupList(higher, cnt);
        
        grps.ForEach(h =>
        {
            //場にある枚数と役を構成する枚数が同じなら組み合わせを考える必要はない
            if (bit.CountBit(h) == cnt)
            {
                bitHands.Add(h);
            }
            else
            {
                var newGrps = GetConbinations(h, cnt);
                bitHands.AddRange(newGrps);
            }
        });
    }

    return bitHands;
}

//n枚で構成されるグループ役からr枚取り出してできる役をすべて取得
private List<ulong> GetConbinations(ulong bitHand, int r)
{
    int n = bit.CountBit(bitHand);
    //BitCard型のカードの集合(bitHand)から1枚ずつ取り出し、BitCard型のリストに変換
    var bitList = bit.ToBitList(bitHand);
    //n枚で構成されるグループ役からr枚取り出してできるすべての組み合わせを取得。
    //組み合わせはビットで表現されている。
    var cnbs = bit.GetConbination(n, r);

    var newBitHand = 0ul;
    List<ulong> bitHands = new List<ulong>();

    for (int i = 0; i < cnbs.Count; i++)
    {
        for (int j = 0; j < n; j++)
        {
            //ビットが立っていたら、対応するカードを役として使う
            if ((cnb[i] & (1 << j)) > 0)
            {
                newBitHand |= bitList[j];
            }
        }

        bitHands.Add(newBitHand);
        newBitHand = 0;
    }

    return bitHands;
}