Unityによる大富豪の作り方 5 ~場に出す役の選択~
スポンサードリンク
場に出す役の選択
選択候補の選出
場に出してもよさそうな役の候補を選出します。候補がない場合パスします。場に出す役の決定
候補に挙がった役の中から、出した後の手札評価値が最も低くなる(同値の場合、役ランクが低い)役を出します。
選択候補の選出
親のとき
nullsuke.com で書いた方法で役を取得。単純に優先評価値が最も高い役を選択候補とします。優先評価値が同じ場合はランクの弱い役を選択候補とします。
子のとき
場の役が階段の場合
対象を出した後の手札があがれそうであるかまたは、出した後の手札評価値 < 出す前の手札評価値 + 1であるものを選択候補とします。
場の役がグループの場合
すべての合法役について以下の条件を順に判定していきます。一度候補の可否が決定されたらそれ以降の判定はしません。
- 場を流せそうな役でかつ、上がれそうな手札の場合
選択候補とする。 - 以下のいずれかの条件を満たした場合、選択候補とする。
- 場を流せそうな役でかつ、手札にある役が4未満
- 場を流せそうな役でかつ、出した後の手札にも場を流せそうな役がある
- 出した後の手札にある役が1でかつ、その役評価値が50以下の場合
選択候補としない。 - 出した後の手札が上がれそうな手札の場合
選択候補とする。 - 1やK(革命時は4や5)の単体やグループでありかつ、出した後の手札にある役が4以上でかつ、出した後の手札評価値が0より大きい場合
選択候補としない。 - 出した後の手札評価値 < 出す前の手札評価値 である場合
選択候補とする。
例1
場が♠️7 ♦️7
でどのカードも使われておらず、誰も上がっていなく
手札が♠️3 ♦️10 ♣️10 ♠️2 ♦️2の場合
合法役は[ ♦️10 ♣️10 ] [ ♠️2 ♦️2 ]
となる。
[ ♦️10 ♣️10 ]
は上記条件の4に該当するので候補となる。
[ ♠️2 ♦️2 ]
は上記条件の2に該当するので候補となる。
[ ♦️10 ♣️10 ]
を出した後の手札[ ♠️3 ♠️2 ♦️2 ]
の手札評価値は0
[ ♠️2 ♦️2 ]
を出した後の手札[ ♠️3 ♦️10 ♣️10 ]
の手札評価値は3
よって[ ♦️10 ♣️10 ]
が選択されます。
例2
場が♠️7
でどのカードも使われておらず、誰も上がっていなく
手札が♠️8 ♦️1
の場合
合法役は[ ♠️8] [ ♦️1 ]
となる。
[ ♠️8 ]
は上記条件の4に該当するので候補となる。
[ ♦️1 ]
は上記条件の3に該当するので候補とならない。
よって[ ♠️8 ]
が選択されます。
例3
場が♠️7
でどのカードも使われておらず、誰も上がっていなく
手札が♠️3 ♦️4 ♣️8 ♦️1 ❤️2
の場合
合法役は[ ♣️8] [ ♦️1 ] [ ❤️1 ]
となる。
[ ♠️8 ]
は上記条件の6に該当するので候補となる。
[ ♦️1 ]
は上記条件の5に該当するので候補とならない。
[ ❤️2 ]
はどの条件にも該当しないので候補とならない。
よって[ ♠️8 ]
が選択されます。
実装
public class PlayerLogic { private static BitUtility bit; private static ulong[] bitPlayerCards; //親のときに役を選択 private ulong SelectBitHandOnDealer(int id, GameData gameData) { var bitPlayerCard = bitPlayerCards[id]; var playerCard = new PlayerCard(bitPlayerCard, gameData); var hands = playerCard.Hands; var ordered = hands.OrderByDescending(h => h.Priority).ThenBy(h => h.Rank) .ToList<Hand>(); return ordered[0].BitHand; } //子のときに役を選択 private ulong SelectBitHandOnNoneDealer(int id, GameData gameData) { var bitPlayerCard = bitPlayerCards[id]; var playerCard = new PlayerCard(bitPlayerCard, gameData); var legalHands = playerCard.GetLegalHands(gameData); if (bit.IsSequence(gameData.BitFieldCard)) { legalHands.ForEach(h => { var next = playerCard.CreateNextPlayerCard(h.BitHand, gameData); if (next.CanEndGame || playerCard.Score <= next.Score + 1) { h.Selected = true; } }); } else { for (int i = 0; i < legalHands.Count; i++) { var h = legalHands[i]; var next = playerCard.CreateNextPlayerCard(h.BitHand, gameData); if (h.CanEndTurn && playerCard.CanEndGame) { h.Selected = true; } else if (h.CanEndTurn) { if (playerCard.Hands.Count < 4 || next.Hands.Exists(h2 => h2.CanEndTurn)) { h.Selected = true; } } else if (next.Hands.Count == 1 && next.Hands[0].Score <= 50) { continue; } else if (next.CanEndGame) { h.Selected = true; } else if (IsPrettyHigh(h.BitHand, gameData.IsRevolutionalizing) && next.Hands.Count >= 4 && next.Score > 0) { continue; } else if (next.Score <= playerCard.Score) { h.Selected = true; } } } var selected = legalHands.Where(h => h.Selected).ToList<Hand>(); if (selected.Count == 0) return 0; var min = Mathf.Infinity; int m = 0; //選択候補の中から、出した後の手札評価値が最も低い役を選択 for (int i = 0; i < selected.Count; i++) { var next = playerCard.CreateNextPlayerCard(selected[i].BitHand, gameData); if (next.Score <= min) { if (next.Score == min) { if (selected[i].Rank < selected[m].Rank) m = i; } else { m = i; } min = next.Score; } } return selected[m].BitHand; } //Kや1(革命時は4や5)の単体やグループかどうか判定する private bool IsPrettyHigh(ulong bitHand, bool isRevolutionalizing) { var qpCard = bit.ToQPCard(bitHand); if (!isRevolutionalizing) { return (qpCard & 0x0000110000000000ul) > 0; } else { return (qpCard & 0x0000000000000110ul) > 0; } } }