Win32 SDK Gui编程系列之--自动机(Automation)

33 篇文章 1 订阅
32 篇文章 1 订阅
本文介绍了如何使用C语言在Windows环境下实现一维细胞自动机,包括规则30、90和110的示例代码,展示了如何初始化、计算和绘制细胞状态。
摘要由CSDN通过智能技术生成

自动机(Automation)

        一维细胞自动机 作为Windows编程的一个简单例子,下面展示了一个一维细胞自动机程序。 ca1d.c

// 一维细胞自动机:
// 在时刻t的内部状态(左,中央,右)111 110 101 100 011 010 001 000
// 在时刻t+1的中央细胞的内部状态 0 1 1 0 0 1 1 0
#include <windows.h>

#define WND_CLASS_NAME TEXT("Cell Automaton")
#define IMAX 300 // 行方向(Y轴)
#define JMAX 300 // 列方向(X轴)
int cell[IMAX][JMAX];
int rule[] = { 0, 1, 1, 0, 0, 1, 1, 0 }; // 从低位开始

void paint(HWND hwnd){
    PAINTSTRUCT ps;
    HDC hdc = BeginPaint(hwnd, &ps);
    int i, j;
    for (i = 0; i < IMAX; i++){
        for (j = 0; j < JMAX; j++){
            if (cell[i][j] == 1) {
            SetPixel(hdc, j, i, RGB(0,0,0));
        } // 在坐标(i,j)画一个1x1的正方形
        }
    }
    EndPaint(hwnd, &ps);
}

void init() {
    int i, j;
    // 初始化
    for (j = 0; j < JMAX; j++) {
        cell[0][j] = rand() % 2;
    }

// 计算
for (i = 1; i < IMAX; i++){ // 第1行~第(IMAX-1)行
    for (j = 0; j < JMAX; j++){ // 第0列~第(JMAX-1)列
        int length = JMAX;
        int before = i - 1; // 前一行
            
        // 确定两边
        int l = (j + length - 1) % length; // left
        int c = j; // center
        int r = (j + 1) % length; // right
            
        // 计算代码 code = 0 ~ 7
        int code = cell[before][l] * 4
                 + cell[before][c] * 2
                 + cell[before][r] * 1;
        // 设置细胞状态
        cell[i][j] = rule[code];
        }
    }
}

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WM_CREATE:
    init();
    break;
case WM_DESTROY:
    PostQuitMessage(0);
    break;
case WM_PAINT:
    paint(hwnd);
    break;
default:
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
HWND hWnd;
WNDCLASS wcl;

wcl.hInstance = hInstance;
wcl.lpszClassName = WND_CLASS_NAME;
wcl.lpfnWndProc = WindowProc;
wcl.style = 0;
wcl.hIcon = NULL;
wcl.hCursor = LoadCursor(NULL, IDC_ARROW);
wcl.lpszMenuName = NULL;
wcl.cbClsExtra = 0;
wcl.cbWndExtra = 0;
wcl.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
 
if (!RegisterClass(&wcl)) return FALSE;
 
hWnd = CreateWindow(
    WND_CLASS_NAME, // LPCTSTR lpClassName 注册的类名
    TEXT("一维细胞自动机"), // LPCTSTR lpWindowName 窗口名
    WS_OVERLAPPEDWINDOW|WS_VISIBLE, // DWORD dwStyle 窗口样式
    20, 20, // int x, y 窗口的横向、纵向位置
    305, 325, // int nWidth, nHeight 窗口的宽度、高度
    NULL, // HWND hWndParent 父窗口或所有者窗口的句柄
    NULL, // HMENU hMenu 菜单句柄或子标识符
    hInstance, // HINSTANCE hInstance 应用程序实例的句柄
    NULL); // LPVOID lpParam 窗口创建数据
if(!hWnd) return FALSE;
 
MSG msg;
while (GetMessage(&msg,NULL,0,0) > 0){
    TranslateMessage(&msg);
    DispatchMessage(&msg);
}
return msg.wParam;
}

此程序的执行结果如下图所示。

使用winlib库后,可以将ca1d.c改写如下。创建窗口时,类名和窗口名是相同的,所以用SetWindowText函数来设置窗口名。
ca1d2.c

// 一维细胞自动机:
// 时刻t的内部状态(左,中心,右)    111 110 101 100 011 010 001 000
// 时刻t+1的中心细胞的内部状态      0   1   1   0   0   1   1   0
// tcc ca1d2.c ../lib/winlib.o

