当前位置: 首页 > article >正文

C语言——海龟作图(对之前所有内容复习)

一.问题描述

海龟作图

     设想有一只机械海龟,他在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>:引入标准输入输出库,用于实现基本的输入输出功能,如printfscanf函数。
  • 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. 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(朝上)。
    • rowcol表示海龟当前在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数组中的图形。

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博客


http://www.kler.cn/a/414412.html

相关文章:

  • elasticsearch单节点模式部署
  • vs 项目属性表
  • Java文件遍历那些事
  • 常见的Web安全漏洞——XSS
  • 解决整合Django与Jinja2兼容性的问题
  • 使用爬虫时,如何确保数据的准确性?
  • 【单片机毕业设计12-基于stm32c8t6的智能称重系统设计】
  • Qt中QML和C++混合编程
  • 华为光学博士面试经验
  • 【AI系统】从 CUDA 对 AI 芯片思考
  • 未来已来?AI技术革新改变我们的生活
  • vscode自动打印日志插件
  • 【k8s深入理解之 Scheme 补充-1】理解 Scheme 中资源的注册以及 GVK 和 go 结构体的映射
  • 同时在github和gitee配置密钥
  • 力扣第 71 题 简化路径
  • 电脑模拟器端口号及相关的操作命令
  • 云计算基础-期末复习
  • 【Linux】文件管理
  • 华为Mate 70系列,行走在AI山脊
  • P1390 公约数的和
  • (73)脉冲幅度调制PAM调制解调通信系统的MATLAB仿真
  • 力扣hot100-->前缀和/前缀书/LRU缓存
  • 文本的预处理(pytorch)
  • Ubuntu环境中RocketMQ安装教程
  • ROS VSCode调试方法
  • Linux 命令详解之 tail 命令