439 lines
16 KiB
C#
439 lines
16 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Data;
|
|
using System.Drawing;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using System.Windows.Forms;
|
|
|
|
namespace AStarPathFinding
|
|
{
|
|
//타일 속성
|
|
//기본, 출발점, 목적지, 벽, 열린리스트, 닫힌리스트, 길
|
|
public enum eTileState
|
|
{ None, Start, Goal, Wall, Road, RRoad, LRoad, URoad, DRoad, Open, Close, Path }
|
|
|
|
public partial class Form1 : Form
|
|
{
|
|
public static string Direction { get; set; } // 방향 설정!!!
|
|
|
|
//구조체=====================
|
|
struct stCurrentAction//사용자의 세팅(타일배치)종류 확인용 구조체
|
|
{
|
|
public object sender;//호출한 버튼
|
|
public eTileState actionType;//세팅 타입
|
|
public stCurrentAction(object sender, eTileState type)
|
|
{
|
|
this.sender = sender;
|
|
this.actionType = type;
|
|
}
|
|
}
|
|
//======================구조체
|
|
|
|
//상수=======================
|
|
const int TABLE_SIZE = 16;//테이블 사이즈 기본 값 16
|
|
readonly Point defaultStartPoint = new Point(5, 6);//디폴트 시작점
|
|
readonly Point defaultGoalPoint = new Point(9, 6);//디폴트 목적지
|
|
readonly Point[] defaultWallPoint = new Point[3]//디폴트 벽 위치
|
|
{ new Point(7, 5), new Point(7, 6), new Point(7, 7) };
|
|
//readonly Point[] defaultRoadPoint = new Point[] { };
|
|
|
|
|
|
|
|
readonly Color defaultButtonColor;//디폴트 버튼 색
|
|
//========================상수
|
|
|
|
//렌더링======================
|
|
readonly int tableNodeSize;//노드사이즈
|
|
readonly Pen pen = new Pen(Color.DimGray, 1);//선 그리기용
|
|
readonly Font font = new Font("바탕", 10, FontStyle.Regular);//폰트
|
|
//=======================렌더링
|
|
|
|
//길찾기=======================
|
|
eTileState[,] tableData;//테이블 데이터
|
|
AstarPathFinder pathFinder;//길찾기 클래스
|
|
Point startPoint;//시작점
|
|
Point goalPoint;//목표점
|
|
|
|
//=======================길찾기
|
|
|
|
//세팅=========================
|
|
stCurrentAction? curAction = null;//현재 사용자가 선택한 배치타입
|
|
//=========================세팅
|
|
|
|
|
|
protected override CreateParams CreateParams
|
|
{ get { var cp = base.CreateParams; cp.ExStyle |= 0x02000000; return cp; } }
|
|
|
|
public Form1()
|
|
{
|
|
InitializeComponent();
|
|
|
|
defaultButtonColor = Color.LightGray;
|
|
|
|
tableNodeSize = pn_Table.Size.Width / TABLE_SIZE;
|
|
|
|
startPoint = defaultStartPoint;
|
|
goalPoint = defaultGoalPoint;
|
|
|
|
tableData = new eTileState[TABLE_SIZE, TABLE_SIZE];
|
|
SetDefault();
|
|
|
|
pathFinder = new AstarPathFinder(new Point(TABLE_SIZE, TABLE_SIZE), tableData);
|
|
}
|
|
|
|
//테이블 초기화
|
|
void SetDefault()
|
|
{
|
|
for(int i = 0; i < TABLE_SIZE; i++)
|
|
{
|
|
for(int j = 0; j < TABLE_SIZE; j++)
|
|
{
|
|
tableData[i, j] = eTileState.None;
|
|
}
|
|
}
|
|
|
|
tableData[defaultStartPoint.X, defaultStartPoint.Y] = eTileState.Start;
|
|
tableData[defaultGoalPoint.X, defaultGoalPoint.Y] = eTileState.Goal;
|
|
|
|
foreach(Point iter in defaultWallPoint)
|
|
tableData[iter.X, iter.Y] = eTileState.Wall;
|
|
|
|
startPoint = defaultStartPoint;
|
|
goalPoint = defaultGoalPoint;
|
|
}
|
|
|
|
//노드 그리기
|
|
void DrawNode(PaintEventArgs e, Color color, AstarNode node)
|
|
{
|
|
Rectangle rect = new Rectangle(node.axis.X * tableNodeSize, node.axis.Y * tableNodeSize, tableNodeSize, tableNodeSize);
|
|
|
|
e.Graphics.FillRectangle(new SolidBrush(color), rect);
|
|
e.Graphics.DrawRectangle(pen, rect);
|
|
|
|
e.Graphics.DrawString(node.F.ToString(), font, Brushes.Black, rect.X + 1, rect.Y + 4);
|
|
e.Graphics.DrawString(node.G.ToString(), font, Brushes.Black, rect.X + 1, rect.Y + tableNodeSize * .7f);
|
|
e.Graphics.DrawString(node.H.ToString(), font, Brushes.Black, rect.X + tableNodeSize - 1, rect.Y + tableNodeSize * .7f, new StringFormat(StringFormatFlags.DirectionRightToLeft));
|
|
|
|
if(node.parent != null)
|
|
{
|
|
Point center = new Point(rect.X + tableNodeSize / 2, rect.Y + tableNodeSize / 2);
|
|
RectangleF centerRect = new RectangleF(new PointF(center.X - 2.5f, center.Y - 2.5f), new SizeF(5, 5));
|
|
e.Graphics.DrawLine(pen, center, pathFinder.AddPoint(center, node.ParentDirection, -8));
|
|
e.Graphics.FillRectangle(new SolidBrush(Color.DimGray), centerRect);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 버튼 선택시 들어옴, 현재 선택한 배치타입 설정
|
|
/// </summary>
|
|
/// <param name="sender">null 일경우 초기화</param>
|
|
/// <param name="type">None 일경우 취소</param>
|
|
void SetCurrentAction(object sender, eTileState type)
|
|
{
|
|
if(type != eTileState.Open)//오픈은 스텝모드,,..
|
|
pathFinder.Initialize();
|
|
|
|
if(curAction != null)
|
|
{
|
|
(curAction.Value.sender as Button).BackColor = defaultButtonColor;
|
|
|
|
if(type == eTileState.None || type == curAction.Value.actionType)
|
|
{
|
|
curAction = null;
|
|
return;
|
|
}
|
|
}
|
|
|
|
if(sender != null)
|
|
{
|
|
curAction = new stCurrentAction(sender, type);
|
|
|
|
if(type != eTileState.None)
|
|
(sender as Button).BackColor = Color.LightSeaGreen;
|
|
}
|
|
}
|
|
|
|
private void pn_Table_Paint(object sender, PaintEventArgs e)
|
|
{
|
|
for(int i = 0; i < TABLE_SIZE; i++)
|
|
{
|
|
for(int j = 0; j < TABLE_SIZE; j++)
|
|
{
|
|
Color color = new Color();
|
|
|
|
switch(tableData[i, j])
|
|
{
|
|
case eTileState.None:
|
|
break;
|
|
case eTileState.Start:
|
|
color = Color.IndianRed;
|
|
break;
|
|
case eTileState.Goal:
|
|
color = Color.LightGreen;
|
|
break;
|
|
case eTileState.Wall:
|
|
color = Color.CornflowerBlue;
|
|
break;
|
|
case eTileState.Open:
|
|
color = Color.LemonChiffon;
|
|
break;
|
|
case eTileState.Close:
|
|
color = Color.BurlyWood;
|
|
break;
|
|
case eTileState.Path:
|
|
color = Color.Plum;
|
|
break;
|
|
case eTileState.Road:
|
|
color = Color.Yellow;
|
|
break;
|
|
case eTileState.LRoad:
|
|
color = Color.DarkRed;
|
|
break;
|
|
case eTileState.RRoad:
|
|
color = Color.DarkBlue;
|
|
break;
|
|
case eTileState.URoad:
|
|
color = Color.Bisque;
|
|
break;
|
|
case eTileState.DRoad:
|
|
color = Color.BlueViolet;
|
|
break;
|
|
}
|
|
DrawNode(e, color, pathFinder.GetAstarNode(new Point(i, j)));
|
|
}
|
|
}
|
|
}
|
|
|
|
private void btn_SetStartPoint_Click(object sender, EventArgs e)
|
|
{
|
|
SetCurrentAction(sender, eTileState.Start);
|
|
}
|
|
|
|
private void btn_SetGoalPoint_Click(object sender, EventArgs e)
|
|
{
|
|
SetCurrentAction(sender, eTileState.Goal);
|
|
}
|
|
|
|
private void btn_SetWallPoint_Click(object sender, EventArgs e)
|
|
{
|
|
SetCurrentAction(sender, eTileState.Wall);
|
|
}
|
|
|
|
private void btn_SetDefault_Click(object sender, EventArgs e)
|
|
{
|
|
SetCurrentAction(sender, eTileState.None);
|
|
|
|
SetDefault();
|
|
pn_Table.Refresh();
|
|
}
|
|
|
|
private void btn_SetRoadPoint_Click(object sender, EventArgs e)
|
|
{
|
|
SetCurrentAction(sender, eTileState.Road);
|
|
}
|
|
|
|
private void btn_SetLeftRoadPoint_Click(object sender, EventArgs e)
|
|
{
|
|
SetCurrentAction(sender, eTileState.LRoad);
|
|
}
|
|
|
|
private void btn_SetRightRoadPoint_Click(object sender, EventArgs e)
|
|
{
|
|
SetCurrentAction(sender, eTileState.RRoad);
|
|
}
|
|
|
|
private void btn_SetUpRoadPoint_Click(object sender, EventArgs e)
|
|
{
|
|
SetCurrentAction(sender, eTileState.URoad);
|
|
}
|
|
|
|
private void btn_SetDownRoadPoint_Click(object sender, EventArgs e)
|
|
{
|
|
SetCurrentAction(sender, eTileState.DRoad);
|
|
}
|
|
|
|
private void pn_Table_MouseDown(object sender, MouseEventArgs e)
|
|
{
|
|
int x = e.X / tableNodeSize;
|
|
int y = e.Y / tableNodeSize;
|
|
|
|
if(tableData[x, y] == eTileState.Start || tableData[x, y] == eTileState.Goal)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if(curAction != null)
|
|
{
|
|
switch(curAction.Value.actionType)
|
|
{
|
|
case eTileState.Start:
|
|
if(tableData[x, y] == eTileState.Wall) break;
|
|
|
|
tableData[startPoint.X, startPoint.Y] = eTileState.None;
|
|
|
|
startPoint = new Point(x, y);
|
|
SetCurrentAction(null, eTileState.None);
|
|
tableData[startPoint.X, startPoint.Y] = eTileState.Start;
|
|
|
|
break;
|
|
case eTileState.Goal:
|
|
if(tableData[x, y] == eTileState.Wall) break;
|
|
|
|
tableData[goalPoint.X, goalPoint.Y] = eTileState.None;
|
|
|
|
goalPoint = new Point(x, y);
|
|
SetCurrentAction(null, eTileState.None);
|
|
tableData[goalPoint.X, goalPoint.Y] = eTileState.Goal;
|
|
|
|
break;
|
|
case eTileState.Wall:
|
|
if(tableData[x, y] == eTileState.Start || tableData[x, y] == eTileState.Goal)
|
|
break;
|
|
|
|
if(tableData[x, y] == eTileState.Wall)
|
|
{
|
|
tableData[x, y] = eTileState.None;
|
|
break;
|
|
}
|
|
|
|
tableData[x, y] = eTileState.Wall;
|
|
break;
|
|
case eTileState.Road:
|
|
if (tableData[x, y] == eTileState.Start || tableData[x, y] == eTileState.Goal)
|
|
break;
|
|
|
|
if (tableData[x, y] == eTileState.Road)
|
|
{
|
|
tableData[x, y] = eTileState.None;
|
|
break;
|
|
}
|
|
|
|
tableData[x, y] = eTileState.Road;
|
|
break;
|
|
case eTileState.LRoad:
|
|
if (tableData[x, y] == eTileState.Start || tableData[x, y] == eTileState.Goal)
|
|
break;
|
|
|
|
if (tableData[x, y] == eTileState.LRoad)
|
|
{
|
|
tableData[x, y] = eTileState.None;
|
|
break;
|
|
}
|
|
|
|
tableData[x, y] = eTileState.LRoad;
|
|
break;
|
|
case eTileState.RRoad:
|
|
if (tableData[x, y] == eTileState.Start || tableData[x, y] == eTileState.Goal)
|
|
break;
|
|
|
|
if (tableData[x, y] == eTileState.RRoad)
|
|
{
|
|
tableData[x, y] = eTileState.None;
|
|
break;
|
|
}
|
|
|
|
tableData[x, y] = eTileState.RRoad;
|
|
break;
|
|
case eTileState.URoad:
|
|
if (tableData[x, y] == eTileState.Start || tableData[x, y] == eTileState.Goal)
|
|
break;
|
|
|
|
if (tableData[x, y] == eTileState.URoad)
|
|
{
|
|
tableData[x, y] = eTileState.None;
|
|
break;
|
|
}
|
|
|
|
tableData[x, y] = eTileState.URoad;
|
|
break;
|
|
case eTileState.DRoad:
|
|
if (tableData[x, y] == eTileState.Start || tableData[x, y] == eTileState.Goal)
|
|
break;
|
|
|
|
if (tableData[x, y] == eTileState.DRoad)
|
|
{
|
|
tableData[x, y] = eTileState.None;
|
|
break;
|
|
}
|
|
|
|
tableData[x, y] = eTileState.DRoad;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
(sender as Panel).Refresh();
|
|
}
|
|
|
|
private void pn_Table_MouseMove(object sender, MouseEventArgs e)
|
|
{
|
|
//if(e.Button == MouseButtons.Left)
|
|
//{
|
|
// int x = e.X / tableNodeSize;
|
|
// int y = e.Y / tableNodeSize;
|
|
|
|
// if (this.tableData[x, y] == eTileState.Start || this.tableData[x, y] == eTileState.Goal)
|
|
// {
|
|
// return;
|
|
// }
|
|
|
|
// if (curAction != null)
|
|
// {
|
|
// switch (curAction.Value.actionType)
|
|
// {
|
|
// case eTileState.Road:
|
|
// if (tableData[x, y] == eTileState.Start || tableData[x, y] == eTileState.Goal)
|
|
// break;
|
|
|
|
// if (tableData[x, y] == eTileState.Road)
|
|
// {
|
|
// tableData[x, y] = eTileState.None;
|
|
// break;
|
|
// }
|
|
|
|
// tableData[x, y] = eTileState.Road;
|
|
// break;
|
|
// default:
|
|
// break;
|
|
// }
|
|
// }
|
|
// (sender as Panel).Refresh();
|
|
//}
|
|
}
|
|
|
|
public bool clickState { get; set; }
|
|
|
|
private void btn_PathFind_Click(object sender, EventArgs e)
|
|
{
|
|
//SetCurrentAction(null, eTileState.None);
|
|
//pathFinder.PathFind(pn_Table, startPoint, goalPoint);
|
|
|
|
{
|
|
if (clickState)
|
|
{
|
|
SetCurrentAction(null, eTileState.None);
|
|
pathFinder.PathFind(pn_Table, startPoint, goalPoint);
|
|
clickState = false;
|
|
Direction = "Up";
|
|
}
|
|
else
|
|
{
|
|
SetCurrentAction(null, eTileState.None);
|
|
pathFinder.PathFind(pn_Table, goalPoint, startPoint);
|
|
clickState = true;
|
|
Direction = "Up";
|
|
}
|
|
}
|
|
}
|
|
|
|
private void btn_Step_Click(object sender, EventArgs e)
|
|
{
|
|
SetCurrentAction(null, eTileState.Open);
|
|
|
|
pathFinder.PathFind(pn_Table, startPoint, goalPoint, true);
|
|
}
|
|
}
|
|
} |