Gå til indholdet

Eksempler

Disse eksempler kan bruges i forbindelse med undervisning i forskellige sammenhænge. Kontakt Michell for yderligere oplysninger.

OOP/FOP

Brug eventuelt disse klasser til at forklare OOP og FOP.

Tip
using TerningSpil;

// Sætter LogMetode til at skrive log til konsollen
Terning.LogMetode = Console.WriteLine;
// eller en fil
// Terning.LogMetode = tekst => File.AppendAllText("log.txt", tekst + Environment.NewLine); ;
// eller begge
Terning.LogMetode += tekst => File.AppendAllText("log.txt", tekst + Environment.NewLine); ;

// Opretter en ny terning og 'ryster' den
Terning t = new();
Skriv("Terningens værdi: " + t);

// Opretter en ny terning med en bestemt værdi
Terning t2 = new(4);
Skriv("Terningens værdi: " + t2);

// Opretter en ny snydeterning
Terning t3 = new(true);
Skriv("Terningens værdi: " + t3);

// Anden måde at oprette en terning på
Terning t4 = 5;

// Sætter LogMetode til at skrive log til en fil

// Opretter en ny LudoTerning og 'ryster' den
LudoTerning lt = new();
Skriv("LudoTerningens værdi: " + lt);
Skriv("Er Globus: " + lt.ErGlobus());
Skriv("Er Stjerne: " + lt.ErStjerne());

TerningBæger terningBæger = new(Terning.OpretTerninger(5));
Skriv(terningBæger);

TerningBæger terningBæger2 = new(LudoTerning.OpretTerninger(5));
Skriv(terningBæger2);
terningBæger2.Ryst();
Skriv(terningBæger2);

static void Skriv(object o)
{
    Console.WriteLine("\r\n" + o + "\r\n");
}

namespace TerningSpil
{
    /// <summary>
    /// Klassen 'Terning' repræsenterer en terning i et spil.
    /// Den kan have en værdi mellem 1 og 6, ligesom en almindelig terning.
    /// Der er også mulighed for at lave en 'snydeterning', som altid lander på 6.
    /// </summary>
    public class Terning
    {
        // En statisk Random-instans, der bruges til at generere tilfældige tal.
        private static readonly Random rnd = new();

        // Et readonly felt, der angiver om terningen er en snydeterning.
        private readonly bool snyd;

        // Privat felt til at holde værdien af terningen.
        private int værdi;
        /// <summary>
        /// Standardkonstruktør. Opretter en ny terning og 'ryster' den for at få en tilfældig værdi.
        /// </summary>
        public Terning()
        {
            Log("Ny terning");
            this.Ryst();
        }

        /// <summary>
        /// Konstruktør, der tillader angivelse af en bestemt værdi til terningen.
        /// </summary>
        /// <param name="værdi">Den ønskede værdi for terningen.</param>
        public Terning(int værdi)
        {
            Log($"Ny terning med værdi {værdi}");
            this.Værdi = værdi;
        }

        /// <summary>
        /// Konstruktør, der skaber en snydeterning. En snydeterning har altid værdien 6.
        /// </summary>
        /// <param name="snyd">Hvis sat til true, laves en snydeterning.</param>
        public Terning(bool snyd)
        {
            Log($"Ny snydeterning");
            this.snyd = snyd;
            this.værdi = 6;
        }

        /// <summary>
        /// En statisk delegate, der kan holde en reference til en log-metode.
        /// LogMetode bruges til at logge forskellige aktiviteter og begivenheder.
        /// </summary>
        public static Action<string?>? LogMetode { get; set; }

        /// <summary>
        /// Egenskab til at få eller sætte værdien af terningen.
        /// Hvis værdien er uden for det tilladte område (1-6), kastes en fejl.
        /// </summary>
        /// <exception cref="ApplicationException">Kastes, hvis værdien er uden for intervallet 1-6.</exception>
        public int Værdi
        {
            get
            {
                Log($"Værdi {værdi} aflæst");
                return værdi;
            }
            set
            {
                if (value < 1 || value > 6)
                {
                    Log($"Værdi {value} er ikke tilladt");
                    throw new ApplicationException("Forkert værdi");
                }
                Log($"Værdi sat til {value}");
                værdi = value;
            }
        }

        /// <summary>
        /// Genererer en tilfældig værdi for en terning.
        /// </summary>
        /// <returns>En tilfældig værdi mellem 1 og 6.</returns>
        public static int FindTilfældigTerningVærdi()
        {
            int v = rnd.Next(1, 7);
            Log("FindTilfældigTerningVærdi kaldt - " + v + " fundet");
            return v;
        }

        /// <summary>
        /// Tillader implicit konvertering fra en Terning til en integer.
        /// </summary>
        /// <param name="terning">Terningen, der skal konverteres til en integer.</param>
        public static implicit operator int(Terning terning)
        {
            Log($"Konvertering fra terning med værdi {terning.Værdi} til int");
            return terning.Værdi;
        }

