     『第 29 楼』:
使用 LLM 解释/回答一下
批处理推箱子源码解释:
1、数据定义的紧凑格式的使用
先把变量定义集放到变量:(要注意分隔符是唯一的,这里用“;”号)
set a=a=i75;b=i79;str=abc
这样变量a的值为:a=i75;b=i79;str=abc
利用预处理时变量值替换:
set %a:;=&set %
相当于以下语句被执行:
set a=i75&set b=i79&set str=abc
或者:
set a=i75
set b=i79
set str=abc
如果要定义的变量很多,综合从占用空间和可读性上看,此法有明显的优势。
2、”推箱子“程序实现算法
1). 读取关级数据放到数组:lev(n)
改变n的值,即为改变关级,这里 n=%lev%
2). 把当前关地图数据还原并存到二维数组:r(n).(m),
(一) 把值为坑“☆”的变量名r(n).(m),集放到变量ke,并把“☆”的个数存到变量ji,同时转为“★”;
%ke%扩展后就是源值为坑“☆”的所有二维变量的实时的值了;只要%ke% 等于 !ji! 表明过关了
(二) 按行把二维变量名存为数组:r(n)
%r(n)%扩展后即为第n行的所有二维数组的实时值
3). 变量ebuf作为显示缓存,所有要显示的内容全部存到ebuf,一次性用echo !ebuf!全部显示完成。
因为for 变更 %%a 在扩展后,会再次扩展!号变量,所以:
for /l %%a in (1,1,!r!) do for %%b in ("!r%%a!") do set ebuf=!ebuf! %%~b!cr!
上面依次把:1到!r!行的变量名数组r(n)扩展后的值,全部存到显示缓存ebuf内,并且加上了换行符!cr!
4).首先定义好按上下左右所进行的操作:
"c1=n-;c2=m-;c3=n+;c4=m+"
这样就可以通过下面代码:
set/a sm=m,sn=n,!c%in%!=1,bm=m,bn=n,!c%in%!=1
分别取得按了 上/下/左/右 后,源点:sm.sn,步进一:bm.bn,步进二:m.n,三个坐标的值
for /f "tokens=1,2" %%a in ("!r%bn%.%bm%! !r%bn%.%bm%!!r%n%.%m%!") do (
取出三个坐标的值并摆开为:(步进一 => %%a) (步进一+步进二 =>%%b) 例如:%%a=▓ %%b=▓∷
for %%c in ("!%%a!!%%b!") do (
%%a %%b 经再扩展后,组后到%%c, 接上例:!▓! =>空, !▓∷! =>▓-∷
则: ▓-∷ => %%c
for /f "tokens=1,2 delims=-" %%1 in (%%c) do (
摆开为:%%1=▓,%%2=∷
接下来就 if 判断了,根据各种情况把三个点和一个“大”站的!源!点的值重新调整
注意:有一点,如果%%c的值为空,如 %%b=▓■ 为时,则这个for将是空转,即连里面的if语句也不会被执行,
使得后面的 set/a m=sm,n=sn 被执行了
3、关级数据压缩与还原
1).压缩,因全角为双字节,用单字转换后可以少一半,如果 ▓=a,zf=▓,则:set zf=!%af%! 就可转过来了
如果不只一个连续的则在字母后跟个数字表示个数,超过9则另起一组,如:a11,则拆为a9a2
2).还原,引用:囧开头的好处,
for /f "tokens=2* delims=囧" %%a in (%~nx0) do (set lev!n!=%%a&set/a n+=1)
这样在读取时可以减去了对其它非数据行的读取,加快了速度
同样的方法把字符转换回来,再把搂字作为for /l 计数重复即可全部转换
if "!tn:%%2=!" neq "!tn!" (set k=%%2) else (set k=1)
for /l %%k in (1,1,!k!) do (
上面的!k!即为字符个数
4、摆脱choice.exe 和 刷屏不闪
就是用debug.exe 来替了,但是这个是通常所有dos系统都会自带的,所以。。三方。。。
debug <%~nx0>nul
调用自身作为管道输入,第一行是出错的,真正有用的只有两行
e 100 cd 16 86 c4 b4 02 cd 10 b4 4C CD 21 写入代码
g 执行
这里面进行了键读取,把当前光标位置设为第一行,第一列,并把按键数据作为返回码到:%errorlevel%
定义:"a=i83=10;i1=7;i72=1;i80=3;i75=2;i77=4;i73=8;i81=9;i57=5;i79=6"
执行:set in=!i%errorlevel%!
就根据定义得到按键情况,如果示定义的则为空
平时写批处理要回到第一行显示时,只有用cls,然后再显示,显然速度也很快,还是觉得有点闪。
直接把光标重置到第一行,第一列,并没有清屏,再次显示时是在原来的基础上的,所以少了闪的感觉
如果看汇编源码,很简单,把debug <%~nx0>nul后面的>nul去掉,再在e 行和g 行间加入一行u 就可以了
5、玩家记录保存,与读取
这里是把记录存在批处理的第一行,
1).读取
set/p yg=< %~nx0 >nul
取第一行到变量 yg
set yg=!yg:~13,52!
set lev=%yg:@=&rem %
因为当前关记录和已过关的记录是以@为分隔的,这样可以只所@前面的给lev,@后面的被rem 掉了
set yg= !yg:* =!
只取已过关的数据,并且保持前后必须有空格
这样已经所当前关,及已过经过了的关的数据全部读取到变量了
2).保存
set a=a 10d`db "!lev!@!yg! "``w`q
(echo %a:`=&echo;%)|debug %~nx0 >nul
经扩展为:
(echo a 10d&echo;db "!lev!@!yg! "&echo;&echo;w&echo;q)|debug %~nx0 >nul
实际上是把以下命令行递给debug 去执行:
a 10d
db "!lev!@!yg! "
w
q
利用了debug 的a命令输入汇编指令时,可以用db 定义字符串,然后直接用W命令可以写打开的文件
并且批处理程序在执行过程中,是可以修改自身的
Last edited by netbenton on 2009-9-9 at 10:58 ]
Batch Processing Sokoban Source Code Explanation:
1. Use of Compact Format for Data Definition
First, put the variable definition set into a variable: (Note that the delimiter is unique, here using the ";" sign)
set a=a=i75;b=i79;str=abc
So the value of variable a is: a=i75;b=i79;str=abc
Use variable value replacement during preprocessing:
set %a:;=&set %
Equivalent to the following statements being executed:
set a=i75&set b=i79&set str=abc
Or:
set a=i75
set b=i79
set str=abc
If there are many variables to define, comprehensively considering from the perspective of occupied space and readability, this method has obvious advantages.
2. "Sokoban" Program Implementation Algorithm
1). Read the level data into an array: lev(n)
Change the value of n, which is to change the level, here n=%lev%
2). Restore the current level map data and store it in a two-dimensional array: r(n).(m)
(1) Collect the variable names r(n).(m) with the value "☆" into variable ke, and store the number of "☆" into variable ji, and convert them to "★" at the same time;
%ke% after expansion is the real-time value of all two-dimensional variables with the source value "☆"; as long as %ke% is equal to !ji! it means the level is passed
(2) Store the two-dimensional variable names as an array by row: r(n)
%r(n)% after expansion is the real-time value of all two-dimensional arrays in row n
3). Variable ebuf is used as a display buffer, all content to be displayed is stored in ebuf, and all is displayed at once with echo !ebuf!
Because after expansion of for variable %%a, the! -quoted variable will be expanded again, so:
for /l %%a in (1,1,!r!) do for %%b in ("!r%%a!") do set ebuf=!ebuf! %%~b!cr!
The above sequentially stores the expanded values of the variable name array r(n) from row 1 to!r! into the display buffer ebuf, and adds the newline character!cr!
4). First define the operations for up, down, left, and right:
"c1=n-;c2=m-;c3=n+;c4=m+"
In this way, through the following code:
set/a sm=m,sn=n,!c%in%!=1,bm=m,bn=n,!c%in%!=1
Respectively obtain the source points: sm.sn, step one: bm.bn, step two: m.n, the values of the three coordinates after pressing up/down/left/right
for /f "tokens=1,2" %%a in ("!r%bn%.%bm%! !r%bn%.%bm%!!r%n%.%m%!") do (
Take out the values of the three coordinates and spread them out as: (step one => %%a) (step one + step two =>%%b) For example: %%a=▓ %%b=▓∷
for %%c in ("!%%a!!%%b!") do (
%%a %%b after re-expansion, grouped into %%c, continuing the example:!▓! => empty,!▓∷! =>▓-∷
Then: ▓-∷ => %%c
for /f "tokens=1,2 delims=-" %%1 in (%%c) do (
Spread out as: %%1=▓, %%2=∷
Next is the if judgment, according to various situations, adjust the values of the three points and a "large" standing! source! point again
Note: There is a point, if the value of %%c is empty, such as when %%b=▓■, then this for will be an empty loop, that is, even the if statement inside will not be executed, making the following set/a m=sm,n=sn be executed
3. Compression and Restoration of Level Data
1). Compression: Since full-width characters are double-byte, converting to single characters can reduce by half. If ▓=a, zf=▓, then: set zf=!%af%! can be converted back
If there are not only one continuous ones, then a number is added after the letter to indicate the number. If it exceeds 9, start a new group, such as: a11, then split into a9a2
2). Restoration, reference: The advantage of starting with 囧,
for /f "tokens=2* delims=囧" %%a in (%~nx0) do (set lev!n!=%%a&set/a n+=1)
In this way, when reading, the reading of other non-data lines can be subtracted, and the speed is accelerated
Similarly, convert the characters back, and then use the 搂 character as the for /l count to repeat to convert all
if "!tn:%%2=!" neq "!tn!" (set k=%%2) else (set k=1)
for /l %%k in (1,1,!k!) do (
The above!k! is the number of characters
4. Get Rid of choice.exe and Screen Flashing
That is, use debug.exe instead, but this is usually available in all DOS systems, so. third-party...
debug <%~nx0>nul
Call itself as pipeline input, the first line is wrong, only two lines are really useful
e 100 cd 16 86 c4 b4 02 cd 10 b4 4C CD 21 Write code
g Execute
Here, key reading is performed, set the current cursor position to the first line, first column, and the key data is used as the return code to: %errorlevel%
Definition: "a=i83=10;i1=7;i72=1;i80=3;i75=2;i77=4;i73=8;i81=9;i57=5;i79=6"
Execution: set in=!i%errorlevel%!
Then get the key situation according to the definition, if not defined, it is empty
Usually, when writing a batch processing to return to the first line to display, only use cls, and then display again. Obviously, the speed is also very fast, but I still feel a bit flashing.
Directly reset the cursor to the first line, first column, without clearing the screen, and when displaying again, it is based on the original one, so the feeling of flashing is reduced
If you look at the assembly source code, it is very simple. Just remove >nul after debug <%~nx0>nul, and add a line u between the e line and the g line.
5. Player Record Saving and Reading
Here, the record is stored in the first line of the batch processing,
1). Reading
set/p yg=< %~nx0 >nul
Take the first line to variable yg
set yg=!yg:~13,52!
set lev=%yg:@=&rem %
Because the current level record and the passed level record are separated by @, so only the part before @ is given to lev, and the part after @ is commented out by rem
set yg= !yg:* =!
Only take the passed data, and keep the space before and after
In this way, the current level and the passed level data are all read into the variable
2). Saving
set a=a 10d`db "!lev!@!yg! "``w`q
(echo %a:`=&echo;%)|debug %~nx0 >nul
Expanded to:
(echo a 10d&echo;db "!lev!@!yg! "&echo;&echo;w&echo;q)|debug %~nx0 >nul
Actually, the following command line is handed to debug to execute:
a 10d
db "!lev!@!yg! "
w
q
Using the a command of debug to input assembly instructions, you can use db to define a string, and then directly use the W command to write to the opened file
And the batch processing program can modify itself during execution
|