image: teaser.webp image_alt: "Das Telefon im Browser während eines Anrufs bei der Höhle: links ein Telefon mit Display, Tastenfeld und rotem Hörer zum Auflegen; rechts das Gespräch, die Sätze des Spiels in Blasen, die gedrückten Tasten 1 und 2 als kleine Tasten, und der nächste Satz erscheint gerade Wort für Wort" kind: projekt language: Ruby / Python / JavaScript languages: [ruby, python, javascript] duration: 3 Doppelstunden curriculum: "Sek I: Algorithmisches Problemlösen (algorithmische Grundstrukturen: Verzweigung, Prozeduren); Oberstufe: Algorithmen und Softwareentwicklung (Sequenz, Auswahl)" topics: [grundstrukturen, unterprogramme] age: Sek I requires: [kata-decisions] reference: [telefonspiel, ruby-python, terminal]

Ein Spiel am Telefon

Du programmierst ein Spiel, das man anrufen kann: Es spricht mit einer echten Stimme, spielt Musik und hört auf die Tasten des Telefons. Erst begrüßt dich dein Programm, dann stellt es eine Frage, und am Ende führt es durch eine Höhle, in der es flüstert, still wird und Musik spielt, wenn man den Schatz findet. Zum Schluss schreibst du deine eigene Geschichte: Jemand aus deiner Klasse spielt sie durch, und im Telefonbuch kann sie jeder anrufen.

1. Der erste Anruf

Ein Telefon im Workspace

»Drücken Sie die 1 für den Kundendienst, die 2 für …«: So ein Telefon, das spricht und auf Tasten hört, ist ein Programm. Es sagt etwas, wartet auf eine Taste und macht je nach Taste anders weiter. Genau so ein Programm schreibst du. Wer anruft, sieht nichts davon: Alles, was dein Spiel zu bieten hat, ist zu hören.

Im Workspace probierst du dein Spiel mit dem Befehl telefon aus. Er startet dein Programm und zeigt dir im Browser ein Telefon mit Tastenfeld. Daneben steht, was das Spiel sagt, Wort für Wort, während du es hörst.

Fertige Spiele kommen ins Telefonbuch. Dort ruft man sie im Browser an, auch ohne Workspace: die Nummer eintippen und auf den grünen Hörer drücken. Steht dort schon ein Spiel, ruf es an, bevor du anfängst, und hör genau hin: Was davon könntest du selbst programmieren?

Eine echte Telefonnummer gibt es noch nicht. Wir arbeiten daran, dass man die Spiele auch mit einem Telefon anrufen kann.

Lege im Terminal (StrgJ) einen Ordner an und öffne ihn mit StrgK StrgO:

mkdir /workspace/telefon

Lege darin die Datei hallo.rb an:

require 'telefon'

say 'Hallo! Hier spricht dein erstes Telefonspiel.'

require 'telefon' lädt die Befehle des Telefons, und say sagt einen Text. Ruby wartet, bis der Satz gesprochen ist, und macht erst dann mit der nächsten Zeile weiter.

Lege darin die Datei hallo.py an:

from telefon import say

say('Hallo! Hier spricht dein erstes Telefonspiel.')

Die erste Zeile holt den Befehl say aus der Bibliothek des Telefons, und say sagt einen Text. Python wartet, bis der Satz gesprochen ist, und macht erst dann mit der nächsten Zeile weiter.

Lege darin die Datei hallo.js an:

const { say } = require('telefon');

say('Hallo! Hier spricht dein erstes Telefonspiel.');

Die erste Zeile holt den Befehl say aus der Bibliothek des Telefons, und say sagt einen Text. JavaScript wartet, bis der Satz gesprochen ist, und macht erst dann mit der nächsten Zeile weiter.

Anrufen

Starte das Telefon im Terminal, im Ordner telefon:

telefon hallo.rb
telefon hallo.py
telefon hallo.js

Das Terminal nennt eine Adresse; sie steht auch im Reiter »Ports« neben »Terminal«, bei Port 8040. Öffne sie im Browser und klick auf den grünen Hörer. Jetzt startet dein Programm, und du hörst seine Stimme: Es spricht Thorsten. Im Terminal steht jeder Satz in dem Moment, in dem er gesprochen wird.

Nach der letzten Zeile ist das Programm zu Ende, und damit auch der Anruf. Ein Klick auf den Hörer ruft noch einmal an: Das Programm startet dann von vorn. Hast du die Datei geändert, hörst du beim nächsten Anruf die neue Fassung; telefon selbst musst du dafür nicht neu starten. Beenden kannst du es im Terminal mit StrgC.

Aufgabe 1Hallo

Dein erstes Telefonspiel in telefon/hallo.rb sagt etwas, wenn man anruft.

Aufgabe 1Hallo

Dein erstes Telefonspiel in telefon/hallo.py sagt etwas, wenn man anruft.

Aufgabe 1Hallo

Dein erstes Telefonspiel in telefon/hallo.js sagt etwas, wenn man anruft.

Ausprobieren: Schreib unter den ersten Satz einen zweiten mit say und ruf noch einmal an. Achte darauf, wann der zweite Satz beginnt: Steht er schon da, während der erste noch gesprochen wird?
Thorsten Müller 2025: ein Mann mit Glatze und schmaler Brille in einem dunkelblauen Polohemd, der vor einer grauen Wand in die Kamera lächelt.

Thorsten Müller aus dem Wetteraukreis bei Frankfurt am Main wollte einen Sprachassistenten bauen, der ohne Cloud auskommt: Ihm war nicht wohl bei dem Gedanken, dass ein Mikrofon zu Hause Sprachaufnahmen an fremde Server schickt. Eine freie deutsche Stimme dafür gab es nicht. Also nahm er ab 2019 abends und an Wochenenden Satz für Satz seine eigene Stimme auf, zusammen mit Dominik Kreutz, der die Aufnahmen bearbeitete. Über die Jahre wurden es mehr als 30 000 Aufnahmen, zusammen über 40 Stunden.

Er hat seine Stimme verschenkt: Die Aufnahmen stehen unter CC0, alle dürfen damit eine Stimme trainieren. Aus ihnen ist die Stimme gemacht, die in deinem Telefonspiel spricht, auch die Stimmungen: Dafür hat er 300 Sätze in jeder Stimmung aufgenommen.

Foto: Thorsten Müller, 2025, CC BY 4.0, zugeschnitten (Wikimedia Commons)

2. Musik und Pausen

Musik im Hintergrund

Ein Spiel am Telefon lebt von dem, was man hört. Mit music spielt dein Programm Musik, und mit einer Pause davor hört man sie erst eine Weile allein, bevor die Stimme einsetzt:

require 'telefon'music 'https://www.youtube.com/watch?v=-xRD8VmjBQM'sleep 3say 'Hallo! Hier spricht dein erstes Telefonspiel.'
from telefon import music, say, sleepmusic('https://www.youtube.com/watch?v=-xRD8VmjBQM')sleep(3)say('Hallo! Hier spricht dein erstes Telefonspiel.')

In der ersten Zeile stehen jetzt auch music und sleep, die anderen beiden Befehle, die dein Programm aus der Bibliothek braucht.

const { music, say, sleep } = require('telefon');music('https://www.youtube.com/watch?v=-xRD8VmjBQM');sleep(3);say('Hallo! Hier spricht dein erstes Telefonspiel.');

In der ersten Zeile stehen jetzt auch music und sleep, die anderen beiden Befehle, die dein Programm aus der Bibliothek braucht.

Von einem Video nimmt das Telefon nur den Ton, und es spielt ihn in einer Schleife, bis dein Programm zu Ende ist. music wartet, bis die Musik läuft. Das Video holt telefon schon, sobald es gestartet ist, und es bereitet auch die Sätze deines Spiels vor; im Terminal steht, wann beides bereit ist. Rufst du gleich nach dem Start an, dauert der erste Anruf darum etwas länger. Statt eines Links nimmt music auch eine Datei; dazu gleich mehr.

