一.问题描述
海龟作图
设想有一只机械海龟,他在C程序控制下在屋里四处爬行。海龟拿了一只笔,这支笔或者朝上,或者朝下。当笔朝下时,海龟用笔画下自己的移动轨迹;当笔朝上时,海龟在移动过程中什么也不画。
使用一个50*50的数组floor,用于记录海龟绘制的图形,数组元素初始化为0。在海龟爬行过程中,如果笔朝下,就把数组floor中对应于海龟所处位置的元素置为1。当给出命令6(打印命令)后,数组中元素为1的位置全部用星号显示,元素为0的位置全部用空格显示。
海龟会从一个装有命令的数组中读取各种命令。
假定海龟总是从地板上(0,0)出发,并且开始时笔是朝上的。
首先我们逐个分析:
二.问题解决
1. 头文件与宏定义
#include <stdio.h>
// 定义命令数组大小和图形数组大小
#define COMMANDSIZE 100
#define PICSIZE 50
#include <stdio.h>
:引入标准输入输出库,用于实现基本的输入输出功能,如printf
和scanf
函数。COMMANDSIZE
:定义了存储用户输入命令的数组的大小,用于限制可接收的命令数量。PICSIZE
:确定了用于记录海龟绘制图形的二维数组的行数和列数,这里设定为 50 * 50 的矩阵。
2. 函数声明
void getCommand(int commands[], int size);
void draw(int commands[], int size, int floor[][PICSIZE], int rows, int cols);
void printArray(int a[][PICSIZE], int rows, int cols);
- 这三个函数分别负责获取用户输入的命令、根据命令控制海龟作图以及将绘制的图形以可视化形式打印出来。
- 函数声明告诉编译器这些函数的存在及其参数类型和返回值类型,使得在
main
函数中调用这些函数时编译器能够识别。
3. main
函数
int main(void) {
int commands[COMMANDSIZE]; // 存储命令
int floor[PICSIZE][PICSIZE] = { 0 }; // 存储图片
getCommand(commands, COMMANDSIZE); // 获取命令
draw(commands, COMMANDSIZE, floor, PICSIZE, PICSIZE); // 作图
return 0;
}
- 在
main
函数中,首先定义了两个数组:commands
数组用于存储用户输入的命令,其大小由COMMANDSIZE
决定。floor
二维数组用于记录海龟绘制的图形,初始化为全 0,表示初始时没有绘制任何内容。
- 然后依次调用
getCommand
函数获取用户输入的命令,将commands
数组和其大小作为参数传递进去。 - 接着调用
draw
函数,传递commands
数组、其大小、floor
数组以及floor
数组的行数和列数作为参数,根据输入的命令控制海龟在floor
数组上 “作画”。
4. getCommand
函数
void getCommand(int commands[], int size) {
int i;
i = 0;
printf("input the commands\n");
scanf("%d", &commands[i]);
while (commands[i]!= 9) {
if (commands[i] == 5) { // 继续读取前进的格数
printf("input steps: ");
i++;
scanf("%d", &commands[i]);
}
i++;
scanf("%d", &commands[i]);
}
}
- 这个函数用于获取用户输入的命令序列。
- 首先初始化索引变量
i
为 0,然后提示用户输入命令。 - 使用
scanf
函数读取用户输入的第一个命令,并存储到commands
数组中。 - 进入
while
循环,只要当前命令不是结束标记 9,就继续读取命令。- 如果读取到的命令是 5,表示海龟要向前移动,此时需要额外读取一个表示移动格数的整数,并将其存储到
commands
数组的下一个位置(i
自增后存储)。 - 无论何种命令,每次读取完命令后
i
都会自增,准备读取下一个命令。
- 如果读取到的命令是 5,表示海龟要向前移动,此时需要额外读取一个表示移动格数的整数,并将其存储到
5. draw
函数
void draw(int commands[], int size, int floor[][PICSIZE], int rows, int cols) {
int write = 0; // 笔的朝向,0表示朝上,1表示朝下
int row = 0, col = 0; // 海龟当前位置
int dir = 0; // 海龟的朝向,0表示北,1表示东,2表示南,3表示西
for (int i = 0; i < size && commands[i]!= 9; i++) {
switch (commands[i]) {
case 1:
write = 0;
break;
case 2:
write = 1;
break;
case 3: // 右转
dir = (dir + 1) % 4;
break;
case 4: // 左转
dir = (dir + 3) % 4;
break;
case 5: { // 画图
int steps = commands[++i]; // 获取前进格数
for (int j = 0; j < steps; j++) {
if (write == 1) { // 如果笔朝下,则画图
floor[row][col] = 1;
}
// 根据海龟朝向更新位置
switch (dir) {
case 0: // 向北
if (row > 0) {
row--;
}
break;
case 1: // 向东
if (col < cols - 1) {
col++;
}
break;
case 2: // 向南
if (row < rows - 1) {
row++;
}
break;
case 3: // 向西
if (col > 0) {
col--;
}
break;
}
}
break;
}
case 6:
printArray(floor, rows, cols);
break;
}
}
}
- 此函数是海龟作图的核心逻辑部分。
- 定义了三个变量来记录海龟的状态:
write
表示笔的朝向,初始化为 0(朝上)。row
和col
表示海龟当前在floor
数组中的位置,初始化为 (0, 0)。dir
表示海龟的朝向,初始化为 0(向北)。
- 使用
for
循环遍历commands
数组中的命令,直到遇到结束标记 9 或超出数组范围。- 根据不同的命令,通过
switch
语句进行相应的操作:- 命令 1:将
write
设置为 0,使笔朝上。 - 命令 2:将
write
设置为 1,使笔朝下,准备绘制轨迹。 - 命令 3:使海龟右转,通过将
dir
加 1 并对 4 取模来更新朝向(实现循环转向)。 - 命令 4:使海龟左转,通过将
dir
加 3 并对 4 取模来更新朝向(实现循环转向)。 - 命令 5:首先获取前进格数
steps
,然后在一个内层循环中,根据笔的朝向和海龟的当前位置,在floor
数组中记录轨迹(如果笔朝下),并根据海龟的朝向更新其位置。 - 命令 6:调用
printArray
函数打印当前floor
数组中的图形。
- 命令 1:将
- 根据不同的命令,通过
6. printArray
函数
void printArray(int a[][PICSIZE], int rows, int cols) {
int row, col;
printf("the array is:\n");
for (row = 0; row <= rows - 1; row++) {
for (col = 0; col <= cols - 1; col++) {
if (a[row][col]!= 0) {
printf("*");
}
else {
printf(" ");
}
}
printf("\n");
}
}
- 该函数用于将
floor
数组中的图形以可视化形式打印出来。 - 使用两层嵌套的
for
循环遍历floor
数组的每一个元素。 - 如果元素的值不为 0,表示海龟在该位置绘制过,打印星号 “*”;否则打印空格 “ ”。
- 每行遍历完后打印换行符,以形成正确的图形输出格式。
三.完整代码如下所示
#include <stdio.h>
// 定义命令数组大小和图形数组大小
#define COMMANDSIZE 100
#define PICSIZE 50
// 函数声明
void getCommand(int commands[], int size);
void draw(int commands[], int size, int floor[][PICSIZE], int rows, int cols);
void printArray(int a[][PICSIZE], int rows, int cols);
int main(void) {
int commands[COMMANDSIZE]; // 存储命令
int floor[PICSIZE][PICSIZE] = { 0 }; // 存储图片
getCommand(commands, COMMANDSIZE); // 获取命令
draw(commands, COMMANDSIZE, floor, PICSIZE, PICSIZE); // 作图
return 0;
}
// 获取命令函数
void getCommand(int commands[], int size) {
int i;
i = 0;
printf("input the commands\n");
scanf("%d", &commands[i]);
while (commands[i]!= 9) {
if (commands[i] == 5) { // 继续读取前进的格数
printf("input steps: ");
i++;
scanf("%d", &commands[i]);
}
i++;
scanf("%d", &commands[i]);
}
}
// 作图函数
void draw(int commands[], int size, int floor[][PICSIZE], int rows, int cols) {
int write = 0; // 笔的朝向,0表示朝上,1表示朝下
int row = 0, col = 0; // 海龟当前位置
int dir = 0; // 海龟的朝向,0表示北,1表示东,2表示南,3表示西
for (int i = 0; i < size && commands[i]!= 9; i++) {
switch (commands[i]) {
case 1:
write = 0;
break;
case 2:
write = 1;
break;
case 3: // 右转
dir = (dir + 1) % 4;
break;
case 4: // 左转
dir = (dir + 3) % 4;
break;
case 5: { // 画图
int steps = commands[++i]; // 获取前进格数
for (int j = 0; j < steps; j++) {
if (write == 1) { // 如果笔朝下,则画图
floor[row][col] = 1;
}
// 根据海龟朝向更新位置
switch (dir) {
case 0: // 向北
if (row > 0) {
row--;
}
break;
case 1: // 向东
if (col < cols - 1) {
col++;
}
break;
case 2: // 向南
if (row < rows - 1) {
row++;
}
break;
case 3: // 向西
if (col > 0) {
col--;
}
break;
}
}
break;
}
case 6:
printArray(floor, rows, cols);
break;
}
}
}
// 打印图形函数
void printArray(int a[][PICSIZE], int rows, int cols) {
int row, col;
printf("the array is:\n");
for (row = 0; row <= rows - 1; row++) {
for (col = 0; col <= cols - 1; col++) {
if (a[row][col]!= 0) {
printf("*");
}
else {
printf(" ");
}
}
printf("\n");
}
}
接下来我们尝试绘制想要的图形。
比如我们要绘制12*12的矩形我们只需要这样:
运行结果如下:
三角形套三角形(类似谢尔宾斯基三角形的简单形式)
- 初始状态:笔朝上,海龟在原点 (0, 0)。
- 输入命令:
2
(笔朝下,开始绘制)5 12
(向前移动 12 格,绘制大三角形的一条边)4
(左转)5 6
(向前移动 6 格,准备绘制内部小三角形的边)3
(右转)5 6
(向前移动 6 格,绘制内部小三角形的一条边)4
(左转)5 3
(向前移动 3 格,准备绘制更小三角形的边)3
(右转)5 3
(向前移动 3 格,绘制更小三角形的一条边)4
(左转)5 1.5
(向前移动 1.5 格,可根据实际精度调整,准备绘制最内部三角形的边)3
(右转)5 1.5
(向前移动 1.5 格,绘制最内部三角形的一条边)1
(笔朝上,停止绘制)6
(打印图形)9
(结束命令输入)
- 图形效果:绘制出一个大三角形,内部嵌套两个逐渐变小的三角形。
-
运行结果
-
* * * * * * * * * * * * * * * ***************** * * * * * * * * * * * * * * * * *
本期海龟作图就分享到这里。
-
往期回顾:
C语言——指针初阶(一)-CSDN博客
C语言函数递归经典题型——汉诺塔问题-CSDN博客
C语言——数组基本知识(二)-CSDN博客
C语言——数组基本知识(一)-CSDN博客
C语言——数组逐元素操作练习-CSDN博客
C语言编程练习:验证哥德巴赫猜想 进制转换 rand函数-CSDN博客
C语言——函数基本知识(三)-CSDN博客
C语言——函数基本知识(二)-CSDN博客
C语言 ——函数基本知识(一)-CSDN博客