added support for daily puzzles.
/ docker_build (push) Successful in 5m42s
/ helm_deploy (push) Successful in 49s
Testing zangramru / lint (push) Successful in 33s
Testing zangramru / pytest (push) Failing after 22s

Signed-off-by: Pavel Kirilin <s3riussan@gmail.com>
This commit is contained in:
2026-07-01 20:38:15 +02:00
parent f1d2b0f6c8
commit 12b0eb08b4
9 changed files with 17689 additions and 17838 deletions
+1
View File
@@ -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
+5 -3
View File
@@ -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
View File
@@ -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.
+17 -10
View File
@@ -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),
@@ -263,20 +268,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 +310,6 @@ class PuzzleGenerator:
word_defs=word_defs,
)
return None
def setup_generator(app: FastAPI) -> None:
"""Create puzzle-generator."""
@@ -319,7 +326,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:
+4
View File
@@ -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:
"""
+310 -353
View File
@@ -48,9 +48,7 @@
border-radius: 8px;
transition: background 0.2s;
}
#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 +63,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 +74,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 +87,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 +169,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 +202,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 +226,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 +345,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 +403,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>
+6
View File
@@ -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
+60 -3
View File
@@ -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,
)