一、前言
文章最后附带完整代码,可实现三子棋简单的人机对战。
二、游戏规则
1、双方玩家轮流在3×3的棋盘上下棋,率先将三枚棋子连成一条线(横向、纵向和对角线)的一方获胜。
2、若棋盘铺满时仍未有一方获胜,则判双方平局。
三、实现思路
1、创建菜单
创建一个菜单打印函数
void menu() {
printf("******************************\n");
printf("******** 1.play **********\n");
printf("******** 0.exit **********\n");
printf("******************************\n");
}
在主函数中利用do...while循环实现多次菜单选择
int input = 0;
do {
menu();
printf("请选择>:");
scanf("%d", &input);
switch (input) {
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("输入错误,请重新输入!!!\n");
break;
}
} while (input);
2、棋盘初始化
在game()函数中利用二元数组创建棋盘
char board[3][3];
在game.c文件中实现初始化函数InitBoard(board)
void InitBoard(char board[3][3]) {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
board[i][j] = ' ';
}
}
}
并在main.h文件中声明
//初始化棋盘
void InitBoard(char board[3][3]);
3、棋盘打印
利用|和-分隔棋盘中的各个格子,将二元数组中的各个其中打印到对应位置。
void DisplayBoard(char board[3][3]) {
printf(" %c | %c | %c \n", board[0][0], board[0][1], board[0][2]);
printf("-----------\n");
printf(" %c | %c | %c \n", board[1][0], board[1][1], board[1][2]);
printf("-----------\n");
printf(" %c | %c | %c \n", board[2][0], board[2][1], board[2][2]);
}
4、开始下棋
玩家和电脑轮流下棋,每次下棋后都要打印当前棋盘并判断输赢。
while (1) {
PlayerMove(board);
DisplayBoard(board);
if (IsWin(board)) break;
ComputerMove(board);
DisplayBoard(board);
if (IsWin(board)) break;
}
(1)玩家下棋
创建函数x,y存储玩家想要下棋位置的坐标,注意判断所下位置坐标是否合法或是否已有棋子。
void PlayerMove(char board[3][3]) {
int x = 0;
int y = 0;
printf("玩家下棋\n");
while (1) {
printf("请输入要下棋子的坐标:>");
scanf("%d%d", &x, &y);
if ((x >= 1 && x <= 3) && (y >= 1 && y <= 3)) {
if (' ' == board[x - 1][y - 1]) {
board[x - 1][y - 1] = '*';
break;
}
else
{
printf("该位置已占有棋子,请重新输入棋子的坐标!!!\n");
}
}
else
{
printf("非法坐标,请重新输入!!!\n");
}
}
}
注意:玩家输入的坐标数字是从1开始的,而储存棋子坐标的数组下标是从0开始的,因次是board[x - 1][y - 1]而非board[x][y]!
(2)电脑下棋
利用函数rand()生成的随机数模拟电脑下棋
void ComputerMove(char board[3][3]) {
printf("电脑下棋\n");
int x = 0;
int y = 0;
while (1) {
x = rand() % 3;
y = rand() % 3;
if (board[x][y] == ' ') {
board[x][y] = '#';
break;
}
}
}
使用函数rand()时要注意在main.h文件中加入两个头文件
#include<time.h>
#include<stdlib.h>
并在main函数中加入
srand((unsigned int)time(NULL));
(3)判断输赢
每下完一个棋子之后都会出现四种情况:玩家胜(1)、电脑胜(2)、平局(3)、继续对局(0)。当判断输赢函数IsWin(board)返回值为非零数是执行break语句,对局结束;返回值为0是break语句不执行,对局继续。
extern int T;
int IsWin(char board[3][3]) {
int x = 0;
/*判断平局*/
T++; //回合数加一
if (9 == T) {
x = 3;
}
for (int i = 0; i < 3; i++) {
//判断行
if (board[i][0] == board[i][1] && board[i][1] == board[i][2]) {
if (board[i][0] == '*') {
printf("玩家胜\n");
x = 1;
}
if (board[i][0] == '#') {
printf("电脑胜\n");
x = 2;
}
}
else {
//判断列
if (board[0][i] == board[1][i] && board[1][i] == board[2][i]) {
if (board[0][i] == '*') {
printf("玩家胜\n");
x = 1;
}
if (board[0][i] == '#') {
printf("电脑胜\n");
x = 2;
}
}
}
}
//判断对角线
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] || board[2][0] == board[1][1] && board[1][1] == board[0][2]) {
if (board[1][1] == '*') {
printf("玩家胜\n");
x = 1;
}
if (board[1][1] == '#') {
printf("电脑胜\n");
x = 2;
}
}
if (3 == x) printf("平局\n");;
return x;
}
当回合数达到9但没有决出胜负时便可以认定为平局。在test.c创建全局变量T,并使用关键字extern将作用于扩展到game.c中。在函数game()开头将T初始化为0,并在每次调用函数IsWin(board)时T++。
四、运行结果
平局 电脑胜
五、完整代码
text.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"main.h"
int T;//记录回合数
void game() {
T = 0; /*回合数清零*/
char board[3][3];
InitBoard(board);
DisplayBoard(board);
while (1) {
PlayerMove(board);
DisplayBoard(board);
if (IsWin(board)) break;
ComputerMove(board);
DisplayBoard(board);
if (IsWin(board)) break;
}
}
void menu() {
printf("******************************\n");
printf("******** 1.play **********\n");
printf("******** 0.exit **********\n");
printf("******************************\n");
}
int main()
{
srand((unsigned int)time(NULL));
int input = 0;
do {
menu();
printf("请选择>:");
scanf("%d", &input);
switch (input) {
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("输入错误,请重新输入!!!\n");
break;
}
} while (input);
return 0;
}
game.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"main.h"
void DisplayBoard(char board[3][3]) {
printf(" %c | %c | %c \n", board[0][0], board[0][1], board[0][2]);
printf("-----------\n");
printf(" %c | %c | %c \n", board[1][0], board[1][1], board[1][2]);
printf("-----------\n");
printf(" %c | %c | %c \n", board[2][0], board[2][1], board[2][2]);
}
void InitBoard(char board[3][3]) {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
board[i][j] = ' ';
}
}
}
void PlayerMove(char board[3][3]) {
int x = 0;
int y = 0;
printf("玩家下棋\n");
while (1) {
printf("请输入要下棋子的坐标:>");
scanf("%d%d", &x, &y);
if ((x >= 1 && x <= 3) && (y >= 1 && y <= 3)) {
if (' ' == board[x - 1][y - 1]) {
board[x - 1][y - 1] = '*';
break;
}
else
{
printf("该位置已占有棋子,请重新输入棋子的坐标!!!\n");
}
}
else
{
printf("非法坐标,请重新输入!!!\n");
}
}
}
void ComputerMove(char board[3][3]) {
printf("电脑下棋\n");
int x = 0;
int y = 0;
while (1) {
x = rand() % 3;
y = rand() % 3;
if (board[x][y] == ' ') {
board[x][y] = '#';
break;
}
}
}
extern int T;
int IsWin(char board[3][3]) {
int x = 0;
/*判断平局*/
T++; //回合数加一
if (9 == T) {
x = 3;
}
for (int i = 0; i < 3; i++) {
//判断行
if (board[i][0] == board[i][1] && board[i][1] == board[i][2]) {
if (board[i][0] == '*') {
printf("玩家胜\n");
x = 1;
}
if (board[i][0] == '#') {
printf("电脑胜\n");
x = 2;
}
}
else {
//判断列
if (board[0][i] == board[1][i] && board[1][i] == board[2][i]) {
if (board[0][i] == '*') {
printf("玩家胜\n");
x = 1;
}
if (board[0][i] == '#') {
printf("电脑胜\n");
x = 2;
}
}
}
}
//判断对角线
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] || board[2][0] == board[1][1] && board[1][1] == board[0][2]) {
if (board[1][1] == '*') {
printf("玩家胜\n");
x = 1;
}
if (board[1][1] == '#') {
printf("电脑胜\n");
x = 2;
}
}
if (3 == x) printf("平局\n");;
return x;
}
main.h
#pragma once
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
//初始化棋盘
void InitBoard(char board[3][3]);
//打印棋盘
void DisplayBoard(char board[3][3]);
//玩家下棋
void PlayerMove(char board[3][3]);
//电脑下棋
void ComputerMove(char board[3][3]);
//判断输赢
int IsWin(char board[3][3]);