Печать

От простого к сложному, пишем на Python логическую игру  «Быки и Коровы». В этой игре игрок должен угадать четырёхзначное число за меньшее число ходов. Игрок вводит число, а компьютер даёт подсказки.

«Программирование - это игра, в которой вы можете создавать свои собственные правила и где конечным результатом будет что угодно, что вы из этого сможете сделать.» 

Линус Торвальдс

Аннотация

Методическая разработка «Программирование логических игр на Python», как учебное пособие, предназначена для занятий с детьми старше 10 лет в кружке программирование. Синтаксису и семантике языка программирования Python здесь уделяется не достаточное для изучения языка Python внимание. Мы считаем, что данное пособие будет полезно детям и взрослым как введение в специальность. Программисты ещё не знакомые с языком Python с этим пособием смогут оценить выразительность языка Python и некоторые возможности графической библиотеки Tkinter. Дети могут самостоятельно запустить на компьютере в среде Python 3  примеры из нашего пособия. Примеры сопровождаются очень подробными комментариями и описанием работы программ. Заинтересованным в более глубоком изучении языка Python могу порекомендовать мобильное приложение Sololearn.

Наше учебное пособие, так же, может быть полезно в проектной деятельности школьников. Выбирая проекты связанные с программированием, созданием компьютерных игр, компьютерных систем тестирования по школьным предметам, школьники и учителя найдут в этом пособии, практически, пошаговую инструкцию по реализации своего проекта.

Введение

Python [ˈpʌɪθ(ə)n], в русском языке питон — высокоуровневый язык программирования общего назначения, ориентированный на повышение производительности разработчика и читаемости кода. Синтаксис ядра Python минималистичен. В то же время стандартная библиотека включает большой набор полезных функций.

Python поддерживает структурное, обобщенное, объектно-ориентированное, функциональное и аспектно-ориентированное программирование. Основные архитектурные черты — динамическая типизация, автоматическое управление памятью, полная интроспекция, механизм обработки исключений, поддержка многопоточных вычислений, высокоуровневые структуры данных. Поддерживается разбиение программ на модули, которые, в свою очередь, могут объединяться в пакеты.

Разработка языка Python была начата в конце 1980-х годов сотрудником голландского института CWI Гвидо ван Россумом.

На сегодня поддерживается одна ветка развития Python 3.x, поддержка ветки Python 2.x закончилась в апреле 2020 года.

Wikipedia

Для программирования на Python на компьютере должен быть установлен интерпретатор Python. В операционной системе Linux он установлен по умолчанию. В Windows и на компьютер Apple установить Python не сложно. Скачать дистрибутив Python можно с официального сайта Python.

Писать программы на Python следует в простых текстовых редакторах, которые не вносят в код программы свои теги форматирования. Например, в Windows это Notepad. Мы рекомендуем установить на компьютер и использовать специализированную среду разработки программ (IDE) на Python, например, IDLE или Thonny. Эти IDE бесплатны и доступны для установки в любой операционной системе. Устанавливая IDE IDLE под Windows, выбирайте дистрибутив для Python 3 последней версии. В процессе установки IDLE будет установлен и интерпретатор Python. В операционной системе Android удобно запускать и писать программы на Python в среде разработки Pydroid 3.

Сохраняйте программы на Python с расширением py. Например, имя файла может быть таким: BullsAndCows02.py. Где py - расширение имени файла, BullsAndCows - имя файла, 02 - версия программы.

Запускать программы на Python можно из командной строки. При этом интерпретатор командной строки должен быть открыт в папке с вашей программой. Наберите в командной строке python3 BullsAndCows02.py и нажмите Ввод (Enter). Командная строка в Windows - это cmd, в Linux и на Apple это терминал. В Windows, программы на python можно запускать двойным щелчком. И самое простое, запускайте программы на python из среды разработки программ (IDE) IDLE или Thonny.

Правила игры «Быки и Коровы»

По правилам игры, компьютер случайным образом выбирает четырёхзначное число таким образом, чтобы первой значащей цифрой не был 0 и чтобы все цифры, составляющие это число были бы уникальными. Цель игрока — угадать число. Если в предложенном вами числе несколько цифр оказались на своём месте, компьютер сообщает сколько есть таких цифр. Цифра на своём месте называется Быком. Если в предложенном вами числе несколько цифр оказались не на своём месте, компьютер сообщает сколько есть таких цифр. Цифра не на своём месте называется Коровой.

В западных источниках подобная игра-головоломка упоминается как "Master-mind". Но, "Master-mind" и в подмётки не годится нашим Быкам и Коровам. В школьные годы мы играли в игру "Быки и Коровы" на листочках в клеточку.

Следует отметить, что программный алгоритм, решатель этой задачи, довольно сложен и в этом пособии не рассматривается. Данной проблемой, в своё время, занимался Дональд Кнут, чьи работы можно найти в интернет.

Дональд Эрвин Кнут, доктор философии (1963), эмерит-профессор Стэнфордского университета, член Американского философского общества (2012), преподаватель и идеолог программирования, автор 19 монографий (в том числе ряда классических книг по программированию) и более 160 статей, разработчик нескольких известных программных технологий. Автор всемирно известной серии книг, посвящённой основным алгоритмам и методам вычислительной математики, а также создатель настольных издательских систем ΤΕΧ и METAFONT, предназначенных для набора и вёрстки книг научно-технической тематики (в первую очередь — физико-математических).

Понятие переменной, строка, операция присваивания, функция print()

Приступим к программированию. По правилам игры, компьютер случайным образом должен составить из четырёх цифр число. Где и как он будет хранить это число?

В простых программах вся информация (данные) хранится в переменных. 

Переменная в программировании — это имя, с которым может быть связано значение.

Значит у переменной есть имя, это имя программист должен придумать сам. У переменной есть значение, значением переменной может быть число, символ, строка символов и более сложные структуры данных. В нашей программе компьютер загадывает 4 цифры (выбирает 4 символа из 10 цифр). 4 цифры могут представлять собой четырёхзначное число или строку из четырёх цифр. Мы, в нашей программе, цифры будем группировать в строки или в списки.

Символы и сроки (наборы символов) в Python заключают в двойные или одинарные кавычки. Создадим в нашей программе переменную со значением равным строке из 10 цифр. Пусть имя переменной будет z, а значение '0123456789'. Знак равно (=) почти во всех языках программирования - операция присваивания.

z = '0123456789'

Эта строка читается так: переменной z присваивается значение '0123456789'. Значение созданной переменной можно читать (передавать или использовать) и изменять.

z = '0123456789'                          # Из 10 цифр создаём строку z
print(z)

Программа 1. Определяем набор допустимых в игре символов.

В программе 1 функция print(z) выводит значение переменной z на экран. Если Вы запускаете свою программу в IDE IDLE, то функция print() осуществляет вывод в командный интерпретатор Python (Shell). Результат работы программы 1 представлен ниже как "Вывод 1".

====== RESTART: /BullsAndCows.py ======
0123456789
>>>

Вывод 1.

Мы рассмотрели работу функции print(). В общем, встроенные функции в Python имеют имя, заканчивающееся круглыми скобками. В круглых скобках в функцию передают параметры. Если параметров несколько, их разделяют запятыми.

Слово print - имя рассмотренной нами функции, z - параметр. Функция print() может принять несколько строковых параметров разделённых запятыми. Вывод строк на экран функция print() осуществляет в одну строку и в конце переводит курсор вывода в начало следующей строки, так что, следующая функция print() осуществляет вывод с начала следующей строки.

Списки, функция list()

Кроме перечисленных ранее чисел, символов и строк данные в Python могут быть представлены в виде списков.

Список в Python — это последовательность значений любого типа.

Создаётся список в квадратных скобках путём перечисления значений элементов списка через запятую:

z = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']

Элементы списка пронумерованы, программисты говорят, — проиндексированы. Нумерация элементов списка начинается с 0. К значению любого элемента списка можно получить доступ по индексу этого элемента. Например, в созданном нами списке z пятый элемент списка z[5] имеет значение '5'. Обращаются к элементу списка по имени списка, указывая после имени индекс элемента в квадратных скобках. Ко всему списку обращаются по имени переменной, содержащей список, без указания квадратных скобок.

z = list('0123456789')          # Создаём список z из строки содержащей 10 цифр
print(z)

Программа 2. Создаём список допустимых в игре символов.

В программе 2 функция list() создаёт список из строки содержащей все десятичные цифры. Функция print(z) выводит на экран весь список, см. вывод 2.

Функция list() может создать список из любого перечислимого объекта указанного в качестве аргумента функции в круглых скобках.

