马踏棋盘图形界面版

算法思想:每次随机选一个初始位置,按照逆时针的方向每次向下试探,在试探到走不通的格子后,就退回上一个格子,偏转到下一个方向继续试探,直至所有的格子被走遍;

界面编程:利用vc++的easyx插件进行绘图;

#include <graphics.h>//设计图形界面所必须的头文件
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
#include <windows.h>
#include <time.h>//显示时间的头文件
#include <mmsystem.h>//播放音效所需的头文件
#pragma comment(lib, “WINMM.LIB”)//播放音效所需的头文件

#define N 20

typedef struct location {
int x;
int y;
}LOC;//记录马的当前位置

typedef struct node {
LOC loc;//当前坐标
    int num;//存储该坐标当前已经试探过的方向! 
struct node * pNext;
}NODE,*PNODE;

typedef struct stack {
struct node * top;//栈顶指针
struct node * bottom;//栈底指针
}STACK,*PSTACK;

void init(); //初始化栈 
void push(LOC loc); //进栈 
void pop(); // 出栈,注意要判空
int empty(); //判空栈 
void trave(); //输出马的行走路线
void clear(); //置空栈 
PNODE GetTop(); //取栈顶元素
LOC check(); //寻找试探下一个有效的格子
int  check1(LOC n); //判断该格子当前是否已经走过
void jiemian();             //
void Time();
LOC beforegame();

STACK sp;
PSTACK s = &sp;//s表示马的行进路径,全局变量必须在定义的同时初始化,否则会报错
LOC size[64];//存储马的坐标
int f = 0,k,size1[64] = {0};          
int  curpos=0;       //总共走了多少步。 
int qipanjud[8][8] = {{0}};//标记该格子是否已经走过,1表示走过,0表示没走