#include <windows.h>

HWND crWindow(HINSTANCE, LPSTR, WNDPROC, int, int, int, int);

#define IMAX  300    // 行方向(Y轴)
#define JMAX  300    // 列方向(X轴)
int cell[IMAX][JMAX];
int rule[] = { 0, 1, 1, 0, 0, 1, 1, 0 }; // 从低位开始

void paint(HWND hwnd){
    PAINTSTRUCT ps;
    HDC hdc = BeginPaint(hwnd, &ps);
    int i, j;
    for (i = 0; i < IMAX; i++){
        for (j = 0; j < JMAX; j++){
            if (cell[i][j] == 1) {
        SetPixel(hdc, j, i, RGB(0,0,0));
            } // 在坐标(i,j)处画一个左上角为1,1的正方形
        }
    }
    EndPaint(hwnd, &ps);
}

void init() {
    int i, j;
    // 初始化
    for (j = 0; j < JMAX; j++) {
        cell[0][j] = rand() % 2;
    }

    // 计算
    for (i = 1; i < IMAX; i++){     // 第1行~第(IMAX-1)行
        for (j = 0; j < JMAX; j++){ // 第0列~第(JMAX-1)列
            int length = JMAX;
            int before = i - 1; // 上一行
                
            // 确定两侧
            int l = (j + length - 1) % length;    // left
            int c = j;                // center
            int r = (j + 1) % length;        // right
                
            // 计算代码 code = 0 ~ 7
            int code = cell[before][l] * 4
                     + cell[before][c] * 2
                     + cell[before][r] * 1;
            // 设置细胞状态
            cell[i][j] = rule[code];
        }
    }
}

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    switch (uMsg) {
    case WM_CREATE:
    init();
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    case WM_PAINT:
        paint(hwnd);
        break;
    default:
        return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }
    return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
    HWND hWnd = crWindow(hInstance, TEXT("Cell Automaton"), WindowProc, 20, 20, 305, 325);
    if (!hWnd) return FALSE;
    SetWindowText(hWnd, TEXT("一维细胞自动机"));
    return msgLoop();
}

同样,以下展示了被称为规则30、90、110的著名一维细胞自动机程序及其执行结果。

rule30.c

/** 一维细胞自动机:规则 30
 *  在时刻t的内部状态(左,中央,右)	111 110	101 100	011 010	001 000
 *  时刻t+1中央细胞的内部状态	         0   0	 0   1	 1   1	 1   0
 *  二进制的(0001 1110)在十进制中为30,因此称为规则30。
 */

#include <windows.h>

HWND crWindow(HINSTANCE, LPSTR, WNDPROC, int, int, int, int);

#define IMAX  200	// 行方向(Y轴)
#define JMAX  200    // 列方向(X轴)
int cell[IMAX][JMAX];
int rule[] = { 0, 1, 1, 1, 1, 0, 0, 0 }; // 从低位开始

void paint(HWND hwnd){
    PAINTSTRUCT ps;
    HDC hdc = BeginPaint(hwnd, &ps);
    int i, j;
    for (i = 0; i < IMAX; i++){
        for (j = 0; j < JMAX; j++){
            if (cell[i][j] == 1) {
		SetPixel(hdc, j, i, RGB(0,0,0));
            } // 在坐标(i,j)处画一个左上角为1x1的正方形
        }
    }
    EndPaint(hwnd, &ps);
}

void init() {
    int i, j;
    // 初始化
    cell[0][JMAX/2] = 1; // 仅第0行中间为1        

    // 计算
    for (i = 1; i < IMAX; i++){		// 第1行~第(IMAX-1)行
        for (j = 0; j < JMAX; j++){	// 第0列~第(JMAX-1)列
            int length = JMAX;
            int before = i - 1;	// 上一行
                
            // 确定两侧
            int l = (j + length - 1) % length;	// left
            int c = j;				// center
            int r = (j + 1) % length;		// right
                
            // 计算代码 code = 0 ~ 7
            int code = cell[before][l] * 4
                     + cell[before][c] * 2
                     + cell[before][r] * 1;
            // 设置细胞状态
            cell[i][j] = rule[code];
        }
    }
}

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    switch (uMsg) {
    case WM_CREATE:  init();  		 break;
    case WM_DESTROY: PostQuitMessage(0); break;
    case WM_PAINT:   paint(hwnd);        break;
    default: return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }
    return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
    HWND hWnd = crWindow(hInstance, TEXT("Rule30"), WindowProc, 20, 20, 205, 225);
    if (!hWnd) return FALSE;
    return msgLoop();
}

