• Advertisement
Sign in to follow this  

Need some hints about a program.

This topic is 3992 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi! I'm new here. I'm reading a book about C++ so I'm quite new to the language. An exercise asks to write a simple "Turtle Graphics" program. This program should be able to simulates very simple graphics thanks to the following commands: Command Meaning 1 - Pen up 2 - Pen down 3 - Turn right 4 - Turn left 5 , n - Move forward n spaces 6 - Print 20-by-20 array 9 - End of data (sentinel) Now, before I post my code, my questions: - is the code clear? I'm not very happy about the two switch I use to decide the command and the direction (in the move function). - I wasn't able to implement the fifth command in one line, I mean you have to write 5, ENTER and than the N. The exercise asks to do it in one line. How can I achieve that? Thank you for any suggestion and please don't be gentle: I want to learn My code:
#include <iostream>

using namespace std;

void printMap(void);
void printCommands(void);
void move(int);

const int END = 9;
const int commands[7] = { 0, 1, 2, 3, 4, 5, 6 };
int map[20][20] = { 0 };
bool penDown = false;
int x = 0;
int y = 0;
int dir = 0; // 0 = N, 1 = E, 2 = S, 3 = O

int main() {

    cout << "Welcome to the Turtle Graphics! Here's the list of commmands:" << endl;
    printCommands();
    
    int command;
    int args;
    
    cout << "Enter a command: ";
    cin >> command;
    if (command == 5) cin >> args;
    
    while (command != END) {
        switch (command) {
            // print commands
            case 0:
            printCommands();
            break;
            
            // set the pen down
            case 1:
            if (penDown) penDown = false;
            else cout << "The pen is already up." << endl;
            break;
            
            // pen up
            case 2:
            if (!penDown) penDown = true;
            else cout << "The pen is already down." << endl;
            break;
            
            // turn right
            case 4:
            dir = (dir + 1) % 4;
            cout << "The new direction is " << dir << endl;
            break;
            
            // turn left
            case 3:
            dir -= 1;
            if (dir < 0) dir = 3;
            cout << "The new direction is " << dir << endl;
            break;
            
            // move forward
            case 5:
            cout << "Moving forward by " << args << endl;
            move(args);
            break;
            
            // show the map
            case 6:
            printMap();
            break;
        
        }
        
        cout << "Enter a command (0 to show commands): ";
        cin >> command;
        if (command == 5) cin >> args;
        
    }
    
    cout << "Bye bye!" << endl;
    return 0;
}

void move(int steps) {
    while (steps-- > 0) {
        switch (dir) {
            // N
            case 0:
            if (y > 0) y--;
            break;
            
            // E
            case 1:
            if (x < 20) x++;
            break;
        
            // S
            case 2:
            if (y < 19) y++;
            break;
            
            // O
            case 3:
            if (x > 0) x--;
            break;
        }
        if (penDown) map[y][x] = 1;
    }
}

void printMap() {
    for (int i = 0; i < 20; i++) {
        for (int j = 0; j < 20; j++) {
            if (x == j && y == i) cout << "X";
            else if (map[j] == 0) cout << " ";
            else cout << "*";
        }
        cout << endl;
    }
}

void printCommands() {
    cout << "0    - Show the commands available\n"
         << "1    - Turn up the pen\n"
         << "2    - Turn down the pen\n"
         << "3    - Turn left\n"
         << "4    - Turn right\n"
         << "5, n - Move therd of n tiles\n"
         << "6    - Show the drawing\n"
         << "9    - Exit program" << endl; 
}

Share this post


Link to post
Share on other sites
Advertisement
Hum - at a cursory first glance, this array seems a bit mysterious:

const int commands[7] = { 0, 1, 2, 3, 4, 5, 6 };


Just an array of the first 7 ints, and it doesn't seem to be used anywhere?