Brauchst du nur eine Stelle aus einem längeren Video, sag, wo sie anfängt und wo sie aufhört: music '…', start: '1:15', stop: '1:52' spielt die Musik von Minute 1:15 bis 1:52 und dann wieder ab 1:15. Ohne stop geht es ab start weiter. Kopierst du bei YouTube mit »Teilen« einen Link ab einer Stelle, endet er auf t=75; auch dann beginnt die Musik dort.

Brauchst du nur eine Stelle aus einem längeren Video, sag, wo sie anfängt und wo sie aufhört: music('…', start='1:15', stop='1:52') spielt die Musik von Minute 1:15 bis 1:52 und dann wieder ab 1:15. Ohne stop geht es ab start weiter. Kopierst du bei YouTube mit »Teilen« einen Link ab einer Stelle, endet er auf t=75; auch dann beginnt die Musik dort.

Brauchst du nur eine Stelle aus einem längeren Video, sag, wo sie anfängt und wo sie aufhört: music('…', { start: '1:15', stop: '1:52' }) spielt die Musik von Minute 1:15 bis 1:52 und dann wieder ab 1:15. Ohne stop geht es ab start weiter. Kopierst du bei YouTube mit »Teilen« einen Link ab einer Stelle, endet er auf t=75; auch dann beginnt die Musik dort.

sleep wartet, so viele Sekunden, wie du angibst. Die Musik spielt dabei weiter.

Aufgabe 2Musik

telefon/hallo.rb spielt Musik und sagt danach etwas.

Tipp

Die Zeile mit music steht vor dem say, mit einem Link oder dem Namen einer Datei in Anführungszeichen.

Aufgabe 2Musik

telefon/hallo.py spielt Musik und sagt danach etwas.

Tipp

Die Zeile mit music('…') steht vor dem say, und in der ersten Zeile holt from telefon import auch music.

Aufgabe 2Musik

telefon/hallo.js spielt Musik und sagt danach etwas.

Tipp

Die Zeile mit music('…'); steht vor dem say, und in der ersten Zeile holt require('telefon') auch music.

Leiser, wenn jemand spricht

Hör genau hin, wenn die Stimme einsetzt: Die Musik wird leiser, solange ein Satz gesprochen wird, und danach wieder laut. So macht es auch das Radio, wenn jemand über die Musik spricht. Dein Programm muss dafür nichts tun.

Ausprobieren: Gib der Musik eine Lautstärke zwischen 0 und 1, in Ruby mit music '…', volume: 0.3, in Python und JavaScript mit music('…', 0.3). Ohne Angabe spielt sie mit 1, so laut wie möglich. Achte darauf, ob du die Stimme bei 1 noch gut verstehst.

Musik aus einer Datei

Statt eines Links nimmt music auch eine Datei. Sie muss direkt im Ordner telefon liegen, neben deinem Spiel; dann schreibst du nur ihren Namen. Ein Stück für die Höhle, das wir selbst gemacht haben, holst du im Terminal in deinen Ordner:

wget https://workspace.hackschule.de/telefonspiel/hoehle.mp3
Ausprobieren: Ersetze in hallo.rb den Link durch den Namen der Datei, music 'hoehle.mp3', und ruf an. Achte darauf, ob die Musik nach dem Satz weiterläuft und ob du hörst, wo sie wieder von vorn beginnt.
Ausprobieren: Ersetze in hallo.py den Link durch den Namen der Datei, music('hoehle.mp3'), und ruf an. Achte darauf, ob die Musik nach dem Satz weiterläuft und ob du hörst, wo sie wieder von vorn beginnt.
Ausprobieren: Ersetze in hallo.js den Link durch den Namen der Datei, music('hoehle.mp3');, und ruf an. Achte darauf, ob die Musik nach dem Satz weiterläuft und ob du hörst, wo sie wieder von vorn beginnt.

Eigene Musik oder ein Geräusch ziehst du aus dem Dateimanager deines Computers in VS Code auf den Ordner telefon. Das Telefon spielt vier Formate, an der Endung der Datei zu erkennen:

Format Endung
MP3 .mp3 klein, und jeder Browser spielt es: Nimm MP3, wenn du die Wahl hast.
WAV .wav jeder Browser spielt es, aber die Datei ist groß; warum, steht im nächsten Abschnitt.
Ogg .ogg klein; das Telefon spielt es, im Workspace nicht jeder Browser.
M4A .m4a so speichern viele Handys Aufnahmen; das Telefon spielt es, im Workspace nicht jeder Browser.

Eine Datei in einem anderen Format oder in einem Unterordner nimmt music nicht an: Sie käme beim Veröffentlichen nicht mit ins Telefonbuch. Dorthin kommt auch nur, was höchstens 20 MB groß ist, alle Dateien zusammen höchstens 40 MB. Hörst du im Workspace nichts, öffne die Datei in Audacity und exportiere sie als MP3. Dieselben Regeln gelten für eigene Aufnahmen, die mit play statt Thorsten sprechen.

Wie aus Ton Zahlen werden

Ton ist schwingende Luft: Der Luftdruck steigt und fällt, viele Male in der Sekunde, und dein Trommelfell schwingt mit. Ein Mikrofon macht daraus eine elektrische Spannung, die genauso steigt und fällt. Der Computer misst diese Spannung in gleichen Abständen und speichert jede Messung als Zahl. Das heißt Abtasten, auf Englisch Sampling; jede Messung ist ein Sample, und wie oft in der Sekunde gemessen wird, ist die Abtastrate (Sample Rate), angegeben in Hertz (Hz).

Zwei Bilder derselben grauen Welle über einer Zeitachse: eine langsame Schwingung, auf der eine schnelle, kleine sitzt. Oben, »Oft gemessen: 48 Messungen«: blaue Punkte auf senkrechten Strichen, durch eine blaue Linie verbunden, die der Welle mit allen kleinen Zacken folgt. Unten, »Selten gemessen: 12 Messungen«: nur wenige Punkte, und die blaue Linie zwischen ihnen zeigt die langsame Schwingung, die kleinen Wellen dazwischen fehlen.

Was zwischen zwei Messungen geschieht, weiß der Computer nicht. Eine Schwingung bleibt nur erhalten, wenn er sie mehr als zweimal pro Schwingung misst: Mit 8.000 Messungen in der Sekunde kommen Töne bis 4.000 Hz an, alles Höhere fehlt. Der tiefe Ton der Höhlenmusik schwingt 55-mal in der Sekunde, also mit 55 Hz; das Zischen eines »s« liegt zum großen Teil über 4.000 Hz.

Ausprobieren: Thorsten sagt in allen fünf denselben Satz über der Höhlenmusik: »Sieben Fledermäuse schlafen still an der feuchten Felswand.« Hör sie nacheinander an und achte auf das »s« in »still«, das »f« in »Felswand« und auf das helle Glöckchen am Ende. Ab welcher Abtastrate kannst du »s« und »f« nicht mehr auseinanderhalten?

Das Telefonspiel rechnet mit 16.000 Messungen in der Sekunde, so kommen Thorsten und die Musik beim Telefon an. Das alte Telefonnetz übertrug nur 8.000; am Telefon buchstabiert man darum mit Wörtern, »S wie Samuel«, weil »s« und »f« dort ähnlich klingen. Eine CD misst 44.100-mal in der Sekunde, etwas mehr als doppelt so oft wie die höchsten Töne, die Menschen hören, um 20.000 Hz.

Jede Messung ist eine Zahl, auf einer CD 2 Byte groß, und eine WAV-Datei speichert jede einzeln: In einer Sekunde Ton mit 44.100 Hz stecken 88.200 Byte, für zwei Lautsprecher doppelt so viel. hoehle.mp3 dauert 48 Sekunden und ist 0,6 MB groß; als WAV wären es 4,2 MB. MP3 lässt weg, was man kaum hört, und speichert den Rest geschickter.

Schwarzweißporträt von Claude Shannon als junger Mann in Anzug und Krawatte.

Claude Shannon (1916–2001). Wie viele Bits eine Nachricht mindestens braucht, rechnete er 1948 aus und gründete damit die Informationstheorie; das Wort Bit machte er bekannt. Er fuhr Einrad, jonglierte und baute die Maus Theseus, die selbst lernte, durch ein Labyrinth zu finden.

