Журнал LinuxFormat - перейти на главную

LXF102:Flash-карточки

Материал из Linuxformat
Перейти к: навигация, поиск

Содержание

Кодируем: Flash-карточки

ЧАСТЬ 2 Улучшите навыки программиста и выучите иностранный язык – помогут Майк Сондерс и ваш собственный инструмент для показа всплывающих карточек...

Одна из причин нашей любви к компьютерам – их способность просто работать. Конечно, устройства могут ломаться, а программы – содержать ошибки, но когда все в порядке, ваши данные не исчезнут как по волшебству. Если вы загрузите, скажем, норвежский словарь, ваш ПК без возражений сохранит его для последующих вызовов. ПК не будет уставать или пытаться изучить другой язык; не сможет он и упиться до полного забвения места, куда вчера записал данные. Он не поссорится с ПК-дамой и не уничтожит ее файлы на почве ревности. В целостной системе данные всегда под рукой.

Однако здесь, в царстве людей, мы постоянно боремся с недочетами и изворотами нашей мысли. Мы вечно все забываем, меняем свое мнение – короче, лучше бы наш мозг походил на ОЗУ, а не на серые комки органики. Всего очевиднее это при изучении иностранного языка: компьютер хранит миллионы слов и никогда их не «забывает», а мы с трудом припоминаем, как по-английски «встреча», даже если использовали это слово вчера. Спасибо, мозг.

Итак, проект кодирования этого месяца – создание программы всплывающих карточек (flash-карт), которая помогает запоминать иностранные слова. Она отображает английские слова и просит вас выбрать их русский эквивалент из списка трех, случайным образом выбранных, слов, начисляя вам очки по мере вашего прогресса. Но она не ограничивается только английским и пригодится для любого языка, или вообще для всего, что нужно изучить! Вы сможете даже настроить ее на отображение названий животных: пусть спросит вас об их виде.

Новый опыт Python

На LXFDVD прошлого месяца была опубликована подшивка LXF за 2005–2007 года; помимо прочего, в ней можно найти и учебник по языку Python (выпуски 74/7583). Не пугайтесь, если вы пропустили прошлый номер или никогда не писали на Python: в нем очень легко разобраться. Если вы знакомы хоть с одним языком программирования, то не встретите проблем при работе с этим кодом.

Наше приложение flash-карт должно будет читать текстовые файлы и генерировать случайные числа. Открытие файлов в Python – плевое дело: создайте новый текстовый файл с именем foo.txt, вбейте в него несколько слов (по одному в строке) и сохраните в домашнем каталоге. Теперь создайте файл с именем test.py, также в домашнем каталоге, со следующим содержимым:

file = open(‘foo.txt’, ‘r’)
print file.readlines()

Для запуска этого Python-скрипта откройте терминал и введите:

python test.py

Этот код открывает foo.txt (‘r’ означает «только для чтения») и связывает его содержимое с новым объектом по имени file.

Во второй строке кода мы вызываем readlines() нашего объекта file, который сканирует foo.txt и сохраняет его строки как элементы массива. При его печати на экране мы увидим:

[‘hello\n’, ‘banana\n’, ‘cupcake\n’]

Понятно, слова будут те, которые вы ввели в foo.txt. Но отсюда видно, как Python получает текст из файла и выводит элементы массива через запятую. Ну, хорошо; а если мы хотим нормально отобразить текст файла?

file = open(‘foo.txt’, ‘r’)
for line in file:
 print line

Этот код выводит все строки из foo.txt. Заметьте, что отступы в Python важны – табуляция перед print line говорит о том, что этот код выполняется внутри цикла for. Конкретно этот цикл for говорит: для (for) каждой строки открытого нами файла, напечатать ее, и так до конца файла.

Итак, мы теперь можем получать текст из файлов и использовать списки слов для наших flash-карточек. Но надо сделать еще кое-что: наша программа должна отобразить список возможных ответов при выводе слова. Кроме того, было бы крайне бесполезно, если бы верным ответом был всегда первый! Поэтому в нашей программе мы собираемся отображать три возможных ответа, один из которых правильный. Вот как получить случайные числа:

