計算機科学のブログ

reading and writing files - Save the last byte for me! - Avoid filesystem errors with using statements

Head First C Sharp: A Learner’s Guide to Real-World Programming with C Sharp and .NET (Andrew Stellman(著)、Jennifer Greene(著)、O’Reilly Media)の Chapter 10(reading and writing files - Save the last byte for me!)、p.549(Exercise)の解答を求めてみる。

コード

Program.cs

using ConsoleApp1;

var filename = "deckofcards.txt";
Deck deck = new();
deck.Shuffle();
for (int i = deck.Count - 1; i > 10; i--)
{
    deck.RemoveAt(i);
}
deck.WriteCards(filename);

Deck cardsToRead = new Deck(filename);
foreach (var card in cardsToRead)
{
    Console.WriteLine(card.Name);
}

Card.cs

namespace ConsoleApp1;

public class Card
{
    public Values Value { get; }
    public Suits Suit { get; }
    public string Name
    {
        get { return $"{Value} of {Suit}"; }
    }

    public Card(Values value, Suits suit)
    {
        Value = value;
        Suit = suit;
    }
}

Deck.cs

using System;

namespace ConsoleApp1;

public class Deck : List<Card>
{
    private static Random random = new Random();
    public Deck()
    {
        Reset();
    }
    public void Reset()
    {
        Clear();
        for (int suit = 0; suit < 4; suit++)
        {
            for (int value = 1; value < 14; value++)
            {
                Add(new Card((Values)value, (Suits)suit));
            }
        }
    }
    public void Shuffle()
    {
        List<Card> cards = new List<Card>(this);
        Clear();
        while (cards.Count > 0)
        {
            int i = random.Next(cards.Count);
            Add(cards[i]);
            cards.RemoveAt(i);
        }
    }
    public Card Deal(int index)
    {
        Card card = base[index];
        RemoveAt(index);
        return card;
    }
    public Deck(string filename)
    {
        using StreamReader streamReader = new(filename);
        while (streamReader.EndOfStream)
        {
            var nextCard = streamReader.ReadLine();
            var cardParts = nextCard?.Split([' ']);
            var suit = cardParts?[2] switch
            {
                "Diamonds" => Suits.Diamonds,
                "Clubs" => Suits.Clubs,
                "Hearts" => Suits.Hearts,
                "Spades" => Suits.Spades,
                _ => throw new InvalidDataException()
            };
            var value = cardParts[0] switch
            {

                "Ace" => Values.Ace,
                "Two" => Values.Two,
                "Three" => Values.Three,
                "Four" => Values.Four,
                "Five" => Values.Five,
                "Six" => Values.Six,
                "Seven" => Values.Seven,
                "Eight" => Values.Eight,
                "Nine" => Values.Nine,
                "Ten" => Values.Ten,
                "Jack" => Values.Jack,
                "Queen" => Values.Queen,
                "King" => Values.King,
                _ => throw new InvalidDataException(),
            };
            Add(new Card(value, suit));
        }
    }
    public void WriteCards(string filename)
    {
        using var sw = new StreamWriter(filename);
        foreach (var card in this)
        {
            sw.WriteLine(card.Name);
        }
    }
}

Suits.cs

namespace ConsoleApp1;

public enum Suits
{
    Diamonds,
    Clubs,
    Hearts,
    Spades,
}

Values.cs

namespace ConsoleApp1;

public enum Values
{
    Ace = 1,
    Two,
    Three,
    Four,
    Five,
    Six,
    Seven,
    Eight,
    Nine,
    Ten,
    Jack,
    Queen,
    King
}

入出力結果(Terminal, Zsh)

% cat deckofcards.txt 
Eight of Spades
Eight of Diamonds
Jack of Diamonds
Six of Clubs
Three of Hearts
King of Clubs
Three of Clubs
Two of Clubs
Two of Diamonds
Five of Hearts
Ace of Hearts
% dotnet run         
% cat deckofcards.txt
Eight of Hearts
Three of Hearts
Ten of Diamonds
Seven of Clubs
Ace of Hearts
Six of Clubs
Eight of Spades
Nine of Diamonds
Two of Clubs
Two of Spades
Four of Spades
%