Pull to refresh

Пишем игру Реверси на Python + PyQt4

Reading time 6 min
Views 16K
Задали нам как-то написать небольшой проект — игру Реверси.
А так как сейчас я изучаю Python, решил писать на нем. Вместе с графической библиотекой PyQt4.
Ну так за чем же дело встало? Создаем SVN и вперед! (Переехали на Github)

Вот такое чудо у меня получилось:
Скриншот игры

По словам википедии (а я с ней вполне согласен)
В игре используется квадратная доска размером 8 × 8 клеток (все клетки могут быть одного цвета) и 64 специальные фишки, окрашенные с разных сторон в контрастные цвета, например, в белый и чёрный. Клетки доски нумеруются от верхнего левого угла: вертикали — латинскими буквами, горизонтали — цифрами. Один из игроков играет белыми, другой — чёрными. Делая ход, игрок ставит фишку на клетку доски «своим» цветом вверх.
В начале игры в центр доски выставляются 4 фишки: чёрные на d5 и e4, белые на d4 и e5.
  • Первый ход делают чёрные. Далее игроки ходят по очереди.
  • Делая ход, игрок должен поставить свою фишку на одну из клеток доски таким образом, чтобы между этой поставленной фишкой и одной из имеющихся уже на доске фишек его цвета находился непрерывный ряд фишек соперника, горизонтальный, вертикальный или диагональный (другими словами, чтобы непрерывный ряд фишек соперника оказался «закрыт» фишками игрока с двух сторон). Все фишки соперника, входящие в «закрытый» на этом ходу ряд, переворачиваются на другую сторону (меняют цвет) и переходят к ходившему игроку.
  • Если в результате одного хода «закрывается» одновременно более одного ряда фишек противника, то переворачиваются все фишки, оказавшиеся на всех «закрытых» рядах.
  • Игрок вправе выбирать любой из возможных для него ходов. Если игрок имеет возможные ходы, он не может отказаться от хода. Если игрок не имеет допустимых ходов, то ход передаётся сопернику.
  • Игра прекращается, когда на доску выставлены все фишки или когда ни один из игроков не может сделать хода. По окончании игры проводится подсчёт фишек каждого цвета, и игрок, чьих фишек на доске выставлено больше, объявляется победителем. В случае равенства количества фишек засчитывается ничья.


Python я знаю на базовом уровне. Что-то писал под Google App Engine (например, костыль для себя для получения удобного RSS канала пользователя YouTube, но не об этом речь). Что-то просто так. Что-то для проекта Эйлера (отличный сайт надо сказать). В общем, игрался:)

С Qt до этого дела не имел. Но разобраться, как оказалось, совсем не сложно.
Основа основ, на русском. А также документация тут и тут. Вместе с дистрибутивом PyQT4 идет хорошая база примеров, которые тоже помогли мне разобраться.

На установке и настройке интерпретатора и библиотек останавливаться смысла нет, это и так кучу раз разжевано и никаких подводных камней мне не встретилось.
Как я уже написал, с Qt я до этого не работал. И первой сложностью было разобраться с системой виджетов, как вообще строится взаимодействие с пользователем. Но впринципе, разобраться совсем несложно, сверяясь с примерами и документацией.
Следующей сложностью было написать простенький AI. Идея была подсмотрена где-то в дебрях интернета и адаптирована под реверси.
Copy Source | Copy HTML
  1. def compStep(player):
  2.     table = [
  3.                 [1, 8, 2, 2, 2, 2, 8, 1],
  4.                 [8, 8, 6, 5, 5, 6, 8, 8],
  5.                 [2, 6, 4, 3, 3, 4, 6, 2],
  6.                 [2, 5, 3, 1, 1, 3, 5, 2],
  7.                 [2, 5, 3, 1, 1, 3, 5, 2],
  8.                 [2, 6, 4, 3, 3, 4, 6, 2],
  9.                 [8, 8, 6, 5, 5, 6, 8, 8],
  10.                 [1, 8, 2, 2, 2, 2, 8, 1]
  11.             ]
  12.     pX = [ 0] * 61
  13.     pY = [ 0] * 61
  14.     minE = 9
  15.     maxE =  0
  16.     NP =  0
  17.     for row in range(8):
  18.         for col in range(8):
  19.             E = eated(row, col, player)
  20.             if (minE > table[row][col]) & (E < 255) & (E >  0):
  21.                 minE = table[row][col]
  22.                 NP =  0
  23.                 maxE =  0
  24.             if (minE == table[row][col]) & (E < 255):
  25.                 if E > maxE:
  26.                     maxE = E
  27.                     NP = 1
  28.                     pX[NP] = row
  29.                     pY[NP] = col
  30.                 elif E == maxE:
  31.                     NP = NP + 1
  32.                     pX[NP] = row
  33.                     pY[NP] = col
  34.     E = 1
  35.     makeStep(player, pX[E], pY[E])
  36.     area[pX[E]][pY[E]] = player


Исходник, если интересно, можете сами пощупать. Кто знает, проблем с запуском не возникнет (нужна библиотека pyqt4).
http://reversi-free0u.googlecode.com/svn/trunk/main.py

UPDATE: Теперь код доступен на Github. За работоспособность не ручаюсь.

Специально для windows. Exe'шник.
http://reversi-free0u.googlecode.com/files/Reversi.7z

Упаковано с помощью py2exe. Я столкнулся с двумя проблемами.

Первая:
Сначала изображения клетки и фишек в игре являли собою картинки, вставляющиеся в игру. И упакованное приложение их успешно не видело.
Проблема решилась просто — отрисовкой изображений средствами Qt (мне просто лень было так делать изначально).

Вторая:
Успешно упакованное приложение запускалось у меня, но отказывалось работать на другом компьютере. После небольших поисков, оказалось, что эта проблема также легко решается :)
Оказалось что не хватает рантайм библиотек visual studio.
I have not seriously used Python 2.6 with py2exe, also I have no experience
with this new manifest stuff, but a little experiment showed that this approach
seems to work for simple cases (I tested only on XP machines, not Vista!):

I deinstalled python 2.6 (since I had installed it 'for all users') and
installed it again 'for me only'. This installation copied the msvcr90.dll
and Microsoft.VC90.CRT.manifest files into the c:\python26 folder.

Then I ran py2exe over a very simple script ('print «Hi»') which created
an executable. This executable worked fine on a machine where msvcr90.dll
was installed in Windows\SxS (or how it's called), but did NOT run on another
machine where msvcr90.dll is not installed in Windows\SxS.

Then I copied the msvcr90.dll and Microsoft.VC90.CRT.manifest files into the dist
folder where py2exe had created my executable. Now the exe works on both machines.

When I tried to do the same for a simple wxPython script py2exe crashed because
it tried to load msvcp90.dll (IIRC), but didn't find it (it seems only to be installed
in the Windows\SxS folder). This may be a bug in py2exe.
То есть самое сложное положить к программе библиотеку и файл манифеста.

Главный минус — большой размер получившегося приложения. Но ничего не поделать. Все таки python — интерпретируемый язык.

Что мне дал этот потраченный на игру выходной?
  • Удовольствие от процесса изучения и написания gui приложение на python
  • Желание поделиться этим с Вами)
За этот топик я получил инвайт

Перенес в коллективный блог. В этой жизни надо попробовать всё 8)

upd: немного изменил имена переменных в исходниках

upd2: для страждущих, версия питона 2.6.4
Tags:
Hubs:
+63
Comments 35
Comments Comments 35

Articles