三子棋
在写代码之前先构思一下整体布局:
1、
先让用户看到界面,构思用二维数组显示棋盘,这里先打印出菜单页面,让用户进行选择“游戏”或者“退出”,写一个函数实现打印菜单页面,这里可以定义一个函数ShowUI()函数打印菜单。
2、
菜单打印完毕之后,如何让用户进行选择,可以在main()函数中写一个判断语句判断用户的选择,例如选择1后开始玩游戏,选择2退出游戏,错误输入后提示用户输入正确的数字,并考虑玩完一局后可以选择继续玩游戏或者退出,这里可以用循环语句实现。
3、
再考虑如何实现游戏函数,定义一个Game()函数实现游戏功能,Game()函数里面首先应该打印棋盘,如何打印打印棋盘,棋盘里刚开始放什么也是需要考虑的问题,首先定义一个3×3的二维数组表示棋盘,其次置空这个棋盘,这里可以用memset()函数实现置空(具体的memset()函数怎么使用可以问一下度娘),或者定义一个Init()函数实现数组的置空,这里我们选择使用memset()函数进行数组的置空。
4、
置空棋盘后接下来要做的是让电脑下棋,定义一个ComputerMove()函数实现电脑走,电脑走完以后再显示棋盘,显示棋盘这里定义一个ShowBoard()函数,然后进行判断,定义一个Judge()函数进行判断谁赢谁输,Judge()函数有四种返回值分别代表,玩家赢,电脑赢,平局,继续下棋。如果Judge()函数判断为继续下棋后,接下来玩家下棋,定义函数PlayerMove()函数实现玩家走,和上面相同,走完后显示棋盘,然后同样进行判断谁赢然后将结果输出。
5、
至此,整个代码里面用到的函数及功能就构思完了,具体代码如下:
先写一个主函数框架:
#include"Three_Chess.h"
int main()
{
int select = 0;
int quit = 0;
while (!quit)
{
ShowUI(); //此处调用ShowUI()函数打印菜单
scanf("%d", &select); //定义变量select让用户进行选择
switch (select)
{
case 1: //选择1玩游戏
Game();
break;
case 2: //选择2退出游戏
quit = 1; //当quit为1时,下次循环判断为0,不进循环
printf("ByeBye!\n");
break;
default:
printf("Please Enter Again!\n");
break;
}
}
system("pause");
return 0;
}
在头文件中将每个函数进行声明:
#pragma once
#ifndef _THREE_CHESS_H_
#define _THREE_CHESS_H_
#include<stdio.h>
#include<windows.h>
#include<string.h>
#include<time.h>
#define ROW 3
#define COL 3
void ShowUI();
void Game();
void ComputerMove(char board[][COL], int row, int col);
void PlayerMove(char board[][COL], int row, int col);
void ShowBoard(char board[][COL], int row, int col);
char Judge(char board[][COL], int row, int col);
#endif
然后分别实现每个函数的功能:
ShowUI()函数打印菜单:
void ShowUI()
{
printf("*******************************\n");
printf("* 1、GAME 2、EXIT *\n");
printf("*******************************\n");
printf("Please Select:\n");
}
ComputerMove()函数实现让电脑下棋:
void ComputerMove(char board[][COL], int row, int col)
{
while (1)
{ //调用rand()函数生成两个随机数作为下标
int x = rand() % row; //这里分别对row和col取模
int y = rand() % col;
if (board[x][y] == ' ') //判断此位置是否为空,如果为空就赋值'O'表示电脑走在此位置
{
board[x][y] = 'O';
break; //退出循环
}
}
}
PlayerMove()函数实现让玩家下棋:
void PlayerMove(char board[][COL], int row, int col)
{
int x, y;
while (1)
{
printf("Please enter position->x y:\n");
scanf("%d %d", &x, &y); //提示用户输入坐标
if (x >= 1 && x <= row && y >= 1 && y <= col)
{ //判断输入的坐标是否满足条件
if (board[x-1][y-1] == ' ') //用户输入的下标是从1开始的,而数组下标是从0开始的,所以这里要对x和y减1
{
board[x-1][y-1] = 'X'; //在此位置放入'X',表示用户下在这里
break;
}
else
{
printf("Your place is taken,Try Again:\n");
}
}
else
{
printf("Enter error,Try Again:\n");
}
}
}
Judge()函数实现判断:
char Judge(char board[][COL], int row, int col)
{
int i = 0;
int j = 0;
for (i = 0; i < row; i++) //判断每一行row是否相等且不能为空
{
if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][2] != ' ')
{
return board[i][0];
}
}
for (i = 0; i < col; i++) //判断每一列col是否相等且不能为空
{
if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[2][i] != ' ')
{
return board[0][i];
}
}
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[2][2] != ' ')
{ //判断左对角线是否都相等且不为空
return board[0][0];
}
if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[2][0] != ' ')
{ //判断右对角线是否都相等且不为空
return board[0][2];
}
//如果上面集中情况即行、列、对角线都没有一样的,下面就要判断是否棋盘放满了
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
if (board[i][j] == ' ')
{
return 'N'; //如果棋盘上有空的,说明没满,返回'N'继续
}
}
}
//如果走到这,说明只有一种可能,那就是平局
return 'E'; //返回'E',表示平局
}
ShowBoard()函数显示棋盘:
void ShowBoard(char board[][COL], int row, int col)
{
system("cls"); //显示棋盘之前每次实现一次清屏
printf(" 1 2 3\n"); //打印第一行的数字列号
printf("---------------\n"); //打印横线
int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{
printf("%d |",i + 1); //打印行号,这里i+1表示从1开始而不是0
for (j = 0; j < col; j++)
{
printf(" %c |",board[i][j]);
}
printf("\n---------------\n");
}
printf("\n");
}
Game()游戏函数:
void Game()
{
char board[ROW][COL]; //定义数组棋盘
memset(board, ' ', sizeof(board)); //实现数组置空
char result = 'N';
srand((unsigned long)time(NULL)); //布置随机数种子,在ComputerMove()函数中用到,头文件#include<time.h>
while (1)
{
ComputerMove(board, ROW, COL);
ShowBoard(board, ROW, COL);
result = Judge(board, ROW, COL);
if (result != 'N') //X玩家赢,O电脑赢,E平局,N继续
{
break;
}
PlayerMove(board, ROW, COL);
ShowBoard(board, ROW, COL);
result = Judge(board, ROW, COL);
if (result != 'N') //X玩家赢,O电脑赢,E平局,N继续
{
break;
}
}
switch (result)
{
case 'X':
printf("Congratulations!You Win!\n");
break;
case 'O':
printf("Damn!You Lose!\n");
break;
case 'E':
printf("Dogfall!\n");
break;
default:
break;
}
}
函数写好之后,将所有函数功能的实现放在Three_Chess.c文件中,并将头文件"Three_Chess.h"包含进来,主函数也一样要包含头文件。
调试运行程序:
选择页面:
玩家赢(Congratulations!You Win!)
电脑赢:(Damn!You Lose!)
平局:(Dogfall!)
选择退出:(Bye,Bye!)
总结:
在这次写的程序中,首先在写一个完整的程序之前要构思好怎样布局,然后再着手去写。
一开始程序中定义了一个二维数组来表示棋盘,里面用到了memset()函数,memset是计算机中C/C++语言初始化函数。作用是将某一块内存中的内容全部设置为指定的值, 这个函数通常为新申请的内存做初始化工作。memset()函数原型是
extern void *memset(void *buffer, int c, int count)
//buffer:为指针或是数组,c:是赋给buffer的值,count:是buffer的长度。
在ShowBoard()函数中加入
system("cls");
实现清屏,让交互界面看起来更友好一点。
在写程序的过程中也出了不少问题,比如由于粗心把for循环里面的判断条件写错导致最后程序运行时好长时间找不出问题出在哪,最后调试了程序找出问题所在并改正,还有就是在这次的程序练习中知道了,数组如何传参,多维数组传参只能省略第一个中括号 [ ] 里的数字,从第二个开始的中括号 [ ] 里的数字不能省略,比如上面的
void ShowBoard(char board[][COL], int row, int col);
并且要传入两个以上的参数,后面的参数要给出数组具体的长度,不然数组会发生降维。
程序中还用到了rand()函数,在使用rand()函数之前要调用srand()函数布置种子,srand函数是随机数发生器的初始化函数。原型:
void srand(unsigned int seed);
srand和rand()配合使用产生伪随机数序列,比如本次程序中写的:
srand((unsigned long)time(NULL));
//布置随机数种子,在ComputerMove()函数中用到,头文件#include<time.h>
以上是通过本次写三子棋程序的部分关键点以及心得。