        /// <summary>
        /// Tillader implicit konvertering fra en integer til en Terning.
        /// </summary>
        /// <param name="value">Integer værdien, der skal konverteres til en Terning.</param>
        public static implicit operator Terning(int value)
        {
            Log($"Konvertering fra int til terning med værdi {value}");
            return new(value);
        }

        // En privat metode til at logge beskeder. Bruger LogMetode, hvis den er sat.
        public static void Log(string tekst)
        {
            string tid = DateTime.Now.ToString("HH:mm:ss:ffff");
            LogMetode?.Invoke($"{tid} {tekst}");
        }
        /// <summary>
        /// Overloader != operatoren for at sammenligne to terninger baseret på deres værdier.
        /// </summary>
        /// <param name="t1">Den første terning til sammenligning.</param>
        /// <param name="t2">Den anden terning til sammenligning.</param>
        /// <returns>True, hvis terningerne ikke har samme værdi, ellers false.</returns>
        public static bool operator !=(Terning t1, Terning t2)
        {
            var v = !(t1 == t2);
            Log("!= kaldt - resultat " + v);
            return v;
        }

        /// <summary>
        /// Overloader < operatoren for at bestemme, om en terning har en lavere værdi end en anden.
        /// </summary>
        /// <param name="t1">Den første terning til sammenligning.</param>
        /// <param name="t2">Den anden terning til sammenligning.</param>
        /// <returns>True, hvis den første ternings værdi er lavere end den anden, ellers false.</returns>
        public static bool operator <(Terning t1, Terning t2)
        {
            var r = t1.Værdi < t2.Værdi;
            Log("< kaldt - resultat " + r);
            return r;
        }

        /// <summary>
        /// Overloader == operatoren for at sammenligne to terninger baseret på deres værdier.
        /// </summary>
        /// <param name="t1">Den første terning til sammenligning.</param>
        /// <param name="t2">Den anden terning til sammenligning.</param>
        /// <returns>True, hvis terningerne har samme værdi, ellers false.</returns>
        public static bool operator ==(Terning t1, Terning t2)
        {
            var v = t1.Værdi == t2.Værdi;
            Log("== kaldt - resultat " + v);
            return v;
        }

        /// <summary>
        /// Overloader > operatoren for at bestemme, om en terning har en højere værdi end en anden.
        /// </summary>
        /// <param name="t1">Den første terning til sammenligning.</param>
        /// <param name="t2">Den anden terning til sammenligning.</param>
        /// <returns>True, hvis den første ternings værdi er højere end den anden, ellers false.</returns>
        public static bool operator >(Terning t1, Terning t2)
        {
            var r = t1.Værdi > t2.Værdi;
            Log("> kaldt - resultat " + r);
            return r;
        }

        /// <summary>
        /// Opretter en liste af terninger med en bestemt størrelse.
        /// </summary>
        /// <param name="antal">antal terninger</param>
        /// <returns>Liste af terninger</returns>
        public static List<Terning> OpretTerninger(int antal)
        {
            List<Terning> terninger = new();
            for (int i = 0; i < antal; i++)
            {
                terninger.Add(new Terning());
            }
            return terninger;
        }

        /// <summary>
        /// Bestemmer om et givet objekt er lig med den aktuelle terning.
        /// </summary>
        /// <param name="obj">Objektet, der skal sammenlignes med den aktuelle terning.</param>
        /// <returns>True, hvis objekterne er ens, ellers false.</returns>
        public override bool Equals(object? obj)
        {
            if (ReferenceEquals(this, obj))
            {
                Log("Equals kaldt - resultat true");
                return true;
            }

            if (obj is null)
            {
                Log("Equals kaldt - resultat false");
                return false;
            }

            throw new NotImplementedException();
        }

        /// <summary>
        /// Returnerer en hashkode for denne instans.
        /// </summary>
        /// <returns>En hashkode for den aktuelle terning.</returns>
        public override int GetHashCode()
        {
            Log("GetHashCode kaldt");
            return base.GetHashCode();
        }

        /// <summary>
        /// Metode til at 'ryste' terningen, hvilket resulterer i en ny tilfældig værdi.
        /// For en snydeterning vil værdien altid være 6.
        /// </summary>
        public void Ryst()
        {
            if (snyd)
            {
                this.Værdi = 6;
                Log("Snydeterning 'rystet' til en 6'er");
            }
            else
            {
                int v = FindTilfældigTerningVærdi();
                Log("Terning rystet til en " + v + "'er");
                this.Værdi = v;
            }
        }

        /// <summary>
        /// Returnerer en strengrepræsentation af terningens nuværende værdi.
        /// </summary>
        /// <returns>En streng, der viser terningens værdi i firkantede parenteser.</returns>
        public override string ToString()
        {
            Log("Terning vist som tekst");
            return $"[ {this.Værdi} ]";
        }
    }

