Timer in Batch im Hintergrund laufen lassen?

4 Antworten

ich hoffe Du schaust noch mal rein...

Die Art wie Du die Variablen setzt ist bei 4 Zellen gerade noch praktikabel.

Ich möchte ganicht wissen was das für ein ge"if"e bei 100 Zellen gegen könnte. 🤢😖🥶😱🥵

In folgender Demo schenke ich Dir zwei einigermaßen unverselle Routinen (das Bezeichnen der variablen uber Parameter habe ich mir wegen der Übersichtlichkeit verkniffen . (immerhin soll man nachvolziehen können was abläuft)

HerzStück ist ein Macro, welches in einem Rutsch die gesamte Spielfläche zeichnet In den Variablen am Anfang muss lediglich die anzuzeigenden Parameter angeben.

Die SteuerRoutine :userMove erscheint zwar auf den ersten Blick umfänglicher als deine :left und :right allerdings Steuert dies alle 4 Achsen und theoretisch beliebig viele Zeilen und Spalten.

@echo off
chcp 65001 >nul
setlocal enableDelayedExpansion


:init


  rem die Dimensionierung des Speilfeldes muss nur einmal eingerichtet werden
set "GameFieldDimensionY=10"
set "GameFieldDimensionX=20"
set /a "GameFieldSize=GameFieldDimensionX*GameFieldDimensionY"
  rem lineare Position des PositionsMarkers
set "currentPos=1"
  rem  so  würde  die Mitte festgelegt
:::set /a "currentPos=GameFieldSize / 2"
  rem Spaltentrenner 
set "colDelimiter=|"
  rem Zeichen für leere Felder (oder Leerzeichen)
set "emptyMarker=_"
set "posMarker=X"


  rem Erklärung in der Subroutine
call :initMacroGameField


  rem zum Anzeigen der initialisierten Variablen ::: entfernen
:::set "field"
:::set "macroDrawGameField"
:::pause


:GameLoop
cls
echo:
%macroDrawGameField%
:reask
choice /c WSADx  /n >nul
  rem richtungen: top,down,left,right
if %errorlevel% equ 1 call :userMove -%GameFieldDimensionX%
if %errorlevel% equ 2 call :userMove  %GameFieldDimensionX%
if %errorlevel% equ 3 call :userMove -1 
if %errorlevel% equ 4 call :userMove  1 
if %errorlevel% equ 5 goto verloren
  rem -1 wird wird von :userMove gesetzt  (wenn  nichts verändert  wurde  müssen wir auch nichts neu Schreiben)
if %errorlevel% equ -1 goto :reask
goto GameLoop
pause
exit /b

::::::::::::::::: Subroutinen ::::::::::::::::::::

:verloren
cls
echo verloren
pause
exit /b


:userMove
set /a "newPos=currentPos+%1"
  rem einfach nur prüfen ob Zeile oder Spalte angesteuert wird (__dummy  nur um evtl. das Vorzeichen zu entfernen)
set "__dummy=%~1"
if %__dummy:-=% lss %GameFieldDimensionX% (
      rem Zeilen überlauf/wrapp Vehindern aus der linearen Position die  aktuelle und Neue Zeile berechnen  (mehrere Berchnungen mit einem  Set /a  sind  schneller)
    set /a "curY=(currentPos+GameFieldDimensionx-1) / GameFieldDimensionx , nwY=(newPos+GameFieldDimensionx-1) / GameFieldDimensionx "
    if !curY! equ !nwY! (
              rem wenn  Gleiche Zeile, in alte Speicherzelle ein Leerfeld schreiben
            set "field!currentPos!=%colDelimiter%%emptyMarker%"
              rem und in die neue unseren Positionsmarker
            set "field!newPos!=%colDelimiter%%posMarker%"
            set "currentPos=!newPos!"
            exit /b 0
    )
) else (
      rem dito für Zeilenänderungen nur  prüfen ob  der Zeiger überhaupt noch im Array ist... 
      rem (ein Goto habe ich aus Geschwindigkeitsgünden  nicht  setzen wollen, deshalhalb der gleiche Code  in jedem if-Zweig)
    if !newPos! gtr 0 (
        if !newPos! leq %GameFieldSize% (
            set "field!currentPos!=%colDelimiter%%emptyMarker%"
            set "field!newPos!=%colDelimiter%%posMarker%"
            set "currentPos=!newPos!"
            exit /b 0
        )
    )
)
  rem Dem Aufrufer per Errorlevel mitteilen das nichts verändert wurde (0 und Negative werden garantiert nicht von Choice generiert)
exit /b -1


  rem hier musst  Du nichts mehr  verändern
:initMacroGameField
  rem Zeilenvorschub in einer Variable, Bei DelayeExpansion werwende !LFD! sonst %LF% (außer innerhalb einer Variablenzuweisung, dann !LF!)
  rem das ganze ist etwas Tricky (gegebenenfalls   hilft einfach  mal Probieren  was  wann funktioniert)
(set LFD=^
%=this line is empty=%
)
set LF=^^^%LFD%%LFD%^%LFD%%LFD%


  rem es wird  Automatisch ein Macro erzeugt, welches das Spielfeld anzeigt egal wo und wann
  rem auch  Batch eigentlich  keine Zeiger (Pointer) kennt kann mann durch  geschicktes maskieren von Variablen, diese simulieren
  rem Im Ergebnis  enthällt  die MacroVariable dann die Zeile: echo !field1!!field2!!field3!!field4!....
  rem die Variablen werden erst bei Ausführung aufgelöst (DelayedExpansion).
  rem die Vorteile: erzeugt automatisch das gesammte Spielfeld  als  abrufbares Macro, die ZeichenRoutine muss nicht für jeden Fall neu geschrieben werden.
  rem ..., Die Steuerung der Darstellungen erfolgt allein über Variablen, das schreiben erfolgt bis Anzahl der Zeilen schneller als einzelne echo-Aufrufe...
  rem Nachteil: In dieser Form  idt  die Anzahl der Felder auf maximal 818 beschränkt. (Batch-Befehlslänge =8191 Zeichen) könnte man jedoch durch verteilen auf mehrere Macros fixen


  rem echo in Macro schreiben 
set "macroDrawGameField=echo "
for /l %%Y in (1,1,%GameFieldDimensionY%) do (
    for /l %%X in (1,1,%GameFieldDimensionX%) do (
          rem aus X und Y lineare Adresse für PseudoArray field berechnen...
        set /a "__num=(%%Y-1)*GameFieldDimensionX+%%X"
          rem Trennzeichen und Marker für Leeres Feld in ArrayZelle schreiben
        set "field!__num!=^%colDelimiter%%emptyMarker%"
          rem String zB. !field1! an macro anhängen die Carrets^  verhindern, dass die Ausrufezeichen sofort als Steuerzeichen ausgewertet werden
        set "macroDrawGameField=!macroDrawGameField!^!field!__num!^!"
    )
    if !__num! lss %GameFieldSize% (
          rem an jedes Zeilenend ein das Trennzeichen eine Zeilenvorschub anhängen (die Carrets  stellen sicher, das  man auch Sonderzeichen in das Makro einfügen kann )
        set "macroDrawGameField=!macroDrawGameField!^^%colDelimiter%!LF!"
    ) else (
          rem an die Letzte Zeile kein Zeilenvorschub
        set "macroDrawGameField=!macroDrawGameField!^^%colDelimiter%"
    )
)
  rem letzten Endes noch den Marker für die aktuelle Position an  die Startpossition schreiben...(hat  aber  nichts mit dem Macro selbst zu tun)
set "field!currentPos!=^%colDelimiter%%posMarker%"
exit /b
:: Ende initMacroGameField

... den /t- parameter von Choice habe ich weggelassen... (hier ging es nur um die Steuerung

Woher ich das weiß:eigene Erfahrung – Ich mach das seit 30 Jahren
Erzesel  06.06.2020, 11:48

alternative Variablen zur Demo

...
set "GameFieldDimensionY=3"
set "GameFieldDimensionX=5"
set /a "GameFieldSize=GameFieldDimensionX*GameFieldDimensionY"
set /a "currentPos=GameFieldSize / 2+1"
set "colDelimiter=:"
set "emptyMarker= "
set "posMarker=▓"
...
0

Mit start /b kannst du eine Art zweiten Thread im gleichen Fenster starten und dort dann eine Sekunde warten. Oder du startest eine zweite Batch minimiert und beendest die erste nach einer Sekunde...

Aber warum so kompliziert, wenn der Befehl den du bereits benutzt schon diese Funktion eingebaut hat?

choice /c abc /t 1 /d c

/t 1 lässt dem Benutzer nur eine Sekunde Zeit eine Auswahl zu treffen. Hier eine genauere Beschreibung aus der Hilfe von choice (choice /?):

/T    Zeitlimit  Bestimmt die Länge der Pause vor der Auswahl
                 in Sekunden. Gültige Wert sind 0 bis 9999.
                 Der Wert 0 bedeutet keine Pause und Verwendung
                 der Standardauswahl.

/D    Auswahl    Bestimmt die Standardauswahl nach nnnn Sekunden.
                 Zeichen müssen im Auswahlsatz durch die Option
                 /C und nnnn mit Option /T festgelegt werden.

Der Choice-Befehl hat eine Timeoutfunktion.

https://ss64.com/nt/choice.html

Choice /c abc /d b /timeout 3 /m "Waehle aus:"
If %Errorlevel% equ 1 echo a gedrueckt
If %Errorlevel% equ 2 echo b gedrueckt
If %Errorlevel% equ 1 echo c gedrueckt
Pause
  • Tasten abc erlaubt
  • b ist default
  • Nach 3 Sekunden ohne Nutzereingabe mit dem Defaultwert fortsetzten.

(Keine Gewähr, habe die Demo unterwegs auf dem Handy geschrieben.)

Woher ich das weiß:eigene Erfahrung – Ich mach das seit 30 Jahren
Simsi18066081sI 
Fragesteller
 03.06.2020, 15:22

Danke für die Antwort, aber geht das auch ohne dem Defaultwert? Ich will es nämlich so machen, dass innerhalb von 3 Sekunden a oder b drücken muss. Wenn man das nicht gemacht hat, soll das Programm zu einem anderen Punkt gehen.

0
Erzesel  03.06.2020, 16:03
@Simsi18066081sI

Ich sollte wohl doch nicht mehr von Unterwegs antworten...🤮 , hab gerad gesehen ich hab 'nen richtig fetten Synaxfehler reingekracht (oder die Autovervollständigung hat das timeout reingewürgt). Das kommt davon , wenn man mehrere Dinge gleichzeitig tut. totaler Schrott 💩🤯😲😖🤢😰

Hier der Code wie ich es mir auf Deine Nachfrage vorstelle. Dazu unterdrücke ich komplett alle Ausgaben von choice und lasse es komplett im stillen arbeiten...

@echo off
  rem Fragen außerhalb von choice stellen
echo Du  hast 3 Sekunden zum Antworten:
echo A oder B
  rem mit /n und >nul Ausgaben von choice  unterdrücken...
choice /c abx /d x /t 3 /n >nul
if %errorlevel% equ 1 echo Du  hast mit A geantwortet!
if %errorlevel% equ 2 echo Du  hast mit B geantwortet!
if %errorlevel% equ 3 goto :andererPunkt
pause
exit /b


:andererPunkt
echo Die Zeit ist abgelaufen!!!!
pause


1
Erzesel  04.06.2020, 07:35
@Simsi18066081sI

So geht das nicht. Erstmal habe ich keinen Zugriff auf Dein Googledrive, zum anderen stehe ich nicht unbedingt darauf irgendwelche Screenshots abzutippen.

Poste doch bitte Deine Codes in Textform, in einer Codebox (</>) .

Sollte der Umfang des Codes die Möglichkeiten des GF-Editors überschreiten nutze Pastebin und poste hier den Link.

1
Simsi18066081sI 
Fragesteller
 04.06.2020, 16:43
@Erzesel

Ja tut mir leid.

Hier:

@echo off

:int 
set p1=:0:
set p2=: :
set p3=: :
set p4=: :

:spiel
cls
chcp 850 >nul
echo.
echo.
echo.
echo.
echo %p1%  %p2%  %p3%  %p4%
echo.
choice /c abx /d x /t 1 /n >nul
if errorlevel 255 goto spiel
if errorlevel 2 goto left
if errorlevel 1 goto right
if errorlevel 3 goto verloren


:left
if "%p2%"==":0:" set p1=:0:&&set p2=: :
if "%p3%"==":0:" set p2=:0:&&set p3=: :
if "%p4%"==":0:" set p3=:0:&&set p4=: :
goto spiel


:right
if "%p3%"==":0:" set p4=:0:&&set p3=: :
if "%p2%"==":0:" set p3=:0:&&set p2=: :
if "%p1%"==":0:" set p2=:0:&&set p1=: :
goto spiel


:verloren
cls
echo verloren
pause
0
Erzesel  04.06.2020, 19:12
@Simsi18066081sI

Die alte Notation der Errorlevelabfrage mit: if Errorlevel n ist extrem kritisch und sollte nicht mehr verwendet werden. (https://ss64.com/nt/errorlevel.html)

verwende immer: if %errorlevel% equ n , dann ist stets eine eindeutige Zuordnung vorhanden.

Errorlevel 255 wird von choice nur bei einem Syntaxfehler gesetzt (siehe Oben falscher Parameter /timeout ) diesen abzufragen ist defakto Quatsch, da dieser wenn die Batch einmal läuft nie auftritt. (Ansonsten sieht man an der Fehlermeldung das etwas nicht stimmt. )

Ich habe das Spielprinzip zwar nicht begriffen , aber nun wird auch zu Verloren gesprungen.

Für alle nichtenglischen Sprachen ist seit Win 10 die Codepage 65001 (UTF8) die beste Wahl. Damit werden alle in Europa gängigen Zeichen richtig dargestellt.

Das doppelte && ist eine Positivbedingte Ausführung abhängig von Errorlevel=0 (sollte nur verwendet werden, wenn man sicher ist, das ein definierte Zustand vorhanden ist).https://ss64.com/nt/syntax-redirection.html

...ansonsten sieht Dein Code wirklich wohlstrukturiert aus, finde ich prima 👍

@echo off
chcp 65001 >nul
:int 
set p1=:0:
set p2=: :
set p3=: :
set p4=: :


:spiel
cls
echo.
echo.
echo.
echo.
echo %p1%  %p2%  %p3%  %p4%
echo.
choice /c abx /d x /t 1 /n >nul
if %errorlevel% equ 1 goto right
if %errorlevel% equ 2 goto left
if %errorlevel% equ 3 goto verloren

:left
if "%p2%"==":0:" set p1=:0:&set p2=: :
if "%p3%"==":0:" set p2=:0:&set p3=: :
if "%p4%"==":0:" set p3=:0:&set p4=: :
goto spiel

:right
if "%p3%"==":0:" set p4=:0:&set p3=: :
if "%p2%"==":0:" set p3=:0:&set p2=: :
if "%p1%"==":0:" set p2=:0:&set p1=: :
goto spiel

:verloren
cls
echo verloren
pause
1
Simsi18066081sI 
Fragesteller
 04.06.2020, 21:16
@Erzesel

Ich danke dir für die Tipps und für die Verbesserung des Codes. Es hat alles super funktioniert und das Spielprinzip kann man nur wirklich verstehen wenn man den ganzen Code sieht .

0
Erzesel  06.06.2020, 11:37
@Simsi18066081sI
Spielprinzip kann man nur wirklich verstehen wenn man den ganzen Code sieht .

ob ich den bei nochmehr Zellen sehen will?

0

Sollte als Batch nicht funktionieren.

Da würde ich dann eher zu einer Programmiersprache greifen. da lässt sich das dann eher einfacher bewerkstelligen. Dort einen Timer starten und dann eine Schleife mit unterschiedlichen "Ausgängen"

Simsi18066081sI 
Fragesteller
 03.06.2020, 08:29

Okay schade, aber trotzdem danke.

0
timlg07  03.06.2020, 10:47
Sollte als Batch nicht funktionieren.

Doch, ist genauso in die Funktionalität von choice eingebaut.

Da würde ich dann eher zu einer Programmiersprache greifen.

Batch ist bereits eine Programmiersprache...

Dort einen Timer starten und dann eine Schleife mit unterschiedlichen "Ausgängen"

Nachdem der Timer abgelaufen ist eine Schleife mit mehreren Ausgängen? Meinst du etwa die berüchtigte "if-Schleife"? Das ergibt vorne und hinten keinen Sinn.

1
qugart  03.06.2020, 11:01
@timlg07

Choice kann das nur wenn man da mit mit mehreren Instanzen arbeitet. Batch ist KEINE Programmiersprache. Es ist ein CLI aka Shell. Dabei werden Kommandos verarbeitet. Oftmals aus einer Skript-Datei heraus. Daran liegt es auch, dass man dabei nur über mehrere Instanzen das gewünschte Szenario nachbilden kann. Ist halt ineffektiv.

Alleine die Geschichte mit einem Timer bis zu einer Sekunde wird schwierig werden. Choice und timeout kann man zwar auch über Umwege zu Millisekunden bringen (besser wäre da ein Ping), dann hast du aber das Problem, dass das öffnen einer neuen Instanz (neuer Prozess) oftmals länger als eine Sekunde dauert und generell (auch wenns im Milliseknudenbereich passiert) aus der Messung dann heraus ist.

Das gewünschte Szenario ist in einem Batch-Skript nur sehr schwer bis gar nicht machbar.

0
Lamanini  14.06.2020, 19:19
@qugart

Batch files werden von einem Interpreter verarbeitet und sind in einer formalen Sprache geschrieben, in der Du Algorithmen und Daten angeben kannst. Damit ist es doch eine Programmiersprache.

2