random position problem

i am currently writing a win32 console application game and cant understand why the player and the traps in game get spawned in a row at a random position instead of the traps spawning spread out randomly and the player getting spawned in a random location. i think the problem is with the random coordinates in the TrapLogic function where Tx and Ty (trap coordinate x and trap coordinate y) are generated after we call the x and y (player coordinates 'p') and because of that the traps try to spawn on the player 'p' while the TrapLogic algorithm prevents that and spawns them x+1 forward but yet i still cant figure out how to fix it after hours of messing with that particular function. the code:
#include<iostream>
#include<Windows.h>
#include<time.h>
#include<string>
using namespace std;

const char Corners[4] = { 201,187,188,200 };
const char HorizontalPiece = 205;
const char VerticalPiece = 186;
short x, y;
short Trap[6][12] = {
{ 0,0,0,0,0,0,0,0,0,0,0,0, },
{ 0,0,0,0,0,0,0,0,0,0,0,0, },
{ 0,0,0,0,0,0,0,0,0,0,0,0, },
{ 0,0,0,0,0,0,0,0,0,0,0,0, },
{ 0,0,0,0,0,0,0,0,0,0,0,0, },
{ 0,0,0,0,0,0,0,0,0,0,0,0, }
};
bool kp_up = false, kp_down = false, kp_left = false, kp_right = false;

void gotoxy(int x, int y);
void TrackerTrap(short difficulty);
void TrapLogic(short difficulty);
void Movement();
void Box(short Hight, short Length, short posx, short posy);
void Instructions();
short Menu();
void Board(short difficulty);
bool WinCondition();

int main()
{
Instructions();
system("CLS");
Board(Menu());
}

void gotoxy(int x, int y)
{
HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
COORD position = { x, y };

SetConsoleCursorPosition(hStdout, position);
}

void TrackerTrap(short difficulty)
{

}

void TrapLogic(short difficulty)
{

const char TrapIcon = 177;
short Tx, Ty, Row, Column;
if (difficulty == 1) { difficulty = 12; }
else if (difficulty == 2) { difficulty = 24; }
else if (difficulty == 3) { difficulty = 36; }
for (; difficulty != 0; --difficulty) {
do
{
Tx = (rand() % 48) + 15;
Ty = (rand() % 19) + 1;
} while ((Ty == 1) || (Tx == 15));
for (Row = 0; Row < 6; ++Row) {
for (Column = 0; Column < 12; Column += 2) {
if (((Trap[Row][Column] == Tx) && (Trap[Row][Column + 1] == Ty)) || ((Tx == x) && (Ty == y))) {
Row = 0;
Column = 0;
do
{
Tx = (rand() % 48) + 15;
Ty = (rand() % 19) + 1;
} while ((Ty == 1) || (Tx == 15));
}
}
}
for (Row = 0; Row < 6; ++Row) {
for (Column = 0; Column < 12; Column += 2) {
if (Trap[Row][Column] == 0) {
Trap[Row][Column] = Tx;
Trap[Row][Column + 1] = Ty;
break;
}
}
if (Trap[Row][Column] == Tx) { break; }
}
cout << TrapIcon;
}
}

void Movement()
{
if ((GetAsyncKeyState(VK_UP) & 0x8000) && (kp_up == false))
{
kp_up = true;
if (y != 2)
{
gotoxy(x, y);
cout << " ";
y = y - 1;
gotoxy(x, y);
cout << "P";
}
}
else if ((GetAsyncKeyState(VK_UP) == false))
kp_up = false;

if ((GetAsyncKeyState(VK_DOWN) & 0x8000) && (kp_down == false))
{
kp_down = true;
if (y != 20)
{
gotoxy(x, y);
cout << " ";
y = y + 1;
gotoxy(x, y);
cout << "P";
}
}
else if ((GetAsyncKeyState(VK_DOWN) == false))
kp_down = false;

if ((GetAsyncKeyState(VK_LEFT) & 0x8000) && (kp_left == false))
{
kp_left = true;
if (x != 16)
{
gotoxy(x, y);
cout << " ";
x = x - 1;
gotoxy(x, y);
cout << "P";
}
}
else if ((GetAsyncKeyState(VK_LEFT) == false))
kp_left = false;

if ((GetAsyncKeyState(VK_RIGHT) & 0x8000) && (kp_right == false))
{
kp_right = true;
if (x != 63)
{
gotoxy(x, y);
cout << " ";
x = x + 1;
gotoxy(x, y);
cout << "P";
}
}
else if ((GetAsyncKeyState(VK_RIGHT) == false))
kp_right = false;
}

