C# :: Aufgabe #272

3 Lösungen Lösungen öffentlich

Das Problemspiel der spagetti-essenden Philosophen

Anfänger - C# von hollst - 04.12.2019 um 18:44 Uhr
wiki
https://de.wikipedia.org/wiki/Philosophenproblem


Fünf Philosophen sitzen um einen runden Tisch, vor jedem ein Teller voll mit Spagetti und links davon eine Gabel (BILD 1).
Um von dem Teller Spagetti essen zu können, benötigt man allerdings zwei Gabeln. Die zweite Gabel kann man sich von seinem
rechten Nachbarn borgen, sofern dieser nicht gerade selber beim Essen ist. Außerdem sollte man seine eigene Gabel auch nicht gerade
an seinen linken Nachbarn verborgt haben.

Das Spiel beginnt beim ersten Philosophen und geht Schritt für Schritt wie folgt reihum:

Jeder Philosoph kann sich in einem von drei möglichen Zuständen befinden,
u. z. denkend (Zustand 1, zu Beginn alle fünf Philosophen), hungernd (2) oder essend (3).

Ein denkender Philosoph kann per Zufallsentscheidung entweder in diesem Zustand 1 verweilen (dann geht der Zeiger sofort weiter an
seinen rechten Nachbarn) oder sich für "Essenwollen" entscheiden (Übergang von Zustand 1 in Zustand 2). In diesem Fall muss er prüfen,
ob ihm zwei Gabeln zur Verfügung stehen. Wenn Ja geht er von Zusand 2 in den Zustand 3 über und kann (sagen wir) zwei [Variable E wie Essen] Runden lang essen. Nach den zwei [E] Runden wird er zunächst wieder zum denkenden Philosophen (Zustand 1), der geleerte Teller wird sofort wieder aufgefüllt, falls der Philosoph erneut Hunger bekommt.

Hat er allerdings keine zwei Gabeln zur Verfügung, bleibt er die Runde hungrig (er verharrt im Zustand 2). Bekommt ein Philosoph
(sagen wir) zehn [Variable T wie Tod] Runden lang hintereinander nichts zu essen, ist er verhungert und das Gelage auch zu ende.

Die Frage lautet, nach wie vielen Runden (abhängig von E und T) ist im Durchschitt der erste Philosoph verhungert. Viel Spaß!

Lösungen:

