/*
 * KkkgAppl.java v3
 * a végleges, grafikus változat, egyszerre Applet és Application
 * last modified by pts@fazekas.hu at Fri May 18 11:53:58 CEST 2001
 * további doksi: a README-ben és e file legkülső class-ának fejkommentjében
 *
 * Kincskereső Kisgömböc (C) Early May 2001 by eNTitánok (Rév Szilvia,
 * Szabó Péter <pts@inf.bme.hu>, Szurdi Miklós, Weizengruber Attila).
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or   
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the  
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package eNTitanok.kkkg;

import eNTitanok.util.Rgb;
import eNTitanok.util.Util;
import eNTitanok.util.Veletlen;
import eNTitanok.util.Sor;
import eNTitanok.util.SorOlvaso;
import eNTitanok.kkkg.Csucslista;

import java.util.Hashtable;
import java.util.Vector;
import java.util.Calendar;
import java.applet.Applet;
import java.awt.GridLayout;
import java.awt.FlowLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.KeyAdapter;
import java.awt.event.FocusAdapter;
import java.awt.event.WindowAdapter;
import java.awt.event.MouseListener;
import java.awt.event.KeyListener;
import java.awt.event.FocusListener;
import java.awt.event.WindowListener;

import eNTitanok.gfx.OkosAWT.OkosApplet;
import eNTitanok.gfx.OkosAWT.OkosFrame;
import eNTitanok.gfx.OkosAWT.OkosCanvas;
import eNTitanok.gfx.Kepek.Kepbetolto;
import eNTitanok.gfx.Kepek.Kep;
import eNTitanok.gfx.Kepek.SdRajzolo;
import eNTitanok.gfx.Kepek.Sdpts;
import eNTitanok.gfx.Kepek.Betutipus;
import eNTitanok.gfx.Kepek.Utkozteto;
import eNTitanok.gfx.Kepek;
import eNTitanok.util.Idozito.Idozitett;
import eNTitanok.util.Idozito;

import java.io.InputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.PrintWriter; // prefer to java.io.PrintStream
import java.io.IOException;

/**
 * A fő applet téglalap.
 * mainly by pts@fazekas.hu at Sat May 12 21:36:08 CEST 2001
 */
public final class KkkgAppl extends OkosApplet {
  /**
   * Akkor váltódik ki, ha nem sikerült az applet téglalapját a megfelelő
   * méretre átméretezni. (JDK 1.3-ban általában a megfelelő méretnél nagyobb
   * lesz az téglalap, de ebbe beletörődünk.)
   */
  public static class AtmeretezesNemSikerultException extends Error {}

  /**
   * Akkor váltódik ki, ha egy objektum olyan attribútumát akarjuk
   * megváltoztatni, melyet csak egyszer szabad.
   */
  public static class MarErtekesError extends Error {
    public MarErtekesError(String s) { super(s)}
    public MarErtekesError() { super()}
  }

  /**
   * Akkor váltódik ki, ha a program futás közben bugot talál magában.
   */
  public static class AsserttError extends Error {
    public AsserttError(String s) { super(s)}
    public AsserttError() { super()}
  }

  public static class Konst {
    /**
     * D_*: A .gif-ekben szereplő RGB konstansok. A prototípusban azért van
     * rájuk szükség, mert a tesztfile-ban levő pályaleírást egy RGB képpé
     * alakítjuk, majd abból építjük fel a labirintust.
     */
    public static final int D_FAL=Rgb.C_FEKETE;
    public static final int D_UT=Rgb.C_FEHER;
    public static final int D_GYEMANT=Rgb.C_PIROS;
    public static final int D_AJANDEK=Rgb.C_SARGA; // keletkezési hely
    public static final int D_SZORNY=Rgb.C_ZOLD; // keletkezési hely
    public static final int D_MEROPONT=Rgb.C_KEK;
    public static final int D_KOMMENT=Rgb.C_LILA;
    public static final int D_KISGOMBOC=Rgb.C_TURKIZ;

    /**
     * K_*: A tesztfile-ban szereplő karakterek konstansai.
     * Minden, amit nem soroltunk fel (beleértve a szóközt),
     * K_FAL-nak minősül.
     */
    public static final char K_FAL='F';
    public static final char K_UT='.';
    public static final char K_GYEMANT='g';
    public static final char K_AJANDEK='a';
    public static final char K_SZORNY='s';
    public static final char K_KISGOMBOC='k';
    public static final char K_MEROPONT='p';
    
    /**
     * Egy K_* konstanst alakít a megfelelő D_* konstansba.
     */
    public static int k2d(char k) {
      return k==K_UT        ? D_UT
           : k==K_GYEMANT   ? D_GYEMANT
           : k==K_AJANDEK   ? D_AJANDEK
           : k==K_SZORNY    ? D_SZORNY
           : k==K_KISGOMBOC ? D_KISGOMBOC
           : k==K_MEROPONT  ? D_MEROPONT
           :                  D_FAL
           ;
    }
  } /// class Konst

  /**
   * Az őt implementáló objektum string-eket tud naplózni.
   */
  public interface Naplozo {
    public void naploz(String sor);
  }
  
  /**
   * A :Kísérő egyetlen példánya program futását végigkíséri, több játékot
   * is. Itt tárolódnak a véletlenszám-generátorok, az ütközésvizsgálók
   * engedélyező bitjei stb. A :Kísérő ezen implementációja főleg a
   * prototípushoz és nem az egész
   * projecthez tartozik. A végleges változatban a :Kiésérő ugyanezekkel az
   * attribútumokkal és metódusokkal fog bírni, viszont az implementáció
   * teljesen más lesz.
   */
  public static class Kisero extends Thread implements Naplozo {
    /**
     * A prototípus futásának egyik lehetséges kimenetele.
     */
    public static class HibasBemenetError extends Error {
      public HibasBemenetError(String s) { super(s)}
    }
    /**
     * A prototípus futásának egyik másik lehetséges kimenetele. Ugyanezzel
     * egyenértékű, ha valami váratlan, általános kivétel lép fel.
     */
    public static class VegzetesError extends Error {
      public VegzetesError(String s) { super(s)}
    }
    /**
     * A prototípus futásának harmadik lehetséges kimenetele.
     */
    public static class MeghiusultError extends Error {
      public MeghiusultError(String s) { super(s)}
    }
    /**
     * A prototípus futásának negyedik lehetséges kimenetele.
     */
    public static class SikerultError extends Error {
      public SikerultError(String s) { super(s)}
    }

    /**
     * Ebbe a file-ba mentjük el a :Csúcslistát. `null' esetén egyáltalán nem
     * mentjük el (ez történik a prototípusban).
     */
    public static final String CSUCSLISTA_FILENEV="kkkg.csl";
    // public static final String CSUCSLISTA_FILENEV=null; // CsakPro
    /**
     * A :Csúcslista.
     */
    public Csucslista csucslista=Csucslista.betolt(CSUCSLISTA_FILENEV);

    /**
     * Ez a program futása során már nem változik.
     */
    public Labirintus.LabirintusRajzolo labirintusRajzolo;
    /**
     * Ez a program futása során már nem változik.
     */
    public JobboldalRajzolo jobboldalRajzolo;
    /**
     * Ez a program futása során már nem változik.
     */
    public Kepbetolto kepbetolto;
    /**
     * Ez a program futása során már nem változik.
     */
    public Idozitett idozitett;

    /**
     * Hányadik ciklusban járunk? Ez néha nullázódik (pl. új Labirintus
     * betöltésekor).
     */
    int ciklus=0;
    /**
     * Pontosan akkor `true', ha ezeddig még nem derült ki, hogy a teszt
     * meghiúsult.
     */
    public boolean sikerult=true;
    /**
     * (false) Pontosan akkor true, ha nem generálunk valódi véletlenszámokat, hanem
     * mindent a tesztfile-ból veszünk. A prototípusban volt true.
     */
    public boolean csakDet=false;
    // public boolean csakDet=true; // CsakPro
    /**
     * Pontosan akkor true, ha a megfelelő ütközést figyeljük.
     */
    public boolean Kisgomboc_Ajandek=true;
    /**
     * Pontosan akkor true, ha a megfelelő ütközést figyeljük.
     */
    public boolean Kisgomboc_Szorny=true;
    /**
     * Pontosan akkor true, ha a megfelelő ütközést figyeljük.
     */
    public boolean Kisgomboc_Gyemant=true;
    /**
     * Pontosan akkor true, ha a megfelelő ütközést figyeljük.
     */
    public boolean Kisgomboc_KetyegoBomba=true;
    /**
     * Pontosan akkor true, ha a megfelelő ütközést figyeljük.
     */
    public boolean Szorny_KetyegoBomba=true;
    /**
     * A prototípus tesztfile-jának a neve.
     */
    public String teszt;
    /**
     * A prototípus naplófile-jának a neve.
     */
    public String naplo;
    /**
     * A prototípus ellenörzőfile-jának a neve.
     */
    public String ellenorzo;
    /**
     * A prototípus tesztfile-ja olvasásra megnyitva.
     */
    protected SorOlvaso tesztf;
    /**
     * A prototípus naplófile-ja írásra megnyitva.
     */
    protected PrintWriter naplof;
    /**
     * A prototípus ellenörzőfile-ja írásra megnyitva.
     */
    protected PrintWriter ellenorzof;
    /**
     * A `palya' egyetlen karakterének ,,mérete'', pixelben.
     */
    public static final int KOCKAMERET=25;
    
    /**
     * A labirintussor egyetlen eleme. Azért nem `static', hogy a csakDet
     * látszódjon.
     */
    public class Labielem {
      public String palya_alja="(palya_alja).gif";
      public String palya_teteje="(palya_teteje).gif";
      public String palya_arnyeka="(palya_arnyeka).gif";
      public String palya_grafja="(palya_grafja).gif";
      public String palya_jobbja="(palya_jobbja).gif";
      /**
       * String-ekből álló Sor, lényegében a tesztfile-ban leírt labirintus
       * gráfleírásának sorai. Soremelés-karakter nélkül.
       */
      // protected Sor palya=new Sor();
      /**
       * Milyen hosszú a `palya' leghosszabb sora?
       */
      protected int palyaMaxx=0;
      /**
       * Új sort vesz fel `palya' végére.
       */
      public void vegehezRak(String s) {
        /*/ // CsakPro if (s.length()>palyaMaxx) palyaMaxx=s.length();
        palya.vegehezFuz(s);
        /***/
      }
      /**
       * Egy RGB színmodellű képtömböt ad vissza a pályáról (úgy, mintha
       * .gif-ből töltöttük volna). A `t[y][x]' érték az adott
       * pont (R&lt;&lt;16)+(G&lt;&lt;8)+B értéke, ahol a komponensek 0..255-ig futnak.
       * Mellékhatásként kiüríti `palya'-t.
       */
      public synchronized int[][] getPix() {
        return null;
        /*/ // CsakPro
        if (palya.length()<1 || palyaMaxx<0) throw new HibasBemenetError("palya tul kicsi");
        // !! Imp: chk for s,a,k,??
        int h=(palya.length()+2)*KOCKAMERET+1;
        int w=(palyaMaxx+2)*KOCKAMERET+1;
        char c[]=new char[palyaMaxx];
        int t[][]=new int[h][];
        int x, y;
        for (y=h-1;y>=0;y--) t[y]=new int[w];
        // ^^^ mindenki 0-s, vagyis Konst.D_FAL
        int alap=KOCKAMERET;
        String sor1;
        int i, k;
        y=alap;
        for (y=alap;null!=(sor1=(String)palya.elsoTorol());y+=KOCKAMERET) {
          sor1.getChars(0,sor1.length(),c,0);
          for (i=sor1.length();i<c.length;i++) c[i]=Konst.K_FAL;
          int u[]=t[y];
          x=alap;
          for (i=0;i<c.length;i++) {
            // System.err.println(w-x); // DEBUG
            if ((u[x]=Konst.k2d(c[i]))!=Konst.D_FAL) {
              if (u[x-KOCKAMERET]!=Konst.D_FAL) for (k=x-KOCKAMERET+1;k<x;k++) u[k]=Konst.D_UT;
              if (u[x+KOCKAMERET]!=Konst.D_FAL) for (k=x+KOCKAMERET-1;k>x;k--) u[k]=Konst.D_UT;
              if (t[y-KOCKAMERET][x]!=Konst.D_FAL) for (k=y-KOCKAMERET+1;k<y;k++) t[k][x]=Konst.D_UT;
              if (t[y+KOCKAMERET][x]!=Konst.D_FAL) for (k=y+KOCKAMERET-1;k>y;k--) t[k][x]=Konst.D_UT;
            } /// IF
            x+=KOCKAMERET;
          } /// NEXT i
        } /// NEXT y
        return t;
        /***/
      } /// getPix()
      
      private int bonbomsimszu_alap[]{ 42, 42, 42, 42 };
      /**
       * Milyen eloszlásban keletkezzenek az :Ajándék-ok?
       */
      public Veletlen.Generalo bonbomsimszu=new Veletlen.Veges(null, csakDet, bonbomsimszu_alap);
      private int okosbutabaljobbbfjl_alap[]{ 28, 28, 28, 28, 0, 0 };
      /**
       * Milyen eloszlásban keletkezzenek az :Szörny-ek?
       */
      public Veletlen.Generalo okosbutabaljobbbfjl=new Veletlen.Veges(null, csakDet, okosbutabaljobbbfjl_alap);
      /**
       * Hányadik szinten járunk?. Csak tájékoztatásul, nem írjuk ki sehol.
       */
      int szintszam=1;
      /**
       * Mikor keletkezzen a következő :Ajándék?. A véletlenszám relatív,
       * ciklusban mérendő.
       */
      public Veletlen.Generalo ajandek=new Veletlen.Normalis(null, csakDet, 680, 760, 720, 20);
      /**
       * Mikor keletkezzen a következő :Szörny?. A véletlenszám relatív,
       * ciklusban mérendő.
       */
      public Veletlen.Generalo szorny=new Veletlen.Normalis(null, csakDet, 680, 760, 720, 20);
      /**
       * Mekkora legyen a keletkező szörny sebessége?
       */
      public Veletlen.Generalo szornyseb=new Veletlen.Normalis(null, csakDet, 20, 40, 30, 5);
      /**
       * Hol (melyik keletkezési helyen) keletkezzen :Ajándék? Ezt a :Labirintus
       * betöltésekor a megfelelő egyenletes eloszlásra állítjuk.
       */
      public Veletlen.Egyenletes ajandekhol=new Veletlen.Egyenletes(null, csakDet, 0, 1);
      /**
       * A megadott ajándékhelyek számából előállítja a véletlenszám-generátort.
       */
      public void ajandekholMeret(int meret) {
        ajandekhol.setB(meret);
      }
      /**
       * Hol (melyik keletkezési helyen) keletkezzen :Szörny? Ezt a :Labirintus
       * betöltésekor a megfelelő egyenletes eloszlásra állítjuk.
       */
      public Veletlen.Egyenletes szornyhol=new Veletlen.Egyenletes(null, csakDet, 0, 1);
      /**
       * Merre forduljon a következő :Szörny a következő döntési helyzetben?.
       */
      public Veletlen.Generalo fordul=new Veletlen.Egyenletes(null, csakDet, 0, 256);
      /**
       * A megadott szörnyhelyek számából előállítja a véletlenszám-generátort.
       */
      public void szornyholMeret(int meret) {
        szornyhol.setB(meret);
      }
    } /// class Labielem

    /**
     * A labirintussor, :Labielem-ekből áll.
     * @see Labielem
     */
    public Sor labirintussor=new Sor();

    public Sor labirintusklon;
    /**
     * Az ellenörzősor, String-ekből (sorokból) áll.
     */
    public Sor ellenorzosor=new Sor();
    
    /**
     * Létrehozza a :Kísérőt, a megadott tesztfile nevét véve paraméternek.
     */
    public Kisero(String teszt) {
      this.teszt=teszt;
      try {
        tesztf=new SorOlvaso(new FileInputStream(teszt));
      } catch (IOException e) { throw new VegzetesError("IO: "+e.getMessage())}
    } /// Kisero()

    /**
     * Létrehozza a :Kísérőt, a megadott tesztfile nevét és az előre megnyitott
     * tesztfile-t véve paraméternek.
     */
    public Kisero(String teszt, SorOlvaso ins) {
      if (ins==null || teszt==null) throw new NullPointerException();
      this.teszt=teszt;
      tesztf=ins;
    }
    /**
     * Létrehozza a :Kísérőt, a megadott tesztfile nevét és az előre megnyitott
     * tesztfile-t véve paraméternek.
     */
    public Kisero(String teszt, InputStream ins) {
      this(teszt, new SorOlvaso(ins));
    }
    
    /**
     * Mivel ez már nem a prototípus, nem csinál semmit. A prototípusban:
     * Kiírja a megadott sort a naplófile-ba, és azonnal ellenőrzi, hogy
     * megegyezik-e a várttal. A `sor' ne tartalmazzon soremelést.
     */
    public synchronized void naploz(String sor) {
      /*/
      if (naplof==null) throw new HibasBemenetError("`naplo' sor nem szerepelt");
      sor=ciklus+" "+sor;
      naplof.println(sor);
      if (naplof.checkError()) throw new VegzetesError("IO: "+naplo);
      if (sikerult) { // még van remény, hogy a teszt sikerüljön
        String sor2=(String)ellenorzosor.elsoTorol();
        if (sor2==null || !sor2.equals(sor)) sikerult=false;
      }
      /***/
    } /// naploz()
    
    /**
     * Csakúgy, mint `this.naploz()', de minden hibát elhallgat, nem vált ki
     * kivételt.
     */
    public void naplozHibatlan(String sor) {
      /*/
      try {
        naploz(sor);
      } catch (Throwable e) {}
      /***/
    } /// naplozHibatlan()
  
    /**
     * Az időpont, amikor ez az objektum létrejött.
     */
    Calendar calendar=Calendar.getInstance();
    
    /**
     * A hátralevő olyan ciklusok száma, melyek során nem olvasunk a
     * tesztfile-ból.
     */
    protected int hatra=0;
    
