【问题标题】:Drawing in 2D Arrays Turtle Graphics在 2D 数组中绘制 Turtle 图形
【发布时间】:2021-03-08 12:41:03
【问题描述】:

我正在尝试用 C 重新创建 Turtle 图形,但我的程序没有给我想要的东西。我的“乌龟”应该从笔向上并朝东开始,但相反,它从朝南开始。我决定为方向提供编号变量,以便我可以轻松管理它们。所以 3 是东,6 是南,9 是西,12 是北我的 0,0 位置在数组的左上角。为了导航,用户可以使用命令来改变方向、决定何时将笔向上或向下以及何时打印。

当我输入命令 2(下笔)、5,15(移动 15 个空格)、6(打印)和 9(显示结果)时,这就是它给我的:

*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*

而不是这个:

***************

这是我的代码:

#include<stdio.h>

int facing = 3; //start by facing east
int pen = 1; //start by pen up
int copyToArrays(int commandCheck[2][2], const int commands);
int readCommand(int commandCheck[]);
void performCommand(const int command, const int factor, int floor[50][50]);
void draw(const int floor[50][50]);
// y and x coordinates of turtle
int posX =0;
int posY =0;

int main(void)
{
    //INSTRUCTIONS
    printf("Command Key: \n\n");
    printf("1 ---- pen up\n");
    printf("2 ---- pen down\n");
    printf("3 ---- turn right\n");
    printf("4 ---- turn left\n");
    printf("5, N ---- move forward N spaces\n");
    printf("6 ---- Print 50 by 50 Floor\n");
    printf("9 ---- End Data\n\n");
   
    printf("Enter your commands.\n");
    int floor[50][50] = {{0}, {0}};// floor of length and width of 50
    int commandArrays[100][2] = {{0}, {0}};// arrays for the commands
    int numberOfCommands = 0;
    
    numberOfCommands = copyToArrays(commandArrays, 100);// calculate how many commands to process
    
    //for loop to go through the commands and perform them one by one
    for(size_t i = 0; i < numberOfCommands; i++)
    {
        performCommand(commandArrays[i][0], commandArrays[i][1], floor);
    }
}


// function to copy commands into arrays and return the number of commands 
int copyToArrays(int commandArray[2][2], const int commands)
{
    int i;
    int commandCheck[2];
    for ( i  = 0; i <commands && readCommand(commandCheck); i++)
    {
        commandArray[i][0] = commandCheck[0];
        commandArray[i][1] = commandCheck[1];
    }
    
    return i;
}

// Function to take input commands from user while checking if it is a move command or not
int readCommand(int commandCheck[])
{
    scanf("%d,%d", &commandCheck[0], &commandCheck[1]);
    
    if(commandCheck[0] != 5)
    {
        commandCheck[1] = 0;
    }
    
    if(commandCheck[0] == 9)
    {
        return 0;
    }
    else
    {
        return 1;
    }
}


// read command and perform task accordingly
void performCommand(const int command, const int factor, int floor[50][50])
{
    int j; 
    switch(command)
    {
        case 1: pen = 1;
            break;
        case 2: pen = 0;
            floor[posX][posY] = 1;
            break;
        case 3: if (facing == 3)
                   {
                    facing = 6;
                   }
               else if (facing == 6)
               {
                facing  = 9;
               } 
               else if (facing == 9)
               {
                facing = 12;
               }
               else if (facing == 12)
               {
                facing  = 3;
               }
               break;
          case 4: if (facing == 3)
                   {
                    facing = 12;
                   }
               else if (facing == 12)
               {
                facing  = 9;
               } 
               else if (facing == 9)
               {
                facing = 6;
               }
               else if (facing == 6)
               {
                facing  = 3;
               }
               break;
           
           case 5: if (facing == 3)
                   {
                    for (j = 1; j <= factor; j++)
                    {
                        posX++;
                        if(pen == 0)
                        {
                            floor[posX][posY] = 1;
                        }
                    }
                    
                   }
                   else if (facing == 6)
                   {
                    for(j = 1; j <= factor; j++)
                    {
                        posY--;
                        if(pen == 0)
                        {
                            floor[posX][posY] = 1;
                        }
                    }
                   }
                   else if (facing == 9)
                   {
                    for(j = 1; j <= factor; j++)
                    {
                        posX--;
                        if(pen == 0)
                        {
                            floor[posX][posY] = 1;
                        }
                    }
                   }
                   else if(facing == 12)
                   {
                    for(j = 1; j <= factor; j++)
                    {
                        posY++;
                        if(pen == 0)
                        {
                            floor[posX][posY] = 1;
                        }
                    }
                   }
                   break;
            case 6: draw(floor);
                    break;
            default:
            break;
    }
}