void Box(short Hight, short Length, short posx, short posy)
{
gotoxy(posx, posy);
cout << Corners[0];
for (short Counter = 0; Counter < (Length - 2); ++Counter) { cout << HorizontalPiece; }
cout << Corners[1];
gotoxy(posx, posy + Hight);
cout << Corners[3];
for (short Counter = 0; Counter < (Length - 2); ++Counter) { cout << HorizontalPiece; }
cout << Corners[2];
++posy;
for (short Counter = 0; Counter < (Hight - 1); ++Counter) {
gotoxy(posx, posy + Counter);
cout << VerticalPiece;
}
--posx;
for (short Counter = 0; Counter < (Hight - 1); ++Counter) {
gotoxy(posx + Length, posy + Counter);
cout << VerticalPiece;
}
}

void Instructions()
{
Box(20, 50, 15, 1);
gotoxy(16, 2);
cout << "Rules: you must go to the finish mark (x) to win";
gotoxy(23, 3);
cout << "if you touch any of the traps you lose.";
gotoxy(16, 5);
cout << "Easy Mode: traps dont move.";
gotoxy(27, 6);
cout << "tracker trap moves randomly.";
gotoxy(16, 8);
cout << "Medium Mode: traps move.";
gotoxy(29, 9);
cout << "tracker trap follows the player";
gotoxy(29, 10);
cout << "slowly.";
gotoxy(16, 12);
cout << "Hard Mode: traps move.";
gotoxy(27, 13);
cout << "tracker trap follows the player";
gotoxy(27, 14);
cout << "faster.";
gotoxy(16, 16);
cout << "Controls: use the arrow keys to navigate.";
gotoxy(16, 18);
system("pause");
}

short Menu()
{
short difficulty;
short posx = 32, posy = 7;
bool kp_Up = true, kp_Down = true, kp_enter = true;
gotoxy(25, 1);
cout << "Welcome to Dungeon Crawl!";
gotoxy(24, 2);
for (short Counter = 0; Counter < 26; ++Counter) { cout << HorizontalPiece; }
gotoxy(27, 4);
cout << "CHOOSE A DIFFICULTY:";
Box(2, 20, 27, 6);
Box(2, 20, 27, 10);
Box(2, 20, 27, 14);
gotoxy(35, 7);
cout << "EASY";
gotoxy(34, 11);
cout << "MEDIUM";
gotoxy(35, 15);
cout << "HARD";
gotoxy(posx, posy);
while (1)
{
if ((GetAsyncKeyState(VK_UP) & 0x8000) && (kp_Up == false))
{
kp_Up = true;
(posy == 7) ? posy = 15 : posy = posy - 4;
gotoxy(posx, posy);
}
else if ((GetAsyncKeyState(VK_UP) == false))
kp_Up = false;

if ((GetAsyncKeyState(VK_DOWN) & 0x8000) && (kp_Down == false))
{
kp_Down = true;
(posy == 15) ? posy = 7 : posy = posy + 4;
gotoxy(posx, posy);
}
else if ((GetAsyncKeyState(VK_DOWN) == false))
kp_Down = false;

if ((GetAsyncKeyState(VK_RETURN) & 0x8000) && (kp_enter == false))
{
kp_enter = true;
break;
}
else if ((GetAsyncKeyState(VK_RETURN) == false))
kp_enter = false;
}
if (posy == 7) { difficulty = 1; return(difficulty); }
else if (posy == 11) { difficulty = 2; return(difficulty); }
else if (posy == 15) { difficulty = 3; return(difficulty); }
}

