Guión del juego Buscaminas (demostración del guión del juego)

1. Introducción

Buscaminas es un juego de Windows muy conocido y ampliamente entretenido como un juego clásico. Entonces, ¿es posible crear un pequeño programa que elimine minas y niveles automáticamente a la velocidad de la luz? La respuesta es sí. Incluso puede llegar al punto de ser invencible. Primero, la imagen de arriba establece el récord en -8 segundos, por lo que nadie puede romper este récord.

2. Método de implementación

1. Implementar lógica

1 ) Cree un proyecto vacío WIN32 ;

2 ) Abra el proceso del buscaminas y obtenga los valores de filas y columnas de acuerdo con la dirección de memoria de las filas y columnas del campo minado;

3 ) Leer los datos del campo minado de acuerdo con la primera dirección del campo minado y el alcance del campo minado;

4 ) Coloque la interfaz del juego Buscaminas en la parte superior, lea el valor en la fila i y la columna j del campo minado y determine si es una mina. Si no, simule una operación de clic izquierdo del mouse. Si es una mina, simular una operación de clic derecho del mouse.

5 ) De acuerdo con el sistema de coordenadas del cliente de la interfaz del juego Buscaminas, calcule la posición de las coordenadas de la i-ésima fila y la j-ésima columna, luego mueva el mouse a esta posición y realice la operación del mouse en el paso 3 .

6 ) Repita 3-4 hasta que se escaneen todos los datos del campo minado.

2. API relacionadas

La función API de Windows utilizada para leer y escribir el contenido de la dirección de memoria es:

BOOL ReadProcessMemory(HANDLE hProcess, LPCVOID lpBaseAddress, LPVOID lpBuffer, TAMAÑO_T nTamaño, TAMAÑO_T *lpNumberOfBytesRead);

BOOL WriteProcessMemory( HANDLE hProcess, LPVOID lpBaseAddress, LPCVOID lpBuffer, TAMAÑO_T nTamaño, TAMAÑO_T *lpNumberOfBytesWritten);

La función API de memoria de lectura y escritura requiere el identificador del proceso de destino como parámetro, para ello es necesario llamar a OpenProcess para obtener el identificador del proceso:

HANDLE OpenProcess(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId);

OpenProcess requiere el ID del proceso como parámetro, que se puede obtener mediante la función GetWindowThreadProcessId .

El numero es:

DWORD GetWindowThreadProcessId(HWND hWnd, LPDWORD lpdwProcessId);

La función GetWindowThreadProcessId requiere el identificador de la ventana como parámetro, que se puede obtener a través de FindWindow . Los dos parámetros de la clase de ventana y el nombre del título de la ventana utilizados por esta función API se obtuvieron a través de Spy++ en el paso 7 .

HWND FindWindowA(LPCSTR lpClassName, LPCSTR lpWindowName);

La función API para simular las operaciones del mouse es mouse_event . El método de uso específico es usar la función API SetCursorPos para mover el mouse a la posición especificada y luego simular la presión del mouse y las operaciones emergentes.

La función se declara de la siguiente manera:

void mouse_event(DWORD dwFlags, DWORD dx, DWORD dy, DWORD dwData, ULONG_PTR dwExtraInfo);

BOOL SetCursorPos(int X, int Y);

En este experimento, la función mouse_event solo necesita configurar el primer parámetro, que incluye específicamente presionar con el botón izquierdo y la ventana emergente ( MOUSEEVENTF_LEFTDOWN , MOUSEEVENTF_LEFTUP ), presionar con el botón derecho y la ventana emergente ( MOUSEEVENTF_RIGHTDOWN , MOUSEEVENTF_RIGHTUP ). 

La función API para colocar una interfaz de programa GUI en la parte superior es:

BOOL SetForegroundWindow(HWND hWnd);

3. Implementación del guión

Determinar el tamaño de la cuadrícula del juego Buscaminas.