//FUntion to draw on the floor
void draw(const int floor[50][50])
{
    
     printf("\n");
     for (int i = 0; i < 49; i++)
     {
        for(int j = 0; j < 49; j++)
        {
            if(floor[i][j] == 1)
            {
                printf("%s", "*");
            }
            else
            {
                printf(" ");
            }
        }
        puts("");
     }
}

【问题讨论】:

  • 因为只有“5”命令需要一个额外的参数,我认为你不能按原样使用简单的scanf("%d,%d",...);。请参阅我最近的回答:stackoverflow.com/questions/64979351/an-array-of-arrays/… 了解读取命令的方法。
  • 由于您标记为 C++,请考虑使用std::vector&lt;std::vector&lt;&gt;&gt;。传递给函数(通过引用)比传递数组更容易。
  • 代替printf("%s", "*");打印1个字符,考虑putchar('*');
  • 因为您的 draw 以错误的顺序循环 ij。将j 循环放在外面,一切正常。

标签: c++ arrays c multidimensional-array graphics


【解决方案1】:

当您执行“移动”命令(命令为5)[或“笔下”]时,您正在转置索引。

也就是说,你这样做:

floor[posX][posY] = 1;

但是,你想要的是:

floor[posY][posX] = 1;

打印时,你正在做:

