先看效果:
思路:
一共定义了8个函数:
- 菜单打印函数
- 棋盘打印函数
- 玩家下棋函数
- 电脑下棋函数
- 赢家判断函数
- 判断棋盘是否满了函数
- 游戏函数
- 主函数
菜单打印:
这个没什么好说的,printf 输出就行,写成什么样都可以
棋盘打印:
我们的棋盘实际上就是 3x3 的数组,数组中的元素有:| — X(代表人下的棋) o(代表电脑下的棋)空格(棋盘初始化需要),用 for 循环打印就行
玩家下棋
输入两个值作为二维数组的下标,要对值进行判断,一是判断位置是否正确,二是判断位置是否为空,所以有可能你得再下一次,直接把下棋写成死循环,如果下棋成功则break就行。同样的,若成功下棋,下一步一定要判断有没有产生赢家,产生就结束游戏,没产生的话就电脑下棋,注意:在电脑下棋之前还得检测现在棋盘内是否还有位置,没有位置就意味着平局,有位置则电脑下棋。
电脑下棋
电脑下棋是自动的,所以得为电脑产生两个随机值作为二维数组的下标,因为有可能你要下棋的地方已经被占了,所以你得再下一次,所以直接把电脑下棋写成死循环,如果下棋成功则break就行。若成功下棋,下一步一定要判断有没有产生赢家,产生就结束游戏,没产生的话就玩家下棋,注意:在玩家下棋之前还得检测现在棋盘内是否还有位置,没有位置就意味着平局,有位置则玩家下棋。
赢家判断
对于 3x3 的矩阵来说,若是有赢家一共有八种情况(3横3竖2交叉),判断这8条线上的字符是否相同,若字符相同且不是空格,则说明赢家产生,当赢家产生时,通过判断字符是’X’ 还是 ‘o’ 就可以得知到底是人赢了还是电脑赢了,若没有赢家产生判断棋盘是会否满了,满了则输出平局,否则继续
棋盘是否满了
这个很简单,循环遍历棋盘看有没有空格存在,有就没满
游戏函数
游戏函数主要是调用上面函数来实现游戏,但是在此之前要先初始化棋盘,即给数组对应的位置放入空格(因为现在定义的棋盘是 3x3 的,以后可能会改,不妨把它们定义成全局变量),然后按照自己的逻辑来调用函数,因为一般的游戏只要你不退出哪怕游戏输了也会从头开始,所以用 循环 来实现。
代码:
为了显得正式一点,特意分了三个文件:
- test.c
- game.c
- game.h
game.h
#ifndef __GAME_H__
#define __GAME_H__
#define ROW 3
#define COL 3
void InitBoard(char map[ROW][COL], int row, int col);
void DisplayBoard(char map[ROW][COL], int row, int col);
void PlayerMove(char map[ROW][COL], int row, int col);
void Computermove(char map[ROW][COL], int row, int col);
char IsWin(char map[ROW][COL], int row, int col);//有返回值的原因是要根据返回值的字符来看看是人赢了还是电脑
char is_full(char map[ROW][COL], int row, int col);//棋盘是否已满
#endif //__GAME_H__
game.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
void InitBoard(char map[ROW][COL], int row, int col)
{
/*int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
map[i][j] = '*';
}
}*/
memset(map, ' ', row*col*sizeof(map[0][0]));
}
void DisplayBoard(char map[ROW][COL], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
int j = 0;
for (j = 0; j < col; j++)
{
printf(" %c ", map[i][j]);
if (j < col - 1)
{
printf("|");
}
}
printf("\n");
if (i < row - 1)
{
for (j = 0; j < col; j++)
{
printf("--- ");
}
printf("\n");
}
}
}
void PlayerMove(char map[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
//下的位置可能有旗,得重复下,死循环
while (1)
{
printf("请玩家输入坐标:");
scanf("%d%d", &x, &y);
if (1 <= x && row >= x && 1 <= y && col >= y) //坐标界限
{
//先判断这个位置是否有元素
if (map[x - 1][y - 1] == ' ')//为空
{
map[x - 1][y - 1] = 'X';//X代表玩家下的
break; //如果下了元素记得跳出循环
}
else
{
printf("该坐标已经有棋,请重新输入!\n");
}
}
else
{
printf("坐标输入有误,请重新输入!\n");
}
}
}
void Computermove(char map[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("该电脑走了\n");
while (1)
{
x = rand() % row;
y = rand() % col;
if (map[x][y] == ' ')
{
map[x][y] = 'o';
break;
}
}
}
char is_full(char map[ROW][COL], int row, int col) {
int count = row*col;
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
if (map[i][j] == ' ')//有空格就返回t
{
return 't';
}
}
}
return 'f';//没有空格返回f
}
char IsWin(char map[ROW][COL], int row, int col)
{
char ret = is_full(map, ROW, COL);
for (int i = 0; i < row; i++) {
//判断每一行
if (map[i][0] == map[i][1] && map[i][0] == map[i][2] && map[i][0] != ' ')
{
return map[i][0];
}
}
for (int i = 0; i < col; i++) {
//判断每一列是否相等
if (map[0][i] == map[1][i] && map[0][i] == map[2][i] && map[0][i] != ' ')
{
return map[0][i];
}
}
//对角线判断
if (map[0][0] == map[1][1] && map[1][1] == map[2][2] && map[1][1] != ' ') {
return map[0][0];
}
if (map[0][2] == map[1][1] && map[1][1] == map[2][0] && map[1][1] != ' ') {
return map[1][1];
}
if ('f' == ret) {
return 'p';
}
if ('t' == ret) {
return 't';
}
}
test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include "game.h"
//菜单打印函数
void menu()
{
printf("**********************************\n");
printf("****** 欢迎来到三子棋游戏 ********\n");
printf("**********************************\n");
printf("****** 1 play 0 exit ********\n");
printf("**********************************\n");
}
void game()
{
char tmp;
char ret;
char map[ROW][COL] = { 0 };
//第一步:画出棋盘
InitBoard(map,ROW,COL);
//DisplayBoard(map, ROW, COL);
system("cls");//清屏
while (1)
{
PlayerMove(map, ROW, COL);
DisplayBoard(map, ROW, COL);
//每下完一次后都判断一下是否有赢家
tmp = IsWin(map,ROW,COL);
if (tmp == 'X')
{
printf("玩家赢!\n");
break;
}
else if (tmp == 'o')
{
printf("电脑赢!\n");
break;
}
//谁都没赢,先判断棋盘是不是满了,没满再下一步
else if (tmp == 'p')
{
printf("平局!\n");
break;
}
else
;
Computermove(map, ROW, COL);
DisplayBoard(map, ROW, COL);
//每下完一次后都判断一下是否有赢家
tmp = IsWin(map, ROW, COL);
if (tmp == 'X')
{
printf("玩家赢!\n");
break;
}
else if (tmp == 'o')
{
printf("电脑赢!\n");
break;
}
//谁都没赢,先判断棋盘是不是满了,没满再下一步
else if (tmp == 'p')
{
printf("平局!\n");
break;
}
else
;
}
}
//主函数
int main()
{
int input = 0;
srand((unsigned)time(NULL));
//用do while循环这样的话,在最初就会执行一次
do {
menu();
printf("请选择:");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("您的输出有误,请重新输入!\n");
}
} while (input);
system("pause");
return 0;
}
有了上面的思路,再来写五子棋就很简单了,只需要修改三部分
- 1,修改棋盘大小
#define ROW 5
#define COL 5
- 2,修改输赢判断条件
char IsWin(char map[ROW][COL], int row, int col)
{
char ret = is_full(map, ROW, COL);
for (int i = 0; i < row; i++) {
//判断每一行
if (map[i][0] == map[i][1] && map[i][0] == map[i][2] && map[i][0] == map[i][3] && map[i][0] == map[i][4] && map[i][0] != ' ')
{
return map[i][0];
}
}
for (int i = 0; i < col; i++) {
//判断每一列是否相等
if (map[0][i] == map[1][i] && map[0][i] == map[2][i] && map[0][i] == map[3][i] && map[0][i] == map[4][i] && map[0][i] != ' ')
{
return map[0][i];
}
}
//对角线判断
if (map[0][0] == map[1][1] && map[1][1] == map[2][2] && map[2][2] == map[3][3] && map[3][3] == map[4][4] && map[2][2] != ' ') {
return map[2][2];
}
if (map[0][4] == map[1][3] && map[1][3] == map[2][2] && map[2][2] == map[3][1] && map[3][1] == map[4][0] && map[2][2] != ' ') {
return map[2][2];
}
if ('f' == ret) {
return 'p';
}
if ('t' == ret) {
return 't';
}
}
- 3,修改打印棋盘的函数
void menu()
{
printf("**********************************\n");
printf("****** 欢迎来到五子棋游戏 ********\n");
printf("**********************************\n");
printf("****** 1 play 0 exit ********\n");
printf("**********************************\n");
}