标题: [特效代码] 我也发个批处理贪吃蛇玩玩 [打印本页]
作者: lltlo 时间: 2022-8-11 20:05 标题: 我也发个批处理贪吃蛇玩玩
界面比较简陋,不太想优化了,主要是验证下批处理下的按键检测、光标定位、控制、Sleep等功能。
本来想再做个人机对战五子棋的,现在没啥闲工夫,等空了再说。
发贴有限制,脚本分两部分发,直接复制合并到一起就行。
上下左右方向键控制方向:- :batch_start
- @echo off
- setlocal
- setlocal ENABLEDELAYEDEXPANSION
-
- rem 必须执行的步骤,初始化c#辅助程序
- call :init_cursor_control
-
- rem 脚本加在下面位置,其他地方不要动
- ::>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
-
- :game_start
-
- for /F %%a in ('echo prompt $E^| cmd') do set "_ESC=%%a"
-
- set Wall_Max_X=50
- set Wall_Max_Y=30
- set /a Wall_Position_Max_X=%Wall_Max_X% - 1
- set /a Wall_Position_Max_Y=%Wall_Max_Y% - 1
-
- set "Char_BlankSpace= "
- set "Char_Return=&echo;"
-
- rem 0最快,数字越大越慢,设置为9时1秒一步,依次累推
- set Snake_Move_Speed=0
- set Enable_Write_Debug_log=1
- set "Char_Wall=#"
- set "Wall_Str="
- set "Snake_Body=O"
- set "Snake_Head=*"
- set "Snake_Tail=."
- set "Snake_Init_Len=10"
- set "Snake_Str="
- set "Snake_Direction=up"
- set "Snake_Head_X=0"
- set "Snake_Head_Y=0"
- set "Char_Food=F"
- set "Food_X=0"
- set "Food_Y=0"
- set /a Snake_Move_Sleep_Time=%Snake_Move_Speed%*100
-
- call :set_cursor_visiable 0
- set /a WindowLines=%Wall_Max_Y% + 1
- mode con: cols=%Wall_Max_X% lines=%WindowLines%
-
- for /l %%l in (1,1,%Wall_Max_Y%) do (
- if %%l equ 1 (
- for /l %%c in (1,1,%Wall_Max_X%) do set Wall_Str=!Wall_Str!!Char_Wall!
- ) else if %%l equ %Wall_Max_Y% (
- set Wall_Str=!Wall_Str!!Char_Return!
- for /l %%c in (1,1,%Wall_Max_X%) do set Wall_Str=!Wall_Str!!Char_Wall!
- ) else (
- set Wall_Str=!Wall_Str!!Char_Return!
- set Wall_Str=!Wall_Str!!Char_Wall!
- set /a BlankCount=%Wall_Max_X% - 2
- for /l %%c in (1,1,!BlankCount!) do set Wall_Str=!Wall_Str!!Char_BlankSpace!
- set Wall_Str=!Wall_Str!!Char_Wall!
- )
- )
-
- echo %Wall_Str%
-
- set /a Snake_Init_X = (%Wall_Max_X% - 2) / 2
- set /a Snake_Init_Y = (%Wall_Max_Y% - 2 - %Snake_Init_Len%) / 2
- set /a Snake_End_Y = %Snake_Init_Y% + %Snake_Init_Len% - 1
- set /a Snake_Head_X = %Snake_Init_X%
- set /a Snake_Head_Y = %Snake_Init_Y%
- for /l %%l in (!Snake_Init_Y!,1,!Snake_End_Y!) do (
- call :set_cursor_position !Snake_Init_X! %%l
- if %%l equ !Snake_Init_Y! (
- echo !Snake_Head!
- ) else if %%l equ !Snake_End_Y! (
- echo !Snake_Tail!
- ) else (
- echo !Snake_Body!
- )
- call :add_position_to_snake_str_tail !Snake_Init_X! %%l
- )
-
- call :random_gen_food
-
- :snake_loop
-
- call :sleep_until_key_press %Snake_Move_Sleep_Time% pressed_key
-
- if "%pressed_key%" equ "UpArrow" (if "%Snake_Direction%" neq "down" set Snake_Direction=up)
- if "%pressed_key%" equ "DownArrow" (if "%Snake_Direction%" neq "up" set Snake_Direction=down)
- if "%pressed_key%" equ "LeftArrow" (if "%Snake_Direction%" neq "right" set Snake_Direction=left)
- if "%pressed_key%" equ "RightArrow" (if "%Snake_Direction%" neq "left" set Snake_Direction=right)
-
- set /a snake_last_head_x = %Snake_Head_X%
- set /a snake_last_head_y = %Snake_Head_Y%
-
- if "%Snake_Direction%" equ "up" set /a Snake_Head_Y = %Snake_Head_Y% - 1
- if "%Snake_Direction%" equ "down" set /a Snake_Head_Y = %Snake_Head_Y% + 1
- if "%Snake_Direction%" equ "left" set /a Snake_Head_X = %Snake_Head_X% - 1
- if "%Snake_Direction%" equ "right" set /a Snake_Head_X = %Snake_Head_X% + 1
-
- call :get_snake_tail_position snake_tail_x snake_tail_y
-
- call :check_position_in_snake %Snake_Head_X% %Snake_Head_Y% in_snake
- if %snake_tail_x% equ %Snake_Head_X% (
- if %snake_tail_y% equ %Snake_Head_Y% (
- set in_snake=0
- )
- )
- if %in_snake% equ 1 (
- call :show_game_over
- pause >nul
- goto :game_start
- )
-
- set snake_in_wall=0
- if %Snake_Head_X% equ 0 set snake_in_wall=1
- if %Snake_Head_X% equ %Wall_Position_Max_X% set snake_in_wall=1
- if %Snake_Head_Y% equ 0 set snake_in_wall=1
- if %Snake_Head_Y% equ %Wall_Position_Max_Y% set snake_in_wall=1
- if %snake_in_wall% equ 1 (
- call :show_game_over
- pause >nul
- goto :game_start
- )
-
- set /a food_in_snake=0
- if %Snake_Head_X% equ %Food_X% (
- if %Snake_Head_Y% equ %Food_Y% (
- set /a food_in_snake=1
- )
- )
- if %food_in_snake% equ 0 (
- call :snake_tail_ahead
- )
-
- call :set_cursor_position %snake_last_head_x% %snake_last_head_y% & echo %Snake_Body%
- call :set_cursor_position %Snake_Head_X% %Snake_Head_Y% & echo %Snake_Head%
- ::call :write_log before add Snake_Str=%Snake_Str%
- call :add_position_to_snake_str_head %Snake_Head_X% %Snake_Head_Y%
- ::call :write_log after add Snake_Str=%Snake_Str%
-
- if %food_in_snake% equ 1 (
- call :random_gen_food
- )
-
- goto :snake_loop
-
-
- :show_game_over
- set /a x = (%Wall_Max_X% - 2 - 5) / 2
- set /a y = (%Wall_Max_Y% - 2) / 2
- call :set_cursor_position %x% %y%
- echo Game Over
- goto :eof
-
- :snake_tail_ahead
- call :get_snake_tail_position snake_tail_x snake_tail_y
- call :set_cursor_position %snake_tail_x% %snake_tail_y% & echo.%Char_BlankSpace%
- ::call :write_log before del Snake_Str=%Snake_Str%
- call :del_position_from_snake_str %snake_tail_x% %snake_tail_y%
- ::call :write_log after del Snake_Str=%Snake_Str%
-
- call :get_snake_tail_position snake_tail_x snake_tail_y
- call :set_cursor_position %snake_tail_x% %snake_tail_y% & echo.%Snake_Tail%
- goto :eof
-
- :random_gen_food
- set /a Food_X = 1 + (%RANDOM% %% (%Wall_Max_X% - 2))
- set /a Food_Y = 1 + (%RANDOM% %% (%Wall_Max_Y% - 2))
- call :check_position_in_snake %Food_X% %Food_Y% in_snake
- if %in_snake% equ 1 (goto :random_gen_food)
- call :set_cursor_position %Food_X% %Food_Y% & echo %Char_Food%
- goto :eof
-
- :sleep_until_key_press
- call :bat_helper_with_output sleeputilkeypress %~1
- for /f "tokens=1* delims=,;" %%a in ("%bat_helper_output%") do (
- set %~2=%%a
- )
- goto :eof
-
- :check_position_in_snake
- call :get_position_string %~1 %~2 position_string
- echo %Snake_Str% | findstr /C:%position_string% >nul
- if %errorlevel% equ 0 (set %~3=1) else (set %~3=0)
- goto :eof
-
- :get_position_string
- set _x=%~1
- set _y=%~2
- if %_x% lss 10 (set _x=0%_x%)
- if %_y% lss 10 (set _y=0%_y%)
- set %~3=[%_x%,%_y%]
- goto :eof
-
- :get_position_from_string
- for /f "tokens=1,2 delims=,[]" %%a in ("%~1") do (
- set x=%%a
- set y=%%b
- if "!x:~0,1!" equ "0" (set /a %~2=!x:~1,1!) else (set /a %~2=!x!)
- if "!y:~0,1!" equ "0" (set /a %~3=!y:~1,1!) else (set /a %~3=!y!)
- )
- goto :eof
-
- :get_snake_tail_position
- set snake_tail_position_str=%Snake_Str:~-7%
- call :get_position_from_string "%snake_tail_position_str%" %~1 %~2
- goto :eof
-
- :add_position_to_snake_str_head
- call :get_position_string %~1 %~2 position_string
- set Snake_Str=!position_string!!Snake_Str!
- goto :eof
-
- :add_position_to_snake_str_tail
- call :get_position_string %~1 %~2 position_string
- set Snake_Str=!Snake_Str!!position_string!
- goto :eof
-
- :del_position_from_snake_str
- call :get_position_string %~1 %~2 position_string
- set Snake_Str=!Snake_Str:%position_string%=!
- goto :eof
-
- :write_log
- if %Enable_Write_Debug_log% equ 0 goto :eof
- echo %date% %time% %* >> debug.log
- goto :eof
-
- rem 脚本加在上面位置,其他地方不要动
- ::<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
-
-
- rem 脚本最后退出位置,下面的代码不要更改
- :batch_end
- endlocal
- exit /b %errorlevel%
-
- rem 获取毫秒时间戳
- :gettimestamp
- call :bat_helper_with_output gettimestamp
- for /f "tokens=1 delims=" %%a in ("%bat_helper_output%") do (set %~1=%%a)
- goto :eof
-
- rem 获取光标是否可见
- :get_cursor_visiable
- call :bat_helper getcursorvisiable
- set /a return_code=%errorlevel%
- ::echo getcursorvisiable return_code=%errorlevel%
- if %return_code%==0 set /a %~1=0
- if %return_code%==1 set /a %~1=1
- goto :eof
-
- rem 设置光标是否可见
- :set_cursor_visiable
- call :bat_helper setcursorvisiable %~1
- ::echo setcursorvisiable return_code=%errorlevel%
- goto :eof
-
- rem 获取backspace回退键
- :get_back_space
- for /F %%a in ('"prompt $h & for %%b in (1) do rem"')do set "%~1=%%a"
- goto :eof
-
- rem 设置光标位置
- :set_cursor_position
- set /a x=%~2 + 1
- set /a y=%~1 + 1
- <nul set /p "=%_ESC%[!x!;!y!H"
- ::call :bat_helper setcursorposition %~1 %~2
- goto :eof
-
- rem 获取当前窗口光标位置以及窗口尺寸
- :get_cursor_info
- call :bat_helper_with_output getcursorposition
- for /f "tokens=1,2,3,4 delims=,;" %%a in ("%bat_helper_output%") do (set %~1=%%a & set %~2=%%b & set %~3=%%c & set %~4=%%d)
- goto :eof
-
- rem 调用helper程序,并且将helper程序输出保存到bat_helper_output,返回值保存到bat_helper_errorlevel
- :bat_helper_with_output
- set bat_helper_output= <nul
- for /f "delims=" %%i in ('%bat_helper_exe_file_path% %*') do (set bat_helper_errorlevel=%errorlevel% & set bat_helper_output=%%i & goto :eof)
- set bat_helper_errorlevel=%errorlevel%
- goto :eof
-
- rem 调用helper程序,helper程序输出直接到终端,返回值保存到bat_helper_errorlevel
- :bat_helper
- %bat_helper_exe_file_path% %*
- set bat_helper_errorlevel=%errorlevel%
- goto :eof
-
- rem 初始化c#辅助程序,如果未找到就进行编译
- :init_cursor_control
- :: find csc.exe
- set "csc="
- for /r "%SystemRoot%\Microsoft.NET\Framework\" %%# in ("*csc.exe") do set "csc=%%#"
- if not exist "%csc%" (
- echo no .net framework installed
- exit /b 10
- )
- set bat_helper_exe_file_path="%tmp%\bat_helper.exe"
- if not exist "%bat_helper_exe_file_path%" (
- call :gen_helper_csharp_source
- call %csc% /nologo /warn:0 /out:%bat_helper_exe_file_path% "%tmp%\bat_helper.cs" || (
- exit /b %errorlevel%
- )
- )
- goto :eof
-
- rem 从此脚本中获取c#源码
- :gen_helper_csharp_source
- for /f "tokens=1,2 delims=: " %%n in ('findstr /N /C:"helper_csharp_start" "%~dpsfnx0"') do (
- ::echo %%n "%%o"
- if "%%o"=="helper_csharp_start" (
- set /a helper_csharp_start_line=%%n+1
- ::echo helper_csharp_start_line=!helper_csharp_start_line!
- more +!helper_csharp_start_line! "%~dpsfnx0" > "%tmp%\bat_helper.cs"
- goto :eof
- )
- )
- goto :eof
复制代码
作者: lltlo 时间: 2022-8-11 20:06
第二部分,接到1楼后面就行。- rem c#辅助程序开始位置
- :helper_csharp_start
-
- using System;
- using System.Runtime.InteropServices;
- using System.Diagnostics;
- using System.IO;
- using System.Text;
-
- namespace bat_helper
- {
- class Program
- {
- [DllImport("kernel32.dll", SetLastError = true)]
- static extern IntPtr GetStdHandle(int nStdHandle);
-
- [DllImport("kernel32.dll", SetLastError = true)]
- static extern bool SetStdHandle(
- uint nStdHandle,
- IntPtr hHandle
- );
-
- [DllImport("kernel32.dll", SetLastError = true)]
- internal static extern bool SetConsoleCursorPosition(
- IntPtr hConsoleOutput,
- COORD dwCursorPosition);
-
- [DllImport("kernel32.dll", SetLastError = true)]
- static extern bool GetConsoleScreenBufferInfo(
- IntPtr hConsoleOutput,
- ref CONSOLE_SCREEN_BUFFER_INFO ConsoleScreenBufferInfo);
-
- [DllImport("kernel32.dll", SetLastError = true)]
- static extern uint GetLastError();
-
- [DllImport("kernel32.dll", SetLastError = true)]
- static extern bool GetConsoleCursorInfo(
- IntPtr hConsoleOutput,
- out CONSOLE_CURSOR_INFO lpConsoleCursorInfo
- );
-
- [DllImport("kernel32.dll", SetLastError = true)]
- static extern bool SetConsoleCursorInfo(
- IntPtr hConsoleOutput,
- [In] ref CONSOLE_CURSOR_INFO lpConsoleCursorInfo
- );
-
- [DllImport("kernel32.dll", SetLastError = true)]
- static extern bool AttachConsole(
- uint dwProcessId
- );
-
- [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
- static extern bool FreeConsole();
-
- public struct CONSOLE_CURSOR_INFO
- {
- public uint dwSize;
- public bool bVisible;
- }
-
- public struct COORD
- {
- public short X;
- public short Y;
- };
-
- public struct SMALL_RECT
- {
- public ushort Left;
- public ushort Top;
- public ushort Right;
- public ushort Bottom;
- };
-
- public struct CONSOLE_SCREEN_BUFFER_INFO
- {
- public COORD dwSize;
- public COORD dwCursorPosition;
- public ushort wAttributes;
- public SMALL_RECT srWindow;
- public COORD dwMaximumWindowSize;
- };
-
- const int STD_INPUT_HANDLE = -10;
- const int STD_OUTPUT_HANDLE = -11;
- const int STD_ERROR_HANDLE = -12;
-
- const uint STD_OUTPUT_HANDLE_uint = 0xFFFFFFF5;
-
- const uint ATTACH_PARENT_PROCESS = 0xffffffff;
-
- static public IntPtr m_pOriginalStdOutputHandle = IntPtr.Zero;
-
- static public void WriteLine(string strText)
- {
- // 先恢复成程序启动时的标准输出句柄,然后输出,再恢复后调用WriteLine时的标准输出句柄
- IntPtr pOriginalStdOutputHandle = GetStdHandle(STD_OUTPUT_HANDLE);
- SetStdHandle(STD_OUTPUT_HANDLE_uint, m_pOriginalStdOutputHandle);
- Console.WriteLine(strText);
- SetStdHandle(STD_OUTPUT_HANDLE_uint, pOriginalStdOutputHandle);
- return;
- }
-
- static int Main(string[] args)
- {
- try
- {
- // 先保存标准输出句柄,父进程重定向调用时,此句柄可能不是控制台,可能是文件或者其他什么句柄
- m_pOriginalStdOutputHandle = GetStdHandle(STD_OUTPUT_HANDLE);
-
- // 附加到父进程的Console,确保父进程重定向调用时,此程序也能获取到标准控制台输出
- FreeConsole();
- AttachConsole(ATTACH_PARENT_PROCESS);
-
- if (0 == args.Length)
- {
- return 87; // ERROR_INVALID_PARAMETER
- }
-
- if (args[0].ToLower() == "sleeputilkeypress")
- {
- if (args.Length < 2)
- {
- return 87; // ERROR_INVALID_PARAMETER
- }
- int iSleepTimeInMs = int.Parse(args[1]);
- long lStartTimeInMs = System.DateTime.Now.Ticks / 10000;
- while (true)
- {
- if (Console.KeyAvailable)
- {
- ConsoleKeyInfo key = Console.ReadKey(true);
- WriteLine(Convert.ToString(key.Key) + ";" + Convert.ToString(key.Modifiers));
- break;
- }
- long lCurrentTimeInMs = System.DateTime.Now.Ticks / 10000;
- long lDiffTimeInMs = lCurrentTimeInMs - lStartTimeInMs;
- if (lDiffTimeInMs >= iSleepTimeInMs)
- {
- break;
- }
- long lNeedSleepTime = iSleepTimeInMs - lDiffTimeInMs;
- if (lNeedSleepTime > 5)
- {
- lNeedSleepTime = 5;
- }
- System.Threading.Thread.Sleep(5);
- }
- return 0;
- }
- else if (args[0].ToLower() == "sleep")
- {
- if (args.Length < 2)
- {
- return 87; // ERROR_INVALID_PARAMETER
- }
- int iSleepTimeInMs = int.Parse(args[1]);
- System.Threading.Thread.Sleep(iSleepTimeInMs);
- return 0;
- }
- else if (args[0].ToLower() == "getcurrentdatetime")
- {
- WriteLine(System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff:ffffff"));
- return 0;
- }
- else if (args[0].ToLower() == "getcursorposition")
- {
- IntPtr iStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
- CONSOLE_SCREEN_BUFFER_INFO oCONSOLE_SCREEN_BUFFER_INFO = new CONSOLE_SCREEN_BUFFER_INFO();
- bool bRes = GetConsoleScreenBufferInfo(iStdOut, ref oCONSOLE_SCREEN_BUFFER_INFO);
- if (!bRes)
- {
- uint uiLastErrorCode = GetLastError();
- return (int)uiLastErrorCode;
- }
-
- WriteLine(Convert.ToString(oCONSOLE_SCREEN_BUFFER_INFO.dwCursorPosition.X)
- + "," + Convert.ToString(oCONSOLE_SCREEN_BUFFER_INFO.dwCursorPosition.Y)
- + ";" + Convert.ToString(oCONSOLE_SCREEN_BUFFER_INFO.dwMaximumWindowSize.X)
- + "," + Convert.ToString(oCONSOLE_SCREEN_BUFFER_INFO.dwMaximumWindowSize.Y));
-
- return 0;
- }
- else if (args[0].ToLower() == "setcursorposition")
- {
- if (args.Length < 3)
- {
- return 87; // ERROR_INVALID_PARAMETER
- }
- COORD oCursorPosition;
- oCursorPosition.X = short.Parse(args[1]);
- oCursorPosition.Y = short.Parse(args[2]);
- IntPtr iStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
- bool bRes = SetConsoleCursorPosition(iStdOut, oCursorPosition);
- if (!bRes)
- {
- uint uiLastErrorCode = GetLastError();
- return (int)uiLastErrorCode;
- }
- return 0;
- }
- else if (args[0].ToLower() == "getcursorvisiable")
- {
- CONSOLE_CURSOR_INFO oCONSOLE_CURSOR_INFO = new CONSOLE_CURSOR_INFO();
- IntPtr iStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
- bool bRes = GetConsoleCursorInfo(iStdOut, out oCONSOLE_CURSOR_INFO);
- if (!bRes)
- {
- uint uiLastErrorCode = GetLastError();
- return ((int)uiLastErrorCode + 100); // 返回值大于100,肯定就是失败
- }
- return (oCONSOLE_CURSOR_INFO.bVisible ? 1 : 0);
- }
- else if (args[0].ToLower() == "setcursorvisiable")
- {
- if (args.Length < 2)
- {
- return 87; // ERROR_INVALID_PARAMETER
- }
-
- CONSOLE_CURSOR_INFO oCONSOLE_CURSOR_INFO = new CONSOLE_CURSOR_INFO();
- IntPtr iStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
- bool bRes = GetConsoleCursorInfo(iStdOut, out oCONSOLE_CURSOR_INFO);
- if (!bRes)
- {
- uint uiLastErrorCode = GetLastError();
- return (int)uiLastErrorCode;
- }
-
- oCONSOLE_CURSOR_INFO.bVisible = (0 == short.Parse(args[1]) ? false : true);
- bRes = SetConsoleCursorInfo(iStdOut, ref oCONSOLE_CURSOR_INFO);
- if (!bRes)
- {
- uint uiLastErrorCode = GetLastError();
- return (int)uiLastErrorCode;
- }
-
- return 0;
- }
-
- return 87; // ERROR_INVALID_PARAMETER
- }
- catch (Exception ex)
- {
- WriteLine("exception: " + ex.ToString());
- return 87; // ERROR_INVALID_PARAMETER
- }
- }
- }
- }
复制代码
欢迎光临 批处理之家 (http://bbs.bathome.net/) |
Powered by Discuz! 7.2 |