Домашнее задание № 10. Крестики-нолики
Задание
Разработать программу для игры в крестики-нолики.
Описание
Программа является консольной. Игровое поле отображается следующим образом:
+---+---+---+ | | | | +---+---+---+ | X | O | | +---+---+---+ | | O | X | +---+---+---+где клетки пронумерованы следующим образом:
+-----------+ | 0 | 1 | 2 | +-----------+ | 3 | 4 | 5 | +-----------+ | 6 | 7 | 8 | +-----------+
Реализация
Программа использует несколько классов. Каждый класс имеет свой *.cs файл. Следует реализовать следующие классы:
Piece
Piece (фигура) – символ, который отображается на игровом поле. Реализуется в виде перечисления следующим образом:
enum Piece { Empty, First, Second }
Определяется в заголовочном файле Board.cs
Board
Класс Board – используется для отображения текущего состояния на игровом поле.Он содержит следующие поля и методы:
private readonly Piece[] _squares;массив, содержащий информацию о содержимом девяти клеток;
- private char ShowPiece(Piece piece) - отображает элемент в виде символа, Piece.Empty отображается в виде пробела ' '; Piece.First - в виде 'X', Piece.Second - в виде 'O';
- private void Clear() - очищает доску, помещает во все клетки Piece.Empty;
- конструктор public Board() - отводит место в памяти для массива _squares и вызывает метод Clear();
- перегрузка public override string ToString() - используется для отображения доски на консоли (использует SrringBuilder)
- public void MakeMove(Piece piece, int cell) - помещает фигуру в клетку;
- public void UndoMove(int cell) - очищает клетку, помещает в неё Piece.Empty;
- public bool IsLegal(int cell) - возвращает истину, если клетка свободна;
- public bool IsWinner(Piece piece) - возвращает истину, если игрок, использующий фигуру piece, выиграл (подсказка: существует всего 8 выигрышных комбинаций, их удобно хранить в классе в виде двумерного массива целых чисел);
- public bool IsFull() - возвращает истину, если поле заполнено.
Player
abstract class PlayerВ нём хранится имя игрока и фигура, которой он играет (например
Piece.First
или Piece.Second
) в виде свойств
public string Name { get; } public Piece Piece { get; }Он обеспечивает следующие методы: защищённый конструктор
protected Player(string name, Piece piece)и одну чисто виртуальную функцию
public abstract void MakeMove(Board board); // чисто виртуальная функция не имеет реализации
HumanPlayer
Класс – наследник Player. Он содержит реализацию MakeMove()
public override void MakeMove(Board board)
Метод MakeMove() запрашивает с пользователя номер клетки, в которую он хотел бы поместить клетку (подсказка: организовать цикл в котором программа запрашивает с пользователя номер клетки, до тех пор, пока он не введёт существующий номер клетки (от 0 до 9), не занятый фигурой). Затем вызывается метод MakeMove класса Board.
Также он имеет конструктор, который содержит только обращение к конструктору базового класса.
ComputerPlayer
Абстрактный класс – наследник Player. Он не реализует метод makeMove(). Он только обеспечивает одно и то же имя для разных компьютерных игроков. Он содержит только защищённый конструктор, который имеет только один параметр Piece piece и вызывает конструктор базового класса так, чтобы имя создаваемого игрока равнялось "Computer".
RandomPlayer
- наследник ComputerPlayer. Метод MakeMove() делает ход на случайно выбранную незанятую клетку. Также имеет открытый конструктор с параметром Piece piece.
Game
- класс для контроля над ходом игры. Имеет три закрытых поля – это объект класса Board
, два объекта типа Player
и целое поле movesMade - количество сделанных ходов.
Имеет следующие методы:
- private Player SelectPlayer(Piece piece) - запрашивает с пользователя тип игрока и его имя (если выбран HumanPlayer);
- private bool IsRunning() - возвращает истину, если поле не заполнено и победителя нет.
- Player NextPlayer() - возвращает игрока, ход которого - следующий;
- открытый конструктор public Game() - инициализирует board новым объектом типа Board;
- public void SelectPlayers() - метод содержит всего две команды - вызов selectPlayer для player1 и player2;
- пока IsRunning() возвращает true, метод вызывает метод MakeMove() для очередного игрока (которого возвратил NextPlayer()) и отображает игровое поле, movesMade на каждом шаге увеличивается на единицу;
- public void AnnounceWinner() - объявляет победителя
Функция Main()
Имеет следующий вид (изменения недопустимы):static void Main(string[] args) { Game game = new Game(); // создаётся объект типа Game; game.SelectPlayers(); // запрашиваем тип и имя игроков у пользователя; game.Play(); // играем игру; game.AnnounceWinner(); // объявляем победителя; Console.ReadKey(); }
Дополнительное задание
Создать класс advancedComputerPlayer – наследник RandomPlayer. Его метод MakeMove() перед тем, как сделать ход, проверяет, существует ли ход, который приносит немедленный выигрыш. Если такой ход есть, он совершается, если его нет, совершается ход в случайную клетку.
Вывод программы выглядит примерно так:
select the type of the player #1 (X) (human - 0, computer - 1, advanced computer player - 2):0 enter the name of the human player: Qwerty select the type of the player #2 (O) (human - 0, computer - 1, advanced computer player - 2):2 +---+---+---+ | | | | +---+---+---+ | | | | +---+---+---+ | | | | +---+---+---+ Qwerty (player #1) makes a move. enter the square number: 0 +---+---+---+ | X | | | +---+---+---+ | | | | +---+---+---+ | | | | +---+---+---+ Computer (player #2) makes a move. +---+---+---+ | X | | | +---+---+---+ | | | | +---+---+---+ | O | | | +---+---+---+ Qwerty (player #1) makes a move. enter the square number: 1 +---+---+---+ | X | X | | +---+---+---+ | | | | +---+---+---+ | O | | | +---+---+---+ Computer (player #2) makes a move. +---+---+---+ | X | X | | +---+---+---+ | | O | | +---+---+---+ | O | | | +---+---+---+ Qwerty (player #1) makes a move. enter the square number: 2 +---+---+---+ | X | X | X | +---+---+---+ | | O | | +---+---+---+ | O | | | +---+---+---+ Player # 1 Qwerty wins!!! Press any key to continue . . .