import random
a = random.randint(1, 5)
b = random.randint(30, 100)
print a, b

Первая строка говорит Python, что мы хотим использовать его генератор случайных чисел. После этого мы создаем две переменные: a и b, и присваиваем им случайные значения стандартной подпрограммой Python random.randint(). Мы указываем диапазон значений – для переменной a это будет число от 1 до 5 (включительно). Для b – число между 30 и 100. Легко!

Создаем flashcard.py 1.0

(thumbnail)
Первая инкарнация нашей программы flash-карт – простой текстовый вариант.

Давайте поработаем с программой. Нам понадобятся два текстовых файла: в одном – английские слова, в другом – соответствующие русские. (Или, например, в одном файле могут быть названия стран, а во втором – названия их столиц.) Важно, чтобы оба файла имели одинаковое число строк и соответствие слов для каждой их пары. Если вы используете названия столиц и седьмая строка первого файла – это «Япония», то седьмая строка второго файла должна содержать «Токио». Иначе ответы не подойдут!

Итак, создадим два текстовых файла в домашнем каталоге и введем по десять слов в каждый из них, по одному в строке. В нашем примере, первый файл называется english.txt и содержит слова ‘Thanks, word, job’ и т.д.; второй файл называется russian.txt и содержит ‘спасибо, слово, работа’ и т.д. Теперь нам необходим код на Python, чтобы работать с этими текстовыми файлами в домашнем каталоге – и вот вам листинг. Он есть на нашем DVD (flashcard.py в разделе Magazine/CodeProject), но пока просто пробегитесь по нему...

# -*- coding: utf_8 -*-
import os, random
count = 0
score = 0
file1 = open(‘english.txt’, ‘r’)
file2 = open(‘russian.txt’, ‘r’)
f1content = file1.readlines()
f2content = file2.readlines()
while count < 10:
os.system(‘clear’)
wordnum = random.randint(0, len(f1content)-1)
print ‘Слово:’, f1content[wordnum], ‘’
options = [random.randint(0, len(f2content)-1),
random.randint(0, len(f2content)-1),
random.randint(0, len(f2content)-1)]
options[random.randint(0, 2)] = wordnum
print ‘1 -’, f2content[options[0]],
print ‘2 -’, f2content[options[1]],
print ‘3 -’, f2content[options[2]],
answer = input(‘\n Ваш выбор:’)
if options[answer-1] == wordnum:
raw_input(‘\n Верно! Нажмите enter...’)
score = score+1
else:
raw_input(‘\n Неверно! Нажмите enter...’)
count = count+1
print ‘\n Набрано очков:’, score

При наличии flashcard.py, russian.txt и english.txt в вашем домашнем каталоге откройте терминал и введите python flashcard.py. Вы увидите, что программа отображает английское слово, а ниже – три возможных русских эквивалента. Эти эквиваленты пронумерованы, и если вы считаете, что верный ответ – это 3, просто нажмите 3, а затем Enter. После этого программа скажет вам, правы вы или ошибаетесь – всего будет задано десять вопросов.

Давайте рассмотрим код более детально. Мы начали строкой с import [Русская версия скрипта начинается с указания используемой в системе кодировки, в противном случае программа не будет выполняться, – прим. пер.], которая говорит Python, какие возможности мы собираемся использовать. В нашем случае необходимо вызывать функцию ОС (для очистки экрана) и генерировать случайные числа. Затем мы описываем две переменные, count и score – первая используется для отображения десяти вопросов, а вторая запоминает число верных ответов. Далее идет:

file1 = open(‘english.txt’, ‘r’)
file2 = open(‘russian.txt’, ‘r’)
f1content = file1.readlines()
f2content = file2.readlines()

Здесь мы открываем два файла и связываем их с двумя переменными с именами file1 и file2. Эти переменные – вроде дескрипторов этих файлов: они представляют файлы, сохраненные в памяти. Но нам не нужны просто сами файлы; нам необходимо их содержимое, поэтому следующие две строки кода по кусочкам переносят реальный текст в два массива с именами f1content и f2content. Теперь у нас есть список английских слов в f1content и список русских слов в f2content. Затем начинается основной цикл программы:

