  
  # ------------------------------------------------------------------------
  # Copyright (c) 1995 Christian Krone, Varziner Str. 12, D-12161 Berlin
  # All rights reserved.
  # ------------------------------------------------------------------------
  # Permission is hereby granted, without written agreement and without
  # license or royalty fees, to use, copy, modify, and distribute this
  # software and its documentation for any purpose, provided that the
  # above copyright notice and the following two paragraphs appear in
  # all copies of this software.
  # ------------------------------------------------------------------------
  # IN NO EVENT SHALL CHRISTIAN KRONE BE LIABLE TO ANY PARTY FOR DIRECT,
  # INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
  # OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF CHRISTIAN
  # KRONE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  # ------------------------------------------------------------------------
  # CHRISTIAN KRONE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
  # NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  # FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN
  # "AS IS" BASIS, AND CHRISTIAN KRONE HAS NO OBLIGATION TO PROVIDE
  # MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  # ------------------------------------------------------------------------
    proc kopiereRegeln {dest src} {
        foreach regel {kartenSatz stapelAnz patName stapelReihe stockBasis
                       stockReihe strafReihe streitArt leerStapelNurHoch
                       talonAbraeumbar teilStapelReihe exist
                       stapelGrund stapelVerdeckt} {
          upvar #0 $regel var

          foreach name [array names var] {
            if {![string compare $src $name]} {
              set var($dest) $var($name)
            } elseif {[regexp ^${src},(.*)$ $name egal subIndex]} {
              set var($dest,$subIndex) $var($name)
            }
          }
        }
      }
    proc liesSpiel {} {
      global patArt patName kartenSatz streitArt exist stapelAnz \
             stapelGrund stapelVerdeckt stapelReihe stockBasis   \
             stockReihe teilStapelReihe strafReihe               \
             leerStapelNurHoch talonAbraeumbar
      global patiencePath neuPat
      foreach spielDir [list $patiencePath/spiel \
                             [split [option get .patience sprPath SprPath] :]] {
        foreach spiel [glob -nocomplain $spielDir/*.spr] {
          source $spiel
        }
      }
      if {![info exists patArt]} {
        set patArt standard
        set patName($patArt,deutsch)    "Standard"
        set patName($patArt,english)    "Standard"
        set kartenSatz($patArt)         2
        set streitArt($patArt)          0
        set exist($patArt,talon)        0
        set exist($patArt,strafe)       0
        set exist($patArt,arbeit)       0
        set stapelAnz($patArt)          8
        set stapelGrund($patArt,0)      3
        set stapelGrund($patArt,1)      3
        set stapelGrund($patArt,2)      3
        set stapelGrund($patArt,3)      3
        set stapelGrund($patArt,4)      3
        set stapelGrund($patArt,5)      3
        set stapelGrund($patArt,6)      3
        set stapelGrund($patArt,7)      3
        set stapelVerdeckt($patArt,0)   2
        set stapelVerdeckt($patArt,1)   2
        set stapelVerdeckt($patArt,2)   2
        set stapelVerdeckt($patArt,3)   2
        set stapelVerdeckt($patArt,4)   2
        set stapelVerdeckt($patArt,5)   2
        set stapelVerdeckt($patArt,6)   2
        set stapelVerdeckt($patArt,7)   2
        set stapelReihe($patArt)        abst,unecht
        set teilStapelReihe($patArt)    abst,unecht
        set stockBasis($patArt)         a
        set stockReihe($patArt)         aufst,echt
        set strafReihe($patArt)         aufAb,echt
        set leerStapelNurHoch($patArt)  0
        set talonAbraeumbar($patArt)    1
      }
      set vorgabe [winfo name .]
      set gefunden 0
      foreach bekannteRegel [array names stapelAnz] {
        if {[string match $bekannteRegel* $vorgabe]} {
          set patArt $bekannteRegel
          set gefunden 1
        }
      }
      if {!$gefunden} {
        set patArt standard
      }
      set neuPat $patArt
    }
    proc schrRegeln {fileName schrPat} {
      global patArt patName kartenSatz streitArt exist stapelAnz \
             stapelGrund stapelVerdeckt stapelReihe stockBasis   \
             stockReihe teilStapelReihe strafReihe               \
             leerStapelNurHoch talonAbraeumbar

      lappend zust "set patArt [string trimleft $schrPat :]"
      foreach regel {kartenSatz stapelAnz patName stapelReihe stockBasis
                     stockReihe strafReihe streitArt leerStapelNurHoch
                     talonAbraeumbar teilStapelReihe exist
                     stapelGrund stapelVerdeckt} {
        upvar #0 $regel var

        foreach name [array names var] {
          if {![string compare $schrPat $name]} {
            lappend zust "set ${regel}(\$patArt) \"$var($name)\""
          } elseif {[regexp ^${schrPat},(.*)$ $name egal subIndex]} {
            lappend zust "set ${regel}(\$patArt,$subIndex) \"$var($name)\""
          }
        }
      }

      set aus [open $fileName "w"]
      global patienceVersion
      puts $aus "# ------------------------------------------------------------"
      puts $aus "#    Patience Version $patienceVersion"
      puts $aus "#    Spielregeln erzeugt durch 'Regeln editieren/Speichern'"
      puts $aus "#    Per Hand aendern ist unsportlich UND wird geahndet."
      puts $aus "# ------------------------------------------------------------"
      foreach zeile $zust {
        puts $aus $zeile
      }
      close $aus
    }
    proc initZustand {} {
        global stapel fuelle verdeckt teilStapelUnterst streitArt patArt \
               inversZug vorschlaege vorschlagZaehler mogelZaehler zugNr

        foreach var {stapel fuelle verdeckt vorschlaege
                     teilStapelUnterst aktiverSpieler} {
          catch "unset $var"
        }
        set fuelle(hand2) " "
        trace variable fuelle(hand)  w chkKartenAnz
        trace variable fuelle(hand2) w chkKartenAnz

        set inversZug        {}
        set vorschlagZaehler 0
        set mogelZaehler     0
        set zugNr            0
      }
    proc schrZustand {fileName inDatei invers} {
      global patienceVersion exist streitArt patArt stapelAnz kartenSatz
      global zugNr mogelZaehler inversZug vorschlagZaehler hand \
             stapel fuelle verdeckt teilStapelUnterst aktuellErste aktiverSpieler

      if {!$inDatei} {
        upvar $fileName zust
        set zust ""
      }

      global tk_version patienceVersion
      lappend zust "# -------------------------------------------------------------"
      lappend zust "#    Patience Version $patienceVersion"
      lappend zust "#    Programmzustand erzeugt durch die Funktion 'Speichern'"
      lappend zust "#    Per Hand aendern ist unsportlich UND wird geahndet."
      lappend zust "# -------------------------------------------------------------"
      lappend zust ""
      lappend zust "global tk_version patienceVersion"
      lappend zust "if {\$tk_version      < $tk_version ||"
      lappend zust "    \$patienceVersion < $patienceVersion} return"

      set schrPat $patArt
      lappend zust "set patArt [string trimleft $schrPat :]"
      foreach regel {kartenSatz stapelAnz patName stapelReihe stockBasis
                     stockReihe strafReihe streitArt leerStapelNurHoch
                     talonAbraeumbar teilStapelReihe exist
                     stapelGrund stapelVerdeckt} {
        upvar #0 $regel var

        foreach name [array names var] {
          if {![string compare $schrPat $name]} {
            lappend zust "set ${regel}(\$patArt) \"$var($name)\""
          } elseif {[regexp ^${schrPat},(.*)$ $name egal subIndex]} {
            lappend zust "set ${regel}(\$patArt,$subIndex) \"$var($name)\""
          }
        }
      }
      lappend zust ""

      lappend zust "global zugNr;            set zugNr            $zugNr"
      lappend zust "global mogelZaehler;     set mogelZaehler     $mogelZaehler"
      lappend zust "global vorschlagZaehler; set vorschlagZaehler $vorschlagZaehler"
      lappend zust "global aktuellErste;     set aktuellErste     $aktuellErste"
      if {[info exists aktiverSpieler]} {
        lappend zust "global aktiverSpieler; set aktiverSpieler   $aktiverSpieler"
      }
      lappend zust "global stapel fuelle verdeckt teilStapelUnterst"
      foreach stap {stapel fuelle verdeckt teilStapelUnterst} {
        if {$invers} {
          set tmpZust ""
          pArray tmpZust $stap
          regsub -all (hand|talon|strafe)2  $tmpZust {\13} tmpZust
          regsub -all (hand|talon|strafe)   $tmpZust {\12} tmpZust
          regsub -all (hand|talon|strafe)23 $tmpZust {\1}  tmpZust
          append zust " $tmpZust"
        } else {
          pArray zust $stap
        }
      }
      if {!$streitArt($patArt)} {
        lappend zust "global inversZug;    set inversZug [list $inversZug]"
      }

      if {$inDatei} {
        set aus [open $fileName "w"]
        foreach zeile $zust {
          puts $aus $zeile
        }
        close $aus
      }
    }
    proc liesZustand {fileName} {
      global patArt patName kartenSatz streitArt exist stapelAnz \
             stapelGrund stapelVerdeckt stapelReihe stockBasis   \
             stockReihe teilStapelReihe strafReihe               \
             leerStapelNurHoch talonAbraeumbar
      global neuPat text

      initZustand
      source $fileName

      set patArt $patArt
      set neuPat $patArt

      setBitPath <>
      if {[info exists aktiverSpieler]
          && ![string compare $aktiverSpieler $text(computer)]} {
        demo
      }
    }
    proc pArray {aus a} {
      upvar #0 $a array
      upvar $aus zust
      global tk_version

      if {$tk_version >= 4.0} {
        lappend zust "array set $a {[array get array]}"
      } else {
        foreach name [array names array] {
          lappend zust [format "  set %s(%s) %s" $a $name $array($name)]
        }
      }
    }
    proc liesTexte {} {
        global text flaeche patiencePath sprache sprachDefault

        set sprache [option get .patience sprache Sprache]
        if {[catch "source $patiencePath/text/$sprache"]} {
          puts "Setzen der deutschen Defaulttexte..."
          set text(patience) "Patience"
          set text(erstelltVon) "Erstellt von"
          set text(spiel)           " Patience "
          set text(streitMit)       "Streit mit "
          set text(computer)        "Computer"
          set text(streitBereit)    "Streitbereit"
          set text(kontaktAufnahme) "Kontakt aufnehmen"
          set text(kontaktPruefen)  "Kontakt prüfen"
          set text(kontaktAbgleich) "Kontakt synchronisieren"
          set text(demo)            "Demo"
          set text(warte)           "Warte "
          set text(sekunden)        " s"
          set text(bildErneuern)    "Bild erneuern"
          set text(beenden)         "Beenden"
          set text(acc,neuesSpiel)  "n"
          set text(acc,demo)        "d"
          set text(acc,beenden)     "e"
          set text(datei)           " Datei "
          set text(spielzustand)    "Spielzustand"
          set text(laden)           "Laden"
          set text(speichern)       "Speichern"
          set text(regelnEditieren) "Regeln editieren"
          set text(sprache)         "Sprache"
          set text(acc,laden)       "l"
          set text(acc,speichern)   "s"
          set text(sprache) "Sprache"
          set text(unterstuetzung)  " Unterstützung "
          set text(vorschlag)       "Vorschlag"
          set text(ablegen)         "Ablegen"
          set text(zugZurueck)      "Zug zurück"
          set text(zumAnfang)       "zum Anfang"
          set text(merken)          "Merken"
          set text(zurMarke)        "Zur Marke"
          set text(veraendern)      "Verändern"
          set text(acc,vorschlag)   "v"
          set text(acc,ablegen)     "a"
          set text(acc,zugZurueck)  "z"
          set text(karten)          " Karten "
          set text(geben)           "Geben"
          set text(noch)            "Noch "
          set text(kartenUebrig)    " Karten"
          set text(kartenfonts)     " Kartenfonts "
          set text(mitComics)       "Mit Comics"
          set text(verteilen)       "Verteilen"
          set text(kartenbewegen)   "Kartenbewegen"
          set text(schatten:)       "Schattenhöhe: "
          set text(acc,geben)       "k"
          set text(hilfe)           " Hilfe "
          set text(spielregeln)     "Spielregeln"
          set text(demoHilfe)    "Das Drücken irgendeiner Taste beendet die Demo"
          set text(streitHilfe)  "Das Drücken von e oder n beendeet das Spiel"
          set text(zurueckHilfe) "Das Drücken irgendeiner Taste beendet die Rücknahme"
          set text(speicherAuswahl) "Dateiauswahl zum Speichern"
          set text(ladeAuswahl)     "Dateiauswahl zum Laden"
          set text(keineKartenFonts) \
                  "Nanu? Keine Kartenbitmap gefunden; deshalb ist jetzt Schluss..."
          set text(schatten)        "Schatten"
          set text(schattenGroesse) \
                  "Höhe der bewegten Karten (in Bildschirmpunkten)"
          set text(hinweis) "Unteren Knopf drücken,
          wenn kein Zug mehr möglich ist
          und der Gegner übernehmen soll"
          set text(demonstration)    "Demonstration"
          set text(zeitverzoegerung) "Zeitverzögerung (in 1/10 Sekunden)"
          set text(sendeFehler)   "Sende-Fehler"
          set text(keineReaktion) "Mitspielende Patience reagiert nicht mehr."
          set text(neuSenden)     "Nochmal senden"
          set text(neuAnfragen)   "Neu Anfragen"
          set text(gegenComputer) "Weiter gegen Computer"
          set text(kontakt)            "Kontakt aufnehmen"
          set text(willDochNicht)      "Gegner will doch nicht mehr spielen"
          set text(nichtEinverstanden) "Partner ist nicht einverstanden"
          set text(anfragen)           "Anfragen"
          set text(abgleich)           "Synchronisieren"
          set text(gegnerFragen)       "Partners um Einverständnis fragen..."
          set text(zustandUebernehmen) "Auf den Spielzustand des Partners aufsetzen?"
          set text(aufgabe)          "Spiel aufgeben"
          set text(kontaktAbbrechen) "Kontakt mit Spielpartner wirklich abbrechen?"
          set text(kontaktNeustart)  "Streitpatience wirklich aufgeben?"
          set text(neuerAnfang) "Gegner gibt auf. Bereit zu einem neuen Spiel?"
          set text(gegnerAngeben)   "Bitte Name des Gegners eintragen."
          set text(gegnerSuchen)    "Gewünschter Gegner wird gesucht..."
          set text(gegnerAnrufen)   "Gewünschter Gegner wird angerufen..."
          set text(gegnerUnwillig)  "Gewünschter Gegner mag gerade nicht streiten."
          set text(gegnerNichtDa)   "Gewünschter Gegner spielt gerade nicht Patience."
          set text(gegnerUnbekannt) "Gewünschter Gegner am gegebenen Rechner unbekannt."
          set text(gegenSelbst)     "Streiten gegen sich selbst geht leider nicht."
          set text(nurLokal)        "Streiten mit anderen Rechnern geht leider nicht."
          set text(keinDaemonDa)    "Am gegebenen Rechner will niemand streiten."
          set text(deinPeerFehlt)   "Zur Zeit kein Kontakt möglich (wegen dir)."
          set text(meinPortFehlt)   "Zur Zeit kein Kontakt möglich (wegen mir)."
          set text(hatAufgegeben) "Der Gegner hat aufgegeben."
          set text(weiterOhneIhn) "Allein weiter spielen"
          set text(spielGefaellig) "Spiel gefällig?"
          set text(besetzt)        "Gewünschter Gegner streitet bereits."
          set text(erMagSpielen)   "Der angegebene User hat Lust auf ein Spiel mit Dir."
          set text(hatKeineLust)   "Gewünschter Spieler hat keine Lust auf ein Spiel."
          set text(spaeter)        "Später vielleicht"
          set text(gehtLos)        "Partner ist mit einem neuen Spiel einverstanden."
          set text(unbekPatArt)    "Spielregeln beim Gegner nicht bekannt."
          set text(gegnerName) "Name des Gegners (user@host):"
          set text(werFaengtAn) "Wer fängt an?"
          set text(regelEditor) "Regel-Editor"
          set text(neu)         "Neu"
          set text(anwenden)    "Anwenden"
          set text(nameIntern)  "Name (intern):"
          set text(nameExtern)  "Name (extern):"
          set text(kartensatz)  "Kartensatz:"
          set text(einSatz)     "1 (52 Karten)"
          set text(zweiSaetze)  "2 (104 Karten)"
          set text(streitArt)   "Streitpatience:"
          set text(nein)        "nein"
          set text(ja)          "ja"
          set text(jaGemeinsam) "ja, gemeinsamer Kartensatz"
          set text(jaGetrennt)  "ja, getrennter  Kartensatz"
          set text(talonExist)  "Talon          :"
          set text(strafeExist) "Strafstapel  :"
          set text(arbeitExist) "Arbeitsstapel:"
          set text(stapelAnz)   "Anz. Stapel  :"
          set text(untereOffen) "Unten liegende Karten offen:" 
          set text(stapelReihe) "Ablage Stapel:"
          set text(absteigend)  "Absteigend"
          set text(aufsteigend) "Aufsteigend"
          set text(aufAb)       "Auf-/Absteigend"
          set text(echt)        "Echt"
          set text(unecht)      "Unecht"
          set text(egal)        "Egal"
          set text(teilStapel)  "Teilstapel:"
          set text(einzelKarte) "nur einzelne Karte"
          set text(komplett)    "Komplett"
          set text(stockReihe)  "Ablage Stock:" 
          set text(strafReihe)  "Ablage Strafe:"
          set text(stockBasis)  "Stock Basis:"
          set text(bauer)       "Bauer"
          set text(dame)        "Dame"
          set text(koenig)      "König"
          set text(as)          "As"
          set text(ersteKarte)  "Erste Karte"
          set text(stapelBasis) "Stapel Basis:"
          set text(jedeKarte)   "jede Karte"
          set text(nurHoechste) "nur höchste Karte"
          set text(talonAb)     "Alte Karten beweglich:"
          set text(neuerSpielregeln) "Neue Spielregeln"
          set text(nameAufforderung) \
                  "Bitte noch nicht benutzten internen Name der Patience angeben:"
          set text(bisherVergeben) "Bisher vergebene interne Namen sind "
          set text(nurErlaubt) \
                  ". Es sind nur Buchstaben, Zahlen sowie - und _ erlaubt."
          set text(fs,ordner) "Ordner:"
          set text(fs,datei)  "Datei:"
          set text(fs,maske)  "Maske:"
          set text(version)          "Version"
          set text(patienceFuerX11)  "Eine Patience für das X11-Windowsystem mit Tcl/Tk"
          set text(erstelltVonCK)    "erstellt von Christian Krone"
          set text(okay)             "Okay"
          set text(beendenTitel)     "Wirklich beenden?"
          set text(hoffeSpielWarGut) "Ich hoffe, Ihnen hat das Patience-Spiel gefallen."
          set text(wirklichBeenden)  "Wirklich Spiel beenden?"
          set text(abbruch)          "Abbruch"
          set text(spielende)        "Spielende"
          set text(neuesSpiel)       "Neues Spiel"
          set text(wirklichNeu)      "Wollen Sie wirklich ein neues Spiel beginnen?"
          set text(glueckwunsch)     "Glückwunsch"
          set text(gratuliere)       "Gratuliere!"
          set text(undEsGab)         "Und es gab "
          set text(einVorschlag)     "1 Vorschlag."
          set text(vorschlaege)      " Vorschläge."
          set text(patienceGeloest)  "Sie haben diese Patience gelöst."
          set text(dazuBenoetigt)    "Dazu benötigten Sie "
          set text(zuege)            " Züge."
          set text(super)            "Super"
          set text(sieHabenGewonnen) "Sie haben diese Streit-Patience gewonnen. "
          set text(undGegnerHat)     "Und der Gegner hatte noch "
          set text(restKarte1)       " Karte auf seinen Stapeln."
          set text(restKarten1)      " Karten auf seinen Stapeln."
          set text(beileid)          "Beileid"
          set text(schade)           "Schade!"
          set text(sieHabenVerloren) "Sie haben diese Streit-Patience leider verloren. "
          set text(undSieHatten)     "Und Sie hatten noch "
          set text(restKarte2)       " Karte auf Ihren Stapeln."
          set text(restKarten2)      " Karten auf Ihren Stapeln."
          set text(naechstesMal)     "Nächste Mal"
          set text(spielAufgegangen) "Die Patience ist aufgegangen!"
          set text(aberSieHaben)     "Aber Sie haben genau "
          set text(malGeschummelt)   " mal geschummelt!"
          set text(vielleichtBesser) "Vielleicht geht es beim nächsten mal besser?"
          set text(probieren)        "Probieren"
          set text(nichtLesbar)        "Nicht Lesbar"
          set text(nichtSchreibbar)    "Nicht Schreibbar"
          set text(dieDatei)           "Die Datei "
          set text(istNichtLesbar)     " ist nicht lesbar."
          set text(istNichtSchreibbar) " ist nicht beschreibbar."
          set text(dannNicht)          "Dann nicht"
          set text(keineVerteilung) "Nur lokal"
          set text(streitNurLokal)  "Hinweis: Streitpatiencen sind leider nur auf dem \
          lokalen Rechner möglich, da das Programm nicht von dpwish interpretiert wird.

          Siehe Kapitel 6 des Handbuchs (oder der Online-Hilfe) für genauere \
          Information zur Installation einer Patience, mit der an verschiedenen \
          Rechnern gestritten werden kann."
          set text(keinDaemon)   "Kein Patience-Daemon"
          set text(daemonFehler) "Obigen Fehler meldete der Patience-Daemon, als er \
          gestartet werden sollte.

          Damit ist es nicht möglich, von Spielerinnen an anderen Rechnern kontaktiert \
          zu werden. Die Kontaktaufnahme zu anderen Spielerinnen sollte jedoch \
          weiterhin funktionieren."
        }
        setzBenutzernamen $text(computer)
      }
    proc setzBenutzernamen {gegnerName} {
      global env ich du text

      if {[info exists env(USER)]} {
        set vorgabe $env(USER)
      } elseif {[info exists env(LOGNAME)]} {
        set vorgabe $env(LOGNAME)
      } else {
        set vorgabe ""
      }
      if {[string length $vorgabe]} {
        set ersterGross [string toupper [string index $vorgabe 0]]
        set restKlein   [string range $vorgabe 1 end]
        set ich  $ersterGross$restKlein
        set du   $gegnerName
      }
    }
    proc kartenFarbe {rang} {
        switch -- $rang {
          0 {set aktFarbe c}
          1 {set aktFarbe h}
          2 {set aktFarbe p}
          3 {set aktFarbe k}
        }
      }
      proc farbRang {farbe} {
        switch -glob $farbe {
          *c* {set aktFarbe 0}
          *h* {set aktFarbe 1}
          *p* {set aktFarbe 2}
          *k* {set aktFarbe 3}
        }
      }
      proc passt {alt neu stapel} {
        global stapelReihe teilStapelReihe stockReihe strafReihe \
               patArt aktuellErste

        if {![string length $neu] && [string match ?,? $stapel]} {
          set stockFarbe [string index $stapel 2]
          return [expr {[string match *,kompl $stockReihe($patArt)]
                        ? [aufsteigend $alt $aktuellErste 1]
                          && $stockFarbe == [string index $alt 1]
                        : [string range $alt 0 1] == "$aktuellErste$stockFarbe"}]
        }
        switch -glob $stapel {
          ?                {set regel $stapelReihe($patArt)}
          ?,?              {set regel $stockReihe($patArt)}
          teil             {set regel $teilStapelReihe($patArt)}
          talon* - strafe* {set regel $strafReihe($patArt)}
          default          {return 0}
        }
        switch -glob $regel {
          aufst,* {if {![aufsteigend $neu $alt 0]} {return 0}}
          abst,*  {if {![aufsteigend $alt $neu 0]} {return 0}}
          aufAb,* {if {![aufsteigend $alt $neu 0] &&
                       ![aufsteigend $neu $alt 0]} {return 0}}

          garNicht {return 0}
        }
        switch -glob $regel {
          *,unecht {if {![unecht $alt $neu]} {return 0}}
          *,echt   {if {![  echt $alt $neu]} {return 0}}
          *,kompl  {return 0}
        }
        return 1
      }
    proc mischen {} {
      global stapel fuelle kartenSatz patArt streitArt streitVorgabe

      if {[info exists streitVorgabe]} {
        global streitVorgabe stapel fuelle aktiverSpieler ich du kontakt

        set du                   $streitVorgabe(du)
        set kontakt(deinRechner) $streitVorgabe(deinRechner)
        set stapel(meinStart)    $streitVorgabe(meinStart)
        set stapel(deinStart)    $streitVorgabe(deinStart)

        foreach srcDest {{deineHand hand} {meineHand hand2}} {
          set src  [lindex $srcDest 0]
          set dest [lindex $srcDest 1]

          set fuelle($dest) [lindex $streitVorgabe($src) 0]
          set streitVorgabe($src) [lrange $streitVorgabe($src) 1 end]
          for {set aktI 0} {$aktI < $fuelle($dest)} {incr aktI} {
            set stapel($dest,$aktI) [lindex $streitVorgabe($src) $aktI]
          }
        }
        return
      }

      foreach runde {0 1} {
        set karten$runde {}
        if {$runde < $kartenSatz($patArt)} {
          foreach wert {k d b 0 9 8 7 6 5 4 3 2 a} {
            foreach farbe {c h p k} {
              lappend karten$runde $wert$farbe$runde
            }
          }
        }
      }

      if {$streitArt($patArt)} {
        set stapel(meinStart) ""
        set stapel(deinStart) ""
        while {$stapel(meinStart) == $stapel(deinStart)} {
          set stapel(meinStart) [lindex $karten0 [unifRand 52]]
          set stapel(deinStart) [lindex $karten0 [unifRand 52]]
        }
      }

      if {$streitArt($patArt) != 2} {
        set karten [concat $karten0 $karten1]
      }

      foreach hand [expr {$streitArt($patArt) ? "hand hand2" : "hand"}] {
        if {$streitArt($patArt) == 2} {
          set karten [expr {$hand=="hand2" ? $karten1 : $karten0}]
        }
        set fuelle($hand) 0
        set nochDa [llength $karten]
        while {$nochDa > 0} {
          set oben [unifRand $nochDa] 
          set stapel($hand,$fuelle($hand)) [lindex $karten $oben]
          set karten [lreplace $karten $oben $oben]
          incr fuelle($hand)
          incr nochDa -1
        }
      }
    }
    proc mkMenue {} {
        global patArt fuelle patiencePath patName streitArt zugNr flaeche ich du \
            kartenFont kartenFonts text sprache warteZeit schatten tk_version

        wm iconbitmap . @$patiencePath/bitmaps/icon
        frame .menu -relief raised -borderwidth 1
        pack  .menu -fill x
        set xlogo [option get $flaeche xlogo Xlogo]
        menubutton .menu.xlogo -menu .menu.xlogo.m
        if [catch {.menu.xlogo configure -bitmap @$xlogo}] {
          .menu.xlogo configure -text X
        }
        menu .menu.xlogo.m
        .menu.xlogo.m add command -label "$text(erstelltVon)..." -com erstelltVon
        menubutton .menu.pat -text $text(spiel) -menu .menu.pat.m -underline 1
        menu .menu.pat.m

        set streitPatienceDa 0
        foreach aktPat [interneRegelNamen] {
          if {[info exists patName($aktPat,$sprache)]} {
            if {$streitArt($aktPat)} {
              set streitPatienceDa 1
            } else {
              .menu.pat.m add radio -label $patName($aktPat,$sprache) \
                          -var neuPat -val $aktPat -command "starteSpiel 1"
            }
          }
        }
        if {$streitPatienceDa} {
          .menu.pat.m add separator
          .menu.pat.m add command -label $text(streitMit)$du -state disabled
          foreach aktPat [interneRegelNamen] {
            if {[info exists patName($aktPat,$sprache)] && $streitArt($aktPat)} {
              .menu.pat.m add radio -label $patName($aktPat,$sprache) \
                          -var neuPat -val $aktPat -command "starteSpiel 1"
            }
          }
          .menu.pat.m add command -label $text(kontaktAufnahme)... -command kontakt
          .menu.pat.m add command -label $text(kontaktPruefen)...  -command ping
          .menu.pat.m add command -label $text(kontaktAbgleich)... -command abgleich
          .menu.pat.m add check   -label $text(streitBereit) -variable streitbar \
                                  -command streitbar
        }
        .menu.pat.m add separator
        .menu.pat.m add command -lab $text(demo) -acc $text(acc,demo) \
                                -com "demo" -und 0
        set zehntel [expr {double($warteZeit)/10}]
        .menu.pat.m add command -lab "$text(warte)$zehntel$text(sekunden)..." \
                                -com "warteZeit" -und 0
        .menu.pat.m add separator
        .menu.pat.m add command -lab $text(bildErneuern) -com "bildNeu" -acc ^L
        .menu.pat.m add separator
        .menu.pat.m add command -lab $text(beenden) -com "schluss" \
                                -und 0 -acc $text(acc,beenden)
        menubutton .menu.datei -text $text(datei) -menu .menu.datei.m -underline 1
        menu .menu.datei.m
        .menu.datei.m add command -lab $text(spielzustand) -state disabled
        .menu.datei.m add command -lab "$text(laden)..." \
                                -com "laden" -acc $text(acc,laden) -und 0
        .menu.datei.m add command -lab "$text(speichern)..." \
                                -com speichern -acc $text(acc,speichern) -und 0
        .menu.datei.m add separator
        .menu.datei.m add command -lab "$text(regelnEditieren)..." \
                                -com "regelEdit" -und 0
        .menu.datei.m add separator
        .menu.datei.m add command -lab $text(sprache) -state disabled
        foreach sprachDatei [glob -nocomplain $patiencePath/text/*] {
          regexp {.*/([^/]*)$} $sprachDatei egal aktSprache
          set ersterGross [string toupper [string index $aktSprache 0]]
          set restKlein   [string range $aktSprache 1 end]
          .menu.datei.m add radio -lab $ersterGross$restKlein \
                        -var sprache -val $aktSprache -command "setzSprache"
        }
        menubutton .menu.hilfe -text $text(hilfe) -menu .menu.hilfe.m -underline 1
        menu .menu.hilfe.m
        .menu.hilfe.m add command -lab "$text(spielregeln)..." -com ersteHilfe -und 0
        if {![file readable $patiencePath/manual/pat-$sprache.tty]} {
          confMenueEntry .menu.hilfe.m $text(spielregeln) -state disabled
        }
        menubutton .menu.schmu -text $text(unterstuetzung) -menu .menu.schmu.m -und 1
        if {$streitArt($patArt)} {
          .menu.schmu configure -state disabled
        } 

        menu .menu.schmu.m
        .menu.schmu.m add command -lab $text(vorschlag) \
                                  -com "vorschlag 0" -acc $text(acc,vorschlag)
        .menu.schmu.m add command -lab $text(ablegen) \
                                  -com "ablegen" -acc $text(acc,ablegen)
        .menu.schmu.m add sep
        .menu.schmu.m add command -lab $text(zugZurueck) -com "zugZurueck"  \
                                        -acc $text(acc,zugZurueck)  -state disabled
        .menu.schmu.m add command -lab $text(zumAnfang) -com "zumAnfang" \
                                                        -state disabled
        .menu.schmu.m add sep
        .menu.schmu.m add check   -lab $text(merken)    -com merken -var gemerkt \
                                                     -state disabled
        .menu.schmu.m add command -lab $text(zurMarke)  -com "zurMarke" \
                                                        -state disabled
        .menu.schmu.m add sep
        .menu.schmu.m add check   -lab $text(veraendern)  -var veraendern
        menubutton .menu.karten -text $text(karten) -menu .menu.karten.m -und 1
        menu .menu.karten.m
        .menu.karten.m add command -lab $text(geben) \
                                   -command "geben hand" -acc $text(acc,geben)
        .menu.karten.m add command -lab $text(noch)0$text(kartenUebrig) \
                                                         -state disabled
        .menu.karten.m add sep
        .menu.karten.m add command -lab $text(kartenfonts) -state disabled
        foreach font [array names kartenFonts] {
          if {$tk_version >= 4.0 || ![info exists kartenFont($font,photo)]} {
            if {[info exists kartenFont($font,name-$sprache)]} {
              set fontLabel $kartenFont($font,name-$sprache)
            } else {
              set fontLabel font
            }
            .menu.karten.m add radio -label $fontLabel -var aktFont -val $font \
                                     -command {setBitPath $aktFont}
          }
        }
        .menu.karten.m add sep
        .menu.karten.m add command -lab $text(mitComics)     -state disabled
        .menu.karten.m add check   -lab $text(verteilen)     -var mitMischComic
        .menu.karten.m add check   -lab $text(kartenbewegen) -var mitBewegComic
        .menu.karten.m add command -lab $text(schatten:)$schatten... -com "schatten"
        global tk_version

        pack .menu.xlogo .menu.pat .menu.datei .menu.schmu .menu.karten -side left
        pack .menu.hilfe -side right
        bind . <Any-Enter> {focus $flaeche}
        if {$tk_version < 4.0} {
          tk_bindForTraversal $flaeche
          tk_menuBar .menu .menu.xlogo .menu.pat    .menu.datei \
                           .menu.schmu .menu.karten .menu.hilfe
        }
        trace variable zugNr        w chkZugNr
      }
    proc chkZugNr {name1 name2 op} {
      global zugNr marke gemerkt streitArt patArt text

      if {!$streitArt($patArt)} {
        confMenueEntry .menu.schmu.m $text(zugZurueck) \
            -state [expr {$zugNr > 0 ? "normal" : "disabled"}]
        confMenueEntry .menu.schmu.m $text(zumAnfang) \
            -state [expr {$zugNr > 0 ? "normal" : "disabled"}]
        if {$zugNr<$marke} {set gemerkt 0}
        confMenueEntry .menu.schmu.m $text(zurMarke) \
            -state [expr {$gemerkt && $zugNr > $marke ? "normal" : "disabled"}]
        confMenueEntry .menu.schmu.m $text(merken) \
            -state [expr {$zugNr > 0 ? "normal" : "disabled"}]
      }
    }
    proc chkKartenAnz {name1 name2 op} {
      upvar #0 $name1 fuelle
      global text streitArt patArt flaeche auchBild

      if {$auchBild} {
        $flaeche itemconfigure \
            [expr {$name2 == "hand2" ? "kartenAnz2" : "kartenAnz"}] \
            -text $fuelle($name2)

        if {$name2 == ($streitArt($patArt) ? "hand2" : "hand")} {
          confMenueEntry .menu.karten.m "$text(noch)*$text(kartenUebrig)" \
            -label $text(noch)$fuelle($name2)$text(kartenUebrig)
        }
      }
    }
    proc confMenueEntry {m index args} {
      set tearOffs [info commands .tearoff*]
      if {[llength $tearOffs]} {
        set m "$m $tearOffs"
      }
      foreach menu $m {
        catch {eval $menu entryconfigure [list $index] $args}
      }
    }
    proc unpostMenueEntry {m index} {
      set tearOffs [info commands .tearoff*]
      if {[llength $tearOffs]} {
        set m "$m $tearOffs"
      }
      foreach menu $m {
        if {![catch {$menu index $index}]} {
          $menu unpost
        }
      }
    }
    proc aktiviereKritischeKommandos {an} {
      global flaeche text streitArt patArt

      if {![string compare $an ein]} {
        if {!$streitArt($patArt)} {
          confMenueEntry .menu.pat.m  $text(demo)      -state normal
        }
        confMenueEntry .menu.schmu.m  $text(vorschlag) -state normal
        confMenueEntry .menu.karten.m $text(geben)     -state normal
      } else {
        confMenueEntry .menu.pat.m    $text(demo)      -state disabled
        confMenueEntry .menu.schmu.m  $text(vorschlag) -state disabled
        confMenueEntry .menu.karten.m $text(geben)     -state disabled

        bind $flaeche <$text(acc,demo)> ""
        bind $flaeche <$text(acc,neuesSpiel)> ""
        bind $flaeche <$text(acc,vorschlag)> ""
        bind $flaeche <$text(acc,geben)> ""
      }
    }
    proc aktiviereGeben {hand an} {
      global flaeche text demoAktiv

      if {![string compare $an ein]} {
        if {!$demoAktiv} {
          $flaeche bind $hand <1> "geben $hand"
          bind $flaeche $text(acc,geben) "geben $hand"
        }
        confMenueEntry .menu.karten.m $text(geben) -state normal
      } else {
        nichtVerschiebbar $hand
        bind $flaeche $text(acc,geben) ""
        confMenueEntry .menu.karten.m $text(geben) -state disabled
      }
    }
    proc aktiviereMenuepunkteFuerStreit {} {
      global text du streitArt patArt

      if {$streitArt($patArt)} {
        if {[string compare [lindex [.menu.schmu configure -state] 4] disabled]} {
          .menu.schmu configure -state disabled
        }
        unpostMenueEntry .menu.schmu.m $text(vorschlag)
      } else {
        if {[string compare [lindex [.menu.schmu configure -state] 4] normal]} {
          .menu.schmu configure -state normal
        }
      }
      confMenueEntry .menu.pat.m $text(streitMit)* -label "$text(streitMit)$du"

      foreach punkt {kontaktAufnahme kontaktPruefen kontaktAbgleich} {
        confMenueEntry .menu.pat.m $text($punkt)... -state disabled
      }
      if {$streitArt($patArt)} {
        if {![string compare $du $text(computer)]} {
          confMenueEntry .menu.pat.m $text(kontaktAufnahme)... -state normal
        } else {
          confMenueEntry .menu.pat.m $text(kontaktPruefen)...  -state normal
          confMenueEntry .menu.pat.m $text(kontaktAbgleich)... -state normal
        }
      }
    }
    proc istGebenAktiv {} {
      global text

      set status [lindex [.menu.karten.m entryconfigure $text(geben) -state] 4]
      return [expr {$status == "normal"}]
    }
    proc menueHilfe {was} {
      global alteMenueLeiste text

      switch $was {
        aus {
          catch {destroy .menu.endtext}
          eval $alteMenueLeiste
        }
        default {
          if {![info exists alteMenueLeiste]} {
            set alteMenueLeiste ""
            global tk_version

            set new [expr {$tk_version >= 4.0 ? "" : "new"}]
            foreach menuePunkt [pack slaves .menu] {
              set aktiv [lindex [$menuePunkt configure -state] 4]
              append alteMenueLeiste "
                     pack $menuePunkt [pack ${new}info $menuePunkt]
                     $menuePunkt configure -state $aktiv"
            }
          }
          foreach menuePunkt [pack slaves .menu] {
            if {![catch {$menuePunkt configure -state disabled}]} {
              pack forget $menuePunkt
            }
          }
          catch {label .menu.endtext -text $text(${was}Hilfe)}
          place .menu.endtext -anchor w -rely 0.5
        }
      }
      update
    }
    proc ersteHilfe {} {
      global sprache patiencePath text tk_version

      set manTkVersion 0
      catch {set manTkVersion [send tkman set tk_version]}
      set tkManDa [expr {$manTkVersion >= 3.0
                         && (($manTkVersion <  4.0 && $tk_version <  4.0) ||
                             ($manTkVersion >= 4.0 && $tk_version >= 4.0))}]
      if {$tkManDa} {
        set hilfe $patiencePath/manual/cat6/pat-$sprache.6
        catch {send tkman {wm deiconify .man; raise .man}}
        set akt {}
        set akt [send tkman lindex \$manx(history.man) 0]
        if {[string compare $akt $hilfe]} {
          catch "send tkman manShowMan $hilfe"
        }
      } else {
        set w .regeln
        catch {destroy $w}
        toplevel $w
        wm title    $w $text(spielregeln)
        wm iconname $w $text(spielregeln)
        button $w.ok -text $text(okay) -command "destroy $w"
        text $w.t -relief raised -bd 2 -yscrollcommand "$w.s set" \
                -font -Adobe-times-medium-r-normal--*-140*
        scrollbar $w.s -relief flat -command "$w.t yview"
        pack $w.ok -side bottom -fill x
        pack $w.s -side right -fill y
        pack $w.t -expand yes -fill both

        set f [open $patiencePath/manual/pat-$sprache.tty]
        while {![eof $f]} {
          $w.t insert end [read $f 1000]
        }
        close $f
        $w.t configure -state disabled 
        bind $w <Any-Enter> "focus $w.t"
      }
    }
    proc speichern {} {
      global zustDateiName text

      if [holDateiName $text(speicherAuswahl) zustDateiName "" \
                       "*.pat" "spiel.pat"] {
        schrZustand $zustDateiName 1 0
      }
    }
    proc laden {} {
      global zustDateiName text streitArt patArt du zugNr \
             demoAktiv kommandoNachDemo

      if [holDateiName $text(ladeAuswahl) zustDateiName "*" \
                       "*.pat" "spiel.pat"] {
        if {$streitArt($patArt) && [string compare $du $text(computer)]} {
          if {![kontaktBeenden 0]} return
          if {$demoAktiv} {
            set demoAktiv        0
            set kommandoNachDemo "liesZustand $zustDateiName"
            return
          }
        }
        liesZustand $zustDateiName
      }
    }
    proc holDateiName {text dateiName magic ext defaultName} {
      upvar 1 $dateiName name

      if {![info exist name] || ![string length $name]} {
        set dir   [pwd]
        set datei $defaultName
      } else {
        set dir   ""; regexp {(.*)/}  $name egal dir
        set datei ""; regexp {[^/]*$} $name datei
      }
      set neuName [fileSelect .fs $text $datei $dir $ext]
      if {![string length $neuName]} {return 0}

      switch -regexp $magic {
        . {
          if {![file readable $neuName]} {
            nichtLesbar $neuName
            return 0
          }
        }
        default {
          if {[file exist $neuName]} {
            set allesKlar [expr {[file writable $neuName] &&
                                 ![file isdirectory $neuName]}]
          } else {
            set zielDirectory [file dirname $neuName]
            set allesKlar [expr {[file writable $zielDirectory] &&
                                 [file isdirectory $zielDirectory]}]
          }
          if {!$allesKlar} {
            nichtSchreibbar $neuName
            return 0
          }
        }
      }
      set name $neuName
      return 1
    }
    proc setzSprache {} {
      global streitArt patArt sprache patiencePath text du

      if {[string compare $du $text(computer)]} {
        set gegnerName $du
      }

      if [catch {source $patiencePath/text/$sprache}] return

      if {![info exists gegnerName]} {
        set gegnerName $text(computer)
      }

      destroy .menu
      setzBenutzernamen $gegnerName
      mkMenue
      aktiviereBindings
      zeigHinweis 0
      aktiviereMenuepunkteFuerStreit
      global patArt fuelle
      foreach var {patArt fuelle(hand) fuelle(hand2)} {
        catch {set $var [set $var]}
      }

      regelEdit 1
    }
    proc mkFlaeche {} {
        global flaeche roteFarbe weisseFarbe graueFarbe warteZeit \
               mitMischComic mitBewegComic tk_version streitbar schatten

        wm withdraw .
        global patiencePath env
        catch {option readfile $patiencePath/app-default startupFile}
        catch {option readfile $env(HOME)/.Xdefaults     userDefault}
        option add *patience.warteZeit     10                  widgetDefault
        option add *patience.rot           IndianRed4          widgetDefault
        option add *patience.grau          gray80              widgetDefault
        option add *patience.weiss         gray95              widgetDefault
        option add *patience.xlogo         /usr/include/X11/bitmaps/xlogo11 \
                                                               widgetDefault
        option add *patience.sprPath       $patiencePath/spiel widgetDefault
        option add *patience.mitMischComic True                widgetDefault
        option add *patience.mitBewegComic True                widgetDefault
        option add *patience.schatten      3                   widgetDefault
        option add *patience.mitStreitbar  False               widgetDefault
        option add *patience.kartenFont    normal              widgetDefault
        option add *patience.sprache       deutsch             widgetDefault
        option add *patience.daemonPort    4567                widgetDefault
        set flaeche [canvas .patience -closeenough 0.0]
        if {$tk_version >= 4.0} {
          $flaeche configure -highlightthickness 0
        }
        liesTexte

        global kartenFont kartenFonts patiencePath aktFont

        foreach kartenSatz [glob -nocomplain $patiencePath/bitmaps/*/dimensionen] {
          source $kartenSatz
          set kartenFonts($kartenSatz) $kartenSatz
        }
        set aktFont [option get $flaeche kartenFont KartenFont]
        if {![info exists kartenFonts($aktFont)]} {
          set aktFont normal
          if {![info exists kartenFonts($aktFont)]} {
            global text

            puts $text(keineKartenFonts)
            exit 1
          }
        }

        set warteZeit [option get $flaeche warteZeit WarteZeit]
        if [catch {set warteZeit [expr int($warteZeit)]}] {
          set warteZeit 10
        }
        set schatten  [option get $flaeche schatten Schatten]
        if {[catch {set schatten [expr int($schatten)]}] || $schatten < 0} {
          set schatten 3
        }

        set roteFarbe   [option get $flaeche rot   Foreground]
        set graueFarbe  [option get $flaeche grau  Background]
        set weisseFarbe [option get $flaeche weiss Background]

        set mitMischComic [string match {[Tt]*} \
                               [option get $flaeche mitMischComic MitComic]]
        set mitBewegComic [string match {[Tt]*} \
                               [option get $flaeche mitBewegComic MitComic]]
        streitbar [string match {[Tt]*} \
                               [option get $flaeche mitStreitbar  mitStreitbar]]

        pack $flaeche -side bottom -expand 1 -fill both
      }
      proc fuellFlaeche {} {
        global patiencePath patName zugNr flaeche patArt tk_version

        trace variable patArt w setzFenstertitel
        setzFenstertitel patArt "" w

        trace variable patArt w setzStrafX
        bind $flaeche <Configure> "setBitPath"
        setBitPath <>

        update
        wm minsize . [winfo width .] [winfo height .]
      }
      proc setzFenstertitel {art leer op} {
        global patienceVersion patName text sprache
        upvar #0 $art patArt

        if {[info exists patName($patArt,$sprache)]} {
          set name $patName($patArt,$sprache)
        } else {
          set name $patArt
        }
        wm title . "$text(patience) $patienceVersion / $name"
      }
      if {$tk_version >= 4.0} {
        proc erzeugeKarten {} {
          global aktFont bitPath weisseFarbe roteFarbe graueFarbe \
                 kartenFont erzeugterFont flaeche

          if {[info exists erzeugterFont]
              && ![string compare $erzeugterFont $aktFont]} return

          set liste {ruecken h w sch}
          foreach farbe {c h p k} {
            foreach wert {s a 2 3 4 5 6 7 8 9 0 b d k} {
              lappend liste $wert$farbe
            }
          }

          if {[info exists kartenFont($aktFont,photo)]} {
            foreach karte $liste {
              image create photo $karte -file $bitPath/$karte
            }
          } else {
            set mitFarbe [expr {![info exists kartenFont($aktFont,sw)]}]
            set mitMaske [info exists kartenFont($aktFont,maske)]
            if {$mitMaske} {
              set maske $kartenFont($aktFont,maske)
            }

            foreach karte $liste {
              image create bitmap $karte -file $bitPath/$karte
              if {$mitMaske} {
                $karte configure -maskfile $bitPath/$maske
              }
              if {[string match {?[ch]} $karte]
                  && ($mitFarbe || [string index $karte 0] != "s")} {
                $karte configure -foreground $roteFarbe
              }
              if {$mitFarbe && [string match {[sh]*} $karte]} {
                $karte configure -background $graueFarbe
              } else {
                $karte configure -background $weisseFarbe
              }
            }
          }
          set erzeugterFont $aktFont
        }
      }
      proc stelleKarteDar {flaeche neu karte tag x y} {
        global tk_version

        if {$tk_version >= 4.0} {
          if {![string compare $neu neu]} {
            $flaeche create image $x $y -anchor nw -tag $tag
          }
          $flaeche itemconfigure $tag -image $karte
        } else {
          global weisseFarbe roteFarbe graueFarbe bitPath kartenFont aktFont

          if {![string compare $neu neu]} {
            $flaeche create bitmap $x $y -background $weisseFarbe \
                                         -anchor nw -tag $tag
          }
          $flaeche itemconfigure $tag -bitmap @$bitPath/$karte
          set mitFarbe [expr {![info exists kartenFont($aktFont,sw)]}]
          if {[string match {?[ch]} $karte]
              && ($mitFarbe || [string index $karte 0] != "s")} {
            $flaeche itemconfigure $tag -foreground $roteFarbe
          } else {
            $flaeche itemconfigure $tag -foreground black
          }
          if {$mitFarbe && [string match {[sh]*} $karte]} {
            $flaeche itemconfigure $tag -background $graueFarbe
          } else {
            $flaeche itemconfigure $tag -background $weisseFarbe
          }
        }
      }
    proc aktiviereBindings {{command {}}} {
      global flaeche streitArt patArt text spezialKommando

      set spezialKommando $command
      if {![string length $command]} {
        foreach event [list Key Button] {
          bind $flaeche <$event> ""
        }
        foreach stapel {hand hand2} {
          $flaeche bind $stapel <1> "geben $stapel"
        }
        bind $flaeche <3>                    "tuWasGutes %x %y"
        bind $flaeche <$text(acc,speichern)> "if {%s==0} {speichern}"
        bind $flaeche <$text(acc,laden)>     "if {%s==0} {laden}"
        bind $flaeche <Control-Key>          "vorschlagDebug %K"
        if {!$streitArt($patArt)} {
          bind $flaeche <$text(acc,ablegen)>    "if {%s==0} {ablegen}"
          bind $flaeche <$text(acc,vorschlag)>  "if {%s==0} {vorschlag 0}"
          bind $flaeche <$text(acc,zugZurueck)> "if {%s==0} {zugZurueck}"
          bind $flaeche <$text(acc,demo)>       "if {%s==0} {demo}"
          bind $flaeche <$text(acc,geben)>      "if {%s==0} {geben hand}"
        } else {
          bind $flaeche <$text(acc,geben)>      "if {%s==0} {geben hand2}"
        }
      } else {
        foreach stapel {hand hand2} {
          $flaeche bind $stapel <1> $command
          $flaeche bind $stapel <3> $command
        }
        if {[string index $command 0] == "+"} {
          set command [string range $command 1 end]
          set addBinding "+"
        } else {
          set addBinding ""
        }
        foreach event [list $text(acc,geben)     $text(acc,ablegen)    \
                            $text(acc,vorschlag) $text(acc,demo)       \
                            $text(acc,speichern) $text(acc,zugZurueck) \
                            $text(acc,laden) Key Button] {
          bind $flaeche <$event> \
                    "${addBinding}if {\[string compare %K Control_L]} {$command}"
        }
      }
      bind $flaeche <$text(acc,beenden)>    "if {%s==0} {schluss}"
      bind $flaeche <$text(acc,neuesSpiel)> "if {%s==0} {starteSpiel 1}"
      bind $flaeche <Control-l>             "bildNeu"
    }
    proc loeschHinweis {} {
      global flaeche

      catch {$flaeche delete hinweis}
    }
    proc setBitPath {{neuFont ""}} {
      global bitPath patiencePath kartenHoehe stapelBreite fuelle \
             pos gesStockHoehe bildBreite bildHoehe flaeche       \
             stockHoehe exist tk_version streitArt stapelAnz      \
             kartenSatz patArt kartenFont aktFont stapel erzeugterFont

      set stapelBreite  $kartenFont($aktFont,breite)
      set kartenHoehe   $kartenFont($aktFont,hoehe)
      set stockHoehe    [expr {$kartenHoehe*2/3}]
      set gesStockHoehe [expr {$stockHoehe*3+$kartenHoehe+2}]

      set minStapel [expr {$stapelAnz($patArt)+$kartenSatz($patArt)
                                              +($exist($patArt,arbeit) > 0)}]
      if {$minStapel < 10} {set minStapel 10}
      set minBreite     [expr {$stapelBreite*$minStapel}] 
      set minHoehe      [expr {$gesStockHoehe+$kartenHoehe+30}]

      set bitPath "$patiencePath/bitmaps/$aktFont"
      if {$tk_version >= 4.0 && ![info exists erzeugterFont]} {
        erzeugeKarten
      }

      set derzeitigeBreite [winfo width $flaeche]
      set derzeitigeHoehe  [winfo height $flaeche]
      if {![string compare $neuFont "<>"]
           && $minBreite <= $derzeitigeBreite
           && $minHoehe  <= $derzeitigeHoehe} {
        set neuFont ""
      }
      if {[string length $neuFont]} {
        wm geometry . {}
        $flaeche configure -width $minBreite -height $minHoehe
        update
        if {$minHoehe != $derzeitigeHoehe || $minBreite != $derzeitigeBreite} {
          return
        }
      }

      set bildBreite [winfo width  $flaeche]
      set bildHoehe  [winfo height $flaeche]
      set pos(x,hand)      [expr $bildBreite-$stapelBreite+4]
      set pos(y,hand)      [expr $bildHoehe-$kartenHoehe]
      set pos(x,hand2)     0
      set pos(y,hand2)     $pos(y,hand)
      set pos(x,talon)     [expr $bildBreite-2*$stapelBreite]
      set pos(y,talon)     $pos(y,hand)
      set pos(x,talon2)    [expr $stapelBreite+2]
      set pos(y,talon2)    $pos(y,hand)
      set pos(x,schachUhr) [expr $bildBreite/2]
      set pos(y,schachUhr) $bildHoehe
      set pos(y,strafe)    $pos(y,hand)
      set pos(x,strafe2)   [expr 2*$stapelBreite+2]
      set pos(y,strafe2)   $pos(y,hand)
      setzStrafX patArt "" w

      if {$bildBreite < $minBreite || $bildHoehe < $minHoehe} {
        # Notfall: Bildschirmgroesse reicht fuer Font nicht aus; deshalb jetzt
        # auf kleinen Font umschalten, und sich selbst rekursiv aufrufen.
        set aktFont normal
        setBitPath $aktFont
      } elseif {[info exists stapel]} {
        # Bild mit dem aktuellen Spiel neu aufbauen.
        bildNeu
      }
    }
    proc setzStrafX {art leer op} {
      global pos bildBreite stapelBreite streitArt
      upvar #0 $art patArt

      if {$streitArt($patArt)} {
        set pos(x,strafe) [expr {$bildBreite-3*$stapelBreite}]
      } else {
        set pos(x,strafe) 0
      }
    }
    proc spielXY {spielX spielY absX absY} {
      upvar $spielX relX $spielY relY
      global bildBreite bildHoehe flaeche

      set relX [$flaeche canvasx $absX]
      set relY [$flaeche canvasy $absY]
      if {$relX<0} {set relX 0} elseif {$relX>$bildBreite} {set relX $bildBreite}
      if {$relY<0} {set relY 0} elseif {$relY>$bildHoehe}  {set relY $bildHoehe}
    }
    proc stapelX {stapel} {
      global stapelBreite bildBreite pos kartenSatz patArt

      switch -glob $stapel {
        ?       {return [expr {$stapel*$stapelBreite+2}]}
        ?,?     {return [expr {$bildBreite 
                                 - $stapelBreite*([string index $stapel 0]+1)}]}
        arbeit? {return [expr {$bildBreite
                                 - $stapelBreite*($kartenSatz($patArt)+1)}]}
        default {return $pos(x,$stapel)}
      }
    }
    proc stapelY {stapel {aktY 0}} {
      global stockHoehe bildHoehe kartenHoehe fuelle exist streitArt patArt pos

      switch -glob $stapel {
        ? {
          if {$aktY <= 0} {return 2}

          set verfuegbar [expr $bildHoehe-10]
          switch $stapel 0 - 1 - 2 {
            if {$streitArt($patArt) || $exist($patArt,strafe) > 0} {
              incr verfuegbar [expr -2*$kartenHoehe]
            }
          }
          set maxHoehe [expr {double($bildHoehe)/20}]
          if {$fuelle($stapel) > 1} {
            set hoeheProKarte [expr {double($verfuegbar)/$fuelle($stapel)}]
            if {$hoeheProKarte > $maxHoehe} {set hoeheProKarte $maxHoehe}
          } else {
            set hoeheProKarte $maxHoehe
          }

          return [expr {$aktY*$hoeheProKarte+2}]
        }
        ?,?     {return [expr {2+$stockHoehe*[farbRang $stapel]}]}
        arbeit? {return [expr {2+$stockHoehe*[string index $stapel 6]}]}
        default {return $pos(y,$stapel)}
      }
    }
    proc findeStapel {neuX neuY} {
      global stapelAnz kartenSatz streitArt patArt fuelle pos exist \
          stapelBreite stockHoehe gesStockHoehe bildBreite kartenHoehe
      
      spielXY x y $neuX $neuY
      
      foreach sonderStapel {talon talon2 strafe strafe2} {
        if {[info exists fuelle($sonderStapel)] && $fuelle($sonderStapel) > 0    \
            && $x>=$pos(x,$sonderStapel)&&$x<$pos(x,$sonderStapel)+$stapelBreite \
            && $y>=$pos(y,$sonderStapel)&&$y<$pos(y,$sonderStapel)+$kartenHoehe} {
          return $sonderStapel
        }
      }
      foreach hand {hand hand2} {
        if {$x>=$pos(x,$hand)&&$x<$pos(x,$hand)+$stapelBreite && \
            $y>=$pos(y,$hand)&&$y<$pos(y,$hand)+$kartenHoehe} {
          if {![string compare $hand hand] || $streitArt($patArt)} {return $hand}
        }
      }
      if {$x < $stapelAnz($patArt)*$stapelBreite} {
        return [expr int($x/$stapelBreite)]
      }
      if {$x > $bildBreite-$kartenSatz($patArt)*$stapelBreite &&
          $y < $gesStockHoehe} {
        if {$y >= $stockHoehe*4} {set y [expr $stockHoehe*4]}
        set aktSatz  [expr int (($bildBreite-$x)/$stapelBreite)]
        set aktFarbe [kartenFarbe [expr int (($y-2)/$stockHoehe)]]
        return $aktSatz,$aktFarbe
      }
      if {$exist($patArt,arbeit)
          && $x > $bildBreite-(1+$kartenSatz($patArt))*$stapelBreite
          && $y < $kartenHoehe+($exist($patArt,arbeit)-1)*$stockHoehe} {
        if {$y >= $stockHoehe*$exist($patArt,arbeit)} {
          set y [expr $stockHoehe*$exist($patArt,arbeit)]
        }
        return arbeit[expr int (($y-2)/$stockHoehe)]
      }
      return ""
    }
    proc umdrehbar {karte stapel} {
      global flaeche

      $flaeche bind $karte <1> "drehUm $karte $stapel 1"
    }
    proc verschiebbar {karte stapel stapY} {
      global flaeche

      $flaeche bind $karte <1> "startEinzelKarte $karte %x %y $stapel $stapY"
    }
    proc teilStapelBar {karte anwStapel untenY} {
      global flaeche

      $flaeche bind $karte <1> "startTeilStapel $anwStapel $untenY %x %y"
    }
    proc nichtVerschiebbar {karte} {
      global flaeche

      $flaeche bind $karte <1> ""
      nichtBewegbar $karte
    }
    proc nichtBewegbar {karte} {
      global flaeche

      $flaeche bind $karte <B1-Motion>           ""
      $flaeche bind $karte <Any-ButtonRelease-1> ""
    }
    proc kurzePause {} {
      after 1 {set kurzePauseZumDruecken 1}
      tkwait variable kurzePauseZumDruecken
    }
    proc pruefStapelFuelle {aktStapel} {
      global stapel fuelle flaeche

      set oben [expr {$fuelle($aktStapel)-1}]
      if {$oben < 1 || [lindex [$flaeche coords $stapel($aktStapel,$oben)] 1]
                         == [stapelY $aktStapel $oben]} return

      set aktX [stapelX $aktStapel]
      for {set aktI 0} {$aktI < $fuelle($aktStapel)} {incr aktI} {
        $flaeche coords $stapel($aktStapel,$aktI) \
                        $aktX [stapelY $aktStapel $aktI]
      }
    }
    proc maleLeereStoecke {} {
      global kartenSatz patArt flaeche streitArt exist

      for {set aktSatz 0} {$aktSatz < $kartenSatz($patArt)} {incr aktSatz} {
        set letzter ""
        foreach aktFarbe {c h p k} {
          set tag s$aktFarbe$aktSatz
          stelleKarteDar $flaeche neu s$aktFarbe $tag \
                    [stapelX $aktSatz,$aktFarbe] [stapelY $aktSatz,$aktFarbe]
          $flaeche lower $tag
          if {[string length $letzter]} {
            $flaeche raise $tag $letzter
          }
          set letzter $tag
        }
      }
      set letzter ""
      for {set aktArb 0} {$aktArb < $exist($patArt,arbeit)} {incr aktArb} {
        set tag w$aktArb
        stelleKarteDar $flaeche neu w $tag \
                    [stapelX arbeit$aktArb] [stapelY arbeit$aktArb]
        $flaeche lower $tag
        if {[string length $letzter]} {
          $flaeche raise $tag $letzter
        }
        set letzter $tag
      }
    }
    proc maleZugbestaetigungsknopf {} {
      global flaeche aktiverSpieler weisseFarbe roteFarbe text ich tk_version

      set x [stapelX schachUhr]
      set y [stapelY schachUhr]
      $flaeche create rectangle [expr {$x-150/2}] [expr {$y-50}] \
                                [expr {$x+150/2}] $y             \
                    -fill white -outline white -tags uhrKnopf
      $flaeche create text $x [expr {$y-25}] -tags schachUhr -width 0
      set lr [expr {[stapelX schachUhr] - 75}]
      set ll [expr {$lr - 10}]
      set rl [expr {[stapelX schachUhr] + 75}]
      set rr [expr {$rl + 10}]
      set u  [stapelY schachUhr]
      set o  [expr {$u - 50}]
      set m  [expr {($o+$u)/2}]
      $flaeche create polygon $lr $u $lr $o $ll $m $lr $u -tags links
      $flaeche create polygon $rl $u $rl $o $rr $m $rl $u -tags rechts
      trace variable aktiverSpieler w chkAktiverSpieler
      chkAktiverSpieler aktiverSpieler "" w
    }
    proc chkAktiverSpieler {name1 name2 op} {
      global aktiverSpieler ich du flaeche roteFarbe

      $flaeche bind uhrKnopf <1> ""
      $flaeche itemconfigure schachUhr -fill grey64 -text $aktiverSpieler
      $flaeche itemconfigure links     -fill ""
      $flaeche itemconfigure rechts    -fill ""

      switch $aktiverSpieler "
        $du {
          $flaeche itemconfigure rechts    -fill $roteFarbe
        }
        $ich {
          $flaeche itemconfigure schachUhr -fill black
          $flaeche itemconfigure links     -fill $roteFarbe
          $flaeche bind uhrKnopf <1> streitZugBestaetigung
        }
      "
    }
    proc streitZugBestaetigung {} {
      global aktiverSpieler text flaeche roteFarbe du

      loeschHinweis
      set aktiverSpieler $du
      if {![string compare $du $text(computer)]} {
        demo
      } else {
        informiereStreitGegner SchachUhr
        aktiviereBindings "#"
      }
    }
    proc schaltSchachuhrAufMensch {mitBindings} {
      global flaeche aktiverSpieler ich talonAbraeumbar patArt stapel \
             fuelle verdeckt roteFarbe

      set aktiverSpieler $ich
      aktiviereGeben hand2 ein
      deaktiviereGegnerStapel
      
      if {!$talonAbraeumbar($patArt)} {
        foreach talon {talon talon2} {
          if {[info exists fuelle($talon)] && $fuelle($talon) > 0} {
            set verdeckt($talon) $fuelle($talon)
            nichtVerschiebbar $stapel($talon,[expr {$fuelle($talon)-1}])
          }
        }
      }
      global hinweisAufSchachuhr

      if {![info exists hinweisAufSchachuhr]} {
        zeigHinweis 1
      }
      if {$mitBindings} {
        aktiviereBindings
      }
    }
    proc zeigHinweis {neu} {
      global hinweisAufSchachuhr bildBreite bildHoehe text flaeche

      if {!$neu} {
        if {[string compare [$flaeche gettags hinweis] hinweis]} return
        loeschHinweis
      }
      set farbe [lindex [$flaeche configure -background] 4]
      $flaeche create rectangle \
            [expr {$bildBreite/2-100}] [expr {$bildHoehe-110}]  \
            [expr {$bildBreite/2+100}] [expr {$bildHoehe-50}]   \
            -outline $farbe -fill $farbe -tags hinweis
      $flaeche create text [expr {$bildBreite/2}] [expr {$bildHoehe-80}] \
            -text $text(hinweis) -justify center -tags hinweis
      $flaeche bind hinweis <Button> loeschHinweis

      set hinweisAufSchachuhr 1
    }
    proc deaktiviereGegnerStapel {} {
      global fuelle stapel

      foreach sonderStapel {talon strafe} {
        if {[info exists fuelle($sonderStapel)] && $fuelle($sonderStapel) > 0} {
          set oben [expr {$fuelle($sonderStapel)-1}]
          nichtVerschiebbar $stapel($sonderStapel,$oben)
        }
      }
    }
    proc bildNeu {} {
      global stapel fuelle verdeckt bildBreite bildHoehe stapelBreite \
             patArt stapelAnz kartenSatz exist flaeche pos streitArt tk_version

      $flaeche delete all
      update
      if {$tk_version >= 4.0} {
        erzeugeKarten
      }

      foreach aktHand {hand hand2} {
        if {[info exists fuelle($aktHand)] && $fuelle($aktHand) != " "} {
          stelleKarteDar $flaeche neu \
                      [expr {$fuelle($aktHand) ? "ruecken" : "h"}] $aktHand \
                      $pos(x,$aktHand) $pos(y,$aktHand)
        }
      }
      maleLeereStoecke
      maleKartenAnz
      for {set aktSatz 0} {$aktSatz < $kartenSatz($patArt)} {incr aktSatz} {
        foreach aktFarbe {c h p k} {
          set aktStock $aktSatz,$aktFarbe
          for {set aktY 0} {$aktY < $fuelle($aktStock)} {incr aktY} {
            set karte    $stapel($aktStock,$aktY)
            maleKarte    $karte neu $aktStock
            steckInStock $aktStock $karte 0
          }
        }
      }
      update
      for {set aktArb 0} {$aktArb < $exist($patArt,arbeit)} {incr aktArb} {
        set aktStapel arbeit$aktArb
        if {$fuelle($aktStapel)} {
          set karte    $stapel($aktStapel,0)
          maleKarte    $karte neu $aktStapel
          steckInStock $aktStapel $karte 0
        }
      }
      foreach sonderStapel {talon talon2 strafe strafe2} {
        if {[info exists fuelle($sonderStapel)]} {
          set verdeckt($sonderStapel) 0
          for {set aktI 0} {$aktI < $fuelle($sonderStapel)} {incr aktI} {
            maleKarte $stapel($sonderStapel,$aktI) neu $sonderStapel
          }
        }
      }
      update
      for {set aktStapel 0} {$aktStapel < $stapelAnz($patArt)} {incr aktStapel} {
        for {set aktY 0} {$aktY < $fuelle($aktStapel)} {incr aktY} {
          set karte $stapel($aktStapel,$aktY)

          if {$aktY < $verdeckt($aktStapel)} {
            stelleKarteDar $flaeche neu ruecken $karte \
                      [stapelX $aktStapel] [stapelY $aktStapel $aktY]
            nichtVerschiebbar $karte
          } else {
            maleKarte $karte neu $aktStapel $aktY
          }
        }
        pruefFreieKarte $aktStapel minusEins
        update
      }
      if {$streitArt($patArt)} {
        maleZugbestaetigungsknopf
      }
    }
    proc maleKartenAnz {} {
      global flaeche pos stapelBreite streitArt patArt fuelle

      $flaeche create text [expr {$pos(x,hand)+$stapelBreite/2}] \
                           [expr {$pos(y,hand)-10}]              \
                           -text $fuelle(hand) -tags kartenAnz
      if {$streitArt($patArt)} {
        $flaeche create text [expr $pos(x,hand2)+$stapelBreite/2] \
                             [expr {$pos(y,hand2)-10}]            \
                             -text $fuelle(hand2) -tags kartenAnz2
      }
    }
    proc maleKarte {karte neu aktStapel {aktY 0}} {
      global flaeche fuelle

      if {![string compare $neu alt]} {
        $flaeche coords $karte [stapelX $aktStapel] [stapelY $aktStapel $aktY]
        $flaeche raise  $karte
      } else {
        stelleKarteDar $flaeche $neu [string range $karte 0 1] $karte \
                    [stapelX $aktStapel] [stapelY $aktStapel $aktY]
      }
      verschiebbar $karte $aktStapel $aktY
    }
    proc maleRuecken {karte aktStapel {aktY -1}} {
      global flaeche

      stelleKarteDar $flaeche  [expr {$aktY >= 0 ? "neu" : "anders"}] ruecken \
             $karte [stapelX $aktStapel] [stapelY $aktStapel $aktY]
      nichtVerschiebbar $karte
    }
    proc pfeil {vonStap vonY nachStap nachY festeZeit} {
      global warteZeit flaeche kartenHoehe stapelBreite demoAktiv

      set tausendstel [expr $warteZeit*100]
      if {$festeZeit && $tausendstel <= 0} {set tausendstel 0}

      set xOffset [expr {$stapelBreite/2}]
      set yOffset [expr {$kartenHoehe/9}]
      set vonX    [expr {[stapelX $vonStap]        +$xOffset}]
      set vonY    [expr {[stapelY $vonStap  $vonY] +$yOffset}]
      set nachX   [expr {[stapelX $nachStap]       +$xOffset}]
      set nachY   [expr {[stapelY $nachStap $nachY]+$yOffset}]

      if {$tausendstel} {
        $flaeche create line $vonX $vonY $nachX $nachY -tag pfeil -width 5 \
            -arrow last -arrowshape {10 10 5}
      }
      update idletasks
      if {$festeZeit} {
        # Ab tk3.3 reagiert after nicht mehr auf Events. Schade eigentlich...
        if {!$demoAktiv} return
        after $tausendstel set warteZeitVorbei 1
        tkwait variable warteZeitVorbei
      } else {
        aktiviereBindings "+set pfeilAus 0"
        tkwait variable pfeilAus
        aktiviereBindings
      }
      if {$tausendstel} {
        $flaeche delete pfeil
      }
    }
    proc mischComic {x y hand richtung} {
      global stapelBreite mitMischComic flaeche

      stelleKarteDar $flaeche neu ruecken $hand $x $y
      if {!$mitMischComic} return

      stelleKarteDar $flaeche neu ruecken beweg $x $y

      # Falls die Hand links unten ist, muss nach rechts gemischt werden...
      set hin     [expr {$richtung == "rechts" ? 3 : -3}]
      set zurueck [expr {-$hin}]

      for {set j 0} {$j < 8} {incr j} {
        $flaeche raise beweg
        for {set i 0} {$i < 20} {incr i} {
          $flaeche move beweg $hin 0
          update idletask
        }
        $flaeche lower beweg
        for {set i 0} {$i < 20} {incr i} {
          $flaeche move beweg $zurueck 0
          update idletask
        }
      }
      $flaeche delete beweg
    }
    proc verteilComic {vonStapel vonY nachStapel nachY {kartenAnz 0} args} {
      global stapelBreite kartenHoehe flaeche mitBewegComic stapel \
             bildBreite bildHoehe

      if {!$mitBewegComic} return

      if {[llength $args] >= 2} {
        spielXY x y [lindex $args 0] [lindex $args 1]
      } else {
        set x [stapelX $vonStapel]
        set y [stapelY $vonStapel $vonY]
      }
      # Das X- und Y-Inkrement zwischen Start und Ziel berechnen.
      set xDist [expr {[stapelX $nachStapel]-$x}]
      set dx    [expr {$bildBreite/20}]
      if {$xDist < 0}   {set dx -$dx}
      if {abs($xDist) < abs($dx)} return
      set yDist [expr {[stapelY $nachStapel $nachY]-$y}]
      set dy    [expr {$yDist*$dx/$xDist}]

      if {$kartenAnz} {
        set tag stap
        for {set aktY $vonY} {$aktY < $vonY+$kartenAnz} {incr aktY} {
          set karte $stapel($vonStapel,$aktY)
          $flaeche raise $karte
          $flaeche itemconfigure $karte -tags "$karte $tag"
        }
      } else {
        set tag beweg
        stelleKarteDar $flaeche neu ruecken $tag $x $y
      }

      for {set sx $dx} {abs($sx) < abs($xDist-$dx/2)} {incr sx $dx} {
        $flaeche move $tag $dx $dy
        update idletask
      }

      if {$kartenAnz} {
        $flaeche dtag $tag $tag
      } else {
        $flaeche delete $tag
      }
    }
    proc schatten {{w .form}} {
        global schatten text

        catch {destroy $w}
        toplevel $w
        wm title $w    $text(schatten)
        wm iconname $w $text(schatten)
        message $w.msg -font -Adobe-times-medium-r-normal--*-180* -width 4i \
                  -text $text(schatten)
        frame $w.f1 -bd 1
        scale $w.f1.scale -orient horizontal -length 280 -from 0 -to 20 \
                -command "setzSchatten" -tickinterval 10
        $w.f1.scale set $schatten
        label $w.f1.label -text $text(schattenGroesse)
        pack append $w.f1 $w.f1.label top $w.f1.scale bottom
        button $w.ok -text $text(okay) -command "destroy $w"
        pack append $w $w.msg {top} $w.f1 {top fillx} $w.ok {bottom fill}
        wm withdraw $w
        update idletasks
        set x [expr [winfo screenwidth $w]/2 - [winfo reqwidth $w]/2 \
                  - [winfo vrootx [winfo parent $w]]]
        set y [expr [winfo screenheight $w]/2 - [winfo reqheight $w]/2 \
                  - [winfo vrooty [winfo parent $w]]]
        wm geom $w +$x+$y
        wm deiconify $w
      }
      proc setzSchatten {wert} {
        global schatten text

        set schatten $wert
        confMenueEntry .menu.karten.m "$text(schatten:)*" \
                       -label "$text(schatten:) $schatten..."
      }
      proc warteZeit {{w .form}} {
        global warteZeit text

        catch {destroy $w}
        toplevel $w
        wm title $w    $text(demonstration)
        wm iconname $w $text(demonstration)
        message $w.msg -font -Adobe-times-medium-r-normal--*-180* -width 4i \
                  -text $text(demonstration)
        frame $w.f1 -bd 1
        scale $w.f1.scale -orient horizontal -length 280 -from 0 -to 100 \
                -command "setWarteZeit" -tickinterval 20
        $w.f1.scale set $warteZeit
        label $w.f1.label -text $text(zeitverzoegerung)
        pack append $w.f1 $w.f1.label top $w.f1.scale bottom
        button $w.ok -text $text(okay) -command "destroy $w"
        pack append $w $w.msg {top} $w.f1 {top fillx} $w.ok {bottom fill}
        wm withdraw $w
        update idletasks
        set x [expr [winfo screenwidth $w]/2 - [winfo reqwidth $w]/2 \
                  - [winfo vrootx [winfo parent $w]]]
        set y [expr [winfo screenheight $w]/2 - [winfo reqheight $w]/2 \
                  - [winfo vrooty [winfo parent $w]]]
        wm geom $w +$x+$y
        wm deiconify $w
      }
      proc setWarteZeit {wert} {
        global warteZeit text

        set warteZeit $wert
        confMenueEntry .menu.pat.m $text(warte)*$text(sekunden)... \
                       -label $text(warte)[expr {double($wert)/10}]$text(sekunden)...
      }
    proc demo {} {
      global fuelle verdeckt stapel stapelAnz streitArt patArt demoAktiv \
             exist kommandoNachDemo

      initVorschlaege
      set dieseRundeLebt 1
      set demoAktiv      1
      menueHilfe [expr {$streitArt($patArt) ? "streit" : "demo"}]
      aktiviereBindings "set demoAktiv $streitArt($patArt)"
      aktiviereGeben hand ein

      # Nun beschaeftigen wir uns solange alleine, bis die Benutzerin andeutet,
      # dass ihr die Demo langweilig ist, oder wir in einer Streitpatience
      # nicht mehr weiter duerfen.
      while {$demoAktiv} {
        set gezogen [vorschlag 1]

        # Eine Denkpause ist unumgaenglich, damit die Spielerin mit ihren
        # Tastendruecken ueberhaupt durchkommt.
        update; kurzePause; if {!$demoAktiv} break

        set gewonnen [expr {$streitArt($patArt) && [checkSpielEnde 1]}]
        if {$gewonnen} {
          set gezogen 0
          aktiviereGeben hand aus
        }

        if {$gezogen} {
          set dieseRundeLebt 1
          for {set aktStap 0} {$aktStap < $stapelAnz($patArt)} {incr aktStap} {
            set oben [expr $fuelle($aktStap)-1]
            if {$oben < 0} continue
            if {$oben < $verdeckt($aktStap)} {
              drehUm $stapel($aktStap,$oben) $aktStap 1
              initVorschlaege
              update
            }
          }
        } elseif {$streitArt($patArt)} {
          if {![istGebenAktiv]} {
            set demoAktiv 0
            schaltSchachuhrAufMensch 0
          }
        } else {
          initVorschlaege
          if {$fuelle(hand) > 0} {
            if {[geben hand]} {set dieseRundeLebt 1}
          } elseif {$exist($patArt,talon) && $fuelle(talon) > 0 && $dieseRundeLebt} {
            set dieseRundeLebt [handNachTalon hand talon 1]
          } else {
            starteSpiel 0
          }
        }
      }
      catch {global flaeche; $flaeche delete pfeil}
      menueHilfe aus
      aktiviereBindings
      
      if {[info exists kommandoNachDemo]} {
        set aktKomm $kommandoNachDemo
        unset kommandoNachDemo
        eval $aktKomm
      }
    }
    proc streitbar {{vorgabe keine}} {
        global streitbar verteilung ich rpcPeer rpcPort dp_version meinRechner

        if {[string compare $vorgabe keine]} {
          set streitbar $vorgabe
        }
        if {![info exists verteilung]} {
          set verteilung [expr {[info exists dp_version] ? "tcl-DP" : "lokal"}]
        }

        switch $verteilung {
          tcl-DP {
            # Reaktion auf eine Veraenderung im Verhalten von tcl-dp...
            set localhost [expr {$dp_version >= 3.3 ? "" : "localhost"}]
            if {$streitbar} {
              global patiencePath

              set daemonPort [option get .patience daemonPort DaemonPort]
              if {[catch {set patDaemon [dp_MakeRPCClient $localhost $daemonPort]}]} {
                set daemon $patiencePath/dppatd
                if {![file executable $daemon]} {
                  keinDaemon "$daemon: not executable"
                  set streitbar 0
                } else {
                  set kommando "$daemon $daemonPort 2>&1 &"
                  if {[catch {open "| /bin/sh -c \"$kommando 2>&1\""} prot]} {
                    keinDaemon "patience: $prot"
                    set streitbar 0
                    catch {close $prot}
                  } else {
                    set zeile [gets $prot]
                    if {![string match *successfully* $zeile]} {
                      keinDaemon $zeile
                      set streitbar 0
                      close $prot
                    }
                  }
                }
              } else {
                dp_CloseRPC $patDaemon
              }
              if {![info exists rpcPeer]} {
                set socketPortList [dp_MakeRPCServer 0 dp_CheckHost none 1]
                set rpcPeer [lindex $socketPortList 0]
                set rpcPort [lindex $socketPortList 1]
              }
            }
            if {$vorgabe != 0 && $streitbar} {
              set daemonPort [option get .patience daemonPort DaemonPort]
              if {[catch [list dp_MakeRPCClient $localhost $daemonPort] patDaemon]} {
                keinDaemon $patDaemon
                set streitbar 0
              } else {
                set meldeProc  [expr {$streitbar ? "dppatAnmelden" : "dppatAbmelden"}]
                dp_RPC $patDaemon $meldeProc $ich $rpcPort
                dp_CloseRPC $patDaemon
              }
            }
          }
          lokal {
            if {$streitbar && ![string compare $vorgabe keine]} {
              nurLokal
            }
          }
        }

        if {[catch {set meinRechner [exec hostname]}]} {
          set meinRechner localhost
        }
      }
    proc senden {args} {
      global text kontakt

      if {![info exists kontakt(unserProt)]} {return 1}

      switch $kontakt(unserProt) {
        send {
          set fhl [catch {send $kontakt(deinPeer) after 0 $args} meldung]
        }
        dp_RPC {
          set fhl [catch {eval dp_RPC $kontakt(deinPeer) after 0 $args} meldung]
        }
        default {return 1}
      }
      if {$fhl} {
        set kontakt(text) $text(keineReaktion)
        kontaktDialog sendeFehler 0 2 \
            [list $text(neuSenden)     "if {!\[senden $args]} kontaktDialogEnde"] \
            [list $text(neuAnfragen)   "kontaktAnfragen"] \
            [list $text(gegenComputer) "kontaktAbbauen 1"]
      }
      return $fhl
    }
    proc kontakt {} {
      global text kontakt

      set kontakt(text) ""
      kontaktDialog kontakt 1 1 \
            [list $text(abbruch)  "kontaktAbbruch willDochNicht 0"] \
            [list $text(anfragen) "kontaktAnfragen"]
    }
    proc ping {} {
      senden pid
    }
    proc abgleich {} {
      global text kontakt

      set kontakt(text) $text(gegnerFragen)
      kontaktDialog abgleich 0 1 \
        [list $text(abbruch) "kontaktDialogEnde; senden kontaktDialogEnde"]
      senden abgleichOkay
    }
    proc abgleichOkay {} {
      global text kontakt

      set kontakt(text) $text(zustandUebernehmen)
      kontaktDialog abgleich 0 1 \
            [list $text(nein) "keinAbgleich"  ] \
            [list $text(ja)   "schickAbgleich"]
    }
    proc keinAbgleich {} {
      kontaktDialogEnde
      senden set kontakt(text) \$text(nichtEinverstanden)
    }
    proc schickAbgleich {} {
      kontaktDialogEnde
      senden set kontakt(text) \$text(ja)
      senden abgleichen
    }
    proc abgleichen {} {
      lappend kommando "initZustand"
      schrZustand kommando 0 1
      lappend kommando "bildNeu; deaktiviereGegnerStapel"
      kontaktDialogEnde
      senden [join $kommando "\n"]
    }
    proc kontaktBeenden {neuesSpiel} {
      global text kontaktBeendenVar ich kontakt meinRechner

      set kontaktBeendenVar 0

      if {$neuesSpiel} {
        set kontakt(text) $text(kontaktNeustart)
        kontaktDialog aufgabe 1 2 \
            [list $text(abbruch)    "kontaktDialogEnde"] \
            [list $text(neuesSpiel) "kontaktNeustart"] \
            [list $text(beenden)    "kontaktAbbruch hatAufgegeben 1"]
      } else {
        set kontakt(text) $text(kontaktAbbrechen)
        kontaktDialog aufgabe 1 1 \
            [list $text(abbruch) "kontaktDialogEnde"] \
            [list $text(beenden) "kontaktAbbruch hatAufgegeben 1"]
      }
      tkwait window .kontakt
      return $kontaktBeendenVar
    }
    proc kontaktNeustart {} {
      global kontaktBeendenVar kontakt text

      set kontakt(text) $text(gegnerAnrufen)

      senden kontaktNeuesSpiel
    }
    proc kontaktNeuesSpiel {} {
      global kontakt text

      set kontakt(text) $text(neuerAnfang)

      set a "kontaktDialogEnde; senden set kontakt(text) \\\$text("
      set z ")"
      kontaktDialog kontakt 0 1 \
            [list $text(nein)       "${a}nichtEinverstanden${z}"] \
            [list $text(neuesSpiel) "${a}gehtLos${z}; starteSpiel 0"]
    }
    proc kontaktAnfragen {} {
      global gegnerName text ich verteilung patArt \
             streitbar kontakt rpcPort rpcPeer meinRechner

      if {![string length $gegnerName]} {
        set kontakt(text) $text(gegnerAngeben)
        return
      }
      if {!$streitbar} {
        streitbar 1
      }
      if {![regexp {([^@]*)@(.*)} $gegnerName egal user host]} {
        set user $gegnerName
        set host $meinRechner
      }
      if {![string compare $host localhost]} {
        set host $meinRechner
      }
      if {![string compare [string tolower $ich] [string tolower $user]]} {
        set kontakt(text) $text(gegenSelbst)
        return
      }    

      if {[string compare $host $meinRechner]
          && ![string compare $verteilung lokal]} {
        set kontakt(text) $text(nurLokal)
        nurLokal
        return
      }

      catch {unset kontakt(unserProt)}
      if {![string compare $host $meinRechner]} {
        set kontakt(text) $text(gegnerSuchen)
        update

        set meinInterp [winfo name .]
        foreach deinInterp [winfo interps] {
          if {[string compare $meinInterp $deinInterp]} {
            if {![catch {send $deinInterp bistDuEinePatience} antwort]} {
              if {[string match jawoll,* $antwort]} {
                if {[regexp -nocase jawoll,user=($user)\$ $antwort]} {
                  set kontakt(unserProt) send
                  set kontakt(meinPort)  $meinInterp
                  set kontakt(deinPeer)  $deinInterp
                  break
                }
                if {[regexp -nocase user=($user),habAberKeineLust\$ $antwort]} {
                  set kontakt(text) $text(gegnerUnwillig)
                  return
                }
              }
            }
          }
        }
      } else {
        set daemonPort [option get .patience daemonPort DaemonPort]
        if {[catch {set dppatPeer [dp_MakeRPCClient $host $daemonPort]}]
            || $dppatPeer == 0} {
          set kontakt(text) $text(keinDaemonDa)
          return
        }
        if {[catch {set kontakt(deinPort) [dp_RPC $dppatPeer dppatPortVon $user]}]
            || $kontakt(deinPort) == 0} {
          set kontakt(text) $text(gegnerUnbekannt)
          return
        }
        dp_CloseRPC $dppatPeer

        if {$rpcPort == 0} {
          set kontakt(text) $text(meinPortFehlt)
          return
        }
        set kontakt(unserProt) dp_RPC
        set kontakt(meinPort)  $rpcPort
        set kontakt(meinPeer)  $rpcPeer
        if {[catch {set kontakt(deinPeer) \
                            [dp_MakeRPCClient $host $kontakt(deinPort)]}]
            || $kontakt(deinPeer) == 0} {
          set kontakt(text) $text(deinPeerFehlt)
          return
        }
      }

      if {[info exists kontakt(unserProt)]} {
          set kontakt(text) $text(gegnerAnrufen)
          update
          senden kontaktGefaellig $ich $meinRechner $patArt \
                                  $kontakt(unserProt) $kontakt(meinPort)
      } else {
        set kontakt(text) $text(gegnerNichtDa)    
      }
    }
    proc kontaktAbbruch {sendeText weiter} {
      global kontakt kontaktBeendenVar ich du meinRechner

      set kontaktBeendenVar 1

      if {[info exists kontakt(unserProt)]} {
        senden undTschuess $sendeText $ich@$meinRechner
        kontaktAbbauen $weiter
      } else {
        kontaktDialogEnde
      }
    }
    proc kontaktAbbauen {weiter} {
      global text ich du aktiverSpieler streitArt patArt kontakt

      if {[info exists kontakt(unserProt)]
          && ![string compare $kontakt(unserProt) dp_RPC]} {
        # baue RPC-Verbindung ab
        catch {close $kontakt(deinPeer)}
      }
      catch {unset kontakt}

      kontaktDialogEnde
      if {!$weiter || !$streitArt($patArt)} return

      set du $text(computer)
      aktiviereMenuepunkteFuerStreit
      if {[string compare $aktiverSpieler $ich]} {
        set aktiverSpieler $du
        demo
      }
    }
    proc undTschuess {sendeText anfrager} {
      global kontakt text du deinRechner

      set kontakt(text) $text($sendeText)
      set weiter [expr {[info exists du] && [info exists kontakt(deinRechner)]
                        && ![string compare $anfrager $du@$kontakt(deinRechner)]}]
      kontaktDialog aufgabe 0 0 \
            [list $text(weiterOhneIhn) "kontaktAbbauen $weiter"]
      catch {unset kontakt(unserProt)}
    }
    proc bistDuEinePatience {} {
      global text ich streitbar

      if {$streitbar} {
        return jawoll,user=$ich
      } else {
        return jawoll,user=$ich,habAberKeineLust
      }
    }
    proc kontaktGefaellig {anfrager host streitPat prot args} {
      global text gegnerName patName sprache kontakt

      switch $prot {
        dp_RPC {
          if {[catch {set port [dp_MakeRPCClient $host $args]} fhl]
              || $port == 0} {
            if {$port == 0} {set fhl "No port"}
            puts stderr $fhl ;# Dies ist eine schlappe Sache!
            return
          }
        }
        default {
          set port $args
        }
      }
      if {[info exist kontakt(unserProt)]} {
        set fhl besetzt
      } elseif {![info exists patName($streitPat,$sprache)]} {
        set fhl unbekPatArt
      } else {
        set fhl iO
      }

      if {[string compare $fhl iO]} {
        catch {$prot $port eval set kontakt(text) \$text($fhl)} msg
        if {![string compare $prot dp_RPC]} {
          close $port
        }
        return
      }

      set kontakt(unserProt) $prot
      set kontakt(deinPeer)  $port

      set a "senden set kontakt(text) \\\$text("
      set z "); unset kontakt(unserProt) kontakt(deinPeer); kontaktDialogEnde"
      set kontakt(text) $text(erMagSpielen)
      set gegnerName    $anfrager@$host

      kontaktDialog spielGefaellig 0 2 \
        [list $text(nein)    "${a}hatKeineLust${z}"] \
        [list $text(spaeter) "${a}spaeter${z}"]      \
        [list $text(okay)    "kontaktDialogEnde; \
                              kontaktJa $anfrager $host $streitPat"]
    }
    proc kontaktJa {name host streitPat} {
      global du kontakt demoAktiv kommandoNachDemo

      if {$demoAktiv} {
        set demoAktiv        0
        set kommandoNachDemo "kontaktJa $name $host $streitPat"
        return
      }

      set du                   $name
      set kontakt(deinRechner) $host

      senden set kontakt(text) \$text(gehtLos)

      starteSpiel 0 $streitPat
    }
    proc kontaktDialog {titel mitEingabe default args} {
      global gegnerName text tk_version

      set w .kontakt
      set dialogWarDa [winfo exists $w]
      if {$dialogWarDa} {
        if {![string compare [wm state $w] iconic]} {wm deiconify $w}
        raise $w
        catch {foreach but [pack slaves $w.default] {destroy $but}}
        catch {foreach but [pack slaves $w.buttons] {destroy $but}}
      } else {
        toplevel    $w
        wm title    $w $text($titel)
        wm iconname $w $text($titel)

        frame $w.eingabe -relief raised -bd 1
        label $w.ausgabe -relief raised -bd 1 -textvariable kontakt(text)
        frame $w.buttons -relief raised -bd 1
        pack  $w.eingabe $w.ausgabe $w.buttons -fill x -expand 1 \
                                               -ipadx 5m -ipady 2m

        label $w.eingabe.text -text $text(gegnerName)
        entry $w.eingabe.name -textvariable gegnerName -width 30
        pack  $w.eingabe.text $w.eingabe.name -side left
      }
      $w.eingabe.name configure \
            -state [expr {$mitEingabe ? "normal" : "disabled"}]
      set i 0
      foreach but $args {
        button $w.button$i -text [lindex $but 0] -command [lindex $but 1]
        if {$i == $default} {
          frame $w.default -relief sunken -bd 1
          raise $w.button$i $w.default
          pack $w.default -in $w.buttons -side left -expand 1 -padx 3m -pady 2m
          pack $w.button$i -in $w.default -padx 2m -pady 2m
          bind $w.eingabe.name <Return> "$w.button$i flash; [lindex $but 1]"
        } else {
          pack $w.button$i -in $w.buttons -side left -expand 1 -padx 3m -pady 2m
        }
        incr i
      }

      if {!$dialogWarDa} {
        bind $w <Any-Enter> "focus $w.eingabe.name"
        wm withdraw $w
        update idletasks
        set x [expr [winfo screenwidth $w]/2 - [winfo reqwidth $w]/2 \
                  - [winfo vrootx [winfo parent $w]]]
        set y [expr [winfo screenheight $w]/2 - [winfo reqheight $w]/2 \
                  - [winfo vrooty [winfo parent $w]]]
        wm geom $w +$x+$y
        wm deiconify $w
      }
    }
    proc kontaktDialogEnde {} {
      catch {destroy .kontakt}
    }
    proc werFaengtAn {} {
      global ich du kartenHoehe stapelBreite flaeche pos stapel \
             aktiverSpieler ich du text

      set aktiverSpieler $text(werFaengtAn)
      maleZugbestaetigungsknopf
      $flaeche create text [expr {$pos(x,hand) +0.5*$stapelBreite}] \
                           [expr {$pos(y,hand) -10}] -text $du  -tag du
      $flaeche create text [expr {$pos(x,hand2)+0.5*$stapelBreite}] \
                           [expr {$pos(y,hand2)-11}] -text $ich -tag ich
      update

      mischComic $pos(x,hand)  $pos(y,hand)  hand  links
      mischComic $pos(x,hand2) $pos(y,hand2) hand2 rechts 

      verteilComic hand  0 talon  0
      stelleKarteDar $flaeche neu [string range $stapel(deinStart) 0 1] \
                     talon  $pos(x,talon)  $pos(y,talon)
      verteilComic hand2 0 talon2 0
      stelleKarteDar $flaeche neu [string range $stapel(meinStart) 0 1] \
                     talon2 $pos(x,talon2) $pos(y,talon2)

      set meinStartWert [expr {[kartenWert $stapel(meinStart)]*13
                             + [farbRang   $stapel(meinStart)]}]
      set deinStartWert [expr {[kartenWert $stapel(deinStart)]*13
                             + [farbRang   $stapel(deinStart)]}]
      set aktiverSpieler [expr {$meinStartWert > $deinStartWert ? $ich : $du}]

      after 3000 {set kurzePauseZumDruecken 1}
      tkwait variable kurzePauseZumDruecken

      $flaeche delete talon talon2 hand hand2 ich du
    }
    proc informiereStreitGegner {zugArt args} {
      switch $zugArt {
        Karte {
          set karte     [lindex $args 0]
          set altStapel [lindex $args 1]
          switch $altStapel {
            hand2   {set altStapel hand}
            talon2  {set altStapel talon}
            strafe2 {set altStapel strafe}
          }
          set neuStapel [lindex $args 2]
          switch $neuStapel {
            hand    {set neuStapel hand2}
            talon   {set neuStapel talon2}
            strafe  {set neuStapel strafe2}
          }
          set kommando "zurueckKarte $karte $neuStapel $altStapel 1"
        }
        Stapel {
          global fuelle

          set altStapel [lindex $args 0]
          set neuStapel [lindex $args 2]
          set altY      $fuelle($altStapel)
          set kommando "zurueckStapel $neuStapel $altY $altStapel"
        }
        Geben {
          set meineHand [lindex $args 0]
          set deineHand [expr {$meineHand == "hand2" ? "hand" : "hand2"}]
          set kommando "geben $deineHand"
        }
        HandNachTalon {
          set meineHand [lindex $args 0]
          set deineHand [expr {$meineHand == "hand2"  ? "hand"  : "hand2"}]
          set meinTalon [lindex $args 1]
          set deinTalon [expr {$meinTalon == "talon2" ? "talon" : "talon2"}]
          set kommando "handNachTalon $deineHand $deinTalon 0"
        }
        DrehUm {
          set kommando "drehUm $args 0"
        }
        SchachUhr {
          set kommando "schaltSchachuhrAufMensch 1"
        }
        Beileid {
          set kommando "streitBeileid $args"
        }
      }
      update
      senden $kommando
    }
    proc vorschlag {mitSchieben} {
        global flaeche vorschlagZaehler vorschlaege zugNr \
               vorschlaegeAnzeigen vorschlagsReihe patArt auchBild

        if {[info exists vorschlagsReihe($zugNr,priori)]} {
          set vorschlaege(zugNr)  $zugNr
          set vorschlaege(anzahl) 1
          set vorschlaege(index)  0
          foreach elem {priori prioriExpr pfeil schieb} {
            set vorschlaege(0,$elem) $vorschlagsReihe($zugNr,$elem)
          }
        } elseif {[info exists vorschlaege] && $vorschlaege(zugNr) == $zugNr
                  && $vorschlaege(anzahl) > 0} {
          if {$mitSchieben || [incr vorschlaege(index)] >= $vorschlaege(anzahl)} {
            # Wir sind einmal rum, und fangen wieder vorne an.
            set vorschlaege(index) 0      
          }
          catch {global flaeche; $flaeche delete pfeil}
        } else {
          berechneVorschlaege $mitSchieben
        }
        if {[info exists vorschlaegeAnzeigen]} {
          set result "Vorschlaege($vorschlaege(zugNr)):\n"
          for {set aktV 0} {$aktV < $vorschlaege(anzahl)} {incr aktV} {
            append result [format "%3d: (%3d) %s <%s>\n" $aktV       \
                $vorschlaege($aktV,priori) $vorschlaege($aktV,pfeil) \
                $vorschlaege($aktV,prioriExpr)]
          }

          if {![winfo exist .vorschlaege]} {
            toplevel .vorschlaege
            text .vorschlaege.text -relief raised -bd 2 -width 40 -height 10 \
                -font -Adobe-times-medium-r-normal--*-140*
            pack .vorschlaege.text
          } else {
            .vorschlaege.text configure -state normal
            .vorschlaege.text delete 1.0 end
          }
          .vorschlaege.text insert 1.0 $result
          .vorschlaege.text configure -state disabled
        }
        incr vorschlagZaehler
        if {$vorschlaege(anzahl) == 0} {
          if {!$mitSchieben} {
            global tk_version
            if {$tk_version >= 4.0} {
              bell
            } else {
              puts -nonewline "\a"
            }
          }
          return 0
        } else {
          global vorschlagFertig pfeilFertig aktPfeil

          if {$mitSchieben} {
            set aktSchieb $vorschlaege($vorschlaege(index),schieb)
            set aktPfeil  $vorschlaege($vorschlaege(index),pfeil)

            if {![info exist vorschlagsReihe([expr {$zugNr+1}],priori)]} {
              set auchBild 0

              eval $aktSchieb
              set vorschlagFertig 0
              set pfeilFertig     0
              after 1 {
                eval $aktPfeil 1
                set pfeilFertig 1
              }
              after 1 {
                berechneVorschlaege 1
                set vorschlagFertig 1
              }
              if {!$vorschlagFertig} {
                tkwait variable vorschlagFertig
              }
              if {!$pfeilFertig} {
                tkwait variable pfeilFertig
              }
              while {[info exists vorschlaegeAnzeigen] && $vorschlaegeAnzeigen > 1} {
                tkwait variable vorschlaegeAnzeigen
              }
              zurueckZumZug [expr {$zugNr-1}]
              set auchBild 1
            } else {
              eval $aktPfeil 1
            }
            eval $aktSchieb
          } else {
            eval $vorschlaege($vorschlaege(index),pfeil) 0
          }
          return 1
        }
      }
    proc berechneVorschlaege {mitSchieben} {
      global flaeche vorschlagZaehler vorschlaege zugNr streitArt \
             vorschlaegeAnzeigen vorschlagsReihe stapelAnz patArt \
             stapel fuelle verdeckt teilStapelUnterst exist       \
             prioritaet teilStapelReihe leerStapelFeld            \
             talonAbraeumbar auchBild teilY stockReihe

      initVorschlaege $zugNr
        set sonderStapelListe ""
          if {$exist($patArt,strafe)} {lappend sonderStapelListe "strafe  strafe"}
          if {$exist($patArt,talon)}  {lappend sonderStapelListe "talon   talon"}
          for {set aktArb 0} {$aktArb < $exist($patArt,arbeit)} {incr aktArb} {
            lappend sonderStapelListe "arbeit$aktArb arbeit"
          }
        if {![string match *,kompl $stockReihe($patArt)]} {
          foreach stapelBeschreibung $sonderStapelListe {
            set sonderStapel [lindex $stapelBeschreibung 0]
            if {$fuelle($sonderStapel) > $verdeckt($sonderStapel)} {
              set oben [expr $fuelle($sonderStapel)-1]
              set karte $stapel($sonderStapel,$oben)
              set neuStock [kannAufStock $karte]
              if {[string length $neuStock]} {
                set stapelKlasse [lindex $stapelBeschreibung 1]
                vorschlagAufStock $sonderStapel $stapelKlasse $oben $karte \
                                  $neuStock [stockBonus $karte]
              }
            }
          }
        }
        set leerStapelFeld {}
        if {[string compare $teilStapelReihe($patArt) garNicht]} {
          set maxTeilStapelAnz 13
          for {set aktStapel 0} {$aktStapel<$stapelAnz($patArt)} {incr aktStapel} {
            set teilY($aktStapel) $teilStapelUnterst($aktStapel)
          }
        } else {
          set maxTeilStapelAnz 1
          for {set suchStap 0} {$suchStap < $stapelAnz($patArt)} {incr suchStap} {
            if {$fuelle($suchStap) == 0} {
              lappend leerStapelFeld $suchStap
              incr maxTeilStapelAnz $maxTeilStapelAnz
            }
          }
          for {set aktStapel 0} {$aktStapel<$stapelAnz($patArt)} {incr aktStapel} {
            set aktY [expr {$fuelle($aktStapel)-1}]
            while {$aktY > $verdeckt($aktStapel)
                   && [passt $stapel($aktStapel,$aktY) \
                             $stapel($aktStapel,[expr {$aktY-1}]) $aktStapel]} {
              incr aktY -1
            }
            set teilY($aktStapel) $aktY
          }
        }
        for {set aktStapel 0} {$aktStapel<$stapelAnz($patArt)} {incr aktStapel} {
          set oben [expr $fuelle($aktStapel)-1]
          if {[string match *,kompl $stockReihe($patArt)]} {
            set oben [expr {$oben-13}]
          }
          if {$oben >= 0 && $oben >= $verdeckt($aktStapel)
              && $oben >= $teilStapelUnterst($aktStapel)} {
            # Es liegt mindestens eine Karte auf dem Stapel.
            set aktKarte $stapel($aktStapel,$oben)
            set neuStock [kannAufStock $aktKarte]
            if {[string length $neuStock]} {
              vorschlagAufStock $aktStapel stapel $oben $aktKarte \
                                $neuStock [stockBonus $aktKarte]
            }
            switch -glob $aktKarte {
              ?c? {set andereFarbe h}
              ?h? {set andereFarbe c}
              ?p? {set andereFarbe k}
              ?k? {set andereFarbe p}
            }
            set andereKarte [string index $aktKarte 0]$andereFarbe
            set neuStock [kannAufStock ${andereKarte}0]
            if {[string length $neuStock]} {
              for {set neuStapel 0} {$neuStapel<$stapelAnz($patArt)} {incr neuStapel} {
                if {![string compare $neuStapel $aktStapel]} continue
                for {set aktY [expr $fuelle($neuStapel)-2]} \
                    {$aktY >= $fuelle($neuStapel)-$maxTeilStapelAnz-1 &&
                     $aktY >= $teilY($neuStapel)} {incr aktY -1} {
                  set verglKarte [string range $stapel($neuStapel,$aktY) 0 1]
                  if {![string compare $andereKarte $verglKarte]} {
                    vorschlagSchieb [expr {$fuelle($neuStapel)-($aktY+1)}]    \
                                    $neuStapel stapel [expr {$aktY+1}]    \
                                    $aktStapel stapel $fuelle($aktStapel) \
                                    $prioritaet(andereFarbePasst)+[stockBonus $andereKarte]
                  }
                }
              }
            }
          }
        }
        if {!$talonAbraeumbar($patArt) && [istGebenAktiv]} {
          vorschlagSchieb 1 hand  talon [expr {$fuelle(hand)-1}] \
                            talon talon $fuelle(talon) 1000
        }
        if {!$mitSchieben || $vorschlaege(anzahl) == 0} {
          if {$streitArt($patArt)} {
            foreach ziel {strafe talon} {
              if {!$exist($patArt,$ziel)} continue
              set zielStapel ${ziel}2
              set zielOben [expr {$fuelle($zielStapel) - 1}]
              if {$zielOben >= 0} {
                set zielKarte $stapel($zielStapel,$zielOben)
                for {set aktStapel 0} {$aktStapel<$stapelAnz($patArt)} {incr aktStapel} {
                  set oben [expr {$fuelle($aktStapel)-1}]
                  if {$oben >= 0 && $oben >= $verdeckt($aktStapel)
                      && [passt $stapel($aktStapel,$oben) $zielKarte $zielStapel]} {
                    vorschlagSchieb 1 $aktStapel stapel $oben \
                                      $zielStapel $ziel $fuelle($zielStapel) \
                                      [stapelBonus $aktStapel $oben]
                  }
                }
                foreach aktStapel {strafe talon} {
                  if {!$exist($patArt,$aktStapel)} continue
                  set oben [expr {$fuelle($aktStapel)-1}]
                  if {$oben >= 0
                      && [passt $stapel($aktStapel,$oben) $zielKarte $zielStapel]} {
                    vorschlagSchieb 1 $aktStapel $aktStapel $oben \
                                      $zielStapel $ziel $fuelle($zielStapel) \
                                      [stapelBonus $aktStapel $oben]
                  }
                }
              }
            }
          }
          foreach stapelBeschreibung $sonderStapelListe {
            set sonderStapel [lindex $stapelBeschreibung 0]
            if {$fuelle($sonderStapel) > $verdeckt($sonderStapel)} {
              set oben [expr $fuelle($sonderStapel)-1]
              set karte $stapel($sonderStapel,$oben)
              set neuStapel 0
              while {42} {
                wohinBewegbar $karte $sonderStapel neuStapel ziel
                if {![string compare $neuStapel nixGehtMehr]} break
                set stapelKlasse [lindex $stapelBeschreibung 1]
                vorschlagSchieb 1 $sonderStapel $stapelKlasse $oben \
                                  $neuStapel $ziel $fuelle($neuStapel) 0
                if {[string match arbeit? $neuStapel]} break
                incr neuStapel
              }
            }
          }
          for {set aktStapel 0} {$aktStapel < $stapelAnz($patArt)} {incr aktStapel} {
            set oben  $teilY($aktStapel)
            if {$oben < $fuelle($aktStapel) && $oben >= $verdeckt($aktStapel)} {
              set neuStapel 0
              while {42} {
                wohinBewegbar $stapel($aktStapel,$oben) $aktStapel neuStapel ziel
                if {![string compare $neuStapel nixGehtMehr]} break

                set aktTeilStapelAnz [expr {$fuelle($aktStapel)-$oben}]
                set aktMaxTeilStapelAnz $maxTeilStapelAnz
                if {$maxTeilStapelAnz < 13} {
                  if {![string compare $ziel leerStapel]} {
                    set aktMaxTeilStapelAnz [expr {int ($aktMaxTeilStapelAnz/2)}]
                  }

                #  for {set aktY [expr $fuelle($aktStapel)-1]} {$aktY>=$oben} {incr aktY -1} {
                #    if {$fuelle($aktStapel)-$aktY > $aktMaxTeilStapelAnz} break

                #    for {set zwStapel 0} {$zwStapel < $stapelAnz($patArt)} {incr zwStapel} {
                #      if {$fuelle($zwStapel) > 0 && [string compare $zwStapel $aktStapel]
                #         && [passt $stapel($aktStapel,$oben) \
                #                   $stapel($zwStapel,[expr $fuelle($zwStapel)-1]) \
                #                   $zwStapel]} {
                #       incr aktMaxTeilStapelAnz $aktMaxTeilStapelAnz
                #      }
                #    }
                #  }
                }

                if {$aktTeilStapelAnz <= $aktMaxTeilStapelAnz} {
                  if {$oben == 0} {
                    set quelle leerStapel
                  } elseif {$oben == $verdeckt($aktStapel)
                            || ![passt $stapel($aktStapel,$oben)            \
                                       $stapel($aktStapel,[expr {$oben-1}]) \
                                       $aktStapel]} {
                    set quelle stapel
                  } else {
                    set quelle fixStapel
                  }
                  vorschlagSchieb [expr {$fuelle($aktStapel)-$oben}]   \
                                  $aktStapel $quelle $oben                     \
                                  $neuStapel $ziel $fuelle($neuStapel) \
                                  [stapelBonus $aktStapel $oben]
                }
                if {[string match arbeit? $neuStapel]} break
                incr neuStapel
              }
            }
          } 
        }
    }
    proc initVorschlaege {{neuZugNr -1}} {
      global vorschlaege prioritaet vorschlagsReihe zugNr

      if {[info exists vorschlaege] && $neuZugNr >= 0
          && $vorschlaege(zugNr) > $zugNr} return

      catch {unset vorschlaege}
      set vorschlaege(zugNr)  $neuZugNr
      set vorschlaege(anzahl) 0
      set vorschlaege(index)  0

      if {$neuZugNr >= 0} {catch {unset vorschlagsReihe}}

      if {![info exists prioritaet]} {
        set prioritaet(lohntNicht)         -1200

        set prioritaet(strafe,stock)         100
        set prioritaet(strafe,strafe)         95
        set prioritaet(strafe,talon)          85
        set prioritaet(strafe,stapel)         75
        set prioritaet(strafe,fixStapel)      73
        set prioritaet(strafe,leerStapel)     45
        set prioritaet(stapel,stock)          80
        set prioritaet(stapel,strafe)         75
        set prioritaet(stapel,talon)          65
        set prioritaet(stapel,stapel)         55
        set prioritaet(stapel,fixStapel)      30
        set prioritaet(stapel,leerStapel)     10
        set prioritaet(fixStapel,stapel)      52
        set prioritaet(fixStapel,fixStapel)   $prioritaet(lohntNicht)
        set prioritaet(fixStapel,leerStapel)   7
        set prioritaet(leerStapel,stapel)     55
        set prioritaet(leerStapel,fixStapel)  30
        set prioritaet(leerStapel,leerStapel) $prioritaet(lohntNicht)
        set prioritaet(talon,strafe)          90
        set prioritaet(talon,talon)           80
        set prioritaet(talon,stock)           75
        set prioritaet(talon,stapel)          10
        set prioritaet(talon,fixStapel)        8
        set prioritaet(talon,leerStapel)       5
        set prioritaet(arbeit,strafe)         76
        set prioritaet(arbeit,talon)          66
        set prioritaet(arbeit,stock)          81
        set prioritaet(arbeit,stapel)         11
        set prioritaet(arbeit,fixStapel)       9
        set prioritaet(arbeit,leerStapel)      6

        set prioritaet(verdeckteWirdFrei)     12
        set prioritaet(stapelWirdFrei)        25
        set prioritaet(grundBonus)            20
        set prioritaet(karteAufStock)         11
        set prioritaet(teilStapelBewegbar)     7
        set prioritaet(stapelGranularitaet)    5
        set prioritaet(andereFarbePasst)     -20
        set prioritaet(stapelNurHoch)        -13
      }
    }
    proc vorschlagDebug {key} {
      global vorschlaegeAnzeigen demoAktiv

      switch $key {
        x - q {set vorschlaegeAnzeigen 1}
        s     {set vorschlaegeAnzeigen 2}
      }
      set demoAktiv 1
    }
    proc wertDiff {wertA wertB} {
      global aktuellerGrenzWert

      if {$wertA < $aktuellerGrenzWert && $wertB > $aktuellerGrenzWert} {
        incr wertA 13
      }
      return [expr $wertA-$wertB]
    }
    proc vorschlagAufStock {quelle quellKlasse vonY karte ziel bonus} {
      global prioritaet

      setzVorschlag $prioritaet($quellKlasse,stock)+$bonus \
          "pfeil $quelle $vonY $ziel 0" "karteAufStock $karte $quelle 1 1"
    }
    proc vorschlagSchieb {kartenAnz quelle quellKlasse quellY \
                                    ziel zielKlasse zielY bonus} {
      global prioritaet teilStapelReihe patArt leerStapelFeld

      if {![string compare $teilStapelReihe($patArt) garNicht]
          && $kartenAnz > 1} {
        set pfeilQuellY [expr {$quellY+$kartenAnz-1}]
        set pfeilZielY  0
        set pfeilZiel   [lindex $leerStapelFeld 0]
      } else {
        set pfeilQuellY $quellY
        set pfeilZielY  [expr {$zielY>0 ? $zielY-1 : 0}]
        set pfeilZiel   $ziel
      }
      setzVorschlag $prioritaet($quellKlasse,$zielKlasse)+$bonus \
            "pfeil $quelle $pfeilQuellY $pfeilZiel $pfeilZielY" \
            "schiebStapel $quelle $quellY $ziel $zielY [list $leerStapelFeld]"
    }
    proc wohinBewegbar {orgKarte orgStapel startStapel zielKlasse} {
      upvar $startStapel aktStapel $zielKlasse ziel
      global stapel fuelle verdeckt stapelAnz patArt \
          leerStapelNurHoch aktuellErste exist

      set moeglicherLeerStapel nixGehtMehr

      while {$aktStapel < $stapelAnz($patArt)} {
        set aktY [expr $fuelle($aktStapel)-1]

        if {$aktY < 0 && ($leerStapelNurHoch($patArt) == 0 \
            || [aufsteigend $orgKarte $aktuellErste 1])} {
          set ziel leerStapel
          set moeglicherLeerStapel $aktStapel
        }

        if {$aktY >= $verdeckt($aktStapel)} {
          if {[passt $orgKarte $stapel($aktStapel,$aktY) teil]} {
            set ziel stapel
            return
          }
          if {[passt $orgKarte $stapel($aktStapel,$aktY) $aktStapel]} {
            set ziel fixStapel
            return
          }
        }
        incr aktStapel
      }
      set aktStapel $moeglicherLeerStapel

      if {![string compare $aktStapel nixGehtMehr] &&
          ![string match arbeit? $orgStapel]} {
        for {set aktArb 0} {$aktArb < $exist($patArt,arbeit)} {incr aktArb} {
          if {[passtKarteAufStapel $startStapel arbeit$aktArb $orgKarte]} {
            set aktStapel arbeit$aktArb
            set ziel leerStapel
            return
          }
        }
      }
    }
    proc schiebStapel {vonStapel vonY neuStapel nachY leerStapelFeld} {
      global stapel fuelle zugNr teilStapelReihe patArt vorschlagsReihe auchBild

      set altFuelle $fuelle($vonStapel)
      set neuUnten  $fuelle($neuStapel)
      set kartenAnz [expr {$altFuelle-$vonY}]
      set art       [expr {$kartenAnz > 1 ? "minusStapel" : "minusEins"}]

      if {![string compare $teilStapelReihe($patArt) garNicht]
          && $kartenAnz>1 && $auchBild} {
        set zugZaehler $zugNr
        hanoi $vonStapel $neuStapel $leerStapelFeld $vonY $nachY \
                                    $kartenAnz zugZaehler

        eval $vorschlagsReihe($zugNr,schieb)
        return
      }

      switch -glob $vonStapel hand* {
        if {$vonY < 0 && $auchBild} {
          handNachTalon $vonStapel $neuStapel 1
        }
        return [handNachTalon $vonStapel $neuStapel 1]
      }

      if {$auchBild} {
        schiebTeilstapel $vonStapel $vonY $neuStapel
      }
      incr fuelle($vonStapel) -$kartenAnz
      for {set aktY $vonY} {$aktY < $altFuelle} {incr aktY} {
        set aktKarte $stapel($vonStapel,$aktY)
        switch -glob $neuStapel {
          arbeit? {
            steckInStock $neuStapel $aktKarte 1
          }
          default {
            steckInStapel $neuStapel $aktKarte plusEinsGueltig
          }
        }
      }
      pruefFreieKarte $vonStapel $art

      incr zugNr
      if {$kartenAnz > 1} {
        protokolliereZug Stapel $vonStapel $neuUnten $neuStapel
      } elseif {$kartenAnz == 1} {
        protokolliereZug Karte $aktKarte $vonStapel $neuStapel 1
      }
    }
    proc stapelBonus {aktStapel untenY} {
      global stapel verdeckt prioritaet aktuellerGrenzWert aktuellErste\
          leerStapelNurHoch patArt exist stapelAnz teilY fuelle

      set aufSockel [expr {$untenY > $verdeckt($aktStapel)}]
      
      set wertUnten [kartenWert $stapel($aktStapel,$untenY)]
      if {$aufSockel} {
        set wertOben [kartenWert $stapel($aktStapel,[expr {$untenY-1}])]
        set bonus [wertDiff $wertUnten $wertOben]
      } else {
        switch $untenY {
          0 {
            if {$leerStapelNurHoch($patArt)} {
              set anzHoch 0
              set anzLeer 0
              for {set such 0} {$such < $stapelAnz($patArt)} {incr such} {
                if {$such == $aktStapel || $fuelle($such) == 0} {
                  incr anzLeer
                } else {
                  set hochY $teilY($such)
                  if {$hochY > 0 &&
                      [aufsteigend $stapel($such,$hochY) $aktuellErste 1]} {
                    incr anzHoch
                  }
                }
              }
              foreach sonder {talon strafe} {
                if {$exist($patArt,$sonder) > 0} {
                  set hochY [expr {$fuelle($sonder)-1}]
                  if {$hochY >= 0 && 
                      [aufsteigend $stapel($sonder,$hochY) $aktuellErste 1]} {
                    incr anzHoch
                  }
                }
              }
              if {$anzHoch < $anzLeer} {return $prioritaet(lohntNicht)}
            }
            set bonus $prioritaet(stapelWirdFrei)
          }
          1 {
            set bonus ($prioritaet(verdeckteWirdFrei)+$wertUnten)
          }
          default {
            set bonus $wertUnten
          }
        }
      }
      if {$aufSockel &&
          [kannAufStock $stapel($aktStapel,[expr {$untenY-1}])] != ""} {
        append bonus +$prioritaet(karteAufStock)
      }
      if {$aufSockel} {
        set aktUnten [expr {$untenY-1}]
        while {$aktUnten > $verdeckt($aktStapel) && \
               [passt $stapel($aktStapel,$aktUnten) \
                      $stapel($aktStapel,[expr {$aktUnten-1}]) teil]} {
          incr aktUnten -1
        }
        set neuStapel 0
        wohinBewegbar $stapel($aktStapel,$aktUnten) $aktStapel neuStapel ziel
        if {[string compare $neuStapel nixGehtMehr]
            && ![string compare $ziel stapel]} {
          # Der naechste Teilstapel kann auf einen anderen verschoben werden!
          append bonus +$prioritaet(teilStapelBewegbar)
        }
      }
      if {$aufSockel && $verdeckt($aktStapel) == 0} {
        set nurHoch 1
        for {set aktY 0} {$aktY <= $untenY && $nurHoch} {incr aktY} {
          set nurHoch [expr {[wertDiff [kartenWert $stapel($aktStapel,$aktY)] \
                                        $aktuellerGrenzWert] >= 10}]
        }
        if {$nurHoch} {
          append bonus $prioritaet(stapelNurHoch)
        }
      }
      if {$aufSockel} {
        set teilAnzahl 0
        for {set letztY $untenY} {$letztY > $verdeckt($aktStapel)} \
            {incr letztY -1} {
          set aktY [expr {$letztY-1}]
          if {![passt $stapel($aktStapel,$letztY) $stapel($aktStapel,$aktY) teil]} {
            incr teilAnzahl
          }
        }
        # Verdeckte Karten zaehlen als je ein Teilstapel.
        incr teilAnzahl $verdeckt($aktStapel)
        # Da es sowieso nur auf die Unterscheidung "1,2,3,viele" ankommt,
        # wird das jetzt hier auch so gesetzt...
        if {$teilAnzahl > 3} {set teilAnzahl 3}

        append bonus -($teilAnzahl*$prioritaet(stapelGranularitaet))
      }  
      return $bonus
    }
    proc stockBonus {karte} {
      global aktuellerGrenzWert

      return (12-[wertDiff [kartenWert $karte] $aktuellerGrenzWert])
    }
    proc hanoi {start ziel leerStapelFeld vonY nachY kartenAnz zugZaehler} {
      upvar $zugZaehler zug

      if {$kartenAnz == 1} {
        setzVorschlagsReihe $start $vonY 1 $ziel [expr {$nachY-1}] zug
      } elseif {$kartenAnz > 1} {
        set zielLeerI [lsearch $leerStapelFeld $ziel]
        if {$zielLeerI >= 0} {
          set aktLeerStapelFeld [lreplace $leerStapelFeld $zielLeerI $zielLeerI]
        } else {
          set aktLeerStapelFeld $leerStapelFeld
        }
        set grundAnz [expr {1<<([llength $aktLeerStapelFeld]-1)}]
        if {$grundAnz >= $kartenAnz} {set grundAnz [expr {$kartenAnz - 1}]}
        set tempAnz [expr {$kartenAnz-$grundAnz}]
        set tempY   [expr {$vonY+$grundAnz}]

        set leerIndex [expr {$tempAnz == 1 ? 0 : [llength $aktLeerStapelFeld]-1}]
        set erstLeer  [lindex   $aktLeerStapelFeld $leerIndex]
        set restLeer  [lreplace $aktLeerStapelFeld $leerIndex $leerIndex]

        hanoi $start $erstLeer $restLeer $tempY 0 $tempAnz zug
        hanoi $start $ziel $restLeer $vonY $nachY $grundAnz zug
        if {$vonY == 0} {lappend restLeer $start}
        hanoi $erstLeer $ziel $restLeer 0 [expr {$nachY+$grundAnz}] $tempAnz zug
      }
    }
    proc setzVorschlagsReihe {start aktY anz ziel zielY zugZaehler} {
      global vorschlagsReihe
      upvar $zugZaehler zug

      set vorschlagsReihe($zug,priori)     666
      set vorschlagsReihe($zug,prioriExpr) hanoi
      set vorschlagsReihe($zug,pfeil)      "pfeil $start $aktY $ziel $zielY"
      set vorschlagsReihe($zug,schieb)     "schiebStapel $start $aktY $ziel $zielY {}"
      incr zug
    }
    proc setzVorschlag {prioritaetExpr pfeilScript schiebScript} {
      global vorschlaege
      
      set prioritaet [expr $prioritaetExpr]
      if {$prioritaet < -1000} return

      set aktI $vorschlaege(anzahl)
      while {$aktI > 0 && $vorschlaege([expr $aktI-1],priori) < $prioritaet} {
        set letztI $aktI
        incr aktI -1
        foreach elem {priori prioriExpr pfeil schieb} {
          set vorschlaege($letztI,$elem) $vorschlaege($aktI,$elem)
        }
      }
      set  vorschlaege($aktI,priori)     $prioritaet
      set  vorschlaege($aktI,prioriExpr) $prioritaetExpr
      set  vorschlaege($aktI,pfeil)      $pfeilScript
      set  vorschlaege($aktI,schieb)     $schiebScript
      incr vorschlaege(anzahl)
    }
    proc zurueckGeben {hand} {
        global zugNr stapelAnz patArt stapel fuelle verdeckt \
               flaeche auchBild mitMischComic pos

        set letztStapel [expr $stapelAnz($patArt)-1]
        for {set aktStapel $letztStapel} {$aktStapel >= 0} {incr aktStapel -1} {
          set oben [expr $fuelle($aktStapel)-1]

          # Nach dem anfaenglichen Verteilen kann evtl. keine Karte vom
          # aktuellen Stapel genommen werden.
          if {$oben < 0} {continue}

          set karte $stapel($aktStapel,$oben)
          set stapel($hand,$fuelle($hand)) $karte

          # Nun, wo die Karte verteilt wurde, auf die Anzahl der Hand dazuzaehlen...
          # Das sollte besser schon vorm Comic passieren, da dann die Anzeige
          # der Kartenanzahl plausibler ist.
          if {!$fuelle($hand) && $auchBild} {
            stelleKarteDar $flaeche anders ruecken $hand $pos(x,$hand) $pos(y,$hand)
          }
          incr fuelle($hand)
          # ... und beim aktuellen Stapel abziehen.
          incr fuelle($aktStapel) -1

          # Den verbliebenen Stapel durchchecken und schauen, ob er expandiert
          # werden kann.
          pruefFreieKarte $aktStapel "minusEins"

          if {$auchBild} {
            # Wegschmeissen der betreffenden Spielkarte.
            if {$mitMischComic} {
              verteilComic $aktStapel $fuelle($aktStapel) $hand 0 1
            }
            $flaeche delete $karte
            update idletask
          }
        }
        incr zugNr -1
      }
    proc zurueckHandNachTalon {hand talon anzahl} {
      global zugNr stapel fuelle flaeche auchBild pos

      if {$fuelle($talon) == 0} {
        # Falls auf die leere Hand geklickt wurde, aber sich noch Karten auf dem
        # Talon befanden, wurden die Talon-Karten wieder auf die Hand genommen.
        while {$fuelle($hand) > 0} {
          karteVonHandNach $hand $talon
        }
        if {$auchBild} {
          verteilComic $hand 0 $talon 0
        }
      } else {
        for {set aktI 0} {$aktI < $anzahl} {incr aktI} {
          incr fuelle($talon) -1
          set karte $stapel($talon,$fuelle($talon))
          if {$auchBild} {
            $flaeche delete $karte
          }
          set stapel($hand,$fuelle($hand)) $karte

          if {!$fuelle($hand) && $auchBild} {
            stelleKarteDar $flaeche anders ruecken $hand $pos(x,$hand) $pos(y,$hand)
          }
          incr fuelle($hand)
        }
        if {$auchBild} {
          verteilComic $talon 0 $hand 0
        }
      }
      if {$auchBild} {update idletask}

      incr zugNr -1
    }
    proc zurueckDrehUm {karte aktStapel} {
      global verdeckt teilStapelUnterst auchBild

      incr verdeckt($aktStapel)
      incr teilStapelUnterst($aktStapel)

      if {$auchBild} {
        maleRuecken $karte $aktStapel
        umdrehbar $karte $aktStapel
      }
    }
    proc zurueckKarte {karte neuStapel altStapel incrZugNr} {
      global stapel fuelle zugNr verdeckt auchBild

      incr fuelle($altStapel) -1
      if {[string match ? $altStapel]} {
        # Die Karte kommt von einem Stapel, also die Stapelfuelle vermindern.
        # und ueberpruefen, ob der Stapel expandiert werden kann.
        pruefFreieKarte $altStapel minusEins
      }

      if {$auchBild} {
        verteilComic $altStapel $fuelle($altStapel) \
                     $neuStapel $fuelle($neuStapel) 1
      }
      switch -glob $neuStapel {
        ?,? - arbeit? {
          steckInStock  $neuStapel $karte 1
        }
        default {
          # Das Folgende wird am Ende von 'zurueckDrehUm' motiviert...
          if {$auchBild && [string match ? $neuStapel] && $fuelle($neuStapel) > 0
                        && $fuelle($neuStapel) == $verdeckt($neuStapel)} {
            nichtVerschiebbar $stapel($neuStapel,[expr {$fuelle($neuStapel)-1}])
          }
          steckInStapel $neuStapel $karte plusEins
        }
      }
      if {$incrZugNr} {incr zugNr -1}
    }
    proc zurueckStapel {neuStapel altY altStapel} {
      global stapel fuelle zugNr flaeche verdeckt auchBild

      # Das Folgende wird am Ende von 'zurueckDrehUm' motiviert. Im Gegensatz zu
      # 'zurueckKarte' wissen wir hier, dass die Karten auf einen Stapel kommen.
      if {$auchBild && $fuelle($neuStapel) > 0
          && $fuelle($neuStapel) == $verdeckt($neuStapel)} {
        nichtVerschiebbar $stapel($neuStapel,[expr {$fuelle($neuStapel)-1}])
      }

      set lastI $fuelle($altStapel)
      set neuX [stapelX $neuStapel]
      if {$auchBild} {
        schiebTeilstapel $altStapel $altY $neuStapel
      }
      for {set aktI $altY} {$aktI < $lastI} {incr aktI} {
        set bewKarte $stapel($altStapel,$aktI)
        set stapel($neuStapel,$fuelle($neuStapel)) $bewKarte
        if {$auchBild} {
          $flaeche coords $bewKarte $neuX [stapelY $neuStapel $fuelle($neuStapel)]
          $flaeche raise  $bewKarte
        }
        incr fuelle($altStapel) -1
        incr fuelle($neuStapel)
      }
      pruefFreieKarte $altStapel minusStapel
      pruefFreieKarte $neuStapel plusStapel

      incr zugNr -1
    }

    proc zugZurueck {} {
      global zugNr ziehtGeradeZurueck

      if {[info exists ziehtGeradeZurueck]} return
      set ziehtGeradeZurueck 1

      if {$zugNr > 0} {zurueckZumZug [expr $zugNr-1]}

      unset ziehtGeradeZurueck
    }

    proc zumAnfang {} {
      global zugNr ziehtGeradeZurueck

      if {[info exists ziehtGeradeZurueck]} return
      set ziehtGeradeZurueck 1

      if {$zugNr > 0} {zurueckZumZug 0}

      unset ziehtGeradeZurueck
    }

    proc merken {} {
      global gemerkt marke zugNr

      set marke $zugNr
      set gemerkt 1
      # Die folgende Zuweisung ist ein indirekter Aufruf von chkZugNr.
      set zugNr $zugNr
    }

    proc zurMarke {} {
      global gemerkt marke zugNr ziehtGeradeZurueck

      if {[info exists ziehtGeradeZurueck]} return
      set ziehtGeradeZurueck 1

      if {$marke > 0} {zurueckZumZug $marke}
      if {$marke == $zugNr} {
        # Die Benutzerin hat die Funktion nicht bereits vorher abgebrochen.
        set gemerkt 0
        set marke   0
      }

      unset ziehtGeradeZurueck
    }
    proc zurueckZumZug {zielZugNr} {
      global zugNr inversZug demoAktiv auchBild

      # Kann denn ueberhaupt gerade ein Zug rueckgaengig gemacht werden?
      if {![info exists inversZug] || [llength $inversZug] == 0} {return}

      # Ab zwei zurueckzunehmenden Zuegen darf die Benutzerin jederzeit abbrechen.
      set langfristig [expr {$zugNr-$zielZugNr > 1 && $auchBild}]
      if {$langfristig} {
        aktiviereBindings "set demoAktiv 0"
        menueHilfe zurueck
        set demoAktiv 1
      }
      if {$auchBild} {initVorschlaege}
        
      while {$zugNr > $zielZugNr && (!$langfristig || $demoAktiv)} {
        # Das letzte Element aus inversZug ausfuehren und wegschmeissen.
        set letztIndex [expr {[llength $inversZug]-1}]
        eval  [lindex $inversZug $letztIndex]
        set inversZug [lreplace $inversZug $letztIndex $letztIndex]
        if {$langfristig} {
          kurzePause
        }
      }

      if {$langfristig} {
        aktiviereBindings
        menueHilfe aus
      }
    }
    proc protokolliereZug {args} {
      global streitArt patArt du text

      setzInversZug zurueck$args
      if {$streitArt($patArt) && [string compare $du $text(computer)]} {
        eval informiereStreitGegner $args
      }
    }
    proc setzInversZug {aktInversZug} {
      global inversZug

      lappend inversZug $aktInversZug
    }
    proc interneRegelNamen {} {
        global stapelAnz

        set regelList {}
        foreach el [array names stapelAnz] {
          if {![regexp ^(back|:) $el]} {
            lappend regelList $el
          }
        }
        return $regelList
      }
    proc fileSelect {w ueberschrift datei dir match} {
        global fileSelect_dateiName fileSelect_dirName tk_version \
               fileSelect_match fileSelect_okay text

        catch {destroy $w}
        toplevel $w -class Dialog
        wm title $w $ueberschrift
        wm iconname $w $ueberschrift

        set fileSelect_dirName   $dir
        set fileSelect_dateiName $datei
        set fileSelect_match     $match
        set fileSelect_okay      1

        label $w.textOben   -text $ueberschrift
        pack  $w.textOben   -fill x

        frame $w.kopf -relief raised -bd 1

        frame $w.kopf.fest
        label $w.kopf.fest.dir   -text $text(fs,ordner)
        label $w.kopf.fest.datei -text $text(fs,datei)
        label $w.kopf.fest.match -text $text(fs,maske)
        pack $w.kopf.fest.dir $w.kopf.fest.datei $w.kopf.fest.match -anchor w

        frame $w.kopf.feld
        entry $w.kopf.feld.dir   -textvariable fileSelect_dirName   -width 40
        entry $w.kopf.feld.datei -textvariable fileSelect_dateiName -width 40
        entry $w.kopf.feld.match -textvariable fileSelect_match     -width 40
        pack $w.kopf.feld.dir $w.kopf.feld.datei $w.kopf.feld.match -anchor w

        pack $w.kopf.fest $w.kopf.feld -side left
        pack $w.kopf

        frame $w.box -relief raised -bd 1
        scrollbar $w.scroll -command "$w.list yview"
        pack $w.scroll -in $w.box -side right -fill y
        listbox $w.list -yscroll "$w.scroll set" -relief raised -setgrid yes
        if {$tk_version >= 4.0} {
          $w.list configure -width 30 -height 20 -selectmode single    
        } else {
          $w.list configure -geometry 30x20
          tk_listboxSingleSelect $w.list
        }
        pack $w.list -in $w.box -side left  -fill both -expand yes
        pack $w.box 
        bind $w.list <ButtonRelease-1> "+uebernimm $w.list"
        bind $w.list <Double-1>        "destroy $w"
        fillDirList $w.list $dir

        frame $w.bot -relief raised -bd 1
        pack  $w.bot -side bottom -fill both

        button $w.okay -text $text(okay) -command "destroy $w"
        frame $w.default -relief sunken -bd 1
        raise $w.okay $w.default
        pack $w.default -in $w.bot -side right -expand 1 -padx 3m -pady 2m
        pack $w.okay -in $w.default -padx 2m -pady 2m -ipadx 2m -ipady 1m

        foreach i "$w $w.kopf.feld.dir $w.kopf.feld.datei $w.kopf.feld.match" {
          bind $i <Return> "$w.okay flash; $w.okay invoke"
        }

        button $w.abbruch -text $text(abbruch) \
          -command "set fileSelect_okay 0; destroy $w"
        pack $w.abbruch -in $w.bot -side left -expand 1 \
                          -padx 3m -pady 3m -ipadx 2m -ipady 1m

        set oldFocus [focus]
        grab $w
        focus $w
        tkwait window $w
        focus $oldFocus

        if {$fileSelect_okay} {
          switch $fileSelect_dirName {
            "/"     {return /$fileSelect_dateiName}
            default {return $fileSelect_dirName/$fileSelect_dateiName}
          }
        } else {
          return ""
        }
      }
    proc fillDirList {list dir} {
      global fileSelect_match

      set dirList [exec ls -a $dir]

      # Evtl. vorhandener alter Schrott wird geloescht.
      $list delete 0 end

      # In der ersten Runde alle Directories aufsammeln,
      foreach i $dirList {
        if {[file isdirectory $dir/$i]} {
          $list insert end $i
        }
      }

      # dann alle sonstigen Dateien, die zu dem gegebenen Muster passen.
      foreach i $dirList {
        if {[string match $fileSelect_match $i] && ![file isdirectory $dir/$i]} {
          $list insert end $i
        }
      }
    }
    proc uebernimm {fs} {
      global fileSelect_dateiName fileSelect_dirName

      if [catch {set datei [selection get]}] {return}

      if [file isdirectory $fileSelect_dirName/$datei] {
        if {![string compare $datei ..]
            && [regsub {/[^/]*$} $fileSelect_dirName "" neuDir]} {
          set fileSelect_dirName [expr {$neuDir == "" ? "/" : $neuDir}]
        } elseif {[string compare $datei .]} {
          set fileSelect_dirName [expr {$fileSelect_dirName == "/" ? "/$datei" :
                                    "$fileSelect_dirName/$datei"}]
        }
        fillDirList $fs $fileSelect_dirName
      } else {
        set fileSelect_dateiName $datei
      }
    }
    proc erstelltVon {} {
        global patienceVersion text

        set ausgabe    "$text(patience) / $text(version) $patienceVersion\n\n"
        append ausgabe "$text(patienceFuerX11)\n$text(erstelltVonCK)\n\n"
        append ausgabe "krischan@cs.tu-berlin.de"

        tk_dialog .t1 $text(erstelltVon) $ausgabe [kartenBild kk] 0 $text(okay)
      }
      proc beenden {} {
        global text

        set ausgabe    "$text(hoffeSpielWarGut)\n\n$text(wirklichBeenden)"
        tk_dialog .t1 $text(wirklichBeenden) $ausgabe "" \
                      1 $text(abbruch) $text(spielende)
      }
      proc neuesSpiel {} {
        global text

        tk_dialog .t1 $text(neuesSpiel) $text(wirklichNeu) \
                  "" 1 $text(abbruch) $text(neuesSpiel)
      }
      proc glueckwunsch {zugNr vorschlagZaehler} {
        global text

        switch $vorschlagZaehler {
          0       { set vorschlaege "" }
          1       { set vorschlaege $text(undEsGab)$text(einVorschlag) }
          default { set vorschlaege $text(undEsGab)$vorschlagZaehler$text(vorschlaege) }
        }

        set ausgabe    "$text(gratuliere)\n\n$text(patienceGeloest)\n"
        append ausgabe "$text(dazuBenoetigt)$zugNr$text(zuege)\n$vorschlaege"
        tk_dialog .t1 $text(glueckwunsch) $ausgabe [kartenBild dp] 0 $text(super)
      }
      proc streitGlueckwunsch {restKarten} {
        global text

        set ausgabe    "$text(gratuliere)\n\n$text(sieHabenGewonnen)"
        append ausgabe "$text(undGegnerHat)$restKarten"
        append ausgabe [expr {$restKarten>1?$text(restKarten1):$text(restKarte1)}]
        tk_dialog .t1 $text(glueckwunsch) $ausgabe [kartenBild dp] 0 $text(super)
      }
      proc streitBeileid {restKarten} {
        global text

        set ausgabe    "$text(schade)\n\n$text(sieHabenVerloren)"
        append ausgabe "$text(undSieHatten)$restKarten"
        append ausgabe [expr {$restKarten>1?$text(restKarten2):$text(restKarte2)}]
        tk_dialog .t1 $text(beileid) $ausgabe [kartenBild dp] 0 $text(naechstesMal)
      }
      proc tadel {zugNr mogelZaehler} {
        global text

        set ausgabe    "$text(spielAufgegangen)\n\n$text(dazuBenoetigt)"
        append ausgabe "$zugNr$text(zuege)\n$text(aberSieHaben)$mogelZaehler"
        append ausgabe "$text(malGeschummelt)\n$text(vielleichtBesser)"
        tk_dialog .t1 $text(glueckwunsch) $ausgabe \
                      [kartenBild bk] 0 $text(probieren)
      }
      proc nichtLesbar {dateiName} {
        global text

        tk_dialog .t1 $text(nichtLesbar) \
                      $text(dieDatei)$dateiName$text(istNichtLesbar) \
                      question 0 $text(dannNicht)
      }
      proc nichtSchreibbar {dateiName} {
        global text

        tk_dialog .t1 $text(nichtSchreibbar) \
                      $text(dieDatei)$dateiName$text(istNichtSchreibbar) \
                      question 0 $text(dannNicht)
      }
      proc nurLokal {} {
        global text nurLokalWarSchon

        if {[info exists nurLokalWarSchon]} return
        tk_dialog .t1 $text(keineVerteilung) $text(streitNurLokal) \
                      [kartenBild ac] 0 $text(schade)
        set nurLokalWarSchon 1
      }
      proc keinDaemon {fehler} {
        global text nurLokalWarSchon

        tk_dialog .t1 $text(keinDaemon) "'$fehler'\n$text(daemonFehler)" \
                      [kartenBild ap] 0 $text(schade)
      }
    proc kartenBild {karte} {
      global bitPath aktFont kartenFont

      if {![info exists bitPath]} {return ""}

      if {![info exists kartenFont($aktFont,photo)]} {
        set path $bitPath/$karte
      } elseif {![info exists kartenFont(normal,photo)]} {
        set path $bitPath/../normal/$karte
      } else {
        return ""
      }

      if {![file exists $path]} {return ""}

      return @$path
    }
    proc startEinzelKarte {karte x y stapel stapY} {
        global lastX lastY flaeche schatten

        global spezialKommando
        if {[string length $spezialKommando]} {
          if {[string index $spezialKommando 0] == "+"} {
            uplevel #0 [string range $spezialKommando 1 end]
          } else {
            uplevel #0 $spezialKommando
            return
          }
        }

        $flaeche raise $karte
        spielXY lastX lastY $x $y

        if {$schatten} {
          stelleKarteDar $flaeche neu sch schatten \
              [stapelX $stapel] [stapelY $stapel $stapY]
          $flaeche lower schatten $karte
          $flaeche move $karte -$schatten -$schatten
          $flaeche itemconfigure schatten -tags "schatten $karte"
        }

        set diffX [expr {$lastX - [stapelX $stapel]}]
        set diffY [expr {$lastY - [stapelY $stapel $stapY]}]

        $flaeche bind $karte <B1-Motion> "schiebKarte $karte %x %y"
        $flaeche bind $karte <Any-ButtonRelease-1> \
                "endEinzelKarte $karte $stapel %x %y $diffX $diffY"
      }
      proc drehUm {karte stapel mitZurueck} {
        global verdeckt teilStapelUnterst fuelle

        maleKarte $karte anders $stapel [expr {$fuelle($stapel)-1}]
        incr verdeckt($stapel) -1
        incr teilStapelUnterst($stapel) -1

        checkTeilStapel $stapel plusEins
        if {$mitZurueck} {
          protokolliereZug DrehUm $karte $stapel
        }
      }
      proc pruefFreieKarte {aktStapel art} {
        global fuelle stapel verdeckt streitArt patArt auchBild

        if {!$auchBild && [string match ? $aktStapel]} {
          checkTeilStapel $aktStapel $art
          return
        }

        switch -glob $aktStapel {
          ? {
            if {$fuelle($aktStapel) > 0} {
              set obenY   [expr $fuelle($aktStapel)-1]
              set oberste $stapel($aktStapel,$obenY)
              if {$fuelle($aktStapel) <= $verdeckt($aktStapel)} {
                umdrehbar $oberste $aktStapel
              } else {
                verschiebbar $oberste $aktStapel $obenY
                checkTeilStapel $aktStapel $art
                pruefStapelFuelle $aktStapel
              }
            }
          }
          talon* {
            if {$streitArt($patArt)} {
              aktiviereGeben [expr {$aktStapel=="talon2"?"hand2":"hand"}] ein
            }
            autoStock $aktStapel
          }
          strafe* {
            autoStock $aktStapel
          }
        }
      }
      proc steckInStapel {neuStapel neuKarte art} {
        global stapel fuelle auchBild

        set stapel($neuStapel,$fuelle($neuStapel)) $neuKarte
        if {$auchBild} {
          maleKarte $neuKarte alt $neuStapel $fuelle($neuStapel)
        }
        incr fuelle($neuStapel)

        if {[string match ? $neuStapel]} {
          # Passt die neue Karte auf den Stapel gut rauf?
          checkTeilStapel $neuStapel $art

          if {$auchBild} {
            # Ueberpruefen, ob der Stapel komprimiert werden muss.
            pruefStapelFuelle $neuStapel
          }
        }
      }
      proc steckInStock {neuStock neuKarte neu} {
        global stapel fuelle flaeche auchBild

        if {$neu} {
          # Die Karte wird gerade neu auf den Stock gelegt.
          set stapel($neuStock,$fuelle($neuStock)) $neuKarte
          incr fuelle($neuStock)
        }

        if {$auchBild} {
          maleKarte $neuKarte alt $neuStock
          switch -glob $neuStock {
            ?,c     {$flaeche lower $neuKarte sh[string index $neuStock 0] }
            ?,h     {$flaeche lower $neuKarte sp[string index $neuStock 0] }
            ?,p     {$flaeche lower $neuKarte sk[string index $neuStock 0] }
            arbeit? {
              global exist patArt

              set nummer [string index $neuStock 6]
              if {$nummer < $exist($patArt,arbeit)-1} {
                $flaeche lower $neuKarte w[expr {$nummer+1}]
              }
            }
          }
        }
      }
      proc startTeilStapel {anwStapel untenY x y} {
        global stapel fuelle teilStapelUnterst lastX lastY flaeche schatten

        global spezialKommando
        if {[string length $spezialKommando]} {
          if {[string index $spezialKommando 0] == "+"} {
            uplevel #0 [string range $spezialKommando 1 end]
          } else {
            uplevel #0 $spezialKommando
            return
          }
        }

        # Bildschirmbezogene Koordinaten auf Spielflaechen-bezogene umrechnen.
        spielXY lastX lastY $x $y

        set maxY  $fuelle($anwStapel)
        set stapX [stapelX $anwStapel]
        for {set aktY $untenY} {$aktY < $maxY} {incr aktY} {
          set karte $stapel($anwStapel,$aktY)
          if {$schatten} {
            stelleKarteDar $flaeche neu sch schatten \
              $stapX [stapelY $anwStapel $aktY]
            $flaeche lower schatten $karte
            $flaeche move $karte -$schatten -$schatten
            $flaeche itemconfigure schatten -tags "schatten teilStapel"
          }

          $flaeche raise $karte
          $flaeche itemconfigure $karte -tags "$karte teilStapel"

          nichtBewegbar $karte
        }

        # Das Bewegen und Loslassen der Maus mit den entspr. Funktionen belegen.
        set diffX [expr {$lastX - $stapX}]
        set diffY [expr {$lastY - [stapelY $anwStapel $untenY]}]
        $flaeche bind teilStapel <B1-Motion> "schiebKarte teilStapel %x %y"
        $flaeche bind teilStapel <Any-ButtonRelease-1> \
                "endTeilStapel $anwStapel $untenY %x %y $diffX $diffY"
      }
      proc ablegen {} {
        global stapelAnz stockReihe patArt stapel fuelle exist teilStapelUnterst

        set gefunden 1
        set kompletteFamilie [string match *,kompl $stockReihe($patArt)]

        while {$gefunden} {
          set gefunden 0
          if {!$kompletteFamilie} {
            set stapelListe {}
            if {$exist($patArt,talon)}  {
              lappend stapelListe talon
            }
            if {$exist($patArt,strafe)} {
              lappend stapelListe strafe
            }
            if {$exist($patArt,arbeit)} {
              for {set aktArb 0} {$aktArb < $exist($patArt,arbeit)} {incr aktArb} {
                lappend stapelListe arbeit$aktArb
              }
            }
            foreach sonderStapel $stapelListe {
              if {$fuelle($sonderStapel) > 0} {
                switch -- [karteAufStock \
                              $stapel($sonderStapel,[expr $fuelle($sonderStapel)-1]) \
                              $sonderStapel 0 1] {
                   1 {set gefunden 1}
                  -1 {return}
                }
              }
            }
          }
          for {set aktStapel 0} {$aktStapel<$stapelAnz($patArt)} {incr aktStapel} {
            set oberst [expr {$fuelle($aktStapel)-($kompletteFamilie?13:1)}]
            if {$oberst < $teilStapelUnterst($aktStapel)} continue

            switch -- [karteAufStock $stapel($aktStapel,$oberst) $aktStapel 0 1] {
               1 {set gefunden 1}
              -1 {return}
            }
          }
        }
      }
      proc tuWasGutes {x y} {
        global tutGeradeWasGutes

        global spezialKommando
        if {[string length $spezialKommando]} {
          if {[string index $spezialKommando 0] == "+"} {
            uplevel #0 [string range $spezialKommando 1 end]
          } else {
            uplevel #0 $spezialKommando
            return
          }
        }

        if {[info exists tutGeradeWasGutes]} return
        set tutGeradeWasGutes 1

        machsBesteDraus $x $y

        unset tutGeradeWasGutes
      }
      proc machsBesteDraus {x y} {
        global verdeckt stapel fuelle teilStapelUnterst \
               streitArt stockReihe stapelAnz talonAbraeumbar patArt

        set anwStapel [findeStapel $x $y]
        if {![string length $anwStapel]} return

        set oberstI   [expr $fuelle($anwStapel)-1]
        set gefunden  0
        switch -glob $anwStapel {
          ? {
            if {$oberstI < $verdeckt($anwStapel)} return
            if {[string match *,kompl $stockReihe($patArt)]} {
              set oberstI [expr $fuelle($anwStapel)-13]
            }
            if {$oberstI < $teilStapelUnterst($anwStapel)} {
              set oberstI -1
            }
            set vonY $teilStapelUnterst($anwStapel)
          }
          talon* {
            if {$oberstI < $verdeckt($anwStapel) ||
                $streitArt($patArt) && $anwStapel == "talon"} return
            set vonY $oberstI
          }
          strafe* {
            if {$oberstI < 0 ||
                $streitArt($patArt) && $anwStapel == "strafe"} return
            set vonY $oberstI
          }
          hand* {
            if {[istGebenAktiv]} {geben $anwStapel}
            return
          }
          arbeit? {
            if {$oberstI < 0} return
            set vonY $oberstI
          }
          default return
        }
        if {$oberstI >= $vonY} {
          if {[karteAufStock $stapel($anwStapel,$oberstI) $anwStapel 0 1]} {
            set gefunden 1
            set neuStapel x,x
          }
        }

        if {!$gefunden} {
          set miesesZiel ""
          if {[string match ? $anwStapel]} {
            set neuStapel [expr {$anwStapel+1}]
            if {$neuStapel<$stapelAnz($patArt)} {
              while {42} {
                wohinBewegbar $stapel($anwStapel,$vonY) $anwStapel neuStapel ziel
                if {![string compare $neuStapel nixGehtMehr]} break
                if {![string compare $ziel stapel]} {
                  schiebStapel $anwStapel $vonY $neuStapel $fuelle($neuStapel) {}
                  set gefunden 1
                  break
                }
                if {![string length $miesesZiel]
                    || ($miesesZiel == "leerStapel" && $ziel != "leerStapel")} {
                  set miesesZiel   $ziel
                  set mieserStapel $neuStapel
                }
                if {[string match arbeit? $neuStapel]} break
                incr neuStapel
              }
            }
          }
          if {!$gefunden} {
            set neuStapel 0
            while {42} {
              wohinBewegbar $stapel($anwStapel,$vonY) $anwStapel neuStapel ziel
              if {![string compare $neuStapel nixGehtMehr]} break
              if {![string compare $ziel stapel]} {
                schiebStapel $anwStapel $vonY $neuStapel $fuelle($neuStapel) {}
                set gefunden 1
                break
              }
              if {![string length $miesesZiel]
                  || ($miesesZiel == "leerStapel" && $ziel != "leerStapel")} {
                set miesesZiel   $ziel
                set mieserStapel $neuStapel
              }
              if {[string match arbeit? $neuStapel]} break
              incr neuStapel
            }
          }
        }

        if {!$gefunden && [string length $miesesZiel]} {
          schiebStapel $anwStapel $vonY $mieserStapel $fuelle($mieserStapel) {}
          set gefunden 1
        }

        if {!$gefunden} {
          global tk_version
          if {$tk_version >= 4.0} {
            bell
          } else {
            puts -nonewline "\a"
          }
        } else {
          if {[string match ?,? $neuStapel] || $streitArt($patArt) || !$fuelle(hand)} {
            if {[checkSpielEnde 0]} return
          }
          switch -glob $anwStapel {
            ? {
              if {$fuelle($anwStapel) == $verdeckt($anwStapel)
                  && $fuelle($anwStapel) > 0} {
                drehUm $stapel($anwStapel,[expr {$fuelle($anwStapel)-1}]) $anwStapel 1
              }
            }
            talon* {
              if {!$talonAbraeumbar($patArt)
                  && $fuelle($anwStapel) == $verdeckt($anwStapel) } {
                handNachTalon [expr {$anwStapel == "talon" ? "hand" : "hand2"}] $anwStapel 1
              }
            }
          }
        }
      }
      proc karteAufStock {anwKarte anwStapel inDemo incrZugNr} {
        global fuelle zugNr flaeche stockReihe patArt auchBild streitArt

        set neuStock [kannAufStock $anwKarte]
        if {![string length $neuStock]} {return 0}

        if {$incrZugNr} {incr zugNr}

        switch -glob $stockReihe($patArt) {
          *,kompl {
            set vonY [expr {$fuelle($anwStapel)-13}]
            schiebTeilstapel $anwStapel $vonY $neuStock
            plaziereTeilstapel $anwStapel $neuStock $vonY
            protokolliereZug Stapel $anwStapel 0 $neuStock
            set art minusStapel
          }
          default {
            incr fuelle($anwStapel) -1
            protokolliereZug Karte $anwKarte $anwStapel $neuStock $incrZugNr
            if {$auchBild} {
              verteilComic $anwStapel $fuelle($anwStapel) $neuStock 0 1
            }
            steckInStock $neuStock $anwKarte 1
            set art minusEins
          }
        }
        if {$auchBild} {
          pruefFreieKarte $anwStapel $art; update
          if {!$streitArt($patArt) && [checkSpielEnde $inDemo]} {return -1}
        }
        return 1
      }
      proc kannAufStock {altKarte} {
        global kartenSatz patArt

        set aktFarbe [string index $altKarte 1]
        for {set aktSatz 0} {$aktSatz < $kartenSatz($patArt)} {incr aktSatz} {
          set aktStock $aktSatz,$aktFarbe
          if [passt $altKarte [getStock $aktStock] $aktStock] {
            return $aktStock
          }
        }
        return ""
      }
      proc geben {hand} {
        global zugNr stapelAnz exist streitArt patArt stapel fuelle stapelGrund \
               verdeckt flaeche mitMischComic pos aktiverSpieler ich

        if {![string length $hand]} {
          set neu  1
          if {$streitArt($patArt)} {
            set hand [expr {$aktiverSpieler == $ich ? "hand2" : "hand"}]
          } else {
            set hand hand
          }
        } else {
          if {$streitArt($patArt)} {
            global aktiverSpieler ich du

            if {![string compare $aktiverSpieler $ich] && [string compare $hand hand2]} {
              return 0
            }
            if {![string compare $aktiverSpieler $du]  && [string compare $hand hand]} {
              return 0
            }
          }
          set neu  0
          if {$exist($patArt,talon) > 0} {
            set talon [expr {$hand == "hand" ? "talon" : "talon2"}]
            return [handNachTalon $hand $talon 1]
          }
        }

        for {set aktStapel 0} {$aktStapel<$stapelAnz($patArt)} {incr aktStapel} {
          # Es werden nur Karten verteilt, wenn noch welche da sind. Das muss in
          # jedem Durchgang zugesichert werden, da nicht bei allen Patiencen
          # fuer jeden Stapel immer noch eine Karte in der Hand ist.
          if {$fuelle($hand) == 0} {return 0}

          set aktHoehe $fuelle($aktStapel)

          # Beim anfaenglichen Verteilen braucht evtl. keine Karte auf den
          # aktuellen Stapel gelegt werden.
          if {$neu && $aktHoehe >= $stapelGrund($patArt,$aktStapel)} {
            continue
          }

          if {$mitMischComic} {
            verteilComic $hand 0 $aktStapel $fuelle($aktStapel)
          }

          # Oberste Karte vom Stapel nehmen und in den Zielstapel stecken.
          set karte $stapel($hand,[incr fuelle($hand) -1])
          set stapel($aktStapel,$aktHoehe) $karte

          if {!$fuelle($hand)} {
            stelleKarteDar $flaeche anders h $hand $pos(x,$hand) $pos(y,$hand)
          }

          # Auf dem Bildschirm darstellen (evtl. auf dem Ruecken).
          if {$fuelle($aktStapel) < $verdeckt($aktStapel)} {
            maleRuecken $karte $aktStapel $fuelle($aktStapel)
          } else {
            maleKarte $karte neu $aktStapel $fuelle($aktStapel)
          }
          update idletask
          incr fuelle($aktStapel)

          if {$fuelle($aktStapel) >= $verdeckt($aktStapel)} {
            pruefFreieKarte $aktStapel plusEins

            # Evtl. werden Karten automatisch auf den Stock geschoben.
            autoStock $aktStapel
          }

          # Hiermit wird erreicht, das die Karten immer abwechselnd von den
          # Haenden der beiden Spielparteien genommen wird.
          if {$neu && $streitArt($patArt)} {
            set hand [expr {$hand == "hand" ? "hand2" : "hand"}]
          }
        }

        if {!$neu} {
          incr zugNr
          protokolliereZug Geben $hand
        }
        return 0
      }
      proc handNachTalon {hand talon mitZurueck} {
        global zugNr stapelAnz exist patArt stapel fuelle pos \
               flaeche streitArt talonAbraeumbar auchBild verdeckt 

        if {$fuelle($hand) == 0} {
          if {$fuelle($talon) == 0} {return 0}
          set anzahl 0
          while {$fuelle($talon) > 0} {
            incr fuelle($talon) -1
            set karte $stapel($talon,$fuelle($talon))
            if {$auchBild} {$flaeche delete $karte}
            set stapel($hand,$fuelle($hand)) $karte
            incr fuelle($hand)
          }
          if {$auchBild} {
            stelleKarteDar $flaeche anders ruecken $hand $pos(x,$hand) $pos(y,$hand)
            verteilComic $talon 0 $hand 0
          }
          set verdeckt($talon) 0
        } else {
          set anzahl $exist($patArt,talon)
          if {!$talonAbraeumbar($patArt) && $fuelle($talon) > 0 && $auchBild} {
            set verdeckt($talon) $fuelle($talon)
            nichtVerschiebbar $stapel($talon,[expr {$fuelle($talon)-1}])
          }
          if {$auchBild} {verteilComic $hand 0 $talon 0}
          if {$fuelle($hand) < $anzahl} {set anzahl $fuelle($hand)}
          for {set aktI 0} {$aktI < $anzahl} {incr aktI} {
            karteVonHandNach $hand $talon
          }
          if {$streitArt($patArt)} {
            aktiviereGeben $hand aus
          }
        }
        if {$auchBild} {update idletask}

        if {$mitZurueck} {
          incr zugNr
          protokolliereZug HandNachTalon $hand $talon $anzahl
        }
        if {$anzahl > 0 && $auchBild} {
          return [autoStock $talon]
        } else {
          return 0
        }
      }
      proc karteVonHandNach {hand dest} {
        global fuelle stapel flaeche auchBild pos

        set karte $stapel($hand,[incr fuelle($hand) -1])
        set stapel($dest,$fuelle($dest)) $karte

        # Nun, wo die Karte verteilt wurde, von der Anzahl der Hand abziehen...
        # Das sollte besser schon vorm Comic passieren, da dann die Anzeige
        # der Kartenanzahl plausibler ist.
        
        if {!$fuelle($hand) && $auchBild} {
          stelleKarteDar $flaeche anders h $hand $pos(x,$hand) $pos(y,$hand)
        }
        # ... und beim Ziel (Talon, Strafstapel oder dergl.) wieder daraufaddieren.
        incr fuelle($dest)

        # Anlegen und Aufdecken der Spielkarte an der gewuenschten Stelle.
        if {$auchBild} {maleKarte $karte neu $dest}
      }
      proc schluss {} {
        global demoAktiv kommandoNachDemo streitArt patArt du text

        if {$streitArt($patArt) && [string compare $du $text(computer)]} {
          if {![kontaktBeenden 0]} return
        } elseif {![beenden]} {
          return
        }

        if {$demoAktiv} {
          set demoAktiv 0
          set kommandoNachDemo "exit"
        }
        exit
      }
      proc starteSpiel {mitRueckfrage {anderePat ""}} {
        global neuPat streitArt kartenSatz patArt zugNr flaeche pos \
               text demoAktiv ich du streitVorgabe aktiverSpieler   \
               kommandoNachDemo spielStartetGerade

        if {$mitRueckfrage > 0} {
          if {$streitArt($patArt) && [string compare $du $text(computer)]} {
            if {![kontaktBeenden [expr ![string compare $neuPat $patArt]]]} {
              set neuPat $patArt; return
            }
          } elseif {$zugNr > 0} {
            if {![neuesSpiel]} {set neuPat $patArt; return}
          }
        }
        if {$mitRueckfrage && $demoAktiv} {
          set demoAktiv        0
          set kommandoNachDemo "starteSpiel 0 $anderePat"
          return
        }
        if {[string length $anderePat]} {
          set neuPat $anderePat
        }
        set patArt $neuPat
        
        if {[info exists spielStartetGerade]} {
          tkwait variable spielStartetGerade
        }
        set spielStartetGerade 1

        if {!$demoAktiv} {
          # Solange wir das Bild aufbauen, darf keine Aufforderung zur Demo stoeren.
          aktiviereKritischeKommandos aus
        }

        # Alle Items der Spielflaeche wegschmeissen und leere Flaeche malen.
        $flaeche delete all
        update

        initZustand

        # Um sicherzustellen, dass alles gemaess der evtl. neuen Regeln auf
        # den Bildschirm passt.
        setBitPath <>

        maleLeereStoecke

        # Zunaechst das tatsaechliche Mischen der Karten in die Haende anstossen.
        mischen
        if {$streitArt($patArt)} {
          kontaktDialogEnde

          if {[string compare $du $text(computer)]
              && ![info exists streitVorgabe]} {
            global stapel fuelle patArt text ich du kontakt meinRechner

            foreach srcDest {{deineHand hand} {meineHand hand2}} {
              set dest [lindex $srcDest 0]
              set src  [lindex $srcDest 1]
              set $dest $fuelle($src)
              for {set aktI 0} {$aktI < $fuelle($src)} {incr aktI} {
                lappend $dest $stapel($src,$aktI)
              }
            }

            senden "
              set streitVorgabe(du)          $ich
              set streitVorgabe(deinRechner) $meinRechner
              set streitVorgabe(deinStart)   $stapel(meinStart)
              set streitVorgabe(meinStart)   $stapel(deinStart)
              set streitVorgabe(deineHand)   [list $meineHand]
              set streitVorgabe(meineHand)   [list $deineHand]
              after 0 starteSpiel -1 $patArt
            "
          }
          catch {unset streitVorgabe}
          aktiviereMenuepunkteFuerStreit
          werFaengtAn
          $flaeche bind schachUhr <1> "streitZugBestaetigung"
        } else {
          aktiviereMenuepunkteFuerStreit
        }

        # Jetzt den oder die Kartenstapel beim Mischen zeichnen.
        mischComic $pos(x,hand) $pos(y,hand) hand links
        if {$streitArt($patArt)} {
          mischComic $pos(x,hand2) $pos(y,hand2) hand2 rechts
        }

        # Das kleine Fensterchen mit der Anzahl der Karten.
        maleKartenAnz

        global kartenSatz stapelGrund stapelVerdeckt stapelAnz patArt \
               aktuellErste streitArt stapel verdeckt fuelle          \
               teilStapelUnterst exist stockBasis flaeche pos         \
               aktuellerGrenzWert talonAbraeumbar mitMischComic

        update idletask

        set maxGrund 0
        for {set aktStapel 0} {$aktStapel < $stapelAnz($patArt)} {incr aktStapel} {
          set fuelle($aktStapel) 0

          set verdeckt($aktStapel)          $stapelVerdeckt($patArt,$aktStapel)
          set teilStapelUnterst($aktStapel) $stapelVerdeckt($patArt,$aktStapel)
          if {$maxGrund < $stapelGrund($patArt,$aktStapel)} {
            set maxGrund $stapelGrund($patArt,$aktStapel)
          }
        }
        for {set aktSatz 0} {$aktSatz < $kartenSatz($patArt)} {incr aktSatz} {
          foreach aktFarbe {c h p k} {
            set fuelle($aktSatz,$aktFarbe) 0
          }
        }
        switch $stockBasis($patArt) {
          erste {
            set karte $stapel(hand,[incr fuelle(hand) -1])
            set aktStock 0,[string index $karte 1]

            # Verteilen, Anlegen und Aufdecken der Karte an der gewuenschten Stelle.
            verteilComic hand 0 $aktStock 0
            maleKarte    $karte neu $aktStock
            steckInStock $aktStock $karte 1
            set aktuellErste       [string index $karte 0]
            set aktuellerGrenzWert [kartenWert $karte]
          } 
          default {
            set aktuellErste $stockBasis($patArt)
            set aktuellerGrenzWert [kartenWert $stockBasis($patArt)]
          }
        }

        if {$exist($patArt,talon) > 0} {
          set fuelle(talon)    0
          set fuelle(talon2)   0
          set verdeckt(talon)  0
          set verdeckt(talon2) 0
        }

        if {$exist($patArt,strafe) > 0} {
          # Aufbau des Strafstapels.
          set fuelle(strafe)    0
          set fuelle(strafe2)   0
          set verdeckt(strafe)  0
          set verdeckt(strafe2) 0

          verteilComic hand 0 strafe 0
          for {set aktI 0} {$aktI < $exist($patArt,strafe)} {incr aktI} {
            karteVonHandNach hand strafe
          }
          if {$streitArt($patArt)} {
            verteilComic hand2 0 strafe2 0
            for {set aktI 0} {$aktI < $exist($patArt,strafe)} {incr aktI} {
              karteVonHandNach hand2 strafe2
            }
          }
          # Evtl. werden Karten automatisch auf den Stock geschoben.
          autoStock strafe
        }

        for {set aktArb 0} {$aktArb < $exist($patArt,arbeit)} {incr aktArb} {  
          set fuelle(arbeit$aktArb) 0
          set verdeckt(arbeit$aktArb) 0
        }

        for {set aktStapel 0} {$aktStapel <= $maxGrund} {incr aktStapel} {  
          geben ""
        }

        if {$exist($patArt,talon) > 0 && $talonAbraeumbar($patArt)} {
          handNachTalon hand talon 0
          if {$streitArt($patArt)} {
            handNachTalon hand2 talon2 0
          }
        }

        if {$exist($patArt,arbeit)} {
          set restAnz $fuelle(hand)
          if {$restAnz > 0} {
            set restHand hand
          }
          if {$streitArt($patArt) && $fuelle(hand2) > 0} {
            incr restAnz $fuelle(hand2)
            lappend restHand hand2
          }
          if {$restAnz <= $exist($patArt,arbeit)} {
            set aktArb [expr {int($exist($patArt,arbeit)/(2*$restAnz))}]
            foreach hand $restHand {
              while {$fuelle($hand)} {
                incr fuelle($hand) -1
                if {$mitMischComic} {
                  verteilComic $hand 0 arbeit$aktArb 0
                }
                set karte $stapel($hand,$fuelle($hand))
                maleKarte $karte neu arbeit$aktArb
                steckInStock arbeit$aktArb $karte 1
                incr aktArb
              }
            }
            stelleKarteDar $flaeche anders h $hand $pos(x,$hand) $pos(y,$hand)
          }
        }

        unset spielStartetGerade
        if {$streitArt($patArt)} {
          confMenueEntry .menu.karten.m $text(geben) -command "geben hand2"
          if {![string compare $aktiverSpieler $ich]} {
            schaltSchachuhrAufMensch 1
          } else {
            streitZugBestaetigung
          }
        } elseif {!$demoAktiv} {
          aktiviereBindings
        }

        if {!$demoAktiv} {
          aktiviereKritischeKommandos ein
        }
      }
    proc schiebKarte {karte x y} {
      global lastX lastY flaeche

      spielXY neuX neuY $x $y
      $flaeche move $karte [expr $neuX-$lastX] [expr $neuY-$lastY]
      set lastX $neuX
      set lastY $neuY
    }
    proc endEinzelKarte {karte anwStapel x y diffX diffY} {
      global stapel fuelle zugNr veraendern mogelZaehler stockReihe \
             streitArt talonAbraeumbar patArt flaeche schatten

      if {$schatten} {$flaeche delete schatten}

      if {[string match ?,? $anwStapel] && !$talonAbraeumbar($patArt)} {
        set treffer 0
      } else {
        set neuStapel [findeStapel $x $y]
        switch -glob $neuStapel {
          ? - talon - strafe - arbeit* {
            set treffer [passtKarteAufStapel $anwStapel $neuStapel $karte]
            if {$veraendern && !$treffer && [string compare $anwStapel $neuStapel]} {
              set treffer 1
              incr mogelZaehler
            }
          }
          ?,? {
            set treffer [expr {![string match *,kompl $stockReihe($patArt)]
                               && [passt $karte [getStock $neuStapel] $neuStapel]
                               && $anwStapel != $neuStapel}]
          }
          default {
            set treffer 0
          }
        }
        if {$treffer} {
          switch -glob $neuStapel {
            ? - talon* - strafe* {
              steckInStapel $neuStapel $karte plusEinsGueltig
            }
            ?,? - arbeit? {
              steckInStock $neuStapel $karte 1
            }
          }
        }
      }
      if {$treffer} {
        incr fuelle($anwStapel) -1
        incr zugNr
        protokolliereZug Karte $karte $anwStapel $neuStapel 1

        pruefFreieKarte $anwStapel minusEins
        if {[string match ?,? $neuStapel] || $streitArt($patArt) || !$fuelle(hand)} {
          if {[checkSpielEnde 0]} return
        }
        if {$streitArt($patArt)} {
          deaktiviereGegnerStapel
        }
      } else {
        set nachY [expr {$fuelle($anwStapel)-1}]
        verteilComic $anwStapel $nachY $anwStapel $nachY 1 \
                     [expr {$x-$diffX}] [expr {$y-$diffY}]
        switch -glob $anwStapel {
          ?,? - arbeit? {steckInStock $anwStapel $karte 0}
          default       {maleKarte $karte alt $anwStapel $nachY}
        }
      }
      nichtBewegbar $karte
    }
    proc passtKarteAufStapel {anwStapel neuStapel karte} {
      global patArt stapel fuelle verdeckt leerStapelNurHoch aktuellErste

      if {![string compare $anwStapel $neuStapel]} {return 0}

      switch -glob $neuStapel {
        talon*  {set umgedreht 0}
        arbeit? {return [expr {$fuelle($neuStapel) == 0}]}
        default {set umgedreht $verdeckt($neuStapel)}
      }
      if {$fuelle($neuStapel) <= $umgedreht} {
        if {$fuelle($neuStapel) == 0} {
          if {![string match ? $neuStapel]} {return 0}
          if {$leerStapelNurHoch($patArt)} {
            return [aufsteigend $karte $aktuellErste 1]
          } else {
            return 1
          }
        } else {
          return 0
        }
      }

      set neuKarte $stapel($neuStapel,[expr $fuelle($neuStapel)-1])
      return [passt $karte $neuKarte $neuStapel]
    }
    proc checkTeilStapel {neuStapel aenderung} {
      global stapel verdeckt fuelle teilStapelUnterst patArt \
             stapelReihe teilStapelReihe auchBild

      set ungueltigSetzen 1
      set neuStapelX      [stapelX $neuStapel]
      set oben            [expr $fuelle($neuStapel)-1]
      switch $aenderung {
        plusEins - plusStapel {
          set unten $teilStapelUnterst($neuStapel)
        }
        minusEins - minusStapel {
          set unten $verdeckt($neuStapel)
        }
        plusStapelGueltig {
          set unten $teilStapelUnterst($neuStapel)
          if {![string compare $stapelReihe($patArt) $teilStapelReihe($patArt)]} {
            set ungueltigSetzen 0
          }
        }
        plusEinsGueltig {
          set unten [expr $oben-1]
          if {$unten < 0} {return}
          if {![string compare $stapelReihe($patArt) $teilStapelReihe($patArt)]} {
            set ungueltigSetzen 0
          } elseif {$unten > $teilStapelUnterst($neuStapel)} {
            set unten $teilStapelUnterst($neuStapel)
          }
        }
        default {return}
      }

      set passtNoch 1
      set verglI    $oben
      while {$verglI > $unten} {
        set verglKarte $stapel($neuStapel,$verglI)
        incr verglI -1
        set unterKarte $stapel($neuStapel,$verglI)
        if {$passtNoch && ![passt $verglKarte $unterKarte teil]} {
          if {!$ungueltigSetzen} {return}
          set passtNoch 0
          set teilStapelUnterst($neuStapel) [expr $verglI+1]
        }
        if {$auchBild} {
          if {$passtNoch} {
            teilStapelBar $unterKarte $neuStapel $verglI
          } else {
            nichtVerschiebbar $unterKarte
          }
        }
      }
      if {$passtNoch && $ungueltigSetzen} {
        set teilStapelUnterst($neuStapel) $unten
      }
    }
    proc endTeilStapel {anwStapel untenY x y diffX diffY} {
      global stapel fuelle zugNr flaeche patArt streitArt schatten

      if {$schatten} {$flaeche delete schatten}

      set karte $stapel($anwStapel,$untenY)
      set neuStapel [findeStapel $x $y]
      switch -glob $neuStapel {
        ?   {set treffer [passtKarteAufStapel $anwStapel $neuStapel $karte]}
        ?,? {set treffer [expr {$fuelle($anwStapel)==$untenY+13 &&
                                [passt $karte [getStock $neuStapel] $neuStapel]}]}
        default {set treffer 0}
      }
      if {$treffer} {
        # Der Stapel wurde an einen gueltigen Ort verschoben.
        set neuY $fuelle($neuStapel)
        plaziereTeilstapel $anwStapel $neuStapel $untenY
        # Wurde eine bisher verdeckte Karte nun freigelegt oder verdeckt, und
        # muss der Stapel expandiert oder komprimiert werden?
        pruefFreieKarte $anwStapel minusStapel
        pruefFreieKarte $neuStapel plusStapelGueltig

        incr zugNr
        protokolliereZug Stapel $anwStapel $neuY $neuStapel
        if {[string match ?,? $neuStapel] || $streitArt($patArt) || !$fuelle(hand)} {
          if {[checkSpielEnde 0]} return
        }
      } else {
        set lastI $fuelle($anwStapel)
        verteilComic $anwStapel $untenY $anwStapel $untenY [expr {$lastI-$untenY}] \
                [expr {$x-$diffX}] [expr {$y-$diffY}]
        for {set aktI $untenY} {$aktI < $lastI} {incr aktI} {
          $flaeche coords $stapel($anwStapel,$aktI) [stapelX $anwStapel] \
                                                    [stapelY $anwStapel $aktI]
          }
        set obenY [expr $fuelle($anwStapel)-1]
        verschiebbar $stapel($anwStapel,$obenY) $anwStapel $obenY
      }
      $flaeche dtag teilStapel teilStapel
    }
    proc schiebTeilstapel {vonStapel vonY neuStapel} {
      global stapel fuelle mitBewegComic

      if {$mitBewegComic} {
        set kartenAnz [expr {$fuelle($vonStapel) - $vonY}]
        verteilComic $vonStapel [expr {$fuelle($vonStapel)-$kartenAnz}] \
                     $neuStapel $fuelle($neuStapel) $kartenAnz
      }
    }
    proc plaziereTeilstapel {anwStapel neuStapel anwTeilStapelNr} {
      global stapel fuelle flaeche auchBild

      set lastI $fuelle($anwStapel)
      set neuX [stapelX $neuStapel]
      for {set aktI $anwTeilStapelNr} {$aktI < $lastI} {incr aktI} {
        set bewKarte $stapel($anwStapel,$aktI)
        set stapel($neuStapel,$fuelle($neuStapel)) $bewKarte
        incr fuelle($anwStapel) -1
        switch -glob $neuStapel {
          ?,? {
            steckInStock $neuStapel $bewKarte 1
            if {$auchBild} {
              nichtVerschiebbar $bewKarte
            }
          }
          default {
            if {$auchBild} {
              $flaeche coords $bewKarte $neuX \
                    [stapelY $neuStapel $fuelle($neuStapel)]
            }
            incr fuelle($neuStapel)
          }
        }
      }
    }
    proc getStock {stock} {
      global stapel fuelle

      set oberst [expr $fuelle($stock)-1]
      return [expr {$oberst < 0 ? "" : $stapel($stock,$oberst)}]
    }
    proc checkSpielEnde {inDemo} {
      global fuelle kartenSatz streitArt stockReihe patArt du text
      
      if {$streitArt($patArt)} {
        set computerAnz 0
        set menschAnz   0
        foreach sonderStapel {hand talon strafe} {
          incr computerAnz $fuelle($sonderStapel)
          incr menschAnz   $fuelle(${sonderStapel}2)
        }
        if {!$computerAnz} {
          streitBeileid $menschAnz
        } elseif {!$menschAnz} {
          if {[string compare $du $text(computer)]} {
            informiereStreitGegner Beileid $computerAnz
          }
          streitGlueckwunsch $computerAnz
        } else {
          return 0
        }
      } else {
        if {$fuelle(hand) > 0} {return 0}
        if {[string match *,kompl $stockReihe($patArt)]} {
          global teilStapelUnterst stapelAnz

          set komplettAnz 0
          for {set aktStapel 0} {$aktStapel < $stapelAnz($patArt)} {incr aktStapel} {
            if {$fuelle($aktStapel) == 13 && !$teilStapelUnterst($aktStapel)} {
              incr komplettAnz
            } elseif {($fuelle($aktStapel))} {
              return 0
            }
          }
          if {$komplettAnz && $komplettAnz != 4*$kartenSatz($patArt)} {return 0}
        } else {
          for {set aktSatz 0} {$aktSatz < $kartenSatz($patArt)} {incr aktSatz} {
            foreach aktFarbe {c h p k} {
              if {$fuelle($aktSatz,$aktFarbe) < 13} {return 0}
            }
          }
        }
        if {!$inDemo} {
          global zugNr vorschlagZaehler mogelZaehler
          if {$mogelZaehler > 0} {
            tadel $zugNr $mogelZaehler
          } else {
            glueckwunsch $zugNr $vorschlagZaehler
          }
        }
      }
      starteSpiel 0
      return 1
    }
    proc autoStock {aktStapel} {
      global stockBasis patArt stapel fuelle verdeckt aktuellErste
      
      # Werden denn ueberhaupt Karten automatisch auf den Stock geschoben?
      if {[string compare $stockBasis($patArt) erste]} {return 0}

      set gefunden 0
      while {42} {
        set aktFuelle $fuelle($aktStapel)
        if {$aktFuelle <= $verdeckt($aktStapel)} {return $gefunden}
        
        set oberste $stapel($aktStapel,[expr $aktFuelle-1])
        if {[string compare $aktuellErste [string index $oberste 0]]} {
          return $gefunden
        }
        
        if {[karteAufStock $oberste $aktStapel 0 0] != 1} {return $gefunden}
        
        set gefunden 1
      }
    }
    proc initPatience {} {
      global auto_path patiencePath demoAktiv auchBild \
             veraendern gemerkt marke zugNr fuelle streitGegner

      set auto_path "$patiencePath $auto_path"

      set demoAktiv     0
      set veraendern    0
      set gemerkt       0
      set marke         0
      set auchBild      1
      set zugNr        -1
      set streitGegner computer

      # fuelle(hand) wird hier tricksigerweise mit 1 initialisiert, damit die Hand
      # nicht beim erstenmal kurzfristig leer dargestellt wird.
      set fuelle(hand) 1

      # Den Zufallszahlengenerator warmlaufen lassen.
      initr [pid]

      # Die Spielregeln in der entsprechenden Directory einlesen.
      liesSpiel
    }
    # 0. Als absolute Vorarbeit die Spielflaeche erzeugen,
    mkFlaeche
    # 1. dann die anderen nicht ganz unwichtigen Vorarbeiten machen...
    initPatience
    mkMenue
    fuellFlaeche
    # 3. Mit Nachdruck dafuer sorgen, dass auch alle Vorarbeiten erledigt sind...
    wm deiconify .
    update
    if {![info exists bildBreite]} {tkwait variable bildBreite}
    # 2. ...und gib das erste Mal
    starteSpiel 0
