目录
(3)初始化数组(应该是第一步,先初始化数组在打印数组,放在第二步是为了解释为什们要初始化数组)
game.h的内容(函数的定义和头文件的声明,能在其他两个文件中使用)
1.什么是三子棋游戏
三子棋游戏是黑白棋的一种。三子棋是一种民间传统游戏,又叫九宫棋、圈圈叉叉、一条龙、井字棋等。将正方形对角线连起来,相对两边依次摆上三个双方棋子,只要将自己的三个棋子走成一条线,对方就算输了。但是,有很多时候会出现和棋的情况。
2.三子棋游戏代码实现的设计思路
(1).基本思路(创建几个文件及其设计意义)
test.c文件 测试三子棋游戏
game.h文件 测试游戏函数的函数声明
game.c文件 游戏函数的实现
test.c:放主函数及其代码的基本框架,以及三子棋的基本逻辑。
game.h: 放三子棋游戏函数的函数声明,以及一些头文件声明,方便在test.c和game.c中使用。
game.c:实现游戏函数的内容。
(2)游戏基本框架
游戏思路有了接下来就要设计游戏框架,进而一步一步的实现游戏,一步步封装游戏。下棋可定要有棋盘,然后我们下棋,电脑下棋,在判断输赢。这就是三子棋游戏的基本框架
- 先要打印棋盘
- 在初始化棋盘(下面会将为什们要初始化棋盘)
- 玩家下棋
- 电脑下棋
- 判断输赢
3.三子棋代码实现
(1)游戏的外部封装
对于三子棋游戏不可能玩一把就不玩了,所以应写循环,玩完一把在玩下一把,不想玩就退出,对于这个游戏至少应该进行一次,所以用do-while()循环。为了让玩家看的明白怎么我玩应该封装一个菜单函数,1---进入游戏,0---退出游戏。为什们这么设置也是有用意的,在循环中0---表示假,就可以直接退出游戏,而1--表示真就可以进入游戏,我们需要选择,可以用switch语句进行选择。下面就是代码实现。可以在游戏函数简单写一个输出函数printf简单模拟游戏函数,然后在简单运行一下,看现在已写代码的正确性。
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
void menu()
{
printf("***************************\n");
printf("******1---进入游戏*********\n");
printf("******0---退出游戏*********\n");
printf("***************************\n");
}
void game()
{
printf("游戏开始\n");
}
int main()
{
int input = 0;
do
{
menu();
printf("请输入n->");
scanf("%d", &input);
switch(input)
{
case 1:
game();
break;
case 0:
printf("退出程序\n");
break;
default:
printf("输入错误,请重新输入\n");
break;
}
} while (input);
return 0;
}
(2)先要打印棋盘
在游戏函数中应该先打印棋盘,而棋盘应用数组来存放要打印这种棋盘。先写打印棋盘函数,在game.h文件写定义,然后在game.c和test.c文件引用#include "game.h"使用game.h中定义的东西,打印棋盘其实就找到规律就很好打印了,两个循环一个打印行一个打印列,___三个下划线中间的下划线要用数组的第一个内容填,打印“ %c ”和“|”这个只有当j!=COL时不打印“|”,其他的都依次类推,就非常简单了。打印棋盘代码如下
void print_board(char board[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
printf(" %c ", board[i][j]);
if (j != col-1)
printf("|");
}
printf("\n");
if (i != row-1)
{
for (j = 0; j < col; j++)
{
printf("---");
if (j != col-1)
printf("|");
}
}
printf("\n");
}
}
这是上述代码打印的棋盘,单数打印的好像有问题,数据行好像并没有打印,是因为初始化数据为0,在ASCⅡ表中0,表示null空字符,所以没打印;所以应该让棋盘初始化为空格,让其也打印出来。所以第一步是将数组初始化为空格。
(3)初始化数组(应该是第一步,先初始化数组在打印数组,放在第二步是为了解释为什们要初始化数组)
初始化为空格就会留一个空,打印棋盘就会好看
//初始化函数 将数组初始化为空格
void init_board(char board[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
board[i][j] = ' ';
}
}
}
(4)玩家下棋
打印玩棋盘就开始玩游戏,玩家下棋,玩家输入'*',电脑下棋,电脑输入'#'。所以先写玩家下棋函数,
玩家下棋应该下的合法,没有被电脑下棋占用,而且也不能超过棋盘的大小,
如果坐标不合法,就重新输入,这时就需要用到循环while(1),一直进行循环,知道合法就break跳出循环。
唯一需要注意的点就是玩家不是程序员,他们下棋就是看棋盘的坐标,并不是根据数组的坐标从0开始,(非常重要)
//玩家下棋
void player_board(char board[ROW][COL], int row, int col)
{
int i = 0;//横坐标
int j = 0;//纵坐标
while (1)
{
printf("请输入坐标->");
scanf("%d%d", &i, &j);
//玩家输入坐标是否合法
if (i >= 1 && i <= row && j >= 1 && j <= col )
{
if (board[i - 1][j - 1] == ' ')//是否被占用
{
board[i - 1][j - 1] = '*';//玩家输入*
break;
}
else
{
printf("坐标已被占用,请重新输入\n");
}
}
else
{
printf("坐标不合法,请重新输入\n");
}
}
}
(5)电脑下棋
电脑下棋就可以类比玩家下棋了,也需要一个循环,让坐标合法。只不过电脑下棋是随机的,需要写一个随机函数,rand()函数,需要用到srand函数和time函数,具体内容去查rand函数的使用
//电脑下棋随机下棋()
void computer_board(char board[ROW][COL], int row, int col)
{
int x = rand() % row;//随机x的坐标,而且对3取余,正好是0,1,2符合数组的大小
int y = rand() % col;//随机y的坐标,而且对3取余,正好是0,1,2符合数组的大小
while (1)
{
if (board[x][y] == ' ')//判断坐标是否合法
{
board[x][y] = '#';//电脑输入#
break;
}
}
}
(6).判断游戏输赢
- 玩家赢 返回*
- 电脑赢 返回#
- 平局 返回Q
- 游戏继续 返回C
对于三子棋游戏,游戏有4种方式,对于这个游戏,玩家赢,返回 *,电脑赢返回#,对于为什们返回这个,肯定是因为简单呀(具体情况请看代码为什们简单),在电脑下完或者玩家下完,就判断输赢,看返回值在进行下一步,所以在test.c文件中的game函数中应该这样设计游戏思路,代码如下:需要在定义一个is_win()函数,来通过返回值来判断输赢。is_win()函数在下面代码的下面。
void game()
{
char ret = 0;
char board[ROW][COL] = { 0 };
//初始化数组
init_board(board, ROW, COL);
//打印棋盘函数
print_board(board,ROW,COL);
while (1)//进行循环玩家下棋,电脑下棋知道棋盘下满在通过break跳出循环。
{
//玩家下棋
player_board(board, ROW, COL);
//每当玩家下完应该判断游戏输赢,如果等于C就继续游戏,不等于C,就跳出循环,输出游戏结果。
ret = is_win(board, ROW, COL);
if (ret != 'C')
break;
print_board(board, ROW, COL);//玩家下完需要看棋盘下在哪里了,因此需要打印棋盘。
//电脑下棋
computer_board(board, ROW, COL);
//每当电脑下完应该判断游戏输赢,如果等于C就继续游戏,不等于C,就跳出循环,输出游戏结果。
int ret = is_win(board, ROW, COL);
if (ret != 'C')
break;
print_board(board, ROW, COL);//电脑下完也需要看其下在哪里了
}
if (ret == '*')//为什们打印这个就是玩家赢,请看后面判断输赢代码
{
printf("玩家胜利\n");
}
else if (ret == '#')//为什们打印这个就是电脑赢,请看后面判断输赢代码
{
printf("电脑胜利\n");
}
else if (ret == 'Q')
{
printf("双方平局\n");
}
print_board(board, ROW, COL);//打印最后结果的的棋盘。结束游戏
}
is_win()函数的封装,及为什么要返回#和*都在注释中,为什们封装is_full()函数也在注释中
//判断棋盘满了没
//满了返回1,没满返回0
int is_full(char board[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
if (board[i][j] == ' ')//有空格返回0,说明没有满
return 0;
}
}
//没有空格,说明满了,就直接返回1.
return 1;
}
char is_win(char board[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
//判断玩家和电脑赢把所有方式列出来
//判断一行的内容是否相等且不等于空格
for (i = 0; i < row; i++)
{
if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' ')
//可以直接返回内容,又方便又易懂,
//所以在is_win()函数中通过返回*和#来看玩家赢和电脑赢,不用写两遍,分别判断玩家和电脑
return board[i][0];
}
//判断一列的内容是否相等且不等于空格
for (j = 0; j < col; j++)
{
if (board[0][j] == board[1][j] && board[1][j] == board[2][j] && board[0][j] != ' ')
// 可以直接返回内容,又方便又易懂,
//所以在is_win()函数中通过返回*和#来看玩家赢和电脑赢,不用写两遍,分别判断玩家和电脑
return board[0][j];
}
//判断两条斜线是否相等
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != ' ')
return board[0][0];
if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[0][2] != ' ')
return board[0][2];
//判断玩家和电脑赢,在判断是否平局,还有是否继续
//判断平局和继续要判断棋盘是否满了,所以在封装一个函数是否满了
if (is_full(board, ROW, COL) == 1)
return 'Q';
else
return 'C';
}
(7)组装函数
现在函数就都封装完了,框架也有了,最后组装在一块就好了。
唯一注意的一点就是一些头文件放在game.h中,像#include<stdio.h>很多,然后在去test.c和game.c中引用就好了不需要重复定义
test.c的内容(就是游戏逻辑)
#define _CRT_SECURE_NO_WARNINGS 1
//使用game.h中的函数定义和头文件的使用
#include "game.h"
//菜单函数给用户看的然后在做出选择
void menu()
{
printf("***************************\n");
printf("******1---进入游戏*********\n");
printf("******0---退出游戏*********\n");
printf("***************************\n");
}
void game()
{
char ret = 0;
char board[ROW][COL] = { 0 };
//初始化数组
init_board(board, ROW, COL);
//打印棋盘函数
print_board(board,ROW,COL);
while (1)//进行循环玩家下棋,电脑下棋知道棋盘下满在通过break跳出循环。
{
//玩家下棋
player_board(board, ROW, COL);
//每当玩家下完应该判断游戏输赢,如果等于C就继续游戏,不等于C,就跳出循环,输出游戏结果。
ret = is_win(board, ROW, COL);
if (ret != 'C')
break;
print_board(board, ROW, COL);//玩家下完需要看棋盘下在哪里了,因此需要打印棋盘。
//电脑下棋
computer_board(board, ROW, COL);
//每当电脑下完应该判断游戏输赢,如果等于C就继续游戏,不等于C,就跳出循环,输出游戏结果。
int ret = is_win(board, ROW, COL);
if (ret != 'C')
break;
print_board(board, ROW, COL);//电脑下完也需要看其下在哪里了
}
if (ret == '*')//为什们打印这个就是玩家赢,请看后面判断输赢代码
{
printf("玩家胜利\n");
}
else if (ret == '#')//为什们打印这个就是电脑赢,请看后面判断输赢代码
{
printf("电脑胜利\n");
}
else if (ret == 'Q')
{
printf("双方平局\n");
}
print_board(board, ROW, COL);//打印最后结果的的棋盘。结束游戏
}
int main()
{
srand((unsigned int)time(NULL));
int input = 0;
do
{
menu();
printf("请输入n->");
scanf("%d", &input);
switch(input)
{
case 1:
game();
break;
case 0:
printf("退出程序\n");
break;
default:
printf("输入错误,请重新输入\n");
break;
}
} while (input);
return 0;
}
game.h的内容(函数的定义和头文件的声明,能在其他两个文件中使用)
#pragma once
#define ROW 3
#define COL 3
#include<stdio.h>
#include<time.h>
#include <stdlib.h>
//初始化棋盘
void init_board(char board[ROW][COL], int row, int col);
//打印棋盘
void display_board(char board[ROW][COL], int row, int col);
//玩家下棋
void player_move(char board[ROW][COL], int row, int col);
//电脑下棋
void computer_move(char board[ROW][COL], int row, int col);
//判断输赢
char is_win(char board[ROW][COL], int row, int col);
game.c的内容(封装函数的声明和内容)
//引用game.h中的函数定义和头文件的使用
#include"game.h"
//初始化数组
void init_board(char board[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
board[i][j] = ' ';//通过循环将每一个数初始化为空格
}
}
}
//打印数组
void print_board(char board[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)//打印第一行数据
{
printf(" %c ", board[i][j]);
if (j != col-1)//通过观察最后一个没有竖杠
printf("|");//换行
}
printf("\n");
if (i != row-1)
{
for (j = 0; j < col; j++)
{
printf("---");
if (j != col-1)
printf("|");
}
}
printf("\n");
}
}
//玩家下棋
void player_board(char board[ROW][COL], int row, int col)
{
int i = 0;//横坐标
int j = 0;//纵坐标
while (1)
{
printf("请输入坐标->");
scanf("%d%d", &i, &j);
//玩家输入坐标是否合法
if (i >= 1 && i <= row && j >= 1 && j <= col )
{
if (board[i - 1][j - 1] == ' ')
{
board[i - 1][j - 1] = '*';
break;
}
else
{
printf("坐标已被占用,请重新输入\n");
}
}
else
{
printf("坐标不合法,请重新输入\n");
}
}
}
//电脑下棋
void computer_board(char board[ROW][COL], int row, int col)
{
int x = rand() % row;//随机x的坐标,而且对3取余,正好是0,1,2符合数组的大小
int y = rand() % col;//随机y的坐标,而且对3取余,正好是0,1,2符合数组的大小
while (1)
{
if (board[x][y] == ' ')//判断坐标是否合法
{
board[x][y] = '#';//电脑输入#
break;
}
}
}
//判断棋盘是否满了
int is_full(char board[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
if (board[i][j] == ' ')//有空格返回0,说明没有满
return 0;
}
}
//没有空格,说明满了,就直接返回1.
return 1;
}
//判断游戏情况输赢
char is_win(char board[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
//判断玩家和电脑赢把所有方式列出来
//判断一行的内容是否相等且不等于空格
for (i = 0; i < row; i++)
{
if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' ')
//可以直接返回内容,又方便又易懂,
//所以在is_win()函数中通过返回*和#来看玩家赢和电脑赢,不用写两遍,分别判断玩家和电脑
return board[i][0];
}
//判断一列的内容是否相等且不等于空格
for (j = 0; j < col; j++)
{
if (board[0][j] == board[1][j] && board[1][j] == board[2][j] && board[0][j] != ' ')
// 可以直接返回内容,又方便又易懂,
//所以在is_win()函数中通过返回*和#来看玩家赢和电脑赢,不用写两遍,分别判断玩家和电脑
return board[0][j];
}
//判断两条斜线是否相等
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != ' ')
return board[0][0];
if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[0][2] != ' ')
return board[0][2];
//判断玩家和电脑赢,在判断是否平局,还有是否继续
//判断平局和继续要判断棋盘是否满了,所以在封装一个函数是否满了
if (is_full(board, ROW, COL) == 1)
return 'Q';
else
return 'C';
}
4.最后总结
其实这个内容不难,就是这个逻辑,只要多看几遍,多练习几遍,逻辑想明白就会很简单。以上就是三子棋游戏的全部代码,源码,只要通过自己的努力自己写出来,肯定成就感满满,而且再让别人玩你的三子棋游戏,你的感觉肯定会不一样的。让我们一起加油!!!!