I need help!

closed account (L0Shb7Xj)
This question has been resolved. Thank you for all your help.

I'm trying to create a game using ASCII characters as a school project. This code serves as a prototype for the eventual map. The idea is that if I can pass a double dimensional array (test) to a function (map()) and the program can create the particular output screen, I can build as many maps as I need with little effort.

Here's the code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
#include <iostream>
#include <windows.h>                                                         
#include <conio.h>                                                                   
#include <iomanip>  
using namespace std;
const char PLAY=16;
const char STOP=-2;
const char UP=72;
const char DOWN=80;
const char LEFT=75;
const char RIGHT=77;
const char ENTER=13;
const char SPACE=32;

void gotoxy (short x, short y);
void map(int s[10][4]);
void sprite(short, short, int);

int main()
{
    //Fullscreen
     HANDLE hConsole;
     COORD size;
     HWND hWnd;
     hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
     size = GetLargestConsoleWindowSize(hConsole);
     SetConsoleScreenBufferSize(hConsole,size);
     SetConsoleTitle("test");
     hWnd = FindWindow(NULL,"test");
     ShowWindow(hWnd,SW_MAXIMIZE);
     
     //Hiding Cursor
     CONSOLE_CURSOR_INFO CursoInfo;
     CursoInfo.dwSize = 1;
     CursoInfo.bVisible = false;
     SetConsoleCursorInfo(hConsole, &CursoInfo);   
    
    int test[10][4]={ 5,  6,  7, 13, 13, 13, 13, 13, 13, 13,
                      8, 11, 10, 13, 13, 13, 13, 13, 13, 13,
                     13,  1, 13, 13, 13, 13, 13, 13, 13, 13,
                     13, 13, 13, 13, 13, 13, 13, 13, 13, 13};
                     
    int i,j;
    char x;
    
    for(;;)
    {
        map(test);
        x=getch();  //check here whether input is UP, DOWN, LEFT or RIGHT
        //move player according to x
        system ("cls");
    }
}

void map(int s[10][4])
{
     short i, j;
     //
     for (i=0; i<10; i++)
     {
        for (j=0; j<4; j++)
        {
           sprite(j*10+1, i*10+1, s[i][j]);
         }
     }
}    

void sprite(short j, short i, int x)
{
     int a;
     
     switch(x)
     {
          case 1:
               for (a=0; a<10; a++, i++)
               {
                   gotoxy(i,j);
                   cout<<"PLYR FRONT";
               }
               break;
          case 2:
               for (a=0; a<10; a++, i++)
               {
                   gotoxy(i,j);
                   cout<<"PLYR  LEFT";
               }
               break;
          case 3:
               for (a=0; a<10; a++, i++)
               {
                   gotoxy(i,j);
                   cout<<"PLYR RIGHT";
               }
               break;
          case 4:
               for (a=0; a<10; a++, i++)
               {
                   gotoxy(i,j);
                   cout<<"PLYR  BACK";
               }
               break;
          case 5:
               for (a=0; a<10; a++, i++)
               {
                   gotoxy(i,j);
                   cout<<"  ROOF1   ";
               }
               break;
          case 6:
               for (a=0; a<10; a++, i++)
               {
                   gotoxy(i,j);
                   cout<<"  ROOF2   ";
               }
               break;
          case 7:
               for (a=0; a<10; a++, i++)
               {
                   gotoxy(i,j);
                   cout<<"  ROOF3   ";
               }
               break;
          case 8:
               for (a=0; a<10; a++, i++)
               {
                   gotoxy(i,j);
                   cout<<"  WALL1   ";
               }
               break;
          case 9:
               for (a=0; a<10; a++, i++)
               {
                   gotoxy(i,j);
                   cout<<"  WALL2   ";
               }
               break;
          case 10:
               for (a=0; a<10; a++, i++)
               {
                   gotoxy(i,j);
                   cout<<"  WALL3   ";
               }
               break;
          case 11:
               for (a=0; a<10; a++, i++)
               {
                   gotoxy(i,j);
                   cout<<"   DOOR   ";
               }
               break;
          case 12:
               for (a=0; a<10; a++, i++)
               {
                   gotoxy(i,j);
                   cout<<"   TREE   ";
               }
               break;
          case 13:
               for (a=0; a<10; a++, i++)
               {
                   gotoxy(i,j);
                   cout<<"  GROUND  ";
               }
               break;
          default:
               for (a=0; a<10; a++, i++)
               {
                   gotoxy(i,j);
                   cout<<"SPRITERROR";
               }
               break;
     }
}

void gotoxy(short x, short y)
{
    COORD pos = {x, y};
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
}


The output of this code is:
https://dl.dropboxusercontent.com/u/89962712/Map%20Prototype%20Help/What%20I%27m%20Getting.jpg

Something's wrong with my logic. The output I want to get is

