1

I'm working on a project that involves developing a game similar to nethack, I have to write it only in C (for now anyway). The idea is that I need to create rooms that are made up of periods ('.'). These rooms need to be placed randomly in the terminal, which I have a grid (basically the dungeon). I've written some code, so hopefully you'll be more encouraged to help me with my problem. The code is posted below and I'll explain it in detail and my problem below it.

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdbool.h>
#include "dungeon.h"

#define HEIGHT 105
#define WIDTH 160
#define N 10

/*Declared the functions that I created.*/
void createDungeon();
bool doOverlap(point l1, point r1, point l2, point r2);
void makeRoom(room aRoom);

int main() {
    srand(time(NULL));
    createDungeon();
    return 0;
}
/*
* Created a function that initializes the dungeon. Each room struct
* has four points that make up the room, and are assigned.
*/
void createDungeon() {
    char dungeonGrid[HEIGHT][WIDTH];
    //room *rooms = malloc(10 * sizeof(room));
    //room *rooms_t = malloc(10 * sizeof(room));
    room rooms[N];
    int i, y, x, q, r, f;
    int a;
    int counter = 0;

    makeRoom(rooms[counter]);

    for (int i = 1; i < 10; i++) {
        makeRoom(rooms[i]);

        if (doOverlap(rooms[i].top_left, rooms[i].bottom_right, rooms[counter].top_left, rooms[counter].bottom_right)) {
            makeRoom(rooms[i]);
            counter++;
        }
    }


    /*for (i = 0; i < 10; i++) {
        int height = (rand() % (10 + 1 - 5)) + 5;
        int width = (rand() % (15 + 1 - 7)) + 7;

        int randomY = (rand() % (105 + 1 - 0)) + 0;
        int randomX = (rand() % (160 + 1 - 0)) + 0;

        rooms[i].top_left.y = randomY;
        rooms[i].top_left.x = randomX;
        rooms[i].top_right.y = randomY;
        rooms[i].top_right.x = randomX + width;
        rooms[i].bottom_left.y = randomY + height;
        rooms[i].bottom_left.x = randomX;
        rooms[i].bottom_right.y = randomY + height;
        rooms[i].bottom_right.x = randomX + width;


    /*Created two for loops that goes through the dungeon grid and puts a space.*/
    for (y = 0; y < HEIGHT; y++) {
        for (x = 0; x < WIDTH; x++) {
            dungeonGrid[y][x] = ' ';
        }
    }
    /*Created three for loops that go through the dungeon grid and assigns a '.' for each
    * point in the room to the grid.
    */
    for (y = 0; y < HEIGHT; y++) {
        for (x = 0; x < WIDTH; x++) {
            for (a = 0; a < 10; a++) {
                if (rooms[a].top_left.y <= y && y <= rooms[a].bottom_left.y && rooms[a].top_left.x <= x && rooms[a].top_right.x >= x) {
                    dungeonGrid[y][x] = '.';
                }
            }
        }
    }

    /*These two for loops print out every character that it finds in the dungeon grid.*/
    for (y = 0; y < HEIGHT; y++) {
        for (x = 0; x < WIDTH; x++) {
            printf("%c", dungeonGrid[y][x]);
        }
        printf("\n");
    }

}


/*Created a boolean method that deals with the rooms overlapping that takes in
* 4 points, l1 = top left point and r1 = bottom right point of the first rectangle,
* l2 = top left point, and r2 = bottom right point of the second rectangle.
*/
bool doOverlap(point l1, point r1, point l2, point r2) {
    if (l1.x > r2.x || l2.x > r1.x) {
        return false;
    }

    if (l1.y < r2.y || l2.y < r1.y) {
        return false;
    }

    return true;
}

void makeRoom(room aRoom)
{
    int height = (rand() % (10 + 1 - 5)) + 5;
    int width = (rand() % (15 + 1 - 7)) + 7;

    int randomY = (rand() % (105 + 1 - 0)) + 0;
    int randomX = (rand() % (160 + 1 - 0)) + 0;

    aRoom.top_left.y = randomY;
    aRoom.top_left.x = randomX;
    aRoom.top_right.y = randomY;
    aRoom.top_right.x = randomX + width;
    aRoom.bottom_left.y = randomY + height;
    aRoom.bottom_left.x = randomX;
    aRoom.bottom_right.y = randomY + height;
    aRoom.bottom_right.x = randomX + width;
}

Now let me explain my code a little bit, at first I only had 2 functions, the createdungeon() function and the doOverlapping() function, because if you look at the commented block of my code, you will see that is how I initially create all of my rooms and I put them in a room * array that was malloc'd. This way actually worked in the sense that I was able to print out all 10 of my rooms in the terminal, but the problem was the overlapping, because in the code I initially made it so that you create all the rooms first, and it would be hard to compare, so I create a third function called makeRoom(), and this would make just one room, and so the idea is that I would make one room and place it randomly somewhere, and then start a for loop where i = 1 and compare it with the previous room. The initial that I placed, I used a counter on it, so that if there is an overlapping, then make another room at that 'i', and then increase the counter so that you keep comparing the room that you are trying to place, with the room that is already placed right before it.

The problem right now, is that no rooms are showing up in my terminal, and I'm not sure why. Any help would be appreciated.

EDIT: I forgot to show my header that I made

