Aufgabenblatt Java Applets
 
Ziel dieses Arbeitsblattes ist es das wohl jedem bekannte Spiel »Hangman« in Java zu implementieren.
 
Kermet ist auf die Idee gekommen doch mal ein Hangman zu Programmieren, welches er auf seine Homepage stellen will um damit den gestressten Internetsurfern eine kleine Ablenkung zu bieten. Dazu hat er schon einige Klassen implementiert, deren Schnittstelle als ausführbar (Runnable) gekennzeichnet ist. Diese Klassen können annimierte Linien und Kreise zeichnen. In diesem Archiv ist auch schon der Quellcode des Applets "hangman.java" enthatlen (zumindest so weit wie Kermet schon gekommen ist.
 
Sein Applet hat er auch schon angefangen und hat erst mal alles hingeschrieben, was er so importieren will:


import java.awt.Font;

import java.awt.Color;
import java.awt.Panel;
import java.awt.Button;
import java.awt.Choice;
import java.awt.Graphics;
import java.awt.TextField;
import java.awt.GridBagLayout;
import java.awt.GridBagConstraints;
import java.lang.Thread;
import java.awt.event.ItemEvent;
import java.awt.event.ActionEvent;
import java.awt.event.ItemListener;
import java.awt.event.ActionListener;
 
Doch schon bei der Definition seiner Klasse hat er ein paar Probleme, er will auf alle Fälle ein Applet erstellen, dass auch "ActionListener" und "ItemListener" ist. Helft ihm doch bitte!
 
public class hangman ...?
{
 
Hier weiss er schon wieder etwas weiter, er will einen Zeichenbereich haben, der 300 Pixel breit und 200 Pixel hoch ist und daneben möchte er ein Auswahlmenue für die Farbe in der der Galgen dann gezeichnet wird. Unter dem Zeichenbereich will er ein Textfeld zur Eingabe der Buchstaben und einen Button zum neu Anfangen. dazu definiert er folgendes:
 
    Thread T = null;
    drawThread dT = null;
    TextField Eingabe;
    Button Neu;
    Choice Farbe;
    Panel unten;
    Color Zeichenfarbe = null;
    String[] Woerter;
    int Wort = 0;
    int ZeichenbereichXMax = 300;
    int ZeichenbereichYMax = 200;
    int Position = 0;
    StringBuffer Ergebnis;
    int[][] Galgen;
    boolean erraten, nextLine;
 
Die "init()" Funktion hat er auch schon fast fertig. Nur mit den "GridBagConstraints" kommt er nicht so recht klar. Er will für das Textfeld so viel Platz wie möglich im Panel zuweisen und dem Knopf daneben so viel Platz wie nötig. Ergänzen Sie die fehlenden Werte und Zeilen.
 
     public void init()
    {
        Eingabe = new TextField();
        Neu = new Button("Neu");
        Farbe = new Choice();
        unten = new Panel();
        erraten = false;
        nextLine = false;;

        Zeichenfarbe = Color.black;

        setLayout(null);
 
        Farbe.addItem("Schwarz");
        Farbe.addItem("Rot");
        Farbe.addItem("Grün");
        Farbe.setLocation(?,?);
        ...?
        ...?
 
        unten.setSize(300,50);
        GridBagLayout gbl = new GridBagLayout();
        GridBagConstraints gbc = new GridBagConstraints();
        unten.setLayout(gbl);
 
        gbc.fill = ?;
        gbc.weightx = ?;
        gbc.weighty = ?;
        gbc.gridheight = ?;
        gbl.setConstraints(Eingabe, gbc);
        Eingabe.addActionListener(this);
        unten.add(Eingabe);
        gbc.gridwidth = ?;
        gbl.setConstraints(Neu, gbc);
        ...?
        unten.add(Neu);
 
        unten.setLocation(?,?);
        ...?
        initGalgen();
        initWoerter();
        setWort();
    }
 
Die Funktionen "initGalgen()", "initWoerter()" und "setWort" hat er sich nach langem Grübeln schon aus den Schwimmhäuten gesogen.
 
    private void initGalgen()
    {
        Galgen = new int[2][22];
        Galgen[0][0] = Galgen[1][3] = Galgen[1][5] = Galgen[1][6] = Galgen[1][7] = Galgen[1][8] = 0;
        Galgen[1][9] = Galgen[1][10] = 10;
        Galgen[1][4] = 20;
        Galgen[0][2] = Galgen[0][3] = Galgen[0][4] = Galgen[0][6] = 25;
        Galgen[0][1] = Galgen[0][5] = Galgen[1][11] = Galgen[1][12] = 50;
        Galgen[1][18] = Galgen[1][20] = 70;
        Galgen[0][17] = Galgen[0][21] = 80;
        Galgen[1][19] = Galgen[1][21] = 90;
        Galgen[0][7] = Galgen[0][8] = Galgen[0][9] = Galgen[0][10] = Galgen[0][11] = Galgen[0][12] = 100;
        Galgen[0][13] = Galgen[0][14] = Galgen[0][16] = Galgen[0][18] = Galgen[0][20] = 100;
        Galgen[1][13] = Galgen[1][14] = Galgen[1][16] = 110;
        Galgen[0][15] = Galgen[0][19] = 120;
        Galgen[1][15] = Galgen[1][17] = 140;
        Galgen[1][0] = Galgen[1][1] = Galgen[1][2] = 170;
    }
 
    private void initWoerter()
    {
        Woerter = new String[10];
        Woerter[0] = "dauerlutscher";
        Woerter[1] = "audiomischpult";
        Woerter[2] = "grundlagenforschung";
        Woerter[3] = "computertisch";
        Woerter[4] = "suchmaschine";
        Woerter[5] = "applikation";
        Woerter[6] = "linuxdesktop";
        Woerter[7] = "pressekodex";
        Woerter[8] = "nachrichtenredaktion";
        Woerter[9] = "risikobereitschaft";
    }


    private void setWort()
    {
        Wort = (int)((Woerter.length)*Math.random());
        Ergebnis = new StringBuffer(Woerter[Wort]);
        for (int i = 0; i<Woerter[Wort].length(); i++)
            Ergebnis.setCharAt(i,'_');
        erraten = false;
    }

Das er die Funktion "actionPerformed(ActionEvent event)" benötigt, hat ihm der Kompiler verraten, dass er darin die Aktionen des Benutzers auswerten soll und was er machen will wenn der Benutzer einen Buchstaben eingetippt hat und wenn er den Butten "Neu" drückt weiss er auch. Nur weiss er nicht wie er mitbekommt, was der Benutzer gemacht hat. Vervollständigen Sie die Funktion.

    public void actionPerformed(ActionEvent event)
    {
        if ("Wenn der Benutzer den Neu-Button gedrückt hat")
        {
            Position = 0;
            setWort();
            Eingabe.setText("");
            dT = null;
            T = null;
            repaint();
        }
        else if ("Wenn er einen Buchstaben eingegeben hat" && Position < 11 && !erraten)
        {
            if (charInWort((Eingabe.getText()).charAt(0)))
                repaint();
            else
                paintNext();
            Eingabe.setText("");
        }
    }

Jetzt erstellt er die Funktion "paintNext()". Da er ja die Klassen zum annimierten Zeichnen selbst geschrieben hat, kennt er sich super damit aus und schreibt sie Fehlerfrei selbst.

    private void paintNext()
    {
        if (T != null)
        {
            dT.drawFast();
            try
            {
                T.join();
            }
            catch (InterruptedException ex){}
        }
        Graphics gr = getGraphics();
        int i = (Position*2);
        boolean Line = true;
        if (i == 10)
            Line = false;
        dT = new drawThread(gr, Zeichenfarbe, Galgen[0][i], Galgen[1][i], Galgen[0][i+1], Galgen[1][i+1],Line);
        T = new Thread(dT);
        Position++;
        nextLine = true;
        repaint();
    }

Die Funktion "charInWort()" schreibt er auch ganz flott. Zu prüfen, ob Ein Buchstabe in einem Wort ist, ist ja nicht schwer. Alle Gefundenen Übereinstimmungen schreibt er auch gleich ins "Ergebnis". Sollten in diesem Schritt alle "Unterstriche" ersetzt werden, wird die globale Variable "erraten" auf "wahr" gesetzt.

    private boolean charInWort(char c)
    {
        boolean Buchstabe = false;
        boolean Unterstrich = false;
        for (int i = 0; i<Woerter[Wort].length(); i++)
        {
            if (Ergebnis.charAt(i) == '_')
            {
                if (Woerter[Wort].charAt(i) == c)
                {
                    Ergebnis.setCharAt(i,c);
                    Buchstabe = true;
                }
                else
                    Unterstrich = true;
            }
        }
        erraten = !Unterstrich;
        return Buchstabe;
    }

Die Funktion "paint()" ist da schon etwas schwieriger für ihn,wenn das Wort keine Unterstriche mehr enthält und der Galgen noch nicht komplett gezeichnet ist, hat der Benutzer das Wort erraten und er will das Wort ausgeben und ein schönes grosses "Erraten!!" auf den Zeichenbereich schreiben. Erledigen Sie das für ihn.

    public void paint(Graphics g)
    {
        if (erraten && Position < Galgen.length()/2)
        {
            ...?
        }

Sollte der Benutzer das Wort noch nicht erraten haben schreibt er das aktuelle Ergebnis auf den Zeichenbereich, sollte "nextLine" wahr sein, muss er am Galgen einen Strich mehr zeichnen, und alle Striche davor auffrischen da sie sonst verschwinden. Sollte der Benutzer einen richtigen Buchstaben eingegeben haben ("nextLine" ist falsch) muss er einfach nur alle Linien bis hier neu zeichnen das sie sonst ebenfalls verschwinden würden.

        else if (Position < 11)
        {
            g.drawString((new String(Ergebnis)),10, 190);
            if (nextLine)
            {
                T.start();
                nextLine = false;
                drawGalgen(g, Position-1);
            }
            else drawGalgen(g, Position);
        }

Sollte auch das nicht zutreffen hat der Benutzer leider Verloren. Dazu will er wieder das Ergebnis auf den Zeichenbereich schreiben und richtig schön gross ein "Verloren!" dazu. Erledigen Sie auch das für ihn.

        else
        {
            ...?
        }
    }

Jetzt hat er jedoch schon wieder ein Problem. Er braucht ja noch die Funktion "drawGalgen(Graphics g, int Position)", die alle striche des Galgens bis zur Position "Position" auf konventionelle Weise mit den Funktionen "drawLine(int x0, int y0, int x1, int y1)" und "drawOval(int x0, int y0, int breite, int hoehe)" aus der Klasse "Graphics" zeichnet. Der Punkt (Galgen[0][10], Galgen[1][10]) ist der oberste Punkt vom Kopf und (Galgen[0][11], Galgen[1][11]) ist der unterste Punkt vom Kopf. (Galgen[1][11]-Galgen[1][10]) ist also der Durchmesser des Kreises. Schreiben Sie die Funktion "drawGalgen(Graphics g, int Position)" mit den hier genannten Mitteln.

    private void drawGalgen(Graphics g, int Pos)
    {
        ...?
    }

Und nun fehlt ihm nur noch eine Funktion, die ihm auch vom Kompiler angezeigt wird. Sie soll die Farbauswahl des Benutzers aus dem "Choice" auswerten und die globale Variable Zeichenfarbe mit den dementsprechenden Werten belegen. Schreiben Sie auch diese Funktion und probieren Sie das Programm aus. Bei richtiger Programmierung sollte es fehlerfrei funktionieren. Es sollte dann ähnlich wie dieses hier aussehen.
 

Last updated: 09.01.2001
Stephan Finn