Вступ
На уроці про цикли я казав, що оператор циклу ‘for’ ми залишимо на пізніше. Так, от пізніше – настало! 😉
Цикл “for”
Якщо зовсім просто, то цикл “for” виконує певний набір дій для кожного значення у списку. Давайте одразу перейдемо до простого прикладу із списком.
1 2 3 4 5 6 7 8 9 |
# приклад 'for' циклу # спочатку створимо список, по якому пізніше будемо пробігатись myList = [10, 'test string', 1234, "Longer Sentence String.", -21] # створюємо цикл і пробігаємось по списку myList призначаючи тимчасовій змінній # 'value' поточний елемент списку, тобто при першому колі змінна value матиме # значення 10, а при останньому -21 for value in myList: print value |
Як ви бачите, коли цикл виконується, він пробігає по усіх значеннях у списку, що йде одразу за ключовим словом ‘in’. Тоді він призначає значення із списку змінній value, запускає своє тіло (тіло циклу), кожен раз маючи змінну value встановлену у поточне значення із списку. Давайте розглянемо ще один приклад з використанням циклу ‘for’ для закріплення:
1 2 3 4 5 6 7 8 |
name = raw_input("What is your name?") print "Hello" for letter in name: print letter print "!" |
Спробуйте перенабрати дану маленьку програму у своєму редакторі і тоді запустити. Вже зрозуміли, що саме вона виконує? І взагалі, працює? … Програма питає ваше ім’я, а тоді друкує кожну літеру вашого імені в окремому рядочку. Що слід тут зауважити:
- як ми з вами бачимо, стрічки (пам’ятаємо: стрічка – це рядочок тексту) у Python є фактично списком символів. Тобто по ній можна пробігатися як по звичайному списку використовуючи цикл ‘for’.
- пригадуємо функцію ‘raw_input’ – це вбудована пітонівська функція, яка дозволяє нам приймати ввід від користувача.
Ніби все. Досить все просто з циклом ‘for’. Погодьтеся 🙂
Створення Функції Меню
А тепер давайте троги попишемо програми. На даний момент ми з вами вивчили, що таке змінні, списки, цикли та функції. Цього абсолютно достатньо для нас, щоб трохи погрограмувати! То ж давайте призначимо тепер собі завдання. Завданням буде ГРА! Яка саме – поясню далі у наступній секції. А поки, для гри необхідна функція друкування меню. Тому почнемо саме з неї. Ось код функції з детальними поясненнями і коментарями.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
# Функція Меню # Функція виводитиме користувачу меню доступних опцій і # проситиме його зробити свій вибір. Після того як користувач # зробив вибір - функція повертатиме назовні вибір користувача. # визначаємо функцію під назвою 'menu', функція наша приймає 2 аргументи # list - це буде список опцій # question - це стрічка, питання до користувача, щоб він зробив вибір def menu(list, question): # пробігаємось по усіх опціях у списку і роздруковуємо їх користувачу # на екран для подальшого вибору for entry in list: # будь-який пітонівський список має метод index, # цей метод приймає елемент списку як аргумент і повертає # індекс даного елементу у списку # Таким чином у рядочку нижче ми виводимо на екран поточний # елементу entry у списку list, збільшуємо його на одиничку, щоб # для користувача список починався з 1, а не з нуля (адже # пам'ятаємо в пітоні індекси елементи у списку починаються з 0) print 1 + list.index(entry), # закриваємо номер опції дужкою, ну і звичайно не забуваємо # вивести після дужки саму назву опції print ") " + entry # після того як вивели усі доступні опції, час і запитати користувача # зробити свій вибір - вивівши на екран питання. # Зауважте, ми віднімаємо одиничку від отриманого від користувача # вибору, щоб отримати справжню позицію елемента зі списку (пам'ятаємо # у рядочках вище ми спеціально цю одиничку додавали при виводі опцій) return input(question) - 1 |
Саме призначення функції може на даний момент бути не до кінця зрозумілим, адже ми ще не дійшли до моменту її використання у нашій грі. Але це ми з’ясуємо пізніше. На даний момент головне, щоб ми з вами розібралися у самій суті даної функції. Я спеціально додав багато коментарів, буквально на кожну стрічку коду. Коментарів, як бачите, значно більше за сам код. В більшості випадків мати коментарі у вашому коді (звичайно не так багато як у прикладі вище, а лише у потрібних місцях, які важко зрозуміти без підказок) є дуже хорошою ідеєю. Особливо, якщо ви плануєте публікувати свій код, щоб інші могли ним користуватися та дописувати у нього, коментарі ніколи не будуть зайвими.
Наша перша “Гра”
Зараз ми з вами напишемо просту текстову приходницьку гру. Звучить цікаво? Гра відбуватиметь лише в одній кімнаті будинку, і в цій кімнаті, окрім дверей, будуть ще 5 предментів. В одному із цих 5-ти предметів будуть знаходитись ключі. Задача гравця знайти ключ і вийти через двері з кімнати. Давайте для початку розберемо хід гри на людській мові. Це ще називається псевдокодом. З його допомогою ми спробуємо окреслити загальний хід (алгоритм) гри.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
Даємо комп'ютеру знати про нашу функцію меню (яку ми напередодні з вами описали) Роздруковуємо на екран для користувача привітальне повідомлення, також описуємо кімнату. Також повідомляємо користувача про п'ять речей у кімнаті: вазонок, картина, ваза, туфля, абажур. Ну і не забуваємо сказати про двері ;) Говоримо комп'ютеру, що двері закриті. Говоримо комп'ютеру де знаходяться ключі. Виводимо користувачу меню вказуючи на речі, які він може обирати: Даємо набір із 6-ти опцій (5 предметів + двері) Задаємо питання: "На що ви поглянете тепер?" Якщо користувач хотів поглянути на: вазонок: Якщо ключ є тут, тоді даємо гравцю ключ Інакше, кажемо, що немає ключа, знову виводимо меню картина: такі самі дії як і у випадку з вазонком і т.д. по решті 3х предментів у кімнаті двері: Якщо гравець має ключ, тоді дозволяємо йому їх відкрити Інакше, кажемо йому, щоб шукав краще Ну і наприкінці, даємо гравцю невеличку похвалу за вдало закінчену гру :) |
Тобто, як бачите, суть гри – найти ключ і відкрити ним двері. Щоб знайти ключ – треба по черзі заглядати під різні предмети. Чим швидше – тим краще. А тепер давайте це все перепишемо на мову… звісно, Python 🙂
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
# -*- coding: utf-8 -*- # ГРА ПРИГОДИ В КІМНАТІ (майже як у фільми пила, тільки без жахів ;) # наша старенька функція меню, далі побачимо як ми її застосовуватимемо def menu(list, question): for entry in list: print 1 + list.index(entry), print ") " + entry return input(question) - 1 # визначаємо список предментів у кімнаті + двері # зауважте, усі вони з літерою u спереду - це означає, що це юнікодові стрічки items = [u"вазонок", u"картина", u"ваза", u"абажур", u"туфля", u"двері"] # визначаємо змінну яка містить значення предмету під яким схований ключ # пам'ятаючи, що нумерація у списку починається з нуля, у нашому випадку (2) # ключ буде схований під вазою (ваза є 3ім елементом у списку items) keylocation = 2 # цю змінну ми використовуватиме як флажочок, який вказуватиме нам чи знайшов # гравець уже ключ, чи ще ні # 0 - не знайшов, 1 - знайшов # тобто початково гравець без ключа звісно ;) keyfound = 0 # ця змінна говоритиме циклу чи продовжувати свою дію, якщо loop стане не 1, # наприклад 0 - тоді цикл зупиниться. Таким чином, тіло циклу має можливість, # через змінну loop, впливати на зупинку самого циклу. loop = 1 # Виведемо привітання та деякі пояснення гравцю щодо гри. Легенда :) print "Останньої ночі ви пішли спати у своєму комфортному ліжечку у " print "власному домі." print "" print "Але тепер, пробудившись, опинився у закритій кімнаті. Ти не знаєш " print "як ти попав туди, і навіть яка зараз година. В кімнаті ти бачиш" print len(items), "речей:" # в цикли роздрукуємо ці речі for x in items: print x print "" print "Двері зачинені! Можливо ключ десь всередині кімнати?" # хватить легенд і містики, вперед до гри! # запускаємо цикл, який "бігатиме" допоки гравець не знайде ключа while loop == 1: # використовуючи нашу функцію меню виводимо гравцю набір опцій для вибору # та просимо його зробити вибір choice = menu(items, "Що саме ти хочеш зараз перевірити? ") # скористаємося умовними операторами для перевірки, чи знайдено ключ у # обраній речі if choice == 0: # заглядаємо під вазонок if choice == keylocation: # ура! знайдено ключ print u" Ти знайшов маленький ключик у вазонку!" # додаємо трохи вертикальних відступів для краси print "" # ключ знайдено, даємо комп'ютеру знати про цю подію використовуючи # наш, наперед визначений флажечок - keyfound keyfound = 1 else: # невдача спіткала print u" Ти нічого не знайшов у вазонку." print "" # і повторюємо процедуру для інших 4-ох речей elif choice == 1: if choice == keylocation: print u" Ти знайшов маленький ключик за картиною!" print "" keyfound = 1 else: print u" Ти нічого не знайшов за картиною." print "" elif choice == 2: if choice == keylocation: print u" Ти знайшов маленький ключик у вазі!" print "" keyfound = 1 else: print u" Ти нічого не знайшов у вазі." print "" elif choice == 3: if choice == keylocation: print u" Ти знайшов маленький ключик над абажуром!" print "" keyfound = 1 else: print u" Ти нічого не знайшов над абажуром." print "" elif choice == 4: if choice == keylocation: print u" Ти знайшов маленький ключик у туфлі!" print "" keyfound = 1 else: print u" Ти нічого не знайшов у туфлі." print "" # особливий вибір - двері elif choice == 5: # у двері можна пройти лише, коли вони відчені, а відчинити їх можна # лише якщо уже знайдений ключих був гравце у попередньому раунді циклу if keyfound == 1: # також завершуємо цикл loop = 0 # відкрив? print u" Ти вставив ключик у замкову щілину, провернув його, " \ u"і... почув клік!" print "" else: # ні - треба шукати ключик спочатку print u" Двері зачинені, спочатку треба знайти ключ." print "" # ну і привітання переможцю :) # пам'ятаємо - бекслеш (\) дозволяє перенести на наступний рядок стрічку коду, # що ще не завершилась print u"Світло пробивається у відкриту кімнату крізь відчинені тобою двері. " \ u"Двері до твоєї свободи! :-)" |
Так, досить проста, але цікава у кодуванні, гра. Не лякайтеся великої кількості коду у грі, близько 70 рядочків – це просто ‘if’ оператори, які насправді є однією з найпростішим частин програми. Спробуйте запустити гру у власному пітон інтерпретаторі та побавитись. Це також допоможе краще і легше зрозуміти суть коду. Якщо виникають питання стосовно логіки – постіть у коментарі. Але, загалом, надіюсь моїх коментарів у коді є достатньо, щоб осягнути загальну картину. Сподобалось? Якщо так, тоді у наступних уроках спробуємо більше ігор 🙂
Покращуємо Гру
Першим вашим питанням має бути “Ця гра працємо?”. Так. Тоді маєте мене запитати “Ця програма є добре написаною?” Логіка – добра, а от кількість рядочків можна зменшити. В грі ми використали функцію menu і це дозволило нам зменшити велику кількість рядків у програмі. А от ‘while’ цикл виглядає трохи “кучеряво” з усіма її вкладеними підрівнями коду, як на просту програму. Ми можемо це зробити краще! Коли ми з вами познайомимося з класами, ця програма матиме можливість набути значно кращого вигляду. Але покищо ми з вами можемо поправити кількість коду використавши старий добрий метод – створення фукцій. Це те, що ми вже освоїли з попереднього уроку. Напишемо функцію, яка прийматиме 2 аргументи – вибір гравця та місцезнаходження ключа. А повертатиме дана функція одну річ – чи був знайдений ключ. Давайте подивимося:
1 2 3 4 5 6 7 8 9 10 11 |
def check(choice, location): if choice == location: print "" print u"Ти знайшов ключ!" print "" return 1 else: print "" print "Нічого цікавого тут." print "" return 0 |
Тепер маючи функцію check можемо трішки підправити нашу гру і зробити наш головний цикл трохи коротшим. У прикладі внизу я навів лише цикл, адже решта програми залишилася без змін:
1 2 3 4 5 6 7 8 9 |
while loop == 1: keyfound = check(menu(items, "Куди цього разу заглянемо? "), keylocation) if keyfound == 1: print u" Ти вставив ключик у замкову щілину, провернув його, " \ u"і... почув клік!" loop = 0 print u"Світло пробивається у відкриту кімнату крізь відчинені тобою двері. " \ u"Двері до твоєї свободи! :-)" |
Ух! Який маленький тепер цикл! З більше 70ти рядочків на менше 10ти! Звичайно, ви напевно вже здогадалися, що у даному варіанті циклу, ми втратили трохи функціоналу. Як от наприклад – окрема обробка дверей. Тепер усі речі однакові, і кроку з виходом через двері тепер немає. Тепер для виграшу достатньо знайти ключ, і все. Тобто гра стала трошки менш цікавою, а також трохи важчою для подальших можливих змін. Але цьому також можна зарадити декількома змінами у нашій функції check. Якими? Це вже вам на домашнє завдання.
На завершення
Якщо сподобалось, тоді пропоную вам на домашнє завдання спробувати написати власну просту пригодницьку гру на зразок тої, що ми написали протягом даного уроку. При цьому не забувайте звертатися до попередніх уроків по безцінний матеріал, що ми з вами проходили. Якщо важко з новою грою, тоді ось список покращень до нашої вже написаної гри:
- додати кілька новий речей куди можна ховати ключ
- замінити замок у дверях, який потребує двох ключів, тобто гравець повинен знайти два ключі, і аж тоді вийти
- після кімнати запрограмувати вхід в коридор, звідти вихід у кухню, аж тоді на двір. Одним словом на скільки фантазія розіграється 🙂
- намалювати гру у командній стрічці, 2d варіант. Обриси кімнати, речей. Це вже для advanced юзерів 😉
Дякую за спільно пройдений урок. Мені було цікаво його писати, надіюсь вам цікаво, а головне корисно, його вивчати. Далі розберемо з вами КЛАСИ і трошки ООП! Буде дуже повчально. Але спершу – перепочиньте! 🙂
Чи може хтось переглянути мій варіант гри з двома ключами? Питання чи цей варіант розв’язку завдання з двома ключами “логічно правильний”?
Приклад:
keylocation1 = 5 # ключ1
keylocation2 = 6 # ключ2
keyfound1 = 0 # флажок1
keyfound2 = 0 # флажок2
# додав умовні оператори:
if choice == keylocation1:
keyfound1 = 1
elif choice == keylocation2:# умова при знаходженні ключа2
keyfound2 = 1
# і завершення циклу:
if (keyfound1)+(keyfound2) == 2: # умова при якій знайдено два ключа
loop = 0
отак доробив функцію меню.
тепере не вибиваєколи ми тест введемо чи числа інші
def menu(list, question):
for entry in list:
print 1 + list.index(entry),
print “) ” + entry
ans = raw_input(question)
if ans.isdigit() and int(ans) > 0 and int(ans) < 7 and len(ans)!=0 :
ans = int(ans)
return ans -1
else :
print u"ведіть номер варіанту цілим числом!"
значить порядок превірки має значення. якщо ans.isdigit() допустимо в кінці блоку умов то значення ans = 2.5 програму кладе)
по друге я так зрозумів що поки не пройшло ретарну то функція буде крутитись по колу?
бо коли я в елсі робив
menu(items, u"Що саме ти хочеш зараз перевірити? ") #ну викликав рекурентно виходить бо хотів повтору запитання при надто хитрому користувачеві
то виявилось це зайвим. а з ним приходилось два рази вводити вірне для перевірки іфа значення
значить на поччатку програми в нас прірнти в коді програми йдуть без u на поатку. і вони ієрогліфами. список в нас вже йде з u тому виводится нормально. і потім коли ми граємо то більшість виводів. йде з u івони коректні.
а от наприклад
choice = menu(items, “Що саме ти хочеш зараз перевірити? “) виводитимется кожен раз абракадаброю. тобто все що є в циклі але без u
Дякую, Віталій!
До твого уроку ніяк не міг збагнути, що можна передавати функції в якості аргументів, та яким чином і що можна з функцій повертати.
У варіанті покращення:
def check(choice, location):
if choice == location:
Якщо функція приймає аргументами вибір гравця та місцезнаходження ключа, аргументом має бути keylocation
Питання по завданню: замінити замок у дверях, який потребує двох ключів, тобто гравець повинен знайти два ключі, і аж тоді вийти.
Через команду keylocation = random.randint(0,6) я зробив так, щоб місце ключів кожного разу було нове. Для двох ключів я переписав код таким чином :
if choice == keylocation:
print u” Ти знайшов маленький ключик за картиною!”
print “”
keyfound = keyfound+1
keylocation = random.randint(0,6)
І тепер в мене питання. Як зробити так, щоб у рендомі можна було виключити одну позицію, в якій ключ вже був знайдений? В мене на думці є тільки один варіант, це на початку коду задати дві змінні (keylocation1, keylocation2) та надати одній рандом наприклад (0,2), а другій (3,6). Проте якщо перший ключ під першим предметом, то немає сенсу перевіряти другий під наступними двома. То чи можна в команді random.randint() робити виключення?
сам думай. а чи можна randint робити виключення – загугли доку по даній функції. сам, сам, сам 😉
Команду keylocation = random.randint(0,6) ще не вивчала, але в ситуації з двома ключами спробувала виключати зі списку предмет, який вже подивились через del items[choice] у def check.
А чому ти не розглядаєш варіант, коли обидва ключі сховані в одному місці?
Для прикладу, я створив дві змінні key1location та key2location, обидві random.randint()
В def check_key() за допомогою логічних виразів and та or обшукую предмети на наявність кожного з ключів:
if choise == key1location and choise == key2location:
elif choise == key1location or choise==key2location:
else:
Додаю лічильник ключів, а головний цикл while мотається, доки лічильник !=2
варто вказати, що на початку програми прописуємо (у всякому разі в 2.7) прописуємо:
import random
все-таки це курс для новачків…
Доповнення до гри так і не зрозумів як заюзати і де саме вони повинні бути розташовані 🙁
Також виникли з грою проблеми. Код копiював 1 в 1. Коли обираєш вірний варінт по місцю знаходження ключа, то воно пише що “так, ви знайшли там-то”, але на цьому гру не закінчує і продовжує пропонувати по новому зробити вибір місця.
При цьому keylocation прописано як і у початку програми, так і далі, де варіант може бути вірним.
Ну а з юнікодом то взагалі якась лажа) Частину нормально, частину ієрогліфами. І то, почало хочаб частину сприймати лише після того, як добавив у початку строку “#!/usr/bin/python”. Але нормально показує лише ті місця, где стоїть “u. Інші – кракозябри) Пробував ставити “u на початку коментів, але нічого не дало. Схоже воно так не працює 🙂
У розділі “Покращуємо гру” шось якесь незрозуміле питання))
“Першим вашим питанням має бути “Ця гра працємо?”. Так”
Привіт. замість циклу ряд.42-46 вставив print list(items), та мені виводить [‘\xe2\xe0\xe7\xee\xed\xee\xea’, ‘\xea\xe0\xf0\xf2\xe8\xed\xe0’, ‘\xe2\xe0\xe7\xe0’, ‘\xe0\xe1\xe0\xe6\xf3\xf0’, ‘\xf2\xf3\xf4\xeb\xff’, ‘\xe4\xe2\xe5\xf0\xb3’], пробув забрати ‘u’все рівно без змін, скопіював код і вставив у новий файл, без змін. коли на латині то все ок.
це нормально. якщо спробуєш принтанути окремий елемент списку print items[0] тоді має конвертнути в байт-стрінгу і відповідно кириличні символі покажуться як завжди.
Проблема с кодуванням. Користуюсь нотпад ++ . При запуску гри тексти з іерогліфами. Копіюю Ваш код. Перелік речей в стовбчик українськоюЮ а решта іерогліфами … Бьюся вже пів години з кодуваннями і нічого не допомагає
Прибрав # -*- coding: utf-8 -*- із коду і всі літери u після оператора print. Все запрацювало. Кодировку в notepad поставив Ansi так як на utf-8 не рпацювало чогось (
Можливо редактор коду не зберігає в utf-8. Треба налаштувати.
Доброго дня.
Було б корисним використати функцію генерації випадкового числа, інакше ключ завжди буде знаходитися під вазою.
А так і діткам цікавіше запускати гру щераз і початківцям дізнатися про цю функцію.
keyfound = random.randint(0,5)
хороша ідея!
у мене в екліпсі видає таку помилку:
Останньої ночі ви пішли спати у своєму комфортному ліжечку у
власному домі.
Але тепер, пробудившись, опинився у закритій кімнаті. Ти не знаєш
як ти попав туди, і навіть яка зараз година. В кімнаті ти бачиш
6 речей:
вазонок
картина
ваза
абажур
туфля
двері
Двері зачинені! Можливо ключ десь всередині кімнати?
1
) вазонок
2
) картина
3
) ваза
4
) абажур
5
) туфля
6
) двері
Що саме ти хочеш зараз перевірити? 2
Traceback (most recent call last):
File “E:\work\workspace\vitaliy_podoba\v_p_lesson_7.py”, line 55, in
choice = menu(items, “Що саме ти хочеш зараз перевірити? “)
File “E:\work\workspace\vitaliy_podoba\v_p_lesson_7.py”, line 12, in menu
return input(question) – 1
TypeError: unsupported operand type(s) for -: ‘str’ and ‘int’
будь ласка перевірте.
все працює добре. дивно, чому у тебе input функція не конвертує передані дані від користувача у ціле число.
спробуй просто огорнути виклик input у функцію int()
З’явилась ось така помилка. Що з нею робити?
Останньої ночі ви пішли спати у своєму комфортному ліжечку у власному домі.
Але тепер, пробудившись, опинився у закритій кімнаті. Ти не знаєш як ті попав туди, інавіть яка зараз година. В кімнаті ти бачиш
6 речей:
вазок
картина
ваза
абажур
туфля
двері
Двері зачинені! Можливо ключ десь всередині кімнати?
1 )вазок
2 )картина
3 )ваза
4 )абажур
5 )туфля
6 )двері
Traceback (most recent call last):
File “C:/Users/mpodanev/YandexDisk/1. Обучение/Python/Гра”, line 25, in
choice = menu(items, “Що саме ти хочешь зараз перевірити? “)
File “C:/Users/mpodanev/YandexDisk/1. Обучение/Python/Гра”, line 6, in menu
return input(question) – 1
NameError: global name ‘question’ is not defined
ти код програми копіював собі в редактор чи вручну переписував?
виглядає на те що радок коду із змінною question або за межами функції, або функція не приймає аргумента question
Я не можу вловити сутi роботи utf-8. Коли вставляю текст ГРИ в редактор, то укр символи вiдображаються iероглiфами, окрiм списку речей – з ними все ок. Коли роблю змiну в кодi з
# -*- coding: utf-8 -*-
на
“# -*- coding: utf-8 -*-”
то отримую зворотний ефект – весь укр текст вiдображений коректно, за вийнятком списку речей – вони iероглiфи…
В мене python 2.7
Знайшов відповідь на своє питання. Якщо ми прописуємо в першому рядку гри про наявність юнікода, тоді не треба перед принтами писати інструмент “u”, інакше виходить конфлікт. Принаймні, в мене так було.
цікаво. у мене і хідер є і u і все ок.
який у тебе редактор? то у ньому мабуть причина…