目录
1.游戏介绍及思路
1.1 游戏介绍
三子棋顾名思义有三个相同的棋子相连即为胜利,首先棋盘是一个3*3大小的棋盘,玩家和电脑控制不同的棋子进行下棋,谁先达到三个棋子在一行、一列或者一个对角线上相连就是胜利。
1.2 思路
要实现三子棋,进入游戏界面后,需要先打印一个菜单来选择是否进行游戏,进入游戏后需要一个菜单来选择难度,然后开始下棋,下棋之前我们需要先用二维数组生成一个棋盘,然后将棋盘初始化内容为空格,然后玩家进行下棋,每次下完一步棋,我们都需要判断一下是否胜利,玩家下完棋后电脑下棋,同样每次电脑下完棋后都要判断是否胜利。
2. 主函数main.c
2.1 菜单
2.1.1 菜单1-menu1( )
这个是用来选择是否进行游戏。
void menu1()
{
printf("*****************************************\n");
printf("**************** 1.play *****************\n");
printf("**************** 0.exit *****************\n");
printf("*****************************************\n");
}
结果为:
2.1.2 菜单2-menu2( )
这个菜单是用来选择游戏的难度。
void menu2()
{
printf("*****************************************\n");
printf("**************** 1.简单 *****************\n");
printf("**************** 0.困难 *****************\n");
printf("*****************************************\n");
}
2.2 game( )
game()函数里面主要是三字棋游戏实现的思路,而具体需要使用到的函数都在game.c里面,比如:
初始化棋盘的函数
打印棋盘的函数
玩家下棋的函数
电脑下棋函数(简单版)
电脑下棋函数(困难版)
判断输赢的函数
void game()
{
menu2();
int input = 0;
printf("请选择难度:>");
scanf("%d", &input);
system("cls");
char ret = 0;
char board[ROW][COL] = { 0 };
//初始化棋盘的函数
InitBoard(board, ROW, COL);
//打印棋盘的函数
DisoalyBoard(board, ROW, COL);
//下棋
while (1)
{
//玩家下棋
PlayerMove(board, ROW, COL);
system("cls");
//判断输赢
ret = IsWin(board, ROW, COL);
if (ret != 'C')
{
break;
}
DisoalyBoard(board, ROW, COL);
//简单版电脑下棋
if (input == 1)
{
ComputerMove1(board, ROW, COL);
Sleep(2000);
system("cls");
//判断输赢
ret = IsWin(board, ROW, COL);
if (ret != 'C')
{
break;
}
DisoalyBoard(board, ROW, COL);
}
//困难版电脑下棋
else if (input == 0)
{
ComputerMove2(board, ROW, COL);
Sleep(1500);
system("cls");
//判断输赢
ret = IsWin(board, ROW, COL);
if (ret != 'C')
{
break;
}
DisoalyBoard(board, ROW, COL);
}
}
if (ret == '*')
{
printf("玩家胜利!\n");
}
else if(ret=='#')
{
printf("电脑胜利!\n");
}
else
{
printf("平局!\n");
}
DisoalyBoard(board, ROW, COL);
}
2.3 main( )函数
这是这个游戏的主体,具体实现如下:
int main()
{
srand((unsigned int)time(NULL));//设置随机数的生成起点(时间戳)
int input = 0;
do
{
menu1();//打印菜单
printf("请选择;>");
scanf("%d", &input);
system("cls");//system是一个库函数,可以执行系统命令,cls是清空屏幕
if (input == 1)
{
printf("三子棋游戏开始!\n");
game();
break;
}
else if (0 == input)
{
printf("退出游戏!\n");
break;
}
else
{
printf("选择错误,请重新选择!\n");
}
} while (input);
return 0;
}
3. game.h
game.h文件中主要包含了该游戏所需要的头文件,函数调用的声明,还有一些宏定义的常量。
#pragma once
#define ROW 3
#define COL 3
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<windows.h>
#include<stdlib.h>
//初始化棋盘
void InitBoard(char board[ROW][COL], int row, int col);
//打印棋盘
void DisoalyBoard(char board[ROW][COL], int row, int col);
//玩家下棋
void PlayerMove(char board[ROW][COL], int row, int col);
//电脑下棋,找到没有下棋的位置随机下棋
//简单版
void ComputerMove1(char board[ROW][COL], int row, int col);
//困难版
void ComputerMove2(char board[ROW][COL], int row, int col);
//判断输赢
//玩家赢-'*'
//电脑赢-'#'
//平局-'Q'
//继续-'C'
char IsWin(char board[ROW][COL], int row, int col);
4. game.c
该文件中主要放了game( )函数中所用到的函数具体实现。
4.1 初始化棋盘函数
该函数会将3*3的棋盘内容全部初始化为空格,代码如下:
//初始化棋盘函数(数组)
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] = ' ';//将棋盘初始化为空格
}
}
}
打印出来显示为:
4.2 打印棋盘的函数
该函数的功能是将当前棋盘的内容全部打印出来。代码如下:
//打印棋盘的函数
void DisoalyBoard(char board[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{
//打印数据
//printf(" %c | %c | %c \n",board[i][0],board[i][1],board[i][2]);
for (j = 0; j < col; j++)
{
printf(" %c ", board[i][j]);
if (j < col - 1)
{
printf("|");
}
}
printf("\n");
//打印分割信息
//printf("---|---|---\n");
for (j = 0; j < col; j++)
{
if (i < row - 1)
{
printf("---");
if (j < col - 1)
{
printf("|");
}
}
}
printf("\n");
}
}
4.3 玩家下棋的函数
该函数是玩家下棋的函数,玩家选择想要下的坐标进行下棋,该坐标必须满足在此数组内,所以要进行一个合法性判断。如果该坐标是空格,就可以下棋,代码如下:
//玩家下棋的函数
void PlayerMove(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
while (1)
{
printf("玩家下棋!\n");
printf("请输入坐标:>");
scanf("%d %d", &x, &y);
//坐标合法性判断
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (board[x - 1][y - 1] == ' ')
{
board[x - 1][y - 1] = '*';
break;
}
else
{
printf("坐标被占用,请选择其他位置下棋!\n");
}
}
else
{
printf("坐标非法,请重新输入\n");
}
}
}
4.4 电脑下棋的函数
4.4.1 简单版
电脑随机找一个未下棋的位置进行下棋,代码如下:
//简单版电脑下棋
void ComputerMove1(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("电脑下棋:>\n");
while (1)
{
x = rand() % row;//生成一个0到row-1的数字
y = rand() % col;//0到col-1
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
4.4.2 困难版
如果第一步棋盘最中间位置未下棋,电脑就会下在中间。当每行、每列、主对角线或者副对角线上有两个玩家下过的棋子,且另一个位置为空格,那么电脑会进行堵棋,下在空格位置。
//困难版电脑下棋
void ComputerMove2(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
int i = 0;
int j = 0;
printf("电脑下棋:>\n");
while (1)
{
x = rand() % row;//生成一个0到row-1的数字
y = rand() % col;//0到col-1
if (board[row / 2 ][col / 2 ] == ' ')
{
board[row / 2 ][col / 2 ] = '#';
break;
}
//判断行或列中是否有两个相同元素为'*',有的话就将剩余的' '变为#
for (i = 0; i < row; i++)
{
int count1 = 0;
int count2 = 0;
for (j = 0; j < col; j++)
{
if (board[i][j] == '*')//判断每行元素是否是*
{
count1++;
}
if (board[j][i] == '*')//判断每列元素是否是*
{
count2++;
}
}
//如果每行有两个相同元素为*,那么剩余的' '元素设为#
if (count1 == 2)
{
for (j = 0; j < col; j++)
{
if (board[i][j] == ' ')
{
board[i][j] = '#';
return;
}
}
}
//如果每列有两个相同元素为*,那么剩余的' '元素设为#
if (count2 == 2)
{
for (j = 0; j < col; j++)
{
if (board[j][i] == ' ')
{
board[j][i] = '#';
return;
}
}
}
}
//判断对角线是否有两个为*,是的话,剩余一个元素设为#
//主对角线
int count1 = 0;
for (i = 0; i < row; i++)
{
if (board[i][i] == '*')
{
count1++;
}
}
if (count1 == 2)
{
for (i = 0; i < row; i++)
{
if (board[i][i] == ' ')
{
board[i][i] = '#';
return;
}
}
}
//副对角线
int count2 = 0;
for (i = 1, j = row - 2; i < row && j >= 0; i++, j--)
{
if (board[i][j] == '*')
{
count2++;
}
}
if (count2 == 2)
{
for (i = 1, j = row - 2; i < row && j >= 0; i++, j--)
{
if (board[i][j] == ' ')
{
board[i][j] = '#';
return;
}
}
}
//如果,行、列、主对角线、副对角线上都没有两个坐标为*,那么电脑就随机下棋
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
玩家和电脑下完一次棋打印出来显示:(玩家是星号,电脑是井号)
4.5 判断输赢的函数
在这里我们设置玩家赢就返回星号,电脑赢就返回井号,平局返回‘Q’,继续游戏返回‘C’,在这里我做了一个有限版和无限制版的,在实际运用中使用一个就可以了。在这两个函数中还用到了一个判断棋盘是否下满的函数,我在4.5.3 中给出了该函数的实现。
4.5.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][1] != ' ')
{
return board[i][1];
}
}
//判断列元素是否相等
int j = 0;
for (j = 0; j < col; j++)
{
if (board[0][j] == board[1][j] && board[1][j] == board[2][j] && board[1][j] != ' ')
{
return board[1][j];
}
}
//判断对角线元素是否相等
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' ')
{
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))
{
return 'Q';
}
//游戏继续
return 'C';
}
4.5.2 无限制版(不限制行数和列数)
//判断输赢函数的升级版(不限制行数列数)
char IsWin(char board[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
//判断行元素是否相等
for (i = 0; i < row; i++)
{
int count = 0;
for (j = 1; j < col; j++)
{
if (board[i][0] == board[i][j] && board[i][0] != ' ')
{
count++;
}
if (count == col-1)
{
return board[i][0];
}
}
}
//判断列元素是否相等
for (j = 0; j < col; j++)
{
int count = 0;
for (i = 1; i < row; i++)
{
if (board[0][j] == board[i][j] && board[0][j] != ' ')
{
count++;
}
}
if (count == row-1)
{
return board[0][j];
}
}
//判断对角线元素是否相等
//判断主对角线
int count1 = 0;
for (i = 1; i < row; i++)
{
if (board[0][0] == board[i][i] && board[0][0] != ' ')
{
count1++;
}
if (count1 == row - 1)
{
return board[0][0];
}
}
//判断副对角线
int count2 = 0;
for (i = 1, j = row - 2; i < row && j >= 0; i++, j--)
{
if (board[0][row - 1] == board[i][j] && board[0][row - 1] != ' ')
{
count2++;
}
if (count2 == row - 1)
{
return board[0][row - 1];
}
}
//....前面没有返回值时,没有人赢时,判断平局
if (IsFull(board, row, col))
{
return 'Q';
}
//游戏继续
return 'C';
}
4.5.3 判断棋盘是否下满的函数
//判断棋盘是否满了的函数
//满了返回1
//不满返回0
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;
}
5. 整体代码
5.1 main.c
#include"game.h"
void menu1()
{
printf("*****************************************\n");
printf("**************** 1.play *****************\n");
printf("**************** 0.exit *****************\n");
printf("*****************************************\n");
}
void menu2()
{
printf("*****************************************\n");
printf("**************** 1.简单 *****************\n");
printf("**************** 0.困难 *****************\n");
printf("*****************************************\n");
}
void game()
{
menu2();
int input = 0;
printf("请选择难度:>");
scanf("%d", &input);
system("cls");
char ret = 0;
char board[ROW][COL] = { 0 };
//初始化棋盘的函数
InitBoard(board, ROW, COL);
//打印棋盘的函数
DisoalyBoard(board, ROW, COL);
//下棋
while (1)
{
//玩家下棋
PlayerMove(board, ROW, COL);
system("cls");
//判断输赢
ret = IsWin(board, ROW, COL);
if (ret != 'C')
{
break;
}
DisoalyBoard(board, ROW, COL);
//简单版电脑下棋
if (input == 1)
{
ComputerMove1(board, ROW, COL);
Sleep(2000);
system("cls");
//判断输赢
ret = IsWin(board, ROW, COL);
if (ret != 'C')
{
break;
}
DisoalyBoard(board, ROW, COL);
}
//困难版电脑下棋
else if (input == 0)
{
ComputerMove2(board, ROW, COL);
Sleep(1500);
system("cls");
//判断输赢
ret = IsWin(board, ROW, COL);
if (ret != 'C')
{
break;
}
DisoalyBoard(board, ROW, COL);
}
}
if (ret == '*')
{
printf("玩家胜利!\n");
}
else if(ret=='#')
{
printf("电脑胜利!\n");
}
else
{
printf("平局!\n");
}
DisoalyBoard(board, ROW, COL);
}
int main()
{
srand((unsigned int)time(NULL));//设置随机数的生成起点(时间戳)
int input = 0;
do
{
menu1();//打印菜单
printf("请选择;>");
scanf("%d", &input);
system("cls");//system是一个库函数,可以执行系统命令,cls是清空屏幕
if (input == 1)
{
printf("三子棋游戏开始!\n");
game();
break;
}
else if (0 == input)
{
printf("退出游戏!\n");
break;
}
else
{
printf("选择错误,请重新选择!\n");
}
} while (input);
return 0;
}
5.2 game.h
#pragma once
#define ROW 3
#define COL 3
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<windows.h>
#include<stdlib.h>
//初始化棋盘
void InitBoard(char board[ROW][COL], int row, int col);
//打印棋盘
void DisoalyBoard(char board[ROW][COL], int row, int col);
//玩家下棋
void PlayerMove(char board[ROW][COL], int row, int col);
//电脑下棋,找到没有下棋的位置随机下棋
//简单版
void ComputerMove1(char board[ROW][COL], int row, int col);
//困难版
void ComputerMove2(char board[ROW][COL], int row, int col);
//判断输赢
//玩家赢-'*'
//电脑赢-'#'
//平局-'Q'
//继续-'C'
char IsWin(char board[ROW][COL], int row, int col);
5.3 game.c
#define _CRT_SECURE_NO_WARNINGS
#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] = ' ';//将棋盘初始化为空格
}
}
}
//打印棋盘的函数
void DisoalyBoard(char board[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{
//打印数据
//printf(" %c | %c | %c \n",board[i][0],board[i][1],board[i][2]);
for (j = 0; j < col; j++)
{
printf(" %c ", board[i][j]);
if (j < col - 1)
{
printf("|");
}
}
printf("\n");
//打印分割信息
//printf("---|---|---\n");
for (j = 0; j < col; j++)
{
if (i < row - 1)
{
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("玩家下棋!\n");
printf("请输入坐标:>");
scanf("%d %d", &x, &y);
//坐标合法性判断
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (board[x - 1][y - 1] == ' ')
{
board[x - 1][y - 1] = '*';
break;
}
else
{
printf("坐标被占用,请选择其他位置下棋!\n");
}
}
else
{
printf("坐标非法,请重新输入\n");
}
}
}
//简单版电脑下棋
void ComputerMove1(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("电脑下棋:>\n");
while (1)
{
x = rand() % row;//生成一个0到row-1的数字
y = rand() % col;//0到col-1
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
//困难版电脑下棋
void ComputerMove2(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
int i = 0;
int j = 0;
printf("电脑下棋:>\n");
while (1)
{
x = rand() % row;//生成一个0到row-1的数字
y = rand() % col;//0到col-1
if (board[row / 2 ][col / 2 ] == ' ')
{
board[row / 2 ][col / 2 ] = '#';
break;
}
//判断行或列中是否有两个相同元素为'*',有的话就将剩余的' '变为#
for (i = 0; i < row; i++)
{
int count1 = 0;
int count2 = 0;
for (j = 0; j < col; j++)
{
if (board[i][j] == '*')//判断每行元素是否是*
{
count1++;
}
if (board[j][i] == '*')//判断每列元素是否是*
{
count2++;
}
}
//如果每行有两个相同元素为*,那么剩余的' '元素设为#
if (count1 == 2)
{
for (j = 0; j < col; j++)
{
if (board[i][j] == ' ')
{
board[i][j] = '#';
return;
}
}
}
//如果每列有两个相同元素为*,那么剩余的' '元素设为#
if (count2 == 2)
{
for (j = 0; j < col; j++)
{
if (board[j][i] == ' ')
{
board[j][i] = '#';
return;
}
}
}
}
//判断对角线是否有两个为*,是的话,剩余一个元素设为#
//主对角线
int count1 = 0;
for (i = 0; i < row; i++)
{
if (board[i][i] == '*')
{
count1++;
}
}
if (count1 == 2)
{
for (i = 0; i < row; i++)
{
if (board[i][i] == ' ')
{
board[i][i] = '#';
return;
}
}
}
//副对角线
int count2 = 0;
for (i = 1, j = row - 2; i < row && j >= 0; i++, j--)
{
if (board[i][j] == '*')
{
count2++;
}
}
if (count2 == 2)
{
for (i = 1, j = row - 2; i < row && j >= 0; i++, j--)
{
if (board[i][j] == ' ')
{
board[i][j] = '#';
return;
}
}
}
//如果,行、列、主对角线、副对角线上都没有两个坐标为*,那么电脑就随机下棋
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
//判断棋盘是否满了的函数
//满了返回1
//不满返回0
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][1] != ' ')
// {
// return board[i][1];
// }
// }
//
// //判断列元素是否相等
// int j = 0;
// for (j = 0; j < col; j++)
// {
// if (board[0][j] == board[1][j] && board[1][j] == board[2][j] && board[1][j] != ' ')
// {
// return board[1][j];
// }
// }
//
// //判断对角线元素是否相等
// if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' ')
// {
// 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))
// {
// return 'Q';
// }
//
// //游戏继续
// return 'C';
//}
//判断输赢函数的升级版(不限制行数列数)
char IsWin(char board[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
//判断行元素是否相等
for (i = 0; i < row; i++)
{
int count = 0;
for (j = 1; j < col; j++)
{
if (board[i][0] == board[i][j] && board[i][0] != ' ')
{
count++;
}
if (count == col-1)
{
return board[i][0];
}
}
}
//判断列元素是否相等
for (j = 0; j < col; j++)
{
int count = 0;
for (i = 1; i < row; i++)
{
if (board[0][j] == board[i][j] && board[0][j] != ' ')
{
count++;
}
}
if (count == row-1)
{
return board[0][j];
}
}
//判断对角线元素是否相等
//判断主对角线
int count1 = 0;
for (i = 1; i < row; i++)
{
if (board[0][0] == board[i][i] && board[0][0] != ' ')
{
count1++;
}
if (count1 == row - 1)
{
return board[0][0];
}
}
//判断副对角线
int count2 = 0;
for (i = 1, j = row - 2; i < row && j >= 0; i++, j--)
{
if (board[0][row - 1] == board[i][j] && board[0][row - 1] != ' ')
{
count2++;
}
if (count2 == row - 1)
{
return board[0][row - 1];
}
}
//....前面没有返回值时,没有人赢时,判断平局
if (IsFull(board, row, col))
{
return 'Q';
}
//游戏继续
return 'C';
}