mirror of
https://github.com/unanmed/ginka-generator.git
synced 2026-05-24 13:11:10 +08:00
feat: 热力图生成
This commit is contained in:
parent
0cb22e9cf7
commit
326e6abf0b
@ -2,6 +2,7 @@ import { writeFile } from 'fs/promises';
|
|||||||
import { autoLabelTowers } from './auto/auto';
|
import { autoLabelTowers } from './auto/auto';
|
||||||
import { IAutoLabelConfig, TowerColor } from './auto/types';
|
import { IAutoLabelConfig, TowerColor } from './auto/types';
|
||||||
import { GinkaDataset, GinkaTrainData } from './types';
|
import { GinkaDataset, GinkaTrainData } from './types';
|
||||||
|
import { normalizeHeatmap } from './auto/heatmap';
|
||||||
|
|
||||||
const [, , output, towerInfo, ...folders] = process.argv;
|
const [, , output, towerInfo, ...folders] = process.argv;
|
||||||
|
|
||||||
@ -328,11 +329,15 @@ const labelConfig: IAutoLabelConfig = {
|
|||||||
const data: GinkaTrainData = {
|
const data: GinkaTrainData = {
|
||||||
map: floor.data.map,
|
map: floor.data.map,
|
||||||
size: [width, height],
|
size: [width, height],
|
||||||
tag: Array(64).fill(0),
|
heatmap: [
|
||||||
|
normalizeHeatmap(info.wallHeatmap),
|
||||||
|
normalizeHeatmap(info.enemyHeatmap),
|
||||||
|
normalizeHeatmap(info.resourceHeatmap),
|
||||||
|
normalizeHeatmap(info.entryHeatmap)
|
||||||
|
],
|
||||||
val: [
|
val: [
|
||||||
info.globalDensity,
|
info.globalDensity,
|
||||||
info.wallDensity,
|
info.wallDensity,
|
||||||
0,
|
|
||||||
info.doorDensity,
|
info.doorDensity,
|
||||||
info.enemyDensity,
|
info.enemyDensity,
|
||||||
info.resourceDensity,
|
info.resourceDensity,
|
||||||
@ -340,9 +345,10 @@ const labelConfig: IAutoLabelConfig = {
|
|||||||
info.potionDensity,
|
info.potionDensity,
|
||||||
info.keyDensity,
|
info.keyDensity,
|
||||||
info.itemDensity,
|
info.itemDensity,
|
||||||
info.entryCount,
|
info.entryCount / width / height,
|
||||||
info.specialDoorCount,
|
0,
|
||||||
info.fishCount,
|
0,
|
||||||
|
0,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0
|
0
|
||||||
|
|||||||
84
data/src/auto/heatmap.ts
Normal file
84
data/src/auto/heatmap.ts
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
/**
|
||||||
|
* 将地图转换为热力图
|
||||||
|
* @param map 地图矩阵
|
||||||
|
* @param tokens 计入热力图的图块
|
||||||
|
*/
|
||||||
|
export function generateHeatmap(
|
||||||
|
map: number[][],
|
||||||
|
tokens: Set<number>,
|
||||||
|
kernel: number = 5
|
||||||
|
): number[][] {
|
||||||
|
if (kernel % 2 !== 1) {
|
||||||
|
throw new Error(`Kernal size must be odd.`);
|
||||||
|
}
|
||||||
|
const width = map[0].length;
|
||||||
|
const height = map.length;
|
||||||
|
const result: number[][] = Array.from({ length: height }, _ =>
|
||||||
|
Array.from({ length: width }, _ => 0)
|
||||||
|
);
|
||||||
|
const radius = Math.floor(kernel / 2);
|
||||||
|
for (let y = 0; y < height; y++) {
|
||||||
|
for (let x = 0; x < width; x++) {
|
||||||
|
const left = Math.max(0, x - radius);
|
||||||
|
const right = Math.min(width, x + radius);
|
||||||
|
const top = Math.max(0, y - radius);
|
||||||
|
const bottom = Math.min(height, y + radius);
|
||||||
|
const size = (right - left) * (bottom - top);
|
||||||
|
let num = 0;
|
||||||
|
for (let ky = top; ky < bottom; ky++) {
|
||||||
|
for (let kx = left; kx < right; kx++) {
|
||||||
|
if (tokens.has(map[ky][kx])) {
|
||||||
|
num++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result[y][x] = num / size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对热力图实施高斯模糊
|
||||||
|
* @param map 热力图
|
||||||
|
* @param sigma 标准差
|
||||||
|
*/
|
||||||
|
export function gaussainHeatmap(map: number[][], sigma: number = 1) {
|
||||||
|
const radius = sigma * 3;
|
||||||
|
const width = map[0].length;
|
||||||
|
const height = map.length;
|
||||||
|
const result: number[][] = Array.from({ length: height }, _ =>
|
||||||
|
Array.from({ length: width }, _ => 0)
|
||||||
|
);
|
||||||
|
const s = sigma ** 2;
|
||||||
|
for (let y = 0; y < height; y++) {
|
||||||
|
for (let x = 0; x < width; x++) {
|
||||||
|
const left = Math.max(0, x - radius);
|
||||||
|
const right = Math.min(width - 1, x + radius);
|
||||||
|
const top = Math.max(0, y - radius);
|
||||||
|
const bottom = Math.min(height - 1, y + radius);
|
||||||
|
let res = 0;
|
||||||
|
for (let ky = top; ky < bottom; ky++) {
|
||||||
|
for (let kx = left; kx < right; kx++) {
|
||||||
|
const dis = (ky - y) ** 2 + (kx - x) ** 2;
|
||||||
|
const g = Math.E ** (-dis / (2 * s)) / (2 * Math.PI * s);
|
||||||
|
res += map[ky][kx] * g;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result[y][x] = res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 归一化热力图
|
||||||
|
* @param map 热力图
|
||||||
|
*/
|
||||||
|
export function normalizeHeatmap(map: number[][]) {
|
||||||
|
const max = Math.max(...map.flat());
|
||||||
|
const min = Math.min(...map.flat());
|
||||||
|
if (max === min) return map;
|
||||||
|
const d = max - min;
|
||||||
|
return map.map(line => line.map(v => (v - min) / d));
|
||||||
|
}
|
||||||
@ -16,6 +16,7 @@ import {
|
|||||||
wallTiles
|
wallTiles
|
||||||
} from '../shared';
|
} from '../shared';
|
||||||
import { NodeType } from '../topology/interface';
|
import { NodeType } from '../topology/interface';
|
||||||
|
import { gaussainHeatmap, generateHeatmap } from './heatmap';
|
||||||
|
|
||||||
interface IRawTowerInfo {
|
interface IRawTowerInfo {
|
||||||
/** 作者 id */
|
/** 作者 id */
|
||||||
@ -227,7 +228,11 @@ export function parseFloorInfo(tower: ITowerInfo, map: number[][]): IFloorInfo {
|
|||||||
specialDoorCount: count(flattened, specialDoorTiles),
|
specialDoorCount: count(flattened, specialDoorTiles),
|
||||||
fishCount,
|
fishCount,
|
||||||
hasUselessBranch,
|
hasUselessBranch,
|
||||||
wallDensityStd: computeWallDensityStd(map, wallTiles, 5)
|
wallDensityStd: computeWallDensityStd(map, wallTiles, 5),
|
||||||
|
wallHeatmap: gaussainHeatmap(generateHeatmap(map, wallTiles)),
|
||||||
|
enemyHeatmap: gaussainHeatmap(generateHeatmap(map, enemyTiles)),
|
||||||
|
resourceHeatmap: gaussainHeatmap(generateHeatmap(map, resourceTiles)),
|
||||||
|
entryHeatmap: gaussainHeatmap(generateHeatmap(map, entryTiles))
|
||||||
};
|
};
|
||||||
|
|
||||||
return floorInfo;
|
return floorInfo;
|
||||||
|
|||||||
@ -93,6 +93,15 @@ export interface IFloorInfo {
|
|||||||
readonly hasUselessBranch: boolean;
|
readonly hasUselessBranch: boolean;
|
||||||
/** 墙壁密度标准差 */
|
/** 墙壁密度标准差 */
|
||||||
readonly wallDensityStd: number;
|
readonly wallDensityStd: number;
|
||||||
|
|
||||||
|
/** 怪物热力图 */
|
||||||
|
readonly enemyHeatmap: number[][];
|
||||||
|
/** 资源热力图 */
|
||||||
|
readonly resourceHeatmap: number[][];
|
||||||
|
/** 入口热力图 */
|
||||||
|
readonly entryHeatmap: number[][];
|
||||||
|
/** 墙壁热力图 */
|
||||||
|
readonly wallHeatmap: number[][];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IMapBlockConfig {
|
export interface IMapBlockConfig {
|
||||||
|
|||||||
@ -43,10 +43,11 @@ export interface GinkaConfig extends BaseConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface GinkaTrainData {
|
export interface GinkaTrainData {
|
||||||
tag: number[];
|
tag?: number[];
|
||||||
val: number[];
|
val: number[];
|
||||||
map: number[][];
|
map: number[][];
|
||||||
size: [number, number];
|
size: [number, number];
|
||||||
|
heatmap?: number[][][];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GinkaDataset {
|
export interface GinkaDataset {
|
||||||
|
|||||||
@ -31,17 +31,14 @@ from .transformer.mask import MapMask
|
|||||||
# 标量值定义:
|
# 标量值定义:
|
||||||
# 0. 整体密度,非空白图块/地图面积,空白图块还包括装饰图块
|
# 0. 整体密度,非空白图块/地图面积,空白图块还包括装饰图块
|
||||||
# 1. 墙体密度,墙壁/地图面积
|
# 1. 墙体密度,墙壁/地图面积
|
||||||
# 2. 装饰密度,装饰数量/地图面积
|
# 2. 门密度,门数量/地图面积
|
||||||
# 3. 门密度,门数量/地图面积
|
# 3. 怪物密度,怪物数量/地图面积
|
||||||
# 4. 怪物密度,怪物数量/地图面积
|
# 4. 资源密度,资源数量/地图面积
|
||||||
# 5. 资源密度,资源数量/地图面积
|
# 5. 宝石密度,宝石数量/地图面积
|
||||||
# 6. 宝石密度,宝石数量/地图面积
|
# 6. 血瓶密度,血瓶数量/地图面积
|
||||||
# 7. 血瓶密度,血瓶数量/地图面积
|
# 7. 钥匙密度,钥匙数量/地图面积
|
||||||
# 8. 钥匙密度,钥匙数量/地图面积
|
# 8. 道具密度,道具数量/地图面积
|
||||||
# 9. 道具密度,道具数量/地图面积
|
# 9. 入口数量
|
||||||
# 10. 入口数量
|
|
||||||
# 11. 机关门数量
|
|
||||||
# 12. 咸鱼门数量(多层咸鱼门只算一个)
|
|
||||||
|
|
||||||
# 图块定义:
|
# 图块定义:
|
||||||
# 0. 空地, 1. 墙壁, 2. 门, 3. 钥匙, 4. 红宝石, 5. 蓝宝石, 6. 绿宝石, 7. 血瓶
|
# 0. 空地, 1. 墙壁, 2. 门, 3. 钥匙, 4. 红宝石, 5. 蓝宝石, 6. 绿宝石, 7. 血瓶
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user