use shared_kernel::{normalize_required_string, normalize_string_list}; use crate::{ SQUARE_HOLE_MAX_DIFFICULTY, SQUARE_HOLE_MAX_SHAPE_COUNT, SQUARE_HOLE_MIN_DIFFICULTY, SQUARE_HOLE_MIN_SHAPE_COUNT, SquareHoleCreatorConfig, SquareHoleError, SquareHoleResultDraft, normalize_hole_options, normalize_shape_options, }; pub fn validate_shape_count(value: u32) -> Result { if (SQUARE_HOLE_MIN_SHAPE_COUNT..=SQUARE_HOLE_MAX_SHAPE_COUNT).contains(&value) { Ok(value) } else { Err(SquareHoleError::InvalidShapeCount) } } pub fn validate_difficulty(value: u32) -> Result { if (SQUARE_HOLE_MIN_DIFFICULTY..=SQUARE_HOLE_MAX_DIFFICULTY).contains(&value) { Ok(value) } else { Err(SquareHoleError::InvalidDifficulty) } } pub fn normalize_theme_text(value: impl AsRef) -> Result { normalize_required_string(value).ok_or(SquareHoleError::MissingText) } pub fn build_creator_config( theme_text: &str, twist_rule: &str, shape_count: u32, difficulty: u32, ) -> Result { let hole_options = normalize_hole_options(Vec::new(), theme_text); Ok(SquareHoleCreatorConfig { theme_text: normalize_theme_text(theme_text)?, twist_rule: normalize_required_string(twist_rule).ok_or(SquareHoleError::MissingText)?, shape_count: validate_shape_count(shape_count)?, difficulty: validate_difficulty(difficulty)?, shape_options: normalize_shape_options(Vec::new(), theme_text, hole_options.as_slice()), hole_options, background_prompt: format!("{theme_text}主题的竖屏游戏背景,舞台中央有多个形状洞口"), cover_image_src: None, background_image_src: None, }) } pub fn build_default_tags(theme_text: &str) -> Vec { normalize_string_list(vec![ "方洞挑战".to_string(), theme_text.to_string(), "反直觉".to_string(), ]) } pub fn default_tags_for_theme(theme_text: &str) -> Vec { let mut tags = vec![ "方洞挑战".to_string(), "反直觉".to_string(), theme_text.to_string(), ]; tags.sort(); tags.dedup(); tags } pub fn validate_publish_requirements(draft: &SquareHoleResultDraft) -> Vec { let mut blockers = Vec::new(); if normalize_required_string(&draft.game_name).is_none() { blockers.push("游戏名称不能为空".to_string()); } if normalize_required_string(&draft.summary).is_none() { blockers.push("简介不能为空".to_string()); } if normalize_required_string(&draft.theme_text).is_none() { blockers.push("题材不能为空".to_string()); } if normalize_required_string(&draft.twist_rule).is_none() { blockers.push("反直觉规则不能为空".to_string()); } if normalize_string_list(draft.tags.clone()).is_empty() { blockers.push("至少需要 1 个标签".to_string()); } if validate_shape_count(draft.shape_count).is_err() { blockers.push(format!( "形状数量必须在 {} 到 {} 之间", SQUARE_HOLE_MIN_SHAPE_COUNT, SQUARE_HOLE_MAX_SHAPE_COUNT )); } if validate_difficulty(draft.difficulty).is_err() { blockers.push("难度必须在 1 到 10 之间".to_string()); } if draft.shape_options.len() < crate::SQUARE_HOLE_MIN_SHAPE_OPTION_COUNT { blockers.push("至少需要 6 个形状图片选项".to_string()); } if draft.hole_options.len() < crate::SQUARE_HOLE_MIN_HOLE_OPTION_COUNT { blockers.push("至少需要 3 个洞口选项".to_string()); } blockers }