/**
* @fileoverview Schema-Definition und Validierung für Heuristik-Konfigurationen.
* Unterstützt Profile (v1_baseline, v2_positional, v3_aggressive) pro Game-Variante.
* @author Alexander Wolf
*/
const HEURISTIC_CONFIG_SCHEMA = {
required: ['game', 'variant'],
games: ['ttt', 'connect4', 'knights-tour', 'chess-variant', 'nim', 'generic'],
variants: {
ttt: ['regular', '3d', 'ultimate'],
connect4: ['regular', '3d'],
'knights-tour': ['warnsdorf'],
'chess-variant': ['pawn-chess', 'anti-chess'],
nim: ['standard'],
generic: ['winLoss']
},
/** Erlaubte Profilnamen für differenzierte Heuristik-Varianten */
profiles: ['v1_baseline', 'v2_positional', 'v3_aggressive'],
weightDefinitions: {
win: { type: 'number', default: 1000, min: 1, max: 1000000 },
loss: { type: 'number', default: -1000, min: -1000000, max: -1 },
draw: { type: 'number', default: 0, min: -100, max: 100 },
twoInLine: { type: 'number', default: 10, min: 0, max: 100000 },
oneInLine: { type: 'number', default: 1, min: 0, max: 100000 },
threeInLine: { type: 'number', default: 100, min: 0, max: 100000 },
fourInRow: { type: 'number', default: 10000, min: 0, max: 1000000 },
opponentTwoInLine: { type: 'number', default: -10, max: 0 },
opponentThreeInLine: { type: 'number', default: -90, max: 0 },
centerBonus: { type: 'number', default: 20, min: 0, max: 100000 },
centerWeight: { type: 'number', default: 3, min: 0, max: 100000 },
spatialControl: { type: 'number', default: 2, min: 0, max: 100000 },
macroWeight: { type: 'number', default: 50, min: 0, max: 100000 },
boardWonBonus: { type: 'number', default: 20, min: 0, max: 100000 },
mobilityWeight: { type: 'number', default: 1, min: 0, max: 100000 },
cornerBonus: { type: 'number', default: 3, min: 0, max: 100000 },
edgeBonus: { type: 'number', default: 1, min: 0, max: 100000 },
forkBonus: { type: 'number', default: 50, min: 0, max: 100000 },
opponentForkPenalty: { type: 'number', default: -50, min: -100000, max: 0 },
pressureWeight: { type: 'number', default: 15, min: 0, max: 100000 },
blockUrgency: { type: 'number', default: 80, min: 0, max: 100000 },
threatMultiplier: { type: 'number', default: 5, min: 0, max: 100000 },
connectivityBonus: { type: 'number', default: 8, min: 0, max: 100000 },
heightPenalty: { type: 'number', default: -2, min: -100000, max: 0 },
setupBonus: { type: 'number', default: 15, min: 0, max: 100000 }
}
};
/**
* Validiert eine Heuristik-Konfiguration gegen das zentrale Schema.
* Unterstützt optionales `profile`-Feld und `description`-Feld.
* @param {Object} config - Rohkonfiguration.
* @returns {Object} Validierte Konfiguration mit normalisierten Gewichten.
*/
function validateHeuristicConfig(config) {
for (const field of HEURISTIC_CONFIG_SCHEMA.required) {
if (config[field] === undefined || config[field] === null || config[field] === '') {
throw new Error(`Pflichtfeld '${field}' fehlt in Heuristik-Config.`);
}
}
if (!HEURISTIC_CONFIG_SCHEMA.games.includes(config.game)) {
throw new Error(`Unbekanntes Spiel: '${config.game}'.`);
}
const allowedVariants = HEURISTIC_CONFIG_SCHEMA.variants[config.game] || [];
if (!allowedVariants.includes(config.variant)) {
throw new Error(`Unbekannte Variante '${config.variant}' für Spiel '${config.game}'.`);
}
const inputWeights = config.weights || {};
const validatedWeights = {};
for (const [key, definition] of Object.entries(HEURISTIC_CONFIG_SCHEMA.weightDefinitions)) {
if (!(key in inputWeights)) {
validatedWeights[key] = definition.default;
continue;
}
const value = inputWeights[key];
if (typeof value !== definition.type) {
throw new Error(`Parameter '${key}' muss vom Typ '${definition.type}' sein.`);
}
if (definition.min !== undefined && value < definition.min) {
throw new Error(`Parameter '${key}' ist kleiner als Minimum ${definition.min}.`);
}
if (definition.max !== undefined && value > definition.max) {
throw new Error(`Parameter '${key}' ist größer als Maximum ${definition.max}.`);
}
validatedWeights[key] = value;
}
for (const key of Object.keys(inputWeights)) {
if (!HEURISTIC_CONFIG_SCHEMA.weightDefinitions[key]) {
if (typeof DebugConfig !== 'undefined' && typeof DEBUG_DOMAINS !== 'undefined') {
DebugConfig.log(DEBUG_DOMAINS.AI_HEURISTICS, 'warn', 'Unknown heuristic weight ignored', { key });
}
}
}
return {
...config,
name: config.name || `${config.game}-${config.variant}`,
profile: config.profile || null,
description: config.description || '',
weights: validatedWeights
};
}