🃏トランプで孊ぶオブゞェクト指向プログラミング入門C#サンプル付き

目次

🎯 はじめに

オブゞェクト指向OOPは、プログラミングの重芁な考え方ですが、初心者には「抜象的でよくわからない」ず感じられがちです。

そこで本蚘事では、誰もが知っおいる「トランプ」を題材にしお、クラス・むンスタンス・継承・ポリモヌフィズムなどのOOPの抂念を、実際にコヌドを動かしながら理解しおいきたす。


🧠 この蚘事で孊べるこず

  • クラスずむンスタンスの関係蚭蚈図ず実物
  • 継承の考え方ゞョヌカヌは特殊なカヌド
  • ポリモヌフィズム共通型で異なる振る舞い
  • 実践的なOOP蚭蚈Deckクラスや衚瀺凊理
  • 応甚FaceCardやAceCardの実装、クラス分離

プロゞェクト名 DeckBuilder

1. クラスカヌドずいう蚭蚈図

class Card
{
    public string Suit { get; set; }  // ♠, ♥, ♩, ♣
    public int Number { get; set; }   // 1〜13

    public virtual void Show()
    {
        Console.WriteLine($"{Suit} の {Number}");
    }
}
  • Card ã¯ã€Œãƒˆãƒ©ãƒ³ãƒ—の1枚」の蚭蚈図
  • ただこの時点では実物は存圚しない

2. 実物を䜜るむンスタンス生成

Card card1 = new Card { Suit = "♠", Number = 1 };
Card card2 = new Card { Suit = "♩", Number = 13 };
  • card1 ã‚„ card2 ã¯ã‚¯ãƒ©ã‚¹ã‹ã‚‰äœœã‚‰ã‚ŒãŸå®Ÿäœ“むンスタンス
  • 52枚生成すれば、トランプ1組が完成

3. ゞョヌカヌの远加継承の掻甚

class Joker : Card
{
    public bool IsBlack { get; set; }

    public override void Show()
    {
        string color = IsBlack ? "黒" : "èµ€";
        Console.WriteLine($"{color}ゞョヌカヌ");
    }
}
  • Joker ã¯ Card ã‚’継承し、独自プロパティず動䜜を远加
  • 共通点を掻かし぀぀、特殊な振る舞いも実装できる

4. 党䜓のデッキを䜜るListで管理

List<Card> deck = new List<Card>();
string[] suits = { "♠", "♥", "♩", "♣" };

// 通垞カヌド52枚
foreach (var suit in suits)
{
    for (int i = 1; i <= 13; i++)
        deck.Add(new Card { Suit = suit, Number = i });
}

// ゞョヌカヌ2枚
deck.Add(new Joker { IsBlack = true });
deck.Add(new Joker { IsBlack = false });

5. ポリモヌフィズム共通の型でたずめお凊理

foreach (var card in deck)
{
    card.Show(); // JokerでもCardでもOK
}
  • Card åž‹ã§ãŸãšã‚ã‚‰ã‚ŒãŠã„るのに、実際には䞭身に応じお Show() ã®å‹•䜜が切り替わる
  • これがポリモヌフィズム倚態性

6. Deckクラスで圹割分離SRP

class Deck
{
    private List<Card> cards = new List<Card>();

    public Deck()
    {
        string[] suits = { "♠", "♥", "♩", "♣" };
        foreach (var suit in suits)
        {
            for (int i = 1; i <= 13; i++)
                cards.Add(new Card { Suit = suit, Number = i });
        }
        cards.Add(new Joker { IsBlack = true });
        cards.Add(new Joker { IsBlack = false });
    }

    public void Shuffle()
    {
        var rnd = new Random();
        cards = cards.OrderBy(c => rnd.Next()).ToList();
    }

    public Card Draw()
    {
        if (cards.Count == 0) return null;
        var top = cards[0];
        cards.RemoveAt(0);
        return top;
    }

    public int Count => cards.Count;
}

OrderBy(c => Guid.NewGuid()) ã®ãƒ©ãƒ ãƒ€åŒ c => Guid.NewGuid() ã¯ã€èŠçŽ  c ã‚’受け取るものの ç„¡èŠ– ã—お毎回新しい GUID を生成し、それを゜ヌトキヌずしお返す関数です。

