// 主程序 test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include"game.h"
#include<stdlib.h>
#include<time.h>
void game()
{
char ret = '0';
char board[ROW][COL] = { '0' }; //初始化棋盘
InitBoard(board, ROW, COL); //清空棋盘
DisplayBoard(board, ROW, COL); //显示棋盘
while (1)
{
PlayerMove(board, ROW, COL); //玩家下棋
DisplayBoard(board, ROW, COL); //显示棋盘
//判断玩家是否赢?
ret = IsWinner(board, ROW, COL);
if (ret !='C')
break;
ComputerMove(board, ROW, COL); //电脑下棋
DisplayBoard(board, ROW, COL); //显示棋盘
//判断是否电脑赢?
ret = IsWinner(board, ROW, COL);
if (ret != 'C')
break;
}
if (ret == '*')
{
printf("玩家赢了\n");
}
else if (ret == '#')
{
printf("电脑赢了\n");
}
else
{
printf("平局\n");
}
DisplayBoard(board, ROW, COL);
}
void menu()
{ //显示菜单
printf("********************\n");
printf("***1.play 0.exit***\n");
printf("********************\n");
}
void test()
{ //控制逻辑
srand((unsigned int)time(NULL)); //产生随机数,以便电脑下棋
int input = 0;
do {
menu();
printf("请确认:>\n");
scanf("%d", &input);
switch (input)
{
case 0:
printf("退出游戏\n");
break;
case 1:
game();
break;
default:
printf("输入错误,请重试");
break;
}
} while (input);
}
int main()
{
test();
return 0;
}
//引用的头文件game.h
#pragma once
#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);
char IsWinner(char board[ROW][COL], int row, int col);
void ComputerMove(char board[ROW][COL], int row, int col);
int IsFull(char board[ROW][COL], int row, int col);
//游戏主文件game.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
#include<stdio.h>
#include<stdlib.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;
int j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{ //打印棋盘的内容
printf(" %c ", board[i][j]); // 打印" %c |",如果是最后一个,则打印" %c "
if (j < col - 1)
printf("|");
}
printf("\n"); // 每行结束之后换行
if (i < row - 1)
{ // 打印棋盘的分割线
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;
while (1)
{
printf("请输入落子的坐标:>\n");
scanf("%d %d", &x, &y);
if (x > 0 && x <= ROW && y>0 && y <= COL)
{
if (board[x - 1][y - 1] = ' ') //转换坐标,因为用户是从1开始,计算机从0开始
{
board[x - 1][y - 1] = '*';
break;
}
else
{
printf("请重新落子\n");
}
}
else
{
printf("落子错误,请重新落子\n");
}
}
}
void ComputerMove(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("电脑下棋:>\n");
while (1)
{
x = rand() % ROW; // 产生随机数
y = rand() % COL;
if (x >= 0 && x < ROW && y >= 0 && y < 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
}
}
break;
}
return 1; // 满了,返回1
}
char IsWinner(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][0]!=' ')
{
return board[i][0];
}
}
//三个连着一列
for (i = 0;i < col;i++)
{
if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[1][i] != ' ')
{
return board[0][1];
}
}
//对角线
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != ' ')
return board[0][0];
// 副对角线
if (board[2][0] == board[1][1] && board[1][1] == board[0][2] && board[2][0] != ' ')
return board[2][0];
if (IsFull(board,ROW,COL))
{
return 'P';
}
return 'C';
}
一、主函数逻辑
二、函数说明
1、
void InitBoard(char board[ROW][COL], int row, int col);
函数功能:初始化row行col列的board[][]二维数组(这里用来模拟棋盘)
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] = ' '; // 遍历棋盘,将所有元素置为空白
}
}
}
遍历所有元素,将元素赋值为空格,表示完成初始化。
2、
void DisplayBoard(char board[ROW][COL], int row, int col);
函数功能:展示row行col列的board[][]二维数组。
void DisplayBoard(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++)
{ //打印棋盘的内容
printf(" %c ", board[i][j]); // 打印" %c |",如果是最后一个,则打印" %c "
if (j < col - 1)
printf("|");
}
printf("\n"); // 每行结束之后换行
if (i < row - 1)
{ // 打印棋盘的分割线
for (j = 0; j < col; j++)
{
printf("---");
if (j < col - 1)
printf("|");
}
printf("\n"); //换行
}
}
}
先遍历每一行每一个元素,将其打印,并打印 | 。如果是最后一个元素,那么只需打印元素内容即可,因为我们不需要打印棋盘边缘
遍历完每一行,我们打印行分界线;如果是最后一行,那么就不需要打印,因为我们这里不打印棋盘边缘。
效果:
3、
void PlayerMove(char board[ROW][COL], int row, int col)
功能:由玩家在row行col列的棋盘中落子
void PlayerMove(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
while (1)
{
printf("请输入落子的坐标:>\n");
scanf("%d %d", &x, &y);
if (x > 0 && x <= ROW && y>0 && y <= COL)
{
if (board[x - 1][y - 1] = ' ') //转换坐标,因为用户是从1开始,计算机从0开始
{
board[x - 1][y - 1] = '*';
break;
}
else
{
printf("请重新落子\n");
}
}
else
{
printf("落子错误,请重新落子\n");
}
}
}
由玩家输入落子坐标,当输入的落子坐标为安全范围内,则落子*,跳出循环;如果输入的数据一直为不安全的坐标,则需要重新输入。
这里优化了用户的体验,因为人是从1开始,而计算机是从0开始,因此所有的坐标在输入之后都应减一。
4、
void ComputerMove(char board[ROW][COL], int row, int col)
函数功能:由电脑随机在row行col列的棋盘中落子
void ComputerMove(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("电脑下棋:>\n");
while (1)
{
x = rand() % ROW; // 产生随机数
y = rand() % COL;
if (x >= 0 && x < ROW && y >= 0 && y < COL)
{
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
}
用rand()产生随机数,如果产生的坐标是安全范围内,则落子为#
5、
int IsFull(char board[ROW][COL], int row, int col)
函数功能:判断row行col列的棋盘中是否下满,以便于游戏结束
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
}
}
break;
}
return 1; // 满了,返回1
}
遍历所有元素,如果发现由空格,则说明没满,返回0;如果遍历完都没发现空格,则返回1.
6、
char IsWinner(char board[ROW][COL], int row, int col)
函数功能:用于判断谁赢了
char IsWinner(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][0]!=' ')
{
return board[i][0];
}
}
//三个连着一列
for (i = 0;i < col;i++)
{
if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[1][i] != ' ')
{
return board[0][1];
}
}
//对角线
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != ' ')
return board[0][0];
// 副对角线
if (board[2][0] == board[1][1] && board[1][1] == board[0][2] && board[2][0] != ' ')
return board[2][0];
if (IsFull(board,ROW,COL))
{
return 'P';
}
return 'C';
}
每次下棋都要进行输赢判定,三子棋输赢判定情况如下:
判定逻辑如下:如果符合上述条件,则返回符合上述条件的棋子,如玩家赢,则返回*,电脑赢,则返回#。如果都不行,并且棋盘已经满了,则返回P表示平局;如果还是不行,则返回C,代表继续。
三、运行结果
1、玩家赢
2、电脑赢
3、平局