воскресенье, 24 мая 2015 г.

Roguelike. Карты, стены.

Способ определения типа стен и глубины вложенности областей карты. Входные данные - карта описанная как пустые и заполненные области. Задача - определить границы стен, их ориентацию, углы и прочее. Также выделить замкнутые области и определить глубину их вложенности (на самом деле интереснее определить чётность этих областей)

Легенда:

  • □ ═║ ╔╦╗ ╠╬╣ ╚╩╝стены
  • 1-9области по уровню вложенности

Начальные данные:



Итоговая карта:




Исходный код (открыть)

module.exports = function (rawMap) {
    rawMap = rawMap.map(function (line) {
        return line.split("");
    });

    var len = rawMap[0].length;
    var hgh = rawMap.length;

    var zones = [];
    var walls = [];
    var map = [];

    rawMap.forEach(function (row, y) {
        map[y] = [];

        row.forEach(function (cell, x) {
            map[y][x] = {
                type: cell == "*" ? "wall" : "floor",
                x: x,
                y: y,
                level: 99
            };
        });
    });

    map[0][0].level = 1;
    zones.push(map[0][0]);

    var checkZone = function (x, y, type, level) {
        if (x < 0 || y < 0 || x >= len || y >= hgh) return false;

        var zone = map[y][x];

        if (zone.type != type) level++;

        if (zone.level > level) {
            zone.level = level;

            if (zone.type == type) zones.unshift(zone);
            else zones.push(zone);
        }

        return zone.type == type;
    };

    var checkNeibs = function (zone) {
        var closed = true;
        [[-1, -1], [-1, 0], [-1, 1], [0, -1], [0, 1], [1, -1], [1, 0], [1, 1]].forEach(function (move) {
            closed = checkZone(zone.x + move[0], zone.y + move[1], zone.type, zone.level) && closed;
        });
        zone.closed = closed;

        if (!zone.closed) {
            if (zone.type == "wall") walls.push(zone);
        }
    };

    while (zones.length) checkNeibs(zones.shift());

    //                 0    1    2    3    4    5    6    7    8    9    10   11   12   13   14   15
    var wallConfig = ["□", "═", "║", "╗", "═", "═", "╔", "╦", "║", "╝", "║", "╣", "╚", "╩", "╠", "╬"];

    var top = 1 << 3;
    var right = 1 << 2;
    var bottom = 1 << 1;
    var left = 1;

    walls.map(function (wall) {
        wall.left = map[wall.y][wall.x - 1];
        wall.right = map[wall.y][wall.x + 1];
        wall.top = map[wall.y - 1][wall.x];
        wall.bottom = map[wall.y + 1][wall.x];

        wall.left = wall.left.type == "wall" && !wall.left.closed;
        wall.right = wall.right.type == "wall" && !wall.right.closed;
        wall.top = wall.top.type == "wall" && !wall.top.closed;
        wall.bottom = wall.bottom.type == "wall" && !wall.bottom.closed;

        var type = 0;
        type += wall.top ? top : 0;
        type += wall.right ? right : 0;
        type += wall.bottom ? bottom : 0;
        type += wall.left ? left : 0;
        wall.typeNum = type;

        return wall;
    }).forEach(function (wall) {
        var neib;

        if (wall.typeNum == 14) { // ╠
            neib = map[wall.y][wall.x + 1];
            if (neib.typeNum == 11) {
                wall.typeNum = 8;
                neib.typeNum = 8;
            }
        } else if (wall.typeNum == 11) { // ╣
            neib = map[wall.y][wall.x - 1];
            if (neib.typeNum == 14) {
                wall.typeNum = 10;
                neib.typeNum = 10;
            }
        } else if (wall.typeNum == 7) { // ╦
            neib = map[wall.y + 1][wall.x];
            if (neib.typeNum == 13) {
                wall.typeNum = 5;
                neib.typeNum = 5;
            }
        } else if (wall.typeNum == 13) { // ╩
            neib = map[wall.y - 1][wall.x];
            if (neib.typeNum == 7) {
                wall.typeNum = 5;
                neib.typeNum = 5;
            }
        }

        wall.symbol = wallConfig[wall.typeNum];
    });

    return map;
}

Комментариев нет:

Отправить комментарий