Exceller's VBA 입문강좌

최초 작성일 : 2005-03-21
최종 수정일 : 2005-03-21

강좌 읽음수 : 106,935회
자료 작성자 : Exceller (권현욱, exceller@amorepacific.com)

강좌 제목 : Sub 프로시저와 Function 프로시저

그리스의 철학자 에픽테투스는 이런 말을 했습니다.

"인간은 일어난 사건에 의해서가 아니라 그 사건에 대한 자신의 의견 때문에 고통을 느끼게 되는 것이다."

불가능이란 "사실"이 아니라 자신의 약한 의지와 다른 사람들의 잘못된 "의견"이 덧붙여진 것일 따름입니다.

무엇을 해도 좋은 계절, 봄이 오고 있습니다. 이번 봄에 꼭 이루고 싶은 것이 하나 있습니다. 그것이 무엇이냐 하면... 비밀이랍니다. ^^* 여러분은 이 봄에 이루고 싶은 어떤 꿈을 가지고 계신가요?


VBA 입문강좌 : Sub 프로시저와 Function 프로시저


 이번 시간에는 Sub 프로시저와 Function 프로시저의 차이점, 그리고 Function 프로시저, 즉 사용자 정의 함수의 기본 개념과 응용 예제들에 대해 살펴봅니다.
 

Sub 프로시저와 Function 프로시저의 차이

우리가 VB Editor에서 작성하는 VBA 코드는 보통 '프로시저'라고 부르며, 가장 일반적인 프로시저는 Sub 프로시저와 Function 프로시저 입니다. 이 두 가지 프로시저의 가장 큰 차이점은,

  • Sub 프로시저 : 특정한 동작을 실행한다.

  • Function 프로시저 : 특정한 계산을 수행하고 그 결과값을 돌려준다.

김 판서가 두 명의 하인에게 똑같은 일거리를 주었습니다. 페인트를 한통씩 주고, "이제 봄이 되었으니 집 앞 담벼락에 페인트 칠을 해라!"하고... 한 나절이 지났습니다. 김 판서가 점검을 하러 나가 보았습니다. 갑돌이에게 맡긴 담벼락은 색칠을 되어 있는데 갑돌이는 어디론가 사라져 버리고 보이지 않는데, 삼돌이는 색칠을 마치고 주인에게 달려와서 결과를 보고합니다.

"저에게 주신 페인트 량은 100리터였는데, 담벼락의 넓이는 가로 10미터, 세로 2미터로 20 평방미터였습니다. 1 평방미터당 소요된 페인트 량이 0.3리터였으므로 60리터를 사용하여, 현재 40 리터의 페인트 재고가 남아 있습니다."

짐작하시겠지만, 여기서 갑돌이는 Sub 프로시저, 삼돌이는 Function 프로시저에 해당됩니다. 어떻습니까? Function 프로시저가 Sub 프로시저보다 더 똑똑해 보이지요? 앞으로는 똘똘한 Function 프로시저만 사용해야 되겠다는 생각이 드시나요?

하지만 세상은 공평한 것... 머리가 똑똑하면 얼굴이 받쳐주지 않고, 외모가 되면 머리가 따라주지 않는 것이 보통이지요. 머리도 똑똑하고 외모도 예술이면... 하다 못해 성격이 괴팍하다거나 팔자가 드세다거나 하는 등, 이 세상에 모든 것을 다 갖춘 사람은 없는 법이지요. Function 프로시저가 Sub 프로시저에 비해 지능은 뛰어난 반면 제약이 있습니다.

Sub 프로시저

보통 여러분이 VBA에서 작성하는 코드는 Sub 프로시저입니다. 매크로 기록기를 이용해서 작성한 코드 역시 Sub 프로시저입니다. 모든 Sub  프로시저는 Sub 라는 키워드로 시작해서 End Sub라는 statement로 끝을 맺습니다.

Sub 안녕하세요()

    MsgBox "안녕하세요 " & Application.UserName & "님!"

End Sub

프로시저명 뒤에는 항상 한 쌍의 괄호가 붙습니다. 보통의 경우, 이 괄호 안에는 아무 것도 들어있지 않지만, 필요한 경우 argument, 즉 인수를 전달하여 실행을 할 수도 있습니다.

Function 프로시저

Function 프로시저는 다른 말로 사용자 정의 함수라고도 부릅니다. 모든 Function  프로시저는 Function 이라는 키워드로 시작해서 End Function 이라는 statement로 끝을 맺습니다. 사용자 정의 함수의 기본적인 작성 형식은 이러합니다.

Function 함수명(인수1, 인수2,...)

    ... 어쩌고 ...

    ... 저쩌고 ...

    함수명 = 결과값

End Function

제곱근을 구해주는 사용자 정의 함수를 만들어 보면,

Function 제곱근(numbern)

    제곱근 = number ^ (1/n)

End Function

여기서 number는 제곱근을 구하고자 하는 값(숫자), n은 몇 제곱근을 구할 것인지를 지정하는 인수입니다. 예를 들어, 위의 코드를 모듈시트에 작성한 다음, 워크시트 내 임의의 셀에 "=제곱근(2,2)" 라고 입력하면 2의 2제곱근 값인 "1.414213..." 라는 결과값이 구해집니다.

Function, 즉 함수는 몇 개의 인수를 가질 수도 있고 전혀 가지지 않을 수도 있습니다(Today, Now, Rand 등과 같이...).

Function 프로시저는 딱 두 가지 방법에 의해서만 실행할 수 있습니다.

  (1) 다른 프로시저(Sub 혹은 Function 프로시저)에서 호출하는 방법
  (2) 워크시트 내에서 수식의 형태로 사용하는 방법

반면, Sub 프로시저는 아주 다양한 방법으로 실행할 수 있는데, 이것이 사람들로 하여금 Sub 프로시저를 더 많이 사용하게 하는 한 가지 이유가 되기도 합니다.

  (1) VBE에서 '표준' 도구모음에 있는 'Sub/사용자 정의 폼 실행' 아이콘 이용
  (2) VBE에서 '실행-Sub/사용자 정의 폼 실행' 메뉴 이용
  (3) VBE에서 '직접 실행 창'에서 바로 실행 ← Sub 프로시저명 입력/엔터
  (4) 단축 키를 통해 실행(Ctrl + 단축 키) ← 단축 키가 미리 지정되어 있을 경우
  (5) 다른 Sub 프로시저에서 호출하여 실행
  (6) 워크시트에서 버튼이나 도형 등의 개체에 연결하여 실행
  (7) '도구-매크로-매크로' 메뉴를 통해 실행
  (8) 도구 모음의 사용자 지정 단추에 연결하여 실행
  (9) 사용자 지정 메뉴에 연결하여 실행
  (10) 특정한 이벤트가 발생하였을 때 실행 ← 이벤트 프로시저에 연결하여

참으로 많은 방법이 있기도 하지요? 이것 말고도 더 있을 지도 모릅니다. 그리고 Function 프로시저는 Sub 프로시저에서 쉽게 할 수 있는 글꼴을 변경한다거나 셀의 색상을 변경한다거나 하는 작업은 할 수 없습니다. 
 

사용자 정의 함수 예제

(1) 인수를 하나도 가지지 않는 사용자 정의 함수

Function UserName()

    UserName = Application.UserName

End Function

'=UserName()' 이라고 입력하면 현재 사용자의 이름이 표시됩니다.

 

(2) 상여금 계산 사용자 정의 함수

아래과 같은 사원 기본정보가 있다고 할 때, 직종에 따라 성과급을 차등 지급하는 사용자 정의 함수를 작성해 보겠습니다.

Function 성과급(직종코드, 연봉)

    Select Case 직종코드
        Case 1
            성과급 = 연봉 * 0.1
        Case 2, 3
            성과급 = 연봉 * 0.08
        Case 4 To 7
            성과급 = 1000000
        Case Is > 7
            성과급 = 500000
        End Select

End Function

이 함수를 실행하면 다음과 같은 결과를 얻을 수 있습니다.

 

(3) 선택적 인수Optional argument를 가지는 사용자 정의 함수

특정한 범위 내에서 상위 5개 값의 평균을 구해야 한다면 어떻게 해야 할까요? 엑셀에는 그런 기능을 수행하는 함수가 따로 없기 때문에 다음과 같은 형태의 수식을 사용해야 할 것입니다.

= (Large(영역, 1) + Large(영역, 2) + ... + Large(영역, 5)) / 5

물론 이 수식은 오류없이 제대로 작동합니다. 하지만 그다지 좋은 해결 방법이라고 하기는 어렵습니다. 왜냐고요? 모로가도 어디로만 가면 되지 않느냐구요?? 그렇다면... 만약 상위 10개 값의 평균을 구해야 한다면 수식을,

= (Large(영역, 1) + Large(영역, 2) + ... + Large(영역, 10)) / 10

