Wie mache ich illegales Verhalten unausführbar?
Zusammenfassung:
Seit ich meine Reise begonnen habe, um F # zu lernen, lerne ich über typgetriebenes Design und eigenschaftsbasiertes Testen. Als Ergebnis verliebte ich mich in die Idee, illegale Staaten nicht darstellbar zu machen.
Aber was ich wirklich gerne tun würde, ist illegales Verhalten nicht ausführbar zu machen.
Ich lerne F #, indem ich ein BlackJack-Spiel schreibe. Als Ergebnis möchte ich sicherstellen, dass, wenn ein Dealer Karten verteilt, der Dealer nur eine "anfängliche Hand" oder einen "Treffer" ausführen kann. Alle anderen Kartenverteilungen sind illegal.
In C # würde ich das Strategie-Muster implementieren und somit einen DealHandCommand und einen DealHitCommand erstellen. Dann würde ich einen konstanten Integer-Wert für die Anzahl der auszugebenden Karten festschreiben (pro Strategie).
DealHandCommand = 2 Karten
DealHitCommand = 1 Karte
Basierend auf diesen Strategien würde ich dann eine Zustandsmaschine implementieren, um eine Sitzung eines BlackJack-Spiels darzustellen. Nachdem ich die erste Hand behandelt habe (d. H. DealHandCommand), führe ich einen Zustandsübergang durch, bei dem zukünftige Deals nur den "DealHitCommand" ausführen können.
Ist es insbesondere sinnvoll, eine State-Machine in einer hybriden Sprache zu implementieren, um illegales Verhalten als nicht ausführbar zu erreichen?
Es ist einfach, eine Zustandsmaschine in F # zu implementieren. Es folgt normalerweise einem dreistufigen Prozess, wobei der dritte Schritt optional ist:
In diesem Fall klingt es für mich wie zwei Zustände:
Das deutet darauf hin, dass diese Deal
diskriminierte Gewerkschaft:
Definieren Sie auch, was ein Game
ist:
Beachten Sie die Verwendung einer diskriminierten Einheit im Einzelfall; es gibt einen Grund dafür .
Definieren Sie nun eine Funktion, die von jedem Zustand in ein Game
übergeht.
Es stellt sich heraus, dass Sie von keinen Spielstatus in den Fall Hand
umwandeln können, weil ein
Im anderen Fall, wenn ein Spiel läuft, sollten Sie nur Hand
, aber nicht Hit
erlauben, also definieren Sie diesen Übergang:
Wie Sie sehen können, müssen Sie für die Funktion Hand
eine vorhandene hit
übergeben.
Was verhindert, dass ein Client einen ungültigen Game
-Wert, z.B. Game
?
Sie können den obigen Zustandsautomaten mit einer Signaturdatei verkapseln:
BlackJack.fsi:
%Vor% Hier sind die Typen [Hand; Hit; Hand; Hit; Hit]
und Deal
deklariert, aber ihre 'Konstruktoren' nicht. Dies bedeutet, dass Sie Werte dieser Typen nicht direkt erstellen können. Dies wird zum Beispiel nicht kompiliert:
Der angegebene Fehler ist:
Fehler FS0039: Der Wert, Konstruktor, Namespace oder Typ 'Spiel' ist nicht definiert
Die einzige Möglichkeit, einen Wert für Game
zu erstellen, besteht darin, eine Funktion aufzurufen, die sie für Sie erstellt:
Dies ermöglicht Ihnen auch, das Spiel fortzusetzen:
%Vor% Sie haben vielleicht bemerkt, dass die obige Signaturdatei auch zwei Funktionen definiert, um die Karten aus den Werten Game
und Game
zu entfernen. Hier sind die Implementierungen:
Ein Client kann sie folgendermaßen verwenden:
%Vor%Beachten Sie, dass dieser Ansatz hauptsächlich strukturell ist; Es gibt wenige bewegliche Teile.
Dies sind die oben verwendeten Dateien:
Cards.fs:
%Vor%BlackJack.fsi:
%Vor%BlackJack.fs:
%Vor%Client.fs:
%Vor%Ein Treffer ist eine weitere Karte richtig?
Wenn ja, dann verwenden Sie einfach zwei Typen :
type HandDealt = Dealt of Card * Card
type Playing = Playing of Cards
Dann haben Sie anstelle von Befehlen einfache Funktionen:
dealHand :: Card * Card -> HandDealt
start :: HandDealt -> Playing
dealAnother :: Playing -> Card -> Playing
Auf diese Weise können Sie nur einem bestimmten Verhalten folgen und es wird statisch überprüft.
natürlich möchten Sie diese Typen auf mehrere Spieler erweitern, aber ich denke, Sie bekommen, was ich
gehe PS: Vielleicht möchtest du sogar die Phase HandDealt
/ start
überspringen (wenn du die mittlere Phase für Dinge wie Wetten / Splitten / etc. nicht brauchst) - aber bitte bedenke, dass ich keine Ahnung von Blackjack habe ):
dealHand :: Card * Card -> Playing
dealAnother :: Playing -> Card -> Playing
es liegt an dir
Tags und Links f# functional-programming state-machines