Tracks
/
Factor
Factor
/
Übungen
/
Promenadenspiele
Promenadenspiele

Promenadenspiele

Lernübung

Einführung

Spiele mit Zufall brauchen eine Quelle für Zufälligkeit. Factors Vokabular random bietet ein generisches Wort, random, das sich an das anpasst, was du ihm übergibst, dazu Hilfsmittel zum Mischen und Ziehen sowie eine Möglichkeit, Zufall für Tests reproduzierbar zu machen.

Ein Wort als inline markieren

Einige Aufgaben dieser Übung definieren ein Wort, das eine Quotation (einen [ … ]-Block) als Argument nimmt und ausführt. Dazu hat Factor eine feste Regel: ein Wort, das eine als Argument erhaltene Quotation callt, muss als inline deklariert werden, geschrieben, indem du inline direkt nach dem abschließenden ; setzt.

inline weist den Compiler an, den Rumpf des Wortes an jeder Aufrufstelle einzufügen, statt ihn einmal separat zu kompilieren.

  • Die Quotation des Aufrufers wird direkt eingefügt, sodass alles, was die Quotation auf dem Stack hinterlässt, zum Aufrufer zurückfließt, obwohl der Stack-Effekt des Wortes selbst keine Ausgabewerte deklariert.

Hier ist ein kleines Wort, das 10 auf den Stack legt und dann die ihm übergebene Quotation ausführt:

USING: kernel math prettyprint ;

: with-ten ( quot -- ) 10 swap call ; inline

Sein Stack-Effekt, ( quot -- ), nennt keine Ausgabewerte, und doch liefert ein Aufruf mit zwei Quotationen mit unterschiedlichen Effekten verschiedene Ergebnisse, die alle zum Aufrufer zurückfließen:

[ 1 + ] with-ten .        ! => 11   (quotation ( n -- n ): one value back)
[ dup 2 * ] with-ten . .  ! => 20
                          ! => 10   (quotation ( n -- n n ): two values back)

random – ein Element

random (in random) ist generisch bezüglich seines Arguments:

random ( obj -- elt )
  • Bei einer Ganzzahl n gibt es eine zufällige Ganzzahl in [0, n) zurück:
USING: random ;

6 random .    ! 4   (a value from 0 to 5)
  • Bei einer Sequenz gibt es ein zufälliges Element zurück:
{ "rock" "paper" "scissors" } random .    ! "paper"

Um einen normalen Würfel zu werfen, verschiebst du den Bereich um eins nach oben: random von 6 ergibt 0 bis 5, also ergibt 6 random 1 + 1 bis 6.

Mehrere Werte ziehen

Um eine feste Anzahl zufälliger Ziehungen zu sammeln, wiederhole eine Quotation mit replicate (in sequences):

replicate ( n quot -- seq )
USING: random sequences ;

3 [ 6 random 1 + ] replicate .    ! { 4 1 6 }   (three dice)

randomize – in-place mischen

randomize (in random) gibt die Sequenz mit ihren Elementen in zufälliger Reihenfolge zurück:

randomize ( seq -- randomized )
{ 1 2 3 4 5 } randomize .    ! { 3 1 5 2 4 }

Es mischt in-place und gibt dieselbe Sequenz zurück. Wenn du die ursprüngliche Reihenfolge behalten willst, rufe also zuerst clone auf.

sample – mehrere verschiedene Elemente

sample (in random) zieht n verschiedene Elemente aus einer Sequenz, wie beim Austeilen einer Hand Karten, nie dieselbe Karte zweimal:

sample ( seq n -- seq' )
{ 10 20 30 40 50 } 3 sample .    ! { 40 10 30 }

Mehr Elemente zu verlangen, als die Sequenz enthält, ist ein Fehler.

Reproduzierbare Zufälligkeit

Standardmäßig zieht random aus einem globalen Generator, der mit der Systemuhr initialisiert wird, sodass jeder Durchlauf anders ausfällt. Für Tests, oder wann immer du ein Spiel haben möchtest, das du nachspielen kannst, bindest du einen Generator mit einem festen Seed.

<mersenne-twister> (in random.mersenne-twister) baut einen Generator aus einem ganzzahligen Seed, und with-random (in random) führt eine Quotation aus, während dieser Generator installiert ist:

<mersenne-twister> ( seed -- rnd )
with-random        ( rnd quot -- )
USING: random random.mersenne-twister ;

42 <mersenne-twister> [ 6 random 1 + ] with-random .
! always the same value for seed 42

Alles innerhalb der Quotation – random, randomize, sample – zieht aus dem mit Seed versehenen Generator, sodass derselbe Seed immer dasselbe Ergebnis reproduziert.

Ein Wort, das eine Quotation als Argument nimmt und sie durch with-random laufen lässt, fällt unter die Regel aus Ein Wort als inline markieren: with-random callt diese Quotation am Ende, also muss ein solcher Wrapper als inline markiert werden.

Anleitung

Du betreibst die Glücksspiele in der Spielhalle auf dem Boardwalk am Meer. Die Spieler würfeln, der Greifautomat zieht einen Preis, und am Kartentisch muss das Deck gemischt und müssen die Hände ausgeteilt werden. Alles angetrieben vom Zufall. Am Ende des Abends möchtest du außerdem eine „Replay“-Funktion, damit ein umstrittenes Spiel mit demselben Seed noch einmal ablaufen kann.

1. Würfle einen Würfel

Definiere roll-die, sodass es die Anzahl der Seiten entgegennimmt und einen Wurf im Bereich 1 bis sides (einschließlich) zurückgibt.

6 roll-die .
! => 4   (some value from 1..6)

2. Schnapp dir einen Preis

Definiere pick-prize, sodass es eine Sequenz von Preisen entgegennimmt und zufällig einen davon zurückgibt.

{ "teddy" "goldfish" "keyring" } pick-prize .
! => "goldfish"

3. Mische das Deck

Definiere shuffle-deck, sodass es ein Deck (eine Sequenz) entgegennimmt und es mit den Karten in zufälliger Reihenfolge zurückgibt.

{ 1 2 3 4 5 } shuffle-deck .
! => { 3 1 5 2 4 }

4. Teile eine Hand aus

Definiere deal-hand, sodass es ein Deck und eine Anzahl n entgegennimmt und n verschiedene Karten aus dem Deck zurückgibt.

{ 10 20 30 40 50 } 3 deal-hand .
! => { 40 10 30 }

5. Mit einem Seed erneut abspielen

Definiere play-seeded, sodass es einen Seed und eine Quotation entgegennimmt und die Quotation mit einem Generator ausführt, der mit dieser Ganzzahl als Seed initialisiert wird. So liefert derselbe Seed immer dasselbe Ergebnis. Das Ergebnis der Quotation soll an den Aufrufer zurückgegeben werden.

42 [ 6 roll-die ] play-seeded .
! => the same value every time for seed 42

! Same seed, same game:
99 [ 5 deal-hand ] play-seeded   99 [ 5 deal-hand ] play-seeded   =  .
! => t
Über GitHub bearbeiten Der Link öffnet sich in einem neuen Fenster oder Tab
Factor Exercism

Bereit, mit Promenadenspiele zu starten?

Melde dich bei Exercism an, um Factor mit 47 Konzepte163 Übungen und echtem menschlichen Mentoring zu lernen und zu meistern, alles kostenlos.