[TOC] --------------------------------------------------------------------------------------------------- # Числовая угадайка Описание проекта: программа генерирует случайное число в диапазоне от 1 до N и просит пользователя угадать это число. Если догадка пользователя больше случайного числа, то программа должна вывести сообщение 'Слишком много, попробуйте еще раз'. Если догадка меньше случайного числа, то программа должна вывести сообщение 'Слишком мало, попробуйте еще раз'. Если пользователь угадывает число, то программа должна поздравить его и вывести сообщение 'Вы угадали, поздравляем!'. ````code from random import randint def to_number(s, n_max=0): if not s.isdigit(): return 0 n = int(s) if n_max == 0 or n <= n_max: return n return 0 def play(n): d = randint(1, n) print(f'Задумано целое число от 1 до {n}. Угадывайте...') count = 0 while True: s = input("Введите ваше предположение: ") i = to_number(s, n) if i == 0: print(f'А может быть все-таки введете целое число от 1 до {n}?') continue count += 1 if i > d: print('Ваше число больше загаданного, попробуйте еще разок') elif i < d: print('Ваше число меньше загаданного, попробуйте еще разок') else: print('Вы угадали, поздравляем!') print(f'Количество попыток: {count}') break another_game = False print('Добро пожаловать в числовую угадайку') while True: if another_game: print() print('Играем ещё раз?') s = input("Введите целое число больше нуля\n(или что-то иное для завершения): ") n = to_number(s) if n > 0: play(n) else: break another_game = True print('Спасибо, что играли в числовую угадайку. Еще увидимся...') ```` В целях инкапсуляции создаем служебную функцию `to_number`, которая преобразует строку в число большее нуля, либо ноль, если введено что-то отличное от цифр. Также эта функция может проверять верхнюю границу. Пример работы программы: ````shell >python guessing_game.py Добро пожаловать в числовую угадайку Введите целое число больше нуля (или что-то иное для завершения): 7 Задумано целое число от 1 до 7. Угадывайте... Введите ваше предположение: 8 А может быть все-таки введете целое число от 1 до 7? Введите ваше предположение: 3 Ваше число больше загаданного, попробуйте еще разок Введите ваше предположение: 2 Ваше число больше загаданного, попробуйте еще разок Введите ваше предположение: 1 Вы угадали, поздравляем! Количество попыток: 3 Играем ещё раз? Введите целое число больше нуля (или что-то иное для завершения): Спасибо, что играли в числовую угадайку. Еще увидимся... ```` Стратегия данной игры обсуждается [здесь]( #guessing_game_strategy). ---------------------------------------------------------------------------------------------------- # Магический шар Описание проекта: магический шар (шар судьбы) — шуточный способ предсказывать будущее. Программа должна просить пользователя задать некий вопрос, чтобы случайным образом на него ответить. ````code from random import randint answers = ['Бесспорно.', 'Мне кажется - да.', 'Пока неясно.', 'Попробуй снова.', 'Даже не думай !', 'Предрешено.', 'Вероятнее всего.', 'Спроси позже.', 'Мой ответ - нет.', 'Никаких сомнений.', 'Хорошие перспективы.', 'Лучше не рассказывать.', 'По моим данным - нет.', 'Определённо да.', 'Знаки говорят - да.', 'Сейчас нельзя предсказать.', 'Перспективы не очень хорошие.', 'Можешь быть уверен в этом', 'Да.', 'Сконцентрируйся и спроси опять.', 'Весьма сомнительно.'] def magic_ball(): s = input('Твой вопрос: ') print(answers[randint(0, 19)]) print('Привет Мир, я магический шар, и я знаю ответ на любой вопрос.') name = input('Как тебя зовут?: ') print('Привет,', name) while True: magic_ball() yes_no = input('Ты хочешь задать вопрос еще раз? ["+" - да, "-" - нет]: ') if yes_no == '+': continue elif yes_no == '-': print('Возвращайся если возникнут вопросы!') break ```` ````shell >python magic_ball.py Привет Мир, я магический шар, и я знаю ответ на любой вопрос. Как тебя зовут?: Феофан Привет, Феофан Твой вопрос: Есть ли жизнь на Марсе? Попробуй снова. Ты хочешь задать вопрос еще раз? ["+" - да, "-" - нет]: - Возвращайся если возникнут вопросы! ```` ---------------------------------------------------------------------------------------------------- # Генератор безопасных паролей Описание проекта: программа генерирует заданное количество паролей и включает в себя настройку на длину пароля, а также на то, какие символы требуется в него включить, а какие исключить. ````code from random import randint, shuffle digits = '0123456789' lowercase_letters = 'abcdefghijklmnopqrstuvwxyz' uppercase_letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' punctuation = '!#$%&*+-=?@^_.' ambiguous = 'il1Lo0O' def input_true_false(prompt): while True: answer = input(prompt).strip().lower() if answer == 'да': return True if answer == 'нет': return False else: print('Надо ввести: да или нет.') def generate_password(length, chars_list): if length < 1: raise Exception ('Длина пароля < 1.') # Выброс исключения if len(chars_list) < 1: raise Exception ('Количество типов символов < 1.') # Выброс исключения if len(chars_list) > length: raise Exception ('Количество типов символов > длины пароля.') # Выброс исключения password = [] for chars in chars_list: password.append(chars[randint(0, len(chars) - 1)]) for _ in range(length - len(chars_list)): chars = chars_list[randint(0, len(chars_list) - 1)] char = chars[randint(0, len(chars) - 1)] password.append(char) shuffle(password) return ''.join(password) chars_list = [] num = int(input('Сколько паролей нужно? ')) length = int(input('Какая длина одного пароля? ')) if input_true_false(f'Включать цифры ({digits})? [да/нет]: '): chars_list.append(set(digits)) if input_true_false(f'Включать прописные буквы ({uppercase_letters})? [да/нет]: '): chars_list.append(set(uppercase_letters)) if input_true_false(f'Включать строчные буквы ({lowercase_letters})? [да/нет]: '): chars_list.append(set(lowercase_letters)) if input_true_false(f'Включать символы пунктуации ({punctuation})? [да/нет]: '): chars_list.append(set(punctuation)) if input_true_false(f'Исключать неоднозначные символы ({ambiguous})? [да/нет]: '): to_remove = set(ambiguous) for i in range(len(chars_list)): chars_list[i] = chars_list[i] - to_remove chars_list = [list(el) for el in chars_list] for _ in range(num): print(generate_password(length, chars_list)) ```` Для удобства реализации используем служебную функцию `input_true_false`, которая корректно запрашивает у пользователя ответ на вопрос типа "да/нет". Функция `generate_password` ответственна за генерацию одного пароля. Мы решили, что пароль должен содержать хотя бы по одному символу каждого указанного типа, поэтому функция принимает список списков. Для исключения неоднозначных символов используется операция разности множеств. Перед вызовом функции `generate_password` список множеств преобразуется в список списков. Пример работы программы: ````shell >python secure_password.py Сколько паролей нужно? 4 Какая длина одного пароля? 14 Включать цифры (0123456789)? [да/нет]: + Надо ввести: да или нет. Включать цифры (0123456789)? [да/нет]: да Включать прописные буквы (ABCDEFGHIJKLMNOPQRSTUVWXYZ)? [да/нет]: да Включать строчные буквы (abcdefghijklmnopqrstuvwxyz)? [да/нет]: да Включать символы пунктуации (!#$%&*+-=?@^_.)? [да/нет]: нет Исключать неоднозначные символы (il1Lo0O)? [да/нет]: да H67en6w83n8dhf NxjYyz43v78V3F ASeW5s4Hstx9TJ 8gcaH834KGneEn ```` ---------------------------------------------------------------------------------------------------- # Шифр Цезаря Предыдущий вариант задачи описан [здесь](#caesar). В этом варианте сделаем следующие изменения: - шифруются только символы из алфавита, остальные выводятся без изменения; - учитывается регистр символов; - программа поддерживает несколько алфавитов; - входной текст поступает из консольного ввода, результат выводится так же в консоль; - программа позволяет перебор смещений (для подбора неизвестного пароля). ````code import sys alfs = {'en': 'abcdefghijklmnopqrstuvwxyz', 'ru': 'абвгдежзийклмнопрстуфхцчшщъыьэюя', } indexes = {k:{v[i] : i for i in range(len(v))} for k, v in alfs.items()} def caesar(sring, shift, lang): alf = alfs[lang] l = len(alf) index = indexes[lang] result = [] for c in sring: c_lower = c.lower() c_isupper = c.isupper() if c_lower not in index: result.append(c) else: c_new = alf[(index[c_lower] + shift) % l] result.append(c_new.upper() if c_isupper else c_new) return ''.join(result) shift = sys.argv[1] lang = sys.argv[2].strip().lower() while True: try: sring = input() except EOFError: break if shift == '?': for i in range(1, len(alfs[lang])): print(f"{i}:".rjust(4, ' '), caesar(sring, i, lang)) else: print(caesar(sring, int(shift), lang)) ```` ````code sring = input() result = [] word = [] lang = 'en' index = indexes[lang] for c in sring: if c.lower() in index: word.append(c) else: if word: result.append(caesar(word, len(word), lang)) result.append(c) word = [] if word: result.append(caesar(word, len(word), lang)) print(''.join(result)) ```` Используем массив `sys.argv` для получения переданных программе аргументов командной строки. ````shell >python caesar.py 11 ru Я люблю своего кота Федора! К цймцй ьнщрощ хщэл Ярпщыл! ^Z >python caesar.py -11 ru К цймцй ьнщрощ хщэл Ярпщыл! Я люблю своего кота Федора! ^Z >python caesar.py ? en Hawnj pk swhg xabkna ukq nqj. 1: Ibxok ql txih ybclob vlr ork. 2: Jcypl rm uyji zcdmpc wms psl. 3: Kdzqm sn vzkj adenqd xnt qtm. 4: Learn to walk before you run. 5: Mfbso up xbml cfgpsf zpv svo. . . . ```` ---------------------------------------------------------------------------------------------------- # Выбор уникальных сообщений Некий поэтический канал публикует короткие стихотворения. Однако было замечено, что автор периодически повторяет свои предыдущие публикации. Требуется вывести уникальные публикации. Всю историю сообщений из этого канала можно выгрузить в формате JSON. Структура документа JSON следующая: ````wrapped { "name": "???", "type": "public_channel", "id": 00000, "messages": [ { "id": 3, "type": "message", "date": "2016-06-23T15:51:08", "date_unixtime": "1466686268", "from": "???", "from_id": "???", "text": "когда земную жизнь окончу\nпопробую еще разок\nно уровень возьму сложнее\nкамбоджа семьдесят шестой", "text_entities": [ { "type": "plain", "text": "когда земную жизнь окончу\nпопробую еще разок\nно уровень возьму сложнее\nкамбоджа семьдесят шестой" } ] }, . . . ] } ```` Как видно из образца, корневым элементом документа является объект JSON, из которого нам требуется атрибут `messages`, который является списком. Элементы этого списка представляют собственно публикации, являются объектами, и нам из них требуется поле `text`. ````code import json with open('input.json', 'r', encoding='UTF-8') as f: j = json.loads(f.read()) print(len(j["messages"])) s = set() count = 0 with open('output.txt', 'w', encoding='UTF-8') as f: for m in j["messages"]: text = m["text"] if type(text) is str: text = text.replace(" \n", "\n") if text not in s: s.add(text) count += 1 f.write(f"----------------- {count}, {m['date']} --------------------\n") f.write(text + "\n") ```` Для разбора документа JSON используется стандартная библиотека Python, которая представляет документ JSON, переменная `j`, в виде имеющихся в языке Python структур данных, таких как словарь и список. Для исключения повторов используется *множество* (`set`). Выяснилось, что некоторые публикации имеют пробелы в конце строк, которые делают одинаковые по сути публикации разными. После удаления этих пробелов количество сообщений сократилось примерно на сотню. ---------------------------------------------------------------------------------------------------- # Цифры в стиле Textart На вход программе подаётся последовательность цифр, которую нужно вывести на экран в стиле *Textart*, который ещё иногда называется *псевдографическим*. Размер всех цифр 4 символа в ширину, и было решено реализовать три различных размера по высоте. Между цифрами в выводе должен быть один пустой столбец. Перед первой цифрой не должно быть пробелов. Интерфейс. Программа принимает 1 или 2 аргумента. Первый аргумент представляет число, которое будет выведено в стиле Textart, второй аргумент указывает высоту цифр: small, medium (по умолчанию), large. ````code from sys import argv templates = { "large": [ ' -- -- -- -- -- -- -- -- ', '| | | | | | | | | | | | | |', '| | | | | | | | | | | | | |', ' -- -- -- -- -- -- -- ', '| | | | | | | | | | | | |', '| | | | | | | | | | | | |', ' -- -- -- -- -- -- -- ', ], "medium": [ ' __ __ __ __ __ __ __ __ ', '| | /| | | | | | | | | | | |', '| | / | __| __| |__| |__ |__ / |__| |__|', '| | | | | | | | | | | | |', '|__| | |__ __| | __| |__| | |__| __|', ], "small": [ ' __ __ __ __ __ __ __ __ ', '| | /| __| __| |__| |__ |__ / |__| |__|', '|__| | |__ __| | __| |__| | |__| __|', ] } if len(argv) not in [2, 3]: raise Exception('Аргументы: 1 - число, 2 - размер: small, medium (по умолчанию), large') digits = [int(d) for d in argv[1]] size = argv[2].lower() if len(argv) == 3 else "medium" for line in templates[size]: space = '' for d in digits: print(space + line[d * 5:d * 5 + 4], end='') space = ' ' print() ```` ````shell >python program.py 4356789 __ __ __ __ __ __ | | | | | | | | | | |__| __| |__ |__ / |__| |__| | | | | | | | | | | __| __| |__| | |__| __| >python program.py 4356789 small __ __ __ __ __ __ |__| __| |__ |__ / |__| |__| | __| __| |__| | |__| __| >python program.py 4356789 large -- -- -- -- -- -- | | | | | | | | | | | | | | | | | | | | -- -- -- -- -- -- | | | | | | | | | | | | | | | | | | -- -- -- -- -- ```` ---------------------------------------------------------------------------------------------------- # Поле чудес Простая реализация игры "Поле чудес" или "Hangman". Код программы смотри [здесь](). Пример сеанса игры: ````shell >python hangman.py И так, начинаем игру "Поле чудес"! -------- | | | | | | --- У вас осталось попыток: 6 Использованные буквы: Угадайте слово: **** Назовите букву: н Нет такой буквы в этом слове :( -------- | | | O | | | --- У вас осталось попыток: 5 Использованные буквы: Н Угадайте слово: **** Назовите букву: о Есть такая буква в этом слове! -------- | | | O | | | --- У вас осталось попыток: 5 Использованные буквы: НО Угадайте слово: ***О Назовите букву: и Нет такой буквы в этом слове :( -------- | | | O | | | | | --- У вас осталось попыток: 4 Использованные буквы: ИНО Угадайте слово: ***О Назовите букву: м Нет такой буквы в этом слове :( -------- | | | O | \| | | | --- У вас осталось попыток: 3 Использованные буквы: ИМНО Угадайте слово: ***О Назовите букву: п Нет такой буквы в этом слове :( -------- | | | O | \|/ | | | --- У вас осталось попыток: 2 Использованные буквы: ИМНОП Угадайте слово: ***О Назовите букву: я Есть такая буква в этом слове! -------- | | | O | \|/ | | | --- У вас осталось попыток: 2 Использованные буквы: ИМНОПЯ Угадайте слово: Я**О Назовите букву: й Есть такая буква в этом слове! -------- | | | O | \|/ | | | --- У вас осталось попыток: 2 Использованные буквы: ИЙМНОПЯ Угадайте слово: ЯЙ*О Назовите букву: ц Есть такая буква в этом слове! Вы угадали: ЯЙЦО -------- | | O | \|/ | | | / \ | --- ````