大家好啊,三子棋算是对于初学者来说比较困难的一个小程序,今天的文章就来讲一下如何独立从头到尾地做出三子棋小程序,如果您感觉学到了东西,不妨给我一个点赞或者关注,在这里祝您新的一年红红火火。
目录
😎博客昵称:陈大大陈
😊座右铭:所谓觉悟,就是在漆黑的荒野上开辟出一条理当前进的光明大道。
😋博主简介:一名热爱C/C++和算法等技术,喜欢运动,爱胡思乱想却胸怀大志的小博主!
😚博主&唠嗑:早中晚安!😄各位CSDN的朋友!😄我是博客新人陈大大陈,希望我的文章能为你带来帮助!欢迎大家在评论区畅所欲言!也希望大家多多为我提出您宝贵的建议!😘如果觉得我写的不错的话还请点个赞和关注哦~😘😘😘
游戏的整体思路
一个较为复杂的小程序一般有着不同的文件来负责不同的功能。我们这里需要新建三个文件。
1. test.c 负责游戏整体流程的实现
2. game.c 负责游戏内部复杂函数的实现
3. game.h 负责包含所有函数所需的头文件
需要注意的是,game.h的创建是在头文件,而game.c和test.c的创建则是在源文件。
且game.c和test.c在创建时选择.cpp文件,而game.h选择.h文件
菜单的实现
以下是我们实现游戏菜单所需的代码段
我们的菜单应该包含这几种功能
1.游戏的进入以及菜单的打印
2.游戏的退出
3.当输入非法时所跳出的错误提示
void menu()
{
printf("**********************************\n");
printf("********* 1 play *********\n");
printf("********* 2 exit *********\n");
printf("**********************************\n");
}
int main()
{
int input;
do
{
menu();
scanf("%d", &input);
switch (input)
{
case 1:
printf("三子棋\n");
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误,请重新选择\n");
break;
}
} while (input);
return 0;
}
我们单独设置一个menu函数,当进入游戏时就会出现玩或者不玩的选项
我们设置选择1是进入游戏,而选择0是退出游戏
while(input)的意思是,只要input不为0,那么循环就一直进行下去
运行截图如下所示
游戏主程序的实现
1.棋盘的初始化
下棋是需要棋盘的,我们首先要进行棋盘的初始化。
想象一下三子棋的形态,是不是很像一个三行三列的二维数组?
那我们就创建一个二维数组来表示棋盘,并借以InitBoard函数将数组清空,也就是清空棋盘,从而方便一会儿下棋。
void game()
{
char board[ROW][COL] = { 0 };
InitBoard(board, ROW, COL);
}
2.棋盘的展现
完成了棋盘方格内部的初始化,下一步就是将棋盘的外壳“井”打印出来。
我们再创建一个DisplayBoard函数,打印棋盘外壳。
void DisplayBoard(char board[ROW][COL],int row,int col)
{
int i, j;
for (i = 0;i < ROW;i++)
{
for (j = 0;j < COL;j++)
{
printf(" %c ",board[i][j]);
if (j < ROW - 1)
{
printf("|");
}
}
printf("\n");
if (i < ROW - 1) {
for (j = 0;j < ROW;j++)
{
printf("---");
if (j < col - 1)
{
printf("|");
}
}
}
printf("\n");
}
}
这个地方难度不高,相信大家一定很容易搞出来,并且方法十分多,我只管抛砖引玉。图案如下。
至于上面出现的ROW和COL两个变量,则是我们为了方便定义的全局变量。
大家在game.h的文件中用define来定义,这里全部取3。
#pragma once
#define COL 3
#define ROW 3
- 为什么要这样做呢?答案是为了之后的修改。
- 要是不使用全局变量,如果代表三子棋行和列的变量出现错误,那将出现我们只能一个一个修改的状况,这是非常麻烦的。
- 所以,方便起见,我们使用便于修改的全局变量。
3.玩家下棋
为了实现玩家下棋这一功能,我们要做到以下几点。
1.对玩家所输入地址的接收,玩家不像程序员,并不知道输入0~2这样的数字,而是会输入从一开始的1~3,所以我们需要将玩家所输入的地址减一。
2.判断玩家下棋的位置是否已有落子,如果不是空白,就重新输入。
3.将玩家下的棋放入对应位置,表现出来。
void PlayerMove(char board[ROW][COL], int row, int col)
{
int x, y;
printf("玩家下棋:\n");
do
{
scanf_s("%d%d", &x, &y);
if (x < 1 || x > row || y < 1 || y > col)//超出范围
{
printf("范围超出,请重新输入\n");
scanf("%d%d", &x, &y);
}
if (x >= 1 && x <= row && y >= 1 && y <= col) {
if (board[x - 1][y - 1] == ' ')//一定要将玩家所输入-1
{
board[x - 1][y - 1] = '*';
break;
}
else
{
printf("位置已有棋子,请重新输入\n");
}
}
} while (1);
}
使用do while循环,当所输入数字不在范围内,则重新输入。
当目标位置等于‘ ’,也就是没有落子时,再往里下棋,之后再用break跳出。
对于玩家下的棋,我们用‘*’表示
4.电脑下棋
要让电脑自动下棋,我们需要引入随机数,随机数的创建依靠下面的代码。
1.srand((unsigned int)time(NULL));
我们通过它调用时间戳产生随机数
2.x = rand() % row;
y = rand() % col;
通过%row来获取1~3的数字,划定随机数的范围
下棋之前,照例要进行有无落子的判断。
void ComputerMove(char board[ROW][COL], int row, int col)
{
printf("电脑下棋\n");
int x, y;
while (1)
{
x = rand() % ROW;
y = rand() % COL;
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
如果成功下棋,就用break跳出,否则再次产生随机数。
对于电脑下的棋,我们用符号‘#’来表示。
5.游戏胜负的判断
棋局千变万化,每一步都有可能产生输赢,我们要不断地进行判断。
而判断的时机,就选择在玩家下棋和电脑下棋之后。
我们创建IsWin函数来判断输赢。
- 我们返回不同的符号来表示不同的状态
- 玩家赢时 --> 返回'*'
- 电脑赢时 --> 返回'#'
- 平局时 --> 返回'C'
- 游戏继续 --> 返回'Q'
void game()
{
int ret;
char board[ROW][COL] = { 0 };
InitBoard(board, ROW, COL);
DisplayBoard(board, ROW, COL);
while (1)
{
PlayerMove(board, ROW, COL);
DisplayBoard(board, ROW, COL);
ret = IsWin(board, ROW, COL);
if (ret != 'Q')
{
break;
}
ComputerMove(board, ROW, COL);
DisplayBoard(board, ROW, COL);
ret = IsWin(board, ROW, COL);
if (ret != 'Q')
{
break;
}
}
if (ret == '*')
{
printf("玩家获胜\n");
}
if (ret == '#')
{
printf("电脑获胜\n");
}
if (ret == 'C')
{
printf("平局\n");
}
}
以上的代码中包含着IsWIn函数,我们需要用它进行胜负判断,它的功能如下。
1.不仅判断行和列,还要判断两条对角线
2.判断棋盘是否被装满,是否分出胜负
int IsWin(char board[ROW][COL], int row,int col)
{
int i, j;
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[1][i] != ' ')
{
return board[0][i];
}
}
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != ' ')
{
return board[1][1];
}
if (board[2][0] == board[1][1] && board[1][1] == board[0][2] && board[1][1] != ' ')
{
return board[1][1];
}
if (IsFull(board, row, col) == 1)
{
return 'C';
}
return 'Q';
}
这一块的代码比较冗杂。我们还需调用IsFull函数来判断棋盘是否已经被装满。
如果棋盘被装满且未分胜负,那就返回‘C’,代码如下。
int IsFull(char board[ROW][COL], int row, int col)
{
int i, j;
for (i = 0;i < ROW;i++)
{
for (j = 0;j < COL;j++)
{
if (board[i][j] == ' ')
{
return 0;//只要有一个空格没有被填满,就返回0
}
}
}
return 1;
}
所以游戏的test.c文件应该这么写
#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void game()
{
int ret;
char board[ROW][COL] = { 0 };
InitBoard(board, ROW, COL);
DisplayBoard(board, ROW, COL);
while (1)
{
PlayerMove(board, ROW, COL);
DisplayBoard(board, ROW, COL);
ret = IsWin(board, ROW, COL);
if (ret != 'Q')
{
break;
}
ComputerMove(board, ROW, COL);
DisplayBoard(board, ROW, COL);
ret = IsWin(board, ROW, COL);
if (ret != 'Q')
{
break;
}
}
if (ret == '*')
{
printf("玩家获胜\n");
}
if (ret == '#')
{
printf("电脑获胜\n");
}
if (ret == 'C')
{
printf("平局\n");
}
}
int main()
{
srand((unsigned int)time(NULL));
int input;
do
{
menu();
scanf("%d", &input);
switch (input)
{
case 1:
printf("三子棋\n");
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误,请重新选择\n");
break;
}
} while (input);
return 0;
}
不要忘记包含“game.h”,那里包含着所需的头文件和函数声明。
下面是game.c文件
#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void InitBoard(char board[ROW][COL],int row,int col)
{
int i, j;
for (i = 0;i < ROW;i++)
{
for (j = 0;j < COL;j++)
{
board[i][j] = ' ';
}
}
}
void DisplayBoard(char board[ROW][COL],int row,int col)
{
int i, j;
for (i = 0;i < ROW;i++)
{
for (j = 0;j < COL;j++)
{
printf(" %c ",board[i][j]);
if (j < ROW - 1)
{
printf("|");
}
}
printf("\n");
if (i < ROW - 1) {
for (j = 0;j < ROW;j++)
{
printf("---");
if (j < col - 1)
{
printf("|");
}
}
}
printf("\n");
}
}
void menu()
{
printf("**********************************\n");
printf("********* 1 play *********\n");
printf("********* 2 exit *********\n");
printf("**********************************\n");
}
void ComputerMove(char board[ROW][COL], int row, int col)
{
printf("电脑下棋\n");
int x, y;
while (1)
{x = rand() % ROW;
y = rand() % COL;
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
void PlayerMove(char board[ROW][COL], int row, int col)
{
int x, y;
printf("玩家下棋:\n");
do
{
scanf_s("%d%d", &x, &y);
if (x < 1 || x > row || y < 1 || y > col)
{
printf("范围超出,请重新输入\n");
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");
}
}
} while (1);
}
int IsFull(char board[ROW][COL], int row, int col)
{
int i, j;
for (i = 0;i < ROW;i++)
{
for (j = 0;j < COL;j++)
{
if (board[i][j] == ' ')
{
return 0;
}
}
}
return 1;
}
int IsWin(char board[ROW][COL], int row,int col)
{
int i, j;
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[1][i] != ' ')
{
return board[0][i];
}
}
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != ' ')
{
return board[1][1];
}
if (board[2][0] == board[1][1] && board[1][1] == board[0][2] && board[1][1] != ' ')
{
return board[1][1];
}
if (IsFull(board, row, col) == 1)
{
return 'C';
}
return 'Q';
}
最后是game.h文件
#pragma once
#define COL 3
#define ROW 3
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<string.h>
void menu();
void DisplayBoard(char board[ROW][COL],int row,int col);
void InitBoard(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);
int IsFull(char board[ROW][COL], int row, int col);
int IsWin(char board[ROW][COL], int row, int col);
下面让我们快乐的来上一把三子棋!
轻松赢下比赛!
本篇文章旨在分享三子棋的写法。🤠希望我的文章能够让大家有所收获!😋😋😋大佬们如果对我的文章有什么建议,或者认为那里写的不好,请在评论区写下您宝贵的意见!😀如果觉得我写的不错的话还请点个赞和关注哦~我会持续输出编程的知识的!🌞🌞🌞