    public static final String FIGYELJUK="figyeljuk";
    public static final String TITKOLJUK="titkoljuk";
    /**
     * Egyetlen ciklust előrelép az időben. Közben olvassa a tesztfile-t, tölti
     * a sorokat stb.
     */
    public void gyerunk() {
      ciklus++;
      while (hatra==0) {
        String sor;
        try {
          sor=tesztf.readLine();
        } catch (IOException e) { throw new VegzetesError("IO: "+e.getMessage())}
        // System.err.println(sor); // DEBUG
        if (null==sor) throw new HibasBemenetError("hianyzo `vege' utasitas");
        int i=sor.indexOf(' ')if (i==-1) i=sor.length();
        String utasitas=sor.substring(0,i);
        while (i<sor.length() && sor.charAt(i)==' ') i++;
        sor=sor.substring(i);
        String rosszpar="rossz parameter `"+utasitas+"' utasitasnak";
        boolean sorszokoz=sor.indexOf(' ')!=-1;
        if (utasitas.equals("kell")) {
          if (ellenorzo==null) throw new HibasBemenetError("`ellenorzo' korabban szerepeljen");
          ellenorzof.println(sor);
          if (ellenorzof.checkError()) throw new VegzetesError("IO: "+ellenorzo);
          ellenorzosor.vegehezFuz(sor);
        } else if (utasitas.equals("vege")) {
          // naploz("vege"); // CsakPro 
          if (sor.length()!=0) throw new HibasBemenetError(rosszpar);
          if (sikerult && ellenorzosor.isUres()) throw new SikerultError("");
          // System.err.println(sikerult);
          throw new MeghiusultError("");
        } else if (utasitas.equals("fordul")) {
          if (sor.length()!=1) throw new HibasBemenetError(rosszpar);
          if (labirintussor.isUres()) throw new HibasBemenetError("`labirintus' korabban szerepeljen");
          char c=sor.charAt(0);
               if (c=='<') ((Labielem)labirintussor.utolso()).fordul.sorba(Csucs.BAL);
          else if (c=='>') ((Labielem)labirintussor.utolso()).fordul.sorba(Csucs.JOBB);
          else if (c=='^') ((Labielem)labirintussor.utolso()).fordul.sorba(Csucs.FEL);
          else if (c=='v') ((Labielem)labirintussor.utolso()).fordul.sorba(Csucs.LE);
          else throw new HibasBemenetError(rosszpar);
        } else if (utasitas.equals("leut")) {
          if (sor.length()!=1) throw new HibasBemenetError(rosszpar);
          if (jatek==null) throw new HibasBemenetError("`leut' kesobb szerepeljen");
          char c=sor.charAt(0);
               if (c=='<') jatek.fordulj(Csucs.BAL);
          else if (c=='>') jatek.fordulj(Csucs.JOBB);
          else if (c=='^') jatek.fordulj(Csucs.FEL);
          else if (c=='v') jatek.fordulj(Csucs.LE);
          else if (c=='-') jatek.bombatLerak();
          else if (c=='?') jatek.megallit();
          else if (c=='!') jatek.lezar();
          else             jatek.hozzafuz(c);
        } else if (utasitas.equals("ciklus")) {
          try {
            hatra=Integer.parseInt(sor);
            if (hatra<0) throw new NumberFormatException();
          } catch (NumberFormatException e) { throw new HibasBemenetError(rosszpar)}
        } else if (utasitas.equals("szintszam")) {
          int ia;
          try {
            ia=Integer.parseInt(sor);
            if (ia<0) throw new NumberFormatException();
          } catch (NumberFormatException e) { throw new HibasBemenetError(rosszpar)}
          ((Labielem)labirintussor.utolso()).szintszam=ia;
          String ss=Util.decformat(ia, 3);
          ((Labielem)labirintussor.utolso()).palya_alja=   "p_"+ss+"h.gif";
          ((Labielem)labirintussor.utolso()).palya_teteje= "p_"+ss+"e.gif";
          ((Labielem)labirintussor.utolso()).palya_arnyeka="p_"+ss+"c.gif";
          ((Labielem)labirintussor.utolso()).palya_grafja= "p_"+ss+"g.gif";
          ((Labielem)labirintussor.utolso()).palya_jobbja= "p_"+ss+"j.gif";
        } else if (utasitas.equals("naplo")) {
          if (sor.length()<1 || sorszokoz) throw new HibasBemenetError(rosszpar);
          if (naplo!=null) throw new HibasBemenetError("`naplo' egyszer szerepeljen");
          naplo=sor;
          /*/ // CsakPro
          try {
            naplof=new PrintWriter(new FileOutputStream(naplo));
          } catch (IOException e) { throw new VegzetesError("IO: "+e.getMessage())}
          naplof.println("#\n# naplofile "+naplo+"\n"+
            "# (tesztfile "+teszt+")\n"+
            "# generalva "+Util.mysqlDateFormat(calendar)+
            "\n# ebbe kerul a program tenyleges futasi eredmenye\n#\n");
          if (naplof.checkError()) throw new VegzetesError("IO: "+naplo);
          /***/
        } else if (utasitas.equals("ellenorzo")) {
          if (sor.length()<1 || sorszokoz) throw new HibasBemenetError(rosszpar);
          if (ellenorzo!=null) throw new HibasBemenetError("`ellenorzo' egyszer szerepeljen");
          ellenorzo=sor;
          /*/ // CsakPro
          try {
            ellenorzof=new PrintWriter(new FileOutputStream(ellenorzo));
          } catch (IOException e) { throw new VegzetesError("IO: "+e.getMessage())}
          ellenorzof.println("#\n# ellenorzofile "+ellenorzo+"\n"+
            "# (tesztfile "+teszt+")\n"+
            "# generalva "+Util.mysqlDateFormat(calendar)+
            "\n# ebbe kerul a vart futasi eredmeny\n#\n");
          if (ellenorzof.checkError()) throw new VegzetesError("IO: "+naplo);
          /***/
        } else if (utasitas.equals("labirintus")) {
          if (sor.length()!=0) throw new HibasBemenetError(rosszpar);
          labirintussor.vegehezFuz(new Labielem());
        } else if (utasitas.equals("palya")) {
          if (sor.length()<1 || sorszokoz) throw new HibasBemenetError(rosszpar);
          if (labirintussor.isUres()) throw new HibasBemenetError("`labirintus' korabban szerepeljen");
          // ((Labielem)labirintussor.utolso()).vegehezRak(sor); // CsakPro
        } else if (utasitas.equals("palya_alja")) {
          if (sor.length()<1 || sorszokoz) throw new HibasBemenetError(rosszpar);
          if (labirintussor.isUres()) throw new HibasBemenetError("`labirintus' korabban szerepeljen");
          ((Labielem)labirintussor.utolso()).palya_alja=sor;
        } else if (utasitas.equals("palya_teteje")) {
          if (sor.length()<1 || sorszokoz) throw new HibasBemenetError(rosszpar);
          if (labirintussor.isUres()) throw new HibasBemenetError("`labirintus' korabban szerepeljen");
          ((Labielem)labirintussor.utolso()).palya_teteje=sor;
        } else if (utasitas.equals("palya_arnyeka")) {
          if (sor.length()<1 || sorszokoz) throw new HibasBemenetError(rosszpar);
          if (labirintussor.isUres()) throw new HibasBemenetError("`labirintus' korabban szerepeljen");
          ((Labielem)labirintussor.utolso()).palya_arnyeka=sor;
        } else if (utasitas.equals("palya_grafja")) {
          if (sor.length()<1 || sorszokoz) throw new HibasBemenetError(rosszpar);
          if (labirintussor.isUres()) throw new HibasBemenetError("`labirintus' korabban szerepeljen");
          ((Labielem)labirintussor.utolso()).palya_grafja=sor;
        } else if (utasitas.equals("palya_jobbja")) {
          if (sor.length()<1 || sorszokoz) throw new HibasBemenetError(rosszpar);
          if (labirintussor.isUres()) throw new HibasBemenetError("`labirintus' korabban szerepeljen");
          ((Labielem)labirintussor.utolso()).palya_jobbja=sor;
        } else if (utasitas.equals("ajandek")) {
          int t[]=Util.szamokInt(sor);
          if (t.length!=2) throw new HibasBemenetError(rosszpar);
          if (labirintussor.isUres()) throw new HibasBemenetError("`labirintus' korabban szerepeljen");
          ((Labielem)labirintussor.utolso()).ajandek=new Veletlen.Normalis(null, csakDet, t[0]-2*t[1], t[0]+2*t[1], t[0], t[1]);
        } else if (utasitas.equals("szorny")) {
          int t[]=Util.szamokInt(sor);
          if (t.length!=2) throw new HibasBemenetError(rosszpar);
          if (labirintussor.isUres()) throw new HibasBemenetError("`labirintus' korabban szerepeljen");
          ((Labielem)labirintussor.utolso()).szorny=new Veletlen.Normalis(null, csakDet, t[0]-2*t[1], t[0]+2*t[1], t[0], t[1]);
        } else if (utasitas.equals("szornyseb")) {
          int t[]=Util.szamokInt(sor);
          if (t.length!=2) throw new HibasBemenetError(rosszpar);
          if (labirintussor.isUres()) throw new HibasBemenetError("`labirintus' korabban szerepeljen");
          ((Labielem)labirintussor.utolso()).szornyseb=new Veletlen.Normalis(null, csakDet, t[0]-2*t[1], t[0]+2*t[1], t[0], t[1]);
        } else if (utasitas.equals("bonbomsimszu")) {
          int t[]=Util.szamokInt(sor);
          if (!Util.eloszlasp(t,4)) throw new HibasBemenetError(rosszpar);
          if (labirintussor.isUres()) throw new HibasBemenetError("`labirintus' korabban szerepeljen");
          ((Labielem)labirintussor.utolso()).bonbomsimszu=new Veletlen.Veges(null, csakDet, t);
        } else if (utasitas.equals("okosbutabaljobbbfjl")) {
          int t[]=Util.szamokInt(sor);
          if (!Util.eloszlasp(t,6)) throw new HibasBemenetError(rosszpar);
          if (labirintussor.isUres()) throw new HibasBemenetError("`labirintus' korabban szerepeljen");
          ((Labielem)labirintussor.utolso()).okosbutabaljobbbfjl=new Veletlen.Veges(null, csakDet, t);
        } else if (utasitas.equals("Bonusz")) {
          int t[]=Util.szamokInt(sor);
          if (t.length!=2) throw new HibasBemenetError(rosszpar);
          if (labirintussor.isUres()) throw new HibasBemenetError("`labirintus' korabban szerepeljen");
          Labielem le=((Labielem)labirintussor.utolso());
          le.bonbomsimszu.sorba(0);
          le.ajandek.sorbaDelta(t[0]);
          le.ajandekhol.sorba(t[1]);
        } else if (utasitas.equals("FelvehetoBomba")) {
          int t[]=Util.szamokInt(sor);
          if (t.length!=2) throw new HibasBemenetError(rosszpar);
          if (labirintussor.isUres()) throw new HibasBemenetError("`labirintus' korabban szerepeljen");
          Labielem le=((Labielem)labirintussor.utolso());
          le.bonbomsimszu.sorba(1);
          le.ajandek.sorbaDelta(t[0]);
          le.ajandekhol.sorba(t[1]);
        } else if (utasitas.equals("SimaElixir")) {
          int t[]=Util.szamokInt(sor);
          if (t.length!=2) throw new HibasBemenetError(rosszpar);
          if (labirintussor.isUres()) throw new HibasBemenetError("`labirintus' korabban szerepeljen");
          Labielem le=((Labielem)labirintussor.utolso());
          le.bonbomsimszu.sorba(2);
          le.ajandek.sorbaDelta(t[0]);
          le.ajandekhol.sorba(t[1]);
        } else if (utasitas.equals("SzuperElixir")) {
          int t[]=Util.szamokInt(sor);
          if (t.length!=2) throw new HibasBemenetError(rosszpar);
          if (labirintussor.isUres()) throw new HibasBemenetError("`labirintus' korabban szerepeljen");
          Labielem le=((Labielem)labirintussor.utolso());
          le.bonbomsimszu.sorba(3);
          le.ajandek.sorbaDelta(t[0]);
          le.ajandekhol.sorba(t[1]);
        } else if (utasitas.equals("OkosSzorny")) {
          int t[]=Util.szamokInt(sor);
          if (t.length!=3) throw new HibasBemenetError(rosszpar);
          if (labirintussor.isUres()) throw new HibasBemenetError("`labirintus' korabban szerepeljen");
          Labielem le=((Labielem)labirintussor.utolso());
          le.okosbutabaljobbbfjl.sorba(0);
          le.szorny.sorbaDelta(t[0]);
          le.szornyhol.sorba(t[1]);
          le.szornyseb.sorba(t[2]);
        } else if (utasitas.equals("ButaSzorny")) {
          int t[]=Util.szamokInt(sor);
          if (t.length!=3) throw new HibasBemenetError(rosszpar);
          if (labirintussor.isUres()) throw new HibasBemenetError("`labirintus' korabban szerepeljen");
          Labielem le=((Labielem)labirintussor.utolso());
          le.okosbutabaljobbbfjl.sorba(1);
          le.szorny.sorbaDelta(t[0]);
          le.szornyhol.sorba(t[1]);
          le.szornyseb.sorba(t[2]);
        } else if (utasitas.equals("BalraSzorny")) {
          int t[]=Util.szamokInt(sor);
          if (t.length!=3) throw new HibasBemenetError(rosszpar);
          if (labirintussor.isUres()) throw new HibasBemenetError("`labirintus' korabban szerepeljen");
          Labielem le=((Labielem)labirintussor.utolso());
          le.okosbutabaljobbbfjl.sorba(2);
          le.szorny.sorbaDelta(t[0]);
          le.szornyhol.sorba(t[1]);
          le.szornyseb.sorba(t[2]);
        } else if (utasitas.equals("JobbraSzorny")) {
          int t[]=Util.szamokInt(sor);
          if (t.length!=3) throw new HibasBemenetError(rosszpar);
          if (labirintussor.isUres()) throw new HibasBemenetError("`labirintus' korabban szerepeljen");
          Labielem le=((Labielem)labirintussor.utolso());
          le.okosbutabaljobbbfjl.sorba(3);
          le.szorny.sorbaDelta(t[0]);
          le.szornyhol.sorba(t[1]);
          le.szornyseb.sorba(t[2]);
        } else if (utasitas.equals("BalraFelSzorny")) {
          int t[]=Util.szamokInt(sor);
          if (t.length!=3) throw new HibasBemenetError(rosszpar);
          if (labirintussor.isUres()) throw new HibasBemenetError("`labirintus' korabban szerepeljen");
          Labielem le=((Labielem)labirintussor.utolso());
          le.okosbutabaljobbbfjl.sorba(4);
          le.szorny.sorbaDelta(t[0]);
          le.szornyhol.sorba(t[1]);
          le.szornyseb.sorba(t[2]);
        } else if (utasitas.equals("JobbraLeSzorny")) {
          int t[]=Util.szamokInt(sor);
          if (t.length!=3) throw new HibasBemenetError(rosszpar);
          if (labirintussor.isUres()) throw new HibasBemenetError("`labirintus' korabban szerepeljen");
          Labielem le=((Labielem)labirintussor.utolso());
          le.okosbutabaljobbbfjl.sorba(5);
          le.szorny.sorbaDelta(t[0]);
          le.szornyhol.sorba(t[1]);
          le.szornyseb.sorba(t[2]);
        } else if (utasitas.equals("Kisgomboc-Ajandek")) {
          if (sor.equals(FIGYELJUK)) Kisgomboc_Ajandek=true;
          else if (sor.equals(TITKOLJUK)) Kisgomboc_Ajandek=false;
          else throw new HibasBemenetError(rosszpar);
        } else if (utasitas.equals("Kisgomboc-Szorny")) {
          if (sor.equals(FIGYELJUK)) Kisgomboc_Szorny=true;
          else if (sor.equals(TITKOLJUK)) Kisgomboc_Szorny=false;
          else throw new HibasBemenetError(rosszpar);
        } else if (utasitas.equals("Kisgomboc-Gyemant")) {
          if (sor.equals(FIGYELJUK)) Kisgomboc_Gyemant=true;
          else if (sor.equals(TITKOLJUK)) Kisgomboc_Gyemant=false;
          else throw new HibasBemenetError(rosszpar);
        } else if (utasitas.equals("Kisgomboc-KetyegoBomba")) {
          if (sor.equals(FIGYELJUK)) Kisgomboc_KetyegoBomba=true;
          else if (sor.equals(TITKOLJUK)) Kisgomboc_KetyegoBomba=false;
          else throw new HibasBemenetError(rosszpar);
        } else if (utasitas.equals("Szorny-KetyegoBomba")) {
          if (sor.equals(FIGYELJUK)) Szorny_KetyegoBomba=true;
          else if (sor.equals(TITKOLJUK)) Szorny_KetyegoBomba=false;
          else throw new HibasBemenetError(rosszpar);
        } else {
          throw new HibasBemenetError("ismeretlen utasitas: `"+utasitas+"'");
        } /// IF
      } /// WHILE
      hatra--;
    } /// gyerunk()
    
    /**
     * Az aktuális :Játék.
     */
    protected Jatek jatek;
    
    private static String vvh="varatlan vegzetes hiba";
    
    //public void visszaKlonoz() {
    //  labirintussor=labirintusklon.klonoz();
    //}

    /**
     * Ez fut a főszálban. Csak apró módosítások a prototípushoz képest.
     */
    public void run() {
      super.setPriority(Thread.MIN_PRIORITY);
      // ^^^ Dat: fontos az allando sebesseghez. Miert??
      try {
        gyerunk();
        // ^^^ a tesztfile elejének beolvasása, első lépésre várás. Ez már
        //     nem a prototípus, úgyhogy csak itt hívjuk meg, a Jatek.fut()-ból
        //     már nem.
        labirintusklon=labirintussor.klonoz();
        while (true) {
          // System.err.println("ELEN"); // DEBUG
          jatek=new Jatek(this);
          jatek.fut();
          labirintussor=labirintusklon.klonoz();
        }
      } catch (Labirintus.HibasGrafError e) {
        System.err.println("hibas tesztfile");
        System.err.println("a megadott labirintusgraf hibas");
        e.printStackTrace(System.err);
      } catch (HibasBemenetError e) {
        System.err.println("hibas tesztfile");
        e.printStackTrace(System.err);
      } catch (SikerultError e) {
        System.err.println("teszt sikerult (nem szabadna bekovetkeznie!)");
      } catch (MeghiusultError e) {
        System.err.println("teszt meghiusult (nem szabadna bekovetkeznie!)");
        sikerult=false;
      } catch (Veletlen.CsakDetException e) {
        System.err.println(vvh);
        System.err.println("tul keves veletlenszamot adtal meg");
        // naplozHibatlan(vvh); // CsakPro
        sikerult=false;
        e.printStackTrace(System.err);
      } catch (VegzetesError e) {
        System.err.println(vvh);
        // naplozHibatlan(vvh); // CsakPro
        sikerult=false;
        e.printStackTrace(System.err);
      } catch (Throwable e) {
        System.err.println(vvh);
        // naplozHibatlan(vvh); // CsakPro
        e.printStackTrace(System.err);
        sikerult=false;
      }
    } /// run()
    
    /**
     * A felhasználó által utoljára leütött billentyűt (betűt) adja vissza,
     * vagy 0-t, ha nem volt ilyen.
     */
    public char utolsoBillentyu() {
      return 0;
    }
    
  } /// class Kisero

