mirror of
https://github.com/InternLM/InternBootcamp.git
synced 2026-04-23 16:55:02 +00:00
init-commit
This commit is contained in:
commit
18a552597a
3461 changed files with 1150579 additions and 0 deletions
0
internbootcamp/libs/wordladder/solving/__init__.py
Executable file
0
internbootcamp/libs/wordladder/solving/__init__.py
Executable file
27
internbootcamp/libs/wordladder/solving/puzzle.py
Executable file
27
internbootcamp/libs/wordladder/solving/puzzle.py
Executable file
|
|
@ -0,0 +1,27 @@
|
|||
from libs.wordladder.solving.word_distance_map import WordDistanceMap
|
||||
from libs.wordladder.words.word import Word
|
||||
|
||||
|
||||
class Puzzle(object):
|
||||
def __init__(self, start_word: Word, end_word: Word):
|
||||
self.start_word = start_word
|
||||
self.end_word = end_word
|
||||
|
||||
def calculate_minimum_ladder_length(self):
|
||||
start: Word = self.start_word
|
||||
end: Word = self.end_word
|
||||
diffs = start - end
|
||||
if diffs == 0 or diffs == 1:
|
||||
return diffs + 1
|
||||
elif diffs == 2:
|
||||
common = set()
|
||||
for word in start.linked_words:
|
||||
common.add(str(word))
|
||||
for word in end.linked_words:
|
||||
if str(word) in common:
|
||||
return 3
|
||||
if len(start.linked_words) > len(end.linked_words):
|
||||
start = self.end_word
|
||||
end = self.start_word
|
||||
return WordDistanceMap(start)[end]
|
||||
|
||||
68
internbootcamp/libs/wordladder/solving/solution.py
Executable file
68
internbootcamp/libs/wordladder/solving/solution.py
Executable file
|
|
@ -0,0 +1,68 @@
|
|||
from __future__ import annotations
|
||||
from libs.wordladder.words.word import Word
|
||||
|
||||
|
||||
class Solution(object):
|
||||
__slots__ = ['ladder']
|
||||
|
||||
def __init__(self, *words: Word):
|
||||
self.ladder = []
|
||||
for word in words:
|
||||
self.ladder.append(word)
|
||||
|
||||
def __str__(self):
|
||||
return '[' + ','.join([str(word) for word in self.ladder]) + ']'
|
||||
|
||||
def __len__(self):
|
||||
return len(self.ladder)
|
||||
|
||||
def __getitem__(self, index) -> Word:
|
||||
return self.ladder[index]
|
||||
|
||||
# supports soring
|
||||
def __lt__(self, other):
|
||||
if not isinstance(other, Solution) or other is None or len(self) < len(other):
|
||||
return True
|
||||
elif len(self) > len(other):
|
||||
return False
|
||||
for i in range(len(self)):
|
||||
if str(self.ladder[i]) < str(other.ladder[i]):
|
||||
return True
|
||||
elif str(self.ladder[i]) > str(other.ladder[i]):
|
||||
return False
|
||||
return False
|
||||
|
||||
|
||||
class CandidateSolution(object):
|
||||
__slots__ = ['ladder', 'seen_words']
|
||||
|
||||
def __init__(self, *words: Word):
|
||||
self.ladder = []
|
||||
for word in words:
|
||||
self.ladder.append(word)
|
||||
self.seen_words = set()
|
||||
for word in self.ladder:
|
||||
self.seen_words.add(str(word))
|
||||
|
||||
def seen(self, word: Word) -> bool:
|
||||
return str(word) in self.seen_words
|
||||
|
||||
def spawn(self, next_word: Word) -> CandidateSolution:
|
||||
result = CandidateSolution(*self.ladder)
|
||||
for s in self.seen_words:
|
||||
result.seen_words.add(s)
|
||||
result.seen_words.add(str(next_word))
|
||||
result.ladder.append(next_word)
|
||||
return result
|
||||
|
||||
def as_solution(self, reverse: bool) -> Solution:
|
||||
if reverse:
|
||||
return Solution(*list(reversed(self.ladder)))
|
||||
return Solution(*self.ladder)
|
||||
|
||||
@property
|
||||
def last_word(self) -> Word:
|
||||
return self.ladder[len(self.ladder) - 1]
|
||||
|
||||
def __len__(self):
|
||||
return len(self.ladder)
|
||||
70
internbootcamp/libs/wordladder/solving/solver.py
Executable file
70
internbootcamp/libs/wordladder/solving/solver.py
Executable file
|
|
@ -0,0 +1,70 @@
|
|||
from libs.wordladder.solving.puzzle import Puzzle
|
||||
from libs.wordladder.solving.solution import Solution, CandidateSolution
|
||||
from libs.wordladder.solving.word_distance_map import WordDistanceMap
|
||||
from libs.wordladder.words.word import Word
|
||||
|
||||
|
||||
class Solver(object):
|
||||
def __init__(self, puzzle: Puzzle):
|
||||
self.puzzle: Puzzle = puzzle
|
||||
self.start_word: Word = puzzle.start_word
|
||||
self.end_word: Word = puzzle.end_word
|
||||
self.explored_count: int = 0
|
||||
self.solutions: list[Solution] = []
|
||||
self.reversed: bool = False
|
||||
self.maximum_ladder_length: int = 0
|
||||
self.end_distances = None
|
||||
|
||||
def solve(self, maximum_ladder_length: int) -> list[Solution]:
|
||||
self.maximum_ladder_length = maximum_ladder_length
|
||||
self.start_word: Word = self.puzzle.start_word
|
||||
self.end_word: Word = self.puzzle.end_word
|
||||
self.reversed = False
|
||||
self.explored_count = 0
|
||||
self.solutions.clear()
|
||||
|
||||
diffs = self.start_word - self.end_word
|
||||
if diffs == 0:
|
||||
self.solutions.append(Solution(self.start_word))
|
||||
return self.solutions
|
||||
elif diffs == 1:
|
||||
self.solutions.append(Solution(self.start_word, self.end_word))
|
||||
if self.maximum_ladder_length == 2:
|
||||
return self.solutions
|
||||
elif self.maximum_ladder_length == 3:
|
||||
self._short_circuit_ladder_length_3()
|
||||
return self.solutions
|
||||
elif diffs == 2 and self.maximum_ladder_length == 3:
|
||||
self._short_circuit_ladder_length_3()
|
||||
return self.solutions
|
||||
|
||||
self.reversed = len(self.start_word.linked_words) > len(self.end_word.linked_words)
|
||||
if self.reversed:
|
||||
self.start_word = self.puzzle.end_word
|
||||
self.end_word = self.puzzle.start_word
|
||||
|
||||
self.end_distances = WordDistanceMap(self.end_word, self.maximum_ladder_length - 1)
|
||||
for linked_word in self.start_word.linked_words:
|
||||
if self.end_distances.reachable(linked_word, self.maximum_ladder_length):
|
||||
self._solve(CandidateSolution(self.start_word, linked_word))
|
||||
return self.solutions
|
||||
|
||||
def _solve(self, candidate: CandidateSolution):
|
||||
self.explored_count += 1
|
||||
last_word = candidate.last_word
|
||||
if last_word == self.end_word:
|
||||
self.solutions.append(candidate.as_solution(self.reversed))
|
||||
return
|
||||
if len(candidate) < self.maximum_ladder_length:
|
||||
new_max = self.maximum_ladder_length - len(candidate)
|
||||
for linked_word in last_word.linked_words:
|
||||
if not candidate.seen(linked_word) and self.end_distances.reachable(linked_word, new_max):
|
||||
self._solve(candidate.spawn(linked_word))
|
||||
|
||||
def _short_circuit_ladder_length_3(self):
|
||||
common: set[str] = set()
|
||||
for word in self.start_word.linked_words:
|
||||
common.add(str(word))
|
||||
for word in self.end_word.linked_words:
|
||||
if str(word) in common:
|
||||
self.solutions.append(Solution(self.start_word, word, self.end_word))
|
||||
36
internbootcamp/libs/wordladder/solving/word_distance_map.py
Executable file
36
internbootcamp/libs/wordladder/solving/word_distance_map.py
Executable file
|
|
@ -0,0 +1,36 @@
|
|||
from collections import deque
|
||||
from libs.wordladder.words.word import Word
|
||||
|
||||
|
||||
class WordDistanceMap(object):
|
||||
def __init__(self, word: Word, maximum_ladder_length: int = None):
|
||||
self.distances = {str(word): 1}
|
||||
queue = deque()
|
||||
queue.append(word)
|
||||
max_distance = maximum_ladder_length if maximum_ladder_length is not None else 255
|
||||
while len(queue) > 0:
|
||||
next_word: Word = queue.popleft()
|
||||
distance = self.distances.get(str(next_word))
|
||||
if distance is None:
|
||||
distance = 0
|
||||
distance = distance + 1
|
||||
if distance <= max_distance:
|
||||
for linked_word in next_word.linked_words:
|
||||
if linked_word not in self:
|
||||
queue.append(linked_word)
|
||||
self.distances[str(linked_word)] = distance
|
||||
|
||||
def __len__(self):
|
||||
return len(self.distances)
|
||||
|
||||
def __contains__(self, word: Word):
|
||||
return str(word) in self.distances
|
||||
|
||||
def __getitem__(self, word: Word):
|
||||
return self.distances.get(str(word))
|
||||
|
||||
def reachable(self, word: Word, maximum_ladder_length: int):
|
||||
distance = self.distances.get(str(word))
|
||||
if distance is None:
|
||||
return False
|
||||
return distance <= maximum_ladder_length
|
||||
Loading…
Add table
Add a link
Reference in a new issue