mirror of
https://github.com/unanmed/ginka-generator.git
synced 2026-05-17 23:21:20 +08:00
feat: 多个塔同时输入 minamo 处理
This commit is contained in:
parent
9f62be3736
commit
5a19a23518
6
.gitignore
vendored
6
.gitignore
vendored
@ -1,3 +1,7 @@
|
||||
__pycache__
|
||||
result
|
||||
node_modules
|
||||
node_modules
|
||||
ginka-dataset.json
|
||||
ginka-eval.json
|
||||
minamo-dataset.json
|
||||
minamo-eval.json
|
||||
@ -1,19 +1,20 @@
|
||||
import { readFile, writeFile } from 'fs-extra';
|
||||
import { join } from 'path';
|
||||
import { convertFloor } from './floor';
|
||||
import { mergeDataset } from './utils';
|
||||
import {
|
||||
FloorData,
|
||||
getAllFloors,
|
||||
mergeDataset,
|
||||
mergeFloorIds,
|
||||
parseTowerInfo
|
||||
} from './utils';
|
||||
import { compareMap } from './topology/compare';
|
||||
import { mirrorMapX, mirrorMapY, rotateMap } from './topology/transform';
|
||||
import { directions, tileType } from './topology/graph';
|
||||
import { calculateVisualSimilarity } from './vision/similarity';
|
||||
import { BaseConfig, TowerInfo } from './types';
|
||||
|
||||
interface MinamoConfig {
|
||||
clip: {
|
||||
defaults: [number, number, number, number];
|
||||
special: Record<string, [number, number, number, number]>;
|
||||
};
|
||||
// data: Record<string, Record<string, number>>;
|
||||
}
|
||||
interface MinamoConfig extends BaseConfig {}
|
||||
|
||||
interface MinamoTrainData {
|
||||
map1: number[][];
|
||||
@ -211,10 +212,9 @@ function generateSimilarData(id: string, map: number[][]) {
|
||||
}
|
||||
|
||||
function generateDataset(
|
||||
floors: Map<string, number[][]>,
|
||||
floors: Map<string, FloorData>,
|
||||
pairs: number[],
|
||||
floorIds: string[],
|
||||
config: MinamoConfig
|
||||
floorIds: string[]
|
||||
): Record<string, MinamoTrainData> {
|
||||
const data: Record<string, MinamoTrainData> = {};
|
||||
|
||||
@ -223,8 +223,8 @@ function generateDataset(
|
||||
const num2 = v % floorIds.length;
|
||||
const id1 = floorIds[num1];
|
||||
const id2 = floorIds[num2];
|
||||
const map1 = floors.get(id1);
|
||||
const map2 = floors.get(id2);
|
||||
const map1 = floors.get(id1)?.map;
|
||||
const map2 = floors.get(id2)?.map;
|
||||
if (!map1 || !map2) return;
|
||||
const [w1, h1] = [map1[0].length, map1.length];
|
||||
const [w2, h2] = [map2[0].length, map2.length];
|
||||
@ -281,44 +281,17 @@ function generateDataset(
|
||||
return data;
|
||||
}
|
||||
|
||||
async function parseOne(path: string): Promise<MinamoDataset> {
|
||||
const dataFile = await readFile(join(path, 'data.js'), 'utf-8');
|
||||
const configFile = await readFile(
|
||||
join(path, 'minamo-config.json'),
|
||||
'utf-8'
|
||||
);
|
||||
const data: any = JSON.parse(dataFile.split('\n').slice(1).join('\n'));
|
||||
const config = JSON.parse(configFile) as MinamoConfig;
|
||||
const floorIds = data.main.floorIds as string[];
|
||||
const name = data.firstData.name as string;
|
||||
const length = floorIds.length;
|
||||
function parseAllData(data: Map<string, FloorData>): MinamoDataset {
|
||||
const length = data.size;
|
||||
const totalCount = Math.round((length * (length - 1)) / 2);
|
||||
|
||||
const pairs = choosePair(length);
|
||||
|
||||
console.log(
|
||||
`✅ 在 ${name} 中发现 ${length} 个楼层,共 ${totalCount} 种组合,选取 ${pairs.length} 个组合`
|
||||
`✅ 共发现 ${length} 个楼层,共 ${totalCount} 种组合,选取 ${pairs.length} 个组合`
|
||||
);
|
||||
|
||||
const floors = new Map(
|
||||
await Promise.all(
|
||||
floorIds.map<Promise<[string, number[][]]>>(async v => {
|
||||
const file = await readFile(
|
||||
join(path, 'floors', `${v}.js`),
|
||||
'utf-8'
|
||||
);
|
||||
const data = file.split('\n').slice(1).join('\n');
|
||||
const json = JSON.parse(data);
|
||||
const map = json.map;
|
||||
const clip = config.clip.special[v] ?? config.clip.defaults;
|
||||
// 裁剪
|
||||
const clipped = convertFloor(map, clip, name, v);
|
||||
return [v, clipped];
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
const trainData = generateDataset(floors, pairs, floorIds, config);
|
||||
const trainData = generateDataset(data, pairs, [...data.keys()]);
|
||||
|
||||
const dataset: MinamoDataset = {
|
||||
datasetId: Math.floor(Math.random() * 1e12),
|
||||
@ -329,9 +302,12 @@ async function parseOne(path: string): Promise<MinamoDataset> {
|
||||
}
|
||||
|
||||
(async () => {
|
||||
const results = await Promise.all(list.map(v => parseOne(v)));
|
||||
const dataset = mergeDataset(...results);
|
||||
await writeFile(output, JSON.stringify(dataset, void 0), 'utf-8');
|
||||
const size = Object.keys(dataset.data).length;
|
||||
const towers = await Promise.all(
|
||||
list.map(v => parseTowerInfo(v, 'minamo-config.json'))
|
||||
);
|
||||
const floors = await getAllFloors(...towers);
|
||||
const results = parseAllData(floors);
|
||||
await writeFile(output, JSON.stringify(results, void 0), 'utf-8');
|
||||
const size = Object.keys(results.data).length;
|
||||
console.log(`✅ 已处理 ${list.length} 个塔,共 ${size} 个组合`);
|
||||
})();
|
||||
|
||||
13
data/src/types.ts
Normal file
13
data/src/types.ts
Normal file
@ -0,0 +1,13 @@
|
||||
export interface BaseConfig {
|
||||
clip: {
|
||||
defaults: [number, number, number, number];
|
||||
special: Record<string, [number, number, number, number]>;
|
||||
};
|
||||
}
|
||||
|
||||
export interface TowerInfo {
|
||||
path: string;
|
||||
name: string;
|
||||
floorIds: string[];
|
||||
config: BaseConfig;
|
||||
}
|
||||
@ -1,8 +1,18 @@
|
||||
import { readFile } from 'fs-extra';
|
||||
import { join } from 'path';
|
||||
import { BaseConfig, TowerInfo } from './types';
|
||||
import { convertFloor } from './floor';
|
||||
|
||||
interface DatasetMergable<T> {
|
||||
datasetId: number;
|
||||
data: Record<string, T>;
|
||||
}
|
||||
|
||||
export interface FloorData {
|
||||
map: number[][];
|
||||
config: BaseConfig;
|
||||
}
|
||||
|
||||
export function mergeDataset<T>(
|
||||
...datasets: DatasetMergable<T>[]
|
||||
): DatasetMergable<T> {
|
||||
@ -38,3 +48,59 @@ export function cosineSimilarity(vecA: number[], vecB: number[]): number {
|
||||
|
||||
return dot / (Math.sqrt(normA) * Math.sqrt(normB));
|
||||
}
|
||||
|
||||
export async function parseTowerInfo(
|
||||
path: string,
|
||||
configName: string
|
||||
): Promise<TowerInfo> {
|
||||
const dataFile = await readFile(join(path, 'data.js'), 'utf-8');
|
||||
const data: any = JSON.parse(dataFile.split('\n').slice(1).join('\n'));
|
||||
const configFile = await readFile(join(path, configName), 'utf-8');
|
||||
|
||||
return {
|
||||
path: path,
|
||||
name: data.firstData.name as string,
|
||||
floorIds: data.main.floorIds as string[],
|
||||
config: JSON.parse(configFile) as BaseConfig
|
||||
};
|
||||
}
|
||||
|
||||
export async function getAllFloors(...info: TowerInfo[]) {
|
||||
const floorData = await Promise.all(
|
||||
info.map(tower => {
|
||||
return Promise.all(
|
||||
tower.floorIds.map(async id => {
|
||||
const floorFile = await readFile(
|
||||
join(tower.path, 'floors', `${id}.js`),
|
||||
'utf-8'
|
||||
);
|
||||
const data = JSON.parse(
|
||||
floorFile.split('\n').slice(1).join('\n')
|
||||
);
|
||||
const map = data.map as number[][];
|
||||
// 裁剪地图
|
||||
const { clip } = tower.config;
|
||||
const area = clip.special[id] ?? clip.defaults;
|
||||
return convertFloor(map, area, tower.name, id);
|
||||
})
|
||||
);
|
||||
})
|
||||
);
|
||||
const maps: Map<string, FloorData> = new Map();
|
||||
floorData.forEach((tower, tid) => {
|
||||
const name = info[tid].name;
|
||||
tower.forEach((map, mid) => {
|
||||
const floorId = info[tid].floorIds[mid];
|
||||
maps.set(`${name}::${floorId}`, { map, config: info[tid].config });
|
||||
});
|
||||
});
|
||||
return maps;
|
||||
}
|
||||
|
||||
export function mergeFloorIds(...info: TowerInfo[]) {
|
||||
const ids: string[] = [];
|
||||
info.forEach(v => {
|
||||
ids.push(...v.floorIds.map(id => `${v.name}:${id}`));
|
||||
});
|
||||
return ids;
|
||||
}
|
||||
|
||||
175
dataset.json
175
dataset.json
@ -1,175 +0,0 @@
|
||||
{
|
||||
"datasetId": 468713377296,
|
||||
"data": {
|
||||
"93529307366/MT1": {
|
||||
"text": [
|
||||
"左右对称结构,右侧包含一个红宝石,左侧包含一个蓝宝石,怪物全部是中等强度",
|
||||
"画一个左右对称,怪物强度中等,需要开门才能上楼的地图",
|
||||
"生成一个有两把黄钥匙,三个黄门,四个血瓶,四个怪物的左右对称地图"
|
||||
],
|
||||
"map": [
|
||||
[1, 1, 1, 1, 1, 1, 1],
|
||||
[1, 5, 1, 10, 1, 5, 1],
|
||||
[1, 8, 0, 2, 0, 8, 1],
|
||||
[1, 4, 1, 6, 1, 3, 1],
|
||||
[1, 8, 6, 2, 6, 8, 1],
|
||||
[1, 5, 1, 10, 1, 5, 1],
|
||||
[1, 1, 1, 1, 1, 1, 1]
|
||||
],
|
||||
"size": [7, 7]
|
||||
},
|
||||
"93529307366/MT2": {
|
||||
"text": [
|
||||
"画一个主干道上只有弱怪,没有宝石,包含咸鱼门的地图",
|
||||
"宝石被中等怪物守护,也可以通过开咸鱼门获得,以弱怪为主的地图",
|
||||
"这是一个主干道在地图边缘的地图,可以考虑开一个黄门提前获得宝石"
|
||||
],
|
||||
"map": [
|
||||
[1, 1, 1, 1, 1, 1, 1],
|
||||
[1, 5, 7, 10, 0, 7, 1],
|
||||
[1, 1, 5, 1, 1, 2, 1],
|
||||
[1, 0, 7, 0, 1, 5, 1],
|
||||
[1, 6, 1, 6, 1, 7, 1],
|
||||
[1, 5, 1, 4, 8, 10, 1],
|
||||
[1, 1, 1, 1, 1, 1, 1]
|
||||
],
|
||||
"size": [7, 7]
|
||||
},
|
||||
"93529307366/MT3": {
|
||||
"text": [
|
||||
"一个红宝石在黄门里面,门前有一个强怪守护,另一个红宝石可以打败一个中怪和两个弱怪后获得",
|
||||
"画一个主干道在中间,左侧有一个强怪守护的红宝石,右侧有一个红宝石的地图",
|
||||
"生成一个左侧怪物较强,右侧怪物较弱的地图,右侧有一个黄门捷径"
|
||||
],
|
||||
"map": [
|
||||
[1, 1, 1, 1, 1, 1, 1],
|
||||
[1, 3, 1, 10, 7, 3, 1],
|
||||
[1, 6, 1, 5, 1, 7, 1],
|
||||
[1, 9, 1, 8, 1, 6, 1],
|
||||
[1, 5, 8, 0, 1, 7, 1],
|
||||
[1, 2, 1, 5, 7, 10, 1],
|
||||
[1, 1, 1, 1, 1, 1, 1]
|
||||
],
|
||||
"size": [7, 7]
|
||||
},
|
||||
"93529307366/MT4": {
|
||||
"text": [
|
||||
"生成一个左右异形对称,包含各种强度的怪物,有中怪守护红宝石,强怪守护蓝宝石的地图",
|
||||
"防御宝石由强怪守护,攻击宝石由中怪守护,左右不完全对称的地图",
|
||||
"画一个可以通过开门绕过一个中等强度怪物和两个弱怪,包含三个血瓶,攻防宝石各一个的地图"
|
||||
],
|
||||
"map": [
|
||||
[1, 1, 1, 1, 1, 1, 1],
|
||||
[1, 5, 7, 10, 7, 0, 1],
|
||||
[1, 8, 1, 6, 1, 8, 1],
|
||||
[1, 3, 1, 5, 7, 5, 1],
|
||||
[1, 1, 1, 6, 1, 1, 1],
|
||||
[1, 10, 8, 0, 9, 4, 1],
|
||||
[1, 1, 1, 1, 1, 1, 1]
|
||||
],
|
||||
"size": [7, 7]
|
||||
},
|
||||
"93529307366/MT5": {
|
||||
"text": [
|
||||
"画一个左上右下对称,中间全是门和宝石,周围全是怪物和血瓶的地图",
|
||||
"中间的门构成一个叉号状,空余位置填充宝石,外围包含怪物和血瓶,几乎没有空地的地图",
|
||||
"生成一个偏资源向的楼层,有很多资源集中在中间,但是需要开门才能获得,地图外围有怪物挡路"
|
||||
],
|
||||
"map": [
|
||||
[1, 1, 1, 1, 1, 1, 1],
|
||||
[1, 8, 5, 7, 0, 10, 1],
|
||||
[1, 5, 6, 4, 6, 0, 1],
|
||||
[1, 7, 3, 6, 3, 7, 1],
|
||||
[1, 2, 6, 4, 6, 5, 1],
|
||||
[1, 10, 2, 7, 5, 8, 1],
|
||||
[1, 1, 1, 1, 1, 1, 1]
|
||||
],
|
||||
"size": [7, 7]
|
||||
},
|
||||
"93529307366/MT6": {
|
||||
"text": [
|
||||
"上楼梯在蓝门里面,需要开门才能上楼,怪物强度比较高,没有弱怪,宝石全由强怪守护,但是其中一个也可以咸门获得",
|
||||
"画一个接近左右对称的地图,最好能好看点",
|
||||
"生成一个有一把黄钥匙,怪物强度高的地图"
|
||||
],
|
||||
"map": [
|
||||
[1, 1, 1, 1, 1, 1, 1],
|
||||
[1, 5, 6, 4, 1, 10, 1],
|
||||
[1, 6, 1, 9, 1, 5, 1],
|
||||
[1, 8, 0, 6, 0, 8, 1],
|
||||
[1, 5, 1, 10, 1, 2, 1],
|
||||
[1, 9, 3, 1, 4, 9, 1],
|
||||
[1, 1, 1, 1, 1, 1, 1]
|
||||
],
|
||||
"size": [7, 7]
|
||||
},
|
||||
"93529307366/MT7": {
|
||||
"text": [
|
||||
"画一个几乎全由怪物组成,没有宝石,只有血瓶钥匙和门的地图",
|
||||
"怪物强度高,但是血瓶数量多",
|
||||
"可以直接开门上楼,没有宝石的地图"
|
||||
],
|
||||
"map": [
|
||||
[1, 1, 1, 1, 1, 1, 1],
|
||||
[1, 5, 9, 2, 9, 5, 1],
|
||||
[1, 8, 0, 10, 0, 8, 1],
|
||||
[1, 5, 9, 6, 9, 5, 1],
|
||||
[1, 0, 8, 10, 8, 0, 1],
|
||||
[1, 6, 0, 5, 0, 6, 1],
|
||||
[1, 1, 1, 1, 1, 1, 1]
|
||||
],
|
||||
"size": [7, 7]
|
||||
},
|
||||
"93529307366/MT8": {
|
||||
"text": [
|
||||
"以走廊为主,没有强怪,只有弱怪和中怪,有一定数量的宝石的地图",
|
||||
"画一个蓝海风,以走廊为主的地图",
|
||||
"生成一个资源比较丰富,有宝石、血瓶,需要开门才能上楼,有一些咸鱼门的地图"
|
||||
],
|
||||
"map": [
|
||||
[1, 1, 1, 1, 1, 1, 1],
|
||||
[1, 5, 8, 10, 7, 2, 1],
|
||||
[1, 2, 1, 5, 1, 7, 1],
|
||||
[1, 3, 1, 3, 6, 4, 1],
|
||||
[1, 6, 1, 6, 1, 8, 1],
|
||||
[1, 10, 7, 5, 1, 5, 1],
|
||||
[1, 1, 1, 1, 1, 1, 1]
|
||||
],
|
||||
"size": [7, 7]
|
||||
},
|
||||
"93529307366/MT9": {
|
||||
"text": [
|
||||
"左右基本对称,但是入口不对称,宝石种类不对称的地图",
|
||||
"画一个左右基本对称,没有强怪的地图",
|
||||
"生成一个有两个红宝石,一个蓝宝石,很多血瓶,没有强怪的地图"
|
||||
],
|
||||
"map": [
|
||||
[1, 1, 1, 1, 1, 1, 1],
|
||||
[1, 4, 1, 10, 1, 3, 1],
|
||||
[1, 5, 7, 0, 7, 5, 1],
|
||||
[1, 8, 6, 5, 6, 8, 1],
|
||||
[1, 5, 8, 6, 8, 5, 1],
|
||||
[1, 10, 5, 1, 5, 3, 1],
|
||||
[1, 1, 1, 1, 1, 1, 1]
|
||||
],
|
||||
"size": [7, 7]
|
||||
},
|
||||
"93529307366/MT10": {
|
||||
"text": [
|
||||
"左右对称的 Boss 层",
|
||||
"画一个 Boss 层,入口在上方,Boss 在下方,中间有几个弱怪挡路",
|
||||
"生成一个 Boss 层,可以咸门提前拿资源"
|
||||
],
|
||||
"map": [
|
||||
[1, 1, 1, 1, 1, 1, 1],
|
||||
[1, 5, 1, 10, 1, 5, 1],
|
||||
[1, 6, 7, 7, 7, 6, 1],
|
||||
[1, 1, 6, 5, 6, 1, 1],
|
||||
[1, 4, 5, 9, 5, 4, 1],
|
||||
[1, 3, 1, 1, 1, 3, 1],
|
||||
[1, 1, 1, 1, 1, 1, 1]
|
||||
],
|
||||
"size": [7, 7]
|
||||
}
|
||||
}
|
||||
}
|
||||
2673
minamo-dataset.json
2673
minamo-dataset.json
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user