Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
a34d63aebe
|
|||
|
039d206ba0
|
|||
|
12b0eb08b4
|
|||
|
f1d2b0f6c8
|
|||
|
da37f240b1
|
|||
|
ef1d94cf68
|
|||
|
4306676699
|
@@ -1 +1,2 @@
|
||||
**/*.csv filter=lfs diff=lfs merge=lfs -text
|
||||
**/*.png filter=lfs diff=lfs merge=lfs -text
|
||||
|
||||
@@ -25,6 +25,7 @@ jobs:
|
||||
push: true
|
||||
file: ./Dockerfile
|
||||
platforms: linux/amd64
|
||||
target: prod
|
||||
tags: |
|
||||
gitea.le-memese.com/s3rius/zangramru:latest
|
||||
gitea.le-memese.com/s3rius/zangramru:${{ gitea.ref_name }}
|
||||
|
||||
@@ -4,12 +4,6 @@ on: push
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
strategy:
|
||||
matrix:
|
||||
cmd:
|
||||
- ruff-format
|
||||
- ruff
|
||||
- mypy
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -22,13 +16,11 @@ jobs:
|
||||
- name: Install deps
|
||||
run: uv sync
|
||||
- name: Run lint check
|
||||
run: uv run pre-commit run -a ${{ matrix.cmd }}
|
||||
run: uv run pre-commit run -a
|
||||
pytest:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Create .env
|
||||
run: touch .env
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
@@ -38,4 +30,7 @@ jobs:
|
||||
with:
|
||||
version: "2.28.0"
|
||||
- name: run tests
|
||||
run: docker-compose run --rm api pytest -vv
|
||||
run: docker compose run --build --rm api pytest -vv
|
||||
- name: show logs
|
||||
if: 'always()'
|
||||
run: docker compose logs
|
||||
|
||||
@@ -31,3 +31,11 @@ RUN --mount=from=uv,source=/usr/local/bin/uv,target=/bin/uv \
|
||||
uv sync --locked --no-dev
|
||||
|
||||
CMD ["/usr/local/bin/python", "-m", "zangramru"]
|
||||
|
||||
FROM prod AS dev
|
||||
|
||||
RUN --mount=from=uv,source=/usr/local/bin/uv,target=/bin/uv \
|
||||
--mount=type=cache,target=/root/.cache/uv \
|
||||
uv sync --locked --all-groups
|
||||
|
||||
|
||||
|
||||
+4
-2
@@ -10,6 +10,7 @@ from piccolo.table import create_tables, drop_tables
|
||||
|
||||
from zangramru.settings import settings
|
||||
from zangramru.web.application import get_app
|
||||
from zangramru.web.lifespan import lifespan_setup
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
@@ -73,14 +74,15 @@ async def setup_db() -> AsyncGenerator[None, None]:
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def fastapi_app() -> FastAPI:
|
||||
async def fastapi_app() -> AsyncGenerator[FastAPI, None]:
|
||||
"""
|
||||
Fixture for creating FastAPI app.
|
||||
|
||||
:return: fastapi app with mocked dependencies.
|
||||
"""
|
||||
application = get_app()
|
||||
return application # noqa: RET504
|
||||
async with lifespan_setup(application):
|
||||
yield application
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
import uuid
|
||||
|
||||
from fastapi import FastAPI
|
||||
from httpx import AsyncClient
|
||||
from starlette import status
|
||||
|
||||
|
||||
async def test_echo(fastapi_app: FastAPI, client: AsyncClient) -> None:
|
||||
"""
|
||||
Tests that echo route works.
|
||||
|
||||
:param fastapi_app: current application.
|
||||
:param client: client for the app.
|
||||
"""
|
||||
url = fastapi_app.url_path_for("send_echo_message")
|
||||
message = uuid.uuid4().hex
|
||||
response = await client.post(url, json={"message": message})
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
assert response.json()["message"] == message
|
||||
@@ -0,0 +1,20 @@
|
||||
from fastapi import FastAPI
|
||||
from httpx import AsyncClient
|
||||
from starlette import status
|
||||
|
||||
from zangramru.web.api.puzzles.schema import PuzzleOutputDTO
|
||||
|
||||
|
||||
async def test_get_random_puzzle(fastapi_app: FastAPI, client: AsyncClient) -> None:
|
||||
"""
|
||||
Tests that echo route works.
|
||||
|
||||
:param fastapi_app: current application.
|
||||
:param client: client for the app.
|
||||
"""
|
||||
url = fastapi_app.url_path_for("random_puzzle")
|
||||
response = await client.get(url)
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
dto = PuzzleOutputDTO.model_validate(response.json())
|
||||
assert sum(len(row) for row in dto.board) == 16
|
||||
assert len(dto.solutions) >= 10
|
||||
@@ -12,6 +12,7 @@ env:
|
||||
ZANGRAMRU_DB_HOST: cnpg-cluster-rw.cnpg-cluster.svc.cluster.local
|
||||
ZANGRAMRU_DB_USER: zangram
|
||||
ZANGRAMRU_DB_BASE: zangram
|
||||
ZANGRAMRU_START_DATE: "2026-07-01"
|
||||
|
||||
probes:
|
||||
liveness:
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
from piccolo.apps.migrations.auto.migration_manager import MigrationManager
|
||||
from piccolo.columns.column_types import Integer
|
||||
from piccolo.columns.indexes import IndexMethod
|
||||
|
||||
ID = "2026-07-01T21:56:16:112157"
|
||||
VERSION = "1.34.0"
|
||||
DESCRIPTION = ""
|
||||
|
||||
|
||||
async def forwards():
|
||||
manager = MigrationManager(
|
||||
migration_id=ID, app_name="zangramru_db", description=DESCRIPTION
|
||||
)
|
||||
|
||||
manager.drop_column(
|
||||
table_class_name="Puzzle",
|
||||
tablename="puzzle",
|
||||
column_name="date",
|
||||
db_column_name="date",
|
||||
schema=None,
|
||||
)
|
||||
|
||||
manager.add_column(
|
||||
table_class_name="Puzzle",
|
||||
tablename="puzzle",
|
||||
column_name="number",
|
||||
db_column_name="number",
|
||||
column_class_name="Integer",
|
||||
column_class=Integer,
|
||||
params={
|
||||
"default": 0,
|
||||
"null": False,
|
||||
"primary_key": False,
|
||||
"unique": False,
|
||||
"index": False,
|
||||
"index_method": IndexMethod.btree,
|
||||
"choices": None,
|
||||
"db_column_name": None,
|
||||
"secret": False,
|
||||
},
|
||||
schema=None,
|
||||
)
|
||||
|
||||
return manager
|
||||
@@ -1,13 +1,15 @@
|
||||
from piccolo.columns import JSON, UUID, Date, Varchar
|
||||
import uuid
|
||||
|
||||
from piccolo.columns import JSON, UUID, Integer, Varchar
|
||||
from piccolo.table import Table
|
||||
|
||||
|
||||
class Puzzle(Table):
|
||||
"""Table for puzzles."""
|
||||
|
||||
id = UUID(primary_key=True)
|
||||
id = UUID(primary_key=True, default=uuid.uuid4)
|
||||
board = Varchar(length=16)
|
||||
solutions = JSON()
|
||||
extra = JSON()
|
||||
definitions = JSON()
|
||||
date = Date()
|
||||
number = Integer()
|
||||
|
||||
+1
-228
@@ -32,7 +32,6 @@ word|def
|
||||
аванпорт|защищенная от волн внешняя часть порта
|
||||
аванпост|место расположения такого поста
|
||||
аванс|деньги (или другие ценности), выдаваемые вперед в счет заработка, причитаю щихся кому-нибудь платежей
|
||||
авансом|в качестве аванса, вперед, заранее
|
||||
авансцена|передняя часть сцены
|
||||
авантюра|рискованное и сомнительное дело, предпринятое в расчете на случайный успех
|
||||
авантюризм|склонность к авантюрам
|
||||
@@ -793,8 +792,6 @@ word|def
|
||||
бебех|всякие домашние вещи
|
||||
бегемот|крупное парнокопытное млекопитающее, живущее в пресноводных бассейнах тропической Африки
|
||||
беглец|тот, кто предпринял побег 1, спасся бегством
|
||||
бегов|бегать и бега 1
|
||||
бегом|двигаясь б-гом
|
||||
бегония|декоративное растение с красивыми пестрыми листьями разной формы, с мелкими цветками
|
||||
беготня|непрерывное движение бегом в разных направлениях
|
||||
бегство|беспорядочное отступление
|
||||
@@ -1063,9 +1060,7 @@ word|def
|
||||
бобик|дворовая собачка [по распространенной кличке]
|
||||
бобина|род катушки, валика для намотки чего-нибудь
|
||||
бобер|грызун с ценным мехом, живущий колониями по лесным рекам
|
||||
бобренок|детеныш бобра
|
||||
бобрик|тяжелая плотная ткань со стоячим ворсом
|
||||
бобриком|ежиком
|
||||
бобслеист|спортсмен, занимающийся бобслеем
|
||||
бобслей|соответствующий вид спорта
|
||||
бобыль|одинокий бессемейный человек
|
||||
@@ -1093,9 +1088,6 @@ word|def
|
||||
бойница|отверстие для стрельбы в оборонительном сооружении, в стене
|
||||
бойня|массовое избиение, резня, убийство
|
||||
бокал|сосуд для вина в виде большой рюмки
|
||||
боков|расположенный сбоку, направленный вбок
|
||||
боковушка|небольшая боковая комната, помещение в стороне, сбоку от чего-нибудь
|
||||
боком|плечом вперед
|
||||
бокс|изолятор в лечебном учреждении
|
||||
боксер|короткошерстая сильная служебная собака с тупой мордой, немецкий бульдог
|
||||
боксит|горная порода, содержащая глинозем, алюминиевая руда
|
||||
@@ -1158,8 +1150,6 @@ word|def
|
||||
бортпроводник|служащий гражданского воздушного флота, обслуживающий пассажиров в самолете
|
||||
борть|улей в дупле или выдолбленном чурбане
|
||||
борщ|суп со свеклой и другими овощами
|
||||
босиком|с босыми ногами, без обуви и чулок
|
||||
босоножка|босая девочка, женщина
|
||||
босоножка|легкие летние туфли с не сплошь закрытым верхом, обычно без задников
|
||||
босс|предприниматель, делец
|
||||
бостон|карточной игры
|
||||
@@ -1513,52 +1503,15 @@ word|def
|
||||
вахта|смена
|
||||
вахтер|дежурный сторож на предприятии, в учреждении
|
||||
ваятель|скульптор
|
||||
вблизи|около, рядом с кем-чем-нибудь, недалеко от кого-чего-нибудь
|
||||
вбок|в сторону
|
||||
вброд|по броду, по дну в мелком месте, не вплавь
|
||||
ввек|вовек
|
||||
вверх|внутренней стороной наружу или нижней стороной наверх
|
||||
вверху|в верхней части чего-нибудь; на верхней части чего-нибудь
|
||||
ввечеру|вечером
|
||||
ввиду|из-за чего-нибудь, по причине чего-нибудь
|
||||
вволю|вдоволь
|
||||
ввосьмеро|в восемь раз
|
||||
ввосьмером|в количестве восьми человек
|
||||
ввысь|вверх, в высоту
|
||||
вглубь|во что-нибудь, внутрь чего-нибудь
|
||||
вгорячах|в раздражении, в запальчивости
|
||||
вдавлина|вмятина
|
||||
вдалеке|вдали
|
||||
вдали|далеко, на далеком расстоянии
|
||||
вдаль|на далекое расстояние
|
||||
вдвое|в два слоя, пласта, ряда; согнув пополам
|
||||
вдвоем|в количестве двух человек
|
||||
вдвойне|вдвое больше
|
||||
вдевятеро|в девять раз
|
||||
вдевятером|в количестве девяти человек
|
||||
вдесятеро|в десять раз
|
||||
вдесятером|в количестве десяти человек
|
||||
вдобавок|в добавление к чему-нибудь
|
||||
вдова|женщина, у которой умер муж
|
||||
вдовец|мужчина, у которого умерла жена
|
||||
вдовица|вдова
|
||||
вдоволь|до полного удовлетворения, вполне достаточно
|
||||
вдовство|состояние вдовы, вдовца
|
||||
вдогон|вслед за кем-чем-нибудь
|
||||
вдогонку|вдогон
|
||||
вдоль|в направлении длины чего-нибудь
|
||||
вдосталь|вдоволь
|
||||
вдох|одно вдыхательное движение
|
||||
вдохновение|творческий подъем, прилив творческих сил
|
||||
вдохновитель|тот, кто вдохновляет на что-нибудь
|
||||
вдребезги|совершенно, полностью
|
||||
вдруг|одновременно, разом; сразу
|
||||
вдругорядь|во второй раз, снова
|
||||
вдрызг|совсем, окончательно
|
||||
вегетарианец|человек, питающийся вегетарианской пищей
|
||||
вегетарианство|питание только растительной или растительной и молочной пищей
|
||||
вегетация|рост и развитие растений
|
||||
ведение|сфера деятельности, управления
|
||||
ведомостичка|листок с краткими сведениями о проделанной работе, о ходе работы
|
||||
ведомость|сводка, список каких-нибудь данных
|
||||
ведомство|учреждение или совокупность учреждений, обслуживающих какую-нибудь область государственного управления
|
||||
@@ -1580,8 +1533,6 @@ word|def
|
||||
большой|велосипед
|
||||
великан|гигант
|
||||
великолепие|пышная красота, роскошь
|
||||
великоросс|русские
|
||||
великорус|русские
|
||||
величание|народная обрядовая величальная песня
|
||||
величество|о ком-чем-нибудь заслуживающем уважения, преклонения
|
||||
величие|наличие в ком-чем-нибудь выдающихся свойств, внушающих преклонение, уважение
|
||||
@@ -1611,7 +1562,6 @@ word|def
|
||||
вербена|травянистое дикорастущее душистое растение, разводимое как декоративное
|
||||
верблюд|жвачное парнокопытное млекопитающее с одним или двумя жировыми горбами
|
||||
верблюдица|самка верблюда
|
||||
верблюжонок|детеныш верблюда
|
||||
вербовщик|человек, который занимается вербовкой
|
||||
вердикт|решение присяжных заседателей о виновности или невиновности обвиняемого
|
||||
веревка|изделие из крученых или витых в несколько рядов длинных прядей пеньки или другого свивающегося материала
|
||||
@@ -1656,7 +1606,6 @@ word|def
|
||||
верхогляд|человек, отличающийся верхоглядством
|
||||
верхоглядство|поверхностное неглубокое ознакомление с чем-нибудь
|
||||
верхолаз|рабочий, специалист по работам на большой высоте
|
||||
верхом|обхватив сиденье ногами
|
||||
верхотура|высоко расположенная часть чего-нибудь
|
||||
верхушка|верх, верхняя часть чего-нибудь
|
||||
верша|плетенная рыболовная снасть конической формы
|
||||
@@ -1702,7 +1651,6 @@ word|def
|
||||
вечеринка|вечернее собрание для дружеской встречи, для развлечения
|
||||
вечерник|учащийся вечернего учебного заведения
|
||||
вечерня|вечерняя церковная служба
|
||||
вечером|в вечернее время
|
||||
вечно|постоянно, очень часто
|
||||
вечность|очень долгое время, бесконечность
|
||||
вечор|вчера вечером
|
||||
@@ -1878,7 +1826,6 @@ word|def
|
||||
вместилище|место, сосуд, резервуар для чего-нибудь, емкость
|
||||
вместимость|способность вмещать то или иное количество чего-нибудь, емкость
|
||||
вместо|заменяя, замещая кого-что-нибудь
|
||||
вмиг|очень быстро, сразу
|
||||
вмятина|вмятое, вдавленное место, вдавлина
|
||||
внаймы|во временное пользование за плату
|
||||
внакидку|не вдевая рук в рукава, накинув на плечи
|
||||
@@ -2003,7 +1950,6 @@ word|def
|
||||
волнушка|съедобный пластинчатый гриб со светлой шляпкой
|
||||
волокита|любитель ухаживать за женщинами
|
||||
волокно|тонкая непряденая нить растительного, минерального или искусственного происхождения
|
||||
волоком|таща, волоча по земле
|
||||
волокуша|сельскохозяйственных и других орудий, применяемых для сгребания, рыхления
|
||||
волонтер|доброволец
|
||||
волос|растительности на голове, на теле
|
||||
@@ -2013,7 +1959,6 @@ word|def
|
||||
волчанка|болезнь, поражающая кожу, а также слизистую оболочку, суставы
|
||||
волчатник|охотник на волков
|
||||
волчица|самка волка
|
||||
волчонок|детеныш волка
|
||||
волшебник|человек, чем-нибудь очаровывающий, пленяющий других
|
||||
волшебство|чарующее действие кого-чего-нибудь
|
||||
волынка|канительное дело
|
||||
@@ -2157,8 +2102,6 @@ word|def
|
||||
впрямую|напрямик, без обиняков
|
||||
впрямь|действительно, в самом деле, вправду
|
||||
впустую|ничего не достигая, зря
|
||||
впятеро|в пять раз
|
||||
впятером|в количестве пяти человек
|
||||
враг|принципиальный противник чего-нибудь
|
||||
вражда|отношения и действия, проникнутые неприязнью, ненавистью
|
||||
враз|все вместе, разом, одновременно
|
||||
@@ -2203,35 +2146,13 @@ word|def
|
||||
вседержатель|всевышний
|
||||
вседозволенность|поведение того, кто в своих поступках чувствует себя свободный от всяких общественно установленных норм, и правил
|
||||
всезнайка|человек, самоуверенно полагающий, что но знает все
|
||||
всемеро|в семь раз
|
||||
всемером|в количестве семи человек
|
||||
всеобуч|широкая пропаганда основ каких-нибудь знаний
|
||||
всепрощение|полное прощение всех обид, зла
|
||||
всепрощенчество|склонность прощать, оправдывать любые поступки
|
||||
всерьез|серьезно, не в шутку
|
||||
всецело|полностью, целиком
|
||||
вскачь|скачками, очень быстро
|
||||
вскользь|кратко и мимоходом, между прочим, попутно
|
||||
вскоре|в скором времени, в недалеком будущем
|
||||
вскорости|вскоре
|
||||
вскрытие|-ся
|
||||
всласть|до полного удовлетворения
|
||||
вслед|по направлению за кем-чем-нибудь
|
||||
вследствие|по причине, чего-нибудь, из-за чего-нибудь, являясь результатом, следствием чего-нибудь
|
||||
вслепую|не видя, не воспринимая зрением
|
||||
вслух|так, что слышно другим, громко
|
||||
всмятку|до полужидкого состояния
|
||||
всплеск|звук, шум плеснувшей воды
|
||||
вспоможение|пособие, материальная помощь
|
||||
вспять|назад
|
||||
встарь|в старое время, в старину
|
||||
встрепка|строгое наказание, с руганью, битьем, нагоняй
|
||||
встреча|-ся
|
||||
встряска|сильное нервное потрясение
|
||||
вступление|начальная часть чего-нибудь, введение к чему-нибудь
|
||||
всуе|зря, напрасно (вспоминать, называть; по отношению к кому-чему-нибудь уважаемому, высокому)
|
||||
всухомятку|без жидкого и горячего
|
||||
всухую|с сухим счетом
|
||||
всхлип|судорожный громкий вздох при плаче
|
||||
всхрап|отрывистый хриплый звук при храпе
|
||||
всюду|во всех местах, везде или в разные, во все места
|
||||
@@ -2240,8 +2161,6 @@ word|def
|
||||
втайне|тайным образом, не обнаруживая
|
||||
втемную|вслепую
|
||||
втирание|-ся
|
||||
втихаря|втихомолку
|
||||
втихомолку|потихоньку, тайком
|
||||
втора|второй голос в музыкальной партии
|
||||
вторник|второй день недели
|
||||
второгодник|ученик, оставшийся в классе на второй год для повторного прохождения программы
|
||||
@@ -2251,17 +2170,11 @@ word|def
|
||||
второпях|торопясь, спеша
|
||||
вторсырье|вторичное сырье, утиль
|
||||
втридорога|второе или во много раз дороже
|
||||
втрое|в три раза
|
||||
втроем|в количестве трех человек
|
||||
втройне|в три раза больше
|
||||
втуз|высшее техническое учебное заведение
|
||||
втулка|цилиндрическая или конической формы деталь машины с продольным отверстием для вставляемой другой детали
|
||||
втуне|бесплодно, напрасно; без результата
|
||||
втык|выговор, строгое внушение
|
||||
вуалетка|небольшая короткая вуаль
|
||||
вуаль|тонкая прозрачная материя
|
||||
вулкан|геологическое образование - комическая гора с кратером на вершине, через который из недр земли время от времени извергается огонь, лава, пепел, горячие газы, пары воды и обломки горных пород
|
||||
вулканизация|технологический процесс превращения каучука в резину
|
||||
вулканолог|специалист ао вулканологии
|
||||
вулканология|наука о вулканах
|
||||
вульгаризатор|человек, который вульгаризирует что-нибудь, упроститель
|
||||
@@ -2269,17 +2182,8 @@ word|def
|
||||
вундеркинд|высокоодаренный ребенок
|
||||
вурдалак|вампир
|
||||
вход|место, где входят
|
||||
вхолостую|не производя полезной работы
|
||||
вчера|день, предшествовавший сегодняшнему
|
||||
вчерне|начерно
|
||||
вчетверо|в четыре раза
|
||||
вчетвером|в количестве четырех человек
|
||||
вчистую|совсем, совершенно, подчистую
|
||||
вчуже|со стороны, сточки зрения чужого, постороннего
|
||||
вшестеро|в шесть раз
|
||||
вшестером|в количестве шести человек
|
||||
вширь|в ширину, на широкое пространство
|
||||
въявь|наяву
|
||||
выбоина|углубление, выбитое на поверхности чего-нибудь
|
||||
выбор|то, из чего можно выбрать
|
||||
выборность|замещение должностей путем выборов, а не назначения
|
||||
@@ -2289,14 +2193,11 @@ word|def
|
||||
вывеска|о внешнем, показаном в поведении, образе жизни, деятельности
|
||||
вывих|место такого смещения
|
||||
вывод|провод, устройство, выходящее или выводящее что-нибудь наружу
|
||||
выводка|птенцы или детеныши млекопитающих, выведенные одной самкой и держащиеся вместе
|
||||
выволочка|взбучка
|
||||
выворот|болезненное состояние, при к-том орган или его часть вывернуты внутренней поверхностью наружу
|
||||
выгиб|образовавшаяся под давлением выпуклость или вдавленное место
|
||||
выговор|качество, характер произношения
|
||||
выгода|польза, преимущество
|
||||
выдвиженец|передовой труженик, выдвинутый на какую-нибудь ответственную работу, должность
|
||||
выделение|-ся
|
||||
выдержка|цитата, выписка
|
||||
выдох|одно выдыхательное движение
|
||||
выдра|мех его
|
||||
@@ -2749,8 +2650,6 @@ word|def
|
||||
голубятня|помещение для домашних голубей(обычно на крыше, на чердаке)
|
||||
голытьба|голь
|
||||
голыш|небольшой круглый гладкий камень
|
||||
голышка|голый ребенок
|
||||
голышом|нагишом
|
||||
голь|оборванцы, нищие, беднота
|
||||
гольд|нанайцев
|
||||
голье|очищенная от волоса шкура, подготавливаемая к дублению
|
||||
@@ -3056,7 +2955,6 @@ word|def
|
||||
гурманство|пристрастие к изысканной пище
|
||||
гурт|большая группа домашних животных, перегоняемая с одного места на другое
|
||||
гуртовщик|погонщик гурта
|
||||
гуртом|гурьбой
|
||||
гурьба|шумливая группа людей, ватага
|
||||
гусак|самец гуся
|
||||
гусар|военнослужащий частей легкой кавалерии [ в Венгрии]
|
||||
@@ -3067,9 +2965,6 @@ word|def
|
||||
гусляр|народный певец, играющий на гуслях
|
||||
гусыня|самка гуся
|
||||
гусь|родственная утке крупная дикая и домашняя водоплавающая птица с длинной шеей
|
||||
гуськом|один вслед за другим, вереницей
|
||||
гусятина|мясо гуся как пища
|
||||
гусятница|работница, занимающаяся уходом за гусями
|
||||
гуталин|мазь для кожаной обуви
|
||||
гуттаперча|упругая, похожая на кожу масса из свернувшегося млечного сока некоторых растений, обладающая высоким электрическим сопротивлением и водонепроницаемостью
|
||||
гуща|густой осадок в жидкости
|
||||
@@ -3102,7 +2997,6 @@ word|def
|
||||
дармовщинка|то, что получается кем-нибудь бесплатно, за чужой счет
|
||||
дармоед|тот, кто живет на чужой счет, бездельник
|
||||
даровщинка|дармовщинка
|
||||
даром|бесплатно
|
||||
дата|помета, указывающая время (год, месяц, число) написания чего-нибудь
|
||||
датчик|устройство непосредственно принимающее, преобразующее и передающее специальным приборам данные каких-нибудь измерений
|
||||
дача|участок земли под лесом
|
||||
@@ -3241,15 +3135,10 @@ word|def
|
||||
делимость|свойство целого числа делиться на другое целое число без остатка
|
||||
делитель|число или величина, на которую делится делимое
|
||||
дело|нечто важное, нужное
|
||||
делопроизводитель|служащий, ведущий канцелярские дела, делопроизводство
|
||||
делопроизводство|ведение канцелярских дел
|
||||
дельта|устье большой реки с его разветвлениями на отдельные рукава и прилегающая к нему часть суши
|
||||
дельтаплан|легкий безмоторный летательный аппарат с обтяжным каркасом, с подвесной системой и ручкой за которую держится спортсмен
|
||||
дельтапланеризм|вид спорта - полеты на дельтапланах
|
||||
дельтапланерист|спортсмен, занимающийся дельтапланеризмом
|
||||
дельфин|морское млекопитающее подотряда зубатых китов
|
||||
дельфинарий|комплекс сооружений с бассейном для содержания, изучения и дрессировки дельфинов
|
||||
дельфиненка|детеныш дельфина
|
||||
деляга|человек, озабоченный в делах только ближайшей выгодой
|
||||
деляна|участок лесосеки
|
||||
делянка|участок земли (поля, леса), выделенный для обработки, вырубки
|
||||
@@ -3345,7 +3234,6 @@ word|def
|
||||
детва|молодые пчелы
|
||||
детвора|маленькие дети
|
||||
детдом|детский дом
|
||||
детдомовец|воспитанник детского дома
|
||||
детектив|литературное произведение или фильм, изображающие раскрытие запутанных преступлений
|
||||
детектор|устройство для преобразования электрических колебаний
|
||||
детеныш|молодое животное, находящееся при матери
|
||||
@@ -3829,7 +3717,6 @@ word|def
|
||||
дуэлянт|участник дуэли, дуэлей
|
||||
дуэт|исполнители такого произведения
|
||||
дыба|орудие пытки, на котором растягивали истязуемого
|
||||
дыбом|торчком, поднявшись вверх
|
||||
дылда|высокий нескладный человек
|
||||
дымка|легкая, как дым, застилающая пелена чего-нибудь
|
||||
дымоход|канал для выхода дыма из печи, топки в трубу
|
||||
@@ -3890,8 +3777,6 @@ word|def
|
||||
ежемесячник|периодическое издание, выходящее один раз в месяц
|
||||
еженедельник|периодическое издание, выходящее один раз в неделю
|
||||
ежик|еж
|
||||
ежиха|самка ежа
|
||||
ежонок|детеныш ежа
|
||||
ездка|одна из нескольких поездок для привоза или отвоза груза
|
||||
ездок|тот, кто умеет ездить
|
||||
ель|оливковое масло, употр. в церковных обрядах
|
||||
@@ -4179,7 +4064,6 @@ word|def
|
||||
задолго|за много времени перед чем-нибудь
|
||||
задолженность|наличие долгов, невыполненных обязательств
|
||||
задолжник|тот, кто имеет задолженность
|
||||
задом|задней стороной, задней частью
|
||||
задор|запальчивое, вызывающее поведение, вызывающий тон
|
||||
задорина|шероховатость на гладкой поверхности
|
||||
задумка|замысел, план
|
||||
@@ -4201,8 +4085,6 @@ word|def
|
||||
займодавец|тот, кто дает взаймы, кредитор
|
||||
займодержатель|владелец облигаций займа
|
||||
зайчатина|мясо зайца как пища
|
||||
зайчиха|самка зайца
|
||||
зайчонок|детеныш зайца
|
||||
закавыка|неожиданное препятствие, затруднение, зацепка
|
||||
заказ|заказанный предмет, предметы
|
||||
заказник|заповедника, где находятся под особой охраной растения и животные
|
||||
@@ -4245,7 +4127,6 @@ word|def
|
||||
заложник|человек, насильственно задержанный в обеспечение выполнения каких-нибудь требований (предъявляемых к тем, кто заинтересован в освобождении)
|
||||
залом|сорт крупной и жирной сельди
|
||||
залп|одновременный выстрел из нескольких огнестрельных орудий, из ручного оружия
|
||||
залпом|сразу, без передышки
|
||||
залысина|идущее вверх от виска места, не покрытое волосами
|
||||
замарашка|тот, кто запачкался испачкал лицо руки( о ребенке)
|
||||
замашка|манера действовать, повадка
|
||||
@@ -4317,7 +4198,6 @@ word|def
|
||||
запятая|знак препинания ( ), обычно обозначающий интонационное членение, а также выделяющий некоторые синтаксические группы
|
||||
запятки|место для слуги на задке кареты, экипажа
|
||||
заработок|работа по найму, обычно временная, вне места постоянного жительства
|
||||
зараз|сразу, за один прием
|
||||
зараза|болезнетворное начало, распространяемое микробами
|
||||
заранее|за некоторое время до чего-нибудь
|
||||
зарево|отсвет пожара или заката на небе
|
||||
@@ -4414,7 +4294,6 @@ word|def
|
||||
звездочет|астролог
|
||||
звездочка|группа из пяти-шести октябрят, входящая в октябрятскую группу при пионерской дружине
|
||||
звено|венец
|
||||
звереныш|детеныш зверя
|
||||
зверинец|место, где в клетках содержат зверей для показа
|
||||
зверобой|луговых и лесных трав или полукустарников, обычно с желтыми цветками
|
||||
зверовод|специалист по звероводству
|
||||
@@ -5421,7 +5300,6 @@ word|def
|
||||
кемпинг|специально оборудованный летний лагерь для автотуристов
|
||||
кенарь|самец канарейки
|
||||
кенаф|однолетнее травянистое растение семейства мальвовых, лубяное волокно употр. для изготовлении текстильного сырья
|
||||
кенгуренок|детеныш кенгуру
|
||||
кенгуру|австралийское сумчатое млекопитающее с удлиненными задними ногами
|
||||
кентавр|получеловек-полуконь - существо с туловищем коня, головой и грудь человека
|
||||
кепи|высокая сужающаяся кверху форменная фуражка с маленьким донышком и прямым козырьком
|
||||
@@ -5686,8 +5564,6 @@ word|def
|
||||
коза|одомашненный вид козлов
|
||||
козел|игры в карты, в домино
|
||||
козерог|дикий горный козел с большими рогами
|
||||
козленок|детеныш козы
|
||||
козел|посдставка в виде бруса на ножках, сбитых крестовиной
|
||||
козлятина|козье мясо как пища
|
||||
козни|злые, коварные умыслы
|
||||
козовод|специалист по козоводству
|
||||
@@ -6192,7 +6068,6 @@ word|def
|
||||
котел|закрытая емкость, устройство для превращения жидкости в пар
|
||||
котелок|голова
|
||||
котельщик|специалист по паровым котлам и их эксплуатации
|
||||
котенок|детеныш кошки
|
||||
котильон|старинный французский танец-игра, в котором танцующие повторяют вслед за первой парой фигуры из разных танцев (вальса, мазурки, польки, кадрили)
|
||||
котлета|зажаренный кусок мяса (обычно с ребрышком - отбивная котлета) или лепешка из мясного, рыбного, овощного фарша
|
||||
котлован|глубокая выемка в земле для закладки фундамента
|
||||
@@ -6417,7 +6292,6 @@ word|def
|
||||
крыло|вращающаяся лопасть колеса ветряного двигателя
|
||||
крыльцо|наружный настил перед входной дверью дома, обычно под навесом, со ступенькой ил и лесенкой
|
||||
крыса|вредный грызун семейства мышей
|
||||
крысенок|детеныш крысы
|
||||
крысоловка|капкан для крыс
|
||||
крыша|верхняя, покрывающая часть строения
|
||||
крышка|конец капут, каюк
|
||||
@@ -6453,7 +6327,6 @@ word|def
|
||||
куверт|прибор за обеденным столом в ресторане, на банкете
|
||||
кувшин|высокий округлый сосуд с горлышком и ручкой
|
||||
кувшинка|водное растение с крупными плавающими листьями и белыми, бело-розовыми или желт ыми цветками, водяная лилия
|
||||
кувырком|перевалившись через голову
|
||||
кугуар|пума
|
||||
кудель|волокнистая часть льна, пеньки
|
||||
кудесник|волшебник
|
||||
@@ -6870,7 +6743,6 @@ word|def
|
||||
лирика|литературных произведений, поэтических, выражащих чувства и переживания
|
||||
лирник|бродячий певец, играющий на лире
|
||||
лиса|хитрый, льстивый человек
|
||||
лисенок|детеныш лисицы
|
||||
лисица|мех его
|
||||
лист|тонкий плоский кусок, пласт какого-нибудь материала
|
||||
листаж|объем в листах 2
|
||||
@@ -6978,9 +6850,6 @@ word|def
|
||||
лопух|широкий лист его
|
||||
лорд|лицо, имеющее этот титул
|
||||
лорнет|складные очки без дужек, на ручке
|
||||
лосенок|детеныш лося
|
||||
лосиный|белые штаны из лосиной кожи как часть военной формы в отдельных полках старой русской и некоторых других армий
|
||||
лосиха|самка лося
|
||||
лоск|безукоризненный вид, внешний блеск
|
||||
лоскут|небольшой участок какой-нибудь поверхности
|
||||
лососина|мясо лосося как пища
|
||||
@@ -7032,8 +6901,6 @@ word|def
|
||||
лыко|луб молодой липы, ивы и некоторых других деревьев, разделяемый на слои и узкие полосы
|
||||
лысина|место, где вылезла, не растет шерсть
|
||||
лычко|узкие поперечные нашивки на погонах
|
||||
львенок|детеныш льва 1
|
||||
львица|самка льва 1
|
||||
льгота|преимущественное право, облегчение, представляемое кому-нибудь как исключение из общих правил
|
||||
льдина|глыба льда
|
||||
льдинка|маленький кусочек льда
|
||||
@@ -7185,7 +7052,6 @@ word|def
|
||||
маменька|мама, мать
|
||||
мамка|кормилица, нянька
|
||||
мамонт|ископаемое млекопитающее семейства слонов с длинной шерстью и большими загнутыми бивнями
|
||||
мамонтенок|детеныш мамонта
|
||||
манатки|мелкие вещи, пожитки
|
||||
мангал|жаровня
|
||||
манго|душистый сладкий плод его
|
||||
@@ -7363,7 +7229,6 @@ word|def
|
||||
медведь|о неуклюжем, неповоротливом человеке
|
||||
медвежатина|межвежье мясо как пища
|
||||
медвежатник|охотник на медведей
|
||||
медвежонок|детеныш медведя
|
||||
медиана|отрезок прямой линии, соединяющий вершину треугольника с серединой противоположной стороны
|
||||
медик|сту дент медицинского учебного заведения
|
||||
медикамент|лекарства, лечебные средства
|
||||
@@ -7417,7 +7282,6 @@ word|def
|
||||
мелочь|мелкие монеты
|
||||
мель|мелководное место в реке, водоеме
|
||||
мельзавод|(мукомольный) завод-мельница
|
||||
мельком|в самое короткое время, бегло
|
||||
мельник|владелец мельницы или работник на мельнице
|
||||
мельница|предприятие, здание с приспособлениями для размола зерна
|
||||
мельхиор|серебристо-белый сплав меди с никелем и некоторыми другими элементами
|
||||
@@ -7545,7 +7409,6 @@ word|def
|
||||
мздоимец|стяжатель, взяточник
|
||||
миазмы|гнилостные испарения, запахи
|
||||
мигалка|яркий мигающий фонарь
|
||||
мигом|очень быстро, скоро или сразу
|
||||
миграция|переселение, перемещение
|
||||
мигрень|приступы боли в одной половине головы
|
||||
мидия|съедобный двустворчатый морской моллюск
|
||||
@@ -7587,9 +7450,7 @@ word|def
|
||||
мимика|движение лица, выражающие внутреннее душевное состояние
|
||||
мимикрия|сходство окраски и формы с окружающей средой, способствующее им в борьбе за существование
|
||||
мимист|артист, искусно владеющий мимикой
|
||||
мимоездом|проезжая мимо, проездом
|
||||
мимоза|южное растение (травы, кустарники, деревья), некоторые виды которого известны тем, что свертывают листья при прикосновении к ним
|
||||
мимоходом|между прочим, вскользь
|
||||
мина|выражение лица, его выразительное движение
|
||||
минарет|башня при мечети, с которой муэдзин призывает на молитву
|
||||
миндалина|один орех миндаля
|
||||
@@ -7753,10 +7614,8 @@ word|def
|
||||
молочник|кувшинчик для молока
|
||||
молочница|грибковое заболевание слизистой оболочки полости рта у грудных детей
|
||||
молочность|способность давать то или иное количество молока
|
||||
молча|ничего не говоря
|
||||
молчальник|человек, предпочитающий из осторожности не высказывать своего мнения, отмалчиваться
|
||||
молчанка|детская игра, в которой проигрывает заговоривший первым
|
||||
молчком|не говоря ни слова, молча
|
||||
молчок|требование молчать
|
||||
молчун|неразговорчивый, молчаливый человек
|
||||
моль|единица количества вещества
|
||||
@@ -7817,8 +7676,6 @@ word|def
|
||||
мореходность|мореходные качества судна
|
||||
мореходство|мореплавание
|
||||
морж|человек, занимающийся плаванием зимой в открытых водоемах
|
||||
моржиха|самка моржа
|
||||
моржонок|детеныш моржа
|
||||
морзянка|сама эта азбу ка
|
||||
морилка|жидкость, которой морят насекомых
|
||||
морковка|один корешок моркови
|
||||
@@ -7985,7 +7842,6 @@ word|def
|
||||
мытарство|страдание, мука
|
||||
мытарь|сборщик податей в Иудее
|
||||
мышеловка|ловушка для мышей
|
||||
мышонок|детеныш мыши
|
||||
мышца|орган тела человека и животного, состоящий из ткани, способной сокращаться под влиянием нервных импульсов
|
||||
мышь|небольшой грызун с острой мордочкой, усиками и длинным хвостом
|
||||
мышьяк|препараты из этого вещества, употр. в медицине и технике
|
||||
@@ -8019,7 +7875,6 @@ word|def
|
||||
набрюшник|повязка, накладка на живот
|
||||
навага|северная морская рыба семейства тресковых
|
||||
наваждение|по суеверным представлениям: то что внушено злой силой с целью соблазнить, увлечь чем-нибудь, запутать
|
||||
навалом|много, в избытке
|
||||
навалоотбойщик|горнорабочий, занятый отбойкой угля и наваливанием его на конвейер в забое
|
||||
навар|прибыль, нажива, барыш
|
||||
навек|навсегда
|
||||
@@ -8052,7 +7907,6 @@ word|def
|
||||
нагайка|короткая ременная плеть
|
||||
наган|револьвер особой системы
|
||||
нагар|обуглившийся при горении кончик фитиля
|
||||
нагишом|в голом виде, совсем без одежды
|
||||
наглазник|щиток или повязка, предохраняющие глаза
|
||||
наглец|наглый человек, нахал
|
||||
наглеца|некоторая степень наглости
|
||||
@@ -8093,7 +7947,6 @@ word|def
|
||||
наедине|вдвоем, без посторонних
|
||||
наезд|кавалерийский набег
|
||||
наездник|тот, кто едет или ездит верхом, всадник
|
||||
наездом|заезжая иногда, по пути, не останавливаясь надолго
|
||||
наезничество|занятие наездника на бегах, в цирке
|
||||
наемник|наемный работник
|
||||
наждак|мелкозернистая горная порода употр. как абразивный материал
|
||||
@@ -8211,7 +8064,6 @@ word|def
|
||||
напиток|продукт, приготовленный для питья
|
||||
напластование|-ся
|
||||
наплечник|часть старинных военных доспехов, защищающих плечи
|
||||
наповал|насмерть сразу
|
||||
напоказ|чтобы показать, для обозрения
|
||||
наполнитель|вещество, материал, к-крым наполняют, дополняют, уплотняют что-нибудь
|
||||
наполовину|одной половиной, одной частью
|
||||
@@ -8223,22 +8075,9 @@ word|def
|
||||
направо|в правую сторону, на правой стороне
|
||||
направщик|работник, занятый направкой чего-нибудь
|
||||
напраслина|ложное обвинение
|
||||
например|для примера, для пояснения
|
||||
напрокат|во временное пользование за плату
|
||||
напролет|без перерыва, целиком
|
||||
напролом|не считаясь с препятствиями, преодолевая силой
|
||||
напротив|иначе, наперекор
|
||||
напрочно|прочно, крепко
|
||||
напрочь|совсем, окончательно
|
||||
напряжение|сосредоточенность сил, внимания на чем-нибудь
|
||||
напрямик|не стесняясь, прямо
|
||||
напрямую|напрямик
|
||||
напульсник|повязки, предохраняющий место на руке, где прощупывается пульс
|
||||
напутствие|поучение, советы на будущее
|
||||
наравне|на одной линии, высоте, глубине
|
||||
нараспашку|в расстегнутом виде
|
||||
нараспев|растягивая слова и в произношении их приближаясь к пению
|
||||
нарасхват|очень охотно (брать, покупать), стараясь перехвалить друг у друга
|
||||
нарез|углубление на чем-нибудь в виде узкой канавки, полоски, сделанное режущим инструментом
|
||||
нарекание|упрек, обвинение
|
||||
наречие|часть речи, обозначающая признак действия, другого признака (качества, свойства), реже - предмета, например ясно, громко, здесь, всегда, домой, ночью, всмятку
|
||||
@@ -8443,7 +8282,6 @@ word|def
|
||||
негоциант|оптовый купец, коммерсант
|
||||
негр|люди, принадлежащие к негроидной расе
|
||||
недавно|в недалеком прошлом; с недавнего времени
|
||||
недаром|не без причины, не без цели
|
||||
недвижимость|недвижимое имущество
|
||||
неделя|семь дней, посвященных кому-нибудь общественному мероприятию пропаганде чего-нибудь
|
||||
недлумение|состояние сомнения, колебания вследствие невозможности понять, в чем дело
|
||||
@@ -8467,7 +8305,6 @@ word|def
|
||||
недомыслие|недодуманность, недостаточная обдуманность чего-нибудь, неосмысленность
|
||||
недонесение|несообщение официальным органам о готовящемся или совершенном преступлении
|
||||
недоносок|недоношенный ребенок, детеныш
|
||||
недопесок|молодой песец
|
||||
недоработка|упущение, недостаток в работе
|
||||
недоразумение|ошибочное, неполное понимание; то, что произошло в результате такого непонимания
|
||||
недород|неурожай
|
||||
@@ -8537,7 +8374,6 @@ word|def
|
||||
ненадобность|отсутствие потребности, нужды в чем-нибудь
|
||||
ненадолго|на короткое время
|
||||
ненападение|отказ государств от враждебных действий по отношению друг к другу, от развязывания войны
|
||||
ненароком|ненамеренно, случайно
|
||||
ненастье|дождливая, пасмурная погода
|
||||
необходимость|надобность, потребность
|
||||
неоглобализм|стремление империалистического государства к мировому господству
|
||||
@@ -8648,7 +8484,6 @@ word|def
|
||||
низменность|равнина, расположенная не выше 200 м над уровнем моря
|
||||
низовье|прилегающая к нему местность
|
||||
низкий|низ, нижняя часть чего-нибудь
|
||||
низом|дор¦гой, идущей под горой; понизу
|
||||
никелировка|слой никеля на чем-нибудь
|
||||
никель|химический элемент, серебристо-белый тугоплавкий металл, широко употр. в технике
|
||||
никогда|ни в какое время, ни при каких обстоятельствах
|
||||
@@ -8670,7 +8505,6 @@ word|def
|
||||
нить|предмет, по форме напоминающий нитку
|
||||
ничего|ничего
|
||||
ничегонеделание|праздность, безделье
|
||||
ничком|лицом вниз
|
||||
ничто|о том, кто (что) ничего собой не представляет, не имеет значения для кого-нибудь
|
||||
ничтожество|ничтожный человек
|
||||
ничуть|нисколько
|
||||
@@ -8984,7 +8818,6 @@ word|def
|
||||
огрех|вообще о недоделке, плохой работе, погрешности
|
||||
огрызок|обгрызенный кусок, остаток чего-нибудь
|
||||
огузок|бедренная часть туши
|
||||
огулом|без разбора, всех или все сразу
|
||||
огурец|огородное растение семейства тыквенных с продолговатым зеленым плодом
|
||||
одалиска|обитательница гарема, наложница
|
||||
одежа|одежда
|
||||
@@ -9098,10 +8931,6 @@ word|def
|
||||
олеандр|южный вечнозеленый кустарник с удлиненными кожистыми листьями и с красными, розовыми или белыми цветками
|
||||
оледенение|процесс расширения их площади
|
||||
оленевод|человек, занимающийся разведением оленей; специалист по оленеводству
|
||||
оленеводство|разведение оленей как отрасль животноводства
|
||||
олененок|детеныш оленя
|
||||
оленина|мясо оленя как пища
|
||||
оленуха|самка оленя
|
||||
олень|крупное парнокопытное животное с ветвистыми рогами
|
||||
олеография|применявшийся в 19 в. способ многокрасочной литографии с картины, писанной масляными красками
|
||||
олива|плод его
|
||||
@@ -9286,8 +9115,6 @@ word|def
|
||||
оскомина|ощущение во рту терпкости и вяжущей кислоты
|
||||
оскорбитель|тот, кто оскорбил, оскорбляет кого-нибудь
|
||||
оскорление|-ся
|
||||
осленок|детеныш осла
|
||||
ослица|самка осла
|
||||
осложнение|-ся
|
||||
ослушник|тот, кто ослушался кого-нибудь, кто поступает своевольно
|
||||
ослышка|ошибка слуха, при которой сказанное принимается за другое, сходно звучащее
|
||||
@@ -9301,7 +9128,6 @@ word|def
|
||||
особа|о человеке (прежде о важном, почтенном, теперь обычно ирон.)
|
||||
особенность|характерное, отличительное свойство кого-чего-нибудь
|
||||
особняк|благоустроенный дом городского типа, предназначенный для одной семьи и для отдельного учреждения
|
||||
особняком|отдельно, в стороне от других
|
||||
осока|многолетняя (обычно болотная) трава с твердыми узкими и длинными листьями
|
||||
осокорь|дерево, родственное тополю
|
||||
осот|крупная сорная колючая трава семейства сложноцветных
|
||||
@@ -9897,7 +9723,6 @@ word|def
|
||||
передовик|человек, который идет впереди других в работе, показывает пример сознательного отношения к труду
|
||||
передовица|передовая статья (
|
||||
передок|двухколесная повозка для снарядов и прицепки артиллерийского орудия
|
||||
передом|впереди
|
||||
передряга|неприятное, хлопотливое, затруднительное дело, положение
|
||||
передышка|непродолжительный перерыв, чтобы отдышаться, перевести дух
|
||||
переезд|место, где переезжают через что-нибудь
|
||||
@@ -10053,7 +9878,6 @@ word|def
|
||||
печь|устройство или сооружение для обработки чего-нибудь нагреванием
|
||||
пешеход|человек, идущий пешком
|
||||
пешка|о незначительном, невлиятельном человеке, несамостоятельном в действиях
|
||||
пешком|на своих ногах
|
||||
пешня|лома для пробивания льда
|
||||
пещера|углубление, полое пространство под землей или в горном массиве, имеющее выход наружу
|
||||
пиажама|домашний или спальный костюм - куртка и брюки свободного покроя
|
||||
@@ -10422,7 +10246,6 @@ word|def
|
||||
поддон|подставка под дно, нижнюю часть чего-нибудь
|
||||
поддонник|небольшой поддон
|
||||
поделка|мелкое изделие, изготовленное ручным способом
|
||||
поделом|справедливо, так и следует (о наказании, расплате)
|
||||
поденка|насекомое, живущее недолго, от нескольких секунд до нескольких дней
|
||||
поденщик|рабочий с поденной оплатой
|
||||
поденщина|поденная работа
|
||||
@@ -10654,7 +10477,6 @@ word|def
|
||||
полесье|низменная лесистая местность
|
||||
полет|движение, передвижение по воздуху
|
||||
полжизни|половина жизни, жизненного пути
|
||||
ползком|припав туловищем к поверхности, перебирая по ней конечностями
|
||||
ползун|тот, кто ползет или ползает
|
||||
ползунок|ребенок (или детеныш), который еще не умеет ходить, а только ползает
|
||||
полив|жидкий состав для обмазки гончарных изделий, глазурь
|
||||
@@ -10909,14 +10731,11 @@ word|def
|
||||
порода|принадлежность к какому-нибудь роду, сословию
|
||||
порождение|то, что порождено кем-чем-нибудь
|
||||
порожняк|транспорт, идущий без груза
|
||||
порожняком|без груза, без пассажиров
|
||||
порознь|врозь, отдельно один от другого
|
||||
порой|иногда
|
||||
порка|развратное поведение
|
||||
поролон|легкий и эластичный синтетический материал
|
||||
поросенок|детеныш свиньи
|
||||
поросль|молодые побеги растений от корней, пней или из семян
|
||||
порося|поросенок в пословицах
|
||||
поросятина|мясо поросенка как птица
|
||||
порох|о вспыьчивом или очень пылком человеке
|
||||
пороховница|сумка, сосуд для хранения пороха
|
||||
@@ -11009,7 +10828,6 @@ word|def
|
||||
посредничество|содействие соглашению, сделке между сторонами
|
||||
посредственность|посредственный бездарный человек
|
||||
посредство|посредничество
|
||||
посредством|при помощи чего-нибудь, каким-нибудь способом, используя что-нибудь
|
||||
поссовет|поселковый Совет народных депутатов
|
||||
пост|само такое наблюдение
|
||||
постав|кустарный ткацкий стан
|
||||
@@ -11060,7 +10878,6 @@ word|def
|
||||
потница|болезнь кожи, проявляющаяся в появлении мелких пузырьков при усиленном выделени и пота (обычно у грудных детей)
|
||||
поток|движущаяся масса чего-нибудь
|
||||
потолок|предел, предельная степень чего-нибудь
|
||||
потом|спустя некоторое время, после; вслед за кем-чем-нибудь
|
||||
потомок|люди будущих поколений
|
||||
потомство|молодое поколение по отношению к старшему, к родителям
|
||||
потомсчтво|потомки, люди последующих поколений
|
||||
@@ -11431,7 +11248,6 @@ word|def
|
||||
притворщик|человек, который притворяется 2
|
||||
притеснитель|тот, кто притесняет кого-нибудь, угнетатель
|
||||
притолока|верхний брус в дверном проеме
|
||||
притом|вместе с тем, к тому же, в добавление к тому
|
||||
притон|место тайных преступных сборищ
|
||||
притча|о непонятном, труднообъяснимом явлении, событии
|
||||
притяжение|физическое явление тяготения тел друг к другу
|
||||
@@ -11771,7 +11587,6 @@ word|def
|
||||
пряжа|нити, полученные прядением
|
||||
пряжка|нагрудный наградной знак
|
||||
прялка|приспособление для ручного прядения, приводимое в движение ножной педалью
|
||||
прямиком|прямо напрямик
|
||||
пряник|сладкое мягкое печенье в виде лепешки или плоской фигурки
|
||||
прясло|часть такой и згороди от столба до столба
|
||||
прятки|детская игра, в которой один (водящий) ищет остальных, спрятавшихся участников игры
|
||||
@@ -12109,7 +11924,6 @@ word|def
|
||||
разночинец|выходец из непривилегированных сословий, из мелкого чиновничества, занимающийся умственным трудом, обычно носитель демократической р еволюционной идеологии
|
||||
разночтение|одна из редакций какой-нибудь части текста произведения
|
||||
разоблачитель|тот, кто разоблачил разоблачает кого-что-нибудь
|
||||
разом|сразу, мгновенно, одновременно
|
||||
разор|разорение
|
||||
разоритель|тот, кто разорил, разоряет, производит разорение
|
||||
разоружение|-ся
|
||||
@@ -12737,8 +12551,6 @@ word|def
|
||||
рыльце|носик сосуда
|
||||
рынок|место розничной торговли под открытым небом в торговых рядах, базар
|
||||
рысак|породистая рысистая лошадь
|
||||
рысенок|детеныш рыси
|
||||
рысиха|самка рыси
|
||||
рысца|мелкая рысь 1, мелкий бег
|
||||
рысь|хищное млекопитающее семейства кошачьих с очень острым зрением
|
||||
рытвина|углубление, выбитое колесами или промытое водой
|
||||
@@ -12756,11 +12568,9 @@ word|def
|
||||
рябиновка|настойка на ягодах рябины
|
||||
рябчик|лесная птица семейства тетеревиных с пестрым оперением
|
||||
рябь|ощущение в глазах пестроты, множества разноцветных точек
|
||||
рядком|рядом
|
||||
рядный|толстый холст домашнего производства
|
||||
рядность|установленный порядок разделения на ряды
|
||||
рядовой|лицо, имеющее это звание
|
||||
рядом|по соседству, близко
|
||||
ряженка|варенец
|
||||
ряженье|праздник с ряжеными
|
||||
ряпушка|небольшая рыбка рода сигов
|
||||
@@ -12882,7 +12692,6 @@ word|def
|
||||
самострел|лук с механическим устройством для натягивания и спуска тетивы
|
||||
самосуд|самочинная расправа с кем-нибудь, без ведома властей, суда
|
||||
самотек|течение жидкости или сыпучих тел, совершающееся силой собственной тяжести, по уклону
|
||||
самотеком|силой собственной тяжести, по уклону
|
||||
самоубийство|намеренное лишение жизни
|
||||
самоубийца|тот, кто совершил самоубийство
|
||||
самоуважение|уважение к самому себе
|
||||
@@ -12898,7 +12707,6 @@ word|def
|
||||
самохвал|человек, который занимается самохвальством, бахвал
|
||||
самохвальство|расхваливание самого себя
|
||||
самоход|самоходная машина, механизм
|
||||
самоходом|двигаясь, своим ходом, на собственной тяге
|
||||
самоцвет|самоцветный камень
|
||||
самоцель|цель, достижение которой не предполагает дальнейших устремлений, новых задач
|
||||
самочувствие|состояние физических и душевных сил человека
|
||||
@@ -13323,7 +13131,6 @@ word|def
|
||||
сила|различные их виды
|
||||
силач|человек, который обладает чрезмерно большой физической силой
|
||||
силикат|минералы, составляющие основную массу земной коры; промышленные материалы для изготовления цемента, стекла, огнеупоров, кирпича, керамики
|
||||
силком|силой, насильно
|
||||
силлогизм|умозаключение, в котором из двух данных суждений (посылок) получается третье (вывод)
|
||||
сила|насильно, против воли
|
||||
силок|петля для ловли птиц, мелких животных
|
||||
@@ -13487,7 +13294,6 @@ word|def
|
||||
скопидом|человек, бережливый до скупости
|
||||
скопидомка|о том, кто склоне запасать, припасать, копить что-нибудь
|
||||
скопище|толпа, сборище; скопление
|
||||
скопом|все вместе, сообща
|
||||
скорбь|крайняя печаль, горесть, страдание
|
||||
скорлупа|твердая оболочка (яйца, ореха)
|
||||
скорняк|мастер, занимающийся производством меховых изделий, выделкой мехов
|
||||
@@ -13557,7 +13363,6 @@ word|def
|
||||
сладострастие|наслаждение, страстная увлеченность
|
||||
сладость|сладкий вкус
|
||||
слайд|диапозитив
|
||||
слалом|скоростное движение по заданному извилистому маршруту
|
||||
слаломист|спортсмен, занимающийся слаломом
|
||||
сланец|слоистые горные породы, обладающие способностью раскалываться на тонкие пластины, слои
|
||||
сластена|человек, который любит сладкое, сладости
|
||||
@@ -13568,7 +13373,6 @@ word|def
|
||||
слегка|не сильно, немного, чуть-чуть
|
||||
следователь|должностное лицо, производящее предварительное следствие 2
|
||||
следовательно|значит, стало быть
|
||||
следом|непосредственно за кем-чем-нибудь
|
||||
следопыт|человек (обычно член ученического коллектива), который собирает материалы о былых исторических событиях, об исторических лицах
|
||||
следствие|выяснение, расследование обстоятельств, собирание и проверка данных, связанных с преступлением
|
||||
слеза|капля влаги на свежем разрезе, разрубе чего-нибудь
|
||||
@@ -13591,7 +13395,6 @@ word|def
|
||||
слизняк|слизень
|
||||
слизь|тягучая, вязкая масса, выделяемая некоторыми клетками живых организмов, слизистыми железами
|
||||
слиток|золотой или серебряный самородок
|
||||
слишком|свыше меры, свыше какого-нибудь предела
|
||||
слияние|-ся
|
||||
слобода|поселение, освобожденное от княжеских повинностей
|
||||
слободка|рабочая или ремесленная слобода
|
||||
@@ -13623,8 +13426,6 @@ word|def
|
||||
сложность|трудность, осложняющее обстоятельство
|
||||
слой|плоская масса вещества, лежащая между или поверх других подобных
|
||||
слон|крупное с двумя большими бивнями хоботное мелекопитающее тропических стран
|
||||
слоненок|детеныш слона
|
||||
слониха|самка слона
|
||||
слоновость|болезненное утолщение кожи и подкожной клетчатки, чаще на ногах
|
||||
слуга|человек, посвятивший себя полностью служению кому-чему-нибудь
|
||||
служака|опытный и усердный служащий (обычно о военных)
|
||||
@@ -14032,7 +13833,6 @@ word|def
|
||||
сплетение|-сь
|
||||
сплетник|человек, который сплетничает
|
||||
сплетня|слух о ком-чем-нибудь, основанный на неточных или заведомо неверных сведениях
|
||||
сплеча|не подумав, сразу
|
||||
сплин|уныние, хандра
|
||||
сплошь|целиком, без исключения
|
||||
сподвижник|помощник в деятельности на каком-нибудь поприще, соратник
|
||||
@@ -14068,7 +13868,6 @@ word|def
|
||||
спьяна|будучи пьяным
|
||||
спячка|физиологическое состояние, сходное с длительным сном
|
||||
сражение|горячий спор, ссора
|
||||
сразу|тут же рядом, в непосредственной близости
|
||||
срам|позор, стыд
|
||||
срамник|бесстыдник
|
||||
срамота|постыдный поступок, срам
|
||||
@@ -14603,7 +14402,6 @@ word|def
|
||||
таежник|человек, который живет и промышляет в тайге
|
||||
таинство|"обряд (крещение, причащение, исповедь и др.), который сообщает верующим ""божественную благодать"""
|
||||
тайга|дикий хвойный лес
|
||||
тайком|тайно, скрытно
|
||||
тайм|определенная часть, период
|
||||
таймень|крупная хищная рыба семейства лососевых
|
||||
тайна|скрытая причина чего-нибудь
|
||||
@@ -14868,8 +14666,6 @@ word|def
|
||||
тиара|головной убор древних восточных царей, а также римского папы
|
||||
тигель|сосуд из огнеупорного материала для плавки или прокаливания чего-нибудь на сильном огне
|
||||
тигр|крупное хищное млекопитающее семейства кошачьих с полосатой шкуро
|
||||
тигренок|детеныш тигра
|
||||
тигрица|самка тигра
|
||||
тигролов|охотник, занимающийся отловом тигров
|
||||
тимофеевка|луговой кормовой злак
|
||||
тимпан|древний ударный музыкальный инструмент, род тарелок, литавр
|
||||
@@ -14893,12 +14689,10 @@ word|def
|
||||
титул|страница, на которой напечатано заглавие, имя автора, год и место издания
|
||||
тиун|название некоторых должностных лиц
|
||||
тифлопедагогика|раздел дефектологии, занимающийся обучением слепых
|
||||
тихомолком|совсем тихо, незаметно; втихомолку
|
||||
тихоня|тихий, смирный человек
|
||||
тихоокеанец|моряк Тихоокеанского флота
|
||||
тихоход|тот, кто ходит, передвигается медленно
|
||||
тишина|спокойствие, умиротворенное состояние
|
||||
тишком|незаметно, потихоньку
|
||||
тишь|тишина
|
||||
тканина|кусок ткани
|
||||
ткань|система преимущественно однородных клеток и продуктов их жизнедеятельности
|
||||
@@ -14933,7 +14727,6 @@ word|def
|
||||
толк|разговоры, слухи, пересуды
|
||||
толкование|объяснение чего-нибудь, изложение точки зрения на что-нибудь
|
||||
толкователь|человек, который занимается толкованием, объяснением чего-нибудь
|
||||
толком|разумно, дельно, ясно
|
||||
толкотня|движения многих теснящихся, толкающихся людей
|
||||
толкучка|место, где толпится много народа; толкотня
|
||||
толмач|переводчик во время беседы, переговоров
|
||||
@@ -15006,7 +14799,6 @@ word|def
|
||||
торт|кондитерское изделие из сладкого сдобного теста с кремом, фруктами
|
||||
торф|полезное ископаемое - плотная масса, образовавшаяся из перегнивших остатков болотных растений, употр, как топливо, удобрение, теплоизоляционный материал
|
||||
торфоразработка|место добычи торфа
|
||||
торчком|в торчащем положении
|
||||
торчок|что-нибудь торчащее, выдающееся вперед, вверх
|
||||
торшер|напольный светильник на высокой подставке
|
||||
тоска|что-нибудь очень скучное, неинтересное
|
||||
@@ -15016,7 +14808,6 @@ word|def
|
||||
тоталитаризм|тоталитарный режим
|
||||
тотем|обожествляемое животное (иногда явление природы, растение, предмет), считающееся родоначальником племени
|
||||
тотемизм|первобытный культ тотемов
|
||||
тотчас|сейчас же, сразу
|
||||
точилка|приспособление, инструмент для точки
|
||||
точило|инструмент, станок для точки, обработки чего-нибудь точением
|
||||
точильщик|рабочий, занимающийся натачиванием чего-нибудь, обточкой
|
||||
@@ -15185,7 +14976,6 @@ word|def
|
||||
тройка|"учебная отметка ""удовлетворительно"""
|
||||
тройник|предмет, содержащий в себе три каких-нибудь единицы или измеряемый тремя какими-нибудь единицами
|
||||
тройня|три младенца (детеныша), одновременно рожденные одной матерью (самкой)
|
||||
тройняшка|трое близнецов
|
||||
тройчатка|состав из трех элементов
|
||||
троллейбус|многоместная электрическая транспортная машина, идущая по безрельсовым путям
|
||||
тромб|вообще сгусток вещества, закупоривающий сосуд, проток
|
||||
@@ -15317,8 +15107,6 @@ word|def
|
||||
тюбетейка|маленькая без тульи и полей узорчатая восточная шапочка, облегающая голову
|
||||
тюбик|металлическая или пластмассовая трубочка, из которой содержимое извлекается выдавливанием
|
||||
тюбинг|металлическая или железобетонная дугообразно изогнутая плита, применяемая для с борки водопроницаемого крепления шахт, тоннелей
|
||||
тюлененок|детеныш тюленя
|
||||
тюленина|мясо тюленя как пища
|
||||
тюль|тонкая сетчатая ткань
|
||||
тюлька|мелкая рыба семейства сельдевых
|
||||
тюльпан|луковичное растение семейства лилейных с крупными яркими цветками
|
||||
@@ -15637,7 +15425,6 @@ word|def
|
||||
утреня|утренняя церковная служба
|
||||
утро|зрелище, представление, литературное или музыкальное собрание в первой половине дня
|
||||
утроба|живот, внутренности
|
||||
утром|в утреннее время
|
||||
утряска|потеря в весе при пересыпке, перевозке
|
||||
утюг|нагревающийся металлически прибор для глаженья
|
||||
утятина|мясо утки как пища
|
||||
@@ -16234,7 +16021,6 @@ word|def
|
||||
хорист|тот, кто поет в хоре
|
||||
хормейстер|хоровой дирижер, руководитель хора
|
||||
хоровод|кольцо взявшихся за руки людей - участников какой-нибудь игры, танца
|
||||
хором|все вместе, единодушно
|
||||
хорошенько|как следует, в достаточной степени
|
||||
хорошист|"учащийся, получающий оценки ""хорошо"""
|
||||
хоругвь|войсковое знамя
|
||||
@@ -16245,10 +16031,8 @@ word|def
|
||||
хоть|к примеру, например
|
||||
хотя|хоть
|
||||
хохлатка|курица
|
||||
хохлом|так расписанные художественные изделия
|
||||
хохлома|так расписанные художественные изделия
|
||||
хохма|шутка, розыгрыш, что-нибудь смешное
|
||||
хохмач|человек, который любит смешить, шутить
|
||||
хохол|украинец
|
||||
хохот|громкий смех
|
||||
хохотун|человек, который много и громко смеется
|
||||
хохотушка|хохотунья
|
||||
@@ -16343,7 +16127,6 @@ word|def
|
||||
цезура|пауза, делящая строку на части; в музыкальном исполнении: очень короткая пауза между двумя фразами или завершенными разделами
|
||||
цейтнот|острый недостаток времени
|
||||
цейхгауз|воинский склад для хранения обмундирования, снаряжения, вооружения и продовольствия
|
||||
целиком|без ограничений, полностью
|
||||
целина|никогда не паханная, не подвергавшаяся обработке земля
|
||||
целинник|человек, который освоил или осваивает целину
|
||||
целитель|исцелитель
|
||||
@@ -16661,7 +16444,6 @@ word|def
|
||||
членкор|член-корреспондент Академии наук
|
||||
членовредительство|нанесение увечья кому-нибудь или умышленное повреждение члена, органа самому себе
|
||||
членство|пребывание членом где-нибудь
|
||||
чохом|все вместе, целиком, не разделяя
|
||||
чрево|живот 1
|
||||
чревовещание|способность говорить, не шевеля губами, создавая впечатление, что звуки исходят изнутри, из живота
|
||||
чревовещатель|человек, способный к чревовещанию
|
||||
@@ -16690,7 +16472,6 @@ word|def
|
||||
чудо|выражение крайнего удивления, недоверия
|
||||
чудовище|устрашающее, уродливое существо
|
||||
чудодей|человек, который производит чудо, чудеса
|
||||
чудом|непонятно как, странным образом или по счастливой случайности
|
||||
чудь|общее название некоторых западно-финских племен
|
||||
чужак|чуждый какой-нибудь среде человек
|
||||
чужанин|чужой человек, чужак
|
||||
@@ -16706,14 +16487,10 @@ word|def
|
||||
чумиза|растение, род хлебного злака, близкого к просу
|
||||
чумичка|разливательная ложка
|
||||
чуня|веревочные лапти
|
||||
чуприн|чуб
|
||||
чурбак|чурбан
|
||||
чурбан|обрубок бревна
|
||||
чурек|плоский пресный белый хлеб
|
||||
чурка|короткий обрубок дерева
|
||||
чуткий|чуть-чуть, немного
|
||||
чуточка|совсем немного
|
||||
чуть|как только, сразу вслед за чем-нибудь
|
||||
чутье|способность понимать, ценить что-нибудь, разбираться в чем-нибудь
|
||||
чучело|фигура наподобие человеческой для отпугивания птиц
|
||||
чушка|небольшой слиток металла, обычно предназначенный для переплавки
|
||||
@@ -16820,7 +16597,6 @@ word|def
|
||||
шелководство|разделение шелкопряда как отрасль сельского хозяйства
|
||||
шелкопряд|бабочка, гусеница которой вьет коконы, идущие на изготовление шелка
|
||||
шелкопрядение|производство шелковой пряжи из коконов, не поддающихся размотке
|
||||
шелом|шлем
|
||||
шелуха|кожура семян
|
||||
шельма|мошенник, плут
|
||||
шельф|прибрежная мелководная зона океана (с глубинами до 200 м)
|
||||
@@ -17127,7 +16903,6 @@ word|def
|
||||
эклетик|исследователь или художник, склонный к эклектизму, к электике
|
||||
эколог|специалист по экологии
|
||||
экология|наука об отношениях растительных и животных организмов друг к другу и к окружающей их среде
|
||||
эконом|экономист
|
||||
экономика|организация, структура и состояние хозяйственной жизни или какой-нибудь отрасли хозяйственной деятельности
|
||||
экономист|специалист в области экономики, экономических наук
|
||||
экономия|выгода, получающаяся при бережном расходовании чего-нибудь
|
||||
@@ -17161,7 +16936,6 @@ word|def
|
||||
экспрессионист|последователь экспрессионизма
|
||||
экспрессия|выражение чувств, переживаний, выразительность
|
||||
экспромт|речь, стихотворение, музыкальное произведение, создаваемые без подготовки, в момент произнесения, исполнения, импровизация
|
||||
экспромтом|сразу, без подготовки
|
||||
экспроприатор|лицо, которое экспроприирует кого-что-нибудь
|
||||
экспроприация|принудительное отчуждение, изъятие собственности
|
||||
экстаз|вид аффективного психического расстройства
|
||||
@@ -17458,7 +17232,6 @@ word|def
|
||||
яхта|небольшое судно для прогулок, спорта
|
||||
яхтсмен|спортсмен, занимающийся парусным спортом
|
||||
ячейка|ячея
|
||||
яченок|детеныш яка
|
||||
ячество|"индивидуализм, выдвижение на первый план себя, своей личности, своего ""я"""
|
||||
ячея|каждое отдельное звено в сети, в плетении
|
||||
ячмень|гнойное воспаление железок у корней ресниц
|
||||
|
||||
|
Can't render this file because it is too large.
|
@@ -1,7 +1,9 @@
|
||||
import csv
|
||||
import datetime
|
||||
import secrets
|
||||
from collections import defaultdict, deque
|
||||
from dataclasses import dataclass
|
||||
from datetime import timedelta
|
||||
from pathlib import Path
|
||||
from pprint import pformat
|
||||
from typing import Annotated
|
||||
@@ -107,7 +109,7 @@ class PuzzleGenerator:
|
||||
with dict_path.open("r") as f:
|
||||
rows = csv.DictReader(f, delimiter="|")
|
||||
for row in rows:
|
||||
word = row["word"]
|
||||
word = row["word"].lower().replace("ё", "е") # noqa: RUF001
|
||||
self.words[word] = row["def"]
|
||||
self.trie.add(word)
|
||||
|
||||
@@ -139,7 +141,10 @@ class PuzzleGenerator:
|
||||
while paths:
|
||||
path, trie_node = paths.pop()
|
||||
if trie_node.valid_word and len(trie_node.value) >= 4:
|
||||
solutions[trie_node.value] = path
|
||||
word = trie_node.value
|
||||
if word in solutions:
|
||||
return {}
|
||||
solutions[word] = path
|
||||
for dx, dy in (
|
||||
(1, 1),
|
||||
(-1, -1),
|
||||
@@ -234,6 +239,7 @@ class PuzzleGenerator:
|
||||
prev = path[0]
|
||||
for tile in path[1:]:
|
||||
neigbours[prev].add(tile)
|
||||
neigbours[tile].add(prev)
|
||||
prev = tile
|
||||
|
||||
extras = {w: p for w, p in solutions.items() if w not in cover}
|
||||
@@ -263,20 +269,24 @@ class PuzzleGenerator:
|
||||
|
||||
return used_cells
|
||||
|
||||
def generate(self, target: int, max_attempts: int) -> Puzzle | None:
|
||||
def generate(self, target: int, timeout: int = 10) -> Puzzle:
|
||||
"""
|
||||
Generate a valid puzzle that has solutions.
|
||||
|
||||
:param target: minimum number of words required to solve the puzzle.
|
||||
:param max_attempts: Since sometimes we might fail to generate a correct
|
||||
puzzle. We try it multiple times, this parameters limits how
|
||||
many attempts we should have before giving up.
|
||||
:param timeout: since puzzles can fail to generate sometimes,
|
||||
we use timeout to not let the puzzle generator hung forever!
|
||||
:return: puzzle.
|
||||
"""
|
||||
board: list[list[str]] = [["" for _ in range(4)] for _ in range(4)]
|
||||
valid_points: set[tuple[int, int]] = set()
|
||||
single_board_attempt = 0
|
||||
for _ in range(max_attempts):
|
||||
started = datetime.datetime.now()
|
||||
while True:
|
||||
if datetime.datetime.now() - started > timedelta(seconds=timeout):
|
||||
raise ValueError(
|
||||
f"Coud not find a valid solution in {timeout} seconds!"
|
||||
)
|
||||
if single_board_attempt > 50:
|
||||
valid_points = set()
|
||||
|
||||
@@ -301,8 +311,6 @@ class PuzzleGenerator:
|
||||
word_defs=word_defs,
|
||||
)
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def setup_generator(app: FastAPI) -> None:
|
||||
"""Create puzzle-generator."""
|
||||
@@ -319,7 +327,7 @@ PuzzleGeneratorDep = Annotated[PuzzleGenerator, Depends(get_generator)]
|
||||
|
||||
if __name__ == "__main__":
|
||||
generator = PuzzleGenerator(CWD / "dict.csv")
|
||||
res = generator.generate(target=10, max_attempts=200)
|
||||
res = generator.generate(target=10)
|
||||
if res is None:
|
||||
print("No solution found!") # noqa: T201
|
||||
else:
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import enum
|
||||
from datetime import date
|
||||
from pathlib import Path
|
||||
from tempfile import gettempdir
|
||||
|
||||
@@ -46,6 +47,9 @@ class Settings(BaseSettings):
|
||||
db_base: str = "zangramru"
|
||||
db_echo: bool = False
|
||||
|
||||
# When first daily puzzle was generated.
|
||||
start_date: date = date(2026, 7, 1)
|
||||
|
||||
@property
|
||||
def db_url(self) -> URL:
|
||||
"""
|
||||
|
||||
+321
-354
@@ -4,6 +4,14 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Занграммы</title>
|
||||
<meta property="og:title" content="Занграммы">
|
||||
<meta property="og:description" content="Игра со словами — находи слова на сетке">
|
||||
<meta property="og:image" content="/preview.png">
|
||||
<meta property="og:type" content="website">
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:title" content="Занграммы">
|
||||
<meta name="twitter:description" content="Игра со словами — находи слова на сетке">
|
||||
<meta name="twitter:image" content="/preview.png">
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body {
|
||||
@@ -40,17 +48,17 @@
|
||||
font-size: 2rem;
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
min-height: 3rem;
|
||||
height: 3rem;
|
||||
margin-bottom: 0.5rem;
|
||||
letter-spacing: 0.3em;
|
||||
cursor: pointer;
|
||||
padding: 0.5rem;
|
||||
border-radius: 8px;
|
||||
transition: background 0.2s;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
}
|
||||
#wordDisplay:hover {
|
||||
background: rgba(255,255,255,0.05);
|
||||
}
|
||||
#wordDisplay:hover { background: rgba(255,255,255,0.05); }
|
||||
#message {
|
||||
min-height: 1.5rem;
|
||||
margin-bottom: 0.5rem;
|
||||
@@ -65,11 +73,7 @@
|
||||
touch-action: none;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
#found {
|
||||
margin-top: 1.5rem;
|
||||
max-width: 500px;
|
||||
width: 100%;
|
||||
}
|
||||
#found { margin-top: 1.5rem; max-width: 500px; width: 100%; }
|
||||
#found h2 { margin-bottom: 0.5rem; font-size: 1.1rem; }
|
||||
.word-item {
|
||||
background: #16213e;
|
||||
@@ -80,28 +84,11 @@
|
||||
flex-direction: column;
|
||||
gap: 0.3rem;
|
||||
}
|
||||
.word-item-inner {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
.word-color {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border-radius: 50%;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.word-text {
|
||||
font-weight: 700;
|
||||
font-size: 1.1rem;
|
||||
color: #fff;
|
||||
}
|
||||
.word-def {
|
||||
color: #888;
|
||||
font-size: 0.9rem;
|
||||
padding-left: 1.5rem;
|
||||
}
|
||||
#gameComplete {
|
||||
.word-item-inner { display: flex; align-items: center; gap: 0.5rem; }
|
||||
.word-color { width: 16px; height: 16px; border-radius: 50%; flex-shrink: 0; }
|
||||
.word-text { font-weight: 700; font-size: 1.1rem; color: #fff; }
|
||||
.word-def { color: #888; font-size: 0.9rem; padding-left: 1.5rem; }
|
||||
.modal {
|
||||
display: none;
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
@@ -110,66 +97,81 @@
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
#gameComplete.show {
|
||||
display: flex;
|
||||
}
|
||||
#gameComplete .popup {
|
||||
.modal.show { display: flex; }
|
||||
.modal .popup {
|
||||
background: #16213e;
|
||||
border-radius: 16px;
|
||||
padding: 2rem 3rem;
|
||||
text-align: center;
|
||||
box-shadow: 0 8px 32px rgba(0,0,0,0.5);
|
||||
max-width: 400px;
|
||||
}
|
||||
#gameComplete .popup h2 {
|
||||
color: #fff;
|
||||
font-size: 1.5rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
#gameComplete .popup .time {
|
||||
color: #2ed573;
|
||||
font-size: 2rem;
|
||||
font-weight: bold;
|
||||
margin: 1rem 0;
|
||||
}
|
||||
#gameComplete .popup button {
|
||||
margin-top: 1rem;
|
||||
padding: 0.7rem 2rem;
|
||||
font-size: 1rem;
|
||||
.modal .popup h2 { color: #fff; font-size: 1.5rem; margin-bottom: 0.5rem; }
|
||||
.modal .popup .time { color: #2ed573; font-size: 2rem; font-weight: bold; margin: 1rem 0; }
|
||||
.modal .popup .buttons { display: flex; flex-direction: column; gap: 0.5rem; margin-top: 1.5rem; }
|
||||
.modal .popup .buttons button { width: 100%; margin-top: 0; }
|
||||
#numberSelector { background: rgba(0,0,0,0.5); z-index: 101; }
|
||||
#numberSelector .popup { padding: 1.5rem 2rem; max-height: 70vh; overflow-y: auto; }
|
||||
#numberSelector .popup h3 { color: #fff; margin-bottom: 1rem; text-align: center; }
|
||||
#numberSelector .number-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(5, 1fr);
|
||||
gap: 0.5rem;
|
||||
}
|
||||
#numberSelector .number-grid button { padding: 0.5rem; font-size: 0.9rem; background: #0f3460; }
|
||||
#numberSelector .number-grid button:hover { background: #1a4a80; }
|
||||
#numberSelector .number-grid button.solved { background: #2ed573; color: #000; }
|
||||
#numberSelector .number-grid button.current { border: 2px solid #feca57; }
|
||||
#numberSelector .popup .close-btn { margin-top: 1rem; width: 100%; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Занграммы</h1>
|
||||
<div class="controls">
|
||||
<span id="status">Загрузка...</span>
|
||||
</div>
|
||||
<div class="controls"><span id="status">Загрузка...</span></div>
|
||||
<div id="wordDisplay"></div>
|
||||
<div id="message"></div>
|
||||
<canvas id="board"></canvas>
|
||||
<div id="found"></div>
|
||||
<div id="gameComplete">
|
||||
|
||||
<!-- Game complete modal -->
|
||||
<div id="gameComplete" class="modal">
|
||||
<div class="popup">
|
||||
<h2>Вы нашли все слова! Ваше время:</h2>
|
||||
<div class="time" id="gameTime"></div>
|
||||
<div class="buttons">
|
||||
<button id="copyResultBtn">Скопировать результат</button>
|
||||
<button id="prevPuzzlesBtn">Предыдущие занграммы</button>
|
||||
<button id="randomPuzzleBtn">Случайная занграмма</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Number selector modal -->
|
||||
<div id="numberSelector" class="modal">
|
||||
<div class="popup">
|
||||
<h3>Выберите занграмму</h3>
|
||||
<div class="number-grid" id="numberGrid"></div>
|
||||
<button class="close-btn" id="closeNumberBtn">Закрыть</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const canvas = document.getElementById('board');
|
||||
(() => {
|
||||
// ===================== DOM =====================
|
||||
const $ = id => document.getElementById(id);
|
||||
const canvas = $('board');
|
||||
const ctx = canvas.getContext('2d');
|
||||
const statusEl = document.getElementById('status');
|
||||
const wordDisplay = document.getElementById('wordDisplay');
|
||||
const msgEl = document.getElementById('message');
|
||||
const foundDiv = document.getElementById('found');
|
||||
const gameCompleteEl = document.getElementById('gameComplete');
|
||||
const gameTimeEl = document.getElementById('gameTime');
|
||||
|
||||
const CELL = 70;
|
||||
const GAP = 20;
|
||||
const GRID = 4;
|
||||
const CELL_PITCH = CELL + GAP;
|
||||
let OFFSET_X, OFFSET_Y;
|
||||
const statusEl = $('status');
|
||||
const wordDisplay = $('wordDisplay');
|
||||
const msgEl = $('message');
|
||||
const foundDiv = $('found');
|
||||
const gameCompleteEl = $('gameComplete');
|
||||
const gameTimeEl = $('gameTime');
|
||||
const numberSelectorEl = $('numberSelector');
|
||||
const numberGridEl = $('numberGrid');
|
||||
|
||||
// ===================== Constants =====================
|
||||
const CELL = 70, GAP = 20, GRID = 4, CELL_PITCH = CELL + GAP;
|
||||
const PALETTE = [
|
||||
'#ff6b6b','#feca57','#48dbfb','#ff9ff3','#54a0ff',
|
||||
'#5f27cd','#01a3a4','#f368e0','#ff6348','#7bed9f',
|
||||
@@ -177,42 +179,30 @@
|
||||
'#eccc68','#a4b0be','#ff7979','#badc58','#dff9fb'
|
||||
];
|
||||
|
||||
// ===================== State =====================
|
||||
let board = null;
|
||||
let allSolutions = {};
|
||||
let extraWords = {};
|
||||
let wordDefs = {};
|
||||
let foundWords = new Set();
|
||||
let foundPaths = {};
|
||||
let word_defs = {};
|
||||
let selected = [];
|
||||
let flashTimer = null;
|
||||
let startTime = null;
|
||||
let puzzleNumber = null;
|
||||
let elapsed = 0;
|
||||
let lastSaveTime = 0;
|
||||
let timerInterval = null;
|
||||
let OFFSET_X, OFFSET_Y;
|
||||
|
||||
// ===================== Helpers =====================
|
||||
function formatTime(ms) {
|
||||
const totalSec = Math.floor(ms / 1000);
|
||||
const min = Math.floor(totalSec / 60).toString().padStart(2, '0');
|
||||
const sec = (totalSec % 60).toString().padStart(2, '0');
|
||||
return min + ':' + sec;
|
||||
const s = Math.floor(ms / 1000);
|
||||
return String(Math.floor(s / 60)).padStart(2, '0') + ':' + String(s % 60).padStart(2, '0');
|
||||
}
|
||||
|
||||
function startTimer() {
|
||||
startTime = Date.now();
|
||||
if (timerInterval) clearInterval(timerInterval);
|
||||
timerInterval = setInterval(() => {
|
||||
const remaining = Object.keys(allSolutions).filter(w => !foundWords.has(w)).length;
|
||||
if (remaining === 0) {
|
||||
clearInterval(timerInterval);
|
||||
const elapsed = Date.now() - startTime;
|
||||
gameTimeEl.textContent = formatTime(elapsed);
|
||||
gameCompleteEl.classList.add('show');
|
||||
}
|
||||
}, 500);
|
||||
}
|
||||
function cellKey(x, y) { return x + ',' + y; }
|
||||
|
||||
function resetTimer() {
|
||||
if (timerInterval) clearInterval(timerInterval);
|
||||
timerInterval = null;
|
||||
startTime = null;
|
||||
function cellCenter(x, y) {
|
||||
return { x: OFFSET_X + x * CELL_PITCH + CELL / 2, y: OFFSET_Y + y * CELL_PITCH + CELL / 2 };
|
||||
}
|
||||
|
||||
function initBoard() {
|
||||
@@ -222,46 +212,11 @@
|
||||
OFFSET_Y = 40;
|
||||
}
|
||||
|
||||
function cellCenter(x, y) {
|
||||
return {
|
||||
x: OFFSET_X + x * CELL_PITCH + CELL / 2,
|
||||
y: OFFSET_Y + y * CELL_PITCH + CELL / 2
|
||||
};
|
||||
}
|
||||
|
||||
function cellKey(x, y) {
|
||||
return x + ',' + y;
|
||||
}
|
||||
|
||||
function getSolutionConnections() {
|
||||
const conns = new Set();
|
||||
for (const [word, path] of Object.entries(allSolutions)) {
|
||||
for (let i = 0; i < path.length - 1; i++) {
|
||||
const a = cellKey(path[i][0], path[i][1]);
|
||||
const b = cellKey(path[i + 1][0], path[i + 1][1]);
|
||||
conns.add(a < b ? a + '-' + b : b + '-' + a);
|
||||
}
|
||||
}
|
||||
return conns;
|
||||
}
|
||||
|
||||
function isAdjacentAndConnected(a, b) {
|
||||
if (Math.abs(a[0] - b[0]) > 1 || Math.abs(a[1] - b[1]) > 1) return false;
|
||||
if (a[0] === b[0] && a[1] === b[1]) return false;
|
||||
const ka = cellKey(a[0], a[1]);
|
||||
const kb = cellKey(b[0], b[1]);
|
||||
const key = ka < kb ? ka + '-' + kb : kb + '-' + ka;
|
||||
const conns = getSolutionConnections();
|
||||
return conns.has(key);
|
||||
}
|
||||
|
||||
function getActiveCells() {
|
||||
const cells = new Set();
|
||||
for (const [word, path] of Object.entries(allSolutions)) {
|
||||
if (foundWords.has(word)) continue;
|
||||
for (const cell of path) {
|
||||
cells.add(cellKey(cell[0], cell[1]));
|
||||
}
|
||||
for (const c of path) cells.add(cellKey(c[0], c[1]));
|
||||
}
|
||||
return cells;
|
||||
}
|
||||
@@ -281,96 +236,118 @@
|
||||
|
||||
function drawPath(path, color, lineWidth, alpha) {
|
||||
if (path.length < 2) return;
|
||||
const t1 = CELL / (2 * CELL_PITCH);
|
||||
const t2 = 1 - CELL / (2 * CELL_PITCH);
|
||||
ctx.strokeStyle = color;
|
||||
ctx.lineWidth = lineWidth;
|
||||
ctx.lineCap = 'round';
|
||||
ctx.globalAlpha = alpha;
|
||||
const t1 = CELL / (2 * CELL_PITCH), t2 = 1 - t1;
|
||||
ctx.strokeStyle = color; ctx.lineWidth = lineWidth; ctx.lineCap = 'round'; ctx.globalAlpha = alpha;
|
||||
ctx.beginPath();
|
||||
for (let i = 0; i < path.length - 1; i++) {
|
||||
const c1 = cellCenter(path[i][0], path[i][1]);
|
||||
const c2 = cellCenter(path[i + 1][0], path[i + 1][1]);
|
||||
const x1 = c1.x + (c2.x - c1.x) * t1;
|
||||
const y1 = c1.y + (c2.y - c1.y) * t1;
|
||||
const x2 = c1.x + (c2.x - c1.x) * t2;
|
||||
const y2 = c1.y + (c2.y - c1.y) * t2;
|
||||
ctx.moveTo(x1, y1);
|
||||
ctx.lineTo(x2, y2);
|
||||
ctx.moveTo(c1.x + (c2.x - c1.x) * t1, c1.y + (c2.y - c1.y) * t1);
|
||||
ctx.lineTo(c1.x + (c2.x - c1.x) * t2, c1.y + (c2.y - c1.y) * t2);
|
||||
}
|
||||
ctx.stroke();
|
||||
ctx.globalAlpha = 1;
|
||||
}
|
||||
|
||||
function shadeColor(color, percent) {
|
||||
let R = parseInt(color.substring(1, 3), 16);
|
||||
let G = parseInt(color.substring(3, 5), 16);
|
||||
let B = parseInt(color.substring(5, 7), 16);
|
||||
R = Math.min(255, Math.max(0, Math.round(R * (100 + percent) / 100)));
|
||||
G = Math.min(255, Math.max(0, Math.round(G * (100 + percent) / 100)));
|
||||
B = Math.min(255, Math.max(0, Math.round(B * (100 + percent) / 100)));
|
||||
return '#' + R.toString(16).padStart(2, '0') + G.toString(16).padStart(2, '0') + B.toString(16).padStart(2, '0');
|
||||
}
|
||||
|
||||
function getWordColor(word) {
|
||||
let h = 0;
|
||||
for (let i = 0; i < word.length; i++) h = word.charCodeAt(i) + ((h << 5) - h);
|
||||
return PALETTE[Math.abs(h) % PALETTE.length];
|
||||
}
|
||||
|
||||
function boardsEqual(a, b) {
|
||||
if (!a || !b) return false;
|
||||
if (a.length !== b.length) return false;
|
||||
for (let i = 0; i < a.length; i++) {
|
||||
if (a[i].length !== b[i].length) return false;
|
||||
for (let j = 0; j < a[i].length; j++) {
|
||||
if (a[i][j] !== b[i][j]) return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// ===================== Persistence =====================
|
||||
function save() {
|
||||
if (puzzleNumber === null) return;
|
||||
elapsed += Date.now() - lastSaveTime;
|
||||
lastSaveTime = Date.now();
|
||||
const state = { foundWords: Array.from(foundWords), elapsed, board, allSolutions, extraWords, wordDefs };
|
||||
localStorage.setItem('puzzle_' + puzzleNumber, JSON.stringify(state));
|
||||
}
|
||||
|
||||
function load() {
|
||||
if (puzzleNumber === null) return null;
|
||||
const raw = localStorage.getItem('puzzle_' + puzzleNumber);
|
||||
if (!raw) return null;
|
||||
const state = JSON.parse(raw);
|
||||
lastSaveTime = Date.now();
|
||||
return state;
|
||||
}
|
||||
|
||||
function clear() {
|
||||
if (puzzleNumber === null) return;
|
||||
localStorage.removeItem('puzzle_' + puzzleNumber);
|
||||
}
|
||||
|
||||
function getSolvedNumbers() {
|
||||
const result = [];
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
if (localStorage.getItem('puzzle_' + i)) result.push(i);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// ===================== Rendering =====================
|
||||
function draw() {
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
const selSet = new Set(selected.map(([x, y]) => cellKey(x, y)));
|
||||
const activeCells = getActiveCells();
|
||||
const activeConns = getActiveConnections();
|
||||
|
||||
// Draw connections between active cells
|
||||
ctx.strokeStyle = '#2a4a7f';
|
||||
ctx.lineWidth = GAP - 6;
|
||||
ctx.lineCap = 'round';
|
||||
ctx.globalAlpha = 0.6;
|
||||
ctx.strokeStyle = '#2a4a7f'; ctx.lineWidth = GAP - 6; ctx.lineCap = 'round'; ctx.globalAlpha = 0.6;
|
||||
ctx.beginPath();
|
||||
for (const key of activeConns) {
|
||||
const [ka, kb] = key.split('-');
|
||||
const [ax, ay] = ka.split(',').map(Number);
|
||||
const [bx, by] = kb.split(',').map(Number);
|
||||
const c1 = cellCenter(ax, ay);
|
||||
const c2 = cellCenter(bx, by);
|
||||
const t1 = CELL / (2 * CELL_PITCH);
|
||||
const t2 = 1 - CELL / (2 * CELL_PITCH);
|
||||
const x1 = c1.x + (c2.x - c1.x) * t1;
|
||||
const y1 = c1.y + (c2.y - c1.y) * t1;
|
||||
const x2 = c1.x + (c2.x - c1.x) * t2;
|
||||
const y2 = c1.y + (c2.y - c1.y) * t2;
|
||||
ctx.moveTo(x1, y1);
|
||||
ctx.lineTo(x2, y2);
|
||||
const c1 = cellCenter(ax, ay), c2 = cellCenter(bx, by);
|
||||
const t1 = CELL / (2 * CELL_PITCH), t2 = 1 - t1;
|
||||
ctx.moveTo(c1.x + (c2.x - c1.x) * t1, c1.y + (c2.y - c1.y) * t1);
|
||||
ctx.lineTo(c1.x + (c2.x - c1.x) * t2, c1.y + (c2.y - c1.y) * t2);
|
||||
}
|
||||
ctx.stroke();
|
||||
ctx.globalAlpha = 1;
|
||||
ctx.stroke(); ctx.globalAlpha = 1;
|
||||
|
||||
// Draw selected path
|
||||
if (selected.length > 1) {
|
||||
drawPath(selected, '#fff', GAP - 2, 0.8);
|
||||
}
|
||||
|
||||
// Draw cells
|
||||
ctx.textAlign = 'center';
|
||||
ctx.textBaseline = 'middle';
|
||||
if (selected.length > 1) drawPath(selected, '#fff', GAP - 2, 0.8);
|
||||
|
||||
ctx.textAlign = 'center'; ctx.textBaseline = 'middle';
|
||||
for (let x = 0; x < GRID; x++) {
|
||||
for (let y = 0; y < GRID; y++) {
|
||||
const cx = OFFSET_X + x * CELL_PITCH;
|
||||
const cy = OFFSET_Y + y * CELL_PITCH;
|
||||
const cx = OFFSET_X + x * CELL_PITCH, cy = OFFSET_Y + y * CELL_PITCH;
|
||||
const key = cellKey(x, y);
|
||||
const isVisible = activeCells.has(key);
|
||||
const isSel = selSet.has(key);
|
||||
|
||||
const isVisible = activeCells.has(key), isSel = selSet.has(key);
|
||||
ctx.globalAlpha = isVisible ? 1 : 0.08;
|
||||
ctx.fillStyle = isSel ? '#16213e' : '#0f3460';
|
||||
ctx.beginPath();
|
||||
ctx.arc(cx + CELL / 2, cy + CELL / 2, CELL / 2, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
|
||||
ctx.beginPath(); ctx.arc(cx + CELL / 2, cy + CELL / 2, CELL / 2, 0, Math.PI * 2); ctx.fill();
|
||||
if (isSel && isVisible) {
|
||||
ctx.strokeStyle = '#fff';
|
||||
ctx.lineWidth = 3;
|
||||
ctx.beginPath();
|
||||
ctx.arc(cx + CELL / 2, cy + CELL / 2, CELL / 2 + 2, 0, Math.PI * 2);
|
||||
ctx.stroke();
|
||||
ctx.strokeStyle = '#fff'; ctx.lineWidth = 3;
|
||||
ctx.beginPath(); ctx.arc(cx + CELL / 2, cy + CELL / 2, CELL / 2 + 2, 0, Math.PI * 2); ctx.stroke();
|
||||
}
|
||||
|
||||
ctx.fillStyle = '#fff';
|
||||
ctx.font = 'bold 30px sans-serif';
|
||||
ctx.fillStyle = '#fff'; ctx.font = 'bold 30px sans-serif';
|
||||
ctx.fillText(board[x][y].toUpperCase(), cx + CELL / 2, cy + CELL / 2);
|
||||
}
|
||||
}
|
||||
ctx.globalAlpha = 1;
|
||||
|
||||
wordDisplay.textContent = selected.map(([x, y]) => board[x][y]).join('');
|
||||
}
|
||||
|
||||
@@ -378,110 +355,51 @@
|
||||
if (flashTimer) clearTimeout(flashTimer);
|
||||
const selSet = new Set(selected.map(([x, y]) => cellKey(x, y)));
|
||||
const flashSet = new Set((path || selected).map(([x, y]) => cellKey(x, y)));
|
||||
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
const activeCells = getActiveCells();
|
||||
const activeConns = getActiveConnections();
|
||||
|
||||
// Draw connections
|
||||
ctx.strokeStyle = '#2a4a7f';
|
||||
ctx.lineWidth = GAP - 6;
|
||||
ctx.lineCap = 'round';
|
||||
ctx.globalAlpha = 0.6;
|
||||
ctx.strokeStyle = '#2a4a7f'; ctx.lineWidth = GAP - 6; ctx.lineCap = 'round'; ctx.globalAlpha = 0.6;
|
||||
ctx.beginPath();
|
||||
for (const key of activeConns) {
|
||||
const [ka, kb] = key.split('-');
|
||||
const [ax, ay] = ka.split(',').map(Number);
|
||||
const [bx, by] = kb.split(',').map(Number);
|
||||
const c1 = cellCenter(ax, ay);
|
||||
const c2 = cellCenter(bx, by);
|
||||
const t1 = CELL / (2 * CELL_PITCH);
|
||||
const t2 = 1 - CELL / (2 * CELL_PITCH);
|
||||
const x1 = c1.x + (c2.x - c1.x) * t1;
|
||||
const y1 = c1.y + (c2.y - c1.y) * t1;
|
||||
const x2 = c1.x + (c2.x - c1.x) * t2;
|
||||
const y2 = c1.y + (c2.y - c1.y) * t2;
|
||||
ctx.moveTo(x1, y1);
|
||||
ctx.lineTo(x2, y2);
|
||||
const c1 = cellCenter(ax, ay), c2 = cellCenter(bx, by);
|
||||
const t1 = CELL / (2 * CELL_PITCH), t2 = 1 - t1;
|
||||
ctx.moveTo(c1.x + (c2.x - c1.x) * t1, c1.y + (c2.y - c1.y) * t1);
|
||||
ctx.lineTo(c1.x + (c2.x - c1.x) * t2, c1.y + (c2.y - c1.y) * t2);
|
||||
}
|
||||
ctx.stroke();
|
||||
ctx.globalAlpha = 1;
|
||||
|
||||
// Draw selected path
|
||||
if (selected.length > 1) {
|
||||
drawPath(selected, color, GAP - 2, 0.9);
|
||||
}
|
||||
|
||||
// Draw cells with flash tint
|
||||
ctx.stroke(); ctx.globalAlpha = 1;
|
||||
if (selected.length > 1) drawPath(selected, color, GAP - 2, 0.9);
|
||||
for (let x = 0; x < GRID; x++) {
|
||||
for (let y = 0; y < GRID; y++) {
|
||||
const cx = OFFSET_X + x * CELL_PITCH;
|
||||
const cy = OFFSET_Y + y * CELL_PITCH;
|
||||
const cx = OFFSET_X + x * CELL_PITCH, cy = OFFSET_Y + y * CELL_PITCH;
|
||||
const key = cellKey(x, y);
|
||||
const isSel = selSet.has(key);
|
||||
const isActive = activeCells.has(key);
|
||||
|
||||
ctx.globalAlpha = flashSet.has(key) ? 1 : (isActive ? 1 : 0.08);
|
||||
ctx.fillStyle = flashSet.has(key) ? shadeColor(color, -40) : '#0f3460';
|
||||
ctx.beginPath();
|
||||
ctx.arc(cx + CELL / 2, cy + CELL / 2, CELL / 2, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
|
||||
ctx.beginPath(); ctx.arc(cx + CELL / 2, cy + CELL / 2, CELL / 2, 0, Math.PI * 2); ctx.fill();
|
||||
if (flashSet.has(key)) {
|
||||
ctx.strokeStyle = color;
|
||||
ctx.lineWidth = 4;
|
||||
ctx.beginPath();
|
||||
ctx.arc(cx + CELL / 2, cy + CELL / 2, CELL / 2 + 2, 0, Math.PI * 2);
|
||||
ctx.stroke();
|
||||
ctx.strokeStyle = color; ctx.lineWidth = 4;
|
||||
ctx.beginPath(); ctx.arc(cx + CELL / 2, cy + CELL / 2, CELL / 2 + 2, 0, Math.PI * 2); ctx.stroke();
|
||||
}
|
||||
|
||||
ctx.fillStyle = '#fff';
|
||||
ctx.font = 'bold 30px sans-serif';
|
||||
ctx.fillStyle = '#fff'; ctx.font = 'bold 30px sans-serif';
|
||||
ctx.fillText(board[x][y].toUpperCase(), cx + CELL / 2, cy + CELL / 2);
|
||||
}
|
||||
}
|
||||
ctx.globalAlpha = 1;
|
||||
|
||||
flashTimer = setTimeout(() => {
|
||||
selected = [];
|
||||
draw();
|
||||
}, 500);
|
||||
}
|
||||
|
||||
function shadeColor(color, percent) {
|
||||
let R = parseInt(color.substring(1, 3), 16);
|
||||
let G = parseInt(color.substring(3, 5), 16);
|
||||
let B = parseInt(color.substring(5, 7), 16);
|
||||
R = parseInt(R * (100 + percent) / 100);
|
||||
G = parseInt(G * (100 + percent) / 100);
|
||||
B = parseInt(B * (100 + percent) / 100);
|
||||
R = (R < 255) ? R : 255;
|
||||
G = (G < 255) ? G : 255;
|
||||
B = (B < 255) ? B : 255;
|
||||
R = Math.round(R < 0 ? 0 : R);
|
||||
G = Math.round(G < 0 ? 0 : G);
|
||||
B = Math.round(B < 0 ? 0 : B);
|
||||
return '#' + (R.toString(16).padStart(2, '0')) + (G.toString(16).padStart(2, '0')) + (B.toString(16).padStart(2, '0'));
|
||||
}
|
||||
|
||||
function getWordColor(word) {
|
||||
let hash = 0;
|
||||
for (let i = 0; i < word.length; i++) {
|
||||
hash = word.charCodeAt(i) + ((hash << 5) - hash);
|
||||
}
|
||||
return PALETTE[Math.abs(hash) % PALETTE.length];
|
||||
flashTimer = setTimeout(() => { selected = []; draw(); }, 500);
|
||||
}
|
||||
|
||||
function renderFound() {
|
||||
foundDiv.innerHTML = '<h2>Найдено (' + foundWords.size + ')</h2>';
|
||||
for (const word of foundWords) {
|
||||
const color = getWordColor(word);
|
||||
const def = word_defs[word] || '';
|
||||
const def = wordDefs[word] || '';
|
||||
const isExtra = word in extraWords;
|
||||
const item = document.createElement('div');
|
||||
item.className = 'word-item';
|
||||
item.style.opacity = isExtra ? '0.6' : '1';
|
||||
item.className = 'word-item'; item.style.opacity = isExtra ? '0.6' : '1';
|
||||
item.innerHTML =
|
||||
'<div class="word-item-inner"><span class="word-color" style="background:' + color + '"></span><span class="word-text">' + word + '</span></div>' +
|
||||
(def ? '<span class="word-def">— ' + def + '</span>' : '');
|
||||
@@ -495,159 +413,208 @@
|
||||
}
|
||||
|
||||
function showMessage(text, color) {
|
||||
msgEl.textContent = text;
|
||||
msgEl.style.color = color || '#feca57';
|
||||
msgEl.textContent = text; msgEl.style.color = color || '#feca57';
|
||||
setTimeout(() => { msgEl.textContent = ''; }, 2000);
|
||||
}
|
||||
|
||||
// ===================== Game Logic =====================
|
||||
function checkWord() {
|
||||
if (selected.length < 4) return;
|
||||
|
||||
const word = selected.map(([x, y]) => board[x][y]).join('').toLowerCase();
|
||||
|
||||
// Already found
|
||||
if (foundWords.has(word)) {
|
||||
// Check if it's a prefix of an unfound word
|
||||
const allWords = Object.keys(allSolutions).concat(Object.keys(extraWords));
|
||||
const isPrefixOfUnfound = allWords.some(w => !foundWords.has(w) && w.length > word.length && w.startsWith(word));
|
||||
if (isPrefixOfUnfound) return;
|
||||
showMessage('Уже найдено!', '#feca57');
|
||||
selected = [];
|
||||
draw();
|
||||
return;
|
||||
selected = []; draw(); return;
|
||||
}
|
||||
|
||||
// Valid solution word
|
||||
if (word in allSolutions) {
|
||||
foundWords.add(word);
|
||||
foundPaths[word] = allSolutions[word];
|
||||
flashPath(allSolutions[word], '#2ed573');
|
||||
renderFound();
|
||||
updateStatus();
|
||||
return;
|
||||
renderFound(); updateStatus(); save(); return;
|
||||
}
|
||||
|
||||
// Valid extra word
|
||||
if (word in extraWords) {
|
||||
foundWords.add(word);
|
||||
foundPaths[word] = extraWords[word];
|
||||
flashPath(extraWords[word], '#feca57');
|
||||
renderFound();
|
||||
showMessage('Бонус!', '#feca57');
|
||||
return;
|
||||
renderFound(); showMessage('Бонус!', '#feca57'); save(); return;
|
||||
}
|
||||
|
||||
// Not a valid word, silently ignore (user still building)
|
||||
}
|
||||
|
||||
function validateWord() {
|
||||
if (selected.length === 0) return;
|
||||
|
||||
const word = selected.map(([x, y]) => board[x][y]).join('').toLowerCase();
|
||||
|
||||
// Already found
|
||||
if (foundWords.has(word)) {
|
||||
const allWords = Object.keys(allSolutions).concat(Object.keys(extraWords));
|
||||
const isPrefixOfUnfound = allWords.some(w => !foundWords.has(w) && w.length > word.length && w.startsWith(word));
|
||||
if (isPrefixOfUnfound) return;
|
||||
showMessage('Уже найдено!', '#feca57');
|
||||
selected = [];
|
||||
draw();
|
||||
return;
|
||||
selected = []; draw(); return;
|
||||
}
|
||||
|
||||
// Too short
|
||||
if (selected.length < 4) {
|
||||
showMessage('Мало букв — нужно минимум 4', '#ff6b6b');
|
||||
selected = [];
|
||||
draw();
|
||||
return;
|
||||
}
|
||||
|
||||
// Not found
|
||||
if (!(word in allSolutions) && !(word in extraWords)) {
|
||||
showMessage('Слово не найдено!', '#ff6b6b');
|
||||
selected = [];
|
||||
draw();
|
||||
return;
|
||||
}
|
||||
|
||||
if (selected.length < 4) { showMessage('Мало букв — нужно минимум 4', '#ff6b6b'); selected = []; draw(); return; }
|
||||
if (!(word in allSolutions) && !(word in extraWords)) { showMessage('Слово не найдено!', '#ff6b6b'); selected = []; draw(); return; }
|
||||
showMessage('Верно!', '#2ed573');
|
||||
}
|
||||
|
||||
function isAdjacentAndConnected(a, b) {
|
||||
if (Math.abs(a[0] - b[0]) > 1 || Math.abs(a[1] - b[1]) > 1) return false;
|
||||
if (a[0] === b[0] && a[1] === b[1]) return false;
|
||||
const ka = cellKey(a[0], a[1]), kb = cellKey(b[0], b[1]);
|
||||
const key = ka < kb ? ka + '-' + kb : kb + '-' + ka;
|
||||
return getActiveConnections().has(key);
|
||||
}
|
||||
|
||||
function handleCellClick(mx, my) {
|
||||
const col = Math.floor((mx - OFFSET_X) / CELL_PITCH);
|
||||
const row = Math.floor((my - OFFSET_Y) / CELL_PITCH);
|
||||
|
||||
if (col < 0 || col >= GRID || row < 0 || row >= GRID) return false;
|
||||
|
||||
// Deselect if clicking already selected tile
|
||||
const idx = selected.findIndex(s => s[0] === col && s[1] === row);
|
||||
if (idx >= 0) {
|
||||
selected = selected.slice(0, idx);
|
||||
draw();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check connection
|
||||
if (idx >= 0) { selected = selected.slice(0, idx); draw(); return true; }
|
||||
if (selected.length > 0) {
|
||||
if (!isAdjacentAndConnected(selected[selected.length - 1], [col, row])) return false;
|
||||
} else {
|
||||
if (!getActiveCells().has(cellKey(col, row))) return false;
|
||||
}
|
||||
selected.push([col, row]);
|
||||
|
||||
draw();
|
||||
checkWord();
|
||||
return true;
|
||||
draw(); checkWord(); return true;
|
||||
}
|
||||
|
||||
let _pointerDown = false;
|
||||
// ===================== Timer =====================
|
||||
function startTimer() {
|
||||
if (timerInterval) clearInterval(timerInterval);
|
||||
timerInterval = setInterval(() => {
|
||||
const remaining = Object.keys(allSolutions).filter(w => !foundWords.has(w)).length;
|
||||
if (remaining === 0) {
|
||||
clearInterval(timerInterval); timerInterval = null;
|
||||
gameTimeEl.textContent = formatTime(elapsed);
|
||||
gameCompleteEl.classList.add('show');
|
||||
}
|
||||
}, 500);
|
||||
}
|
||||
|
||||
function resetTimer() {
|
||||
if (timerInterval) clearInterval(timerInterval); timerInterval = null;
|
||||
elapsed = 0;
|
||||
lastSaveTime = Date.now();
|
||||
}
|
||||
|
||||
// ===================== Load Puzzle =====================
|
||||
async function loadPuzzle(number) {
|
||||
statusEl.textContent = 'Генерация...';
|
||||
gameCompleteEl.classList.remove('show');
|
||||
numberSelectorEl.classList.remove('show');
|
||||
resetTimer();
|
||||
|
||||
let data;
|
||||
if (number != null) {
|
||||
const res = await fetch('/api/puzzles/daily?number=' + number);
|
||||
if (res.status === 404) { statusEl.textContent = 'Занграмма не найдена'; return; }
|
||||
data = await res.json();
|
||||
if (data.error) { statusEl.textContent = 'Ошибка: ' + data.error; return; }
|
||||
puzzleNumber = data.number;
|
||||
} else {
|
||||
const res = await fetch('/api/puzzles/daily');
|
||||
data = await res.json();
|
||||
if (data.error) { statusEl.textContent = 'Ошибка: ' + data.error; return; }
|
||||
puzzleNumber = data.number;
|
||||
}
|
||||
|
||||
const raw = localStorage.getItem('puzzle_' + data.number);
|
||||
if (raw) {
|
||||
const parsed = JSON.parse(raw);
|
||||
foundWords = new Set(parsed.foundWords);
|
||||
elapsed = parsed.elapsed || 0;
|
||||
lastSaveTime = Date.now();
|
||||
statusEl.textContent = 'Возобновление...';
|
||||
} else {
|
||||
foundWords = new Set();
|
||||
}
|
||||
|
||||
board = data.board;
|
||||
allSolutions = data.solutions || {};
|
||||
extraWords = data.extra || {};
|
||||
wordDefs = data.word_defs || {};
|
||||
selected = [];
|
||||
initBoard(); draw(); renderFound(); updateStatus();
|
||||
|
||||
if (foundWords.size > 0 && foundWords.size === Object.keys(allSolutions).length) {
|
||||
gameTimeEl.textContent = formatTime(elapsed);
|
||||
gameCompleteEl.classList.add('show');
|
||||
return;
|
||||
}
|
||||
|
||||
startTimer();
|
||||
}
|
||||
|
||||
// ===================== Random Puzzle =====================
|
||||
async function loadRandomPuzzle() {
|
||||
gameCompleteEl.classList.remove('show');
|
||||
statusEl.textContent = 'Генерация...';
|
||||
resetTimer();
|
||||
puzzleNumber = null;
|
||||
const res = await fetch('/api/puzzles/random');
|
||||
const data = await res.json();
|
||||
if (data.error) { statusEl.textContent = 'Ошибка: ' + data.error; return; }
|
||||
foundWords = new Set();
|
||||
board = data.board;
|
||||
allSolutions = data.solutions || {};
|
||||
extraWords = data.extra || {};
|
||||
wordDefs = data.word_defs || {};
|
||||
selected = [];
|
||||
initBoard(); draw(); renderFound(); updateStatus();
|
||||
startTimer();
|
||||
}
|
||||
|
||||
// ===================== Number Selector =====================
|
||||
async function showNumberSelector() {
|
||||
numberGridEl.innerHTML = '';
|
||||
const solved = getSolvedNumbers();
|
||||
try {
|
||||
const res = await fetch('/api/puzzles/daily');
|
||||
const data = await res.json();
|
||||
if (data.error) return;
|
||||
const maxNum = data.number || 0;
|
||||
for (let i = maxNum; i >= 1; i--) {
|
||||
const btn = document.createElement('button');
|
||||
btn.textContent = i;
|
||||
if (solved.includes(i)) btn.classList.add('solved');
|
||||
if (i === puzzleNumber) btn.classList.add('current');
|
||||
btn.addEventListener('click', () => loadPuzzle(i));
|
||||
numberGridEl.appendChild(btn);
|
||||
}
|
||||
} catch (e) {}
|
||||
numberSelectorEl.classList.add('show');
|
||||
}
|
||||
|
||||
// ===================== Copy Result =====================
|
||||
function copyResult() {
|
||||
const text = 'Занграммы #' + puzzleNumber + '\n\ud83c\udf89 Мне потребовалось всего лишь ' + formatTime(elapsed) + '\n\n' + window.location.href;
|
||||
navigator.clipboard.writeText(text).then(
|
||||
() => showMessage('Результат скопирован!', '#2ed573'),
|
||||
() => showMessage('Не удалось скопировать', '#ff6b6b')
|
||||
);
|
||||
}
|
||||
|
||||
// ===================== Events =====================
|
||||
wordDisplay.addEventListener('click', validateWord);
|
||||
$('copyResultBtn').addEventListener('click', copyResult);
|
||||
$('prevPuzzlesBtn').addEventListener('click', showNumberSelector);
|
||||
$('randomPuzzleBtn').addEventListener('click', loadRandomPuzzle);
|
||||
$('closeNumberBtn').addEventListener('click', () => numberSelectorEl.classList.remove('show'));
|
||||
|
||||
canvas.addEventListener('pointerdown', (e) => {
|
||||
e.preventDefault();
|
||||
_pointerDown = true;
|
||||
const r = canvas.getBoundingClientRect();
|
||||
handleCellClick(e.clientX - r.left, e.clientY - r.top);
|
||||
});
|
||||
|
||||
canvas.addEventListener('pointerup', (e) => {
|
||||
_pointerDown = false;
|
||||
});
|
||||
|
||||
canvas.addEventListener('pointerup', () => {});
|
||||
canvas.addEventListener('pointercancel', (e) => {
|
||||
e.preventDefault();
|
||||
_pointerDown = false;
|
||||
selected = [];
|
||||
draw();
|
||||
selected = []; draw();
|
||||
});
|
||||
|
||||
async function loadPuzzle() {
|
||||
statusEl.textContent = 'Генерация...';
|
||||
gameCompleteEl.classList.remove('show');
|
||||
resetTimer();
|
||||
try {
|
||||
const res = await fetch('/api/puzzles/random');
|
||||
const data = await res.json();
|
||||
if (data.error) { statusEl.textContent = 'Ошибка: ' + data.error; return; }
|
||||
board = data.board;
|
||||
allSolutions = data.solutions;
|
||||
extraWords = data.extra || {};
|
||||
word_defs = data.word_defs || {};
|
||||
selected = [];
|
||||
foundWords = new Set();
|
||||
foundPaths = {};
|
||||
initBoard();
|
||||
draw();
|
||||
renderFound();
|
||||
updateStatus();
|
||||
startTimer();
|
||||
} catch (e) {
|
||||
statusEl.textContent = 'Не удалось загрузить головоломку';
|
||||
}
|
||||
}
|
||||
|
||||
wordDisplay.addEventListener('click', validateWord);
|
||||
|
||||
// ===================== Init =====================
|
||||
loadPuzzle();
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
@@ -8,3 +8,9 @@ class PuzzleOutputDTO(BaseModel):
|
||||
solutions: dict[str, list[tuple[int, int]]]
|
||||
extra: dict[str, list[tuple[int, int]]]
|
||||
word_defs: dict[str, str]
|
||||
|
||||
|
||||
class DailyPuzzleDTO(PuzzleOutputDTO):
|
||||
"""Daily puzzles DTO."""
|
||||
|
||||
number: int
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
from fastapi import APIRouter
|
||||
import json
|
||||
from datetime import date, timedelta
|
||||
|
||||
from fastapi import APIRouter, HTTPException
|
||||
from pydantic import PositiveInt
|
||||
from starlette import status
|
||||
|
||||
from zangramru.db.models.puzzle import Puzzle
|
||||
from zangramru.services.puzzles import PuzzleGeneratorDep
|
||||
from zangramru.settings import settings
|
||||
|
||||
from .schema import PuzzleOutputDTO
|
||||
from .schema import DailyPuzzleDTO, PuzzleOutputDTO
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
@@ -10,5 +17,55 @@ router = APIRouter()
|
||||
@router.get("/random")
|
||||
def random_puzzle(generator: PuzzleGeneratorDep) -> PuzzleOutputDTO:
|
||||
"""Generate a random puzzle."""
|
||||
puzzle = generator.generate(target=10, max_attempts=500)
|
||||
puzzle = generator.generate(target=10)
|
||||
return PuzzleOutputDTO.model_validate(puzzle, from_attributes=True)
|
||||
|
||||
|
||||
@router.get("/daily")
|
||||
async def daily_puzzle(
|
||||
generator: PuzzleGeneratorDep,
|
||||
number: PositiveInt | None = None,
|
||||
) -> DailyPuzzleDTO:
|
||||
"""Generate a random puzzle."""
|
||||
# Because they start at one, so we need to subtract one.
|
||||
target_date = date.today()
|
||||
if number is not None:
|
||||
target_date = settings.start_date + timedelta(days=number - 1)
|
||||
|
||||
if target_date > date.today():
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail="Doesn't exist",
|
||||
)
|
||||
|
||||
number = (target_date - settings.start_date).days
|
||||
|
||||
daily_puzzle = await Puzzle.objects().where(Puzzle.number == number).first()
|
||||
|
||||
if daily_puzzle is not None:
|
||||
board = [list(daily_puzzle.board[i * 4 : i * 4 + 4]) for i in range(4)]
|
||||
return DailyPuzzleDTO(
|
||||
number=(date.today() - settings.start_date).days,
|
||||
board=board,
|
||||
solutions=json.loads(daily_puzzle.solutions),
|
||||
extra=json.loads(daily_puzzle.extra),
|
||||
word_defs=json.loads(daily_puzzle.definitions),
|
||||
)
|
||||
puzzle = generator.generate(target=10)
|
||||
compressedboard = "".join("".join(row) for row in puzzle.board)
|
||||
await Puzzle(
|
||||
{
|
||||
Puzzle.board: compressedboard,
|
||||
Puzzle.number: number,
|
||||
Puzzle.solutions: json.dumps(puzzle.solutions),
|
||||
Puzzle.definitions: json.dumps(puzzle.word_defs),
|
||||
Puzzle.extra: json.dumps(puzzle.extra),
|
||||
}
|
||||
).save()
|
||||
return DailyPuzzleDTO(
|
||||
number=number,
|
||||
board=puzzle.board,
|
||||
solutions=puzzle.solutions,
|
||||
extra=puzzle.extra,
|
||||
word_defs=puzzle.word_defs,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user