rule90.c

/** 一维细胞自动机:规则 90
 *  时刻t的内部状态(左,中,右)	111 110	101 100	011 010	001 000
 *  时刻t+1的中央细胞的内部状态	 0   1	 0   1	 1   0	 1   0
 *  二进制的(0101 1010)转换为十进制等于90,因此称为规则90。
 */

#include <windows.h>

HWND crWindow(HINSTANCE, LPSTR, WNDPROC, int, int, int, int);

#define IMAX  200	// 行方向(Y轴)
#define JMAX  200    // 列方向(X轴)
int cell[IMAX][JMAX];
int rule[] = { 0, 1, 0, 1, 1, 0, 1, 0 }; // 从低位开始

void paint(HWND hwnd){
    PAINTSTRUCT ps;
    HDC hdc = BeginPaint(hwnd, &ps);
    int i, j;
    for (i = 0; i < IMAX; i++){
        for (j = 0; j < JMAX; j++){
            if (cell[i][j] == 1) {
		SetPixel(hdc, j, i, RGB(0,0,0));
            } // 在坐标(i,j)处绘制一个1x1的正方形
        }
    }
    EndPaint(hwnd, &ps);
}

void init() {
    int i, j;
    // 初始化
    cell[0][JMAX/2] = 1; // 仅第0行中间为1        

    // 计算
    for (i = 1; i < IMAX; i++){		// 第1行~第(IMAX-1)行
        for (j = 0; j < JMAX; j++){	// 第0列~第(JMAX-1)列
            int length = JMAX;
            int before = i - 1;	// 上一行
                
            // 确定左右两侧
            int l = (j + length - 1) % length;	// left
            int c = j;				// center
            int r = (j + 1) % length;		// right
                
            // 计算代码 code = 0 ~ 7
            int code = cell[before][l] * 4
                     + cell[before][c] * 2
                     + cell[before][r] * 1;
            // 设置细胞状态
            cell[i][j] = rule[code];
        }
    }
}

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    switch (uMsg) {
    case WM_CREATE:  init();  		 break;
    case WM_DESTROY: PostQuitMessage(0); break;
    case WM_PAINT:   paint(hwnd);        break;
    default: return  DefWindowProc(hwnd, uMsg, wParam, lParam);
    }
    return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
    HWND hWnd = crWindow(hInstance, TEXT("Rule90"), WindowProc, 20, 20, 205, 225);
    if (!hWnd) return FALSE;
    return msgLoop();
}

rule110.c

/** 一维细胞自动机:规则 110
 *  在时刻t的内部状态(左,中心,右) 111 110 101 100 011 010 001 000
 *  在时刻t+1的中心单元的内部状态      0   1   1   0   1   1   1   0
 *  二进制的(01101110)转换为十进制等于110,因此称之为规则110。
 */

#include <windows.h>

HWND crWindow(HINSTANCE, LPSTR, WNDPROC, int, int, int, int);

#define IMAX  200    // 行方向(Y轴)
#define JMAX  200    // 列方向(X轴)
int cell[IMAX][JMAX];
int rule[] = { 0, 1, 1, 0, 1, 1, 1, 0 }; // 从低位开始

void paint(HWND hwnd){
    PAINTSTRUCT ps;
    HDC hdc = BeginPaint(hwnd, &ps);
    int i, j;
    for (i = 0; i < IMAX; i++){
        for (j = 0; j < JMAX; j++){
            if (cell[i][j] == 1) {
        SetPixel(hdc, j, i, RGB(0,0,0));
            } // 在坐标(i,j)处画一个左上角为1x1的正方形
        }
    }
    EndPaint(hwnd, &ps);
}

