C/C++——元胞自动机&万花筒

程序功能

实现一个简单的元胞自动机,可以自定义初始状态、运行规则。以此基础实现一个能自动绘制大量万花筒图像的程序。
注:为了防止二维数组输出时画面闪烁,采取双屏幕缓冲区轮流显示。将缓冲区写好后一次性输出可以防止数组循环输出方式会导致的画面闪烁。

效果

生命游戏中的“滑翔机(gliders)”:
生命游戏
万花筒:
万花筒

代码
#include <windows.h>
#include <stdlib.h>
#include <conio.h>
#include <string>
#include <time.h>
#include <math.h>
#include <iostream>
#define BLACK 0
#define WHITE 15
#define GREEN 10
#define YELLOW 14
#define RED 12
#define BLUE 9
#define CYAN 11
#define PURPLE 13
#define INCI(x) (((x)+1)%(COL))
#define DECI(x) (((x)+COL-1)%(COL))
#define INCJ(x) (((x)+1)%(RAW))
#define DECJ(x) (((x)+RAW-1)%(RAW))
#define MODE "mode 82,42"
#define COL 41
#define RAW 41
using namespace std;
int ct=0;
HANDLE hOutput, hOutBuf;//控制台屏幕缓冲区句柄
COORD coord={0,0};
WORD att;
DWORD bytes=0;
char data[COL][RAW];
int clr[8]={BLACK,WHITE,GREEN,YELLOW,RED,BLUE,CYAN,PURPLE};
int a[COL][RAW]={0},b[COL][RAW]={0};
unsigned int counts=0;
char str[11];
void f0()//规则0:空心万花筒
{
	int i,j,k;
	memset(b,0,sizeof(b));
	for(i=0;i<COL;i++)
		for(j=0;j<RAW;j++)
		{
			k=a[i][j];
			b[(i+rand()%3-1)%COL][(j+rand()%3-1)%RAW]+=k;
			b[(i+rand()%3-1)%COL][(j+rand()%3-1)%RAW]+=k;
		}
	for(i=0;i<COL;i++)
		for(j=0;j<RAW;j++)
		{
			a[i][j]=b[i][j]%8;
		}
}
void f1()//规则1:万花筒
{
	int i,j,k;
	memset(b,0,sizeof(b));
	for(i=0;i<COL;i++)
		for(j=0;j<RAW;j++)
		{
			k=a[i][j];
			//b[i][j]+=k;
			b[DECI(i)][j]+=k;
			b[INCI(i)][j]+=k;
			b[i][DECJ(j)]+=k;
			b[i][INCJ(j)]+=k;
		}
	for(i=0;i<COL;i++)
		for(j=0;j<RAW;j++)
		{
			a[i][j]=b[i][j]%8;
		}
}
void f2p()//滑翔机初始化
{
	a[1][5]=1;
	a[2][5]=1;
	a[1][6]=1;
	a[2][6]=1;
	a[11][5]=1;
	a[11][6]=1;
	a[11][7]=1;
	a[12][4]=1;
	a[12][8]=1;
	a[13][3]=1;
	a[13][9]=1;
	a[14][3]=1;
	a[14][9]=1;
	a[15][6]=1;
	a[16][4]=1;
	a[16][8]=1;
	a[17][5]=1;
	a[17][6]=1;
	a[17][7]=1;
	a[18][6]=1;
	a[21][3]=1;
	a[21][4]=1;
	a[21][5]=1;
	a[22][3]=1;
	a[22][4]=1;
	a[22][5]=1;
	a[23][2]=1;
	a[23][6]=1;
	a[25][1]=1;
	a[25][2]=1;
	a[25][6]=1;
	a[25][7]=1;
	a[35][3]=1;
	a[35][4]=1;
	a[36][3]=1;
	a[36][4]=1;
}
void f2()//规则2:生命游戏
{
	int i,j,k;
	memset(b,0,sizeof(b));
	for(i=0;i<COL;i++)
		for(j=0;j<RAW;j++)
		{
			k=0;
			if(a[DECI(i)][j])k++;
			if(a[INCI(i)][j])k++;
			if(a[i][DECJ(j)])k++;
			if(a[i][INCJ(j)])k++;
			if(a[DECI(i)][DECJ(j)])k++;
			if(a[DECI(i)][INCJ(j)])k++;
			if(a[INCI(i)][DECJ(j)])k++;
			if(a[INCI(i)][INCJ(j)])k++;
			if(k==3)b[i][j]=1;
			else if(k==2)b[i][j]=a[i][j];
			else b[i][j]=0;
		}
	for(i=0;i<COL;i++)
		for(j=0;j<RAW;j++)
		{
			a[i][j]=b[i][j];
		}
}
void show()//显示
{
    int i,j;
    for(i=0;i<COL;i++)
    {
        for(j=0;j<RAW;j++)
        {
        	coord.X=2*i;
			coord.Y=j;
			att=clr[a[i][j]];
            if(a[i][j])
			{
				WriteConsoleOutputCharacterA(hOutBuf,"■",2,coord,&bytes);
			}
			else WriteConsoleOutputCharacterA(hOutBuf,"  ",2,coord,&bytes);
        	WriteConsoleOutputAttribute(hOutBuf,&att,1,coord,&bytes);
        	coord.X++;
			WriteConsoleOutputAttribute(hOutBuf,&att,1,coord,&bytes);
		}
    }
    itoa(counts,str,10);
    coord.X=0;coord.Y=41;
    WriteConsoleOutputCharacterA(hOutBuf,str,sizeof(str),coord,&bytes);
    att=WHITE;
    WriteConsoleOutputAttribute(hOutBuf,&att,1,coord,&bytes);
    SetConsoleActiveScreenBuffer(hOutBuf);
    f1();//规则替换处
    //Sleep(50);
    getch();//任意键继续
    counts++;
    for(i=0;i<COL;i++)
    {
        for(j=0;j<RAW;j++)
        {
        	coord.X=2*i;
			coord.Y=j;
			att=clr[a[i][j]];
            if(a[i][j])
			{
				WriteConsoleOutputCharacterA(hOutput,"■",2,coord,&bytes);
			}
			else WriteConsoleOutputCharacterA(hOutput,"  ",2,coord,&bytes);
        	WriteConsoleOutputAttribute(hOutput,&att,1,coord,&bytes);
        	coord.X++;
			WriteConsoleOutputAttribute(hOutput,&att,1,coord,&bytes);
		}
    }
    itoa(counts,str,10);
    coord.X=0;coord.Y=41;
    WriteConsoleOutputCharacterA(hOutput,str,sizeof(str),coord,&bytes);
    att=WHITE;
    WriteConsoleOutputAttribute(hOutput,&att,1,coord,&bytes);
    SetConsoleActiveScreenBuffer(hOutput);
    f1();//规则替换处
    //Sleep(50);
    getch();counts++;
}
int main()
{
	srand(time(NULL));
	system(MODE);
    hOutBuf = CreateConsoleScreenBuffer(
        GENERIC_WRITE,
        FILE_SHARE_WRITE,
        NULL,
        CONSOLE_TEXTMODE_BUFFER,
        NULL
    );
    hOutput = CreateConsoleScreenBuffer(
        GENERIC_WRITE,
        FILE_SHARE_WRITE,
        NULL,
        CONSOLE_TEXTMODE_BUFFER,
        NULL
    );
    CONSOLE_CURSOR_INFO cci;
    cci.bVisible = 0;
    cci.dwSize = 1;
    SetConsoleCursorInfo(hOutput, &cci);
    SetConsoleCursorInfo(hOutBuf, &cci);
    a[COL/2][RAW/2]=1;
    //a[rand()%COL][rand()%RAW]=1;
	//f2p();
    while(1)show();
}

