#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <time.h>
#define SIZE 4
#define SWAP(x,y,t) ((t)=(x),(x)=(y),(y)=(t))
int *total_choice=NULL;
int step=0;
void display(int board[][SIZE]); //展示棋盘的函数
int is_valid(int board[][SIZE],int choice); //判断玩家选择是否有效的函数
void move(int board[][SIZE],int choice); //移动数字的函数
int is_complete(int board[][SIZE]); //判断拼图是否完成的函数
void initial(int board[][SIZE]); //初始化棋盘
void turn_left(int board[][SIZE]); //电脑左移
void turn_right(int board[][SIZE]); //电脑右移
void turn_up(int board[][SIZE]); //电脑上移
void turn_down(int board[][SIZE]); //电脑下移
void main()
{
int board[SIZE][SIZE]={ //The board
{1,2,3,4}, //Initial values are reference numbers
{5,6,7,8}, //used to select a vacant square for
{9,10,11,12}, //a turn
{13,14,15,0}
};
char again=0;
int choice=0;
int i=0;
long now=0;
int step=0;
printf("欢迎你来到简单的拼图游戏\n");
printf("选择相应的数字,该数字会移到空格处\n");
printf("如果不能移动该数字,将显示出来,并让玩家重新选择数字移动\n");
printf("Good luck!Press Enter to start.\n");
scanf("%c",&again);
total_choice=(int*)malloc(15*sizeof(int));
initial(board);
display(board);
getchar();
for(i=0;i<15;i++)
{
move(board,total_choice[15-i-1]);
display(board);
now=clock();
for(;clock()-now<CLOCKS_PER_SEC;);
system("cls");
}
do
{
for(;;)
{
display(board);
printf("请输入你要移动的数字: ");
scanf("%d",&choice);
if(is_valid(board,choice)) //如果移动有效则移动该数字并显示结果
{
move(board,choice);
display(board);
system("cls"); //清屏
}
else //如果移动无效,则显示为无效移动
printf("无效的移动\n");
if(is_complete(board)&&is_valid(board,choice))
{
display(board);
printf("Good job!\n");
printf("Mission completed!\n");
break;
}
}
printf("你想再玩一次吗?(y or n) ");
scanf(" %c",&again);
}while(tolower(again)=='y');
}
void display(int board[][SIZE])
{
int row=0; //Row index
int col=0; //Column index
for(row=0;row<SIZE;row++)
{
printf(" +");
for(col=0;col<SIZE;col++)
printf("----+");
printf("\n");
for(col=0;col<SIZE;col++)
printf(" |%2d%s",board[row][col],board[row][col]?"":"\b "); //展示棋盘上的数字,当数字为0时,显示为空白
printf(" |\n");
}
printf(" +");
for(col=0;col<SIZE;col++)
printf("----+"); //Display the bottom line
printf("\n"); //Display the end of bottom line
}
int is_valid(int board[][SIZE],int choice)
{
int row=0;
int col=0;
int rowdelta=0; //Row increment around a square
int coldelta=0; //Column increment around a square
int flag=0; //跳出循环标记
for(row=0;row<SIZE;row++) //获取玩家选择数字的位置
{
for(col=0;col<SIZE;col++)
{
if(board[row][col]==choice)
{
flag=1;
break;
}
}
if(flag==1)
break;
}
for(rowdelta=-1;rowdelta<=1;rowdelta++)
{
for(coldelta=-1;coldelta<=1;coldelta++)
{//不能检查越界位置,choice所在位置,以及与choice成对角线的位置
if(row+rowdelta>=SIZE||row+rowdelta<0||
col+coldelta>=SIZE||col+coldelta<0||
rowdelta==coldelta||board[row+rowdelta][col+coldelta])
continue;
if(board[row+rowdelta][col+coldelta]==0) //空白就在choice旁边,则为有效choice
return 1;
}
}
return 0;
}
void move(int board[][SIZE],int choice)
{
int choice_row=0; //存储choice的row
int choice_col=0; //存储choice的col
int zero_row=0; //存储0的row
int zero_col=0; //存储0的col
int temp=0;
int flag=0; //循环跳出标记
if(!is_valid(board,choice))
return;
for(choice_row=0;choice_row<SIZE;choice_row++) //获取choice的row,col
{
for(choice_col=0;choice_col<SIZE;choice_col++)
{
if(board[choice_row][choice_col]==choice)
{
flag=1;
break;
}
}
if(flag==1)
{
flag=0;
break;
}
}
for(zero_row=0;zero_row<SIZE;zero_row++) //获取zero的row,col
{
for(zero_col=0;zero_col<SIZE;zero_col++)
{
if(board[zero_row][zero_col]==0)
{
flag=1;
break;
}
}
if(flag==1)
break;
}
SWAP(board[choice_row][choice_col],board[zero_row][zero_col],temp); //交换数字
}
int is_complete(int board[][SIZE])
{
int row=0;
int col=0;
int temp[SIZE][SIZE]={ //用于检查拼图是否拼好而定义的原始拼图
{1,2,3,4},
{5,6,7,8},
{9,10,11,12},
{13,14,15,0}
};
for(row=0;row<SIZE;row++)
{
for(col=0;col<SIZE;col++)
{
if(board[row][col]!=temp[row][col])
return 0;
}
}
return 1;
}
void initial(int board[][SIZE]) //问题就出在这里,初始化后的局面很简单
{
int row=0;
int col=0;
int flag=0; //跳出循环的标记
int on_left[2]={-1,0}; //往左上角偏移
int on_right[2]={-1,0}; //往右上角偏移
int up=0; //向上偏移次数
int left=0; //向左偏移次数
int right=0; //向右偏移次数
int rowdelta=0;
int coldelta=0;
int i=0; //循环变量
int j=0;
while(board[0][0]==1)
{
for(;;)
{
srand(time(NULL));
rowdelta=on_left[rand()%2];
if(rowdelta==0)
{
coldelta=-1;
turn_left(board);
left++;
}
else
{
coldelta=0;
turn_up(board);
up++;
}
if(left==2)
{//如果向左移了2次,则应该向上移3-turn_up
for(i=0;i<3-up;i++)
{
turn_up(board);
}
//再次向左移一次
turn_left(board);
break;
}
if(up==2)
{//如果向上移了2次,则应该向左移3-turn_left
for(j=0;j<3-left;j++)
{
turn_left(board);
}
//再次向上移一次
turn_up(board);
break;
}
}
}
for(i=0;i<3;i++) //向下移动三步
{
turn_down(board);
}
up=0; //初始化turn_up
for(;;) //向右上角移动
{
srand(time(NULL));
rowdelta=on_right[rand()%2];
if(rowdelta==0)
{
coldelta=1;
turn_right(board);
right++;
}
else
{
coldelta=0;
turn_up(board);
up++;
}
if(right==2)
{//如果向右移了2次,则应该向上移3-turn_up
for(i=0;i<3-up;i++)
{
turn_up(board);
}
//再右移动一次
turn_right(board);
break;
}
if(up==2)
{//如果向上移了2次,则应该向右移3-turn_right
for(j=0;j<3-right;j++)
{
turn_right(board);
}
//再次上移
turn_up(board);
break;
}
}
printf("Step=%d\n",step);
}
void turn_left(int board[][SIZE])
{
int row=0;
int col=0;
int flag=0;
//获取0的坐标
for(row=0;row<SIZE;row++)
{
for(col=0;col<SIZE;col++)
{
if(board[row][col]==0)
{
flag=1;
break;
}
}
if(flag==1)
{
flag=0;
break;
}
}
total_choice[step++]=board[row][col-1];
move(board,board[row][col-1]);
}
void turn_right(int board[][SIZE])
{
int row=0;
int col=0;
int flag=0;
//获取0的坐标
for(row=0;row<SIZE;row++)
{
for(col=0;col<SIZE;col++)
{
if(board[row][col]==0)
{
flag=1;
break;
}
}
if(flag==1)
{
flag=0;
break;
}
}
total_choice[step++]=board[row][col+1];
move(board,board[row][col+1]);
}
void turn_up(int board[][SIZE])
{
int row=0;
int col=0;
int flag=0;
//获取0的坐标
for(row=0;row<SIZE;row++)
{
for(col=0;col<SIZE;col++)
{
if(board[row][col]==0)
{
flag=1;
break;
}
}
if(flag==1)
{
flag=0;
break;
}
}
total_choice[step++]=board[row-1][col];
move(board,board[row-1][col]);
}
void turn_down(int board[][SIZE])
{
int row=0;
int col=0;
int flag=0;
//获取0的坐标
for(row=0;row<SIZE;row++)
{
for(col=0;col<SIZE;col++)
{
if(board[row][col]==0)
{
flag=1;
break;
}
}
if(flag==1)
{
flag=0;
break;
}
}
total_choice[step++]=board[row+1][col];
move(board,board[row+1][col]);
}
我最近写了个拼图游戏是4*4的方格,只要
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 0
数字与上面一一对应,就拼图成功了(0用空格显示出来,只有它可以移动,比如现在只能是12和15与0交换位置
来实现数字的移动)
我已经完成了数字移动功能,但关于如何初始化拼图数字(就是随机打乱数字的顺序)没有很好的办法
我想实现当玩家不能完成拼图,由电脑帮助移动数字,并能将过程显示出来
所以我打算由电脑随机移动数字(移动步数不能太多),并把这些数字记录下来,以便于后面让电脑还原原图
我想过很多办法来初始化拼图,但效果都不理想,初始化的图不够乱,以至于玩家一下子就能拼出图形
我也实现过让初始化数字很乱的方法,就是在while(图形四个角不是原来的数字)的循环下,让电脑随机移动
生成的拼图确实够乱,但是耗时比较长,一般循环了10000000步左右,这肯定不现实,即便初始化的拼图很乱,
但让电脑还原并显示出来,肯定不现实,玩家也不会有那么多耐心
问题就是拼图的初始化不成功,生成的拼图很简单,由于代码还没完全完成,所以生成拼图后按回车就自动还原了
现在修改过了,基本上能玩了
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#define SIZE 4
#define SWAP(x,y,t) ((t)=(x),(x)=(y),(y)=(t))
int *total_choice=NULL;
int step=0;
void display(int board[][SIZE]); //展示棋盘的函数
int is_valid(int board[][SIZE],int choice); //判断玩家选择是否有效的函数
void move(int board[][SIZE],int choice); //移动数字的函数
int is_complete(int board[][SIZE]); //判断拼图是否完成的函数
void initial(int board[][SIZE]); //初始化棋盘
void turn_left(int board[][SIZE]); //电脑左移
void turn_right(int board[][SIZE]); //电脑右移
void turn_up(int board[][SIZE]); //电脑上移
void turn_down(int board[][SIZE]); //电脑下移
void main()
{
int board[SIZE][SIZE]={ //The board
{1,2,3,4}, //Initial values are reference numbers
{5,6,7,8}, //used to select a vacant square for
{9,10,11,12}, //a turn
{13,14,15,0}
};
char again=0;
int choice=0;
int i=0;
int j=0;
long now=0;
int step=36;
char temp[4];
int capacity=100;
int *temp_choice=NULL;
int temp_step=0;
int count=0;
printf("欢迎你来到简单的拼图游戏\n");
printf("选择相应的数字,该数字会移到空格处\n");
printf("如果不能移动该数字,将显示出来,并让玩家重新选择数字移动\n");
printf("如果玩家实在拼不出原图,可以输入密码god,由电脑帮你还原\n");
printf("Good luck!Press Enter to start.\n");
scanf("%c",&again);
total_choice=(int*)malloc(capacity*sizeof(int));
if(total_choice==NULL)
{
printf("Out of memory!\n");
abort();
}
do
{
count=0;
for(i=0;i<SIZE;i++)
{
for(j=0;j<SIZE;j++)
board[i][j]=++count;
}
board[3][3]=0;
total_choice=(int*)malloc(capacity*sizeof(int)); //为total_choice分配空间
if(total_choice==NULL)
{
printf("Out of memory!\n");
abort();
}
initial(board);
for(;;)
{
if(step==capacity)
{
temp_step=step;
capacity+=50;
temp_choice=(int *)malloc(capacity*sizeof(int));
if(total_choice==NULL)
{
printf("Out of memory!\n");
exit(1);
}
for(i=0;i<temp_step;i++)
temp_choice[temp_step]=total_choice[temp_step];
free(total_choice);
total_choice=temp_choice;
temp_choice=NULL;
}
display(board);
printf("请输入你要移动的数字: ");
gets(temp);
if(strcmp(temp,"god")==0)
{
for(i=0;i<step;i++)
{
move(board,total_choice[step-i-1]);
display(board);
now=clock();
for(;clock()-now<CLOCKS_PER_SEC;);
system("cls");
}
free(total_choice);
total_choice=NULL;
break;
}
else
{
choice=atoi(temp);
}
if(is_valid(board,choice)) //如果移动有效则移动该数字并显示结果
{
move(board,choice);
total_choice[step++]=choice;
display(board);
system("cls"); //清屏
}
else //如果移动无效,则显示为无效移动
printf("无效的移动\n");
if(is_complete(board)&&is_valid(board,choice))
{
display(board);
printf("Good job!\n");
printf("Mission completed!\n");
free(total_choice);
total_choice=NULL;
break;
}
}
printf("你想再玩一次吗?(y or n) ");
scanf(" %c",&again);
fflush(stdin);
}while(tolower(again)=='y');
}
void display(int board[][SIZE])
{
int row=0; //Row index
int col=0; //Column index
for(row=0;row<SIZE;row++)
{
printf(" +");
for(col=0;col<SIZE;col++)
printf("----+");
printf("\n");
for(col=0;col<SIZE;col++)
printf(" |%2d%s",board[row][col],board[row][col]?"":"\b "); //展示棋盘上的数字,当数字为0时,显示为空白
printf(" |\n");
}
printf(" +");
for(col=0;col<SIZE;col++)
printf("----+"); //Display the bottom line
printf("\n"); //Display the end of bottom line
}
int is_valid(int board[][SIZE],int choice)
{
int row=0;
int col=0;
int rowdelta=0; //Row increment around a square
int coldelta=0; //Column increment around a square
int flag=0; //跳出循环标记
for(row=0;row<SIZE;row++) //获取玩家选择数字的位置
{
for(col=0;col<SIZE;col++)
{
if(board[row][col]==choice)
{
flag=1;
break;
}
}
if(flag==1)
break;
}
for(rowdelta=-1;rowdelta<=1;rowdelta++)
{
for(coldelta=-1;coldelta<=1;coldelta++)
{//不能检查越界位置,choice所在位置,以及与choice成对角线的位置
if(row+rowdelta>=SIZE||row+rowdelta<0||
col+coldelta>=SIZE||col+coldelta<0||
rowdelta==coldelta||board[row+rowdelta][col+coldelta]||rowdelta==-coldelta)
continue;
if(board[row+rowdelta][col+coldelta]==0) //空白就在choice旁边,则为有效choice
return 1;
}
}
return 0;
}
void move(int board[][SIZE],int choice)
{
int choice_row=0; //存储choice的row
int choice_col=0; //存储choice的col
int zero_row=0; //存储0的row
int zero_col=0; //存储0的col
int temp=0;
int flag=0; //循环跳出标记
if(!is_valid(board,choice))
return;
for(choice_row=0;choice_row<SIZE;choice_row++) //获取choice的row,col
{
for(choice_col=0;choice_col<SIZE;choice_col++)
{
if(board[choice_row][choice_col]==choice)
{
flag=1;
break;
}
}
if(flag==1)
{
flag=0;
break;
}
}
for(zero_row=0;zero_row<SIZE;zero_row++) //获取zero的row,col
{
for(zero_col=0;zero_col<SIZE;zero_col++)
{
if(board[zero_row][zero_col]==0)
{
flag=1;
break;
}
}
if(flag==1)
break;
}
SWAP(board[choice_row][choice_col],board[zero_row][zero_col],temp); //交换数字
}
int is_complete(int board[][SIZE])
{
int row=0;
int col=0;
int temp[SIZE][SIZE]={ //用于检查拼图是否拼好而定义的原始拼图
{1,2,3,4},
{5,6,7,8},
{9,10,11,12},
{13,14,15,0}
};
for(row=0;row<SIZE;row++)
{
for(col=0;col<SIZE;col++)
{
if(board[row][col]!=temp[row][col])
return 0;
}
}
return 1;
}
void initial(int board[][SIZE]) //问题就出在这里,初始化后的局面很简单
{
int row=0;
int col=0;
int flag=0; //跳出循环的标记
int on_left[2]={-1,0}; //往左上角偏移
int on_right[2]={-1,0}; //往右上角偏移
int up=0; //向上偏移次数
int left=0; //向左偏移次数
int right=0; //向右偏移次数
int rowdelta=0;
int coldelta=0;
int i=0; //循环变量
int j=0;
srand(time(NULL));
step=0;
while(board[0][0]==1)
{
for(;;)
{
rowdelta=on_left[rand()%2];
if(rowdelta==0)
{
coldelta=-1;
turn_left(board);
left++;
}
else
{
coldelta=0;
turn_up(board);
up++;
}
if(left==2)
{//如果向左移了2次,则应该向上移3-turn_up
for(i=0;i<3-up;i++)
{
turn_up(board);
}
//再次向左移一次
turn_left(board);
break;
}
if(up==2)
{//如果向上移了2次,则应该向左移3-turn_left
for(j=0;j<3-left;j++)
{
turn_left(board);
}
//再次向上移一次
turn_up(board);
break;
}
}
}
for(i=0;i<3;i++) //向下移动三步
{
turn_down(board);
}
up=0; //初始化turn_up
for(;;) //向右上角移动
{
rowdelta=on_right[rand()%2];
if(rowdelta==0)
{
coldelta=1;
turn_right(board);
right++;
}
else
{
coldelta=0;
turn_up(board);
up++;
}
if(right==2)
{//如果向右移了2次,则应该向上移3-turn_up
for(i=0;i<3-up;i++)
{
turn_up(board);
}
//再右移动一次
turn_right(board);
break;
}
if(up==2)
{//如果向上移了2次,则应该向右移3-turn_right
for(j=0;j<3-right;j++)
{
turn_right(board);
}
//再次上移
turn_up(board);
break;
}
}
for(i=0;i<3;i++) //向下移动3步
{
turn_down(board);
}
for(i=0;i<2;i++) //向左移动2步
{
turn_left(board);
}
for(i=0;i<3;i++) //向上移动3步
{
turn_up(board);
}
for(i=0;i<2;i++) //向右移动2步
{
turn_right(board);
}
for(i=0;i<3;i++) //向下移动3步
{
turn_down(board);
}
turn_left(board); //向左移动1步
for(i=0;i<3;i++) //向上移动三步
{
turn_up(board);
}
turn_right(board); //向右移动1步
for(i=0;i<3;i++) //向下移动三步
{
turn_down(board);
}
}
void turn_left(int board[][SIZE])
{
int row=0;
int col=0;
int flag=0;
//获取0的坐标
for(row=0;row<SIZE;row++)
{
for(col=0;col<SIZE;col++)
{
if(board[row][col]==0)
{
flag=1;
break;
}
}
if(flag==1)
{
flag=0;
break;
}
}
total_choice[step++]=board[row][col-1];
move(board,board[row][col-1]);
}
void turn_right(int board[][SIZE])
{
int row=0;
int col=0;
int flag=0;
//获取0的坐标
for(row=0;row<SIZE;row++)
{
for(col=0;col<SIZE;col++)
{
if(board[row][col]==0)
{
flag=1;
break;
}
}
if(flag==1)
{
flag=0;
break;
}
}
total_choice[step++]=board[row][col+1];
move(board,board[row][col+1]);
}
void turn_up(int board[][SIZE])
{
int row=0;
int col=0;
int flag=0;
//获取0的坐标
for(row=0;row<SIZE;row++)
{
for(col=0;col<SIZE;col++)
{
if(board[row][col]==0)
{
flag=1;
break;
}
}
if(flag==1)
{
flag=0;
break;
}
}
total_choice[step++]=board[row-1][col];
move(board,board[row-1][col]);
}
void turn_down(int board[][SIZE])
{
int row=0;
int col=0;
int flag=0;
//获取0的坐标
for(row=0;row<SIZE;row++)
{
for(col=0;col<SIZE;col++)
{
if(board[row][col]==0)
{
flag=1;
break;
}
}
if(flag==1)
{
flag=0;
break;
}
}
total_choice[step++]=board[row+1][col];
move(board,board[row+1][col]);
}
运行效果如下: