Contents
順位をつける
殺しの七並べの場合、先にあがれば上位なのかというと違います。殺されたカードが少ない方が上位です。カードが同数のときは先にあがったほうが上位です。またパスを4回してしまって脱落した場合は先に脱落した人が下位になります。
もっとはやくつくるべきだったPlayerクラス
ゲームが終わったら順位をつけます。
そのためにPlayerというクラスをつくります。本当はこのクラスを先につくっておけばよかったのですが、順序が逆になってしまいました。普通の七並べではプレーヤーの情報はそんなに多くなかったのでクラスをつくって管理する必要がなかったからです。
遅ればせながらクラスをつくってデータを格納します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
class Player { public Player(int playerId, int deadCardCount, long agariTime, long lostTime) { PlayerId = playerId; DeadCardCount = deadCardCount; AgariTime = agariTime; LostTime = lostTime; } public int PlayerId = 0; public int DeadCardCount = 0; public long AgariTime = 0; public long LostTime = 0; } |
あがったときの処理と脱落したときの処理に少し付け足します。あがったときの時刻、リタイアしたときの時刻を取得すれば先にあがったのは誰か、先にリタイアしたのは誰かがわかります。
あがったり脱落したプレーヤーをPlayersのなかに格納し、全員がゲームから抜けたときにLINQのメソッドを使えば簡単に順位をつけることができます。
あがったときやリタイアしたときに成績を登録する
あがったときはプレーヤー番号とあがった時刻と殺されたカードの枚数をPlayerクラスのコンストラクタに渡して成績を登録します。
まずはあがったときのメソッドを示します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
public partial class Form1 : Form { List<Player> Players = new List<Player>(); void OnAgari(int player) { if(player == 0) MessageBox.Show("あなたはあがりました"); else MessageBox.Show(player.ToString() + " はあがりました"); long agariTime = DateTime.Now.Ticks; // これを追加した Players.Add(new Player(player, deadCount[player], agariTime, -1)); // 4人ともあがるかリタイアしていればゲームセット if(Players.Count == 4) OnGameSet(); } void OnGameSet() { // 後述 } } |
以下はパスを4回してしまってリタイアしたときのメソッドです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
public partial class Form1 : Form { void OnRivalLost(int rivalID) { // これを追加した Players.Add(new Player(rivalID, deadCount[rivalID], -1, DateTime.Now.Ticks)); var playerCards = playersCards[rivalID]; foreach(Card card in playerCards) { card.isExists = true; } Invalidate(); // 4人ともあがるかリタイアしていればゲームセット if(Players.Count == 4) OnGameSet(); } } |
OnRivalsTurnメソッドを一部変更
それからライバルターンに関するメソッドも変更する必要があります。
カードがないので強制パス?
カードが殺されて手持ちのカードがなくなった場合、出せるカードは持っていないので強制的にパスになってしまいます。これではいけないので順番が回ってきたときにカードがない場合はアガリにします。実際のルールでもカードが殺されて手持ちのカードがゼロになったときも、その状態ではあがれず、つぎに順番が回ってきたときにアガリになるそうです。(これもローカルルールかも)
ところがいまのままではライバルのターンが終わると出せるカードがあるかどうか判断して、ないのであれば自動的にパスにしています。「カードを1枚も持っていないので出せるカードがない、だからパス」では困ります。
またライバルも自分のカードが殺されることで手持ちがゼロになったとき、Playersリストに自分の成績を登録する機会がありません。これではゲームが終わっても結果が表示されないという問題がおきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
public partial class Form1 : Form { async void OnRivalsTurn() { // このif文はかわらず if(playersCards[0].Count == 0 && !isAgari) { OnAgari(0); isAgari = true; } // あがってもいないしリタイアもしていないときはカードを出すのだが・・・ for(int i = 1; i< playersCards.Length; i++) { if(playersCards[i].Count != 0 && passCounts[i] <= PASS_MAX) { await System.Threading.Tasks.Task.Delay(1000); RivalTurn(i); if(playersCards[i].Count == 0) { OnAgari(i); } } else { // これまでこの部分がなかった!! // カードが殺されて手持ちのカードがなくなっていることがあるので注意すること // Playersに情報が格納されていないなら格納する if(!Players.Any(x => x.PlayerId == i)) { OnAgari(i); } } } // このif文はかわらず前のものと変わらず if(isAgari || passCounts[0] > PASS_MAX) { if( (playersCards[1].Count != 0 && passCounts[1] <= PASS_MAX) || (playersCards[2].Count != 0 && passCounts[2] <= PASS_MAX) || (playersCards[3].Count != 0 && passCounts[3] <= PASS_MAX) ) OnRivalsTurn(); return; } // この部分も追加!! // カードが殺されて手持ちのカードがなくなった場合、永久にパスすることになってしまう if(playersCards[0].Count == 0 && !isAgari) { OnAgari(0); isAgari = true; } else if(!CanPlayerTakeoutCard(0)) { MyPass(); OnRivalsTurn(); } else IsMyTurn = true; } } |
ゲームセットになったら順位をつける
ゲームセットになったらOnGameSetメソッドが呼ばれます。これまでに集めた情報を利用して順位をつけます。途中でリタイアした人はあがることができた人より順位は下です。また殺されたカードが少ない順に並べますが、同じ場合はあがった時刻で順位を決めます。OrderBy~ThenByというのは便利です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
public partial class Form1 : Form { void OnGameSet() { // 脱落しないであがったプレイヤーの順位をつける List<Player> players1 = Players.Where(x => x.AgariTime > 0). OrderBy(x => x.DeadCardCount).ThenBy(x => x.AgariTime).ToList(); // 脱落してしまったプレイヤーの順位をつける List<Player> players2 = Players.Where(x => x.AgariTime < 0). OrderByDescending(x => x.AgariTime).ToList(); players1.AddRange(players2); int i = 1; string str = ""; foreach(Player player in players1) { string name = ""; if(player.PlayerId == 0) name = "あなた"; else name = player.PlayerId.ToString(); if(i == 1) str += "一位:" + name + "\n"; if(i == 2) str += "二位:" + name + "\n"; if(i == 3) str += "三位:" + name + "\n"; if(i == 4) str += "最下位:" + name + "\n"; i++; } // 順位がわかれば必要ない Players.Clear(); MessageBox.Show(str, "ゲームの結果", MessageBoxButtons.OK, MessageBoxIcon.Information); } } |
実際に遊んでみてわかったことは12枚殺しや8枚殺しはけっこうな確率で起きやすいということ。終盤になってカードが大量死することもかなりの割合でおきます。