Python地图生成函数优化咨询:循环、Append与Tkinter性能问题
地图文明填充代码优化方案
一、GenerateWorld函数核心性能优化
1. 替换低效的文明存在性检查
原代码通过str(basemap.getcolors())判断文明是否已放置,这会遍历全地图并生成字符串,效率极低。改为直接在文明字典中维护标记:
# 初始化时为每个文明添加放置标记 for civ_id in civilisationdictionary: civilisationdictionary[civ_id]['placed'] = False # GenerateWorld函数内判断逻辑 if not civilisationdictionary[i]['placed']: # 执行初始像素放置逻辑 # 放置成功后更新标记 civilisationdictionary[i]['placed'] = True
2. 预生成陆地候选点,避免随机循环
原代码随机选点后反复判断是否为水域,可提前为每个文明的区域预存所有陆地坐标:
# 预生成各文明区域内的陆地坐标(全局执行一次) world_land_coords = {} allpixels = basemap.load() for civ_id in worldmapdictionary: civ_lands = [] regions = zip( worldmapdictionary[civ_id]['minx'], worldmapdictionary[civ_id]['maxx'], worldmapdictionary[civ_id]['miny'], worldmapdictionary[civ_id]['maxy'] ) for minx, maxx, miny, maxy in regions: for x in range(minx, maxx+1): for y in range(miny, maxy+1): if allpixels[x,y] != (255,255,255,255): civ_lands.append((x,y)) world_land_coords[civ_id] = civ_lands # GenerateWorld内直接从预存列表选点 x, y = random.choice(world_land_coords[i])
3. 用Numpy矢量化替代像素遍历
原双重循环遍历全地图找文明像素,改用Numpy数组实现批量操作:
import numpy as np def GenerateWorldNumpy(img_array, civilisationdictionary): water_color = np.array([255,255,255,255]) for i in civilisationdictionary.keys(): colour = np.array(list(civilisationdictionary[i]['colour1']) + [255]) if not civilisationdictionary[i]['placed']: x, y = random.choice(world_land_coords[i]) img_array[y, x] = colour civilisationdictionary[i]['placed'] = True else: # 批量找出文明所有像素 mask = np.all(img_array == colour, axis=-1) own_pixels = np.argwhere(mask) # 生成8邻接坐标并过滤边界 offsets = [(-1,-1), (-1,0), (-1,1), (0,-1), (0,1), (1,-1), (1,0), (1,1)] neighbor_coords = [] for dx, dy in offsets: neighbors = own_pixels + [dx, dy] valid = (neighbors[:,0] >=0) & (neighbors[:,0] < img_array.shape[0]) & \ (neighbors[:,1] >=0) & (neighbors[:,1] < img_array.shape[1]) neighbor_coords.append(neighbors[valid]) neighbor_coords = np.vstack(neighbor_coords) # 排除文明自身像素 own_set = set(tuple(p) for p in own_pixels) new_pixels = [p for p in neighbor_coords if tuple(p) not in own_set] if not new_pixels: continue # 随机选非水域像素 whilecounter = 0 while whilecounter < 1000: y, x = random.choice(new_pixels) if not np.all(img_array[y, x] == water_color): img_array[y, x] = colour break whilecounter +=1 return img_array
4. 优化邻接像素筛选逻辑
原代码用列表判断j not in ownpixels(时间复杂度O(n)),改为集合查找(O(1)):
own_set = set(tuple(p) for p in ownpixels) newpixels = [j for j in allnewpixels if tuple(j) not in own_set]
二、Tkinter地图更新环节优化
1. 减少UI更新频率
不必每回合都更新界面,可间隔N回合更新一次,避免阻塞主循环:
def GenerateWorldMapMain(): global tkbasemap basemap = Image.open('basemap.png') img_array = np.array(basemap) # 预生成陆地坐标、初始化文明标记(省略重复代码) for i in range(1000): print('Turn:',i) img_array = GenerateWorldNumpy(img_array, d1.civilisationdictionary) # 每10回合更新一次UI if i % 10 == 0: basemap = Image.fromarray(img_array) tkbasemap = ImageTk.PhotoImage(basemap) imagelabel.configure(image=tkbasemap) imagelabel.image=tkbasemap imagelabel.update_idletasks() # 用非阻塞更新代替update() # 最后全量更新一次 basemap = Image.fromarray(img_array) tkbasemap = ImageTk.PhotoImage(basemap) imagelabel.configure(image=tkbasemap) imagelabel.image=tkbasemap
2. 避免全局变量来回转换
直接保留Numpy数组或PIL图像对象,仅在需要更新UI时转换为PhotoImage,省去ImageTk.getimage()的反向转换开销。
三、其他辅助优化
- 提前预处理文明颜色:一次性将所有文明的
colour1转换为带alpha通道的格式,存入字典,避免循环内重复转换。 - 使用局部变量:将全局变量(如
worldmapdictionary)赋值为函数内局部变量,减少全局查找的性能损耗。 - 过滤无效邻接像素:生成邻接坐标时直接排除图像边界外的像素,避免后续无效判断。
内容的提问来源于stack exchange,提问作者user2286565
相关产品推荐
相关产品推荐

