Создание игры в "Пять в ряд" на C

CCBeginner
Практиковаться сейчас

💡 Этот учебник переведен с английского с помощью ИИ. Чтобы просмотреть оригинал, вы можете перейти на английский оригинал

Введение

В этом проекте мы создадим простую текстовую игру в Гомоку на языке программирования C. Гомоку - это двухигровая стратегическая дошковая игра, целью которой является первым собрать пять подряд идущих фишек в ряд, горизонтально, вертикально или по диагонали. Мы разработаем эту игру на игровой доске размером 15x15.

👀 Предпросмотр

Игра в Гомоку

🎯 Задачи

В этом проекте вы научитесь:

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

🏆 Достижения

После завершения этого проекта вы сможете:

  • Работать с двумерными массивами в C.
  • Проектировать и реализовать игровой процесс с использованием функций.
  • Проверять условия выигрыша в игре.
  • Компилировать и запускать программу на C.

Создание файлов проекта

Сначала создайте новый файл с именем gomoku.c и откройте его в предпочитаемом редакторе кода.

cd ~/project
touch gomoku.c
✨ Проверить решение и практиковаться

Проектирование шахматной доски

Используем 'O' и 'X' для представления фишек

Во - первых, нам нужна шахматная доска (15 * 15), чтобы записать "ситуацию" каждого положения на доске. Поэтому мы можем определить массив chessboard[16][16]. Почему не [15][15]? Это потому, что таким образом координаты массива могут точно соответствовать строкам и столбцам шахматной доски, что делает последующий код легче для написания.

#include <stdio.h>

#define N 15

// Определяем массив и присваиваем каждому элементу начальное значение 0.
int chessboard[N + 1][N + 1] = { 0 };
✨ Проверить решение и практиковаться

Главная функция

Прежде чем начать писать главную функцию, давайте кратко рассмотрим типичный ход игры. Во - первых, мы заходим в главное меню игры, затем нажимаем кнопку "Старт", чтобы войти в игру, затем отображается игровой экран, определяется победитель или поражение, и игра заканчивается. Так, как выглядит ход игры в Гомоку?

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

// Используется для отслеживания,轮到哪个玩家,нечетное число означает,轮到玩家 1, а четное число означает,轮到玩家 2.
int whoseTurn = 0;

int main(void)
{
	// Пользовательская функция, которая инициализирует игру, то есть отображает экран приветствия и входит в игровую доску.
	initGame();

	// Этот цикл для того, чтобы два игрока по очереди ходили.
	while (1)
	{
		// Каждый цикл увеличивается на 1, чтобы два человека могли по очереди ходить.
		whoseTurn++;

		// Пользовательская функция, которая выполняет операцию по размещению фишки.
		playChess();
	}

	return 0;
}
✨ Проверить решение и практиковаться

Функция initGame

В этой функции мы хотим реализовать следующие функции:

  • Отобразить простой экран приветствия.
  • Запросить ввод 'Y' и отобразить шахматную доску после ввода.
void initGame(void)
{
	char c;

	printf("Please input 'y' to enter the game:");
	c = getchar();
	if ('y'!= c && 'Y'!= c)
		exit(0);

	//Очистить
	system("clear");

	//Здесь мы снова вызываем пользовательскую функцию, функция которой заключается в том, чтобы вывести шахматную доску.
	printChessboard();
}

В функции initGame мы используем функции exit и system, поэтому нам нужно включить заголовочный файл stdlib.h в начале программы.

#include <stdlib.h>
✨ Проверить решение и практиковаться

Функция printChessboard

В этой функции наша цель заключается в том, чтобы:

  • Распечатать номера строк и столбцов и вывести шахматную доску.
  • Если значение элемента массива равно 0, вывести звездочку (*), чтобы показать, что данное положение свободно.
  • Если значение элемента массива равно 1, вывести实心ную окружность (X), представляющую фишку игрока 1.
  • Если значение элемента массива равно 2, вывести пустую окружность (O), представляющую фишку игрока 2.
void printChessboard(void)
{
	int i, j;

	for (i = 0; i <= N; i++)
	{
		for (j = 0; j <= N; j++)
		{
			if (0 == i)		//Это выводит номер столбца.
				printf("%3d", j);
			else if (j == 0)	//Выводит номер строки.
				printf("%3d", i);
			else if (1 == chessboard[i][j])
				printf("  X");
			else if (2 == chessboard[i][j])
				printf("  O");
			else
				printf("  *");
		}
		printf("\n");
	}
}
✨ Проверить решение и практиковаться

Функция playChess

В этой функции мы хотим достичь следующего:

  • Предложить игроку ввести позицию для размещения фишки.
  • Если сейчас ходит игрок 1, присвоить значение 1 соответствующему элементу в массиве.
  • Если сейчас ходит игрок 2, присвоить значение 2 соответствующему элементу в массиве.
  • После каждого хода определить, выиграл ли текущий игрок.