图片

一些比较好看的:
图片

  • 8
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
元胞自动机(Cellular Automaton)是由细胞(Cell)组成的网格,并且每个细胞可以根据一定的规则进行状态的转变。这个概念最早由物理学家冯·诺依曼(John von Neumann)于1950年提出。元胞自动机的代码一般用来描述每个细胞的状态及其更新规则。 在C语言中,我们可以使用二维数组来表示元胞自动机的网格。具体代码如下所示: ```c #include <stdio.h> // 定义元胞自动机网格大小 #define WIDTH 10 #define HEIGHT 10 // 定义元胞的状态 #define ALIVE 1 #define DEAD 0 // 定义元胞自动机网格 int grid[WIDTH][HEIGHT] = {0}; // 更新元胞状态的函数 void updateGrid() { int newGrid[WIDTH][HEIGHT] = {0}; // 用来存储更新后的状态 // 遍历每个细胞 for (int i = 0; i < WIDTH; i++) { for (int j = 0; j < HEIGHT; j++) { int aliveNeighbors = 0; // 存储活着的邻居数量 // 统计该细胞周围8个邻居的状态 for (int x = -1; x <= 1; x++) { for (int y = -1; y <= 1; y++) { if (x == 0 && y == 0) continue; // 不统计自己 int neighborX = (i + x + WIDTH) % WIDTH; // 处理边界情况 int neighborY = (j + y + HEIGHT) % HEIGHT; // 处理边界情况 aliveNeighbors += grid[neighborX][neighborY]; } } // 根据规则更新细胞状态 if (grid[i][j] == ALIVE) { if (aliveNeighbors < 2 || aliveNeighbors > 3) { newGrid[i][j] = DEAD; } else { newGrid[i][j] = ALIVE; } } else { if (aliveNeighbors == 3) { newGrid[i][j] = ALIVE; } } } } // 将更新后的状态复制给原网格 for (int i = 0; i < WIDTH; i++) { for (int j = 0; j < HEIGHT; j++) { grid[i][j] = newGrid[i][j]; } } } // 打印元胞自动机网格的函数 void printGrid() { for (int i = 0; i < WIDTH; i++) { for (int j = 0; j < HEIGHT; j++) { printf("%c ", grid[i][j] == ALIVE ? '*' : ' '); } printf("\n"); } } int main() { // 设置初始状态 grid[2][1] = ALIVE; grid[2][2] = ALIVE; grid[2][3] = ALIVE; // 打印初始状态 printGrid(); printf("----------\n"); // 更新状态并打印每一代的状态 for (int generation = 1; generation < 6; generation++) { updateGrid(); printf("Generation %d:\n", generation); printGrid(); printf("----------\n"); } return 0; } ``` 以上是一个简单的元胞自动机代码示例,在初始状态下,网格中的3个细胞会根据规则进行状态的更新。程序会输出每一代的状态,总共输出5代。你可以根据需要修改网格的大小、初始状态以及更新规则,体验元胞自动机的魅力。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值