struggling with binary arrays: python
I am currently working on a released bot for a game in the hopes of learning more about programming. Unfortunately, a new command i was adding that seemed simple at first became overwhelmingly difficult when i got into the subject of binary arrays. Basically, i took an already made command in which you place an item in two places in order to define the area in which you will be restoring. My edit to the command would be that it would allow the complete restoration of the entire map without placing any items to define the map.
Before a restore command is done, a backup command is done in which a binary array is made of the entire map and then stored in a file. In order to restore the entire map, the new command still has to deal with the coordinates of the two points. One would be at the bottom corner of the map (0,0,0) and then another at the corner at the top opposite side of the map which would always be vary depending on which server you want. My reasoning to solve this would be to simply just retrieve the length of the binary array for each coordinate. Unfortunately, I have been out of luck trying to do that and I really don't know how to find the dimensions of a binary array. The pack and unpack of the array are shown and the part of the code that i can't solve.
One strange thing is that if I input the num开发者_StackOverflow社区bers manually like the if statement with that one server ip address, the bot works perfectly. It's just that any effort to make a code that would work for any map rather than just that one map has been fruitless.
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).")
It seems the only place you use x2,y2,z2 is to set limits on x1,y, and z in these loops:
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
What happens if you set, say, x2 too large? Do you get an exception? If so, perhaps you can simply catch the exception to find out how large x2 can be. For example:
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
As the saying goes, it's easier to ask for forgiveness than permission.
PS. To find out what specific exception to catch, remove the try
and except
above and run the script, letting it fail. The last line of the traceback error message tells you the type of exception which was raised. For example, it might say something like
IndexError: x,y,z out of bounds
In that case, add back the try
and except
changing Exception
to IndexError
.
Consider the length 1024
; this could be turned into (x, y, z):
2 2 256
2 4 128
2 8 64
2 16 32
2 32 16
...
128 4 2
256 2 2
Even if the length of the array was 1001
, you wouldn't get very friendly answers:
7 11 13
11 7 13
7 13 11
11 13 7
13 11 7
13 7 11
So, your saved file must include the (x, y, z) coordinates for each specific map.
It looks like the onBackup()
routine saves the coordinates of the bot in the first three integer positions (four bytes each). You could extend this program by walking the bot to the furthest extent of the map, and then save the coordinates. Or you could see if the server can report the extent of the map somehow, and capture the information.
But I don't think you can just guess the dimensions from a given input array.
精彩评论