Atari Adventure in Scratch

Bildschirmfotos

Man kann auch mal für Aufgaben erst eine Lösung präsentieren und dann die Schüler und Schülerinnen mal machen lassen und schauen, wie weit sie sich ihr nähern können. Wir hatten eigentlich vorerst schon mit Scratch aufgehört und uns Robot Karol genähert, da erinnerte ich mich an ein Computerspiel meienr Kindheit. Ich kannte dieses Spiel – Atari Adventure – aus der Reklame, hatte es aber selber nie, sondern nur so ähnliche. Und dieses Atari Adventure war berühmt für die reichhaltige Fülle der Welt, in der man sich bewegen konnte, und die ansprechende Grafik. So sah das Spiel aus:

Der Inhalt ist nicht verfügbar.
Bitte erlaube Cookies, indem du auf Übernehmen im Banner klickst.

Solche Zeiten waren das.

Ich habe den SuS das Let’s‑Play-Video oben vorgespielt und als Referenz zur Verfügung gestellt, und während die meisten mit Robot Karol weitermachten – hier ein differenzierendes Arbeitsblatt mit gemischten Aufgaben zur Wiederholung mit fester Anzahl, mit Lösungstipps auf der Rückseite – versuchten fünf Schüler, das Atari Adventure zu rekonstruieren. Zweiweinhalb Stunden hatten sie Zeit dafür, und da kamen sehr ordentliche Sachen heraus:

Bildschirmfotos

Passende Grafik, Bewegung, Mauern als Hindernisse, verschiedene Räume, ein Schlüssel zum Auf- und Mitnehmen, ein ebensolches Schwert, mit dem man einen Gegener töten kann. Der hat selber ein rotierendes Schwert, dem man ausweichen muss:

Screenshot Spiel

Screenshot Spiel

Wenn die sich jetzt zusammentäten und gemeinsam weitermachten, käme ein brauchbares Spiel heraus. Mal schauen, wie wir weitermachen.

Array enaktiv

lastikbox mit kleinen nummerierten Schubladen

Seit ich das beim Kollegen Sebastian Buch gelesen habe, freue ich mich aufs Nachmachen:

lastikbox mit kleinen nummerierten Schubladen

Wie man einsetzt, beschreibt Sebastian unter dem Link oben. Beim Deklarieren des Feldes wird der leere Kasten hingestellt. Beim Initialisieren kommen leere Schubladen in einer Anzahl hinzu, die der Feldgröße entspricht. Ab jetzt kann man die einzelnen Fächer des Feldes ansprechen, und zum Beispiel Zettelchen hineinlegen lassen, beschriftet mit “Annas Radiergummi” und “Billys Radiergummi”, falls das ein Feld für Radiergummis ist.

(Für Nichtinformatiker: Ein Feld oder Array ist eine Datenstruktur, die ein Verzeichnis ist für gleichartige Daten, also lauter Radiergummis oder ganze Zahlen oder Wörter. Die Länge des Feldes kann nicht mehr geändert werden, sobald sie einmal festgelegt ist. Jedes Element im Feld kann man über den Index ansprechen, also die Nummer im Feld, meist angefangenm bei 0.)

Storyworld – ein Java-Projekt für die 10. Klasse

Klassendiagramm Story-Klassen

Paket für ILTB 2017 Download, Zip, ~20 MB (enthält Präsentation, Anleitung, Code)

Storyworld habe ich als Projekt für 10. Klassen am Gymnasium in Bayern im Rahmen des Fachs Informatik durchgeführt. Es geht dabei darum, dass Schülerinnen und Schüler für eine gemeinsame Fantasy-Spielwelt Geschichten schreiben, die in Form von Zustandsautomaten umgesetzt werden und die miteinander in Zusammenhang stehen können.

Vorgeschichte und Hintergrund

Eine beispielhafte Spielwelt

So sieht zum Beispiel eine Welt aus, die aus 6 Location-Objekten und 5 Connections besteht. Es ist Absicht, dass La Isla Bonita nicht so einfach zu erreichen ist.

Landkarte der Spielwelt

Im Spiel kann man sich zwischen den Orten, die durch Kanten verbunden sind, bewegen. Der eigentliche Clou: An manchen Orten werden zusätzlich zu den Ortsbeschreibungen Geschichten oder Teile von Geschichten präsentiert.

Die Geschichte vom Froschkönig, klassisch und linear

Klassische Geschichten sind linear in dem Sinn, dass sie Absatz für Absatz gelesen werden und man auch nicht mehr zurückspringt. Das gilt auch dann, wenn nicht chronologisch erzählt wird, sondern mit Sprüngen, wie etwa in der Odyssee. Deutschlehrer verlangen manchmal von ihren Schülern, die Geschichte in einzelne Stationen aufzuteilen. Das sieht dann, etwas formalisiert, so aus:

Zustandsübergangsdiagramm Froschkönig klassisch

Die Geschichte vom Froschkönig, als nichtlineares Spiel umgestaltet

Spiele sind of nicht-linear in dem Sinn, dass man zu vorherigen Zuständen zurück kann und bestimmte Phasen mehrfach durchläuft. Auch gibt es möglicherweise unterschiedliche Wege zwischen den Stationen. In der Informatik kann man so etwas als Zustandsautomat modellieren. Das sieht dann so aus, mit auslösenden Aktionen bei den Übergängen, ausgelösten Aktionen nach dem Schrägstrich, und zusätzlichen Bedingungen für den Zustandsübergang in eckigen Klammern.

Zustandsübergangsdiagramm Froschkönig nichtlinear

Die zentralen Methoden der Geschichtenklassen

Bewegt man sich durch die Welt, erscheinen Reiter mit den zur Verfügung stehenden Geschichten. Wählt man eine davon, sieht man zum Beispiel dieses schlichte Beispiel – der Spieler befindet sich gerade im Hafen, könnte nach Innismund wechseln, und hat gerade die Geschichte “Das öde Haus” ausgewählt:
Benutzeroberfläche Spiel

Zu diesem Zweck hat jede Geschichtenklasse zwei Methoden: createReport und receiveMessage. Die erste Methode wird aufgerufen, damit die Geschichte einen Bericht oder eine Beschreibung abgeben kann, möglichweise mit einer oder mehreren Optionen, die der Spieler danach wählen kann. Die zweite Methode gibt an, was geschieht, wenn der Spieler die jeweilige Option wählt, sie entspricht mehr oder weniger der klassischen Zustandsübergangsmethode:

class LeeresHaus extends SingleLocationStory {
 
 public Report createReport() { 
  Report r = new Report("Ein leeres Haus.");
  r.addOption("Du untersuchst es", "anschauen");
  return r;
 }
 
 public void receiveMessage(String s) {
  if (s.equals("anschauen")) {
   sendMessage("Niemand zu Hause");
   if(get("Neugier")<10)increase("Neugier", 1);
  }
 }
 
 public String getName() { return "Das öde Haus"; }
 public String startStoryAt() { return "Hafen"; }
 public String getImageName() { return "resources/haus.png"; }
 
}

Die Methode getName gibt den Namen der Geschichte zurück, die für diese Unterklasse von Geschichten notwendige Methode startStoryAt gibt den Ort zurück, an dem die Geschichte spielt, die optionale Methode getImageName gibt den Ort und Namen eines passenden Bildes an.

Zu den typischen ausgelösten Aktionen bei der Zustandsübergangsmethode gehören set, increase, decrease von beliebigen Spielwelt- oder Spielerattributen. (Wenn ein Attribut dieses Namens noch nicht existiert, wird es angelegt.) Den Wert dieses geschichtenübergreifenden Attributs kann man auch mit get abfragen, um Anweisungen von bestimmten Bedingungen abhängig zu machen.
Außerdem kann man mit sendMessage Text ausgeben. Daneben gibt es viele Möglichkeiten, den Zustand der Spielwelt zu ändern – man kann diese Geschichte an einen anderen ort platzieren, den Spieler auch, neue Orte oder Verbinungen zwischen Orten erschaffen. Häufig wird man auch ein Zustandsattribut in die eigene Geschichtenklasse einbauen und dessen Wert ändern. Von dem Wert dieses eigenen Zustandsattributs hängt dann auch der zurückgegebene Report ab, und die damit verbundenen Optionen – und schon hat man einen einfachen Zustandsautomaten.

– Wer die Trennung oder Doppelung der zwei Methoden createReport und receiveMessage unübersichtlich findet, für den gibt es Alternativen: In einem Anhang unten habe ich die verschiedene anderen Geschichtenklassen gegenübergestellt. Sie sind alle Unterklassen von AbstractStory, und logisch alle äquivalent, bieten eben nur unterschiedliche Implementierungen.

ActionStory

Implementiert eine Geschichtenklasse das Interface ActionStory, so muss es eine Methode void act() geben. Diese Methode wird jedesmal aufgerufen, wenn der Spieler sich entscheidet, zu einem anderen Ort zu gehen. So kann man zum Beispiel einen Wanderer erschaffen, der sich bei jeder Bewegung des Spielers auch bewegt, zum Beispiel zu einem zufälligen Nachbarort.

Ausgelöste Aktionen

Typisch sind:

  • set(String, int), increase(String, int), decrease(String, int)
  • movePlayerTo(String)
  • sendMessage(String)
  • moveStoryTo(String) – das geht nur bei Objekten der Klasse SingleLocationStory und deren Unterklassen, da nur diese Geschichten an genau einem Ort spielen
  • addLocation(Location), removeLocation(Location)
  • addConnection(Location, Location, int), removeConnection(Location, Location)
  • enter() und exit() – optional: nachdem man mit enter() eine Geschichte betreten hat, kann man nicht mehr zu einer anderen Geschichte oder einem anderen Ort wechseln, bis man zu einem Ende gekommen ist, das einen mit exit() wieder aus der Geschichte entlässt (es gibt auch einen automaticEntryMode)
  • introduceStory(AbstractStory)
  • deleteStory(AbstractStory)

