Linux/Tip2012. 10. 1. 06:57

호스트명 변경

호스트명 확인

[voip@voipfnms ~]$ hostname
www.bsidc.co.kr
[voip@voipfnms ~]$

호스트명을 변경하는 파일은 "IP Address변경하기"강좌편에서 말씀드린 바와같이 /etc/sysconfig/network에서 변경만 해주고 네트웍환경을 적용하는 스크립트(/etc/rc.d/init.d/network)를 재실행 해주면 끝이다. 

www.bsidc.co.kr이던 호스트명을 www.abcd.co.kr로 변경하였다

참고 : http://jobdahan.net/server_linux/1139320


 


우분투 -  호스트네임 설정호스트네임 확인

citylock@citylock-ubuntu:~$ hostname
citylock-ubuntu


호스트네임변경 : /etc/hostname 파일의 내용을 변경하면된다.

citylock@citylock-ubuntu:~$ sudo vi  /etc/hostname
인보강-NW연구팀


변경내용 적용


citylock@citylock-ubuntu:~$ sudo /bin/hostname -F /etc/hostname
hostname: the specified hostname is invalid
citylock@citylock-ubuntu:/$ hostname
인보강_NW연구팀
citylock@citylock-ubuntu:/$

=> 아마도 한글, _  이런것들을 사용해서 그런지 메시지가 하나 뜨기는 하나 변경된 내용을 확인할수 있다.

리눅스 & 우분투에서 호스트명 변경 성공~

 

http://citylock.tistory.com/158

Posted by 쿨한넘
Linux/Tip2012. 10. 1. 06:56

우분투 : 아파지 서버의 설정 방법
일반적으로 아파치의 경우 httpd.conf 파일에서 설정을 해주는걸로 알고 있었는데, 우분투로 아파치를 설치했더니 httpd.conf 에는 아무것도 없었다. 그래서 인터넷 검색을 해봤더니 아래 설명들을 확인할수 있다. 다음에 같은 실수를 막기 위해서 기록...

 

아파치 서버 설정파일 :

/etc/apache2/sites-available/default

설정 파일을 수정하고 아파치를 재구동해야 한다.
sudo /etc/init.d/apache2 restart

적용된 내용을 아래 내용에서 확인 할수 있다.
/etc/apache2/sites-enable/default 
아파치 설정 (/etc/apache2/sites-available/default )
<VirtualHost *:80>
   ServerAdmin webmaster@localhost      

   # DocumentRoot /var/www/

DocumentRoot /home/citylock/programmingSrc/php/        ( 기본 디렉토리 변경 )    <Directory />
      Options FollowSymLinks
      AllowOverride None
   </Directory>
   <Directory /home/citylock/programmingSrc/php/>           (기본 디렉토리 변경)
      Options Indexes FollowSymLinks MultiViews
      AllowOverride None
      Order allow,deny
      allow from all
   </Directory>

   ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
   <Directory "/usr/lib/cgi-bin">
      AllowOverride None
      Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
      Order allow,deny
      Allow from all
   </Directory>

   ErrorLog /var/log/apache2/error.log

   # Possible values include: debug, info, notice, warn, error, crit,
   # alert, emerg.
   LogLevel warn

   CustomLog /var/log/apache2/access.log combined

    Alias /doc/ "/usr/share/doc/"
    <Directory "/usr/share/doc/">
        Options Indexes MultiViews FollowSymLinks
        AllowOverride None
        Order deny,allow
        Deny from all
        Allow from 127.0.0.0/255.0.0.0 ::1/128
    </Directory>

</VirtualHost>
 

'Linux > Tip' 카테고리의 다른 글

Using Intel Compilers for Linux with Ubuntu  (0) 2012.10.01
아파치 설치  (0) 2012.10.01
우분투 - 호스트네임 설정  (0) 2012.10.01
리눅스에서 Apache 2.2 + Tomcat 6.0 원초적인 설치방법  (0) 2012.10.01
spring note backup #1  (0) 2012.10.01
Posted by 쿨한넘
Linux/Tip2012. 10. 1. 06:55

리눅스에서 Apache 2.2 + Tomcat 6.0 원초적인 설치방법

▶ 정보통신얘기 ◀ 2009/08/05 10:46

될 수 있으면 OS에서 제공되는 패키지를 이용해서 어플리케이션을 설치하고 관리하려고 하지만, 해당 패키지가 제공되지 않거나, 특별한 설정을 필요로 하는 경우에는 직접 소스를 다운로드 받아서 설치해야 하는 경우가 발생합니다. 데비안 리눅스에서도 Apache 2.2 + Tomcat 6.0 을 패키지로 설치하면 쉽고 빠르게 설치가 가능합니다. 그러나, 다른 리눅스 환경에서는 그다지 만족할만하지 못했습니다. 그리고 데비안 리눅스에서도 톰캣의 인스턴스를 2개 이상 띄워야 할 경우에도 별도 설치를 필요로 합니다. Apache 2.2 에서는 Proxy AJP 모듈이 제공되는데 mod_jk 없이도 편하게 연동이 가능하다고 합니다.
 
  1. /usr/local/src 디렉토리를 생성한다.
  2. http://httpd.apache.org/download.cgi 에서 Apache 2.2 를 다운로드 받는다.
  3. http://tomcat.apache.org/download-60.cgi 에서 Tomcat 6.0 을 다운로드 받는다.
  4. http://java.sun.com 에서 JDK 1.6 을 다운로드 받는다.
  5. 프로젝트를 위한 디렉토리를 생성한다.
              mkdir -p /opt/project/프로젝트이름/web/프로젝트이름/WebContent
              
  6. 프로젝트 디렉토리에 테스트를 위한 인덱스 페이지(index.jsp)를 생성한다.
              <?xml version="1.0" encoding="UTF-8" ?>
    <
    %@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"

    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>
    테스트닷컴</title>
    </head>
    <body>테스트닷컴
    </body>
    </html>
  7. JDK 설치
              # cd /usr/local/src
    # chmod 755 jdk-6u14-linux-i586.bin
    # cp jdk-6u14-linux-i586.bin ..
    # cd ..
    # ./jdk-6u14-linux-i586.bin
    # rm -rf jdk-6u14-linux-i586.bin
    # mv jdk1.6.0_14 jdk1.6

    /etc/profile 에 다음을 추가합니다.

              export PATH="/usr/local/jdk1.6/bin:$PATH"
    export JAVA_HOME="/usr/local/jdk1.6"
    export CATALINA_HOME="/usr/local/tomcat6"
  8. Tomcat 설치
              # cd /usr/local/src
    # cp apache-tomcat-6.0.20.tar.gz ..
    # cd ..
    # tar xvfz apache-tomcat-6.0.20.tar.gz
    # mv apache-tomcat-6.0.20 tomcat6
    # rm -rf apache-tomcat-6.0.20.tar.gz

    /usr/local/tomcat6/conf/server.xml 에 다음과 같이 추가한다.

                    <!-- test.com -->
    <Host name="test.com" debug="0" appBase="" unpackWARs="true" autoDeploy="true">
    <Logger className="org.apache.catalina.logger.FileLogger"

    directory
    ="logs" prefix="test.com_" suffix=".log" timestamp="true"/>

    <Context path="" docBase="/opt/project/프로젝트이름/web/프로젝트이름/WebContent" debug="0">
    <Resources className="org.apache.naming.resources.FileDirContext" allowLinking="true" />
    </Context>
    </Host>

    이제 Tomcat을 다시 시작하고, hosts 파일에 test.com 을 설정하고, 
    웹브라우저에서 http://test.com:8080 을 입력하면 테스트닷컴 페이지를 볼 수 있을 것이다.

  9. Apache 설치 (/usr/local/apache2 에 설치된다.)
              # cd /usr/local/src
    # tar xvfz httpd-2.2.12.tar.gz
    # cd httpd-2.2.12
    # ./configure --enable-mods-shared=all --enable-so --enable-rewrite --enable-proxy --enable-proxy-ajp

    # make; make install

    /usr/local/apache2/conf/httpd.conf 파일을 열어 다음을 추가합니다.

              LoadModule proxy_module modules/mod_proxy.so
    LoadModule proxy_ajp_module modules/mod_proxy_ajp.so
    LoadModule rewrite_module modules/mod_rewrite.so
    LoadModule authz_host_module modules/mod_authz_host.so
    LoadModule log_config_module modules/mod_log_config.so

    가상호스팅 관련 설정을 인클루드 하도록 주석을 풀어줍니다.

              Include conf/extra/httpd-vhosts.conf
              

    /usr/local/apache2/conf/extra/httpd-vhosts.conf 파일을 열어 가상호스트를 추가합니다.

              <VirtualHost *:80>
    DocumentRoot /opt/project/프로젝트이름/web/프로젝트이름/WebContent
    ServerName test.com
    ErrorLog logs/test.com-error_log
    CustomLog logs/test.com-access_log common

    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} \.(htm|html|xhtml|js|css|jpg|gif|png|swf)$
    RewriteRule (.*) - [L]
    RewriteRule (.*) ajp://localhost:8009$1 [P]
    </VirtualHost>

    위와같은 rewrite를 통한 설정은 htm, html, xhtml, js, css, jpg, gif, png, swf 확장자를 가진 요청은 아파치가 처리하도록 하고 나머지는 톰캣이 처리하도록 합니다.

  10. 이제 아파치와 톰캣을 재시작한 후에, 웹브라우저에서 http://test.com 으로 입력하면 테스트페이지를 볼 수 있을 것입니다.

'Linux > Tip' 카테고리의 다른 글

Using Intel Compilers for Linux with Ubuntu  (0) 2012.10.01
아파치 설치  (0) 2012.10.01
우분투 - 호스트네임 설정  (0) 2012.10.01
우분투 : 아파지 서버의 설정 방법  (0) 2012.10.01
spring note backup #1  (0) 2012.10.01
Posted by 쿨한넘
Linux/Tip2012. 10. 1. 06:54

If you happen to be following this tutorial (http://www.simplisticcomplexity.com/2006/8/13/apache-2-2-mod_proxy_balancer-mongrel-on-ubuntu-6-06) and you receive the following error message when compiling Apache 2.2.3 on Ubuntu Dapper Drake.


---------------->


/usr/bin/ld: /usr/local/lib/libz.a(crc32.o): relocation R_X86_64_32 against `a local symbol' can not be used when making a shared object; recompile with -fPIC

/usr/local/lib/libz.a: could not read symbols: Bad value


---------------->


Here is the solution; add this flag when configuring zlib: CFLAGS="-O3 -fPIC" ./configure


This helpful nugget worked for me, I hope it helps someone else.

Posted by 쿨한넘


1. 새로운 게임 시작


design view에서 File 메뉴 -> New를 더블 클릭하여 해당하는 이벤트 핸들러 코드를 생성시킨다. 그리고 아래와 같이 수정한다.


		//
		//	start a new game
		//
		private void newToolStripMenuItem_Click( object sender, EventArgs e )
		{
			if ( GameStarted )
			{
				var response = MessageBox.Show( "Do you want to save current game?",
												"Save current game",
												MessageBoxButtons.YesNoCancel,
												MessageBoxIcon.Question );

				if ( response == DialogResult.Yes )
					SaveGameToDisk( false );
				else if ( response == DialogResult.Cancel )
					return;

			}

			StartNewGame();
		}


SaveGameToDisk()는 일단 아래와 같이 작성해 놓는다.


		//
		//	Save the game to disk
		//
		public void SaveGameToDisk( Boolean saveAs )
		{
			return;
		}


StartNewGame()은  몇가지 변수 업데이트와 statusbar 에 있는 Label control 업데이트, 그리고 ClearBoard() 호출을 담고있다. 코드은 아래와 같다.


		//
		//	start a new game
		//
		public void StartNewGame()
		{
			saveFileName = String.Empty;
			txtActivities.Text = String.Empty;
			seconds = 0;

			ClearBoard();

			GameStarted = true;
			timer1.Enabled = true;
			toolStripStatusLabel1.Text = "New game started";
		}


ClearBoard()는 각 셀을 다시 리셋하고, Moves-RedoMoves 스택의 인스턴스를 새로 생성한다.


		//
		//	clear the board
		//
		public void ClearBoard()
		{
			//	initialize the stacks
			Moves = new Stack<string>();
			RedoMoves = new Stack<string>();

			//	initialize the cells in the board
			for ( int row = 1; row < 10; row++ )
				for ( int col = 1; col < 10; col++ )
					SetCell( col, row, 0, 1 );

		}


SetCell()은 잠시 내버려 둔다.

StartNewGame()에서 timer1.Enabled = true 를 통해 게임을 시작하면 타이머를 활성화 시켰다. 타이머가 활성화 되면 StatusBar의 Label control에 경과한 시간을 타나내고, 이는 timer1_Tick() 이벤트 핸들러에서 처리한다.

Design view에서 timer1의 프라퍼티에서 Interval 을 1000 (1s)로 설정하고, 이벤트 창에서 Tick을 더블클릭하여 timer_Tick() 이벤트 핸들러 코드를 생성한다.


 



		//
		//	increment the time counter
		//
		private void timer1_Tick( object sender, EventArgs e )
		{
			toolStripStatusLabel2.Text = "Elapsed time: " + seconds + " second(s)";

			seconds += 1;
		}



2. 셀에 입력할 수의 선택


SelectedNumber 변수는 입력을 위해 선택된 수를 가지고 있으며, Erase 버튼을 선택하면 값은 0을 가지게 된다.

Design view에서 ToolStrip에 있는 Button 10개를 동시에 선택하고 Click 이벤트 핸들러 항목에 'toolStripButton_Click'를 입력한다. 이러면 각 버튼의 클릭 이벤트를 하나의 핸들러에서 처리가 가능하다.



 



생성된 코드를 아래와 같이 수정한다.



		private void ToolStripButton_Click( object sender, EventArgs e )
		{
			//	ToolStripButton selectedButton = (ToolStripButton)sender;		//	ok
			ToolStripButton selectedButton = sender as ToolStripButton;

			//	uncheck all the Button controls in the ToolStrip
			toolStripButton1.Checked = false;
			toolStripButton2.Checked = false;
			toolStripButton3.Checked = false;
			toolStripButton4.Checked = false;
			toolStripButton5.Checked = false;
			toolStripButton6.Checked = false;
			toolStripButton7.Checked = false;
			toolStripButton8.Checked = false;
			toolStripButton9.Checked = false;
			toolStripButton10.Checked = false;

			//	set the selected button to "checked"
			selectedButton.Checked = true;

			//	set the appropriate number selected
			if ( selectedButton.Text == "Erase" )
				SelectedNumber = 0;
			else
				SelectedNumber = int.Parse( selectedButton.Text );

		}



3. ToolStrip Label의 Click 이벤트 핸들링


셀을 클릭하게 되면 ToolStrip에 있는 선택된 버튼의 값이 셀에 입력된다. 그러나 셀의 값이 퍼즐의 고유 값, 즉 erasable 하지 않으면 바로 리턴한다(즉, Lable의 Tag 프라퍼티가 "0"이면 바로 리턴). Label의 Tag 값이 "1" (erasable) 이면 이벤트 Sender object의 Name으로 value를 결정한다. 그리고  Moves 스택에 push. 그런후에 puzzle이 완전히 완성이 되었는지도 검사한다. Cell_Click()을 다음과 같이 수정한다.



		//
		//	event handler for cell click
		//
		private void Cell_Click( object sender, EventArgs e )
		{
			//	check to see if game has even started or not

			if ( !GameStarted )
			{
				DisplayActivity( "Click File->New to start a new game or File->Open to load an existing game", true );
				return;
			}

			Label cellLabel = sender as Label;

			//	if cell is not erasable then exit
			if ( cellLabel.Tag.ToString() == "0" )
			{
				DisplayActivity( "Selected cell is not empty", false );
				return;
			}

			//	determine the col and row of the selected cell
			int col = int.Parse( cellLabel.Name.Substring( 0, 1 ) );
			int row = int.Parse( cellLabel.Name.Substring( 1, 1 ) );

			//	if erasing a cell
			if ( SelectedNumber == 0 )
			{
				//	if cell is empty then no need to erase
				if ( actual[col, row] == 0 )
					return;

				//	save the value in the array
				SetCell( col, row, SelectedNumber, 1 );
				DisplayActivity( "Number erased at (" + col + ", " + row + ")", false );
			}
			else if ( cellLabel.Text == String.Empty )
			{
				//	else set a value, check if move is valid
				if ( !IsMoveValid( col, row, SelectedNumber ) )
				{
					DisplayActivity( "Invalid move at (" + col + ", " + row + ")", false );
					return;
				}

				//	save the value in the array
				SetCell( col, row, SelectedNumber, 1 );
				DisplayActivity( "Number " + SelectedNumber.ToString() + " placed at (" + col + ", " + row + ")", false );

				//	save the move into the stack
				Moves.Push( cellLabel.Name.ToString() + SelectedNumber );

				//	check if the puzzle is solved
				if ( IsPuzzleSolved() )
				{
					timer1.Enabled = false;
					Console.Beep();
					toolStripStatusLabel1.Text = "**** Puzzle is Solved ****";
				}
			}

		}



4. 움직임의 유효성 검사


셀에 값을 입력하기 전에 스도쿠 룰에 따라 입력 하려는 값이 유효한지 검사한다. 입력하려는 수는 minigrid, column, row에서 유일한 값이어야 한다. IsMoveValid() 함수는 아래와 같이 구현한다.



		//
		//	check if move is valid
		//

		public Boolean IsMoveValid( int col, int row, int value )
		{
			Boolean puzzleSolved = true;

			//	scan through column
			for ( int i = 1; i < 10; i++ )
				if ( actual[col, i] == value )		//	duplicate
					return false;

			//	scan through row
			for ( int i = 1; i < 10; i++ )
				if ( actual[i, row] == value )		//	duplicate
					return false;

			//	scan through minigrid
			int startCol = col - ( ( col - 1 ) % 3 );
			int startRow = row - ( ( row - 1 ) % 3 );

			for ( int rr = 0; rr < 3; rr++ )
				for ( int cc=0; cc < 3; cc++ )
					if ( actual[startCol + cc, startRow + rr] == value )	//	duplicate
						return false;

			return true;
		}



5. 퍼즐이 해결되었는지를 검사


셀에 값이 입력이 되면 퍼즐이 완성되었는지를 검사한다. IsPuzzleSolved()는 아래와 같다.



		//
		//	check whether a puzzle is solved
		//
		public Boolean IsPuzzleSolved()
		{
			String pattern;

			//	check row by row
			for ( int r = 1; r < 10; r++ )
			{
				pattern = "123456789";

				for ( int c = 1; c < 10; c++ )
					pattern = pattern.Replace( actual[c, r].ToString(), String.Empty );

				if ( pattern.Length > 0 )
					return false;
			}

			//	check column by column
			for ( int c = 1; c < 10; c++ )
			{
				pattern = "123456789";

				for ( int r = 1; r < 10; r++ )
					pattern = pattern.Replace( actual[c, r].ToString(), String.Empty );

				if ( pattern.Length > 0 )
					return false;
			}

			//	check by minigrid

			for ( int c=1; c < 10; c = c + 3 )
			{
				pattern = "123456789";

				for ( int r=1; r < 10; r = r + 3 )
				{
					for ( int cc=0; cc < 3; cc++ )
						for ( int rr=0; rr < 3; rr++ )
							pattern = pattern.Replace( actual[c + cc, r + rr].ToString(), String.Empty );
				}

				if ( pattern.Length > 0 )
					return false;
			}

			return true;
		}



6. 셀의 값 갱신


SetCell() 함수는 지정된 column, row 위치의 cell이 erasable 한지를 검사하고, 그 셀에 값을 지정한다. 셀은 동적으로 생성된 Label 콘트롤로 표현되어 있어서, Controls 클래스의 Find() 메쏘드를 사용한다. SetCell()은 또한 셀의 컬러를 지정한다.



		//
		//	set a cell to a given value
		//
		public void SetCell( int col, int row, int value, int erasable )
		{
			//	locate particular Label control
			Control [] lbl = this.Controls.Find( col.ToString() + row.ToString(), true );
			Label cellLabel = lbl[0] as Label;

			//	save the value in the array
			actual[col, row] = value;

			//	set the appearance for the Label control
			if ( value == 0 )		//	erasing the cell
			{
				cellLabel.Text = String.Empty;
				cellLabel.Tag = erasable;
				cellLabel.BackColor = DEFAULT_BACKCOLOR;
			}
			else
			{
				if ( erasable == 0 )
				{
					//	means default puzzle values
					cellLabel.BackColor = FIXED_BACKCOLOR;
					cellLabel.ForeColor = FIXED_FORECOLOR;
				}
				else
				{
					//	means user-set value
					cellLabel.BackColor = USER_BACKCOLOR;
					cellLabel.ForeColor = USER_FORECOLOR;
				}

				cellLabel.Text = value.ToString();
				cellLabel.Tag = erasable;
			}
		}



7. 메세지 출력


폼의 TextBox 콘트롤에 메세지를 출력하는 DisplayActivity()는 다음과 같다.



		//
		//	Display a message in the Activities text box
		//
		public void DisplayActivity( String str, Boolean soundBeep )
		{
			if ( soundBeep )
				Console.Beep();

			txtActivities.Text += str + Environment.NewLine;
		}



일단 여기까지면 빌드와 테스트를 할 수 있다.





Posted by 쿨한넘

이제는 코드 작업.


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 쿨한넘

이 챕터에서 구현할 스도쿠 어플리케이션의 기능은,


  • 스도쿠 어플리케이션의 유저 인터페이스
  • 그리드(셀)의 값을 어레이(배열)을 이용하여 표현
  • 움직임(푸는 과정)을 스택 데이터 스트럭쳐에 저장
  • Label controls를 이용하여 그리드를 동적으로 생성
  • Label controls의 마우스 클릭 이벤트를 핸들링
  • 움직임의 유효성 검사 (스도쿠 룰)
  • 퍼즐이 해결되었는지 검사
  • 셀(cell)의 값 업데이트
  • Undoing/Redoing
  • 게임 저장
  • 저장된 게임 로드
  • 게임 끝마치기


퍼즐 풀기등의 기능은 chapter 3에서 구현.

이 챕터에서 구현될 어플리케이션의 모습은,



이런 모습이다. 디자인에서 책과는 조금 다른 점이 있다.




1. 프로젝트를 만든다.






2. 유저 인터페이스를 만든다.


위와 같은 폼이 생기면 폼의 프라퍼티에서 아래 테이블과 같이 속성을 지정한다.


그러면,





3. MenuStrip Control을 추가한다.


Toolbox에서 Menustrip을 찾아 드래그 또는 더블클릭으로 폼에 추가한다.



추가된 MenuStrip의 smart tag을 클랙해서 'Insert Standard Items'를 선택한다.



아래와 같이 메뉴 항목을 수정한다.


 

Level 메뉴 항목은 다음과 같이 수정하면 된다. 나는 'E&xtremely Difficult'로 했다.




4. ToolStrip Control 추가한다.


MenuStrip Control과 마찬가지로 Toolbox에서 ToolStrip을 찾아 폼에 추가한다. MenuStrip 바로 아래에 붙어서 생성된다. 그리고 1개의 Label과 10개의 Button을 ToolStrip에 추가한다.



Label의 Text 프라퍼티를 'Select Number'로 바꾼다. Button의 'DisplayStyle' 프라퍼티를 'Text'로 바꾸고 각 Button의 'Text'프라퍼티를 1, 2, 3, 4, 5, 6, 7, 8, 9, Ease로 설정한다. Button을 다중선택하고 프라퍼티를 변경할 수 있다.





5. StatusStrip Control을 추가한다.


Toolbox에서 StatusStrip을 찾아 추가한다. 폼의 아래에 생긴다. 추가된 StatusStrip에 두개의 Label을 추가한다.




6. 기타 Control 추가.


아래 그림과 표를 참조하여 각 Control 들을 추가한다.



각 control의 프라퍼티에서 (Name) 속성을 btnHint, btnSolvePuzzle, txtActivities 으로 각각 바꿔준다.



셀 그리드는 Label을 이용하여 동적으로 생성한다. 코드 참조.


그리고 마지막으로 Toolbox에서 Timer를 찾아 추가한다.


여기까지의 모양은 아래와 같다. 각각의 control에서 폰트를 Tahoma로 바꾸었다.



Posted by 쿨한넘

별건 없고, 스도쿠에 관한 설명.



3x3 격자를 이 책에서는 minigrid 라고 부른다. 총 9개의 minigrid.




이 좌표는 프로그래밍 전반에 걸쳐서 사용된다. 일반적으로 좌표는 ( 행(row), 열(column) )로 사용하는 게 내 버릇이지만, 여기서는 ( 열(column), 행(row) ) 형식의 좌표를 사용하므로 주의한다.


책에서 소개한 스도쿠 관련 사이트



Posted by 쿨한넘

우연히 얻게된 "Programming Sudoku" (Wei-Meng Lee, Apress, 2006).



이 책은 Visual Basic을 이용하여 스도쿠 어플리케이션 작성을 설명했다.

이를 기본으로 C#으로 옮기는 과정을 기록한다.

책은 Microsoft Visual Basic 2005를 기준으로 설명을 했고, 나는 Microsoft Visual C# 2010, .NET Framework 4.0을 사용하였다. Visual Basic도 모르고, C#, .NET Framework도 몰라서 나중에라도 더 좋은 구현 방법을 찾을 수 있겠다.

Posted by 쿨한넘
BSD2012. 9. 20. 11:28

/etc/fstab 에 다음을 추가한다.


proc           /proc       procfs  rw  0   0


'BSD' 카테고리의 다른 글

ubuntu tweak 설치하기  (0) 2012.09.14
ubuntu에 apt-get 이 있다면, openSUSE 에는  (0) 2012.09.07
Kubuntu 12.04 에서 google chrome browser install  (0) 2012.09.07
Posted by 쿨한넘