python
Необычная система счисления в bc
В моём временно любимом bc есть интересная, но не сразу понятная особенность работы с числами. Даже в режиме ввода десятичных чисел принимаются буквы в верхнем регистре, то есть число может состоять из цифр в диапазонах 0…9 и A…Z. Буквы при этом обозначают цифры от десяти до тридцати пяти.
Но так как режим десятичный, результирующее значение числа, содержащего буквы, вычисляется необычно. Я специально не описываю словами, ниже скажу почему. Принцип на картинке, думаю, понятно как всё получается.
Мне стало интересно решить задачу конвертации десятичных чисел в такую необычную систему. Из самого принципа следует, что десятичное число может быть представлено несколькими способами, так что придумать можно куда больше одного алгоритма.
Сегодня на работе, пока обедали с братишкой, пытались в режиме обсуждения решить задачу в уме. Потратили на это почти весь обед, в конце я перенёс то, что придумалось, в код программы:
def convert(num):
if num == 0: return 0
out, orig_num = "", num
while num:
num, r = divmod(num, 10)
v = min(2 if r > 5 else 3, num)
if (digit := v * 10 + r) > 9:
out = chr(digit - 10 + ord('A')) + out
else:
out = str(digit) + out
num -= v
return out if len(out) < len(str(orig_num)) else orig_numА потом мы решили развлечься ещё одним способом — аккуратно сформулировать эту задачу в тексте и решить её искусственным интеллектом. Взяли топовые сети — ЧатГПТ, ДипСик и так далее.
Я намеренно не показываю получившийся промпт, вдруг вы захотите тоже попробовать, но скажу сразу — с первого или даже пятого раза сформулировать задачу так, чтобы хоть
Из этого можно сделать важный
А если посмотреть чуть глубже, то можно додуматься вот до чего. В ближайшее время искусственный интеллект не убьёт профессию программиста, а просто её модифицирует. Сейчас программисты описывают задачу, переведённую ими в алгоритм, на языке программирования, а в будущем буду описывать её на натуральных языках.
Возвращение плагина PogodaStatusBar
У меня есть традиция — время от времени чинить мой старенький и порядком уже поднадоевший мне плагин для редактора «Саблайм 3». Плагин называется PogodaStatusBar, потому что он
Эпоха бесплатных сервисов кончилась и «Яндекс» постепенно стал закрывал все те ходы, которыми я пользовался, чтобы получать эти данные. Я искал новые,
Всё нормально работало,
После новогоднего отдыха появились время и силы и я решил их часть израсходовать на плагин.
Надо сказать, что я не знаю как правильно отлаживать плагины в «Саблайме». В документации ничего не нашёл, поэтому написал небольшую обвязку и запускаю свой плагин просто из командной строки. Но в этот раз этот способ не сработал — в обвязке плагин работал, а внутри «Сайблайма» — нет.
Я уже с таким сталкивался. У «Саблайма» внутри две версии «Пайтона» — 3.3 и 3.8. Обе,
Таким образом между «Пайтоном» у меня в командной строке и внутри «Сайблайма» — десять версий. Иногда я использую в коде
И вот непонятно как об этом узнавать. Можно, думаю, раздобыть старенький «Пайтон» в контейнере, но лень.
Обычно я просто пристально смотрю на код, пока не понимаю как его исправить. А в этот раз так не вышло. Мне несколько раз казалось, что я понимаю в чём дело, я коммитил новый код, собирал релиз, дожидался, пока тулчейн репозитория плагинов «Саблайма» увидит новую версию, обновлялся и не получал положительного результата.
В итоге, мне это надоело. Я нашёл в какой папке «Саблайм» держит плагины, они там лежат, к слову, в архивированном виде, и попытался подсунуть туда свой код — паковал папку с модифицированным кодом и заменял файл плагина. Но гадкий «Саблайм»
С этим я опять поленился разбираться, вместо этого попытался отредактировать код прямо в архиве через консольный файловый менеджер mc. Неожиданно это сработало. Так я узнал, что ошибка была в том, что я использую вызов html.unescape, который появился только в «Пайтоне» 3.4. Пришлось заменить его на вполне устроивший меня в этом месте replace('"', '"') и всё заработало.
«Киберслав»
Вчера вышла первая серия отечественного сериала «Киберслав». Я выхода первой серии ждал несколько лет, с тех пор как впервые увидел тизер. Очень боялся, что результат окажется очень слабым,
Но обошлось, смотрится отлично.
В заставке серии, кстати, используется идея,
Заодно посмотрел как модуль curses в «Пайтоне» позволяет облегчить работу в консоли. Много про него слышал, но не доводилось попробовать.
Замена цифр
Придумал тут штуку интересную. Как у я уже писал ранее, полюбилось мне
Сначала я сделал достаточно просто, — отредактировал раскладку, которой я пользуюсь. Мне не нравилось это решение, так как пришлось выкинуть из неё
А сегодня мне пришло в голову решение лучше — попробовать обойтись функцией «Замены текста», которая встроена в «МакОСь». Мысль простая — заменять двоеточие и две цифры на то же самое, но без двоеточия и в верхнем индексе. Сначала я пытался набрать всё нужное руками, а потом случайно нашёл функцию импорта.
Формат для импорта оказался довольно простым. После того как я в нём разобрался, накидал небольшую программу на «Пайтоне», которая мне за мгновение сформировала нужный файл.
print("""
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array>""")
trans = str.maketrans("0123456789", "⁰¹²³⁴⁵⁶⁷⁸⁹")
for i in range(0, 60):
print(f"""
<dict>
<key>phrase</key>
<string>{f"{i:02d}".translate(trans)}</string>
<key>shortcut</key>
<string>:{i:02d}</string>
</dict>""")
print("</array></plist>")Чтобы его импортировать, нужно перейти в «Системные настройки…», оттуда в «Клавитуру», там нажать на кнопку «Замены текста…» и перетащить на открывшийся список получившийся файл.
После этого можно проверить что получилось, — если написать в любом месте «13:00», оно должно само преобразоваться в «13⁰⁰».
И опять чинил PogodaStatusBar
Прям заметно, что эпоха открытого веба закончилась. Было время вокруг были открытые сервисы, используй сколько влезет. Потом всё
В общем, прошла неделя и мне снова прикрыли лавочку — урл «Гисметео», который я использовал, чтобы определять айди населённого пункта по названию вдруг меня забанил. На любой запрос выдаётся «доступ запрещён». Да что ж такое!
Полез я снова смотреть погодный плагин, смотреть как сделано там. Он же
Координаты у меня уже есть, я их могу забрать у «Яндекса», надо только распарсить:
@functools.cache
def _getRegionData(self):
try:
url = "https://yandex.ru/tune/geo/"
content = urllib.request.urlopen(url).read().decode('utf-8')
region_data = re.search(r'data-bem="([^"]+coords[^"]+)"', content).group(1)
parsed_region_data = json.loads(html.unescape(region_data))
# {'id': xx, 'region': 'XXXXX', 'coords': ['XX.XXXXX', 'XX.XXXXX'], 'accuracy': 'XXXXXX'}
return parsed_region_data['checkbox']['auto']
except (IOError, AttributeError):
return NoneВ итоге, получилась такая схема: в «Яндексе» получаем координаты и айди населённого пункта у «Яндекса», по этому айди получаем информацию по пробкам. Далее по координатам получаем айди населённого пункта у «Гисметео», по которому получаем погоду.
Опять чинил PogodaStatusBar
Сегодня участвовал в довольно скучной видеоконференции. Моё участие там было хоть и необходимое, но небольшое. А чтобы не одуреть от безделья, пока я слушал всю эту скуку, решил
Плагин в строке статуса показывает текущую погоду и пробки в вашем городе. Много лет данные для этого я брал с неофициального урла «Яндекса», но компания решила коммерциализировать погоду и, сколько я не искал новый способ получить её бесплатно, так и не нашёл.
Пробки, кстати, тоже перестали нормально работать.
Я перебрал несколько малоизвестных сервисов, пока, наконец, не увидел, что страница yandex.ru/tune/geo/ содержит в себе необходимый номер. Этого хватило, чтобы починить показ пробок.
С «Гисметео» пришлось повозиться. Не нашёл официальную информацию
Определить номер города в формате «Гисметео» помогает сервис www.gismeteo.ru/rmq/search/{название}/1/, куда я подставляю название, полученное от «Яндекс.Пробок» — там он возвращается вместе с остальными данными.
Оставалось только расшифровать иконку погоды. В документации есть часть описания (остаток можно понять, скачав с «Гисметео» значки погоды), выглядит всё несложно. Например, d.r3 означает «день» (day) и «дождь максимальной интенсивности» (rain 3).
Поскольку у меня Юникод, в нём есть не все необходимые значки, я сделал вот такой объект, содержащий признаки, которые позволяют мне выбрать какую иконку показать:
_icons = {
"🌞": {"d"}, # day
"🌙": {"n"}, # nite
"☁️": {"n", "c"}, # night, cloud
"🌧": {"rs", "c", "r"}, # rain+snow, cloud, rain
"🌤": {"d", "c"}, # day, cloud
"🌦": {"d", "r"}, # day, rain
"🌩️": {"c", "st"}, # #day, storm
"⛈️": {"c", "st", "r"}, # cloud, storm, rain
"🌨": {"c", "s"}, # cloud, storm
"💨": {"mist"}, # mist
"⚡️": {"st"}, # storm
}И вот такой простой алгоритм для выбора иконки:
def _getStatus(self, coded_weather):
codes = {x.strip("0123456789") for x in coded_weather.split(".")}
max_icon = None
max_score = 0
for icon, code in self._icons.items():
result = codes & code
score = sum(len(x) for x in result)
if score > max_score:
max_icon, max_score = icon, score
return max_iconИдея простая — чем больше значков совпало, тем лучше; если совпал значок с более длинным названием (st, mist), считаем его более конкретным и важным.
Графики в стиле xkcd
xkcd — культовая серия
У xkcd очень узнаваемый стиль рисовки и, когда я их вдруг встречаю, они
Вот код:
import matplotlib.pyplot as plt
import numpy as np
t = np.linspace(0, 2*np.pi, 1000)
x = 16 * np.sin(t)**3
y = 13 * np.cos(t) - 5 * np.cos(2*t) - 2 * np.cos(3*t) - np.cos(4*t)
plt.xkcd()
plt.figure(figsize=(8, 6))
plt.plot(x, y, color='b')
plt.title('cos(…) = ?')
plt.show()А вот результат:
Шутка, которая не работает
Тут в чате бывших коллег, где мы постим мемы, пробежала картинка, которая больше повеселила меня не смыслом, который в неё вкладывал автор, а тем, что на системе, под которую написан код на ней (Виндоуз, очевидно), она не выполнится.
Проблема тут в том, что вызов os.remove умеет удалять только файл, тогда как System32 — папка, знакомая многим пользователям Виндоуз. Я не уверен точно, но думаю, что при её удалении система будет сопротивляться. Она, вроде,
Возможно, кстати, код и не предполагалось делать рабочим, а шутка немного тоньше — ведь вызов os.remove можно прочитать как «удалить операционную систему», не знаю, я в любом случае хотел рассказать не об этом.
Дело в том, что шутка написана под ОС, под которой она работать не будет, но смешно то, что под ОС, на которую она рассчитана не была, она вполне может заработать.
В Линуксе или МакОСи надо в любом месте, где будет запускаться эта программа, создать папку C:, в ней — папку Windows, а в ней — файл System32, который и удалится, если выпадет искомое число на рандомайзере.
Анекдот на Пайтоне
У меня есть друг, которому я регулярно шлю шутки про «Вархаммер». Сам в этой теме не разбираюсь, но хочется думать, что его они веселят. А я — тот самый друг, которому шлют то же, но на тему программирования. Пару раз даже присылали мои собственные шутеечки.
Вчера прислали известный неприличный анекдот про Василия Ивановича и Петьку, но написанный на «Пайтоне». И хотя у меня довольно пуританский блог, анекдот так вырвиглазно написан, что пришлось его переписать.
Вот что мне прислали:
class Chapaev:
nyuans = True
def fuck(Class):
Class.nyuans = True
Class.ass.append('Dick')
class Petyka:
nyuans = False
ass = []
if Chapaev.nyuans == True and Petyka.nyuans == False:
Chapaev.fuck(Petyka)Как по мне, плохо написано примерно всё, мне очень не понравилось, так что держите, вот вам моя версия, которая, кстати, как мне кажется, более точно отражает суть анекдота:
Chapaev = []
Petka = []
dick = [20, Chapaev]
Petka.insert(*dick)
isNuance = Chapaev in Petka and Petka not in Chapaev
print(isNuance) // TrueНу и пока у меня ещё был запал, переписал на ПХП известнейший мем из фильма «ДМБ»:
class Gopher implements Countable
{
public function count(): int
{
return 0;
}
}
$gopher = new Gopher;
var_dump(count($gopher)); // 0
var_dump(empty($gopher)); // falseПочинил PogodaStatusBar
Обратил внимание, что мой
Пришлось исправить две вещи —
Остался ещё один баг — если «Яндекс» не отдаёт информацию о пробках (в некоторых небольших городах такой информации нет), то плагин работать не будет. Не знаю, стоит ли это править,
InlineC
Продолжая тему интерфейсов к языку Си, кстати будет упомянуть появившийся недавно модуль inlinec для Пайтона. Он позволяет вставлять в программу на Пайтоне
# coding: inlinec
from inlinec import inlinec
@inlinec
def Q_rsqrt(number):
float Q_rsqrt( float number )
{
long i;
float x2, y;
const float threehalfs = 1.5F;
x2 = number * 0.5F;
y = number;
i = * ( long * ) &y;
i = 0x5f3759df - ( i >> 1 );
y = * ( float * ) &i;
y = y * ( threehalfs - ( x2 * y * y ) );
return y;
}
print(Q_rsqrt(1.234))Я проверил, это действительно работает. Тут вычисляется так называемый быстрый обратный квадратный корень от числа 1,234.
Пока этот модуль скорее прототип — скорость оставляет желать лучшего, в рабочем каталоге создаётся куча мусорных временных файлов, любое отступление от эталонного примера грозит выводом ошибки, которая совсем не помогает понять что не так.
Куда интереснее разобраться как это всё работает. Декоратор @inlinec тут ничего не делает. Судя по коду модуля, он возвращает функцию как есть и служит маркером, что ниже пойдёт сишная функция. Всё работу выполняет кодек, который подключается первой строкой.
Приём не новый, несколько лет назад я про него уже рассказывал — в Пайтоне в специальном магическом комментарии можно указать кодек, который пропускает через себя текст программы. Обычно он используется для программирования в кодировках, отличных
Итак, код перед выполнением скармливается специальному кодеку inlinec, который разбирает программу, находит в ней
PythonFuck: разбор
Как я писал в конце прошлого года, есть такое развлечение — не используя
Получилась такая программа, работающая только из консоли интерпретатора и только под вторым «Пайтоном»:
_=(''<())+(''<());__=_**_**_
___='%'+('%'+`'±'`[_])%(__-_-_)
___*(_*_*_-_)%((
(__+_)*_*_,
`{_}`[_/_],
)+(`(''<'')`[_],)*_+\
(
__*_*_*_-__-_/_,
__*_+_/_,
))Пришло время разобрать как она работает. Я собирался сделать написать разбор через неделю после её написания, но заботы конца года не позволили.
С самого начала было очевидно, что в указанных ограничениях Пайтон не позволит вызвать
module, method = "__builtin__", "print"
vars(vars()[module])[method]("Hello")Есть варианты, но без использования букв — никак.
Так как в силу вышеизложенного функцию печати не вызовешь, пришлось довольствоваться выражением в консоли интерпретатора — там результат выводится на экран автоматически. В остальном, как будет видно ниже, удалось обойтись теми конструкциями, которые есть в языке.
Посмотрим в код. Первая строка:
_=(''<())+(''<());__=_**_**_Тут два разных выражения, разделённых точкой с запятой. В первом в скобках я дважды сравниваю строку и кортеж, получая два True. Второй Пайтон позволяет сравнивать разные встроенные типы, возвращая результат сравнения их названий, записанных как строки. Так как строка str меньше tuple, то результат — истина.
Два True в арифметической сумме дают двойку, неявно преобразовываясь к числу в этой операции. В принципе тут можно использовать унарный минус и тильду, но тогда мне это в голову не пришло:
_=-~(''<()) # число «2» можно получить и так тожеРезультат мы кладём в переменную с именем «подчёркивание». В той же строке мы получаем «16» возводя два в степень два в степени два, результат помещается в переменную «два подчёркивания».
Вторая строка:
___='%'+('%'+`'±'`[_])%(__-_-_)Тут используется символ «±», он
Этот символ вставлен внутрь конструкции «обратный апостроф», которая является во втором Пайтоне эквивалентом repr — функции, возвращающей строковое представление объекта, в данном случае это будет «'\\xc2\\xb1'». Нам отсюда нужен второй символ (нумерация с нуля) — «x». Цифра два для индекса у нас уже есть — в переменной _.
Дальше используется оператор «процент» — форматированный вывод. Полученное «x» используется как шаблон для «процента», чтобы преобразовать число в шестнадцатеричный вид. Из выражения __-_-_ (16−2−2) получаем «12» или, после преобразования, «c».
Вообще можно было обойтись без этого шага, получив эту же букву из строкового представления «±» («'\\xc2\\xb1'»), но в процессе продумывания я себе выписал ряд трюков и мне хотелось использовать их все.
В итоге, в переменную «три подчёркивания» попадает строка «%с», её мы будем использовать для оператора форматированного вывода («%»), чтобы получать символ по его коду.
Дальше символы получаются следующим образом:
(__+_)*_*_ # (16+2)*2*2 = 72, код символа «H», через шаблон «%c» получим отсюда букву
`{_}`[_/_] # первая часть даёт строку «set([2])», отсюда берём символ «e»
`(''<'')`[_]*_ # получаем строку «False», оттуда символ «l», удваиваем его умножением на два
__*_*_*_-__-_/_ # 16*2*2*2-16-2/2 = 111, код символа «о»
__*_+_/_ # 16*2+2/2 = 33, код символа «!»Не требующее преобразования оставляем как есть, а из кодов символы получаем шаблоном «%с». В результате складывается строка «Hello!».
Второй, а не третий Пайтон нужен, в основном,
PythonFuck ★
Давайте вспомним, что у меня блог ещё и про программирование.
Есть такое развлечение — не используя
Для некоторых языков такого ещё никто не делал, приходится изобретать собственные приёмы, в конечном счете это интереснее всего. Я уже делал PHPFuck, BashFuck (и даже не один раз) и совмещал JavaScriptFuck с языком программирования Brainfuck.
Как правило ещё стараются использовать как можно меньше различных символов, но я этим не заморачиваюсь, мне гораздо интереснее соблюсти запрет на буквы и цифры.
Долго мне казалось, что с Пайтоном ничего такого не сделать и я даже пытался, но не получилось. А вчера, пока делал для студентов
_=(''<())+(''<());__=_**_**_
___='%'+('%'+`'±'`[_])%(__-_-_)
___*(_*_*_-_)%((
(__+_)*_*_,
`{_}`[_/_],
)+(`(''<'')`[_],)*_+\
(
__*_*_*_-__-_/_,
__*_+_/_,
))Это запускается и работает (выводит строку «Hello!»), но только из командной строки и только во второй версии Пайтона. Когда напишу небольшой разбор кода, станет понятным почему.
Reduce
Мы с коллегами сейчас проходим курс по машинному обучению, организованный для нас университетом Иннополиса. Курс рассчитан на два месяца, к настоящему моменту мы бегло пробежались по высшей математике и начали изучать Пайтон — один из языков, популярных в машинном обучении.
По Пайтону соскучился — он мне нравится, а я всерьёз не программировал на нём несколько лет. С удовольствием смотрю что наворотили в третьей версии, которую я почти не трогал. Бо́льшая часть языка легко и почти сразу вспоминается, но долгое отсутствие практики всё же сказывается.
Решали сегодня задачки из «Проекта Эйлер», в частности
from functools import reduce
def read():
with open('p067_triangle.txt') as f:
for line in f.readlines()[::-1]:
yield tuple(int(x) for x in line.strip().split(' '))
reduce(lambda cur, prv: [max(cur[pos:pos+2])+v for pos, v in enumerate(prv)], read())Пока решали, преподаватель упомянул, что задачу можно решить через фолдинг. Я загорелся идеей — настолько не умею обращаться с фолдингом, что ни разу не сумел его
Результат мозговых усилий выше. Код сократился до одной строки (функция над ней — просто чтение данных).
Наверное хорошо бы порешать подобные задачи — которые гарантированно изящно решаются через фолдинг, чтобы плотнее уложить концепцию на извилины, но не знаю где такие задачки можно было бы взять. Впрочем есть и другой путь — начать
На закуску вот вам фолдинг на «Баше», взятый из комментария со «Стека Оверфлоу»:
foldl() {
echo $(($(</dev/stdin)$2))
} < <(tr '\n' "$1" <$3)
# Sum 20 random ints from 0-999
foldl + 0 <(while ((n=RANDOM%999,x++<20)); do echo $n; done)Тут суммируются двадцать псевдослучайных чисел из диапазона 0—999.
Как сконвертировать bytea
Пока сегодня ехал домой с военного поиска (я в таком уже участвовал в прошлом году), написала в «телеграм» дипломница — она не смогла разобраться как сконвертировать в буквы формат постгреса bytea, в котором мы ей выгрузили
Отдельно про поездку рассказывать не буду, я вообще подумал, что пора завязывать с публикациями на такие темы, а пока ехал, накидал на коленке функцию на Пайтоне, положу сюда, чтобы не потерялась:
def decodeBytea(bytes: bytearray, charset: str) -> str:
if bytes[:2] == b'\\x':
return bytearray.fromhex(bytes[2:].decode()).decode(charset)
else:
raise ValueError('Invalid format')Формат немудрёный — впереди
Погодный плагин для «Sublime Text» ★
Написал свой первый плагин для «Саблайма» — для отображения в строке состояния погоды и пробок «Яндекса». Заодно немного повспоминал «Пайтон», давно на нём ничего не писал.
Удивительно, но факт — другого работоспособного плагина на эту тему не обнаружилось. Единственный конкурент использует старое АПИ «Яху», которое уже не работает, потому не работает и плагин.
Отдельное спасибо «Яндексу» за то, что их АПИ умеет определять текущее местоположение — ничего задавать в конфиге не надо, удобно.
Поскольку в строке состояния можно выводить только буквы, воспользовался Юникодом для вывода погодных значков, для уровня пробок не нашлось ничего лучше фруктов, так что индикатором загруженности дорог у меня служат зелёное яблоко, жёлтый лимон и красный помидор. Не знаю будут ли видны эти символы пользователям Линукса или Виндоуза, мне негде посмотреть.
Пришлось повозиться с АПИ самого «Саблайма».
В настройках есть шаблон вывода, можно убрать пробки или погоду, если они не нужны.
Подал пул реквест на включение в саблаймовский пакетный менеджер, но особо упорствовать не буду, если откажут.
«Кремниевая долина»
Пока отхожу от операции, смотрю сериал «Кремниевая долина» и дабы не заржавел мозг, сделал расшифровку надписи на футболке Эрлиха — одного из героев сериала, на трёх языках: Перле, Пайтоне и Тикле. Листинг один для трёх языков:
#\
"@{[$\=qq{\n},\
print map {chr $_} (0b1000010, 0b1101001, 0b1110100, 0b1100011, 0b1101111, 0b1101001, 0b1101110)]}";#\
__END__ = 1;\
print(''.join(chr(b) for b in (0b1000010, 0b1101001, 0b1110100, 0b1100011, 0b1101111, 0b1101001, 0b1101110))); #\
"""
foreach name {01000010 01101001 01110100 01100011 01101111 01101001 01101110} {
puts -nonewline [binary format B* $name]
}
puts {} ;#"""Дольше всего с Перлом возился, пока не вспомнил, что у него есть вычисление выражений внутри строк через конструкцию @{[…]}. Нужно рассказать как всё работает?
Массив с конца: ~n
Чудесное нашлось в комментариях на «Хабре»: логичный, на мой взгляд, способ получать значения с конца массива. Способ, вообще говоря, для «Пайтона», но и для «ПХП» можно применить.
В «Пайтоне» есть такая проблема, даже не то чтобы проблема, скорее мелкое неудобство, что списки, если их считать с начала, нумеруются с нуля, а если с конца — с минус единицы:
>>> print([1,2,3][0], [3,2,1][-1])
(1, 1)Лично я к этому так привык, что в нелогичность такого поведения сразу и не вник. Неудобство становится более очевидным, если от фиксированных значений перейти к переменным:
>>> i=2
>>> print([1,2,3,4][i], [4,3,2,1][-i-1])
(3, 3)Чтобы брать значения с конца, везде, как приклееную, приходится таскать эту дурацкую минус единицу. Но есть способ лучше, более того, я им иногда пользовался,
>>> i=2
>>> print([1,2,3,4][i], [4,3,2,1][~i])
(3, 3)
>>> print([1,2,3][0], [3,2,1][~0])
(1, 1)Для тех, кто не понимает смысла операции «тильда» можно объяснить, что без тильды значения берутся с начала, с тильдой — с конца. Здо́рово!
Обычно в таких случаях возражают, что новички будут путаться. Это
«Словохват»
Вчера подсел на игру «Словохват», вроде игра незамысловатая, но очень интересная.

