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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/924918.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

游戏引擎学习第22天

移除 DllMain() 并成功重新编译 以下是对内容的详细复述与总结&#xff1a; 问题和解决方案&#xff1a; 在编译过程中遇到了一些问题&#xff0c;特别是如何告知编译器不要退出程序&#xff0c;而是继续处理。问题的根源在于编译过程中传递给链接器的参数设置不正确。原本尝试…

路面交通工具和个数识别,支持YOLO,COCO,VOC三种格式,带标注可识别自行车,摩的,公共汽车,装载机,面包车,卡车,轿车等

预处理 自动定向&#xff1a; 已应用 调整大小&#xff1a; 拉伸至 640x640 增强 每个训练示例的输出&#xff1a; 3 翻转&#xff1a; 水平 自行车 公交车

goframe框架bug-记录

implement not found for interface ICompany, forgot register? 错误解决检查&#xff1a; 1.有没有init 2. 注入问题 3. 注入问题

基于SpringBoot实现的民宿管理系统(代码+论文)

&#x1f389;博主介绍&#xff1a;Java领域优质创作者&#xff0c;阿里云博客专家&#xff0c;计算机毕设实战导师。专注Java项目实战、毕设定制/协助 &#x1f4e2;主要服务内容&#xff1a;选题定题、开题报告、任务书、程序开发、项目定制、论文辅导 &#x1f496;精彩专栏…

vue3实现自定义导航菜单

一、创建项目 1. 打开HBuilder X 图1 2. 新建一个空项目 文件->新建->项目->uni-app 填写项目名称&#xff1a;vue3demo 选择项目存放目录&#xff1a;D:/HBuilderProjects 一定要注意vue的版本&#xff0c;当前选择的版本为vue3 图2 点击“创建”之后进入项目界面 图…

如何利用ATECLOUD平台来实现数据报告的导出和数据分析?-纳米软件

1.数据报告导出 选择报告模板&#xff1a;ATECLOUD 平台通常会提供多种预设的数据报告模板&#xff0c;这些模板是根据不同的测试场景和需求设计的。例如&#xff0c;在电源模块测试中&#xff0c;有针对输出电压、电流、功率等基本参数的报告模板&#xff0c;也有包含纹波系数…

5G NR:带宽与采样率的计算

100M 带宽是122.88Mhz sampling rate这是我们都知道的&#xff0c;那它是怎么来的呢&#xff1f; 采样率 子载波间隔 * 采样长度 38.211中对于Tc的定义&#xff0c; 在LTE是定义了Ts&#xff0c;在NR也就是5G定义了Tc。 定义这个单位会对我们以后工作中的计算至关重要。 就是在…

思科实现网络地址转换(NAT)和访问控制列表(ACL)和动态路由配置并且区分静态路由和动态路由配置。

实验拓扑(分为静态路由和动态路由两种) 静态路由互通 动态路由互通 实验背景 这个是想实现外网与内网的连接跟网络的探讨&#xff0c;最终实现互通以及使用并且在网络地址转换后能使用网络然后再这个基础上再配置访问控制列表和网络地址转换的的学习过程。 实验需了解的知识…

人工智能如何改变你的生活?

在我们所处的这个快节奏的世界里&#xff0c;科技融入日常生活已然成为司空见惯的事&#xff0c;并且切实成为了我们生活的一部分。在这场科技变革中&#xff0c;最具变革性的角色之一便是人工智能&#xff08;AI&#xff09;。从我们清晨醒来直至夜晚入睡&#xff0c;人工智能…

Spring系列之批处理Spring Batch介绍

概述 官网&#xff0c;GitHub A lightweight, comprehensive batch framework designed to enable the development of robust batch applications vital for the daily operations of enterprise systems. 执行流程 实战 假设有个待处理的任务&#xff0c;如文件batch-tes…

[保姆式教程]使用labelimg2软件标注定向目标检测数据和格式转换