이런 식으로 바꾸어 주실 것입니까? 그러면 100개 값의 평균은 어떻습니까? 곤란하겠지요? 이런 경우 사용자 정의 함수를 만들면 간단히 해결할 수 있습니다.

Function 상위평균(rngX, Optional n = 5)

    Dim dblSum As Double
    Dim i As Integer

    For i = 1 To n
        dblSum = dblSum + Application.WorksheetFunction.Large(rngX, i)
    Next i

    상위평균 = dblSum / n

End Function

여기서... Optional 이라는 새로운 단어가 하나 나왔군요. 우리가 잘 아는 Left 함수를 생각해 보면,

Left(텍스트, 추출할 문자 수)

이런 형식으로 사용됩니다. 만약 '추출할 문자 수' 인수를 생략하면 엑셀이 알아서 1로 간주합니다. 즉 다음 두 수식은 같은 결과값을 돌려줍니다.

= Left(A1, 1)
= Left(A1)

이처럼, 사용자 정의 함수에서 특정한 인수를 생략하면 기본적으로 어떤 값을 갖도록 설정할 때 사용하는 것이 Optional 키워드입니다.

(4) 인수의 개수가 정해져 있지 않은 사용자 정의 함수

어떤 워크시트 함수는 인수의 개수가 미리 정해져 있지 않은 것이 있습니다. 어떤 것이 있을까요? 대표적인 것으로 Sum 함수가 있습니다.

= Sum(number1, number2,...)

이런 식으로 30개 까지의 인수를 가질 수 있습니다. 여기서 첫번째 인수는 반드시 있어야 하지만 나머지 인수는 상황에 따라 변합니다. 이런 함수는 어떻게 하면 만들 수 있을까요? ParamArray 키워드를 사용하면 가능합니다.

Function MySum(ParamArray XXX() As Variant) As Double
    Dim varX As Variant

    For Each varX In XXX
        MySum = MySum + varX
    Next varX
End Function
 

ParamArray 키워드는 항상 Variant 데이터 타입이며, 항상 선택적 인수Optional argument입니다. 설령 Optonal 키워드를 사용하지 않았더라도 말입니다.

사용자 정의 함수 범주 변경하기

기본적으로 사용자 정의 함수는 '사용자 정의' 범주에 포함되어 있습니다. VBA를 이용하면 이 범주를 변경할 수 있습니다(왜 그렇게 만들었는지 이유를 알 수는 없지만, 워크시트 상태에서 수작업으로는 바꾸어 줄 방법이 없습니다).

 

MacroOptions 메서드를 사용하여 다음과 같이 해 주면 '상위평균'이라는 사용자 정의 함수의 범주가 수학/삼각함수 범주로 변경됩니다.

Sub ChangeCategory()
    Application.MacroOptions macro:="상위평균", Category:=3
End Sub

<MacroOption 메서드의 기본 제공 범주>

함수 범주

0

모두

1

재무

2

날짜/시간

3

수학/삼각

4

통계

5

찾기/참조 영역

6

데이터베이스

7

텍스트

8

논리

9

정보

10

Commands(이 범주는 화면상에 표시되지 않습니다)

11

Customizing(이 범주도 숨겨져 있습니다)

12

Macro Control(이 범주도 숨겨져 있습니다)

13

DDE/External(이 범주도 숨겨져 있습니다)

14

사용자 정의(Default)

15

공학(분석 도구를 추가 설치한 경우 나타납니다)

사용자 정의 함수 설명 추가하기

'함수 마법사' 대화상자에서 엑셀의 워크시트 함수를 선택해 보면 해당 함수에 대한 간단한 설명이 나타나는 것을 볼 수 있습니다. 하지만 사용자 정의 함수에 대해서도 마찬가지로 이러한 설명이 나타나도록 할 수 있습니다.

 

  (1) '도구-매크로-매크로' 메뉴를 선택하니다.
  (2) '매크로 이름' 항목에 해당 함수의 이름을 입력합니다.
       ('매크로' 대화상자에는 사용자 정의 함수의 이름이 표시되지 않습니다)
  (3) '옵션' 버튼을 클릭합니다.
  (4) '설명' 항목에 함수에 대한 자세한 설명을 기입합니다.
  (5) '확인' 버튼을 클릭합니다.
  (6) '취소' 버튼을 클릭합니다.

   새로운 함수 범주를 만들 수 있을까?

함수 범주를 새로이 추가할 수는 없습니다. 또한 사용자 정의 함수의 인수argument에 세부적인 설명을 추가할 수도 없습니다. 대신 사용자 정의 함수의 인수 이름을 의미있는 것으로 지정해 주면 어느 정도는 직관적으로 이해할 수 있게 되므로 편리합니다.

원래 이번 강좌는 계획에 없던 것입니다만, 오피스 튜터에서 가졌던 [Excel VBA 활용 과정]을 수강하신 분들에게 설명드린 내용을 정리하면서 포함하는 것이 좋을 것 같아 작성하였습니다.

이번 강좌는 여기까지...
 


 Previous

Next 

 

ⓒ 2005 Exceller Corporation. All rights reserved.


1.    F1 : 선택된 항목에 대한 비주얼 베이직 도움말 보기
2.    F2 : 개체 찾아보기
3.    F3 : 다음 찾기
4.    F5 : 컴파일하기
5.    Crtl+F5 : 전체 컴파일한 후 다시 시작하기
6.    Crtl+F : 찾아보기 (Find)
7.    Crtl+H : 바꾸기
8.    Crtl+I : 변수등의 요약 정보
9.    Crtl+J : 속성과 메소드 목록보기
10.    Crtl+Z : 실행 취소
11.    Crtl+DEL : 한 단어만 지우기
12.    Crtl+오른쪽 화살표 : 한 단어만큼 오른쪽으로 이동
13.    Crtl+왼쪽 화살표 : 한 단어만큼 왼쪽으로 이동
14.    Crtl+Home : 해당 모듈의 처음으로 이동
15.    Crtl+End : 해당 모듈의 끝으로 이동
16.    Crtl+아래쪽 화살표 : 다음 프로시저의 첫번째 줄로 이동
17.    Crtl+위쪽 화살표 : 이전 프로시저의 첫번째 줄로 이동
18.    Crtl+Page Up : 이전 프로시저 선언으로 가기
19.    Crtl+Page down : 다음 프로시저 선언으로 가기
20.    Crtl+스페이스바 : 나머지 단어 채우기
21.    Shift+F2 : 프로시저 정의 보기
22.    Shift+F3 : 이전 찾기
23.    Shift+F10 : 오른쪽 마우스 버튼 클릭한것과 동일한 효과
24.    Shift+Tab : 선택된 부분의 들여쓰기 해제
25.    Shift+오른쪽 화살표 : 오른쪽으로 한 단어 더 선택하기
26.    Shift+왼쪽 화살표 : 왼쪽으로 선택된 한 단어 해제하기
27.    Shift+아래쪽 화살표 : 위로 한 줄 더 선택하기/지우기
28.    Ctrl+Shift+F2 : 가장 마지막으로 가기
29.    Ctrl+Shift+J : 상수 열거
30.    Ctrl+Shift+I : 인수 정보 보기


  1. Shift + F2        : 선언된 함수, 변수로 이동하기
  2. Shift + Ctrl + F2 : Shift + F2 로 가서 되돌아오기
  3. F8                : 한문장씩 실행하기(중지모드에서 사용)
  4. Shift + F8        : 어떤 문장이 사용자 정의 함수를 호출할시
                         F8키는 함수안으로 들어가지만, Shift + F8 키는
                         함수를 모두 실행하고 다음 문장으로 이동합니다.
                         (중지모드에서 사용)
  5. Ctrl + F9         : 노란색선을 원하는 위치로 이동하기
                         중지모드에서 현재 실행중인 코드가 노란색으로
                         나타납니다. 마우스나 키보드로 특정문장으로
                         커서를 이동 시킨뒤 Ctrl + F9키를 누르면 
                         여기부터 다시 실행할 수 있습니다.
  6. Ctrl + SpaceBar   : 단어채우기
                         코딩중 긴함수나 긴변수를 일일히 쓰는건 아주
                         짜증나는 일입니다. 만약 변수명이 mintRecordCount
                         일 경우 mintR 한다음에 Ctrl + SpaceBar를
                         누르면 단어가 자동으로 채워 집니다. 
                         (중복 단어가 있으면 골라서 사용할 수 있습니다.)
  7. 꽁수(....^^)
     만약 어떤 이벤트를 테스트할 목적으로 디버깅 하려면 여러분들은
     보통 어떤식으로 하십니까?... 아마 그 이벤트에 F9키를 눌러서
     중단점을 잡아 놓고서 F5키를 눌러서 실행 할 것입니다.
     그런데 중단점을 잡아 놓지 않고, 할수 있는 방법이 있는데 그 방법을
     설명해 드리겠습니다...

     먼저 실행도중에 Ctrl + Break키를 눌러서 중지모드 상태로 들어갑니다.
     다음에 F8키를 누르고, 어떤 이벤트(버튼클릭 또는 키보드 입력 ....)를 
     발생시키면 디버깅 상태로 들어갈 것입니다.(전재조건 : 발생시킨 이벤트 
     안에는 반드시 코드가 있어야겠죠...)