void Board(short difficulty)
{
system("CLS");
Box(20, 50, 15, 1);
srand((unsigned)time(NULL));
do
{
x = (rand() % 48) + 15;
y = (rand() % 19) + 1;
} while ((y == 1) || (x == 15));
gotoxy(x, y);
cout << "P";
TrapLogic(difficulty);
while (1)
{
Movement();
}
}

bool WinCondition()
{

return 0;
}
Last edited on
brief description:
the project is a game that is called dungeon crawl and it has a player marked as 'p' that is spawned in a random position and a set number of traps are spawned in a random position (but doesn't spawn on the player himself), the number is set by the difficulty in the menu() function and than a tracker trap should be spawned in a random position and follow the player in a set speed according to the difficulty(that is still incomplete and cant spawn on the player directly aswell), if the player touches a traps or the tracker trap touches the player, the player will loose and if the player reaches the randomly spawned x he will win (both are incomplete) and than the wincondition function should pop and give the player an option to play again on the same difficulty, restart the game totally or quit (incomplete).

the approach to the task:
the Box() function is simply an algorithm that i use to enclose things like the menu,instructions,board.
the gotoxy() function is what i use to set a position inside the console.
the Movement() function allows us to move the player 'p' with the arrow keys and doesn't give him to get out of the game board.
the board() function prints the game board calls a random seed and chooses a random position for the player 'p' to get spawned inside the game boards boarders and than call the TrapLogic() function that spawns a set number of traps according to the difficulty that i think is bugged because it doesn't spawn the traps in a random position spread out but in a line after the player 'p'.

what the program does do:
-print the instructions.
-prints the menu and allows to navigate, and returns the correct difficulty value when a difficulty is chosen.
-prints the game board and gives the player the option to navigate around it.
Last edited on
Hi,
Some hints from you are needed so that we can better diagnose your problem.

+ Your brief description of your project
+ What approach & algorithm are you trying to implement in order to get the job done?
+ What your program has managed to do correctly till now (and what it is currently performing poorly or incorrectly)
+ The functions you suspect that they may contain bugs or errors
When posting, please use [code] tags.


To answer your question you need to follow the flow of your program:

    After the Menu() you call Board().

    Board() explicitly positions the player 'P' in a random spot, using gotoxy().
    Board() then calls TrapLogic().

    TrapLogic() uses a loop (12, 24, or 36 iterations) to perform some calculations, but never positions the display cursor.
    At the end of the loop, a 'trap' is written to the console.

That is why you have a P with 12, 24, or 36 'trap's written to the screen.


Now, a quick (hopefully helpful) critique of your design:

gameboard
You have not given enough thought to the way you will keep track of information in your game, particularly the gameboard. All the stuff that happens in your game should modify your gameboard. Then on every output, draw your gameboard to the display.

traps should be items
You do have a 2D array called "Trap", which I think you need to reconsider.
The list of traps should be just that, a simple list (or array). Make sure you have a big enough array for the number of traps you intend to use. Each trap should be treated much like the player - an item with position (in the gameboard), way to display it (to draw it to the gameboard, and way to move it with a behavior function.

random numbers
Getting random numbers properly is also an issue. Your code should look like this:
    tx = get a random number in range ax..bx  
    ty = get a random number in range ay..by  
And not that stuff in a loop. See the FAQ for more about getting a random number properly (includes cut-n-paste code you can use):
http://www.cplusplus.com/faq/beginners/random-numbers/

types
You are using too many integer types. Stick with int unless you have to use another type.

input
GetAsyncKeyState() is a programming trap. You should not be using it!
It is easily very popular because it is very easy to use instead of doing input the correct, but difficult way. If you want simple, use <conio.h>. Example:

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
#include <cctype>
#include <iostream>

#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <conio.h>
#include <windows.h>

int main()
{
  std::cout << "Press some keys\n(Press Esc twice to quit)\n";
  int last = 0;
  bool done = false;
  while (!done)
  {
    int c = _getch();
    switch (c)
    {
      // "Extended" keys
      case 0: case 0xE0:
        switch(c = _getch())
        {
          case 71:  std::cout << "Home\n"; break; 
          case 72:  std::cout << "Up Arrow\n"; break;
          case 73:  std::cout << "PgUp\n"; break;
          case 75:  std::cout << "Left Arrow\n"; break;
          case 77:  std::cout << "Right Arrow\n"; break;
          case 79:  std::cout << "End\n"; break;
          case 80:  std::cout << "Down Arrow\n"; break;
          case 81:  std::cout << "PgDn\n"; break;
          case 82:  std::cout << "Ins/Insert\n"; break;
          case 83:  std::cout << "Del/Delete\n"; break;
          case 133: std::cout << "F11\n"; break;
          case 134: std::cout << "F12\n"; break;
          default:  if (c >= 59 && c <= 68)
                      std::cout << "F" << (c-58) << "\n"; 
                    else
                      std::cout << "Extended key code " << c << "\n"; 
                    break;
        }
        break;
        
      case 8:  std::cout << "Backspace\n"; break;
      case 9:  std::cout << "Tab\n"; break;
      case 13: std::cout << "Enter\n"; break;
      
      case 27: done = (last == 27);
               std::cout << "Esc\n"; 
               break;
               
      default: if (std::isalpha( c ))
                 std::cout << "Alpha " << (char)c << "\n";
               else if (std::isdigit( c ))
                 std::cout << "Number " << (char)c << "\n";
               else
                 std::cout << "Key code " << c << "\n";
               break;
    }
    last = c;
  }
  std::cout << "All done!\n";
}

If you want to do anything fancier you will have to play with ReadConsoleInput() directly, which I don't recommend for your first time through...

Hope this helps.
@5a8Ym3906 thanks for the tip i edited everything so it is more understandable now.
@Duoas again i'm thankful for your help on yet another one of my posts!
i will use and modify the code for the arrow keys and i have some questions if you have the time to answer:
1) i have simplified the game a bit so the traps are not supposed to move do they still need to be treated the same as the player?
2) about the types i have a bit nooby question does usage of the short type to initialize a variable more cost effective than the regular int type in terms of memory ?
3)i am going to use the Board function to check if the players position is the same as the trap or trackers trap position or if the player reached the 'x' in an infinite loop and send a value to the Wincondition function accordingly (wincondition will be changed totally to output a few options like: play again, restart or quit) and wanted to know is it a good idea?
4)should i use the gotoxy() function as an inline function due to it being shorter than the other functions?
5)a question about coding in general should i first write the code to get the job done and than shorten it and make it more effective or should i think about writing the code as effective as possible before it does the job?
P.S: the problem with the TrapLogic was that i didn't put a gotoxy(Tx,Ty) before the cout << TrapIcon but now everything works perfectly.
1) Nope. Just place them on the gameboard. The player must still interact with the gameboard.
2) Probably not. Memory is cheap. Use int.
3) It is difficult to follow run-on sentences. You should be more careful in naming your functions. "Board" is a noun and not descriptive of what it does. A better name might be "Play".
You should have a termination condition that causes the play/board function to terminate, returning to main(). main() itself should have a loop that displays the main menu and reacts to the user's input.
4) No.
5) Neither. You should plan how things are to behave before coding. This takes some skill, though. For your purposes, don't worry about efficiency/effectiveness until it is obvious that you must. Your first programs will always be messy. The ability to write clean code is a skill that you develop over time.

Hope this helps.
it does! thanks for the tips!
i finished the game and forgot to replay.
Topic archived. No new replies allowed.