三子棋游戏:一方三子连珠则赢,需要有交互界面———菜单,棋盘展示,玩家下棋,电脑下棋,判断输赢——电脑赢,玩家赢,平局,游戏继续。
将功能的实现分别用函数来表示。因此我们将代码分为三个文件——main.c, game.c, game.h。
其中game.c用来存放函数的定义,game.h用于存放函数的定义还有所需头文件声明,宏定义等。
在两个源文件中我们都需要进行自定义头文件的声明:
#include "game.h"
game.h :
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define ROW 3
#define COL 3
//菜单
void menu();
void game();
//初始化棋盘
void InitBoard(char board[ROW][COL],int row, int col);
//打印棋盘
void DisplayBoard(char board[ROW][COL],int row, int col);
//玩家下棋
void PlayerInput(char board[ROW][COL],int row ,int col);
//电脑下棋
void ComputerBoard(char board[ROW][COL], int row, int col);
//判断输赢
char IsWin(char board[ROW][COL], int row, int col);
构思:
程序开始运行时,用户则需进行选择:玩或者退出,选择玩游戏,则会进入游戏,这将由swicth语句实现。接着便是玩家下棋,电脑下棋,这是一个循环的过程,系统应该在玩家和电脑下棋时都分别判断一次输赢。有一方赢或者平局,都退出循环,和否则继续游戏。判断输赢后,下棋应该停止,再次弹出菜单,让用户选择是继续玩还是退出游戏(同时也应该考虑到用户输入错误的情况)。因此,菜单和游戏的接口应该放在一个循环里。这将构成主函数的部分。
而棋盘本身,我们将其定义成一个二维的字符数组。方便输入和遍历输出(即:展示棋盘)。
main.c部分
#include "game.h"
//下三子棋,三子相连则为赢
int main()
{
int c, count = 0;
srand((unsigned int) time (NULL));
while(1)
{
menu();
printf("请选择:");
scanf("%d",&c);
switch(c)
{
case 1:
game();
break;
case 0:
printf("游戏结束\n");
count = 1;
break;
default:
printf("输入错误,请重新输入\n");
}
if(count)
break;
}
return 0;
}
自定义函数部分
交互界面,即:菜单。是用户开始游戏和退出游戏的选择窗口。
void menu()
{
printf("**************************\n");
printf("******* 1.play *******\n");
printf("******* 0.exit *******\n");
printf("**************************\n");
}
每次上一轮游戏结束后,都应该弹出菜单给用户继续选择
因此如果用户选择1,则需弹出一个全新的棋盘,这就包含了对棋盘的初始化,还有对棋盘的展示。我们不妨将其分别设为一个单独的函数,方便放入循环调用。
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("--- ");
}
}
printf("\n");
}
}
之所以分开设为两个函数,是因为每次玩家下棋和电脑下棋后都需要展示棋盘。
玩家下棋:
你需要考虑玩家下棋的符号,即:棋子。(电脑也是如此)
且需考虑所下坐标是否已经被占位
void PlayerInput(char board[ROW][COL],int row ,int col)
{
int x = 0;
int y = 0;
printf("玩家下棋:\n");
while(1)
{
printf("请输入坐标:");
scanf("%d %d",&x,&y);
if(x >= 1 && x <= row && y >= 1 && y <= col)
{
if(board[x-1][y-1] == ' ')
{
board[x-1][y-1] = '*';
break;
}
else
printf("该坐标已被占有,请重新输入\n");
}
else
printf("非法输入,请重新输入\n");
}
}
电脑下棋:
电脑下棋则不需要考虑是否会有违法输入,因为我们在设置的时候就会限制他。
void ComputerBoard(char board[ROW][COL], int row, int col)
{
printf("电脑下棋:\n");
int x;
int y;
while(1)
{
x = rand()%row;
y = rand()%row;
if(board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
注意要使用rand()函数,为了避免伪随机数的出现,我们需要调用srand()
即:在main()中调用:
srand((unsigned int) time (NULL));
这需要包含头文件:
#include <stdlib.h>
#include <time.h>
判断棋盘是否满的函数:
每次一方下棋的结果除了电脑赢,玩家赢,平局外,还有游戏尚未结束
其中判断是否游戏继续和是否平局,取决于棋盘满没满。因此我们将其写成一个函数方便调用:
且将其设为static,将外部连接属性改为内部连接属性,因为它只需在game.c中被调用即可,这也可以保护函数。
static int IsFull(char board[ROW][COL], int row, int col)
{
int i, j, count = 0;
for(i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
if(board[i][j] == ' ')
count = 1;
}
}
return count;//当棋盘未满时返回真值
}
* 玩家赢
# 电脑赢
C 游戏继续
Q 平局
判断输赢函数:
char IsWin(char board[ROW][COL], int row, int col)
{
int i;
for(i = 0; i < row; i++)
{
if(board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][1] != ' ')
//此处一定要注意,三子连珠要字符相等,但是不能等于空格!!!
return board[i][1];
}
for(i = 0; i < col; i++)
{
if(board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[1][i] != ' ')
return board[1][i];
}
if(board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' ')
return board[1][1];
if(board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
return board[1][1];
if(IsFull(board,ROW,COL))
return 'C';
else
return 'Q';
}
将函数设为char的返回类型,可以方便主函数直接用char类型变量接收函数返回值,判断谁赢。而且函数内容也将更简洁。