Bedingungen/Informationen über die Welt

  • int get(String)
  • boolean playerIsIn(String)
  • String getPlayerLocationName()
  • String getRandomNeighbourName(String)
  • Location [] getAllNeighbours(String)
  • Location getRandomLocation()
  • int getTimeSinceLastReport()

Mögliche Geschichten

  • Ein Wanderer, der zufällig herumzieht.
  • Ein Tribble, das gefangen werden kann und dann verschwindet, sich ansonsten vermehrt, indem es als ActionStory in jedem Spielerzug mit einer gewissen Wahrscheinlichkeit neue Objekte der eigenen Klasse ins Spiel bringt. (Besser mit Obergrenze, da exponentielles Wachstum.)
  • Eine klassische Kuriermission, bei der ein Gegenstand von Ort A nach Ort B gebracht werden muss und man dafür eine Belohnung erhält.
  • Romeo und Julia: Man trägt Briefe zwischen beiden hin und her, bis beider Geschichte ein Ende findet.
  • Eine Begleitmission, bei der man einen Passagier zu einem möglicherweise unbekannten Ort geleiten und abliefern muss. (Die letzten drei sind Beispiele für Geschichten, die an mehr als einem Ort spielen.)
  • Ein bürokratisches Labyrinth, aus dem man herausfinden muss.
  • Eine Fähre zwischen dem Hafen und La Isla Bonita – als Geschichte, die nur an einem Ort spielt, der aber mit moveStoryTo geändert wird, oder als Geschichte an zwei Orten. (An dem einen hat man die Fähre und die Möglichkeit, sie zu besteigen; am anderen wird man auf die abwesende Fähre hingewiesen. Die Fähre wechselt natürlich den Ort, entweder durch Spieleraktion oder selbstständig.)
  • “Das öde Haus” von E.T.A. Hoffmann, umgeformt in eine Minigeschichte, mit viel Originalzitaten.

Langer Anhang: Varianten der zentralen Methoden in verschiedenen Unterklassen

Ich finde die Trennung in zwei Methoden createReport und receiveMessage übersichtlich und praktisch. Aber gerade wenn man die Geschichte mit einem Zustandsattribut umsetzt, gibt es unschöne Doppelungen im Code: Man braucht für beide Methoden ein ähnliches if-else- oder switch-Konstrukt, um den aktuellen Zustand abzufragen, von dem ja sowohl der Report als auch der Zustandsübergang abhängen. Wem das nicht gefällt, für den gibt es andere Möglichkeiten. Es folgt ein kurzer Überblick über die verschiedenen Geschichtenklassen. Eine Schüler-Klasse ist jeweils eine Unterklasse einer davon; die in diesem Fall zu überschreibenden Methoden sind jeweils farblich markiert.

Klassendiagramm Story-Klassen

AbstractStory

Das ist die allgemeinste Klasse. Unterklassen davon müssen einfach nur drei Methoden implementieren; wem das reicht, der kann die restlichen Klassen ignorieren:

  • String getName() – das gilt für alle Geschichten-Klassen. Jede Geschichte braucht einen (eindeutigen) Namen.
  • Report createReport(String locationName) – die Geschichte wird bei jeder Bewegung und jeder Entscheidung eines Spielers gebeten, einen Bericht abzuliefern. Dieser Bericht hängt vielleicht vom Zustand der Geschichte ab, aber ganz sicher vom Ort des Spielers, dessen Bezeichner als Argument übergeben wird. Wenn eine Geschichte in Innismund und in Das Schloss spielt, wird sie nur in diesen beiden Fällen einen Report abgeben, in allen anderen Fällen null zurückgeben. So ein Null-Report wird dann nicht angezeigt.
    Einem Report kann man Optionen hinzufügen, die dann als anklickbare Knöpfe erscheinen. Das geht unter anderem mit der Methode addOption(String, String). (Man kann auch Option-Objekte erzeugen, die dann mehr Möglichkeiten bieten.) Der erste String ist der Text, den der Spieler zu sehen kriegt; der zweite String ist die Nachricht, die an die Geschichtenklasse geschickt wird, damit auf die Wahl des Spielers reagiert werden kann – siehe folgende Methode.
  • void receiveMessage(String message) – diese Methode wird aufgerufen, wenn der Spieler auf den entsprechenden Options-Knopf geklickt hat, dabei wird der String, der der Option als zweites Argument übergeben worden ist, zum Argument der receiveMessage(String)-Methode gemacht. (Tatsächlich wird vorher die Methode receiveMessage(Option) aufgerufen, wobei aus dem Option-Argument eine Reihe von Consequence-Objekten extrahiert und automatisch ausgeführt werden, bevor der Message-String extrahiert und an receiveMessage(String) übergeben wird.)
import storyworld.*;
public class Fischer extends AbstractStory {
    int zustand = 0;
    public Fischer () { }
    public String getName() { return "Der Angler"; }    
 
