<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="http://wiki.linuxformat.ru/wiki/skins/common/feed.css?303"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
		<id>http://wiki.linuxformat.ru/wiki/index.php?action=history&amp;feed=atom&amp;title=LXF113-114%3APython</id>
		<title>LXF113-114:Python - История изменений</title>
		<link rel="self" type="application/atom+xml" href="http://wiki.linuxformat.ru/wiki/index.php?action=history&amp;feed=atom&amp;title=LXF113-114%3APython"/>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/index.php?title=LXF113-114:Python&amp;action=history"/>
		<updated>2026-05-13T07:23:59Z</updated>
		<subtitle>История изменений этой страницы в вики</subtitle>
		<generator>MediaWiki 1.19.20+dfsg-0+deb7u3</generator>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/index.php?title=LXF113-114:Python&amp;diff=9873&amp;oldid=prev</id>
		<title>2sash-kan: /* Не останавливайтесь на достигнутом */</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/index.php?title=LXF113-114:Python&amp;diff=9873&amp;oldid=prev"/>
				<updated>2010-03-14T14:53:14Z</updated>
		
		<summary type="html">&lt;p&gt;‎&lt;span dir=&quot;auto&quot;&gt;&lt;span class=&quot;autocomment&quot;&gt;Не останавливайтесь на достигнутом&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;table class='diff diff-contentalign-left'&gt;
				&lt;col class='diff-marker' /&gt;
				&lt;col class='diff-content' /&gt;
				&lt;col class='diff-marker' /&gt;
				&lt;col class='diff-content' /&gt;
			&lt;tr valign='top'&gt;
			&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;← Предыдущая&lt;/td&gt;
			&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;Версия 14:53, 14 марта 2010&lt;/td&gt;
			&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Строка 278:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Строка 278:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;&amp;#160;&lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;Сложнее добавить дополнительные диски. Во многих версиях ханойских башен число дисков можно выбрать в начале, и даже с пятью дисками для решения головоломки нужно сделать гораздо больше ходов. Функцию '''try_move()''' изменять не потребуется, но придется переписать метод '''draw_discs()''' для обработки большего количества сочетаний дисков и для того, чтобы сделать игру гораздо сложнее.&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;&amp;#160;&lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;Сложнее добавить дополнительные диски. Во многих версиях ханойских башен число дисков можно выбрать в начале, и даже с пятью дисками для решения головоломки нужно сделать гораздо больше ходов. Функцию '''try_move()''' изменять не потребуется, но придется переписать метод '''draw_discs()''' для обработки большего количества сочетаний дисков и для того, чтобы сделать игру гораздо сложнее.&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;&amp;#160;&lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;&amp;#160;&lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;−&lt;/td&gt;&lt;td style=&quot;background: #ffa; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;Дайте нам знать, что у вас получится! Если у вас есть вопросы по коду или вы хотите поделиться идеями с другими читателями, присоединяйтесь к дискуссиям на Линуксфоруме (http://&lt;del class=&quot;diffchange diffchange-inline&quot;&gt;www&lt;/del&gt;.&lt;del class=&quot;diffchange diffchange-inline&quot;&gt;linuxforum.ru&lt;/del&gt;). '''LXF'''&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;background: #cfc; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;Дайте нам знать, что у вас получится! Если у вас есть вопросы по коду или вы хотите поделиться идеями с другими читателями, присоединяйтесь к дискуссиям на Линуксфоруме (http://&lt;ins class=&quot;diffchange diffchange-inline&quot;&gt;unixforum&lt;/ins&gt;.&lt;ins class=&quot;diffchange diffchange-inline&quot;&gt;org&lt;/ins&gt;). '''LXF'''&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;&amp;#160;&lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;&amp;#160;&lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;&amp;#160;&lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;===Списки и башни===&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;&amp;#160;&lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;===Списки и башни===&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;</summary>
		<author><name>2sash-kan</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/index.php?title=LXF113-114:Python&amp;diff=9485&amp;oldid=prev</id>
		<title>Crazy Rebel: викификация, оформление, иллюстрация</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/index.php?title=LXF113-114:Python&amp;diff=9485&amp;oldid=prev"/>
				<updated>2010-01-14T13:56:25Z</updated>
		
		<summary type="html">&lt;p&gt;викификация, оформление, иллюстрация&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Новая страница&lt;/b&gt;&lt;/p&gt;&lt;div&gt;: Пишем игру-головоломку, изучая ''PyGame''&lt;br /&gt;