int main(void) {
LOC loc,n;//坐标
int flag;
char a[N];
flag = 1;
jiemian();
loc = beforegame();
init();//初始化栈

size[f] = loc;//记录已经走过的坐标
    qipanjud[loc.x][loc.y]=1;   //已经走过增加棋盘标识 
        settextcolor(BLACK);        //设置文字的颜色
        settextstyle(40, 0, _T(“宋体”));//设置字体
RECT r = {0+(size[f].x-1)*80,0+(size[f].y-1)*80,80+size[f].x*80,80+size[f].y*80};//定义一个矩形绘图区域
setfillcolor(DARKGRAY);//设置填充颜色为灰色
fillrectangle(0+(size[f].x-1)*80,0+(size[f].y-1)*80,size[f].x*80,size[f].y*80);//用灰色填充指定矩形区域
        sprintf(a, “%d”, curpos+1);//将整形变量格式化为字符串,并将值存储到字符数组a中
printf(“%s”,a);
        outtextxy(80*size[f].x-40,80*size[f].y-40,a);//将字符数组a的内容在指定位置打印输出
        PlaySound(“G:\\click.wav”,NULL,SND_FILENAME|SND_ASYNC);//发出声音
    curpos++;          //记录已经走过的棋盘格字数
push(loc);
s->top->num = 0;    //开始方向偏向为 0 ,记录下当前位置的已经试探的方向数为0

while(1) {//走棋盘
    n = check();//试探栈顶位置坐标的8个可能选择的方向
        if((n.x != size[f].x||n.y != size[f].y)) {//如果返回的坐标原来坐标不同,则该坐标为有效的坐标
f++;
size[f] = n;//将该存入数组中,
printf(“入栈:(%d,%d)     第:%d\n”,size[f].x,size[f].y,curpos+1);
settextcolor(BLACK);//设置文字颜色为黑色
settextstyle(40, 0, _T(“宋体”));//设置字体为宋体40号
RECT r = {0+(size[f].x-1)*80,0+(size[f].y-1)*80,80+size[f].x*80,80+size[f].y*80};//初始化一个矩形绘图区域
setfillcolor(DARKGRAY);//设置填充颜色为灰色
fillrectangle(0+(size[f].x-1)*80,0+(size[f].y-1)*80,size[f].x*80,size[f].y*80);//用灰色填充指定矩形区域
        sprintf(a, “%d”, curpos+1);//将整形变量格式化为字符串,并将值存储到字符数组a中
        outtextxy(80*size[f].x-40,80*size[f].y-40,a);//将字符数组a的内容在指定位置打印输出
        PlaySound(“G:\\click.wav”,NULL,SND_FILENAME|SND_ASYNC);  //发出马走棋盘时的声音     
push(size[f]);//将该坐标压入栈
//Sleep(500);
qipanjud[size[f].x][size[f].y]=1; //将该坐标标记为1,表示已经走过
curpos++;//走过的格子数加1
}
else {//如果返回的坐标与原来坐标相同,则该坐标为无效坐标
printf(“出栈:%d,%d,%d  ,第:%d\n”,s->top->loc.x,s->top->loc.y,s->top->num,curpos-1);
        settextcolor(BLACK);//设置文字颜色为黑色
settextstyle(40, 0, _T(“宋体”));//设置字体为宋体40号
RECT r = {0+(size[f].x-1)*80,0+(size[f].y-1)*80,80+size[f].x*80,80+size[f].y*80};//初始化一个矩形绘图区域
setfillcolor(WHITE);//设置填充颜色为白色
fillrectangle(0+(size[f].x-1)*80,0+(size[f].y-1)*80,size[f].x*80,size[f].y*80);//用白色填充指定矩形区域
        sprintf(a, “%d”, 0);//将整形变量格式化为字符串,并将值存储到字符数组a中
        outtextxy(80*size[f].x-40,80*size[f].y-40,a);//将字符数组a的内容在指定位置打印输出
qipanjud[s->top->loc.x][s->top->loc.y]=0;//将该位置标记为0,表示没走过
pop();//将该坐标出栈
        //Sleep(500);
f–;
curpos–;//走过的格子数减1

}

if(curpos == 64)//当走过的格子数达到64个时,马走遍整个棋盘,程序退出
break;

}
printf(“马的行走路线是:”);
trave();
getch();
    settextcolor(BLACK);
    settextstyle(50, 0, _T(“宋体”));
drawtext(“游戏结束,按任意键退出”, &r, DT_CENTER | DT_VCENTER | DT_SINGLELINE);//在界面上输出提示语
    getch();
    clearrectangle(0,0,640,640);//清空绘图区域
    closegraph();//关闭绘图环境
Time();//打印输出当前的系统时间
return 0;
}
LOC beforegame() {
   int i,j;
LOC loc;
MOUSEMSG m; //定义一个接受鼠标点击事件返回值的结构体变量
fflush(stdin);//清空缓存
settextcolor(BLACK);//设置提示语文字的颜色为黑色
settextstyle(50, 0, _T(“宋体”));//设置提示语的字体为宋体50号
RECT r1 = {0, 0, 640, 640};//定义一个640*640的正方形绘图区域
drawtext(“按任意键开始游戏”, &r1, DT_CENTER | DT_VCENTER | DT_SINGLELINE);//在上面绘图区域界面中央打印出提示语
getch();//按任意键继续
clearrectangle(0,0,640,640);//清空上面的绘图区域
closegraph();//关闭图形环境
jiemian();//界面设计函数
getchar();
FlushMouseMsgBuffer();//清空鼠标消息缓冲区
m = GetMouseMsg();//获取一个鼠标的点击事件,将点击坐标的点返回保存在结构体m中
//因为绘图环境的物理坐标是640*640的,而逻辑坐标是1-8的,下面的嵌套for循环是为了将坐标从640*640转化为8*8的坐标表示
for(i = 1;i < 9;i++) {
for(j = 1;j < 9;j++) {
if(m.x > 80*(i-1) &&m.x < 80*i&&m.y >80*(j-1)&&m.y < 80*j) {
loc.x = i;
loc.y = j;
break;
}else 
continue;
}
}
return loc;
}