ROOF1  ROOF2    ROOF3  GROUND GROUND GROUND GROUND...
ROOF1  ROOF2    ROOF3  GROUND GROUND GROUND GROUND...
ROOF1  ROOF2    ROOF3  GROUND GROUND GROUND GROUND...
ROOF1  ROOF2    ROOF3  GROUND GROUND GROUND GROUND...
ROOF1  ROOF2    ROOF3  GROUND GROUND GROUND GROUND...
ROOF1  ROOF2    ROOF3  GROUND GROUND GROUND GROUND...
ROOF1  ROOF2    ROOF3  GROUND GROUND GROUND GROUND...
ROOF1  ROOF2    ROOF3  GROUND GROUND GROUND GROUND...
ROOF1  ROOF2    ROOF3  GROUND GROUND GROUND GROUND...
ROOF1  ROOF2    ROOF3  GROUND GROUND GROUND GROUND...
WALL1  DOOR     WALL3  GROUND GROUND GROUND GROUND...
WALL1  DOOR     WALL3  GROUND GROUND GROUND GROUND...
WALL1  DOOR     WALL3  GROUND GROUND GROUND GROUND...
WALL1  DOOR     WALL3  GROUND GROUND GROUND GROUND...
WALL1  DOOR     WALL3  GROUND GROUND GROUND GROUND...
WALL1  DOOR     WALL3  GROUND GROUND GROUND GROUND...
WALL1  DOOR     WALL3  GROUND GROUND GROUND GROUND...
WALL1  DOOR     WALL3  GROUND GROUND GROUND GROUND...
WALL1  DOOR     WALL3  GROUND GROUND GROUND GROUND...
WALL1  DOOR     WALL3  GROUND GROUND GROUND GROUND...
WALL1  DOOR     WALL3  GROUND GROUND GROUND GROUND...
GROUND PLYRFRNT GROUND GROUND GROUND GROUND GROUND...
GROUND PLYRFRNT GROUND GROUND GROUND GROUND GROUND...
GROUND PLYRFRNT GROUND GROUND GROUND GROUND GROUND...
GROUND PLYRFRNT GROUND GROUND GROUND GROUND GROUND...
GROUND PLYRFRNT GROUND GROUND GROUND GROUND GROUND...
GROUND PLYRFRNT GROUND GROUND GROUND GROUND GROUND...
GROUND PLYRFRNT GROUND GROUND GROUND GROUND GROUND...
GROUND PLYRFRNT GROUND GROUND GROUND GROUND GROUND...
GROUND PLYRFRNT GROUND GROUND GROUND GROUND GROUND...
GROUND PLYRFRNT GROUND GROUND GROUND GROUND GROUND...
GROUND PLYRFRNT GROUND GROUND GROUND GROUND GROUND...
GROUND...
GROUND...
GROUND...
GROUND...
GROUND...
GROUND...
GROUND...
GROUND...
GROUND...
GROUND...


Can someone help me, please? If you can correct my logic or come up with a better logic, it would be awesome.

PS: I need to use console. School project.
PSS: I'm a newbie.
Last edited on
It might help if you described what you need to do.
closed account (L0Shb7Xj)

The output (simplified) is:

ROOF1  GROUND GROUND WALL3  GROUND GROUND   GROUND ...
ROOF2  GROUND GROUND GROUND GROUND PLYRFRNT GROUND ...
ROOF3  GROUND WALL1  GROUND GROUND GROUND   GROUND ...
GROUND GROUND DOOR   GROUND GROUND GROUND   GROUND ...


Something's wrong with my logic. The output I want to get is

ROOF1  ROOF2    ROOF3  GROUND GROUND GROUND GROUND...
WALL1  DOOR     WALL3  GROUND GROUND GROUND GROUND...
GROUND PLYRFRNT GROUND GROUND GROUND GROUND GROUND...
GROUND...


That's basically it...
Yeah, we got that part. But it doesn't expain anything.
closed account (L0Shb7Xj)
Whoops. Just realised. Updated the first post. The first few lines explain it.
Last edited on
I hope this explains what's going on. You're initialising your array incorrectly.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
int main()
{
    int A[10][4] =
    { 5,  6,  7, 13, 13, 13, 13, 13, 13, 13,
      8, 11, 10, 13, 13, 13, 13, 13, 13, 13,
     13,  1, 13, 13, 13, 13, 13, 13, 13, 13,
     13, 13, 13, 13, 13, 13, 13, 13, 13, 13
    };

    int B[10][4] =
    {
        { 5,  6,  7, 13 },
        {13, 13, 13, 13 },
        {13, 13,  8, 11 },
        {10, 13, 13, 13 },
        {13, 13, 13, 13 },
        {13,  1, 13, 13 },
        {13, 13, 13, 13 },
        {13, 13, 13, 13 },
        {13, 13, 13, 13 },
        {13, 13, 13, 13 }
    };

    return 0;
}
closed account (L0Shb7Xj)
Nope, that didn't change anything. I updated the first post again. Maybe this makes it more clear what I want to do.
I think kbw was pointing out that while you thought you were doing this

1
2
3
4
5
6
    int C[10][4] = // broken!
    { { 5,  6,  7, 13, 13, 13, 13, 13, 13, 13},
      { 8, 11, 10, 13, 13, 13, 13, 13, 13, 13},
      {13,  1, 13, 13, 13, 13, 13, 13, 13, 13},
      {13, 13, 13, 13, 13, 13, 13, 13, 13, 13}
    };