  public static class Csucs {
    /**
     * Hányadik mérőpont ez a csúcs?. Ha nem mérőpont, akkor -1.
     */
    protected int meropont=-1;
    public int getMeropont() { return meropont; }
    public void setMeropont(int meropont) { 
      if (this.meropont!=-1) throw new MarErtekesError();
      this.meropont=meropont;
    }
    public static class NincsRajtaException extends Error {}
    public static class NemKothetoOsszeException extends Error {}
    public static final int LE=0, FEL=2, JOBB=1, BAL=3, PIHI=4, SEMERRE=5;
    /**
     * A négy szomszéd :Csúcs.
     */
    protected Csucs szomsz[];
    protected int x, y;
    /**
     * Milyen messza van innen a :Kisgömböc?. A lehető legrövidebb út
     * távolsága.
     */
    protected int legkoztav;
    public void setTavolsag(int legkoztav) { this.legkoztav=legkoztav; }
    public int getTavolsag() { return legkoztav; }
    
    public Csucs(int x, int y) {
      this.x=x;
      this.y=y;
      szomsz=new Csucs[4];
    }
    public Csucs getSzomsz(int merre) { return szomsz[merre]}
    public Csucs getSzomsz0(int merre) { return szomsz[merre]!=null ? szomsz[merre]this}
    public int getX() { return x; }
    public int getY() { return y; }
    public void felold() { szomsz[FEL]=szomsz[LE]=szomsz[JOBB]=szomsz[BAL]=null}
    public void osszekot(Csucs masik) {
      /* összeköti ezt a csúcsot egy másikkal */
      if (masik.x==x) {
             if (masik.y<y) { szomsz[FEL]=masik; masik.szomsz[LE]=this}
        else if (masik.y>y) { szomsz[LE]=masik; masik.szomsz[FEL]=this}
        else throw new NemKothetoOsszeException();
      } else if (masik.y==y) {
             if (masik.x<x) { szomsz[BAL]=masik; masik.szomsz[JOBB]=this}
        else if (masik.x>x) { szomsz[JOBB]=masik; masik.szomsz[BAL]=this}
        else throw new NemKothetoOsszeException();
      } else throw new NincsRajtaException();
    }
    /**
     * Segédtömb `merreLegrovidebb()'-nek.
     */
    int merret[]=new int[5];
    /**
     * Segédtömb `merreLegrovidebb()'-nek és `merreVeletlen()'-nek.
     */
    int merrei[]=new int[5];
    /**
     * Azt az irányt adja vissza, amelyen a :Kisgömböc-öt leghamarabb el
     * lehet érni. `generalo'-t csak akkor használja, ha több irányba is
     * ugyanolyan messze van a :Kisgömböc.
     */
    int merreLegrovidebb(Veletlen.Generalo generalo) {
      merret[FEL]=(szomsz[FEL]!=null)?szomsz[FEL].legkoztav+tavolsag(szomsz[FEL]):Integer.MAX_VALUE;
      merret[LE]=(szomsz[LE]!=null)?szomsz[LE].legkoztav+tavolsag(szomsz[LE]):Integer.MAX_VALUE;
      merret[JOBB]=(szomsz[JOBB]!=null)?szomsz[JOBB].legkoztav+tavolsag(szomsz[JOBB]):Integer.MAX_VALUE;
      merret[BAL]=(szomsz[BAL]!=null)?szomsz[BAL].legkoztav+tavolsag(szomsz[BAL]):Integer.MAX_VALUE;
      // System.err.println(merret[FEL]+" "+merret[LE]+" "+merret[JOBB]+" "+merret[BAL]+"."); // DBG
      merrei[FEL]=FEL;
      merrei[LE]=LE;
      merrei[JOBB]=JOBB;
      merrei[BAL]=BAL;
      boolean g=false;
      // vvv 4 elem egy lehetséges rendezőhálózata :-)
      do { g=!g;
        if (merret[2]<merret[1]) {
          merrei[4]=merrei[2]; merrei[2]=merrei[1]; merrei[1]=merrei[4];
          merret[4]=merret[2]; merret[2]=merret[1]; merret[1]=merret[4];
        }
        if (merret[1]<merret[0]) {
          merrei[4]=merrei[1]; merrei[1]=merrei[0]; merrei[0]=merrei[4];
          merret[4]=merret[1]; merret[1]=merret[0]; merret[0]=merret[4];
        }
        if (merret[3]<merret[2]) {
          merrei[4]=merrei[3]; merrei[3]=merrei[2]; merrei[2]=merrei[4];
          merret[4]=merret[3]; merret[3]=merret[2]; merret[2]=merret[4];
        }
      } while (g);
      // System.err.println("M"+merret[0]+" "+merret[1]+" "+merret[2]+" "+merret[3]+"."); // DBG
      if (merret[0]==merret[1]) { int mod=2;
        if (merret[1]==merret[2]) { mod++;
          if (merret[2]==merret[3]) mod++;
        }
        /*/ // CsakPro
        int gen=generalo.general()%4;
        if (gen>=mod) throw new Kisero.HibasBemenetError("arra nem legrovidebb");
        return gen;
        /***/
        int gen=generalo.general()%mod;
        if (gen>=mod) throw new Kisero.HibasBemenetError("arra nem legrovidebb");
        return merrei[gen];
      } else return merrei[0];
    } /// merreLegrovidebb()
    /**
     * A megadott `generalo' segítségével egy véletlenszerű indulási irányt
     * jelöl meg ebből a csúcsból, ami lehetőleg nem `elkerul'.
     */
    int merreVeletlen(Veletlen.Generalo generalo, int elkerul) {
      int lehet=(szomsz[0]==null?0:1)+(szomsz[2]==null?0:1)+
                (szomsz[1]==null?0:1)+(szomsz[3]==null?0:1);
      if (lehet<2) elkerul=Csucs.PIHI;
      int irany=generalo.general();
      if (irany>=0 && irany<4 && irany!=elkerul) return irany;
      // if (irany==elkerul) System.err.println("elkerul "+elkerul); // DBG
      //               else System.err.println("RIRI"); // DBG
      // if (true) throw new AsserttError("riri"); // DBG
      int j=0;
      for (int i=0;i<4;i++) if (i!=elkerul && szomsz[i]!=null) merrei[j++]=i;
      // if (j==0 && elkerul<4 && szomsz[elkerul]!=null) merrei[j++]=elkerul;
      if (j==0) throw new AsserttError("elszigetelt :Csucs");
      return merrei[generalo.general()%j];
    }

    /**
     * A szomszédai `legkoztav'-ját próbálja csökkenteni; ha sikerül, felveszi
     * őket a :Sor-ba.
     */
    public void kozelit(Sor sor) {
      int tav;
      for (int i=0;i<4;i++) if (szomsz[i]!=null && szomsz[i].legkoztav>(tav=legkoztav+tavolsag(szomsz[i]))) {
        szomsz[i].legkoztav=tav;
        sor.vegehezFuz(szomsz[i]);
      }
    }
    /**
     * A szomszédai `legkoztav'-ját próbálja növelni Integer.MAX_VALUE-ra;
     * ha sikerül, felveszi őket a :Sor-ba.
     */
    public void tavolit(Sor sor) {
      for (int i=0;i<4;i++) if (szomsz[i]!=null && szomsz[i].legkoztav!=Integer.MAX_VALUE) {
        szomsz[i].legkoztav=Integer.MAX_VALUE;
        sor.vegehezFuz(szomsz[i]);
      }
    }
    
    /**
     * Összeköti ezt a csúcsot egy másikkal, ha ennek a csúcsnak még nincs
     * közelebbi szomszédja a megfelelő irányban.
     */
    public void osszekot_kozelit(Csucs masik) {
      // Imp: régi szomsz-ot is átláncolni
      if (masik.x==x) {
             if (masik.y<y) { if (szomsz[FEL]==null || szomsz[FEL].y<masik.y) { szomsz[FEL]=masik; masik.szomsz[LE]=this} }
        else if (masik.y>y) { if (szomsz[LE]==null || szomsz[LE].y>masik.y) { szomsz[LE]=masik; masik.szomsz[FEL]=this} }
        else throw new NemKothetoOsszeException();
      } else if (masik.y==y) {
             if (masik.x<x) { if (szomsz[BAL]==null || szomsz[BAL].x<masik.x) { szomsz[BAL]=masik; masik.szomsz[JOBB]=this} }
        else if (masik.x>x) { if (szomsz[JOBB]==null || szomsz[JOBB].x>masik.x) { szomsz[JOBB]=masik; masik.szomsz[BAL]=this} }
        else throw new NemKothetoOsszeException();
      } else throw new NincsRajtaException();
    }
    public int tavolsag(Csucs masik) {
      /* milyen messze van this és masik -- feltesszük, hogy szomszédosak */
      if (x==masik.x) return Math.abs(y-masik.y);
      else if (y==masik.y) return Math.abs(x-masik.x);
      else throw new NincsRajtaException();
    }
    public int tavolsag(int merre) {
      return szomsz[merre]==null ? 0 : tavolsag(szomsz[merre]);
    }
    public Csucs uj_csucs(int ux, int uy) {
      /* egy új csúcsot hoz létre this szomszédságában
       * Imp: Helyzet-eket update-elni!
       */
      if (ux==x && uy==y) return this;
      Csucs uj=new Csucs(ux, uy);
      int arra;
      if (ux==x) {
             if (uy<y) { arra=FEL; }
        else if (uy>y) { arra=LE; }
        else throw new NemKothetoOsszeException()// Assert: never happens
      } else if (uy==y) {
             if (ux<x) { arra=BAL; }
        else if (ux>x) { arra=JOBB; }
        else throw new NemKothetoOsszeException()// Assert: never happens
      } else throw new NincsRajtaException();
      if (szomsz[arra]!=null) {
        int ta=tavolsag(szomsz[arra]);
        int tu=tavolsag(uj);
        if (ta==tu) return szomsz[arra]// uj-t fel lehet szabadítani
        if (ta<tu) throw new NemKothetoOsszeException();
        uj.szomsz[arra]=szomsz[arra];
      }
      uj.szomsz[arra^2]=this;
      return uj;
    }
    /* az innen kitörölt szetvag() függvény bugos volt, és sosem használtuk. */
  }

  public static class Helyzet {
    /* Helyzet: egy mozgó lény (Kisgömböc vagy Szörny) helyét tárolja */
    public static final int H_C1BEN=1, H_JOBBRA=2, H_LEFELE=3;
    /**
     * H_* konstansok valamelyike.
     */
    private int hol;
    protected int x, y;
    private int ex, ey; // maximum koordinatak c1-bol; c1.getX()<=x<=ex, hasonloan y-ra
    private Csucs c1;
    // ^^^ c2 lejjebb/jobbrább van, mint c1
    // ^^^ (x,y) c1-re eshet, de c2-re csak akkor, ha c2!=c1

    public int getX() { return x; }
    public int getY() { return y; }

    /**
     * Visszadja azt a csúcsot, ahol éppen vagyunk. Ha épp két csúcs között
     * vagyunk, akkor <code>null</code>-t ad vissza.
     */
    public Csucs getCsucsban() {
      return hol==H_C1BEN?c1:null;
    }
    /**
     * Visszadja, hányadik mérpontbank. Ha épp két csúcs között
     * vagyunk, vagy az aktuális csúcs nem mérőpont, akkor -1-et
     * ad vissza.
     */
    public int getMeropontban() {
      // if (hol==H_C1BEN) System.err.println("HC1");
      return hol==H_C1BEN?c1.getMeropont():-1;
    }
    /**
     * Visszaadja `csucs' és `this' síkon mért távolságának négyzetét.
     */
    int ferdeTavolsag(Csucs cs) {
      int dx=x-cs.getX();
      int dy=y-cs.getY();
      return dx*dx+dy*dy;
    }
    /**
     * Visszaadja `helyzet' és `this' síkon mért távolságának négyzetét.
     */
    int ferdeTavolsag(Helyzet helyzet) {
      int dx=x-helyzet.x;
      int dy=y-helyzet.y;
      return dx*dx+dy*dy;
    }

    public void ugrik() {
      // ex-et, ey-t, hol-t a semmibol ujraszamolja; c1,x,y mar helyes.
      Csucs c2;
      c2=c1.getSzomsz0(Csucs.JOBB); ex=c2.getX();
      c2=c1.getSzomsz0(Csucs.LE);   ey=c2.getY();
      if (x>c1.getX()) hol=H_JOBBRA;
      else if (y>c1.getY()) hol=H_LEFELE;
      else hol=H_C1BEN;
    }

    public Helyzet() {
      /* gagyi, kamu konstruktor, kesobb csucsba-val lehet korrigalni */
      this.c1=null;
    }
    public Helyzet(Csucs c1) {
      this.c1=c1;
      x=c1.getX(); y=c1.getY();
      ugrik();
    }

    /**
     * Copy konstruktor.
     */
    public Helyzet(Helyzet h) {
      athelyez(h);
    }

    /**
     * A megadott :Csúcs-ba helyezi át this-t.
     */
    public void athelyez(Csucs c1) {
      this.c1=c1;
      x=c1.getX(); y=c1.getY();
      ugrik();
    }

    /**
     * A megadott :Helyzet-be helyezi át this-t.
     */
    public void athelyez(Helyzet h) {
      c1=h.c1; hol=h.hol;
      x=h.x; y=h.y;
      ex=h.ex; ey=h.ey;
    }

    /**
     * A két szomszéd :Csúcs-ot helyezi el a :Sor-ba, és beállítja a
     * távolságukat this-től.
     */
    public void ketSzomszed(Sor sor) {
      sor.vegehezFuz(c1);
      if (hol==H_C1BEN) {
        c1.setTavolsag(0);
      } else if (hol==H_JOBBRA) {
        int xx=c1.getX();
        c1.setTavolsag(x-xx);
        Csucs c2=c1.getSzomsz(Csucs.JOBB);
        sor.vegehezFuzNemNull(c2);
        c2.setTavolsag(ex-x);
      } else if (hol==H_LEFELE) {
        int yy=c1.getY();
        c1.setTavolsag(y-yy);
        Csucs c2=c1.getSzomsz(Csucs.LE);
        sor.vegehezFuzNemNull(c2);
        c2.setTavolsag(ey-y);
      }
    } /// ketSzomszed()

    protected int halad_alap(int merre, int mennyit) {
      // ne ezt hívd, hanem Mozgo.halad(*,*)-ot. Az ellenőriz és callback-kel is.
      // if (hol==H_C1BEN) System.err.println("Hudok "+merre+" "+mennyit+"."); // DEBUG
      // Imp: clean this up (code works, but is ugly)
      int menyi=mennyit;
      if (merre==Csucs.FEL || merre==Csucs.BAL) menyi*=-1;
      if (hol==H_JOBBRA) { x+=menyi;
        if (x==ex) { c1=c1.getSzomsz0(merre); ugrik()}
        else if (x==c1.getX()) hol=H_C1BEN;
        return mennyit;
      }
      if (hol==H_LEFELE) { y+=menyi;
        if (y==ey) { c1=c1.getSzomsz0(merre); ugrik()}
        else if (y==c1.getY()) hol=H_C1BEN;
        return mennyit;
      }
      if (menyi<0) c1=c1.getSzomsz(merre);
      if (merre==Csucs.FEL || merre==Csucs.LE) { y+=menyi; if (y==ey) c1=c1.getSzomsz0(merre)}
                                          else { x+=menyi; if (x==ex) c1=c1.getSzomsz0(merre)}
      ugrik();
      return mennyit;
    }

    public int mennyit_mehet(int merre) {
      /* @return: innen mennyit mehet az akt. élen a megadott irányba */
      if (hol==H_JOBBRA) {
        if (merre==c1.BAL) return x-c1.getX();
        else if (merre==c1.JOBB) return ex-x; // c1.tavolsag(c1.JOBB)-x+c1.getX();
        else return 0;
      } else if (hol==H_LEFELE) {
        if (merre==c1.FEL) return y-c1.getY();
        else if (merre==c1.LE) return ey-y; // c1.tavolsag(c1.LE)-y+c1.getY();
        else return 0;
      }
      //: hol==H_C1BEN
      // System.err.println("MM:"+merre); // DEBUG
      // try { Thread.sleep(1000); } catch (InterruptedException e) {}
      return c1.tavolsag(merre);
    }
  } /// class Helyzet

  // ---

  public abstract static class Lathato extends Helyzet {
    /**
     * Egyedi azonosító. A :Labirintus osztja ki és használja. Ha kisebb
     * nullánál, akkor a :Látható még nem jelent meg a labirintusban, vagy
     * egy korábbi ciklusban már eltűnt belőle.
     */
    protected int id=-2;
    protected Kep[] kepek;
    protected Kep aktkep;
    protected int akti;
    /**
     * A naplóba írandó osztálynév (például mérőpont elérésekor).
     * Felüldefiniálandó.
     */
    private static String klassz="Lathato";
    /**
     * Visszadja a naplóba írandó osztálynevet. Azért nem `static', hogy
     * virtuális lehessen.
     */
    public String getKlassz() { return klassz; }
    /**
     * Egy nemnegatív konstanst ad vissza: minél nagyobb a konstans, annál
     * feljebb kell rajzolni az objektumot.
     */
    public abstract int getReteg();

    /**
     * Ő végzi ezen :Láthatóval történtek naplózását.
     */
    protected Naplozo naplozo;
    public void setNaplozo(Naplozo naplozo) {
      if (this.naplozo!=null) throw new MarErtekesError();
      this.naplozo=naplozo;
    }
    /**
     * Már nem csinál semmit, mert ez már nem a prototípus. Prototípusban:
     * Egy sort naplóz, eléfűzve `this.getKlassz()'-t.
     * @see eNTitanok.kkkg.KkkgAppl.Lathato#getKlassz
     */
    public void naploz(String s, Naplozo naplozo) {
      // naplozo.naploz(getKlassz()+s); // CsakPro
    }
    /**
     * Már nem csinál semmit, mert ez már nem a prototípus. Prototípusban:
     * Egy sort naplóz, eléfűzve `this.getKlassz()'-t.
     * @see eNTitanok.kkkg.KkkgAppl.Lathato#getKlassz
     */
    public void naploz(String s) {
      // naplozo.naploz(getKlassz()+s); // CsakPro
    }
    
    public void setId(int id) { this.id=id; }
    public int getId() { return id; }
    public String[] getKepnevek() {
      int i;
      String[] t=new String[kepek.length];
      for (i=0;i<kepek.length;i++) t[i]=kepek[i].getFilenev();
      return t;
    }

