一、代码
1.text.c
#define _CRT_SECURE_NO_WARNINGS 1
#pragma warning(disable:6031)
//测试游戏
#include"game.h"
void meun()
{
printf("**************************************\n");
printf("************* 1.play *************\n");
printf("************* 0.exit *************\n");
printf("**************************************\n");
}
void game()
{
//棋盘
char board[X][Y] = { 0 };
//初始化棋盘
Initboard(board, X, Y);
//空棋盘
Emptyboard(board, X, Y);
char ret = 0;
while (1)
{
//玩家
Playboard(board, X, Y);
Emptyboard(board, X, Y);
//判断输赢
ret = Iswin(board, X, Y);
if (ret != 'C')
break;
//电脑
computerboard(board, X, Y);
Emptyboard(board, X, Y);
//判断输赢
ret = Iswin(board, X, Y);
if (ret != 'C')
break;
}
if (ret == '#')
{
printf("玩家胜利\n");
}
else if (ret == '*')
{
printf("电脑胜利\n");
}
else
{
printf("平局\n");
}
}
int main()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
meun();
printf("请选择:");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出\n");
break;
default:
printf("选择错误,重新选择\n");
break;
}
} while (input);
return 0;
}
2.game.c
#define _CRT_SECURE_NO_WARNINGS 1
#pragma warning(disable:6031)
//游戏的实现
#include"game.h"
//初始化棋盘
void Initboard(char board[X][Y], int x, int y)
{
int i = 0;
for (i = 0; i < x; i++)
{
int j = 0;
for (j = 0; j < y; j++)
{
board[i][j] = ' ';
}
}
}
//空
void Emptyboard(char board[X][Y], int x, int y)
{
int i = 0;
for (i = 0; i < x; i++)
{
//字符
for (int j = 0; j < y; j++)
{
printf(" %c ", board[i][j]);
if (j < y - 1)
{
printf("|");
}
}
printf("\n");
//分割线
if (i < x-1)
{
for (int j = 0; j < y; j++)
{
printf("---");
if (j < y - 1)
{
printf("|");
}
}
}
printf("\n");
}
}
//玩家
void Playboard(char board[X][Y], int x, int y)
{
//发坐标
int row = 0;//横
int col = 0;//纵
printf("玩家下棋(#)\n");
while (1)
{
printf("玩家输入坐标(空格分隔):");
scanf("%d %d", &row, &col);
//1.未超出
if (row <= x && row > 0 && col <= y && col > 0)
{
//未占用
if (board[row - 1][col - 1] == ' ')
{
board[row - 1][col - 1] = '#';
break;
}
//占用
else
{
printf("坐标占用,请再次输入\n");
}
}
//2.超出
else
{
printf("坐标超出,请再次输入\n");
}
}
}
//电脑
void computerboard(char board[X][Y], int x, int y)
{
//发坐标
int row = 0;//横
int col = 0;//纵
printf("电脑下棋(*)\n");
//随机分配x进制
while (1)
{
row = rand() % x;
col = rand() % y;
if (board[row][col] == ' ')
{
board[row][col] = '*';
break;
}
}
}
//是否满员
int Isfull(char board[X][Y], int x, int y)
{
int i = 0;
for (i = 0; i < x; i++)
{
int j = 0;
for (j = 0; j < y; j++)
{
if (board[i][j] == ' ')
{
return 0;
}
}
}
return 1;
}
//判断输赢
char Iswin(char board[X][Y], int x, int y)
{
//玩家 - #
//电脑 - *
//平局 - Q
//继续 - C
int i = 0;
//行(0,0)(0,1)(0,2)
for (i = 0; i < x; i++)
{
if (board[i][0] == board[i][1] && board[i][2] == board[i][1] && board[i][0] != ' ')
{
return board[i][0];
}
}
//列(0,0)(1,0)(2,0)
for (i = 0; i < y; i++)
{
if (board[0][i] == board[1][i] && board[2][i] == board[1][i] && board[0][i] != ' ')
{
return board[0][i];
}
}
//斜(0,0)(1,1)(2,2)
if (board[0][0] == board[1][1] && board[2][2] == board[1][1] && board[0][0] != ' ')
{
return board[1][1];
}
//斜(2,0)(1,1)(0,2)
if (board[2][0] == board[1][1] && board[0][2] == board[1][1] && board[1][1] != ' ')
{
return board[1][1];
}
//平局满了即平局
if (Isfull(board, X, Y) == 1)
{
return 'Q';
}
return 'C';
}
3.game.h
#pragma once
//游戏函数声明
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
//不可以横X 列Y不一样
#define X 3
#define Y 3
//初始化棋盘
void Initboard(char board[X][Y], int x, int y);
//空棋盘
void Emptyboard(char board[X][Y], int x, int y);
//玩家
void Playboard(char board[X][Y], int x, int y);
//电脑
void computerboard(char board[X][Y], int x, int y);
//判断输赢
char Iswin(char board[X][Y], int x, int y);
二、思路剖析
1.整体轮廓
- 在test.c文件中游戏测试
- 在game.c文件中游戏实现
- 在game.h文件中游戏声明
在test.c文件中游戏测试
首先打印菜单,表示打开游戏
void meun()
{
printf("**************************************\n");
printf("************* 1.play *************\n");
printf("************* 0.exit *************\n");
printf("**************************************\n");
}
在main函数中进行引用,为实现玩了一把还可以选择是否再次玩,将菜单meun放入循环内
- 先显示菜单,故用do……while()循环,首先进行打印,随后在判断是否要继续
- 根据菜单显示,输入1 — 玩游戏,输入0 — 退出,若输入其他则提醒再次输入
将输入的数字作为是否循环的标志
输入0跳出循环,输入1继续循环,输入其他则需要继续输入
- 输入为数字,用switch语句会更加便捷
int main()
{
int input = 0;
do
{
meun();
printf("请选择:");
scanf("%d", &input);
switch (input)
{
case 1:
printf("玩游戏\n");
break;
case 0:
printf("退出\n");
break;
default:
printf("选择错误,重新选择\n");
break;
}
} while (input);
return 0;
}
进行测试
在玩游戏处调用game(),在game()函数中,调用game.c文件中的函数。
步骤
(1)进行数据的存储,可以使用3*3的二维数组
(2)下棋前数组中为空格以及分割线(初始化)
(3)玩家发坐标
(4)电脑发坐标
(5)判断,当行、列、斜都为相同字母时,返回结果。
void game()
{
//棋盘
char board[X][Y] = { 0 };
//初始化棋盘
Initboard(board, X, Y);
//空棋盘
Emptyboard(board, X, Y);
char ret = 0;
while (1)
{
//玩家
Playboard(board, X, Y);
Emptyboard(board, X, Y);
//判断输赢
ret = Iswin(board, X, Y);
if (ret != 'C')
break;
//电脑
computerboard(board, X, Y);
Emptyboard(board, X, Y);
//判断输赢
ret = Iswin(board, X, Y);
if (ret != 'C')
break;
}
if (ret == '#')
{
printf("玩家胜利\n");
}
else if (ret == '*')
{
printf("电脑胜利\n");
}
else
{
printf("平局\n");
}
}
玩家和电脑输入字符后,进行打印棋盘,显示出字符输入
//玩家
Playboard(board, X, Y);
Emptyboard(board, X, Y);
//电脑
computerboard(board, X, Y);
Emptyboard(board, X, Y);
在每次玩家或者电脑输入字符后,都应判断一次是否胜利。
任何一方取得胜利或者棋盘都为字符,结束游戏。
方式为:
玩家或者电脑输入字符后,判断是否返回结束标志。
若返回C,即代表没有胜利且还有空格。
若返回其他字符,则跳出循环,判定最终结果。
在game.c文件中游戏实现
- 初始化棋盘
void Initboard(char board[X][Y], int x, int y)
{
int i = 0;
for (i = 0; i < x; i++)
{
int j = 0;
for (j = 0; j < y; j++)
{
board[i][j] = ' ';
}
}
}
将二维数组board[X][Y]中的元素都初始化为“空格”
board[i][j] = ' ';
一个字符用’ ',字符串用" "
- 空棋盘(打印棋盘)
void Emptyboard(char board[X][Y], int x, int y)
{
int i = 0;
for (i = 0; i < x; i++)
{
for (int j = 0; j < y; j++)
{
printf(" %c ", board[i][j]);//可以输入不同的字符
if (j < y - 1)
{
printf("|");//在每个方格后加入竖线分隔符
}
}
printf("\n");
if (i < x - 1)
{
for (int j = 0; j < y; j++)
{
printf("---");
if (j < y - 1)
{
printf("|");//在每个横线分隔符后加入竖线分隔符
}
}
}
printf("\n");
}
}
为了可以使之后玩家玩,需要在打印棋盘时,将棋盘的内容拥有可变性
printf(" %c ", board[i][j]);
-
在每个字符后加入竖线分割线,用于三子棋的竖向分割线。
-
在每个字符下面加入横线分割线,打印的一个字符占三个空格,故用三个短线用于三子棋的横向分割线。
-
横向分割线后也应有竖向分割线。
- 玩家下棋
void Playboard(char board[X][Y], int x, int y)
{
//发坐标
int row = 0;//横
int col = 0;//纵
printf("玩家下棋(#)\n");
while (1)
{
printf("玩家输入坐标(空格分隔):");
scanf("%d %d", &row, &col);
//1.未超出
if (row <= x && row > 0 && col <= y && col > 0)
{
//未占用
if (board[row - 1][col - 1] == ' ')
{
board[row - 1][col - 1] = '#';
break;
}
//占用
else
{
printf("坐标占用,请再次输入\n");
}
}
//2.超出
else
{
printf("坐标超出,请再次输入\n");
}
}
}
- 输入玩家下棋的横纵坐标。
- 判断两个条件:1.是否超出棋盘范围 2.是否坐标已被占用。满足其一都将重新输入。
- 两个条件中,超出棋盘范围为大范围,若已超出棋盘范围,则不用判断坐标是否被占用。
- 坐标未被占用,则将此处的空格换为玩家下棋的符号即‘#’,随后跳出循环,结束玩家下棋。
- 电脑下棋
void computerboard(char board[X][Y], int x, int y)
{
//发坐标
int row = 0;//横
int col = 0;//纵
printf("电脑下棋(*)\n");
//随机分配x进制
while (1)
{
row = rand() % x;
col = rand() % y;
if (board[row][col] == ' ')
{
board[row][col] = '*';
break;
}
}
}
电脑下棋为随机下棋
rand()函数返回介于0到RAND_MAX之间的伪随机数
row = rand() % x;
col = rand() % y;
使得row的范围在0~x之间(包括0且不包括x)
使得col的范围在0~y之间(包括0且不包括y)
5. 判断是否胜利
//判断输赢
char Iswin(char board[X][Y], int x, int y)
{
//玩家 - #
//电脑 - *
//平局 - Q
//继续 - C
int i = 0;
//行(0,0)(0,1)(0,2)
for (i = 0; i < x; i++)
{
if (board[i][0] == board[i][1] && board[i][2] == board[i][1] && board[i][0] != ' ')
return board[i][0];
}
//列(0,0)(1,0)(2,0)
for (i = 0; i < y; i++)
{
if (board[0][i] == board[1][i] && board[2][i] == board[1][i] && board[0][i] != ' ')
return board[0][i];
}
//斜(0,0)(1,1)(2,2)
if (board[0][0] == board[1][1] && board[2][2] == board[1][1] && board[0][0] != ' ')
return board[1][1];
//斜(2,0)(1,1)(0,2)
if (board[2][0] == board[1][1] && board[0][2] == board[1][1] && board[1][1] != ' ')
return board[1][1];
//平局满了即平局
if (Isfull(board, X, Y) == 1)
return 'Q';
return 'C';
}
玩家和电脑胜利条件:行、列、斜都为相同字符且不为 ‘空格’
当棋盘满了但玩家和电脑都未胜利,则平局
玩家胜利 - 返回‘#’,电脑胜利 - 返回‘*’,平局 - 返回‘Q’
所以main函数中用字符接收返回类型为字符的返回值。
判断是否棋盘已满调用Isfull函数(放在Iswin函数上方)
棋盘已满返回1,棋盘未满返回0
//是否满员
int Isfull(char board[X][Y], int x, int y)
{
int i = 0;
for (i = 0; i < x; i++)
{
int j = 0;
for (j = 0; j < y; j++)
{
if (board[i][j] == ' ')
return 0;
}
}
return 1;
}
在game.h文件中游戏声明
- test.c和game.c中使用的函数在此库函数中包含。
//游戏函数声明
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
- board棋盘的行和列,目的是该表行和列的长度时,更加容易改变。可直接在game.h中改变一次,整个程序中都会改变。
//不可以横X 列Y不一样
#define X 3
#define Y 3
- 实现游戏的函数,为了连接game.c和test.c
//初始化棋盘
void Initboard(char board[X][Y], int x, int y);
//空棋盘
void Emptyboard(char board[X][Y], int x, int y);
//玩家
void Playboard(char board[X][Y], int x, int y);
//电脑
void computerboard(char board[X][Y], int x, int y);
//判断输赢
char Iswin(char board[X][Y], int x, int y);
2.补充
在电脑下棋时,电脑下棋是随机下棋:
int rand (void);
生成随机数 rand():
返回介于0和RAND_MAX之间的伪随机数
头文件为#include<stdlib.h>
rand每次调用会返回一个明显不相关的数字序列,应使用srand函数初始化不同的值。
void srand (unsigned int seed);
srand:初始化随机数生成器,为了生成类似随机数,用函数time返回的值(时间戳)
time_t time (time_t* timer);
time()获取当前时间
头文件#include<time.h>
time_t为long long整型,time_t* timer可以为空指针
time函数与srand套娃时,可将time的类型强制转换成(unsigned int)
srand((unsigned int)time(NULL));
在一次游戏的过程中,只需要初始化一次随机数即可,故应将初始化随机数放入main函数的循环外
int main()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
//游戏
}while(input);
return 0;
}