단축키(ShortCut Key) 설명 
   CTRL+C              선택영역 복사하기  
   CTRL+X              선택영역 잘라내기 
   CTRL+Y              현재줄 잘라내기  
   CTRL+V              붙여넣기  
   CTRL+DELETE         문장단위로 지우기 
   TAB                 선택영역 한번에 내여쓰기  
   SHIFT+TAB           선택영역 한번에 들여쓰기  
   CTRL+Z              되돌리기(실행취소)  
   CTRL+RIGHT ARROW    다음 단어로 이동  
   CTRL+LEFT ARROW     이전 단어로 이동  
   CTRL+DOWN ARROW     다음 프로시져로 이동  
   CTRL+UP ARROW       이전 프로시져로 이동 
   SHIFT+F2            정의 보기  
   CTRL+F              찾기  
   CTRL+H              바꾸기  
   CTRL+S              저장하기  
   F7                  코드창으로 이동하기 
   F4                  속성창으로 이동하기  
   CTRL+R              프로젝트 탐색기로 이동하기  
   F5                  실행  
   F8                  한 단계씩 코드 실행

'Knowledge > Visual Basic 6+' 카테고리의 다른 글

[VB6] Replace Function - Visual Basic 6.0  (0) 2018.04.02
Visual Basic 문법  (0) 2018.03.27
[VB6] What is Me.Caption  (0) 2018.03.26
For...Next Statement (Visual Basic)  (0) 2018.03.13
Sub 프로시저와 Function 프로시저  (0) 2018.03.13

Encoding URL (a.k.a Percent Encoding)

개발을 하다가 URL을 왜 Encoding 해야 하는가? 라는 생각이 들자 갑자기 URL을 Encoding 한다는게 의미하는게 정확히 뭔가? 라는 생각이 들었다.

URL을 Encoding해야 되는 이유는 크게 2가지다.

1. RFC3986에 따르면 URL은 ASCII Character-set으로만 구성되어야 하기 때문에 한글을 포함한 대부분의 외국어나 ASCII에 정의되지 않은 특수문자의 경우 URL에 포함될 수 없기 때문에.

2. URL 내에서 의미를 갖고 있는 문자(%, ?, #)나 URL에 올 수 없는 문자 (Space) 혹은 System에서 해석이 될 수 있는 문자(<, >)를 치환하여 야기될 수 있는 문제점을 예방하기 위해. 
* URL에서 문제를 야기할 수 있는 문자들은 이 링크에 잘 정리되어 있습니다.

1) 태초에 URL은 ASCII Character-set으로만 구성되도록 설계되었고, 인터넷 초창기에는 이러한 부분이 크게 문제가 되지도 불편하지도 않았을 거다.  2) 허나 시간이 흐르고, 예상과 다르게 인터넷이 빅히트를 치고 URL이 세계적으로 광범위하게 사용됨에 따라, ASCII의 128개 Character-set으로만 URL을 구성하는건 마치 딸기맛 새콤달콤 밖에 만들 수 없는 제약과 비슷하게 느껴졌을 것이다. 또한 세종대왕 포함 각국의 오피니언 리더들은 모국어로 URL을 만들고 싶은 바램이 있었을 것이다.  3) 이러한 시대의 바램에 부응하기 위해 URL은 ASCII의 한계를 벗어나는 노력을 게을리 하지 않았고, 마침내 Percent Encoding이라는 꼼수라면 꼼수요, 규약이라면 규약을 통해 ASCII의 한계를 벗어날 수 있었던 것이다.

URL Encoding은 어떻게 이루어지는가?

URL Encoding stands for encoding certain characters in a URL by replacing them with one or more character triplet(s) that consist of the percent character %” followed by two hexadecimal digits.

위의 문장이 가장 깔끔하게 URL Encoding을 정의한다. URL에서 문제가 될 수 있는 문자를 %와 2개의 16진수로 구성된 triplet(s)들로 치환한다. 몇개의 triplet으로 하나의 문자를 표현하는지는 Encoding Type과 치환하려는 글자의 종류에 따라 다르다.

Examples) URL Encoding이 필요한 경우와 before & after.

  • ASCII에 정의되지 않는 문자가 포함된 경우. (라틴어는 UTF-8 기준 2byte로 표현된다.) 
    Ex) François  ->Fran%C3%A7ois
  • ASCII에 정의되지 않는 문자가 포함된 경우. (한글은 UTF-8 기준 3byte로 표현된다.) 
    Ex) 왜 -> %EC%99%9C
  • URL에 공백이 포함된 경우. (URL에는 공백이 포함될 수 없기 때문에 %20으로 치환된다) 
    Ex) hello world -> hello%20world
  • %는 URL Encoding을 판단하는 문자로 % 이후는 인코딩 타입으로 인식한다. 따라서 %를 그대로 URL로 전달할때는 %25로 치환해야한다. 
    Ex) 50%people -> 50%25people
  •  #은 URL에서 Fragment 구분자로 사용되기 때문에 #을 그대로 사용하려면 %23으로 치환해서 사용해야 한다. 
    Ex) apple# -> apple%23

위의 설명에 가장 부합하도록 URL(URI)을 Encoding 해주는 Library는 commons-httpclient에 포함되어 있는 URIUtil Class의 encodeQuery(String) 함수가 가장 원하는 결과를 반환하는 것 같다.

* References (More examples and practice) 
http://www.ietf.org/rfc/rfc3986.txt 
http://www.url-encode-decode.com/ 
http://bluestarblogkr.blogspot.kr/2011/10/url-encoding.html


'Knowledge' 카테고리의 다른 글

[MS-SQL] 테이블 복사  (0) 2018.03.16
[MS-SQL] date와 Datetime의 차이점  (1) 2018.03.16
PSTN  (0) 2018.03.04
C# Winforms Message Box  (0) 2018.03.04
Wave 파일 압축 코덱 비교  (0) 2018.02.24

교환국을 통해 불특정 다수의 가입자들에게 음성 전화나 자료 교환 서비스를 제공한다. 이를 이용하여 자료 전송을 하려는 경우에는 모뎀을 사용하여야 한다. 우리나라에는 약 1,800만 이상의 전화 가입자가 접속되어 있으며 어느 전화기에서도 상대방 전화번호를 누르면 15초 이내에 1,800만여 개 번호 중에서 오직 다이얼한 그 번호를 정확하게 골라 접속할 수 있도록 되어 있다.

각 가정(또는 사무실)의 전화기는 가입자 선을 통하여 전화국의 교환기에 접속되어 있는데 가입자 선을 수용하는 이 교환기를 지역교환기(LS:Local Switch, 가입자 선 교환기라고도 함)라고 한다. LS가 설치되어 있는 전화국은 보통 가입자를 수용하기 편리하도록 그 구역의 중심에 자리잡고 있으며, 수km 내지 십수km 간격으로 설치되어 있다.

교환기는 작은 스위치의 집합으로, 다이얼한 번호를 따라 차례로 스위치를 닫아서 전화를 걸고자 하는 상대방의 가입자 선에 접속하게 해준다. 상대방이 같은 구역 내에 거주하고 있으면 같은 LS 내에서 쉽게 접속될 수 있지만, 다른 구역에 있을 경우에는 그 구역의 LS까지 전송로를 연결시키지 않으면 안 된다. 그래서 시외전화일 때는 경로가 훨씬 복잡해진다. 다이얼 숫자를 보고 시외전화임을 식별하게 되면 LS시외전화국의 교환기를 선택하여 접속하고, 여기서 상대방의 구역에 접속하는 구조로 되어 있다. 

가입자와는 직접 접속하지 않고 교환기와 교환기를 중계하는 기능을 가진 교환기는 시외 교환기 또는 시외 중계교환기라고 부른다. 전화국과 전화국 사이를 연결하는 전송로는 국간 전송로라고 하며, 전송로 매체로는 동축케이블, 마이크로웨이브 무선, 그리고 광섬유 케이블 등이 사용된다.

[네이버 지식백과] PSTN [public switched telephone network] (두산백과)


'Knowledge' 카테고리의 다른 글

[MS-SQL] date와 Datetime의 차이점  (1) 2018.03.16
Encoding URL  (0) 2018.03.07
C# Winforms Message Box  (0) 2018.03.04
Wave 파일 압축 코덱 비교  (0) 2018.02.24
[mysql] 트랜젝션  (0) 2018.02.23