vote_ok
von Heftog (300 Punkte) - 08.12.2019 um 21:46 Uhr
Quellcode ausblenden C#-Code
/// <summary>
        /// Philosophenproblem -> Wiki; Wie lange überleben 5 Philosophen wenn Gabel Zustand und Hunger kriterien sind.
        /// </summary>
        private static void Aufgabe_272()
        {
            int essensRunden = 2; //Variable e = Essens, Rundendauer wenn gegessen wird.
            int rundenBisHungertod = 10; //Variable t = Tod, wenn er Anzahl an Runden hungernd bleibt.
            bool nobodyDead = true; //Trigger für Spielende

            List<int> avrRoundEnds = new List<int>();
            for (int avrCalculator = 0; avrCalculator < 10; avrCalculator++)
            {
                nobodyDead = true;
                int round = 0;
                List<Philosoph_272A> philosophen = new Philosoph_272A[5].ToList().Select(dD => dD = new Philosoph_272A()).ToList(); // 5 Philosophen; denkend und mit einer Gabel

                while (nobodyDead)
                {
                    round++;
                    for (int i = 0; i < philosophen.Count; i++)
                    {
                        //Persönlich werden. Sprich Ihn an
                        Philosoph_272A derD = philosophen[i];
                        //Wir nehmen die Gabel vom Anderen weg (rechts von uns, bzw index+1), 
                        //also geben wir Ihm auch einen Namen. Vermeiden von OutOfIndexEx.
                        Philosoph_272A derAndere = philosophen[i + 1 == philosophen.Count ? 0 : i + 1];


                        //Prüfen ob jeweilige Person schon verhungert ist. Trigger für Spiel ende
                        if (derD.HungerndeTage > rundenBisHungertod) { nobodyDead = false; continue; }

                        //Prüfen ob der Teller leer ist (Essensrunden)
                        if (derD.EssendeTage > essensRunden)
                        {
                            derD.EssendeTage = 0;
                            derD.Zustand = Philosoph_272A.PhilosophenZustand_272A.Denkend;
                            derAndere.LinkeGabel = true;
                        }

                        if (derD.Zustand == Philosoph_272A.PhilosophenZustand_272A.Denkend)
                        {
                            //Den "Zufall" entscheiden lassen ob wir Denkend bleiben oder Hunger bekommen
                            derD.Zustand = new Random().Next(0, 1000) % 2 == 0 ?
                                Philosoph_272A.PhilosophenZustand_272A.Denkend :
                                Philosoph_272A.PhilosophenZustand_272A.Hungernd;

                        }

                        if (derD.Zustand == Philosoph_272A.PhilosophenZustand_272A.Essend) { ++derD.EssendeTage; };

                        if (derD.Zustand == Philosoph_272A.PhilosophenZustand_272A.Hungernd)
                        {
                            //Sind beide Gabeln zur Verfügung, nehmen wir die Gabel unserem Nachbar weg und Essen. -> Gabeln gesperrt duch EssendeTage != 0
                            if (derAndere.LinkeGabel == true &&
                                derAndere.EssendeTage == 0 &&
                                derD.LinkeGabel == true)
                            {
                                derAndere.LinkeGabel = false;
                                derD.Zustand = Philosoph_272A.PhilosophenZustand_272A.Essend;
                                derD.EssendeTage++;
                                derD.HungerndeTage = 0;
                            }
                            else
                            {
                                derD.HungerndeTage += 1;
                            }
                        }


                        Console.WriteLine($"P{i}: Essend: {derD.EssendeTage} Hungernd: {derD.HungerndeTage} Gabel: {derD.LinkeGabel} Zustand: {derD.Zustand.ToString()}");
                    }

                }
                avrRoundEnds.Add(round);
                Console.WriteLine($"\n");
            }

            Console.WriteLine($"\n\n\n\n\nDie durschnittliche Rundenanzahl bis einer stirbt ist: {avrRoundEnds.Average()}\nRundenergebnisse:\n");
            avrRoundEnds.ForEach(dD => Console.WriteLine($"{dD} Runden"));


        }

Quellcode ausblenden C#-Code
        public class Philosoph_272A
        {
            public Philosoph_272A()
            {
                Zustand = PhilosophenZustand_272A.Denkend;
                LinkeGabel = true;

                HungerndeTage = EssendeTage = 0;

            }

            public PhilosophenZustand_272A Zustand { get; set; }
            public bool LinkeGabel { get; set; }

            public int HungerndeTage { get; set; }
            public int EssendeTage { get; set; }

            public enum PhilosophenZustand_272A
            {
                Denkend,
                Hungernd,
                Essend
            }
        }