&lt;br /&gt;
{{Цикл/Python}}&lt;br /&gt;
&lt;br /&gt;
==Кодируем: Башни Ханоя==&lt;br /&gt;
&lt;br /&gt;
: В последней статье этого цикла '''Майк Сондерс''' задействует все изученные нами приемы в одном проекте.&lt;br /&gt;
&lt;br /&gt;
В прошлых номерах мы с вами написали клон ''Space Invaders'' и гоночную игру. Мы узнали, как работать со спрайтами, выводить текст, проигрывать музыку и обрабатывать ввод с клавиатуры. Отличная подготовка к последнему проекту! После длительных размышлений мы решили, что лучшим способом обобщить полученные знания будет игра «''Ханойские башни''».&lt;br /&gt;
&lt;br /&gt;
Если вы никогда раньше не играли в ханойские башни, вот суть процесса: у вас есть три стопки, в которые можно складывать диски.&lt;br /&gt;
Вначале все диски находятся в левой стопке, и цель игры – переместить их в правую. Но брать диски можно только по одному, причем на меньший диск нельзя класть больший. Все диски имеют разный размер, и после решения головоломки на правой башне внизу должен лежать&lt;br /&gt;
самый большой диск, а вверху – самый маленький.&lt;br /&gt;
&lt;br /&gt;
В нашей версии с воображаемым названием ''PyHanoi'' будет всего три диска – это упростит код. В конце мы узнаем, как можно добавить еще дисков. Это поможет вам, если у вас уже есть некоторый опыт программирования. Но не будем зацикливаться на теории – перейдем сразу к делу!&lt;br /&gt;
&lt;br /&gt;
===Часть 1 Готовим почву===&lt;br /&gt;
&lt;br /&gt;
Как и раньше, мы будем использовать ''Python'' и ''PyGame'': очень простой в понимании язык программирования и очень полезный набор подпрограмм для мультимедиа. На нашем DVD в разделе '''Журнал/Coding''' вы найдете файл '''PyHanoi.tar.gz'''; скопируйте его в свой домашний каталог и распакуйте. В получившейся директории вы найдете подкаталог '''data''' – он содержит изображения и музыкальные файлы, которые позволят персонализировать игру; вот что вам нужно о них знать.&lt;br /&gt;
* '''backdrop.jpg''' Фоновая картинка игры размером 640 х 480 пикселей. Если захотите изменить ее, подбирайте светлую и неконтрастную, что-&lt;br /&gt;
бы диски было хорошо видно.&lt;br /&gt;
* '''disc1.png, disc2.png''' и '''disc3.png''' Изображения дисков. Мы смотрим на башни спереди, и диски показаны как прямоугольники. Откройте их в ''GIMP'', чтобы определить разрешение, если хотите создать новые. &lt;br /&gt;
* '''highlight1.png''' и '''highlight2.png''' Это желтый и красный прямоугольники, которые будут отображаться поверх одной из групп дисков и перемещаться, когда пользователь нажимает стрелки вправо и влево. Мы будем использовать желтый прямоугольник, когда пользователь выбирает группу дисков, и красный, когда он нажал '''Enter''', подтверждая отмеченный вариант.&lt;br /&gt;
* '''music.mod''' Музыкальный файл в формате MOD (например, созданный в ''SoundTracker''), который будет проигрываться бесконечно.&lt;br /&gt;
&lt;br /&gt;
Смело изменяйте любой из этих файлов (или попросите кого-нибудь другого поработать над ними, пока будете изучать код!). Или&lt;br /&gt;
просто ими воспользуйтесь. Прежде чем писать код, составим короткий алгоритм игры. В ''PyHanoi'' игрок сначала выделяет одну из стопок и&lt;br /&gt;
нажимает '''Enter''' для выбора диска. Затем он выделяет другую стопку и перемещает диск. Если ход является корректным, мы обновляем счетчик в переменной '''moves'''. Таким образом, алгоритм будет следующим:&lt;br /&gt;
# Нарисовать все на экране (фон, диски, счетчик очков, выделить текущие группы дисков).&lt;br /&gt;
# Проверить нажатия клавиш (стрелка влево/вправо для перемещения выделения, '''Enter''' для выбора диска и '''Esc''' для выхода).&lt;br /&gt;
# Попробовать переместить диск, если игрок выбрал одну группу дисков, а затем другую. В случае успеха учесть «'''+1'''» в счетчике ходов.&lt;br /&gt;
# Перейти к пункту '''1'''.&lt;br /&gt;
&lt;br /&gt;
Во врезке «Списки для башен» можно узнать, как мы будем использовать те или иные возможности ''Python'' для реализации групп дисков&lt;br /&gt;
нашей игры. После того, как разберетесь с этим, запустите программу (''python pyhanoi.py'') и увидите, как она работает.&lt;br /&gt;
&lt;br /&gt;
===Часть 2 Разбираемся в коде===&lt;br /&gt;
&lt;br /&gt;
{{Врезка | Заголовок=Скорая помощь | Содержание= Если вы привыкли программировать на другом языке, обратите внимание на то, что в ''Python'' для обозначения блоков кода используются отступы. Здесь нет фигурных скобок, как в ''C'': циклы, блоки '''if''' и т.п. выделяются отступами. Проще всего делать их с помощью табуляции. Но можно оформить отступы и с помощью пробелов, лишь бы их количество было&lt;br /&gt;
одинаковым для всего блока. | Ширина=200px}}&lt;br /&gt;
&lt;br /&gt;
В ''PyHanoi'' имеются функции (подпрограммы), поэтому лучше пройтись по коду в порядке его выполнения. В начале файла ''pyhanoi.py'' мы&lt;br /&gt;
видим:&lt;br /&gt;
&lt;br /&gt;
 from pygame import *&lt;br /&gt;
