三子棋是一种民间传统游戏,又叫九宫棋、圈圈叉叉、一条龙、井字棋等。将正方形对角线连起来,相对两边依次摆上三个双方棋子,只要将自己的三个棋子走成一条线,对方就算输了。但是,有很多时候会出现和棋的情况。
我们学习c语言也有一段时间了,现在我们尝试自己用C语言写一个三子棋小游戏玩玩吧!
工程文件思路:
主函数放到ticktacktoe(三子棋)中
三子棋具体的实现放到game.c / game.h中
主函数游戏思路:
三子棋游戏思路:
1、至少玩一次,可以玩多次,do…while循环
2、进入游戏后先打印菜单提示
3、提示用户输入,根据输入值来确定后续的游戏进程(1代表玩游戏,0代表退出,其他需要重新选择
三子棋玩游戏的思路:
首先我们要知道三子棋的一些信息:
1、三子棋形状
2、游戏规则:同一形状连成直线(三格)即获胜
所以获胜的条件:1、横排同形状 2、竖排同形状 3、对角线同形状
三子棋游戏实现具体思路:
1.我们要记录下棋的结果,就需要对应的二维数组来存储
2.创建的二维数组要进行初始化,赋值成空格" "
3.打印棋盘,看一下展示的效果
可优化点
1.电脑走可优化,将随机走变成有策略走,让电脑看起来更像“玩家”。(代码中实现了这个优化)
2.判断游戏进展部分可优化,比如说后续ROW,COL都改成4,也就是将三子棋变成四子棋,本程序中的游戏进展部分也需要调整了。为了让ROW,COL在变化调整后依然适用,我们可以对其进行相应的优化。(本次代码暂未实现该优化)
优化1实现:
思路:这个优化的实现注意考虑两个方面的内容:
1、如果电脑落子,有机会直接赢,则优先落在能赢的坐标上
2、如果玩家落子有机会赢,拦截玩家路子坐标(步骤1优先级高于步骤2)
3、如果步骤1、步骤2均不满足,电脑继续伪随机落子
源文件ticktacktoe.c内容
/*******************/
//以下是源文件ticktacktoe.c内容
/*******************/
#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void game_menu(void)
{
printf("*********************************\n");
printf("********* 1.play game ***********\n");
printf("********* 0.exit game ***********\n");
printf("*********************************\n");
}
void play_game(void)
{
char board[ROW][COL] = {
0 };//创建二维数组来存储棋盘下棋数据
Init_board(board, ROW, COL);//初始化棋盘
Display_board(board, ROW, COL);//打印棋盘
char ret = 0;//接收游戏进行的进展
//玩家赢:* 电脑赢:# 平局:Q 继续:C
while (1)
{
Player_move(board, ROW, COL);//玩家下棋
Display_board(board, ROW, COL);//打印棋盘
ret = Is_win(board, ROW, COL);//判断游戏是否继续
if (ret != 'C')
break;
Computer_move(board, ROW, COL);//电脑下棋
Display_board(board, ROW, COL);//打印棋盘
ret = Is_win(board, ROW, COL);//判断游戏是否继续
if (ret != 'C')
break;
}
if (ret == '*')
{
printf("恭喜你,玩家赢得游戏!\n");
}
else if (ret == '#')
{
printf("很遗憾,电脑赢得游戏!\n");
}
else if (ret == 'Q')
{
printf("这把平局,还差一点点就赢了哦!\n");
}
Display_board(board, ROW, COL);//打印棋盘
}
int main()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
game_menu();//打印游戏菜单
printf("请选择:>>");
scanf("%d", &input);
switch (input)
{
case 1:
play_game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误,请重选\n");
break;
}
} while (input);
return 0;
}
头文件game.h内容
/*******************/
//以下是头文件game.h内容
/*******************/
#pragma once
#include
#include
#include
//定义行号和列号
#define ROW 3
#define COL 3
//初始化棋盘声明
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);
//判断电脑能否赢
int Check_computer(char board[ROW][COL], int row, int col);
//判断玩家能否赢
int Judge_player(char board[ROW][COL], int row, int col, int k);
源文件game.c内容
/*******************/
//以下是源文件game.c内容
/*******************/
#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 Display_board(char board[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
for (i = 0; i < row; i++)//打印row行,将棋盘一行 + ___看作一行打印内容
{
for (j = 0; j < col; j++)//打印col列
{
printf(" %c ", board[i][j]);//将 %c 看作一个打印单位
if (j < col - 1)//一行就前col-1个需要打印|,最后一个不打印
printf("|");
}
printf("\n");//一行内容打印完后换行
if (i < row - 1)//最后一行不打印
{
for (j = 0; j < col; j++)
{
printf("---");//将___视为一个整体
if (j < col - 1)//一行就前col-1个需要打印|,最后一个不打印
printf("|");
}
}
//printf("___|___|___\n");//这种打印方式仅能打印三行三列的棋盘,不推荐
printf("\n");//一行内容打印完后换行
}
}
//实现玩家下棋
void Player_move(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("玩家落子:>>\n");
while (1)
{
printf("请输入落子的坐标:>>");
scanf("%d %d", &x, &y);
if ((x >= 1 && x <= row) && (y >= 1 && y <= col))//坐标合理性判断
{
//判断该坐标是否被占用
if (board[x - 1][y - 1] == ' ')//玩家输入的1 1 对应的下标其实是 0 0
{
board[x - 1][y - 1] = '*';
break;
}
else
{
printf("坐标已被占用,请重新输入\n");
}
}
else
{
printf("坐标输入错误,请重新输入\n");
}
}
}
//实现电脑下棋
//void Computer_move(char board[ROW][COL], int row, int col)
//{
//
// while (1)
// {
// int x = rand() % row;
// int y = rand() % col;
// if (board[x][y] == ' ')
// {
// board[x][y] = '#';
// break;
// }
// }
//}
int Judge_player(char board[ROW][COL], int row, int col, int k)
{
//下面这个函数就是判断玩家是否有机会赢,如果能赢就堵住他
int i = 0;
int j = 0;
while (0 == k)
{
//判断玩家在横行上是否会赢
for (i = 0; i < row; i++)
{
if (board[i][0] == board[i][1] && board[i][1] == '*' && board[i][2] == ' ')
{
board[i][2] = '#';
k = 1;
break;
}
if (board[i][0] == board[i][2] && board[i][0] == '*' && board[i][1] == ' ')
{
board[i][1] = '#';
k = 1;
break;
}
if (board[i][1] == board[i][2] && board[i][1] == '*' && board[i][0] == ' ')
{
board[i][0] = '#';
k = 1;
break;
}
}
if (k != 0)
break;
//判断玩家在竖列上是否会赢
for (j = 0; j < col; j++)
{
if (board[0][j] == board[1][j] && board[1][j] == '*' && board[2][j] == ' ')
{
board[2][j] = '#';
k = 1;
break;
}
if (board[0][j] == board[2][j] && board[2][j] == '*' && board[1][j] == ' ')
{
board[1][j] = '#';
k = 1;
break;
}
if (board[1][j] == board[2][j] && board[2][j] == '*' && board[0][j] == ' ')
{
board[0][j] = '#';
k = 1;
break;
}
}
break;
}
//判断玩家在对角线上是否会赢,又加了一个while是为了让判断对角线的代码成块。
while (0 == k)
{
if (board[0][0] == board[1][1] && board[1][1] == '*' && board[2][2] == ' ')
{
board[2][2] = '#';
k = 1;
break;
}
if (board[0][0] == board[2][2] && board[2][2] == '*' && board[1][1] == ' ')
{
board[1][1] = '#';
k = 1;
break;
}
if (board[1][1] == board[2][2] && board[1][1] == '*' && board[0][0] == ' ')
{
board[0][0] = '#';
k = 1;
break;
}
if (board[0][2] == board[1][1] && board[0][2] == '*' && board[2][0] == ' ')
{
board[2][0] = '#';
k = 1;
break;
}
if (board[0][2] == board[2][0] && board[2][0] == '*' && board[1][1] == ' ')
{
board[1][1] = '#';
k = 1;
break;
}
if (board[1][1] == board[2][0] && board[2][0] == '*' && board[0][2] == ' ')
{
board[0][2] = '#';
k = 1;
break;
}
break;
}
return k;//返回值如果是1那么已经对玩家进行了阻拦,如果是0则无需阻拦。
}
int Check_computer(char board[ROW][COL], int row, int col)//判断电脑下一步落子能否赢游戏
{
int i = 0;
int j = 0;
int k = 0;
while (k == 0)
{
//判断电脑行排能否赢
for (i = 0; i < row; i++)
{
if (board[i][0] == board[i][1] && board[i][0] == '#' && board[i][2] == ' ')
{
board[i][2] = '#';
k = 1;
break;
}
if (board[i][0] == board[i][2] && board[i][0] == '#' && board[i][1] == ' ')
{
board[i][1] = '#';
k = 1;
break;
}
if (board[i][1] == board[i][2] && board[i][1] == '#' && board[i][0] == ' ')
{
board[i][0] = '#';
k = 1;
break;
}
}
if (k != 0)//落子后跳出
break;
//判断电脑列排能否赢
for (j = 0; j < col; j++)
{
if (board[0][j] == board[1][j] && board[0][j] == '#' && board[2][j] == ' ')
{
board[2][j] = '#';
k = 1;
break;
}
if (board[0][j] == board[2][j] && board[0][j] == '#' && board[1][j] == ' ')
{
board[1][j] = '#';
k = 1;
break;
}
if (board[2][j] == board[1][j] && board[0][j] == '#' && board[0][j] == ' ')
{
board[0][j] = '#';
k = 1;
break;
}
}
break;
}
//判断电脑对角线能否赢
while (0 == k)
{
//左上角到右下角对角线判断
if (board[0][0] == board[1][1] && board[0][0] == '#' && board[2][2] == ' ')
{
board[2][2] = '#';
k = 1;
break;
}
if (board[0][0] == board[2][2] && board[0][0] == '#' && board[1][1] == ' ')
{
board[1][1] = '#';
k = 1;
break;
}
if (board[1][1] == board[2][2] && board[0][0] == '#' && board[0][0] == ' ')
{
board[0][0] = '#';
k = 1;
break;
}
//左下角到右上角对角线判断
if (board[2][0] == board[1][1] && board[2][0] == '#' && board[0][2] == ' ')
{
board[0][2] = '#';
k = 1;
break;
}
if (board[2][0] == board[0][2] && board[2][0] == '#' && board[1][1] == ' ')
{
board[1][1] = '#';
k = 1;
break;
}
if (board[0][2] == board[1][1] && board[0][2] == '#' && board[2][0] == ' ')
{
board[2][0] = '#';
k = 1;
break;
}
break;
}
k = Judge_player(board, row, col, k);
return k;
}
//实现电脑下棋优化
void Computer_move(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
int ret = 0;
ret = Check_computer(board, row, col);
while (0 == ret)
{
x = rand() % row;
y = rand() % col;
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;
int count = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
if (board[i][j] == ' ')
count++;
}
}
if (count == 0)
return 1;
else
return 0;
}
//实现判断游戏进展
char Is_win(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][0] == board[i][2]) && (board[i][0] != ' '))
{
return board[i][0];
}
}
//判断三列
for (i = 0; i < row; i++)
{
if ((board[0][i] == board[1][i]) && (board[0][i] == board[2][i]) && (board[0][i] != ' '))
{
return board[0][i];
}
}
//判断两条对角线
if ((board[0][0] == board[1][1]) && (board[0][0] == board[2][2]) && (board[0][0] != ' '))
{
return board[0][0];
}
if ((board[0][2] == board[1][1]) && (board[0][2] == board[2][0]) && (board[0][2] != ' '))
{
return board[0][2];
}
//判断平局 棋盘满了返回1,不满返回0
int ret = Is_full(board, row, col);
if (ret == 1)
return 'Q';
else
return 'C';
}