    public Report createReport(String locationName) {
        if (!locationName.equals("Hafen")) return null; // die Geschichte gibt nur für einen Ort einen Report zurueck
        if (zustand == 0) {
            Report r = new Report("Ein Fischer sitzt am Kai und angelt.");
            r.addOption("Du fragst ihn, wie es so läuft.", "ansprechen");
            return r;
        } else {
            Report r = new Report("'Toll!' Der Angler erzählt dir eine lange Geschichte, wie er einmal fast den größten Fisch gefangen hat, denn es je zu sehen gab, und gibt dir einen Fisch.");
            r.addOption("Du dankst für das Gespräch und den Fisch.", "beenden"); 
            return r;
        }
    }
 
    public void receiveMessage(String s) {
        if (zustand==0) {
            if (s.equals("ansprechen") ) // ausloesende Aktion
            { 
                if (get("Fische")<3) { // Bedingung des Zustandsuebergangs 
                    zustand = 1; 
                    increase("Fische", 1); // ausgeloeste Aktionen
                } else {
                    sendMessage("Du hast schon genug Fische."); 
                }
            }
        }
        else if (zustand==1) {
            if (s.equals("beenden")) // ausloesende Aktion
            {
                zustand = 0; 
            }
        }
    }    
}

SingleLocationStory

Diese Klasse ist für Einsteiger gedacht; bei ihr muss die Methode createReport() ohne Argument überschrieben werden. Diese Methode wird nämlich nur dann aufgerufen, wenn der Spieler sich an dem Ort befindet, an dem die Geschichte spielt, und der am Anfang durch startStoryAt() festgelegt wird. Dafür kann die Geschichte aber auch nur an einem Ort gleichzeitig spielen. Dieser Ort kann mit moveStoryTo(String) geändert werden.
Die Methoden getName() und receiveMessage(String) funktionieren wie oben.

import storyworld.*;
public class Fischer extends SingleLocationStory {
    int zustand = 0;
    public Fischer () { }
    public String startStoryAt() { return "Hafen"; }
    public String getName() { return "Der Angler"; }    
 
    public Report createReport() {        
        if (zustand == 0) {
            Report r = new Report("Ein Fischer sitzt am Kai und angelt.");
            r.addOption("Du fragst ihn, wie es so läuft.", "ansprechen");
            return r;
        } else {
            Report r = new Report("'Toll!' Der Angler erzählt dir eine lange Geschichte, wie er einmal fast den größten Fisch gefangen hat, denn es je zu sehen gab, und gibt dir einen Fisch.");
            r.addOption("Du dankst für das Gespräch und den Fisch.", "beenden"); 
            return r;
        }
    }
 
    public void receiveMessage(String s) {
        if (zustand==0) {
            if (s.equals("ansprechen") ) // ausloesende Aktion
            { 
                if (get("Fische")<3) { // Bedingung des Zustandsuebergangs 
                    zustand = 1; 
                    increase("Fische", 1); // ausgeloeste Aktionen
                } else {
                    sendMessage("Du hast schon genug Fische."); 
                }
            }
        }
        else if (zustand==1) {
            if (s.equals("beenden")) // ausloesende Aktion
            {
                zustand = 0; 
            }
        }
    }    
}

ShopStory

Eine Klasse, um Läden anzulegen, die Waren oder Gegenstände kaufen und verkaufen. Arbeitet viel mit Requirement- und Consequence-Objekten bei den Optionen. Überschrieben werden muss keine Methode, aber sinnvollerweise werden mit addItem im Konstruktor Waren hinzugefügt, die der Laden kauft und verkauft.

import storyworld.*;
 
public class KleinerLaden extends ShopStory {
    public String startStoryAt() {  return "Innismund"; }
    public String getName() { return "Der kleine Laden";}
    public KleinerLaden() {
        setDescription("Hier gibt es allerlei Dinge.");        
        addItem("Wasser",50, "Geld", 2, "Geld", 1); // 50 Wasser vorhanden, fuer 2 Geld zu kaufen, fuer 1 Geld an den Laden verkaufen 
        shopSells("Kräuterbaguette",5, "Geld",1000); // 1 Kraeuterbaguette für 1000 Geld kaufen (5 vorhanden)             
        shopBuys ("Seele",1, "Geld", 1000); // 1 Seele fuer 1000 Geld verkaufen
        shopBuys ("Ansehen",10, "Geld", 1); // 10 Ansehen fuer 1 Geld verkaufen
        shopBuys ("Tribble",1, "Geld", 1); // 1 Tribble fuer 1 Geld verkaufen
    }
}

TestableStory

Eine Unterklasse, die speziell für das Projekt eingerichtet wurde; sie hat eine test-Methode, die eine Welt erzeugt und die Geschichte, die die Methode aufgerufen hat, in die Testwelt einbaut. Diese Methode muss von der Unterklasse am Ende des Konstruktors aufgerufen werden.

SimpleStory

Ist identisch zu SingleLocationStory, nur mit der zusätzlichen Möglichkeit des Testens, indem am Ende des Konstruktors test() aufgerufen wird.

MultiplaceStory

Entspricht letztlich der Klasse AbstractStory – das heißt, die createReport-Methode wird jetzt wieder bei jeder Location aufgerufen, dafür erhält sie jetzt wieder als String-Argument den Namen der aktuellen Location. Am Ende des Konstruktors wird test() aufgerufen.