vote_ok
von DanielWagner (220 Punkte) - 14.12.2019 um 21:39 Uhr
Quellcode ausblenden C#-Code
enum Zustand { denkend, essend, hungernd }
    class Philosoph
    {
        public static List<Philosoph> AllePhilosophen = new List<Philosoph>();

        public int Id;
        public string Name;
        public Enum Zustand { get; set; }
        public bool IsAlive;
        public int RundeBisZumTod;
        public int EssensRunden;

        public Philosoph(int id, string name, Enum zustand, bool isAlive)
        {
            Id = id;
            Name = name;
            Zustand = zustand;
            IsAlive = isAlive;
            AllePhilosophen.Add(this);
        }


    }
    class Program
    {
        static Random rand = new Random();
        static void Main(string[] args)
        {
            new Philosoph(1, "Philosoph 1", Zustand.denkend, true);
            new Philosoph(2, "Philosoph 2", Zustand.denkend, true);
            new Philosoph(3, "Philosoph 3", Zustand.denkend, true);
            new Philosoph(4, "Philosoph 4", Zustand.denkend, true);
            new Philosoph(5, "Philosoph 5", Zustand.denkend, true);

            bool schalter = true;
            int round = 0;

            while (schalter)
            {

             
                foreach(Philosoph p in Philosoph.AllePhilosophen)
                {
                    // wenn er nicht beim essen schon ist
                    if (!p.Zustand.Equals(Zustand.essend))
                    {
                        // zustand per Zufall wählen  
                        p.Zustand = (Zustand)rand.Next(2);
                        // Console.WriteLine(p.Zustand);

                        // zustand überprüfen, wenn essend dann weiter zum essen, sonst nächster Philosoph
                        if (p.Zustand.Equals(Zustand.essend))
                        {
                            // prüfen ob zwei Gabel zur Verfügung stehen
                            bool GabelFrei = false;

                            if (p.Id == Philosoph.AllePhilosophen.Count)
                            {
                                if (!Philosoph.AllePhilosophen[0].Zustand.Equals(Zustand.essend))
                                {
                                    p.Zustand = Zustand.essend;
                                    GabelFrei = true;
                                }
                            }
                            else
                            {
                                if (!Philosoph.AllePhilosophen[p.Id].Zustand.Equals(Zustand.essend))
                                {
                                    p.Zustand = Zustand.essend;
                                    GabelFrei = true;
                                }
                            }
                         

                            // wenn true -> essensrunde auf 2 setzen
                            if (GabelFrei)
                            {
                                p.EssensRunden = 2;

                            }   
                            // wenn false -> RundeBisZumTod++
                            else
                            {
                                p.Zustand = Zustand.hungernd;
                                p.RundeBisZumTod++;

                            }
                                
                        }

                    }
                    // sonst wenn er beim essen ist 
                    else if(p.Zustand.Equals(Zustand.essend))
                    {
                        // essensrunde--
                        p.EssensRunden--;
                        if(p.RundeBisZumTod > 0)
                            p.RundeBisZumTod--;

                        // wenn essensrunde == 0
                        if (p.EssensRunden == 0)
                        {
                            // zustand auf denkend  und RundenBisZumTod auf 0 setzen
                            p.Zustand = Zustand.denkend;
                            
                        }
                            
                    }

                    // prüfen ob RundeBisZumTod == 10 ist, denn IsAlive == false
                    if (p.RundeBisZumTod == 10)
                    {
                        p.IsAlive = false;

                    }


                }


                // überprüfen ob ein Philosoph ist schon verhungert, damit wird schleife beendet
                Philosoph.AllePhilosophen.ForEach(p =>
                {
                    if (!p.IsAlive)
                    {
                        schalter = false;
                    }
                       
                });
                

                // Rounds
                round++;

                // Test
                Console.WriteLine("Round " + round);
                Philosoph.AllePhilosophen.ForEach(p =>
                {
                    Console.WriteLine(p.Name + " Zustand: " + p.Zustand + ", Essensrunden: " + p.EssensRunden + " Runde bis zum Tod: " + p.RundeBisZumTod + ", ist am Leben? - " + p.IsAlive);

                });
            }

            // Ausgabe
            Philosoph.AllePhilosophen.ForEach(p => 
            {
                Console.WriteLine($"Round {round}");
                Console.WriteLine(p.Name + ", ist am Leben? - " + p.IsAlive);

            });


            Console.ReadKey();
        }
    }
vote_ok
von krokiritter (220 Punkte) - 09.09.2020 um 14:44 Uhr
Quellcode ausblenden C#-Code
using System;
using System.Collections.Generic;
using System.Linq;