    // public void setKep(int i, Image kep) { kepek[i].setKep(kep); }
    public void mozgat(int ujx, int ujy) {
      x=ujx; y=ujy;
    }
    public void rarajzolArnyek(Sdpts sd) {
      //sd.drawImage(aktkep.kep, x/24+aktkep.bx1, y/24+aktkep.bx1);
      // sd.drawShadow(x/24+aktkep.bx1-5, y/24+aktkep.bx1-5, aktkep.kep.getWidth(null)+10, aktkep.kep.getHeight(null)+10);
      aktkep.felrajzol_arnyek(x/24,y/24);
    }
    public void rarajzol(Sdpts sd) {
      //sd.drawImage(aktkep.kep, x/24+aktkep.bx1, y/24+aktkep.bx1);
      // sd.drawImageCover(aktkep.kep, x/24+aktkep.bx1, y/24+aktkep.bx1);
      // ^^^ még mindig érezhetően lassít
      aktkep.felrajzol_kep(x/24,y/24);
    }
    // public void tisztit() { dirty=false; }

    public boolean utkozik_e(Lathato masik) {
      // vvv Imp: / 0 felé kerekítsen!! (x>=0??)
      return aktkep.utkozik_e(masik.aktkep, -x/24+masik.x/24, -y/24+masik.y/24);
      /*/ // CsakPro
      if (this instanceof KetyegoBomba && ((KetyegoBomba)this). getRobban()
       ||masik instanceof KetyegoBomba && ((KetyegoBomba)masik).getRobban()) {
        // System.err.println("ROBI"); // DBG
        return Math.abs(x-masik.x)<63*24 && Math.abs(y-masik.y)<63*24;
      }
      return Math.abs(x-masik.x)<23*24 && Math.abs(y-masik.y)<23*24;
      /***/
    } /// utkozik_e()

    /**
     * Labirintus hívja meg új :Látható felvételekor (az újra és a régiekre is);
     * pontosan akkor ad vissza true-t, ha kell ütközésvizsgálatot végezni this
     * és `masik' között. Az ütközésvizsgálatot Labirintus végzi this.utkozik_e
     * módszeres hivogatásával.
     * Érdemes átdefiniálni.
     */
    public boolean akarsz_e_utkozni(Lathato masik) {
      return false;
    }

    /**
     * Egy lépes egy ciklusban. Nem feltétlenül mozgás, lehet ütközésvizsgálat
     * és más :Láthatókra hatás stb.
     */
    protected abstract void halad();
  } /// class Lathato

  /**
   * A :Tárgy fő jellemzője, hogy egy helyben áll a pályán, és az egyetlen
   * dolog, ami történhet vele, az az, hogy a :Kisgömböc felveszi.
   */
  public static abstract class Targy extends Lathato {
    /**
     * Figyeljük-e az ütközést :Kisgömböc-cel?
     */
    protected boolean kutk;
    protected Labirintus labirintus;
    abstract protected void felveve();
    /**
     * Egy helyben áll, és várja :Kisgömböcöt. Amint ütközik vele, meghívja
     * `this.felveve()'-t, majd eltűnik.
     */
    protected void halad() {
      Lathato ut[]=labirintus.getUtkozesek(this);
      if (ut!=null) for (int i=0;i<ut.length;i++) {
        if (ut[i] instanceof Kisgomboc) {
          felveve();
          labirintus.removeLathato(this);
        }
      }
    } /// halad()
    protected Targy(Labirintus labirintus, boolean kutk) {
      this.labirintus=labirintus;
      this.kutk=kutk;
    }
    public boolean akarsz_e_utkozni(Lathato masik) {
      return kutk && masik instanceof Kisgomboc;
    }
    public int getReteg() { return 20; }
  } /// class Targy

  /**
   * A :Gyémánt azért nem Ajándék, mert nem véletlenszerűen jelenik meg, és
   * nem tűnik el.
   */
  public static class Gyemant extends Targy {
    private static String klassz="Gyemant";
    public String getKlassz() { return klassz; }
    public Gyemant(Labirintus l, boolean kutk) {
      super(l, kutk);
      kepek=new Kep[1];
      kepek[0]=l.getKepbetolto().betolt("gyemant.gif").initi(l.getSd(),-12,-12,0);
      aktkep=kepek[akti=0];
    }
    public void felveve() {
      labirintus.getJatek().novelPontszam(23);
    }
    public int getReteg() { return 30; }
  } /// class Gyemant

  public static class KetyegoBomba extends Lathato {
    private static String klassz="KetyegoBomba";
    public String getKlassz() { return klassz; }
    /**
     * Figyeljük-e az ütközést :Szörny-nyel?
     */
    protected boolean sutk;
    /**
     * Figyeljük-e az ütközést :Kisgömböc-cel?
     */
    protected boolean kutk;
    protected Labirintus labirintus;
    /**
     * Hány ciklust ért meg? (0, ha ebben a ciklusban született)
     */
    protected int eletkor=0;
    protected boolean robban=false;
    public boolean getRobban() { return robban; }
    public int getReteg() { return 10; }
    public KetyegoBomba(Labirintus labirintus, boolean kutk, boolean sutk) {
      this.labirintus=labirintus;
      this.kutk=kutk;
      this.sutk=sutk;
      kepek=new Kep[2];
      kepek[0]=labirintus.getKepbetolto().betolt("kbomba.gif").initi(labirintus.getSd(),-12,-12,0);
      kepek[1]=labirintus.getKepbetolto().betolt("kbombar.gif").initi(labirintus.getSd(),-34,-12,0);
      aktkep=kepek[akti=0];
    }
    public boolean akarsz_e_utkozni(Lathato masik) {
      return kutk && masik instanceof Kisgomboc
          || sutk && masik instanceof Szorny;
    }
    public void halad() {
      if (eletkor>=63) { // 1 másodperc
        Lathato ut[]=labirintus.getUtkozesek(this);
        if (!robban && (eletkor>=313 || ut!=null)) { // 5 másodperc
          // naploz(" felrobban"); // CsakPro
          robban=true; aktkep=kepek[akti=1];
          eletkor=313;
          // labirintus.removeLathato(this);
        }
        if (ut!=null) for (int i=0;i<ut.length;i++) {
          if (ut[i] instanceof Mozgo) {
            // System.err.println("DDD"); // DBG
            labirintus.removeLathato(ut[i]);
          }
        }
        if (eletkor>=438) labirintus.removeLathato(this)// 7 másodperc
      }
      eletkor++;
    } /// halad()
  } /// class KetyegoBomba

  /**
   * Az :Ajándék-ok közös jellegzetessége, hogy véletlenszerűen jelennek meg
   * a :Labirintusban, és véletlenszerűen tűnnek is el.
   */
  public static abstract class Ajandek extends Targy {
    /**
     * Hány ciklus van még hátra, mielőtt az ajándék magától eltűnik?.
     */
    protected int hatralevo=313; // 5 másodperc
    protected Ajandek(Labirintus labirintus, boolean kutk) { super(labirintus, kutk)}
    /**
     * Csökkenti a hátralevő időt, és magától eltűnik, ha nulla lesz.
     * `this.felveve()'-t természetesen meghívja.
     */
    protected void halad() {
      super.halad();
      if (--hatralevo<0) labirintus.removeLathato(this);
    }
    /**
     * Pontosan akkor `true', ha `this' szeretne keletkezni Kisgömböc-től
     * (a középpontokat tekintve)
     * a folyosókon mérve `tavolsag'-ra, a síkon mérve `ferdeTavolsag'
     * négyzetére. Implementáció: ha a `tavolsag' nem végtelen, és a síkon
     * mért távolság legalább 100 pixel.
     */
    public boolean alkalmasKel(int tavolsag, int ferdeTavolsag) {
      return tavolsag!=Integer.MAX_VALUE && ferdeTavolsag>=(100*25)*(100*25);
    }
  } /// class Ajandek

  public static class FelvehetoBomba extends Ajandek {
    private static String klassz="FelvehetoBomba";
    public String getKlassz() { return klassz; }
    public FelvehetoBomba(Labirintus l, boolean kutk) {
      super(l, kutk);
      kepek=new Kep[1];
      kepek[0]=l.getKepbetolto().betolt("fbomba.gif").initi(l.getSd(),-12,-12,0);
      aktkep=kepek[akti=0];
      hatralevo=313;
     }
    public void felveve() {
      labirintus.getJatek().novelPontszam(3);
      labirintus.getJatek().novelBombaszam();
    }
  } /// class FelvehetoBomba

  public static class Bonusz extends Ajandek {
    private static String klassz="Bonusz";
    public String getKlassz() { return klassz; }
    public Bonusz(Labirintus l, boolean kutk) {
      super(l, kutk);
      kepek=new Kep[1];
      kepek[0]=l.getKepbetolto().betolt("bonusz.gif").initi(l.getSd(),-12,-12,0);
      aktkep=kepek[akti=0];
      hatralevo=313;
     }
    public void felveve() {
      labirintus.getJatek().novelPontszam(137);
    }
  } /// class Bonusz

  public static class SimaElixir extends Ajandek {
    private static String klassz="SimaElixir";
    public String getKlassz() { return klassz; }
    public SimaElixir(Labirintus l, boolean kutk) {
      super(l, kutk);
      kepek=new Kep[1];
      kepek[0]=l.getKepbetolto().betolt("sielixir.gif").initi(l.getSd(),-12,-12,0);
      aktkep=kepek[akti=0];
      hatralevo=313;
    }
    public void felveve() {
      labirintus.getJatek().novelPontszam(2);
      labirintus.getJatek().novelEletszam(1);
    }
  } /// class SimaElixir

  public static class SzuperElixir extends Ajandek {
    private static String klassz="SzuperElixir";
    public String getKlassz() { return klassz; }
    public SzuperElixir(Labirintus l, boolean kutk) {
      super(l, kutk);
      kepek=new Kep[1];
      kepek[0]=l.getKepbetolto().betolt("szelixir.gif").initi(l.getSd(),-12,-12,0);
      aktkep=kepek[akti=0];
      hatralevo=313;
    }
    public void felveve() {
      labirintus.getJatek().novelPontszam(18);
      labirintus.getJatek().novelEletszam(0);
    }
  } /// class SzuperElixir

  // ---

  public static abstract class Mozgo extends Lathato {
    protected abstract void elfordult();
    // ^^^ akkor hivodik meg, ha a haladasi irany megvaltozik. Feluldefinialando.

    protected int ero; // mennyit lephet most
    protected int max_ero; // mennyi a max sebessege
    protected int irany=Csucs.PIHI; // milyen iranyba lepett legutoljara >=1-et
    public int setMax_ero(int max_ero) { return this.max_ero=max_ero; }
    public int setEro() { return this.ero=this.max_ero; }

    /**
     * Az adott irányba próbál az adott egységnyit haladni. Siker esetén
     * `this.elfordult()' meghívódik -- és ha még mérőpontra is ér, akkor
     * ez a tény naplózódik.
     */
    public int halad(int merre, int mennyit) {
      if (merre>=4 || mennyit==0) return 0;
      // System.err.println("Halad "+merre+" "+mennyit+"."); // DEBUG
      mennyit=Math.min(mennyit, mennyit_mehet(merre));
      if (mennyit==0) return 0;
      if (irany!=merre) {
        irany=merre;
        /*/ // vvv CsakPro
        switch (irany) {
          case Csucs.FEL: naploz(" ^ fordul")break;
          case Csucs.LE:  naploz(" v fordul")break;
          case Csucs.JOBB:naploz(" > fordul")break;
          case Csucs.BAL: naploz(" < fordul")break;
        }
        /***/
        elfordult();
      }
      mennyit=halad_alap(merre, mennyit);
      if (mennyit==0) throw new AsserttError();
      /*/ // vvv CsakPro
      // System.err.println("DBGMP "+getKlassz()+" "+x);
      int meropont=getMeropontban();
      if (meropont!=-1) naploz(" meropontban "+meropont);
      /***/
      return mennyit;
    }

    public int halad(int merre) {
      // annyit halad az adott iranyba, amennyi az erejebol tellik
      int sikerult=halad(merre, ero);
      ero-=sikerult;
      return sikerult;
    }

    void halad_balra_fordul() {
      if (irany==Csucs.PIHI) irany=Csucs.FEL;
      int erobk=0;
      while (erobk!=ero) { // atugorja a csomopontokat
        erobk=ero;
        for (int i=5;i>=2;i--) { if (0<halad((irany+i)%4)) break}
      }
    }
    void halad_jobbra_fordul() {
      if (irany==Csucs.PIHI) irany=Csucs.FEL;
      int erobk=0;
      while (erobk!=ero) { // atugorja a csomopontokat
        erobk=ero;
        for (int i=3;i<=6;i++) { if (0<halad((irany+i)%4)) break}
      }
    }
  } /// class Mozgo

  public static abstract class Szorny extends Mozgo {
    protected Labirintus labirintus;
    /**
     * Ezzel generáljuk a kanyarodáshoz esetlegesen szükséges véletlenszámokat.
     */
    Veletlen.Generalo generalo;
    /**
     * Figyeljük-e az ütközést :Kisgömböc-cel?
     */
    protected boolean kutk;
    public int getReteg() { return 40; }
    protected Szorny(Labirintus labirintus, int max_ero, Veletlen.Generalo generalo, boolean kutk) {
      this.labirintus=labirintus;
      this.max_ero=max_ero;
      this.generalo=generalo;
      this.kutk=kutk;
    }
    protected void elfordult() { aktkep=kepek[irany]; akti=irany; }
    public boolean akarsz_e_utkozni(Lathato masik) {
      return kutk && masik instanceof Kisgomboc;
    }
    /**
     * Ha ütközik :Kisgömböc-cel, megöli.
     */
    protected void megoli() {
      Lathato ut[]=labirintus.getUtkozesek(this);
      if (ut!=null) for (int i=0;i<ut.length;i++)
        if (ut[i] instanceof Kisgomboc) labirintus.removeLathato(ut[i]);
    }
    /**
     * Pontosan akkor `true', ha `this' szeretne keletkezni Kisgömböc-től
     * (a középpontokat tekintve)
     * a folyosókon mérve `tavolsag'-ra, a síkon mérve `ferdeTavolsag'
     * négyzetére. Implementáció: ha a `tavolsag' nem végtelen, és a síkon
     * mért távolság legalább 100 pixel.
     */
    public boolean alkalmasKel(int tavolsag, int ferdeTavolsag) {
      // CsakPro
      return tavolsag!=Integer.MAX_VALUE && ferdeTavolsag>=(24*100)*(24*100);
    }
  } /// class Szorny

  public static class BalraSzorny extends Szorny {
    private static String klassz="BalraSzorny";
    public String getKlassz() { return klassz; }
    protected void halad() {
      setEro(); halad_balra_fordul(); megoli();
      aktkep=kepek[akti=irany*4+labirintus.getJatek().getHat()%4];
    }
    public BalraSzorny(Labirintus labirintus, int max_ero, Veletlen.Generalo generalo, boolean kutk) {
      super(labirintus, max_ero, generalo, kutk);
      Kepbetolto kepbetolto=labirintus.getKepbetolto();
      Sdpts sd=labirintus.getSd();
      kepek=new Kep[16];
      kepek[Csucs.JOBB*4+0]=kepbetolto.betolt("bornyj0.gif").initi(sd,-12,-12);
      kepek[Csucs.JOBB*4+1]=kepbetolto.betolt("bornyj1.gif").initi(sd,-12,-12);
      kepek[Csucs.JOBB*4+2]=kepbetolto.betolt("bornyj2.gif").initi(sd,-12,-12);
      kepek[Csucs.JOBB*4+3]=kepbetolto.betolt("bornyj3.gif").initi(sd,-12,-12);
      kepek[Csucs.BAL *4+0]=kepbetolto.betolt("bornyb0.gif").initi(sd,-12,-12);
      kepek[Csucs.BAL *4+1]=kepbetolto.betolt("bornyb1.gif").initi(sd,-12,-12);
      kepek[Csucs.BAL *4+2]=kepbetolto.betolt("bornyb2.gif").initi(sd,-12,-12);
      kepek[Csucs.BAL *4+3]=kepbetolto.betolt("bornyb3.gif").initi(sd,-12,-12);
      kepek[Csucs.FEL *4+0]=kepbetolto.betolt("bornyf0.gif").initi(sd,-12,-12);
      kepek[Csucs.FEL *4+1]=kepbetolto.betolt("bornyf1.gif").initi(sd,-12,-12);
      kepek[Csucs.FEL *4+2]=kepbetolto.betolt("bornyf2.gif").initi(sd,-12,-12);
      kepek[Csucs.FEL *4+3]=kepbetolto.betolt("bornyf3.gif").initi(sd,-12,-12);
      kepek[Csucs.LE  *4+0]=kepbetolto.betolt("bornyl0.gif").initi(sd,-12,-12);
      kepek[Csucs.LE  *4+1]=kepbetolto.betolt("bornyl1.gif").initi(sd,-12,-12);
      kepek[Csucs.LE  *4+2]=kepbetolto.betolt("bornyl2.gif").initi(sd,-12,-12);
      kepek[Csucs.LE  *4+3]=kepbetolto.betolt("bornyl3.gif").initi(sd,-12,-12);
      aktkep=kepek[akti=Csucs.LE*4];
    }
  } /// BalraSzorny
  
  public static class JobbraSzorny extends Szorny {
    private static String klassz="JobbraSzorny";
    public String getKlassz() { return klassz; }
    protected void halad() {
      setEro(); halad_jobbra_fordul(); megoli();
      aktkep=kepek[akti=irany*4+labirintus.getJatek().getHat()%4];
    }
    public JobbraSzorny(Labirintus labirintus, int max_ero, Veletlen.Generalo generalo, boolean kutk) {
      super(labirintus, max_ero, generalo, kutk);
      Kepbetolto kepbetolto=labirintus.getKepbetolto();
      Sdpts sd=labirintus.getSd();
      kepek=new Kep[16];
      kepek[Csucs.JOBB*4+0]=kepbetolto.betolt("bornyj0.gif").initi(sd,-12,-12);
      kepek[Csucs.JOBB*4+1]=kepbetolto.betolt("bornyj1.gif").initi(sd,-12,-12);
      kepek[Csucs.JOBB*4+2]=kepbetolto.betolt("bornyj2.gif").initi(sd,-12,-12);
      kepek[Csucs.JOBB*4+3]=kepbetolto.betolt("bornyj3.gif").initi(sd,-12,-12);
      kepek[Csucs.BAL *4+0]=kepbetolto.betolt("bornyb0.gif").initi(sd,-12,-12);
      kepek[Csucs.BAL *4+1]=kepbetolto.betolt("bornyb1.gif").initi(sd,-12,-12);
      kepek[Csucs.BAL *4+2]=kepbetolto.betolt("bornyb2.gif").initi(sd,-12,-12);
      kepek[Csucs.BAL *4+3]=kepbetolto.betolt("bornyb3.gif").initi(sd,-12,-12);
      kepek[Csucs.FEL *4+0]=kepbetolto.betolt("bornyf0.gif").initi(sd,-12,-12);
      kepek[Csucs.FEL *4+1]=kepbetolto.betolt("bornyf1.gif").initi(sd,-12,-12);
      kepek[Csucs.FEL *4+2]=kepbetolto.betolt("bornyf2.gif").initi(sd,-12,-12);
      kepek[Csucs.FEL *4+3]=kepbetolto.betolt("bornyf3.gif").initi(sd,-12,-12);
      kepek[Csucs.LE  *4+0]=kepbetolto.betolt("bornyl0.gif").initi(sd,-12,-12);
      kepek[Csucs.LE  *4+1]=kepbetolto.betolt("bornyl1.gif").initi(sd,-12,-12);
      kepek[Csucs.LE  *4+2]=kepbetolto.betolt("bornyl2.gif").initi(sd,-12,-12);
      kepek[Csucs.LE  *4+3]=kepbetolto.betolt("bornyl3.gif").initi(sd,-12,-12);
      aktkep=kepek[akti=Csucs.LE*4];
    }
  } /// JobbraSzorny

  public static class OkosSzorny extends Szorny {
    private static String klassz="OkosSzorny";
    public String getKlassz() { return klassz; }
    protected void halad() {
      setEro();
      int erobk=0, haladt;
      while (ero>0 && erobk!=ero) { // áthalad a csomopontokon
        erobk=ero;
        Csucs cs=getCsucsban();
        haladt=cs==null ? halad(irany)
                        : halad(cs.merreLegrovidebb(generalo));
        if (haladt==0) throw new AsserttError();
      }
      megoli();
      aktkep=kepek[akti=irany*4+labirintus.getJatek().getHat()%4];
    }
    public OkosSzorny(Labirintus labirintus, int max_ero, Veletlen.Generalo generalo, boolean kutk) {
      super(labirintus, max_ero, generalo, kutk);
      Kepbetolto kepbetolto=labirintus.getKepbetolto();
      Sdpts sd=labirintus.getSd();
      kepek=new Kep[16];
      kepek[Csucs.JOBB*4+0]=kepbetolto.betolt("oornyj0.gif").initi(sd,-12,-12);
      kepek[Csucs.JOBB*4+1]=kepbetolto.betolt("oornyj1.gif").initi(sd,-12,-12);
      kepek[Csucs.JOBB*4+2]=kepbetolto.betolt("oornyj2.gif").initi(sd,-12,-12);
      kepek[Csucs.JOBB*4+3]=kepbetolto.betolt("oornyj3.gif").initi(sd,-12,-12);
      kepek[Csucs.BAL *4+0]=kepbetolto.betolt("oornyb0.gif").initi(sd,-12,-12);
      kepek[Csucs.BAL *4+1]=kepbetolto.betolt("oornyb1.gif").initi(sd,-12,-12);
      kepek[Csucs.BAL *4+2]=kepbetolto.betolt("oornyb2.gif").initi(sd,-12,-12);
      kepek[Csucs.BAL *4+3]=kepbetolto.betolt("oornyb3.gif").initi(sd,-12,-12);
      kepek[Csucs.FEL *4+0]=kepbetolto.betolt("oornyf0.gif").initi(sd,-12,-12);
      kepek[Csucs.FEL *4+1]=kepbetolto.betolt("oornyf1.gif").initi(sd,-12,-12);
      kepek[Csucs.FEL *4+2]=kepbetolto.betolt("oornyf2.gif").initi(sd,-12,-12);
      kepek[Csucs.FEL *4+3]=kepbetolto.betolt("oornyf3.gif").initi(sd,-12,-12);
      kepek[Csucs.LE  *4+0]=kepbetolto.betolt("oornyl0.gif").initi(sd,-12,-12);
      kepek[Csucs.LE  *4+1]=kepbetolto.betolt("oornyl1.gif").initi(sd,-12,-12);
      kepek[Csucs.LE  *4+2]=kepbetolto.betolt("oornyl2.gif").initi(sd,-12,-12);
      kepek[Csucs.LE  *4+3]=kepbetolto.betolt("oornyl3.gif").initi(sd,-12,-12);
      aktkep=kepek[akti=Csucs.LE*4];
    }
  } /// OkosSzorny

  public static class ButaSzorny extends Szorny {
    private static String klassz="ButaSzorny";
    public String getKlassz() { return klassz; }
    protected void halad() {
      setEro();
      int erobk=0, haladt;
      while (ero>0 && erobk!=ero) { // áthalad a csomopontokon
        erobk=ero;
        Csucs cs=getCsucsban();
        haladt=cs==null ? halad(irany)
                        : halad(cs.merreVeletlen(generalo, irany^2))// !! irany^2
        // if (haladt==0) throw new AsserttError(); // !!
      }
      megoli();
      aktkep=kepek[akti=irany*4+labirintus.getJatek().getHat()%4];
    }
    public ButaSzorny(Labirintus labirintus, int max_ero, Veletlen.Generalo generalo, boolean kutk) {
      super(labirintus, max_ero, generalo, kutk);
      Kepbetolto kepbetolto=labirintus.getKepbetolto();
      Sdpts sd=labirintus.getSd();
      kepek=new Kep[16];
      kepek[Csucs.JOBB*4+0]=kepbetolto.betolt("bornyj0.gif").initi(sd,-12,-12);
      kepek[Csucs.JOBB*4+1]=kepbetolto.betolt("bornyj1.gif").initi(sd,-12,-12);
      kepek[Csucs.JOBB*4+2]=kepbetolto.betolt("bornyj2.gif").initi(sd,-12,-12);
      kepek[Csucs.JOBB*4+3]=kepbetolto.betolt("bornyj3.gif").initi(sd,-12,-12);
      kepek[Csucs.BAL *4+0]=kepbetolto.betolt("bornyb0.gif").initi(sd,-12,-12);
      kepek[Csucs.BAL *4+1]=kepbetolto.betolt("bornyb1.gif").initi(sd,-12,-12);
      kepek[Csucs.BAL *4+2]=kepbetolto.betolt("bornyb2.gif").initi(sd,-12,-12);
      kepek[Csucs.BAL *4+3]=kepbetolto.betolt("bornyb3.gif").initi(sd,-12,-12);
      kepek[Csucs.FEL *4+0]=kepbetolto.betolt("bornyf0.gif").initi(sd,-12,-12);
      kepek[Csucs.FEL *4+1]=kepbetolto.betolt("bornyf1.gif").initi(sd,-12,-12);
      kepek[Csucs.FEL *4+2]=kepbetolto.betolt("bornyf2.gif").initi(sd,-12,-12);
      kepek[Csucs.FEL *4+3]=kepbetolto.betolt("bornyf3.gif").initi(sd,-12,-12);
      kepek[Csucs.LE  *4+0]=kepbetolto.betolt("bornyl0.gif").initi(sd,-12,-12);
      kepek[Csucs.LE  *4+1]=kepbetolto.betolt("bornyl1.gif").initi(sd,-12,-12);
      kepek[Csucs.LE  *4+2]=kepbetolto.betolt("bornyl2.gif").initi(sd,-12,-12);
      kepek[Csucs.LE  *4+3]=kepbetolto.betolt("bornyl3.gif").initi(sd,-12,-12);
      aktkep=kepek[akti=Csucs.LE*4];
    }
  } /// ButaSzorny

  public static class BalraFelSzorny extends Szorny {
    private static String klassz="BalraFelSzorny";
    public String getKlassz() { return klassz; }
    protected void halad() {
      setEro();
      int erobk=0;
      while (ero>0 && erobk!=ero) { // áthalad a csomopontokon
        erobk=ero;
        if (0==halad(Csucs.BAL)) halad(Csucs.FEL);
      }
      megoli();
      aktkep=kepek[akti=irany*4+labirintus.getJatek().getHat()%4];
    }
    public BalraFelSzorny(Labirintus labirintus, int max_ero, Veletlen.Generalo generalo, boolean kutk) {
      super(labirintus, max_ero, generalo, kutk);
      Kepbetolto kepbetolto=labirintus.getKepbetolto();
      Sdpts sd=labirintus.getSd();
      kepek=new Kep[16];
      kepek[Csucs.JOBB*4+0]=kepbetolto.betolt("bornyj0.gif").initi(sd,-12,-12);
      kepek[Csucs.JOBB*4+1]=kepbetolto.betolt("bornyj1.gif").initi(sd,-12,-12);
      kepek[Csucs.JOBB*4+2]=kepbetolto.betolt("bornyj2.gif").initi(sd,-12,-12);
      kepek[Csucs.JOBB*4+3]=kepbetolto.betolt("bornyj3.gif").initi(sd,-12,-12);
      kepek[Csucs.BAL *4+0]=kepbetolto.betolt("bornyb0.gif").initi(sd,-12,-12);
      kepek[Csucs.BAL *4+1]=kepbetolto.betolt("bornyb1.gif").initi(sd,-12,-12);
      kepek[Csucs.BAL *4+2]=kepbetolto.betolt("bornyb2.gif").initi(sd,-12,-12);
      kepek[Csucs.BAL *4+3]=kepbetolto.betolt("bornyb3.gif").initi(sd,-12,-12);
      kepek[Csucs.FEL *4+0]=kepbetolto.betolt("bornyf0.gif").initi(sd,-12,-12);
      kepek[Csucs.FEL *4+1]=kepbetolto.betolt("bornyf1.gif").initi(sd,-12,-12);
      kepek[Csucs.FEL *4+2]=kepbetolto.betolt("bornyf2.gif").initi(sd,-12,-12);
      kepek[Csucs.FEL *4+3]=kepbetolto.betolt("bornyf3.gif").initi(sd,-12,-12);
      kepek[Csucs.LE  *4+0]=kepbetolto.betolt("bornyl0.gif").initi(sd,-12,-12);
      kepek[Csucs.LE  *4+1]=kepbetolto.betolt("bornyl1.gif").initi(sd,-12,-12);
      kepek[Csucs.LE  *4+2]=kepbetolto.betolt("bornyl2.gif").initi(sd,-12,-12);
      kepek[Csucs.LE  *4+3]=kepbetolto.betolt("bornyl3.gif").initi(sd,-12,-12);
      aktkep=kepek[akti=Csucs.LE*4];
    }
  } /// BalraFelSzorny

  public static class JobbraLeSzorny extends Szorny {
    private static String klassz="JobbraLeSzorny";
    public String getKlassz() { return klassz; }
    protected void halad() {
      setEro();
      int erobk=0;
      while (ero>0 && erobk!=ero) { // áthalad a csomopontokon
        erobk=ero;
        if (0==halad(Csucs.JOBB)) halad(Csucs.LE);
      }
      megoli();
      aktkep=kepek[akti=irany*4+labirintus.getJatek().getHat()%4];
    }
    public JobbraLeSzorny(Labirintus labirintus, int max_ero, Veletlen.Generalo generalo, boolean kutk) {
      super(labirintus, max_ero, generalo, kutk);
      Kepbetolto kepbetolto=labirintus.getKepbetolto();
      Sdpts sd=labirintus.getSd();
      kepek=new Kep[16];
      kepek[Csucs.JOBB*4+0]=kepbetolto.betolt("bornyj0.gif").initi(sd,-12,-12);
      kepek[Csucs.JOBB*4+1]=kepbetolto.betolt("bornyj1.gif").initi(sd,-12,-12);
      kepek[Csucs.JOBB*4+2]=kepbetolto.betolt("bornyj2.gif").initi(sd,-12,-12);
      kepek[Csucs.JOBB*4+3]=kepbetolto.betolt("bornyj3.gif").initi(sd,-12,-12);
      kepek[Csucs.BAL *4+0]=kepbetolto.betolt("bornyb0.gif").initi(sd,-12,-12);
      kepek[Csucs.BAL *4+1]=kepbetolto.betolt("bornyb1.gif").initi(sd,-12,-12);
      kepek[Csucs.BAL *4+2]=kepbetolto.betolt("bornyb2.gif").initi(sd,-12,-12);
      kepek[Csucs.BAL *4+3]=kepbetolto.betolt("bornyb3.gif").initi(sd,-12,-12);
      kepek[Csucs.FEL *4+0]=kepbetolto.betolt("bornyf0.gif").initi(sd,-12,-12);
      kepek[Csucs.FEL *4+1]=kepbetolto.betolt("bornyf1.gif").initi(sd,-12,-12);
      kepek[Csucs.FEL *4+2]=kepbetolto.betolt("bornyf2.gif").initi(sd,-12,-12);
      kepek[Csucs.FEL *4+3]=kepbetolto.betolt("bornyf3.gif").initi(sd,-12,-12);
      kepek[Csucs.LE  *4+0]=kepbetolto.betolt("bornyl0.gif").initi(sd,-12,-12);
      kepek[Csucs.LE  *4+1]=kepbetolto.betolt("bornyl1.gif").initi(sd,-12,-12);
      kepek[Csucs.LE  *4+2]=kepbetolto.betolt("bornyl2.gif").initi(sd,-12,-12);
      kepek[Csucs.LE  *4+3]=kepbetolto.betolt("bornyl3.gif").initi(sd,-12,-12);
      aktkep=kepek[akti=Csucs.LE*4];
    }
  } /// JobbraLeSzorny

  public static class Kisgomboc extends Mozgo {
    private static String klassz="Kisgomboc";
    public String getKlassz() { return klassz; }
    protected Labirintus labirintus;
    public int getReteg() { return 50; }
    /**
     * Megpróbál kanyarodni arra, amerre a játékos szeretné; ha nem
     * sikerül, megy tovább egyenesen. Továbbá itt kezdeményezzük a
     * legrövidebbút-keresést és a bombalerakást. Ütközésvizsgálatot nem
     * végzünk, azt végez helyettünk mindenki más.
     */
    protected void halad() {
      if (labirintus.getJatek().isMostBombaLe()) {
        // naploz(" bombat rak le"); // CsakPro
        labirintus.bombatLerak(this);
      }
      setEro();
      int erobk=0;
      while (erobk!=ero) { // áthalad a csomopontokon
        erobk=ero;
        if (0==halad(labirintus.getJatek().getUjIrany())) halad(irany);
        if (getCsucsban()!=null) labirintus.kitablazando();
      }
      aktkep=kepek[akti=irany*4+labirintus.getJatek().getHat()%4];
    }
    Kisgomboc(Labirintus l) {
      this.labirintus=l;
      Kepbetolto kepbetolto=l.getKepbetolto();
      Sdpts sd=l.getSd();
      kepek=new Kep[20];
      kepek[Csucs.JOBB*4+0]=kepbetolto.betolt("gombocj0.gif").initi(sd,-12,-12,5);
      kepek[Csucs.JOBB*4+1]=kepbetolto.betolt("gombocj1.gif").initi(sd,-12,-12,5);
      kepek[Csucs.JOBB*4+2]=kepbetolto.betolt("gombocj2.gif").initi(sd,-12,-12,5);
      kepek[Csucs.JOBB*4+3]=kepbetolto.betolt("gombocj3.gif").initi(sd,-12,-12,5);
      kepek[Csucs.BAL *4+0]=kepbetolto.betolt("gombocb0.gif").initi(sd,-12,-12,5);
      kepek[Csucs.BAL *4+1]=kepbetolto.betolt("gombocb1.gif").initi(sd,-12,-12,5);
      kepek[Csucs.BAL *4+2]=kepbetolto.betolt("gombocb2.gif").initi(sd,-12,-12,5);
      kepek[Csucs.BAL *4+3]=kepbetolto.betolt("gombocb3.gif").initi(sd,-12,-12,5);
      kepek[Csucs.FEL *4+0]=kepbetolto.betolt("gombocf0.gif").initi(sd,-12,-12,5);
      kepek[Csucs.FEL *4+1]=kepbetolto.betolt("gombocf1.gif").initi(sd,-12,-12,5);
      kepek[Csucs.FEL *4+2]=kepbetolto.betolt("gombocf2.gif").initi(sd,-12,-12,5);
      kepek[Csucs.FEL *4+3]=kepbetolto.betolt("gombocf3.gif").initi(sd,-12,-12,5);
      kepek[Csucs.LE  *4+0]=kepbetolto.betolt("gombocl0.gif").initi(sd,-12,-12,5);
      kepek[Csucs.LE  *4+1]=kepbetolto.betolt("gombocl1.gif").initi(sd,-12,-12,5);
      kepek[Csucs.LE  *4+2]=kepbetolto.betolt("gombocl2.gif").initi(sd,-12,-12,5);
      kepek[Csucs.LE  *4+3]=kepbetolto.betolt("gombocl3.gif").initi(sd,-12,-12,5);
      kepek[Csucs.PIHI*4+0]=kepbetolto.betolt("gombocp0.gif").initi(sd,-12,-12,5);
      kepek[Csucs.PIHI*4+1]=kepbetolto.betolt("gombocp0.gif").initi(sd,-12,-12,5);
      kepek[Csucs.PIHI*4+2]=kepbetolto.betolt("gombocp0.gif").initi(sd,-12,-12,5);
      kepek[Csucs.PIHI*4+3]=kepbetolto.betolt("gombocp0.gif").initi(sd,-12,-12,5);
      max_ero=40;
      aktkep=kepek[akti=Csucs.PIHI*4];
      // System.err.println(klassz); // mindig "Kisgomboc"
    }
    protected void elfordult() {}
    // aktkep=kepek[irany]; akti=irany*4; }
    // akarsz_e_utkozni()-nek jo a default `return false;'-sa
  } /// Kisgomboc

  // ---

  public static class Jatek {
    // nyílbillentyűk: haladás
    // szóköz: bomba lerakása
    // Esc: játék felfüggesztés ki/be
    // betűk: csúcslistába beírás
    // Enter: csúcslistába beírás vége/ játék vége
    
    // Imp: flag-ek, thread safety??
    /**
     * A következő :Labirintus betöltése folyamatban.
     */
    public static final int A_SZINTLEPES=1;
    /**
     * A :Labirintus már be van töltve, az első billentyű leütésére várunk.
     */
    public static final int A_LABKEZDODIK=2;
    /**
     * A játék folyik (fut).
     */
    public static final int A_FOLYIK=3;
    /**
     * A játék fel van függesztve (várakozik).
     */
    public static final int A_FELFUGGESZTVE=4;
    /**
     * A játék véget ért, az esetleges csúcslistába beírás folyik.
     */
    public static final int A_BEIRAS=5;
    /**
     * A játék teljesen véget ért, a csúcslistába beírás is megtörtént.
     */
    public static final int A_LEGVEGE=6;

    protected Kisero kisero;
    // protected Kepbetolto kepbetolto;
    protected Labirintus.LabirintusRajzolo lr;
    protected JobboldalRajzolo jr;
    protected Labirintus labirintus;
    protected Idozitett idozitett;
    protected int eletszam, maxeletszam, bombaszam, maxbombaszam, pontszam, szint;
    protected int status; // a `status'-t csak this.run() módosíthatja

    // vvv kívülről jövő, aszinkron ingerek
    volatile protected char uj_karakter;
    public static final int F_BOMBALERAKANDO=1, F_MEGHALT=2,
      F_MEGALLITANDO=4, F_HOZZAFUZENDO=8, F_LEZARANDO=16, F_SZINTLEPENDO=32,
      F_INDITANDO=64;
    volatile protected int inger;

    // public Jatek(Kepbetolto kepbetolto, Labirintus.LabirintusRajzolo lr, JobboldalRajzolo jr, Idozitett idozitett)
    public Jatek(Kisero kisero) {
      this.kisero=kisero;
      this.lr=kisero.labirintusRajzolo;
      this.jr=kisero.jobboldalRajzolo;
      this.idozitett=kisero.idozitett;
      idozitett.ujraindit()// !! stat-okat nulláz stb.
      maxeletszam=5;
      maxbombaszam=3;

      eletszam=maxeletszam;
      bombaszam=0; 
      // bombaszam=3; // FEJL!!
      pontszam=0;
      // `szint=0;' esetén fog az első szintről indulni
      szint=0;
      status=A_SZINTLEPES;
    }
    public Sdpts getLabSd() { return lr.getSd()}
    public Kepbetolto getKepbetolto() { return kisero.kepbetolto; }
    public Labirintus getLabirintus() { return labirintus; }

    // public synchronized int getStatus() { return status; }
    // protected synchronized void setStatus(int uj_status) { this.uj_status=status; }

    /**
     * Jelzi, hogy a következő lépésben szintet kell lépni.
     */
    public synchronized void szintlepes() { inger|=F_SZINTLEPENDO; }

    /**
     * Az előírt haladási irány.
     */
    volatile protected int ujIrany;
    /**
     * Jelzi, hogy a következő lépésben merre kell (kéne) fordulni.
     */
    public synchronized void fordulj(int irany) {
      // System.err.println("Fordulj!"); // DEBUG
      if (status==A_LABKEZDODIK) { ujIrany=irany; inger|=F_INDITANDO; }
      else if (status==A_FOLYIK) { ujIrany=irany; }
    }
    /**
     * Visszadja, hogy merre akart menni legutoljára a játékos.
     */
    public int getUjIrany() { return ujIrany; }

    /**
     * Jelzi, hogy a következő lépésben bombát kell lerakni.
     */
    public synchronized void bombatLerak() {
      if (status==A_FOLYIK) inger|=F_BOMBALERAKANDO;
    }
    /**
     * Pontosan akkor `true', ha ebben a lépésben bombát kell lerakni (és van
     * is bomba felvéve). Miután
     * egyszer visszatért `true'-val, legközelebb `false'-t ad vissza. Ha
     * `true'-t ad vissza, egyben csökkenti is a rendelkezésre álló bombák
     * számát. Ezt csak a `Kisgomboc.halad()' hívja.
     * @see eNTitanok.kkkg.KkkgAppl.Kisgomboc#halad()
     */
    public synchronized boolean isMostBombaLe() {
      if (0!=(inger&F_BOMBALERAKANDO)) {
        inger&=~F_BOMBALERAKANDO;
        if (bombaszam>0) { bombaszam--; return true}
      }
      return false;
    }

    /**
     * Jelzi, hogy a csúcslistához egy karaktert hozzá kell fűzni.
     */    
    public synchronized void hozzafuz(char c) {
      if (status==A_BEIRAS) {
        inger|=F_HOZZAFUZENDO;
        uj_karakter=c;
      }
    }
    
    /**
     * Jelzi, hogy a csúcslista módosítása véget ért.
     */
    public synchronized void lezar() {
      if (status==A_BEIRAS) inger|=F_LEZARANDO;
    }
    
    /**
     * A játék felfüggesztettségét ellentétesre változtatja.
     */
    public synchronized void megallit() {
      if (status==A_FOLYIK) inger|=F_MEGALLITANDO;
      else if (status==A_FELFUGGESZTVE) inger|=F_INDITANDO;
    }
    // ^^^ Imp: szinkronizálás...

    protected synchronized int ingerTorles() { int i=inger; inger=0; return i; }

    /**
     * Ez az egyetlen hely, ahol módosítjuk a this.status-t, this.inger
     * alapján. Mivel `synchronized', ezért az ide írt kódot gyorsra kell
     * tervezni.
     * @see status
     * @see inger
     */
    public synchronized void statusLeptet() {
      if (status==A_BEIRAS) {
        if (0!=(inger&F_HOZZAFUZENDO)) {
          // kisero.naploz("csucslistaba "+uj_karakter); // CsakPro
          kisero.csucslista.hozzafuz(uj_karakter);
          inger&=~F_HOZZAFUZENDO;
          csucslistaRajzolando=true;
          // statRajzolando=true;
        }
        if (0!=(inger&F_LEZARANDO)) {
          String debug=kisero.csucslista.lezar();
          // kisero.naploz(debug==null?"csucslista marad":"csucslistaba: "+debug); // CsakPro
          kisero.csucslista.kiment();
          inger=0;
          status=A_LEGVEGE;
          // statRajzolando=true;
          csucslistaRajzolando=true;
          // labirintus.feloszlat();
          labirintus=null;
        }
      } else if (status==A_FELFUGGESZTVE) {
        if (0!=(inger&F_INDITANDO)) {
          inger=0;
          status=A_FOLYIK;
          // System.err.println("FOLYIK"); // DEBUG
          idozitett.ujraindit();
        }
      } else if (status==A_LABKEZDODIK) {
        if (0!=(inger&F_INDITANDO)) {
          // kisero.naploz("jatekos elindult"); // CsakPro
          inger=0;
          status=A_FOLYIK;
        }
      } else if (status==A_FOLYIK) {
        if (0!=(inger&F_SZINTLEPENDO) && kisero.labirintussor.isUres()) {
          // nincs már több labirintus
          pontszam+=eletszam*997;
          eletszam=1;
          inger=F_MEGHALT;
        }
        if (0!=(inger&F_SZINTLEPENDO)) {
          // System.err.println("DDD"); // DEBUG
          inger=0;
          status=A_SZINTLEPES;
          labirintus.feloszlat();
          labirintus=null;
        } else if (0!=(inger&F_MEGHALT)) {
          inger=0;
          if (--eletszam==0) {
            status=A_BEIRAS;
            // kisero.naploz("jatek vege, csucslista jon"); // CsakPro
            labirintus.feloszlat();
            labirintus.alaphelyzetbe();
            kisero.csucslista.felvesz(pontszam);
            labirintus.elorajzol();
            lr.paintMost();
            statRajzolando=true;
            csucslistaRajzolando=true;
          } else {
            status=A_LABKEZDODIK;
            // kisero.naploz("eletvesztes. maradt "+eletszam); // CsakPro
            labirintus.alaphelyzetbe();
            labirintus.elorajzol();
            lr.paintMost();
          }
          // statRajzolando=true;
        } else if (0!=(inger&F_MEGALLITANDO)) {
          inger=0;
          status=A_FELFUGGESZTVE;
        }
      } /// IF
    } /// statusLeptet()

    /**
     * Szinte csak ez <I>fut</I> a főszálban. Frissíti a játékállást
     * (,,mozgatja a játékot''), betölti a pályákat, csúcslistába ír,
     * kezdeményezi a képernyő újrarajzolását. Figyeli, ahogy telik az idő.
     * Szóval (időben) ez csinál majdnem mindent.
     */
    public void fut() {
      while (true) {
        // System.err.println("megint "+status+";;"+ujIrany); // DEBUG
        // Imp: sync, Thread safe
        // kisero.gyerunk();
        // ^^^ már nem hívjuk meg, csak a legelején
        statusLeptet();
        // System.err.println("Elore!"); // DEBUG
        if (status==A_LEGVEGE) {
          // kisero.naploz("jatek legvege"); // CsakPro
          statRajzolando=true;
          statRajzol();
          break;
        } else if (status==A_SZINTLEPES) {
          // kisero.naploz("szintlepes"); // CsakPro
          // System.err.println("Szintlépés!"); // DEBUG
          // status=A_SZINTLEPES;
          // Imp: érvénytelenítés előtt várakozás stb.
          lr.ervenytelenit("Szintlépés");
          lr.paintMost();
          // Idozito.alszik(1000);
          szint++; statRajzolando=true;
          csucslistaRajzolando=true;
          if (labirintus!=null) throw new AsserttError();
          // labirintus=null;
          // System.err.println("SZISZ"); // DEBUG
          jr.masikHatter(((Kisero.Labielem)kisero.labirintussor.elso()).palya_jobbja, kisero.kepbetolto);
          labirintus=new Labirintus(this, szint);
          // bombaszam=0; // 8.1-es teszteset miatt nem nullázunk
          ujIrany=Csucs.PIHI;
          kisero.kepbetolto.mind_meglegyen();
          labirintus.palya_betoltve();
          lr.ervenyesit(labirintus);
          // lr.setDebugUzenet("csuhaj");
          labirintus.elorajzol();
          // !!!
          statRajzol()// jr.paintMost(); // Imp: nem mindig !!
          // csucslistaRajzol();
          // jr.repaint();
          lr.paintMost();
          status=A_LABKEZDODIK;
          // !!! az egészet újrarajzolni, nem csak a labirintust
          idozitett.ujraindit()// idozito.kezdd_ujra();
          kisero.ciklus=0;
          // kisero.naploz("uj szint"); // CsakPro
          // System.err.println("HUH."); // DEBUG
        } else if (status==A_FELFUGGESZTVE) {
          statRajzol();
          idozitett.altass_el();
        } else if (status==A_LABKEZDODIK) {
          statRajzol();
          idozitett.altass_el();
        } else if (status==A_BEIRAS) {
          // statRajzolando=true;
          statRajzol();
          // csucslistaRajzol();
          // System.err.println("beiras van!"); // DEBUG
          idozitett.altass_el();
        } else if (status==A_FOLYIK) {
          // System.err.println("Kukk!"); // DEBUG
          // lr.setDebugUzenet("megt="+idozitett.getMegteve()+" lass="+idozitett.getSikerultPeriodus()+"/"+
          //  idozitett.getEloirtPeriodus()+"  "+idozitett.getLassuMuveletSzazalek()+"%/100%");
          // labirintus.getKisgomboc().fordul(ujIrany);
          // ^^^ ehelyett a :Kisgömböc maga hívja a getUjIrany-t
          // System.err.println("Mukk"); // DEBUG
          labirintus.mozgat();
          // System.err.println("TOTO"); // DEBUG
          if (idozitett.lehet_lassu_muvelet()) {
            // most jön a rajzolás sd-re. Ez egy lassú művelet, úgyhogy csak
            // akkor végezzük, ha jól állunk időben
            // System.err.println("HAHOHO"); // DEBUG
            labirintus.elorajzol();
            statRajzol()// jr.paintMost();
            lr.paintMost();
            idozitett.lassu_muvelet()//rajzoltunk_osszesen++; //nem_rajzoltunk=0; idozito.altass_el(this);
          } else {
            idozitett.gyors_muvelet()// nem_rajzoltunk++; nem_rajzoltunk_osszesen++; idozito.altass_el(this);
          }
        } else throw new AsserttError();
      } // WHILE(true)
    } /// run()
    public int getHat() { return (int)idozitett.getGyorsMuvelet()/6; }

    protected boolean statRajzolando;
    protected boolean csucslistaRajzolando;
    protected void statRajzol() {
      // if (true) return;
      if (!statRajzolando && !csucslistaRajzolando) return;
      jr.getSd().dirtyClear();
      //if (statRajzolando) {
        int gyemantc=labirintus==null?0:labirintus.getGyemantc();
        jr.statUjraRajzol(gyemantc, pontszam, bombaszam, eletszam, szint);
         // jr.getSd().dirtyAddClear();
        // statRajzol(jr.getGraphics());
        // jr.getSd().dirtyAddMax();
      //}
      //if (csucslistaRajzolando) {
        jr.csucslistaUjraRajzol(kisero.csucslista);
      //}
      jr.paintMost();
      // System.err.println("KKK: "+labirintus.getGyemantc()); // DEBUG
      statRajzolando=false;
      csucslistaRajzolando=false;
    } /// statRajzol()
    /**
     * A megadott értékkel növeli a szerzett pontszámot.
     */
    protected void novelPontszam(int mennyivel) {
      pontszam+=mennyivel;
      statRajzolando=true;
    }
    /**
     * Eggyel csökkenti az életek számát. A :Labirintus hívja egyszer, nem a
     * :Láthatók külön-külön.
     */
    public synchronized void csokkentEletszam() {
      if ((inger&F_MEGHALT)!=0) return;
      // if (eletszam--==0) throw new AsserttError();
      statRajzolando=true;
      inger|=F_MEGHALT;
    }
    /**
     * A megadott értékkel (vagy maximumra) növeli az életek számát. Akkor
     * növel maximumra, ha a megadott érték kisebb, mint 1.
     */
    public void novelEletszam(int mennyivel) {
      if (mennyivel<1 && eletszam<maxeletszam) eletszam=maxeletszam;
      else if (mennyivel<1) eletszam++;
      else eletszam+=mennyivel;
      statRajzolando=true;
    }
    /**
     * Eggyel növeli a felvett bombák számát.
     */
    public void novelBombaszam() {
      bombaszam++;
      statRajzolando=true;
    }
    public Kisero getKisero() { return kisero; }
  } /// class Jatek

  public static class JobboldalRajzolo extends SdRajzolo {
    Betutipus betutipus;
    public JobboldalRajzolo(Betutipus betutipus) {
      this.betutipus=betutipus;
      atmeretez(160, 80);
      super.atmeretez(160, 480);
      this.setBackground(Color.red);
      init_sd();
    }
    public void masikHatter(String kepnev, Kepbetolto kepbetolto) {
      Kep kep=kepbetolto.betolt(kepnev).initi(sd,0,0);
      kepbetolto.mind_meglegyen();
      Graphics g=this.sd.getBackgroundGraphics();
      kep.rarajzol(g,0,0);
      this.sd.dirtyAddClear();
    }
    Betutipus getBetutipus() { return betutipus; }
    public void paint(Graphics g) { // Canvas újrarajzolás
      this.sd.renderAll(g, 0, 0);
      // g.setColor(Color.white); g.drawString("Csiribá", 10, 50);
      // if (betutipus!=null) betutipus.nyomtat(g,10,80,"Tősgyökeres Űrkikötőkerülő"); // DEBUG
    }
    /**
     * Ténylegesen, feltétel nélkül újrarajzolja a jobboldal stat részét.
     */
    protected void statUjraRajzol(int gyemantc, int pontszam, int bombaszam, int eletszam, int szint) {
      // Graphics g=jr.getSd().getBackgroundGraphics();
      Graphics g=getSd().getGraphics();
      // g.setColor(Color.black);
      // g.fillRect(0,0,160,100);
      // g.setColor(Color.white); // ezt betutipus init-kor kell állítani
      sd.dirtyAdd(0,0,160,150);
      // betutipus.nyomtat(g,80,10,"gy.mar: "+gyemantc);
      betutipus.nyomtatBalra(g,140, 0, ""+pontszam);
      betutipus.nyomtatBalra(g,140,20, ""+eletszam);
      betutipus.nyomtatBalra(g,140,40, ""+bombaszam);
      betutipus.nyomtatBalra(g,140,60, ""+szint);
      // g.dispose(); // itt tilos hívni!
      // kisero.naploz("elet="+eletszam+" pont="+pontszam+" szint="+szint+" bomba="+bombaszam); // CsakPro
    } /// statUjraRajzol()
    protected void csucslistaUjraRajzol(Csucslista cs) {
      // Graphics g=jr.getSd().getBackgroundGraphics();
      Graphics g=getSd().getGraphics();
      // g.setColor(Color.black);
      // g.fillRect(0,0,160,100);
      // g.setColor(Color.white); // ezt betutipus init-kor kell állítani
      sd.dirtyAdd(0,80,160,190);
      for (int i=cs.length()-1;i>=0;i--) {
        betutipus.nyomtat(g,35,94+(i+1)*17,cs.nevAt(i));
        betutipus.nyomtatBalra(g,150,94+(i+1)*17,""+cs.pontszamAt(i));
      }
      // g.dispose(); // itt tilos hívni!
    } /// csucslistaUjraRajzol()
  } /// class Jobboldalrajzolo

  public static class Labirintus {
    /**
     * Legfeljebb ennyi :Látható lehet egyszerre a :Labirintusban. Értéke: 42.
     * Értékét nem érdemes túl nagyra venni, mert négyzetesen lassul a játék
     * és nő a memóriaszükséglet.
     */
    public static final int MAX_LATHATOK=42;
    
    public static final int U_MINDEGY=0, U_NEMUTKOZIK=1, U_UTKOZIK=2;

    protected Kisero.Labielem le;

    protected Kep palya_alja;
    protected Kep palya_teteje;
    protected Kep palya_arnyeka;
    protected Kep palya_grafja;
    protected Sdpts sd;
    protected Jatek jatek;
    protected Csucs kezdocsucs;

    /**
     * A következő ciklus bombalerakással kezdődik, mégpedig a megadott
     * :Helyzet-be.
     */
    protected Helyzet bombaLerakando;
    /**
     * Bombalerakást kezdeményez (a kovetkezo ciklusra) a megadott :Helyzet-be.
     */
    public void bombatLerak(Helyzet h) { bombaLerakando=new Helyzet(h)}

    /**
     * A :Labirintusban található :Gyémánt-ok száma.
     */
    protected int gyemantc;
    /**
     * A :Labirintusban található :Szörny-ek száma.
     */
    protected int szornyc;
    /**
     * A :Labirintusban található :Ajándék-ok száma.
     */
    protected int ajandekc;
    // private Vector csucsok; // num->Csucs

    public int getGyemantc() { return gyemantc; }
    /**
     * getRegeg() szerint növekvő sorrendben.
     */
    protected Lathato lathatok[];
    /**
     * A vele azonos indexű `this.lathatok'-beli elem törlendő-e?
     */
    protected boolean torlendo[];
    protected int utkozesek[][];
    protected int utkozesc[];
    // protected int addLathatoI; // a legutolsó index, ahova addLathato adott

    /**
     * Ellenőrzi, hogy a `lathatok' és a `torlendo' tömb (és az egyéb
     * attribútumok) konzisztensek-e.
     * `AsserttError' kivételt vált ki, ha nem.
     */
    public void assertt() {
      if (gyemantc<0 || szornyc<0 || ajandekc<0) throw new AsserttError();
      int c=gyemantc;
      int cc=0;
      if (lathatok==null) throw new AsserttError();
      if (torlendo==null || lathatok.length!=torlendo.length) throw new AsserttError();
      for (int i=0;i<lathatok.length;i++) {
        if (torlendo[i] && lathatok[i]==null) throw new AsserttError();
        if (lathatok[i]==null) continue;
        if (lathatok[i].getId()!=i) throw new AsserttError();
        if (lathatok[i] instanceof Gyemant) c--;
        if (lathatok[i] instanceof Kisgomboc) cc++;
      }
      if (c!=0) throw new AsserttError(c+" +Gyemant ("+gyemantc+")");
      if (cc>1) throw new AsserttError(cc+" db :Kisgomboc");
    }
    