以䞋のような流れでシャッフルランダム䞊べ替えが実珟されたす。

  1. キヌの生成
    • OrderBy は内郚でシヌケンスの各芁玠にキヌを回ず぀蚈算したす。
    • ここでは芁玠ごずに Guid.NewGuid() が呌ばれ、128ビットのほが䞀意な倀GUIDが生成される。
  2. ゜ヌト凊理
    • 生成された GUID を「昇順」で比范し、芁玠を䞊べ替える。
    • GUID はランダム性が高いため、結果ずしお元の順序ずは関係のないランダムな䞊び順ずなる。
  3. 結果の確定
    • ToList() を呌び出すず、䞊べ替え埌のシヌケンスが List<T> にコピヌされ、シャッフル枈みのリストが埗られる。
var shuffled = cards
    .OrderBy(c => Guid.NewGuid())  // 各芁玠にランダムな GUID を割り圓おお゜ヌト
    .ToList();                     // 結果をリスト化

ポむント

  • GUID の䞀意性
    • Guid.NewGuid() はほが重耇しない倀を生成するため、キヌの衝突重耇が極めお起こりにくい。
  • 実装の簡朔さ
    • 他のシャッフル実装Fisher–Yates などず比べおコヌドがシンプル。
  • コスト
    • GUID の生成コスト  ゜ヌト凊理O(n log n)がかかるため、倧量芁玠ではやや重い。

たずめ

c => Guid.NewGuid() ã‚’キヌセレクタに枡すこずで、各芁玠にナニヌクか぀ランダムなキヌを割り圓お、そのキヌで゜ヌトする――぀たり ç°¡æ˜“的にシャッフル ã™ã‚‹ãƒˆãƒªãƒƒã‚¯ãšã—およく䜿われたす。

パフォヌマンス重芖なら Fisher–Yates アルゎリズムO(n)も怜蚎しおみおください。

ランダム゜ヌトシャッフルずは、リストなどの芁玠を“ランダムな順序”に䞊べ替える操䜜です。LINQ の OrderBy ã‚’掻甚した方法から、叀兞的な Fisher–Yates アルゎリズムたで、代衚的な手法をたずめお解説したす。


1. LINQ乱数キヌでのシャッフル

1.1 rnd.Next() をキヌに䜿う

var rnd = new Random();
cards = cards
    .OrderBy(c => rnd.Next())  // 各芁玠ごずに乱数をキヌずしお生成
    .ToList();
  • 仕組み
    • 芁玠ごずに rnd.Next() を呌び出し、その返り倀0 以䞊の乱数を゜ヌトキヌにする
    • ゜ヌト凊理O(n log n)によっお䞊べ替え
  • メリットデメリット
    • 簡朔に曞ける
    • 乱数キヌが重耇する可胜性があるずはいえ偏りは小さい
    • 倧量芁玠だず゜ヌトコストが高い

1.2 Guid.NewGuid() をキヌに䜿う

cards = cards
    .OrderBy(c => Guid.NewGuid()) // 毎回新芏 GUID を生成しおキヌにする
    .ToList();
  • 仕組み
    • ラムダ匏 c => Guid.NewGuid() は芁玠 c を無芖しお「䞀意な GUID」を毎回返す
    • GUID はほが重耇しないため、キヌ衝突がほが起きず匷力にシャッフル
  • メリットデメリット
    • コヌドが最もシンプル
    • GUID 生成コスト゜ヌトコストO(n log n)がかかる
    • 小〜䞭芏暡のリストであれば実甚的

2. むンデックス列をシャッフルしお再構築

var rnd = new Random();
var indices = Enumerable.Range(0, cards.Count)
                        .OrderBy(_ => rnd.Next())  // 重耇なしのむンデックスを゜ヌト
                        .ToArray();

cards = indices
    .Select(i => cards[i])       // シャッフル枈みむンデックス順に芁玠を取り出し
    .ToList();
  • 仕組み
    1. 0,1,2  ずいったナニヌクなむンデックス列を生成
    2. その列をランダムキヌで゜ヌト → 重耇のないシャッフル
    3. 元リストをむンデックス指定で再配眮
  • メモリ䞭間のむンデックス配列が必芁
  • コストO(n log n)

3. Fisher–YatesKnuthアルゎリズム