#ifndef DUNGEON_DUNGEON_H
#define DUNGEON_DUNGEON_H

typedef struct Point {
    int y;
    int x;
} point;

typedef struct Room {
    point top_left;
    point top_right;
    point bottom_left;
    point bottom_right;
} room;

#endif //DUNGEON_DUNGEON_H
DsDude
  • 135
  • 1
  • 8
  • Be thankful you are writing in all in C -- you have all the control you will ever need. – David C. Rankin Jan 19 '18 at 23:20
  • note - While not an error, the standard coding style for C avoids the use of `camelCase` or `MixedCase` variable names in favor of all *lower-case* while reserving *upper-case* names for use with macros and constants. – David C. Rankin Jan 19 '18 at 23:26

1 Answers1

3

As your title implies, the issue is that you are passing a copy of the data to your makeRoom function, rather than a pointer to the actual data, so changes in your makeRoom function are not reflected in the calling function.

You can rewrite your makeRoom function to accept and use a pointer, like:

void makeRoom(room *aRoom)
{
    int height = (rand() % (10 + 1 - 5)) + 5;
    int width = (rand() % (15 + 1 - 7)) + 7;

    int randomY = (rand() % (105 + 1 - 0)) + 0;
    int randomX = (rand() % (160 + 1 - 0)) + 0;

    aRoom->top_left.y = randomY;
    aRoom->top_left.x = randomX;
    aRoom->top_right.y = randomY;
    aRoom->top_right.x = randomX + width;
    aRoom->bottom_left.y = randomY + height;
    aRoom->bottom_left.x = randomX;
    aRoom->bottom_right.y = randomY + height;
    aRoom->bottom_right.x = randomX + width;
}

Then when you call it, you pass the element by reference, like:

makeRoom(&rooms[counter]);
EdmCoff
  • 3,506
  • 1
  • 9
  • 9
  • Well... it's actually still pass by value (that's all C has), but you are passing the *address of* the struct as a parameter, so the copy of the pointer in the function contains the same address as the original allowing changes made to be available back in the caller (more a simulated pass by reference `:)` – David C. Rankin Jan 19 '18 at 23:23
  • ok I see, I'm having trouble understanding this error: error: request for member ‘top_right’ in something not a structure or union aRoom.top_right.x = randomX + width; I'm getting it for all of the points for the room, I think it had something to do with how I'm retrieving the info from the struct, but I'm not sure – DsDude Jan 19 '18 at 23:39
  • @DavidC.Rankin That seems unnecessary pedantic. I mean, you're right that the address itself is a value, but that address is a reference to the data that we care about. – EdmCoff Jan 19 '18 at 23:40
  • @DsDude It sounds like you only changed the function definition. You also need to change the "aRoom.top_right" bits to "aRoom->top_right" (or aRoom[0].top_right"). (See all my edits in the function.) – EdmCoff Jan 19 '18 at 23:41
  • Yes, it's pedantic, and I knew what you meant and I voted for your question, but sometimes the details matter. – David C. Rankin Jan 19 '18 at 23:42
  • @EdmCoff Thank you for helping me with understand pointers and referencing. This solve one part of my problem, since I wanted to be able to create rooms individually instead of all together at the same time, but my problem with overlapping rooms still exists, is my doOverlapping function incorrect? I read up on it and I thought I had the right idea by checking the corners, so I'm not sure what it wrong. – DsDude Jan 20 '18 at 03:02
  • 1
    No, using the logic from the first answer [here](https://stackoverflow.com/questions/306316/determine-if-two-rectangles-overlap-each-other) I think your condition in the function should be `if (l1.x <= r2.x && r1.x >= l2.x && l1.y >= r2.y && r1.y <= l2.y) { return false; } else {return true;}`. – EdmCoff Jan 20 '18 at 03:46
  • Having said that, I'm not sure I understand why you only want to check for overlap against the most recent room (e.g. room 8 can't overlap with room 7, but room 8 can overlap with room 6). I also think if doOverlap returns true you should increment your counter _otherwise_ remake the room (as opposed to what you have now, which is to do both ops if doOverlap returns true and nothing if it returns false.) – EdmCoff Jan 20 '18 at 03:47
  • @EdmCoff It's still overlapping, it must be something with my loop, all I want to do is make the first room, cause it can be anywhere, and then compare the next room to the first one, and then compare the third room with the last two, and compare the fourth room with the last three, just a simple loop process like this, but I can't seem to get it right, any insight would be helpful. – DsDude Jan 20 '18 at 04:31
  • 1
    Sorry, I think I made a mistake in my previous comment. I think it should be: `(l1.x <= r2.x && r1.x >= l2.x && l1.y <= r2.y && r1.y >= l2.y)` Also, I think you want your loop logic to be more like: for (i = 0; i < 10; ) { makeRoom(&rooms[i]); bool overlap = false; for (counter = 0; counter < i; ++counter) { if (!doOverlap(rooms[i].top_left, rooms[i].bottom_right, rooms[counter].top_left, rooms[counter].bottom_right)) { overlap = true; break; } } if (!overlap) { ++i; } } – EdmCoff Jan 20 '18 at 05:36
  • Ok I see, i didn't think about making a bool variable as a switch, that's clever, I was trying to figure out how to do it with two for loops and the switch is what I was missing, thank you so much, it works! I gave your answer a green check mark! – DsDude Jan 20 '18 at 06:25