C# Winforms Message Box Properties

in C# winforms when we display a message box it has no title in the title bar and no title in its button that is in the task bar.

What if i want to set title and icon for a message box.

one option is that create a form that appears and behaves like a message box and i show and hide it when i want. yes that can be done but i want to modify the "MessageBox"

3 Answers

Use a MessageBox.Show overload such as:

public static DialogResult Show(
    string text,
    string caption,
    MessageBoxButtons buttons,
    MessageBoxIcon icon
)

passing your title bar text in caption and your icon in icon e.g.

MessageBox.Show("Oh noes!", "My Application", MessageBoxButtons.OK, MessageBoxIcon.Error);

There is an overloaded version of show message box that will accept a title string and let you specify the icon and number/type of buttons.

The MessageBox.Show method has a bunch of overrides that allow you to set the properties of the pop-up.

http://msdn.microsoft.com/en-us/library/system.windows.forms.messagebox.show%28VS.71%29.aspx


'Knowledge' 카테고리의 다른 글

Encoding URL  (0) 2018.03.07
PSTN  (0) 2018.03.04
Wave 파일 압축 코덱 비교  (0) 2018.02.24
[mysql] 트랜젝션  (0) 2018.02.23
DataGrip 사용법 페이지  (0) 2018.02.23

Wave 파일 압축 코덱 비교

오디오 압축 관리

PCM, GSM, ADPCM, CELP, SBC, TrueSpeech, 및 MPEG Layer-3 등의 오디오 압축 관리자를 사용하여 ".wav" 및 ".dct"에 사용할 수 있는 다양한 wave 압축 코덱의 오디오 품질과 압축 비트 레이트의 목록입니다. 참고: 오디오 압축 관리자 (ACM)는 .wav (wave) 또는 .dct (dictation) 파일로 녹음할 때 사용됩니다. 기타 포맷에 대해서는 사운드 파일 포맷 페이지를 참조하십시오.

ACM을 사용하는 제품:

이 페이지에 기재되어 있는 오디오 파일의 압축 형식은 낮은 비트레이트 오디오 형식입니다. 높은 비트레이트의 음악 및 방송 음성 포맷은 표시되지 않았습니다.

각각의 오디오 형식의 샘플을 청취하려면, "견본" 링크를 클릭하십시오.

형식

비트레이트

1분 =

견본

11,025Hz 16비트 PCM176.4kbs1292k11k16bitpcm.wav
8000Hz 16비트 PCM128kbs937.5k8k16bitpcm.wav
11,025Hz 8비트 PCM88.2kbs646k11k8bitpcm.wav
11,025Hz u-Law88.2kbs646k11kulaw.wav
8,000Hz 8비트 PCM64kbs468.8k8k8bitpcm.wav
8,000Hz u-Law
*회선 전화 품질
64kbs468.8k8kulaw.wav
11,025Hz 4비트 ADPCM44.1kbs323k11kadpcm.wav
8000Hz 4비트 ADPCM32kbs234.4k8kadpcm.wav
11,025Hz GSM6.1018kbs131.8k11kgsm.wav
8000Hz Mp3 16k16kbs117k8kmp316.wav
8,000Hz GSM6.10
* 휴대 전화 품질
13kbs102.5k8kgsm.wav
8000Hz Lernout & Hauspie SBC 12k12.0kbs87.9k8ksbc12.wav
8,000Hz DSP Group TrueSpeech9kbs65.9k8ktruespeech.wav
8000Hz Mp3 8k8kbs60k8kmp38.wav
8,000Hz Lernout & Hauspie CELP4.8kbs35k8kcelp.wav

댓글

위에 열거한 것들은 wave 파일들입니다 - mp3 코덱을 포함하더라도 ".wav" 또는 ".dct" 확장자가 붙습니다. 다른 파일 포맷의 개요에 대해서는, 사운드 파일 포맷 페이지를 참조하십시오.

추천 코덱

현재 NCH 소프트웨어는 음성 녹음의 경우에 GSM6.10 8000Hz를 권장하고 있습니다.

형식 문제

Windows 2000/XP에 포함된 "마이크로 소프트 G.723.1"는 ACM 코덱에 버그가 있기 때문에 인코딩 / 리코딩에 사용할 수 없습니다. 이 포맷은 사용하지 마십시오.

토론 포럼

ACM 코덱에 대한 질문이나 또는 관심이 있다면, 사운드 포맷 토론 포럼을 참조하십시오.

ACM을 지원하는 소프트웨어

많은 NCH 소프트웨어 전문 오디오 소프트웨어 응용 프로그램은 오디오 압축 관리자를 포함하고 있습니다:


'Knowledge' 카테고리의 다른 글

PSTN  (0) 2018.03.04
C# Winforms Message Box  (0) 2018.03.04
[mysql] 트랜젝션  (0) 2018.02.23
DataGrip 사용법 페이지  (0) 2018.02.23
G.711  (0) 2018.02.21

mysql transaction


트랜잭션을 알아보기 이전에 먼저 엔진을 확인해야 합니다.

MySQL에는 많은 엔진이 있지만 대표적으로 InnoDB와 MyISAM을 사용하고 있는데요

InnoDB인 경우에만 트랜잭션을 사용할 수 있습니다


트랜잭션이란 쉽게 설명해드리면 은행 입출금을 생각해볼 수 있습니다

A라는 사람이 B한데 10만원을 송금하는 과정에서 A계좌에서 -10만원을 하고 B계좌에 +10만원하는 과정에서 오류가 나면 A계좌에만 10만원이 빠져있는 현상이 발생하겠죠

그래서 필요한게 트랜잭션입니다

트랜잭션은 여러 단계의 처리를 하나의 처리처럼 다루는 기능입니다.

트랜잭션의 실행 결과를 데이터베이스에 반영하는것을 커밋(commit), 다시 이전으로 되돌리는 것을 롤백(rollback)이라고 합니다


트랜잭션 시작하기

> START TRANSACTION;

> A 계좌에 -10만원

> B 계좌에 +10만원

> COMMIT

결과 : A계좌에 10만원이 빠져나가있고 B계좌에 10만원이 들어와있음


> START TRANSACTION;

> A 계좌에 -10만원

> B 계좌에 +10만원

> ROLLBACK

결과 : A,B계좌 금액 변동 없음


트랜잭션은 기본적으로 자동커밋을 사용하고 있습니다.

이를 OFF로 하기 위해서는

> set autocommit=0;

을 실행하면 됩니다.


만약에 데이터베이스를 여럿이서 공유하고 있다면 set autocommit을 수행하면 다른 사람들에게는 꼭 알려줘야겠죠?

그래서 데이터베이스에서 직접 바꾸는 것이 아닌 코드상에서 자동커밋을 막고 하는걸 권해드립니다


단, 아래의 쿼리는 트랜잭션을 지원하지 않으니 주의해주세요

* DROP DATABASE

* DROP TABLE

* DROP

* ALTER TABLE

[출처] mysql transaction|작성자 티딩


'Knowledge' 카테고리의 다른 글

PSTN  (0) 2018.03.04
C# Winforms Message Box  (0) 2018.03.04
Wave 파일 압축 코덱 비교  (0) 2018.02.24
DataGrip 사용법 페이지  (0) 2018.02.23
G.711  (0) 2018.02.21

해당 페이지에 가면 다른 사용법을 터득할 수 있다.


https://www.jetbrains.com/datagrip/whatsnew/#executing-queries



Executing queries

DataGrip now prompts you to choose a database/schema along with a data source when you try to run an SQL file from the context menu.

A similar enhancement: the list of data sources with related consoles will appear when attaching the console to a file.

There was only one Execute action before; now there are three of them. Change the behavior, and assign shortcuts: they are completely independent. For example, you can create an action which will execute the whole script, without having to choose the exact query from the script.

There is a small improvement for those who didn’t like to use the mouse to choose the schema of the console or the search path. Now there is an action called Set Current Schema. You can invoke it from Find Action(Ctrl+Shift+A).

Or just assign a shortcut! For example, Ctrl+Up can work. And you’ll be able to switch the context for the query console.


'Knowledge' 카테고리의 다른 글

PSTN  (0) 2018.03.04
C# Winforms Message Box  (0) 2018.03.04
Wave 파일 압축 코덱 비교  (0) 2018.02.24
[mysql] 트랜젝션  (0) 2018.02.23
G.711  (0) 2018.02.21

G.711

위키백과, 우리 모두의 백과사전.
이동: 둘러보기, 검색

G.711ITU-T의 오디오 컴팬딩을 위한 표준이다. 주로 전화에서 많이 쓰인다. 공식적인 명칭은 '음성 주파수의 펄스 부호 변조(PCM)'이다. G.711은 또한 IP 네트워크 상의 팩스 통신에도 사용된다. 펄스 부호 변조(PCM)으로도 알려져 있는 G.711은 파형 코덱으로 자주 사용된다. G.711은 64 kbit/s에서 시외 전화 정도의 품질을 제공하는 협대역 오디오 코덱이다. G.711은 300-3400 Hz 범위의 오디오 신호를 통과시키며 초당 8000샘플링의 레이트로 샘플링한다.

