Python :: Aufgabe #234 :: Lösung #2

2 Lösungen Lösungen öffentlich
#234

Das Problemspiel der spagetti-essenden Philosophen

Anfänger - Python 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ß!
#2
vote_ok
von kaschperl (400 Punkte) - 24.02.2020 um 15:24 Uhr
Quellcode ausblenden Python-Code
import random
import pandas as pd
import statistics


class Phil:
    '''Stellt einen Philosophen dar

    Zustände Philosoph Status:
    D = Denken
    H = Hungrig
    E = Essen
    T = Tot

    Zustände der Gabel des Philosophen
    T = auf dem Tisch
    H = linke Hand
    V = verliehen / steht nicht zur Verfügung'''

    def __init__(self, number, name, neighbour):
        self.number = number
        self.name = name
        self.status = 'D'
        self.status_round_count = 0
        self.fork = 'T'
        self.right_neighbour = neighbour

        #self.print_Phil()

    def print_Phil(self):
        print(f'Nummer: {self.number}')
        print(f'Name: {self.name}')
        print(f'Status: {self.status}')
        print(f'Status Runde: {self.status_round_count}')
        print(f'Fork: {self.fork}')
        print(f'Rechter Nachbar: {self.right_neighbour}')


class PhilTable:
    '''Steuerung der Philosophen beim Essen.'''

    def __init__(self, rounds_to_eat, rounds_to_death, tables_to_play):
        self.rounds_to_eat = rounds_to_eat
        self.rounds_to_death = rounds_to_death
        self.tables_to_play = tables_to_play
        self.phil_list = [Phil(x, "Philosoph " + str(x+1), x-1) for x in range(5)]
        self.round = 0
        self.STATUS_Dic = {"D": "denkt",
                           "H": "ist hungrig",
                           "E": "am essen",
                           "T": "ist Tot"}
        self.LEFTFORKDIC = {"T": "auf dem Tisch",
                            "H": "in der Hand",
                            "V": "ist verliehen"}
        self.RIGHTFORKDIC = {"T": "auf dem Tisch",
                             "V": "in der Hand",
                             "H": "nicht verfügbar"}
        self.results_of_death = []

        # Korrektur des right_neighbour für den ersten Philosophen
        self.phil_list[0].right_neighbour = len(self.phil_list)-1
        self.table_status()
        self.get_results()
        #self.return_rounds()

    def get_results(self):
        '''Durchschnitt ermitteln wie lange alle am Leben sind'''
        for x in range(self.tables_to_play):
            self.results_of_death.append(self.return_rounds())
            self.reset_table()
        print(f'Ergebnisse: {self.results_of_death}')
        print(f'Durchschnitt: {statistics.mean(self.results_of_death)}')

    def reset_table(self):
        '''Philosophen wiederbeleben
           denkend, Gabeln auf den Tisch und Counter auf 0'''
        self.round = 0
        for phil in self.phil_list:
            phil.status = 'D'
            phil.fork = 'T'
            phil.status_round_count = 0

    def take_fork_from_right(self, phil_no):
        '''True - Gabel auf dem Tisch / verfügbar - Gabel wird entwendet
           False - Gabel nicht auf dem Tisch / nicht verfügbar'''
        ret = (self.phil_list[phil_no].fork == 'T')
        if ret is True:
            self.phil_list[phil_no].fork = 'V'
        return ret

    def take_own_fork_from_left(self, phil_no):
        '''True - Gabel auf dem Tisch / verfügbar - Gabel wird entwendet
           False - Gabel nicht auf dem Tisch / nicht verfügbar'''
        ret = (self.phil_list[phil_no].fork == 'T')
        if ret is True:
            self.phil_list[phil_no].fork = 'H'
        return ret

    def return_fork(self, phil_no):
        '''Gabel wird auf den Tisch gelegt'''
        self.phil_list[phil_no].fork = 'T'

    def set_status(self, phil_no, status):
        '''Setzt den Status
           Der Rundenzähler wird auf 0 gestellt'''
        self.phil_list[phil_no].status = status
        self.phil_list[phil_no].status_round_count = 0

    def count_up_status_round_count(self):
        '''Nach jedder Runde wird der Counter um eins erhöht'''
        for phil in self.phil_list:
            phil.status_round_count += 1

    def table_status(self):
        '''Ausgabe aller Statusinformationen in Tabellenform'''
        print(f'#### Status Runde {self.round} ###')
        status_pd = pd.DataFrame(index=['Status',
                                        'Runden im Status',
                                        'seine linke Gabel',
                                        'Nachbars Gabel (rechts)',
                                        'rechter Nachbar'])
        for phil in self.phil_list:
            new_col = [self.STATUS_Dic[str(phil.status)],
                       str(phil.status_round_count),
                       self.LEFTFORKDIC[str(phil.fork)],
                       self.RIGHTFORKDIC[self.phil_list[phil.right_neighbour].fork],
                       str(self.phil_list[phil.right_neighbour].name)]
            status_pd[str(phil.name)] = new_col
        print(status_pd)
        print(f'#### ENDE Status Runde {self.round} ###')

    def return_rounds(self):
        '''Rundensteuerung'''
        while True:
            self.round += 1
            print(f'### Round {self.round} ###')
            for phil in self.phil_list:
                if phil.status == "D":
                    if phil.status_round_count > self.rounds_to_death:
                        self.set_status(phil.number, 'T')
                        print(f'{phil.name} hat zu lange gedacht und ist dabei verhungert!!!')
                        break
                    if random.randint(0, 1) == 1:
                        self.set_status(phil.number, 'H')
                        print(f'{phil.name} bekommt jetzt Hunger.')
                    else:
                        print(f'{phil.name} denkt bis nächste Runde weiter.')
                if phil.status == "E":
                    if phil.status_round_count >= self.rounds_to_eat:
                        self.return_fork(phil.number)
                        self.return_fork(phil.right_neighbour)
                        self.set_status(phil.number, 'D')
                        print(f'{phil.name} ist mit Essen fertig!.')
                        print(f'{phil.name} legt seine linke Gabel wieder auf den Tisch.')
                        print(f'{phil.name} gibt die rechte Gabel an seinen rechten Nachbarn {self.phil_list[phil.right_neighbour].name} zurück.')
                        print(f'{phil.name} fängt das Denken wieder an.')
                    else:
                        print(f'{phil.name} isst noch eine Runde.')
                if phil.status == "H":
                    # linke Gabel
                    if self.take_own_fork_from_left(phil.number):
                        print(f'{phil.name} nimmt seine linke Gabel in die Hand.')
                    elif phil.fork == 'H':
                        print(f'{phil.name} hat hunger und seine linke Gabel in der Hand.')
                    else:
                        print(f'{phil.name} hat hunger, aber seine linke Gabel verliehen.')
                    # rechte Gabel
                    if self.take_fork_from_right(phil.right_neighbour):
                        print(f'{phil.name} ergattert die Gabel von seinem rechten Nachbarn {self.phil_list[phil.right_neighbour].name}.')
                    else:
                        print(f'{phil.name} hat hunger, aber sein rechter Nachbar {self.phil_list[phil.right_neighbour].name} braucht seine Gabel selbst.')
                    # Essen?
                    if (phil.fork == 'H') and (self.phil_list[phil.right_neighbour].fork == 'V'):
                        self.set_status(phil.number, 'E')
                        print(f'{phil.name} fängt das Essen an.')
                    else:
                        print(f'{phil.name} hungert seit {phil.status_round_count} Runden.')
                        if phil.status_round_count > self.rounds_to_death:
                            self.set_status(phil.number, 'T')
                            print(f'{phil.name} ist verhungert!!!')
                            break
            # nächste Runde vorbereiten
            self.count_up_status_round_count()
            self.table_status()
            # input('Return for next Round')
        print(f'Das Spiel endete nach {self.round} Runden!')
        return self.round


if __name__ == "__main__":
    PhilTable(2, 10, 10)

# Example:
# Ergebnisse: [1851, 666, 1614, 1298, 254, 2047, 796, 1102, 5056, 59]
# Durchschnitt: 1474.3




Kommentare:

Für diese Lösung gibt es noch keinen Kommentar

Bitte melden Sie sich an um eine Kommentar zu schreiben.
Kommentar schreiben
2097175

Du scheinst einen AdBlocker zu nutzen. Ich würde mich freuen, wenn du ihn auf dieser Seite deaktivierst und dich davon überzeugst, dass die Werbung hier nicht störend ist.