Пошаговое руководство по созданию шахматной игры из командной строки

Я вспомнил, когда впервые начал учиться кодировать, я был в восторге от того, что могу делать такие вещи, как печать Hello World! , но я понял, что во многих онлайн-курсах не хватает уроков о том, как начать создавать что-то с нуля. Обычно на каждом уроке предоставляется неполный код, и ученику предлагается завершить его с помощью ряда задач. Но как мне на самом деле использовать то, чему я научился, чтобы сделать то, что я хочу? Какие файлы я создаю? Как заставить их взаимодействовать друг с другом? Как мне на самом деле запустить его на моем компьютере?

Введение

В этом руководстве я опишу пошаговый процесс того, как вы можете создать свою собственную игру в шахматы из командной строки. Это означает, что я сделаю все возможное, чтобы предоставить вам как можно меньше кода, чтобы вы могли подумать о том, как на самом деле реализовать идею, и вместо этого предоставить вам основу, которую вы могли бы применить к своему следующему проекту. Тем не менее, я предоставлю код, который я написал, в конце этого руководства на случай, если вы когда-нибудь застрянете или просто захотите поиграть в шахматы.

Получившаяся игра представляет собой шахматную игру из командной строки, что означает, что вы не перетаскиваете фигуры с помощью мыши, а вместо этого ваша командная строка будет принимать некоторый пользовательский ввод через текст для взаимодействия с игрой. Тем не менее, если вы настроены амбициозно, его определенно можно расширить, чтобы включить эту функциональность, разветвив репозиторий git.

Следующее руководство предполагает наличие базовых знаний о программировании на Python, таких как переменные, типы, функции и циклы, и его будет намного легче понять тем, кто знаком с концепцией классов. Тем не менее, это определенно возможно для тех, кто не знаком с объектами и классами, потому что вот краткий обзор, который вы также можете пропустить, если вы уже знакомы с этими понятиями:

Объекты

Объект в коде подобен объекту в реальной жизни. У него есть данные, которые описывают его или его текущее состояние, и у него есть методы, которые могут манипулировать этими данными и использовать их. Возьмем, к примеру, стул. Его данные могут быть представлены следующим образом:

num_legs = 4
position = (0, 0)
color = "brown"
rolls = False

Методы стула могут включать следующее:

def move_chair(self, to):
    self.position = to
def paint_chair(self, new_color):
    self.color = new_color
...

Классы

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

class Chair():
    def __init__(self, num_legs, position, color, rolls):
        self.num_legs = num_legs
        self.position = position
        self.color = color
        self.rolls = rolls
    def move_chair(self, to):
        self.position = to
    def paint_chair(self, new_color):
        self.color = new_color

Подклассы

Подклассы, как следует из названия, представляют собой более узкую категоризацию объектов родительского класса. У них также есть данные и методы, относящиеся к классу, но что особенного, они также наследуют все от родительского класса. Например, подклассом стульев могут быть стулья с прикрепленным к ним столом, которые можно выдвигать или складывать. Вы можете не только добавить больше данных и методов, относящихся только к стульям со столами, но вам не нужно переписывать все остальное, что есть у всех стульев.

class DeskChair(Chair):
    def __init__(self, num_legs, position, color, rolls):
        super().__init__(num_legs, position, color, rolls)
        self.desk_out = False
    def use_desk(self):
        self.desk_out = True
    def fold_desk(self):
        self.desk_out = False   

В подклассе DeskChair выше мне не нужно было переписывать методы move_chair(to), потому что он автоматически имеет этот метод, будучи подклассом Chair. Однако объекты, созданные с помощью класса Chair, не могут использовать методы use_desk() или fold_desk(), поскольку они специфичны для класса DeskChair.

Создание и использование объектов

В приведенных выше примерах классов каждый класс имеет функцию __init__(), которая автоматически вызывается при создании объекта. Ниже показано, как вы можете создавать и использовать объекты:

normal_chair = Chair(4, (0,0), "brown", False)
normal_chair.move_chair((1,1))
print(normal_chair.position) # prints "(1, 1)"
desk_chair = DeskChair(4, (2,2), "black", True)
desk_chair.move_chair((3,3))
print(desk_chair.position) # prints "(3, 3)"
desk_chair.use_desk()
print(desk_chair.desk_out) # prints "True"

Актуальное руководство

0. Установите Python3

Если у вас еще не установлен Python3, сделайте это в первую очередь! Чтобы проверить, установлен ли он у вас уже, откройте командную строку и введите python --version или python3 --version. У пользователей Mac уже должна быть предустановлена ​​версия Python.

Для пользователей Windows просто перейдите на https://www.python.org/downloads/windows/ и загрузите нужную версию. Следуйте инструкциям, и вскоре вы сможете запустить приведенную выше команду, чтобы проверить версию Python.

1. Подумайте, какие занятия вам понадобятся

Теоретические аспекты классов

Даже если ваши классы не нуждаются в полной конкретизации, подумайте о том, как организовать свой код в классы, чтобы он был интуитивно понятным и имел разумный размер.

Что я имею в виду под интуитивным, так это то, что атрибуты класса («данные», относящиеся к объекту) и методы класса имеют смысл сгруппировать вместе. Если у вас есть класс A и класс B, не помещайте атрибуты, относящиеся к классу A, в класс B. Важно отметить, что иногда это может быть неоднозначно и обычно не влияет на производительность вашей итоговой игры, но делайте то, что имеет для вас наибольший смысл, чтобы, когда вам нужно что-то исправить или добавить, вы знали, где это искать.

