Создание комнаты для подземелья дает неправильные размеры/отсутствие стен

Я использую Python 2.7 libtcod для создания Roguelike, и в настоящее время пытаюсь получить функцию для создания отдельная комната на основе заданного номера этажа, набора координат x1, x2, y1 и y2. Ожидаемое поведение состоит в том, что я должен получить комнату, ограниченную стенами и иначе заполненную пустотой. Например, makeRoom(0, 1, 1, 10, 10) должен дать:

----------
|********|
|********|
|********|
|********|
|********|
|********|
|********|
|********|
----------

Однако вместо этого я получаю комнату такой же ширины, как пол подземелья, учитывая только высоту, а боковые стены никогда не достигаются. Поэтому вместо этого я получаю примерно такую ​​аранжировку:

---------------------------
***************************
***************************
***************************
***************************
***************************
***************************
***************************
***************************
---------------------------

Изменение общей доступной ширины пола подземелья приводит к тому, что комната сжимается или увеличивается по горизонтали, независимо от того, какой размер я задаю. Боковые стены никогда не появляются независимо от того, как я настраиваю диапазоны, где я их настраиваю или что я комментирую или раскомментирую. Короче говоря, всегда соблюдаются только высота и верх/низ, независимо от того, что я пытаюсь сделать.

base.py (основной игровой цикл):

import sys
import libtcodpy as libtcod
import entity
import dungeon

SCREEN_WIDTH = 80
SCREEN_HEIGHT = 50
LIMIT_FPS = 20

libtcod.console_set_custom_font('../dejavu10x10_gs_tc.png', libtcod.FONT_TYPE_GRAYSCALE | libtcod.FONT_LAYOUT_TCOD)
libtcod.console_init_root(SCREEN_WIDTH, SCREEN_HEIGHT, 'MadNet Zero', False)
libtcod.console_set_foreground_color(0, libtcod.white)

# The buggy functions
saturnSeven = dungeon.Dungeon(5)
saturnSeven.makeRoom(0, 1, 1, 10, 10)

player = entity.Player(25,25,3,4,0)
libtcod.console_print_left(0, player.X, player.Y, libtcod.BKGND_NONE, '@')
libtcod.console_flush()

while not libtcod.console_is_window_closed():
    libtcod.console_set_foreground_color(0, libtcod.white)
    #clear the player's old position
    libtcod.console_print_left(0, player.X, player.Y, libtcod.BKGND_NONE, ' ')

    #print terrain
    for y in range(len(saturnSeven.floor[player.Z][0])):
        for x in range(len(saturnSeven.floor[player.Z])):
            symbol = saturnSeven.getTerrainSymbol(x,y,player.Z)
            libtcod.console_print_left(0, x, y, libtcod.BKGND_NONE, symbol)
    libtcod.console_print_left(0, player.X, player.Y, libtcod.BKGND_NONE, player.char)
    libtcod.console_flush()

dungeon.py (делает основную часть работы):

# Define terrain types as a pseudo-enum
wall, empty, solid = range(3)
class Cell(object):
    def __init__(self, terrain, items):
        self.terrain = terrain
        self.items = items
    def isPassable(self):
        if self.terrain != wall:
            return True
        else:
            return False

class Dungeon(object):
    def __init__(self, numfloors):
        self.MAXFLOORS = numfloors
        self.floor = [None]*numfloors
        for i in range(numfloors):
            self.floor[i] = makeFloor(20,20)

    def makeRoom(self, floorNum, Xmin, Ymin, Xmax, Ymax):
        #inner area
        for x in range(Xmin+1, Xmax):
            for y in range(Ymin+1, Ymax):
                self.floor[floorNum][x][y] = Cell(empty, None)
        #top/bottom wall
        for x in range(Xmin,Xmax+1):
            self.floor[floorNum][x][Ymin] = Cell(wall, None)
            self.floor[floorNum][x][Ymax] = Cell(wall, None)
        #left/right wall
        for y in range(Ymin, Ymax+1):
            self.floor[floorNum][Xmin][y] = Cell(wall, None)
            self.floor[floorNum][Xmax][y] = Cell(wall, None)

    def getTerrainSymbol(self, X, Y, Z):
        if self.floor[Z][X][Y] == None:
            return ' '
        if self.floor[Z][X][Y].terrain == wall:
            return '#'
        if self.floor[Z][X][Y].terrain == solid:
            return ' '
        if self.floor[Z][X][Y].terrain == empty:
            return '.'


def makeFloor(Xmax, Ymax):
    return [[Cell(solid, None)]*Xmax]*Ymax

Я исключил графику как проблему; само подземелье определенно не так, а не то, как оно отображается на экране. Однако я не могу найти никаких причин, по которым алгоритм должен быть неправильным.

РЕДАКТИРОВАТЬ: исходная версия кода, которая дала приведенную выше диаграмму, имела часть «внутренней области» под частью, из которой сделаны стены; размещение его сверху, как я сделал, приводит к тому, что вся комната состоит из стен, но все же слишком широкая. Насколько я могу судить, они должны давать эквивалентные результаты; они не.


person tacoman    schedule 03.02.2012    source источник
comment
Пробовали ли вы смотреть на self.floor до и после каждого из блоков, из которых состоит комната?   -  person Nobody moving away from SE    schedule 03.02.2012
comment
У меня был цикл, который дал мне координаты, где он должен был писать отдельные сегменты стены, и я прокомментировал/раскомментировал каждую часть функции по очереди, чтобы увидеть разные результаты. Даже если я сужу его до одной строки, эта строка все равно окажется настолько широкой, насколько это возможно физически, а не такой широкой, как должна быть.   -  person tacoman    schedule 03.02.2012


Ответы (1)


Ваша проблема (или по крайней мере одна из них) заключается в определении makeFloor. Попробуйте это вместо этого:

def makeFloor(Xmax, Ymax):
    return [[Cell(solid,None) for i in range(Xmax)]
            for j in range(Ymax)]

Объяснение: Если вы сделаете [x]*10, вы получите список, содержащий 10 элементов, каждый из которых равен x -- тот самый x. Если вы измените одно, то и другие изменятся. Точно так же, если вы сделаете [[x]]*10, вы получите список, содержащий 10 подсписков, каждый из которых является одним и тем же подсписком — опять же, изменение одного изменит их все.

person Edward Loper    schedule 03.02.2012
comment
Это было именно так: комната настроена именно так, как она должна с вашим определением. Спасибо! - person tacoman; 03.02.2012