123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216 |
- #!/usr/local/bin/python3
- # -*- coding: utf-8 -*-
- import torch
- import torch.nn as nn
- import torch.nn.functional as F
- import torch.utils.data as tudata
- import numpy as np
- import sys
- import json
- import os
- import sqlite3
- #将block信息保存到数据库中,方便后续查询
- class BlockDB:
- def __init__(self):
- self.blocks = []
- self.conn = sqlite3.connect('blocks.db')
- if self.conn is None:
- print("open db failed")
- else:
- cursor = self.conn.cursor()
- cursor.execute("SELECT * FROM blocks")
- rows = cursor.fetchall()
- for row in rows:
- block = {}
- block['id'] = row[0]
- self.blocks.add(block)
- def add_block(self, block):
- # 检查必要信息是否存在
- if 'id' not in block:
- return
- self.blocks.add(block)
- def get_block(self, block):
- if block in self.blocks:
- return block
- else:
- return None
- def dump(self):
- cursor = self.conn.cursor()
- cursor.execute("CREATE TABLE IF NOT EXISTS blocks (id TEXT)")
- for block in self.blocks:
- cursor.execute("INSERT INTO blocks (id) VALUES (?)", (block['id'],))
- self.conn.commit()
- #将数据输出到一个json文件,便于在tiled进行观察,可以是单层或者多层的,多层的话,层级按照从小到大排列(层级是布局层级,不是视觉层级)
- def output_to_json(slices, suffix="ex"):
- with open("/Users/xulianxin/Documents/develop/game/TileMatch/TileManor.Lv/TileManor/templates/tm_0000.json", 'r') as f:
- json_temp = json.load(f)
- for i in range(0, len(slices)):
- with open("/Users/xulianxin/Documents/develop/game/TileMatch/TileManor.Lv/TileManor/slices/slice_%d_%s.json" % (i, suffix), "w") as out_f:
- json_temp["layers"][0]["data"] = slices[i]
- json.dump(json_temp, out_f)
- def output_block(block, size, suffix):
- with open("/Users/xulianxin/Documents/develop/game/TileMatch/TileManor.Lv/TileManor/templates/tm_0000.json", 'r') as f:
- json_temp = json.load(f)
- with open("/Users/xulianxin/Documents/develop/game/TileMatch/TileManor.Lv/TileManor/blocks/block_%s.json" % (suffix,), "w") as out_f:
- for pos in block:
- x,y,z = pos
- # 0 是 mark
- json_temp["layers"][z+1]["data"][y*size[1]+x] = '1'
- json.dump(json_temp, out_f)
- def get_block_from(tiles_from, tiles_by_pos):
- block = set()
- stack = [p for p in tiles_from]
- while len(stack) > 0:
- tile = stack.pop()
- block.add(tile)
- x,y,z = tile
- while z > 0:
- for adj in [(0,0), (0,1), (0,-1), (1,0), (-1,0), (-1,-1), (1,1), (-1,1), (1,-1)]:
- pos = (x+adj[0], y+adj[1], z-1)
- if pos in tiles_by_pos:
- stack.append(pos)
- z -= 1
- return block
- # 将 tiles_at_top 按照连通性,划分成若干个组
- # tiles_at_top只有xy坐标,无z
- def split_shapes(tiles_at_top):
- # 从第一个tile开始,逐个tile进行遍历,如果该tile的上下左右有tile,则将其加入到一个组中,直至所有的tile都被处理
- shapes = []
- for tile in tiles_at_top:
- shape_aleary = None
- for shape in shapes:
- if tile in shape:
- shape_aleary = shape
- break
- if shape_aleary == None:
- shape_aleary = set()
- shape_aleary.add(tile)
- shapes.append(shape_aleary)
- x,y = tile
- for adj in [(0,2), (0,-2), (1,2), (1,-2), (-1,2), (-1,-2), (2,0), (-2,0), (2,1), (-2,1), (2,-1), (-2,-1)]:
- adj_x = x + adj[0]
- adj_y = y + adj[1]
- pos = (adj_x, adj_y)
- if pos in tiles_at_top:
- # 如果该位置已经在某个shape里面,则将两个shape合并
- shape1 = None
- for shape in shapes:
- if pos in shape:
- shape1 = shape
- break
- if shape1 != None and shape1 != shape_aleary:
- shape_aleary.update(shape1)
- shapes.remove(shape1)
- else:
- shape_aleary.add(pos)
- return shapes
- # 解析一个关卡文件,得到各层的数据,是按照视觉层次划分的
- def parse_blocks(jsonLv):
- jsonData = ""
- tilesByPos = {}
- maxZ = 0
- w = 0
- h = 0
- # 处理各层的tile数据
- with open(jsonLv, 'r') as f:#, encoding='utf-8'
- jsonData = json.load(f)
- # 得到宽高信息
- w = int(jsonData['width'])
- h = int(jsonData['height'])
- for item in jsonData['layers']:
- name = item['name']
- if not name.startswith('Tile_'):
- # stacked
- continue
- z = int(name[5:])
- data = item['data']
- for i in range(0, len(data)):
- if data[i] == 0:
- continue
- tile_x = (int)(i % w)
- tile_y = (int)(i / h)
- tile_z = z
- # 一些统计信息
- tilesByPos[(tile_x, tile_y, tile_z)] = [1,0] # [tile类型,zView--视觉层级,默认是0]
- if tile_z > maxZ:
- maxZ = tile_z
- # 根据上面的布局信息,得到视觉顶层的所有tile
- tiles_at_top = []
- for z in range(0, maxZ+1):
- z = maxZ - z
- for x in range(0, w+1):
- for y in range(0, h+1):
- if (x,y,z) in tilesByPos:
- tile = tilesByPos[(x, y, z)]
- adjs = [(x,y),(x,y+1),(x,y-1),(x+1,y),(x+1,y+1),(x+1,y-1),(x-1,y),(x-1,y-1),(x-1,y+1)]
- # 确定视觉层级
- zvMax = -1
- for zup in range(z+1, maxZ+1):
- for adj in adjs:
- if (adj[0],adj[1],zup) in tilesByPos:
- zv = tilesByPos[adj[0],adj[1],zup][1]
- if zv > zvMax:
- zvMax = zv
- zv = zvMax + 1
- tilesByPos[(x, y, z)][1] = zv
- if zv == 0:
- tiles_at_top.append((x, y, z))
- # 将 tiles_at_top 按照连通性,划分成若干个组
- tops = [(x,y) for x,y,z in tiles_at_top]
- print("tops:", tops)
- shapes = split_shapes(tops)
- print("shapes:", shapes)
- # 对每一个组,得到其block
- blocks = []
- for i in range(0, len(shapes)):
- shape = shapes[i]
- ts = [(x,y,z) for x,y,z in tiles_at_top if (x,y) in shape]
- block = get_block_from(ts, tilesByPos)
- if len(block) > len(ts):
- blocks.append(block)
- return blocks, (w,h)
- # 测试获取视觉层级的数据是否ok
- def test_parse_blocks():
- parse_blocks("/Users/xulianxin/Documents/develop/game/TileMatch/TileManor.Lv/TileManor/templates/tm_0004.json")
- #评估一个布局的好坏,返回一个分数
- #布局的好坏,可以从几个方面来评估:
- #1. 是否超出范围;
- #2. 是否有某种对称性;
- #3. tile的数量是否合理;
- def eva_layout():
- pass
- # 生成一个随机的
- def generate_tops():
- pass
- if __name__ == '__main__':
- blocks_lib = set()
- for directory in ["/Users/xulianxin/Documents/develop/game/TileMatch/TileManor.Lv/TileManor/tf_templates", ]:
- for filename in os.listdir(directory):
- filepath = os.path.join(directory, filename)
- if os.path.isfile(filepath) and filepath.endswith('.json'):
- blocks, size = parse_blocks(filepath)
- for i in range(len(blocks)):
- block = blocks[i]
- # 将block都挪动到左上角,进行排重
- minx = min([x for x,y,z in block])
- miny = min([y for x,y,z in block])-1
- block = tuple((x-minx, y-miny, z) for x,y,z in block)
- if block not in blocks_lib:
- blocks_lib.add(block)
- output_block(block, size, filename.split(".")[0] + "_%d" % (i,))
- else:
- print("dumplicated!")
- pass
|