    /**
     * Akkor váltódik ki, ha `this.lathatok[]' betelt.
     */
    public static class NincsHelyError extends Error {}
    
    /**
     * Egy új :Látható-t helyez el this.lathatok-ban.
     */
    protected Lathato addLathato(Lathato lathato) {
      int i, k;
      // null-okat összenyomjuk
      int j=0;
      for (i=0;i<lathatok.length;i++) if (lathatok[i]!=null) {
        lathatok[j]=lathatok[i];
        lathatok[j].setId(j);
        torlendo[j]=torlendo[i];
        j++;
      } // NEXT
      if (j==lathatok.length) throw new NincsHelyError();
      for (k=j;k<lathatok.length;k++) { lathatok[k]=null; torlendo[k]=false}
      
      int ujreteg=lathato.getReteg();
      k=0; // első jó index
      for (i=j-1;i>=0;i--) {
        if (lathatok[i].getReteg()<=ujreteg) k=i+1;
      }
      // System.err.println(j); // DEBUG
      for (i=j;i>k;i--) {
        lathatok[i]=lathatok[i-1];
        torlendo[i]=torlendo[i-1];
        lathatok[i].setId(i);
      }

      // a tényleges hozzáadás
      i=k;
      torlendo[i]=false;
      lathatok[i]=lathato;
      lathato.setId(i);
      lathato.setNaplozo(jatek.getKisero());
      // lathato.naploz(" keletkezik"); // CsakPro
      if (lathato instanceof Gyemant) gyemantc++;
      if (lathato instanceof Szorny) szornyc++;
      if (lathato instanceof Ajandek) ajandekc++;
      for (i=0;i<lathatok.length;i++) { if (lathatok[i]!=null) {
        for (j=0;j<lathatok.length;j++) if (i!=j && lathatok[j]!=null) {
          utkozesek[i][j]=lathatok[i].akarsz_e_utkozni(lathatok[j])?U_NEMUTKOZIK:U_MINDEGY;
          utkozesek[j][i]=lathatok[j].akarsz_e_utkozni(lathatok[i])?U_NEMUTKOZIK:U_MINDEGY;
        }
      } }
      return lathato;
    } // addLathato()

    /**
     * A `Lathato.halad()'-ok hívják, ha valakit el akarnak távolítani.
     * Egyelőre csak feljegyzi, hogy el kell távolítani, és a tényleges
     * munkat `Labirintu.eltunnek()'-re hagyja.
     * @see eNTitanok.kkkg.KkkgAppl.Labirintus#eltunnek()
     */
    public void removeLathato(Lathato lathato) {
      if (lathato==null) return;
      int id=lathato.getId();
      if (id>=0) torlendo[id]=true;
    }
    
    /**
     * A `removeLathato()'-val elvett :Láthatókat tünteti el végleg.
     * @see eNTitanok.kkkg.KkkgAppl.Labirintus#removeLathato
     */
    public void eltunnek() {
      for (int i=0;i<lathatok.length;i++) if (torlendo[i]) {
        Lathato lathato=lathatok[i];
        if (lathato==null) throw new AsserttError();
        lathato.setId(-1);
        // lathato.naploz(" eltunik"); // CsakPro
        if (lathato instanceof Gyemant) {
          if (--gyemantc<1) jatek.szintlepes()// FEJL!!
          // gyemantc--; jatek.szintlepes(); // FEJL!!
        } else if (lathato instanceof Kisgomboc) jatek.csokkentEletszam();
        else if (lathato instanceof Ajandek) ajandekc--;
        else if (lathato instanceof Szorny) szornyc--;
        int u[]=utkozesek[i];
        for (int j=0;j<lathatok.length;j++) u[j]=U_MINDEGY;
        for (int j=0;j<lathatok.length;j++) utkozesek[j][i]=U_MINDEGY;
        // for (int j=0;j<lathatok.length;j++) utkozesek[i][j]=U_MINDEGY;
        lathatok[i]=null;
        torlendo[i]=false;
      }
    } /// eltunnek()

    /**
     * Eltörli a szörnyeket és az ajándékokat, továbbá a kezdőcsúcsba mozgatja
     * a :Kisgömböc-öt. `this.mozgat()'-on belülről tilos hívni.
     */
    public void alaphelyzetbe() {
      bombaLerakando=null;
      for (int i=0;i<lathatok.length;i++) if (lathatok[i]!=null) {
        Lathato lathato=lathatok[i];
        if (lathato instanceof Ajandek) removeLathato(lathato);
        else if (lathato instanceof Szorny) removeLathato(lathato);
        else if (lathato instanceof KetyegoBomba) removeLathato(lathato);
        else if (lathato instanceof Kisgomboc && !torlendo[i]) throw new AsserttError();
      }
      eltunnek();
      if (kezdocsucs!=null)
        addLathato(new Kisgomboc(this)).athelyez(kezdocsucs);
    }

    /**
     * Akkor hívódik meg, amikor a :Játék-nak már nincs szüksége this-re.
     * Csak az a dolga, hogy felszabadítson némi memóriát.
     */
    public void feloszlat() {
      kezdocsucs=null;
      removeLathato(getKisgombocNull());
      // ^^^ bugfix by pts@fazekas.hu at Wed May 16 09:41:33 CEST 2001
      // System.err.println(getKisgomboc());
    }
    public void elorajzol() {
      sd.dirtyClear();
      for (int i=0;i<lathatok.length;i++) if (lathatok[i]!=null) lathatok[i].rarajzolArnyek(sd);
      // ^^^ előbb az _összes_ árnyékot felrajzoljuk
      for (int i=0;i<lathatok.length;i++) if (lathatok[i]!=null) lathatok[i].rarajzol(sd);
      // sd.dirtyCover(); // az sprite-okat fedje a falrács
      // sd.fullCover(); // az egészet fedje a falrács
      // KkkgAppl.this.repaint(); // rögtön visszatér, de összevissza bufferel
    }

    public Labirintus(Jatek jatek, int sorszam) {
      Kepbetolto kepbetolto=jatek.getKepbetolto();
      this.jatek=jatek;
      this.sd=jatek.getLabSd();
      this.le=(Kisero.Labielem)jatek.getKisero().labirintussor.elsoTorol();
      if (this.le==null) throw new NincsKovetkezoError("szintlepeshez nincs kov. palya");

      palya_alja=   kepbetolto.betolt(le.palya_alja).initi(sd,0,0);
      palya_teteje= kepbetolto.betolt(le.palya_teteje).initi(sd,0,0);
      palya_arnyeka=kepbetolto.betolt(le.palya_arnyeka).initi(sd,0,0);
      palya_grafja= kepbetolto.betolt(le.palya_grafja).initi(sd,0,0);

      // String ss=Util.decformat(sorszam, 3);
      // palya_alja=   kepbetolto.betolt("p_"+ss+"h.gif").initi(sd,0,0);
      // palya_teteje= kepbetolto.betolt("p_"+ss+"e.gif").initi(sd,0,0);
      // palya_arnyeka=kepbetolto.betolt("p_"+ss+"g.gif").initi(sd,0,0);
      // palya_grafja= kepbetolto.betolt("p_"+ss+"g.gif").initi(sd,0,0);

      lathatok=new Lathato[MAX_LATHATOK];
      torlendo=new boolean[lathatok.length];
      // addLathatoI=lathatok.length-1;
      utkozesek=new int[lathatok.length][];
      utkozesc=new int[lathatok.length];
      for (int i=0;i<lathatok.length;i++) utkozesek[i]=new int[lathatok.length];

      // addLathato(new Kisgomboc(this));
      
      // vvv csak azért, hogy a képét letöltse
      new Kisgomboc(this);
      new Gyemant(this,false);
      new OkosSzorny(this,0,null,false);
      new ButaSzorny(this,0,null,false);
      new JobbraSzorny(this,0,null,false);
      new BalraSzorny(this,0,null,false);
      new BalraFelSzorny(this,0,null,false);
      new JobbraLeSzorny(this,0,null,false);
      new SimaElixir(this,false);
      new SzuperElixir(this,false);
      new FelvehetoBomba(this,false);
      new Bonusz(this,false);
      new KetyegoBomba(this,false,false);
      
      //addLathato(new BalraSzorny(this,40));
      //for (int i=0;i<8;i++) addLathato(new RepuloGyemant(this,48-i,24-i)).mozgat(50*24,50*24);
      
      // a képek betöltődésére várni kell, a további inicializalast a
      // palya_betoltve() vegzi
    }
    public Jatek getJatek() { return jatek; }
    public Kepbetolto getKepbetolto() { return jatek.getKepbetolto()}
    public Sdpts getSd() { return sd; }

    //-- public Kisgomboc getKisgomboc() { return (Kisgomboc)lathatok[0]; }
    //-- public void kezdocsucsba(Helyzet h) { h.athelyez(kezdocsucs); }
    // ^^^ public void kezdocsucsba(Helyzet h) { h.athelyez((Csucs)csucsok.get(0)); }
    
    public int getUtkozesc(int id) { return utkozesc[id]}
    /**
     * Azokat a :Láthatókat adja vissza, akikkel `lathato' éppen
     * ütközik. (Persze `lathato' nem szerepel a visszaadott listában.)
     */
    public Lathato[] getUtkozesek(Lathato lathato) {
      int id=lathato.getId();
      if (id<0 || utkozesc[id]<1) return null;
      Lathato t[]=new Lathato[utkozesc[id]];
      int i=0;
      int u[]=utkozesek[id];
      for (int j=0;j<u.length;j++) if (u[j]==U_UTKOZIK) t[i++]=lathatok[j];
      return t;
    }

    /**
     * Inicializálás azután, hogy a pálya már betöltődött.
     */
    public void palya_betoltve() {
      jatek.getKepbetolto().elfelejt(palya_alja.getFilenev());
      jatek.getKepbetolto().elfelejt(palya_teteje.getFilenev());
      jatek.getKepbetolto().elfelejt(palya_arnyeka.getFilenev());
      jatek.getKepbetolto().elfelejt(palya_grafja.getFilenev());
      grafot_felepit();
      // lathatok[0].utkozes_teszt(lathatok[2]);
      //--System.err.println(lathatok[0].mennyit_mehet(Csucs.BAL));
      //--System.err.println(lathatok[0].mennyit_mehet(Csucs.FEL));
      //--this.kezdocsucsba((Helyzet)lathatok[0]);
      //--this.kezdocsucsba((Helyzet)lathatok[1]);
    }

    /**
     * Hány ciklus múlva fog keletkezni :Szörny. `-1', ha még nem döntöttük
     * el.
     */
    int szornyHatra=-1;
    /**
     * Hány ciklus múlva fog keletkezni :Ajándék. `-1', ha még nem döntöttük
     * el.
     */
    int ajandekHatra=-1;

    public boolean utkozik_barmivel(Lathato lathato) {
      for (int j=0;j<lathatok.length;j++)
        if (lathatok[j]!=null && lathato!=lathatok[j] && lathato.utkozik_e(lathatok[j])) return true;
      return false;
    }

    /**
     * Itt keletkeznek az új :Szörny-ek és :Ajándék-ok és :Bombák.
     */
    public void keletkeznek() {
      // System.err.println("KK");
      Kisero kisero=jatek.getKisero();
      if (bombaLerakando!=null) {
        addLathato(new KetyegoBomba(
          this, kisero.Kisgomboc_KetyegoBomba, kisero.Szorny_KetyegoBomba
        )).athelyez(bombaLerakando);
        bombaLerakando=null;
      }
      // System.err.println("SH="+szornyHatra); // DBG
      if (szornyHatra<1 || ajandekHatra<1) {
        Kisgomboc kisgomboc=getKisgomboc();
        int maradt=10; // legfeljebb ennyiszer próbálkozunk lerakni
        while (szornyHatra<1) {
          // System.err.println("SS"); // DBG
          if (szornyHatra<0 || maradt--<=0) szornyHatra=Math.max(0,le.szorny.general());
          // System.err.println("SS h="+szornyHatra); // DBG
          if (szornyHatra==0) { // :Szörny keletkezik épp most
            int milyen=le.okosbutabaljobbbfjl.general();
            int seb=le.szornyseb.general();
            Szorny sz=null;
            switch (milyen) {
              case 0: sz=new OkosSzorny(this, seb, le.fordul, kisero.Kisgomboc_Szorny)break;
              case 1: sz=new ButaSzorny(this, seb, le.fordul, kisero.Kisgomboc_Szorny)break;
              case 2: sz=new BalraSzorny(this, seb, le.fordul, kisero.Kisgomboc_Szorny)break;
              case 3: sz=new JobbraSzorny(this, seb, le.fordul, kisero.Kisgomboc_Szorny)break;
              case 4: sz=new BalraFelSzorny(this, seb, le.fordul, kisero.Kisgomboc_Szorny)break;
              case 5: sz=new JobbraLeSzorny(this, seb, le.fordul, kisero.Kisgomboc_Szorny)break;
              defaultthrow new AsserttError();
            }
            int hely;
            Csucs cs=(Csucs)szornyhelyek.elementAt(hely=le.szornyhol.general());
            if (szornyc<3 && !utkozik_barmivel(sz) && sz.alkalmasKel(cs.getTavolsag(), kisgomboc.ferdeTavolsag(cs))) {
              addLathato(sz).athelyez(cs);
              szornyHatra=-1;
            } else {
              // sz.naploz(" nem keletkezik "+hely+". helyen", kisero); // CsakPro
            } // IF
          } // IF
        } // WHILE
        // System.err.println("Mostjo"); // DEBUG
        maradt=10; // legfeljebb ennyiszer próbálkozunk lerakni
        while (ajandekHatra<1) {
          // System.err.println("AA"); // DBG
          if (ajandekHatra<0 || maradt--<=0) ajandekHatra=Math.max(0,le.ajandek.general());
          // System.err.println("AA h="+ajandekHatra); // DBG
          if (ajandekHatra==0) { // :Ajándék keletkezik épp most
            int milyen=le.bonbomsimszu.general();
            Ajandek aj=null;
            switch (milyen) {
              case 0: aj=new Bonusz(this, kisero.Kisgomboc_Ajandek)break;
              case 1: aj=new FelvehetoBomba(this, kisero.Kisgomboc_Ajandek)break;
              case 2: aj=new SimaElixir(this, kisero.Kisgomboc_Ajandek)break;
              case 3: aj=new SzuperElixir(this, kisero.Kisgomboc_Ajandek)break;
              defaultthrow new AsserttError();
            }
            int hely;
            Csucs cs=(Csucs)ajandekhelyek.elementAt(hely=le.ajandekhol.general());
            if (ajandekc<5 && !utkozik_barmivel(aj) && aj.alkalmasKel(cs.getTavolsag(), kisgomboc.ferdeTavolsag(cs))) {
              addLathato(aj).athelyez(cs);
              // aj.naploz("NNN"); // DEBUG
              ajandekHatra=-1;
            } else {
              // aj.naploz(" nem keletkezik "+hely+". helyen", kisero); // CsakPro
            }
          } // IF
        } // WHILE
      } // IF
      szornyHatra--; ajandekHatra--;
    } /// keletkeznek()

    /**
     * Megvizsgálja az összes érdekes ütközést az összes lehetséges
     * :Látható-párra, és az eredményt
     * `this.utkozesek'-be gyűjti.
     */
    public void utkozesvizsgalat() {
      int i, j, u[], uc;
      for (i=0;i<lathatok.length;i++) {
        u=utkozesek[i];
        uc=0;
        for (j=0;j<lathatok.length;j++) if (lathatok[i]!=null && lathatok[j]!=null && u[j]!=U_MINDEGY)
//        for (j=0;j<lathatok.length;j++) if (u[j]!=U_MINDEGY)
          // ^^^ !! null vizsgálat -- úgy tűnik -- kell
          if (lathatok[i].utkozik_e(lathatok[j])) {
            u[j]=U_UTKOZIK; uc++;
            // lathatok[i].naploz(" utkozik "+lathatok[j].getKlassz()+"-vl"); // CsakPro
          } else { u[j]=U_NEMUTKOZIK; }
        utkozesc[i]=uc;
      }
    } /// utkozesvizsgalat()

    /**
     * Egyetlen ciklusnyi időnek megfelelően mozgatja a labirintus :Látható-it.
     */
    public void mozgat() {
      // System.err.println("0=>"+((Csucs)meropontok.elementAt(0)).getTavolsag()); // DBG
      // System.err.println("1=>"+((Csucs)meropontok.elementAt(1)).getTavolsag()); // DBG
      // System.err.println("3=>"+((Csucs)meropontok.elementAt(3)).getTavolsag()); // DBG
      assertt()// CsakPro
      kitablaz();
      keletkeznek()// kitablaz() eredményét már felhasználjuk
      assertt()// CsakPro
      utkozesvizsgalat();
      // vvv meghívjuk a halad-ot minden :Látható-ra (a halad már felhasználja az ütközési táblázatot
      for (int i=0;i<lathatok.length;i++) if (lathatok[i]!=null) lathatok[i].halad();
      // ((Helyes)lathatok[0]).halad_amerre_fordul();
      eltunnek();
      assertt()// CsakPro
    }

    // --- most jönnek a gráfot felépítő segédrutinok

    public static class HibasGrafError extends Error {
      public HibasGrafError(String s) { super(s)}
    }
    public static class NincsKovetkezoError extends HibasGrafError {
      public NincsKovetkezoError(String s) { super(s)}
    }
    // public static class KisgombocHianyzikException extends HibasGrafException {}
    /**
     * Pontosan akkor `true', ha a megadott pozíción határcsúcs van, vagyis
     * olyan csúcs, melyet :Csúcs-nak fel kell vennünk a gráfba. Csak a
     * grafot_felepit() hívja.
     */
    private boolean hatarcsucs_e(int[][] tt, int x, int y) {
      if (tt[y][x]==Konst.D_FAL) return false;
      if (tt[y][x]!=Konst.D_UT) return true;
      boolean fel=tt[y-1][x]!=Konst.D_FAL;
      boolean le=tt[y+1][x]!=Konst.D_FAL;
      boolean jobb=tt[y][x+1]!=Konst.D_FAL;
      boolean bal=tt[y][x-1]!=Konst.D_FAL;
      return !((fel&&le&&!jobb&&!bal) || (!fel&&!le&&jobb&&bal));
    }
    
