mirror of
https://github.com/unanmed/ginka-generator.git
synced 2026-05-14 04:41:12 +08:00
feat: ginka 数据集生成工具生成新版数据集
This commit is contained in:
parent
44b90e7630
commit
8add448195
@ -1,24 +1,15 @@
|
||||
import { GinkaConfig } from './types';
|
||||
|
||||
const numMap: Record<number, number> = {
|
||||
0: 0, // 空地
|
||||
1: 1, // 墙壁
|
||||
21: 2, // 钥匙
|
||||
27: 3, // 红宝石
|
||||
28: 4, // 蓝宝石
|
||||
31: 5, // 血瓶
|
||||
81: 6, // 门
|
||||
201: 7, // 弱怪
|
||||
202: 8, // 中怪
|
||||
203: 9, // 强怪
|
||||
87: 10, // 楼梯
|
||||
88: 10, // 楼梯
|
||||
91: 11, // 箭头
|
||||
92: 11, // 箭头
|
||||
93: 11, // 箭头
|
||||
94: 11, // 箭头
|
||||
53: 12, // 道具
|
||||
29: 13 // 绿宝石
|
||||
0: 0,
|
||||
1: 1,
|
||||
2: 2,
|
||||
91: 29,
|
||||
92: 29,
|
||||
93: 29,
|
||||
94: 29,
|
||||
87: 28,
|
||||
88: 28
|
||||
};
|
||||
|
||||
export interface Enemy {
|
||||
@ -45,39 +36,158 @@ function convert(
|
||||
clipped.push(row);
|
||||
}
|
||||
|
||||
// 2. 转换一般图块
|
||||
const mapping: Record<number, number> = {};
|
||||
config.mapping.wall.forEach(v => (mapping[v] = 1));
|
||||
config.mapping.key.forEach(v => (mapping[v] = 2));
|
||||
config.mapping.redGem.forEach(v => (mapping[v] = 3));
|
||||
config.mapping.blueGem.forEach(v => (mapping[v] = 4));
|
||||
config.mapping.potion.forEach(v => (mapping[v] = 5));
|
||||
config.mapping.door.forEach(v => (mapping[v] = 6));
|
||||
config.mapping.item.forEach(v => (mapping[v] = 12));
|
||||
config.mapping.greenGem.forEach(v => (mapping[v] = 13));
|
||||
const yellowGem = new Set(config.mapping.yellowGem);
|
||||
const res: number[][] = Array.from({ length: clipped.length }, () =>
|
||||
Array.from({ length: clipped[0].length })
|
||||
);
|
||||
|
||||
// 2. 初步映射
|
||||
for (let nx = 0; nx < w; nx++) {
|
||||
for (let ny = 0; ny < h; ny++) {
|
||||
const tile = clipped[ny][nx];
|
||||
const enemy = enemyMap[tile];
|
||||
if (yellowGem.has(tile)) {
|
||||
const rand = Math.random();
|
||||
if (rand < 2 / 5) {
|
||||
clipped[ny][nx] = 3;
|
||||
} else if (rand < 4 / 5) {
|
||||
clipped[ny][nx] = 4;
|
||||
} else {
|
||||
clipped[ny][nx] = 13;
|
||||
}
|
||||
continue;
|
||||
if (numMap[tile] !== void 0) {
|
||||
res[ny][nx] = numMap[tile];
|
||||
}
|
||||
if (mapping[tile]) clipped[ny][nx] = mapping[tile];
|
||||
else if (numMap[tile]) clipped[ny][nx] = numMap[tile];
|
||||
else if (!enemy) clipped[ny][nx] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 转换怪物
|
||||
// 3. 转换一般图块
|
||||
const mapping: Record<number, number> = {};
|
||||
const dict = config.mapping;
|
||||
dict.wall.forEach(v => (mapping[v] = 1));
|
||||
dict.decoration.forEach(v => (mapping[v] = 2));
|
||||
dict.floor.forEach(v => (mapping[v] = 28));
|
||||
dict.arrow.forEach(v => (mapping[v] = 29));
|
||||
for (let nx = 0; nx < w; nx++) {
|
||||
for (let ny = 0; ny < h; ny++) {
|
||||
const tile = clipped[ny][nx];
|
||||
if (mapping[tile] !== void 0) res[ny][nx] = mapping[tile];
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 转换含等级图块
|
||||
const redGemSet = new Set<number>();
|
||||
const blueGemSet = new Set<number>();
|
||||
const greenGemSet = new Set<number>();
|
||||
const potionSet = new Set<number>();
|
||||
for (let nx = 0; nx < w; nx++) {
|
||||
for (let ny = 0; ny < h; ny++) {
|
||||
const tile = clipped[ny][nx];
|
||||
if (dict.redGem[tile] !== void 0) {
|
||||
redGemSet.add(dict.redGem[tile]);
|
||||
} else if (dict.blueGem[tile] !== void 0) {
|
||||
blueGemSet.add(dict.blueGem[tile]);
|
||||
} else if (dict.greenGem[tile] !== void 0) {
|
||||
greenGemSet.add(dict.greenGem[tile]);
|
||||
} else if (dict.yellowGem[tile] !== void 0) {
|
||||
redGemSet.add(dict.yellowGem[tile]);
|
||||
blueGemSet.add(dict.yellowGem[tile]);
|
||||
greenGemSet.add(dict.yellowGem[tile]);
|
||||
} else if (dict.potion[tile] !== void 0) {
|
||||
potionSet.add(dict.potion[tile]);
|
||||
}
|
||||
}
|
||||
}
|
||||
const minRedGem = Math.min(...redGemSet);
|
||||
const maxRedGem = Math.max(...redGemSet);
|
||||
const minBlueGem = Math.min(...blueGemSet);
|
||||
const maxBlueGem = Math.max(...blueGemSet);
|
||||
const minGreenGem = Math.min(...greenGemSet);
|
||||
const maxGreenGem = Math.max(...greenGemSet);
|
||||
const minPotion = Math.min(...potionSet);
|
||||
const maxPotion = Math.max(...potionSet);
|
||||
|
||||
for (let nx = 0; nx < w; nx++) {
|
||||
for (let ny = 0; ny < h; ny++) {
|
||||
const tile = clipped[ny][nx];
|
||||
if (dict.redGem[tile] !== void 0) {
|
||||
const value = dict.redGem[tile];
|
||||
if (maxRedGem === minRedGem) {
|
||||
res[ny][nx] = 10;
|
||||
} else {
|
||||
const level = Math.floor(
|
||||
((value - minRedGem) / (maxRedGem - minRedGem)) * 3
|
||||
);
|
||||
res[ny][nx] = 10 + level;
|
||||
}
|
||||
} else if (dict.blueGem[tile] !== void 0) {
|
||||
const value = dict.blueGem[tile];
|
||||
if (maxBlueGem === minBlueGem) {
|
||||
res[ny][nx] = 13;
|
||||
} else {
|
||||
const level = Math.floor(
|
||||
((value - minBlueGem) / (maxBlueGem - minBlueGem)) * 3
|
||||
);
|
||||
res[ny][nx] = 13 + level;
|
||||
}
|
||||
} else if (dict.greenGem[tile] !== void 0) {
|
||||
const value = dict.greenGem[tile];
|
||||
if (maxGreenGem === minGreenGem) {
|
||||
res[ny][nx] = 16;
|
||||
} else {
|
||||
const level = Math.floor(
|
||||
((value - minGreenGem) / (maxGreenGem - minGreenGem)) *
|
||||
3
|
||||
);
|
||||
res[ny][nx] = 16 + level;
|
||||
}
|
||||
} else if (dict.yellowGem[tile] !== void 0) {
|
||||
const rand = Math.random();
|
||||
const value = dict.yellowGem[tile];
|
||||
if (rand < 2 / 5) {
|
||||
if (maxRedGem === minRedGem) {
|
||||
res[ny][nx] = 10;
|
||||
} else {
|
||||
const level = Math.floor(
|
||||
((value - minRedGem) / (maxRedGem - minRedGem)) * 3
|
||||
);
|
||||
res[ny][nx] = 10 + level;
|
||||
}
|
||||
} else if (rand < 4 / 5) {
|
||||
if (maxBlueGem === minBlueGem) {
|
||||
res[ny][nx] = 13;
|
||||
} else {
|
||||
const level = Math.floor(
|
||||
((value - minBlueGem) / (maxBlueGem - minBlueGem)) *
|
||||
3
|
||||
);
|
||||
res[ny][nx] = 13 + level;
|
||||
}
|
||||
} else {
|
||||
if (maxGreenGem === minGreenGem) {
|
||||
res[ny][nx] = 16;
|
||||
} else {
|
||||
const level = Math.floor(
|
||||
((value - minGreenGem) /
|
||||
(maxGreenGem - minGreenGem)) *
|
||||
3
|
||||
);
|
||||
res[ny][nx] = 16 + level;
|
||||
}
|
||||
}
|
||||
} else if (dict.potion[tile] !== void 0) {
|
||||
const value = dict.potion[tile];
|
||||
if (maxGreenGem === minGreenGem) {
|
||||
res[ny][nx] = 19;
|
||||
} else {
|
||||
const level = Math.floor(
|
||||
((value - minPotion) / (maxPotion - minPotion)) * 3
|
||||
);
|
||||
res[ny][nx] = 19 + level;
|
||||
}
|
||||
} else if (dict.door[tile] !== void 0) {
|
||||
const level = dict.door[tile];
|
||||
res[ny][nx] = 3 + level;
|
||||
} else if (dict.key[tile] !== void 0) {
|
||||
const level = dict.key[tile];
|
||||
res[ny][nx] = 7 + level;
|
||||
} else if (dict.item[tile] !== void 0) {
|
||||
const level = dict.item[tile];
|
||||
res[ny][nx] = 22 + level;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 5. 转换怪物
|
||||
const enemySet = new Set<Enemy>();
|
||||
for (let nx = 0; nx < w; nx++) {
|
||||
for (let ny = 0; ny < h; ny++) {
|
||||
@ -89,39 +199,30 @@ function convert(
|
||||
}
|
||||
const enemyArr = [...enemySet];
|
||||
enemyArr.sort((a, b) => a.num - b.num);
|
||||
if (
|
||||
enemyArr.length === 3 &&
|
||||
enemyArr[0].num === 201 &&
|
||||
enemyArr[1].num === 202 &&
|
||||
enemyArr[2].num === 203
|
||||
) {
|
||||
// pass
|
||||
} else {
|
||||
const attrs = [...enemySet].map(v => (v.atk + v.def) * v.hp);
|
||||
const maxAttr = Math.max(...attrs);
|
||||
const minAttr = Math.min(...attrs);
|
||||
const delta = maxAttr - minAttr;
|
||||
for (let ny = 0; ny < w; ny++) {
|
||||
for (let nx = 0; nx < h; nx++) {
|
||||
const tile = clipped[ny][nx];
|
||||
if (tile < 32) continue;
|
||||
const enemy = enemyMap[tile];
|
||||
if (!enemy) continue;
|
||||
// 替换为弱怪/中怪/强怪
|
||||
const attr = (enemy.atk + enemy.def) * enemy.hp;
|
||||
const ad = attr - minAttr;
|
||||
if (ad < delta / 3) {
|
||||
clipped[ny][nx] = 7;
|
||||
} else if (ad < (delta * 2) / 3) {
|
||||
clipped[ny][nx] = 8;
|
||||
} else {
|
||||
clipped[ny][nx] = 9;
|
||||
}
|
||||
|
||||
const attrs = [...enemySet].map(v => (v.atk + v.def) * v.hp);
|
||||
const maxAttr = Math.max(...attrs);
|
||||
const minAttr = Math.min(...attrs);
|
||||
const delta = maxAttr - minAttr;
|
||||
for (let ny = 0; ny < w; ny++) {
|
||||
for (let nx = 0; nx < h; nx++) {
|
||||
const tile = clipped[ny][nx];
|
||||
const enemy = enemyMap[tile];
|
||||
if (!enemy) continue;
|
||||
// 替换为弱怪/中怪/强怪
|
||||
const attr = (enemy.atk + enemy.def) * enemy.hp;
|
||||
const ad = attr - minAttr;
|
||||
if (ad < delta / 3 || delta === 0) {
|
||||
res[ny][nx] = 25;
|
||||
} else if (ad < (delta * 2) / 3) {
|
||||
res[ny][nx] = 26;
|
||||
} else {
|
||||
res[ny][nx] = 27;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return clipped;
|
||||
return res;
|
||||
}
|
||||
|
||||
export function convertFloor(
|
||||
|
||||
@ -11,11 +11,15 @@ export function parseGinka(data: Map<string, FloorData>) {
|
||||
|
||||
data.forEach((floor, key) => {
|
||||
const config = floor.config as GinkaConfig;
|
||||
const text = config.data[floor.id] ?? [];
|
||||
const data = config.data[floor.id] ?? {
|
||||
tag: Array(64).fill(0),
|
||||
val: Array(16).fill(0)
|
||||
};
|
||||
resolved[key] = {
|
||||
map: floor.map,
|
||||
size: [floor.map[0].length, floor.map.length],
|
||||
text: text
|
||||
tag: data.tag,
|
||||
val: data.val
|
||||
};
|
||||
i++;
|
||||
progress.update(i);
|
||||
|
||||
@ -12,23 +12,40 @@ export interface TowerInfo {
|
||||
config: BaseConfig;
|
||||
}
|
||||
|
||||
export interface GinkaData {
|
||||
tag: number[];
|
||||
val: number[];
|
||||
}
|
||||
|
||||
export interface GinkaConfig extends BaseConfig {
|
||||
data: Record<string, string[]>;
|
||||
data: Record<string, GinkaData>;
|
||||
mapping: {
|
||||
redGem: number[];
|
||||
blueGem: number[];
|
||||
greenGem: number[];
|
||||
yellowGem: number[];
|
||||
item: number[];
|
||||
potion: number[];
|
||||
key: number[];
|
||||
door: number[];
|
||||
/** 键表示图块,值表示等级或其增加的属性值,0是最低级,以此类推 */
|
||||
redGem: Record<number, number>;
|
||||
/** 键表示图块,值表示等级或其增加的属性值,0是最低级,以此类推 */
|
||||
blueGem: Record<number, number>;
|
||||
/** 键表示图块,值表示等级或其增加的属性值,0是最低级,以此类推 */
|
||||
greenGem: Record<number, number>;
|
||||
/** 键表示图块,值表示等级或其增加的属性值,0是最低级,以此类推 */
|
||||
yellowGem: Record<number, number>;
|
||||
/** 键表示图块,值表示等级或其增加的属性值,0是最低级,以此类推 */
|
||||
item: Record<number, number>;
|
||||
/** 键表示图块,值表示等级或其增加的属性值,0是最低级,以此类推 */
|
||||
potion: Record<number, number>;
|
||||
/** 键表示图块,值表示等级或其增加的属性值,0是最低级,以此类推 */
|
||||
key: Record<number, number>;
|
||||
/** 键表示图块,值表示等级或其增加的属性值,0是最低级,以此类推 */
|
||||
door: Record<number, number>;
|
||||
floor: number[];
|
||||
arrow: number[];
|
||||
wall: number[];
|
||||
decoration: number[];
|
||||
};
|
||||
}
|
||||
|
||||
export interface GinkaTrainData {
|
||||
text: string[];
|
||||
tag: number[];
|
||||
val: number[];
|
||||
map: number[][];
|
||||
size: [number, number];
|
||||
}
|
||||
|
||||
@ -36,9 +36,8 @@ from shared.image import matrix_to_image_cv
|
||||
# 19-21. 三种等级的血瓶
|
||||
# 22-24. 三种等级的道具
|
||||
# 25-27. 三种等级的怪物
|
||||
# 28-29. 留空
|
||||
# 30. 楼梯入口
|
||||
# 31. 箭头入口
|
||||
# 28. 楼梯入口
|
||||
# 29. 箭头入口
|
||||
|
||||
BATCH_SIZE = 16
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user