C语言三子棋小游戏
提示:本文使用的编码环境为VS2013
前言
三子棋为3 X 3的九格棋盘,由人机对弈,其中任一方先三子联成一条直线为则视为胜出,如九格下满双方都未有三子成线则为平局。对弈过程由玩家输入坐标操作完成,根据输入坐标的位置来确定棋子的位置。
一、实现方式
1.主函数
代码如下:
#include "game.h"
// main.c
int main()
{
while (1)
{
int choice = 0;
int i = Meun(choice);
switch (i)
{
case 1:
Game();
break;
case 2:
printf("再见!\n");
break;
default:
printf("输入有误!\n");
break;
}
}
system("pause");
return 0;
}
2.主要函数分析
2.1 棋盘界面
代码如下:
static void ChessBoard(char board[][COL], int row, int col)
{ /*棋盘界面*/
printf(" 1 2 3 \n");
printf(" +---+---+---+\n");
for (int row = 0; row < ROW; row++)
{
printf("%d", row + 1);
printf(" | %c | %c | %c |\n", board[row][0],
board[row][1], board[row][2]);//memset(board,' ',sizeof(board)); %c 打印空格。
printf(" +---+---+---+\n");
}
}
注意事项
静态函数使用
static void ChessBoard(char board[][COL], int row, int col)
函数也有存储类别, 可以是外部函数(默认) 或 静态函数。 外部函数可以被其他文件的函数访问, 但是静态函数只能用于其定义所在的文件。 假设一个文件中包含了以下函数原型:
double gamma(double); /* 该函数默认为外部函数 */
static double beta(int, int);
extern double delta(double, int);
在同一个程序中, 其他文件中的函数可以调用gamma()和delta(), 但是不能调用beta(), 因为以static存储类别说明符创建的函数属于特定模块私有。 这样做避免了名称冲突的问题, 由于beta()受限于它所在的文件, 所以在其他文件中可以使用与之同名的函数。
通常的做法是: 用extern 关键字声明定义在其他文件中的函数。 这样做是为了表明当前文件中使用的函数被定义在别处。 除非使用static关键字,否则一般函数声明都默认为extern。
二维数组的函数调用
char board[][COL] 形参实例化时,二维数组降维成数组指针,所以初始化二维数组的第二个[COL]必须有值。第1个形参告诉函数该数组的地址和数据类型, 第2个形参告诉函数该数组中元素的个数。
2.2 电脑落子
static void ComputerMove(char board[][COL], int row, int col)
{ /*电脑落子*/
while (1)
{
int x = rand() % row;//如要产生[m,n]范围内的随机数num,可用:int num = rand() % (n - m + 1) + m;
int y = rand() % col;//产生一个[0,clo-1]数
if (board[x][y] == ' ')
{
board[x][y] = C_COLOR;
break;
}
}
}
注意事项
int x = rand() % row;
rand()是“伪随机数生成器”, 意思是可预测生成数字的实际序列。 但是, 数字在其取值范围内均匀分布。
int num = rand() % (n - m + 1) + m; 产生[m,n]范围内的随机数num。int x = rand() % row;则产生[0,2]的随机数。
2.3 游戏判断
void Game()
{
srand((unsigned long)time(NULL));//种一个随机数种子
char board[ROW][COL];
memset(board,' ',sizeof(board));//将数组board用空格替换;sizeof(board)代表整个数组大小
char result = 'x';
do{
ChessBoard(board, ROW, COL);
PlayerMove(board, ROW, COL);
result = Judge(board, ROW, COL);
if (result != NEXT)
{
break;
}
ComputerMove(board, ROW, COL);
result = Judge(board, ROW, COL);
if (result != NEXT)
{
break;
}
} while (1);
if (P_COLOR == result)
{
printf("你赢了!\n");
}
else if (C_COLOR == result)
{
printf("你输了!\n");
}
else
{
printf("和棋!\n");
}
ChessBoard(board, ROW, COL);
}
注意事项
srand((unsigned long)time(NULL));
种一个随机数种子。
memset(board,' ',sizeof(board));
memset() 函数可以说是初始化内存的“万能函数”,通常为新申请的内存进行初始化工作。它是直接操作内存空间,mem即“内存”(memory)的意思。
void *memset(void *s, int c, unsigned long n);
该函数的功能是:将指针变量 s 所指向的前 n 字节的内存单元用一个“整数” c 替换,注意 c 是 int 型。s 是 void* 型的指针变量,所以它可以为任何类型的数据进行初始化。
二、全部代码
1.game.c文件
#include "game.h"
int Meun(int choice)
{
printf("*************************************\n");
printf("**** 1.Play *** 2.Exit ****\n");
printf("*************************************\n");
printf("请选择:");
scanf("%d", &choice);
return choice;
}
//char board[][COL] 形参实例化时,二维数组降维成数组指针,
//所以初始化二维数组的第二个[COL]必须有值。
//静态函数只能本game.c文件中调用。
static void ChessBoard(char board[][COL], int row, int col)
{ /*棋盘界面*/
printf(" 1 2 3 \n");
printf(" +---+---+---+\n");
for (int row = 0; row < ROW; row++)
{
printf("%d", row + 1);
printf(" | %c | %c | %c |\n", board[row][0],
board[row][1], board[row][2]);//memset(board,' ',sizeof(board)); %c 打印空格。
printf(" +---+---+---+\n");
}
}
static void PlayerMove(char board[][COL], int row, int col)
{ /*棋手落子*/
int x = 0;
int y = 0;
int quit = 0;
while (1){
printf("请输入你的位置# ");
scanf("%d %d", &x, &y);
if (x < 1 || x > 3 || y < 1 || y > 3)
{
printf("你输入的坐标有误!\n");
continue;
}
else if (board[x - 1][y - 1] != ' ')
{
printf("该位置已经被占用!\n");
continue;
}
else
{
board[x - 1][y -1] = P_COLOR;
break;
}
}
}
static char Judge(char board[][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][0] != ' ')//反斜杠接续下一行
{
return board[i][0];
}
}
for (int j = 0; j < col; j++)//"列"三子连珠
{
if (board[0][j] == board[1][j] && \
board[1][j] == board[2][j] && \
board[0][j] != ' ')
{
return board[0][j];
}
}
if (board[0][0] == board[1][1] && \
board[1][1] == board[2][2] && \
board[0][0] != ' ')//"\"三子连珠
{
return board[1][1];
}
if (board[0][2] == board[1][1] && \
board[1][1] == board[2][0] && \
board[1][1] != ' ')//"/"三子连珠
{
return board[1][1];
}
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
if (board[i][j] == ' ')
{
return NEXT;//还有空位,正在落子。
}
}
}
return DRAW;//没有空位,和棋平局。
}
static void ComputerMove(char board[][COL], int row, int col)
{ /*电脑落子*/
while (1)
{
int x = rand() % row;//如要产生[m,n]范围内的随机数num,可用:int num = rand() % (n - m + 1) + m;
int y = rand() % col;//产生一个[0,clo-1]数
if (board[x][y] == ' ')
{
board[x][y] = C_COLOR;
break;
}
}
}
void Game()
{
srand((unsigned long)time(NULL));//种一个随机数种子
char board[ROW][COL];
memset(board,' ',sizeof(board));//将数组board用空格替换;sizeof(board)代表整个数组大小
char result = 'x';
do{
ChessBoard(board, ROW, COL);
PlayerMove(board, ROW, COL);
result = Judge(board, ROW, COL);
if (result != NEXT)
{
break;
}
ComputerMove(board, ROW, COL);
result = Judge(board, ROW, COL);
if (result != NEXT)
{
break;
}
} while (1);
if (P_COLOR == result)
{
printf("你赢了!\n");
}
else if (C_COLOR == result)
{
printf("你输了!\n");
}
else
{
printf("和棋!\n");
}
ChessBoard(board, ROW, COL);
}
2.game.c文件
#ifndef __GAME_H__
#define __GAME_H__
#include <stdio.h>
#include <windows.h>
#include <time.h>
#pragma warning(disable:4996)
#define ROW 3
#define COL 3
#define P_COLOR 'X'
#define C_COLOR 'O'
#define NEXT 'N'
#define DRAW 'D'
int Meun(int choice);
void Game();
#endif
三、运行结果