Вопрос

Мне нужна карта радиусом 2, нарисованная от текущей комнаты игрока в MUD, который я создаю на Python (или больше, если возможно).Комнаты представляют собой контейнеры с self.exits = {'west':1, 'north':2} где ключ — это направление, в котором находится значение (UID соседней комнаты).Комнаты соединены между собой только таким образом.Игрок с self.location, равным 0, может ввести «n», и его местоположение, основанное на указанной выше переменной, тогда будет равно 2, а к содержимому этой комнаты будет добавлен UID игрока.

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

    [ ]
     |
[ ]-[u]

я достиг этот часть, так как это всего лишь радиус 1.Вот небольшой (сильно измененный для публикации здесь) фрагмент того, как я это сделал, и вы поймете, почему я публикую это плохой код.

mloc = '[u]'
mn = '   '
mw = '   '
spn= ' '
spw= ' '
for Exit in room.exits.keys():
  if Exit == 'north':
    mn = '[ ]'
    spn = '|'
  if Exit == 'west': 
    mw = '[ ]-'
# player.hear() is our function for printing a line to the player's screen
player.hear('    '+mn)
player.hear('     '+sp)
player.hear(mw+mloc)

В своем безумии мне удалось сделать эту работу со всеми 8 разными направлениями (диагонали, не считая вверх и вниз).Но тогда мне придется зацикливаться на комнатах, которые я просто проанализировал со своим первым для цикла, а затем нарисовать их, а затем расстаться, а затем принять во внимание перекрытие (SP) таких тазовых тапов, таких как «» или ' | '' Если есть пути, которые пересекают друг друга.Эта небольшая задача сразу же превратилась в кошмар, и прежде чем я закончил, потребовалось еще 200 строк.

Еще одним препятствием является то, что я могу печатать только построчно.Итак, если высота карты составляет 50 символов, мне нужно иметь player.hear() на 50 строк, против чего я не против.Просто имейте это в виду, прежде чем публиковать ответ.

Я также не придирчив к форматированию.Мне просто нужна «карта с первого взгляда», которая поможет игрокам во время путешествий по миру.

Спасибо ребята.Надеюсь, я предоставил достаточно информации.Дайте мне знать, если нет.(Вот ссылка на весь (незаконченный и УЖАСНЫЙ) модуль, на который я ссылаюсь. Map.py

Это было полезно?

Решение

Этот код находится в серьезной проблеме.Начнем проектирование с нуля.Мы надеемся, что это послужит хорошим уроком о том, как проектировать и создавать классы и структуры данных.

Для начала вам следует организовать свой код вокруг Map class, который затем представляет ваши комнаты в виде сетки.Вам не следует думать о «комнате 1», «комнате 2» и т. д. (что очень сложно отследить на карте), а лучше думать о комнатах с точки зрения координат.

Итак, есть несколько возможных функций, которые мы игнорируем вначале, в том числе игрок, который видит только те комнаты, в которых он был, игрок, остающийся в центре карты, и диагональные пути.Если они вам нужны, вы можете добавить их позже, когда основные функции заработают.На данный момент мы стремимся к чему-то примерно такому:

[ ]-[u] [ ] [ ]
 |
[ ]-[ ]-[ ] [ ]
     |
[ ]-[ ]-[ ] [ ]
 |
[ ]-[ ]-[ ]-[ ]

То есть мы представляем это в виде сетки, в которой одни комнаты соединены, а другие нет.Пусть у каждой комнаты будет пара координат, примерно так:

      0   1   2   3
   0 [ ]-[u] [ ] [ ]
      |
   1 [ ]-[ ]-[ ] [ ]
          |
   2 [ ]-[ ]-[ ] [ ]
      |
   3 [ ]-[ ]-[ ]-[ ]

Пусть x будет сверху, а y — сбоку.Вверху слева — (0, 0), тот, у которого [u] в нем (0, 1).

Теперь, каковы компоненты нашего Map сорт?

  1. высота карты:целое число

  2. ширина карты:целое число)

  3. игрок_x, игрок_y:координаты игрока

  4. возможные пути:список пар комнат, между которыми мы можем перемещаться.Приведенная выше карта будет представлена ​​как:

    [((0, 0), (1, 0)), ((0, 0), (1, 0)), ((1, 0), (1, 1)), ((1, 1), (2, 1)),
     ((1, 0), (1, 2)), ((0, 2), (1, 2)), ((1, 2), (2, 2)), ((0, 2), (0, 3)),
     ((0, 3), (1, 3)), ((1, 3), (2, 3)), ((2, 3), (3, 3))]
    

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

Итак, теперь, когда у нас есть дизайн, давайте напишем это Map сорт!

Я могу придумать четыре метода, которые нам нужны: print_map, move, и инициализатор.Инициализация проста:просто установите четыре атрибута, которые мы перечислили выше:

class Map:
    def __init__(self, height, width, player_x, player_y, paths):
        self.height = height
        self.width = width
        self.x = player_x
        self.y = player_y
        self.paths = paths

