Files
aibis-dream/Assets/Scripts/MiniGame/HuoShan/AnalysisSystem/AnalysisModeGenerator.cs
T
2025-12-11 18:27:51 +08:00

359 lines
13 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using UnityEngine;
using System.Collections.Generic;
using System.Linq;
namespace AibisDream.MiniGame.Language
{
/// <summary>
/// 分析模式网格生成器
/// 根据配置数据智能生成网格布局,确保唯一解
/// </summary>
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();
}
/// <summary>
/// 生成完整的网格数据
/// </summary>
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;
}
/// <summary>
/// 放置答案词
/// </summary>
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
};
}
}
/// <summary>
/// 放置诱饵词(相同情绪,但不匹配解码器)
/// </summary>
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<string> decoyWords = config.wordPool.GetRandomWords(
emotion,
decoyCount,
emotion == config.answerEmotion ? config.answerWords : null
);
// 放置诱饵词
PlaceWordsRandomly(grid, gridWidth, gridHeight, decoyWords, emotion, false);
}
}
/// <summary>
/// 填充中性词
/// </summary>
private void FillNeutralWords(GridCell[,] grid, int gridWidth, int gridHeight)
{
List<string> neutralWords = new List<string>(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++;
}
}
}
}
/// <summary>
/// 随机放置词语
/// </summary>
private void PlaceWordsRandomly(GridCell[,] grid, int gridWidth, int gridHeight,
List<string> words, EmotionType emotion, bool isTarget)
{
List<Vector2Int> availablePositions = new List<Vector2Int>();
// 收集所有可用位置
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
};
}
}
/// <summary>
/// 验证唯一解:检查是否只有一个位置和情绪组合能匹配所有答案词
/// </summary>
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<string> matchedWords = new List<string>();
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;
}
/// <summary>
/// 生成笑话演出数据(可选)
/// 将网格数据转换为笑话段落,用于初始演出
/// </summary>
public List<string> GenerateJokePhrases(GridCell[,] grid, int gridWidth, int gridHeight)
{
// 如果配置中有笑话,直接使用
if (config.jokePhrases != null && config.jokePhrases.Count > 0)
{
return new List<string>(config.jokePhrases);
}
// 否则从网格词语生成简单的笑话段落
List<string> phrases = new List<string>();
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;
}
/// <summary>
/// 生成解析目标配置(用于 AnalysisModeManager
/// </summary>
public AnalysisTarget GenerateAnalysisTarget()
{
AnalysisTarget target = new AnalysisTarget
{
name = config.levelName,
emotion = config.answerEmotion,
stripPosition = config.correctDecoderPosition,
isCorrectAnswer = true,
words = new List<TargetWord>()
};
// 添加目标词
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;
}
}
}