Нет никаких причин гнаться за чужой одержимостью своей единственной истиной. Как и у любого языка, у пакетной обработки есть свои особенности, но основная методология является общей.
С процедурными языками я придерживался аналогичной структуры на протяжении десятилетий. Суть в том, чтобы иметь только ОДНУ процедуру, взаимодействующую с пользователем. Остальная часть программы затем становится конечным автоматом, направляемым из одного состояния в другое в ответ на ввод пользователя. Это может занять некоторое время, но я успешно (и быстро) разрабатывал программы, использующие этот принцип в пакетном режиме, коболе, паскале, базовом, прогрессе, богомоле и других.
@ECHO OFF
SETLOCAL
SET state=0
SET "savefile="
:mainloop
CALL :state%state%
IF %state% neq 999999 GOTO mainloop
GOTO :EOF
::
:: USER I/O
::
:userio
IF NOT DEFINED savefile GOTO useriolp
set>%savefile%
:useriolp
SET "response="
SET /p response="%message% ? "
IF NOT DEFINED response GOTO useriolp
SET response=%response: =_%
FOR %%r IN (EXIT quit) DO IF /i %response%==%%r SET state=999999&GOTO :EOF
SET "state="
FOR %%r IN (%vr%) DO IF DEFINED state (
IF /i %%r==%response% GOTO :EOF
SET "state="
) ELSE (SET state=%%r)
IF DEFINED state GOTO :eof
ECHO Invalid response
GOTO useriolp
::State 0 - get username
:state0
SET "vr=100"
SET message=Your name
GOTO userio
:: State 100 - have username.
:: Load user's savefile if it exists
:state100
SET savefile=%response%
IF exist %savefile% GOTO S100.1
:: New game - initialise data
:: set start-state in STATE
SET example=exampledata
SET state=1000
GOTO :eof
:: Load game - including STATE
:S100.1
SET "state="
FOR /f "tokens=1*delims==" %%i IN (%savefile%) DO IF NOT defined %%i SET %%i=%%j
GOTO :eof
:: State 1000 - start game
:state1000
:: ** Just for a demo, show example as loaded from savefile
ECHO example=%example%
ECHO You see a shimmering blue-hued house with four doors numbered 1,2,3 and 4
SET "vr=1001 1 1002 2 1003 3 1004 4 1001 one 1002 two 1003 three 1004 four"
SET message=Which door do you choose
GOTO userio
:: State 1001 - door 1
:state1001
ECHO You see John Lodge
SET example=John Lodge
:: OK, from here, you're on your own. I'll force a state and loop
SET state=1000
GOTO :eof
:: State 1002 - door 2
:state1002
ECHO You see Graeme Edge
SET example=Graeme Edge
:: OK, from here, you're on your own. I'll force a state and loop
SET state=1000
GOTO :eof
:: State 1003 - door 3
:state1003
ECHO You see Justin Hayward
SET example=Justin Hayward
:: OK, from here, you're on your own. I'll force a state and loop
SET state=1000
GOTO :eof
:: State 1004 - door 4
:state1004
ECHO You see Ray Thomas
SET example=Ray Thomas
:: OK, from here, you're on your own. I'll force a state and loop
SET state=1000
GOTO :eof
С приведенным выше кодом вы можете увидеть скелет. :mainloop
просто устанавливает «повторять до тех пор, пока exitstructure, where
EXIT» не станет состоянием = 999999. Я использовал числа для штатов, но это просто вопрос выбора.
Для любого конкретного состояния вы (необязательно) что-то делаете, затем настраиваете подсказку (не называйте ее prompt
— это пакетное ключевое слово) и набор допустимых ответов (vr
легче ввести, чем valid_responses
), затем переходите к :userio
процедура (которая возвращается к :mainloop
после принятия ответа.
:userio
сохраняет всю текущую среду (поэтому имеет функцию «автосохранения»), затем запрашивает сообщение и принимает ответ. Set /p
оставит response
без изменений, если нажать enter, поэтому установка response
на [ничего] сначала гарантирует, что enter не будет повторять предыдущий ответ.
Я решил заменить любые введенные символы space символами подчеркивания — это упрощает обработку, поскольку вам не нужно беспокоиться о пробелах в строках (это неполные — запятые, табуляции и точки с запятой; перенаправления и амперсанд). тоже могут быть проблемы...)
Затем, если пользователь вводит ВЫХОД или ВЫХОД, назначается состояние выхода.
В противном случае строка действительных ответов сопоставляется с полученным ответом. Строка vr
просто
nextstate ifthisresponse nextstate ifthisresponse nextstate ifthisresponse nextstateotherwise
nextstate в противном случае не должен появляться, и если это не так, генерируется сообщение invalid response
и повторно запрашивается ввод.
Итак, из состояния 0 вам будет предложено ввести ваше имя, а следующее состояние будет равно 100 независимо от этого.
State100 устанавливает savefile
в ответ пользователя (имя), и если этот файл существует, любая переменная, записанная в файле сохранения, перезагружается в среду, восстанавливая игру до ее точного состояния, когда в последний раз программа была EXIT
ed. Если файл не существует, то у вас есть возможность установить любые необходимые игровые данные - я только что установил переменную example
в качестве примера.
State1000 запускает игру. Я только что показал значение example
в демонстрационных целях. Он должен начинаться как exampledata
, как установлено в state100-no-savefile. Итак, вы получаете описание сценария, устанавливаете подсказку и vr
определяет следующее состояние как 1001, если ваш ответ (1 или один); 1002 за (2 или два)...
Выбор 1,2,3 или 4 переключает вас в следующее состояние; строка example
изменена, и - ну, я заставил state1000 быть пунктом назначения. Что бы вы сделали, так это просто следили бы за прыгающим мячом в состоянии 1000.
Теперь - если вы наберете exit
, программа завершится. Повторно запустите и введите то же имя пользователя, и значение example
будет отображаться как последнее установленное значение, восстановленное из файла сохранения.
В качестве небольшого расширения вы можете добавить систему help
, просто добавив
IF /i %response%==help call :help&goto useriolp
после строки FOR %%r IN (EXIT quit) ...
. Обратите внимание, что вы можете сделать подпрограмму :help
контекстно-зависимой, потому что у вас есть значение state
, чтобы сообщить вам, где вы находитесь.
Точно так же вы можете реализовать систему look
, если хотите, по тому же принципу.
Все в пакете. Другие языки вообще не нужны... :)
person
Magoo
schedule
04.08.2013