ModifiedSimpleStory

Vielleicht stört den einen oder anderen die Doppelung der if-Anweisung in den beiden Methoden. Deshalb bietet diese Klasse eine Methode Report receiveChoice(String message), die überschrieben werden muss. Sie ersetzt die beiden Methoden receiveMessage und createReport der Oberklasse, die demnach nicht überschrieben werden müssen.
Auch diese Methode wird nur dann aufgerufen, wenn der Spieler an dem einen Ort ist, an dem die Geschichte spielt. Man muss also nie einen Null-Report zurückgeben.
In dieser Klasse muss man zwar nur eine zentrale Methode schreiben, aber dese Methode enthält wieder zwei gro0ße if/switch-Blöcke: Zuerst einen für das Auswerten der Nachricht, dann einen für das Senden des aktuellen Zustands-Reports.

import storyworld.*;
public class Fischer extends ModifiedSimpleStory {
    int zustand = 0;
    public Fischer () { }
    public String startStoryAt() { return "Hafen"; }
    public String getName() { return "Der Angler"; }    
 
    public Report createReport(String s) {
        //Teil 1   
        if (zustand==0) {
            if (s.equals("ansprechen") ) // ausloesende Aktion
            { 
                if (get("Fische")<3) { // Bedingung des Zustandsuebergangs 
                    zustand = 1; 
                    increase("Fische", 1); // ausgeloeste Aktionen
                } else {
                    sendMessage("Du hast schon genug Fische."); 
                }
            }
        }
        else if (zustand==1) {
            if (s.equals("beenden")) // ausloesende Aktion
            {
                zustand = 0; 
            }
        }
        //Teil 2
        if (zustand == 0) {
            Report r = new Report("Ein Fischer sitzt am Kai und angelt.");
            r.addOption("Du fragst ihn, wie es so läuft.", "ansprechen");
            return r;
        } else {
            Report r = new Report("'Toll!' Der Angler erzählt dir eine lange Geschichte, wie er einmal fast den größten Fisch gefangen hat, denn es je zu sehen gab, und gibt dir einen Fisch.");
            r.addOption("Du dankst für das Gespräch und den Fisch.", "beenden"); 
            return r;
        }
    }
}

ModifiedMultiplaceStory

Analog zu MultiplaceStory wird hier Report receiveChoice(String message) an jedem Ort des Spiels aufgerufen, man muss in dieser Methode also für die meisten Orte einen Null-Report zurückgeben. (Die Methoden receiveMessage und createReport entfallen wieder.)

Letztlich wie die Oberklasse, nur mit einem zusätzlichen if (!s.equals("Hafen")) return null;

YetAnotherModifiedSimpleStory

Diese Klasse ist für Leute, die die zwei if/switch-Blöcke stören: Hier gibt es nur einen davon. Da der verlangte Report ja erst am Schluss der Methode zurückgegeben werden kann, hat die zu implementierende Methode void createReport(String message) hier keinen Rückgabetyp; dafür wird mit Aufrufen von setReport(Report) der später zurückzugebende Report festgelegt.

import storyworld.*;
public class Fischer extends YetAnotherModifiedSimpleStory{
    int zustand = 0;
    public Fischer () { }
    public String startStoryAt() { return "Hafen"; }
    public String getName() { return "Der Angler"; }    
 
    public void receiveChoice(String s) {        
        if (zustand == 0) {
            Report r = new Report("Ein Fischer sitzt am Kai und angelt.");
            r.addOption("Du fragst ihn, wie es so läuft.", "ansprechen");
            setReport(r);
            if (s.equals("ansprechen")) {
               if (get("Fische")<3) { // Bedingung des Zustandsuebergangs 
                   zustand = 1; 
                   increase("Fische", 1); // ausgeloeste Aktionen
               } else {
                   sendMessage("Du hast schon genug Fische."); 
               }
           }
        } else {
            Report r = new Report("'Toll!' Der Angler erzählt dir eine lange Geschichte, wie er einmal fast den größten Fisch gefangen hat, denn es je zu sehen gab, und gibt dir einen Fisch.");
            r.addOption("Du dankst für das Gespräch und den Fisch.", "beenden"); 
            setReport(r);
            if (s.equals("beenden")) {
                zustand = 0;
            }
        }
    }
}

SimpleStoryChrisGraessl

Eine weitere, sehr elegante Methode. Hier muss man nur Report createReport() überschreiben, die Methode receiveMessage(String) entfällt beziehungsweise ist in der Oberklasse festgelegt. Das zweite Argument von:

addOption(String, String)

wird dabei als Methodenbezeichner verwendet. Setzt man diese Option:

addOption("Du isst den Kuchen.", "essen");

so wird, wenn der Spieler sich für sie entscheidet, die Methode void essen() aufgerufen, die natürlich existieren muss.

import storyworld.*;
public class Fischer extends SimpleStoryChrisGraessl {
    int zustand = 0;
    public Fischer () { }
    public String startStoryAt() { return "Hafen"; }
    public String getName() { return "Der Angler"; }    
 
