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

news/2024/11/29 7:23:50/

一.问题描述

海龟作图

     设想有一只机械海龟,他在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.ppmy.cn/news/1550846.html

相关文章

uniapp介入极光推送教程 超级详细

直接按照下面教程操作 一步一步来 很快就能 完成 下面的文章非常详细 &#xff0c;我就不班门弄斧了 直接上原文链接 https://blog.csdn.net/weixin_52830464/article/details/143823231

【Linux系列】Chrony时间同步服务器搭建完整指南

1. 简介 Chrony是一个用于Linux系统的高效、精准的时间同步工具&#xff0c;通常用于替代传统的NTP&#xff08;Network Time Protocol&#xff09;服务。Chrony不仅在系统启动时提供快速的时间同步&#xff0c;还能在时钟漂移较大的情况下进行及时调整&#xff0c;因此广泛应…

No.2 杀戮尖塔Godot复刻2卡牌拖动和状态机1|CardUI|BattleUI

杀戮尖塔中有两种卡 单一目标卡牌和非单一目标卡牌 使用卡牌方法&#xff1a; 如果按住鼠标左键拖动防御卡并将其释放到屏幕中的某个位置&#xff0c;该卡就会被打出另一种方法是鼠标左键单击防御卡&#xff0c;不按下左键&#xff0c;将其拖到屏幕中间&#xff0c;再次单击鼠…

Django websocket 进行实时通信(消费者)

1. settings.py 增加 ASGI_APPLICATION "django_template_v1.routing.application"CHANNEL_LAYERS {"default": {# This example apps uses the Redis channel layer implementation channels_redis"BACKEND": "channels_redis.core.Red…

代码随想录算法训练营第六十天|Day60 图论

Bellman_ford 队列优化算法&#xff08;又名SPFA&#xff09; https://www.programmercarl.com/kamacoder/0094.%E5%9F%8E%E5%B8%82%E9%97%B4%E8%B4%A7%E7%89%A9%E8%BF%90%E8%BE%93I-SPFA.html 本题我们来系统讲解 Bellman_ford 队列优化算法 &#xff0c;也叫SPFA算法&#xf…

Zookeeper学习心得

本人学zookeeper时按照此文路线学的 Zookeeper学习大纲 - 似懂非懂视为不懂 - 博客园 一、Zookeeper安装 ZooKeeper 入门教程 - Java陈序员 - 博客园 Docker安装Zookeeper教程&#xff08;超详细&#xff09;_docker 安装zk-CSDN博客 二、 zookeeper的数据模型 ZooKeepe…

免费下载 | 2024年中国网络安全产业分析报告

《2024年中国网络安全产业分析报告》由中国网络安全产业联盟&#xff08;CCIA&#xff09;发布&#xff0c;主要内容包括&#xff1a; 前言&#xff1a;强调网络安全是国家安全的重要组成部分&#xff0c;概述了中国在网络安全治理方面的进展和挑战。 网络安全产业发展形势&am…

【linux】(21)进程端口排查-fuser

fuser 是一个用于显示进程使用的文件、套接字或端口的 Linux 命令。它可以帮助诊断某个文件、目录、端口或设备被哪个进程占用。 基本语法 fuser [选项] 文件或端口常用选项 选项说明-a显示所有指定文件或端口的进程信息。-k杀死占用指定文件或端口的进程。-i在杀死进程前询问…