今人不见古时月,今月曾经照古人,
现在是2025年7月31日,工作之余学习C语言的第98天,目前学习内容是操作符,
这两天有一个关于三子棋的小游戏项目,坦诚的说我是看过一次教程,才自己动手写的,所以最重要的主体框架是借鉴来的,当然自己写这四百多行代码的时候也是出现了很多的BUG,各种差错,比如变量名拼写错误,循环少写break,缺少判断胜负判定,if else 与 if 混淆导致判定结果出错,测试代码的时候总是能跳出我的“完美逻辑”,整出幺蛾子,由于我用的是宏定义的 行和列,那么后期优化为五子棋,十字棋都是很方便的,只要把输赢判断逻辑这个大工程处理好也不是不可以,下面就是我的三子棋游戏代码,
//game.h// 头文件名,声明函数,
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define ROW 3 // 宏定义,属于预处理指令,核心理解为文本替换,不进行类型校验,
#define COL 3
// 初始化棋盘 initboard
// 显示棋盘内容 displayboard
// 玩家下棋 playermove
// 电脑下棋 computermove // 找没有下棋的地方随机下棋,
// 初始化棋盘,
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);
// 判断输赢,
// 玩家赢,返回 ' * '
// 电脑赢,返回 ' # '
// 平局 返回 ' q '( quit )
// 胜负未分 返回 ' c '( continue )
char iswin(char board[ROW][COL], int row, int col);
// 判断棋盘是否下完,
// 棋盘下完返回 0
// 棋盘未下完返回 1
int full(char board[ROW][COL], int row, int col);
//logic.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(char board[ROW][COL],int row,int col)
{
// 初始化棋盘,
initboard(board,row,col);
// 显示棋盘,
displayboard(board,row,col);
// 轮流下棋,
while (1)
{
// 用于接收判断输赢的变量,
int result = iswin(board, row, col);
if (result == 'c')
{
playermove(board, row, col);
displayboard(board, row, col);
// 判断输赢,
result=iswin(board, row, col);
if (result == '*')
{
printf("铁汁,你赢了!\a\a\a\a\a\n");
break;
}
computermove(board, row, col);
displayboard(board, row, col);
// 判断输赢,
result=iswin(board, row, col);
if (result == '#')
{
printf("还得练,\a\n");
break;
}
}
if (result == 'q')
{
printf("平局,旗鼓相当的对手!\a\n");
break;
}
}
}
int main()
{
srand((unsigned int)time(NULL));// 设置随机数的生成起点,
char board[ROW][COL] = { 0 };
int input = 0;
do
{
menu();// 打印菜单,
scanf("%d", &input);
switch (input)
{
case 1:
printf(" 三子棋游戏( 规则; 先将三个棋子连成一线的获胜)\n 下棋示例:\n 第一格坐标:< 1 , 1 >\n 第二格坐标;< 1 , 2 >\n");
game(board, ROW, COL);
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("输入错误,请重新输入:\n");
break;
}
} while (input);
return 0;
}
//game.c// 源文件名,游戏实现,
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
// 初始化棋盘,
void initboard(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 displayboard(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");
// }
// }
// printf(" | | \n");
//}
void displayboard(char board[ROW][COL], int row, int col)
{
for (int i = 0; i < row; i++)// 打印行内容,
{
for (int j = 0; j < col; j++)
{
printf(" %c ",board[i][j]);
if (j < col - 1)// 过滤掉最后一列 " | "
{
printf("|");
}
}
printf("\n");
if (i < row - 1)// 过滤掉最后一行 " ___ "
{
for (int j = 0; j < col; j++)
{
printf("___");
if (j < col - 1)// 过滤掉最后一列 " | "
{
printf("|");
}
}
printf("\n");
}
}
for (int 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("请输入坐标:<__,__>\n");
scanf("%d %d", &x, &y);
if (x>=0&&x<=row&&y>=0&&y<=3)
{
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");
int x = 0;
int y = 0;
while (1)
{
x = rand() % row;// 得到行下标范围 0 - 2
y = rand() % col;// 得到列下标范围 0 - 2
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
break;// 第二次 BUG ,漏写一个 braak; 导致棋盘下满但无法输出平局信息,
}
}
// 判断输赢,
char iswin(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][1] != ' ')
{
return board[i][1];// 此处为了确保唯一性,所以不能返回 board[i][0], 与满足对角线情况重复,
}
}
// 判断列,
for (int j = 0; j < col; j++)
{
if (board[0][j] == board[1][j] && board[2][j] == board[1][j] && board[1][j] != ' ')
{
return board[1][j];// 此处为了确保唯一性,所以不能返回 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[2][0] == board[1][1] && board[1][1] == board[0][2] && board[1][1] != ' ')
{
return board[1][1];
}
// 平局,
if (full(board, row, col))
{
return 'c';
}
else// 第一次出现 BUG 就是这里,少写 else 导致无法再次回到 game() 中的 while(1) 循环,
{
return 'q';
}
}
// 判断棋盘是否下完,棋盘没下完返回 1 ,棋盘下完返回 0
int 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 1;
}
}
}
return 0;
}