1. 问题与分析
问题:设计个15×15规格的五子棋游戏,自己跟电脑对局,要判断胜负与平局
- 需求分析:
- 主函数:进入游戏界面-->选择是否进入游戏-->给个while循环可以多次玩(包含退出指令)
- 头文件:常量符号定义;头文件包含;函数声明;
- 游戏主要现实:初始化棋盘-->打印棋盘-->玩家下棋/电脑下棋-->判断胜利(需要用指针获取所下棋子的坐标);
2. 代码
2.1 头文件--game.h
#pragma once
//1. 符号定义:
#define ROW 15
#define COL 15
#define tag 5
//2. 头文件包含:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
//3. 函数声明:
//初始化棋盘:
void InitBoard(char board[ROW][COL], int row, int col);
//打印棋盘:
void DisplayBoard(char board[ROW][COL], int row, int col);
//玩家下棋:
void Playerdo(char board[ROW][COL], int row, int col, int*pa, int* pb);
//电脑下棋:
void Computerdo(char board[ROW][COL], int row, int col, int* pa, int* pb);
//判断胜负,返回判断结果:
char Judge(char board[ROW][COL], int row, int col, int x, int y);
//返回 '*'--玩家胜利;
//返回 '#'--电脑胜利;
//返回 'Q'--打成平局;
//返回 'C'--继续游戏
2.2 主函数--main()
#define _CRT_SECURE_NO_WARNINGS 1
#pragma warning(disable:6031)
#include "game.h"
void menu()
{
printf("************************\n");
printf("***** 您已进入游戏 *****\n");
printf("***** 1--play *****\n");
printf("***** 0--exit *****\n");
printf("************************\n");
}
void game()
{
//下棋就得记录棋子,也就得存储数据,棋盘是二维的,所以用二维数组来存储;
char board[ROW][COL];
//初始化棋盘---把数组都变成空格;
InitBoard(board, ROW, COL);
//打印棋盘---把棋盘符号与数组对应起来,然后打印数组;
DisplayBoard(board, ROW, COL);
int flag = rand() % 2; //生成随机数1/0,判断谁先下棋
//printf("flag = %d\n", flag);
char ret = 0; //接收游戏状态
int a = 0;
int b = 0;
//给个初始化的坐标,用于接收落子的坐标;
while (1)
{
if (flag == 1)
{ //玩家下棋
Playerdo(board, ROW, COL, &a, &b);
DisplayBoard(board, ROW, COL);
//判断输赢
ret = Judge(board, ROW, COL, a, b);
if (ret != 'C')
break;
//电脑下棋
Computerdo(board, ROW, COL, & a, &b);
DisplayBoard(board, ROW, COL);
ret = Judge(board, ROW, COL, a, b);
if (ret != 'C')
break;
//判断输赢
}
else
{ //电脑下棋
Computerdo(board, ROW, COL, &a, &b);
DisplayBoard(board, ROW, COL);
//判断输赢
ret = Judge(board, ROW, COL, a, b);
if (ret != 'C')
break;
//玩家下棋
Playerdo(board, ROW, COL, &a, &b);
DisplayBoard(board, ROW, COL);
//判断输赢
ret = Judge(board, ROW, COL, a, b);
if (ret != 'C')
break;
}
}
if (ret == '*')
{
printf("恭喜你赢得胜利!\n");
}
else if (ret == '#')
{
printf("电脑赢得胜利!\n");
}
else
{
printf("打成平局!\n");
}
}
int main()
{
menu(); //游戏界面提示
int input = 0;
srand((unsigned int)time(NULL));
do {
printf("\n请输入游戏指令<1/0>:");
scanf("%d", &input);
switch (input)
{
case 1:
printf("游戏已启动,祝您玩得开心!\n");
game();
break;
case 0:
printf("退出游戏!\n");
break;
default:
printf("输入有误!\n");
break;
}
} while (input);
return 0;
}
2.3 游戏实现--game.c
#define _CRT_SECURE_NO_WARNINGS 1
#pragma warning(disable:6031)
#include "game.h"
void InitBoard(char board[ROW][COL], int row, int col)
{
int i, j;
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, j;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
printf(" %c ", board[i][j]);
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 Playerdo(char board[ROW][COL], int row, int col, int* pa, int* pb)
{
printf("*^-^* 玩家下棋 *^-^* \n");
int i, j;
while (1)
{
printf("请输入棋子坐标>:");
scanf("%d%d", &i, &j);
if (i >= 1 && i <= row && j >= 1&& j <= col)
{
if (board[i-1][j-1] == ' ')
{
board[i-1][j-1] = '*';
*pa = i - 1;
*pb = j - 1;
break;
}
else
{
printf("此处已有棋子,请重新下子!\n");
}
}
else
{
printf("坐标非法,请重新输入!\n");
}
}
}
void Computerdo(char board[ROW][COL], int row, int col, int* pa, int* pb)
{
printf("*^-^* 电脑下棋 *^-^* \n");
while (1)
{
int x = rand() % row;
int y = rand() % col;
//千万别把 x, y 定义和初始化放在外面,否则下棋位置被占,就会停下来;
if (board[x][y] == ' ')
{
board[x][y] = '#';
*pa = x;
*pb = y;
break;
}
}
}
char ISfull(char board[ROW][COL], int row, int col)
{
int i, j;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
if (board[i][j] == ' ')
return 'K';
}
}
return 'M';
}
char Column(char board[ROW][COL], int row, int col, int x, int y) {
int count = 1;
//判断纵向:(先上后下)
for (int i = x - 1; i >= 0; i--) {
if (board[i][y] == board[x][y]) {
count++;
if (count == tag) {
return board[x][y];
}
}
/*else {
return 'C';
}*/
}
for (int i = x + 1; i < row; i++) {
if (board[i][y] == board[x][y]) {
count++;
if (count == tag) {
return board[x][y];
}
}
/*else {
return 'C';
}*/
}
return 'N';
}
char Transverse(char board[ROW][COL], int row, int col, int x, int y) {
int count = 1;
//判断横向,先左后右;
for (int j = y - 1; j >= 0; j--) {
if (board[x][j] == board[x][y]) {
count++;
if (count == tag) {
return board[x][y];
}
}
/*else {
return 'C';
}*/
}
for (int j = y + 1; j < col; j++) {
if (board[x][j] == board[x][y]) {
count++;
if (count == tag) {
return board[x][y];
}
}
/*else {
return 'C';
}*/
}
return 'N';
}
char Diagonal1(char board[ROW][COL], int row, int col, int x, int y) {
int count = 1;
int sum = x + y;
//对角线:左下右上(sum = x+y)
for (int i = x + 1; i < row; i++) {
if (board[i][sum - i] == board[x][y]) {
count++;
if (count == tag) {
return board[x][y];
}
}
/*else {
return 'C';
}*/
}
for (int i = x - 1; i >= 0; i--) {
if (board[i][sum - i] == board[x][y]) {
count++;
if (count == tag) {
return board[x][y];
}
}
/*else {
return 'C';
}*/
}
return 'N';
}
char Diagonal2(char board[ROW][COL], int row, int col, int x, int y) {
int count = 1;
int suml = x + y;
int sumr = suml;
//对角线:左上右下(x=y)
for (int i = x - 1; i >= 0; i--) {
suml -= 2;
if (board[i][suml - i] == board[x][y]) {
count++;
if (count == tag) {
return board[x][y];
}
}
/*else {
return 'C';
}*/
}
for (int i = x + 1; i < row; i++) {
sumr += 2;
if (board[i][sumr - i] == board[x][y]) {
count++;
if (count == tag) {
return board[x][y];
}
}
/*else {
return 'C';
}*/
}
return 'N';
}
char Judge(char board[ROW][COL], int row, int col, int x, int y) {
char tmp = 0;
int tip = 0;
switch (tip) {
case 0:{
tmp = Column(board, row, col, x, y);
if (tmp == '*') {
return '*';
}
else if (tmp == '#') {
return '#';
}
else if (tmp == 'C') {
return 'C';
}
else if (tmp == 'N') {
tip++;
}
else {
break;
}
}
case 1:{
tmp = Transverse(board, row, col, x, y);
if (tmp == '*') {
return '*';
}
else if (tmp == '#') {
return '#';
}
else if (tmp == 'C') {
return 'C';
}
else if (tmp == 'N') {
tip++;
}
else {
break;
}
}
case 2:{
tmp = Diagonal1(board, row, col, x, y);
if (tmp == '*') {
return '*';
}
else if (tmp == '#') {
return '#';
}
else if (tmp == 'C') {
return 'C';
}
else if (tmp == 'N') {
tip++;
}
else {
break;
}
}
case 3:{
tmp = Diagonal2(board, row, col, x, y);
if (tmp == '*') {
return '*';
}
else if (tmp == '#') {
return '#';
}
else if (tmp == 'C') {
return 'C';
}
else if (tmp == 'N') {
tip++;
}
else {
break;
}
}
default:{
tmp = ISfull(board, row, col);
if (tmp == 'M') {
return 'Q';
}
else {
break;
}
}
}
return 'C';
}
3. 总结与展望
- 在学C课程时,老师做了个简单的三子棋,有点简单,而且在代码没有延展性(就是说,不能拓展成五子棋,而且判断条件也很死板),其实老师只是想抛砖引玉,然我们思考游戏实现的每一步,而且要让代码具有延展性(比如从三子棋到五子棋,不需要改代码主体,只需要在头文件把常量符号改一下就好)。基于此,熬熬夜,终于把游戏雏形搞出来了。你不知道,当按下Ctrl+F5的时候,没有报错和警告,游戏跑下来也没有bug的 时候,激动得饭都不用吃了,我太开心了。(现在有多开心,过程就有多艰苦 )
- 拓展:框架还是很粗糙,没有行列号提示,没有黑白子,棋盘也是黑框,还不能触屏……总之,还有很多需要实现和完善的,比如给电脑下棋整个算法,让它聪明一些。