while count < 10:
os.system(‘clear’)
wordnum = random.randint(0, len(f1content)-1)
print ‘Слово:’, f1content[wordnum], ‘’

Мы хотим задать десять вопросов, то есть выполнить весь код с отступом десять раз (переменная-счетчик каждый раз увеличивается). Первая строка этого цикла очищает экран, вызывая стандартную утилиту /usr/bin/clear, а затем мы отображаем случайное слово. Мы говорим: wordnum должно принять случайное значение, представляющее строку в файле слов, так что дай мне число между нулем и размером файла (в строках). Хотя файл слов может иметь строки от первой до десятой, массивы нумеруются с нуля, вот почему мы берем случайное число от нуля до числа строк в файле минус один. То есть строка один в f1content (english.txt) – на самом деле нулевой элемент массива, а строка десять – девятый. Затем мы отображаем слово из файла english.txt.

options = [random.randint(0, len(f2content)-1),
random.randint(0, len(f2content)-1),
random.randint(0, len(f2content)-1)]
options[random.randint(0, 2)] = wordnum

Далее создается массив трех возможных ответов с именем options. Мы задаем для каждого ответа случайное число, ограниченное сверху числом строк в f2content (russian.txt). Теперь у нас есть три случайных русских слова – но стойте, одно из них должно быть верным, ведь так? Иначе получится три неверных ответа! Так что положим один из ответов в options равным wordnum – то есть верному. И вместо того, чтобы верный ответ всегда был, скажем, первым, мы размещаем его в случайное место в списке из трех возможных ответов.

Оставшийся код понять очень просто. Он печатает на экране три возможных ответа затем запрашивает ответ у пользователя – то есть ввод 1, 2 или 3. Когда пользователь вводит ответ, мы проверяем, соответствует ли он верному слову. То есть, если русское слово – «спасибо» и номер варианта thanks – «2», когда пользователь вводит 2, наша программа говорит: «Ах! Вариант два является седьмым в файле русских слов. И истинный номер ответа wordnum также равен семи, так что все верно! Слова совпадают.» В точку.

Версия с картинками

Теперь у нас есть текстовый инструмент flash-карт, превосходный для множества применений, а как насчет графической версии? Допустим, картинка с животным и три возможных названия – идеально для детей. А может, вы захотите нарисовать национальные флаги – кстати, именно это мы и собираемся сделать. Как и прежде, программу можно преобразовать во что угодно, использующее слова и картинки: блюда и их названия на испанском, фотографии звезд и их имена...

Для этого необходимо выйти за границы командной строки и воспользоваться графическим слоем. К счастью, у нас есть прекрасный выбор для нашего Python-приключения: PyGame, библиотека, связывающая Python с популярным медиа-слоем SDL. PyGame позволяет создавать окна и отображать соответствующие картинки на экране, причем с минимумом усилий. Собственно, большая часть кода останется той же – надо только заставить отображаться вместо текста картинки.

Наша первая версия flashcard.py использовала два текстовых файла с соответствиями слов, а эта графическая инкарнация будет использовать соответствия слов и картинок. То есть file1.txt может содержать «Непал, Канада, Финляндия...», а file2.txt – ‘nepalflag.png, canadaflag.png, finlandflag.png...’ и так далее. Слова будем получать из file1, а картинки для отображения – из file2.

