目录

一、了解五子棋基本元素

二、了解五子棋下棋过程

三、重要功能设计

1、初始化棋子

2、初始化棋盘

3、判断胜负

4、人机对战随机算法

5、判断棋盘是否已满

6、保存当前棋局并退出游戏

7、复盘游戏

四、源代码及运行结果

 五、总结


一、了解五子棋基本元素

1、棋子

五子棋分黑白两色,形状为扁圆形。双方进行博弈时要将棋子下在棋盘的交叉点处。

棋子符号包括:

黑子:○    白子:●

棋盘每一个位置分为三种状态,白子、黑子、空白。可以使用宏定义:

#define WHITE -1

#define BLACK 1

#define BLANK 0

(该实践默认在人机对战时,玩家执黑棋,电脑执白棋)

2、棋盘

目前国际上使用的五子棋棋盘都是15×15,由横纵交叉线形成了225个交叉点。

棋盘符号包括:

┌    ┬    ┐

├    ┼    ┤

└    ┴    ┘

棋盘最大行数15,最大列数15。可以使用宏定义:

#define MAX_ROW 15

#define MAX_COL 15

棋盘可以抽象为一个二维数组chessboard[MAX_ROW][MAX_COL]存储棋子的下标位置

二、了解五子棋下棋过程

1、在菜单界面选择对战方式、进行上一局或退出游戏

2、绘制棋盘、棋子

3、执黑子的玩家先落子,然后双方轮流落子

4、判断胜负或平局

5、退出游戏

三、重要功能设计

1、初始化棋子

void draw_chessman(int type, char *tableline) {
	if (type == WHITE)
		printf("●");
	if (type == BLACK)
		printf("○");
	if (type == BLANK)
		printf("%s", tableline);//此处传入另一个参数tableline,是为了绘制棋盘更加方便

}

2、初始化棋盘

观察棋盘可以发现,遍历绘制棋盘需分成三种不同的情况,即第一行,最后一行,其余行

//棋盘可分为三部分,第一行,最后一行,中间行
//用i代表行,j代表列
void draw_chessboardn(int row, int col, int chessboard[][MAX_COL]) {
	for (int i = 0; i < row ; i++) {
		if (i == 0) {
			for (int j = 0; j < col; j++) {
				if (j == 0)
					draw_chessman(chessboard[i][j], "┌ ");
				else if (j == 14)
					draw_chessman(chessboard[i][j], "┐");
				else
					draw_chessman(chessboard[i][j], "┬ ");
			}
			printf("\n");//第一行┌┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┐
		} else if (i == 14) {
			for (int j = 0; j < col; j++) {
				if (j == 0)
					draw_chessman(chessboard[i][j], "└ ");
				else if (j == 14)
					draw_chessman(chessboard[i][j], "┘ ");
				else
					draw_chessman(chessboard[i][j], "┴ ");
			}
			printf("\n");//最后一行└┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┘
		} else {
			for (int j = 0; j < col; j++) {
				if (j == 0)
					draw_chessman(chessboard[i][j], "├ ");
				else if (j == 14)
					draw_chessman(chessboard[i][j], "┤");
				else
					draw_chessman(chessboard[i][j], "┼ ");
			}
			printf("\n");//其他行├┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┼┤
		}
	}
}

3、判断胜负

五子棋连成五子即为胜,判断输赢须在一个棋子的上、下、左、右、右上、右下、左上、左上共八个方向遍历是否有相连的五子。但可以发现上和下在一条线上,左和右在一条线上,依此类推只需判断四个方向,即横、竖、左斜、右斜方向。

//返回当前棋子的值,若值为1,代表黑棋胜,若值为-1,代表白棋胜
int is_win(int chessboard[][MAX_COL], int row, int col) {
	int i, j;
	for (i = 0; i < row; i++) {
		for (j = 0; j < col; j++) {
			if (chessboard[i][j] == BLANK)
				continue;

            //  (-)横着连成五子
			if (j < col - 4)
				if (chessboard[i][j] == chessboard[i][j + 1] && chessboard[i][j] ==      
                        chessboard[i][j + 2]
				        && chessboard[i][j] == chessboard[i][j + 3] && chessboard[i][j] 
                        == chessboard[i][j + 4])
					return chessboard[i][j];

            //  (|)竖着连成五子
			if (i < row - 4)
				if (chessboard[i][j] == chessboard[i + 1][j] && chessboard[i][j] == 
                        chessboard[i + 2][j]
				        && chessboard[i][j] == chessboard[i + 3][j] && chessboard[i][j] 
                        == chessboard[i + 4][j])
					return chessboard[i][j];

            //  (\)左斜连成五子
			if (i < row - 4 && j < col - 4)
				if (chessboard[i][j] == chessboard[i + 1][j + 1] && chessboard[i][j] == 
                        chessboard[i + 2][j + 2]
				        && chessboard[i][j] == chessboard[i + 3][j + 3] && chessboard[i] 
                        [j] == chessboard[i + 4][j + 4])
					return chessboard[i][j];

            //  (/)右斜连成五子 
			if (i < row - 4 && j > 4)                  
				if (chessboard[i][j] == chessboard[i + 1][j - 1] && chessboard[i][j] == 
                        chessboard[i + 2][j - 2]
				        && chessboard[i][j] == chessboard[i + 3][j - 3] && chessboard[i] 
                        [j] == chessboard[i + 4][j - 4])
					return chessboard[i][j];
		}
	}
	return BLANK;
}

