如下图片input.bmp,里面是一个迷宫,用程序算出一条从入口到出口的路径,
还给出了一个示例图片
说实话,刚开始我看到这个题目的时候,真有点蒙了,这是什么啊,尤其是图片,在我的邮件里那么模糊的一片。而且没有什么说明,要求就是要给出一个求解的算法,并且能有输出结果。
不过还好经过一天的努力我最终还是把这个程序给写出来了,中间我还找出自己上学时的数据结构的课本来现学了半天(不知这算不算作弊^_^).比较郁闷的是我为了是程序运行起来更好看,我用了实时查找路径显示(可以通过把SearchPath.cs中第76行“_picBox.Image = _image;”注释掉,把第157行“//_picBox.Image = _image;”注释取消来实现),这样我忽略了一个问题就是在线程里不能用到界面控件,因为我的机器运行比较慢不会出错(我也不知道为什么),但到运行比较快的机器上就不行了,就会抛出异常,到现在我也没想出办法解决,如果有那位高手有办法解决的话,希望能告诉我,我将非常感谢。
当时也是因为时间原因没有进行代码优化,后来没有优化是因为我的懒惰,在这里自我批评一下,如果有感兴趣的看到我写的不好的地方也非常希望您能告诉我,不胜感激!
如下是我的程序源码:
MainForm.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using System.Threading;
namespace Maze
{
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
ISearchPath _searchPath;
DateTime _start;
System.Timers.Timer _timer;
private void toolBtnStart_Click(object sender, EventArgs e)
{
_searchPath = new SearchPath(picBox, new Point(608, 210), new Point(8, 210));
//_searchPath = new SearchPathTopFirst(picBox, new Point(608, 210), new Point(8, 208));
System.Threading.Thread t = new Thread(new ThreadStart(_searchPath.GetPath));
t.Start();
//StartTime();
}
private void StartTime()
{
_start = System.DateTime.Now;
_timer = new System.Timers.Timer(10);
_timer.Elapsed += new System.Timers.ElapsedEventHandler(PrintTime);
_timer.Enabled = true;
_timer.Start();
}
private void PrintTime(object sender, System.Timers.ElapsedEventArgs e)
{
if (!_searchPath.IsEnd)
{
TimeSpan ts1 = new TimeSpan(DateTime.Now.Ticks);
TimeSpan ts2 = new TimeSpan(_start.Ticks);
TimeSpan ts = ts1.Subtract(ts2).Duration();
statusLabel.Text = String.Format("{0} : {1}",ts.Minutes ,ts.Seconds);
}
else
{
_timer.Stop();
_timer.Enabled = false;
}
}
private void toolBtnSave_Click(object sender, EventArgs e)
{
SaveFileDialog dialog = new SaveFileDialog();
dialog.FileName = "result.bmp";
if (DialogResult.OK == dialog.ShowDialog())
{
_searchPath.SaveFile(dialog.FileName);
}
}
}
}
MainForm.Designer.cs
namespace Maze
{
partial class MainForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.toolStrip1 = new System.Windows.Forms.ToolStrip();
this.toolBtnStart = new System.Windows.Forms.ToolStripButton();
this.toolBtnSave = new System.Windows.Forms.ToolStripButton();
this.statusStrip1 = new System.Windows.Forms.StatusStrip();
this.statusLabel = new System.Windows.Forms.ToolStripStatusLabel();
this.picBox = new System.Windows.Forms.PictureBox();
this.toolStrip1.SuspendLayout();
this.statusStrip1.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.picBox)).BeginInit();
this.SuspendLayout();
//
// toolStrip1
//
this.toolStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.toolBtnStart,
this.toolBtnSave});
this.toolStrip1.Location = new System.Drawing.Point(0, 0);
this.toolStrip1.Name = "toolStrip1";
this.toolStrip1.Size = new System.Drawing.Size(635, 25);
this.toolStrip1.TabIndex = 4;
this.toolStrip1.Text = "toolStrip1";
//
// toolBtnStart
//
this.toolBtnStart.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
this.toolBtnStart.Image = global::Maze.Properties.Resources.Start;
this.toolBtnStart.ImageTransparentColor = System.Drawing.Color.Magenta;
this.toolBtnStart.Name = "toolBtnStart";
this.toolBtnStart.Size = new System.Drawing.Size(23, 22);
this.toolBtnStart.Text = "Start";
this.toolBtnStart.Click += new System.EventHandler(this.toolBtnStart_Click);
//
// toolBtnSave
//
this.toolBtnSave.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
this.toolBtnSave.Image = global::Maze.Properties.Resources.Save;
this.toolBtnSave.ImageTransparentColor = System.Drawing.Color.Magenta;
this.toolBtnSave.Name = "toolBtnSave";
this.toolBtnSave.Size = new System.Drawing.Size(23, 22);
this.toolBtnSave.Text = "Save";
this.toolBtnSave.Click += new System.EventHandler(this.toolBtnSave_Click);
//
// statusStrip1
//
this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.statusLabel});
this.statusStrip1.Location = new System.Drawing.Point(0, 440);
this.statusStrip1.Name = "statusStrip1";
this.statusStrip1.Size = new System.Drawing.Size(635, 22);
this.statusStrip1.TabIndex = 5;
this.statusStrip1.Text = "statusStrip1";
//
// statusLabel
//
this.statusLabel.Name = "statusLabel";
this.statusLabel.Size = new System.Drawing.Size(0, 17);
//
// picBox
//
this.picBox.Image = global::Maze.Properties.Resources.input;
this.picBox.Location = new System.Drawing.Point(0, 26);
this.picBox.Name = "picBox";
this.picBox.Size = new System.Drawing.Size(635, 421);
this.picBox.TabIndex = 2;
this.picBox.TabStop = false;
//
// MainForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(635, 462);
this.Controls.Add(this.statusStrip1);
this.Controls.Add(this.toolStrip1);
this.Controls.Add(this.picBox);
this.Name = "MainForm";
this.Text = "Maze";
this.toolStrip1.ResumeLayout(false);
this.toolStrip1.PerformLayout();
this.statusStrip1.ResumeLayout(false);
this.statusStrip1.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.picBox)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.PictureBox picBox;
private System.Windows.Forms.ToolStrip toolStrip1;
private System.Windows.Forms.ToolStripButton toolBtnSave;
private System.Windows.Forms.StatusStrip statusStrip1;
private System.Windows.Forms.ToolStripStatusLabel statusLabel;
private System.Windows.Forms.ToolStripButton toolBtnStart;
}
}
SearchPath.cs
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
namespace Maze
{
class SearchPath : ISearchPath
{
Stack<StackItem> _stack = new Stack<StackItem>();
FootMarkTable _fmt = new FootMarkTable();
PictureBox _picBox;
Bitmap _image;
Point _start;
Point _end;
Color _pathColor = Color.Red;
public Color PathColor
{
set
{
_pathColor = value;
}
}
private SearchPath()
{ }
public SearchPath(PictureBox picBox, Point start, Point end)
{
_picBox = picBox;
_image = new Bitmap(picBox.Image);
_start = start;
_end = end;
}
public void GetPath()
{
_isEnd = false;
StackItem stackItem = InitStackItem();
do
{
stackItem = ChangeDir(stackItem);
if (!isWall(stackItem.curPos) && !_fmt.isFootMark(stackItem.curPos))
{
ChangeLastItemDir(stackItem.dir);
stackItem.order++;
_stack.Push(stackItem); //入栈
_fmt.isFootMark(stackItem.curPos);//标记已经走过
if (stackItem.curPos.X == _end.X && stackItem.curPos.Y == _end.Y)
{//到达终点退出
break;
}
stackItem.dir = 1;
ChangePointColor(stackItem.curPos, _pathColor);
}
else
{
if (stackItem.dir == 4)
{
stackItem = PopLastItem();
}
else
{
if (isWall(stackItem.curPos) || _fmt.isFootMark(stackItem.curPos))
{
stackItem = Untread(stackItem);
stackItem.dir++;
}
}
}
}
while (_stack.Count > 0);
_picBox.Image = _image;
//清空栈
_stack.Clear();
_isEnd = true;
}
private bool isInBoundary(Point p)
{
return p.X >= _end.X && p.X <= _start.X;
}
/// <summary>
/// 栈顶元素出栈
/// </summary>
/// <returns></returns>
private StackItem PopLastItem()
{
StackItem stackItem = new StackItem();
if (_stack.Count > 0)
{
ChangePointColor(((StackItem)_stack.Pop()).curPos, Color.White);
}
if (_stack.Count > 0)
{
StackItem stackItemTemp = (StackItem)_stack.Pop();
stackItem.dir = stackItemTemp.dir;
stackItem.order = stackItemTemp.order;
stackItem.curPos.X = stackItemTemp.curPos.X;
stackItem.curPos.Y = stackItemTemp.curPos.Y;
if (stackItem.dir != 4)
{
stackItem.dir++;
}
_stack.Push(stackItem);
}
return stackItem;
}
private StackItem InitStackItem()
{
StackItem stackItem = new StackItem();
stackItem.curPos = _start;
stackItem.order = 0;
stackItem.dir = 0;
return stackItem;
}
/// <summary>
/// 退回前一个坐标
/// </summary>
/// <param name="stackItem"></param>
/// <returns></returns>
protected virtual StackItem Untread(StackItem stackItem)
{
switch (stackItem.dir)
{
case 1:
stackItem.curPos.X = stackItem.curPos.X + 1;
break;
case 2:
stackItem.curPos.Y = stackItem.curPos.Y + 1;
break;
case 3:
stackItem.curPos.Y = stackItem.curPos.Y - 1;
break;
default:
break;
}
return stackItem;
}
/// <summary>
/// 修改坐标的颜色
/// </summary>
/// <param name="p"></param>
/// <param name="c"></param>
/// <returns></returns>
private Point ChangePointColor(Point p, Color c)
{
_image.SetPixel(p.X, p.Y, c);
//_picBox.Image = _image;
return p;
}
/// <summary>
/// 修改上一坐标的方向
/// </summary>
/// <param name="tmpDir"></param>
private void ChangeLastItemDir(int tmpDir)
{
if (_stack.Count > 0)
{
StackItem stackItemTemp = (StackItem)_stack.Pop();
stackItemTemp.dir = tmpDir;
_stack.Push(stackItemTemp);
}
}
protected virtual StackItem ChangeDir(StackItem stackItem)
{
switch (stackItem.dir)
{
case 1://向左
stackItem.curPos.X = stackItem.curPos.X - 1;
break;
case 2://向上
stackItem.curPos.Y = stackItem.curPos.Y - 1;
break;
case 3://向下
stackItem.curPos.Y = stackItem.curPos.Y + 1;
break;
case 4://向右
stackItem.curPos.X = stackItem.curPos.X + 1;
break;
case 0:
stackItem.dir = 1;
break;
default:
break;
}
return stackItem;
}
/// <summary>
/// 判断是否是墙
/// </summary>
/// <param name="p"></param>
/// <returns></returns>
private bool isWall(Point p)
{
Color c = _image.GetPixel(p.X, p.Y);
return c.A == Color.Black.A && c.B == Color.Black.B && c.G == Color.Black.G && c.R == Color.Black.R;
}
public void SaveFile(string fileName)
{
_image.Save(fileName);
}
private bool _isEnd = true;
public bool IsEnd
{
get { return _isEnd; }
}
}
public struct StackItem
{
public int order;
public int dir;
public Point curPos;
}
}
Program.cs
using System.Collections.Generic;
using System.Windows.Forms;
namespace Maze
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
}
}
如下图是我得出的结果:
浙公网安备 33010602011771号