Сейчас, move это довольно просто.Учитывая направление n/e/s/w:

    def move(self, direction):
        if direction == "n":
            if ((self.x, self.y - 1), (self.x, self.y)) not in self.paths:
                print "Cannot go north"
            else:
                self.y -= 1

А move функция для «севера» просто проверяет, есть ли путь к комнате над той, в которой мы находимся.

Теперь самое интересное:распечатка карты.Вы делаете это, перебирая строки (от 0 до self.height) и по столбцам (от 0 до self.width). (Примечание:ты не можешь использовать print в этой ситуации, поскольку после строки автоматически помещается новая строка или пробел.Вместо этого мы используем sys.stdout.write.

def print_map(self):
    for y in range(0, self.height):
        # print the yth row of rooms
        for x in range(0, self.width):
            if self.x == x and self.y == y:
                sys.stdout.write("[u]")  # this is the player's room
            else:
                sys.stdout.write("[ ]")  # empty room
            # now see whether there's a path to the next room
            if ((x, y), (x + 1, y)) in self.paths:
                sys.stdout.write("-")
            else:
                sys.stdout.write(" ")
        # now that we've written the rooms, draw paths to next row
        print  # newline
        for x in range(0, self.width):
            sys.stdout.write(" ")  # spaces for above room
            if ((x, y), (x, y + 1)) in self.paths:
                sys.stdout.write("|  ")
            else:
                sys.stdout.write("   ")
        print

А теперь давайте соберем все это вместе и попробуем.Вот код:

import sys

class Map:
    def __init__(self, height, width, player_x, player_y, paths):
        self.height = height
        self.width = width
        self.x = player_x
        self.y = player_y
        self.paths = paths

    def move(self, direction):
        if direction == "n":
            if ((self.x, self.y - 1), (self.x, self.y)) not in self.paths:
                print "Cannot go north"
            else:
                self.y -= 1
        if direction == "s":
            if ((self.x, self.y), (self.x, self.y + 1)) not in self.paths:
                print "Cannot go south"
            else:
                self.y += 1
        if direction == "e":
            if ((self.x, self.y), (self.x + 1, self.y)) not in self.paths:
                print "Cannot go east"
            else:
                self.x += 1
        if direction == "w":
            if ((self.x - 1, self.y), (self.x, self.y)) not in self.paths:
                print "Cannot go west"
            else:
                self.x -= 1

    def print_map(self):
        for y in range(0, self.height):
            # print the yth row of rooms
            for x in range(0, self.width):
                if self.x == x and self.y == y:
                    sys.stdout.write("[u]")  # this is the player's room
                else:
                    sys.stdout.write("[ ]")  # empty room
                # now see whether there's a path to the next room
                if ((x, y), (x + 1, y)) in self.paths:
                    sys.stdout.write("-")
                else:
                    sys.stdout.write(" ")
            # now that we've written the rooms, draw paths to next row
            print  # newline
            for x in range(0, self.width):
                sys.stdout.write(" ")  # spaces for above room
                if ((x, y), (x, y + 1)) in self.paths:
                    sys.stdout.write("|  ")
                else:
                    sys.stdout.write("   ")
            print


paths = [((0, 0), (1, 0)), ((0, 0), (1, 0)), ((1, 0), (1, 1)), ((1, 1),
         (2, 1)), ((1, 1), (1, 2)), ((0, 2), (1, 2)), ((1, 2), (2, 2)),
         ((0, 2), (0, 3)), ((0, 3), (1, 3)), ((1, 3), (2, 3)), ((2, 3),
         (3, 3))]
m = Map(4, 4, 0, 0, paths)

while True:
    m.print_map()
    direction = raw_input("What direction do you want to move? [n/e/s/w] ")
    m.move(direction)

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

Davids-MacBook-Air:test dgrtwo$ python Map.py 
[u]-[ ] [ ] [ ] 
     |          
[ ] [ ]-[ ] [ ] 
     |          
[ ]-[ ]-[ ] [ ] 
 |              
[ ]-[ ]-[ ]-[ ] 

What direction do you want to move? [n/e/s/w] e
[ ]-[u] [ ] [ ] 
     |          
[ ] [ ]-[ ] [ ] 
     |          
[ ]-[ ]-[ ] [ ] 
 |              
[ ]-[ ]-[ ]-[ ] 

What direction do you want to move? [n/e/s/w] s
[ ]-[ ] [ ] [ ] 
     |          
[ ] [u]-[ ] [ ] 
     |          
[ ]-[ ]-[ ] [ ] 
 |              
[ ]-[ ]-[ ]-[ ] 

What direction do you want to move? [n/e/s/w] w
Cannot go west
[ ]-[ ] [ ] [ ] 
     |          
[ ] [u]-[ ] [ ] 
     |          
[ ]-[ ]-[ ] [ ] 
 |              
[ ]-[ ]-[ ]-[ ] 

What direction do you want to move? [n/e/s/w] e
[ ]-[ ] [ ] [ ] 
     |          
[ ] [ ]-[u] [ ] 
     |          
[ ]-[ ]-[ ] [ ] 
 |              
[ ]-[ ]-[ ]-[ ] 

В этот код можно внести множество улучшений (в частности, move метод повторяется), но это хорошее начало.Попробуйте сделать карту размером 20x20, и вы увидите, что она прекрасно расширяется.

Расчетное время прибытия:Я должен отметить, что print_map можно было бы переписать в гораздо более короткой форме примерно так:

def print_map(self):
    for y in range(0, self.height):
        print "".join(["[%s]%s" %
                    ("u" if self.x == x and self.y == y else " ",
                     "-" if ((x, y), (x + 1, y)) in self.paths else " ")
                        for x in range(0, self.width)])
        print " " + "   ".join(["|" if ((x, y), (x, y + 1)) in self.paths
                              else " " for x in range(0, self.width)])

Но это немного более интенсивно.

Другие советы

Я сделал это в качестве упражнения, в котором комнаты и сетка «распечатываются».Я добавляю это к обсуждению, поскольку, возможно, это будет проще реализовать с помощью более крупной сетки.

Карта ASCII

+++++++++++++++
+++++++++++++++
+++++++++++++++
++++++   ++++++
++++++ 2 ++++++
++++++/| ++++++
+++  / | ++++++
+++ 3--1 ++++++
+++     \++++++
+++++++++\  +++
+++++++++ 4 +++
+++++++++   +++
+++++++++++++++
+++++++++++++++
+++++++++++++++

Каждая ячейка в этой сетке представляет собой набор знаков «+» размером три на три.Четыре комнаты реализованы со значениями идентификаторов от 1 до 4.Соединения между комнатами представлены косыми чертами, обратными косыми чертами и трубами.

Код

class Room(object):
    def __init__(self, id, loc, exits):
        self.id = id # unique identifier, may be a name
        self.row = loc[0] # loc is tuple of (row, col)
        self.col = loc[1] 
        # exits is a list where 'X' means no exit and 
        # any other value is id of destination
        self.exits = exits 

    def __str__(self):
        directions = '\\|/- -/|\\'
        room = [ e if e == 'X' else ' ' for e in self.exits ]
        for idx in range(len(room)):
            if room[idx] == ' ':
                room[idx] = directions[idx]
            if room[idx] == 'X':
                room[idx] = ' '
        room[4] = self.id[0] # only print first char of id
        return ''.join(room)

class Map(object):
    def __init__(self, rows, cols, rooms):
        self.rows = rows
        self.cols = cols
        self.rooms = rooms

    def __str__(self):
        world = []
        for i in range(self.rows * 3):
            world.append( ['+++'] * self.cols )
        for room in self.rooms:
            ascii = str(room)
            x = room.col
            y = room.row
            for idx in range(0, 3):
                cell = ascii[idx*3:idx*3+3]
                world[y*3+idx][x] = cell
        return '\n'.join( [ ''.join(row) for row in world ] )


if __name__ == '__main__':
    # set up four rooms
    # each room has unique id (string of any length) and coordinates
    # it also has a set of 8 possible exits, represented as a list where
    # 'X' means exit is blocked and valid exits contain the id of the target room
    r1 = Room(id='1', loc=(2,2), exits=['X','2','X',
                                        '3',' ','X',
                                        'X','X','4',])
    r2 = Room(id='2', loc=(1,2), exits=['X','X','X',
                                        'X',' ','X',
                                        '3','1','X',])
    r3 = Room(id='3', loc=(2,1), exits=['X','X','2',
                                        'X',' ','1',
                                        'X','X','X',])
    r4 = Room(id='4', loc=(3,3), exits=['1','X','X',
                                        'X',' ','X',
                                        'X','X','X',])
    # initialize Map with a list of these four rooms
    map = Map(rows = 5, cols=5, rooms=[r1, r2, r3, r4])
    print map

Процедура перемещения не реализована, и для того, чтобы это представление работало, хорошо будут отображаться только идентификаторы отдельных символов.

Преимущества этой системы:

  • легко добавлять комнаты и удалять их
  • определение комнаты удобочитаемо для человека
  • функции вывода перегружаются __str__ и, следовательно, комнаты и сетка «распечатываются», и это может оказаться полезным для будущей отладки или адаптации к будущим форматам, например.как ячейки в таблице HTML.

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

Однако вы все равно можете использовать ответ @david-robinson.Что вам нужно сделать, так это держать мини-карту примерно по центру игрока и динамически обновлять ее, используя данные выхода.Не пытайтесь сохранить карту всей территории;динамически обновляя, вы избежите некоторых географических конфликтов.

Для записи карты в грязевой клиент все, что вам нужно сделать, это написать строку карты с правильным интервалом и завершить ее новой строкой.Вы помещаете все строки карты в список, чтобы он отправлялся как одна группа строк (вы не хотите, чтобы между строками карты была вставлена ​​​​какая-то другая строка, например, когда она отправляется из сокета), и любой грязевой клиент распечатает ее. правильно (разумеется, с моноширинным шрифтом).

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top