4、人机对战随机算法

利用产生随机数的函数随机产生随机数,用于表示棋子的行和列

int random_create_point(void) {
	int point;
	srand(time(NULL));
	point = rand() % MAX_ROW;
	return point;
}

5、判断棋盘是否已满

遍历数组,棋盘若下满了棋子,则表示本次对弈为和棋

int is_full(int chessboard[][MAX_COL], int row, int col) {
	int ret = 1;
	for (int i = 0; i < row; i++) {
		for (int j = 0; j < col; j++) {
			if (chessboard[i][j] == BLANK) {
				ret = 0;
				break;
			}
		}
	}
	return ret;
}

6、保存当前棋局并退出游戏

void  save_chess(int chessboard[][MAX_COL], int row, int col) {
	int choice ;
	FILE *fp;
	printf("是否选择结束游戏,并保存当前棋局\n");
	printf("*********1.存盘并退出***********\n");
	printf("*********2.继续游戏*************\n");
	printf("请选择 :");
	while (1) {
		scanf("%d", &choice);
		if (choice > 2||choice < 1) {
			printf("输入错误,请重新选择\n");
			continue;
		}
		break;
	}
	if (choice == 1) {
		if ( ( fp = fopen( "Save_chess.txt", "w" ) ) == NULL ) {
			printf(" 保存失败\n");
		} else {
			for (int i = 0; i < row; i++) {
				for (int j = 0; j < col; j++) {
					fprintf(fp, "%d", chessboard[i][j]);
				}
			}
			fclose(fp);
			printf("恭喜您,保存成功");
		}
		exit(0);
	}
}

7、复盘游戏

void replay_chess(void) {
	int  chessboard[MAX_ROW][MAX_COL] = {BLANK};
	FILE *fp;
	char ch;
	if ((fp = fopen("Save_chess.txt", "w")) == NULL) {
		printf("复盘失败");
	} else {
		for (int i = 0; i < MAX_ROW; i++) {
			for (int j = 0; j < MAX_COL; j++) {
				fscanf(fp, "%d", chessboard[i][j]);
			}
		}
		fclose(fp);
		draw_chessboardn(MAX_ROW, MAX_COL, chessboard);
	}
}

四、源代码及运行结果

#include <stdio.h>
#include <stdlib.h>
#define MAX_ROW 15
#define MAX_COL 15
#define WHITE -1
#define BLACK 1
#define BLANK 0

void draw_chessboardn(int row, int col, int chessboard[][MAX_COL]);
void draw_chessman(int type, char *tableline);
int random_create_point(void);
void draw_menu(void);
void person_person(void);
void person_computer_random(void);
int is_full(int chessboard[][MAX_COL], int row, int col);
int is_win(int chessboard[][MAX_COL], int row, int col);
void save_chess(int chessboard[][MAX_COL], int row, int col);
void replay_chess(void);
int  ChooseArrow(int chessboard[][MAX_COL], int row, int col);

