feat: consolida lessico semantico, temi controllati e filler a quota tematica
This commit is contained in:
@@ -62,7 +62,7 @@ class FillCandidate:
|
||||
slot: FillSlot
|
||||
new_letters: int
|
||||
reused_letters: int
|
||||
local_score: Tuple[int, int, int]
|
||||
local_score: Tuple[int, ...]
|
||||
|
||||
|
||||
class CrosswordFiller:
|
||||
@@ -73,6 +73,9 @@ class CrosswordFiller:
|
||||
*,
|
||||
target_empty_ratio: float = TARGET_EMPTY_RATIO,
|
||||
vocabulary_metadata: Optional[Dict[str, Dict[str, object]]] = None,
|
||||
semantic_metadata: Optional[Dict[str, Dict[str, object]]] = None,
|
||||
selected_topic: str = "general",
|
||||
max_themed_fill_words: int = 10,
|
||||
seed: Optional[int] = None,
|
||||
) -> None:
|
||||
self.state = state.copy()
|
||||
@@ -83,6 +86,9 @@ class CrosswordFiller:
|
||||
self.vocabulary = self._normalize_vocabulary(vocabulary)
|
||||
self.words_by_length = self._index_vocabulary(self.vocabulary)
|
||||
self.vocabulary_metadata = vocabulary_metadata or {}
|
||||
self.semantic_metadata = semantic_metadata or {}
|
||||
self.selected_topic = selected_topic.strip().lower()
|
||||
self.max_themed_fill_words = max(0, max_themed_fill_words)
|
||||
self.seed = seed
|
||||
self.rng = random.Random(seed)
|
||||
self.bounds = self._compute_bounds(self.state.grid)
|
||||
@@ -281,9 +287,11 @@ class CrosswordFiller:
|
||||
new_letters = sum(1 for cell in slot.cells if cell not in self.state.grid)
|
||||
reused_letters = slot.fixed_letters
|
||||
local_score = (
|
||||
self._semantic_topic_score(word),
|
||||
reused_letters,
|
||||
new_letters,
|
||||
self._word_quality(word),
|
||||
self._semantic_quality(word),
|
||||
len(set(word)),
|
||||
)
|
||||
candidates.append(
|
||||
@@ -311,6 +319,56 @@ class CrosswordFiller:
|
||||
except (TypeError, ValueError):
|
||||
return 0
|
||||
|
||||
def _semantic_entry(self, word: str) -> Dict[str, object]:
|
||||
return self.semantic_metadata.get(word, {})
|
||||
|
||||
def _semantic_quality(self, word: str) -> int:
|
||||
entry = self._semantic_entry(word)
|
||||
semantic = entry.get("semantic", {})
|
||||
score = 0
|
||||
if semantic.get("matched"):
|
||||
score += 2
|
||||
score += min(3, len(semantic.get("glosses", [])))
|
||||
score += min(2, len(semantic.get("synonyms", [])))
|
||||
return score
|
||||
|
||||
def _semantic_topic_score(self, word: str) -> int:
|
||||
if not self.selected_topic or self.selected_topic == "general":
|
||||
return 0
|
||||
|
||||
entry = self._semantic_entry(word)
|
||||
try:
|
||||
relevance = int(entry.get("_topic_relevance", 0))
|
||||
except (TypeError, ValueError):
|
||||
relevance = 0
|
||||
if relevance:
|
||||
if self._themed_added_count() < self.max_themed_fill_words:
|
||||
return relevance
|
||||
return min(relevance, 10)
|
||||
|
||||
topics = {str(item).lower() for item in entry.get("topics", [])}
|
||||
semantic = entry.get("semantic", {})
|
||||
semantic_topics = {str(item).lower() for item in semantic.get("semantic_topics", [])}
|
||||
score = 0
|
||||
if self.selected_topic in topics:
|
||||
score += 4
|
||||
if self.selected_topic in semantic_topics:
|
||||
score += 6
|
||||
if "general" in topics:
|
||||
score += 1
|
||||
return score
|
||||
|
||||
def _themed_added_count(self) -> int:
|
||||
total = 0
|
||||
for placement in self.added_words:
|
||||
entry = self._semantic_entry(placement.word)
|
||||
try:
|
||||
if int(entry.get("_strong_topic_relevance", 0)) > 0:
|
||||
total += 1
|
||||
except (TypeError, ValueError):
|
||||
continue
|
||||
return total
|
||||
|
||||
def _placement_is_valid(self, slot: FillSlot, word: str) -> bool:
|
||||
dx, dy = (1, 0) if slot.direction == HORIZONTAL else (0, 1)
|
||||
before = (slot.x - dx, slot.y - dy)
|
||||
@@ -380,6 +438,7 @@ class CrosswordFiller:
|
||||
f"vuote={self.empty_cells_count()}/{self.total_cells} "
|
||||
f"target={self.target_empty_cells} "
|
||||
f"aggiunte={len(self.added_words)} "
|
||||
f"tema={self._themed_added_count()}/{self.max_themed_fill_words} "
|
||||
f"ultima={self.last_word} "
|
||||
f"t={elapsed:0.1f}s"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user