Тема лабораторной
На данном занятии вы займётесь программированием еще одной игры - Крестики-нолики (Tic Tac Toe).
Цели
- Работа с массивами.
- Работать с ветвлением и циклами в программе.
- Освоить работу с параметрами функций.
- Ознакомиться с двурозмерным полем (массивом).
Инструкции
Шаг 1: Крестики-нолики
На данном этапе напиши простую игру Крестики-нолики (1D). Игровой план в данном случае - одноразмерный массив длиной N
. В игре принимают участие 2 игрока, оба записывают крестики (знак Х). Первый, у которого выйдет заполнить поле 3 своими знаками в ряд (диагональ) - выигрывает.
Для отладки программы и устранения возможных ошибок, используйте утилиту cgdb с прошлого занятия.
Задача 1.1
Напишите функцию void draw(const int size, char field[])
, которая выведет на экран актуальную ситуацию на поле.
Если field
будет содержать в себе следующее:
char field[] = { ' ', 'X', ' ', 'X', ' '};
в таком случае, функция выведет на экран поле в следующем формате:
+-+-+-+-+-+
| |X| |X| |
+-+-+-+-+-+
1 2 3 4 5
Помимо содержания самого поля функция выведет и индексы каждого из элементов. С помощью данных индексов игроки смогут ориентироваться и записывать координаты, куда записывать свой знак. Обратите внимание, что для игроков нумерация начинается с 1.
Задача 1.2
Измените главную функцию программы так, что игрок сначала введёт размер игрового поля, которое затем должно вывестись на экран.
Размер поля может быть от 4 до 9. В случае неправильного ввода, программа запросит ввести размер снова.
$ ./tictactoe Enter the size of field: 3 Enter the size of field: 22 Enter the size of field: 7 +-+-+-+-+-+-+-+ | | | | | | | | +-+-+-+-+-+-+-+ 1 2 3 4 5 6 7
Задача 1.3
Напишите функцию int add_cross(const int size, char field[], const int position)
, которая поместит знак на позицию, указанную в параметре position
знак игрока.
В случае если на месте, куда ставится знак, уже находится знак, функция возвращает 0, в успешном случае - 1.
Задача 1.4
Измените функцию int add_cross()
так, что она должна вернуть -1, если пользователь вводит позицию для помещения знак, находящуюся вне интервала игрового поля.
Задача 1.5
Напишите функцию int is_solved(const int size, char field[])
, с помощью котрой можно будет проверить, закончена ли игра.
Функция возвращает 1, если в поле находятся минимально 3 знака друг около друга. В противном случае - значение, равное 0.
Задача 1.6
Используя только что написанные функции, реализуйте игру.
Диалог между двумя игроками может выглядеть следующим образом:
$ ./tictactoe Enter the size of field: 9 +-+-+-+-+-+-+-+-+-+ | | | | | | | | | | +-+-+-+-+-+-+-+-+-+ 1 2 3 4 5 6 7 8 9 Player A: 2 +-+-+-+-+-+-+-+-+-+ | |X| | | | | | | | +-+-+-+-+-+-+-+-+-+ 1 2 3 4 5 6 7 8 9 Player B: 5 +-+-+-+-+-+-+-+-+-+ | |X| | |X| | | | | +-+-+-+-+-+-+-+-+-+ 1 2 3 4 5 6 7 8 9 Player A: 9 +-+-+-+-+-+-+-+-+-+ | |X| | |X| | | |X| +-+-+-+-+-+-+-+-+-+ 1 2 3 4 5 6 7 8 9 Player B: 10 Wrong position! Player A: 2 X is already there! Player B: 8 +-+-+-+-+-+-+-+-+-+ | |X| | |X| | |X|X| +-+-+-+-+-+-+-+-+-+ 1 2 3 4 5 6 7 8 9 Player A: 7 +-+-+-+-+-+-+-+-+-+ | |X| | |X| |X|X|X| +-+-+-+-+-+-+-+-+-+ 1 2 3 4 5 6 7 8 9 Player A wins!
Шаг 2: 2D
На данном этапе вам предстоит изменить код программы так, чтобы она использовала двухразмерное поле.
- Таким образом, программу нужно изменить так, чтобы поле
field[]
было двухразмерное. Поле будет квадратного вида, т.е. высота и ширина будут равны. - Игрок будет вводить 2 координаты - х, у.
- Ось х - горизонтальная ось, нумерованная слева направо, начиная со значения 1. Должна выводиться под игровым полем. Ось у - вертикальная ось, нумерованная снизу вверх, также начиная со значения 1. Выводится на экран слева от поля.
- Первому игроку соответствуют крестики X, а второму игроку - нолики O.
- Диалог двух игроков может выглядеть следующим образом:
$ ./tictactoe Enter the size of field: 5 +-+-+-+-+-+ 5 | | | | | | +-+-+-+-+-+ 4 | | | | | | +-+-+-+-+-+ 3 | | | | | | +-+-+-+-+-+ 2 | | | | | | +-+-+-+-+-+ 1 | | | | | | +-+-+-+-+-+ 1 2 3 4 5 Player A: 0 3 Wrong position! Player B: 3 3 +-+-+-+-+-+ 5 | | | | | | +-+-+-+-+-+ 4 | | | | | | +-+-+-+-+-+ 3 | | |O| | | +-+-+-+-+-+ 2 | | | | | | +-+-+-+-+-+ 1 | | | | | | +-+-+-+-+-+ 1 2 3 4 5 Player A: 2 2 +-+-+-+-+-+ 5 | | | | | | +-+-+-+-+-+ 4 | | | | | | +-+-+-+-+-+ 3 | | |O| | | +-+-+-+-+-+ 2 | |X| | | | +-+-+-+-+-+ 1 | | | | | | +-+-+-+-+-+ 1 2 3 4 5 Player B: 4 4 +-+-+-+-+-+ 5 | | | | | | +-+-+-+-+-+ 4 | | | |O| | +-+-+-+-+-+ 3 | | |O| | | +-+-+-+-+-+ 2 | |X| | | | +-+-+-+-+-+ 1 | | | | | | +-+-+-+-+-+ 1 2 3 4 5 Player A: 6 5 Wrong position! Player B: 5 5 +-+-+-+-+-+ 5 | | | | |O| +-+-+-+-+-+ 4 | | | |O| | +-+-+-+-+-+ 3 | | |O| | | +-+-+-+-+-+ 2 | |X| | | | +-+-+-+-+-+ 1 | | | | | | +-+-+-+-+-+ 1 2 3 4 5 Player B wins!
Задача 2.1
Измените декларацию поля field
в функции main()
так, чтобы оно было двухразмерным.
Высота и ширина поля равны. Они определяются переменной, в которой сохранён размер игрового поля. Данный параметр игры задаёт игрок.
Все элементы поля сначала содержат в себе знаки ' ' (пробел).
Задача 2.2
Измените декларацию и дефиницию функции draw()
так, чтобы она использовала двухразмерное поле.
Декларация изменится следующим образом: void draw(const int size, char field[][size])
, в которой size
это размер поля (вертикальный и горизонтальный), field
- само двухразмерное поле. Второй размер (число во вторых квадратных скобках) при работе с двухразмерными полями обязателен. Поэтому, параметр size
указан как первый (в момент своего использования уже должен быть известен).
Функция должна вывести на экран поле так, чтобы ось х была пронумерована слева направо, начиная с 1 под игровым полем. Ось у нумеруется снизу вверх, начиная с 1, изображается слева от игрового поля.
Задача 2.3
Измените декларацию функции add_cross()
так, чтобы она использовала двухразмерный массив.
Декларация изменится следующим способом: int add_cross(const int size, char field[][size], const int x, const int y, const char player)
, где size
это размеры поля (горизонтальный + вертикальный), а field
представляет собой поле. Параметры x
и y
представляют координаты на соответствующих осях, по которым игрок хочет поставить свой знак. Параметр player
определяет, чьего игрока очередь.
Функция должна в поле field
добавить крестик (знак X), если в данный момент очередь игрока A, кружок (знак O) - если игрок B. То, чья очередь, определяет параметр player
.
Не забудьте изменить и место вызова функции (добавьте новые параметры).
Задача 2.4
Измените декларацию функции is_solved()
так, чтобы она использовала двухразмерный массив.
Декларация изменится следующим образом: int is_solved(const int size, char field[][size])
, где size
это размеры поля (горизонтальный + вертикальный), а field
сам двухразмерный массив.
Функция должна определить, является ли игра выигранной (законченной), т.е. находятся ли друг около друга 3 в ряд крестика (нолика). Под проверку подлегают 3 крестика по горизонтали, вертикали, или диагонали.
Задача 2.5
Проверьте правильность вашей реализации.
Дополнительные задачи
Задача A.1
Напишите функцию void make_turn(const int size, char field[][size])
. Данная функция будет представлять искусственный интеллект, играющий против игрока, которым будет сам компьютер.
Задача A.2
Создайте функции int find_min(const int size, char field[][size])
и int find_max(const int size, char field[][size])
, которые будут возвращать позиции наименьшего элемента и наибольшего элемента. В случае, если таких элементов, больше одного, функции должны вернуть позицию первого.
Задача A.3
Напишите функцию int compare(const int size1, char field1[][size1], const int size2, char field2[][size2])
, возвращающую 1, если два массива одинаковы. в противном случае - 0.