Смысл — занять одну из клеток противника, помеченного «звёздочкой», в терминах игры это называется «столица». Чтобы занять клетку, нужно придумать слово с буквой, которая написана на этой клетке, причём нужно уложиться в отведённое время — сверху тикает таймер.
Клетку можно использовать, только если она примыкает к клетке вашего цвета. Клетки чужого цвета захватываются по тому же правилу, но в первый раз они становятся серыми и только в следующий — вашего цвета.
На медиане поля действуют ещё
У автора получилась неплохая такая тактическая игра. Мне играть было скучновато — очень лень выдумывать слова, поэтому я написал небольшую программу на Пайтоне, которая работает со словарём под редакцией профессора Лопатина, ей нужно задать файл словаря и буквы, которые у вас есть, она придумает слово:

Работает неспешно, я оптимизировать не стал, времени, даваемого игрой, на поиск вполне хватает (по крайней мере на моём ноуте). Если
У меня на каждом запуске словарь преобразуется заново. Естественно, в словаре, помимо разрешённых частей речи, есть прилагательные, глаголы и так далее — их я не отфильтровываю, в словаре нет для этого информации.
# coding: utf-8
import itertools
import sys
import codecs
# дружим с консолью
sys.stdin = codecs.getreader('utf-8')(sys.stdin)
sys.stdout = codecs.getwriter('utf-8')(sys.stdout)
# строки с пропусками любых букв в любом количестве
def combinations(str):
for l in xrange(2, len(str)+1):
yield itertools.combinations(str, l)
# собираем каждую в строку
def iterstr(str):
for s in itertools.chain(*combinations(str)):
yield u''.join(s)
# все наши комбинации
def uniqcombinations(str):
return set(iterstr(sorted(str)))
# проходим по словарю
def iterdict(name, min, max):
with open(name, 'r') as f:
for line in f:
line = line.strip().decode('cp1251')
# текущее слово должно содержать только буквы и быть не больше искомого слова
if max >= len(line) >= min and line.isalpha():
yield u''.join(sorted(line)), line
# ищем наше слово
def find(word, dictname):
words = uniqcombinations(word)
for line, original in iterdict(dictname, 3, len(word)):
if line in words: print(original)
# запуск программы и небольшая помощь
try:
find(sys.argv[2].decode('utf-8'), sys.argv[1].decode('utf-8'))
except IndexError:
print(u'Запуск: {0} <словарь> <буквы в наличии>'.format(sys.argv[0]))Писал именно на Пайтоне
Если вы думаете, что выиграть можно бездумно подставляя слова из моей программы, то сильно ошибаетесь — на сайте попадаются противники, которые вас с таким подходом разнесут в пух и прах.
30 банковских дней
Делал жене программу, чтобы отсчитывать от введёной даты 30 банковских дней в текущем году, может пригодится кому (в запускаемый файл преобразовал при помощи PyInstaller, получается один файл, очень удобно). При первом запуске программа скачивает календарь с сайта Calend.Ru и сохраняет рядом, потом берёт из него выходные и праздничные дни.
# coding: utf-8
import re
import httplib
import pickle
import ctypes
from datetime import date, datetime, timedelta
MB_OKCANCEL = 1
MB_SYSTEMMODAL = 4096
IDOK = 1
IDCANCEL = 2
def getCalend():
h = httplib.HTTPConnection('www.calend.ru')
h.request('GET', '/work/')
return h.getresponse().read()
def getHolidays():
table = re.findall(r'<table\s.+?time_of_death(.+)</table>', getCalend(), re.DOTALL)[0]
return re.findall(r'<td\s+class="\S+\s+col5"\s+day="(\d+)"\s+month="(\d+)"', table, re.DOTALL)
def readHolidays():
year = str(date.today().year)
try:
with open(year + '.cache', 'r') as f:
holidays = pickle.load(f)
except IOError:
with open(year + '.cache', 'w') as f:
holidays = tuple(getHolidays())
pickle.dump(holidays, f)
return [datetime(day=int(d[0]), month=int(d[1]), year=int(year)) for d in holidays]
def getStartDate():
while 1:
input = re.split(r'\D', raw_input("Enter start date (dd.mm): "))
try:
input = [int(x) for x in input]
if len(input) == 2:
break
except ValueError:
pass
return (date.today().year, input[1], input[0])
delta = timedelta(days = 1)
holidays = readHolidays()
msgbox = ctypes.windll.user32.MessageBoxW
while 1:
try:
date = datetime(*getStartDate())
for i in xrange(0, 30):
while 1:
date += delta
if date not in holidays: break
if msgbox(
0,
u'Получилась следующая дата: %02d.%02d.%04d' % (date.day, date.month, date.year),
u'Ответ',
MB_OKCANCEL | MB_SYSTEMMODAL
) == IDCANCEL:
raise StopIteration
except (KeyboardInterrupt, StopIteration):
breakПрограмму написал быстро, а сложнее всего было её отправить — ГМэйл упорно не принимает запускаемые файлы, даже в архивах.