前言:
本文讲述的是如何用C语言实现最基础的三子棋游戏,主要采用的是数组知识。
若不需要过程详情解释,只需工程代码,我会在最后总结全部展示出来。
一.创建工程:
分别创造三个项到工程中,分别是
test.c( 测试三子棋游戏 )
game.h( 游戏的函数声明 )
game.c( 游戏函数的实现 )
二.设计和实现代码:
2.1 设计和实现游戏菜单和选项
首先,既然是游戏,当然有游戏的开始菜单和选项,这边我们现在test.c文件中,实现菜单函数,打印出简易的菜单列表。
menu() {
printf("*********************************\n");
printf("******** 1. play ********\n");
printf("******** 0. exit ********\n");
printf("*********************************\n");
}
这样我们便有了简易的菜单列表展示,既然有选项,当然也需要给玩家设计能选择选项的功能。
int main() {
int input = 0;//选项
do
{
menu();
printf("请选择:\n");
scanf("%d", &input);
switch (input) {
case 0:
printf("退出游戏");
break;
case 1:
game();//之后实现的游戏功能
break;
default:
printf("输入有误,请重新输入:\n");
break;
}
} while (input);
return 0;
}
这样当玩家选择0时,会退出游戏;选择1时,会开始游戏;若选错,则会重新选择。
2.2 设计和实现棋盘
首先我们要设计出棋盘的样子,假设我们的棋盘是“井”字状,那棋盘应该是这样的
那么 我们的代码打印出来可以是这样的
根据图中所想,来实现代码
首先在game函数中,初始化一个棋盘数组,然后再调用game.c中的display_board()实现棋盘(已在game.h中包含所需库函数和声明行(row)和列(col))
game() {
char board[ROW][COL] = { 0 };
display_board(board,ROW,COL);
}
void display_board(char board[ROW][COL], int row, int col) {
for (int i = 0; i < row; i++) {
//打印数据
printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]);
if (i < row - 1)
printf("---|---|---\n");
}
}
接着我们测试运行下函数,看是否实现我们所想的棋盘样子
由图可以看出,我们的代码应该在某一部分出现了问题。
问题就出再了我们的初始化数组上,因为我们初始化数组时所赋的值是{0},而在打印时,0(\0)打印的时候是不会显示出来的,所以可以从上图看出来,我们在打印数据那行,每一个小格中都缺少了一个字符空间。
既然问题找到了,我们就开始解决问题。我们设计在game.c中设计一个初始化函数,把数组中每一个空间都赋一个空格。
game() {
char board[ROW][COL] = { 0 };
init_board(board, ROW, COL);
display_board(board,ROW,COL);
}
void init_board(char board[ROW][COL], int row, int col)
{
for (int i = 0; i < row; i++){
for (int j = 0; j < col; j++){
board[i][j] = ' ';
}
}
}
接着在测试运行代码:
这回就可以看到,棋盘是符合我们所需要的。
既然棋盘已经设计和实现好了,接着便是在棋盘下棋了。
2.2 玩家下棋
首先设计玩家下棋的规则,选择棋子落子位置,必须在方框里面,且如果已经被有棋子在里面了,应该提示玩家有棋子,让玩家重新选择,所以:实现玩家下棋函数player_move()
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] = ' ') {
board[x - 1][y - 1] = '*';
break;
}
else {
printf("该坐标已被占用,请重新选择坐标\n");
}
}
else {
printf("该坐标不在棋盘范围内,请重新选择坐标\n");
}
}
}
然后测试,假设落子到(1,1)的位置,结果如下图:
2.3 电脑下棋
接下来设计电脑下棋,由于电脑是随机下棋的,首先我们得设计一个在棋盘范围内下棋的随机数值,其实还得考虑电脑下棋应该选择更好赢的位置,但这里只是简单的随机下棋,就不过多在设计复杂函数。
所以接下来实现函数电脑下棋void computer_move()
在test.c的main函数中已使用srand()来设计随机的随机数值。
void computer_move(char board[ROW][COL], int row, int col) {
printf("电脑下棋:\n");
while (1) {
//实现电脑下棋的坐标
int x = rand() % row;
int y = rand() % col;
if (board[x][y] == ' '){
board[x][y] = '#';
break;
}
}
}
测试下代码,结果如图:
2.4 判断输赢和平局
首先我们要设计,怎样算赢,怎样算输,怎样算平局。
赢输:某一方所拥有的棋子,能在横、竖、对角线其中任意一方连接起三个棋子,则算赢,反之则输。
平局:在棋盘全部位置已经有棋子的情况下,仍未达到输赢条件,则算平局。
根据上面所设计的规则,实现函数。首先实现函数 is_full(),判断棋盘是否满了。
int is_full(char board[ROW][COL], int row, int col){
for (int i = 0; i < row; i++){
for (int j = 0; j < col; j++){
if (' ' == board[i][j]){
return 0;
}
}
}
return 1;
}
接着实现函数is_win(),判断是否赢了.
char is_win(char board[ROW][COL], int row, int col){
//判断横方向是否达到赢的条件
for (int 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 (int 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 (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 (is_full(board, row, col) == 1){
return 'Q';
}
//继续
return 'C';
}
2.5 设计和完成game()函数运行逻辑
根据上面所实现的判断输赢平局的代码,我们应设计一个接收值,如果返回的是
‘#’ ——电脑赢
‘*’ ——玩家赢
‘Q’——平局
‘C’——再来一局
接着,应该设计运行逻辑:
1.初始化一个二维数组(棋盘)
2.打印棋盘
3-8循环(游玩过程)
3.玩家下棋
4.打印棋盘
5.判断输赢、平局
6.电脑下棋
7.打印棋盘
8.判断输赢、平局
根据上述逻辑实现代码:
game() {
char ret = 0;
//数据的存储需要一个3*3的二维数组
char board[ROW][COL] = { 0 };
init_board(board, ROW, COL);
display_board(board, ROW, COL);
//玩游戏
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);
}
这样就可以实现一个入门级的三子棋游戏了
总体代码:
test.c:
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
menu() {
printf("*********************************\n");
printf("******** 1. play ********\n");
printf("******** 0. exit ********\n");
printf("*********************************\n");
}
game() {
char ret = 0;
//数据的存储需要一个3*3的二维数组
char board[ROW][COL] = { 0 };
init_board(board, ROW, COL);
display_board(board, ROW, COL);
//玩游戏
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
{
menu();
printf("请选择:");
scanf("%d", &input);
switch (input) {
case 0:
printf("退出游戏");
break;
case 1:
game();//之后实现的游戏功能
break;
default:
printf("输入有误,请重新输入:\n");
break;
}
} while (input);
return 0;
}
game.h:
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#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);
game.c:
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
void init_board(char board[ROW][COL], int row, int col)
{
for (int i = 0; i < row; i++) {
for (int j = 0; j < col; j++) {
board[i][j] = ' ';
}
}
}
void display_board(char board[ROW][COL], int row, int col) {
for (int i = 0; i < row; i++) {
//打印数据
printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]);
if (i < row - 1)
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] = ' ') {
board[x - 1][y - 1] = '*';
break;
}
else {
printf("该坐标已被占用,请重新选择坐标\n");
}
}
else {
printf("该坐标不在棋盘范围内,请重新选择坐标\n");
}
}
}
void computer_move(char board[ROW][COL], int row, int col) {
printf("电脑下棋:\n");
while (1) {
//实现电脑下棋的坐标
int x = rand() % row;
int y = rand() % col;
if (board[x][y] == ' '){
board[x][y] = '#';
break;
}
}
}
int is_full(char board[ROW][COL], int row, int col){
for (int i = 0; i < row; i++){
for (int j = 0; j < col; j++){
if (' ' == board[i][j]){
return 0;
}
}
}
return 1;
}
char is_win(char board[ROW][COL], int row, int col){
//判断横方向是否达到赢的条件
for (int 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 (int 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 (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 (is_full(board, row, col) == 1){
return 'Q';
}
//继续
return 'C';
}