最近学了三子棋C语言写法,费了很多心血,特地发出来,希望大家可以互相交流,共同进步
首先,为了将代码写的简洁明了,我将三子棋代码实现分为了三个部分,分别是test.c game.c和game.h,它们各司其职,功能如下图所示
我先将代码写出来
1.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()
{ //储存二维数组(引用game.h)
char board[ROW][COL];
//初始化棋盘-初始化为空格
Initboard(board, ROW, COL);
//打印棋盘--本质是打印数组的内容
DisplayBoard(board,ROW,COL);
char ret=0;//接收游戏状态
while (1)
{
//玩家下棋
PlayerMove(board, ROW, COL);
DisplayBoard(board, ROW, COL);
//判断玩家是否赢了游戏
ret=IsWin(board, ROW,COL);
if (ret!='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 if(ret=='Q')
{
printf("平局\n");
}
//DisplayBoard(board, ROW, COL);
}
int main()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
menu();
printf("请选择:>");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("输入错误,请重新输入\n");
break;
}
} while (input);/*当输入1时, 玩游戏, 在break跳出来, 再重新输入input;
输入0时, 直接结束了; 输入其他值, 也会重新输入input.*/
}
game.h部分是游戏内容的总纲,起头部作用
#pragma once
//注意game.h是用来定义函数的,具体实现在game.c中
#include<stdio.h>//头文件的包含,这样那那两个.c文件就不用引
#include<stdlib.h>
#include<time.h>
//宏定义 符号的定义
#define ROW 3
#define COL 3 //列 column
// 函数的声明--初始化棋盘
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);
//在游戏过程中:
//1.玩家赢了-----*
//2.电脑赢了-----#
//3.平局-----Q
//4.游戏继续-----C
//只有返回C时游戏还要jixu
//
//IsWin 用来判断游戏的结果
char IsWin(int board[ROW][COL], int row, int col);
game.c部分是三子棋游戏的具体函数实现,里面有许多巧妙的设计,我也尽我所能加了注释,值得好好琢磨
#pragma once
#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 = 0;
// 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)//为了使棋盘只有row-1行---|
// {
// printf("---|---|---\n");
// }
//
// }
//} 适用性不好
void DisplayBoard(char board[ROW][COL], int row, int col)//写小写的单词是因为形参是实参的一份临时拷贝
{
int i = 0;
for (int 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)//为了使棋盘只有row-1行---|
{
//printf("---|---|---\n");
int j = 0;
for (j = 0; j < col; j++)
{
printf("---");
if (j < col - 1)
printf("|");
}
printf("\n");
}
}
}
void PlayerMove(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("玩家走:>\n");
while (1)
{
printf("请输入下棋的坐标:>");
scanf_s("%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 ComputerMove(char board[ROW][COL], int row, int col)
{
printf("电脑走:>\n");
while (1)
{
int x = rand() % row;//确保x在0到row-1之间
int 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][1] != ' ')
return board[i][1];//设计非常巧妙
}
int j = 0;
for ( j = 0; j < col; j++)
{
if (board[0][j] == board[1][j] && board[1][j] == board[2][j] && board[1][j] != ' ')
return board[0][j];
}
//判断两条对角线
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];
}
//上面都没人赢,所以要判读平局
//如果棋盘满了就平局了就返回1,不满就返回0
int ret=IsFull(board, row, col);
if ( ret == 1)
return 'Q';
return 'C';
}
主要的逻辑就是先用do while将三子棋的框架搭好,然后想好大体的要点.如初始化棋盘---打印棋盘的内容---实现玩家与电脑的下棋功能---判断赢的条件,最后在game.c中细化函数步骤
三子棋实现过程中运用了许多好的编程思想,如宏的定义,利用循环来更好地实现初始化数组,while循环结束的控制,随机数值的获取,思维的严密性……
代码中有许多我个人认为十分巧妙的地方,如果读者有兴趣可以粘贴至编译器上运行测试,看看效果如何。欢迎大家纠错指教!