G.711에는 두가지 강화 버전이 있는데 G.711.0과 G.711.1이다. G.711.0은 대역폭 사용을 줄이기 위해 무손실 데이터 압축을 활용한다. G.711.1은 대역폭을 크게 하여 오디오 품질을 증가시킨다.

기능[편집]

  • 샘플링 주파수 8 kHz
  • 64 kbit/s 비트레이트(8kHz 샘플링 주파수 x 8 비트/샘플 수)
  • 형식적 알고리즘 지연 시간은 0.125 ms이며 look-ahead 지연은 없음.
  • G.711은 파형 음성 코더
  • G.711 부록 I은 패킷화된 네트워크에서 전송 손실을 숨기는 것을 도와주는 패킷 손실 은폐(PLC) 알고리즘을 정의한다.
  • G.711 부록 II는 무음 상태일 때 대역폭 사용을 줄이기 위해 음성 활동 감지(VAD)와 안정 소음 발생(CNG)를 사용하는 불연속 전송(DTX) 알고리즘을 정의한다.
  • 이상적인 조건 하에서 테스트 했을 때 PSQM은 G.711 μ-law가 4.45점, G.711 A-law가 4.45점의 평균 오피니언 평점을 도출해냈다.
  • 네트워크 부하 상태에서 테스트 했을 때 PSQM은 G.711 μ-law가 4.13점, G.711 A-law가 4.11점의 평균 오피니언 평점을 도출해냈다.

라이선스[편집]

G.711이 1972년에 발표됐기 때문에 특허는 이미 사라진지 오래되었다. 그러므로 자유롭게 사용가능하다.[1]


'Knowledge' 카테고리의 다른 글

PSTN  (0) 2018.03.04
C# Winforms Message Box  (0) 2018.03.04
Wave 파일 압축 코덱 비교  (0) 2018.02.24
[mysql] 트랜젝션  (0) 2018.02.23
DataGrip 사용법 페이지  (0) 2018.02.23

import java.io.BufferedReader;

import java.io.File;

import java.io.FileReader;

import java.io.InputStreamReader;

import java.util.ArrayList;

import java.util.HashSet;

import java.util.Stack;

import java.util.StringTokenizer;


class Point {

int y, x;


public Point(int y, int x) {

this.y = y;

this.x = x;

}

}


class Process {

int y, x;


public Process(int y, int x) {

this.y = y;

this.x = x;

}


HashSet<Point> moveSet = new HashSet();


public boolean on(int rIndex) {

// 해당 방향으로 전선을 잇는다.


int nextY = y;

int nextX = x;

int endIndex = Solution.MapSize - 1;


while (true) {

nextY += Solution.rotY[rIndex];

nextX += Solution.rotX[rIndex];


if (isRight(nextY, nextX)) {

// 경로기록

moveSet.add(new Point(nextY, nextX));

//경계지점에 도달

if (nextX == 0 || nextY == 0 || nextX == endIndex || nextY == endIndex) {

// 전선연결

for (Point item : moveSet) {

Solution.Visited[item.y][item.x] = 1;

}


return true;

}

} else {

// 경로 삭제

moveSet.clear();

return false;

}

}

}


public boolean isRight(int y, int x) {

if (x < 0 || y < 0 || x >= Solution.MapSize || y >= Solution.MapSize) {

// 배열범위

return false;

} else if (Solution.Visited[y][x] != 0) {

// 해당구획

return false;

}

return true;

}


public void off() {

// 전선을 제거한다.

for (Point item : moveSet) {

Solution.Visited[item.y][item.x] = 0;

}


moveSet.clear();

}


}


class Solution {


static boolean Debug = true;

private static int T;

static int MapSize;


static int[][] Visited; // 시간정보

private static ArrayList<Process> pList;

private static int processLen;

private static int[] checkMin;


public static void main(String args[]) throws Exception {


BufferedReader br;

if (Debug) {

File f = new File("C:\\Users\\wvimi\\Downloads", "sample_input (14).txt");

FileReader reader = new FileReader(f);

br = new BufferedReader(reader);

} else {

br = new BufferedReader(new InputStreamReader(System.in)); // 직접입력시 이용

}


StringTokenizer st;


int TestSize = Integer.parseInt(br.readLine());

for (T = 1; T <= TestSize; T++) {


// 맵의 크기

MapSize = Integer.parseInt(br.readLine());


// 프로세스 리스트

pList = new ArrayList<>();

Visited = new int[MapSize][];


// Map 읽기

for (int i = 0; i < MapSize; i++) {

// Map[i] = new int[MapSize];

Visited[i] = new int[MapSize];

st = new StringTokenizer(br.readLine());

for (int j = 0; j < MapSize; j++) {


int item = Integer.parseInt(st.nextToken());

// 맵, Visited 초기화

Visited[i][j] = item == 1 ? 2 : item; // 0:빈공간, 1:방문, 2:프로세스


// 프로세스 등록

if (item == 1) {

boolean inner = i != 0 && j != 0 && i != MapSize - 1 && j != MapSize - 1;

if (inner) {

// 관리 프로세스에 등록

pList.add(new Process(i, j));

}

}


}

}


offProcLen = Integer.MAX_VALUE;

processLen = pList.size();

checkMin = new int[13];


// 최대 값을 저장할 배열

for (int i = 0; i < 13; i++) {

checkMin[i] = Integer.MAX_VALUE;

}


// 탐색

findPath(0, 0);


// 결과 출력

for (int i = 11; i >= 0; i--) {

// 성공한 길이를 탐색

if (checkMin[i] != Integer.MAX_VALUE) {

System.out.println(String.format("#%d %d", T, checkMin[i]));

break;

}

// 그 어떤 전선도 없는 경우

if (i == 0) {

System.out.println(String.format("#%d %d", T, 0));

}

}


}


}


static int offProcLen; // 도달한 0의 개수 (브레이크 조건으로 활용)

static Stack<Integer> debStack = new Stack();


private static void findPath(int index, int bitmask) {


// 끝지점에 도달

if (index == processLen) {


// 0을 몇 번 썼는지 체크

int count_one = countOne(bitmask);

int offLen = processLen - count_one;

if (offProcLen > offLen) {

offProcLen = offLen;

}


// 전선의 길이

int length = 0;

for (Process process : pList) {

length += process.moveSet.size();

}


// 프로세스 개수 별로 최대 개수를 달리한다.

if (checkMin[count_one] > length) {

checkMin[count_one] = length;

}


return;

}


Process item = pList.get(index);


// 프로세스에 전선을 잇는 경우

for (int i = 0; i < 4; i++) {

// 연결이 가능한 경우에만 탐색

int nextBitmask = bitmask + (1 << index);


// 최대 끌 수 있는 프로세스를 고려 (1개까지 꺼서 성공했으면, 2개는 허용 못함)

if (index + 1 - countOne(nextBitmask) <= offProcLen)

if (item.on(i)) {

// debStack.add(i + 1);

findPath(index + 1, nextBitmask);

item.off();

// debStack.pop();

}

}


// 프로세스에 전선을 잇지 않는 경우

// debStack.add(0);

findPath(index + 1, bitmask);

// debStack.pop();


}


static void printMap() {


for (int i = 0; i < MapSize; i++) {

String temp = "";

for (int j = 0; j < MapSize; j++) {

temp += Visited[i][j];

}

log(temp);

}


}


private static int countOne(int bitmask) {


int count = 0;

for (int i = 0; i < processLen; i++) {

if ((bitmask & (1 << i)) != 0) {

count++;

} else {


}

}


return count;

}


static int[] rotY = { -1, 0, 1, 0 };

static int[] rotX = { 0, 1, 0, -1 };


public static void log(String input) {

if (Debug) {

System.out.println(input);

}

}


public static void log(String input, Object... args) {

if (Debug) {

System.out.println(String.format(input, args));

}

}


}

'Knowledge > 알고리즘' 카테고리의 다른 글

[스크랩] MD5 (위키백과)  (0) 2018.06.04
백준 3671번: 산업 스파이의 편지  (0) 2017.10.20
백준 14500번: 테트로미노  (0) 2017.10.20
백준 13460번: 째로탈출2  (0) 2017.10.20
백준 12100번: 2048(Easy)  (0) 2017.10.19

import java.io.BufferedReader;

import java.io.File;

import java.io.FileReader;

import java.io.InputStreamReader;

import java.util.HashSet;

import java.util.StringTokenizer;