Touching your problem with command 5, you probably want to cin to a string rather than an int, then do parsing on the string; so if the user inputs "5, 4" you have code to return "command 5, increment 4" and if he inputs "dsayhfs" you don't get an instant error, because your parser is bright enough to say "I don't recognise that command".

Share this post


Link to post
Share on other sites
The only way I can think of to get command 5 to work is to make a few assumptions on the input. For instance, if you retrieved every command as a string like so:

std::string command;
std::cin >> command;
//
while (command[0] != END)
{
switch(command[0])
{
// print commands
case '0': // character '0' instead of integer 0
printCommands();
break;
//etc


Then for case '5' you'd access the Nth byte in the string to access the number of spaces to move (you can get an integer version of the number with the rule that Number = Letter - '0'). However this way makes good programmers cry due to the major possibility of reading past the buffer and accessing uninitialized data. If the user entered

5,

with no number after it then your program won't be correct. Another problem is that with this method you can only move 0 to 9 spaces because you only read 1 digit.

There may be another method that works with one line, but I can't think of any.

Edit: upon further examination, define '1 line'

Share this post


Link to post
Share on other sites
Thanks to anyone for answering.

Quote:
Original post by King of Men
Hum - at a cursory first glance, this array seems a bit mysterious:

const int commands[7] = { 0, 1, 2, 3, 4, 5, 6 };


Just an array of the first 7 ints, and it doesn't seem to be used anywhere?

Touching your problem with command 5, you probably want to cin to a string rather than an int, then do parsing on the string; so if the user inputs "5, 4" you have code to return "command 5, increment 4" and if he inputs "dsayhfs" you don't get an instant error, because your parser is bright enough to say "I don't recognise that command".


Well actually the exercise specify to put all the commands in an array, but I didn't manage to find a way to use it... so I forgot about it. I found easier a switch statement as you see. The string manipulation is in the next chapter so I don't think it's the right way (for me).


to nobodynews: Thanks for the suggestion, I'll test it when I'll know more about string manipulation : )

Share this post


Link to post
Share on other sites
Quote:
Original post by ziofu
Well actually the exercise specify to put all the commands in an array, but I didn't manage to find a way to use it... so I forgot about it. I found easier a switch statement as you see.


It's possible what they meant was to put the command *implementations* into an array - i.e., have an array of function pointers, and then use the read-in number to index into the array (remembering that the array indices start at 0, not 1! Also you should do error-checking on the value *before* attempting to index in).

As for the second argument for '5', it seems like it should just work fine. Did you try, for example, '5 20' on a single line of input?

In general, though, it is a much better idea to read standard input a line at a time, and then re-parse the lines. Here is a typical structure...


std::string line;
// "for as long as we can read a line of the standard input,"
// (the standard input can be "ended" by inputting ctrl-Z under DOS or
// ctrl-D under Linux)
while (std::getline(cin, line)) {
// "put the line of text into an input string-stream"
std::istringstream iss(line);
// Now we can "read from" the stringstream exactly the same way we do from
// std::cin.
int command, args;
if (!(iss >> command)) { error(); } // bad line of input: no number.
if ((command == 5) && !(iss >> args)) { error(); } // bad argument value.
char garbage;
if (command >> std::ws >> garbage) { error(); } // there was extra stuff in the line.
// Otherwise, we have some valid input: interpret the 'command' value and
// do whatever's appropriate.
}


With this structure, you never have to worry about infinite loops caused by the user typing garbage, because the "damage" is done to the temporary stringstream object: if it contains garbage, then it just gets thrown away and reconstructed with the next line of input. You also make sure that you never have problems due to "leftover" text from a previous line of input, because your reading from cin is a line at a time, and therefore stays in sync with the input passed to your program (since the console does "line buffering" and feeds it to your program a line at a time).

Quote:
The string manipulation is in the next chapter so I don't think it's the right way (for me).


It's really hard to teach everything "in the right order", or really in any specific order. Probably best not to let the book constrain you in this way. :)

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement