Учим Python, делая крутые игры 2018. Invent your owncomputer gameswith python
Скачать 6.56 Mb.
|
animals = ['аксолотль', 'аргонавт', 'астрильд', 'альберт'] >>> animals[9999] Traceback (most recent call last): File "", line 1, in animals[9999] IndexError: list index out of range Ошибка возникла, потому что элемента с индексом 99999 не существует. Присваивание индексов элементам Значения элементов списка можно изменять путем присваивания индексов. В интерактивной оболочке наберите следующее: >>> animals = ['аксолотль', 'аргонавт', 'астрильд', 'альберт'] >>> animals[1] = 'АРГОНАВТ' >>> animals ['аксолотль', 'АРГОНАВТ', 'астрильд', 'альберт'] Строка, прописанная в списке под вторым индексом, примет новое зна- чение 'АРГОНАВТ'. Таким образом, выражение animals[1] само по себе преоб- разуется в значение списка с индексом два. В данном случае это выражение находится в левой части оператора присваивания, и вся инструкция заносит новое значение в этот элемент списка. Конкатенация списков Можно соединить несколько списков в один , как и обычные строки, исполь- зуя оператор +. Такая операция называется конкатенацией списков. Чтобы пона- блюдать за этой операцией, укажите следующий код в интерактивной оболочке: >>> [1, 2, 3, 4] + ['апельсины', 'яблоки'] + ['Алиса', 'Борис'] [1, 2, 3, 4, 'апельсины', 'яблоки', 'Алиса', 'Борис'] Написание кода игры «Виселица» 127 Выражение ['апельсины'] + ['яблоки'] будет преобразовано в ['апельси- ны', 'яблоки'] . Но выражение ['апельсины'] + 'яблоки' приведет к возникно- вению ошибки. При помощи оператора + нельзя складывать элементы списка и строки. Если необходимо добавить элементы в конец списка, не используя конкатенацию, следует применить метод append(), описанный в разделе «Ме- тоды reverse() и append()» далее в этой главе. Оператор in Оператор in позволяет определить наличие в списке элемента с опреде- ленным значением. Выражения с оператором in возвращают значение True, если искомое значение содержится в списке, или False — если нет. В интерак- тивной оболочке наберите следующее: >>> animals = ['аксолотль', 'аргонавт', 'астрильд', 'альберт'] >>> 'астрильд' in animals True >>> 'муравей' in animals False Выражение 'астрильд' in animals вернет значение True, так как строка 'астрильд' — элемент списка animals. В списке она находится с индексом 2. А вот выражение 'муравей' in animals вернет значение False, потому что стро- ки 'муравей' в списке нет. Оператор in также применим и к строкам. В этом случае он проверяет, является ли одна строка частью другой. Для наглядности наберите в интерак- тивной оболочке следующее: >>> 'привет' in 'Алиса сказала привет Борису.' True Мы получили истинный результат, так как подстрока 'привет' содержит- ся в строке в правой стороне инструкции. Вызов методов Метод — это функция, привязанная к объекту (списку или строке). Для вызова метода необходимо привязать его к конкретному объекту. В языке Python встроено много полезных методов, некоторые из них мы используем 128 Глава 8 в игре «Виселица». Но сначала рассмотрим несколько методов для работы со списками и строками. Методы списков reverse() и append() Списки поддерживают два встроенных метода, которые используются наиболее часто, — reverse() и append() . Метод reverse() разворачивает (об- ращает) список. Попробуйте ввести spam = [1, 2, 3, 4, 5, 6, 'мяу', 'гав'], а затем выполнить spam.reverse() для обращения списка. Далее введите spam, чтобы просмотреть содержимое переменной. >>> spam = [1, 2, 3, 4, 5, 6, 'мяу', 'гав'] >>> spam.reverse() >>> spam ['гав', 'мяу', 6, 5, 4, 3, 2, 1] Но наиболее часто в списках используется метод append(). Он добавляет но- вые значения в конец списка. Наберите в интерактивной оболочке следу ющее: >>> eggs = [] >>> eggs.append('самолет') >>> eggs ['самолет'] >>> eggs.append('теплоход') >>> eggs ['самолет', 'теплоход'] Эти методы изменяют списки, которые их вызывают. Они не создают но- вые списки. Это называется изменением списков по месту. Строковый метод split() Строки имеют встроенный метод split() , который возвращает список, сформированный из строковых переменных, на которые разбивается строка. Попробуйте использовать метод split(), введя следующий код: >>> sentence = input() Моя неутомимая мать только что приготовила нам буррито. >>> sentence.split() ['Моя', 'неутомимая', 'мать', 'только', 'что', 'приготовила', 'нам', 'буррито.'] Написание кода игры «Виселица» 129 В результате получится список из восьми элементов, по одному элемен- ту на каждое слово в исходной строке. Указателем для разделения строки на слова (элементы) является пробел между словами. Пробелы не включаются ни в один элемент списка. В 38-й строке кода игры «Виселица» тоже используется метод split(), как показано ниже. Код выглядит длинным, но, на самом деле, это просто длин- ная строка слов, разделенных пробелами, с вызовом метода split() в конце. Метод split() создает список, в котором каждое слово из строки становится отдельным элементом списка. 38. words = 'аист акула бабуин баран барсук бобр бык верблюд волк воробей ворон выдра голубь гусь жаба зебра змея индюк кит кобра коза козел койот корова кошка кролик крыса курица лама ласка лебедь лев лиса лосось лось лягушка медведь моллюск моль мул муравей мышь норка но- сорог обезьяна овца окунь олень орел осел панда паук питон попугай пума семга скунс собака сова тигр тритон тюлень утка форель хорек черепаха ястреб ящерица'.split() Метод split() облегчает программирование. В самом деле, чтобы создать список, надо записать слова в одинарных кавычках через запятую и заклю- чить их в квадратные скобки. Например, так: ['аист', 'акула', 'бабуин' и так далее. Правда, утомительно? Вы можете добавить собственные слова в код строки 38 или удалить какие-нибудь из них, если не хотите, чтобы они присутствовали в игре. Глав- ное, убедитесь, что слова разделены пробелами. Получение секретного слова из списка В строке 40 определяется функция getRandomWord(). Значения элементов списка передаются аргументу wordlist в качестве параметров. Эта функция возвращает единичное секретное слово из списка. 40. def getRandomWord(wordList): 41. # Эта функция возвращает случайную строку из переданного списка. 42. wordIndex = random.randint(0, len(wordList) - 1) 43. return wordList[wordIndex] В строке 42 из этого списка в качестве значения переменной wordIndex сохраняется элемент со случайным индексом. Случайный выбор элемента производится функцией randint() с двумя аргументами. Первый аргумент — 130 Глава 8 это 0 (для первого возможного индекса), а второй — значение выражения len(wordList) — 1 , определяющего последний возможный индекс. Напомним, индексация элементов списка начинается с 0, а не с 1. Если имеется список из трех элементов, то индекс первого элемента — 0, второ- го — 1, а третьего — 2. Длина такого списка равна 3, но индекса 3 в списке нет. Вот почему в строке 42 из длины списка вычитается единица. Код в строке 42 работает вне зависимости от размеров списка wordList. Теперь вы можете спокойно добавлять и удалять строки из списка wordList. Переменная wordIndex хранит случайный индекс из списка, переданного с помощью параметра wordList. Код в строке 43 возвращает из списка wordList значение элемента с соответствующим индексом, который сохраняется как целое число в wordIndex. Предположим, что ['яблоко', 'апельсин', 'виноград'] передается как аргу- мент в функцию getRandomWord(), тогда randint(0, 2) возвращает 2. Это значит, что строка 43, в которой возвращается значение wordList[2], вернет значение 'виноград' Вот так функция getRandomWord() возвращает случайную строку из списка wordList То есть входными данными для функции getRandomWord() служит список строк, а выходными — случайно выбранная строка. В игре «Виселица», таким образом, выбирается секретное слово, которое будет угадывать игрок. Отображение игрового поля для игрока Далее необходима функция прорисовки игрового поля игры «Виселица». На нем должно отображаться количество введенных игроком букв, угадан- ных как верно, так и ошибочно. 45. def displayBoard(missedLetters, correctLetters, secretWord): 46. print(HANGMAN_PICS[len(missedLetters)]) 47. print() В следующем коде определяется функция с именем displayBoard(). У этой функции есть три параметра: • missedLetters . Строка букв, которые игрок назвал, но их нет в загадан- ном слове; • correctLetters . Строка букв, которые игрок угадал в загаданном слове ; • secretWord . Строка с загаданным словом, которое игрок пытается уга- дать. Написание кода игры «Виселица» 131 Сначала функция print() вызывает отображение игрового поля. Гло- бальная переменная HANGMAN_PICS содержит список строковых переменных для прорисовки всех возможных этапов игры. (Напомню, что глобальные переменные доступны из функции.) Код HANGMAN_PICS[0] отображает пустую «виселицу», код HANGMAN_PICS[1] показывает голову (когда игрок назвал не- правильно одну букву), код HANGMAN_PICS[2] показывает голову и тело (когда игрок неправильно назвал две буквы) и так далее до HANGMAN_PICS[6], которая показывает «висельника» целиком. Число букв, сохраняемое в переменной missedLetters, отражает количе- ство неправильных предположений, сделанных игроком. Для определения этого числа вызывается функция len(missedLetters). То есть если значение переменной missedLetters равно, к примеру, 'аист', то код len('аист') вернет 4 . Код HANGMAN_PICS[4] отобразит повешенного, соответствующего четырем промахам. Это то, во что преобразуется код HANGMAN_PICS[len(missedLetters)] в строке 46. Код в строке 49 выводит сообщение 'Ошибочные буквы:' с символом про- бела в конце, вместо символа новой строки. 49. print('Ошибочные буквы:', end=' ') 50. for letter in missedLetters: 51. print(letter, end=' ') 52. print() В строке 50 начинается цикл for, в котором происходит перебор всех сим- волов из строчного значения переменной missedLetters и вывод их на экран. Напомню, что выражение end=' ' замещает символ новой строки, который по- мещается в конце каждой строки, — единичным пробелом. Например, если зна- чение missedLetters равно 'аызх', то такой цикл for выведет на экран а ы з х. Остальная часть кода функции displayBoard() (строки 54–62) выводит на экран буквы и формирует строку — секретное слово, в котором еще не уга- данные буквы замещены пробелами. Это достигается с помощью функции range() и среза списка. Функции list() и range() Функция range() , вызываемая с одним аргументом, возвращает последо- вательность чисел от 0 до величины аргумента, сам аргумент в последователь- ность не включается. Такую последовательность можно использовать в цикле for , но можно и преобразовать в список с помощью функции list() . Введите в интерактивную оболочку код list(range(10)): 132 Глава 8 >>> list(range(10)) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> list('Привет') ['П', 'р', 'и', 'в', 'е', 'т'] Функция list() очень похожа на функции str() или int(). Она принима- ет последовательность величин и возвращает их в виде списка. С помощью функций list() и range() легко генерировать огромные списки. Например, наберите в интерактивной оболочке код list(range(10000)): >>> list(range(10000)) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,... -- пропуск-- ...9990, 9991, 9992, 9993, 9994, 9995, 9996, 9997, 9998, 9999] Получившийся список настолько огромен, что не помещается на экране. Но этот список можно сохранить в переменной. >>> spam = list(range(10000)) Если функция range() вызывается с двумя целочисленными аргументами, она возвращает последовательность чисел, начиная с первого аргумента до (не включая) второго. Попробуйте набрать код list(range(10, 20)) и вы по- лучите следующее: >>> list(range(10, 20)) [10, 11, 12, 13, 14, 15, 16, 17, 18, 19] Как видим, список начинается с 10 и доходит только до 19, не вклю- чая 20. Срезы списков и строк Срез списка создает новый список с подмножеством элементов родитель- ского списка. Для создания среза списка используются два индекса (началь- ный и конечный), которые помещаются в конец имени, в квадратных скобках Написание кода игры «Виселица» 133 и разделяются двоеточием. Для примера наберите в интерактивной оболочке следующее: >>> spam = ['апельсины', 'бананы', 'морковка', 'халапеньо'] >>> spam[1:3] ['бананы', 'морковка'] Выражение spam[1:3] выводит список с элементами из списка spam, индек- сы которых от 1 до (не включая) 3. Если опустить первый индекс, то вместо него Python будет использовать индекс 0. >>> spam = ['апельсины', 'бананы', 'морковка', 'халапеньо'] >>> spam[:2] ['апельсины', 'бананы'] Если опустить второй индекс, то будет выведена оставшаяся часть спи- ска, начиная с указанного индекса. >>> spam = ['апельсины', 'бананы', 'морковка', 'халапеньо'] >>> spam[2:] ['морковка', 'халапеньо'] Такие же срезы можно производить и со строками. Символы строк будут аналогичны элементам списка. Наберите в интерактивной оболочке следу- ющее: >>> myName = 'Марсик объелся мышей' >>> myName[4:12] 'ик объел' >>> myName[:10] 'Марсик объ' >>> myName[7:] 'объелся мышей' В следующей части кода нашей игры используются срезы. 134 Глава 8 Вывод секретного слова с пробелами При желании можно вывести секретное слово с пробелами вместо неуга- данных букв. Можно также использовать символ нижнего подчеркивания (_) . Сначала нужно создать строку из символов нижнего подчеркивания для всех букв секретного слова. Затем заменить пробелы этими символами. На- пример, для секретного слова 'ворон' пустая строка-подчеркивание выглядит так: '_ _ _ _ _' (пять подчеркиваний). Если значение переменной correctLeters равно 'он', секретное слово надо напечатать в виде: '_ о _ о н'. Код в стро- ках 54–58 делает именно это. 54. blanks = '_' * len(secretWord) 55. 56. for i in range(len(secretWord)): # заменяет пропуски отгаданными буквами 57. if secretWord[i] in correctLetters: 58. blanks = blanks[:i] + secretWord[i] + blanks[i+1:] В строке 54 создается строковая переменная blanks, с подчеркиваниями по числу букв секретного слова. Напомню, что оператор * применим для перемен- ных строкового и целого типов, поэтому выражение '_'*5 будет преобразовано в строку '_ _ _ _ _'. Эта операция служит гарантом того, что переменная blanks содержит столько же подчеркиваний, сколько букв в секретном слове. Код в строке 56 в цикле for производит последовательный перебор всех букв секретного слова и замещает подчеркивания буквами, содержащимися в переменной correctLetters. Давайте рассмотрим цикл предыдущего примера с другими данными, пусть секретное слово 'ворон', а значение переменной correcLetters равно 'он'. Нуж- но вывести на экран строку '_ о _ о н'. Давайте подумаем, как это сделать. Код в строке 56 после вызова len(secretWord) вернет значение 5. Вызов range(len(secretWord)) примет вид range(5), тогда цикл for произведет итера- ции от 0 до 4 включительно. Так как значение переменной i будет последовательно принимать значе- ния [0, 1, 2, 3, 4], код цикла for будет выглядеть примерно так: if secretWord[0] in correctLetters: blanks = blanks[:0] + secretWord[0] + blanks[1:] if secretWord[1] in correctLetters: blanks = blanks[:1] + secretWord[1] + blanks[2:] -- пропуск-- Написание кода игры «Виселица» 135 Мы показали только две первые итерации цикла for, но, на самом деле, переменная итерации i поочередно будет принимать все значения последо- вательности, начиная с 0. В первой итерации i будет равна 0, поэтому оператор if проверит, содер- жится ли буква секретного слова с индексом 0 в строке correctLetters. Такая проверка будет произведена в цикле для каждой буквы секретного слова, по одной итерации на каждую букву. Если вы сомневаетесь в отношении, какого либо значения, например secretWord[0] или blank[3:], обратитесь к рис. 8.1. Там показаны значения secretWord, переменной blanks и индексы для каж- дой буквы в строке. blanks secretWord 0 1 2 3 4 o t t e r 0 1 2 3 4 _ _ _ _ _ в о о н р Рис. 8.1. Индексы строк blanks и secretWord Если срез списка и список индексов заменить значениями их элементов, то код цикла выглядел бы примерно так: if 'в' in 'он': # False blanks = '' + 'в' + '____' # Код в строке пропускается. -- пропуск-- if 'н' in 'он': # True blanks = '_о_о_' + 'н' + '' # Код в строке выполняется. # переменной blanks присвоено значение _о_он'. Пример кода, приведенный выше, делает все то же самое, когда значе- ние secretWord равно 'ворон', а значение correctLetters равно 'он'. Следующий фрагмент кода выводит на экран новое значение blanks с пробелами между буквами. 60. for letter in blanks: # Показывает секретное слово с пробелами между буквами 61. print(letter, end=' ') 62. print() 136 Глава 8 Отметим, что цикл for в строке 60 не вызывает функцию range(). Вместо ранжирования операций последовательностью возвращаемой range, итера- ции производятся по значению строковой переменной blanks. При каждой итерации берется одна новая буква из строки 'ворон' переменной blanks. В результате после добавления пробелов будет выведено '_о_о_н'. Получение предположений игрока При вызове функции getGuess() игрок может ввести предполагаемую бук- ву. Эта функция возвращает букву, предложенную игроком, в виде строки. Далее функция getGuess() проверяет допустимость введенного символа, пре- жде чем передать его в функцию. 64. def getGuess(alreadyGuessed): 65. # Возвращает букву, введенную игроком. Эта функция проверяет, что игрок ввел только одну букву и ничего больше. Строка букв, предложенных игроком, передается в качестве аргумента в параметр alreadyGuessed функции. Затем функция getGuess() просит игро- ка ввести одну букву. Эту букву функция getGuess() вернет как свое значе- ние. Так как Python чувствителен к регистру, следует убедиться, что введена строчная буква, чтобы ее можно было корректно сопоставить с буквами се- кретного слова. Для этого понадобится метод lower(). |