三子棋
实现思路:
其实三子棋就是五子棋的简易版,只是三子棋的棋盘较小(本例子中棋盘较小),判断输赢的逻辑比较简单,要实现三子棋:
(1):显示棋盘,棋盘可以用二维数组表示;
(2):实现人机对战,电脑落子的位置可以用随机数表示;
(3):判断输赢(三子连珠),还要注意棋盘是否已满;
(4):每下一步子显示棋盘的时候刷新界面(这个属于windows的命令,很有意思,有兴趣可以搜索一下);
具体的细节放在代码块注释中吧!
代码如下:
本次采用多文件形式来编写代码,采用多文件编写代码的好处就是当程序的功能很多或者分为多个模块时,方便在后期调试,修改某一功能模块时不会影响其他模块,只需该一个子模块就好。
首先时头文件
game.h
#ifndef __GAME_H__//头文件标准开头
#define __GAME_H__
#include<stdio.h>//将所有要包含的头文件都写在本文件中
#include<time.h>
#include<windows.h>
#pragma warning(disable:4996)
#define row 3//宏定义也写在本文件中
#define col 3//此处的3为棋盘大小
#define K ' '//将字符K宏定义为空格
void initboard(char board[][col], int ROW, int COL);//同样函数声明也要由(只声明不实现!)
void showboard(char board[][col], int ROW, int COL);
void game();
void computer(char board[][col], int ROW,int COL);
char judgeboard(char board[][col],int ROW,int COL);
#endif//头文件结尾
然后是源文件(源文件主要是实现头文件中声明的函数)
game.c
#include"game.h"//包含前面定义的头文件
void initboard(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] = K;//K已经被宏定义为空格
}
}
}
void showboard(char board[][col], int ROW, int COL){//显示棋盘,这个函数最麻烦,因为要一次一次的试输出格式,结尾会有输出显示
int i = 0;
int j = 0;
printf(" 1 | 2 | 3 \n");
printf("---------------\n");
for (i = 0; i < ROW; i++){
printf("%d |", i + 1);
for (j = 0; j < COL; j++){
printf("%c |", board[i][j]);
}
printf("\n");
printf("------------------\n");
}
}
void computer(char board[][col], int ROW, int COL){//此函数为电脑落子函数,用随机数来决定
do{//用do{}while()函数的原因是可能随机数生成的坐标可能是已经落子过的,所以要重新随机坐标,直到满足条件
int x = rand() % ROW;//随机数函数
int y = rand() % COL;
if (board[x][y] == ' '){//判断此坐标是否已经被占用
board[x][y] = 'O';
break;//满足就跳出循环
}
} while (1);
}
char judgeboard(char board[][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] != K//不能为空格){
return board[i][0];//满足就返回数组值
}
else if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != K){/判断列是否三子连珠
return board[0][i];
}
}
//以下是判断两个对角线是否三子连珠
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != K){
return board[1][1];
}
else if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != K){
return board[1][1];
}
//没有满足以上就判断棋盘是否已满
for (i = 0; i < ROW; i++){
int j = 0;
for (j = 0; j < COL; j++){
if (board[i][j] == ' '){
return 'N';//未满返回N,N->未满
}
}
}
return 'F';//F->棋盘已满
}
void game(){//游戏主要实现框架函数(重点是流程)
srand((unsigned long)time(NULL));//随机数种子(computer()函数中用到)
char board [row][col];//二位数组表示棋盘
initboard(board, row, col);//先初始化数组
char result;//将判断输赢函数(judgeboard())返回值赋给result
do{
system("cls");//windows清屏命令
showboard(board, row, col);//落子之前子先要显示棋盘(初始化后的数组)
int x = 0;//玩家落子位置
int y = 0;
printf("请输入坐标\n");
scanf("%d %d", &x, &y);
//判断输入坐标是否有效
if (x<1 || x>3 || y<1 || y>3){
printf("输入错误,请重新输入:\n");
continue;
}
else if (board[x-1][y-1] != K){
printf("输入错误,请重新输入:\n");
continue;
}
else{
board[x-1][y-1] = 'X';//因为是面向玩家的,玩家输入1到3,而数组范围为0到2,所以要减一
}
computer(board, row, col);//玩家落完子轮到电脑
showboard(board, row, col);//显示落子后的棋盘
result = judgeboard(board, row, col);//其实可以优化到至少有一个人走三步再判断输赢
if (result != 'N'){//如果返回的不是N->next,就说明输赢已分或者棋盘已满
break;
}
} while (1);
//以下就是根据result输出结果
if (result == 'F'){
printf("平局\n");
}
else if (result == 'X'){
printf("你赢了\n");
}
else if(result == 'O'){
printf("你输了\n");
}
}
接下来是主函数main.c (学过JAVA的应该会对多文件更好理解,此处的主函数就相当于JAVA中的测试类)
#include"game.h"//同样要包含头文件
void Meue(){//一个简易游戏开始菜单(有点过于简易哈哈)
printf("#####################\n");
printf("###欢迎来到三子棋 ###\n");
printf("###1;play 2:exit###\n");
printf("#####################\n");
printf("请输入你的选择\n");
}
int main()
{
int qute = 0;//判断玩家是否还想再来一把
while (!qute)(初始为非0){
Meue();
int select = 0;//玩家的选择
scanf("%d", &select);
switch (select)
{
case 1://输入开始游戏
game();
break;
case 2://输入2退出游戏
printf("Bye bye\n");
qute = 1;//要退出令quit = 1就跳出while循环
break;
default:
printf("输入有误,请重新输入\n");//其他输入情况重新输入
continue;
}
}
system("pause");
return 0;
}```
**总结**
其实实现本程序中的每一个模块都很简单,但是那些都不是重点,重点是锻炼对于一个程序整体的设计以及对程序运行流程的掌握,这里面有很多细节,以后要多加练习。