int main () {
	int choice;
	draw_menu();
	while (1) {
		scanf("%d", &choice);
		switch (choice) {
			case 1:
				person_person();
				break;
			case 2:
				person_computer_random();
				break;
			case 3:
				replay_chess();
				break;
			case 4:
				exit(0);
				break;
			default:
				printf("输入错误,请重新选择\n");
		}
	}
	return 0;
}
//绘制棋盘
void draw_chessboardn(int row, int col, int chessboard[][MAX_COL]) {
	for (int i = 0; i < row ; i++) {
		if (i == 0) {
			for (int j = 0; j < col; j++) {
				if (j == 0)
					draw_chessman(chessboard[i][j], "┌ ");
				else if (j == 14)
					draw_chessman(chessboard[i][j], "┐");
				else
					draw_chessman(chessboard[i][j], "┬ ");
			}
			printf("\n");
		} else if (i == 14) {
			for (int j = 0; j < col; j++) {
				if (j == 0)
					draw_chessman(chessboard[i][j], "└ ");
				else if (j == 14)
					draw_chessman(chessboard[i][j], "┘ ");
				else
					draw_chessman(chessboard[i][j], "┴ ");
			}
			printf("\n");
		} else {
			for (int j = 0; j < col; j++) {
				if (j == 0)
					draw_chessman(chessboard[i][j], "├ ");
				else if (j == 14)
					draw_chessman(chessboard[i][j], "┤");
				else
					draw_chessman(chessboard[i][j], "┼ ");
			}
			printf("\n");
		}
	}
}
//绘制棋子
void draw_chessman(int type, char *tableline) {
	if (type == WHITE)
		printf("●");
	if (type == BLACK)
		printf("○");
	if (type == BLANK)
		printf("%s", tableline);
}
//随机算法获取棋子的坐标
int random_create_point(void) {
	int point;
	point = rand() % MAX_ROW;
	return point;
}
//绘制主菜单
void draw_menu(void) {
	printf("******************************\n");
	printf("******* 欢迎使用五子棋 *******\n");
	printf("***     研发者:Hiya(a     ***\n");
	printf("***     请选择对战方式     ***\n");
	printf("*      1.人-人对战           *\n");
	printf("*      2.人-机对战(随机算法) *\n");
	printf("*      3.复盘                *\n");
	printf("*      4.退出                *\n");
	printf("******************************\n");
	printf("请选择:");
}
//人人对战
void person_person(void) {
	int chessboard[MAX_ROW][MAX_COL] = {BLANK};
	int i, j;
	char key;
	draw_chessboardn(MAX_ROW, MAX_COL, chessboard);
	for (int step = 1; step <= MAX_ROW * MAX_COL; step++) {    //黑子先行,然后双方轮流下棋
		if (step % 2 == 1) {                                   //当前步数为单数,黑棋落子。
	        printf("请黑棋落子:");
			while (1) {
				scanf("%d %d", &i, &j);
				if (chessboard[i][j] != BLANK) {
					printf("该位置已有棋子,请重新输入\n");        //棋子只能落在空白处
					continue;
				}
				if (i >= MAX_ROW || j >= MAX_COL || i < 0 || j < 0) {
					printf("输入超出棋盘范围,请重新输入\n");      //棋子坐标不可超出棋盘
					continue;
				}
				break;
			}
			chessboard[i][j] = BLACK;
			draw_chessboardn(MAX_ROW, MAX_COL, chessboard);
			if (is_win(chessboard, MAX_ROW, MAX_COL) == BLACK) {
				printf("黑棋胜");
				exit(0);
			}
			save_chess(chessboard, MAX_ROW, MAX_COL);
		} else if (step % 2 == 0) {                            //当前步数为双数,则白棋落子
			printf("请白棋落子:");
			while (1) {
				scanf("%d %d", &i, &j);
				if (chessboard[i][j] != BLANK) {
					printf("该位置已有棋子,请重新输入\n");        //棋子只能落在空白处
					continue;
				}
				if (i >= MAX_ROW || j >= MAX_COL || i < 0 || j < 0) {
					printf("输入超出棋盘范围,请重新输入\n");     //棋子坐标不可超出棋盘
					continue;
				}
				break;
			}
			chessboard[i][j] = WHITE;
			draw_chessboardn(MAX_ROW, MAX_COL, chessboard);
			if (is_win(chessboard, MAX_ROW,  MAX_COL) == WHITE) {
				printf("白棋胜");
				exit(0);
			}
			save_chess(chessboard, MAX_ROW, MAX_COL);
		}
	}
	if (is_full(chessboard, MAX_ROW, MAX_COL) == 1)
		printf("棋盘已满");
}
//判断棋盘是否已满
int is_full(int chessboard[][MAX_COL], int row, int col) {
	int ret = 1;
	for (int i = 0; i < row; i++) {
		for (int j = 0; j < col; j++) {
			if (chessboard[i][j] == BLANK) {        //遍历数组,当有一个位置为空,则棋盘不满
				ret = 0;
				break;
			}
		}
	}
	return ret;
}
//判断胜负
int is_win(int chessboard[][MAX_COL], int row, int col) {
	int i, j;
	for (i = 0; i < row; i++) {
		for (j = 0; j < col; j++) {
			if (chessboard[i][j] == BLANK)
				continue;
			if (j < col - 4)
				if (chessboard[i][j] == chessboard[i][j + 1] && chessboard[i][j] == chessboard[i][j + 2]
				        && chessboard[i][j] == chessboard[i][j + 3] && chessboard[i][j] == chessboard[i][j + 4])
					return chessboard[i][j];
			if (i < row - 4)
				if (chessboard[i][j] == chessboard[i + 1][j] && chessboard[i][j] == chessboard[i + 2][j]
				        && chessboard[i][j] == chessboard[i + 3][j] && chessboard[i][j] == chessboard[i + 4][j])
					return chessboard[i][j];
			if (i < row - 4 && j < col - 4)
				if (chessboard[i][j] == chessboard[i + 1][j + 1] && chessboard[i][j] == chessboard[i + 2][j + 2]
				        && chessboard[i][j] == chessboard[i + 3][j + 3] && chessboard[i][j] == chessboard[i + 4][j + 4])
					return chessboard[i][j];
			if (i < row - 4 && j > 4)
				if (chessboard[i][j] == chessboard[i + 1][j - 1] && chessboard[i][j] == chessboard[i + 2][j - 2]
				        && chessboard[i][j] == chessboard[i + 3][j - 3] && chessboard[i][j] == chessboard[i + 4][j - 4])
					return chessboard[i][j];
		}
	}
	return BLANK;
}
//人机对战
void person_computer_random(void) {
	int chessboard[MAX_ROW][MAX_COL] = {BLANK};
	int i, j;
	draw_chessboardn(MAX_ROW, MAX_COL, chessboard);
	for (int step = 1; step <= MAX_ROW * MAX_COL; step++) {
		if (step % 2 == 1) {
			printf("请黑棋落子:");
			while (1) {
				scanf("%d %d", &i, &j);
				if (chessboard[i][j] != BLANK) {
					printf("该位置已有棋子,请重新输入\n");
					continue;
				}
				if (i >= MAX_ROW || j >= MAX_COL || i < 0 || j < 0) {
					printf("输入超出棋盘范围,请重新输入\n");
					continue;
				}
				break;
			}
			chessboard[i][j] = BLACK;
			draw_chessboardn(MAX_ROW, MAX_COL, chessboard);
			if (is_win(chessboard, MAX_ROW, MAX_COL) == BLACK) {
				printf("黑棋胜");
				exit(0);
			}
			save_chess(chessboard, MAX_ROW, MAX_COL);
		} else if (step % 2 == 0) {
			while (1) {
				i = random_create_point();
				j = random_create_point();
				if (chessboard[i][j] == BLANK)
					break;
			}
			chessboard[i][j] = WHITE;
			draw_chessboardn(MAX_ROW, MAX_COL, chessboard);
			if (is_win(chessboard, MAX_ROW,  MAX_COL) == WHITE) {
				printf("白棋胜");
				exit(0);
			}
			save_chess(chessboard, MAX_ROW, MAX_COL);
		}
	}
	if (is_full(chessboard, MAX_ROW, MAX_COL) == 1)
		printf("棋盘已满");
}
//存盘
void  save_chess(int chessboard[][MAX_COL], int row, int col) {
	int choice ;
	FILE *fp;
	printf("是否选择结束游戏,并保存当前棋局\n");
	printf("*********1.存盘并退出***********\n");
	printf("*********2.继续游戏*************\n");
	printf("请选择 :");
	while (1) {
		scanf("%d", &choice);
		if (choice > 2) {
			printf("输入错误,请重新选择\n");
			continue;
		}
		break;
	}
	if (choice == 1) {
		if ( ( fp = fopen( "Save_chess.txt", "w" ) ) == NULL ) {
			printf(" 保存失败\n");
		} else {
			for (int i = 0; i < row; i++) {
				for (int j = 0; j < col; j++) {
					fprintf(fp, "%d", chessboard[i][j]);
				}
			}
			fclose(fp);
			printf("恭喜您,保存成功");
		}
		exit(0);
	}
}
//复盘
void replay_chess(void) {
	int  chessboard[MAX_ROW][MAX_COL] = {BLANK};
	FILE *fp;
	char ch;
	if ((fp = fopen("Save_chess.txt", "w")) == NULL) {
		printf("复盘失败");
	} else {
		for (int i = 0; i < MAX_ROW; i++) {
			for (int j = 0; j < MAX_COL; j++) {
				fscanf(fp, "%d", chessboard[i][j]);
			}
		}
		fclose(fp);
		draw_chessboardn(MAX_ROW, MAX_COL, chessboard);
	}
}

 五、总结

用C语言设计五子棋小游戏的过程中,充分利用了C当中的数组和循环判断的知识,通过设计五子棋的实践,更加深入的理解C。有错误大家可以指出,共同进步。

 

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