Matlab 进行迷宫行走游戏求解

Matlab 进行迷宫行走游戏求解

原题用C(C++)写

题目:有一个愚蠢的机器人走进一个w*h的迷宫,迷宫里有空地和陷阱。他想要访问迷宫的每个方格,但是它很笨,只会按照指令的方向走。当机器人不能走的时候,也就是下一步会遇到陷阱、迷宫边界或者访问过的格子,它会向右转90度(顺时针旋转90度,不能访问已经访问过的方格,且在原地只转一次,移动后可获得又一次旋转机会)。请问这个机器人最多可以经过多少个方格。

示意图

Matlab 进行迷宫行走游戏求解_第1张图片
图片题目来自于http://39.106.164.46/problem.php?id=1021&tdsourcetag=s_pcqq_aiomsg

特点

  • 可以生成任何大小的迷宫;
  • 随机确定障碍物的地址;
  • 随机确定初始点的位置、方向

设计思想

1. 边界判别

这一步的主要目的是,将机器人的行走情况分开来讨论

function logic = judge_edge(mat,location)

[i,j]= ind2sub(size(mat),location);
[L,W]= size(mat);
if i == 1 | i == L | j == 1 | j == W
    logic = 1;
else 
    logic = 0;
end

end

2. 转向判别

对于内部点

% 在执行该算法前,必须得线判断当前点是否为边界点。
% 如果不是边界的话,执行下面程序
% 判断当前方向下一点是否为可行点
% next_location 输出下一点坐标
% a 跟新矩阵
% 考虑矩阵内部时,对于每一个当前点方向,接下来可能有两种走向。四个边界点是特殊点
function [next_location,mat,next_direction] = jude_point(mat,temp_location,direction)

[L,W] = size(mat);

[i,j] = ind2sub(size(mat),temp_location);

% avail = 1;
%% first combination up or right
if direction == 10
    if mat(temp_location - 1) == 1  

        next_location = temp_location - 1;
        mat(temp_location) = 0;
        next_direction = 10;
    else
        avail = 1;
       
    end
    
    if exist('avail')
        % 往右手边找是否可行
        
        if mat(temp_location + L) == 1
            
            next_location = temp_location + L;
            mat(temp_location) = 0;
            next_direction = 5;
        else
            
            next_direction = 0;
            mat(temp_location) = 0;
            next_location = temp_location;
        end
    end
end
%% second combination right or down
if direction == 5
    if mat(temp_location + L) == 1

        next_location = temp_location + L;
        mat(temp_location) = 0;
        next_direction = 5;
    else            % 原方向不可行
        avail = 1;
       
    end
    
    
    if exist('avail')   % 如果原方向不可行的话,
        % 往右手边找是否可行
        if mat(temp_location + 1) == 1

            next_location = temp_location + 1;
            mat(temp_location) = 0;
            next_direction = -10;
        else
         
            next_direction = 0;
            mat(temp_location) = 0;
            next_location = temp_location;
           
        end
    end
end

%% third combination down or left
if direction == -10
    if mat(temp_location + 1) == 1

        next_location = temp_location + 1;
        mat(temp_location) = 0;
        next_direction = -10;    
    else
        avail = 1;
    end
    
    
    if  exist('avail') 
        % 往左手边找是否可行
        if mat(temp_location - L) == 1

            next_location = temp_location - L;
            mat(temp_location) = 0;
            next_direction = -5;
        else
            %change = 0;
            next_direction = 0;
            mat(temp_location) = 0;
            next_location = temp_location;
        end 
    end 
end
%% forth combination left or up

if direction == -5
    if mat(temp_location - L) == 1

        next_location = temp_location -L;
        mat(temp_location) = 0;
        next_direction = -5;
    else
        avail = 0;
    end
    
    if   exist('avail') 
        % 往右手边找是否可行(上方)
        if mat(temp_location - 1) == 1

            next_location = temp_location - 1;
            mat(temp_location) = 0;
            next_direction = 10;
        else
           
            next_direction = 0;
            mat(temp_location) = 0;
            next_location = temp_location;
        end
     end
 end

