【C#入門】第12回 クラスについて【じゃんけんゲームを作ろう その12】

2023年2月7日

こんにちは!ノムノムです。

前回は文字列と型変換の説明をしました。

【C#入門】第11回 文字列と型変換について【じゃんけんゲームを作ろう その11】
【C#入門】第11回 文字列と型変換について【じゃんけんゲームを作ろう その11】
こんにちは!ノムノムです。 前回は配列についてやりました。 今回は、前回の答え合わせを含めて文字列についてやっ…
http://nomux2.net/string/

今回は、ついにクラスです。
はやくクラスの説明をしたくてウズウズしてたんです。

クラス

クラスとは、オブジェクトを作るための設計図です

どういうことか説明します。

みなさんゲーム好きですか?私は大好きです。ロールプレイングゲームで考えてみましょう。

クラスとはズバリ職業のことです。例えば戦士という職業があったとします。
戦士という職業は以下の特性があるとします。

  • HP(ヒットポイント)が高い
  • 剣が装備できる
  • 必殺技が使える

このままでは戦士のキャラはいません。ピンときましたか?
オブジェクトというのは、ゲームでいうところのキャラクターを指します。

クラスは、職業でありキャラクター(オブジェクト)を作成するためのものです。
つまりクラスを定義しておけば、同じ特性をもったキャラクター(オブジェクト)をいくつも量産できるということです。

クラスの作成方法

クラスを作成するには、新しくクラスファイルを作成した方が扱いやすいので新しくファイルを追加します。

追加するにはプロジェクトを右クリックして[追加]-[クラス]を選択します。
※ソリューションではありませんので注意してください。

そうすると以下の画面がでてきます。今回はロボをクラス化しようと思っていますので名前を「ClassRobo」としてください。

クラスが追加されたでしょうか?

クラスの使用方法

クラスは変数宣言の型として使用します。今回「ClassRobo」クラスを作成しましたので以下のような例になります。

ClassRobo robo;

これだけです。int や stringと変わりませんね。

インスタンスの作成

クラスの宣言をしてもこのままでは使えません。単に入れ物を作っただけで中身は空っぽなので新しく中身を入れてあげなければいけません。

簡単にいうと入れ物を作ったので「そこに入るもの」を入れてくださいよ的な感じだとイメージして頂ければと思います。

プログラムでは実体(インスタンス)を作成するといいます。インスタンスを作成するにはnewしてあげます。先ほどの例でいくと以下のようになります。

robo = new ClassRobo();

こうすることで実際のロボが完成します。もちろん宣言と同時にインスタンス作成もできます。

ClassRobo robo = new ClassRobo();

ロボをクラス化して個性を出してみよう

ロボをクラス化しようとした意味は、せっかく対戦するので局面をみて出す手を変えるような戦略性をロボに埋め込んで個性を出そうと思いました。

難しくいってますが、どういうときにどんな手をだそうかな、そのときロボの感情とかどんなのかなをクラスに入れていきたいと思います。

クラスの中はこれまで説明してきた関数や変数を書いていきます。

privateとpublic

それではまず勝率からロボの感情を表す文字列を表示してみましょう。
まずロボと何回戦って、何回勝ったかをロボットが持っていないといけません。

class ClassRobo
{
    private int cnt_win = 0;
    private int cnt_lose = 0;
    private int cnt_draw = 0;
    
    public void setMatchResult(int res)
    {
        switch(res)
        {
            case 0:
                cnt_draw++;
                break;
            case 1:
                cnt_lose++;
                break;
            case 2:
                cnt_win++;
                break;
            default:
                break;
        }
    }
}

これでロボの中に何回勝って、何回負けて、何回あいこになったのか確保できます。

基本的には今までと変わりませんが、注目すべきはprivateとpublicです。

private

private宣言した変数や関数は、そのクラスの中でしか利用できません。

public

public宣言した変数や関数は、インスタンスを作成した他のクラス内でも利用することができます。

それでは実際にクラスを宣言して、インスタンスを作成しましょう。
勝敗履歴も入れようと思います。

public partial class Form1 : Form
{

