三子棋
我们分以下三个文件来实现三子棋:
test.c - 主函数 - 设计整个游戏过程
游戏的逻辑
game.c - 函数的实现
game.h - 函数的声明
成品展示
首先我们打印一个菜单,让玩家选择,选择后会出现棋盘界面,然后让玩家输入坐标下棋。
然后玩家输入坐标,之后实现玩家走和电脑走,直到一方获得胜利,游戏结束。
首先讲一讲我们整体的思路框架,我们设计这个游戏,让玩家想玩的时候可以一直玩,所以我们采用do…while循环语句,然后打印菜单,写一个菜单函数,让玩家进行选择,这里我们采用switch分支语句,当我们选择1时进入游戏,此时需要写一个游戏函数,选择0时退出游戏,选择其他时,告诉他选择错误,重新输入,我们发现当选择1和选择错误时我们需要循环继续,退出游戏是我们退出循环的时候,所以我们将while()里的循环条件设置成玩家输入的选择。
我们的整体逻辑框架如下代码:
test.c
void game()
{
//游戏的实现,这里先不写
}
void menu()
{
printf("********************\n");
printf("*******1.play*******\n");
printf("*******0.exit*******\n");
printf("********************\n");
}
int main()
{
int input=0;
do
{
menu();
printf("请选择:>");
scanf("%d",&input);
switch(input)
{
case 1:
game();
break;
case 2:
printf("退出游戏\n");
break;
default:
printf("选择错误,重新选择\n");
break;
}
}while(input)
return 0;
}
那么游戏的实现,我们该怎么弄呢?
从刚开始我们进行成品展示时,实现这个游戏,我们需要:
1、创建一个存储数据的字符数组
行列的元素个数我们用#define在game.h中定义常量,这样我们需要修改棋盘行列时就很简单,使我们的游戏程序更加灵活多变。
char board[ROW][COL] = { 0 };
2、初始化数据
首先打印的界面数据为空的,我们需要初始化数据为空格
void InitBoard(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]=' ';
}
}
}
3、打印棋盘
打印棋盘代码:
void DisplayBoard(char board[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 ",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");
}
}
}
我们把打印棋盘分成了打印数据行和打印分割行,我们发现分割行我们只打印两次,最后一行我们不需要分割行,所以我们将判断条件设置为i<row-1时我们才打印分割行,我们再看列,最后一行我们不打印|,所以|的打印我们给判断条件j<col-1。
我们还有另一种打印棋盘的方法:
//打印棋盘
//写法不好,当我们想要打印10*10的棋盘时,行会打印10行,但列是3列,通用性不好
//void DisplayBoard(char board[ROW][COL],int row,int col)
//{
// int i=0;
// for(i=0;i<row;i++)
// {
// printf(" %c | %c | %c \n",board[i][0],board[i][1],board[i][2]);
// if(i<row-1)
// {
// printf("---|---|---\n");
// }
// }
//}
但是这种不太建议,写法不好,这个代码只操作了行,不操作列,当我们想要打印10*10的棋盘时,行会打印10行,但列是3列,通用性不好。
4、玩家走
玩家走的函数代码如下:
void PlayerMove(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
while (1)
{
printf("玩家走,请输入下棋的坐标:>");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= 3)
{
if (board[x - 1][y - 1] == ' ')
{
board[x - 1][y - 1] = '*';
break;
}
else
{
printf("该坐标已被占用,请重新选择坐标\n");
}
}
else
{
printf("坐标非法,请重新输入\n");
}
}
}
首先我们需要判断该玩家输入的下棋坐标是否合法,我们的棋盘是三行三列,所以玩家输入的坐标需要再范围内,如果坐标合法了,我们再判断该坐标是否被占用,如果没有被占用,则将该坐标所对应数组下标数据赋值为‘*’(因为我们玩家玩游戏时输入(1,1)坐标时,对应的数组下标为board[0] [0],所以我们判断条件的数组下标需要设置为x-1,y-1)。
5、判断输赢
首先我们看一下判断输赢的基本框架:
我们设定判断输赢函数的返回值
1.玩家赢,返回*
2.电脑赢,返回#
3.平局,返回Q
4.游戏继续,返回C
ret = IsWin(board, ROW, COL);
//1.玩家赢,返回*
//2.电脑赢,返回#
//3.平局,返回Q
//4.游戏继续,返回C
我们在玩家走后判断输赢,在循环内部判断,如果返回的不是C,则说明游戏结束,则跳出循环判断其他三种情况
if (ret != 'C')//游戏已结束
{
break;
}
循环外面判断:
if (ret == '*')
{
printf("玩家赢\n");
}
else if (ret == '#')
{
printf("电脑赢\n");
}
else if (ret == 'Q')
{
printf("平局\n");
}
判断输赢函数代码:
char IsWin(char board[ROW][COL], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
//行
if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' ')
{
return board[i][0];
}
}
for (i = 0; i < col; i++)
{
//列
if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')
{
return board[0][i];
}
}
//对角线
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[2][2] != ' ')
{
return board[1][1];
}
if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
{
return board[1][1];
}
//平局 - 棋盘满
if (IsFull(board,row,col) == 1)
{
return 'Q';
}
return 'C';
}
我们需要判断行、列、对角线是否形成三个一样的字符,以及棋盘是否满判断游戏是否结束,因为我们假定1.玩家赢,返回*,2.电脑赢,返回#所以我们判断行列对角线时可以直接return三个里面任意一个字符,平局我们需要写一个棋盘是否满的函数,如果返回值为1,则表示满–平局,如果电脑赢,玩家赢,平局这三个都不满足,则游戏继续,return字符‘C’。
判断棋盘是否满的代码
//判断棋盘是否满
int IsFull(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] == ' ')
return 0;
}
}
return 1;
}
访问数组每个元素,如果有一个元素等于字符空格,则不满,返回0。
6、电脑走
电脑走函数代码:
void ComputerMove(char board[ROW][COL], int row, int col)
{
printf("电脑走\n");
while (1)
{
int x = rand() % row;
int y = rand() % col;
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
电脑走我们可以弄个随机数,x给他取余行,y取余列,x范围就为0到row-1,y范围就为0到col-1,所以我们直接将下标设置为x,y进行判断是否为空格字符,我们设置一个循环,当坐标被占用时,则一直循环。
7、再次判断输赢
由成品展示,我们需要实现以上功能,我们需要在玩家走后要判断输赢,在电脑走后判断输赢。
test.c中的游戏函数代码如下:
void game()
{
//1.创建存储数据的字符数组,行列的元素我们用#define定义,这样我们需要修改棋盘行列时就很简单
char board[ROW][COL] = { 0 };
//2.首先打印的界面数据为空的,我们需要初始化数据为空格
InitBoard(board, ROW, COL);
//3.打印棋盘
DispalyBoard(board, ROW, COL);
char ret = 0;
while (1)
{
//4.玩家走
PlayerMove(board, ROW, COL);
//判断输赢
ret = IsWin(board, ROW, COL);
//1.玩家赢,返回*
//2.电脑赢,返回#
//3.平局,返回Q
//4.游戏继续,返回C
DispalyBoard(board, ROW, COL);
if (ret != 'C')//游戏已结束
{
break;
}
//电脑走
ComputerMove(board, ROW, COL);
ret = IsWin(board, ROW, COL);
DispalyBoard(board, ROW, COL);
if (ret != 'C')//游戏已结束
{
break;
}
}
if (ret == '*')
{
printf("玩家赢\n");
}
else if (ret == '#')
{
printf("电脑赢\n");
}
else if (ret == 'Q')
{
printf("平局\n");
}
}
游戏的实现中用到的函数我们在game.h文件中声明
game.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define ROW 3
#define COL 3
//初始化数组数据函数声明
void InitBoard(char board[ROW][COL],int row,int col);
//打印棋盘函数声明
void DispalyBoard(char board[ROW][COL], int row, int col);
//玩家走函数声明
void PlayerMove(char board[ROW][COL], int row, int col);
//电脑走函数声明
void ComputerMove(char board[ROW][COL], int row, int col);
//检查输赢函数声明
char IsWin(char board[ROW][COL], int row, int col);
我们在game.c中写函数的定义
game.c
#include"game.h"
//初始化数据函数定义
void InitBoard(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]=' ';
}
}
}
//打印棋盘
//写法不好,当我们想要打印10*10的棋盘时,行会打印10行,但列是3列,通用性不好
//void DisplayBoard(char board[ROW][COL],int row,int col)
//{
// int i=0;
// for(i=0;i<row;i++)
// {
// printf(" %c | %c | %c \n",board[i][0],board[i][1],board[i][2]);
// if(i<row-1)
// {
// printf("---|---|---\n");
// }
// }
//}
//打印棋盘函数定义
void DisplayBoard(char board[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 ",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 PlayerMove(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
while (1)
{
printf("玩家走,请输入下棋的坐标:>");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= 3)
{
if (board[x - 1][y - 1] == ' ')
{
board[x - 1][y - 1] = '*';
break;
}
else
{
printf("该坐标已被占用,请重新选择坐标\n");
}
}
else
{
printf("坐标非法,请重新输入\n");
}
}
}
//电脑走函数定义
void ComputerMove(char board[ROW][COL], int row, int col)
{
printf("电脑走\n");
while (1)
{
int x = rand() % row;
int y = rand() % col;
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
//判断棋盘是否满
int IsFull(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] == ' ')
return 0;
}
}
return 1;
}
//检查输赢函数定义
char IsWin(char board[ROW][COL], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
//行
if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' ')
{
return board[i][0];
}
}
for (i = 0; i < col; i++)
{
//列
if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')
{
return board[0][i];
}
}
//对角线
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[2][2] != ' ')
{
return board[1][1];
}
if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
{
return board[1][1];
}
//平局 - 棋盘满
if (IsFull(board,row,col) == 1)
{
return 'Q';
}
return 'C';
}
test.c
#include"game.h"
void game()
{
//1.创建存储数据的字符数组,行列的元素我们用#define定义,这样我们需要修改棋盘行列时就很简单
char board[ROW][COL] = { 0 };
//2.首先打印的界面数据为空的,我们需要初始化数据为空格
InitBoard(board, ROW, COL);
//3.打印棋盘
DispalyBoard(board, ROW, COL);
char ret = 0;
while (1)
{
//4.玩家走
PlayerMove(board, ROW, COL);
//判断输赢
ret = IsWin(board, ROW, COL);
//1.玩家赢,返回*
//2.电脑赢,返回#
//3.平局,返回Q
//4.游戏继续,返回C
DispalyBoard(board, ROW, COL);
if (ret != 'C')//游戏已结束
{
break;
}
//电脑走
ComputerMove(board, ROW, COL);
ret = IsWin(board, ROW, COL);
DispalyBoard(board, ROW, COL);
if (ret != 'C')//游戏已结束
{
break;
}
}
if (ret == '*')
{
printf("玩家赢\n");
}
else if (ret == '#')
{
printf("电脑赢\n");
}
else if (ret == 'Q')
{
printf("平局\n");
}
}
void menu()
{
printf("**************************\n");
printf("***********1.play*********\n");
printf("***********0.exit*********\n");
printf("**************************\n");
}
int main()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
menu();
printf("请选择:>");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择有误,请重新输入\n");
break;
}
} while (input);
return 0;
}
如有疑问,请留言!欢迎大家学习交流!