    /// <summary>
    /// Klassen 'LudoTerning' udvider 'Terning'-klassen og tilføjer specifik funktionalitet for et Ludo-spil.
    /// Denne klasse introducerer specielle terningsider som 'Globus' og 'Stjerne', udover de normale værdier fra 1 til 6.
    /// </summary>
    public class LudoTerning : Terning
    {
        /// <summary>
        /// Standardkonstruktør. Opretter en ny LudoTerning med en tilfældig værdi.
        /// </summary>
        public LudoTerning() : base()
        {
            Log("Ny LudoTerning");
        }

        /// <summary>
        /// Konstruktør, der tillader angivelse af en bestemt værdi til LudoTerningen.
        /// </summary>
        /// <param name="værdi">Den ønskede værdi for LudoTerningen.</param>
        public LudoTerning(int værdi) : base(værdi)
        {
            Log("Ny LudoTerning med værdi " + værdi);
        }

        /// <summary>
        /// Konstruktør, der skaber en LudoTerning, som kan være en snydeterning.
        /// </summary>
        /// <param name="snyd">Hvis sat til true, laves en snyde LudoTerning.</param>
        public LudoTerning(bool snyd) : base(snyd)
        {
            Log("Ny LudoTerning med snyd " + snyd);
        }

        /// <summary>
        /// Opretter en liste af ludo terninger med en bestemt størrelse.
        /// </summary>
        /// <param name="antal">antal terninger</param>
        /// <returns>Liste af terninger</returns>
        public static List<LudoTerning> OpretLudoTerninger(int antal)
        {
            List<LudoTerning> terninger = new();
            for (int i = 0; i < antal; i++)
            {
                terninger.Add(new LudoTerning());
            }
            return terninger;
        }

        /// <summary>
        /// Bestemmer om LudoTerningens nuværende værdi er et 'Globus' symbol.
        /// I Ludo repræsenterer 'Globus' en speciel handling eller regel.
        /// </summary>
        /// <returns>True, hvis terningen viser et 'Globus', ellers false.</returns>
        public bool ErGlobus()
        {
            var r = this.Værdi == 3;
            Log("ErGlobus kaldt - resultat " + r);
            return r;
        }

        /// <summary>
        /// Bestemmer om LudoTerningens nuværende værdi er et 'Stjerne' symbol.
        /// I Ludo repræsenterer 'Stjerne' en speciel handling eller regel.
        /// </summary>
        /// <returns>True, hvis terningen viser en 'Stjerne', ellers false.</returns>
        public bool ErStjerne()
        {
            var r = this.Værdi == 5;
            Log("ErStjerne kaldt - resultat " + r);
            return r;
        }

        /// <summary>
        /// Returnerer en strengrepræsentation af LudoTerningens nuværende værdi.
        /// Viser 'G' for Globus, 'S' for Stjerne, eller den numeriske værdi for andre sider.
        /// </summary>
        /// <returns>En streng, der repræsenterer LudoTerningens nuværende side.</returns>
        public override string ToString()
        {
            if (this.ErGlobus())
            {
                Log("LudoTerning vist som globus");
                return "[ G ]";
            }
            else if (this.ErStjerne())
            {
                Log("LudoTerning vist som stjerne");
                return "[ S ]";
            }
            else
            {
                Log("LudoTerning vist som tekst");
                return base.ToString();
            }
        }
    }
    /// <summary>
    /// Repræsenterer et bæger, der kan indeholde en samling af Terning-objekter.
    /// </summary>
    public class TerningBæger
    {
        // Liste til at holde terninger.
        private readonly List<Terning> terninger;

        /// <summary>
        /// Initialiserer en ny instans af TerningBæger-klassen med en foruddefineret liste af Terning-objekter.
        /// </summary>
        /// <param name="terninger">Listen af terninger, der skal tilføjes til bægeret.</param>
        /// <exception cref="ArgumentNullException">Kastes, hvis den medfølgende liste er null.</exception>
        public TerningBæger(List<Terning> terninger)
        {
            // Sikrer, at den medfølgende liste ikke er null.
            if (terninger is null)
            {
                throw new ArgumentNullException(nameof(terninger), "Liste af terninger må ikke være null.");
            }
            Terning.Log("Bæger med terninger oprettet");
            this.terninger = terninger;
        }

        /// <summary>
        /// Ryster alle terningerne i bægeret for at ændre deres værdi.
        /// </summary>
        public void Ryst()
        {
            foreach (var t in terninger)
            {
                t.Ryst();
            }
            Terning.Log("Bæger rystet");
        }

        /// <summary>
        /// Returnerer en strengrepræsentation af bægerets indhold.
        /// </summary>
        /// <returns>En streng, der viser hver ternings værdi i bægeret.</returns>
        public override string ToString()
        {
            Terning.Log("Bæger vist som tekst");
            string result = "";
            foreach (var t in terninger)
            {
                result += t.ToString() + " ";
            }
            return result.TrimEnd();
        }
    }
}