📜 ⬆️ ⬇️

His sapper on his batch file

image

Once I wanted to write Minesweeper ... on batch files. And I wrote it.

Meet !!! Minesweeper for cmd.exe
')
So, the features of this product:
In general, this is a real sapper (and not those pitiful similarities - KMines and a sapper for Windows) for real men. And then you can read how to make your cool sapper.

image
Screenshot game.

Any serious bat program should not leave behind traces, such as unnecessary variables. The setlocal (at the beginning) and endlocal (at the end) commands are used for this. More information: setlocal /? .. Okay, let's move on to the game itself.

First of all, we will create two arrays - real and visible fields. Since there are no arrays, we will improvise - we will create a bunch of variables of the form mfield34 and rfield 69. For this we will use a for loop.
  for / L %% x in (1,1,9) do for / L %% y in (1,1,9) do set mfield %% x %% y =?
 for / L %% x in (1,1,9) do for / L %% y in (1,1,9) do set rfield %% x %% y =? 
In general, for helps in solving a large number of tasks. You can read more by running cmd.exe -> for /?

Now you need to put down the bombs on the field. To do this, use the variable% random% (contains a decimal number between 0 and 32767) and the extension string. Details: cmd.exe -> set /? ..
  set / a bx =% random: ~ -2%
 set bx =% bx: ~ 0.1% 
Explanations:
1. set / a is used to use a variable as a number and perform arithmetic operations (again, read cmd.exe -> set /?)
2.% random: ~ -2% - a number between 0 and 99
3.% bx: ~ 0.1% - the first digit of the resulting nonsense.

Now we are trying to create a new bomb (and add a unit to the bomb counter) using the call command, i.e. call another procedure and pass it two parameters: the content of the variable and the name of the variable (the variable is part of the array). By the way, the contents of a variable can only be obtained using the call command (example: call: procedure %% variable% counter1 %% counter2 %%%). By the way, REM is a comment in bat files.
  : genbomb
 call: newbomb %% rfield% r1 %% r2 %%% rfield% r1 %% r2%
 REM Check on the number of bombs.  If equal to the maximum, then exit the procedure.
 if "% bombs%" == "% maxbombs%" goto: eof

 : newbomb
 if not "% 1" == "X" (
	 set% 2 = X
	 set / a bombs =% bombs% + 1
	 )
 REM goto: eof is a quick return from the procedure.
 goto: eof 
You also need to call the procedure: genbomb from the initialization cycle (that is, when starting a new game) using call.

Now we need to put down the numbers in all cells that are not filled with bombs. Using the for loop, we call a special procedure, which passes four parameters. In this procedure, we simply count the number of bombs standing nearby. It should be noted that there are 8 neighbors for point (4; 4), and only three for point (1; 1).
  for / L %% x in (1,1,9) do for / L %% y in (1,1,9) do call: dosumfield %% x %% y %% rfield %% x %% y %% rfield %% x %% y

 : dosumfield
 REM If there is something in the cell (bomb), then we exit.
 if not "% 3" == "?"  goto: eof
 REM Set the coordinates of the first neighboring cell.
 set / a x1 =% 1 - 1 
 set / a y1 =% 2 + 1

 REM ..... Skipping the code .....

 set sum = 0
 REM If the coordinates of the first point enter the array, then call the procedure to increase the number of bombs
 if% 1 GTR 1 if% 2 LSS 9 call: newsum %% rfield% x1 %% y1 %%%

 REM ..... Skipping the code .....

 : newsum
 if "% 1" == "X" set / a sum + = 1
 goto: eof 


So, we have a field, now we need to withdraw it. Again, you need to use a for loop (well, if you’re bored, you can manually prescribe everything). By the way, a new feature of the call command is used here: the first argument is to enter another command (echo, set). And so no need to create single-line procedures.
  for / L %% y in (1,1,9) do call set line %% y =: %% y: %% mfield %% y1 %% %% mfield %% y2 %% %% mfield %% y3% % %% mfield %% y4 %% %% mfield %% y5 %% %% mfield %% y6 %% %% mfield %% y7 %% %% mfield %% y8 %%% mfield %% y9 %%: %% y:
 REM All cells that do not have neighbors bombs do not display
 for / L %% y in (1,1,9) do call set line %% y = %% line %% y: 0 = %%
 echo% line0%
 echo: ---------------------------------:
 for / L %% y in (1,1,9) do call echo %% line %% y %%
 echo: ---------------------------------:
 echo% line0% 