定向目标检测是一种在图像或视频中识别和定位对象的同时&#xff0c;还估计它们方向的技术。这种技术特别适用于处理有一定旋转或方向变化的对象&#xff0c;例如汽车、飞机或文本。定向目标检测器的输出是一组旋转的边界框&#xff0c;这些框精确地包围了图像中的对象&#xf…

go结构体匿名“继承“方法冲突时继承优先顺序

在 Go 语言中&#xff0c;匿名字段&#xff08;也称为嵌入字段&#xff09;可以用来实现继承的效果。当你在一个结构体中匿名嵌入另一个结构体时&#xff0c;嵌入结构体的方法会被提升到外部结构体中。这意味着你可以直接通过外部结构体调用嵌入结构体的方法。 如果多个嵌入结…

八、利用CSS制作导航栏菜单

8.1 水平顶部导航栏 水平菜单导航栏是网站设计中应用范围最广的导航设计&#xff0c;一般放置在页面的顶部。水平导航适用性强&#xff0c;几乎所有类型的网站都可以使用。 如果导航过于普通&#xff0c;无法容纳复杂的信息结构&#xff0c;就需要在内容模块较多的情况…

rustdesk 自建服务

RustDesk 部署RustDesk sudo docker image pull rustdesk/rustdesk-server sudo docker run --name hbbs -p 21115:21115 -p 21116:21116 -p 21116:21116/udp -p 21118:21118 -v pwd:/root -td --nethost rustdesk/rustdesk-server hbbs sudo docker run --name hbbr -p 2111…

景联文科技:高质量数据采集标注服务引领AI革新

在当今这个数字化时代&#xff0c;数据已经成为推动社会进步和产业升级的关键资源。特别是在人工智能领域&#xff0c;高质量的数据是训练出高效、精准的AI模型的基础。景联文科技是一家专业的数据采集与标注公司&#xff0c;致力于为客户提供高质量的数据处理服务&#xff0c;…

Git上传本地项目到远程仓库(gitee/github)

目录 序言一、创建git本地版本库二、连接远程仓库&#xff08;以gitee为例&#xff09;三、将项目提交到git&#xff08;本地&#xff09;版本库1.由工作区添加到暂存区2.由暂存区添加到版本库 四、将代码由本地仓库上传到 gitee远程仓库1.获取远程库与本地同步2.把当前分支 ma…

RabbitMQ 消息确认机制

RabbitMQ 消息确认机制 本文总结了RabbitMQ消息发送过程中的一些代码片段&#xff0c;详细分析了回调函数和发布确认机制的实现&#xff0c;以提高消息传递的可靠性。 返回回调机制的代码分析 主要用途 这个代码主要用于设置RabbitMQ消息发送过程中的回调函数&#xff0c;即…

租辆酷车小程序开发(二)—— 接入微服务GRPC

vscode中golang的配置 设置依赖管理 go env -w GO111MODULEon go env -w GOPROXYhttps://goproxy.cn,direct GO111MODULEauto 在$GOPATH/src 外面且根目录有go.mod 文件时&#xff0c;开启模块支持 GO111MODULEoff 无模块支持&#xff0c;go会从GOPATH 和 vendor 文件夹寻找包…

Qt6.8安卓Android开发环境配置

时隔多年&#xff0c;重拾QtCreator下Android开发。发现Qt6下安卓开发环境配置变简单不少&#xff01;只需三步即可在QtCreator下进行Android开发&#xff1a; 一、使用Qt Mantenance Tool进行Android模块的安装&#xff1a; 如果感觉安装网速较慢&#xff0c;可以查看本人另外…

Java篇——Java通过JNA调用c++库时传参含有结构体时数据错乱的解决办法

Java通过JNA调用c库时传参含有结构体时&#xff0c;只继承Structure是不够的&#xff0c;还需要实现Structure.ByValue&#xff0c;或者强制指定结构体字节对齐。示例如下&#xff1a; 1、c库中的结构体定义&#xff1a; 2、java中结构体定义&#xff1a; 3、java中调用 如果没…