目录
一、了解五子棋基本元素
二、了解五子棋下棋过程
三、重要功能设计
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], "┐");elsedraw_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], "┘ ");elsedraw_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], "┤");elsedraw_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 0void 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], "┐");elsedraw_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], "┘ ");elsedraw_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], "┤");elsedraw_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。有错误大家可以指出,共同进步。