you were actually doing B above. Your original version A and B are equivalent.

The version I've posted (C) doesn't compile as the number of elems on each row is two big for the array. Which is why it's good idea to use braces for each row of a 2D array, rather than trusting the compiler to pack things as you want (e.g. help you notice if you inverted your array)

Andy

Last edited on
closed account (L0Shb7Xj)
Thanks, kbw and andywestken!
Initialising the array as int test[4][10]; and changing the function parameters to accept this change helped.
So, well, thanks again!
Cool! While I'm here, a few (well, 5) suggestions:

1. by convention, i, j (and k, if you're 3D) are are used for the x, y, (and z), and in that order. You should alter your functions to you follow it!

(I found the swapping of i and j a bit confusing, on top of the swapping of the array.)

2. Each case of the switch statement in sprite() does exactly the same thing to a different string. If you're intending to make each case do some thing different, fine. Otherwise you should factor the function something like this.

1
2
3
4
5
6
7
8
9
10
void sprite(short i, short j, int spriteId) // reordered i and j
{
    int a;
     
    for (a=0; a<10; a++, i++) // or C++ for (int a=0; a<10; a++, i++)
    {
        gotoxy(i,j);
        cout<<getDisplayString(spriteId);
    }
}


where (e.g.) getSpriteDisplayString is (something like) either:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const char* getSpriteDisplayString(int spriteId)
{
    switch(spriteId)
    {
        // no need for breaks as we're returning
        case 1: return "PLYR FRONT"
        case 2: return "PLYR  LEFT";
        case 2: return "PLYR  RIGHT";
        // etc
        default: { /* I generally handle default outside loop
                      when it's a function, as I like the return
                      at the very end. But you could return
                      here instead. */
        }
        break;
    }
    return "SPRITERROR";
}


or

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const char* getSpriteDisplayString(int spriteId)
{
    const char* displayString = "SPRITERROR";
    switch(spriteId)
    {
        case 1: spriteDisplayName = "PLYR FRONT"; break;
        case 2: spriteDisplayName = "PLYR  LEFT" ; break;
        case 2: spriteDisplayName = "PLYR  RIGHT"; break;
        // etc
        default: { /* Nothing to do, as displayString was
                      initialized to the error value. */
        }
        break;
    }
    return displayString;
}


3. Eliminate the "magic numbers"
http://en.wikipedia.org/wiki/Magic_number_%28programming%29

You're already using defining constants for your commands (PLAY, STOP, UP, ...). You should do the same for your sprite IDs (or whatever you call them).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//etc

const char PLYR_FRONT = 1;
const char PLYR_LEFT  = 3;
const char PLYR_RIGHT = 4;
// etc

// etc

        case PLYR_FRONT: return "PLYR FRONT"
        case PLYR_LEFT : return "PLYR  LEFT";
        case PLYR_RIGHT: return "PLYR  RIGHT";

// etc 


You should also do the same for the array dimension and then use the values in your loops. Then, if you ever want to change the array size, you don't have to touch any of the code to do so.

4. If you know abiut enums, you should use them for the commands, etc rather than const chars

1
2
3
4
5
6
7
8
enum CommandId {
    PLAY=16,
    STOP=-2,
    UP=72,   // of even UP='H'
    DOWN=80, // DOWN='P'
    LEFT=75, // LEFT='K'
    // etc
};


Then use this new enum type for your function parameters, etc (so you can't pass a command id when you mean a sprite id.)

5. If you want to, you can cast the return of getgh() to a char.

While the signature is the same as file input functions, e.g. the C int getc(FILE*stream); and int getchar(), it never returns EOF (-1) to mean error (like the others do). So you know the return is always a char (or a pair of chars, on subsequent calls, it it's a function or arrow key).

From _getch, _getwch (the new name for getch)
http://msdn.microsoft.com/en-us/library/078sfkak%28v=vs.80%29.aspx
Returns the character read. There is no error return.

(If you use MinGW with Code::Blocks, CodeLite, etc rather than the Visual C++, you still link to the Microsoft runtime library (DLL). So the behaviour is the same, irrespective of whether you use the new _getch name or old getch).

Andy
Last edited on
closed account (L0Shb7Xj)
I did not understand this part:


5. If you want to, you can cast the return of getgh() to a char.

While the signature is the same as file input functions, e.g. the C int getc(FILE*stream); and int getchar(), it never returns EOF (-1) to mean error (like the others do). So you know the return is always a char (or a pair of chars, on subsequent calls, it it's a function or arrow key).

From _getch, _getwch (the new name for getch)
http://msdn.microsoft.com/en-us/library/078sfkak%28v=vs.80%29.aspx
Returns the character read. There is no error return.

(If you use MinGW with Code::Blocks, CodeLite, etc rather than the Visual C++, you still link to the Microsoft runtime library (DLL). So the behaviour is the same, irrespective of whether you use the new _getch name or old getch).


But thanks a lot for 1-4. I will take those into account, and it should really help.

And about the swapping of i and j, it was unavoidable at the time, but I should be able to work around that to make my code more readable.

All in all, thanks!
Topic archived. No new replies allowed.