    public Report createReport() {        
        if (zustand == 0) {
            Report r = new Report("Ein Fischer sitzt am Kai und angelt.");
            r.addOption("Du fragst ihn, wie es so läuft.", "ansprechen");
            return r;
        } else {
            Report r = new Report("'Toll!' Der Angler erzählt dir eine lange Geschichte, wie er einmal fast den größten Fisch gefangen hat, denn es je zu sehen gab, und gibt dir einen Fisch.");
            r.addOption("Du dankst für das Gespräch und den Fisch.", "beenden"); 
            return r;
        }
    }
 
    public void ansprechen() {
        if (get("Fische")<3) { // Bedingung des Zustandsuebergangs 
            zustand = 1; 
            increase("Fische", 1); // ausgeloeste Aktionen
        } else {
            sendMessage("Du hast schon genug Fische."); 
        }
    }
 
    public void beenden() {
        zustand = 0; 
    }    
}

Death Race 2000 – Frankensteins Todesrennen

Gestern zufällig auf ein Interview mit Roger Corman vom letzten Herbst gestoßen, das jetzt erst veröffentlicht wurde. Wie schön – ich wusste nicht, dass er noch lebt, aber mit 90 Jahre ist er auch weniger alt, als ich gedacht hätte. Anlass des Interviews war der Film Death Race 2050, der Anfang des Jahres 2017 herauskam, ein Remake von Death Race 2000 (deutsch: Frankensteins Todesrennen) aus dem Jahr 1975, produziert von Roger Corman. (2008 gab es schon mal ein Remake.)

Und just diesen Originalfilm (Regie: Paul Bartel), dessen Titel ich seit frühen Jahren kenne, habe ich vor wenigen Monaten zum ersten Mal gesehen, und er hat mit sehr gut gefallen. Schön fand ich das Sparsame der Produktion. Da ist nichts Überflüssiges daran, keine lyrische Landschaft, kein episches Herumgucken, keine, uh, Schauspielerei, und kein ordentliches Bühnehnbild. Als zum ersten Mal die zentrale der geheimen Widerstandsbewegung gezeigt wurde, meinte Frau Rau: “Das sieht aus wie bei der Probe eines Brechttheaters”, und exakt so sieht es auch wirklich aus.

Die Geschichte: Ein dystopisches USA der nahen Zukunft. Es gibt einen Präsidenten, eine möglicherweise repressive Regierung (aber das wird allenfalls angedeutet), eine Widerstandsbewegung, und das jährliches Toderesrennen, bei dem Fahrer schnellstmöglich durch die USA fahren und dabei außerdem Punkte für überfahrene Passanten erhalten. Dazu überdrehte Medienberichterstattung vom Rennen. Die Fahrer – in der Hauptrolle David Carradine, als Konkurrenz Sylvester Stallone – versuchen einander umzubrinnen; der Widerstand versucht Frankenstein umzubringen; Frankenstein hat eigene Pläne und einen Spion im Auto. Dazu ein paar blanke Busen, mäßig motiviert. Alles ohne schauspielerische Leistung, ohne große Kulissen oder Innenausstattung. Wie schön, dass man früher einfach solche Filme machen konnte!

Der Inhalt ist nicht verfügbar.
Bitte erlaube Cookies, indem du auf Übernehmen im Banner klickst.

ILTB 2017 in Passau

Passau Uni Außengelände

Ach! Am Anfang der Woche war ich in Passau auf dem 10. ILTB, das ist der Tag der Informatiklehrerinnen und ‑Lehrer). Das ist ein inzwischen jährlicher Fortbildungstag, der ursprünglich rotierend von den verschiedenen Unis ausgerichtet wurde – einmal habe ich das mitgekriegt, kurz bevor ich an die LMU ging, und diese Organisation ist so viel Arbeit, dass eine Uni allein das nur mit Anstrengung stemmen kann. Die Informatikabteilungen sind ja oft sehr klein. Inzwischen teilen sich die Organisation eine Universität, die Gesellschaft für Informatik, und die jeweilige regionale Lehrerfortbildung, also der Fachreferent oder die Fachreferentin für Informatik für den Regierungsbezirk. Und das klappt wohl sehr gut, jedenfalls sind die ILTBs tadellos organisiert und immer sehr interessant.

2009 war ich auf meinem ersten, noch vor meiner Unizeit, als Referent, und habe darüber gebloggt. Seitdem war ich tatsächlich jedesmal dabei, meist auch als Referent. Ich fahre stets mit gemischten Gefühlen hin, weil ich ohnehin ein wenig ein Stubenhocker bin (oder sagen wir, weil ich mich zu Hause sehr wohl fühle und sehr gerne Zeit mit Frau Rau verbringe) und weil mich wie ein Hochstapler fühle. Ist mein Workshop verständlich? Sinnvoll? Habe ich – so ist das mit Gästen – zu viel aufgetischt oder zu wenig, so dass sie intellektuell hungrig nach Hause gehen müssen? Außerdem sitzen da lauter wichtige Leute, die sich alle kennen, und echte Informatiker, die noch dazu wirklich schlau sind. Ein bisschen bin ich ja doch stereotyper Nerd, weil ich sozial eher zurückhaltend bin und ungeschickt, bis ich – nach langer Zeit – endlich auftaue. Im Klassenzimmer übrigens nicht, da bin ich ganz Rampensau.

Schild Workshop

Inzwischen – darf ich’s wagen? – fühle ich mich ein bisschen zugehörig zu der Gruppe dieser Leute, die sich alle kennen. Als ich aus dem Bahnhof ausstieg und mich hilflos auf der Karte meines kleinen Tablets zu orientieren versuchte, fragte mich gleich ein vorbeikommender Passant, ob ich der Herr Rau sei, und half mir zu meinem Hotel zu kommen. (Ein Leser meines Blogs und ILTB-Referent, der zufällig des Wegs kam. Das war lustig.)

Passau Uni Außengelände

Passau ist übrigens sehr schmuck. Zum Pokémonsammeln bin ich aber kaum gekommen – Bahnhof, Hotel, abendliche Pizzeria und Uni waren jeweils so gut fünf Minuten von einander entfernt, da bin ich gar nicht zum Spazieren gekommen.

An Anregungen habe ich wieder sehr viel mitgenommen. Ein Blatt, wild bekritzelt mit Stichworten und Links, zu allen möglichen informatischen und anderen Themen, das ich jetzt am Wochenende in den Computer sortieren werde. So mache ich das immer mit meinen Notizen, das sind stets Blätter oder Zettel mit Kritzeleien darauf. Gestern habe ich schon die Kinect des Kollegen mit Scratch verbunden und mit Schülern ein bisschen herumprobiert, das wird gleich das nächjste Projekt.

Außerdem ist es doch immer weider schön, Leute zu treffen. Zwei, die ich seit meinem Studium nicht mehr gesehen habe, andere aus meiner Unifrühzeit, und auch die, die ich jedes Jahr am ILTB sehe. Ich freue mich schon auf 2018.

Der Richter und sein Henker, und heldenhafte Lehrer (Alpha Alpha)

Ich habe zum Halbjahr zwei Informatikklassen mit zusammen 4 Stunden abgegeben und eine Klasse in Deutsch neu erhalten, mit vier Stunden. Das kommt öfter vor: Zum Halbjahr gehen immer einer paar Referendare und Referendarinnen, andere werden der Schule neu zugewiesen, und deren Fächerkombinationen sind selten genau die gleichen, so dass sie nicht einfach die Klassen der Vorgänger übernehmen können. Also gibt es Tausche und Ringtausche, und mit meiner Deutsch-Informatik-Englisch-Kombination bin ich da eine geeignete Tauschstelle, ein sehr kurzer Weg zwischen Sprachen und den exakteren Wissenschaften.

Das Arbeiten mit der neuen Klasse macht Vergnügen. Eine Schülerin liest gerade sogar Stalky & Co. Tiralala-itu! Dass es so etwas noch gibt!

Wir lesen Der Richter und sein Henker, von der Referendarin ererbt. Ich glaube, ich habe das Buch 1998 in meinem ersten halben Jahr als Lehrer als Schullektüre eingesetzt und in guter Erinnerung; allerdings weiß ich auch, dass es mich als Schüler überhaupt nicht interessiert hatte. (Denn ich arbeite immer noch mit der Ausgabe, die ich 1982 als Lektüre erwarb; damals ein deutlichg jüngeres Buch als heute; Seitenzahl identisch, aber die – aus der Seitenzählung herausgenommene – zweiseitige Reklame für Pfandbriefe und Kommunalobligationen gibt es heute nicht mehr.)

Anzahl der Frauen im Buch: 3, davon 2 mit Namen. Keine ist wichtig, zwei sind dezidierte Anhängel von Männern, eine davon wird als Besitz quasi weitervererbt, wenn auch ganz höflich: “Werden Sie mir […] das gleiche wie Ihrem verstorbenen Bräutigam sein?”
Der ermittelnde Polizist verrät seine dem Leser verborgenen Informationen über den Täter nicht etwa dadurch, dass er diesen als “Mann” deklariert. An eine Frau in so aktiver Rolle denkt man im Rahmen dieser Männergeschichte gar nicht.
In der Parallelklasse lese ich “Schachnovelle”, eine Schülerwahl. Anzahl der Frauen: 1, ohne Namen, eine beiläufig erwähnte Krankenschwester, wenn ich mich richtig erinnere. Darauf sollte man Schülerinnen und Schüler immer wieder mal hinweisen, bis es ihnen vielleicht selbst einmal auffällt.

***

Bin ich der einzige, der bei Der Richter und sein Henker von Friedrich Dürrenmatt an The Maltese Falcon von Dashiell Hammett denken muss? Ich sehe da Parallelen. Der übermächtige Gegenspieler des Ermittlers begegnet dem Leser in dem einen Buch zuerst als mysteriöse Initiale G, von der man nicht weiß, wer sich dahinter verbirgt. Im anderen Buch erscheint der mächtigste Gegenspieler des Ermittlers dem Leser zuerst als ein von einem anderen Schurken in die Luft gezeichnetes G – das Kapitel heißt sogar “G in the Air”. Bei Dürrenmatt steckt dahinter “Gastmann”, bei Hammett “Gutman” – gespielt von Sydney Greenstreet in der bekanntesten Falcon-Verfilmung, und auch wenn wir über Gastmanns äußere Erscheinung nicht mehr erfahren als dass er “bäuerlich” wirkt, was alles und nichts heißen kann, habe ich mir immer Sydney Greenstreet in dieser Rolle vorgestellt.

In beiden Romanen geht es um eine jahrzehnte dauernde Jagd, nach Gastmann im einen, nach dem Falken im anderen. Beide Romane haben eine philosophische Note: Das Gespräch von Gastmann und Bärlach in Istanbul; die Anekdote, die Sam Spade von Charles Pierce erzählt. Istanbul ist der Ausgangspunkt der Fehde Bärlach-Gastmann, und Konstantinopel (also Istanbul) ist der Punkt, von dem die Falkenjäger nach San Francisco gehen und zu dem sie am Ende des Romans wieder hinwollen, um die Spur weiter zu verfolgen.
Eine Falkenstatue haben wir nicht bei Dürrenmatt, aber einen Schlangendolch.

***

Neulich beim Ukuleletreffen im Gastwirtschafts-Nebenraum gesellten sich Mutter und Kind zu uns, die uns von außen durch ein Fenster gesehen und zugehört hatten. Dann wollten sie halt noch mehr hören und kamen herein. Wir haben dann ein paar Wünsche erfüllt und hatten überhaupt seine sehr schöne Zeit.

***

Mein Freund B. hat mir eine Fernsehserie der frühen 1970er Jahre empfohlen. Die weiteren Episoden – es gibt insgesamt nur 13 – sollen überraschend gut und ihrer Zeit weit voraus sein. Die erste Episode ist es noch nicht so sehr.

Der Inhalt ist nicht verfügbar.
Bitte erlaube Cookies, indem du auf Übernehmen im Banner klickst.

Die Geschichte: Eine Geheimorganisation sucht für internationale Einsätze hochkarätige Agenten, sogenannte Alphas. “Persönlichkeiten, die fähig sein müssen, für die Menschheit zu entscheiden.” Nicht jeder ist qualifiziert, viele arbeiten nur als Betas – schon auch wichtig, aber halt nur Helferlinge.
So futuristisch die Organisation ist: Am Anfang kriegen wir zu sehen, wie Nachrichten aus aller Welt eingehen und verteilt werden – von Frauen, versteht sich. Die Führungsriege der Organisation besteht aus fünf – Männern, versteht sich.

Anklänge von The Prisoner, Mission Impossible, durchaus ehrenhaft. Sehenswert die Drehorte: München zur Baustellenzeit vor den Olympischen Spielen 1972. Eine Szene spielt auf dem Olympiaturm.
Produktionsqualität: Na ja, schon okay, öffentlich-rechtlich. Aber wegen eines Schauspieler-Versprechers hat man da noch lange keine zweite Aufnahme einer Einstellung gemacht.

Für unsereiner zusätzlich interessant: Der Held und zukünftige Alpha, der in der ersten Episode allerlei Prüfungen besteht und schließlich in die Organisation aufgenommen wird, ist – ein Studienrat. Graumeliert, Mathematik und Sport. Bewährt sich gegen fiese Rockerbanden (“Bill, Jim, erledigt das!”); setzt bei der Exkursion in die Satellitenzentrale seine anwesenden Mathematikschüler, männlich, zur Berechnung ein, weil ein Computer ausfällt; vertauscht erfolgreich – wenn auch nicht überzeugend – den Medizinball in der Sporthalle gegen Kampfkunstmanöver, um sich eines Pistolenheinis zu erwehren.

Zoobesuch 2017

Heulende Wölfe

Heulende Wölfe“Listen to them, the children of the night. What music they make!” (Bram Stoker, Dracula.) Haben alle drei geheult, und es hört sich so an wie im Kino. Aber beeindruckender.

Roter PandaRoter Panda, englisch: Firefox.

Königspinguine mit JungtierKönigspinguine. Einer davon erst fünf Monate alt… man sieht den Unterschied, glaube ich.

NashörnerNashörner. Sehe ich immer wieder gern.

“It is one thing to describe an interview with a gorgon or a griffin, a creature who does not exist. It is another thing to discover that the rhinoceros does exist and then take pleasure in the fact that he looks as if he didn’t.” (G. K. Chesterton)

PelikanePelikane. Auf Deutsch: Rosapelikan. Auf Englisch: Great white pelican.

LöweLöwe, schauend.

Pfau, liegendPfau, liegend.

Kattas in KorbKattas. Waren alle sehr müde.

RhesusaffenRhesusaffen sitzen noch ein Weilchen nach dem Essen zusammen.

FlinkwallabysFlinkwallabys mit rosa Ohren. Gibt es dann auch Plumpwallabys?

AmeisenbärAmeisenbär, alter Freund.