public class Main {


private static boolean Debug = true;

private static int PrimeCount;

static int[] pocket;

static HashSet<String> primeSet;

private static int NumberLen;

private static int T;


public static void main(String[] args) throws Exception {


BufferedReader br;


if (Debug) {

File f = new File("C:\\Users\\wvimi\\Downloads", "2048.txt");

FileReader reader = new FileReader(f);

br = new BufferedReader(reader);

} else {

br = new BufferedReader(new InputStreamReader(System.in)); // 직접입력시 이용

}

StringTokenizer st;


int TestLen = Integer.parseInt(br.readLine());

for (T = 0; T < TestLen; T++) {


String NumberStr = br.readLine();

NumberLen = NumberStr.length();

pocket = new int[NumberLen];

for (int i = 0; i < NumberLen; i++) {

pocket[i] = NumberStr.charAt(i) - '0';

}


// 탐색 리스트 초기화

primeSet = new HashSet();

findPath(0, "");

primeSet.remove("");


PrimeCount = 0;

for (String item : primeSet) {

// 소수라면 PrimeCount++

isPrime(Integer.parseInt(item));

}


// 소수의 개수 출력

System.out.println(PrimeCount);

}


}


// 소수 판별

private static boolean isPrime(int num) {


// 2 ~ 제곱근까지 검색

int end = (int) Math.sqrt(num);

for (int i = 2; i <= end; i++) {

if (num % i == 0) {

return false;

}

}


// 2보다 작으면 안되!

if (num < 2) {

return false;

}


PrimeCount++;

return true;

}


private static void findPath(int check, String input) {

// 중복되는 경우는 제거

if (primeSet.contains(input)) {

return;

} else {

primeSet.add(input);

}


// 0인 비트를 골라 1로 채운뒤, 문자열을 조립한다.

for (int i = 0; i < NumberLen; i++) {


int using = 1 << i;


// 시작은 0을 제외한다.

if (check == 0 && pocket[i] == 0) {

continue;

}


if ((check & using) == 0) {

findPath(check + using, input + pocket[i]);

}


}


}


public static void log(String input) {

if (Debug) {

System.out.println(input);

}

}


public static void log(String input, Object... args) {

if (Debug) {

System.out.println(String.format(input, args));

}

}


}



import java.io.BufferedReader;

import java.io.File;

import java.io.FileReader;

import java.io.InputStreamReader;

import java.util.ArrayList;

import java.util.HashMap;

import java.util.Map.Entry;

import java.util.StringTokenizer;


class Block {


HashMap<Integer, int[][]> shapeList;

int[][] origin;

int[] flag;

ArrayList<Integer> fList;


// 블록에 해당하는 모양 Data를 만들어줍니다.

public Block(int[][] data, int[] flag) {

this.origin = data;

this.flag = flag;


fList = new ArrayList<>();

for (int item : flag) {

fList.add(item);

}


shapeList = new HashMap<>();

createShape();

// printAllShape();

}


// 회전과 대칭에 따른 데이터(모양) 생성

private void createShape() {


int[][] temp = origin;


// 0번 모양

shapeList.put(0, origin);


// 1~3번 모양(90, 180, 270)

for (int i = 1; i <= 3; i++) {

temp = rotate(temp);

if (fList.contains(i)) {

shapeList.put(i, temp);

}

}


// 4번 모양

int[][] rev = null;

if (fList.contains(4)) {

rev = reverse(origin);

shapeList.put(4, rev);

}


temp = rev;

// 5~7번 모양 rev + (90, 180, 270)

if (fList.contains(5)) {

for (int i = 4; i <= 7; i++) {

temp = rotate(temp);

shapeList.put(i, temp);

}

}


}


// 디버깅을 위한 출력

public void printAllShape() {


int[][] shape;

int ysize, xsize;

for (Entry<Integer, int[][]> entry : shapeList.entrySet()) {


shape = entry.getValue();

ysize = shape.length;

xsize = shape[0].length;


Main.log("[%d]", entry.getKey());


for (int i = 0; i < ysize; i++) {

String line = "";

for (int j = 0; j < xsize; j++) {

line += String.format("%d ", shape[i][j]);

}

Main.log(line);

}

}


}


// 회전 유틸

private int[][] rotate(int[][] data) {

int ysize = data.length;

int xsize = data[0].length;

int end_index = ysize - 1;


int[][] rData = new int[xsize][];

for (int i = 0; i < xsize; i++) {

rData[i] = new int[ysize];

for (int j = 0; j < ysize; j++) {

rData[i][j] = data[end_index - j][i];

}

}


return rData;

}


// 대칭 유틸

private int[][] reverse(int[][] data) {

int ysize = data.length;

int xsize = data[0].length;

int end_index = xsize - 1;


int[][] rData = new int[ysize][];

for (int i = 0; i < ysize; i++) {

rData[i] = new int[xsize];

for (int j = 0; j < xsize; j++) {

rData[i][j] = data[i][end_index - j];

}

}


return rData;

}


}


public class Main {


private static int MapSize_Y;

private static int MapSize_X;

static int[][] Map;


static private ArrayList<Block> bList;


private static boolean Debug = true;

private static int MaxSum;


public static void main(String[] args) throws Exception {


BufferedReader br;


if (Debug) {

File f = new File("C:\\Users\\wvimi\\Downloads", "2048.txt");

FileReader reader = new FileReader(f);

br = new BufferedReader(reader);

} else {

br = new BufferedReader(new InputStreamReader(System.in)); // 직접입력시 이용

}

StringTokenizer st;


// 맵 크기

st = new StringTokenizer(br.readLine());

MapSize_Y = Integer.parseInt(st.nextToken());

MapSize_X = Integer.parseInt(st.nextToken());


// 맵 데이터 입력

Map = new int[MapSize_Y][];

for (int i = 0; i < MapSize_Y; i++) {

st = new StringTokenizer(br.readLine());

Map[i] = new int[MapSize_X];

for (int j = 0; j < MapSize_X; j++) {

Map[i][j] = Integer.parseInt(st.nextToken());

}

}


// 블록을 담을 리스트

bList = new ArrayList<>();

Block item; // 블록에는 모양 값들이 저장 된다.


// 블록 모양, 필요한 모양 값 (0: 원형, 1~3: 회전, 4: 대칭, 5~7: 대칭 후 회전)

int[][] 네모Shape = { { 1, 1 }, { 1, 1 } };

item = new Block(네모Shape, new int[] { 0 });

bList.add(item);


int[][] 일자Shape = { { 1, 1, 1, 1 } };

item = new Block(일자Shape, new int[] { 0, 1 });

bList.add(item);


int[][] 산Shape = { { 1, 1, 1 }, { 0, 1, 0 } };

item = new Block(산Shape, new int[] { 0, 1, 2, 3 });

bList.add(item);


int[][] 기역Shape = { { 1, 0 }, { 1, 0 }, { 1, 1 } };

item = new Block(기역Shape, new int[] { 0, 1, 2, 3, 4, 5, 6, 7 });

bList.add(item);


int[][] 어긋Shape = { { 1, 0 }, { 1, 1 }, { 0, 1 } };

item = new Block(어긋Shape, new int[] { 0, 1, 2, 3, 4, 5, 6, 7 });

bList.add(item);


// 완전탐색

MaxSum = -1;

dfs();


// 시간 출력

System.out.println(MaxSum);

}


public static void dfs() {


int blockLen = bList.size();

// 모든 블록에 대한 경우

for (int i = 0; i < blockLen; i++) {

Block block = bList.get(i);


// 각 블록에 따른 데이터를 가져온다. (대칭 및 회전이 포함된 데이터)

for (Entry<Integer, int[][]> item : block.shapeList.entrySet()) {

int[][] data = item.getValue();

int ysize = data.length, xsize = data[0].length;


// 탐색범위 지정(드레그)

int endy, endx;

endy = MapSize_Y - ysize;

endx = MapSize_X - xsize;


// 지정된 탐색 범위에서, data에 맞도록 검색

search(endy, endx, data);

}


}


}


// 해당 블록 모양을 가지고, 해당 위치에서 검색을 해봅니다.

public static void search(int endy, int endx, int[][] data) {


// 탐색 사이즈

int yszie = data.length, xsize = data[0].length;

// 탐색 구간은 (0,0) ~ (endy, endx) 드레그

for (int y = 0; y <= endy; y++) {

for (int x = 0; x <= endx; x++) {


// Block 모양에 따른 탐색

int sum = 0;

for (int i = 0; i < yszie; i++) {

for (int j = 0; j < xsize; j++) {

if (data[i][j] == 1) { // 탐색

sum += Map[y + i][x + j];

}

}

}


// 최대값 판별

if (MaxSum < sum) {

MaxSum = sum;

}


}

}

// log("합: " + sum);

}


public static void log(String input) {

if (Debug) {

System.out.println(input);

}

}


public static void log(String input, Object... args) {

if (Debug) {

System.out.println(String.format(input, args));

}

}


}



