이제는 코드 작업.


1. 멤버 변수 선언




solution explorer에서 Form1.cs를 선택하고 표시된 아이콘을 클릭하면 Form1.cs 소스 화일을 보여준다.

이 에디터에서 작업을 한다.


		//	dimension of each cell in the grid
		const int CellWidth = 32;
		const int CellHeight = 32;

		//	offset from the top-left corner of the window
		const int xOffset = -20;
		const int yOffset = 25;

		//	color for empty cells
		private Color DEFAULT_BACKCOLOR = Color.White;

		//	color for original puzzle values
		private Color FIXED_FORECOLOR = Color.Blue;
		private Color FIXED_BACKCOLOR = Color.LightSteelBlue;

		//	color for user inserted values
		private Color USER_FORECOLOR = Color.Black;
		private Color USER_BACKCOLOR = Color.LightYellow;

		//	the number currently selected for insertion
		private int SelectedNumber;

		//	stacks to keep track of all the moves
		//	private Stack Moves = new Stack();				//	이 표현도 괜찮은 듯
		private Stack<string> Moves = new Stack<string>();	//	generic type?
		private Stack<string> RedoMoves = new Stack<string>();

		//	keep track of filename to save to
		private String saveFileName = String.Empty;

		//	used to represent the values in the grid
		private int [,] actual = new int[10, 10];

		//	used to keep track of elapsed time
		private int seconds = 0;

		//	has the game started?
		private Boolean GameStarted = false;


위 코드를 class Form1안에 추가한다.




2. 그리드(셀) 값의 표현



아래 그림과 같은 값을 표현할 때에는,




actual(1, 1) = 4
actual(2, 1) = 0
actual(3, 1) = 2
actual(4, 1) = 0
actual(5, 1) = 3
...
actual(1, 2) = 7
...


이렇게 표현한다. 따라서 10x10 배열이 필요하고, (0,x), (x, 0) 은 사용하지 않는다.




3. 셀의 이름


각 셀은 동적으로 생성된 Label control로 나타내어진다. 각 Label의 Name 프라퍼티는 column과 row의 조합으로 구성된다. 즉,


cell (1, 1) => 11
cell (2, 1) => 21
...


이렇게 표현된다.




4. Erasability of a Cell



각 셀은 유저가 입력한 값(value)나 퍼즐의 고유한 값이 입력된다. 유저가 입력한 값은 지울 수 있고, 퍼즐 고유의 값은 지울 수 없다. 이 특성은 Label의 Tag 프라퍼티를 이용하여 구현한다.


Label.Tag = "1"    //    value can be erased
Label.Tag = "0"    //    cannot be erased




5. 스택에 Moves 저장하기


셀에 값이 입력 될 때마다 스택에 좌표와 값을 저장한다. 유저가 undo를 할 경우 Moves 스택에서 값을 pop하여 Redo 스택에 push 하여 저장한다. 유저가 redo를 선택하면 redo 스택에서 값을 pop 하여 Moves 스택에 push 한다. 스택에 저장되는 값은 세자리의 숫자로 이루어진 스트링이다. (1, 3)에 값 5 => "135" 이렇게 표현된다.






6. 그리드의 동적 생성


어플리케이션이 실행될 때 처음으로 할 일은 9x9, 총 81개의 그리드를 생성하는 일이다. 다음의 코드를 Form1 class 안에 추가한다.


		public void DrawBoard()
		{
			//  default selected number is 1
			toolStripButton1.Checked = true;
			SelectedNumber = 1;

			//  used to store the location of the cell
			Point location = new Point();

			for ( int row = 1; row < 10; row++ )
			{
				for ( int col = 1; col < 10; col++ )
				{
					location.X = col * ( CellWidth + 1 ) + xOffset;
					location.Y = row * ( CellHeight + 1 ) + yOffset;

					Label lbl = new Label();

					lbl.Name = col.ToString() + row.ToString();
					lbl.BorderStyle = BorderStyle.None;
					lbl.Location = location;
					lbl.Width = CellWidth;
					lbl.Height = CellHeight;
					lbl.TextAlign = ContentAlignment.MiddleCenter;
					lbl.BackColor = DEFAULT_BACKCOLOR;
					lbl.Font = new Font( lbl.Font, lbl.Font.Style | FontStyle.Bold );
					lbl.Tag = "1";


					//	Add Handler
					lbl.Click += new EventHandler( Cell_Click );

					this.Controls.Add( lbl );
				}
			}
		}


lbl.Click += new EventHandler( Cell_Click ) 에서 각 Label이 마우스 클릭 이벤트가 발생할 때마다 Cell_Click을 실행하라는 이벤트핸들러를 등록하는 것을 눈여겨 본다. 그리고 this.Controls.Add( lbl ) 로 생성된 Label control을 Form1 (this) 에 추가시킨다.

Cell_Click() 이 없어서 빌드가 되지 않으니 일단 아래의 코드를 추가하여 둔다.


		//	event handler for cell click
		private void Cell_Click( object sender, EventArgs e )
		{
			return;
		}


빌드를 하고 실행을 하여보면 그리드가 그려지지 않는다. 그리드를 그리는 DraqBoard()가 실행되지 않았기 때문. 초기화는 Form1이 실행될 때 발생하는 이벤트인 Form1_Load()에서 한다. Form1.cs [Design]에서 폼을 더블클릭하면 숨겨져 있던 Form1_Load() 코드를 구현해준다. 다음과 같이 수정한다.


		private void Form1_Load( object sender, EventArgs e )
		{
			//	initialize the status bar
			toolStripStatusLabel1.Text = String.Empty;
			toolStripStatusLabel2.Text = String.Empty;

			//	draw the board
			DrawBoard();
		}


다시 Design 창에가서 Form1을 선택하고 프라퍼티 창을 보면 다음과 같이 이벤트 Load에 대한 핸들러를 확인 할 수 있다. 이런 구조를 잘 기억한다.


다시 빌드하고 실행을 해보면 그리드가 그려진다. 3x3 의 minigrid의 outline을 그린다. Form1의 Paint 이벤트 핸들러를 이용하여 그린다. 아래 그림처럼 Form1의 프라퍼티 창, 이벤트 뷰에서 Paint 항목을 찾고, 더블 클릭한다. 그러면 자동으로 Form1_Paint() 이벤트 핸들러 코드를 생성한다.



아래와 같이 Form1_Paint()를 수정한다.


		//
		//	draw the lines outlining the minigrids
		//
		private void Form1_Paint( object sender, PaintEventArgs e )
		{
			int x1, y1, x2, y2;

			//	draw the horizontal lines
			x1 = 1 * ( CellWidth + 1 ) + xOffset - 1;
			x2 = 9 * ( CellWidth + 1 ) + xOffset + CellWidth;

			for ( int i = 1; i <= 10; i = i + 3 )
			{
				y1 = i * ( CellHeight + 1 ) + yOffset - 1;
				y2 = y1;

				e.Graphics.DrawLine( Pens.Black, x1, y1, x2, y2 );
			}

			//	draw the vertical lines
			y1 = 1 * ( CellHeight + 1 ) + yOffset - 1;
			y2 = 9 * ( CellHeight + 1 ) + yOffset + CellHeight;

			for ( int j = 1; j <= 10; j += 3 )
			{
				x1 = j * ( CellWidth + 1 ) + xOffset - 1;
				x2 = x1;

				e.Graphics.DrawLine( Pens.Black, x1, y1, x2, y2 );
			}
		}


빌드를 하고 실행을 하면 아래와 같은 모습을 볼 수 있다.





Posted by 쿨한넘