目录
一、创作灵感
在看完卡片中的视频后,想到了使用C语言对高斯的蚂蚁随机游走问题,因为是简单的模拟,所以只有5只蚂蚁(想尝试多只蚂蚁的uu直接在代码定义常量的地方改蚂蚁的数量就可以了)。
bilibili_随机漫步,高斯手中的蚂蚁_科技3D视界https://www.bilibili.com/video/BV1g94y1p7ry
二、背景与要求
(一)背景要求
- 每只蚂蚁每次只能移动一格。
- 每只蚂蚁每次只能向一个方向(x轴或y轴方向)移动,即不能对角运动。
- 每只蚂蚁每秒钟只移动一次。
- 蚂蚁不会出现跳出所属系的行为,比如不会通过第三维度从二维坐标系中跳出。
- 蚂蚁没有智力。
- 蚂蚁之间不会交流。
(二)题目要求
- 用户可以选择一维模拟或二维模拟。
- 坐标轴x轴用`-`表示,y轴用`|`表示,坐标原点用`+`表示。
- 蚂蚁用`*`表示。
- 当坐标轴上有蚂蚁时,优先在这个位置显示蚂蚁而不是坐标轴。
- 当有两只及以上蚂蚁堆叠(即在同一位置)时, 请用不同颜色的`*`表示。
(三)本代码
- 询问用户需要模拟一维还是二维。
- 输出界面进行了美化。
- 一只蚂蚁时是白色`*`,两只是黄色`*`,三只是绿色`*`,四只是紫色`*`,五只及以上是红色`*`,输出过程中的文字说明与边框是青色。
- 模拟大小:一维:1*21;二维:21*21 。
三、主要思路与代码
注:作者使用的软件是VS2017。
(一)随机数生成
首先需要调用一下文件头:
#include <stdlib.h>
然后运用以下代码生成随机数:
srand(time(NULL)); // 初始化随机数种子
int random_num = rand(); // 生成随机数
这样就能够保证运动的随机性。
(二)一维运动的处理
既然我们生成了随机数,而且课题是随机游走,那么我们肯定是使用生成的随机数来处理蚂蚁的运动,而一维下蚂蚁只可能向左或向右运动,那么我们不妨将随机数对2取余得到0或1:
random_num %= 2;//对2取模得到0或1
这样我们就把随机数变成了0或1的数字了,那么为了方便记忆,我们不妨假设1是向x轴正方向运动,那么0自然而然就是向负方向运动了。
我们还需要对蚂蚁原来的位置与将到达的位置进行处理,避免输出错误。比如蚂蚁向正方向运动,那我们就应该有:
if (X[i]==10)
Map[0][X[i]] = '+';
else if ((X[i] >= 0) && (X[i] <= 20))
Map[0][X[i]] = '-';
X[i]++;
if ((X[i] >= 0) && (X[i] <= 20))
Map[0][X[i]] = '*';
负方向就是把`++`改为`--`就行了。按顺序输出就行了。
(三)二维运动的处理
首先我们知道蚂蚁一次只能往一个方向运动,那么我们不妨用刚刚用随机数确定蚂蚁在一维坐标轴正负方向运动的方法来得到蚂蚁该次运动是在x轴运动还是在y轴运动(代码重复就不再作展示了)。
在确定完蚂蚁的运动矢量方向后,我们就把蚂蚁的运动转化成了一个一维运动,重复一维的步骤即可。
此外需要注意的是,一维坐标轴没有空格,而二维坐标系就有有空格的区域了,这一点很容易导致出错。
(四)输出颜色
以一维输出为例:
if (Map[0][i]=='*')//如果这个位置有蚂蚁
switch (Num[0][i])//这是记录各个位置蚂蚁数量的二维数组
{
case 1://一只蚂蚁就正常白色
printf_s("\033[0m%c\033[0m", Map[0][i]);
break;
case 2://两只蚂蚁堆叠用黄色表示
printf_s("\033[33m%c\033[0m", Map[0][i]);
break;
case 3://三只蚂蚁堆叠用绿色表示
printf_s("\033[32m%c\033[0m", Map[0][i]);
break;
case 4://四只蚂蚁堆叠用紫色表示
printf_s("\033[35m%c\033[0m", Map[0][i]);
break;
default://五只及以上蚂蚁堆叠用红色表示
printf_s("\033[31m%c\033[0m", Map[0][i]);
break;
//不用考虑0是因为0就表示没有蚂蚁,就不符合第一行if的条件了
}
常见的几种颜色输出:
printf("\033[0m");//白色
printf("\033[31m");//红色
printf("\033[32m");//绿色
printf("\033[33m");//黄色
printf("\033[34m");//蓝色
printf("\033[35m");//紫色
printf("\033[36m");//青色
//注意:
//什么颜色指的是在这之后输出的内容都是以这种颜色输出
//之前已经输出的内容不受影响
//颜色代码自生不会被输出
(五)unistd.h代码 与运用
unistd.h文件代码如下;
#ifndef _UNISTD_H #define _UNISTD_H #include <io.h> #include <process.h> #endif
使用需要先调用:
#include <Windows.h>
#include "unistd.h"
然后就能够使用Sleep()函数实现延时功能了:
Sleep(1000);
注意,Windows环境下该函数单位是ms,比如上述代码就是等待1s后再运行。
四、完整代码
下载传送门(免费):C语言简单模拟高斯的蚂蚁:随机游走问题(图形化)
以下是完整代码:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <Windows.h>
#include <time.h>
#include "unistd.h"
#define NumberOfAnts 5//定义蚂蚁数量的常量
///想要尝试其他数量蚂蚁的可以自行修改这里的数字
char Map[21][21];//储存地图数据
int Num[21][21];//储存各个位置有多少蚂蚁
void Print(char chMap[21][21],int Dime);
/*将结果输出到屏幕上*/
void Calculate_1(int X[NumberOfAnts]);
void Calculate_2(int X[NumberOfAnts],int Y[NumberOfAnts]);
int main(void)
{
int Ant_X[NumberOfAnts];
int Ant_Y[NumberOfAnts];
/*定义蚂蚁的x、y变量并将其放在坐标轴中央*/
int Dimension = 0;//用户需要输入的维度
for (int i = 0; i < NumberOfAnts; i++)
Ant_X[i] = Ant_Y[i] = 10;
for (int i = 0; i < 21; i++)
for (int j = 0; j < 21; j++)
{
Map[i][j] = ' ';//初始化
Num[i][j] = 0;
}
WrongInputToBack://如果输入错误,则跳回到这里
printf_s("\033[35m>\033[32mPlease input the dimension you want to imitate:\033[0m");
scanf_s("%d", &Dimension);//提示用户输入需要模拟的维度
switch (Dimension)
{
case 1:
{//一位坐标轴模拟
do {
Calculate_1(Ant_X);
Sleep(1000);
} while (1);
break;
}
case 2:
{//二位坐标系模拟
do {
Calculate_2(Ant_X, Ant_Y);
Sleep(1000);
} while (1);
break;
}
default:
printf_s("\033[35m>\033[31mYour input is not allowed!Please input 1 or 2.\033[0m\n");
goto WrongInputToBack;
}
return 0;
}
void Print(char chMap[21][21], int Dime)
{/*将结果输出到屏幕上*/
switch (Dime)
{
case 1:
printf_s("\033[36m\t\t\t\t\t\t\t\t\t\t\t\t ┃\n\033[0m");
for (int i = 0; i < 21; i++)
{
if ((Map[0][i] == '-') || (Map[0][i] == '>') || (Map[0][i] == '+'))
printf_s("%c", Map[0][i]);
if (Map[0][i]=='*')
switch (Num[0][i])
{
case 1://一只蚂蚁就正常白色
printf_s("\033[0m%c\033[0m", Map[0][i]);
break;
case 2://两只蚂蚁堆叠用黄色表示
printf_s("\033[33m%c\033[0m", Map[0][i]);
break;
case 3://三只蚂蚁堆叠用绿色表示
printf_s("\033[32m%c\033[0m", Map[0][i]);
break;
case 4://四只蚂蚁堆叠用紫色表示
printf_s("\033[35m%c\033[0m", Map[0][i]);
break;
default://五只及以上蚂蚁堆叠用红色表示
printf_s("\033[31m%c\033[0m", Map[0][i]);
break;
}
}
printf_s("\t\033[0m*\033[36m:1 ant \t\033[33m*\033[36m:2 ants\t\033[32m*\033[36m:3 ants\t\033[35m*\033[36m:4 ants\t\033[31m*\033[36m:5+ ants ┃");
printf_s("\n\033[36m\t\t\t\t\t\t\t\t\t\t\t\t ┃\n");
printf_s("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫\n\033[0m");
//一维输出到这里结束
break;
case 2:
printf_s("\033[36m\t\t\t\t\t\t\t┃\n\033[0m");
for (int i = 0; i < 21; i++)
{
for (int j = 0; j < 21; j++)
{
if ((Map[i][j] == '-') || (Map[i][j] == '>') || (Map[i][j] == '+') || (Map[i][j] == '|') || (Map[i][j] == ' ') || (Map[i][j] == '^'))
printf_s("%c", Map[i][j]);
if (Map[i][j] == '*')
switch (Num[i][j])
{
case 1://一只蚂蚁就正常白色
printf_s("\033[0m%c\033[0m", Map[i][j]);
break;
case 2://两只蚂蚁堆叠用黄色表示
printf_s("\033[33m%c\033[0m", Map[i][j]);
break;
case 3://三只蚂蚁堆叠用绿色表示
printf_s("\033[32m%c\033[0m", Map[i][j]);
break;
case 4://四只蚂蚁堆叠用紫色表示
printf_s("\033[35m%c\033[0m", Map[i][j]);
break;
default://五只及以上蚂蚁堆叠用红色表示
printf_s("\033[31m%c\033[0m", Map[i][j]);
break;
}
}
if (i >= 0 && i <= 4)
{
switch (i)
{
case 0:
printf_s("\t\t\033[0m*\033[36m:1 ant \033[36m\t\t┃\n\033[0m");
break;
case 1:
printf_s("\t\t\033[33m*\033[36m:2 ants\033[36m\t\t┃\n\033[0m");
break;
case 2:
printf_s("\t\t\033[32m*\033[36m:3 ants\033[36m\t\t┃\n\033[0m");
break;
case 3:
printf_s("\t\t\033[35m*\033[36m:4 ants\033[36m\t\t┃\n\033[0m");
break;
case 4:
printf_s("\t\t\033[31m*\033[36m:5+ ants\033[36m\t\t┃\n\033[0m");
break;
}
}
else printf_s("\t\t\t\t\t\033[36m┃\n\033[0m");
}
printf_s("\033[36m\t\t\t\t\t\t\t┃\n");
printf_s("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫\n\033[0m");
break;
}
for (int i=0;i<21;i++)
for (int j = 0; j < 21; j++)
{
Map[i][j] = ' ';
Num[i][j] = 0;
}//每次运行都进行初始化,否则会出问题
return;
}
void Calculate_1(int X[NumberOfAnts])
{/*对一维模拟的运算*/
srand(time(NULL)); // 初始化随机数种子
int random_num = rand(); // 生成随机数
for (int i = 0; i < NumberOfAnts; i++)
{
random_num = rand();
random_num %= 2;//对2取模得到0或1
if (random_num == 1)//1则向右走
{
if (X[i]==10)
Map[0][X[i]] = '+';
else if ((X[i] >= 0) && (X[i] <= 20)) Map[0][X[i]] = '-';
X[i]++;
if ((X[i] >= 0) && (X[i] <= 20)) Map[0][X[i]] = '*';
}
else
{//0则向左走
if (X[i] == 10)
Map[0][X[i]] = '+';
else if ((X[i] >= 0) && (X[i] <= 20))Map[0][X[i]] = '-';
X[i]--;
if ((X[i] >= 0) && (X[i] <= 20)) Map[0][X[i]] = '*';
}
}//以上完成了5只蚂蚁的一位模拟
//接下来将一维坐标轴的各位记录统计
for (int i = 0; i < NumberOfAnts; i++)
if ((X[i] >= 0) && (X[i] <= 20))
Num[0][X[i]]++;
for (int i = 0; i < 21; i++)
if (Map[0][i] == ' ')
Map[0][i] = '-';
Map[0][20] = '>';
if (Map[0][10] != '*') Map[0][10] = '+';
Print(Map, 1);//调用函数进行输出
return;
}
void Calculate_2(int X[NumberOfAnts], int Y[NumberOfAnts])
{/*对二维模拟的运算*/
srand(time(NULL)); // 初始化随机数种子
int random_num = rand(); // 生成随机数
for (int i = 0; i < NumberOfAnts; i++)
{
random_num = rand();
random_num %= 2;//得到0或1
switch (random_num)
{
case 0://如果得到0,则在y轴方向移动
{
random_num = rand(); // 生成随机数
random_num %= 2;//得到0或1
/*再次生成随机数以确定向上还是向下*/
switch (random_num)
{
case 1://1则向上运动
{
if ((Y[i] == 10) && (X[i] == 10))
{
Map[Y[i]][X[i]] = '+';
}//注意第一维度是y轴,第二维度是x轴
else if (X[i]==10 && Y[i]>=0 && Y[i]<=10) Map[Y[i]][X[i]] = '|';
else if ((X[i] >= 0) && (X[i] <= 20) && (Y[i] >= 0) && (Y[i] <= 20)) Map[Y[i]][X[i]] = ' ';
Y[i]++;
if ((X[i] >= 0) && (X[i] <= 20) && (Y[i] >= 0) && (Y[i] <= 20)) Map[Y[i]][X[i]] = '*';
break;
}
case 0://0则向下运动
{
if ((Y[i] == 10) && (X[i] == 10))
{
Map[Y[i]][X[i]] = '+';
}//注意第一维度是y轴,第二维度是x轴
else if (X[i] == 10 && Y[i] >= 0 && Y[i] <= 10) Map[Y[i]][X[i]] = '|';
else if ((X[i] >= 0) && (X[i] <= 20) && (Y[i] >= 0) && (Y[i] <= 20)) Map[Y[i]][X[i]] = ' ';
Y[i]--;
if ((X[i] >= 0) && (X[i] <= 20) && (Y[i] >= 0) && (Y[i] <= 20)) Map[Y[i]][X[i]] = '*';
break;
}
}
break;
}
case 1://如果得到1,则在x轴方向移动
{
random_num = rand(); // 生成随机数
random_num %= 2;//得到0或1
/*再次生成随机数以确定向右还是向左*/
switch (random_num)
{
case 1://1则向右运动
{
if ((Y[i] == 10) && (X[i] == 10))
{
Map[Y[i]][X[i]] = '+';
}//注意第一维度是y轴,第二维度是x轴
else if (Y[i] == 10 && X[i] >= 0 && X[i] <= 10) Map[Y[i]][X[i]] = '-';
else if ((X[i] >= 0) && (X[i] <= 20) && (Y[i] >= 0) && (Y[i] <= 20)) Map[Y[i]][X[i]] = ' ';
X[i]++;
if ((X[i] >= 0) && (X[i] <= 20) && (Y[i] >= 0) && (Y[i] <= 20)) Map[Y[i]][X[i]] = '*';
break;
}
case 0://0则向左运动
{
if ((Y[i] == 10) && (X[i] == 10))
{
Map[Y[i]][X[i]] = '+';
}//注意第一维度是y轴,第二维度是x轴
else if (Y[i] == 10 && X[i] >= 0 && X[i] <= 10) Map[Y[i]][X[i]] = '-';
else if ((X[i] >= 0) && (X[i] <= 20) && (Y[i] >= 0) && (Y[i] <= 20)) Map[Y[i]][X[i]] = ' ';
X[i]--;
if ((X[i] >= 0) && (X[i] <= 20) && (Y[i] >= 0) && (Y[i] <= 20)) Map[Y[i]][X[i]] = '*';
break;
}
}
break;
}
}
}
//以上完成了5只蚂蚁的移动模拟
//接下来统计与写入
for (int i = 0; i < NumberOfAnts; i++)
if ((X[i] >= 0) && (X[i] <= 20) && (Y[i] >= 0) && (Y[i] <= 20))
Num[Y[i]][X[i]]++;
for (int i = 0; i < 21; i++)
{
if (Map[10][i] == ' ')
Map[10][i] = '-';
if (Map[i][10] == ' ')
Map[i][10] = '|';
}
Map[10][20] = '>';
Map[0][10] = '^';
if (Map[10][10] != '*') Map[10][10] = '+';
Print(Map, 2);//调用函数进行输出
return;
}
五、运行结果展示
提示用户输入所需维数并在输入错误时提醒作者错误与重新输入
(一)一维模拟
(二)二维模拟
Tips:当我们把蚂蚁数量增多、坐标系扩大,将会发现有趣的现象~