Compare commits
2 Commits
bc15c440a7
...
3078813d37
Author | SHA1 | Date |
---|---|---|
Jonas Weinz | 3078813d37 | |
Jonas Weinz | 77882f4981 |
|
@ -42,8 +42,8 @@
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
outline: none;
|
outline: none;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 15em;
|
width: 30em;
|
||||||
height: 10em;
|
height: 20em;
|
||||||
top: 0;
|
top: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
|
@ -54,17 +54,41 @@
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.bigbox {
|
||||||
|
background-color: black;
|
||||||
|
border-color: white;
|
||||||
|
border-width: 0.2em;
|
||||||
|
border-style: solid;
|
||||||
|
max-width: 30em;
|
||||||
|
max-height: 6em;
|
||||||
|
box-shadow: none;
|
||||||
|
outline: none;
|
||||||
|
position: relative;
|
||||||
|
margin: 1em;
|
||||||
|
padding: 1em;
|
||||||
|
color: white;
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.box {
|
.box {
|
||||||
background-color: black;
|
background-color: black;
|
||||||
border-color: white;
|
border-color: white;
|
||||||
border-width: 0.2em;
|
border-width: 0.2em;
|
||||||
border-style: solid;
|
border-style: solid;
|
||||||
max-width: 15em;
|
flex: auto;
|
||||||
|
width: 33%;
|
||||||
|
text-decoration: none;
|
||||||
|
max-width: 30em;
|
||||||
max-height: 3em;
|
max-height: 3em;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
outline: none;
|
outline: none;
|
||||||
position: relative;
|
position: relative;
|
||||||
margin: 1em;
|
margin: 0.5em;
|
||||||
padding: 1em;
|
padding: 1em;
|
||||||
color: white;
|
color: white;
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
|
@ -76,13 +100,25 @@
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<div class="centerbox">
|
<div class="centerbox">
|
||||||
<h3>Select the language:</h3>
|
<h3>choose language and difficulty:</h3>
|
||||||
<a href="./german.html">
|
|
||||||
<div class="box"> German </div>
|
<div class="bigbox"> <div> German </div>
|
||||||
</a>
|
<div class="flex">
|
||||||
<a href="./english.html">
|
<a href="./german.html?difficulty=0" class="box"> easy </a>
|
||||||
<div class="box"> English </div>
|
<a href="./german.html?difficulty=1" class="box"> normal </a>
|
||||||
</a>
|
<a href="./german.html?difficulty=2" class="box"> hard </a>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bigbox"> <div> English </div>
|
||||||
|
<div class="flex">
|
||||||
|
<a href="./english.html?difficulty=0" class="box"> easy </a>
|
||||||
|
<a href="./english.html?difficulty=1" class="box"> normal </a>
|
||||||
|
<a href="./english.html?difficulty=2" class="box"> hard </a>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -81,7 +81,8 @@ export class InfoBox extends LitElement {
|
||||||
|
|
||||||
onNew() {
|
onNew() {
|
||||||
setCookie("session", "");
|
setCookie("session", "");
|
||||||
window.location.href = location.protocol + '//' + location.host + location.pathname;
|
var crosswordRoot = location.pathname.substr(0, location.pathname.lastIndexOf("/"));
|
||||||
|
window.location.href = location.protocol + '//' + location.host + crosswordRoot;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ export class ServerConnection extends WebsocketConnection {
|
||||||
this.sessionId = null;
|
this.sessionId = null;
|
||||||
this.isRegistered = false;
|
this.isRegistered = false;
|
||||||
this.crossword_grid = null;
|
this.crossword_grid = null;
|
||||||
|
this.difficulty = 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,6 +41,9 @@ export class ServerConnection extends WebsocketConnection {
|
||||||
this.sessionId = params.get('session');
|
this.sessionId = params.get('session');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (params.has('difficulty')) {
|
||||||
|
this.difficulty = parseInt(params.get('difficulty'));
|
||||||
|
}
|
||||||
const cookie_session = getCookie('session');
|
const cookie_session = getCookie('session');
|
||||||
if (cookie_session != "") {
|
if (cookie_session != "") {
|
||||||
this.sessionId = cookie_session;
|
this.sessionId = cookie_session;
|
||||||
|
@ -54,6 +58,7 @@ export class ServerConnection extends WebsocketConnection {
|
||||||
this.sendMessage({
|
this.sendMessage({
|
||||||
'type': 'register',
|
'type': 'register',
|
||||||
'sessionId': this.sessionId,
|
'sessionId': this.sessionId,
|
||||||
|
'difficulty': this.difficulty,
|
||||||
'lang': this.lang
|
'lang': this.lang
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ import enum
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
from numpy.lib.function_base import diff
|
||||||
|
|
||||||
from . import crossword_generator
|
from . import crossword_generator
|
||||||
|
|
||||||
|
@ -105,10 +106,11 @@ class LetterField(Field):
|
||||||
|
|
||||||
|
|
||||||
class Grid(object):
|
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._width = width
|
||||||
self._height = height
|
self._height = height
|
||||||
self._lang_code = lang_code
|
self._lang_code = lang_code
|
||||||
|
self._difficulty = difficulty
|
||||||
self._density = density
|
self._density = density
|
||||||
self._grid = []
|
self._grid = []
|
||||||
self._solution_locations = None
|
self._solution_locations = None
|
||||||
|
@ -213,10 +215,11 @@ class Grid(object):
|
||||||
return status_update
|
return status_update
|
||||||
|
|
||||||
def check_and_reveal_word(self, x: int, y: int):
|
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
|
# check also the solution locations
|
||||||
|
|
||||||
is_solution_cell = False
|
is_solution_cell = False
|
||||||
for location in self._solution_locations:
|
for location in self._solution_locations:
|
||||||
ly = location[0]
|
ly = location[0]
|
||||||
|
@ -228,10 +231,10 @@ class Grid(object):
|
||||||
if cell.get_user_content() != cell.get_content():
|
if cell.get_user_content() != cell.get_content():
|
||||||
# not solved, nothing to do, return only grid update
|
# not solved, nothing to do, return only grid update
|
||||||
return grid_update
|
return grid_update
|
||||||
|
|
||||||
if not is_solution_cell:
|
if not is_solution_cell:
|
||||||
return grid_update
|
return grid_update
|
||||||
|
|
||||||
solution_updates = []
|
solution_updates = []
|
||||||
for location in self._solution_locations:
|
for location in self._solution_locations:
|
||||||
ly = location[0]
|
ly = location[0]
|
||||||
|
@ -267,7 +270,7 @@ class Grid(object):
|
||||||
|
|
||||||
cell.user_input(letter.lower())
|
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:
|
if len(revealed_changes) == 0:
|
||||||
return [{
|
return [{
|
||||||
|
@ -282,8 +285,11 @@ class Grid(object):
|
||||||
return self._solution_locations
|
return self._solution_locations
|
||||||
|
|
||||||
def _build_grid(self):
|
def _build_grid(self):
|
||||||
raw_grid, word_infos, solution_locations = crossword_generator.create_word_grid(
|
raw_grid, word_infos, solution_locations = crossword_generator.create_word_grid(self._width - 1,
|
||||||
self._width - 1, self._height - 1, lang_code=self._lang_code, target_density=self._density)
|
self._height - 1,
|
||||||
|
lang_code=self._lang_code,
|
||||||
|
target_density=self._density,
|
||||||
|
difficulty=self._difficulty)
|
||||||
|
|
||||||
self._solution_locations = solution_locations
|
self._solution_locations = solution_locations
|
||||||
# fix solution locations offsets
|
# fix solution locations offsets
|
||||||
|
@ -334,10 +340,11 @@ class Grid(object):
|
||||||
|
|
||||||
|
|
||||||
class Crossword(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._width = width
|
||||||
self._height = height
|
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):
|
def serialize(self):
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -31,7 +31,7 @@ class CrosswordConnection(json_websockets.JsonWebsocketConnection):
|
||||||
|
|
||||||
self._session = None
|
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:
|
if sessionId not in CrosswordConnection.sessions:
|
||||||
await self.send_error(msg="unknown session")
|
await self.send_error(msg="unknown session")
|
||||||
return
|
return
|
||||||
|
@ -45,7 +45,7 @@ class CrosswordConnection(json_websockets.JsonWebsocketConnection):
|
||||||
await self.send_error(msg="you are not registered to given session")
|
await self.send_error(msg="you are not registered to given session")
|
||||||
return
|
return
|
||||||
|
|
||||||
crossword = sess.get_crossword(lang=lang)
|
crossword = sess.get_crossword(lang=lang, difficulty=difficulty)
|
||||||
await self.send({
|
await self.send({
|
||||||
'type': 'crossword',
|
'type': 'crossword',
|
||||||
'crossword': crossword.serialize()
|
'crossword': crossword.serialize()
|
||||||
|
@ -70,7 +70,7 @@ class CrosswordConnection(json_websockets.JsonWebsocketConnection):
|
||||||
'updates': update_message
|
'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:
|
if sessionId is None:
|
||||||
|
|
||||||
|
@ -85,7 +85,7 @@ class CrosswordConnection(json_websockets.JsonWebsocketConnection):
|
||||||
await self.send_error("unknown session id")
|
await self.send_error("unknown session id")
|
||||||
|
|
||||||
# register with new id:
|
# register with new id:
|
||||||
await self.register(lang=lang)
|
await self.register(lang=lang, difficulty=difficulty)
|
||||||
return
|
return
|
||||||
|
|
||||||
sess = CrosswordConnection.sessions[sessionId]
|
sess = CrosswordConnection.sessions[sessionId]
|
||||||
|
@ -98,7 +98,7 @@ class CrosswordConnection(json_websockets.JsonWebsocketConnection):
|
||||||
'sessionId': sessionId
|
'sessionId': sessionId
|
||||||
})
|
})
|
||||||
|
|
||||||
await self.send_crossword(sessionId, lang=lang)
|
await self.send_crossword(sessionId, lang=lang, difficulty=difficulty)
|
||||||
|
|
||||||
# clean up old session
|
# clean up old session
|
||||||
CrosswordConnection.clean_sessions()
|
CrosswordConnection.clean_sessions()
|
||||||
|
@ -119,11 +119,14 @@ class CrosswordConnection(json_websockets.JsonWebsocketConnection):
|
||||||
if message['type'] == 'register':
|
if message['type'] == 'register':
|
||||||
sessionId = None
|
sessionId = None
|
||||||
lang = "en"
|
lang = "en"
|
||||||
|
difficulty = 0
|
||||||
if 'sessionId' in message:
|
if 'sessionId' in message:
|
||||||
sessionId = message['sessionId']
|
sessionId = message['sessionId']
|
||||||
if "lang" in message:
|
if "lang" in message:
|
||||||
lang = message['lang']
|
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
|
return
|
||||||
|
|
||||||
if self._session is None:
|
if self._session is None:
|
||||||
|
|
|
@ -6,6 +6,24 @@ import pathlib
|
||||||
import logging
|
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:
|
def get_database(lang: str = "en") -> dict:
|
||||||
if lang not in get_database._dbs:
|
if lang not in get_database._dbs:
|
||||||
current_folder = pathlib.Path(__file__).parents[0]
|
current_folder = pathlib.Path(__file__).parents[0]
|
||||||
|
@ -116,8 +134,15 @@ class WordInfo(object):
|
||||||
return self._is_vertical
|
return self._is_vertical
|
||||||
|
|
||||||
|
|
||||||
def create_word_grid(w: int, h: int, lang_code: str = "en", target_density=0.5):
|
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")
|
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)
|
database = get_database(lang=lang_code)
|
||||||
list_words = list(database.keys())
|
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)
|
index = random.randint(0, n_words-1)
|
||||||
word = list_words[index][:]
|
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)
|
index = random.randint(0, n_words-1)
|
||||||
word = list_words[index][:]
|
word = list_words[index][:]
|
||||||
|
num_translations = database[word]['num_translations']
|
||||||
|
|
||||||
return word
|
return word
|
||||||
|
|
||||||
|
|
|
@ -4,13 +4,13 @@ from . import crossword
|
||||||
|
|
||||||
|
|
||||||
class Session(object):
|
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.crossword = None
|
||||||
self.datetime_created = dt.datetime.utcnow()
|
self.datetime_created = dt.datetime.utcnow()
|
||||||
self.connected_sockets = set()
|
self.connected_sockets = set()
|
||||||
self.last_touched = self.datetime_created
|
self.last_touched = self.datetime_created
|
||||||
self.days_to_expire = 2
|
self.days_to_expire = 2
|
||||||
|
|
||||||
def cleanup(self):
|
def cleanup(self):
|
||||||
sockets_to_remove = []
|
sockets_to_remove = []
|
||||||
for socket in self.connected_sockets:
|
for socket in self.connected_sockets:
|
||||||
|
@ -22,7 +22,7 @@ class Session(object):
|
||||||
|
|
||||||
def connect_socket(self,
|
def connect_socket(self,
|
||||||
websocket: json_websockets.JsonWebsocketConnection) -> None:
|
websocket: json_websockets.JsonWebsocketConnection) -> None:
|
||||||
|
|
||||||
self.cleanup()
|
self.cleanup()
|
||||||
self.connected_sockets.add(websocket)
|
self.connected_sockets.add(websocket)
|
||||||
|
|
||||||
|
@ -38,20 +38,21 @@ class Session(object):
|
||||||
def get_datetime_created(self) -> dt.datetime:
|
def get_datetime_created(self) -> dt.datetime:
|
||||||
return self.datetime_created
|
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,
|
self.crossword = crossword.Crossword(width=width,
|
||||||
height=height,
|
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:
|
if self.crossword is None:
|
||||||
self.create_crossword(lang = lang)
|
self.create_crossword(lang=lang, difficulty=difficulty)
|
||||||
|
|
||||||
return self.crossword
|
return self.crossword
|
||||||
|
|
||||||
def touch(self):
|
def touch(self):
|
||||||
self.last_touched = dt.datetime.utcnow()
|
self.last_touched = dt.datetime.utcnow()
|
||||||
|
|
||||||
def is_expired(self):
|
def is_expired(self):
|
||||||
self.cleanup()
|
self.cleanup()
|
||||||
if len(self.connected_sockets) > 0:
|
if len(self.connected_sockets) > 0:
|
||||||
|
@ -59,6 +60,5 @@ class Session(object):
|
||||||
now = dt.datetime.utcnow()
|
now = dt.datetime.utcnow()
|
||||||
if (now - self.last_touched).days > self.days_to_expire:
|
if (now - self.last_touched).days > self.days_to_expire:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
Loading…
Reference in New Issue