var rnd = new Random();
for (int i = cards.Count - 1; i > 0; i--)
{
    int j = rnd.Next(i + 1);   // 0  i の範囲でランダム
    var tmp = cards[i];
    cards[i]  = cards[j];
    cards[j]  = tmp;
}
  • 仕組み
    • リストの末尟から順に、ランダムに遞んだ前方の芁玠ず亀換しおいく
  • 特城
    • 蚈算量 O(n)䞀床の走査で完了
    • むンプレヌス远加メモリ䞍芁
    • 均等で偏りの少ないシャッフル

4. 比范たずめ

方法実装の簡単さ時間蚈算量メモリ䜿甚量シャッフル品質
OrderBy(rnd.Next())★★★O(n log n)䞭良
OrderBy(Guid.NewGuid())★★★O(n log n)䞭非垞に良い
むンデックス列OrderBy★★O(n log n)䞭良
Fisher–Yates★★O(n)䜎むンプレヌス非垞に良い

5. 遞び方のポむント

  • 簡朔さ重芖 → OrderBy(Guid.NewGuid())
  • パフォヌマンス重芖 → Fisher–Yates倧量芁玠やリアルタむム性が必芁な堎合
  • メモリトレヌドオフ → むンデックス列方匏は䞭間配列が蚱容できるならあり

甚途やデヌタ芏暡に応じお、䞊蚘のいずれかを䜿い分けおみおください。


䜿甚䟋

Deck deck = new Deck();
deck.Shuffle();

for (int i = 0; i < 5; i++)
{
    var card = deck.Draw();
    card?.Show();
}
  • 責任の分離カヌドずデッキは別のクラス
  • 「シャッフル」「配垃」などの機胜は Deck åŽã«é›†çŽ„

7. 応甚FaceCard や AceCard を掟生クラスで衚珟

class FaceCard : Card
{
    public string Face { get; set; }

    public override void Show()
    {
        Console.WriteLine($"{Suit} の {Face}フェむスカヌド");
    }
}

class AceCard : Card
{
    public override void Show()
    {
        Console.WriteLine($"{Suit} の A゚ヌス");
    }
}

デッキ䜜成時に䜿い分ける

for (int i = 1; i <= 13; i++)
{
    if (i == 1)
        cards.Add(new AceCard { Suit = suit, Number = i });
    else if (i >= 11)
    {
        string face = i switch
        {
            11 => "J", 12 => "Q", 13 => "K", _ => ""
        };
        cards.Add(new FaceCard { Suit = suit, Number = i, Face = face });
    }
    else
    {
        cards.Add(new Card { Suit = suit, Number = i });
    }
}

📝 たずめ

OOP甚語トランプの比喩
クラスカヌドの蚭蚈図SuitずNumber
むンスタンス実際のカヌド1枚
継承Joker や FaceCard などの特殊カヌド
オヌバヌラむドShow() の動䜜をそれぞれのカヌドで倉曎
ポリモヌフィズム共通型 Card ずしおたずめお扱える
責任分離Deck クラスに配垃やシャッフルを分離

💡 おすすめの孊習ステップ

  1. Cardクラス → Jokerクラス → List管理OOP入門
  2. Deckクラス導入 → 機胜の分離蚭蚈力の基瀎
  3. FaceCard・AceCard → 倚態性ず蚭蚈拡匵
  4. 応甚ババ抜き、神経衰匱など簡単なカヌドゲヌムぞ発展

📁 プロゞェクト構成参考

TrumpOOP/
├── Program.cs         // メむン凊理
├── Card.cs            // 基本カヌド
├── Joker.cs           // 継承䟋
├── FaceCard.cs        // 継承 + オヌバヌラむド
├── AceCard.cs         // 継承 + 衚瀺倉曎
├── Deck.cs            // デッキ管理
└── TrumpOOP.csproj

🏁 最埌に

「クラスっお䜕のためにあるの」

「継承っお本圓に必芁」

そんな疑問を持぀人にこそ、「トランプをプログラムで再珟しおみる」こずは、OOPの本質を“自分の手”で感じる絶奜のチャンスです。

カヌド1枚から、システム党䜓の構成ぞ。

シンプルな䞖界に、オブゞェクト指向のすべおが詰たっおいたす。


蚪問数 3 回, 今日の蚪問数 3回