MainForm.cs 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Data;
  5. using System.Drawing;
  6. using System.Linq;
  7. using System.Text;
  8. using System.Threading.Tasks;
  9. using System.Windows.Forms;
  10. namespace AStar
  11. {
  12. public partial class MainForm : Form
  13. {
  14. public enum UpdateType { None, Init, Create, Build, Move };
  15. private bool _isCreated; // 맵 생성 여부
  16. private bool _isStarted; // 길찾기 시작 여부
  17. private int _mapSizeX;
  18. private int _mapSizeY;
  19. private List<Tile> _tiles;
  20. private List<Tile> _path;
  21. private List<Tile> _openList;
  22. private List<Tile> _closeList;
  23. private UpdateType _updateType;
  24. private Brush _backgroundBrush;
  25. private Brush _normalBrush;
  26. private Brush _blockBrush;
  27. private Brush _pathBrush;
  28. private Brush _textBrush;
  29. private Pen _pen;
  30. private Font _font;
  31. #region Constructor
  32. public MainForm()
  33. {
  34. InitializeComponent();
  35. }
  36. #endregion
  37. #region Control Event
  38. private void MainForm_Load(object sender, EventArgs e)
  39. {
  40. if (DesignMode) return;
  41. _mapSizeX = (int) numericUpDown_x.Value;
  42. _mapSizeY = (int) numericUpDown_y.Value;
  43. _tiles = new List<Tile>();
  44. _path = new List<Tile>();
  45. _openList = new List<Tile>();
  46. _closeList = new List<Tile>();
  47. _backgroundBrush = new SolidBrush(Color.Black);
  48. _normalBrush = new SolidBrush(Color.Gray);
  49. _blockBrush = new SolidBrush(Color.DarkSlateGray);
  50. _pathBrush = new SolidBrush(Color.Red);
  51. _textBrush = new SolidBrush(Color.Yellow);
  52. _pen = new Pen(Color.DarkGray);
  53. _font = new Font("맑은 고딕", 10);
  54. UpdateMap(UpdateType.Init);
  55. }
  56. private void numericUpDown_x_ValueChanged(object sender, EventArgs e)
  57. {
  58. if (_isStarted)
  59. {
  60. numericUpDown_x.Value = _mapSizeX;
  61. }
  62. else
  63. {
  64. _mapSizeX = (int) numericUpDown_x.Value;
  65. }
  66. }
  67. private void numericUpDown_y_ValueChanged(object sender, EventArgs e)
  68. {
  69. if (_isStarted)
  70. {
  71. numericUpDown_y.Value = _mapSizeY;
  72. }
  73. else
  74. {
  75. _mapSizeY = (int) numericUpDown_y.Value;
  76. }
  77. }
  78. private void button_createMap_Click(object sender, EventArgs e)
  79. {
  80. if (_isStarted) return;
  81. _isCreated = false;
  82. int width = (pictureBox_map.Size.Width - 10) / _mapSizeX;
  83. int height = (pictureBox_map.Size.Height - 10) / _mapSizeY;
  84. if (width < height) height = width;
  85. else if (height < width) width = height;
  86. _tiles.Clear();
  87. for (int x = 0; x < _mapSizeX; x++)
  88. {
  89. for (int y = 0; y < _mapSizeY; y++)
  90. {
  91. int locWidth = (x + 1) * width;
  92. int locHeight = (y + 1) * height;
  93. var loc = new Tile()
  94. {
  95. X = x,
  96. Y = y,
  97. Region = new Rectangle(new Point(x * width, y * height), new Size(width, height)),
  98. };
  99. _tiles.Add(loc);
  100. }
  101. }
  102. UpdateMap(UpdateType.Create);
  103. }
  104. private void button_start_Click(object sender, EventArgs e)
  105. {
  106. if (!_isCreated) return;
  107. // 기존 정보 초기화
  108. _tiles.ForEach(o => o.Text = null);
  109. _openList.Clear();
  110. _closeList.Clear();
  111. _path.Clear();
  112. var startTile = _tiles[0];
  113. var endTile = _tiles[_tiles.Count - 1];
  114. _openList.Add(startTile);
  115. Tile tile = null;
  116. do
  117. {
  118. if (_openList.Count == 0) break;
  119. tile = _openList.OrderBy(o => o.F).First();
  120. _openList.Remove(tile);
  121. _closeList.Add(tile);
  122. if (tile == endTile) break;
  123. foreach (var target in _tiles)
  124. {
  125. if (target.IsBlock) continue;
  126. if (_closeList.Contains(target)) continue;
  127. if (!IsNearLoc(tile, target)) continue;
  128. if (!_openList.Contains(target))
  129. {
  130. _openList.Add(target);
  131. target.Execute(tile, endTile);
  132. }
  133. else
  134. {
  135. if (Tile.CalcGValue(tile, target) < target.G)
  136. {
  137. target.Execute(tile, endTile);
  138. }
  139. }
  140. }
  141. }
  142. while (tile != null);
  143. if (tile != endTile)
  144. {
  145. MessageBox.Show("길막힘");
  146. return;
  147. }
  148. do
  149. {
  150. _path.Add(tile);
  151. tile = tile.Parent;
  152. }
  153. while (tile != null);
  154. _path.Reverse();
  155. for (int i = 0; i < _path.Count; i++)
  156. {
  157. if (i == 0) _path[i].Text = "START";
  158. else if (i == _path.Count - 1) _path[i].Text = "END";
  159. else _path[i].Text = i.ToString();
  160. }
  161. _isStarted = true;
  162. UpdateMap(UpdateType.Move);
  163. }
  164. private void pictureBox_map_MouseDown(object sender, MouseEventArgs e)
  165. {
  166. if (!_isCreated || _isStarted) return;
  167. int clickX = e.Location.X;
  168. int clickY = e.Location.Y;
  169. foreach (var loc in _tiles)
  170. {
  171. int minX = loc.Region.X;
  172. int maxX = loc.Region.X + loc.Region.Width;
  173. int minY = loc.Region.Y;
  174. int maxY = loc.Region.Y + loc.Region.Height;
  175. if (clickX >= minX && clickX <= maxX && clickY >= minY && clickY <= maxY)
  176. {
  177. loc.IsBlock = !loc.IsBlock;
  178. break;
  179. }
  180. }
  181. UpdateMap(UpdateType.Build);
  182. }
  183. private void pictureBox_map_Paint(object sender, PaintEventArgs e)
  184. {
  185. if (_updateType == UpdateType.None) return;
  186. switch (_updateType)
  187. {
  188. case UpdateType.Init:
  189. string waitMsg = "1.맵 크기 설정\r\n2.Create 클릭\r\n3.맵에 마우스 왼쪽버튼을 클릭하여 장애물 생성\r\n4.Start 클릭";
  190. int width = pictureBox_map.Size.Width - 10;
  191. int height = pictureBox_map.Size.Height - 10;
  192. if (width < height) height = width;
  193. else if (height < width) width = height;
  194. e.Graphics.FillRectangle(_backgroundBrush, new Rectangle(0, 0, width, height));
  195. e.Graphics.DrawString(waitMsg, _font, _textBrush, 0, 0);
  196. break;
  197. case UpdateType.Create:
  198. foreach (var loc in _tiles)
  199. {
  200. e.Graphics.FillRectangle(_normalBrush, loc.Region);
  201. e.Graphics.DrawRectangle(_pen, loc.Region);
  202. }
  203. _isCreated = true;
  204. break;
  205. case UpdateType.Build:
  206. foreach (var loc in _tiles)
  207. {
  208. if (loc.IsBlock) e.Graphics.FillRectangle(_blockBrush, loc.Region);
  209. else e.Graphics.FillRectangle(_normalBrush, loc.Region);
  210. e.Graphics.DrawRectangle(_pen, loc.Region);
  211. }
  212. break;
  213. case UpdateType.Move:
  214. foreach (var loc in _tiles)
  215. {
  216. if (loc.IsBlock) e.Graphics.FillRectangle(_blockBrush, loc.Region);
  217. else e.Graphics.FillRectangle(_normalBrush, loc.Region);
  218. e.Graphics.DrawRectangle(_pen, loc.Region);
  219. if (!string.IsNullOrWhiteSpace(loc.Text))
  220. {
  221. e.Graphics.DrawString(loc.Text, _font, _textBrush, loc.Region.X, loc.Region.Y);
  222. }
  223. }
  224. foreach (var loc in _path)
  225. {
  226. e.Graphics.FillRectangle(_pathBrush, loc.Region);
  227. e.Graphics.DrawRectangle(_pen, loc.Region);
  228. if (!string.IsNullOrWhiteSpace(loc.Text))
  229. {
  230. e.Graphics.DrawString(loc.Text, _font, _textBrush, loc.Region.X, loc.Region.Y);
  231. }
  232. }
  233. _isStarted = false;
  234. break;
  235. }
  236. _updateType = UpdateType.None;
  237. }
  238. #endregion
  239. #region Private Method
  240. private void UpdateMap(UpdateType type)
  241. {
  242. _updateType = type;
  243. pictureBox_map.Invalidate();
  244. }
  245. private bool IsNearLoc(Tile srcLoc, Tile targetLoc)
  246. {
  247. int diffX = Math.Abs(srcLoc.X - targetLoc.X);
  248. int diffY = Math.Abs(srcLoc.Y - targetLoc.Y);
  249. return diffX <= 1 && diffY <= 1;
  250. }
  251. #endregion
  252. }
  253. }