Schon als Student am MIT zeigte er 1937 in seiner Masterarbeit, dass sich Schaltungen aus Relais mit der Algebra von George Boole beschreiben und vereinfachen lassen, mit 1 und 0 für einen Kontakt, der geschlossen oder offen ist. Damit begann die Theorie der digitalen Schaltungen.

Einen Code mit so wenigen Bits wie möglich suchten er und Robert Fano fast gleichzeitig, jeder für sich. Der Shannon-Fano-Code kam nah heran, aber nicht immer ganz.

In derselben Arbeit von 1948 ließ er englische Texte Wort für Wort entstehen, jedes Wort nach dem vorigen aus einem Buch gezogen: ein winziges Sprachmodell, von Hand.

1949 bewies er einen Satz, den Nachrichtentechniker schon kannten: Schwingt ein Signal höchstens W-mal in der Sekunde, ist es ganz festgehalten, wenn man es 2W-mal in der Sekunde misst. Nach diesem Abtasttheorem richtet sich, wie oft ein Computer Ton misst.

Foto: Tekniska museet, CC BY 2.0, zugeschnitten (Wikimedia Commons)

Telefonieren über das Internet

Früher lief ein Anruf als elektrische Schwingung durch Kupferdrähte, und Vermittlungsstellen schalteten für jedes Gespräch eine Leitung von einem Telefon zum anderen durch. Fachleute nennen dieses alte Netz POTS, »plain old telephone service«. Heute geht fast jeder Anruf als Datenpakete durch das Internet, Voice over IP: Der Router zu Hause oder das Handy macht aus der Stimme Zahlen und schickt sie in kleinen Paketen los, eines alle 20 Millisekunden. In Deutschland hat die Telekom bis Ende 2020 alle ihre Anschlüsse so umgestellt, Großbritannien schaltet sein altes Netz Ende Januar 2027 ab.

So wird auch die Telefonnummer des Telefonspiels angeschlossen, an der wir arbeiten: Ein Anruf kommt über das Protokoll SIP bei einem Server an, auf dem Asterisk ihn annimmt, und Thorstens Stimme geht in Paketen zurück, 16.000 Zahlen in der Sekunde.

3. Eine Frage mit Tasten

Auf eine Taste warten

Jetzt soll dein Spiel zuhören. Lege eine neue Datei an:

frage.rb:

require 'telefon'

say 'Katzen oder Hunde? Drück 1 für Katzen, 2 für Hunde.'
key = keys(1)
if key == '1'
  say 'Miau! Katzen schlafen bis zu sechzehn Stunden am Tag.'
elsif key == '2'
  say 'Wuff! Hunde hören Töne, die für dich zu hoch sind.'
else
  say 'Du hast nichts gedrückt. Schade!'
end

frage.py:

from telefon import keys, say

say('Katzen oder Hunde? Drück 1 für Katzen, 2 für Hunde.')
key = keys(1)
if key == '1':
    say('Miau! Katzen schlafen bis zu sechzehn Stunden am Tag.')
elif key == '2':
    say('Wuff! Hunde hören Töne, die für dich zu hoch sind.')
else:
    say('Du hast nichts gedrückt. Schade!')

frage.js:

const { keys, say } = require('telefon');

say('Katzen oder Hunde? Drück 1 für Katzen, 2 für Hunde.');
const key = keys(1);
if (key === '1') {
  say('Miau! Katzen schlafen bis zu sechzehn Stunden am Tag.');
} else if (key === '2') {
  say('Wuff! Hunde hören Töne, die für dich zu hoch sind.');
} else {
  say('Du hast nichts gedrückt. Schade!');
}

keys(1) wartet auf eine Taste und gibt sie zurück, als Text: '1', wenn jemand die 1 drückt. Drückt zehn Sekunden lang niemand etwas, gibt keys einen leeren Text zurück, ''. Danach entscheidet die Verzweigung, was das Spiel sagt. Starte das Telefon mit der neuen Datei und probier alle drei Wege aus: die 1, die 2 und gar keine Taste.

Eine Taste, die jemand drückt, während das Spiel noch spricht, geht nicht verloren: Sie wartet, bis dein Programm keys aufruft. Wer die Frage schon kennt, muss sie also nicht bis zum Ende anhören.

Text oder Zahl?

Auf dem Telefon steht eine 1, und keys gibt '1' zurück, mit Anführungszeichen. Ist das nicht dasselbe?

Vermutung 3Text oder Zahl?

Jemand ändert in frage.rb die Zeile if key == '1' in if key == 1, ohne Anführungszeichen. Was sagt das Spiel, wenn man die 1 drückt?

Text oder Zahl?
Vermutung 3Text oder Zahl?

Jemand ändert in frage.py die Zeile if key == '1': in if key == 1:, ohne Anführungszeichen. Was sagt das Spiel, wenn man die 1 drückt?

Text oder Zahl?
Vermutung 3Text oder Zahl?