====== RESTART: /BullsAndCows.py ======
['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
>>>

Вывод 2.

Пришло время объяснить, почему, работая над программой игры «Быки и Коровы», мы не остановились на перечислении допустимых символов для игры числом 1234567890, или строкой '0123456789', а решили создать список из этих символов. Просто,  мы хотим воспользоваться функцией shuffle() из библиотеки random, а она умеет перемешивать элементы списка.

Библиотека функций random, функция shuffle()

Библиотека random предоставляет функции для генерации случайных чисел, букв, случайного выбора элементов последовательности и т.п. Функция shuffle() случайным образом перемешивает элементы последовательности, например, списка.

from random import shuffle      # Импортируем функцию shuffle (перемешивание) из библиотеки random

z = list('0123456789')          # Создаём список z из строки содержащей 10 цифр
shuffle(z)                      # Перемешиваем элементы списка z
print(z)

Программа 3. Создаём перемешанный список допустимых в игре символов.

В программе 3 функция shuffle() перемешивает элементы списка z. В результате, мы получаем список z состоящий из элементов исходного списка но перемешанных случайным образом, см. вывод 3.

====== RESTART: /BullsAndCows.py ======
['3', '2', '1', '9', '6', '8', '7', '0', '4', '5']
>>>

Вывод 3.

Срез списка

Срез списка - это подмножество элементов исходного списка.

Анализируя список, сформированный программой 3, мы приходим к выводу, что почти любые четыре элемента подряд из этого списка удовлетворяют правилам формирования случайного числа в игре быки и коровы. Не удовлетворяет этим правилам только группа элементов начинающаяся с символа '0'.

from random import shuffle      # Импортируем функцию shuffle (перемешивание) из библиотеки random

z = list('0123456789')          # Создаём список z из строки содержащей 10 цифр
shuffle(z)                      # Перемешиваем элементы списка z
x = z[3:7]                      # Создаём список x из 4-х элементов списка z
print(x)

Программа 4. Выбираем из 10 перемешанных цифр 4 подряд.

Мы уже говорили, что по имени переменной значением которой является список можно обратиться ко всему списку, по имени переменной с индексом можно выбрать отдельный элемент списка. Так же, можно получить доступ к части списка (срезу), если указать в квадратных скобках после имени переменной диапазон значений индексов элементов списка. Указывая диапазон, сначала указывают начальное значение диапазона, а затем, через двоеточие, конечное значение диапазона. Причём, начальное значение входит в диапазон, а конечное исключается. Все целые числа между начальным и конечным значением диапазона входят в диапазон.

В программе 4 в строке

x = z[3:7]

создаётся новая переменная x со значением равным срезу списка z, включающим элементы z[3], z[4], z[5], z[6]. Результат работы программы 4 можно видеть в выводе 4.

====== RESTART: /BullsAndCows.py ======
['8', '6', '4', '3']
>>>

Вывод 4.

Срез списка z[3:7] не гарантирует, что список не будет начинаться с символа '0'. Если список z[3:7] начинается с символа '0', то можно взять срез z[4:8] что гарантированно избавит нас от символа '0' в начале списка.

Тернарная операция if else

If переводится с английского языка как если, else как иначе. Тернарная операция if else - это условная операция. Тернарная операция получает три параметра, логическое условие и два вычислимых выражения одного типа. Если условие истинно (True) тернарная операция возвращает результат вычисления первого выражения, если условие ложно (False) - возвращается результат вычисления второго выражения.

from random import shuffle              # Импортируем функцию shuffle (перемешивание) из библиотеки random

z = list('0123456789')                  # Создаём список z из строки содержащей 10 цифр
shuffle(z)                              # Перемешиваем элементы списка z
x = z[3:7] if z[3] != '0' else z[4:8]   # Создаём список x из 4-х элементов списка z, так, чтобы '0' не оказался на первом месте
print(x)

 Программа 5.

В программе 5 в строке

x = z[3:7] if z[3] != '0' else z[4:8]

переменной х присваивается значение среза списка z[3:7] если z[3] не равно '0', иначе x присваивается значение среза z[4:8]. Результат работы программы 5 можно видеть в выводе 5.

====== RESTART: /BullsAndCows.py ======
['2', '8', '4', '7']
>>>

Вывод 5.

Функция input()

В игре «Быки и Коровы» предполагается диалог игрока с компьютером. Игрок вводит своё число, а компьютер ему сообщает сколько "быков" и "коров" в этом числе.

Функция input() выводит в командную строку интерпретатора Python сообщение и ожидает ввод строки от пользователя. Пользователь вводит текст и завершает ввод нажатием на клавишу «Ввод» (На некоторых клавиатурах «Enter» или «Return»). Функция input() возвращает в программу введённую пользователем строку.

from random import shuffle              # Импортируем функцию shuffle (перемешивание) из библиотеки random

z = list('0123456789')                  # Создаём список z из строки содержащей 10 цифр
shuffle(z)                              # Перемешиваем элементы списка z
x = z[3:7] if z[3] != '0' else z[4:8]   # Создаём список x из 4-х элементов списка z, так, чтобы '0' не оказался на первом месте
y = input("Введите четырёхзначное число: ")         # Функция ввода строки с клавиатуры
print ('Ваше число:', y, 'Моё число:', x)

Программа 6.

Программа 6, дойдя до строки y = input("Введите четырёхзначное число: "), приостанавливает работу. В командную строку выводится приглашение "Введите четырёхзначное число: ". В ответ на это приглашение игрок должен ввести своё число и нажать на клавишу «Ввод». Как только игрок закончит ввод строки, выполнение программы продолжится. Функция input() возвращает в программу введённую игроком строку, которая с помощью оператора присваивания сохраняется в переменной y.

====== RESTART: /BullsAndCows.py ======
Введите четырёхзначное число: 1234
Ваше число: 1234 Моё число: ['4', '0', '1', '2']
>>>

Вывод 6.

Программа 6 выводит в командную строку с помощью функции print() число введённое игроком и загаданный список из четырёх цифр см. вывод 6. Но в игре «Быки и Коровы» загаданное компьютером число должно быть скрыто от игрока до победы. Компьютер, вместо этого, должен сообщать игроку сколько "быков" и "коров" в его числе. Значит, программа должна считать "быков" и "коров" и хранить эти значения.

from random import shuffle              # Импортируем функцию shuffle (перемешивание) из библиотеки random

z = list('0123456789')                  # Создаём список z из строки содержащей 10 цифр
shuffle(z)                              # Перемешиваем элементы списка z
x = z[3:7] if z[3] != '0' else z[4:8]   # Создаём список x из 4-х элементов списка z, так, чтобы '0' не оказался на первом месте
y = input("Введите четырёхзначное число: ")         # Функция ввода строки с клавиатуры
b = 0; c = 0                            # Создаём переменные Bulls и Cows
print(y, ' содержит ', b, ' быка и ', c, ' коровы')

Программа 7.

В программе 7 мы создали две переменные b (bull) и c (cow). Начальные значения этих переменных равны 0. Мы, так же переписали параметры функции print(), которая теперь выводит загаданное игроком число и количество "быков" и "коров" равными 0. Но, программа 7 не считает "быков" и "коров", см. вывод 7.

====== RESTART: /BullsAndCows.py ======
Введите четырёхзначное число: 5678
5678  содержит  0  быка и  0  коровы
>>>

Вывод 7.

Надо считать "быков" и "коров".

Условный оператор if, логическое выражение, операция сравнения

Условный оператор if изменяет обычный, построчный ход выполнения программы. Оператор if проверяет логическое условие и если это условие истинно (True) выполняется следующий за if блок операторов. Если условие ложно (False), следующий за if блок операторов не выполняется.

Блок операторов в Python выделяется из другой части программы наличием отступа от начала строки. Рекомендуется делать отступ в 4 пробела.

from random import shuffle              # Импортируем функцию shuffle (перемешивание) из библиотеки random

z = list('0123456789')                  # Создаём список z из строки содержащей 10 цифр
shuffle(z)                              # Перемешиваем элементы списка z
x = z[3:7] if z[3] != '0' else z[4:8]   # Создаём список x из 4-х элементов списка z, так, чтобы '0' не оказался на первом месте
y = input("Введите четырёхзначное число: ")         # Функция ввода строки с клавиатуры
b = 0; c = 0                            # Создаём переменные Bulls и Cows
if y[0] == x[0]:                        # Проверяем цифра на своём месте,
    b += 1                              # если да, то добавляем быка
print(y, ' содержит ', b, ' быка и ', c, ' коровы')

Программа 8. Сравнение первых элементов строки y и списка x.

В программе 8 в строке

if y[0] == x[0]:

логическим условием оператора if является логическое выражение y[0] == x[0], где логическая операция сравнения == сравнивает первые элементы (с индексом 0) строки y и списка x. Все перечисленные понятия являются логическими потому, что они возвращают логическое значение True или False (тип boolean).

Если первый символ строки введённой игроком y[0], равен первому элементу x[0] списка из символов загаданных компьютером, то выполняется операция:

b += 1

Где к старому значению b прибавляется 1 и новое значение сохраняется в переменной b, см. вывод 8. Программа 8 проверяет, является ли первая цифра в строке введённой игроком "быком".

====== RESTART: /BullsAndCows.py ======
Введите четырёхзначное число: 1234
1234  содержит  0  быка и  0  коровы
>>>

Вывод 8.

Вывод 8, результат работы программы 8, показывает что в строке, введённой игроком не угадана ни одна цифра. Это и не удивительно, наша программа 8 сравнивает только первые элементы (элементы с индексом 0) в строке y и списке x. То есть, программа ищет "быка" на первом месте в строке введённой игроком. А мы знаем, что не легко угадать 1 цифру из 10.

Оператор elif, операция in

Что ещё должна сделать наша программа с первой цифрой из строки введённой игроком? Программа должна сравнить первую цифру из строки y со второй и остальными цифрами в загаданном компьютером списке x. И если будет найдено совпадение, число "коров" должно быть увеличено на 1. И есть ещё одно ограничение, если первая цифра в y оказалась "быком", проверять её как "корову" не надо, не надо сравнивать её с остальными цифрами в x. Для программиста, задача найти корову оказывается ещё сложнее чем найти быка:

Оператор elif может использоваться только совместно с оператором if, а функционал у elif такой же, как у if. Если логическое условие оператора if оказалось истинным, то оператор elif не выполняется и его блок операторов так же не выполняется. Если же логическое условие оператора if оказалось ложным, то оператор elif выполняется, а его блок операторов выполняется или не выполняется в зависимости от значения, возвращаемого логическим условием оператора elif.

from random import shuffle              # Импортируем функцию shuffle (перемешивание) из библиотеки random

z = list('0123456789')                  # Создаём список z из строки содержащей 10 цифр
shuffle(z)                              # Перемешиваем элементы списка z
x = z[3:7] if z[3] != '0' else z[4:8]   # Создаём список x из 4-х элементов списка z, так, чтобы '0' не оказался на первом месте
y = input("Введите четырёхзначное число: ")         # Функция ввода строки с клавиатуры
b = 0; c = 0                            # Создаём переменные Bulls и Cows
if y[0] == x[0]:                        # Проверяем цифра на своём месте,
    b += 1                              # если да, то добавляем быка
elif y[0] in x:                         # если нет, проверяем есть ли в загаданном числе эта цифра,
    c += 1                              # если да, то добавляем корову
print(y, ' содержит ', b, ' быка и ', c, ' коровы')

Программа 9. Проверка, является ли первая цифра в строке введённой игроком "быком" или "коровой".

В программе 9 в строке

elif y[0] in x:

логическим условием оператора elif является логическое выражение y[0] in x, где логическая операция in последовательно сравнивает первый элемент (с индексом 0) строки y со всеми элементами списка x. Если хотя бы одно совпадение найдено, y[0] in x возвращает True, если совпадений не найдено, возвращается False.

Если логическое условие оператора elif истинно, то выполняется операция:

c += 1

Где к старому значению с прибавляется 1 и новое значение сохраняется в переменной с, см. вывод 9. Программа 9 проверяет, является ли первая цифра в строке введённой игроком "коровой", см вывод 9.

====== RESTART: /BullsAndCows.py ======
Введите четырёхзначное число: 3456
3456  содержит  0  быка и  1  коровы
>>>

Вывод 9.

Программа 9 проверяет только первую цифру введённую игроком. Теперь нам необходимо осуществить такую же проверку всех цифр из строки, введённой игроком.

from random import shuffle              # Импортируем функцию shuffle (перемешивание) из библиотеки random

z = list('0123456789')                  # Создаём список z из строки содержащей 10 цифр
shuffle(z)                              # Перемешиваем элементы списка z
x = z[3:7] if z[3] != '0' else z[4:8]   # Создаём список x из 4-х элементов списка z, так, чтобы '0' не оказался на первом месте
y = input("Введите четырёхзначное число: ")         # Функция ввода строки с клавиатуры
b = 0; c = 0                            # Создаём переменные Bulls и Cows
if y[0] == x[0]: b += 1                 # Проверяем, цифра на своём месте, то это бык
elif y[0] in x:  c += 1                 # если нет, проверяем есть ли в загаданном числе эта цифра (корова).
if y[1] == x[1]: b += 1                 # Проверяем, цифра на своём месте, то это бык
elif y[1] in x:  c += 1                 # если нет, проверяем есть ли в загаданном числе эта цифра (корова).
if y[2] == x[2]: b += 1                 # Проверяем, цифра на своём месте, то это бык
elif y[2] in x:  c += 1                 # если нет, проверяем есть ли в загаданном числе эта цифра (корова).
if y[3] == x[3]: b += 1                 # Проверяем, цифра на своём месте, то это бык
elif y[3] in x:  c += 1                 # если нет, проверяем есть ли в загаданном числе эта цифра (корова).

print(y, ' содержит ', b, ' быка и ', c, ' коровы')

Программа 10. Проверка цифры, в строке введённой игроком, являются "быками" или "коровами".

====== RESTART: /BullsAndCows.py ======
Введите четырёхзначное число: 1234
1234  содержит  0  быка и  2  коровы
>>>

Вывод 10.

Цикл for in, функция range()

Решить задачу проверки всех цифр из строки, введённой игроком можно копированием четырёх строк программы 9 начиная с условного оператора if четыре раза. В логических условиях надо будет индекс 0 поменять на индексы 0, 1, 2, 3. Но, можно эти четыре строки программы выполнить четыре раза с помощью оператора цикла.

Создавая цикл for, после ключевого слова for указывают имя переменной, которая последовательно будет принимать значения из списка или диапазона указанного после ключевого слова in. Когда элементы списка или диапазона закончатся, цикл будет завершён. В конце строки определяющей параметры цикла for ставят двоеточие ( : ). Тело цикла в Python выделяется отступами от начала строки. Рекомендуется добавлять 4 пробела.

from random import shuffle              # Импортируем функцию shuffle (перемешивание) из библиотеки random

z = list('0123456789')                  # Создаём список z из строки содержащей 10 цифр
shuffle(z)                              # Перемешиваем элементы списка z
x = z[3:7] if z[3] != '0' else z[4:8]   # Создаём список x из 4-х элементов списка z, так, чтобы '0' не оказался на первом месте
y = input("Введите четырёхзначное число: ")         # Функция ввода строки с клавиатуры
b = 0; c = 0                            # Создаём переменные Bulls и Cows
for i in range(4):                      # В цикле из 4-x повторений
    if y[i] == x[i]:                    # проверяем цифра на своём месте,
        b += 1                          # если да, то добавляем быка
    elif y[i] in x:                     # если нет, проверяем есть ли в загаданном числе эта цифра,
        c += 1                          # если да, то добавляем корову
print(y, ' содержит ', b, ' быка и ', c, ' коровы')

Программа 11. Проверка количества "быков" и "коров"во введённой игроком строке.

В программе 11 в строкой

for i in range(4):

создан цикл из четырёх повторений. Переменная цикла i последовательно принимает значения из диапазона созданного функцией range().

Функция range(4) создаёт диапазон из целых чисел начиная от 0 включительно и заканчивая 4. Число 4 - правая граница диапазона не входит в этот диапазон. То есть, в цикле, переменная i последовательно принимает значения 0, 1, 2, 3.

В программе 11 переменная i используется в теле цикла как индекс элементов строки y и списка x. Таким образом последовательно проходят проверку на соответствие званию "бык" или "корова" все элементы строки y (y[0], y[1], y[2], y[3]).

====== RESTART: /BullsAndCows.py ======
Введите четырёхзначное число: 1234
1234  содержит  0  быка и  2  коровы
>>>

Вывод 11.

Посмотрите на результат работы программы 11 - вывод 11. Здесь компьютер загадал число, игрок ввёл своё число. Компьютер подсчитал в строке введённой игроком количество "быков" и "коров" и вывел результат на экран. С первого раза отгадать четырёхзначное число маловероятно. Мы должны создать такую программу, которая будет загадывать своё число и давать возможность игроку делать попытки отгадать его несколько раз, до победы.

Цикл while

Для решения поставленной задачи, мы должны в нашей программе, начиная со строки содержащей функцию input() и до конца программы создать бесконечный цикл. Для этого мы могли бы ещё раз воспользоваться циклом for c большим или огромным диапазоном range(). Но, практически во всех языках программирования имеется оператор while который позволяет создавать бесконечные циклы.

Цикл while выполняется до тех пор, пока истинно условие выполнения цикла.

from random import shuffle              # Импортируем функцию shuffle (перемешивание) из библиотеки random

z = list('0123456789')                  # Создаём список z из строки содержащей 10 цифр
shuffle(z)                              # Перемешиваем элементы списка z
x = z[3:7] if z[3] != '0' else z[4:8]   # Создаём список x из 4-х элементов списка z, так, чтобы '0' не оказался на первом месте
while True:                             # Запускаем бесконечный цикл
    y = input("Введите четырёхзначное число: ")         # Функция ввода строки с клавиатуры
    b = 0; c = 0                        # Создаём переменные Bulls и Cows
    for i in range(4):                  # В цикле из 4-x повторений
        if y[i] == x[i]:                # проверяем цифра на своём месте,
            b += 1                      # если да, то добавляем быка
        elif y[i] in x:                 # если нет, проверяем есть ли в загаданном числе эта цифра,
            c += 1                      # если да, то добавляем корову
    print(y, ' содержит ', b, ' быка и ', c, ' коровы')

Программа 11. С бесконечным циклом.

В программе 11 в строке

while True:

мы записали в качестве условия выполнения цикла логическую константу True. True переводится как истина. Таким образом, добавив в программу while True: мы создали бесконечный цикл. Телом этого цикла являются все строки программы, расположенные под ключевым словом while с отступом от левого края окна с программой.

====== RESTART: /BullsAndCows.py ======
Введите четырёхзначное число: 1234
1234  содержит  0  быка и  1  коровы
Введите четырёхзначное число: 5678
5678  содержит  0  быка и  2  коровы
Введите четырёхзначное число: 7893
7893  содержит  1  быка и  1  коровы
Введите четырёхзначное число: 2340
2340  содержит  0  быка и  0  коровы
Введите четырёхзначное число: 7591
7591  содержит  1  быка и  1  коровы
Введите четырёхзначное число: 8196
8196  содержит  0  быка и  4  коровы
Введите четырёхзначное число: 9861
9861  содержит  4  быка и  0  коровы
Введите четырёхзначное число:

Вывод 11.

Результат работы программы 11 представлен в выводе 11. Здесь мы видим, что игрок может последовательно, следуя подсказкам компьютера, логически вычислить число, загаданное компьютером. Но, программа 11 на этом не заканчивает свою работу. Цикл while продолжает работать хотя после победы смысла в этом нет. В своей программе мы должны предусмотреть выход из цикла while.

Оператор break

Оператор break применяется только внутри цикла while или for. На операторе break выполнение цикла прекращается, операторы тела цикла, следующие за break не выполняются. После оператора break выполняется следующий за телом цикла оператор. Оператор break помогает завершить цикл с помощью дополнительных условий завершения цикла и в любом месте тела цикла.

from random import shuffle              # Импортируем функцию shuffle (перемешивание) из библиотеки random

z = list('0123456789')                  # Создаём список z из строки содержащей 10 цифр
shuffle(z)                              # Перемешиваем элементы списка z
x = z[3:7] if z[3] != '0' else z[4:8]   # Создаём список x из 4-х элементов списка z, так, чтобы '0' не оказался на первом месте
while True:                             # Запускаем бесконечный цикл
    y = input("Введите четырёхзначное число: ")         # Функция ввода строки с клавиатуры
    b = 0; c = 0                        # Создаём переменные Bulls и Cows
    for i in range(4):                  # В цикле из 4-x повторений
        if y[i] == x[i]:                # проверяем цифра на своём месте,
            b += 1                      # если да, то добавляем быка
        elif y[i] in x:                 # если нет, проверяем есть ли в загаданном числе эта цифра,
            c += 1                      # если да, то добавляем корову
    print(y, ' содержит ', b, ' быка и ', c, ' коровы')
    if b == 4:                          # Если число угадано,
        print('You win!')               # поздравляем
        break

Программа 12. Игра «Быки и Коровы»

В программе 12 условием выхода из цикла while является победа игрока, то есть нахождение всех цифр в загаданном компьютером числе и размещение этих цифр по своим местам (4 "быка"). Проверяется это условие в строке

if b == 4:

Если проверка условия возвращает True, на экран выводится строка 'You win!' и выполняется оператор break. Так как после цикла while в программе 12 нет ни каких операторов, выполнение программы заканчивается см. вывод 12.

====== RESTART: BullsAndCows.py ======
Введите четырёхзначное число: 1234
1234  содержит  0  быка и  1  коровы
Введите четырёхзначное число: 5678
5678  содержит  0  быка и  1  коровы
Введите четырёхзначное число: 3456
3456  содержит  2  быка и  0  коровы
Введите четырёхзначное число: 9406
9406  содержит  1  быка и  2  коровы
Введите четырёхзначное число: 3906
3906  содержит  2  быка и  2  коровы
Введите четырёхзначное число: 3096
3096  содержит  4  быка и  0  коровы
You win!
>>>

Вывод 12.

Управляющие последовательности функции print()

Еще раз сформулируем правила игры:

Быки и коровы — компьютерная логическая игра, в начале которой, компьютер загадывает 4-х значное число. Это число не может начинаться с цифры 0 и все цифры в нём должны быть уникальными, то есть, не повторяются.

За несколько попыток Игрок должен угадать, какое число загадал компьютер. Делая очередную попытку, игрок вводит с клавиатуры своё 4-х значное число. Компьютер определяет сколько "быков" и "коров" содержится в числе предложенном игроком. Бык - цифра на своём месте. Корова - цифра не на своём месте.

С каждой попыткой у Игрока увеличивается шанс отгадать загаданное компьютером число. В процессе игры, Игрок анализирует множества введённых 4-х значных чисел на предмет пересечения этих множеств с множеством "коров", цифр которые содержатся в числе, загаданном компьютером. С каждым последующим ходом игрок ищет цифры из множества коров и их место в загаданном компьютером числе.

Вы побеждаете, если компьютер сообщает что Ваше число содержит 4 быка. Надо стремиться найти 4 быка за меньшее число ходов.

Добавим эти правила в нашу программу.

from random import shuffle              # Импортируем функцию shuffle (перемешивание) из библиотеки random

print('\n  Быки и коровы — компьютерная логическая игра,\n'
      'в начале которой, компьютер загадывает 4-х значное число.\n'
      'Это число не может начинаться с цифры 0 и все цифры в нём\n'
      'должны быть уникальными, то есть, не повторяются.\n\n'
      '  За несколько попыток Игрок должен угадать,\n'
      'какое число загадал компьютер.\n'
      'Делая очередную попытку, игрок вводит с клавиатуры\n'
      'своё 4-х значное число.\n'
      'Компьютер определяет сколько "быков"\n'
      'и "коров" содержится в числе предложенном игроком.\n'
      'Бык - цифра на своём месте.\n'
      'Корова - цифра не на своём месте.\n\n'
      '  С каждой попыткой у Игрока увеличивается шанс\n'
      'отгадать загаданное компьютером число.\n'
      'В процессе игры, Игрок анализирует множества\n'
      'введённых 4-х значных чисел на предмет\n'
      'пересечения этих множеств с множеством "коров",\n'
      'цифр которые содержатся в числе, загаданном компьютером.\n'
      'С каждым последующим ходом игрок ищет цифры\n'
      'из множества коров и их место в загаданном компьютером числе.\n\n'
      '  Вы побеждаете, если компьютер сообщает,\n'
      'что Ваше число содержит 4 быка.\n'
      'Надо стремиться найти 4 быка за меньшее число ходов.\n')

z = list('0123456789')                  # Создаём список z из строки содержащей 10 цифр
shuffle(z)                              # Перемешиваем элементы списка z
x = z[3:7] if z[3] != '0' else z[4:8]   # Создаём список x из 4-х элементов списка z, так, чтобы '0' не оказался на первом месте
while True:                             # Запускаем бесконечный цикл
    y = input("Введите четырёхзначное число: ")         # Функция ввода строки с клавиатуры
    b = 0; c = 0                        # Создаём переменные Bulls и Cows
    for i in range(4):                  # В цикле из 4-x повторений
        if y[i] == x[i]:                # проверяем цифра на своём месте,
            b += 1                      # если да, то добавляем быка
        elif y[i] in x:                 # если нет, проверяем есть ли в загаданном числе эта цифра,
            c += 1                      # если да, то добавляем корову
    print(y, ' содержит ', b, ' быка и ', c, ' коровы')
    if b == 4:                          # Если число угадано,
        print('You win!')               # поздравляем
        break

Программа 12-а. Игра «Быки и Коровы»

===== RESTART: ~/boolsAndCows12a.py =====

  Быки и коровы — компьютерная логическая игра,
в начале которой, компьютер загадывает 4-х значное число.
Это число не может начинаться с цифры 0 и все цифры в нём
должны быть уникальными, то есть, не повторяются.

  За несколько попыток Игрок должен угадать,
какое число загадал компьютер.
Делая очередную попытку, игрок вводит с клавиатуры
своё 4-х значное число.
Компьютер определяет сколько "быков"
и "коров" содержится в числе предложенном игроком.
Бык - цифра на своём месте.
Корова - цифра не на своём месте.

  С каждой попыткой у Игрока увеличивается шанс
отгадать загаданное компьютером число.
В процессе игры, Игрок анализирует множества
введённых 4-х значных чисел на предмет
пересечения этих множеств с множеством "коров",
цифр которые содержатся в числе, загаданном компьютером.
С каждым последующим ходом игрок ищет цифры
из множества коров и их место в загаданном компьютером числе.

  Вы побеждаете, если компьютер сообщает,
что Ваше число содержит 4 быка.
Надо стремиться найти 4 быка за меньшее число ходов.

Введите четырёхзначное число: 1234
1234  содержит  2  быка и  0  коровы
Введите четырёхзначное число: 5678
5678  содержит  0  быка и  1  коровы
Введите четырёхзначное число: 7895
7895  содержит  2  быка и  0  коровы
Введите четырёхзначное число: 1295
1295  содержит  2  быка и  0  коровы
Введите четырёхзначное число: 1894
1894  содержит  4  быка и  0  коровы
You win!
>>>

Вывод 12-а.

Рис. 1. Перевод правил игры на английский язык с помощью Яндекс переводчика.

Графический интерфейс к программе.

Программа 12 игра «Быки и Коровы» с интерфейсом командной строки. Но такими программами (играми) с интерфейсом командной строки уже более 35 лет никто не пользуется. Есть класс задач, где программы с интерфейсом командной строки широко используются и ещё долго будут востребованы - это утилиты. Мы же написали игру, а компьютерные игры уже давно обзавелись графическим интерфейсом. Игра «Быки и Коровы», надеюсь, станет более привлекательной если мы её снабдим графическим интерфейсом.

Библиотека tkinter

Сначала, создадим графический интерфейс (GUI) для программы «Быки и Коровы». GUI для программы «Быки и Коровы» будем создавать с помощью графической библиотеки Tkinter.

Библиотека Tkinter предназначена для организации диалогов в программах написанных на языке на Python с помощью оконного графического интерфейса GUI. Tkinter основана на более универсальной библиотеке Tk. Обычно, она входит в состав дистрибутива Python. Tkinter позиционируется как библиотека для быстрого написания GUI-приложений.

Wikipedia

Библиотека tkinter входит в состав Python 3 и старше. Библиотека Tkinter входит в состав Python 2.7 и младше. Обе библиотеки будут совместимы на уровне тех функций, которые мы будем использовать в нашей программе и, следовательно, наша программа будет работать с Python 3 и с Python 2.7. Надо только заменить имя библиотеки tkinter на имя Tkinter в первой строчке программы, и может быть, ещё кое какие мелочи. Впрочем, рекомендуется использовать последние версии Python 3, а Python 2.7 уже уходит в историю.

Ключевые слова from, import, конструктор Tk(), функция mainloop()

В начале программы 14 с помощью ключевых слов from и import мы импортируем все функции из библиотеки Tkinter в нашу программу. Импортируем, значит вставляем программный код библиотеки в то место в своей программе где указано ключевое слово import с именем библиотеки. На то что мы импортируем все функции указывает звёздочка в строке

from tkinter import *

После выполнения этой строки программы, далее, в тексте своей программы, мы можем использовать функции из библиотеки tkinter

from tkinter import *           # Импортируем все функции из библиотеки TKinter

Tk()                            # Создаём объект окно пиложения

mainloop()                      # Цикл ожидания событий

Программа 14. Создание главного окна программы.

В программе 14 мы используем функцию Tk() из библиотеки tkinter. Функция Tk() из библиотеки tkinter создаёт главное окно программы с графическим интерфейсом. Так как функция Tk() создаёт объект класса Tk, функцию Tk() называют конструктором объекта.

Рис. 1. Главное окно программы.

Конструктор Tk() создал главное окно программы на экране, и оно появляется на экране, как на рис. 1. Но мы могли бы не увидеть окно созданное конструктором Tk() если бы не этом наша программа заканчивалась. После выполнения последней строчки программы заканчивается выполнение программы.

Функция mainloop() из библиотеки tkinter создаёт главный цикл программы с графическим интерфейсом. Этот цикл создан в библиотеке, в определении функции mainloop() с помощью ключевого слова while, которое в программах на Python создаёт циклы.

Методы geometry() и title()

Функция mainloop() будет выполняться бесконечно. В функции mainloop() будут отслеживаться все события, происходящие с окном вашей программы и будут выполняться методы (функции) вызываемые этими событиями. Например, даже если вы ещё не зарегистрировали в Вашей программе ни одного обработчика события, в вашей программе всё равно отслеживаются такие события, как клик кнопкой мыши по кнопкам свернуть, развернуть или закрыть окно программы. В случае наступления перечисленных событий, будут вызваны соответствующие им обработчики событий (методы) и с окном вашей программы произойдут соответствующие метаморфозы.

from tkinter import *           # Импортируем все функции из библиотеки TKinter

tk = Tk()                       # Создаём объект окно пиложения и даём ему имя tk
tk.geometry('500x350')          # Задаём размер окна пиложения в пикселях
tk.title('Быки и Коровы')       # title название программы в заголовке окна

mainloop()                      # Цикл ожидания событий

Программа 15.

В программе 15:

  1. метод Tk() из библиотеки tkinter создаёт главное окно программы,
  2. объекту главное окно программы мы присваиваем имя tk,
  3. объекту tk (главному окну программы) методом geometry() мы задаём размер в пикселях,
  4. для объекта tk методом title() мы меняем заголовок окна.

Рис. 2.

Конструктор Message() и метод pack()

У каждой игры есть правила игры. В следующей версии программы мы, с помощью конструктора объекта Message() библиотеки tkinter, добавим в главное окно программы окно сообщений, в которое выведем правила игры.

 

from tkinter import *           # Импортируем все функции из библиотеки TKinter

tk = Tk()                       # Создаём объект окно пиложения и даём ему имя tk
tk.geometry('500x350')          # Задаём размер окна пиложения в пикселях
tk.title('Быки и Коровы')       # title название программы в заголовке окна
msg = Message(text='Введите следующее число от 1023 до 9876 '
              'такое, чтобы цифры, составляющие это число,'
              ' не повторялись!')   # Создаём поле сообщений с именем объекта msg
msg.pack()                      # Выводим поле сообщений на экран в окне tk

mainloop()                      # Цикл ожидания событий

Программа 16.

В программе 16:

  1. метод Message(), конструктор из библиотеки tkinter создаёт объект окно сообщений в главном окне программы,
  2. объекту класса Message ( окно сообщений) мы присваиваем имя msg,
  3. объект msg мы размещаем в главном окне программы методом pack()

 

Рис. 3.

Метод config()

dxdfbgfsdg

from tkinter import *           # Импортируем все функции из библиотеки TKinter

tk = Tk()                       # Создаём объект окно пиложения и даём ему имя tk
tk.geometry('500x350')          # Задаём размер окна пиложения в пикселях
tk.title('Быки и Коровы')       # title название программы в заголовке окна
msg = Message(text='Введите следующее число от 1023 до 9876 '
              'такое, чтобы цифры, составляющие это число,'
              ' не повторялись!')   # Создаём поле сообщений с именем объекта msg
msg.pack()                      # Выводим поле сообщений на экран в окне tk
msg.config(bg='light grey', fg='olive',
           font=('times', 12, 'italic'),
           width=400)           # Параметры для msg

mainloop()                      # Цикл ожидания событий

Программа 17.

Параметры метода config() для объекта класса Message:

Рис. 4.

Конструктор Entry()

Для игры «Быки и Коровы» нам понадобится поле ввода символов с клавиатуры. Добавим поле ввода в главное окно программы с помощью конструктора объекта Entry() библиотеки tkinter.

from tkinter import *           # Импортируем все функции из библиотеки TKinter

tk = Tk()                       # Создаём объект окно пиложения и даём ему имя tk
tk.geometry('500x350')          # Задаём размер окна пиложения в пикселях
tk.title('Быки и Коровы')       # title название программы в заголовке окна
msg = Message(text='Введите следующее число от 1023 до 9876 '
              'такое, чтобы цифры, составляющие это число,'
              ' не повторялись!')   # Создаём поле сообщений с именем объекта msg
msg.pack()                      # Выводим поле сообщений на экран в окне tk
msg.config(bg='light grey', fg='olive',
           font=('times', 12, 'italic'),
           width=400)           # Параметры для msg
ent = Entry(width=4)            # Создаём поле ввода
ent.pack()                      # Размещаем поле ввода в окне tk

mainloop()                      # Цикл ожидания событий

Программа 18.

В программе 18 метод Entry(), конструктор из библиотеки tkinter создаёт объект поле ввода (окошко) в главном окне программы Параметр width=4 в методе Entry() определяет ширину поля ввода в 4 символа. Объекту класса Entry (поле ввода) мы присваиваем имя ent. Объект ent мы размещаем в главном окне программы методом pack().

Рис. 5.

Метод focus()

from tkinter import *           # Импортируем все функции из библиотеки TKinter

tk = Tk()                       # Создаём объект окно пиложения и даём ему имя tk
tk.geometry('500x350')          # Задаём размер окна пиложения в пикселях
tk.title('Быки и Коровы')       # title название программы в заголовке окна
msg = Message(text='Введите следующее число от 1023 до 9876 '
              'такое, чтобы цифры, составляющие это число,'
              ' не повторялись!')   # Создаём поле сообщений с именем объекта msg
msg.pack()                      # Выводим поле сообщений на экран в окне tk
msg.config(bg='light grey', fg='olive',
           font=('times', 12, 'italic'),
           width=400)           # Параметры для msg
ent = Entry(width=4)            # Создаём поле ввода
ent.pack()                      # Размещаем поле ввода в окне tk
ent.focus()                     # Поместить фокус в поле ввода

mainloop()                      # Цикл ожидания событий

Программа 19.

Методом focus(), в программе 19 передаём в объект ent фокус ввода, помещаем в него курсор и  делаем это поле активным.

Рис. 6.

Наша игра «Быки и Коровы» рассчитана на игру человека (игрока) с компьютером. Игрок вводит число, компьютер отвечает, есть ли в этом числе цифры совпадающие с цифрами в загаданном числе по знакоместу (быки) и сколько угадано цифр которые находятся не на своём месте (коровы). Для диалога игрока с программой, кроме поля ввода, нам понадобится вывод информации из программы. Создадим в нашей программе ещё одно поле класса Message() с именем msg2 и компьютер будет в это поле выводить количество быков и коров. Но, в начале игры, пусть в поле msg2 выводится уточняющая информация о быках и коровах. 

from tkinter import *           # Импортируем все функции из библиотеки TKinter

tk = Tk()                       # Создаём объект окно пиложения и даём ему имя tk
tk.geometry('500x350')          # Задаём размер окна пиложения в пикселях
tk.title('Быки и Коровы')       # title название программы в заголовке окна
msg = Message(text='Введите следующее число от 1023 до 9876 '
              'такое, чтобы цифры, составляющие это число,'
              ' не повторялись!')   # Создаём поле сообщений с именем объекта msg
msg.pack()                      # Выводим поле сообщений на экран в окне tk
msg.config(bg='light grey', fg='olive',
           font=('times', 12, 'italic'),
           width=400)           # Параметры для msg
ent = Entry(width=4)            # Создаём поле ввода
ent.pack()                      # Размещаем поле ввода в окне tk
ent.focus()                     # Поместить фокус в поле ввода

msg2 = Message(text='Бык - цифра на своём месте.\nКорова - цифра '
               'не на своём месте.')     # Создаём поле сообщений
msg2.pack()                     # Размещаем поле сообщений в окне tk
msg2.config(font=('times', 12, 'normal'),
            width=400)          # Параметры для msg2

mainloop()                      # Цикл ожидания событий

Программа 20.

В программе 20 текст в поле msg2 мы разбили на две строку с помощью экранированного n (\n). Обратная наклонная черта \ в строках экранирует следующий за ней символ. Экранированный символ не печатается, а превращается в управляющий символ. В частности, управляющая последовательность символов \n переводит вывод следующего текста на новую строку.

Рис. 7.

Ключевое слово def, методы bind() и get()

Для создания бесконечного диалога программы с игроком, кроме бесконечного цикла mainloop() нам будет необходимо зарегистрировать событие "ввод текста в поле ввода ent закончен нажатием на клавишу Enter (Return)". Так же, к этому событию необходимо привязать обработчик события - функцию, которая будет вести диалог с игроком в поле msg2.

from tkinter import *           # Импортируем все функции из библиотеки TKinter

def play(event):                # Функция, созданная пользователем
    '''
    Функция которая получает число из поля ввода от игрока,
    сравнивает каждую цифру введённую игроком с загаданным x,
    и выводит результаты в окно сообщений msg.
    '''
    msg2.config(text='Вы ввели число: ' + ent.get())    # Сообщение в поле msg2

tk = Tk()                       # Создаём объект окно пиложения и даём ему имя tk
tk.geometry('500x350')          # Задаём размер окна пиложения в пикселях
tk.title('Быки и Коровы')       # title название программы в заголовке окна
msg = Message(text='Введите следующее число от 1023 до 9876 '
              'такое, чтобы цифры, составляющие это число,'
              ' не повторялись!')   # Создаём поле сообщений с именем объекта msg
msg.pack()                      # Выводим поле сообщений на экран в окне tk
msg.config(bg='light grey', fg='olive',
           font=('times', 12, 'italic'),
           width=400)           # Параметры для msg
ent = Entry(width=4)            # Создаём поле ввода
ent.pack()                      # Размещаем поле ввода в окне tk
ent.focus()                     # Поместить фокус в поле ввода
ent.bind( '<Return>', play)     # Опеределяем функцию, обработчик события "Ввод"

msg2 = Message(text='Бык - цифра на своём месте.\nКорова - цифра '
               'не на своём месте.')     # Создаём поле сообщений
msg2.pack()                     # Размещаем поле сообщений в окне tk
msg2.config(font=('times', 12, 'normal'),
            width=400)          # Параметры для msg2

mainloop()                      # Цикл ожидания событий

Программа 21.

В программе 21, с помощью ключевого слова def мы создали новую функцию play().

Функции, которые создаёт программист, называют функциями определёнными пользователем (UDF User-defined function).

В определении функции play(), в круглых скобках указан передаваемый в функцию параметр параметр event. Event - зарезервированное слово, переводится как событие. Через параметр event в функцию передаются параметры события. Наша функция play будет в нашей программе выполнять роль обработчика события "нажатие на клавишу Enter (Return) в поле ent".

В программе 21 мы еще не прописали в создаваемой нами функции play() всех действий, которые она должна будет выполнять. Пока функция play является заглушкой, позволяющей тестировать остальную часть кода программы. В функцию play мы добавили только метод  config поля msg2, который выведет в поле msg2 сообщение и число, которое мы ввели в поле ent.

Возвращает в программу строку, которую мы ввели в поле ввода, метод get(), который мы применяем к объекту класса Entry (поле ввода). В нашей программе мы написали ent.get(). К полю именем ent применили метод get().

В программе 21, в созданной нами функции play, мы добавили описание этой функции. В Python описания создаваемых пользователем классов или функций заключают в тройные кавычки. Описания классов возвращает функция help(). Нам описание функции play очень пригодится для дальнейшей работы над созданием программного кода этой функции.

С помощью метода bind() зарегистрируем функцию play в качестве обработчика события происходящего с полем ввода ent. Первый параметр метода bind() указывает при наступлении какого события вызывать обработчик. Имя функции, обработчика события без скобок указывают вторым параметром метода bind. См. листинг 15, строка ent.bind( '<Return>', play). Здесь указано событие '<Return>' - нажатие на клавишу Enter (Ввод). На старых клавиатурах на клавише "Ввод" чаще встречалась надпись "Return", иногда, "Enter" или вообще не было надписи, только стрелка влево, обозначающая перевод в начало следующей строки.

Рис. 8.

Метод delete()

 Метод delete() объекта класса Entry очищает поле ввода. Первый аргумент метода delete() указывает от какого по счёту символа очищать поле, а второй аргумент указывает до какого по счёту символа очищать это поле. Если используется зарезервированное слово END в качестве второго аргумента то поле очищается до конца.

from tkinter import *           # Импортируем все функции из библиотеки TKinter

def play(event):                # Функция, созданная пользователем
    '''
    Функция которая получает число из поля ввода от игрока,
    сравнивает каждую цифру введённую игроком с загаданным x,
    и выводит результаты в окно сообщений msg.
    '''
    msg2.config(text='Вы ввели число: ' + ent.get())    # Сообщение в поле msg2
    ent.delete(0, END)          # Очищаем поле ввода ent

tk = Tk()                       # Создаём объект окно пиложения и даём ему имя tk
tk.geometry('500x350')          # Задаём размер окна пиложения в пикселях
tk.title('Быки и Коровы')       # title название программы в заголовке окна
msg = Message(text='Введите следующее число от 1023 до 9876 '
              'такое, чтобы цифры, составляющие это число,'
              ' не повторялись!')   # Создаём поле сообщений с именем объекта msg
msg.pack()                      # Выводим поле сообщений на экран в окне tk
msg.config(bg='light grey', fg='olive',
           font=('times', 12, 'italic'),
           width=400)           # Параметры для msg
ent = Entry(width=4)            # Создаём поле ввода
ent.pack()                      # Размещаем поле ввода в окне tk
ent.focus()                     # Поместить фокус в поле ввода
ent.bind( '<Return>', play)     # Опеределяем функцию, обработчик события "Ввод"

msg2 = Message(text='Бык - цифра на своём месте.\nКорова - цифра '
               'не на своём месте.')     # Создаём поле сообщений
msg2.pack()                     # Размещаем поле сообщений в окне tk
msg2.config(font=('times', 12, 'normal'),
            width=400)          # Параметры для msg2

mainloop()                      # Цикл ожидания событий

Программа 22.

В программе 22 в функции play() с помощью метода delete() после каждого хода очищается поле ent.

Рис. 9.

from tkinter import *           # Импортируем все функции из библиотеки TKinter
from random import shuffle      # Импортируем функцию shuffle (перемешивание) из библиотеки random

z = list('0123456789')          # Создаём список z из строки содержащей 10 цифр
shuffle(z)                      # Перемешиваем элементы списка z
x = z[3:7] if z[3] != '0' else z[4:8]   # Создаём список x из 4-х элементов списка z, так, чтобы '0' не оказался на первом месте

def play(event):                # Функция, созданная пользователем
    '''
    Функция которая получает число из поля ввода от игрока,
    сравнивает каждую цифру введённую игроком с загаданным x,
    и выводит результаты в окно сообщений msg.
    '''
    print(x)
    msg2.config(text='Вы ввели число: ' + ent.get())    # Сообщение в поле msg2
    ent.delete(0, END)          # Очищаем поле ввода ent

tk = Tk()                       # Создаём объект окно пиложения и даём ему имя tk
tk.geometry('500x350')          # Задаём размер окна пиложения в пикселях
tk.title('Быки и Коровы')       # title название программы в заголовке окна
msg = Message(text='Введите следующее число от 1023 до 9876 '
              'такое, чтобы цифры, составляющие это число,'
              ' не повторялись!')   # Создаём поле сообщений с именем объекта msg
msg.pack()                      # Выводим поле сообщений на экран в окне tk
msg.config(bg='light grey', fg='olive',
           font=('times', 12, 'italic'),
           width=400)           # Параметры для msg
ent = Entry(width=4)            # Создаём поле ввода
ent.pack()                      # Размещаем поле ввода в окне tk
ent.focus()                     # Поместить фокус в поле ввода
ent.bind( '<Return>', play)     # Опеределяем функцию, обработчик события "Ввод"

msg2 = Message(text='Бык - цифра на своём месте.\nКорова - цифра '
               'не на своём месте.')     # Создаём поле сообщений
msg2.pack()                     # Размещаем поле сообщений в окне tk
msg2.config(font=('times', 12, 'normal'),
            width=400)          # Параметры для msg2

mainloop()                      # Цикл ожидания событий

Программа 23.

В программу 23 мы добавили три строки программного кода в которых в переменную x записывается список, состоящий из 4-цифр, отобранных случайным образом в соответствии с правилами игры. 

from tkinter import *           # Импортируем все функции из библиотеки TKinter
from random import shuffle      # Импортируем функцию shuffle (перемешивание) из библиотеки random

z = list('0123456789')          # Создаём список z из строки содержащей 10 цифр
shuffle(z)                      # Перемешиваем элементы списка z
x = z[3:7] if z[3] != '0' else z[4:8]   # Создаём список x из 4-х элементов списка z, так, чтобы '0' не оказался на первом месте

def play(event):                # Функция, созданная пользователем
    '''
    Функция которая получает число из поля ввода от игрока,
    сравнивает каждую цифру введённую игроком с загаданным x,
    и выводит результаты в окно сообщений msg.
    '''
    print(x)
    y = ent.get()               # Введённая игроком в поле ввода строка
    b = 0; c = 0                # Создаём переменные Bulls и Cows
    for i in range(4):          # В цикле из 4-x повторений
        if y[i] == x[i]:        # проверяем цифра на своём месте,
            b += 1              # если да, то добавляем быка
        elif y[i] in x:         # если нет, проверяем есть ли в загаданном числе эта цифра,
            c += 1              # если да, то добавляем корову
    msg2.config(text = 'Ваше число: ' + y + ' содержит ' + str(b) + ' быка и ' + str(c) + ' коровы')
    ent.delete(0, END)          # Очищаем поле ввода ent

tk = Tk()                       # Создаём объект окно пиложения и даём ему имя tk
tk.geometry('500x350')          # Задаём размер окна пиложения в пикселях
tk.title('Быки и Коровы')       # title название программы в заголовке окна
msg = Message(text='Введите следующее число от 1023 до 9876 '
              'такое, чтобы цифры, составляющие это число,'
              ' не повторялись!')   # Создаём поле сообщений с именем объекта msg
msg.pack()                      # Выводим поле сообщений на экран в окне tk
msg.config(bg='light grey', fg='olive',
           font=('times', 12, 'italic'),
           width=400)           # Параметры для msg
ent = Entry(width=4)            # Создаём поле ввода
ent.pack()                      # Размещаем поле ввода в окне tk
ent.focus()                     # Поместить фокус в поле ввода
ent.bind( '<Return>', play)     # Опеределяем функцию, обработчик события "Ввод"

msg2 = Message(text='Бык - цифра на своём месте.\nКорова - цифра '
               'не на своём месте.')     # Создаём поле сообщений
msg2.pack()                     # Размещаем поле сообщений в окне tk
msg2.config(font=('times', 12, 'normal'),
            width=400)          # Параметры для msg2

mainloop()                      # Цикл ожидания событий

Программа 24.

Рис. 11.

Метод cget()

В следующей версии программы необходимо позаботиться о том, что бы выводились на экран результаты всех ходов игрока.

from tkinter import *           # Импортируем все функции из библиотеки TKinter
from random import shuffle      # Импортируем функцию shuffle (перемешивание) из библиотеки random

z = list('0123456789')          # Создаём список z из строки содержащей 10 цифр
shuffle(z)                      # Перемешиваем элементы списка z
x = z[3:7] if z[3] != '0' else z[4:8]   # Создаём список x из 4-х элементов списка z, так, чтобы '0' не оказался на первом месте

def play(event):                # Функция, созданная пользователем
    '''
    Функция которая получает число из поля ввода от игрока,
    сравнивает каждую цифру введённую игроком с загаданным x,
    и выводит результаты в окно сообщений msg.
    '''
    y = ent.get()               # Введённая игроком в поле ввода строка
    b = 0; c = 0                # Создаём переменные Bulls и Cows
    for i in range(4):          # В цикле из 4-x повторений
        if y[i] == x[i]:        # проверяем цифра на своём месте,
            b += 1              # если да, то добавляем быка
        elif y[i] in x:         # если нет, проверяем есть ли в загаданном числе эта цифра,
            c += 1              # если да, то добавляем корову
    msg2.config(text = 'Ваше число: ' + y + ' содержит ' + str(b) + ' быка и ' + str(c) + ' коровы\n' + msg2.cget('text'))
    ent.delete(0, END)          # Очищаем поле ввода ent

tk = Tk()                       # Создаём объект окно пиложения и даём ему имя tk
tk.geometry('500x350')          # Задаём размер окна пиложения в пикселях
tk.title('Быки и Коровы')       # title название программы в заголовке окна
msg = Message(text='Введите следующее число от 1023 до 9876 '
              'такое, чтобы цифры, составляющие это число,'
              ' не повторялись!')   # Создаём поле сообщений с именем объекта msg
msg.pack()                      # Выводим поле сообщений на экран в окне tk
msg.config(bg='light grey', fg='olive',
           font=('times', 12, 'italic'),
           width=400)           # Параметры для msg
ent = Entry(width=4)            # Создаём поле ввода
ent.pack()                      # Размещаем поле ввода в окне tk
ent.focus()                     # Поместить фокус в поле ввода
ent.bind( '<Return>', play)     # Опеределяем функцию, обработчик события "Ввод"

msg2 = Message(text='Бык - цифра на своём месте.\nКорова - цифра '
               'не на своём месте.')     # Создаём поле сообщений
msg2.pack()                     # Размещаем поле сообщений в окне tk
msg2.config(font=('times', 12, 'normal'),
            width=400)          # Параметры для msg2

mainloop()                      # Цикл ожидания событий

Программа 25.

В программе 25 чтобы сохранить в объекте msg2 количество быков и коров в каждой попытке игрока угадать число, мы с помощью метода cget() с параметром 'text', извлекаем из объекта msg2 текстовую строку с прежним текстом и прибавляем перед этой строкой количество быков и коров в текущей попытке.

Рис. 12.

from tkinter import *           # Импортируем все функции из библиотеки TKinter
from tkinter.dialog import *    # Импортируем класс dialog для создания окна диалога
from random import shuffle      # Импортируем функцию shuffle (перемешивание) из библиотеки random

z = list('0123456789')          # Создаём список z из строки содержащей 10 цифр
shuffle(z)                      # Перемешиваем элементы списка z
x = z[3:7] if z[3] != '0' else z[4:8]   # Создаём список x из 4-х элементов списка z, так, чтобы '0' не оказался на первом месте

def play(event):                # Функция, созданная пользователем
    '''
    Функция которая получает число из поля ввода от игрока,
    сравнивает каждую цифру введённую игроком с загаданным x,
    и выводит результаты в окно сообщений msg.
    '''
    y = ent.get()               # Введённая игроком в поле ввода строка
    b = 0; c = 0                # Создаём переменные Bulls и Cows
    for i in range(4):          # В цикле из 4-x повторений
        if y[i] == x[i]:        # проверяем цифра на своём месте,
            b += 1              # если да, то добавляем быка
        elif y[i] in x:         # если нет, проверяем есть ли в загаданном числе эта цифра,
            c += 1              # если да, то добавляем корову
    msg2.config(text = 'Ваше число: ' + y + ' содержит ' + str(b) + ' быка и ' + str(c) + ' коровы\n' + msg2.cget('text'))
    ent.delete(0, END)          # Очищаем поле ввода ent
    if b == 4:                  # В случае победы, появляется окно диалога
        gameOwer = Dialog(title = 'Вы победили',
                          text = '     Сыграем ещё?           ',
                          strings = ('Да', 'Нет'),
                          bitmap = 'questhead',
                          default = 0)

tk = Tk()                       # Создаём объект окно пиложения и даём ему имя tk
tk.geometry('500x350')          # Задаём размер окна пиложения в пикселях
tk.title('Быки и Коровы')       # title название программы в заголовке окна
msg = Message(text='Введите следующее число от 1023 до 9876 '
              'такое, чтобы цифры, составляющие это число,'
              ' не повторялись!')   # Создаём поле сообщений с именем объекта msg
msg.pack()                      # Выводим поле сообщений на экран в окне tk
msg.config(bg='light grey', fg='olive',
           font=('times', 12, 'italic'),
           width=400)           # Параметры для msg
ent = Entry(width=4)            # Создаём поле ввода
ent.pack()                      # Размещаем поле ввода в окне tk
ent.focus()                     # Поместить фокус в поле ввода
ent.bind( '<Return>', play)     # Опеределяем функцию, обработчик события "Ввод"

msg2 = Message(text='Бык - цифра на своём месте.\nКорова - цифра '
               'не на своём месте.')     # Создаём поле сообщений
msg2.pack()                     # Размещаем поле сообщений в окне tk
msg2.config(font=('times', 12, 'normal'),
            width=400)          # Параметры для msg2

mainloop()                      # Цикл ожидания событий

Программа 26.

Рис. 13.

#!/usr/bin/python3
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: t; c-basic-offset: 4; tab-width:$

# Bulls and Cows (Быки и Коровы)
# This is my version of the game, known as "Master-mind".
#
# Created on July 21, 2021.
# Author of this program code : Diorditsa A.
# I thank Sergey Polozkov for checking the code for hidden errors
# Dedicated to classmate Anya Lezhepekova
#
# BullsAndCows.py is distributed in the hope that it will be useful, but
# WITHOUT WARRANTY OF ANY KIND; not even an implied warranty
# MARKETABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See. See the GNU General Public License for more information.
# You can get a copy of the GNU General Public License
# by link http://www.gnu.org/licenses/

from tkinter import *           # Импортируем все функции из библиотеки TKinter
from tkinter.dialog import *    # Импортируем класс dialog для создания окна диалога
from random import shuffle      # Импортируем функцию shuffle (перемешивание) из библиотеки random

z = list('0123456789')          # Создаём список z из строки содержащей 10 цифр
shuffle(z)                      # Перемешиваем элементы списка z
x = z[3:7] if z[3] != '0' else z[4:8]   # Создаём список x из 4-х элементов списка z, так, чтобы '0' не оказался на первом месте

def play(event):                # Функция, созданная пользователем
    global x, z
    '''
    Функция которая получает число из поля ввода от игрока,
    сравнивает каждую цифру введённую игроком с загаданным x,
    и выводит результаты в окно сообщений msg.
    '''
    y = ent.get()               # Введённая игроком в поле ввода строка
    b = 0; c = 0                # Создаём переменные Bulls и Cows
    for i in range(4):          # В цикле из 4-x повторений
        if y[i] == x[i]:        # проверяем цифра на своём месте,
            b += 1              # если да, то добавляем быка
        elif y[i] in x:         # если нет, проверяем есть ли в загаданном числе эта цифра,
            c += 1              # если да, то добавляем корову
    msg2.config(text = 'Ваше число: ' + y + ' содержит ' + str(b) + ' быка и ' + str(c) + ' коровы\n' + msg2.cget('text'))
    ent.delete(0, END)          # Очищаем поле ввода ent
    if b == 4:                  # В случае победы, появляется окно диалога
        gameOwer = Dialog(title = 'Вы победили',
                          text = '     Сыграем ещё?           ',
                          strings = ('Да', 'Нет'),
                          bitmap = 'questhead',
                          default = 0)
        if gameOwer.num == 1:
            exit()                # Закончить игру
        else:                                       # Иначе:
            shuffle(z)                              # Перемешиваем элементы списка z
            x = z[3:7] if z[3] != '0' else z[4:8]   # Создаём список x из 4-х элементов списка z
            msg2.config(text='')                    # Очищаем окно сообщений msg2

tk = Tk()                       # Создаём объект окно пиложения и даём ему имя tk
tk.geometry('500x350')          # Задаём размер окна пиложения в пикселях
tk.title('Быки и Коровы')       # title название программы в заголовке окна
msg = Message(text='Введите следующее число от 1023 до 9876 '
              'такое, чтобы цифры, составляющие это число,'
              ' не повторялись!')   # Создаём поле сообщений с именем объекта msg
msg.pack()                      # Выводим поле сообщений на экран в окне tk
msg.config(bg='light grey', fg='olive',
           font=('times', 12, 'italic'),
           width=400)           # Параметры для msg
ent = Entry(width=4)            # Создаём поле ввода
ent.pack()                      # Размещаем поле ввода в окне tk
ent.focus()                     # Поместить фокус в поле ввода
ent.bind( '<Return>', play)     # Опеределяем функцию, обработчик события "Ввод"

msg2 = Message(text='Бык - цифра на своём месте.\nКорова - цифра '
               'не на своём месте.')     # Создаём поле сообщений
msg2.pack()                     # Размещаем поле сообщений в окне tk
msg2.config(font=('times', 12, 'normal'),
            width=400)          # Параметры для msg2

mainloop()                      # Цикл ожидания событий

Программа 27.

Рис. 14.

#!/usr/bin/python3
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: t; c-basic-offset: 4; tab-width:$

# Bulls and Cows (Быки и Коровы)
# This is my version of the game, known as "Master-mind".
#
# Created on July 21, 2021.
# Author of this program code : Diorditsa A.
# I thank Sergey Polozkov for checking the code for hidden errors
# Dedicated to classmate Anya Lezhepekova
#
# BullsAndCows.py is distributed in the hope that it will be useful, but
# WITHOUT WARRANTY OF ANY KIND; not even an implied warranty
# MARKETABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See. See the GNU General Public License for more information.
# You can get a copy of the GNU General Public License
# by link http://www.gnu.org/licenses/

from tkinter import *           # Импортируем все функции из библиотеки TKinter
from tkinter.dialog import *    # Импортируем класс dialog для создания окна диалога
from random import shuffle      # Импортируем функцию shuffle (перемешивание) из библиотеки random

z = list('0123456789')          # Создаём список z из строки содержащей 10 цифр
shuffle(z)                      # Перемешиваем элементы списка z
x = z[3:7] if z[3] != '0' else z[4:8]   # Создаём список x из 4-х элементов списка z, так, чтобы '0' не оказался на первом месте

def play(event):                # Функция, созданная пользователем
    global x, z
    '''
    Функция которая получает число из поля ввода от игрока,
    сравнивает каждую цифру введённую игроком с загаданным x,
    и выводит результаты в окно сообщений msg.
    '''
    y = ent.get()               # Введённая игроком в поле ввода строка
    if len(y) !=4:              # Если введённая игроком строка состоит не из 4-х символов,
        return                  # то выйти из функции
    b = 0; c = 0                # Создаём переменные Bulls и Cows
    for i in range(4):          # В цикле из 4-x повторений
        if y[i] == x[i]:        # проверяем цифра на своём месте,
            b += 1              # если да, то добавляем быка
        elif y[i] in x:         # если нет, проверяем есть ли в загаданном числе эта цифра,
            c += 1              # если да, то добавляем корову
    msg2.config(text = 'Ваше число: ' + y + ' содержит ' + str(b) + ' быка и ' + str(c) + ' коровы\n' + msg2.cget('text'))
    ent.delete(0, END)          # Очищаем поле ввода ent
    if b == 4:                  # В случае победы, появляется окно диалога
        gameOwer = Dialog(title = 'Вы победили',
                          text = '     Сыграем ещё?           ',
                          strings = ('Да', 'Нет'),
                          bitmap = 'questhead',
                          default = 0)
        if gameOwer.num == 1:
            exit()              # Закончить игру
        else:                                       # Иначе:
            shuffle(z)                              # Перемешиваем элементы списка z
            x = z[3:7] if z[3] != '0' else z[4:8]   # Создаём список x из 4-х элементов списка z
            msg2.config(text='')                    # Очищаем окно сообщений msg2

def validate_entry(index, myNumber):
    '''
    Функция, допускающая ввод в поле ввода только 4 цифры.
    '''
    pattern = re.compile("^\d{0,4}$")               # паттерн допускает ввод только 4-х цифр
    return pattern.match(myNumber) is not None      # Возвращает объект или None

tk = Tk()                       # Создаём объект окно пиложения и даём ему имя tk
tk.geometry('500x350')          # Задаём размер окна пиложения в пикселях
tk.title('Быки и Коровы')       # title название программы в заголовке окна
msg = Message(text='Введите следующее число от 1023 до 9876 '
              'такое, чтобы цифры, составляющие это число,'
              ' не повторялись!')   # Создаём поле сообщений с именем объекта msg
msg.pack()                      # Выводим поле сообщений на экран в окне tk
msg.config(bg='light grey', fg='olive',
           font=('times', 12, 'italic'),
           width=400)           # Параметры для msg
ent = Entry(width=4)            # Создаём поле ввода
ent.pack()                      # Размещаем поле ввода в окне tk
ent.focus()                     # Поместить фокус в поле ввода
ent.bind( '<Return>', play)     # Опеределяем функцию, обработчик события "Ввод"
valent = (ent.register(validate_entry), "%i", "%P") # Обёртка для передачи параметров в функцию
ent.config(validate="key", validatecommand=valent)  # Валидация при любом изменении содержимого поля

msg2 = Message(text='Бык - цифра на своём месте.\nКорова - цифра '
               'не на своём месте.')     # Создаём поле сообщений
msg2.pack()                     # Размещаем поле сообщений в окне tk
msg2.config(font=('times', 12, 'normal'),
            width=400)          # Параметры для msg2

mainloop()                      # Цикл ожидания событий

Программа 28.

В программе 28 добавлена функция проверки символов вводимых в поле ввода на соответствие правилам игры. Символами должны быть цифры и их должно быть 4. Эту проверку осуществляет функция validate_entry(). Зарегистрирована функция validate_entry(), как валидатор поля ввода ent методом config() с параметрами validate="key" и validatecommand=valent. Где valent = (ent.register(validate_entry), "%i", "%P").

Параметр validate "key", предписывает запускать валидацию при любом изменении содержимого поля ent.

В  validatecommand регистрируется функция, которая вызывается при запуске валидации.

Функция valent создана методом register класса Widget библиотеки tkinter, так как для запуска валидации в функцию validate_entry необходимо передать параметры. "%i", "%P" замещение для каждого параметра, который будет передаться в функцию validate_entry. В итоге эти значения группируются в кортеж.

Кроме того, в функцию play() добавлена проверка количества введённых в поле ввода символов. Если количество введённых в поле ввода символов не равно 4, программа функции play() не выполняется.

Добавляем счётчик ходов.

#!/usr/bin/python3
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: t; c-basic-offset: 4; tab-width:$

# Bulls and Cows (Быки и Коровы)
# This is my version of the game, known as "Master-mind".
#
# Created on July 21, 2021.
# Author of this program code : Diorditsa A.
# I thank Sergey Polozkov for checking the code for hidden errors
# Dedicated to classmate Anya Lezhepekova
#
# BullsAndCows.py is distributed in the hope that it will be useful, but
# WITHOUT WARRANTY OF ANY KIND; not even an implied warranty
# MARKETABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See. See the GNU General Public License for more information.
# You can get a copy of the GNU General Public License
# by link http://www.gnu.org/licenses/

from tkinter import *           # Импортируем все функции из библиотеки TKinter
from tkinter.dialog import *    # Импортируем класс dialog для создания окна диалога
from random import shuffle      # Импортируем функцию shuffle (перемешивание) из библиотеки random

n = 0                           # Счётчик ходов
z = list('0123456789')          # Создаём список z из строки содержащей 10 цифр
shuffle(z)                      # Перемешиваем элементы списка z
x = z[3:7] if z[3] != '0' else z[4:8]   # Создаём список x из 4-х элементов списка z, так, чтобы '0' не оказался на первом месте

def play(event):                # Функция, созданная пользователем
    global x, z, n
    '''
    Функция которая получает число из поля ввода от игрока,
    сравнивает каждую цифру введённую игроком с загаданным x,
    и выводит результаты в окно сообщений msg.
    '''
    y = ent.get()               # Введённая игроком в поле ввода строка
    if len(y) !=4:              # Если введённая игроком строка состоит не из 4-х символов,
        return                  # то выйти из функции
    b = 0; c = 0                # Создаём переменные Bulls и Cows
    for i in range(4):          # В цикле из 4-x повторений
        if y[i] == x[i]:        # проверяем цифра на своём месте,
            b += 1              # если да, то добавляем быка
        elif y[i] in x:         # если нет, проверяем есть ли в загаданном числе эта цифра,
            c += 1              # если да, то добавляем корову
    n += 1                      # увеличиваем счётчик ходов на 1
    msg2.config(text = str(n) + '. Ваше число: ' + y + ' содержит ' + str(b) + ' быка и ' + str(c) + ' коровы\n' + msg2.cget('text'))
    ent.delete(0, END)          # Очищаем поле ввода ent
    if b == 4:                  # В случае победы, появляется окно диалога
        gameOwer = Dialog(title = 'Вы победили за ' + str(n) + ' ходов',
                          text = '     Сыграем ещё?           ',
                          strings = ('Да', 'Нет'),
                          bitmap = 'questhead',
                          default = 0)
        if gameOwer.num == 1:
            exit()              # Закончить игру
        else:                                       # Иначе:
            shuffle(z)                              # Перемешиваем элементы списка z
            x = z[3:7] if z[3] != '0' else z[4:8]   # Создаём список x из 4-х элементов списка z
            msg2.config(text='')                    # Очищаем окно сообщений msg2

def validate_entry(index, myNumber):
    '''
    Функция, допускающая ввод в поле ввода только 4 цифры.
    '''
    pattern = re.compile("^\d{0,4}$")               # паттерн допускает ввод только 4-х цифр
    return pattern.match(myNumber) is not None      # Возвращает объект или None

tk = Tk()                       # Создаём объект окно пиложения и даём ему имя tk
tk.geometry('500x350')          # Задаём размер окна пиложения в пикселях
tk.title('Быки и Коровы')       # title название программы в заголовке окна
msg = Message(text='Введите следующее число от 1023 до 9876 '
              'такое, чтобы цифры, составляющие это число,'
              ' не повторялись!')   # Создаём поле сообщений с именем объекта msg
msg.pack()                      # Выводим поле сообщений на экран в окне tk
msg.config(bg='light grey', fg='olive',
           font=('times', 12, 'italic'),
           width=400)           # Параметры для msg
ent = Entry(width=4)            # Создаём поле ввода
ent.pack()                      # Размещаем поле ввода в окне tk
ent.focus()                     # Поместить фокус в поле ввода
ent.bind( '<Return>', play)     # Опеределяем функцию, обработчик события "Ввод"
valent = (ent.register(validate_entry), "%i", "%P") # Обёртка для передачи параметров в функцию
ent.config(validate="key", validatecommand=valent)  # Валидация при любом изменении содержимого поля

msg2 = Message(text='Бык - цифра на своём месте.\nКорова - цифра '
               'не на своём месте.')     # Создаём поле сообщений
msg2.pack()                     # Размещаем поле сообщений в окне tk
msg2.config(font=('times', 12, 'normal'),
            width=400)          # Параметры для msg2

mainloop()                      # Цикл ожидания событий

Программа 29.

Рис. 15. 

#!/usr/bin/python3
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: t; c-basic-offset: 4; tab-width:$

# Bulls and Cows (Быки и Коровы)
# This is my version of the game, known as "Master-mind".
#
# Created on July 21, 2021.
# Author of this program code : Diorditsa A.
# I thank Sergey Polozkov for checking the code for hidden errors
# Dedicated to classmate Anya Lezhepekova
#
# BullsAndCows.py is distributed in the hope that it will be useful, but
# WITHOUT WARRANTY OF ANY KIND; not even an implied warranty
# MARKETABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See. See the GNU General Public License for more information.
# You can get a copy of the GNU General Public License
# by link http://www.gnu.org/licenses/

from tkinter import *           # Импортируем все функции из библиотеки TKinter
from tkinter.dialog import *    # Импортируем класс dialog для создания окна диалога
from random import shuffle      # Импортируем функцию shuffle (перемешивание) из библиотеки random
from time import *              # Импортируем функции времени

n = 0                           # Счётчик ходов
t = 0                           # Счётчик времени
z = list('0123456789')          # Создаём список z из строки содержащей 10 цифр
shuffle(z)                      # Перемешиваем элементы списка z
x = z[3:7] if z[3] != '0' else z[4:8]   # Создаём список x из 4-х элементов списка z, так, чтобы '0' не оказался на первом месте

def play(event):                # Функция, созданная пользователем
    global x, z, n, t
    '''
    Функция которая получает число из поля ввода от игрока,
    сравнивает каждую цифру введённую игроком с загаданным x,
    и выводит результаты в окно сообщений msg.
    '''
    y = ent.get()               # Введённая игроком в поле ввода строка
    if len(y) !=4:              # Если введённая игроком строка состоит не из 4-х символов,
        return                  # то выйти из функции
    if n == 0:                  # Если это первый ход, то
        t = time()              # запускаем счётчик времени.
    b = 0; c = 0                # Создаём переменные Bulls и Cows
    for i in range(4):          # В цикле из 4-x повторений
        if y[i] == x[i]:        # проверяем цифра на своём месте,
            b += 1              # если да, то добавляем быка
        elif y[i] in x:         # если нет, проверяем есть ли в загаданном числе эта цифра,
            c += 1              # если да, то добавляем корову
    n += 1                      # увеличиваем счётчик ходов на 1
    msg2.config(text = str(n) + '. Ваше число: ' + y + ' содержит ' + str(b) + ' быка и ' + str(c) + ' коровы\n' + msg2.cget('text'))
    ent.delete(0, END)          # Очищаем поле ввода ent
    if b == 4:                  # В случае победы, появляется окно диалога
        gameOwer = Dialog(title = 'Вы победили за ' + str(n) + ' ходов; ' + str(int(time()-t)) + ' сек.',
                          text = '     Сыграем ещё?           ',
                          strings = ('Да', 'Нет'),
                          bitmap = 'questhead',
                          default = 0)
        if gameOwer.num == 1:
            exit()              # Закончить игру
        else:                                       # Иначе:
            shuffle(z)                              # Перемешиваем элементы списка z
            x = z[3:7] if z[3] != '0' else z[4:8]   # Создаём список x из 4-х элементов списка z
            msg2.config(text='')                    # Очищаем окно сообщений msg2
            n = 0                                   # Обнуляем счётчик ходов

def validate_entry(index, myNumber):
    '''
    Функция, допускающая ввод в поле ввода только 4 цифры.
    '''
    pattern = re.compile("^\d{0,4}$")               # паттерн допускает ввод только 4-х цифр
    return pattern.match(myNumber) is not None      # Возвращает объект или None

tk = Tk()                       # Создаём объект окно пиложения и даём ему имя tk
tk.geometry('500x350')          # Задаём размер окна пиложения в пикселях
tk.title('Быки и Коровы')       # title название программы в заголовке окна
msg = Message(text='Введите следующее число от 1023 до 9876 '
              'такое, чтобы цифры, составляющие это число,'
              ' не повторялись!')   # Создаём поле сообщений с именем объекта msg
msg.pack()                      # Выводим поле сообщений на экран в окне tk
msg.config(bg='light grey', fg='olive',
           font=('times', 12, 'italic'),
           width=400)           # Параметры для msg
ent = Entry(width=4)            # Создаём поле ввода
ent.pack()                      # Размещаем поле ввода в окне tk
ent.focus()                     # Поместить фокус в поле ввода
ent.bind( '<Return>', play)     # Опеределяем функцию, обработчик события "Ввод"
valent = (ent.register(validate_entry), "%i", "%P") # Обёртка для передачи параметров в функцию
ent.config(validate="key", validatecommand=valent)  # Валидация при любом изменении содержимого поля

msg2 = Message(text='Бык - цифра на своём месте.\nКорова - цифра '
               'не на своём месте.')     # Создаём поле сообщений
msg2.pack()                     # Размещаем поле сообщений в окне tk
msg2.config(font=('times', 12, 'normal'),
            width=400)          # Параметры для msg2

mainloop()                      # Цикл ожидания событий

Программа 30.

Рис. 16.

Для замера времени, потраченного на поиск загаданного числа, мы ввели в нашу программу 30 счётчик времени.

Функции Time(), int()

Для учёта времени, мы импортировали в программу функции из библиотеки time и создали переменную t. 

Функция time() возвращает время в секундах от начала эпохи с точностью до до 7-ми знаков после запятой.

В тот момент, когда игрок ввёл поле ввода своё первое число и нажал клавишу Enter, в переменной t программа сохраняет время возвращаемое функцией time(). В тот момент, когда игрок одержал победу, в title окна диалога выводится разность time() - t, это и есть время затраченное игроком на поиск числа, загаданного компьютером. 

Время, затраченное игроком на поиск числа вычисляется в секундах, с точностью до 7-ми знаков после запятой. Такая высокая точность нас не интересует, поэтому, используя функцию int() мы округляем значение времени до целых секунд отсекая цифры после запятой. 

Кроме того, в программу (листинг 21), в её заголовок, мы добавили большой блок комментариев, который содержит имя автора программы и лицензионное соглашение. Эта программа распространяется под стандартной GNU General Public лицензией. С полным текстом лицензионного соглашения можно ознакомиться на сайте http://www.gnu.org/licenses/ 

Моей однокласснице Ане Лежепёковой посвящаю.