用c语言实现人机对战的三子棋(多子琪),代码无写死,可通过宏定义灵活改动,但是电脑下棋并不够智能,需要自己加一些算法来训练电脑,出奇制胜。
首先需要先写一个菜单函数,不管我们玩不玩都会先执行一遍,所以采用的do、while,再执行switch,判断玩家选择的是什么分支,执行无错误之后再开始改动。
接着写我们的初始化面板函数和展示面板函数,实现实时打印面板状态。
接着编写我们的玩家/电脑下棋函数,玩家下棋需要先判断输入的坐标是否在范围内,且是否为空,电脑下棋需要rand函数结合srand函数产生随机数在空位置随机下棋。
判断输赢函数,在每次下棋之后执行,最后完成了我们的三子棋程序。
最后,美化代码,为我们的代码添加注释,方便日后阅读。
test.c文件
#include "game.h"
void menu()
{
printf("******************************\n");
printf("*******1. play 0. exit********\n");
printf("******************************\n");
}
void game()
{
int ret = 0;
char Board[ROW][COL] = { 0 };
InitBoard(Board, ROW, COL); // 初始化游戏棋盘
DisplayBoard(Board, ROW, COL); // 显示初始游戏棋盘
while (1)
{
PlayerMove(Board, ROW, COL); // 玩家进行移动
ret = IsWin(Board, ROW, COL); // 检查是否有玩家胜利
if (ret != 'C')
{
break; // 如果有胜利者,则退出游戏循环
}
DisplayBoard(Board, ROW, COL); // 显示更新后的游戏棋盘
ComputerMove(Board, ROW, COL); // 计算机进行移动
ret = IsWin(Board, ROW, COL); // 检查是否有计算机胜利
if (ret != 'C')
{
break; // 如果有胜利者,则退出游戏循环
}
DisplayBoard(Board, ROW, COL); // 显示更新后的游戏棋盘
}
if (ret == '*')
{
printf("The Winner is Player\n"); // 打印玩家获胜信息
}
else if (ret == '#')
{
printf("The Winner is Computer\n"); // 打印计算机获胜信息
}
else
{
printf("Game Tie\n"); // 打印平局信息
}
DisplayBoard(Board, ROW, COL); // 最终显示游戏棋盘
}
int main()
{
srand((unsigned int)time(NULL)); // 设置随机数种子
int input = 0;
do
{
menu(); // 显示游戏菜单
printf("Please Enter a Number > ");
scanf("%d", &input); // 获取用户输入的数字
switch (input)
{
case 1:
game(); // 开始游戏
break;
case 0:
printf("Successfully Exited the Game!\n"); // 输出退出游戏信息
break;
default:
printf("Instruction Exception!Please Re-enter!\n"); // 输出指令异常信息
break;
}
} while (input); // 循环直到用户输入 0 退出游戏
return 0;
}
game.h文件
#define _CRT_SECURE_NO_WARNINGS
#pragma once
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#define ROW 3 // 定义棋盘的行数
#define COL 3 // 定义棋盘的列数
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); // 计算机进行移动
char IsWin(char Board[ROW][COL], int row, int col); // 检查游戏是否有胜者
int IsFull(char 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 = 0;
int j = 0;
// 使用嵌套循环遍历棋盘的每个元素
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 (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)
{
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("Player chess > \n"); // 提示玩家下棋
while (1) // 无限循环,直到玩家输入合法且空闲的坐标位置
{
printf("Please enter coordinates > \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("This location is already occupied,Please re-enter!\n"); // 坐标位置已被占用提示
}
}
else
{
printf("Abnormal coordinates!Please re-enter!\n"); // 坐标输入不合法提示
}
}
}
void ComputerMove(char Board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("Computer chess > \n"); // 提示计算机下棋
while (1) // 无限循环,直到计算机找到合法且空闲的坐标位置
{
x = rand() % row; // 随机生成行坐标
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; // 如果有空闲位置,返回0表示棋盘未满
}
}
}
return 1; // 如果没有空闲位置,返回1表示棋盘已满
}
char IsWin(char Board[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
for (i = 0; i < row; i++) // 检查每一行是否有相同的棋子
{
if (Board[i][0] != ' ') // 如果第一个格子不为空
{
char first = Board[i][0]; // 记录第一个格子的棋子类型
int count = 1; // 记录相同棋子的数量,初始化为1,因为已经有一个相同的棋子
for (j = 1; j < col; j++)
{
if (Board[i][j] == first) // 如果当前格子的棋子类型与第一个相同
{
count++; // 增加相同棋子的数量
if (count == col) // 如果一整行都是相同的棋子
{
return first; // 返回获胜的棋子类型
}
}
else
{
break; // 如果遇到不同的棋子类型,结束内循环
}
}
}
}
for (j = 0; j < col; j++) // 检查每一列是否有相同的棋子
{
if (Board[0][j] != ' ') // 如果第一行的某个格子不为空
{
char first = Board[0][j]; // 记录第一个格子的棋子类型
int count = 1; // 记录相同棋子的数量,初始化为1,因为已经有一个相同的棋子
for (i = 1; i < row; i++)
{
if (Board[i][j] == first) // 如果当前格子的棋子类型与第一个相同
{
count++; // 增加相同棋子的数量
if (count == row) // 如果一整列都是相同的棋子
{
return first; // 返回获胜的棋子类型
}
}
else
{
break; // 如果遇到不同的棋子类型,结束内循环
}
}
}
}
if (Board[0][0] != ' ') // 检查从左上到右下的对角线是否有相同的棋子
{
char first = Board[0][0]; // 记录左上角第一个格子的棋子类型
int count = 1; // 记录相同棋子的数量,初始化为1,因为已经有一个相同的棋子
for (i = 1; i < row; i++)
{
if (Board[i][i] == first) // 如果当前格子的棋子类型与第一个相同
{
count++; // 增加相同棋子的数量
if (count == row) // 如果一整条对角线都是相同的棋子
{
return first; // 返回获胜的棋子类型
}
}
else
{
break; // 如果遇到不同的棋子类型,结束内循环
}
}
}
if (col - 1 >= 0 && Board[0][col - 1] != ' ') // 检查从右上到左下的对角线是否有相同的棋子
{
char first = Board[0][col - 1]; // 记录右上角第一个格子的棋子类型
int count = 1; // 记录相同棋子的数量,初始化为1,因为已经有一个相同的棋子
for (i = 1; i < row; i++)
{
if (col - 1 - i >= 0 && Board[i][col - 1 - i] == first) // 如果当前格子的棋子类型与第一个相同
{
count++; // 增加相同棋子的数量
if (count == row) // 如果一整条对角线都是相同的棋子
{
return first; // 返回获胜的棋子类型
}
}
else
{
break; // 如果遇到不同的棋子类型,结束内循环
}
}
}
if (IsFull(Board, row, col)) // 如果棋盘已满且没有任何一方获胜
{
return 'Q'; // 返回平局标志
}
return 'C'; // 如果棋盘未满且没有任何一方获胜,返回继续游戏标志
}