'Knowledge > 알고리즘' 카테고리의 다른 글

1767. [SW Test 샘플문제] 프로세서 연결하기  (0) 2017.10.21
백준 3671번: 산업 스파이의 편지  (0) 2017.10.20
백준 13460번: 째로탈출2  (0) 2017.10.20
백준 12100번: 2048(Easy)  (0) 2017.10.19
백준 3190번: 뱀  (0) 2017.10.19

import java.io.BufferedReader;

import java.io.File;

import java.io.FileReader;

import java.io.InputStreamReader;

import java.util.Stack;

import java.util.StringTokenizer;


class Ball {


int y, x;

static int MapSize_Y;

static int MapSize_X;

static int holeY;

static int holeX;


public Ball(int y, int x) {

this.y = y;

this.x = x;


Main.Map[y][x] = 'X'; // 공의 위치 표기

}


public void move(int rIndex) {


int tempY = y;

int tempX = x;

int moveY = y + Main.rotY[rIndex];

int moveX = x + Main.rotX[rIndex];

// 한 방향으로 직진

while (isRight(moveY, moveX)) {

// 성공좌표를 저장 한다.


y = moveY;

x = moveX;


// 전진

moveY += Main.rotY[rIndex];

moveX += Main.rotX[rIndex];

}


// 공의 위치를 변경한다.

Main.Map[tempY][tempX] = '.';

Main.Map[y][x] = isHoll() ? 'O' : 'X';

}


public void move(int inputY, int inputX) {

Main.Map[this.y][this.x] = isHoll() ? 'O' : '.';

this.y = inputY;

this.x = inputX;

Main.Map[this.y][this.x] = isHoll() ? 'O' : 'X';

}


public boolean isRight(int inputY, int inputX) {


if (inputY < 0 || inputX < 0 || inputY >= MapSize_Y || inputX >= MapSize_X) {

// 배열 밖이라면 No

return false;

} else if (isHoll()) {

// 구멍에 있다면 No

return false;

} else if (Main.Map[inputY][inputX] == 'O') {

// 구멍으로 간다면 Yes

return true;

}


// 빈칸이라면 Yes

return Main.Map[inputY][inputX] == '.';

}


public int getXY() {

return y * MapSize_X + x;

}


public boolean isHoll() {

return Ball.holeX == x && Ball.holeY == y;

}


}


public class Main {


private static boolean Debug = true;


private static final int left = 3, right = 1, up = 0, down = 2;

static int[] rotY = { -1, 0, 1, 0 };

static int[] rotX = { 0, 1, 0, -1 };


private static int MapSize_Y;

private static int MapSize_X;

static char[][] Map;

private static int minFindRed;

static Ball rBall;


private static Ball bBall;


private static int[][] Visited;


public static void main(String[] args) throws Exception {


BufferedReader br;


if (Debug) {

File f = new File("C:\\Users\\wvimi\\Downloads", "2048.txt");

FileReader reader = new FileReader(f);

br = new BufferedReader(reader);

} else {

br = new BufferedReader(new InputStreamReader(System.in)); // 직접입력시 이용

}

StringTokenizer st;


// 맵 크기, 사과 개수

st = new StringTokenizer(br.readLine());

MapSize_Y = Integer.parseInt(st.nextToken());

MapSize_X = Integer.parseInt(st.nextToken());

Ball.MapSize_Y = MapSize_Y;

Ball.MapSize_X = MapSize_X;


// 맵 생성

Map = new char[MapSize_Y][];

for (int i = 0; i < MapSize_Y; i++) {

Map[i] = new char[MapSize_X];

String input = br.readLine();

char item;

for (int j = 0; j < MapSize_X; j++) {


// 맵에 기록, Ball 객체 생성

item = input.charAt(j);

switch (item) {

case 'B':

bBall = new Ball(i, j);

Map[i][j] = 'X';

break;

case 'R':

rBall = new Ball(i, j);

Map[i][j] = 'X';

break;

case 'O':

Ball.holeY = i;

Ball.holeX = j;

Map[i][j] = 'O';

break;

default:

Map[i][j] = item;

break;

}

}

}


// 방문배열 생성 [rBall.getXY()][bBall.getXY()]

int vSize = MapSize_X * MapSize_Y;

Visited = new int[vSize][];

for (int i = 0; i < vSize; i++) {

Visited[i] = new int[vSize];

}


minFindRed = Integer.MAX_VALUE;

// 프레임 체크 (첫 번째 순간은 중복되지 않는다.)

Visited[rBall.getXY()][bBall.getXY()] = 1;


// printMap();

tiltBoard(0);


// 시간 출력

System.out.println(minFindRed == Integer.MAX_VALUE ? -1 : minFindRed);

}


static Stack<Integer> debStack = new Stack();


private static void tiltBoard(int index) {


if (minFindRed <= index) {

// log("탐색불필요 " + debStack);

return;

} else if (bBall.isHoll()) {

// log("[블루볼] " + debStack);

return;

}


// 1.레드볼 여부 && 2. index == 10

if (rBall.isHoll()) { // && !bBall.isHoll() // 위에서 이미 체크

if (minFindRed > index) {

minFindRed = index;

}

// log("[레드볼]" + debStack.toString());

return;

} else if (index == 10) {

// log("[index 10] " + debStack);

return;

}


int redY = rBall.y;

int redX = rBall.x;

int blueY = bBall.y;

int blueX = bBall.x;

for (int i = 0; i < 4; i++) {


// 1. 공을 움직인다.

switch (i) {

case left:

if (redX < blueX) {

rBall.move(i);

bBall.move(i);

} else {

bBall.move(i);

rBall.move(i);

}

break;

case right:

if (redX > blueX) {

rBall.move(i);

bBall.move(i);

} else {

bBall.move(i);

rBall.move(i);

}

break;

case up:

if (redY < blueY) {

rBall.move(i);

bBall.move(i);

} else {

bBall.move(i);

rBall.move(i);

}

break;

case down:

if (redY > blueY) {

rBall.move(i);

bBall.move(i);

} else {

bBall.move(i);

rBall.move(i);

}

break;

}


// 2. 가능한 위치로 이동하여 탐색한다. (좌표 정보는 Ball 객체에 담겨있다.)

// 모두 제자리에 있으면, 탐색X

// 실행됬던 프레임이라면, 탐색X

if (rBall.x == redX && rBall.y == redY && bBall.x == blueX && bBall.y == blueY) {

// non-target

} else if (Visited[rBall.getXY()][bBall.getXY()] == 0) {

Visited[rBall.getXY()][bBall.getXY()] = 1;

// debStack.push(i);


// printMap();

tiltBoard(index + 1);


Visited[rBall.getXY()][bBall.getXY()] = 0;

// debStack.pop();

}


// 3. 공을 원위치로 시킨다.

rBall.move(redY, redX);

bBall.move(blueY, blueX);

}


}


// 디버깅용 프린트 맵

private static void printMap() {


for (int i = 0; i < MapSize_Y; i++) {

String temp = "";

for (int j = 0; j < MapSize_X; j++) {

temp += Map[i][j];

}

if (i == 0) {

temp += "시작";

}

log(temp);

}


}


public static void log(String input) {

if (Debug) {

System.out.println(input);

}

}


public static void log(String input, Object... args) {

if (Debug) {

System.out.println(String.format(input, args));

}

}


}



'Knowledge > 알고리즘' 카테고리의 다른 글

백준 3671번: 산업 스파이의 편지  (0) 2017.10.20
백준 14500번: 테트로미노  (0) 2017.10.20
백준 12100번: 2048(Easy)  (0) 2017.10.19
백준 3190번: 뱀  (0) 2017.10.19
백준 14499번: 주사위 굴리기  (0) 2017.10.19

import java.io.BufferedReader;

import java.io.File;

import java.io.FileReader;

import java.io.InputStreamReader;

import java.util.LinkedList;

import java.util.Queue;

import java.util.StringTokenizer;


