目录
三子棋的介绍
三子棋,想必大家都一定玩过,就是一个3*3的表格,两个玩家交替落子,谁先使棋盘中的某一行,或者某一列,又或者某一对角线全部落成字节的子,则谁就获胜。如果棋盘下满了还没有获胜,就表示平局。上面便是三子棋的整个游戏过程,那么我们究竟如何把三子棋用代码实现呢?这便是我们这一期要探讨的内容。
三子棋代码实现
设置游戏菜单
//设置游戏菜单
void menu()
{
printf("*************************\n");
printf("******** 1.play *******\n");
printf("******** 0.exit *******\n");
}
游戏过程
创建二维数组
char board[ROW][COL];
整个棋盘可以看做是一个3行3列的二维数组,这里用了宏定义,因为如果创建二维直接给定行数和列数为3的话,后续维护代码时所有3的地方都应该修改,较为繁琐,这也是我们后续编码时的一个小技巧。
初始化棋盘
//初始化棋盘
void InitBoard(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 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) {
printf("玩家走\n");
int x = 0;
int y = 0;
while (1)
{
printf("请输入坐标>\n");
scanf("%d%d", &x, &y);//传给的x,y值是要放入的坐标,如果是2,1;那么对应数组元素的下标就是1,0;
if (x >= 0 && x <= row && y >= 0 && y <= col)
{
if (board[x - 1][y - 1] == ' ')
{
board[x - 1][y - 1] = '*';
break;
}
else
{
printf("坐标被占用,请重新输入\n");
}
}
else {
printf("坐标违法,超出范围\n");
}
}
}
玩家输入一个坐标,但是坐标一般是从1开始的,而数组的元素的下标是从0开始的,所以得给坐标减去1(x-1,y-1);在落子之前得判断要落子的位置的元素是否为空,只有为空,才可以落子
电脑下棋
//电脑下棋
void ComputerMove(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;
if (board[x][y] == ' ') {
board[x][y] = '#';
break;
}
}
}
电脑落子是随机的,所以我们用到了库中的rand()函数,返回的整型模row后,范围为(0—row-1),而数组的行标的范围就是(0—row-1),所以可以直接(x,y)表示数组元素的下标。
判断输赢
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 (IsFull(board, ROW, COL)) {
return 'Q';
}
//游戏继续
else {
return 'C';
}
}
有四种返回值,
//返回 '*', 玩家胜
//返回 '#',电脑胜
//返回 'C',游戏继续
//返回 'Q',平局
//分析:以上四种状态,只有返回'C'这种状态,游戏继续进行,其它三种状态都是游戏结束
游戏整个过程实现
//游戏过程
void game()
{
//三子棋的过程,本质上就是一个二维数组
char board[ROW][COL];
//初始化棋盘,每个元素全部初始化为空格
InitBoard(board, ROW, COL);
//打印棋盘
DisplayBoard(board,ROW,COL);
//开始下棋,创建一个变量ret,用来表示游戏的状态
char ret = 0;
//游戏进行的整个过程
while (1)
{
//玩家下棋
PlayerMove(board,ROW,COL);
//打印棋盘
DisplayBoard(board, ROW, COL);
//判断游戏状态
ret = IsWin(board,ROW,COL);
if (ret != 'C') { //游戏既然能够进行,证明ret的值肯定是'c',若果不是'c',证明游戏结束
//游戏结束
break;
}
//电脑下棋
ComputerMove(board,ROW,COL);
//打印棋盘
DisplayBoard(board,ROW,COL);
//判断游戏状态
ret = IsWin(board,ROW,COL);
if (ret != 'C') {
break;
}
}
//游戏结束之后,判断是谁获胜
if (ret == '*') {
printf("玩家获胜\n");
}
else if (ret == '#') {
printf("电脑玩家获胜\n");
}
else {
printf("平局\n");
}
}
注意:不管玩家还是电脑,每落完一次子,就得打印一次棋盘,因为只有打印了棋盘,玩家才能知道往哪里落子。而且,每落子一次就得判断游戏的状态,游戏的状态就是IsWin函数的四种返回值。
全部代码
总共分为了三个文件:
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 DisplayBoard(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);
//判断游戏状态
//要返回四种不同的状态
//返回'*', 玩家胜
//返回'#',电脑胜
//返回'C',游戏继续
//返回'Q',平局
//分析:以上四种状态,只有返回'C'这种状态,游戏继续进行,其它三种状态都是游戏结束
char IsWin(char board[ROW][COL], int row, int col);
game.c(相关函数的实现)
#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
//初始化棋盘
void InitBoard(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 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) {
printf("玩家走\n");
int x = 0;
int y = 0;
while (1)
{
printf("请输入坐标>\n");
scanf("%d%d", &x, &y);//传给的x,y值是要放入的坐标,如果是2,1;那么对应数组元素的下标就是1,0;
if (x >= 0 && x <= row && y >= 0 && y <= col)
{
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) {
int x = 0;
int y = 0;
printf("电脑走\n");
while (1) {
x = rand() % row; //随机数函数,模行数之后的范围就是0—row-1.刚好是行标的范围
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 (IsFull(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");
}
//游戏过程
void game()
{
//三子棋的过程,本质上就是一个二维数组
char board[ROW][COL];
//初始化棋盘,每个元素全部初始化为空格
InitBoard(board, ROW, COL);
//打印棋盘
DisplayBoard(board,ROW,COL);
//开始下棋,创建一个变量ret,用来表示游戏的状态
char ret = 0;
//游戏进行的整个过程
while (1)
{
//玩家下棋
PlayerMove(board,ROW,COL);
//打印棋盘
DisplayBoard(board, ROW, COL);
//判断游戏状态
ret = IsWin(board,ROW,COL);
if (ret != 'C') { //游戏既然能够进行,证明ret的值肯定是'c',若果不是'c',证明游戏结束
//游戏结束
break;
}
//电脑下棋
ComputerMove(board,ROW,COL);
//打印棋盘
DisplayBoard(board,ROW,COL);
//判断游戏状态
ret = IsWin(board,ROW,COL);
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
{
menu();
printf("请选择> \n");
scanf("%d",&input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误\n");
break;
}
} while (input);
return 0;
}
以上便是三子棋的所有代码, 需要的小伙伴自行提取。
总结
总的来说,以上的代码基本上实现了三子棋的基本功能,但是需要注意的是,以上的电脑玩家是很笨的,因为是随机的函数,也就是说,电脑玩家下的每一步都是随机的,与此前游戏进行的每一步都是没有关联的,这就导致了,你可能想让电脑玩家赢,电脑玩家都不会去赢,这只是一个基本的三子棋案例,电脑玩家的聪明程度可完全取决于各位。
本期内容到此结束^_^

文章介绍了如何使用C语言实现一个简单的三子棋游戏,包括创建二维数组表示棋盘,初始化棋盘,玩家和电脑轮流下棋的逻辑,以及判断输赢和平局的函数。代码分为游戏菜单设置、游戏过程实现、棋盘操作和游戏状态判断等部分,电脑的走棋是随机的,游戏结束条件是玩家、电脑获胜或平局。
844

被折叠的 条评论
为什么被折叠?



