/* NetHack 5.0	rect.c	$NHDT-Date: 1596498203 2020/08/03 23:43:23 $  $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.14 $ */
/* Copyright (c) 1990 by Jean-Christophe Collet                   */
/* NetHack may be freely redistributed.  See license for details. */

#include "hack.h"

int get_rect_ind(NhRect *);

staticfn boolean intersect(NhRect *, NhRect *, NhRect *);

/*
 * In this file, we will handle the various rectangle functions we
 * need for room generation.
 */

#define XLIM 4
#define YLIM 3

static NhRect *rect = (NhRect *) 0;
static int n_rects = 0;
static int rect_cnt;

/*
 * Initialization of internal structures. Should be called for every
 * new level to be build...
 */

void
init_rect(void)
{
    if (!rect) {
        n_rects = (COLNO * ROWNO) / 30;
        rect = (NhRect *) alloc(sizeof(NhRect) * n_rects);
        if (!rect)
            panic("Could not alloc rect");
    }

    rect_cnt = 1;
    rect[0].lx = rect[0].ly = 0;
    rect[0].hx = COLNO - 1;
    rect[0].hy = ROWNO - 1;
}

void
free_rect(void)
{
    if (rect)
        free(rect);
    rect = 0;
    n_rects = rect_cnt = 0;
}


/*
 * Search Index of one precise NhRect.
 *
 */

int
get_rect_ind(NhRect *r)
{
    NhRect *rectp;
    int lx, ly, hx, hy;
    int i;

    lx = r->lx;
    ly = r->ly;
    hx = r->hx;
    hy = r->hy;
    for (i = 0, rectp = &rect[0]; i < rect_cnt; i++, rectp++)
        if (lx == rectp->lx && ly == rectp->ly && hx == rectp->hx
            && hy == rectp->hy)
            return i;
    return -1;
}

/*
 * Search a free rectangle that include the one given in arg
 */

NhRect *
get_rect(NhRect *r)
{
    NhRect *rectp;
    int lx, ly, hx, hy;
    int i;

    lx = r->lx;
    ly = r->ly;
    hx = r->hx;
    hy = r->hy;
    for (i = 0, rectp = &rect[0]; i < rect_cnt; i++, rectp++)
        if (lx >= rectp->lx && ly >= rectp->ly && hx <= rectp->hx
            && hy <= rectp->hy)
            return rectp;
    return 0;
}

/*
 * Get some random NhRect from the list.
 */

NhRect *
rnd_rect(void)
{
    return rect_cnt > 0 ? &rect[rn2(rect_cnt)] : 0;
}

/*
 * Search intersection between two rectangles (r1 & r2).
 * return TRUE if intersection exist and put it in r3.
 * otherwise returns FALSE
 */

staticfn boolean
intersect(NhRect *r1, NhRect *r2, NhRect *r3)
{
    if (r2->lx > r1->hx || r2->ly > r1->hy || r2->hx < r1->lx
        || r2->hy < r1->ly)
        return FALSE;

    r3->lx = (r2->lx > r1->lx ? r2->lx : r1->lx);
    r3->ly = (r2->ly > r1->ly ? r2->ly : r1->ly);
    r3->hx = (r2->hx > r1->hx ? r1->hx : r2->hx);
    r3->hy = (r2->hy > r1->hy ? r1->hy : r2->hy);

    if (r3->lx > r3->hx || r3->ly > r3->hy)
        return FALSE;
    return TRUE;
}

/* Put the rectangle containing both r1 and r2 into r3 */
void
rect_bounds(NhRect r1, NhRect r2, NhRect *r3)
{
    r3->lx = min(r1.lx, r2.lx);
    r3->ly = min(r1.ly, r2.ly);
    r3->hx = max(r1.hx, r2.hx);
    r3->hy = max(r1.hy, r2.hy);
}

/*
 * Remove a rectangle from the list of free NhRect.
 */

void
remove_rect(NhRect *r)
{
    int ind;

    ind = get_rect_ind(r);
    if (ind >= 0)
        rect[ind] = rect[--rect_cnt];
}

/*
 * Add a NhRect to the list.
 */

void
add_rect(NhRect *r)
{
    if (rect_cnt >= n_rects) {
        impossible("n_rects may be too small.");
        return;
    }
    /* Check that this NhRect is not included in another one */
    if (get_rect(r))
        return;
    rect[rect_cnt] = *r;
    rect_cnt++;
}

/*
 * Okay, here we have two rectangles (r1 & r2).
 * r1 was already in the list and r2 is included in r1.
 * What we want is to allocate r2, that is split r1 into smaller rectangles
 * then remove it.
 */

void
split_rects(NhRect *r1, NhRect *r2)
{
    NhRect r, old_r;
    int i;

    old_r = *r1;
    remove_rect(r1);

    /* Walk down since rect_cnt & rect[] will change... */
    for (i = rect_cnt - 1; i >= 0; i--)
        if (intersect(&rect[i], r2, &r))
            split_rects(&rect[i], &r);

    if (r2->ly - old_r.ly - 1
        > (old_r.hy < ROWNO - 1 ? 2 * YLIM : YLIM + 1) + 4) {
        r = old_r;
        r.hy = r2->ly - 2;
        add_rect(&r);
    }
    if (r2->lx - old_r.lx - 1
        > (old_r.hx < COLNO - 1 ? 2 * XLIM : XLIM + 1) + 4) {
        r = old_r;
        r.hx = r2->lx - 2;
        add_rect(&r);
    }
    if (old_r.hy - r2->hy - 1 > (old_r.ly > 0 ? 2 * YLIM : YLIM + 1) + 4) {
        r = old_r;
        r.ly = r2->hy + 2;
        add_rect(&r);
    }
    if (old_r.hx - r2->hx - 1 > (old_r.lx > 0 ? 2 * XLIM : XLIM + 1) + 4) {
        r = old_r;
        r.lx = r2->hx + 2;
        add_rect(&r);
    }
}

/*rect.c*/