public class Main {


private static boolean Debug = true;

private static int MapSize;

private static int[][] OriginMap;

private static int[][] CopyMap;

private static Queue<Integer>[] bQueue;

static int MaxNum = 0;


final static int north = 0, east = 1, south = 2, west = 3;


public static void main(String[] args) throws Exception {


BufferedReader br;


if (Debug) {

File f = new File("C:\\Users\\wvimi\\Downloads", "2048.txt");

FileReader reader = new FileReader(f);

br = new BufferedReader(reader);

} else {

br = new BufferedReader(new InputStreamReader(System.in)); // 직접입력시 이용

}

StringTokenizer st;


// 맵 크기, 사과 개수

MapSize = Integer.parseInt(br.readLine());

MaxNum = 0;


// 맵 생성

OriginMap = new int[MapSize][];

for (int i = 0; i < MapSize; i++) {

OriginMap[i] = new int[MapSize];

st = new StringTokenizer(br.readLine());

int item;

for (int j = 0; j < MapSize; j++) {

item = Integer.parseInt(st.nextToken());

OriginMap[i][j] = item;

// 합칠 수 없는 경우, 처음 주어진 수가 가장 크다.

if (MaxNum < item) {

MaxNum = item;

}

}

}


// 큐 초기화 (블록을 옮기는 데 사용된다.

bQueue = new LinkedList[MapSize];

for (int i = 0; i < MapSize; i++) {

bQueue[i] = new LinkedList<>();

}


// 00000 ~ 33333

int[] bitmasking = new int[5];

execute(bitmasking, 0);


// 시간 출력

System.out.println(MaxNum);

}


private static void execute(int[] bitmask, int index) {


// 비트마스킹을 조립

if (index <= 4) {

for (int i = 0; i < 4; i++) {

bitmask[index] = i;

execute(bitmask, index + 1);

}

return;

}


// 맵초기화

initMap();


// 실행

int rIndex;

for (int i = 0; i < 5; i++) {

rIndex = bitmask[i];

tiltMap(rIndex);

}


}


private static void initMap() {


// Merge를 위한 지도 초기화

CopyMap = new int[MapSize][];

for (int i = 0; i < MapSize; i++) {

CopyMap[i] = new int[MapSize];

for (int j = 0; j < MapSize; j++) {


int num = OriginMap[i][j];

if (num != 0) { // 0은 빈공간

CopyMap[i][j] = num;

} else {

// non-target

}

}

}


}


private static void tiltMap(int rIndex) {

// log("tiltMap(%d)", rIndex);


// 정방향|역방향

// 행기준|열기준

boolean good = (rIndex == west || rIndex == north);

boolean isRow = (rIndex == west || rIndex == east);

// 방향에 따른 병합 및 매칭

int j_start = (good ? 0 : MapSize - 1);

int j_end = (good ? MapSize : -1);

int j_add = (good ? 1 : -1);


for (int i = 0; i < MapSize; i++) {

// 1. 큐에 대입

int j = j_start;

while (j != j_end) {


// 행기준 열기준에 따라 값을 큐에 넣는다. 

int item = isRow ? CopyMap[i][j] : CopyMap[j][i];

if (item != 0) {

bQueue[i].add(item);

// 값을 옮기면, 해당 자리는 빈공간으로 체크

if (isRow) {

CopyMap[i][j] = 0;

} else {

CopyMap[j][i] = 0;

}

}


j += j_add;

}


// 2. 머지

bQueue[i] = mergeBlock(bQueue[i]);


// 3. 맵에 매칭

j = j_start;

while (j != j_end) {

if (!bQueue[i].isEmpty()) {


if (isRow) {

CopyMap[i][j] = bQueue[i].poll();

// log("큐 방출 [%d][%d] = %d", i, j, CopyMap[i][j].num);

} else {

CopyMap[j][i] = bQueue[i].poll();

// log("큐 대입 [%d][%d] = %d", j, i, CopyMap[j][i].num);

}


} else {

break;

}

j += j_add;

}


}


}


static Queue<Integer> rQue;


private static Queue<Integer> mergeBlock(Queue<Integer> que) {


// 반환을 위한 큐

rQue = new LinkedList<>();


// 합치고

int item1 = 0, item2 = 0;

while (true) {


// 합칠 대상1 픽업

if (item1 == 0) {

if (!que.isEmpty()) {

item1 = que.poll();

} else {

// 큐가 비었으므로

break;

}

}


// 합칠 대상2 픽업

if (item2 == 0) {

if (!que.isEmpty()) {

item2 = que.poll();

} else {

// 비교대상이 없으므로

rQue.add(item1);

break;

}

}


// item1과 item2를 합친다.

if (item1 == item2) {


int mergeNum = item1 * 2;

rQue.add(mergeNum);


// 최고값 측정

if (MaxNum < mergeNum) {

MaxNum = mergeNum;

}

item1 = 0;

item2 = 0;

} else { // 합칠수 없는 경우, 이전 비교대상은 rQue에 넣는다.


rQue.add(item1);

item1 = item2; // 다음비교 대상이 첫번 째가 된다.

item2 = 0;

}


}


return rQue;

}


public static void log(String input) {

if (Debug) {

System.out.println(input);

}

}


public static void log(String input, Object... args) {

if (Debug) {

System.out.println(String.format(input, args));

}

}


}



'Knowledge > 알고리즘' 카테고리의 다른 글

백준 14500번: 테트로미노  (0) 2017.10.20
백준 13460번: 째로탈출2  (0) 2017.10.20
백준 3190번: 뱀  (0) 2017.10.19
백준 14499번: 주사위 굴리기  (0) 2017.10.19
백준 14502번: 연구소  (0) 2017.10.17

import java.io.BufferedReader;

import java.io.InputStreamReader;

import java.util.Hashtable;

import java.util.LinkedList;

import java.util.Queue;

import java.util.StringTokenizer;


class Snake {

Queue<Integer> body = new LinkedList<>();


// 해당 위치로 움직인다.

void move(int where, boolean hasApple) {

if (hasApple) {

body.add(where);

} else {

body.poll();

body.add(where);

}

}


// 자기 자신에 충돌하는지 체크한다.

boolean isSelf(int where) {

return body.contains(where);

}

}


public class Main {


private static boolean Debug = false;

private static int MapSize;

private static int[][] Map;

private static Hashtable<Integer, Character> comMap;

private static Snake snake = new Snake();


public static void main(String[] args) throws Exception {


BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

StringTokenizer st;


// 맵 크기, 사과 개수

MapSize = Integer.parseInt(br.readLine());

int AppSize = Integer.parseInt(br.readLine());


// 맵 생성

Map = new int[MapSize][];

for (int i = 0; i < MapSize; i++) {

Map[i] = new int[MapSize];

}


// 사과 위치 배정

int y, x;

for (int i = 0; i < AppSize; i++) {

st = new StringTokenizer(br.readLine());

y = Integer.parseInt(st.nextToken()) - 1;

x = Integer.parseInt(st.nextToken()) - 1;

Map[y][x] = 1;

}


// 커맨드 읽기

comMap = new Hashtable();

int cSize = Integer.parseInt(br.readLine());

int time;

char direct;

for (int i = 0; i < cSize; i++) {

st = new StringTokenizer(br.readLine());

time = Integer.parseInt(st.nextToken());

direct = st.nextToken().charAt(0);

comMap.put(time, direct);

}


// 위치 초기화, 시간 초기화

y = x = 0;

rIndex = 1;

timer = 0;


// 뱀이 움직인다.

snake.move(0, false);

findPath();


// 시간 출력

System.out.println(timer);

}


static int[] rotY = { -1, 0, 1, 0 };

static int[] rotX = { 0, 1, 0, -1 };


static int y, x;

static int rIndex;

static int timer;


private static void findPath() {


// 해당 시간에 방향 전환이 발생하는가?

if (comMap.containsKey(timer)) {

char direct = comMap.get(timer);


// 왼쪽 회전 =>  rIndex--;  // 오른쪽 회전 => rIndex++;

if (direct == 'L') {

rIndex = rIndex == 0 ? 3 : rIndex - 1;

} else {

rIndex = rIndex == 3 ? 0 : rIndex + 1;

}

comMap.remove(timer);

}


// 움직임이 시작되는 순간

timer++;


// 움직이려는 방향이 맞다면 움직인다.

if (isVaild(rIndex)) {


y += rotY[rIndex];

x += rotX[rIndex];


int where = y * MapSize + x;

// 자신의 몸에 충돌하는가?

if (snake.isSelf(where)) {

return;

}


// 사과가 있다면

if (Map[y][x] == 1) {

Map[y][x] = 0;

snake.move(where, true);

} else { // 사과가 없다면

snake.move(where, false);

}


findPath();

} else {

// 움직이는 방향이 맵 밖인 경우, 이탈한다.

return;

}


}


// 해당 방향이 맵의 범위를 초과하는지를 판단한다.

private static boolean isVaild(int index) {


switch (index) {

case 0:

return y - 1 >= 0;

case 2:

return y + 1 < MapSize;

case 1:

return x + 1 < MapSize;

case 3:

return x - 1 >= 0;

}


return false;

}


public static void log(String input) {

if (Debug) {

System.out.println(input);

}

}


public static void log(String input, Object... args) {

if (Debug) {

System.out.println(String.format(input, args));

}

}


}



'Knowledge > 알고리즘' 카테고리의 다른 글

백준 13460번: 째로탈출2  (0) 2017.10.20
백준 12100번: 2048(Easy)  (0) 2017.10.19
백준 14499번: 주사위 굴리기  (0) 2017.10.19
백준 14502번: 연구소  (0) 2017.10.17
백준 14501번: 퇴사  (0) 2017.10.17

+ Recent posts