이제는 코드 작업.
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 ); } }
빌드를 하고 실행을 하면 아래와 같은 모습을 볼 수 있다.
'Programming > Programming Sudoku' 카테고리의 다른 글
Chapter 2. Creating the Sudoku Application (4) (0) | 2012.10.04 |
---|---|
Chapter 2. Creating the Sudoku Application (3) (0) | 2012.09.27 |
Chapter 2. Creating the Sudoku Application (1) (0) | 2012.09.27 |
Chapter 1. What Is Sudoku? (0) | 2012.09.27 |
Intro (0) | 2012.09.27 |