борется с двоичными массивами: python - PullRequest
2 голосов
/ 01 апреля 2011

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

Перед выполнением команды восстановления выполняется команда резервного копирования, в которой двоичный массив создается из всей карты и затем сохраняется в файле. Чтобы восстановить всю карту, новая команда все еще должна иметь дело с координатами двух точек. Один будет в нижнем углу карты (0,0,0), а затем другой в углу в верхней противоположной стороне карты, который всегда будет варьироваться в зависимости от того, какой сервер вы хотите. Моим аргументом для решения этой проблемы было бы просто получить длину двоичного массива для каждой координаты. К сожалению, мне не повезло, пытаясь это сделать, и я действительно не знаю, как найти размеры двоичного массива. Упаковка и распаковка массива показаны и часть кода, которую я не могу решить.

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

enter code here
def onBackup(self,user,filename):
    fn = bakFolder+filename+".backup"
    try:
        f = open(fn,"r")
        self.bot.sendMessage("A backup by that name already exists.")
        f.close()
        return
    except IOError:
      try:
        f = open(fn,"wb")
        f.write(struct.pack("!3i",self.bot.level_x,self.bot.level_y,self.bot.level_z))
        self.bot.block_array.tofile(f)
        self.bot.sendMessage("Backup saved to file %s.backup"%filename)
        print "Backup save to %s.backup"%filename
        return
      except IOError:
        self.bot.sendMessage("Error opening %s.backup"%filename, false)
        print "Backup: Error opening file"
        return
def restoremap(self):
    fn = bakFolder+self.restore_filename+".backup"
    try:
        f = open(fn,"rb")
        header_x, header_y, header_z = struct.unpack('!3i',f.read(12))
        backup_array = array.array('B')
        backup_array.fromfile(f,header_x*header_y*header_z)
        x1,y1,z1 = (0,0,0) 
        if server == "204.232.197.228":
            x2,y2,z2 = (64,1020,64) #special server that already has coordinates
        else:
            x2,y2,z2 = ??? rest of servers, coordinates derived from the binary array
        if x1 > x2 : x1, x2 = x2, x1
        if y1 > y2 : y1, y2 = y2, y1
        if z1 > z2 : z1, z2 = z2, z1
        tiles_to_deglass = []
        tiles_to_build   = []
        while x1 <= x2:
            y = y1
            while y <= y2:
                z = z1
                while z <= z2:
                    offset = self.bot.calculateOffset(x1,y,z)
                    current_tile = int(self.bot.block_array[offset])
                    backup_tile  = int(backup_array[offset])
                    if not ( current_tile == backup_tile):
                        if (current_tile == 0) and (backup_tile in self.valid_blocks):
                            tiles_to_build.append((backup_tile,x1,y,z))
                        elif (current_tile >= 8) and (current_tile <= 11) and (backup_tile == 0):
                            ## This deals with water & lava in what used to be empty spaces
                            ## first we'll glass it all, and then deglass later!
                            self.blocks.append((20,x1,y,z))
                            tiles_to_deglass.append((0,x1,y,z))
                        elif backup_tile == 7:##use stone
                            tiles_to_build.append((0,x1,y,z))
                            tiles_to_build.append((1,x1,y,z))
                        elif backup_tile in self.valid_blocks:
                            ## This is the fall through... We'll try to erase
                            ## the current tile and then restore it to the other state
                            tiles_to_build.append((0,x1,y,z))
                            tiles_to_build.append((backup_tile,x1,y,z))
                        elif (backup_tile == 0) and not (current_tile == 0):
                            tiles_to_build.append((0,x1,y,z))

                    z+=1
                y += 1
            x1 +=1
        self.DrawBlocks()
        self.blocks += tiles_to_build
        self.DrawBlocks()
        self.blocks += tiles_to_deglass
        self.DrawBlocks()
        self.bot.sendMessage("Restoring...",ignorable=True)
        ##self.bot.action_queue.append(SayAction(self.bot,"Done restoring."))
        self.onReset(silent=True)

    except IOError:
        self.bot.sendMessage("Error while restoring (couldn't read file).")

Ответы [ 2 ]

1 голос
/ 01 апреля 2011

Кажется, единственное место, где вы используете x2, y2, z2 - это установить ограничения для x1, y и z в следующих циклах:

    while x1 <= x2:
        y = y1
        while y <= y2:
            z = z1
            while z <= z2:
                offset = self.bot.calculateOffset(x1,y,z)
                current_tile = int(self.bot.block_array[offset])
                ...
                z+=1
            y += 1
        x1 +=1

Что произойдет, если вы установите, скажем, x2 слишком большим? Вы получаете исключение? Если так, возможно, вы можете просто поймать исключение, чтобы узнать, насколько большим может быть x2. Например:

    x2=y2=z2=None
    while x2 is None or x1<=x2:
        y = y1
        while y2 is None or y<=y2:
            z = z1
            while z2 is None or z<=z2:
                try:
                    offset = self.bot.calculateOffset(x1,y,z)
                    current_tile = int(self.bot.block_array[offset])
                except Exception: #<-- Change to most specific exception possible
                    if z2 is None:
                        z2=z-1
                    elif y2 is None:
                        y2=y-1
                    elif x2 is None:
                        x2=x1-1
                    break
                ...
                z+=1
            y += 1
        x1 +=1

Как говорится, проще просить прощения, чем разрешения .


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

IndexError: x,y,z out of bounds

В этом случае добавьте обратно try и except, изменив Exception на IndexError.

0 голосов
/ 01 апреля 2011

Рассмотрим длину 1024;это можно превратить в (x, y, z):

2  2  256
2  4  128
2  8   64
2 16   32
2 32   16
...
128 4  2
256 2  2

Даже если длина массива будет 1001, вы не получите очень дружелюбные ответы:

 7 11 13
11  7 13
 7 13 11
11 13  7
13 11  7
13  7 11

Итак, ваш сохраненный файл должен включать координаты (x, y, z) для каждой конкретной карты.

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

Но я не думаю, что вы можете просто угадать размеры из данного входного массива.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...