Now we will try to count user commands. The first character is the command, the second and third is the coordinate. Just in case, remove all spaces. In order to exclude batch-injection (execution of extraneous commands using text input) or just the death of a batch file, we work with only three characters. You also need to check whether the last two characters are numbers.
  REM Enter the magic string in the input, in case the user closes input.
 set input = 0 00
 set / p "input = Input:"
 set input =% input: =%
 REM The first letter is a necessary action.
 set action =% input: ~ 0.1%

 REM Example Action
 if "% action%" == "h" (
	 cls
	 REM Call the help (call) and go to the game loop (goto)
	 call: help
	 goto: gamecycle
	 )

 REM If the first character is not a command, then tell something to the user.
 if not "% action%" == "q" if not "% action%" == "h" if not "% action%" == "o" if not "% action%" == "f" if not "% action%" == "n" call: errorIO2
 REM If the second and third characters are not coordinates, then we set them equal to zero. 
 set ix = 0
 set iy = 0
 for / L %% a in (1,1,9) do if "%% a" == "% input: ~ 1.1%" set ix = %% a
 for / L %% a in (1,1,9) do if "%% a" == "% input: ~ 2.1%" set iy = %% a
 REM If the second / third character is not a coordinate, then we will display a message (call) for it and proceed to the game cycle.
 if "% ix%" == "0" (
	 call: errorIO1
	 goto: gamecycle
	 )
 if "% iy%" == "0" (
	 call: errorIO1
	 goto: gamecycle
	 )
 REM Next come the commands requiring the correct coordinates


Now it remains to paint how to open the field cells. In the sapper there is one feature: if there are 0 bombs next to the cell, then open the adjacent cells (not diagonally). Those. must use recursion.
 REM If the user command - open the cell, then run the special.  procedure with parameters: coordinates, cell value in a real field, cell value in a visible field.
 if "% action%" == "o" (
	 call: openpoint% ix%% iy% %% rfield% ix %% iy %%% %% mfield% ix %% iy %%%
	 goto: gamecycle
	 )
 REM ..... Skipping a lot of code .....

 : openpoint
 REM If the cell is not empty - we tell the user a lot of interesting things; if there is a bomb in the cell, it is already too late to tell something.
 if not "% 4" == "?"  (
	 echo Point x =% 1 y =% 2 already opened
	 pause> nul
	 goto: eof
	 )
 if "% 3" == "X" (
	 REM Set the die variable to one, and then draw conclusions. 
	 set die = 1
	 for / L %% x in (1,1,9) do for / L %% y in (1,1,9) do call set mfield %% x %% y = %% rfield %% x %% y% %
	 goto: eof
	 )
 REM And if neither one nor the other, then try to open this and nearby cells.
 call: oaf% 1% 2% 3% 4
 goto: eof 

 REM And that's exactly the recursive function.
 : oaf
 REM If the cell is empty (out of the field) or there is a bomb in it - we leave here.
 if "% 3" == "" goto: eof
 if "% 3" == "X" goto: eof
 REM Open this cell
 call set mfield% 1% 2 = %% rfield% 1% 2 %%
 REM If there are 0 bombs in this cell, then we try to open all nearby cells.
 if not "% 3" == "0" goto: eof

 REM xn, yn - coordinates of the next cell.  The diagonal is not checked.
 set / a xn =% 1
 set / a yn =% 2 + 1
 REM Check whether this cell is open in a visible field.
 set dooaf = 0
 call: checkoaf %% mfield% xn %% yn %%%
 REM If not (doaf == 1), then we call ourselves, but with different coordinates.
 if% dooaf% == 1 call: oaf% xn%% yn% %% rfield% xn %% yn %%% %% mfield% xn %% yn %%%

 REM ..... Still a lot of code .....
 goto: eof 


All we have left two interesting things - setting flags and checking whether the user won. The first is not interesting, except that it is worth noting that the procedure should ensure the installation and removal of the flag from the field by one team.

User won in two cases:
User did not win in one of three cases:
The last two options are defined as:
  REM We count the number of correctly set flags and not open cells.
 set nopoints = 0
 set rflags = 0
 for / L %% x in (1,1,9) do for / L %% y in (1,1,9) do call: checkfo %% mfield %% x %% y %% %% rfield %% x %% y %%
 REM ..... There is a lot of code .....
 : checkfo
 if "% 1" == "?"  set / a nopoints + = 1
 if "% 1" == "!"  if "% 2" == "X" set / a rflags + = 1
 goto: eof
After working out such a procedure in the variable nopoints will contain the number of empty flags, and rflags - the number of correctly placed flags.

Naturally, I wrote not all the code, but only part of it. The code itself can be viewed here: Google Docs, html or here: Plain Text

PS : If there are questions - why so, and not otherwise - ask, I will answer. I, unfortunately, not every line painted, but only necessary (in my opinion). If you do not understand something - ask questions. Also apologize for my english and variable / procedure names.
PPS : Jabber on batch file to support laziness, so I abandoned him :-)

UPD1 : Corrections:
UPD2 : Corrections:
UPD3 : Corrections:

Source: https://habr.com/ru/post/75649/


All Articles