for (int i = 0;  i < 49;  i++) {
    for (int j = 0;  j < 49;  j++) {

但是,你想要的是:

for (int i = 0;  i < 50;  i++) {
    for (int j = 0;  j < 50;  j++) {

一些额外的清理...

“右转”和“左转”可以简化为switch。但是,它们也可以是简单的加法/减法。

如果我们定义两个变量(例如incXincY),“移动”命令不需要四个单独的for 循环

这是包含错误修复和清理的完整代码。我使用的约定是用cpp 条件来描述旧代码和新代码:

#if 0
// old code ...
#else
// new code ...
#endif

以下是更改:

#include <stdio.h>

int copyToArrays(int commandCheck[2][2],const int commands);
int readCommand(int commandCheck[]);
void performCommand(const int command,const int factor,int floor[50][50]);
void draw(const int floor[50][50]);

int facing = 3; //start by facing east
int pen = 1; //start by pen up

// y and x coordinates of turtle
int posX = 0;
int posY = 0;

int
main(void)
{
    //INSTRUCTIONS
    printf("Command Key: \n\n");
    printf("1 ---- pen up\n");
    printf("2 ---- pen down\n");
    printf("3 ---- turn right\n");
    printf("4 ---- turn left\n");
    printf("5,N ---- move forward N spaces\n");
    printf("6 ---- Print 50 by 50 Floor\n");
    printf("9 ---- End Data\n\n");

    printf("Enter your commands.\n");
    int floor[50][50] = {{0},{0}};// floor of length and width of 50
    int commandArrays[100][2] = {{0},{0}};// arrays for the commands
    int numberOfCommands = 0;

    // calculate how many commands to process
    numberOfCommands = copyToArrays(commandArrays,100);

    //for loop to go through the commands and perform them one by one
    for (size_t i = 0;  i < numberOfCommands;  i++) {
        performCommand(commandArrays[i][0],commandArrays[i][1],floor);
    }
}


// function to copy commands into arrays and return the number of commands
int
copyToArrays(int commandArray[2][2],const int commands)
{
    int i;
    int commandCheck[2];
    for (i  = 0;  i <commands && readCommand(commandCheck);  i++) {
        commandArray[i][0] = commandCheck[0];
        commandArray[i][1] = commandCheck[1];
    }

    return i;
}

// Function to take input commands from user while checking if it is a move
// command or not
int
readCommand(int commandCheck[])
{

    commandCheck[0] = -3;
    commandCheck[1] = -3;

    scanf("%d,%d",&commandCheck[0],&commandCheck[1]);

#if 0
    printf("DEBUG: %d,%d\n",commandCheck[0],commandCheck[1]);
#endif

    if (commandCheck[0] != 5) {
        commandCheck[1] = 0;
    }

    if (commandCheck[0] == 9) {
        return 0;
    }
    else {
        return 1;
    }
}

// read command and perform task accordingly
void
performCommand(const int command,const int factor,int floor[50][50])
{
    int j;
#if 1
    int incX = 0;
    int incY = 0;
#endif

    switch (command) {
    case 1:
        pen = 1;
        break;

    case 2:
        pen = 0;
#if 0
        floor[posX][posY] = 1;
#else
        floor[posY][posX] = 1;
#endif
        break;

    case 3:
#if 0
        if (facing == 3) {
            facing = 6;
        }
        else if (facing == 6) {
            facing  = 9;
        }
        else if (facing == 9) {
            facing = 12;
        }
        else if (facing == 12) {
            facing  = 3;
        }
#endif
#if 0
        switch (facing) {
        case 3:
            facing = 6;
            break;
        case 6:
            facing = 9;
            break;
        case 9:
            facing = 12;
            break;
        case 12:
            facing = 3;
            break;
        }
#endif
#if 1
        facing += 3;
        if (facing > 12)
            facing -= 12;
#endif
        break;

    case 4:
#if 0
        if (facing == 3) {
            facing = 12;
        }
        else if (facing == 12) {
            facing  = 9;
        }
        else if (facing == 9) {
            facing = 6;
        }
        else if (facing == 6) {
            facing  = 3;
        }
#endif
#if 0
        switch (facing) {
        case 3:
            facing = 12;
            break;
        case 6:
            facing = 3;
            break;
        case 9:
            facing = 6;
            break;
        case 12:
            facing = 9;
            break;
        }
#endif
#if 1
        facing -= 3;
        if (facing <= 0)
            facing += 12;
#endif
        break;

    case 5:
#if 0
        if (facing == 3) {
            for (j = 1;  j <= factor;  j++) {
                posX++;
                if (pen == 0) {
                    floor[posX][posY] = 1;
                }
            }
        }
        else if (facing == 6) {
            for (j = 1;  j <= factor;  j++) {
                posY--;
                if (pen == 0) {
                    floor[posX][posY] = 1;
                }
            }
        }
        else if (facing == 9) {
            for (j = 1;  j <= factor;  j++) {
                posX--;
                if (pen == 0) {
                    floor[posX][posY] = 1;
                }
            }
        }
        else if (facing == 12) {
            for (j = 1;  j <= factor;  j++) {
                posY++;
                if (pen == 0) {
                    floor[posX][posY] = 1;
                }
            }
        }
#else
        switch (facing) {
        case 3:
            incX = 1;
            break;
        case 6:
            incY = -1;
            break;
        case 9:
            incX = -1;
            break;
        case 12:
            incY = 1;
            break;
        }
        for (j = 1;  j <= factor;  j++) {
            posX += incX;
            posY += incY;
            if (pen == 0) {
#if 0
                floor[posX][posY] = 1;
#else
                floor[posY][posX] = 1;
#endif
            }
        }
#endif
        break;

    case 6:
        draw(floor);
        break;

    default:
        break;
    }
}


//FUntion to draw on the floor
void
draw(const int floor[50][50])
{

    printf("\n");

#if 0
    for (int i = 0;  i < 49;  i++) {
        for (int j = 0;  j < 49;  j++) {
            if (floor[i][j] == 1) {
                printf("%s","*");
            }
            else {
                printf(" ");
            }
        }
        puts("");
    }
#else
    for (int i = 0;  i < 50;  i++) {
        for (int j = 0;  j < 50;  j++) {
            if (floor[i][j] == 1) {
                putchar('*');
            }
            else {
                putchar(' ');
            }
        }
        putchar('\n');
    }
#endif
}

这是完全清理的版本。

它还添加了超出边缘的检查(通过包装)。并且,它为文字添加了#define(例如50100

#include <stdio.h>

#define DIM_Y   50
#define DIM_X   50

int copyToArrays(int commandCheck[2][2],const int commands);
int readCommand(int commandCheck[]);
void performCommand(const int command,const int factor,int floor[DIM_Y][DIM_X]);
void draw(const int floor[DIM_Y][DIM_X]);

int facing = 3; //start by facing east
int pen = 1; //start by pen up

// y and x coordinates of turtle
int posX = 0;
int posY = 0;

#define MAXCMD  100

int
main(void)
{
    //INSTRUCTIONS
    printf("Command Key: \n\n");
    printf("1 ---- pen up\n");
    printf("2 ---- pen down\n");
    printf("3 ---- turn right\n");
    printf("4 ---- turn left\n");
    printf("5,N ---- move forward N spaces\n");
    printf("6 ---- Print %d by %d Floor\n",DIM_Y,DIM_X);
    printf("9 ---- End Data\n\n");

    printf("Enter your commands.\n");
    int floor[DIM_Y][DIM_X] = {{0},{0}};// floor of length and width of 50
    int commandArrays[MAXCMD][2] = {{0},{0}};// arrays for the commands
    int numberOfCommands = 0;

    // calculate how many commands to process
    numberOfCommands = copyToArrays(commandArrays,MAXCMD);

    //for loop to go through the commands and perform them one by one
    for (size_t i = 0;  i < numberOfCommands;  i++) {
        performCommand(commandArrays[i][0],commandArrays[i][1],floor);
    }
}


// function to copy commands into arrays and return the number of commands
int
copyToArrays(int commandArray[MAXCMD][2],const int commands)
{
    int i;
    int commandCheck[2];
    for (i  = 0;  i < commands && readCommand(commandCheck);  i++) {
        commandArray[i][0] = commandCheck[0];
        commandArray[i][1] = commandCheck[1];
    }

    return i;
}

// Function to take input commands from user while checking if it is a move
// command or not
int
readCommand(int commandCheck[])
{

    commandCheck[0] = -3;
    commandCheck[1] = -3;

    scanf("%d,%d",&commandCheck[0],&commandCheck[1]);

#if 0
    printf("DEBUG: %d,%d\n",commandCheck[0],commandCheck[1]);
#endif

    if (commandCheck[0] != 5)
        commandCheck[1] = 0;

    return (commandCheck[0] != 9);
}

int
move(int pos,int inc,int dim)
{
    pos += inc;

    if (pos < 0)
        pos += dim;

    if (pos >= dim)
        pos -= dim;

    return pos;
}

// read command and perform task accordingly
void
performCommand(const int command,const int factor,int floor[DIM_Y][DIM_X])
{
    int j;
    int incX = 0;
    int incY = 0;

    switch (command) {
    case 1:
        pen = 1;
        break;

    case 2:
        pen = 0;
        floor[posY][posX] = 1;
        break;

    case 3:
        facing += 3;
        if (facing > 12)
            facing -= 12;
        break;

    case 4:
        facing -= 3;
        if (facing <= 0)
            facing += 12;
        break;

    case 5:
        switch (facing) {
        case 3:
            incX = 1;
            break;
        case 6:
            incY = -1;
            break;
        case 9:
            incX = -1;
            break;
        case 12:
            incY = 1;
            break;
        }
        for (j = 1;  j <= factor;  j++) {
            posX = move(posX,incX,DIM_X);
            posY = move(posY,incY,DIM_Y);
            if (pen == 0)
                floor[posY][posX] = 1;
        }
        break;

    case 6:
        draw(floor);
        break;

    default:
        break;
    }
}

//FUntion to draw on the floor
void
draw(const int floor[DIM_Y][DIM_X])
{

    printf("\n");

    for (int i = 0;  i < DIM_Y;  i++) {
        for (int j = 0;  j < DIM_X;  j++) {
            if (floor[i][j] == 1)
                putchar('*');
            else
                putchar(' ');
        }
        putchar('\n');
    }
}

【讨论】:

    【解决方案2】:

    改用这个。

    void draw(const int floor[50][50])
    {
        
         printf("\n");
         for(int j = 0; j < 49; j++)
         {
            for (int i = 0; i < 49; i++)
            {
                if(floor[i][j] == 1)
                {
                    printf("%s", "*");
                }
                else
                {
                    printf(" ");
                }
            }
            puts("");
         }
    }
    

    您的代码正在内部循环中遍历y。这意味着您正在转置矩阵,因为您正在 x 方向(列)打印。另一种方法是摆脱愚蠢的多维数组语法 - 实际上,它导致的问题比它解决的问题多 - 并坚持使用 Width*Height 维度的一维数组,每个元素由 y * width + x 索引。这消除了任何歧义,删除了嵌套循环等。这也是该领域的每个人都这样做的方式。

    【讨论】:

      猜你喜欢
      • 2021-11-05
      • 2016-08-12
      • 1970-01-01
      • 2012-09-20
      • 2019-08-08
      • 2021-07-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多