using UnityEngine; using System.Collections.Generic; using System.Linq; namespace AibisDream.MiniGame.Language { /// /// 分析模式网格生成器 /// 根据配置数据智能生成网格布局,确保唯一解 /// public class AnalysisModeGenerator { private AnalysisModeData config; private System.Random random; public AnalysisModeGenerator(AnalysisModeData config, int seed = -1) { this.config = config; this.random = seed >= 0 ? new System.Random(seed) : new System.Random(); } /// /// 生成完整的网格数据 /// public GridCell[,] GenerateGrid(int gridWidth, int gridHeight) { GridCell[,] grid = new GridCell[gridHeight, gridWidth]; // 第一步:放置答案词(在正确的解码器位置) PlaceAnswerWords(grid, gridWidth, gridHeight); // 第二步:放置诱饵词(相同情绪,但位置不匹配解码器) PlaceDecoyWords(grid, gridWidth, gridHeight); // 第三步:填充中性词 FillNeutralWords(grid, gridWidth, gridHeight); // 第四步:验证唯一解 if (!ValidateUniqueSolution(grid, gridWidth, gridHeight)) { Debug.LogWarning("[AnalysisModeGenerator] 生成的网格可能没有唯一解,建议调整配置"); } return grid; } /// /// 放置答案词 /// private void PlaceAnswerWords(GridCell[,] grid, int gridWidth, int gridHeight) { Vector2Int decoderPos = config.correctDecoderPosition; for (int i = 0; i < config.answerWords.Count; i++) { // 计算答案词的绝对位置 = 解码器位置 + 孔洞相对位置 Vector2Int holeOffset = config.holePositions[i]; int row = decoderPos.x + holeOffset.x; int col = decoderPos.y + holeOffset.y; // 确保位置在网格范围内 if (row < 0 || row >= gridHeight || col < 0 || col >= gridWidth) { Debug.LogError($"[AnalysisModeGenerator] 答案词位置({row}, {col})超出网格范围"); continue; } // 放置答案词 grid[row, col] = new GridCell { row = row, col = col, word = config.answerWords[i], emotion = config.answerEmotion, isTarget = true }; } } /// /// 放置诱饵词(相同情绪,但不匹配解码器) /// private void PlaceDecoyWords(GridCell[,] grid, int gridWidth, int gridHeight) { // 为每种情绪生成诱饵词 EmotionType[] emotions = { EmotionType.Joy, EmotionType.Sadness, EmotionType.Anger, EmotionType.Fear }; foreach (var emotion in emotions) { // 获取该情绪的诱饵词数量 int decoyCount = config.decoyCountPerEmotion; // 如果是答案情绪,减去答案词数量 if (emotion == config.answerEmotion) { decoyCount = Mathf.Max(0, decoyCount - config.answerWords.Count); } // 获取随机词语(排除答案词) List decoyWords = config.wordPool.GetRandomWords( emotion, decoyCount, emotion == config.answerEmotion ? config.answerWords : null ); // 放置诱饵词 PlaceWordsRandomly(grid, gridWidth, gridHeight, decoyWords, emotion, false); } } /// /// 填充中性词 /// private void FillNeutralWords(GridCell[,] grid, int gridWidth, int gridHeight) { List neutralWords = new List(config.wordPool.neutralWords); // 随机打乱 neutralWords = neutralWords.OrderBy(x => random.Next()).ToList(); int wordIndex = 0; for (int row = 0; row < gridHeight; row++) { for (int col = 0; col < gridWidth; col++) { if (grid[row, col] == null) { // 如果词库用完了,重新开始 if (wordIndex >= neutralWords.Count) { wordIndex = 0; } grid[row, col] = new GridCell { row = row, col = col, word = neutralWords[wordIndex], emotion = EmotionType.Neutral, isTarget = false }; wordIndex++; } } } } /// /// 随机放置词语 /// private void PlaceWordsRandomly(GridCell[,] grid, int gridWidth, int gridHeight, List words, EmotionType emotion, bool isTarget) { List availablePositions = new List(); // 收集所有可用位置 for (int row = 0; row < gridHeight; row++) { for (int col = 0; col < gridWidth; col++) { if (grid[row, col] == null) { availablePositions.Add(new Vector2Int(row, col)); } } } // 随机打乱 availablePositions = availablePositions.OrderBy(x => random.Next()).ToList(); // 放置词语 for (int i = 0; i < words.Count && i < availablePositions.Count; i++) { Vector2Int pos = availablePositions[i]; grid[pos.x, pos.y] = new GridCell { row = pos.x, col = pos.y, word = words[i], emotion = emotion, isTarget = isTarget }; } } /// /// 验证唯一解:检查是否只有一个位置和情绪组合能匹配所有答案词 /// private bool ValidateUniqueSolution(GridCell[,] grid, int gridWidth, int gridHeight) { int matchCount = 0; Vector2Int correctPos = config.correctDecoderPosition; // 遍历所有可能的解码器位置 for (int row = 0; row <= gridHeight - config.decoderHeight; row++) { for (int col = 0; col <= gridWidth - config.decoderWidth; col++) { // 遍历所有情绪 foreach (EmotionType emotion in System.Enum.GetValues(typeof(EmotionType))) { if (emotion == EmotionType.Neutral) continue; // 检查是否所有孔洞位置都匹配该情绪 bool allMatch = true; List matchedWords = new List(); foreach (var hole in config.holePositions) { int checkRow = row + hole.x; int checkCol = col + hole.y; if (checkRow >= gridHeight || checkCol >= gridWidth) { allMatch = false; break; } GridCell cell = grid[checkRow, checkCol]; if (cell == null || cell.emotion != emotion) { allMatch = false; break; } matchedWords.Add(cell.word); } // 如果所有孔洞都匹配 if (allMatch) { matchCount++; // 检查是否是正确答案 bool isCorrectAnswer = (row == correctPos.x && col == correctPos.y && emotion == config.answerEmotion); if (isCorrectAnswer) { // 验证词语是否完全匹配 bool wordsMatch = true; for (int i = 0; i < config.answerWords.Count; i++) { if (matchedWords[i] != config.answerWords[i]) { wordsMatch = false; break; } } if (!wordsMatch) { Debug.LogError("[AnalysisModeGenerator] 正确位置的词语不匹配答案!"); return false; } } else { // 诱饵解 Debug.Log($"[AnalysisModeGenerator] 发现诱饵解: 位置({row},{col}), 情绪{emotion}, 词语[{string.Join(",", matchedWords)}]"); } } } } } // 应该恰好有一个解 if (matchCount == 0) { Debug.LogError("[AnalysisModeGenerator] 没有找到任何解!"); return false; } else if (matchCount > 1) { Debug.LogWarning($"[AnalysisModeGenerator] 找到 {matchCount} 个可能的解(包括诱饵),这可能增加难度"); } else { Debug.Log("[AnalysisModeGenerator] 验证通过:唯一解"); } return true; } /// /// 生成笑话演出数据(可选) /// 将网格数据转换为笑话段落,用于初始演出 /// public List GenerateJokePhrases(GridCell[,] grid, int gridWidth, int gridHeight) { // 如果配置中有笑话,直接使用 if (config.jokePhrases != null && config.jokePhrases.Count > 0) { return new List(config.jokePhrases); } // 否则从网格词语生成简单的笑话段落 List phrases = new List(); System.Text.StringBuilder sb = new System.Text.StringBuilder(); for (int row = 0; row < gridHeight; row++) { for (int col = 0; col < gridWidth; col += 10) // 每10个词组成一句 { sb.Clear(); for (int i = 0; i < 10 && col + i < gridWidth; i++) { if (grid[row, col + i] != null) { sb.Append(grid[row, col + i].word); } } if (sb.Length > 0) { phrases.Add(sb.ToString()); } } } return phrases; } /// /// 生成解析目标配置(用于 AnalysisModeManager) /// public AnalysisTarget GenerateAnalysisTarget() { AnalysisTarget target = new AnalysisTarget { name = config.levelName, emotion = config.answerEmotion, stripPosition = config.correctDecoderPosition, isCorrectAnswer = true, words = new List() }; // 添加目标词 for (int i = 0; i < config.answerWords.Count; i++) { Vector2Int holeOffset = config.holePositions[i]; Vector2Int absolutePos = new Vector2Int( config.correctDecoderPosition.x + holeOffset.x, config.correctDecoderPosition.y + holeOffset.y ); target.words.Add(new TargetWord { position = absolutePos, word = config.answerWords[i] }); } return target; } } }