Jemand ändert in frage.js die Zeile if (key === '1') { in if (key === 1) {, ohne Anführungszeichen. Was sagt das Spiel, wenn man die 1 drückt?

Text oder Zahl?

Hier geht es weiter, sobald du deine Antwort oben abgegeben hast.

Das Spiel sagt »Du hast nichts gedrückt. Schade!« Denn keys gibt einen Text zurück, auch wenn er nur aus einer Ziffer besteht, und ein Text ist nie gleich einer Zahl: '1' == 1 ist falsch.

Das Spiel sagt »Du hast nichts gedrückt. Schade!« Denn keys gibt einen Text zurück, auch wenn er nur aus einer Ziffer besteht, und ein Text ist nie gleich einer Zahl: '1' == 1 ist falsch.

Das Spiel sagt »Du hast nichts gedrückt. Schade!« Denn keys gibt einen Text zurück, auch wenn er nur aus einer Ziffer besteht, und === prüft auch, ob beides von derselben Art ist: '1' === 1 ist falsch. Mit == wäre es wahr, weil JavaScript den Text dann erst in eine Zahl verwandelt; darum vergleicht man in JavaScript mit ===.

Darum vergleicht dein Programm mit '1' in Anführungszeichen. So kann keys auch den Stern '*' zurückgeben, und mehrere Tasten auf einmal, wie '472'. Nur die Raute # gibt keys nie zurück: Sie beendet eine Eingabe aus mehreren Tasten.

Eine dritte Wahl

Jetzt bist du dran: Biete Fische als dritte Wahl an. Mit der 3 sagt das Spiel »Blubb! Fische haben keine Augenlider.« Vergiss nicht, die Frage am Anfang so zu ändern, dass sie die 3 auch nennt.
Tipp

Jede Antwort ist ein eigener Zweig der Verzweigung. Für die 3 kommt ein weiterer dazu, vor dem Zweig für »nichts gedrückt«: Der fängt alles auf, was die Zweige davor nicht erkannt haben.

Nächster Tipp

Ein neuer Zweig zwischen dem für die 2 und else:

elsif key == '…'
  say '…'

Ein neuer Zweig zwischen dem für die 2 und else::

elif key == '…':
    say('…')

Ein neuer Zweig zwischen dem für die 2 und else:

} else if (key === '…') {
  say('…');
Lösung anzeigen
require 'telefon'say 'Katzen, Hunde oder Fische? Drück 1 für Katzen, 2 für Hunde, 3 für Fische.'key = keys(1)…elsif key == '2'  say 'Wuff! Hunde hören Töne, die für dich zu hoch sind.'elsif key == '3'  say 'Blubb! Fische haben keine Augenlider.'else
from telefon import keys, saysay('Katzen, Hunde oder Fische? Drück 1 für Katzen, 2 für Hunde, 3 für Fische.')key = keys(1)…elif key == '2':    say('Wuff! Hunde hören Töne, die für dich zu hoch sind.')elif key == '3':    say('Blubb! Fische haben keine Augenlider.')else:
const { keys, say } = require('telefon');say('Katzen, Hunde oder Fische? Drück 1 für Katzen, 2 für Hunde, 3 für Fische.');const key = keys(1);…} else if (key === '2') {  say('Wuff! Hunde hören Töne, die für dich zu hoch sind.');} else if (key === '3') {  say('Blubb! Fische haben keine Augenlider.');} else {
Aufgabe 4Eine dritte Wahl

telefon/frage.rb bietet Fische als dritte Wahl an: Die Frage nennt sie, und mit der 3 sagt das Spiel »Blubb! …«. Die anderen Antworten bleiben, wie sie sind.

Aufgabe 4Eine dritte Wahl

telefon/frage.py bietet Fische als dritte Wahl an: Die Frage nennt sie, und mit der 3 sagt das Spiel »Blubb! …«. Die anderen Antworten bleiben, wie sie sind.

Aufgabe 4Eine dritte Wahl

telefon/frage.js bietet Fische als dritte Wahl an: Die Frage nennt sie, und mit der 3 sagt das Spiel »Blubb! …«. Die anderen Antworten bleiben, wie sie sind.

Wie lange gewartet wird

Zehn Sekunden sind lang, wenn man schon weiß, was man drücken will, und kurz für eine schwere Frage. Wie lange keys wartet, sagst du in Sekunden:

keys(1, timeout: 5) wartet nur fünf Sekunden.

keys(1, timeout=5) wartet nur fünf Sekunden.

keys(1, 5) wartet nur fünf Sekunden.

Und mit keys(3) wartet dein Programm auf bis zu drei Tasten, etwa für eine Geheimzahl; die Raute # beendet die Eingabe früher. Die Wartezeit gilt für jede Taste neu: Nach jeder Taste hat man wieder die ganze Zeit für die nächste.

Ausprobieren: Gib der Frage zwei Sekunden und ruf an. Achte darauf, ob du es schaffst, nach dem Ende der Frage noch zu drücken, und was passiert, wenn du schon während der Frage drückst.

Wie das Telefon die Tasten hört

Drückst du am Telefon im Workspace eine Taste, hörst du einen kurzen Ton. Genau genommen sind es zwei Töne zugleich: einer für die Zeile der Taste und einer für ihre Spalte. Die Taste 5 klingt mit 770 Hz und 1.336 Hz. Daran erkannte früher die Vermittlungsstelle, welche Taste gedrückt wurde: Sie suchte in dem, was durch die Leitung kam, nach diesen sieben Frequenzen. Das Verfahren heißt Mehrfrequenzwahl, auf Englisch DTMF (Dual-Tone Multi-Frequency).

Ausprobieren: Drück »Rätsel: drei Tasten« und lies die drei Tasten im Wasserfall ab. Achte darauf, welche Frequenz der untere Strich hat und welche der obere: Der untere sagt die Zeile, der obere die Spalte.

Zwei Töne statt einem, damit eine Stimme oder ein Lied nicht aus Versehen eine Taste drückt: Dass genau zwei dieser Frequenzen zugleich und allein klingen, kommt in Sprache und Musik selten vor. Bei Telefonie über das Internet geht eine Taste heute meist als eigenes kleines Paket mit, das nur sagt, welche Taste es war; die Töne hörst du im Hörer trotzdem.

4. Eine Höhle aus Szenen

Vor der Höhle

Ein Abenteuer besteht aus Szenen: Jede sagt, wo man gerade ist, und welche Taste wohin führt. Auf einer Karte sind die Szenen Kästen und die Tasten Pfeile. Diese Höhle hat erst einmal drei Szenen: davor, nach Hause und den Schatz.

Die Karte der ersten Höhle: ein Kasten »vor der Höhle«, von dem ein Pfeil mit der 1 nach rechts zum blau umrandeten Kasten »Schatz« führt und ein Pfeil mit der 2 nach unten zum Kasten »nach Hause«. Ein Pfeil mit »Start« zeigt auf »vor der Höhle«, dort beginnt das Spiel. Die Karte der ersten Höhle: ein Kasten »vor der Höhle«, von dem ein Pfeil mit der 1 nach unten zum blau umrandeten Kasten »Schatz« führt und ein Pfeil mit der 2 nach rechts zum Kasten »nach Hause«. Ein Pfeil mit »Start« zeigt auf »vor der Höhle«, dort beginnt das Spiel.

Vor der Höhle wartet eine Frage wie die nach Katzen und Hunden. Lege hoehle an:

hoehle.rb:

require 'telefon'

music 'https://www.youtube.com/watch?v=-xRD8VmjBQM'
sleep 3
say 'Du stehst vor einer dunklen Höhle. Drück 1, um hineinzugehen, oder 2, um nach Hause zu gehen.'
key = keys(1)
if key == '1'
  say 'Im Licht einer Fackel glänzt eine Kiste voller Gold. Du hast den Schatz gefunden!'
elsif key == '2'
  say 'Du gehst nach Hause. Vielleicht ein anderes Mal.'
end
say 'Ende.'

hoehle.py:

from telefon import keys, music, say, sleep

music('https://www.youtube.com/watch?v=-xRD8VmjBQM')
sleep(3)
say('Du stehst vor einer dunklen Höhle. Drück 1, um hineinzugehen, oder 2, um nach Hause zu gehen.')
key = keys(1)
if key == '1':
    say('Im Licht einer Fackel glänzt eine Kiste voller Gold. Du hast den Schatz gefunden!')
elif key == '2':
    say('Du gehst nach Hause. Vielleicht ein anderes Mal.')
say('Ende.')

hoehle.js:

const { keys, music, say, sleep } = require('telefon');

music('https://www.youtube.com/watch?v=-xRD8VmjBQM');
sleep(3);
say('Du stehst vor einer dunklen Höhle. Drück 1, um hineinzugehen, oder 2, um nach Hause zu gehen.');
const key = keys(1);
if (key === '1') {
  say('Im Licht einer Fackel glänzt eine Kiste voller Gold. Du hast den Schatz gefunden!');
} else if (key === '2') {
  say('Du gehst nach Hause. Vielleicht ein anderes Mal.');
}
say('Ende.');

Erst Musik, eine Pause, dann die Frage vor der Höhle; nach der Antwort sagt das Spiel »Ende.«, und der Anruf ist vorbei. Ruf an und probier die 1 und die 2.

Szenen als Funktionen

Bald hat die Höhle mehr Szenen, und zu manchen kommt man mehr als einmal. Darum bekommt jede Szene einen Namen: Sie wird eine Funktion. Pack den Satz vom Schatz in die Funktion treasure und die Szene vor der Höhle in die Funktion cave:

require 'telefon'

def treasure
  say 'Im Licht einer Fackel glänzt eine Kiste voller Gold. Du hast den Schatz gefunden!'
end

def cave
  say 'Du stehst vor einer dunklen Höhle. Drück 1, um hineinzugehen, oder 2, um nach Hause zu gehen.'
  key = keys(1)
  if key == '1'
    treasure
  elsif key == '2'
    say 'Du gehst nach Hause. Vielleicht ein anderes Mal.'
  end
end

music 'https://www.youtube.com/watch?v=-xRD8VmjBQM'
sleep 3
cave
say 'Ende.'
from telefon import keys, music, say, sleep


def treasure():
    say('Im Licht einer Fackel glänzt eine Kiste voller Gold. Du hast den Schatz gefunden!')


def cave():
    say('Du stehst vor einer dunklen Höhle. Drück 1, um hineinzugehen, oder 2, um nach Hause zu gehen.')
    key = keys(1)
    if key == '1':
        treasure()
    elif key == '2':
        say('Du gehst nach Hause. Vielleicht ein anderes Mal.')


music('https://www.youtube.com/watch?v=-xRD8VmjBQM')
sleep(3)
cave()
say('Ende.')
const { keys, music, say, sleep } = require('telefon');

function treasure() {
  say('Im Licht einer Fackel glänzt eine Kiste voller Gold. Du hast den Schatz gefunden!');
}

function cave() {
  say('Du stehst vor einer dunklen Höhle. Drück 1, um hineinzugehen, oder 2, um nach Hause zu gehen.');
  const key = keys(1);
  if (key === '1') {
    treasure();
  } else if (key === '2') {
    say('Du gehst nach Hause. Vielleicht ein anderes Mal.');
  }
}

music('https://www.youtube.com/watch?v=-xRD8VmjBQM');
sleep(3);
cave();
say('Ende.');

Ruf an: Das Spiel klingt genau wie vorher. Die Zeilen sind dieselben, sie stehen nur an einem anderen Ort.

Von def cave bis zu seinem end steht, was zu cave gehört. Dabei sagt das Spiel noch nichts: Erst die Zeile cave weiter unten ruft die Funktion auf, und dann laufen ihre Zeilen, eine nach der anderen. Genauso ruft cave die Funktion treasure auf, wenn jemand die 1 drückt.

Was unter def cave(): eingerückt steht, gehört zu cave. Dabei sagt das Spiel noch nichts: Erst die Zeile cave() weiter unten ruft die Funktion auf, und dann laufen ihre Zeilen, eine nach der anderen. Genauso ruft cave die Funktion treasure auf, wenn jemand die 1 drückt.

Was in den geschweiften Klammern von function cave() steht, gehört zu cave. Dabei sagt das Spiel noch nichts: Erst die Zeile cave(); weiter unten ruft die Funktion auf, und dann laufen ihre Zeilen, eine nach der anderen. Genauso ruft cave die Funktion treasure auf, wenn jemand die 1 drückt.

Die Szene »nach Hause« ist so kurz, dass sie keine eigene Funktion braucht: Sie ist nur ein Satz.

Ausprobieren: Setz ein # vor die Zeile cave unten, damit sie nicht mehr läuft, und ruf an. Achte darauf, was du nach der Musik noch hörst. Nimm das # danach wieder weg.
Ausprobieren: Setz ein # vor die Zeile cave() unten, damit sie nicht mehr läuft, und ruf an. Achte darauf, was du nach der Musik noch hörst. Nimm das # danach wieder weg.
Ausprobieren: Setz // vor die Zeile cave(); unten, damit sie nicht mehr läuft, und ruf an. Achte darauf, was du nach der Musik noch hörst. Nimm die // danach wieder weg.

Wenn niemand drückt

Die Verzweigung in cave bekommt einen letzten Zweig, für alles außer der 1 und der 2:

  elsif key == '2'    say 'Du gehst nach Hause. Vielleicht ein anderes Mal.'  else    cave  endend
    elif key == '2':        say('Du gehst nach Hause. Vielleicht ein anderes Mal.')    else:        cave()
  } else if (key === '2') {    say('Du gehst nach Hause. Vielleicht ein anderes Mal.');  } else {    cave();  }}