Под разумным размером я подразумеваю не кодировать всю игру в один класс. Причин много, одна из них нарушает предыдущее «интуитивное правило». В то время как кодирование всего в один большой класс может сэкономить вам время на размышления о разных классах и о том, как они взаимодействуют друг с другом (что не должно быть слишком сложно, если вы следуете интуитивному правилу), весь ваш код будет в одном большом файле, который будет занимает много времени, просто прокручивая, чтобы найти часть кода, которую вы хотите отредактировать. Другим людям и даже вам, когда вы оглядываетесь назад, сложнее понять код. Опять же, если ваш проект достаточно мал, чтобы поместить его в один класс, это тоже нормально, но этот проект не входит в их число.

Результат

Существует несколько различных концепций того, как можно визуализировать эту шахматную партию, но наиболее интуитивным я считаю использование трех основных классов: Chess , Board и Piece .

Класс Chess представляет состояние игры, например, чей сейчас ход, объект Board и может ли следующий игрок на проходе. Методы, которые я также решил включить в этот класс, предназначены для перемещения фигуры и продвижения пешки в конце доски.

Класс Board представляет конфигурацию доски, что означает, где фигуры находятся на доске, с методом печати доски.

Класс Piece представляет шахматную фигуру, и для меня наиболее целесообразно иметь подклассы, представляющие каждую уникальную шахматную фигуру, такие как класс Rook и класс Pawn. Фигура описывается своим именем и цветом и имеет метод, который проверяет, является ли перемещение фигуры из точки А в точку Б допустимым ходом в соответствии с правилами конкретной фигуры.

Скелет для классов приведен ниже, чтобы вы начали:

Просто чтобы подчеркнуть, приведенные выше скелеты — это всего лишь предложение и то, как это работает в моей реализации. Надеюсь, они помогут вам начать работу или, по крайней мере, намекнут на функциональность, которая вам понадобится, когда вы начнете программировать.

2. Начните программировать основы

Как только у вас появится представление о классах, которые вы собираетесь использовать, или если вы собираетесь использовать приведенные выше скелеты, создайте необходимые файлы. Определенного правила о том, сколько файлов создавать, нет, но обычно это один файл на класс. Подклассы могут находиться в одном файле или в отдельных файлах. Я решил сохранить все подклассы Piece в одном файле, потому что создание 6 или 7 дополнительных файлов, некоторые из которых могут быть короче пары строк, не имело для меня интуитивного смысла.

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

Предлагаемый заказ

Я предлагаю начать с класса Board и предположить, что у вас уже есть конструкторы различных частей. Для класса Board вам нужно подумать о том, как представить вашу доску, предпочитаете ли вы двумерный список, словарь или какую-либо другую структуру данных. В своей реализации я использовал двумерный список.

Теперь, когда вы знаете, как представлен ваш Board, вам будет легче приступить к кодированию класса Piece и его подклассов, потому что is_valid_move(), скорее всего, будет зависеть от доски, так как вам нужно будет проверить ее на наличие таких вещей, как наличие фигур вдоль пути из точки А в точку Б, что может заблокировать движение.

Наконец, соберите все вместе в классе Chess.

Чтобы связать различные файлы, которые вы создали, например, создайте Board для хранения в классе Chess, просто добавьте import [name of the file containing the Board class without the file extension] вверху файла chess. Так, например, у меня есть файл с именами board.py и chess.py, и мой файл chess.py будет выглядеть примерно так:

import board
class Chess():
    def __init__(self):
        self.board = board.Board()
...

Код драйвера

Ниже приведен код, используемый для фактического запуска игры, чтобы вы могли сосредоточиться на кодировании своих классов и не беспокоиться о том, как они работают. Поверьте, что классы, которые вы кодируете, действительно что-то сделают. Я поместил его в тот же файл, что и класс Chess, но он может быть и в отдельном файле.

3. Запускай! Часть 1

Игра далека от завершения, но мне всегда приятно убедиться, что то, что вы написали до сих пор, действительно работает! Для некоторого сходства с шахматной игрой минимальный код, который вам потребуется выполнить, — это код для печати доски, на которой есть хотя бы одна фигура, код для разрешения допустимого хода указанной фигуры и код который может переместить эту фигуру с одного места доски на другое.

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

4. Завершите программирование игры

Прелесть кодирования собственной игры в том, что вы можете устанавливать свои правила в отношении того, что делает ваша игра. Технически вам даже не нужно иметь код, чтобы проверить правильность хода фигуры! Это будет похоже на игру в шахматы с настоящей физической доской, и игроки будут нести ответственность друг перед другом за соблюдение правил. Поэтому, когда я говорю «завершить» кодирование игры, я имею в виду делать столько, сколько вы хотите. Если вы не доделаете рокировку, просто назовите ее «Шахматы без рокировки», и с этим никто не поспорит.

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

5. Запускай! Часть 2

По мере того, как вы добавляете все больше и больше функций, запускайте свою игру и экспериментируйте с ней. Убедитесь, что добавленная функциональность работает так, как вы ожидали.

6. Распространяйте информацию

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

Вывод

Если в какой-то момент вы почувствуете, что безнадежно застряли, вот мой завершенный код: https://github.com/xsanon/chess

Код полностью документирован и снабжен комментариями для лучшего понимания кода.

Я призываю вас разрабатывать и реализовывать все самостоятельно, чтобы вы могли называть свою завершенную игру своей собственной, поскольку легко попасть в ловушку копирования чужого кода. Конечно, я ожидаю, что программисты разного уровня попытаются совершить этот удивительный подвиг, поэтому не бойтесь просматривать код.

Дайте мне знать в комментариях, если вам удалось завершить свою собственную шахматную партию, и дайте мне знать, если вы найдете какие-либо ошибки в моей.