对于三子棋,我们再熟悉不过了,它的规则我们大家都知道,首先向读者展示一下我的代码运行效果,由于背景是黑色的原因,白棋是图片中黑色的笑脸,对应于ASCII码值为1,黑棋是图片中白色的笑脸对应于ASCII码值为2。
在此我说明一点,我并没有把使电脑聪明的算法写进去,读者有兴趣可以自己添加,只需要用算法改写(电脑走)函数即可。
//电脑走
void RobotMove(char board[ROWS][COLS])
{
srand((unsigned int)time(NULL)); //产生随机数
if ((BoardFull(board)) == 0)
{
while (1)
{
row = rand() % ROWS;
col = rand() % COLS;
if (board[row][col] == ' ')
{
board[row][col] = BLACK;
break;
}
}
}
}
要三子棋改为五子棋,只需要将头文件define定义的Num的值修改为5即可。同样的,要改变棋盘的大小只需要修改ROW(行数)和COL(列数)即可。同时还可以改变玩家棋子的颜色(黑或白),交换define定义的 BLACK和WHITE的值即可。头文件代码如下:
# ifndef __GAME_H__
# define __GAME_H__
# pragma warning(disable: 4996)
# include <stdio.h>
# include <time.h>
# include <math.h>
# include <stdlib.h>
# define ROWS 8
# define COLS 10
# define NUM 5
# define BLACK 2
# define WHITE 1
//初始化棋盘
void InitBoard(char board[ROWS][COLS]);
//打印棋盘
void PrintBoard(char board[ROWS][COLS]);
//玩家走
void PlayerMove(char board[ROWS][COLS]);
//电脑走
void RobotMove(char board[ROWS][COLS]);
//检查输赢
char Check(char board[ROWS][COLS]);
# endif //__GAME_H__
下面是我写的源码,读者可以通过代码注释理解代码,如果有不对的地方欢迎指点:
game.c
#define _CRT_SECURE_NO_WAENINGS 1
# include "game.h"
int row = 0;
int col = 0;
void game()
{
char board[ROWS][COLS] = { 0 };
char ret = ' ';
int first_player = 0;
InitBoard(board);
while (1)
{
printf("请选择(0. 电脑先下 1.你先下):\t");
scanf("%d", &first_player);
printf("\n");
switch (first_player)
{
case 0:
{
for (int i = 0; i < NUM - 2; ++i) //对于n子棋,它的前n-1次不存在输赢,因此不需要调用Check()函数;
//比如:对于五子棋,前四次是不需要检查输赢
{
RobotMove(board);
PrintBoard(board);
PlayerMove(board);
}
RobotMove(board);
PrintBoard(board);
}
break;
case 1:
{
for (int i = 0; i < NUM - 1; ++i)
{
PrintBoard(board);
PlayerMove(board);
RobotMove(board);
}
PrintBoard(board);
}
break;
default:
printf("选择错误,请重新选择:\n\n\n");
break;
}
do
{
PlayerMove(board);
if ((ret = Check(board)) != ' ')
{
PrintBoard(board);
break;
}
RobotMove(board);
if ((ret = Check(board)) != ' ')
{
PrintBoard(board);
break;
}
PrintBoard(board);
} while (ret == ' ');
if (ret == 2)
{
printf("黑棋胜!\n");
break;
}
if (ret == 1)
{
printf("白棋胜!\n");
break;
}
if (ret == 'P')
{
printf("不容易,平局!\n");
break;
}
}
}
//初始化棋盘
void InitBoard(char board[ROWS][COLS])
{
int i = 0;
int j = 0;
for (i = 0; i < ROWS; i++)
{
for (j = 0; j < COLS; j++)
{
board[i][j] = ' ';
}
}
}
//打印棋盘
void PrintBoard(char board[ROWS][COLS])
{
int i = 0;
int j = 0;
for (i = 0; i < COLS; ++i)
{
printf(" ___");
}
printf("\n");
for (i = 0; i < ROWS; ++i)
{
for (j = 0; j < COLS; ++j)
{
printf("| ");
printf("%c", board[i][j]);
printf(" ");
}
printf("|\n");
for (j = 0; j < COLS; ++j)
{
printf("|___");
}
printf("|\n");
}
printf("\n");
}
//玩家走
void PlayerMove(char board[ROWS][COLS])
{
printf("请输入你想下的坐标: ");
scanf("%d %d", &row, &col);
row--;
col--;
if (board[row][col] == ' ')
{
board[row][col] = WHITE;
}
else
{
printf("坐标有误,请重新输入\n");
PlayerMove(board);
}
}
//电脑走
void RobotMove(char board[ROWS][COLS])
{
printf("电脑下!!!!!!!!!!!!!!\n");
srand((unsigned int)time(NULL)); //产生随机数
if ((BoardFull(board)) == 0)
{
while (1)
{
row = rand() % ROWS;
col = rand() % COLS;
if (board[row][col] == ' ')
{
board[row][col] = BLACK;
break;
}
}
}
}
//判断输赢
char Check(char board[ROWS][COLS])
{
int i = 0;
if (BoardFull(board) == 1)
{
return 'P';
PrintBoard(board);
}
else
{
int n = 1;
//判断本次落棋的地方和 上方及下方是否存在NUM个连续相同的棋子
//先往上方依次扫描NUM-1个位置的过程中如果碰到相同棋子,则给标志加一,
//如果碰到边界、空位符或者不同的棋子则反向扫描,下面扫描其它方向时同理
for (i = 1; i < NUM; ++i)
{
if ((row - i) < 0 || board[row - i][col] != board[row][col])
{
break;
}
else
{
n++;
}
}
if (n >= NUM)
{
return board[row][col];
}
//此时,开始从起始位置向下扫描
for (i = 1; i < NUM; ++i)
{
if ((row + i) >= ROWS || board[row + i][col] != board[row][col])
{
break;
}
else
{
n++;
}
}
if (n >= NUM)
{
return board[row][col];
}
n = 1;
//判断本次落棋的地方和 右上方及左下方是否存在NUM个连续相同的棋子
for (i = 1; i < NUM; ++i)
{
if ((row - i) < 0 || (col + i) >= COLS || board[row - i][col + i] != board[row][col])
{
break;
}
else
{
n++;
}
}
if (n >= NUM)
{
return board[row][col];
}
//此时,开始从起始位置左下方扫描
for (i = 1; i < NUM; ++i)
{
if ((row + i) >= ROWS || (col - i) < 0 || board[row + i][col - i] != board[row][col])
{
break;
}
else
{
n++;
}
}
if (n >= NUM)
{
return board[row][col];
}
n = 1;
//判断本次落棋的地方和左右方是否存在NUM个连续相同的棋子
for (i = 1; i < NUM; ++i)
{
if ((col - i) < 0 || board[row][col - i] != board[row][col])
{
break;
}
else
{
n++;
}
}
if (n >= NUM)
{
return board[row][col];
}
//此时,开始从起始位置向右扫描
for (i = 1; i < NUM; ++i)
{
if ((col + i) >= COLS || board[row][col + i] != board[row][col])
{
break;
}
else
{
n++;
}
}
if (n >= NUM)
{
return board[row][col];
}
n = 1;
//判断本次落棋的地方和 左上方及右下方是否存在NUM个连续相同的棋子
for (i = 1; i < NUM; ++i)
{
if ((row - i) < 0 || (col - i) < 0 || board[row - i][col - i] != board[row][col])
{
break;
}
else
{
n++;
}
}
if (n >= NUM)
{
return board[row][col];
}
//此时,开始从起始位置右下方扫描
for (i = 1; i < NUM; ++i)
{
if ((row + i) >= ROWS || (col + i) >= COLS || board[row + i][col + i] != board[row][col])
{
break;
}
else
{
n++;
}
}
if (n >= NUM)
{
return board[row][col];
}
return ' ';
}
}
//判断棋盘是否下满
//这里注意的是这个函数内部封装即可,不需要向往展示,这也是代码安全性的一种考虑
static int BoardFull(char board[ROWS][COLS])
{
int i = 0;
int j = 0;
for (i = 0; i<ROWS; i++)
{
for (j = 0; j<COLS; j++)
{
if (board[i][j] == ' ') //棋盘未满时返回0,否则返回1
return 0;
}
}
return 1;
}
test.c
#define _CRT_SECURE_NO_WAENINGS 1
#pragma warning(disable: 4996)
# include "game.h"
# include <windows.h>
void game();
void menu()
{
printf("***********************************\n\n");
printf("1.开始游戏\t");
printf("0.退出游戏\n\n");
printf("***********************************\n");
}
int main()
{
int choose = 1;
while (choose)
{
menu();
printf("请选择(0或1):\t");
scanf("%d", &choose);
printf("\n");
switch (choose)
{
case 0:
printf("下次再见~\n");
break;
case 1:
game();
break;
default:
printf("选择错误,请重新选择:\n\n\n");
break;
}
}
system("pause");
return 0;
}
如果读者有什么疑问,欢迎留言。