All files / js rect.js

93.29% Statements 153/164
96.92% Branches 63/65
76.92% Functions 10/13
93.29% Lines 153/164

Press n or j to go to the next uncovered block, b, p or k for the previous block.

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 16573x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 73x 223x 71x 71x 71x 3976x 3976x 71x 223x 223x 223x 223x 223x 223x 73x 73x 73x       73x 73x 73x 1224x 1224x 2445x 2445x 2445x 2445x 2445x 1x 1224x 73x 73x 73x 73x 1638x 1638x 4036x 4036x 4036x 4036x 4036x 1460x 1638x 73x 73x 73x 73x 12942x 12900x 12942x 73x 73x 73x 73x 6x 6x 73x 73x 2370x 2370x 2370x 2370x 431x 2370x 2370x 2370x 2370x 2370x 2370x 2370x 431x 2370x 73x 73x 73x           73x 73x 73x 1224x 1224x 1223x 1223x 1223x 1224x 73x 73x 73x 1375x       1375x 1375x 1238x 1238x 1375x 73x 73x 73x 73x 1224x 1224x 1224x 1224x 1224x 2370x 2370x 2370x 2370x 1224x 1224x 1224x 1224x 141x 141x 141x 141x 1224x 1224x 1224x 478x 478x 478x 478x 1224x 1224x 1224x 282x 282x 282x 282x 1224x 1224x 1224x 474x 474x 474x 474x 1224x 73x 73x 72x 72x 72x 72x  
// rect.js — Rectangle allocator for room placement (port of rect.c)
// Used by makerooms() to find free space for room placement.
// Only RNG call: rn2(rect_cnt) in rnd_rect().
 
import { game } from './gstate.js';
import { COLNO, ROWNO } from './const.js';
import { rn2 } from './rng.js';
 
const XLIM = 4;
const YLIM = 3;
 
// C ref: rect.c:28 init_rect()
export function init_rect() {
    if (!game.nhrect) {
        game.n_rects = Math.trunc((COLNO * ROWNO) / 30);
        game.nhrect = new Array(game.n_rects);
        for (let i = 0; i < game.n_rects; i++) {
            game.nhrect[i] = { lx: 0, ly: 0, hx: 0, hy: 0 };
        }
    }
    game.rect_cnt = 1;
    game.nhrect[0].lx = 0;
    game.nhrect[0].ly = 0;
    game.nhrect[0].hx = COLNO - 1;
    game.nhrect[0].hy = ROWNO - 1;
}
 
// C ref: rect.c:44 free_rect()
export function free_rect() {
    game.nhrect = null;
    game.n_rects = game.rect_cnt = 0;
}
 
// C ref: rect.c:59 get_rect_ind()
export function get_rect_ind(r) {
    const { lx, ly, hx, hy } = r;
    for (let i = 0; i < game.rect_cnt; i++) {
        const rectp = game.nhrect[i];
        if (lx === rectp.lx && ly === rectp.ly
            && hx === rectp.hx && hy === rectp.hy)
            return i;
    }
    return -1;
}
 
// C ref: rect.c:81 get_rect()
// Find a free rectangle that includes the given one.
export function get_rect(r) {
    const { lx, ly, hx, hy } = r;
    for (let i = 0; i < game.rect_cnt; i++) {
        const rectp = game.nhrect[i];
        if (lx >= rectp.lx && ly >= rectp.ly
            && hx <= rectp.hx && hy <= rectp.hy)
            return rectp;
    }
    return null;
}
 
// C ref: rect.c:103 rnd_rect()
// RNG: rn2(rect_cnt)
export function rnd_rect() {
    if (game.rect_cnt <= 0) return null;
    return game.nhrect[rn2(game.rect_cnt)];
}
export function get_rect_cnt() { return game.rect_cnt; }
 
// C: within_bounded_area(x, y, lx, ly, hx, hy) — check if point is within bounds
export function within_bounded_area(x, y, lx, ly, hx, hy) {
    return (x >= lx && x <= hx && y >= ly && y <= hy);
}
 
// C ref: rect.c:115 intersect()
function intersect(r1, r2, 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;
}
 
// C ref: rect.c:133 rect_bounds()
export function rect_bounds(r1, r2, r3) {
    r3.lx = Math.min(r1.lx, r2.lx);
    r3.ly = Math.min(r1.ly, r2.ly);
    r3.hx = Math.max(r1.hx, r2.hx);
    r3.hy = Math.max(r1.hy, r2.hy);
}
 
// C ref: rect.c:146 remove_rect()
export function remove_rect(r) {
    const ind = get_rect_ind(r);
    if (ind >= 0) {
        game.rect_cnt--;
        game.nhrect[ind] = { ...game.nhrect[game.rect_cnt] };
    }
}
 
// C ref: rect.c:160 add_rect()
export function add_rect(r) {
    if (game.rect_cnt >= game.n_rects) {
        // impossible("n_rects may be too small.")
        return;
    }
    if (get_rect(r))
        return;
    game.nhrect[game.rect_cnt] = { ...r };
    game.rect_cnt++;
}
 
// C ref: rect.c:181 split_rects()
// Split r1 to accommodate r2 (r2 is included in r1).
export function split_rects(r1, r2) {
    const old_r = { ...r1 };
    remove_rect(r1);
 
    // Walk down since rect_cnt & rects[] will change
    for (let i = game.rect_cnt - 1; i >= 0; i--) {
        const r = { lx: 0, ly: 0, hx: 0, hy: 0 };
        if (intersect(game.nhrect[i], r2, r))
            split_rects(game.nhrect[i], r);
    }
 
    // Top piece
    if (r2.ly - old_r.ly - 1
        > (old_r.hy < ROWNO - 1 ? 2 * YLIM : YLIM + 1) + 4) {
        const r = { ...old_r };
        r.hy = r2.ly - 2;
        add_rect(r);
    }
    // Left piece
    if (r2.lx - old_r.lx - 1
        > (old_r.hx < COLNO - 1 ? 2 * XLIM : XLIM + 1) + 4) {
        const r = { ...old_r };
        r.hx = r2.lx - 2;
        add_rect(r);
    }
    // Bottom piece
    if (old_r.hy - r2.hy - 1
        > (old_r.ly > 0 ? 2 * YLIM : YLIM + 1) + 4) {
        const r = { ...old_r };
        r.ly = r2.hy + 2;
        add_rect(r);
    }
    // Right piece
    if (old_r.hx - r2.hx - 1
        > (old_r.lx > 0 ? 2 * XLIM : XLIM + 1) + 4) {
        const r = { ...old_r };
        r.lx = r2.hx + 2;
        add_rect(r);
    }
}
 
export function init_rect_globals() {
    game.nhrect = null;
    game.n_rects = 0;
    game.rect_cnt = 0;
}