&lt;br /&gt;
Эта строка одинакова во всех наших проектах: она сообщает ''Python'' о нашем желании использовать все возможности библиотеки ''PyGame''&lt;br /&gt;
(звездочка здесь является шаблоном, как в оболочке). Далее идут наши функции:&lt;br /&gt;
&lt;br /&gt;
 def wait_for_key():&lt;br /&gt;
 ...&lt;br /&gt;
 def draw_discs():&lt;br /&gt;
 ...&lt;br /&gt;
 def try_move(first, second):&lt;br /&gt;
&lt;br /&gt;
Функции, в порядке следования, приостанавливают программу, ожидая нажатия клавиши; рисуют на экране диски в соответствии с их текущим положением на башнях; и пытаются переместить диск с одной башни на другую по правилам игры. Их код здесь не показан, потому что нам пока незачем вникать, как они работают – мы вернемся к ним позже. Далее, создаем окно игры:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
 init()&lt;br /&gt;
 screen = display.set_mode((640,480))&lt;br /&gt;
 display.set_caption(‘PyHanoi’)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данный код инициализирует ''PyGame'', создает окно размером&lt;br /&gt;
640 x 480 пикселей и устанавливает его заголовок. Теперь загрузим&lt;br /&gt;
вышеупомянутые изображения:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
 backdrop = image.load(‘data/backdrop.jpg’)&lt;br /&gt;
 disc1 = image.load(‘data/disc1.png’)&lt;br /&gt;
 disc2 = image.load(‘data/disc2.png’)&lt;br /&gt;
 disc3 = image.load(‘data/disc3.png’)&lt;br /&gt;
 highlight1 = image.load(‘data/highlight1.png’)&lt;br /&gt;
 highlight2 = image.load(‘data/highlight2.png’)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В ''PyGame''' это делается очень просто: вызовите функцию '''image.load()''' с именем файла в качестве аргумента, и она вернет объект изображения, который можно вывести на экран и поработать с ним. Кроме изображений, нам понадобится шрифт для счетчика ходов и сообщения об ошибке при попытке некорректного перемещения:&lt;br /&gt;
&lt;br /&gt;
  movesfont = font.Font(None, 40)&lt;br /&gt;
&lt;br /&gt;
Этот код создает новый объект шрифта '''movesfont''' с гарнитурой ‘'''None'''’ и размером '''40'''. Вместо ‘'''None'''’ можно указать настоящее имя шрифта, но его может не оказаться на другом компьютере – поэтому проще использовать ‘'''None'''’ (при этом загружается общий шрифт семейства Sans Serif). &lt;br /&gt;
&lt;br /&gt;
Пока все идет молчком; добавим-ка немного музыки. &lt;br /&gt;
&lt;br /&gt;
  mixer.music.load(‘data/music.mod’)&lt;br /&gt;
  mixer.music.play(-1)&lt;br /&gt;
&lt;br /&gt;
Здесь мы загружаем и проигрываем музыкальный файл в формате MOD с помощью модуля '''mixer''' библиотеки ''PyGame''. Параметр '''-1'''&lt;br /&gt;
означает, что музыка будет звучать бесконечно (в смысле, пока мы не выйдем из игры).&lt;br /&gt;
&lt;br /&gt;
Итак, у нас есть функции, изображения загружены и проигрывается прекрасная музыка. Пора перейти к логике программы.&lt;br /&gt;
&lt;br /&gt;
  stack = [[3, 2, 1], [], []]&lt;br /&gt;
&lt;br /&gt;
Эта строка кода создает три списка, обозначенных квадратными скобками. Списки соответствуют башням. В начале игры все диски&lt;br /&gt;
находятся на первой башне, поэтому первый список содержит [3, 2, 1] – самый большой диск с номером 3 внизу и самый маленький с номером 1 наверху (и его уже можно перемещать). Два других списка соответствуют пустым башням, поэтому они пустые [].&lt;br /&gt;
&lt;br /&gt;
Нам также нужно создать несколько переменных:&lt;br /&gt;
&lt;br /&gt;
  moves = 0&lt;br /&gt;
  position = 0&lt;br /&gt;
  selected1 = -1&lt;br /&gt;
  selected2 = -1&lt;br /&gt;
&lt;br /&gt;
Первая – наш счетчик ходов, содержащий общее число перемещений за всю игру. Вторая обозначает башню, выделенную желтым прямоугольником – игрок сможет двигать его с помощью стрелок вправо и влево. У нас есть три башни с номерами 0, 1 и 2; так, если '''position''' равна '''0''', то первой будет выделена первая башня. Переменные '''selected1''' и '''selected2''' будут хранить номер башни, на которой игрок нажал '''Enter''', чтобы переместить диск. В самом начале игры и в любой момент, когда игрок не выделяет башни для перемещения, эти переменные будут равны '''-1''', то есть они ни на что не указывают.&lt;br /&gt;
&lt;br /&gt;
Наша следующая задача – начать основной цикл игры:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
  quit = 0&lt;br /&gt;
  while (quit == 0):&lt;br /&gt;
   screen.blit(backdrop, (0,0))&lt;br /&gt;
   draw_discs()&lt;br /&gt;
   if selected1 == -1:&lt;br /&gt;
     screen.blit(highlight1, (position * 200 + 30, 250))&lt;br /&gt;
   else:&lt;br /&gt;
     screen.blit(highlight2, (position * 200 + 30, 250))&lt;br /&gt;
   movestext = movesfont.render(‘Moves: ‘ + str(moves), True, (255,255,255), (0,0,0))&lt;br /&gt;
   screen.blit(movestext, (5,5))&lt;br /&gt;
   display.update()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Мы создаем новую переменную '''quit''' и устанавливаем ее в '''0'''. Основной цикл игры начинается с команды '''while'''. Будут выполняться&lt;br /&gt;
все команды с отступом, пока переменная '''quit''' не сменит свое значение с нуля на какое-то другое (например, если нажата клавиша '''Esc''', как мы скоро увидим). В начале цикла надо все нарисовать, поэтому сначала мы «блитируем» (выводим) фоновое изображение в главное окно, начиная с точки с координатами '''0,0''' – это его левый верхний угол. В ''PyGame'', как и в большинстве графических библиотек, начало координат находится в левом верхнем углу, и координаты отсчитываются от нуля. Таким образом, координаты правого нижнего угла окна будут равны '''639, 479'''.&lt;br /&gt;
&lt;br /&gt;
Прорисовав фон, мы вызываем функцию '''draw_discs()''': она проходит по трем башням и отрисовывает все находящиеся на них диски&lt;br /&gt;
в соответствующих местах экрана. Затем мы рисуем прямоугольник выделения: если пользователь перемещает диск и нажал '''Enter''', мы&lt;br /&gt;
изображаем '''highlight2''' (красный прямоугольник) в текущей позиции. В противном случае, рисуем только '''highlight1''' (желтый прямоугольник). Горизонтальная координата прямоугольника на экране определяется выражением '''position * 200 + 30''': в зависимости от значения переменной '''position''' он будет выведен на расстоянии '''30, 230''' или '''430''' пикселей справа (и всегда на '''250''' пикселей вниз от начала координат).&lt;br /&gt;
&lt;br /&gt;
Затем мы создаем изображение '''movestext''' путем обращения к созданному ранее объекту '''movesfont'''. Первый параметр содержит слово&lt;br /&gt;
Moves:, объединенное с количеством ходов (конвертированным в строку с помощью функции '''str()'''). Второй параметр, '''‘True’''', велит использовать сглаживание. Затем идут два цвета (в нашем случае – белый текст на черном фоне). В конце мы выводим созданное изображение&lt;br /&gt;
'''movestext''' на экран.&lt;br /&gt;
&lt;br /&gt;
===Обрабатываем ввод игрока===&lt;br /&gt;
&lt;br /&gt;
Обратите внимание, что до сих пор все графические операции осуществлялись в скрытом графическом буфере: это делалось по соображениям производительности. Их результат не появится на экране, пока не будет вызван метод '''display.update()'''. Пора обработать ввод с&lt;br /&gt;
клавиатуры от игрока:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
 ourevent = event.wait()&lt;br /&gt;
 if ourevent.type == KEYDOWN:&lt;br /&gt;
   if ourevent.key == K_ESCAPE:&lt;br /&gt;
     quit = 1&lt;br /&gt;
   if ourevent.key == K_LEFT and position &amp;gt; 0:&lt;br /&gt;
     position -= 1&lt;br /&gt;
   if ourevent.key == K_RIGHT and position &amp;lt; 2:&lt;br /&gt;
     position += 1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь все очевидно: мы ожидаем появления события, которым может быть обновление экрана, перемещение мыши и т.д. Нам интересно только событие '''KEYDOWN''': оно возникает, когда пользователь нажимает какую-то клавишу. И стоит пользователю так сделать, как мы проверяем, что это за клавиша: если '''Esc''', то устанавливаем созданную ранее переменную '''quit''' в '''1''', это остановит основной цикл игры.&lt;br /&gt;
&lt;br /&gt;
Если пользователь нажал стрелку вправо или влево, нужно обновить переменную '''position''', определяющую, где нужно нарисовать прямоугольник выделения. Но нужно также проверить, не пытается ли игрок переместить прямоугольник слишком далеко, поэтому условия&lt;br /&gt;
'''position &amp;gt; 0''' и '''position &amp;lt; 2''' ограничивает значения переменной множеством из 0, 1 и 2 – другими словами, прямоугольник нельзя перемещать за пределы башен.&lt;br /&gt;
&lt;br /&gt;
Следующий фрагмент чуть сложнее. Если пользователь нажимает '''Enter''', это означает, что он хочет выбрать башню, на которую нужно&lt;br /&gt;
переместить диск:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
   if ourevent.key == K_RETURN:&lt;br /&gt;
     if selected1 == -1:&lt;br /&gt;
       selected1 = position&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
То есть, если игрок еще ничего не выбрал (переменная '''selected1''' равна '''-1'''), мы устанавливаем ее в текущую позицию. Однако если&lt;br /&gt;
'''selected1''' не равна '''-1''', это означает, что игрок уже нажал '''Enter''' на этой башне и тем самым уже выбрал исходную башню для операции перемещения диска. Поэтому в данном случае игрок выбирает другую башню – целевую.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
   else:&lt;br /&gt;
     selected2 = position&lt;br /&gt;
     if selected2 == selected1:&lt;br /&gt;
       selected1 = -1&lt;br /&gt;
       selected2 = -1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Мы записываем в '''selected2''' текущую позицию. А что будет, если игрок выберет одну и ту же башню как источник и место назначения?&lt;br /&gt;
Ну, в этом случае делать ничего не нужно, поэтому мы сбрасываем переменные '''selected1''' и '''selected2''' в их исходные значения '''-1''' – это означает, что все начинается снова.&lt;br /&gt;
&lt;br /&gt;
Если были выбраны разные башни, выполняется этот код:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
   else:&lt;br /&gt;
     x = try_move(selected1, selected2)&lt;br /&gt;
    moves += x&lt;br /&gt;
    selected1 = -1&lt;br /&gt;
    selected2 = -1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Чтобы определить, можно ли переместить диск с башни '''selected1''' на башню '''selected2''', мы вызываем функцию '''try_move()''' (через минуту мы о ней поговорим). Функция '''try_move()''' возвращает '''1''', если диск перемещен успешно, и '''0''' в противном случае. Мы обновляем счетчик перемещений и сбрасываем '''selected1''' и '''selected2''' для нового перемещения.&lt;br /&gt;
&lt;br /&gt;
На этом основной код заканчивается! Он не обращает внимание на то, решили ли вы головоломку: необходимые изменения (например,&lt;br /&gt;
вывод на экран красочных поздравлений) можно добавить позже. А сейчас взглянем на функции, определенные в начале программы. Вот&lt;br /&gt;
первая из них:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
 def wait_for_key():&lt;br /&gt;
   ourevent = event.wait()&lt;br /&gt;
   while ourevent.type != KEYDOWN:&lt;br /&gt;
       ourevent = event.wait()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Она просто приостанавливает выполнение программы вплоть до нажатия клавиши. Рисуем диски:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
 def draw_discs():&lt;br /&gt;
   offset = 50&lt;br /&gt;
   for x in range (0, 3):&lt;br /&gt;
     if stack[x] == [3, 2, 1]:&lt;br /&gt;
        screen.blit(disc3, (offset, 400))&lt;br /&gt;
        screen.blit(disc2, (offset+25, 380))&lt;br /&gt;
        screen.blit(disc1, (offset+50, 360))&lt;br /&gt;
   ...&lt;br /&gt;
   offset += 200&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Функция пробегает по башням (в цикле '''for x in range''') и для каждой из них проверяет порядок дисков. Для первой башни диски отображаются на расстоянии 50 пикселей от левого края экрана с использованием переменной '''offset''', а переходя к следующей башне, мы прибавляем к смещению 200 и двигаемся дальше вправо. От самого большого до самого малого ширина дисков уменьшается на 50 пикселей, поэтому для центрирования дисков на башне используются выражения '''offset+25''' и '''offset+50'''.&lt;br /&gt;
&lt;br /&gt;
Обратите внимание, что код функции приведен здесь не полностью: есть несколько одинаковых проверок и операций вывода для дисков различных типов, но их код мало чем отличается. Так что строки, помеченные здесь многоточием, можно посмотреть в исходном файле '''pyhanoi.py'''.&lt;br /&gt;
&lt;br /&gt;
Наконец, мы пришли к самой важной функции – коду, выполняющему перемещение диска. Он принимает в качестве аргументов два числа – номера исходной и целевой башен:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
 def try_move(first, second):&lt;br /&gt;
   if len(stack[first]) == 0:&lt;br /&gt;
     return 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Номер исходной башни содержится в переменной '''first''', целевой – в '''second'''. Мы проверяем, равна ли нулю длина списка для первой башни; если да, то с нее нечего снимать, операция перемещения некорректна и мы возвращаемся к основному коду (0 означает, что перемещения не произошло). Но если первый список не пуст:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
  if len(stack[first]) &amp;gt; 0 and len(stack[second]) == 0:&lt;br /&gt;
     a = stack[first].pop()&lt;br /&gt;
     stack[second].append(a)&lt;br /&gt;
     return 1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Мы проверяем, пуст ли список целевой башни. Если это так, мы просто извлекаем число из списка для первой башни и добавляем его в список для второй. Вуаля – диск на новом месте! Но вдруг оба списка не пусты? Мы не можем просто взять диск из первого списка и добавить во второй: нужно следовать правилам и не позволять игроку класть больший диск на меньший.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
   else:&lt;br /&gt;
    if len(stack[first]) &amp;gt; 0 and len(stack[second]) &amp;gt; 0:&lt;br /&gt;
      a = stack[first].pop()&lt;br /&gt;
      b = stack[second].pop()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь мы записываем во временные переменные '''a''' и''' b''' верхние диски каждой башни. Затем&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
      if a &amp;gt; b:&lt;br /&gt;
        invalidtext = movesfont.render(‘Invalid move!’, True, (255,255,255), (0,0,0))&lt;br /&gt;
        screen.blit(invalidtext, (235,200))&lt;br /&gt;
        display.update()&lt;br /&gt;
        wait_for_key()&lt;br /&gt;
        stack[first].append(a)&lt;br /&gt;
        stack[second].append(b)&lt;br /&gt;
        return 0&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если диск на исходной башне больше диска на целевой башне, мы выводим сообщение об ошибке, ждем, пока пользователь нажмет клавишу, возвращаем диски обратно на их башни и выходим из функции. В противном случае&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
    else:&lt;br /&gt;
      stack[second].append(b)&lt;br /&gt;
      stack[second].append(a)&lt;br /&gt;
     return 1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Помните, мы сняли диск со второй башни, чтобы сравнить размеры? Здесь мы помещаем диск обратно на его башню, затем добавляем&lt;br /&gt;
диск с первой башни, завершая перемещение.&lt;br /&gt;
&lt;br /&gt;
{{ Врезка | Содержание= [[Изображение:LXF113_62_1.jpg|300px]] Законченная крутейшая игра, сжатая всего в 120 строк красивого кода.| Ширина=300px}}&lt;br /&gt;
&lt;br /&gt;
===Не останавливайтесь на достигнутом===&lt;br /&gt;
&lt;br /&gt;
В ''PyHanoi'' мы воспользовались знаниями, полученными на предыдущих уроках, и коснулись разработки игры нового типа. Взявшись за&lt;br /&gt;
расширение ''PyHanoi'', можно начать с проверки завершения игры (это несложно). Можно добавить проверки в конце кода и вывести текст&lt;br /&gt;
или изображение перед ожиданием нажатия клавиши и выходом.&lt;br /&gt;
&lt;br /&gt;
Сложнее добавить дополнительные диски. Во многих версиях ханойских башен число дисков можно выбрать в начале, и даже с пятью дисками для решения головоломки нужно сделать гораздо больше ходов. Функцию '''try_move()''' изменять не потребуется, но придется переписать метод '''draw_discs()''' для обработки большего количества сочетаний дисков и для того, чтобы сделать игру гораздо сложнее.&lt;br /&gt;
&lt;br /&gt;
Дайте нам знать, что у вас получится! Если у вас есть вопросы по коду или вы хотите поделиться идеями с другими читателями, присоединяйтесь к дискуссиям на Линуксфоруме (http://www.linuxforum.ru). '''LXF'''&lt;br /&gt;
&lt;br /&gt;
===Списки и башни===&lt;br /&gt;
&lt;br /&gt;
Наша версия ханойских башен проста: в ней всего три башни и три диска, так что на одной башне не может быть больше трех дисков. Перемещая диск, вы всегда берете верхний диск с одной башни и кладете его на верх другой – диск нельзя положить на произвольное место, и вы всегда имеете дело с самым верхним диском. В ''Python'' есть тип данных «список», который позволит нам прекрасно имитировать башни без необходимости возиться с массивами. Посмотрите на список:&lt;br /&gt;
&lt;br /&gt;
 foo = [1, 2, 3]&lt;br /&gt;
&lt;br /&gt;
Эта строка кода объявляет список '''foo''', состоящий из трех элементов (целочисленных переменных). Для извлечения элемента из конца списка используется метод '''pop''':&lt;br /&gt;
&lt;br /&gt;
 a = foo.pop()&lt;br /&gt;
&lt;br /&gt;
Переменная '''а''' теперь содержит значение '''3''', а '''foo''' – '''[1, 2]'''. Размер списка изменяется автоматически – в конце&lt;br /&gt;
не появляется пустого или нулевого элемента. Метод '''append''' добавляет число в список:&lt;br /&gt;
&lt;br /&gt;
  foo.append(99)&lt;br /&gt;
&lt;br /&gt;
Теперь '''foo''' содержит '''[1, 2, 99]'''. Списки позволят нам очень просто создать стопки – ханойские башни, куда мы будем помещать диски (добавляя в список числа). Самому большому диску соответствует число '''3''', самому маленькому – '''1'''.&lt;br /&gt;
&lt;br /&gt;
{{ Врезка | Содержание= [[Изображение:LXF113_61_1.jpg|300px]] Пример башен и содержимого их списков во время игры. Видно, что в списке для средней башни — два элемента [2, 1], так как на нем находятся средний и малый диски. | Ширина=300px}}&lt;br /&gt;
&lt;br /&gt;
Чтобы код был простым (и легко расширяемым), создадим список из трех башен, каждый элемент которого будет содержать подсписок дисков, которые в данный момент находятся на башне. Посмотрите на рисунок: первая башня – '''stack[0]''', вторая – '''stack[1]''' и третья –&lt;br /&gt;
'''stack[2]'''. Каждая содержит список своих дисков. Башня со всеми дисками будет содержать элементы '''[3, 2, 1]''', т.е. самый большой диск (3) находится внизу башни, а самый маленький (1) – наверху. Мы можем взять самый маленький диск сверху и переместить его на другую&lt;br /&gt;
башню (добавить в другой список).&lt;/div&gt;</summary>
		<author><name>Crazy Rebel</name></author>	</entry>

	</feed>