    /**
     * :Csucs-okból álló Vector, a lehetséges :Szörny keletkezési helyeket
     * tárolja.
     */
    protected Vector szornyhelyek;
    /**
     * :Csucs-okból álló Vector, a lehetséges :Ajándék keletkezési helyeket
     * tárolja.
     */
    protected Vector ajandekhelyek;
    
    /**
     * Csak hibakeresés céljára.
     */
    private Vector meropontok=new Vector();
    
    /**
     * Pontosan akkor true, ha a ciklus végén `this.kitablaz()'-t kell
     * futtatni. A :Kisgömböc állítja be néha true-ra
     * @see eNTitanok.kkkg.KkkgAppl.Labirintus#kitablazando()
     */
    protected boolean kitablazando_e=true;
    /**
     * `this.kitablazando=true'.
     */
    public void kitablazando() { kitablazando_e=true}
    /**
     * A :Kisgömböc felé vezető legrövidebb utat keresi meg. Az összes :Csúcs
     * irány- és távolságjelző tábláját frissíti. Implementáció: ez egy
     * legrövidebbút-kereső gráfalgoritmus, amit tipikusan Dijkstra módszerével
     * szoktak leprogramozni. Mi kihasználjuk, hogy a labirintusgráfunk
     * euklideszi síkon van, így egy gyorsabb, egyszerűbb szélességi keresés
     * is jó (optimális, legrövidebb) eredményt ad.
     */
    public void kitablaz() {
      if (!kitablazando_e) return;
      // vvv először is mindenkit kinyomunk plusz végtelenbe
      Sor szurke=new Sor()// :Csúcs-okból áll
      kezdocsucs.setTavolsag(Integer.MAX_VALUE);
      szurke.vegehezFuz(kezdocsucs);
      Csucs csucs;
      while (null!=(csucs=(Csucs)szurke.elsoTorol()))
        csucs.tavolit(szurke);
      // vvv megkeressük a legrövidebb utat szélességi kereséssel
      // Dat: szurke most üres.
      getKisgomboc().ketSzomszed(szurke);
      while (null!=(csucs=(Csucs)szurke.elsoTorol()))
        csucs.kozelit(szurke);
    }

    /**
     * A :Labirintusban található egyetlen :Kisgömböc objektumot adja vissza.
     * Csak a :Labirintusból hívható, külsősöknek semmi közük hozzá.
     */
    protected Kisgomboc getKisgomboc() {
      for (int i=0;i<lathatok.length;i++) if (lathatok[i] instanceof Kisgomboc) return (Kisgomboc)lathatok[i];
      throw new AsserttError();
    }
    /**
     * A :Labirintusban található egyetlen :Kisgömböc objektumot adja vissza,
     * vagy null-t, ha nincs.
     * Csak a :Labirintusból hívható, külsősöknek semmi közük hozzá.
     */
    protected Kisgomboc getKisgombocNull() {
      for (int i=0;i<lathatok.length;i++) if (lathatok[i] instanceof Kisgomboc) return (Kisgomboc)lathatok[i];
      return null;
    }
    
    /**
     * A `palya_grafja' kép alapján felépíti a labirintusgráfot.
     */
    public void grafot_felepit() {
      int tt[][]=null;
      tt=palya_grafja.getPixelttkerek();
      // tt=le.getPix(); // CsakPro
      Csucs ki[][]=new Csucs[tt.length][];
      kezdocsucs=null;
      ajandekhelyek=new Vector();
      szornyhelyek=new Vector();

      int meropontc=0;
      gyemantc=0; ajandekc=0; szornyc=0;
      Csucs cs=null;
      for (int y=tt.length-2;y>=1;y--) {
        int uu[]=tt[y];
        ki[y]=new Csucs[uu.length];
        for (int x=uu.length-2;x>=1;x--) {
          if (uu[x]==Konst.D_KOMMENT) uu[x]=Konst.D_FAL;
          if (!hatarcsucs_e(tt, x, y)) continue;
          cs=new Csucs(x*24, y*24);
          if (uu[x]==Konst.D_KISGOMBOC) {
            if (kezdocsucs!=null) throw new MarErtekesError();
            kezdocsucs=cs;
            addLathato(new Kisgomboc(this)).athelyez(cs);
          } else if (uu[x]==Konst.D_AJANDEK) {
            ajandekhelyek.addElement(cs);
          } else if (uu[x]==Konst.D_SZORNY) {
            szornyhelyek.addElement(cs);
          } else if (uu[x]==Konst.D_MEROPONT) {
            cs.setMeropont(meropontc++);
            meropontok.addElement(cs);
          } else if (uu[x]==Konst.D_GYEMANT) {
            addLathato(new Gyemant(this, jatek.getKisero().Kisgomboc_Gyemant)).athelyez(cs);
          }
          ki[y][x]=cs;
          // csucsok.addElement(cs);
          if (uu[x+1]!=Konst.D_FAL) { // összekötünk jobbra
            int i=x+1;
            while (!hatarcsucs_e(tt, i, y)) i++;
            cs.osszekot(ki[y][i]);
          }
          if (tt[y+1][x]!=Konst.D_FAL) { // összekötünk le
            int i=y+1;
            while (!hatarcsucs_e(tt, x, i)) i++;
            cs.osszekot(ki[i][x]);
          }
        } // NEXT x
      } // NEXT y
      if (szornyhelyek.size()<1) throw new HibasGrafError("nincs Szorny keletkezesi hely");
      if (ajandekhelyek.size()<1) throw new HibasGrafError("nincs Ajandek keletkezesi hely");
      le.szornyholMeret(szornyhelyek.size());
      le.ajandekholMeret(ajandekhelyek.size());
      // if (kezdocsucs==null) kezdocsucs=cs;
      if (kezdocsucs==null) throw new HibasGrafError("Kisgomboc hianyzik");
      // System.exit(42); // applet-ből SecurityException-t ad
      palya_grafja.pixelt_felejt();
    }

    public static class LabirintusRajzolo extends SdRajzolo {
      protected String miertErvenytelen;
      protected String debugUzenet;

      public LabirintusRajzolo() {
        super.atmeretez(320, 480);
        // System.err.println(this.getSize()); // debug
        init_sd();
        miertErvenytelen="Inicializálok...";
      }

      public void ervenytelenit(String miert) { miertErvenytelen=miert; }
      public void setDebugUzenet(String miert) { debugUzenet=miert; }
      /**
       * Egyszer hívódik meg, miután a képek betöltődtek.
       */
      public void ervenyesit(Labirintus l) {
        Graphics g=this.sd.getBackgroundGraphics();
        l.palya_alja.rarajzol(g,0,0);
        // g.setColor(Color.pink); g.fillRect(100,100,200,200);
        // sd.dirtyAdd(0,0,screenW,screenH);
        this.sd.dirtyAddClear();
        // g.dispose(); // Tilos hívni!

        // g=this.sd.getCoverGraphics(); l.palya_teteje.rarajzol(g,0,0); g.dispose();
        this.sd.setCover(l.palya_teteje.getImage());

        // g=this.sd.getShadowGraphics(); l.palya_arnyeka.rarajzol(g,0,0); g.dispose();
        this.sd.setShadow(l.palya_grafja.getImage());

        this.sd.dirtyAdd(0,0,this.sd.getWidth(),this.sd.getHeight());
        this.sd.dirtyClear();
        miertErvenytelen=null;
      }

      public void paint(Graphics g) { // Canvas újrarajzolás
        if (miertErvenytelen!=null) {
          g.setColor(Color.green.darker());
          g.fillRect(0, 0, this.sd.getWidth()this.sd.getHeight());
          g.setColor(Color.red.brighter());
          // g.drawString("Épp töltögetek...", 10, 20);
          g.drawString(miertErvenytelen, 10, 20);
        } else {
          this.sd.renderAll(g, 0, 0);
          // ^^^ az egész ablakot cakumpakk újrarajzoljuk

          // g.setColor(Color.white);
          // for (int i=0;i<elek.length;i++) { elek[i].rarajzol(g); }
          // ^^^ csak debug, már nem kell

          // if (sebesseg!=0) {}
          if (debugUzenet!=null) {
            // if (true) throw new NullPointerException();
            g.setColor(Color.white);
            //g.drawString("Lassúság: eddig="+sebesseg+"/"+1000*idozito.getInterval()+
            //  " rajzolás="+(100*(rajzoltunk_osszesen)/(rajzoltunk_osszesen+nem_rajzoltunk_osszesen))+
            //  "%.",10,20);
            g.drawString(debugUzenet, 10, 20);
          }
          //frissitesre_varunk=false;
        }
        //palya_teteje.rarajzol(g, 0, 0);
      } /// paint()
    } /// class LabirintusRajzolo
  } /// class Labirintus

  public void update(Graphics g) { this.paint(g)}
  // ^^^ Panel.this.paint()-et meghagyjuk

  private boolean application_e; // pontosan akkor true, ha Java Application-ként futunk
  // private Jatek jatek;
  private Kisero kisero;
  private Labirintus.LabirintusRajzolo labirintusRajzolo;
  private JobboldalRajzolo jobboldalRajzolo;

  public KkkgAppl() {}
  private KkkgAppl(boolean application_e) { this.application_e=application_e; }
  public java.net.URL getCodeBase() {
    return application_e?null:super.getCodeBase();
  }
  
  /**
   * A tesztfile neve, mielőtt létrehozzuk a :Kísérő-t. Ha null, akkor
   * a beépített resource-ot vesszük tesztfile-nak.
   * @see Kisero
   */
  protected String teszt;
  public void setTeszt(String teszt) { this.teszt=teszt; }

  /**
   * Mindhárom komponenshez hozzáadja a *Listener-eket. Elvileg elég lenne
   * csak az applet-hez, de Java 1.1.7, Linux alatt mindegyikhez kell,
   * különben nem működik.
   */
  public void initFigyelok() {
    FocusListener myFocusListener=new FocusAdapter() {
      public void focusGained(java.awt.event.FocusEvent e) {
        // System.err.println("Fokk"); // DEBUG
      }
    };
    this.addFocusListener(myFocusListener);
    labirintusRajzolo.addFocusListener(myFocusListener);
    jobboldalRajzolo.addFocusListener(myFocusListener);
    MouseListener myMouseListener=new MouseAdapter() {
      public void mouseClicked(java.awt.event.MouseEvent e) {
        // nem hívódik meg, mert az al-komponensek kapják meg az üzenetet
        // ,elfelejtodik'' meghivodni, ha az eger elmozdult a gomblenyomas
        // es a felengedes kozott
        //KkkgAppl.this.repaint(teglalap_x-40,teglalap_y-25,80,50);

        //teglalap_x=e.getX(); teglalap_y=e.getY();
        //System.err.println("Klitty x="+Integer.toString(e.getX())+
        //  " y="+Integer.toString(e.getY())+"."); // DEBUG
        // KkkgAppl.this.repaint(teglalap_x-40,teglalap_y-25,80,50);
        // KkkgAppl.this.repaint();
        KkkgAppl.this.requestFocus();
      }
    };
    this.addMouseListener(myMouseListener);
    labirintusRajzolo.addMouseListener(myMouseListener);
    jobboldalRajzolo.addMouseListener(myMouseListener);
    KeyListener myKeyListener=new KeyAdapter() {
      /**
       * Csak olyan billentyukre hivodik meg, amelyek karakter beszurasat eredemenyezik.
       * Tehat peldaul meghivodik A, ó, Enter, szóköz stb-re, de nem hivodik meg
       * pl. Home, Shift, NumLock stb.-re.
       */
      public void keyTyped(java.awt.event.KeyEvent e) {
        // System.err.println("Potty karakter Unicode U+"+Util.hexformat(e.getKeyChar(),4)+"."); // DEBUG
      }
      // vvv for Java version 1.1.7 compatibility
      public final int VK_KP_UP=0xE0;
      public final int VK_KP_DOWN=0xE1;
      public final int VK_KP_LEFT=0xE2;
      public final int VK_KP_RIGHT=0xE3;
      /**
       * Minden billentyűre meghivodik.
       */
      public void keyPressed(java.awt.event.KeyEvent e) {
        if (kisero.jatek==null) return;
        int kc=e.getKeyCode();
        char c=e.getKeyChar();
        // if (kc==e.VK_UP) { menne_fel=true; menne_le=false; }
        // if (kc==e.VK_DOWN) { menne_le=true; menne_le=false; }
        // if (kc==e.VK_UP || kc==e.VK_KP_UP) jatek.getLabirintus().getKisgomboc().fordul(Csucs.FEL);
        //else if (kc==e.VK_DOWN || kc==e.VK_KP_DOWN) jatek.getLabirintus().getKisgomboc().fordul(Csucs.LE);
        //else if (kc==e.VK_LEFT || kc==e.VK_KP_LEFT) jatek.getLabirintus().getKisgomboc().fordul(Csucs.BAL);
        //else if (kc==e.VK_RIGHT || kc==e.VK_KP_RIGHT) jatek.getLabirintus().getKisgomboc().fordul(Csucs.JOBB);

        if (kc==e.VK_UP || kc==VK_KP_UP) kisero.jatek.fordulj(Csucs.FEL);
        else if (kc==e.VK_DOWN || kc==VK_KP_DOWN) kisero.jatek.fordulj(Csucs.LE);
        else if (kc==e.VK_LEFT || kc==VK_KP_LEFT) kisero.jatek.fordulj(Csucs.BAL);
        else if (kc==e.VK_RIGHT || kc==VK_KP_RIGHT) kisero.jatek.fordulj(Csucs.JOBB);
        else if (kc==e.VK_SPACE)  kisero.jatek.bombatLerak();
        else if (kc==e.VK_ESCAPE) kisero.jatek.megallit();
        else if (kc==e.VK_ENTER)  kisero.jatek.lezar();
        else if (c>='a' && c<='z'
              || c>='A' && c<='Z'
              || c>='0' && c<='9'
              || c=='_'
                ) kisero.jatek.hozzafuz(c);
        // else System.err.println("Potty le  bilkod="+new Integer(e.getKeyCode()).toString()+"."); // DEBUG
      }
      public void keyReleased(java.awt.event.KeyEvent e) {
        // System.err.println("Potty fel bilkod="+new Integer(e.getKeyCode()).toString()+"."); // DEBUG
        // KkkgAppl.this.repaint();
      }
    };
    this.addKeyListener(myKeyListener);
    labirintusRajzolo.addKeyListener(myKeyListener);
    jobboldalRajzolo.addKeyListener(myKeyListener);
  } /// initFigyelok()

  /**
   * Az ablak első megjelenése <I>előtti</I> inicializálásokat végzi el,
   * például háttérszín és méret beállítás, pakolási stratégia és a két
   * komponens felvétele.
   */
  public void initAblak() {
    // Kepek.setMainComponent(this); // -- fölösleges, OkosApplet alapból tudja
    // először a megjelenítést inicializáljuk
    this.setBackground(Color.yellow)// sose szabadna látszania!!
    this.resize(480, 480);
    // ^^^ appletviewer-nek kell. application-ként nagyobbra?!
    if (this.getSize().width<480 || this.getSize().height<480)
      throw new AtmeretezesNemSikerultException();
    //this.setLayout(new GridLayout(1,2,0,0)); // SUXX, fix méret nem állítható be
    this.setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0));
    this.add(labirintusRajzolo);
    this.add(jobboldalRajzolo);
    this.requestFocus();
    // ^^^ enelkul nem kapnank meg a billentyuleuteseket appletviewer-ben
    this.repaint();
    this.requestFocus();
  }

  /**
   * Megtesz minden tőle telhetőt, hogy megragadja a billentyűzetfókuszt.
   */    
  public void fokusztKer() {
    this.requestFocus();
    this.repaint();
    this.requestFocus()// nincs hatása JDK1.1.7-ben
    // Thread.yield(); Idozito.alszik(2000);
    labirintusRajzolo.requestFocus();
  }

  /**
   * Ezt a függvényt hívná az Appletviewer a program indulásakor. Mi kézzel
   * hívjuk a main()-ból.
   */
  public void init() {
    // System.err.println("HEELO!"); // DEBUG
    // a.setTeszt(argv[0]); // !!
    Kepbetolto kepbetolto=new Kepbetolto()// ezt még bármilyen kép előtt
    Idozito idozito=new Idozito(16)// 16.
    idozito.setDaemon(true);
    idozito.start();
    // Object idozito=null; // kamu
    Kep k=kepbetolto.betolt("ss13.gif");
    kepbetolto.mind_meglegyen();
    // Betutipus betutipus=new Betutipus(k,0x000000); // fekete betűk
    Betutipus betutipus=new Betutipus(k,0xFFFFFF)// fehér betűk
    labirintusRajzolo=new Labirintus.LabirintusRajzolo();
    jobboldalRajzolo=new JobboldalRajzolo(betutipus);
    initAblak();
    kisero=(teszt==null)?new Kisero("(eroforras)",getEroforrasStream("eNTitanok/kkkg/a_jatek.txt"))
                        :new Kisero(teszt);
    kisero.labirintusRajzolo=labirintusRajzolo;
    kisero.jobboldalRajzolo=jobboldalRajzolo;
    kisero.kepbetolto=kepbetolto;
    kisero.idozitett=new Idozitett(idozito);

    jobboldalRajzolo.repaint();
    this.initFigyelok();
    // ^^^ csak kisero=... után

    this.fokusztKer();
    kisero.start()// !!
  }
  public void start() { /* Applet.start() felülírva */
    this.fokusztKer()// itt sincs hatása JDK1.1.7-ben
  }
  public void stop() { /* Applet.stop() felülírva */
  }

  public static void main(String argv[]) {
    System.err.println("Kincskereso Kisgomboc Jatek (Application), 3. verzio\n(C) Summer 2001 by eNTitanok. http://www.inf.bme.hu/~pts/entitanok/\nTHIS SOFTWARE COMES WITH ABSOLUTELY NO WARRANTY! USE AT YOUR OWN RISK!\n");
    final KkkgAppl a=new KkkgAppl(true);
    if (argv.length>0) a.setTeszt(argv[0]);
    final OkosFrame f=new OkosFrame("eNTitánok: Kincskereső Kisgömböc játék", a, OkosFrame.A_APPLETKILEP);
    // ^^^ esetleg hullámvonalas ő jelenhet meg. \u0151 se lenne jobb, mert
    //     az nem Unicode-os rendszerekben Q betűt eredményezne.
    f.setSizeC(480,480);
    f.setBackground(Color.pink);
    f.setResizable(false);
    f.show();
    // ^^^ azért kell minél hamarabb kirakni, mert a createImage() csak akkor
    //     képes képet készíteni, ha a komponens már megjelent.
    a.init();
    f.show();
    a.start();
    // Azért nem lép ki a program a main-ből való visszatérés után, mert
    // vannak még ,,elvarratlan'' szálak.
  } // main()
} /// class KkkgAppl