end 
end

对于边界点

% 重新判断边界
% 如果走不通了,则next_direction = 0 并且 mat(temp_location)=0;
function [ next_direction, next_location,mat] =  edge_operation(mat,temp_location,direction)

[L,W] = size(mat);

[i,j] = ind2sub(size(mat),temp_location);


%% 当前方向向上
if direction == 10
    if i == 1
        if j == W   %如果是右上角点的话
            next_direction = 0;
            next_location = temp_location;
            mat(next_location) = 0;
        else       % 如果不是的话
            if mat(temp_location+L) == 1
                next_direction = 5;
                next_location = temp_location+L;
                mat(temp_location) = 0;
            else
                next_direction = 0;
                next_location = temp_location;
                mat(next_location) = 0;
            end
        end
    else
        % 如果不是最上面一行的话,
        if mat(temp_location-1) == 1  % 如果上面行存在可行点则
            next_direction = 10;
            next_location = temp_location-1;
            mat(temp_location) = 0;
        else    % 如果不存在,则转向
            %                     next_direction = 0;
            %                     next_location = temp_location;
            %                     mat(temp_location) = 2;
            change =1;
        end
        % 如果需要转向的话
        if exist('change')
            if mat(temp_location+L) == 1   %如果转向可行的话
                next_location = temp_location + L;
                next_direction = 5;
                mat(temp_location) =0;
            else                        % 如果转向不可行的话
                next_location = temp_location;
                next_direction = 0;
                mat(temp_location) = 0;
            end
        end
    end
end


%% 当前方向向下
if direction == -10
    if i == L
        if j == 1   %如果是左下角点的话
            next_direction = 0;
            next_location = temp_location;
            mat(next_location) = 0;
        else       % 如果不是的话
            if mat(temp_location-L) == 1
                next_direction = -5;
                next_location = temp_location-L;
                mat(temp_location) = 0;
            else
                next_direction = 0;
                next_location = temp_location;
                mat(next_location) = 0;
            end
         end
    else
        % 如果不是最下一行的话,
        if mat(temp_location+1) == 1  % 如果上面行存在可行点则
            next_direction = -10;
            next_location = temp_location+1;
            mat(temp_location) = 0;
        else    % 如果不存在,则转向
            change =1;
        end
        % 如果需要转向的话
        if exist('change')
            if mat(temp_location-L) == 1   %如果转向可行的话
                next_location = temp_location - L;
                next_direction = -5;
                mat(temp_location) =0;
            else                        % 如果转向不可行的话
                next_location = temp_location;
                next_direction = 0;
                mat(temp_location) = 0;
            end
        end
    end
end

%% 当前方向向右
if direction == 5
    if j == L
        if i == W    %如果是右下角点的话
            next_direction = 0;
            next_location = temp_location;
            mat(next_location) = 0;
        else       % 如果不是的话
            if mat(temp_location+1) == 1
                next_direction = -10;
                next_location = temp_location+1;
                mat(temp_location) = 0;
            else
                next_direction = 0;
                next_location = temp_location;
                mat(next_location) = 0;
            end
            %             next_direction = 0;
            %             next_location = temp_location;
            %                 change = 1; % 判断是否要转向
        end
    else
        % 如果不是最右侧一行的话,
        if mat(temp_location+L) == 1  % 如果上面行存在可行点则
            next_direction = 5;
            next_location = temp_location+L;
            mat(temp_location) = 0;
        else    % 如果不存在,则转向
            %                     next_direction = 0;
            %                     next_location = temp_location;
            %                     mat(temp_location) = 2;
            change =1;
        end
        % 如果需要转向的话
        if exist('change')
            if mat(temp_location+1) == 1   %如果转向可行的话
                next_location = temp_location + 1;
                next_direction = -10;
                mat(temp_location) =0;
            else                        % 如果转向不可行的话
                next_location = temp_location;
                next_direction = 0;
                mat(temp_location) = 0;
            end
        end
    end
end

%% 当前方向向左
if direction == -5
     if j == 1
        if i == 1    %如果是左上角点的话
            next_direction = 0;
            next_location = temp_location;
            mat(next_location) = 0;
        else       % 如果不是的话
            if mat(temp_location-1) == 1
                next_direction = 10;
                next_location = temp_location-1;
                mat(temp_location) = 0;
            else
                next_direction = 0;
                next_location = temp_location;
                mat(next_location) = 0;
            end
            %             next_direction = 0;
            %             next_location = temp_location;
            %                 change = 1; % 判断是否要转向
        end
    else
        % 如果不是最左侧一行的话,
        if mat(temp_location-L) == 1  % 如果上面行存在可行点则
            next_direction = -5;
            next_location = temp_location-L;
            mat(temp_location) = 0;
        else    % 如果不存在,则转向
            %                     next_direction = 0;
            %                     next_location = temp_location;
            %                     mat(temp_location) = 2;
            change =1;
        end
        % 如果需要转向的话
        if exist('change')
            if mat(temp_location-1) == 1   %如果转向可行的话
                next_location = temp_location - 1;
                next_direction = 10;
                mat(temp_location) =0;
            else                        % 如果转向不可行的话
                next_location = temp_location;
                next_direction = 0;
                mat(temp_location) = 0;
            end
        end
    end
end
end 

主程序

% yang  2019.3.14
clc
clear  all

% 0 表示已经走过的点   1 表示可行点   3 表示禁止点
%% 构造原始矩阵
a = ones(40,40);   
% direction:up = 10; down = -10; right = 5;left = -5;
[l,w] = size(a);
n = l*w;
init_station = randperm(n,1);
a(init_station) = 0;   % 起始点位置
init_obs = randperm(n,150); % 这个4 可以是随机的,代表障碍物数
% 禁行点 为3
a(init_obs) = 3;
temp_location = init_station;
%%选定初始方向
direction = [10,-10,5,-5];% 分别表示 上 下 右  左
select = randperm(4,1);
direction = direction(select);

%显示颜色 
mapcolor(:,:,1) = a/3;
mapcolor(:,:,3) = zeros(l);

%% 迭代
for k = 1:2000
   
   if judge_edge(a,temp_location)  % 判断是否为边界,如果是的话,按边界行走方式
       
       [next_direction, next_location,a] =  edge_operation(a,temp_location,direction)
       temp_location = next_location;
       direction = next_direction;
       
   else  % 如果不是边界,则进行内部行走运算
      [next_location,a,next_direction] = jude_point(a,temp_location,direction);
      temp_location = next_location;
      direction = next_direction;
   end
     pause(0.2)
   % 循环终止
    mapcolor(:,:,2) = a/3;
    imagesc(mapcolor);
    set(gca,'xtick',[],'ytick',[])

    title(['这是第',num2str(k),'步'])
    im = frame2im(getframe(gcf));    
    [I, map] = rgb2ind(im,256);
    if i==1
        imwrite(I,map,'middle.gif','gif','writeMode','overwrite','loopcount',inf);
    else
        imwrite(I,map,'middle.gif','gif','WriteMode','append','DelayTime',0.1);
    end  
   if direction == 0    
       break;       
   end     
end 
 
% 输出个数
temp = a==0;
num = sum(temp(:));
fprintf('一共走过了%d个格子\n',num)
title(['一共走过了',num2str(num),'步'])

效果图

Matlab 进行迷宫行走游戏求解_第2张图片

后记

  • 第一次写Markdown,发现这东西真好用,可惜渣渣的我代码貌似写的太复杂了,欢迎大神私下交流算法。

  • 以后会放一些交通类的程序代码,欢迎关注!向莫烦大神学习!

Authors
Yang

你可能感兴趣的:(Interesting)