こんにちは、あんみんどうふです。
ここ最近時間が取れずヨットの開発に手を付けられていませんが、ランキング機能だけでも実装しようと思います。
少なくとも月に一つぐらいは進捗があってほしいので・・・。
「ヨットって何?」という方は前回の記事をご覧ください。
ざっくり仕様
ランキングのデータはCSVで管理します。1行ごとに1データ。項目は「名前」と「スコア」のみ。
CSVファイルを作成する機能、CSVに名前とスコアのデータを登録する機能、CSVを読み込んで内容を表示する機能の3つを主に作ります。
CSV関連は「ControlCsv」というクラスにまとめ、ランキング登録用の「RankingAdd」、ランキング表示用の「ViewRanking」というフォームを使います。
ちなみにCSVファイルの名前はわかりやすく「ranking.csv」とします。
CSVファイル作成
特に難しいことは無く、出力先のパスを決めてFireStreamからファイル作成するだけです。
※名前空間「System.IO」必須です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | public string FilePath = "./ranking.csv"; // CSVファイルパス public bool Create() { bool result = true; // 作成処理 using (FileStream fs = File.Create(FilePath)) { // ファイルが正しく作成されていなければfalseを返す if (!File.Exists(FilePath)) { result = false; } } return result; } |
usingを使うと、処理が終わったら勝手にDispose(破棄)してくれる上にコードがスッキリするのでとても便利です。
わかりやすく言うと、使った物を自動で元の場所に戻してくれるようなイメージ。
ランキングに登録
登録するデータは先程の通り「名前」と「スコア」です。これらは呼び出される時に引数からそれぞれ受け取ります。
CSVファイルはカンマ区切りで項目が分けられているので、「名前,スコア」のフォーマットでCSVに追記することになります。
また、CSVファイルが無いと何もできないので、存在しない場合はさっきのCreateメソッドを呼び出してファイルを作ります。
登録処理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | public bool registScore(string name, int score) { // CSVファイルが無ければ作る if (!File.Exists(FilePath)) { bool res = Create(); if(!res) return false; } if (name != "" && score >= 0) { using (StreamWriter sw = new StreamWriter(FilePath, true, Encoding.UTF8)) { // 「名前,スコア」の形式で書き込む sw.WriteLine(name + "," + score); } } return true; } |
登録フォーム
次にこれらの処理を実行するフォームを作成します。
とてもシンプルに、名前だけ入力して登録できるようにしています。ゲーム終了したらこの画面が表示されるようなイメージで。
順位取得
まず、CSVの中身をListに全部格納するメソッドを作ります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | public List<List<string>> getCSV() { List<List<string>> list = new List<List<string>>(); using (StreamReader data = new StreamReader(File.OpenRead(FilePath))) { while (!data.EndOfStream) { var line = data.ReadLine(); var values = line.Split(","); // カンマ区切り // 1行ずつ格納 List<string> col = new List<string>(); foreach (var val in values) { col.Add(val); } list.Add(col); } } return list; } |
次にCSVが格納されたListをスコア基準に降順でソートし、上から順番に引数のスコアとList内のスコアで比較します。
※ソートの部分でLinqを使っているので、名前空間「System.Linq」必須です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | public int ranking(int score) { // CSV取得 var list = getCSV(); // Listをスコア降順でソート var sorted = list.OrderByDescending(e => int.Parse(e[1])); // 受け取ったスコアがどの順位に入るかを返す int rank = 1; foreach (var row in sorted) { if (score > int.Parse(row[1])) break; rank++; } return rank; } |
List内のスコアより引数のスコアの方が高ければそこで順位が確定されます(13行目)。
ここまでの処理で取得した順位とスコアを表示するため、フォーム側に以下のコードを書きます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | public int score = 0; ControlCsv c = new ControlCsv(); private void FormAddRanking_Load(object sender, EventArgs e) { int rank = 1; string csv = "./ranking.csv"; // 順位決定 if (!File.Exists(csv)) c.Create(); if(c.GetLines() > 0) { rank = c.ranking(score); } labelRank.Text = "あなたは " + rank.ToString() + "位です!"; labelScore.Text = score.ToString(); } |
別の画面からスコアを格納できるように、score変数はpublicにしています。
ゲーム画面側は未完成なので、とりあえず以下のデバッグ用乱数でスコアを代用します・・・。
1 2 3 | // debug Random r = new Random(); score = r.Next(0, 1000); |
これで実行すると、
スコアの値によって順位が変わるようになりました。
ちなみに、登録ボタンは最初に書いたregistScoreを引数込みで実行するだけです。処理を終えたらフォームを閉じます。
1 2 3 4 5 | private void buttonAdd_Click(object sender, EventArgs e) { c.registScore(rankingName.Text, score); this.Close(); } |
ランキングをフォームに表示
今回の本題です。
「フォームが開かれる→CSVを開く→中身をフォーム内の表に展開」の順に実行していきます。
フォーム
DataGridViewというコントロールで表っぽく表示する領域を作りました。見た目はプロパティでちょっぴり調整していますが、細かい部分なので割愛します。
CSV取得・表示
フォーム側のコードを書いていきます。
※ここでもLinqを使ってソートしているので名前空間「System.Linq」を忘れずに。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | private void ViewRanking_Load(object sender, EventArgs e) { ControlCsv c = new ControlCsv(); // CSV取得してListに格納 List<List<string>> list = c.getCSV(); rankingGrid.ColumnCount = 3; // Listをスコア降順でソート var sorted = list.OrderByDescending(e => int.Parse(e[1])); int rank = 1; foreach (var row in sorted) { rankingGrid.Rows.Add(rank, row[0], row[1]); rank++; } } |
CSVを展開し、ソートして上から順番にDataGridViewへ追加しています。
適当にデータを入れて開いてみるとこうなります。
というわけでランキング完成です!
今までLinqは全然使っていなかったんですけど、SQL文みたいにいろいろできるみたいで便利そうですね。
次回までには全部完成させたいです・・・。