diff --git a/multiplayer_crosswords/crossword.py b/multiplayer_crosswords/crossword.py index 72ad2d1..3e0b0bd 100644 --- a/multiplayer_crosswords/crossword.py +++ b/multiplayer_crosswords/crossword.py @@ -1,6 +1,6 @@ from enum import Enum from typing import List, Tuple, Optional -from .dictionary import Dictionary, Word +from multiplayer_crosswords.dictionary import Dictionary, Word class Orientation(Enum): HORIZONTAL = 1 @@ -85,4 +85,16 @@ class Crossword: return '\n'.join( ''.join(cell if cell else '.' for cell in row) for row in self.grid - ) \ No newline at end of file + ) + +if __name__ == "__main__": + # Example usage + dictionary = Dictionary() + dictionary.add_word(Word("hello", ["greeting"], "easy")) + dictionary.add_word(Word("world", ["earth"], "easy")) + + crossword = Crossword(5, 5, dictionary) + crossword.add_word(dictionary.words[0], 1, 0, Orientation.HORIZONTAL) + crossword.add_word(dictionary.words[1], 0, 4, Orientation.VERTICAL) + + print(crossword) \ No newline at end of file diff --git a/multiplayer_crosswords/crossword_generators.py b/multiplayer_crosswords/crossword_generators.py new file mode 100644 index 0000000..5fc99b3 --- /dev/null +++ b/multiplayer_crosswords/crossword_generators.py @@ -0,0 +1,55 @@ +# algorithms will be implemnented here + +from typing import List, Tuple, Dict, Set, Optional +from multiplayer_crosswords.crossword import Crossword, Orientation +from multiplayer_crosswords.dictionary import Dictionary, Word + +class Slot: + def __init__(self, row: int, col: int, orientation: Orientation, length: int): + self.row = row + self.col = col + self.orientation = orientation + self.length = length + self.id = (row, col, orientation) # Unique identifier + + def __repr__(self): + return f"Slot(row={self.row}, col={self.col}, orientation={self.orientation}, length={self.length})" + +def extract_slots(grid: List[List[str]], min_length: int = 2) -> List[Slot]: + rows, cols = len(grid), len(grid[0]) + slots = [] + + # Horizontal slots + for r in range(rows): + c = 0 + while c < cols: + while c < cols and grid[r][c] == '#': + c += 1 + start = c + while c < cols and grid[r][c] != '#': + c += 1 + length = c - start + if length >= min_length: + slots.append(Slot(r, start, Orientation.HORIZONTAL, length)) + # Vertical slots + for c in range(cols): + r = 0 + while r < rows: + while r < rows and grid[r][c] == '#': + r += 1 + start = r + while r < rows and grid[r][c] != '#': + r += 1 + length = r - start + if length >= min_length: + slots.append(Slot(start, c, Orientation.VERTICAL, length)) + return slots + +def slot_pattern(grid: List[List[str]], slot: Slot) -> str: + dr, dc = (0, 1) if slot.orientation == Orientation.HORIZONTAL else (1, 0) + pattern = [] + for i in range(slot.length): + r, c = slot.row + dr * i, slot.col + dc * i + cell = grid[r][c] + pattern.append(cell if cell and cell != '#' else '*') + return ''.join(pattern) \ No newline at end of file diff --git a/multiplayer_crosswords/dictionary.py b/multiplayer_crosswords/dictionary.py index bc9f838..171a757 100644 --- a/multiplayer_crosswords/dictionary.py +++ b/multiplayer_crosswords/dictionary.py @@ -128,7 +128,7 @@ def main(): words.append(word) return words - N = 500_000 + N = 100_000 MIN_WORD_LENGTH = 4 MAX_WORD_LENGTH = 8 dummy_words = generate_dummy_words(N, MIN_WORD_LENGTH, MAX_WORD_LENGTH) diff --git a/tests/test_crossword.py b/tests/test_crossword.py index ce30c4b..b6d59ff 100644 --- a/tests/test_crossword.py +++ b/tests/test_crossword.py @@ -84,4 +84,16 @@ def test_placed_words_tracking(): assert placed.word == word assert placed.row == 1 assert placed.col == 1 - assert placed.orientation == Orientation.VERTICAL \ No newline at end of file + assert placed.orientation == Orientation.VERTICAL + +def test_valid_hello_world_crossword(): + cw = make_crossword() + assert cw.add_word(DummyWord("HELLO"), 1, 0, Orientation.HORIZONTAL) + assert cw.add_word(DummyWord("WORLD"), 0, 4, Orientation.VERTICAL) + assert str(cw).count('H') == 1 + assert str(cw).count('E') == 1 + assert str(cw).count('L') == 3 + assert str(cw).count('O') == 1 + assert str(cw).count('W') == 1 + assert str(cw).count('R') == 1 + assert str(cw).count('D') == 1 \ No newline at end of file diff --git a/tests/test_crossword_generators.py b/tests/test_crossword_generators.py new file mode 100644 index 0000000..7a3e93e --- /dev/null +++ b/tests/test_crossword_generators.py @@ -0,0 +1,49 @@ +import pytest +from multiplayer_crosswords.crossword_generators import extract_slots, slot_pattern, Slot +from multiplayer_crosswords.crossword import Orientation + +def test_extract_slots_simple(): + grid = [ + ['', '', '', '#', ''], + ['', '#', '', '', ''], + ['', '', '', '', ''], + ['#', '', '#', '', ''], + ['', '', '', '', ''], + ] + slots = extract_slots(grid, min_length=2) + # Should find horizontal and vertical slots of length >= 2 + assert any(s.orientation == Orientation.HORIZONTAL and s.length == 3 for s in slots) + assert any(s.orientation == Orientation.VERTICAL and s.length == 3 for s in slots) + # No slot should start at a '#' cell + for slot in slots: + r, c = slot.row, slot.col + assert grid[r][c] != '#' + + assert len(slots) == 10 # Total slots found + +def test_slot_pattern(): + grid = [ + ['a', '', '', '#', ''], + ['', '#', '', '', ''], + ['', '', '', '', ''], + ['#', '', '#', '', ''], + ['', '', '', '', ''], + ] + slot = Slot(0, 0, Orientation.HORIZONTAL, 3) + pattern = slot_pattern(grid, slot) + assert pattern == 'a**' + + slot2 = Slot(2, 1, Orientation.VERTICAL, 3) + pattern2 = slot_pattern(grid, slot2) + assert pattern2 == '***' # All empty cells in this slot + +def test_extract_slots_min_length(): + grid = [ + ['#', '', '', '#'], + ['', '', '', ''], + ['#', '', '', '#'], + ] + slots = extract_slots(grid, min_length=3) + # Only slots of length 3 or more + assert all(slot.length >= 3 for slot in slots) + assert len(slots) == 3 \ No newline at end of file