之前在外面看到的一个大一学生学习 C 语言,学到二维数组和多维数组那块的一个课后作业。

要求是利用控制台的等宽字体模拟一个 5×75\times 75×7 的点阵字体(其实就是单片机用的那种液晶屏)并按照这种方式输出系统时间。

在这里插入图片描述

(图片来源网络,侵删)


Solution

纯模拟,算法层面完全没什么难的,但是调试非常考验耐心 👇

  • 如何对齐字符,如何保证输出不错乱都需要仔细调整;
  • 控制台窗口宽度不够,同样会导致输出混乱;
  • 打表 - 最枯燥的过程,没有之一。

参考实现

#if _MSVC_LANG
 #pragma warning(disable:4996)
#endif

#include<windows.h>
#include<time.h>
#include<stdio.h>

#if !__cplusplus
 #define constexpr const
 #define bool int
#endif
// 枚举10个数码
constexpr bool num[10][7][5] = {
	{ {0,1,1,1,0},{1,0,0,0,1},{1,0,0,1,1},{1,0,1,0,1},{1,1,0,0,1},{1,0,0,0,1},{0,1,1,1,0} },
	{ {0,0,1,0,0},{0,1,1,0,0},{0,0,1,0,0},{0,0,1,0,0},{0,0,1,0,0},{0,0,1,0,0},{0,1,1,1,0} },
	{ {0,1,1,1,0},{1,0,0,0,1},{0,0,0,0,1},{0,0,0,1,0},{0,0,1,0,0},{0,1,0,0,0},{1,1,1,1,1} },
	{ {0,1,1,1,0},{1,0,0,0,1},{0,0,0,0,1},{0,0,1,1,0},{0,0,0,0,1},{1,0,0,0,1},{0,1,1,1,0} },
	{ {0,0,0,1,0},{0,0,1,1,0},{0,1,0,1,0},{1,0,0,1,0},{1,1,1,1,1},{0,0,0,1,0},{0,0,0,1,0} },
	{ {1,1,1,1,1},{1,0,0,0,0},{1,1,1,1,0},{0,0,0,0,1},{0,0,0,0,1},{1,0,0,0,1},{0,1,1,1,0} },
	{ {0,0,1,1,0},{0,1,0,0,0},{1,0,0,0,0},{1,1,1,1,0},{1,0,0,0,1},{1,0,0,0,1},{0,1,1,1,0} },
	{ {1,1,1,1,1},{0,0,0,0,1},{0,0,0,1,0},{0,0,1,0,0},{0,1,0,0,0},{0,1,0,0,0},{0,1,0,0,0} },
	{ {0,1,1,1,0},{1,0,0,0,1},{1,0,0,0,1},{0,1,1,1,0},{1,0,0,0,1},{1,0,0,0,1},{0,1,1,1,0} },
	{ {0,1,1,1,0},{1,0,0,0,1},{1,0,0,0,1},{0,1,1,1,1},{0,0,0,0,1},{0,0,0,1,0},{0,1,1,0,0} } };

// 用bool数组表示六个时间数码以及两个冒号, 每两个字符之间有一个像素宽度的间隔, 因此6个数字加上两个冒号共8个字符有7个间隔, 需要一个7行47列的数组
bool time_display[7][48];

bool date_display[7][64];

// 每个数字的位置
constexpr int time_position[6] = { 0, 6, 18, 24, 36, 42 }, date_position[8] = { 0, 6, 12, 18, 30, 36, 48, 54 };

// 用中括号填充数字, xstart表示起始列(只可为0,6,18,24,36,42), number表示要填充的数字(-1表示冒号)
void insert_time(int xstart, int digit)
{
	for (int i = 0; i <= 6; i += 1) for (int j = xstart; j <= xstart + 4; j += 1) time_display[i][j] = num[digit][i][j - xstart];
}

void insert_date(int xstart, int digit)
{
	for (int i = 0; i <= 6; i += 1) for (int j = xstart; j <= xstart + 4; j += 1) date_display[i][j] = num[digit][i][j - xstart];
}

// 初始化操作
void init(void)
{
	// 插入冒号
	time_display[1][14] = time_display[5][14] = time_display[1][32] = time_display[5][32] = 1;
	date_display[6][26] = date_display[6][25] = date_display[5][26] = date_display[5][25] = 
		date_display[6][43] = date_display[6][44] = date_display[5][43] = date_display[5][44] = 1;
	// system("color ce");
}

// 获取时间填充数字
void input_time(void)
{
	time_t tp;
	time(&tp);
	tm* p = localtime(&tp);
	int digit[6] = { p->tm_hour / 10, p->tm_hour % 10, p->tm_min / 10, p->tm_min % 10, p->tm_sec / 10, p->tm_sec % 10 };
	int date[8] = { (p->tm_year + 1900) / 1000, ((p->tm_year + 1900) % 1000) / 100, ((p->tm_year + 1900) % 100) / 10, (p->tm_year + 1900) % 10,
		(p->tm_mon + 1) / 10, (p->tm_mon + 1) % 10, p->tm_mday / 10, p->tm_mday % 10 };
	for (int i = 0; i <= 5; i += 1) insert_time(time_position[i], digit[i]);
	for (int i = 0; i <= 7; i += 1) insert_date(date_position[i], date[i]);
}

// 输出与清屏
void print_time(void)
{
	system("cls");
	printf("\n");
	for (int i = 0; i <= 6; i += 1)
	{
		printf("    ");
		for (int j = 0; j <= 59; j += 1) printf(date_display[i][j] ?
#if _WIN32_WINNT == _WIN32_WINNT_WIN10 
			"\u2588\u2588"
#elif _WIN32_WINNT == _WIN32_WINNT_WIN7
			"\u2588"
#elif _WIN32_WINNT == _WIN32_WINNT_WINXP
			"[]"
#endif
			: "  ");
		putchar(10);
	}
	printf("\n\n");
	for (int i = 0; i <= 6; i += 1)
	{
		printf("    ");
		for (int j = 0; j <= 46; j += 1) printf(time_display[i][j] ? 
#if _WIN32_WINNT == _WIN32_WINNT_WIN10 
			"\u2588\u2588"
#elif _WIN32_WINNT == _WIN32_WINNT_WIN7
			"\u2588"
#elif _WIN32_WINNT == _WIN32_WINNT_WINXP
			"[]"
#endif
			: "  ");
		putchar(10);
	}
	Sleep(950);
}

int main()
{
	init();
	while (1)
	{
		input_time();
		print_time();
	}
}

输出结果(例子):

在这里插入图片描述

一些闲话

P.S. 2024~2025 年以前的 AI 做不到从零开始构建出无 bug 的程序,主要问题都出在不知道怎么把点阵数字输出在一行。

不知道现在的能否从头完成这个作业。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