Код для этого выйдет более длинный, и чтобы зря не тратить место, мы приведем здесь лишь основную часть. Но это большая часть, и она вам покажет, как работает графическая версия. На нашем DVD в разделе Magazine/CodeProject/Graphical имеется полный листинг кода со множеством комментариев (обозначенных символом #).

Заметьте, что перед запуском программы необходимо установить библиотеку PyGame: большинство дистрибутивов имеют ее в своих репозиториях (поищите в вашем менеджере пакетов), но если это не так, исходный код вы найдете в разделе Разработка нашего DVD.

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

init()
screen = display.set_mode((640, 480))
display.set_caption(‘Flashcard’)
font = font.Font(None, 48)
while count < 10:
screen.fill(0)
wordnum = random.randint(0, len(f2content)-1)
mainpic = image.load(f2content[wordnum].rstrip(‘\n’))
screen.blit(mainpic, (255, 50))
options = [random.randint(0, len(f1content)-1),
random.randint(0, len(f1content)-1),
random.randint(0, len(f1content)-1)]
options[random.randint(0, 2)] = wordnum
text1 = font.render(‘1 - ‘ + f1content[options[0]].rstrip(‘\n’),
True, (255, 255, 255))
text2 = font.render(‘2 - ‘ + f1content[options[1]].rstrip(‘\n’),
True, (255, 255, 255))
text3 = font.render(‘3 - ‘ + f1content[options[2]].rstrip(‘\n’),
True, (255, 255, 255))
screen.blit(text1, (30, 200))
screen.blit(text2, (30, 300))
screen.blit(text3, (30, 400))
display.update()

Первые четыре строки кода говорят PyGame настроить экран. Мы инициализируем PyGame, а затем велим ему создать новое окно размером 640 x 480 пикселей, поместив в заголовок окна соответствующий текст. Затем создаем новый шрифт: создадим объект с именем font, используя собственную систему шрифтов PyGame, и скажем ‘None’, что означает: нам неважно, какой шрифт использовать – пусть будет стандартный системный. А размер шрифта установим 48 пунктов.

Затем запускается главный цикл, выдавая десять вопросов. screen. fill(0) просто заполняет экран нулевым цветом, то есть черным – это очищает окно для каждого вопроса. Затем мы выбираем строку для случайного слова, которое будет ответом, так же, как и в текстовой версии, а затем у нас идет:

mainpic = image.load(f2content[wordnum].rstrip(‘\n’))

Это довольно большая инструкция, так что давайте разберем ее. Мы создаем новый объект PyGame: картинку с именем mainpic, для отрисовки на экране. Однако картинку необходимо откуда-то загрузить, и это должна быть картинка для верного ответа – а мы здесь сказали, чтоб Python выбрал ее случайным образом.

Как и до этого, в полном коде мы загружаем два текстовых файла в f1content и f2content. f1content содержит список слов – в нашем случае, «Непал, Канада, Финляндия...». f2content содержит список имен соответствующих файлов изображений: ‘nepalflag.png, canadaflag.png, finlandflag.png...’. Наша переменная wordnum указывает на слово в f1content, а также на имя файла связанного изображения в f2content. Если wordnum равно 2, то она может указывать на «Непал» в f1content и ‘nepal.png’ в f2content – вот почему записи в файлах должны попарно соответствовать друг другу!

Итак, загружаем нашу картинку в соответствии с именем файла из f2content, удалив символ перевода строки при помощи rstrip – не то PyGame нас не поймет! Далее, делаем один из трех вариантов правильным, как и ранее. Затем создаем три отрывка текста для отображения на экране. Вот первый:

text1 = font.render(‘1 - ‘ + f1content[options[0]].rstrip(‘\n’),True, (255, 255, 255))
(thumbnail)
При помощи Python и PyGame, мы теперь можем создать графический тест вроде этого.

Здесь создается новое изображение с именем text1, содержащее первый случайный вариант из нашего списка слов f1content. True означает, что текст должен быть сглаженным, а (255, 255, 255) – цвет текста в формате красный, зеленый, синий: белый, стало быть. Делаем то же для других вариантов, затем отрисуем (blit) текст на экране и обновим его, чтобы все отобразилось.

Оставшийся код с комментариями, который вы можете просмотреть на нашем DVD, обрабатывает ввод пользователя. Мы проверяем, что нажал пользователь – 1, 2 или 3 – и реагируем соответственно: выводим «Верно!» и обновляем счетчик очков, или выводим «Неверно!». Затем ждем нажатия Enter и вновь запускаем цикл.

Завершаем

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

С этой программой можно еще много чего сделать, и если у вас получится что-то классное, пожалуйста, сообщите нам, и мы, возможно, разместим это на нашем DVD. Если у вас возникли вопросы по данному уроку, обратитесь к разделу Программирование на http://www.linuxforum.ru. Наслаждайтесь!

Персональные инструменты
купить
подписаться
Яндекс.Метрика