    System.Random r = new System.Random();
    int[] array_match_result = new int[0];
    private ClassRobo robo = new ClassRobo();

宣言してインスタンス作成します。

//勝負スタート
private void MatchStart(int my_hand)
{

    string message = "";

    int cpu_hand = GetCpuHand();       //0~2の乱数をCPUの手にします。

    //イメージを設定
    this.picYou.Image = GetJankenImage(my_hand);     //あなたの手
    this.picCPU.Image = GetJankenImage(cpu_hand);    //CPUの手

    //勝敗判定
    int judge = JadgeJanken(my_hand, cpu_hand);

    //勝負の結果を配列に追加
    Array.Resize(ref array_match_result, array_match_result.Length + 1);
    array_match_result[array_match_result.Length - 1] = judge;
    
    //勝敗をロボに教えてあげる(自分の結果とは反転させる勝ちだったら負け、負けだったら勝ち)
    robo.setMatchResult(Math.Abs(judge - 3) % 3);

    //勝敗結果文字列を取得
    int ret = ConvertVictoryMessage(judge, ref message);

    //結果を表示
    if (ret == 0)
    {
        this.lblResult.Text = message;
    }
    else
    {
        this.lblResult.Text = "不正な結果が返ってきました。";
    }
}

Math.Abs関数は、絶対値を取得する関数です。勝ちの場合は(2-3)の絶対値で1になります。あいこの場合は、(0-3)の絶対値で3になるので%で3で割った余りを取得するようにして0~2になるようにします。

仕上げ

それでは今の気持ちを取得する関数を作るようにしましょう。
ClassRobo.cs

public string GetKimochi()
{
    //勝負回数を計算
    int cnt_match = cnt_win + cnt_lose + cnt_draw;

    //対戦前は開始前のセリフにする
    if (cnt_match == 0) return "よ~し勝負だ!";

    //ロボの勝率を計算する
    int per_win = 100 * cnt_win / cnt_match;

    //勝率でセリフを変える
    if (per_win > 40) return "楽勝~♪";
    if (per_win > 30) return "接戦だ!";
    if (per_win > 20) return "まだまだ";
    if (per_win > 10) return "ちくしょー";

    return "勝てない・・・。";
}

勝率だけしか見ていませんがもっといろんなパターンが作れれば、勝負を盛り上げてくれそうですね。

それではこれを追加してみましょう。今回もlblResultに入れましょう。
From1.cs

//勝負スタート
private void MatchStart(int my_hand)
{

    string message = "";

    int cpu_hand = GetCpuHand();       //0~2の乱数をCPUの手にします。

    //イメージを設定
    this.picYou.Image = GetJankenImage(my_hand);     //あなたの手
    this.picCPU.Image = GetJankenImage(cpu_hand);    //CPUの手

    //勝敗判定
    int judge = JadgeJanken(my_hand, cpu_hand);

    //勝負の結果を配列に追加
    Array.Resize(ref array_match_result, array_match_result.Length + 1);
    array_match_result[array_match_result.Length - 1] = judge;

    //勝敗結果文字列を取得
    int ret = ConvertVictoryMessage(judge, ref message);
    
    //ロボのメッセージを取得
    string robo_mess = "ロボ「" + robo.GetKimochi() + "」";

    //結果を表示
    if (ret == 0)
    {
        this.lblResult.Text = message + "\r\n" + robo_mess;
    }
    else
    {
        this.lblResult.Text = "不正な結果が返ってきました。";
    }

}	

表示してみましょう

さて実行して表示してみましょう。

勝率でロボが悔しがったりしますね。

まとめ

今回、ロボをクラス化して実体を持たせることでプログラムに広がりを持たせました。

フォームに書くこともできますが、それだとソースコードがわかりにくくなると思いません?

例えば難易度設定を作った時に、難易度ごとの出す手を変えるソースコードをフォームに追加すると1ファイルのソースコード量がどんどん増えていってしまいます。

ロボに難易度ごとに出す手を考えさせるようにするなら、ロボクラスに難易度を渡せば出す手はロボの方でやってくれる方がソースコードがすっきりします。

【C#入門】第13回 タイマーについて【じゃんけんゲームを作ろう その13】
【C#入門】第13回 タイマーについて【じゃんけんゲームを作ろう その13】
こんにちは、ノムノムです。 前回はクラスをやりました。クラスまで理解できてしまえば初心者から初級者になれると思…
http://nomux2.net/timer/

C#クラス

Posted by nomux2