Abra Spy++ , haga clic en " Monitor - Registrar mensaje " , marque " Ocultar opciones de Spy++ " y arrastre la " Herramienta de búsqueda de programa " a la interfaz principal del juego Buscaminas, como se muestra en la Figura 8-4 . El contenido mostrado incluye el Buscaminas. nombre de la clase de ventana ( WNDCLASS ) y nombre del título.

Cambie a la ventana " Mensaje " de Spy++ , primero borre todos los mensajes y luego verifique los dos mensajes "WM_LBUTTONDOWN y WM_LBUTTONUP" , como se muestra en la Figura 8-5 . Haga clic en Aceptar para regresar a la interfaz principal de Spy++ .

Regrese a la interfaz del juego Buscaminas, haga clic en las tres cuadrículas en la esquina superior izquierda, inmediatamente a la derecha de la esquina superior izquierda e inmediatamente debajo de la esquina superior izquierda. Verifique los valores xPos e yPos registrados por Spy++ cuando el mouse se hace clic y calcula el ancho y la suma de cada cuadrícula.

Las coordenadas del primer campo minado son:

xPos =14

yPos =58

En la interfaz de Spy++, haga clic con el botón derecho en Borrar registro de mensajes y luego repita la operación anterior. También puede hacer clic en varias cuadrículas para calcular el valor promedio de cada cuadrícula como el valor de ancho y alto de cada cuadrícula. El ancho de la cuadrícula es: 16 ; la altura de la cuadrícula es: 16 .

#include <windows.h>

int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
    const char* text = "扫雷";
    HWND hwnd = FindWindow(text, text);
    if (hwnd == NULL)
    {
        MessageBox(NULL, TEXT("Winmine is not found!"), TEXT("AutoMineSweeper"), MB_ICONSTOP);
        return 1;
    }

    DWORD pid;
    GetWindowThreadProcessId(hwnd, &pid);
    HANDLE handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);

    int width, height;
    width = -1;
    height = -1;
    ReadProcessMemory(handle, (LPVOID)0x01005334, &width, 4, NULL);
    ReadProcessMemory(handle, (LPVOID)0x01005338, &height, 4, NULL);

    /*BYTE **data;
    data=(BYTE**)malloc(32 * height * sizeof(BYTE));*/
    //BYTE data[] = new BYTE(32 * height);
    BYTE data[32*32] = { 0 };
    ReadProcessMemory(handle, (LPVOID)0x01005361, &data, 32 * height, NULL);
    
    ShowWindow(hwnd, SW_RESTORE);
    SetForegroundWindow(hwnd);
    Sleep(300);

    int width_num = 32;
    int x_pos = 14;		//雷区首个格子的位置
    int y_pos = 58;

    RECT rc;
BOOL bRet = GetClientRect(hwnd, &rc);
//更改扫雷时间,将其设置为-8
int time = -8;
   	WriteProcessMemory(handle, (LPVOID)0x0100579C, &time, 4, NULL);

    for (int y = 1; y <= height; y++)
    {
        for (int x = 1; x <= width; x++)
        {
            UINT downMsg = x_pos, upMsg = y_pos;
            if (data[width_num * (x - 1) + (y - 1)] == 0x10)
                break;
            else
            {
                if (data[(x - 1) + width_num * (y - 1)] == 0x0F)
                {
                    downMsg = MOUSEEVENTF_LEFTDOWN;
                    upMsg = MOUSEEVENTF_LEFTUP;
                }
                else
                {
                    downMsg = MOUSEEVENTF_RIGHTDOWN;
                    upMsg = MOUSEEVENTF_RIGHTUP;
                }
            }
            POINT curPos = { rc.left + x_pos + (x - 1) * 16, rc.top + y_pos + (y - 1) * 16 };
            ClientToScreen(hwnd, &curPos);
            SetCursorPos(curPos.x, curPos.y);
            mouse_event(downMsg, 0, 0, 0, 0);
            mouse_event(upMsg, 0, 0, 0, 0);
            Sleep(1);

        }
    }
    CloseHandle(handle);
    return 0;
}

Supongo que te gusta

Origin blog.csdn.net/HUANGliang_/article/details/127354969
Recomendado
Clasificación