diff --git a/server/crossword.py b/server/crossword.py index e168d07..d4f2d46 100644 --- a/server/crossword.py +++ b/server/crossword.py @@ -2,6 +2,7 @@ import enum import json import logging import numpy as np +from numpy.lib.function_base import diff from . import crossword_generator @@ -105,10 +106,11 @@ class LetterField(Field): class Grid(object): - def __init__(self, width: int, height: int, lang_code: str, density=0.55): + def __init__(self, width: int, height: int, lang_code: str, density=0.55, difficulty: int = 0): self._width = width self._height = height self._lang_code = lang_code + self._difficulty = difficulty self._density = density self._grid = [] self._solution_locations = None @@ -213,10 +215,11 @@ class Grid(object): return status_update def check_and_reveal_word(self, x: int, y: int): - grid_update = self.check_and_reveal_horizontal(x, y) + self.check_and_reveal_vertical(x, y) + grid_update = self.check_and_reveal_horizontal( + x, y) + self.check_and_reveal_vertical(x, y) # check also the solution locations - + is_solution_cell = False for location in self._solution_locations: ly = location[0] @@ -228,10 +231,10 @@ class Grid(object): if cell.get_user_content() != cell.get_content(): # not solved, nothing to do, return only grid update return grid_update - + if not is_solution_cell: return grid_update - + solution_updates = [] for location in self._solution_locations: ly = location[0] @@ -267,7 +270,7 @@ class Grid(object): cell.user_input(letter.lower()) - revealed_changes = self.check_and_reveal_word(x,y) + revealed_changes = self.check_and_reveal_word(x, y) if len(revealed_changes) == 0: return [{ @@ -282,8 +285,11 @@ class Grid(object): return self._solution_locations def _build_grid(self): - raw_grid, word_infos, solution_locations = crossword_generator.create_word_grid( - self._width - 1, self._height - 1, lang_code=self._lang_code, target_density=self._density) + raw_grid, word_infos, solution_locations = crossword_generator.create_word_grid(self._width - 1, + self._height - 1, + lang_code=self._lang_code, + target_density=self._density, + difficulty=self._difficulty) self._solution_locations = solution_locations # fix solution locations offsets @@ -334,10 +340,11 @@ class Grid(object): class Crossword(object): - def __init__(self, width: int, height: int, lang_code: str = "en"): + def __init__(self, width: int, height: int, lang_code: str = "en", difficulty: int = 0): self._width = width self._height = height - self._grid = Grid(width, height, lang_code) + self._difficulty = difficulty + self._grid = Grid(width, height, lang_code, difficulty=difficulty) def serialize(self): return { diff --git a/server/crossword_connection.py b/server/crossword_connection.py index d9fa2ef..4397420 100644 --- a/server/crossword_connection.py +++ b/server/crossword_connection.py @@ -31,7 +31,7 @@ class CrosswordConnection(json_websockets.JsonWebsocketConnection): self._session = None - async def send_crossword(self, sessionId: str, lang: str = "en"): + async def send_crossword(self, sessionId: str, lang: str = "en", difficulty: int = 0): if sessionId not in CrosswordConnection.sessions: await self.send_error(msg="unknown session") return @@ -45,7 +45,7 @@ class CrosswordConnection(json_websockets.JsonWebsocketConnection): await self.send_error(msg="you are not registered to given session") return - crossword = sess.get_crossword(lang=lang) + crossword = sess.get_crossword(lang=lang, difficulty=difficulty) await self.send({ 'type': 'crossword', 'crossword': crossword.serialize() @@ -70,7 +70,7 @@ class CrosswordConnection(json_websockets.JsonWebsocketConnection): 'updates': update_message }) - async def register(self, sessionId: str = None, lang: str = "en"): + async def register(self, sessionId: str = None, lang: str = "en", difficulty: int = 0): if sessionId is None: @@ -85,7 +85,7 @@ class CrosswordConnection(json_websockets.JsonWebsocketConnection): await self.send_error("unknown session id") # register with new id: - await self.register(lang=lang) + await self.register(lang=lang, difficulty=difficulty) return sess = CrosswordConnection.sessions[sessionId] @@ -98,7 +98,7 @@ class CrosswordConnection(json_websockets.JsonWebsocketConnection): 'sessionId': sessionId }) - await self.send_crossword(sessionId, lang=lang) + await self.send_crossword(sessionId, lang=lang, difficulty=difficulty) # clean up old session CrosswordConnection.clean_sessions() @@ -119,11 +119,14 @@ class CrosswordConnection(json_websockets.JsonWebsocketConnection): if message['type'] == 'register': sessionId = None lang = "en" + difficulty = 0 if 'sessionId' in message: sessionId = message['sessionId'] if "lang" in message: lang = message['lang'] - await self.register(sessionId=sessionId, lang=lang) + if "difficulty" in message: + difficulty = message["difficulty"] + await self.register(sessionId=sessionId, lang=lang, difficulty=difficulty) return if self._session is None: diff --git a/server/crossword_generator.py b/server/crossword_generator.py index fa57a1c..2706106 100644 --- a/server/crossword_generator.py +++ b/server/crossword_generator.py @@ -6,6 +6,24 @@ import pathlib import logging +def get_difficulty_threshold(lang: str, difficulty: int): + return get_difficulty_threshold.thresholds[lang][difficulty] + + +get_difficulty_threshold.thresholds = { + 'de': { + 0: 12, + 1: 6, + 2: 0 + }, + 'en': { + 0: 200, + 1: 100, + 2: 10 + } +} + + def get_database(lang: str = "en") -> dict: if lang not in get_database._dbs: current_folder = pathlib.Path(__file__).parents[0] @@ -116,8 +134,15 @@ class WordInfo(object): return self._is_vertical -def create_word_grid(w: int, h: int, lang_code: str = "en", target_density=0.5): - logging.info("generate new crossword") +def create_word_grid(w: int, h: int, lang_code: str = "en", target_density: float = 0.5, difficulty: int = 0): + logging.info("generate new crossword with params: w:%s h:%s lang:%s density:%s difficulty:%s", + str(w), + str(h), + lang_code, + str(target_density), + str(difficulty)) + + t_num_translations = get_difficulty_threshold(lang = lang_code, difficulty = difficulty) database = get_database(lang=lang_code) list_words = list(database.keys()) @@ -145,9 +170,13 @@ def create_word_grid(w: int, h: int, lang_code: str = "en", target_density=0.5): index = random.randint(0, n_words-1) word = list_words[index][:] - while len(word) >= max_length or not word.isalnum() or len(word) <= min_length: + num_translations = database[word]['num_translations'] + t = t_num_translations + + while len(word) >= max_length or not word.isalnum() or len(word) <= min_length or num_translations < t: index = random.randint(0, n_words-1) word = list_words[index][:] + num_translations = database[word]['num_translations'] return word diff --git a/server/session.py b/server/session.py index 7eae29d..16936f5 100644 --- a/server/session.py +++ b/server/session.py @@ -4,13 +4,13 @@ from . import crossword class Session(object): - def __init__(self, days_to_expire:int = 2) -> None: + def __init__(self, days_to_expire: int = 2) -> None: self.crossword = None self.datetime_created = dt.datetime.utcnow() self.connected_sockets = set() self.last_touched = self.datetime_created self.days_to_expire = 2 - + def cleanup(self): sockets_to_remove = [] for socket in self.connected_sockets: @@ -22,7 +22,7 @@ class Session(object): def connect_socket(self, websocket: json_websockets.JsonWebsocketConnection) -> None: - + self.cleanup() self.connected_sockets.add(websocket) @@ -38,20 +38,21 @@ class Session(object): def get_datetime_created(self) -> dt.datetime: return self.datetime_created - def create_crossword(self, width: int = 20, height: int = 20, lang: str = "en"): + def create_crossword(self, width: int = 20, height: int = 20, lang: str = "en", difficulty: int = 0): self.crossword = crossword.Crossword(width=width, height=height, - lang_code=lang) + lang_code=lang, + difficulty=difficulty) - def get_crossword(self, lang: str = "en") -> crossword.Crossword: + def get_crossword(self, lang: str = "en", difficulty: int = 0) -> crossword.Crossword: if self.crossword is None: - self.create_crossword(lang = lang) - + self.create_crossword(lang=lang, difficulty=difficulty) + return self.crossword - + def touch(self): self.last_touched = dt.datetime.utcnow() - + def is_expired(self): self.cleanup() if len(self.connected_sockets) > 0: @@ -59,6 +60,5 @@ class Session(object): now = dt.datetime.utcnow() if (now - self.last_touched).days > self.days_to_expire: return True - - return False + return False