Was passiert jetzt, wenn vor der Höhle niemand etwas drückt? Überleg es dir, bevor du anrufst.

Vermutung 5Niemand drückt

Du rufst hoehle an und drückst vor der Höhle zehn Sekunden lang gar nichts. Was passiert dann?

Niemand drückt

Hier geht es weiter, sobald du deine Antwort oben abgegeben hast.

Nach zehn Sekunden sagt das Spiel den Satz vor der Höhle noch einmal. keys gibt dann '' zurück, und im Zweig für alles andere ruft cave sich selbst auf: Die Szene beginnt von vorn. Das passt zum Telefon. Wer nicht weiß, was er drücken soll, hört die Wahl noch einmal. Dasselbe passiert bei einer Taste, die in dieser Szene nichts bedeutet, etwa der 7. Auf der Karte ist das ein Bogen zurück in denselben Kasten:

Die Karte der ersten Höhle: ein Kasten »vor der Höhle«, von dem ein Pfeil mit der 1 nach rechts zum blau umrandeten Kasten »Schatz« führt und ein Pfeil mit der 2 nach unten zum Kasten »nach Hause«. Ein Bogen mit »keine Taste« führt von »vor der Höhle« zurück in denselben Kasten. Ein Pfeil mit »Start« zeigt auf »vor der Höhle«, dort beginnt das Spiel. Die Karte der ersten Höhle: ein Kasten »vor der Höhle«, von dem ein Pfeil mit der 1 nach unten zum blau umrandeten Kasten »Schatz« führt und ein Pfeil mit der 2 nach rechts zum Kasten »nach Hause«. Ein Bogen mit »keine Taste« führt von »vor der Höhle« zurück in denselben Kasten. Ein Pfeil mit »Start« zeigt auf »vor der Höhle«, dort beginnt das Spiel.

Der Gang

Hinter dem Eingang soll sich der Weg teilen. Die 1 vor der Höhle führt dann nicht mehr direkt zum Schatz, sondern in einen Gang: Links flackert Licht, dort liegt der Schatz. Rechts rauscht Wasser, das ist eiskalt, und man muss zurück in den Gang.

Die Karte mit dem Gang: von »vor der Höhle« führt die 1 nach rechts zum Kasten »Gang« und die 2 nach unten zu »nach Hause«; vom Gang führt die 1 weiter nach rechts zum blau umrandeten »Schatz«. Über »vor der Höhle« ein Bogen »keine Taste« zurück in denselben Kasten, über »Gang« zwei Bögen zurück in den Gang: »keine Taste« und die 2 mit »eiskaltes Wasser«. Ein Pfeil mit »Start« zeigt auf »vor der Höhle«, dort beginnt das Spiel. Die Karte mit dem Gang, von oben nach unten: von »vor der Höhle« führt die 1 nach unten zum Kasten »Gang« und die 2 nach rechts zu »nach Hause«; vom Gang führt die 1 weiter nach unten zum blau umrandeten »Schatz«. Über »vor der Höhle« ein Bogen »keine Taste« zurück in denselben Kasten, über »Gang« zwei Bögen zurück in den Gang: »keine Taste« und die 2 mit »eiskaltes Wasser«. Ein Pfeil mit »Start« zeigt auf »vor der Höhle«, dort beginnt das Spiel.

Jetzt bist du dran: Schreib die Szene tunnel als Funktion zwischen treasure und cave. Sie sagt »Drinnen teilt sich der Gang. Links flackert Licht, rechts rauscht Wasser. Drück 1 für links, 2 für rechts.« Mit der 1 geht es zum Schatz. Mit der 2 sagt sie »Das Wasser ist eiskalt. Du gehst zurück.« und beginnt von vorn, ohne Taste ebenso. In cave führt die 1 jetzt in den Gang.
Tipp

Spiel es erst auf der Karte durch: vor der Höhle die 1, im Gang die 2, dann die 1. Welche Sätze hörst du nacheinander? Die Funktion tunnel sieht aus wie cave, nur mit anderen Sätzen und anderen Zielen.

Nächster Tipp

In Worten: Sag den Satz des Gangs. Warte auf eine Taste. Ist es die 1, geh zum Schatz. Ist es die 2, sag den Satz vom Wasser und geh in den Gang. Sonst geh in den Gang. »Geh in den Gang« heißt: ruf tunnel auf.

Nächster Tipp
def tunnel
  say '…'
  key = keys(1)
  if key == '1'
    …
  elsif key == '2'
    say '…'
    …
  else
    …
  end
end
def tunnel():
    say('…')
    key = keys(1)
    if key == '1':
        …
    elif key == '2':
        say('…')
        …
    else:
        …
function tunnel() {
  say('…');
  const key = keys(1);
  if (key === '1') {
    …
  } else if (key === '2') {
    say('…');
    …
  } else {
    …
  }
}
Lösung anzeigen
def tunnel
  say 'Drinnen teilt sich der Gang. Links flackert Licht, rechts rauscht Wasser. Drück 1 für links, 2 für rechts.'
  key = keys(1)
  if key == '1'
    treasure
  elsif key == '2'
    say 'Das Wasser ist eiskalt. Du gehst zurück.'
    tunnel
  else
    tunnel
  end
end

In cave führt die 1 in den Gang:

  key = keys(1)  if key == '1'    tunnel  elsif key == '2'