void init() {
    int i, j;
    // 初始化
    cell[0][JMAX/2] = 1; // 仅第0行的中心为1        

    // 计算
    for (i = 1; i < IMAX; i++){     // 第1行~第(IMAX-1)行
        for (j = 0; j < JMAX; j++){ // 第0列~第(JMAX-1)列
            int length = JMAX;
            int before = i - 1; // 上一行
                
            // 确定两侧
            int l = (j + length - 1) % length; // left
            int c = j;                         // center
            int r = (j + 1) % length;          // right
                
            // 计算代码 code = 0 ~ 7
            int code = cell[before][l] * 4
                     + cell[before][c] * 2
                     + cell[before][r] * 1;
            // 设置单元状态
            cell[i][j] = rule[code];
        }
    }
}

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    switch (uMsg) {
    case WM_CREATE:  init();         break;
    case WM_DESTROY: PostQuitMessage(0); break;
    case WM_PAINT:   paint(hwnd);        break;
    default: return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }
    return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
    HWND hWnd = crWindow(hInstance, TEXT("Rule110"), WindowProc, 20, 20, 205, 225);
    if (!hWnd) return FALSE;
    return msgLoop();
}

通过菜单选择规则 前一节提到的程序算法相同,只是数据不同,因此非常容易统一。下面展示了程序和执行示例。

cellautomata.c

/** 一维细胞自动机:规则110的情况
 *  时间t时的内部状态(左,中央,右)	111 110	101 100  011 010 001 000
 *  时间t+1时中央的细胞的内部状态	 0   1	 1   1	  0   1	  1   0
 *  二进制的(0110 1110)转换为十进制后为110,因此称之为规则110。
 */

#include <windows.h>

HWND crWindow(HINSTANCE, LPSTR, WNDPROC, int, int, int, int);

#define IMAX  200	// 行方向(Y轴)
#define JMAX  200    // 列方向(X轴)
int cell[IMAX][JMAX];
int rules[4][8] = {
    { 0, 1, 1, 0,  0, 1, 1, 0 },	// 规则102
    { 0, 1, 1, 1,  1, 0, 0, 0 },	// 规则30
    { 0, 1, 0, 1,  1, 0, 1, 0 },	// 规则90
    { 0, 1, 1, 1,  0, 1, 1, 0 } 	// 规则110
};
char *name[] = { "规则102", "规则30", "规则90", "规则110" };
int nRule = 0;

void paint(HWND hwnd){
    PAINTSTRUCT ps;
    HDC hdc = BeginPaint(hwnd, &ps);
    int i, j;
    char buf[128];

    wsprintf(buf, "%s", name[nRule]);
    SetWindowText(hwnd, buf);

    // 初始化
    cell[0][JMAX/2] = 1; // 第0行的中央设为1        

    // 计算
    for (i = 1; i < IMAX; i++){		// 第1行~第(IMAX-1)行
        for (j = 0; j < JMAX; j++){	// 第0列~第(JMAX-1)列
            int length = JMAX;
            int before = i - 1;	// 前一行
                
            // 确定两侧
            int l = (j + length - 1) % length;	// left
            int c = j;				// center
            int r = (j + 1) % length;		// right
                
            // 计算代码 code = 0 ~ 7
            int code = cell[before][l] * 4
                     + cell[before][c] * 2
                     + cell[before][r] * 1;
            // 设置细胞状态
            cell[i][j] = rules[nRule][code];
        }
    }
    for (i = 0; i < IMAX; i++){
        for (j = 0; j < JMAX; j++){
            if (cell[i][j] == 1) {
		SetPixel(hdc, j, i, RGB(0,0,0));
            } // 在坐标(i,j)处绘制一个左上角为1x1大小的正方形
        }
    }
    EndPaint(hwnd, &ps);
}

void init(HWND hWnd) {
    HMENU hMenu = CreateMenu();
    HMENU hSubMenu = CreatePopupMenu();
    int i;
    for (i = 0; i < 4; i++)
        AppendMenu(hSubMenu, MFT_STRING, i, name[i]);
    AppendMenu(hMenu, MF_POPUP | MFT_STRING, (UINT)hSubMenu, "规则");
    SetMenu(hWnd, hMenu);
}

void command(HWND hWnd, UINT cmd) {
    nRule = cmd;
    InvalidateRect(hWnd, NULL, TRUE);
    UpdateWindow(hWnd);
}

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    switch (uMsg) {
    case WM_CREATE:  init(hwnd);	    break;
    case WM_COMMAND: command(hwnd, wParam); break;
    case WM_DESTROY: PostQuitMessage(0);    break;
    case WM_PAINT:   paint(hwnd);           break;
    default: return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }
    return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
    HWND hWnd = crWindow(hInstance, TEXT("Cell Automaton"), WindowProc, 20, 20, 210, 250);
    if (!hWnd) return FALSE;
    return msgLoop();
}

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值