namespace PastaFari
{
    class Program
    {
        static void Main(string[] args)
        {
            Random rnd = new Random();
            List<Philosopher> deathList = new List<Philosopher>();
            List<Philosopher> loopList = new List<Philosopher>();
            int round = 0; bool forkTake;
            Philosopher p1 = new Philosopher("Platon");
            Philosopher p2 = new Philosopher("Aristoteles");
            Philosopher p3 = new Philosopher("Sokrates");
            Philosopher p4 = new Philosopher("Archimedes");
            Philosopher p5 = new Philosopher("Voltaire");
            loopList.Add(p1); loopList.Add(p2); loopList.Add(p3); loopList.Add(p4); loopList.Add(p5);

            while (!deathList.Any())
            {
                for (int i = 0; i < loopList.Count; i++)
                {
                    Philosopher currentP = loopList[i];
                    Philosopher nextP = loopList[i + 1 == loopList.Count ? 0 : i + 1];
                    if (currentP.IstZustand == Philosopher.Zustand.Essend)        //Prüft ob essend
                    {
                        if (currentP.Counter == 0)
                        {
                            currentP.StillEating();             //Essen für 2 Runden
                            currentP.Counter--;
                        }
                        else
                        {
                            currentP.LeftFork = nextP.LeftFork = false;           //Gabeln wieder frei
                            currentP.IstZustand = Philosopher.Zustand.Denkend;    //Nicht mehr essend
                            currentP.FinishEating();
                            currentP.Counter = 0;
                        }
                    }
                    else if (currentP.IstZustand == Philosopher.Zustand.Hungernd) //Prüft ob hungernd
                    {
                        currentP.TryEat();
                        forkTake = IsTaken(currentP, nextP);    //Verbindet 2 bools in einen für switch
                        switch (forkTake)
                        {
                            case false:
                                currentP.Counter = 0;
                                currentP.IstZustand = Philosopher.Zustand.Essend; //Beginnt zu essen
                                currentP.LeftFork = currentP.LeftFork = true;     //Gabeln besetzt
                                currentP.StartEating();
                                break;
                            default:
                                if (currentP.Counter == 9)                        //Prüft ob 10 Runden Hungernd (0-9)
                                {
                                    deathList.Add(currentP);                      //Schleifen-Bedingung
                                }
                                currentP.Hungry();
                                currentP.Counter++;
                                break;
                        }
                    }
                    else
                    {
                        switch (rnd.Next(1, 3))      //Random ob denken oder essen
                        {
                            case 1:
                                currentP.Think();
                                break;
                            case 2:
                                currentP.TryEat();
                                forkTake = IsTaken(currentP, nextP);
                                switch (forkTake)
                                {
                                    case false:
                                        currentP.Counter = 0;
                                        currentP.IstZustand = Philosopher.Zustand.Essend;
                                        currentP.LeftFork = nextP.LeftFork = true;
                                        currentP.StartEating();
                                        break;
                                    default:
                                        currentP.Hungry();
                                        currentP.IstZustand = Philosopher.Zustand.Hungernd;
                                        currentP.Counter++;
                                        break;
                                }
                                break;
                        }
                    }
                    Console.WriteLine("Der Nächste ist an der Reihe");
                }
                round++;
            }
            foreach (Philosopher p in deathList)
            {
                p.Dead();
                Console.WriteLine("Das Gelage dauerte {0} Runden!", round);
            }
            Console.ReadKey();
        }
        public static bool IsTaken(Philosopher f, Philosopher g)
        {
            if ( f.LeftFork == false && g.LeftFork == false)
            {
                return false;
            }
            else
            {
                return true;
            }
        }
    }
}




Quellcode ausblenden C#-Code
using System;

namespace PastaFari
{
    public class Philosopher
    {
        public string Name { get; set; }
        public int Counter { get; set; }
        public bool LeftFork { get; set; }

        public Zustand IstZustand { get; set; }

        public Philosopher(string name)
        {
            Name = name;
            Counter = 0;
            IstZustand = Zustand.Denkend;
            LeftFork = false;

        }
        public enum Zustand                                                     //ein enum für die Zustände um Variablen zu sparen
        {
            Denkend,
            Hungernd,
            Essend
        }
        public void Think()                                                          //Methoden die eigentlich nur zum Spaß da sind um das Geschehen zu verfolgen
        {
            Console.WriteLine($"{Name} is thinking!");
        }
        public void TryEat()
        {
            Console.WriteLine($"{Name} wants to eat!");
        }
        public void Hungry()
        {
            Console.WriteLine($"{Name} is hungry!");
        }
        public void Dead()
        {
            Console.WriteLine($"{Name} died!");
        }
        public void StillEating()
        {
            Console.WriteLine($"{Name} is still eating!");
        }
        public void FinishEating()
        {
            Console.WriteLine($"{Name} has finished eating!");
        }
        public void StartEating()
        {
            Console.WriteLine($"{Name} is starting to eat!");
        }
    }
}