def tunnel():
    say('Drinnen teilt sich der Gang. Links flackert Licht, rechts rauscht Wasser. Drück 1 für links, 2 für rechts.')
    key = keys(1)
    if key == '1':
        treasure()
    elif key == '2':
        say('Das Wasser ist eiskalt. Du gehst zurück.')
        tunnel()
    else:
        tunnel()

In cave führt die 1 in den Gang:

    key = keys(1)    if key == '1':        tunnel()    elif key == '2':
function tunnel() {
  say('Drinnen teilt sich der Gang. Links flackert Licht, rechts rauscht Wasser. Drück 1 für links, 2 für rechts.');
  const key = keys(1);
  if (key === '1') {
    treasure();
  } else if (key === '2') {
    say('Das Wasser ist eiskalt. Du gehst zurück.');
    tunnel();
  } else {
    tunnel();
  }
}

In cave führt die 1 in den Gang:

  const key = keys(1);  if (key === '1') {    tunnel();  } else if (key === '2') {
Aufgabe 6Der Gang

In telefon/hoehle.rb führt die 1 vor der Höhle in den Gang. Dort führt die 1 zum Schatz, die 2 zum eiskalten Wasser und zurück in den Gang, und ohne Taste beginnt der Gang von vorn.

Aufgabe 6Der Gang

In telefon/hoehle.py führt die 1 vor der Höhle in den Gang. Dort führt die 1 zum Schatz, die 2 zum eiskalten Wasser und zurück in den Gang, und ohne Taste beginnt der Gang von vorn.

Aufgabe 6Der Gang

In telefon/hoehle.js führt die 1 vor der Höhle in den Gang. Dort führt die 1 zum Schatz, die 2 zum eiskalten Wasser und zurück in den Gang, und ohne Taste beginnt der Gang von vorn.

Stimmen in der Höhle

Thorsten muss nicht jeden Satz gleich sagen. Bekommt say eine Stimmung, flüstert er, wundert sich oder klingt müde. Wer vor der Höhle die 2 drückt, geht jetzt müde nach Hause:

  elsif key == '2'    say 'Du gehst nach Hause. Vielleicht ein anderes Mal.', mood: 'sleepy'  else
    elif key == '2':        say('Du gehst nach Hause. Vielleicht ein anderes Mal.', mood='sleepy')    else:
  } else if (key === '2') {    say('Du gehst nach Hause. Vielleicht ein anderes Mal.', { mood: 'sleepy' });  } else {

Die Stimmung steht hinter dem Text, durch ein Komma getrennt. Auf der Seite des Telefons steht sie klein über dem Satz.

Thorsten kann einen Satz in acht Stimmungen sagen; hör sie dir an, jede mit einem Satz, der zu ihr passt:

Die Sätze mit Stimmung spricht eine zweite Stimme von Thorsten, die etwas weniger klar klingt als die gewohnte. Setz Stimmungen darum sparsam ein, dort, wo sie etwas erzählen: Ein einziges Flüstern im dunklen Gang wirkt stärker als zehn.

Ausprobieren: Ruf an und drück die 2. Achte auf Tempo und Betonung des Satzes. Setz dann drunk statt sleepy ein und vergleiche beide.
Jetzt bist du dran: Im Gang ist es dunkel. Lass das Spiel den Satz im Gang flüstern. Wer das Gold findet, soll es überrascht hören.
Tipp

Es sind zwei Sätze: Der eine steht in tunnel, der andere in treasure.

Nächster Tipp

An beide kommt hinter den Text ein Komma und die Stimmung: mood: 'whisper' für das Flüstern, mood: 'surprised' für die Überraschung.

An beide kommt hinter den Text ein Komma und die Stimmung: mood='whisper' für das Flüstern, mood='surprised' für die Überraschung.

An beide kommt hinter den Text ein Komma und die Stimmung in geschweiften Klammern: { mood: 'whisper' } für das Flüstern, { mood: 'surprised' } für die Überraschung.

Lösung anzeigen
def treasure  say 'Im Licht einer Fackel glänzt eine Kiste voller Gold. Du hast den Schatz gefunden!', mood: 'surprised'enddef tunnel  say 'Drinnen teilt sich der Gang. Links flackert Licht, rechts rauscht Wasser. Drück 1 für links, 2 für rechts.', mood: 'whisper'
def treasure():    say('Im Licht einer Fackel glänzt eine Kiste voller Gold. Du hast den Schatz gefunden!', mood='surprised')def tunnel():    say('Drinnen teilt sich der Gang. Links flackert Licht, rechts rauscht Wasser. Drück 1 für links, 2 für rechts.', mood='whisper')
function treasure() {  say('Im Licht einer Fackel glänzt eine Kiste voller Gold. Du hast den Schatz gefunden!', { mood: 'surprised' });}function tunnel() {  say('Drinnen teilt sich der Gang. Links flackert Licht, rechts rauscht Wasser. Drück 1 für links, 2 für rechts.', { mood: 'whisper' });
Aufgabe 7Stimmen in der Höhle

In telefon/hoehle.rb flüstert das Spiel den Satz im Gang, und beim Gold klingt es überrascht.

Aufgabe 7Stimmen in der Höhle

In telefon/hoehle.py flüstert das Spiel den Satz im Gang, und beim Gold klingt es überrascht.

Aufgabe 7Stimmen in der Höhle

In telefon/hoehle.js flüstert das Spiel den Satz im Gang, und beim Gold klingt es überrascht.

Stille und Musik

Musik erzählt mit, und am deutlichsten, wenn sie sich ändert. Hört sie plötzlich auf, horcht man auf: Im dunklen Gang soll nur noch das Flüstern zu hören sein. music nil schaltet die Musik aus.

Musik erzählt mit, und am deutlichsten, wenn sie sich ändert. Hört sie plötzlich auf, horcht man auf: Im dunklen Gang soll nur noch das Flüstern zu hören sein. music(None) schaltet die Musik aus.

Musik erzählt mit, und am deutlichsten, wenn sie sich ändert. Hört sie plötzlich auf, horcht man auf: Im dunklen Gang soll nur noch das Flüstern zu hören sein. music(null) schaltet die Musik aus.

Ein neues music mitten im Spiel ersetzt die Musik, die gerade läuft. Wer den Schatz findet, hat Musik verdient, die nach Gewinnen klingt: »No Quarter« aus dem Spiel Thimbleweed Park, Synthie-Pop im Stil der Achtziger. Für den Schatz reicht die Stelle von 0:16 bis 0:32, und die wiederholt sich, solange sie läuft. Sechzehn Sekunden sind bei diesem Stück genau acht Takte, darum springt die Wiederholung nicht mitten aus dem Takt.

Jetzt bist du dran: Mach den Gang still: Am Anfang von tunnel hört die Musik auf. Am Anfang von treasure spielt »No Quarter« (https://www.youtube.com/watch?v=oR450XGc-j4) von 0:16 bis 0:32. Damit man die Musik nach dem Satz noch hört, wartet treasure danach acht Sekunden.
Tipp

Für jede der beiden Stellen reicht eine Zeile. Wie music nur einen Ausschnitt spielt, steht oben unter »Musik im Hintergrund«: mit start und stop.

Nächster Tipp
def treasure
  music '…', start: '…', stop: '…'
  say '…', mood: 'surprised'
  sleep …
end

def tunnel
  music …
  say '…', mood: 'whisper'
def treasure():
    music('…', start='…', stop='…')
    say('…', mood='surprised')
    sleep(…)


def tunnel():
    music(…)
    say('…', mood='whisper')
function treasure() {
  music('…', { start: '…', stop: '…' });
  say('…', { mood: 'surprised' });
  sleep(…);
}

function tunnel() {
  music(…);
  say('…', { mood: 'whisper' });
Lösung anzeigen
def treasure  music 'https://www.youtube.com/watch?v=oR450XGc-j4', start: '0:16', stop: '0:32'  say 'Im Licht einer Fackel glänzt eine Kiste voller Gold. Du hast den Schatz gefunden!', mood: 'surprised'  sleep 8enddef tunnel  music nil
def treasure():    music('https://www.youtube.com/watch?v=oR450XGc-j4', start='0:16', stop='0:32')    say('Im Licht einer Fackel glänzt eine Kiste voller Gold. Du hast den Schatz gefunden!', mood='surprised')    sleep(8)def tunnel():    music(None)
function treasure() {  music('https://www.youtube.com/watch?v=oR450XGc-j4', { start: '0:16', stop: '0:32' });  say('Im Licht einer Fackel glänzt eine Kiste voller Gold. Du hast den Schatz gefunden!', { mood: 'surprised' });  sleep(8);}function tunnel() {  music(null);
Aufgabe 8Stille und Musik

In telefon/hoehle.rb hört die Musik im Gang auf, und beim Schatz spielt »No Quarter« von 0:16 bis 0:32.

Aufgabe 8Stille und Musik

In telefon/hoehle.py hört die Musik im Gang auf, und beim Schatz spielt »No Quarter« von 0:16 bis 0:32.

Aufgabe 8Stille und Musik

In telefon/hoehle.js hört die Musik im Gang auf, und beim Schatz spielt »No Quarter« von 0:16 bis 0:32.

Ungeduld

Wer zum dritten Mal anruft, kennt den Satz vor der Höhle auswendig. Eine Taste, die man währenddessen drückt, geht zwar nicht verloren, aber den Satz muss man trotzdem bis zum Ende anhören. Mit interrupt bricht er ab, sobald jemand eine Taste drückt, und das nächste keys bekommt genau diese Taste:

def cave  say 'Du stehst vor einer dunklen Höhle. Drück 1, um hineinzugehen, oder 2, um nach Hause zu gehen.', interrupt: true
def cave():    say('Du stehst vor einer dunklen Höhle. Drück 1, um hineinzugehen, oder 2, um nach Hause zu gehen.', interrupt=True)
function cave() {  say('Du stehst vor einer dunklen Höhle. Drück 1, um hineinzugehen, oder 2, um nach Hause zu gehen.', { interrupt: true });

Das passt zu Sätzen, die man nach dem ersten Mal kennt, wie der Wahl vor der Höhle. Ein Satz mit einem Hinweis, den niemand verpassen darf, bleibt besser ohne interrupt.

Ausprobieren: Ruf an und drück schon während des Satzes vor der Höhle die 1. Achte darauf, an welcher Stelle der Satz abbricht und was danach in seiner Blase steht.

Auflegen

Bisher endet ein Anruf, wenn das Programm zu Ende ist. Manchmal soll er mittendrin enden: Wer im Gang ins Wasser springt, kommt nicht wieder. hangup legt sofort auf, egal in welcher Szene das Spiel gerade ist. Danach kommt kein Satz mehr, auch nicht das »Ende.« am Schluss des Programms, und auf dem Telefon ertönt das Besetztzeichen.

Bisher endet ein Anruf, wenn das Programm zu Ende ist. Manchmal soll er mittendrin enden: Wer im Gang ins Wasser springt, kommt nicht wieder. hangup() legt sofort auf, egal in welcher Szene das Spiel gerade ist. Danach kommt kein Satz mehr, auch nicht das »Ende.« am Schluss des Programms, und auf dem Telefon ertönt das Besetztzeichen.

Bisher endet ein Anruf, wenn das Programm zu Ende ist. Manchmal soll er mittendrin enden: Wer im Gang ins Wasser springt, kommt nicht wieder. hangup() legt sofort auf, egal in welcher Szene das Spiel gerade ist. Danach kommt kein Satz mehr, auch nicht das »Ende.« am Schluss des Programms, und auf dem Telefon ertönt das Besetztzeichen.

Jetzt bist du dran: Gib dem Gang eine dritte Wahl: Mit der 3 springt man ins Wasser. Das Spiel sagt »Du springst ins Wasser. Die Strömung reißt dich fort, hinaus in die Nacht.« und legt auf. Vergiss nicht, die 3 im Satz des Gangs zu nennen.
Tipp

Die 3 bekommt einen eigenen Zweig vor dem else, wie die Fische in der Frage nach den Tieren.

Nächster Tipp

Reicht nicht auch der Satz allein? Spiel es im Kopf durch: Nach dem Satz ist tunnel zu Ende, das Programm macht in cave weiter, dann ist auch cave zu Ende, und ganz unten sagt das Programm noch »Ende.« Erst das Auflegen beendet den Anruf sofort.

Nächster Tipp
  elsif key == '3'
    say '…'
    …
    elif key == '3':
        say('…')
        …

In der ersten Zeile holt from telefon import dann auch hangup.

  } else if (key === '3') {
    say('…');
    …

In der ersten Zeile holt require('telefon') dann auch hangup.

Lösung anzeigen
def tunnel  music nil  say 'Drinnen teilt sich der Gang. Links flackert Licht, rechts rauscht Wasser. Drück 1 für links, 2 für rechts, 3, um ins Wasser zu springen.', mood: 'whisper'  …  elsif key == '2'    say 'Das Wasser ist eiskalt. Du gehst zurück.'    tunnel  elsif key == '3'    say 'Du springst ins Wasser. Die Strömung reißt dich fort, hinaus in die Nacht.'    hangup  else
from telefon import hangup, keys, music, say, sleep…def tunnel():    music(None)    say('Drinnen teilt sich der Gang. Links flackert Licht, rechts rauscht Wasser. Drück 1 für links, 2 für rechts, 3, um ins Wasser zu springen.', mood='whisper')    …    elif key == '2':        say('Das Wasser ist eiskalt. Du gehst zurück.')        tunnel()    elif key == '3':        say('Du springst ins Wasser. Die Strömung reißt dich fort, hinaus in die Nacht.')        hangup()    else:
const { hangup, keys, music, say, sleep } = require('telefon');…function tunnel() {  music(null);  say('Drinnen teilt sich der Gang. Links flackert Licht, rechts rauscht Wasser. Drück 1 für links, 2 für rechts, 3, um ins Wasser zu springen.', { mood: 'whisper' });  …  } else if (key === '2') {    say('Das Wasser ist eiskalt. Du gehst zurück.');    tunnel();  } else if (key === '3') {    say('Du springst ins Wasser. Die Strömung reißt dich fort, hinaus in die Nacht.');    hangup();  } else {
Aufgabe 9Ein Sprung ins Wasser

In telefon/hoehle.rb nennt der Gang eine dritte Wahl. Mit der 3 springt man ins Wasser, das Spiel sagt »… Strömung …« und legt auf, ohne danach noch »Ende.« zu sagen.

Aufgabe 9Ein Sprung ins Wasser

In telefon/hoehle.py nennt der Gang eine dritte Wahl. Mit der 3 springt man ins Wasser, das Spiel sagt »… Strömung …« und legt auf, ohne danach noch »Ende.« zu sagen.

Aufgabe 9Ein Sprung ins Wasser

In telefon/hoehle.js nennt der Gang eine dritte Wahl. Mit der 3 springt man ins Wasser, das Spiel sagt »… Strömung …« und legt auf, ohne danach noch »Ende.« zu sagen.

Aussprache

Thorsten liest alles, was in say steht, wie einen deutschen Text. Meistens klingt das richtig. Bei Zahlen, Abkürzungen und englischen Wörtern lohnt es sich, genau hinzuhören:

Im Text Thorsten sagt So klingt es anders
Raum 123 »Raum hundertdreiundzwanzig« Raum 1 2 3: »Raum eins zwei drei«
ZDF »Zett De Eff«: Abkürzungen buchstabiert er
Psst, Hm, Brr den Laut, nicht die Buchstaben
Game Over »Gahme Ohver«, deutsch gelesen [[ ɡˈeɪm ]] over

Ein Komma macht eine kurze Pause, ein Punkt, ein Fragezeichen oder ein Ausrufezeichen eine längere. Zwischen zwei doppelten eckigen Klammern steht Lautschrift, das Internationale Phonetische Alphabet (IPA): Dann spricht Thorsten genau diese Laute. Das Zeichen ˈ steht vor der betonten Silbe, ː macht den Laut davor lang. Meist reicht es, nur das Wort in Lautschrift zu schreiben, das falsch klingt: »over« spricht Thorsten so, wie man es auf Deutsch meistens sagt.

Leider verloren. [[ ɡˈeɪm ]] over!

Die Lautschrift eines Wortes steht im Wiktionary unter »Aussprache«, bei englischen Wörtern im englischen Wiktionary. Die Zeichen kopierst du von dort. Auf der Seite des Telefons steht die Lautschrift ohne die Klammern.

Ausprobieren: Gib dem Sprung ins Wasser ein »Game over«, einmal als Text und einmal mit »Game« in Lautschrift. Achte auf den Vokal in »Game«.

5. Deine Geschichte

Erst die Karte

Jetzt erfindest du dein eigenes Abenteuer: eine Burg, ein Raumschiff, ein Wald, ein Schulgebäude nach Mitternacht. Zeichne zuerst die Karte auf Papier, mit einem Kasten für jede Szene und einem Pfeil für jede Taste, wie bei der Höhle. Dabei merkst du, ob jede Szene einen Ausgang hat und ob man das Ende überhaupt erreichen kann.

Deine Geschichte hat mindestens vier Szenen und zwei verschiedene Enden, ein gutes und ein schlechtes zum Beispiel. Jede Szene sagt, welche Taste wohin führt; wer anruft, sieht deine Karte ja nicht.

Programmieren

Schreib dein Spiel in eine neue Datei geschichte.rb im Ordner telefon: eine Funktion für jede Szene, unten die Musik und der Aufruf der ersten Szene. Ruf nach jeder neuen Szene einmal an und spiel sie durch.

Schreib dein Spiel in eine neue Datei geschichte.py im Ordner telefon: eine Funktion für jede Szene, unten die Musik und der Aufruf der ersten Szene. Ruf nach jeder neuen Szene einmal an und spiel sie durch.

Schreib dein Spiel in eine neue Datei geschichte.js im Ordner telefon: eine Funktion für jede Szene, unten die Musik und der Aufruf der ersten Szene. Ruf nach jeder neuen Szene einmal an und spiel sie durch.

Was ein Spiel am Telefon gut macht:

  • Kurze Sätze. Was man hört, kann man nicht noch einmal lesen.
  • Die Tasten zum Schluss. »Drück 1 für links« am Ende einer Szene merkt man sich leichter als am Anfang.
  • Nichts drücken ist auch eine Wahl. Wiederhol die Szene, oder lass etwas passieren: Wer im Wald zu lange wartet, hört Schritte.
  • Musik erzählt mit. Jede Szene darf ihre eigene haben, am Anfang ihrer Funktion; ein Ausschnitt mit start und stop reicht oft. Und Stille ist auch Musik.
  • Stimmungen sparsam. Ein Flüstern an der richtigen Stelle, eine Hexe, die wütend klingt, wenn man sie weckt.
  • Abkürzen erlaubt. interrupt für Sätze, die man beim zweiten Mal schon kennt.
  • Auflegen als Ende. Nach dem Sturz in die Schlucht legt das Spiel mit hangup auf, und das Besetztzeichen sagt den Rest.
Aufgabe 10Deine Geschichte

telefon/geschichte.rb spielt Musik, sagt etwas und wartet dann auf eine Taste.

Aufgabe 10Deine Geschichte

telefon/geschichte.py spielt Musik, sagt etwas und wartet dann auf eine Taste.

Aufgabe 10Deine Geschichte

telefon/geschichte.js spielt Musik, sagt etwas und wartet dann auf eine Taste.

Spieltest

Lass jemanden aus deiner Klasse an deinem Rechner anrufen, ohne dass er oder sie deinen Code oder deine Karte sieht. Schau zu, ohne zu helfen: Wo zögert die Person, wo drückt sie etwas, das du nicht erwartet hast, wo kommt sie nicht weiter? Danach änderst du dein Spiel.

Aufgabe 11Spieltest

Wer hat dein Spiel gespielt? Wo hat die Person gezögert oder etwas anderes gedrückt, als du erwartet hast, und was hast du danach geändert?

Mindestens 20 Wörter. Nur du und deine Lehrkraft können die Antwort lesen.

Veröffentlichen

Ist dein Spiel fertig, kommt es ins Telefonbuch: Dort steht es mit seinem Titel und einer Nummer, unter der man es anruft. Such dir die Nummer aus, mit drei oder vier Ziffern, oder ein Wort aus drei oder vier Buchstaben wie DINO: Man wählt es mit den Tasten, auf denen die Buchstaben stehen, hier 3466. Bevor es im Telefonbuch steht, sieht es sich jemand an, und du bekommst eine E-Mail, ob es veröffentlicht ist. Im Telefonbuch steht nicht, wer es geschrieben hat, nur der Titel, der Satz dazu und die Nummer.

Vorher gibt dein Spiel sich selbst einen Namen und einen Satz, der im Telefonbuch unter dem Namen steht. Beides gehört an den Anfang deiner Datei:

require 'telefon'title 'Die Höhle der Echos'subtitle 'Ein Abenteuer mit drei Wegen und einem Schatz.'
from telefon import keys, music, say, sleep, subtitle, title

title('Die Höhle der Echos')
subtitle('Ein Abenteuer mit drei Wegen und einem Schatz.')
const { keys, music, say, sleep, subtitle, title } = require('telefon');

title('Die Höhle der Echos');
subtitle('Ein Abenteuer mit drei Wegen und einem Schatz.');

Das Telefon zeigt den Namen an, sobald dein Spiel ihn sagt.

Eingereicht wird eine Kopie deines Spiels und der Dateien daneben, etwa deiner MP3s: Änderst du danach etwas, reich es noch einmal ein, unter derselben Nummer; die neue Fassung ersetzt die alte, sobald sie freigegeben ist. Zurückziehen kannst du dein Spiel jederzeit, dann ist seine Nummer wieder frei.

Deine Spiele werden geladen …

6. Ein Zahlenschloss Extra

Ein Extra für Schnelle. Wer es auslässt, springt zu Wie geht es weiter?.

Am Ende der Höhle könnte eine Tür mit einem Zahlenschloss warten. keys(3) wartet auf bis zu drei Tasten, und wer weniger braucht, drückt danach die Raute:

def door
  say 'Eine Tür mit einem Zahlenschloss. Gib drei Ziffern ein.'
  code = keys(3)
  if code == '472'
    say 'Klick. Die Tür springt auf.'
  else
    say 'Nichts passiert.'
    door
  end
end
def door():
    say('Eine Tür mit einem Zahlenschloss. Gib drei Ziffern ein.')
    code = keys(3)
    if code == '472':
        say('Klick. Die Tür springt auf.')
    else:
        say('Nichts passiert.')
        door()
function door() {
  say('Eine Tür mit einem Zahlenschloss. Gib drei Ziffern ein.');
  const code = keys(3);
  if (code === '472') {
    say('Klick. Die Tür springt auf.');
  } else {
    say('Nichts passiert.');
    door();
  }
}

Woher kennt man die Zahl? Vielleicht sagt sie eine andere Szene nebenbei: »Auf einem Zettel an der Wand steht 472.« Wer gut zuhört, kommt weiter.

Ausprobieren: Gib nur zwei Ziffern ein und warte. Was gibt keys(3) nach zehn Sekunden zurück? Und was, wenn du nach zwei Ziffern die Raute drückst?

7. Wie geht es weiter?

Dein Abenteuer merkt sich noch nichts: Wer die Fackel nimmt, hat sie in der nächsten Szene schon wieder vergessen. Wie eine Welt Gegenstände, Räume und eine Tasche bekommt, die sich alles merkt, baust du im Textadventure aus Objekten. Und wenn du lieber schreibst als programmierst: Mit BIF erzählst du eine Geschichte mit Entscheidungen, Seite für Seite.

Sind es viele Szenen, wird jede neue Funktion fast eine Kopie der vorigen. Dann lohnt es sich, die Szenen als Daten aufzuschreiben: ein Hash (Dictionary) mit dem Namen jeder Szene, ihrem Text und wohin ihre Tasten führen, und eine einzige Schleife, die von Szene zu Szene geht. Wie ein Hash funktioniert, übst du in den Katas zu Dictionaries.