void playChess(void)
{
	int i, j, winner;

	//Определить,轮到哪个玩家,и затем присвоить значение соответствующему элементу в массиве.
	if (1 == whoseTurn % 2)
	{
		printf("Ходит игрок 1, введите позицию, формат: номер строки + пробел + номер столбца: ");
		scanf("%d %d", &i, &j);
		chessboard[i][j] = 1;
	}
	else
	{
		printf("Ходит игрок 2, введите позицию, формат: номер строки + пробел + номер столбца: ");
		scanf("%d %d", &i, &j);
		chessboard[i][j] = 2;
	}

	//Вывести доску снова.
	system("clear");
	printChessboard();	//Эта функция вызывается снова.

	/*
	*Следующий раздел вызывает пользовательскую функцию (функцию裁判员).
	*Она используется для определения, выиграл ли текущий игрок ходом или нет.
	*/
	if (judge(i, j, whoseTurn))
	{
		if (1 == whoseTurn % 2)
			printf("Победитель - игрок 1!\n");
		else
			printf("Победитель - игрок 2!\n");
	}
}
✨ Проверить решение и практиковаться

Функция judge

Параметры функции:

  • x: номер строки текущего хода
  • y: номер столбца текущего хода

Возвращаемое значение:

  • 1 или 0. 1 означает, что текущий игрок выиграл после хода.
int judge(int x, int y)
{
    int i, j;
    int t = 2 - whoseTurn % 2;
    const int step[4][2]={{-1,0},{0,-1},{1,1},{1,0}};
    for(int i=0;i<4;++i)
    {
        const int d[2]={-1,1};
        int count=1;
        for(int j=0;j<2;++j)
            for(int k=1;k<=4;++k){
                int row=x+k*d[j]*step[i][0];
                int col=y+k*d[j]*step[i][1];
                if( row>=1 && row<=N && col>=1 && col<=N &&
                    chessboard[x][y]==chessboard[row][col])
                    count+=1;
                else
                    break;
            }
        if(count>=5)
            return 1;
    }
    return 0;
}

В функции judge есть 3 вложенных цикла for, и их цель - определить, есть ли ряд из пяти подряд идущих фишек.

Ряд из пяти фишек может быть горизонтальным, вертикальным или диагональным. Здесь мы будем использовать метод проб и ошибок, ищем последовательные фишки по горизонтали, вертикали и диагоналям. Возьмем пример:

Gomoku Game

На приведенной выше шахматной доске мы объясним алгоритм определения наличия ряда из пяти фишек по координатам (9, 10).

Во - первых, мы проверяем, есть ли диагональный ряд из пяти фишек, начиная с (9, 10). Процесс следующий:

  • Начиная с (9, 10), мы ищем в направлении верх - левый. Координаты, удовлетворяющие условию, это (8, 9), (7, 8) и (6, 7). Поскольку (5, 6) не удовлетворяет условию, мы переходим к следующему шагу.
  • Затем мы ищем в направлении нижний - правый и находим (10, 11), которая является единственной координатой, удовлетворяющей условию.
  • Мы нашли пять точек в прямой линии, поэтому игрок 2 выигрывает.

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

✨ Проверить решение и практиковаться

Моя фишка была "съедена"

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

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

void playChess(void)
{
	int i, j, winner;
	if (1 == whoseTurn % 2)
	{
		printf("Ходит игрок 1, введите позицию, формат: номер строки + пробел + номер столбца: ");
		scanf("%d %d", &i, &j);
		//debug
		while(chessboard[i][j]!= 0)
		{
			printf("Данная позиция уже занята, введите позицию снова: ");
			scanf("%d %d",&i, &j);
		}
		//debug
		chessboard[i][j] = 1;
	}
	else
	{
		printf("Ходит игрок 2, введите позицию, формат: номер строки + пробел + номер столбца: ");
		scanf("%d %d", &i, &j);
		//debug
		while(chessboard[i][j]!= 0)
		{
			printf("Данная позиция уже занята, введите позицию снова: ");
			scanf("%d %d",&i, &j);
		}
		//debug
		chessboard[i][j] = 2;
	}

	system("clear");
	printChessboard();

	if (judge(i, j))
	{
		if (1 == whoseTurn % 2)
			printf("Победитель - игрок 1!\n");
		else
			printf("Победитель - игрок 2!\n");
	}
}

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

✨ Проверить решение и практиковаться

Почему я никогда не могу выиграть?

Когда есть ряд из пяти фишек и выводится сообщение "Победитель - игрок 1" или "Победитель - игрок 2", а затем выводится сообщение "Ходит игрок *, введите позицию вашей фишки...". Это не раздражает? Фактически, все, что нам нужно сделать, - это добавить одну строку кода!

	if (judge(i, j))
	{
		if (1 == whoseTurn % 2)
		{
			printf("Победитель - игрок 1!\n");
			exit(0);	//debug
		}
		else
		{
			printf("Победитель - игрок 2!\n");
			exit(0);	//debug
		}
	}
}

Кроме того, чтобы сообщить игроку, кто выиграл после победы, выйти из игры с помощью exit(0).

✨ Проверить решение и практиковаться

Компиляция и запуск

Выполните команду gcc для компиляции:

cd ~/project
gcc -o gomoku gomoku.c
./gomoku
Gomoku Game
✨ Проверить решение и практиковаться

Резюме

Поздравляем! Вы создали простую игру в "Пять в ряд" на языке C. Игроки могут по очереди размещать свои фишки на игровой доске размером 15x15, и когда у игрока образуется ряд из пяти подряд идущих фишек, программа объявляет его победителем. Наслаждайтесь игрой в эту текстовую игру с друзьями!