天生棋局
1.案例描述
要求创建一个棋盘,在棋盘生成的同时初始化棋盘,根据初始化后棋盘中棋子的位置来判断此时的棋局是否是一局好棋。具体要求如下:
(1)棋盘的大小根据用户的指令确定;
(2)棋盘中棋子的数量也由用户设定;
(3)棋子的位置由随机数函数随机确定,若生成的棋盘中有两颗棋子落在同一行或同一列,则判定为“好棋”,否则判定为“不是好棋”。
2.案例设计
(根据案例分析中的棋局生成步骤设计程序,可将程序代码模块化为4个功能函数和1个主函数。
(1)创建棋盘
案例分析中提出,棋盘信息存放在动态生成的空间中。首先创建一个函数,并设计一个(2n+1)(2n+1)的二维数组,用于存放棋盘数据,使用void calloc (size_t num, size_t size)函数动态分布棋盘空间,初始化棋盘数据为0,并返回一个指向该棋盘地址的二级指针
(2)生成棋子数据
创建两个奇数随机数作为作为棋子的坐标,并判断该位置是否已经有棋子,有则重新生成,没有则使该位置为1,代表棋子。
(3)输出棋盘
将棋盘数据中的偶数位作为棋盘边框,奇数位作为存放棋子的位置。奇数位若为1,则放棋子,为零则放空格
(4)判断是否为好棋
将棋盘的每行或者每列奇数位之和计算出来,若同一行或者同一列之和大于1则使好棋。
(5)释放指针空间
在创建棋盘时申请的空间,在使用完毕后手动释放。使用void free (void* ptr)函数。
3.代码实现
方案一:
//天生棋局
#include<string.h>
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
int main(){
srand((unsigned)time(NULL));
int row,column,num,**p;
//加载函数
int **creat_checkerboard(int row,int column);
void creat_piece(int **p,int num,int row,int column);
void print_checkerboard(int **p,int row,int column);
void is_good(int **p,int row,int column);
void free_board(int **p, int row);
printf("请输入行和列的数量:");
scanf("%d%d",&row,&column);
printf("请输入棋子的数量:");
scanf("%d",&num);
row=2*row+1;
column=2*column+1;
p=creat_checkerboard(row,column);//获取棋盘指针
creat_piece(p,num,row,column);//创建棋子数据
print_checkerboard(p,row,column);//输出棋盘
is_good(p,row,column);//判断是否为好棋
printf("row = %d column = %d\n",row,column);
printf("num = %d\n",num);
free_board(p,row); //释放内存空间
return 0;
}
int ** creat_checkerboard(int row,int column){//创建棋盘,并初始化为零
int **p = (int**)calloc(sizeof(int*), row);
/*
头文件:#include <stdlib.h>
原型:
void* calloc (size_t num, size_t size);
作用:用于分配num个size大小的连续内存空间,且初始化每个字节都为零
返回值:为未指定类型,需要强转
*/
int i = 0;
for (i = 0; i < row; i++)
{
p[i] =(int*)calloc(sizeof(int), column);
}
for(int x=0;x<row;x++)//将棋盘数据全部赋值为零
for(int y=0;y<column;y++)
p[x][y]=0;
/*
for(int x=0;x<row;x++)//输出棋盘数据确认
{for(int y=0;y<column;y++)
printf(" %d",p[x][y]);
printf("\n");
}
printf("\n");*/
return p;
}
void creat_piece(int **p,int num,int row,int column){//生成棋子数据
int x,y,count=0;
while(count!=num){
x = rand()%row;
y = rand()%column;
if(x%2==1&&y%2==1&&p[x][y]==0){//把棋子放到棋盘的奇数位
p[x][y]=1;
count++;
}
}
/*
for(int x=0;x<row;x++)//查看赋值是否正常
{for(int y=0;y<column;y++)
printf(" %d",p[x][y]);
printf("\n");
}*/
}
void print_checkerboard(int **p,int row,int column){//输出棋盘
for(int x=0;x<row;x++){
if(x%2==0)
for(int y=0;y<column;y++)//行偶数位为边框
printf("—");
else{
for(int y=0;y<column;y++)
if(p[x][y]==1)//值为1的位置放棋子
printf("o ");
else
if(y%2==0)
printf("| ");//列的偶数位为边框
else
printf(" ");//没有棋子的奇数位为空格
}
printf("\n");
}
}
void is_good(int **p,int row,int column){
int flag=0,row_sum,column_sum;
for(int x = 1;x<row;x += 2){//确保x为奇数位
row_sum=0;//遍历一行后归零
for(int y = 1;y<column-2;y += 2){//确保y为奇数位
row_sum +=p[x][y];//行之和大于1,是好棋
if(row_sum>1){
flag=1;
break;
}
}
}
for(int y= 1;y<column;y+= 2){//确保y为奇数位
column_sum=0;//遍历一列后归零
for(int x = 1;x<row-2;x += 2){//确保x为奇数位
column_sum +=p[x][y];
if(column_sum>1){//列之和大于1,是好棋
flag=1;
break;
}
}
}
printf("flag=%d\n",flag);
if(flag)
printf("是好棋\n") ;
else
printf("不是好棋\n") ;
}
//释放内存空间
void free_board(int **p, int row){
/*
头文件:#include <stdlib.h>
原型为:
void free (void* ptr);
作用:释放某一级的指针指向的内存空间
返回值:空
*/
for (int i = 0; i < row; ++i)
{
free(p[i]); //释放一级指针指向的空间
}
free(p); //释放二级指针指向的空间
}
方案二:(相邻位子上有棋子才算好棋)
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include<stdlib.h>
#include<string.h>
#include<time.h>
int ** createBoard(int n)//用返回类型是二维指针的类型,创建一个棋盘,长度由主函数传递来
{
int **p = (int**)calloc(sizeof(int*), n);
int i = 0;
for (i = 0; i < n; i++)
{
p[i] = calloc(sizeof(int), n);
}
return p;
}
//初始化棋盘
int initBoard(int **p, int n, int tmp)//用随机数下棋
{
int i, j;
int t = tmp;
while (t > 0)
{
i = rand() % n;
j = rand() % n;
if (p[i][j] == 1)//坐标内已有棋子则再次循环
continue;
else
{
p[i][j] = 1;
t--;
}
}
return 0;
}
//输出棋盘
int printfBoard(int **p, int n)
{
int i, j;
for (i = 0; i < n; i++)//用行列计数变量检测同一行或列是否多于2个棋子
{
for (j = 0; j < n; j++)
{
if (p[i][j] == 1) //输出棋子
{
printf("●");
}
else //搭建棋盘
{
if (i == 0 && j == 0)
printf("┏");
else if (i == 0 && j == n - 1)
printf("┓");
else if (i == n - 1 && j == 0)
printf("┗");
else if (i == n - 1 && j == n - 1)
printf("┛");
else if (j == 0)
printf("┠");
else if (i == n - 1)
printf("┷");
else if (j == n - 1)
printf("┨");
else if (i == 0)
printf("┯");
else
printf("┼");
}
}
putchar('\n');
}
for (i = 0; i < n; i++)//用行列两个循环判断是否行列上有两个相邻的棋子
{
for (j = 0; j<n; j++)
{
if (p[i][j] == 1)
{
if (j>0 && p[i][j - 1] == 1) //判断同一行有无相邻棋子
{
printf("好棋!\n");
return 0;
}
if (i > 0 && p[i - 1][j] == 1) //判断同一列有无相邻棋子
{
printf("好棋\n");
return 0;
}
}
}
}
printf("不是好棋\n");
return 0;
}
//销毁棋盘
void freeBoard(int **p, int n)
{
int i;
for (i = 0; i < n; ++i)
{
free(p[i]); //释放一级指针指向的空间
}
free(p); //释放二级指针指向的空间
}
int main()
{
srand((unsigned int)time(NULL));
int n = 0, tmp = 0;
printf("设置棋盘大小:");
scanf("%d", &n); //输入棋盘行(列)值
int **p = createBoard(n); //创建棋盘
printf("设置棋子数量 :");
scanf("%d", &tmp); //输入棋盘上的棋子数量
initBoard(p, n, tmp); //初始化棋盘
printfBoard(p, n); //打印棋盘
freeBoard(p, n); //释放棋盘
return 0;
}
4.运行结果
方案一:
方案二: