前言
三子棋简单来说就是井字棋
规则:双方依次在9宫格棋盘上摆放棋子,率先将自己的三个棋子走成一条线就视为胜利,而对方就算输了,但是三子棋在很多时候会出现和棋的局面。
大致过程:
在一个棋盘上,一个人率先下棋子,然后就是另外一个人下棋,直到一方的棋子能够连成一条直线或是棋盘下满了但双方都没有赢(和棋)
经过了解,我们第一步需要设计一个简单的棋盘
例如:
一、设计一个棋盘
1、'手动’打印棋盘
我们可以把一行看做一个整体,再将每一行打印出来
每一行就是:
void print_board()
{
int i = 0;
for (i = 0;i < 3;i++)
{
printf(" | | \n");
printf("---|---|---\n");
}
}
int main()
{
//将打印棋盘封装为一个函数
print_board();
return 0;
}
运行结果:
很显然:框起来的是多余的,咱们不需要它。
改进棋盘:
void print_board()
{
int i = 0;
for (i = 0;i < 3;i++)
{
printf(" | | \n");
//当到第三行是不想"---|---|---"的
if(i<3-1)
printf("---|---|---\n");
}
}
int main()
{
print_board();
return 0;
}
运行结果:
看来我们已经成功打印出棋盘了,如果我们想打印出更大的棋盘呢?,那每次修改棋盘的大小都需要我们自己动手修改程序,是不是太麻烦呢!!
2、'自动’打印棋盘
举个例子:还是打印三子棋的棋盘
我们定义一个变量(ROW)控制行,定义一个变量(COL)控制列,当然这个变量是可以修改的(C语言中我们可以使用宏定义)。
我们还是可以把一行看做一个整体,再将每一行打印出来
每一行就是:
再把每一行分为:
第一行:空格、空格、空格和 | 。
第二行:-、-、- 和 | 。
用COL控制它们的数量
代码实现:
#define ROW 3
#define COL 3
void print_board(int row,int col)
{
int j = 0;
//
for (j = 0;j < col;j++)
{
printf(" ");//这里是打印三个空格,后面的时候中间的空格是用来下棋子的
if (j < col - 1)
printf("|");
}
printf("\n");
for (j = 0;j < col;j++)
{
printf("---");
if (j < col - 1)
printf("|");
}
}
int main()
{
print_board(ROW,COL);
return 0;
}
运行结果:
打印三个这样的东西:
#define ROW 3
#define COL 3
void print_board(int row,int col)
{
int i = 0;
int j = 0;
for (i = 0;i < row; i++)
{
//打印 空格空格空格|
for (j = 0;j < col;j++)
{
printf(" ");
if (j < col - 1)
printf("|");
}
printf("\n");
//打印---|
for (j = 0;j < col;j++)
{
printf("---");
if (j < col - 1)
printf("|");
}
printf("\n");
}
}
int main()
{
print_board(ROW,COL);
return 0;
}
运行结果:
框起来的还是不需要的,将它去除。
#define ROW 3
#define COL 3
void print_board(int row,int col)
{
int i = 0;
int j = 0;
for (i = 0;i < row; i++)
{
for (j = 0;j < col;j++)
{
printf(" ");//打印三个空格,中间的空格是落棋子的
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");
}
}
int main()
{
print_board(ROW,COL);
return 0;
}
运行结果:
这样我们想修改棋盘的大小时,只需要修改宏定义的ROW和COL了,是不是很方便了。
例如:打印5*5的棋盘
这样一来,棋盘就已经设计好了,接下来就是下棋了。
二、下棋
1、初始化棋盘
我们可以定义一个二维数组,将这个二维数组的全部元素初始化为空格(因为空格是透明的)。还是将它封装为一个函数(init_board)
这个二维数组其实就是记录棋盘内容的。
void init_board(char board[][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] = ' ';
}
}
}
如果我们要使用print_board打印棋盘的元素的话,还要需要修改一下print_board。
前面提到三个空格中间的一个就是落棋子的(即放棋盘元素的位置)
void print_board(char board[][COL], int row, int col)
{
int i = 0;
int j = 0;
for (i = 0;i < row; i++)
{
for (j = 0;j < col;j++)
{
//%c是打印字符,打印的是棋盘元素的第i行第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");
}
}
这样我们就可以打印数组内容了,举个例子:我将数组全部初始化为‘*’
print_board结果就是:
2、玩家下棋
玩家输入对应的棋盘坐标,我们就把数组对应的坐标赋值为’*',这就相当玩家落棋了。封装为函数(play_move)
代码实现:
void player_move(char board[ROW][COL], int row, int col)
{
printf("玩家下棋\n");
int x = 0;
int y = 0;
while (1)
{
printf("请选择下棋的位置:>");
scanf("%d %d", &x, &y);
//输入棋盘的有效下标才有用
if (x >= 1 && x <= row && y >= 1 && y <= col && board[x-1][y-1]==' ')
{
board[x-1][y-1] = '*';
break;
}
else
{
printf("输入错误!\n");
}
}
}
3、电脑下棋
电脑生成两个随机数(0<=随机数的值<=2),我们再将数组下标对应的这个两个随机数赋值为’#'。这样电脑下棋就好了
当然,这个两个随机数不能重复。数组已经赋值了的下标也不能使用。
代码实现:
void computer_move(char board[ROW][COL], int row, int col)
{
printf("电脑下棋\n");
while (1)
{
//rang是一个库函数,它是用来生成随机数的,随机数%row(3),就是生成0到2的随机数。rand是用使用条件的,后面再说。
int x = rand() % row;
int y = rand() % col;
//is_full()这个函数是判断数组元素是否已经满了,满了的话就只能终止循环。后面会实现
if (is_full(board, row, col))
break;
if (x >= 0 && x < row && y >= 0 && y < col && board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
4、判断棋盘的情况
玩家和电脑下完棋后,有三种情况
详细一点就是:
第一种:电脑或玩家完成如图的任意一种情况,连起来的数组元素是相同的。
第二种:数组已经装满了,但还没有人赢(和棋)
第三种:数组还没有装满,也没有人赢,这种情况就还需要继续下棋。
还是写成一个函数,既然这个函数需要反应多种情况,我们就把它的返回类型设置为char,第一种情况就返回已经连成一条线的任意一个元素,第二种就返回’Q’(表示平局),第三种就返回’C’(表示继续游戏)。
代码实现:
//判断数组元素是否已经全部初始化(棋盘是否满了)
int is_full(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;
}
}
}
//如果for没有return 0,就是说明数组全部的元素都已经初始化(即棋盘落棋落满了)
return 1;
}
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][1] == board[i][2] && board[i][1] != ' ')
return board[i][1];
//这是竖三列
else if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')
return board[0][i];
//这是对角线的两种情况
else if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' ')
return board[1][1];
else if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
return board[1][1];
}
//判断棋盘是否满了,满了的话就返回1,if语句就会return Q,跳出当前函数
if (is_full(board, row, col))
return 'Q';
else
return 'C';
}
三、组装
前面大致介绍了如何做一个棋盘,玩家如何下棋,电脑如何下棋,以及判断棋盘的情况。
那我们如何将它组成一个可以执行的小游戏呢?
我们需要一个test.c(测试游戏逻辑)
还要game.c (实现三子棋的函数)和game.h(函数声明)
直接看代码:
首先是:game.h
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#define ROW 3
#define COL 3
void game();
void test();
//初始化棋盘
void init_board(char board[ROW][COL], int row, int col);
//打印棋盘
void print_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);
//玩家赢返回'*'
//电脑赢返回'#'
//平局返回'Q'
//剩余的一种情况就是继续下棋,返回'C'
接下来是:game.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
//初始化棋盘
void init_board(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++)
{
board[i][j] = ' ';
}
}
}
//打印棋盘
void print_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++)
{
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 < row - 1)
printf("|");
}
printf("\n");
}
}
}
//玩家下棋
void player_move(char board[ROW][COL], int row, int col)
{
printf("玩家下棋\n");
int x = 0;
int y = 0;
while (1)
{
printf("请选择下棋的位置:>");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col && board[x-1][y-1]==' ')
{
board[x-1][y-1] = '*';
break;
}
else
{
printf("输入错误!\n");
}
}
}
int is_full(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;
}
//电脑下棋
void computer_move(char board[ROW][COL], int row, int col)
{
printf("电脑下棋\n");
while (1)
{
int x = rand() % row;
int y = rand() % col;
if (is_full(board, row, col))
break;
if (x >= 0 && x < row && y >= 0 && y < col && board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
//判断输赢
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][1] == board[i][2] && board[i][1] != ' ')
return board[i][1];
else if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')
return board[0][i];
else if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' ')
return board[1][1];
else if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
return board[1][1];
}
if (is_full(board, row, col))
return 'Q';
else
return 'C';
}
最后是:test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
void menu()
{
printf("*********************\n");
printf("****** 1.play ****\n");
printf("****** 0.exit ****\n");
printf("*********************\n");
}
void game()
{
char ret = ' ';
srand(time(NULL));
char board[ROW][COL] = { 0 };
init_board(board,ROW,COL);
print_board(board, ROW, COL);
while (1)
{
player_move(board, ROW, COL);
print_board(board, ROW, COL);
ret = is_win(board, ROW, COL);
if (ret != 'C')
{
break;
}
computer_move(board, ROW, COL);
print_board(board, ROW, COL);
ret = is_win(board, ROW, COL);
if (ret != 'C')
{
break;
}
}
if (ret == '*')
printf("玩家赢\n");
else if (ret == '#')
printf("电脑赢\n");
else
printf("平局\n");
}
void test()
{
int input = 0;
do
{
menu();
printf("请选择:>");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default :
printf("选择错误\n");
break;
}
} while (input);
}
int main()
{
test();
return 0;
}
最后来看看游戏的运行过程吧。
QQ录屏20221108172525
总结
以上就是三子棋的全部代码了,快去试一试吧。