void Time() {
time_t rawtime;  
struct tm * timeinfo;  
time ( &rawtime );  
timeinfo = localtime ( &rawtime );  
printf ( “当前的时间是: %s”, asctime (timeinfo) );
}
void jiemian() {
int i;
initgraph(640, 640);//初始化一个640*640的绘图环境
setbkcolor(0xFFFFFF);//设置当前绘图的背景色为白色
    cleardevice();//是用当前背景色清空屏幕,并将当前点移至 (0, 0)。
     setlinecolor(BLACK);//设置划线的颜色为黑色
//用图线绘制出一个8*8的棋盘
for(i = 1;i < 9 ;i++) {
        line(0,80*i,640,80*i);
}
for(i = 1;i < 9;i++) {
        line(80*i,0,80*i,640);
}
}

void init() {//初始化栈,将栈顶指针和栈底指针指向同一个节点
s->top = (PNODE)malloc(sizeof(NODE));
if(s->top == NULL) {
printf(“error!!!\n”);
exit(1);
}
s->bottom = s->top;
s->top->pNext = NULL;
}

void push(LOC loc) {//进栈操作
PNODE pNew = (PNODE)malloc(sizeof(NODE));//动态分配一个新的空间,并用pNew指针指向这块新分配的空间;
if(pNew == NULL) {
printf(“error!!!\n”);
exit(1);
}
pNew->pNext = s->top;//将pNew指向的节点与头指针指向的节点相连接
s->top = pNew;//用头指针指向pNew指针指向的节点
pNew->loc = loc;//赋值
pNew->num=0;
}

int empty() {
if(s->top == s->bottom)
return 1;
else 
return 0;
}

void pop() {//出栈,注意要判空
PNODE p;
if(!empty()) {
        p = s->top;
s->top = s->top->pNext;
free(p);
p = NULL;
}
}

void trave() {//输出马的行走路线
int i=0;
while(i<64)
{
if(i%8==0) printf(“\n”);
printf(“(%d,%d)   “,size[i].x,size[i].y);
i++;
}
}
void clear() {//置空栈
PNODE p,q;
p = s->top;
    q = p->pNext;
while(p != s->bottom) {
free(p);
p = q;
q = q->pNext;
}
s->top = s->bottom;
}

PNODE GetTop() {//取栈顶元素
return s->top;
}

LOC check()
{
LOC n;
int i,p=s->top->num;
//用两个一维数组来存储每个坐标可能的8个试探方向
    int Htry1[8] = {-2,-1,1,2,2,1,-1,-2};
int Htry2[8] = {1,2,2,1,-1,-2,-2,-1};
for(i = 0 ;i < 8;i++) { 
n.x = s->top->loc.x + Htry1[i];
n.y = s->top->loc.y + Htry2[i];
if(n.x > 8||n.x < 1||n.y > 8||n.y < 1||check1(n))
{//如果坐标在棋盘外或者此前已经走过,就继续试探下一个方向
   continue;
}
   else{//如果该坐标为有效坐标
if(s->top->num==8)//当这个坐标的已经试探的方向超过8时,这次试探是无效试探,将其已经试探过的方向置为0,返回原来的坐标
{
   s->top->num=0;
return s->top->loc;
}
if(p!=0) {
p–;
continue;  
   }
s->top->num++;//将试探方向加1
  break;
        }
}

if(!check1(n)&&i!=8)//如果坐标是有效的就返回该有效坐标,否则就返回原坐标
return n;

else 
return s->top->loc;
}

int  check1(LOC n)  //检测此处是否已经走过 
{
if(qipanjud[n.x][n.y]==1)
return 1;
return 0;
}

王兆鹏

    原文作者:骑士周游问题
    原文地址: https://blog.csdn.net/xiyou_android/article/details/49849539
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